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.
26 #include "smu7_dyn_defaults.h"
28 #include "smu_ucode_xfer_vi.h"
29 #include "fiji_smumgr.h"
30 #include "fiji_ppsmc.h"
31 #include "smu73_discrete.h"
32 #include "ppatomctrl.h"
33 #include "smu/smu_7_1_3_d.h"
34 #include "smu/smu_7_1_3_sh_mask.h"
35 #include "gmc/gmc_8_1_d.h"
36 #include "gmc/gmc_8_1_sh_mask.h"
37 #include "oss/oss_3_0_d.h"
38 #include "gca/gfx_8_0_d.h"
39 #include "bif/bif_5_0_d.h"
40 #include "bif/bif_5_0_sh_mask.h"
41 #include "dce/dce_10_0_d.h"
42 #include "dce/dce_10_0_sh_mask.h"
43 #include "hardwaremanager.h"
44 #include "cgs_common.h"
46 #include "pppcielanes.h"
48 #include "smu7_hwmgr.h"
51 #define AVFS_EN_MSB 1568
52 #define AVFS_EN_LSB 1568
54 #define FIJI_SMC_SIZE 0x20000
56 #define VOLTAGE_SCALE 4
57 #define POWERTUNE_DEFAULT_SET_MAX 1
58 #define VOLTAGE_VID_OFFSET_SCALE1 625
59 #define VOLTAGE_VID_OFFSET_SCALE2 100
60 #define VDDC_VDDCI_DELTA 300
61 #define MC_CG_ARB_FREQ_F1 0x0b
63 /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs
64 * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ]
66 static const uint16_t fiji_clock_stretcher_lookup_table
[2][4] = {
67 {600, 1050, 3, 0}, {600, 1050, 6, 1} };
69 /* [FF, SS] type, [] 4 voltage ranges, and
70 * [Floor Freq, Boundary Freq, VID min , VID max]
72 static const uint32_t fiji_clock_stretcher_ddt_table
[2][4][4] = {
73 { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
74 { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
76 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%]
77 * (coming from PWR_CKS_CNTL.stretch_amount reg spec)
79 static const uint8_t fiji_clock_stretch_amount_conversion
[2][6] = {
80 {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} };
82 static const struct fiji_pt_defaults fiji_power_tune_data_set_array
[POWERTUNE_DEFAULT_SET_MAX
] = {
83 /*sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc */
85 /* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase */
89 static const struct SMU73_Discrete_GraphicsLevel avfs_graphics_level
[8] = {
90 /* Min Sclk pcie DeepSleep Activity CgSpll CgSpll spllSpread SpllSpread CcPwr CcPwr Sclk Display Enabled Enabled Voltage Power */
91 /* Voltage, Frequency, DpmLevel, DivId, Level, FuncCntl3, FuncCntl4, Spectrum, Spectrum2, DynRm, DynRm1 Did, Watermark, ForActivity, ForThrottle, UpHyst, DownHyst, DownHyst, Throttle */
92 { 0x3c0fd047, 0x30750000, 0x00, 0x03, 0x1e00, 0x00200410, 0x87020000, 0x21680000, 0x0c000000, 0, 0, 0x16, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
93 { 0xa00fd047, 0x409c0000, 0x01, 0x04, 0x1e00, 0x00800510, 0x87020000, 0x21680000, 0x11000000, 0, 0, 0x16, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
94 { 0x0410d047, 0x50c30000, 0x01, 0x00, 0x1e00, 0x00600410, 0x87020000, 0x21680000, 0x0d000000, 0, 0, 0x0e, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
95 { 0x6810d047, 0x60ea0000, 0x01, 0x00, 0x1e00, 0x00800410, 0x87020000, 0x21680000, 0x0e000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
96 { 0xcc10d047, 0xe8fd0000, 0x01, 0x00, 0x1e00, 0x00e00410, 0x87020000, 0x21680000, 0x0f000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
97 { 0x3011d047, 0x70110100, 0x01, 0x00, 0x1e00, 0x00400510, 0x87020000, 0x21680000, 0x10000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
98 { 0x9411d047, 0xf8240100, 0x01, 0x00, 0x1e00, 0x00a00510, 0x87020000, 0x21680000, 0x11000000, 0, 0, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 },
99 { 0xf811d047, 0x80380100, 0x01, 0x00, 0x1e00, 0x00000610, 0x87020000, 0x21680000, 0x12000000, 0, 0, 0x0c, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00 }
102 static int fiji_start_smu_in_protection_mode(struct pp_hwmgr
*hwmgr
)
106 /* Wait for smc boot up */
107 /* PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, SMC_IND,
108 RCU_UC_EVENTS, boot_seq_done, 0); */
110 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
111 SMC_SYSCON_RESET_CNTL
, rst_reg
, 1);
113 result
= smu7_upload_smu_firmware_image(hwmgr
);
118 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
121 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
122 SMC_SYSCON_CLOCK_CNTL_0
, ck_disable
, 0);
124 /* De-assert reset */
125 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
126 SMC_SYSCON_RESET_CNTL
, rst_reg
, 0);
128 /* Wait for ROM firmware to initialize interrupt hendler */
129 /*SMUM_WAIT_VFPF_INDIRECT_REGISTER(hwmgr, SMC_IND,
130 SMC_INTR_CNTL_MASK_0, 0x10040, 0xFFFFFFFF); */
132 /* Set SMU Auto Start */
133 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
134 SMU_INPUT_DATA
, AUTO_START
, 1);
136 /* Clear firmware interrupt enable flag */
137 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
138 ixFIRMWARE_FLAGS
, 0);
140 PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr
, SMC_IND
, RCU_UC_EVENTS
,
141 INTERRUPTS_ENABLED
, 1);
143 cgs_write_register(hwmgr
->device
, mmSMC_MSG_ARG_0
, 0x20000);
144 cgs_write_register(hwmgr
->device
, mmSMC_MESSAGE_0
, PPSMC_MSG_Test
);
145 PHM_WAIT_FIELD_UNEQUAL(hwmgr
, SMC_RESP_0
, SMC_RESP
, 0);
147 /* Wait for done bit to be set */
148 PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr
, SMC_IND
,
149 SMU_STATUS
, SMU_DONE
, 0);
151 /* Check pass/failed indicator */
152 if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
153 SMU_STATUS
, SMU_PASS
) != 1) {
154 PP_ASSERT_WITH_CODE(false,
155 "SMU Firmware start failed!", return -1);
158 /* Wait for firmware to initialize */
159 PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr
, SMC_IND
,
160 FIRMWARE_FLAGS
, INTERRUPTS_ENABLED
, 1);
165 static int fiji_start_smu_in_non_protection_mode(struct pp_hwmgr
*hwmgr
)
169 /* wait for smc boot up */
170 PHM_WAIT_VFPF_INDIRECT_FIELD_UNEQUAL(hwmgr
, SMC_IND
,
171 RCU_UC_EVENTS
, boot_seq_done
, 0);
173 /* Clear firmware interrupt enable flag */
174 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
175 ixFIRMWARE_FLAGS
, 0);
178 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
179 SMC_SYSCON_RESET_CNTL
, rst_reg
, 1);
181 result
= smu7_upload_smu_firmware_image(hwmgr
);
185 /* Set smc instruct start point at 0x0 */
186 smu7_program_jump_on_start(hwmgr
);
189 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
190 SMC_SYSCON_CLOCK_CNTL_0
, ck_disable
, 0);
192 /* De-assert reset */
193 PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
194 SMC_SYSCON_RESET_CNTL
, rst_reg
, 0);
196 /* Wait for firmware to initialize */
197 PHM_WAIT_VFPF_INDIRECT_FIELD(hwmgr
, SMC_IND
,
198 FIRMWARE_FLAGS
, INTERRUPTS_ENABLED
, 1);
203 static int fiji_start_avfs_btc(struct pp_hwmgr
*hwmgr
)
206 struct smu7_smumgr
*smu_data
= (struct smu7_smumgr
*)(hwmgr
->smu_backend
);
208 if (0 != smu_data
->avfs
.avfs_btc_param
) {
209 if (0 != smu7_send_msg_to_smc_with_parameter(hwmgr
,
210 PPSMC_MSG_PerformBtc
, smu_data
->avfs
.avfs_btc_param
)) {
211 pr_info("[AVFS][Fiji_PerformBtc] PerformBTC SMU msg failed");
215 /* Soft-Reset to reset the engine before loading uCode */
217 cgs_write_register(hwmgr
->device
, mmCP_MEC_CNTL
, 0x50000000);
218 /* reset everything */
219 cgs_write_register(hwmgr
->device
, mmGRBM_SOFT_RESET
, 0xffffffff);
221 cgs_write_register(hwmgr
->device
, mmGRBM_SOFT_RESET
, 0);
226 static int fiji_setup_graphics_level_structure(struct pp_hwmgr
*hwmgr
)
229 uint32_t table_start
;
230 uint32_t level_addr
, vr_config_addr
;
231 uint32_t level_size
= sizeof(avfs_graphics_level
);
233 PP_ASSERT_WITH_CODE(0 == smu7_read_smc_sram_dword(hwmgr
,
234 SMU7_FIRMWARE_HEADER_LOCATION
+
235 offsetof(SMU73_Firmware_Header
, DpmTable
),
236 &table_start
, 0x40000),
237 "[AVFS][Fiji_SetupGfxLvlStruct] SMU could not "
238 "communicate starting address of DPM table",
241 /* Default value for vr_config =
242 * VR_MERGED_WITH_VDDC + VR_STATIC_VOLTAGE(VDDCI) */
243 vr_config
= 0x01000500; /* Real value:0x50001 */
245 vr_config_addr
= table_start
+
246 offsetof(SMU73_Discrete_DpmTable
, VRConfig
);
248 PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(hwmgr
, vr_config_addr
,
249 (uint8_t *)&vr_config
, sizeof(int32_t), 0x40000),
250 "[AVFS][Fiji_SetupGfxLvlStruct] Problems copying "
251 "vr_config value over to SMC",
254 level_addr
= table_start
+ offsetof(SMU73_Discrete_DpmTable
, GraphicsLevel
);
256 PP_ASSERT_WITH_CODE(0 == smu7_copy_bytes_to_smc(hwmgr
, level_addr
,
257 (uint8_t *)(&avfs_graphics_level
), level_size
, 0x40000),
258 "[AVFS][Fiji_SetupGfxLvlStruct] Copying of DPM table failed!",
264 static int fiji_avfs_event_mgr(struct pp_hwmgr
*hwmgr
, bool smu_started
)
266 struct smu7_smumgr
*smu_data
= (struct smu7_smumgr
*)(hwmgr
->smu_backend
);
268 switch (smu_data
->avfs
.avfs_btc_status
) {
269 case AVFS_BTC_COMPLETED_PREVIOUSLY
:
272 case AVFS_BTC_BOOT
: /*Cold Boot State - Post SMU Start*/
275 smu_data
->avfs
.avfs_btc_status
= AVFS_BTC_FAILED
;
276 PP_ASSERT_WITH_CODE(0 == fiji_setup_graphics_level_structure(hwmgr
),
277 "[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics Level"
278 " table over to SMU",
280 smu_data
->avfs
.avfs_btc_status
= AVFS_BTC_VIRUS_FAIL
;
281 PP_ASSERT_WITH_CODE(0 == smu7_setup_pwr_virus(hwmgr
),
282 "[AVFS][fiji_avfs_event_mgr] Could not setup "
283 "Pwr Virus for AVFS ",
285 smu_data
->avfs
.avfs_btc_status
= AVFS_BTC_FAILED
;
286 PP_ASSERT_WITH_CODE(0 == fiji_start_avfs_btc(hwmgr
),
287 "[AVFS][fiji_avfs_event_mgr] Failure at "
288 "fiji_start_avfs_btc. AVFS Disabled",
291 smu_data
->avfs
.avfs_btc_status
= AVFS_BTC_ENABLEAVFS
;
293 case AVFS_BTC_DISABLED
: /* Do nothing */
294 case AVFS_BTC_NOTSUPPORTED
: /* Do nothing */
295 case AVFS_BTC_ENABLEAVFS
:
298 pr_err("AVFS failed status is %x !\n", smu_data
->avfs
.avfs_btc_status
);
304 static int fiji_start_smu(struct pp_hwmgr
*hwmgr
)
307 struct fiji_smumgr
*priv
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
309 /* Only start SMC if SMC RAM is not running */
310 if (!(smu7_is_smc_ram_running(hwmgr
)
311 || cgs_is_virtualization_enabled(hwmgr
->device
))) {
312 fiji_avfs_event_mgr(hwmgr
, false);
314 /* Check if SMU is running in protected mode */
315 if (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
,
317 SMU_FIRMWARE
, SMU_MODE
)) {
318 result
= fiji_start_smu_in_non_protection_mode(hwmgr
);
322 result
= fiji_start_smu_in_protection_mode(hwmgr
);
326 fiji_avfs_event_mgr(hwmgr
, true);
329 /* To initialize all clock gating before RLC loaded and running.*/
330 cgs_set_clockgating_state(hwmgr
->device
,
331 AMD_IP_BLOCK_TYPE_GFX
, AMD_CG_STATE_GATE
);
332 cgs_set_clockgating_state(hwmgr
->device
,
333 AMD_IP_BLOCK_TYPE_GMC
, AMD_CG_STATE_GATE
);
334 cgs_set_clockgating_state(hwmgr
->device
,
335 AMD_IP_BLOCK_TYPE_SDMA
, AMD_CG_STATE_GATE
);
336 cgs_set_clockgating_state(hwmgr
->device
,
337 AMD_IP_BLOCK_TYPE_COMMON
, AMD_CG_STATE_GATE
);
339 /* Setup SoftRegsStart here for register lookup in case
340 * DummyBackEnd is used and ProcessFirmwareHeader is not executed
342 smu7_read_smc_sram_dword(hwmgr
,
343 SMU7_FIRMWARE_HEADER_LOCATION
+
344 offsetof(SMU73_Firmware_Header
, SoftRegisters
),
345 &(priv
->smu7_data
.soft_regs_start
), 0x40000);
347 result
= smu7_request_smu_load_fw(hwmgr
);
352 static bool fiji_is_hw_avfs_present(struct pp_hwmgr
*hwmgr
)
356 uint32_t mask
= (1 << ((AVFS_EN_MSB
- AVFS_EN_LSB
) + 1)) - 1;
358 if (cgs_is_virtualization_enabled(hwmgr
->device
))
361 if (!atomctrl_read_efuse(hwmgr
->device
, AVFS_EN_LSB
, AVFS_EN_MSB
,
369 static int fiji_smu_init(struct pp_hwmgr
*hwmgr
)
372 struct fiji_smumgr
*fiji_priv
= NULL
;
374 fiji_priv
= kzalloc(sizeof(struct fiji_smumgr
), GFP_KERNEL
);
376 if (fiji_priv
== NULL
)
379 hwmgr
->smu_backend
= fiji_priv
;
381 if (smu7_init(hwmgr
))
384 for (i
= 0; i
< SMU73_MAX_LEVELS_GRAPHICS
; i
++)
385 fiji_priv
->activity_target
[i
] = 30;
390 static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr
*hwmgr
,
391 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_table
,
392 uint32_t clock
, uint32_t *voltage
, uint32_t *mvdd
)
396 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
397 *voltage
= *mvdd
= 0;
400 /* clock - voltage dependency table is empty table */
401 if (dep_table
->count
== 0)
404 for (i
= 0; i
< dep_table
->count
; i
++) {
405 /* find first sclk bigger than request */
406 if (dep_table
->entries
[i
].clk
>= clock
) {
407 *voltage
|= (dep_table
->entries
[i
].vddc
*
408 VOLTAGE_SCALE
) << VDDC_SHIFT
;
409 if (SMU7_VOLTAGE_CONTROL_NONE
== data
->vddci_control
)
410 *voltage
|= (data
->vbios_boot_state
.vddci_bootup_value
*
411 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
412 else if (dep_table
->entries
[i
].vddci
)
413 *voltage
|= (dep_table
->entries
[i
].vddci
*
414 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
416 vddci
= phm_find_closest_vddci(&(data
->vddci_voltage_table
),
417 (dep_table
->entries
[i
].vddc
-
419 *voltage
|= (vddci
* VOLTAGE_SCALE
) << VDDCI_SHIFT
;
422 if (SMU7_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
)
423 *mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
*
425 else if (dep_table
->entries
[i
].mvdd
)
426 *mvdd
= (uint32_t) dep_table
->entries
[i
].mvdd
*
429 *voltage
|= 1 << PHASES_SHIFT
;
434 /* sclk is bigger than max sclk in the dependence table */
435 *voltage
|= (dep_table
->entries
[i
- 1].vddc
* VOLTAGE_SCALE
) << VDDC_SHIFT
;
437 if (SMU7_VOLTAGE_CONTROL_NONE
== data
->vddci_control
)
438 *voltage
|= (data
->vbios_boot_state
.vddci_bootup_value
*
439 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
440 else if (dep_table
->entries
[i
-1].vddci
) {
441 vddci
= phm_find_closest_vddci(&(data
->vddci_voltage_table
),
442 (dep_table
->entries
[i
].vddc
-
444 *voltage
|= (vddci
* VOLTAGE_SCALE
) << VDDCI_SHIFT
;
447 if (SMU7_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
)
448 *mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
* VOLTAGE_SCALE
;
449 else if (dep_table
->entries
[i
].mvdd
)
450 *mvdd
= (uint32_t) dep_table
->entries
[i
- 1].mvdd
* VOLTAGE_SCALE
;
456 static uint16_t scale_fan_gain_settings(uint16_t raw_setting
)
459 tmp
= raw_setting
* 4096 / 100;
460 return (uint16_t)tmp
;
463 static void get_scl_sda_value(uint8_t line
, uint8_t *scl
, uint8_t *sda
)
466 case SMU7_I2CLineID_DDC1
:
467 *scl
= SMU7_I2C_DDC1CLK
;
468 *sda
= SMU7_I2C_DDC1DATA
;
470 case SMU7_I2CLineID_DDC2
:
471 *scl
= SMU7_I2C_DDC2CLK
;
472 *sda
= SMU7_I2C_DDC2DATA
;
474 case SMU7_I2CLineID_DDC3
:
475 *scl
= SMU7_I2C_DDC3CLK
;
476 *sda
= SMU7_I2C_DDC3DATA
;
478 case SMU7_I2CLineID_DDC4
:
479 *scl
= SMU7_I2C_DDC4CLK
;
480 *sda
= SMU7_I2C_DDC4DATA
;
482 case SMU7_I2CLineID_DDC5
:
483 *scl
= SMU7_I2C_DDC5CLK
;
484 *sda
= SMU7_I2C_DDC5DATA
;
486 case SMU7_I2CLineID_DDC6
:
487 *scl
= SMU7_I2C_DDC6CLK
;
488 *sda
= SMU7_I2C_DDC6DATA
;
490 case SMU7_I2CLineID_SCLSDA
:
494 case SMU7_I2CLineID_DDCVGA
:
495 *scl
= SMU7_I2C_DDCVGACLK
;
496 *sda
= SMU7_I2C_DDCVGADATA
;
505 static void fiji_initialize_power_tune_defaults(struct pp_hwmgr
*hwmgr
)
507 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
508 struct phm_ppt_v1_information
*table_info
=
509 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
512 table_info
->cac_dtp_table
->usPowerTuneDataSetID
<= POWERTUNE_DEFAULT_SET_MAX
&&
513 table_info
->cac_dtp_table
->usPowerTuneDataSetID
)
514 smu_data
->power_tune_defaults
=
515 &fiji_power_tune_data_set_array
516 [table_info
->cac_dtp_table
->usPowerTuneDataSetID
- 1];
518 smu_data
->power_tune_defaults
= &fiji_power_tune_data_set_array
[0];
522 static int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr
*hwmgr
)
525 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
526 const struct fiji_pt_defaults
*defaults
= smu_data
->power_tune_defaults
;
528 SMU73_Discrete_DpmTable
*dpm_table
= &(smu_data
->smc_state_table
);
530 struct phm_ppt_v1_information
*table_info
=
531 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
532 struct phm_cac_tdp_table
*cac_dtp_table
= table_info
->cac_dtp_table
;
533 struct pp_advance_fan_control_parameters
*fan_table
=
534 &hwmgr
->thermal_controller
.advanceFanControlParameters
;
535 uint8_t uc_scl
, uc_sda
;
537 /* TDP number of fraction bits are changed from 8 to 7 for Fiji
538 * as requested by SMC team
540 dpm_table
->DefaultTdp
= PP_HOST_TO_SMC_US(
541 (uint16_t)(cac_dtp_table
->usTDP
* 128));
542 dpm_table
->TargetTdp
= PP_HOST_TO_SMC_US(
543 (uint16_t)(cac_dtp_table
->usTDP
* 128));
545 PP_ASSERT_WITH_CODE(cac_dtp_table
->usTargetOperatingTemp
<= 255,
546 "Target Operating Temp is out of Range!",
549 dpm_table
->GpuTjMax
= (uint8_t)(cac_dtp_table
->usTargetOperatingTemp
);
550 dpm_table
->GpuTjHyst
= 8;
552 dpm_table
->DTEAmbientTempBase
= defaults
->DTEAmbientTempBase
;
554 /* The following are for new Fiji Multi-input fan/thermal control */
555 dpm_table
->TemperatureLimitEdge
= PP_HOST_TO_SMC_US(
556 cac_dtp_table
->usTargetOperatingTemp
* 256);
557 dpm_table
->TemperatureLimitHotspot
= PP_HOST_TO_SMC_US(
558 cac_dtp_table
->usTemperatureLimitHotspot
* 256);
559 dpm_table
->TemperatureLimitLiquid1
= PP_HOST_TO_SMC_US(
560 cac_dtp_table
->usTemperatureLimitLiquid1
* 256);
561 dpm_table
->TemperatureLimitLiquid2
= PP_HOST_TO_SMC_US(
562 cac_dtp_table
->usTemperatureLimitLiquid2
* 256);
563 dpm_table
->TemperatureLimitVrVddc
= PP_HOST_TO_SMC_US(
564 cac_dtp_table
->usTemperatureLimitVrVddc
* 256);
565 dpm_table
->TemperatureLimitVrMvdd
= PP_HOST_TO_SMC_US(
566 cac_dtp_table
->usTemperatureLimitVrMvdd
* 256);
567 dpm_table
->TemperatureLimitPlx
= PP_HOST_TO_SMC_US(
568 cac_dtp_table
->usTemperatureLimitPlx
* 256);
570 dpm_table
->FanGainEdge
= PP_HOST_TO_SMC_US(
571 scale_fan_gain_settings(fan_table
->usFanGainEdge
));
572 dpm_table
->FanGainHotspot
= PP_HOST_TO_SMC_US(
573 scale_fan_gain_settings(fan_table
->usFanGainHotspot
));
574 dpm_table
->FanGainLiquid
= PP_HOST_TO_SMC_US(
575 scale_fan_gain_settings(fan_table
->usFanGainLiquid
));
576 dpm_table
->FanGainVrVddc
= PP_HOST_TO_SMC_US(
577 scale_fan_gain_settings(fan_table
->usFanGainVrVddc
));
578 dpm_table
->FanGainVrMvdd
= PP_HOST_TO_SMC_US(
579 scale_fan_gain_settings(fan_table
->usFanGainVrMvdd
));
580 dpm_table
->FanGainPlx
= PP_HOST_TO_SMC_US(
581 scale_fan_gain_settings(fan_table
->usFanGainPlx
));
582 dpm_table
->FanGainHbm
= PP_HOST_TO_SMC_US(
583 scale_fan_gain_settings(fan_table
->usFanGainHbm
));
585 dpm_table
->Liquid1_I2C_address
= cac_dtp_table
->ucLiquid1_I2C_address
;
586 dpm_table
->Liquid2_I2C_address
= cac_dtp_table
->ucLiquid2_I2C_address
;
587 dpm_table
->Vr_I2C_address
= cac_dtp_table
->ucVr_I2C_address
;
588 dpm_table
->Plx_I2C_address
= cac_dtp_table
->ucPlx_I2C_address
;
590 get_scl_sda_value(cac_dtp_table
->ucLiquid_I2C_Line
, &uc_scl
, &uc_sda
);
591 dpm_table
->Liquid_I2C_LineSCL
= uc_scl
;
592 dpm_table
->Liquid_I2C_LineSDA
= uc_sda
;
594 get_scl_sda_value(cac_dtp_table
->ucVr_I2C_Line
, &uc_scl
, &uc_sda
);
595 dpm_table
->Vr_I2C_LineSCL
= uc_scl
;
596 dpm_table
->Vr_I2C_LineSDA
= uc_sda
;
598 get_scl_sda_value(cac_dtp_table
->ucPlx_I2C_Line
, &uc_scl
, &uc_sda
);
599 dpm_table
->Plx_I2C_LineSCL
= uc_scl
;
600 dpm_table
->Plx_I2C_LineSDA
= uc_sda
;
606 static int fiji_populate_svi_load_line(struct pp_hwmgr
*hwmgr
)
608 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
609 const struct fiji_pt_defaults
*defaults
= smu_data
->power_tune_defaults
;
611 smu_data
->power_tune_table
.SviLoadLineEn
= defaults
->SviLoadLineEn
;
612 smu_data
->power_tune_table
.SviLoadLineVddC
= defaults
->SviLoadLineVddC
;
613 smu_data
->power_tune_table
.SviLoadLineTrimVddC
= 3;
614 smu_data
->power_tune_table
.SviLoadLineOffsetVddC
= 0;
620 static int fiji_populate_tdc_limit(struct pp_hwmgr
*hwmgr
)
623 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
624 struct phm_ppt_v1_information
*table_info
=
625 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
626 const struct fiji_pt_defaults
*defaults
= smu_data
->power_tune_defaults
;
628 /* TDC number of fraction bits are changed from 8 to 7
629 * for Fiji as requested by SMC team
631 tdc_limit
= (uint16_t)(table_info
->cac_dtp_table
->usTDC
* 128);
632 smu_data
->power_tune_table
.TDC_VDDC_PkgLimit
=
633 CONVERT_FROM_HOST_TO_SMC_US(tdc_limit
);
634 smu_data
->power_tune_table
.TDC_VDDC_ThrottleReleaseLimitPerc
=
635 defaults
->TDC_VDDC_ThrottleReleaseLimitPerc
;
636 smu_data
->power_tune_table
.TDC_MAWt
= defaults
->TDC_MAWt
;
641 static int fiji_populate_dw8(struct pp_hwmgr
*hwmgr
, uint32_t fuse_table_offset
)
643 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
644 const struct fiji_pt_defaults
*defaults
= smu_data
->power_tune_defaults
;
647 if (smu7_read_smc_sram_dword(hwmgr
,
649 offsetof(SMU73_Discrete_PmFuses
, TdcWaterfallCtl
),
650 (uint32_t *)&temp
, SMC_RAM_END
))
651 PP_ASSERT_WITH_CODE(false,
652 "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
655 smu_data
->power_tune_table
.TdcWaterfallCtl
= defaults
->TdcWaterfallCtl
;
656 smu_data
->power_tune_table
.LPMLTemperatureMin
=
657 (uint8_t)((temp
>> 16) & 0xff);
658 smu_data
->power_tune_table
.LPMLTemperatureMax
=
659 (uint8_t)((temp
>> 8) & 0xff);
660 smu_data
->power_tune_table
.Reserved
= (uint8_t)(temp
& 0xff);
665 static int fiji_populate_temperature_scaler(struct pp_hwmgr
*hwmgr
)
668 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
670 /* Currently not used. Set all to zero. */
671 for (i
= 0; i
< 16; i
++)
672 smu_data
->power_tune_table
.LPMLTemperatureScaler
[i
] = 0;
677 static int fiji_populate_fuzzy_fan(struct pp_hwmgr
*hwmgr
)
679 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
681 if ((hwmgr
->thermal_controller
.advanceFanControlParameters
.
682 usFanOutputSensitivity
& (1 << 15)) ||
683 0 == hwmgr
->thermal_controller
.advanceFanControlParameters
.
684 usFanOutputSensitivity
)
685 hwmgr
->thermal_controller
.advanceFanControlParameters
.
686 usFanOutputSensitivity
= hwmgr
->thermal_controller
.
687 advanceFanControlParameters
.usDefaultFanOutputSensitivity
;
689 smu_data
->power_tune_table
.FuzzyFan_PwmSetDelta
=
690 PP_HOST_TO_SMC_US(hwmgr
->thermal_controller
.
691 advanceFanControlParameters
.usFanOutputSensitivity
);
695 static int fiji_populate_gnb_lpml(struct pp_hwmgr
*hwmgr
)
698 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
700 /* Currently not used. Set all to zero. */
701 for (i
= 0; i
< 16; i
++)
702 smu_data
->power_tune_table
.GnbLPML
[i
] = 0;
707 static int fiji_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr
*hwmgr
)
709 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
710 struct phm_ppt_v1_information
*table_info
=
711 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
712 uint16_t HiSidd
= smu_data
->power_tune_table
.BapmVddCBaseLeakageHiSidd
;
713 uint16_t LoSidd
= smu_data
->power_tune_table
.BapmVddCBaseLeakageLoSidd
;
714 struct phm_cac_tdp_table
*cac_table
= table_info
->cac_dtp_table
;
716 HiSidd
= (uint16_t)(cac_table
->usHighCACLeakage
/ 100 * 256);
717 LoSidd
= (uint16_t)(cac_table
->usLowCACLeakage
/ 100 * 256);
719 smu_data
->power_tune_table
.BapmVddCBaseLeakageHiSidd
=
720 CONVERT_FROM_HOST_TO_SMC_US(HiSidd
);
721 smu_data
->power_tune_table
.BapmVddCBaseLeakageLoSidd
=
722 CONVERT_FROM_HOST_TO_SMC_US(LoSidd
);
727 static int fiji_populate_pm_fuses(struct pp_hwmgr
*hwmgr
)
729 uint32_t pm_fuse_table_offset
;
730 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
732 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
733 PHM_PlatformCaps_PowerContainment
)) {
734 if (smu7_read_smc_sram_dword(hwmgr
,
735 SMU7_FIRMWARE_HEADER_LOCATION
+
736 offsetof(SMU73_Firmware_Header
, PmFuseTable
),
737 &pm_fuse_table_offset
, SMC_RAM_END
))
738 PP_ASSERT_WITH_CODE(false,
739 "Attempt to get pm_fuse_table_offset Failed!",
743 if (fiji_populate_svi_load_line(hwmgr
))
744 PP_ASSERT_WITH_CODE(false,
745 "Attempt to populate SviLoadLine Failed!",
748 if (fiji_populate_tdc_limit(hwmgr
))
749 PP_ASSERT_WITH_CODE(false,
750 "Attempt to populate TDCLimit Failed!", return -EINVAL
);
752 if (fiji_populate_dw8(hwmgr
, pm_fuse_table_offset
))
753 PP_ASSERT_WITH_CODE(false,
754 "Attempt to populate TdcWaterfallCtl, "
755 "LPMLTemperature Min and Max Failed!",
759 if (0 != fiji_populate_temperature_scaler(hwmgr
))
760 PP_ASSERT_WITH_CODE(false,
761 "Attempt to populate LPMLTemperatureScaler Failed!",
765 if (fiji_populate_fuzzy_fan(hwmgr
))
766 PP_ASSERT_WITH_CODE(false,
767 "Attempt to populate Fuzzy Fan Control parameters Failed!",
771 if (fiji_populate_gnb_lpml(hwmgr
))
772 PP_ASSERT_WITH_CODE(false,
773 "Attempt to populate GnbLPML Failed!",
777 if (fiji_populate_bapm_vddc_base_leakage_sidd(hwmgr
))
778 PP_ASSERT_WITH_CODE(false,
779 "Attempt to populate BapmVddCBaseLeakage Hi and Lo "
780 "Sidd Failed!", return -EINVAL
);
782 if (smu7_copy_bytes_to_smc(hwmgr
, pm_fuse_table_offset
,
783 (uint8_t *)&smu_data
->power_tune_table
,
784 sizeof(struct SMU73_Discrete_PmFuses
), SMC_RAM_END
))
785 PP_ASSERT_WITH_CODE(false,
786 "Attempt to download PmFuseTable Failed!",
792 static int fiji_populate_cac_table(struct pp_hwmgr
*hwmgr
,
793 struct SMU73_Discrete_DpmTable
*table
)
797 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
798 struct phm_ppt_v1_information
*table_info
=
799 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
800 struct phm_ppt_v1_voltage_lookup_table
*lookup_table
=
801 table_info
->vddc_lookup_table
;
802 /* tables is already swapped, so in order to use the value from it,
803 * we need to swap it back.
804 * We are populating vddc CAC data to BapmVddc table
805 * in split and merged mode
808 for (count
= 0; count
< lookup_table
->count
; count
++) {
809 index
= phm_get_voltage_index(lookup_table
,
810 data
->vddc_voltage_table
.entries
[count
].value
);
811 table
->BapmVddcVidLoSidd
[count
] =
812 convert_to_vid(lookup_table
->entries
[index
].us_cac_low
);
813 table
->BapmVddcVidHiSidd
[count
] =
814 convert_to_vid(lookup_table
->entries
[index
].us_cac_high
);
820 static int fiji_populate_smc_voltage_tables(struct pp_hwmgr
*hwmgr
,
821 struct SMU73_Discrete_DpmTable
*table
)
825 result
= fiji_populate_cac_table(hwmgr
, table
);
826 PP_ASSERT_WITH_CODE(0 == result
,
827 "can not populate CAC voltage tables to SMC",
833 static int fiji_populate_ulv_level(struct pp_hwmgr
*hwmgr
,
834 struct SMU73_Discrete_Ulv
*state
)
838 struct phm_ppt_v1_information
*table_info
=
839 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
841 state
->CcPwrDynRm
= 0;
842 state
->CcPwrDynRm1
= 0;
844 state
->VddcOffset
= (uint16_t) table_info
->us_ulv_voltage_offset
;
845 state
->VddcOffsetVid
= (uint8_t)(table_info
->us_ulv_voltage_offset
*
846 VOLTAGE_VID_OFFSET_SCALE2
/ VOLTAGE_VID_OFFSET_SCALE1
);
848 state
->VddcPhase
= 1;
851 CONVERT_FROM_HOST_TO_SMC_UL(state
->CcPwrDynRm
);
852 CONVERT_FROM_HOST_TO_SMC_UL(state
->CcPwrDynRm1
);
853 CONVERT_FROM_HOST_TO_SMC_US(state
->VddcOffset
);
858 static int fiji_populate_ulv_state(struct pp_hwmgr
*hwmgr
,
859 struct SMU73_Discrete_DpmTable
*table
)
861 return fiji_populate_ulv_level(hwmgr
, &table
->Ulv
);
864 static int fiji_populate_smc_link_level(struct pp_hwmgr
*hwmgr
,
865 struct SMU73_Discrete_DpmTable
*table
)
867 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
868 struct smu7_dpm_table
*dpm_table
= &data
->dpm_table
;
869 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
872 /* Index (dpm_table->pcie_speed_table.count)
873 * is reserved for PCIE boot level. */
874 for (i
= 0; i
<= dpm_table
->pcie_speed_table
.count
; i
++) {
875 table
->LinkLevel
[i
].PcieGenSpeed
=
876 (uint8_t)dpm_table
->pcie_speed_table
.dpm_levels
[i
].value
;
877 table
->LinkLevel
[i
].PcieLaneCount
= (uint8_t)encode_pcie_lane_width(
878 dpm_table
->pcie_speed_table
.dpm_levels
[i
].param1
);
879 table
->LinkLevel
[i
].EnabledForActivity
= 1;
880 table
->LinkLevel
[i
].SPC
= (uint8_t)(data
->pcie_spc_cap
& 0xff);
881 table
->LinkLevel
[i
].DownThreshold
= PP_HOST_TO_SMC_UL(5);
882 table
->LinkLevel
[i
].UpThreshold
= PP_HOST_TO_SMC_UL(30);
885 smu_data
->smc_state_table
.LinkLevelCount
=
886 (uint8_t)dpm_table
->pcie_speed_table
.count
;
887 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
=
888 phm_get_dpm_level_enable_mask_value(&dpm_table
->pcie_speed_table
);
893 static int fiji_calculate_sclk_params(struct pp_hwmgr
*hwmgr
,
894 uint32_t clock
, struct SMU73_Discrete_GraphicsLevel
*sclk
)
896 const struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
897 struct pp_atomctrl_clock_dividers_vi dividers
;
898 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
899 uint32_t spll_func_cntl_3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
900 uint32_t spll_func_cntl_4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
901 uint32_t cg_spll_spread_spectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
902 uint32_t cg_spll_spread_spectrum_2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
904 uint32_t ref_divider
;
908 /* get the engine clock dividers for this clock value */
909 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
, clock
, ÷rs
);
911 PP_ASSERT_WITH_CODE(result
== 0,
912 "Error retrieving Engine Clock dividers from VBIOS.",
915 /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
916 ref_clock
= atomctrl_get_reference_clock(hwmgr
);
917 ref_divider
= 1 + dividers
.uc_pll_ref_div
;
919 /* low 14 bits is fraction and high 12 bits is divider */
920 fbdiv
= dividers
.ul_fb_div
.ul_fb_divider
& 0x3FFFFFF;
922 /* SPLL_FUNC_CNTL setup */
923 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
924 SPLL_REF_DIV
, dividers
.uc_pll_ref_div
);
925 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
926 SPLL_PDIV_A
, dividers
.uc_pll_post_div
);
928 /* SPLL_FUNC_CNTL_3 setup*/
929 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
, CG_SPLL_FUNC_CNTL_3
,
932 /* set to use fractional accumulation*/
933 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
, CG_SPLL_FUNC_CNTL_3
,
936 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
937 PHM_PlatformCaps_EngineSpreadSpectrumSupport
)) {
938 struct pp_atomctrl_internal_ss_info ssInfo
;
940 uint32_t vco_freq
= clock
* dividers
.uc_pll_post_div
;
941 if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr
,
942 vco_freq
, &ssInfo
)) {
944 * ss_info.speed_spectrum_percentage -- in unit of 0.01%
945 * ss_info.speed_spectrum_rate -- in unit of khz
947 * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2
949 uint32_t clk_s
= ref_clock
* 5 /
950 (ref_divider
* ssInfo
.speed_spectrum_rate
);
951 /* clkv = 2 * D * fbdiv / NS */
952 uint32_t clk_v
= 4 * ssInfo
.speed_spectrum_percentage
*
953 fbdiv
/ (clk_s
* 10000);
955 cg_spll_spread_spectrum
= PHM_SET_FIELD(cg_spll_spread_spectrum
,
956 CG_SPLL_SPREAD_SPECTRUM
, CLKS
, clk_s
);
957 cg_spll_spread_spectrum
= PHM_SET_FIELD(cg_spll_spread_spectrum
,
958 CG_SPLL_SPREAD_SPECTRUM
, SSEN
, 1);
959 cg_spll_spread_spectrum_2
= PHM_SET_FIELD(cg_spll_spread_spectrum_2
,
960 CG_SPLL_SPREAD_SPECTRUM_2
, CLKV
, clk_v
);
964 sclk
->SclkFrequency
= clock
;
965 sclk
->CgSpllFuncCntl3
= spll_func_cntl_3
;
966 sclk
->CgSpllFuncCntl4
= spll_func_cntl_4
;
967 sclk
->SpllSpreadSpectrum
= cg_spll_spread_spectrum
;
968 sclk
->SpllSpreadSpectrum2
= cg_spll_spread_spectrum_2
;
969 sclk
->SclkDid
= (uint8_t)dividers
.pll_post_divider
;
974 static int fiji_populate_single_graphic_level(struct pp_hwmgr
*hwmgr
,
975 uint32_t clock
, uint16_t sclk_al_threshold
,
976 struct SMU73_Discrete_GraphicsLevel
*level
)
979 /* PP_Clocks minClocks; */
980 uint32_t threshold
, mvdd
;
981 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
982 struct phm_ppt_v1_information
*table_info
=
983 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
985 result
= fiji_calculate_sclk_params(hwmgr
, clock
, level
);
987 /* populate graphics levels */
988 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
989 table_info
->vdd_dep_on_sclk
, clock
,
990 (uint32_t *)(&level
->MinVoltage
), &mvdd
);
991 PP_ASSERT_WITH_CODE((0 == result
),
992 "can not find VDDC voltage value for "
993 "VDDC engine clock dependency table",
996 level
->SclkFrequency
= clock
;
997 level
->ActivityLevel
= sclk_al_threshold
;
998 level
->CcPwrDynRm
= 0;
999 level
->CcPwrDynRm1
= 0;
1000 level
->EnabledForActivity
= 0;
1001 level
->EnabledForThrottle
= 1;
1003 level
->DownHyst
= 0;
1004 level
->VoltageDownHyst
= 0;
1005 level
->PowerThrottle
= 0;
1007 threshold
= clock
* data
->fast_watermark_threshold
/ 100;
1009 data
->display_timing
.min_clock_in_sr
= hwmgr
->display_config
.min_core_set_clock_in_sr
;
1011 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_SclkDeepSleep
))
1012 level
->DeepSleepDivId
= smu7_get_sleep_divider_id_from_clock(clock
,
1013 hwmgr
->display_config
.min_core_set_clock_in_sr
);
1016 /* Default to slow, highest DPM level will be
1017 * set to PPSMC_DISPLAY_WATERMARK_LOW later.
1019 level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
1021 CONVERT_FROM_HOST_TO_SMC_UL(level
->MinVoltage
);
1022 CONVERT_FROM_HOST_TO_SMC_UL(level
->SclkFrequency
);
1023 CONVERT_FROM_HOST_TO_SMC_US(level
->ActivityLevel
);
1024 CONVERT_FROM_HOST_TO_SMC_UL(level
->CgSpllFuncCntl3
);
1025 CONVERT_FROM_HOST_TO_SMC_UL(level
->CgSpllFuncCntl4
);
1026 CONVERT_FROM_HOST_TO_SMC_UL(level
->SpllSpreadSpectrum
);
1027 CONVERT_FROM_HOST_TO_SMC_UL(level
->SpllSpreadSpectrum2
);
1028 CONVERT_FROM_HOST_TO_SMC_UL(level
->CcPwrDynRm
);
1029 CONVERT_FROM_HOST_TO_SMC_UL(level
->CcPwrDynRm1
);
1034 static int fiji_populate_all_graphic_levels(struct pp_hwmgr
*hwmgr
)
1036 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1037 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
1039 struct smu7_dpm_table
*dpm_table
= &data
->dpm_table
;
1040 struct phm_ppt_v1_information
*table_info
=
1041 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1042 struct phm_ppt_v1_pcie_table
*pcie_table
= table_info
->pcie_table
;
1043 uint8_t pcie_entry_cnt
= (uint8_t) data
->dpm_table
.pcie_speed_table
.count
;
1045 uint32_t array
= smu_data
->smu7_data
.dpm_table_start
+
1046 offsetof(SMU73_Discrete_DpmTable
, GraphicsLevel
);
1047 uint32_t array_size
= sizeof(struct SMU73_Discrete_GraphicsLevel
) *
1048 SMU73_MAX_LEVELS_GRAPHICS
;
1049 struct SMU73_Discrete_GraphicsLevel
*levels
=
1050 smu_data
->smc_state_table
.GraphicsLevel
;
1051 uint32_t i
, max_entry
;
1052 uint8_t hightest_pcie_level_enabled
= 0,
1053 lowest_pcie_level_enabled
= 0,
1054 mid_pcie_level_enabled
= 0,
1057 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
1058 result
= fiji_populate_single_graphic_level(hwmgr
,
1059 dpm_table
->sclk_table
.dpm_levels
[i
].value
,
1060 (uint16_t)smu_data
->activity_target
[i
],
1065 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
1067 levels
[i
].DeepSleepDivId
= 0;
1070 /* Only enable level 0 for now.*/
1071 levels
[0].EnabledForActivity
= 1;
1073 /* set highest level watermark to high */
1074 levels
[dpm_table
->sclk_table
.count
- 1].DisplayWatermark
=
1075 PPSMC_DISPLAY_WATERMARK_HIGH
;
1077 smu_data
->smc_state_table
.GraphicsDpmLevelCount
=
1078 (uint8_t)dpm_table
->sclk_table
.count
;
1079 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
=
1080 phm_get_dpm_level_enable_mask_value(&dpm_table
->sclk_table
);
1082 if (pcie_table
!= NULL
) {
1083 PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt
),
1084 "There must be 1 or more PCIE levels defined in PPTable.",
1086 max_entry
= pcie_entry_cnt
- 1;
1087 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++)
1088 levels
[i
].pcieDpmLevel
=
1089 (uint8_t) ((i
< max_entry
) ? i
: max_entry
);
1091 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
1092 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
1093 (1 << (hightest_pcie_level_enabled
+ 1))) != 0))
1094 hightest_pcie_level_enabled
++;
1096 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
1097 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
1098 (1 << lowest_pcie_level_enabled
)) == 0))
1099 lowest_pcie_level_enabled
++;
1101 while ((count
< hightest_pcie_level_enabled
) &&
1102 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
1103 (1 << (lowest_pcie_level_enabled
+ 1 + count
))) == 0))
1106 mid_pcie_level_enabled
= (lowest_pcie_level_enabled
+ 1 + count
) <
1107 hightest_pcie_level_enabled
?
1108 (lowest_pcie_level_enabled
+ 1 + count
) :
1109 hightest_pcie_level_enabled
;
1111 /* set pcieDpmLevel to hightest_pcie_level_enabled */
1112 for (i
= 2; i
< dpm_table
->sclk_table
.count
; i
++)
1113 levels
[i
].pcieDpmLevel
= hightest_pcie_level_enabled
;
1115 /* set pcieDpmLevel to lowest_pcie_level_enabled */
1116 levels
[0].pcieDpmLevel
= lowest_pcie_level_enabled
;
1118 /* set pcieDpmLevel to mid_pcie_level_enabled */
1119 levels
[1].pcieDpmLevel
= mid_pcie_level_enabled
;
1121 /* level count will send to smc once at init smc table and never change */
1122 result
= smu7_copy_bytes_to_smc(hwmgr
, array
, (uint8_t *)levels
,
1123 (uint32_t)array_size
, SMC_RAM_END
);
1130 * MCLK Frequency Ratio
1131 * SEQ_CG_RESP Bit[31:24] - 0x0
1132 * Bit[27:24] \96 DDR3 Frequency ratio
1133 * 0x0 <= 100MHz, 450 < 0x8 <= 500MHz
1134 * 100 < 0x1 <= 150MHz, 500 < 0x9 <= 550MHz
1135 * 150 < 0x2 <= 200MHz, 550 < 0xA <= 600MHz
1136 * 200 < 0x3 <= 250MHz, 600 < 0xB <= 650MHz
1137 * 250 < 0x4 <= 300MHz, 650 < 0xC <= 700MHz
1138 * 300 < 0x5 <= 350MHz, 700 < 0xD <= 750MHz
1139 * 350 < 0x6 <= 400MHz, 750 < 0xE <= 800MHz
1140 * 400 < 0x7 <= 450MHz, 800 < 0xF
1142 static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock
)
1144 if (mem_clock
<= 10000)
1146 if (mem_clock
<= 15000)
1148 if (mem_clock
<= 20000)
1150 if (mem_clock
<= 25000)
1152 if (mem_clock
<= 30000)
1154 if (mem_clock
<= 35000)
1156 if (mem_clock
<= 40000)
1158 if (mem_clock
<= 45000)
1160 if (mem_clock
<= 50000)
1162 if (mem_clock
<= 55000)
1164 if (mem_clock
<= 60000)
1166 if (mem_clock
<= 65000)
1168 if (mem_clock
<= 70000)
1170 if (mem_clock
<= 75000)
1172 if (mem_clock
<= 80000)
1174 /* mem_clock > 800MHz */
1178 static int fiji_calculate_mclk_params(struct pp_hwmgr
*hwmgr
,
1179 uint32_t clock
, struct SMU73_Discrete_MemoryLevel
*mclk
)
1181 struct pp_atomctrl_memory_clock_param mem_param
;
1184 result
= atomctrl_get_memory_pll_dividers_vi(hwmgr
, clock
, &mem_param
);
1185 PP_ASSERT_WITH_CODE((0 == result
),
1186 "Failed to get Memory PLL Dividers.",
1189 /* Save the result data to outpupt memory level structure */
1190 mclk
->MclkFrequency
= clock
;
1191 mclk
->MclkDivider
= (uint8_t)mem_param
.mpll_post_divider
;
1192 mclk
->FreqRange
= fiji_get_mclk_frequency_ratio(clock
);
1197 static int fiji_populate_single_memory_level(struct pp_hwmgr
*hwmgr
,
1198 uint32_t clock
, struct SMU73_Discrete_MemoryLevel
*mem_level
)
1200 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1201 struct phm_ppt_v1_information
*table_info
=
1202 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1204 uint32_t mclk_stutter_mode_threshold
= 60000;
1206 if (table_info
->vdd_dep_on_mclk
) {
1207 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
1208 table_info
->vdd_dep_on_mclk
, clock
,
1209 (uint32_t *)(&mem_level
->MinVoltage
), &mem_level
->MinMvdd
);
1210 PP_ASSERT_WITH_CODE((0 == result
),
1211 "can not find MinVddc voltage value from memory "
1212 "VDDC voltage dependency table", return result
);
1215 mem_level
->EnabledForThrottle
= 1;
1216 mem_level
->EnabledForActivity
= 0;
1217 mem_level
->UpHyst
= 0;
1218 mem_level
->DownHyst
= 100;
1219 mem_level
->VoltageDownHyst
= 0;
1220 mem_level
->ActivityLevel
= (uint16_t)data
->mclk_activity_target
;
1221 mem_level
->StutterEnable
= false;
1223 mem_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
1225 /* enable stutter mode if all the follow condition applied
1226 * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI,
1227 * &(data->DisplayTiming.numExistingDisplays));
1229 data
->display_timing
.num_existing_displays
= 1;
1231 if (mclk_stutter_mode_threshold
&&
1232 (clock
<= mclk_stutter_mode_threshold
) &&
1233 (!data
->is_uvd_enabled
) &&
1234 (PHM_READ_FIELD(hwmgr
->device
, DPG_PIPE_STUTTER_CONTROL
,
1235 STUTTER_ENABLE
) & 0x1))
1236 mem_level
->StutterEnable
= true;
1238 result
= fiji_calculate_mclk_params(hwmgr
, clock
, mem_level
);
1240 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MinMvdd
);
1241 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MclkFrequency
);
1242 CONVERT_FROM_HOST_TO_SMC_US(mem_level
->ActivityLevel
);
1243 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MinVoltage
);
1248 static int fiji_populate_all_memory_levels(struct pp_hwmgr
*hwmgr
)
1250 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1251 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
1252 struct smu7_dpm_table
*dpm_table
= &data
->dpm_table
;
1254 /* populate MCLK dpm table to SMU7 */
1255 uint32_t array
= smu_data
->smu7_data
.dpm_table_start
+
1256 offsetof(SMU73_Discrete_DpmTable
, MemoryLevel
);
1257 uint32_t array_size
= sizeof(SMU73_Discrete_MemoryLevel
) *
1258 SMU73_MAX_LEVELS_MEMORY
;
1259 struct SMU73_Discrete_MemoryLevel
*levels
=
1260 smu_data
->smc_state_table
.MemoryLevel
;
1263 for (i
= 0; i
< dpm_table
->mclk_table
.count
; i
++) {
1264 PP_ASSERT_WITH_CODE((0 != dpm_table
->mclk_table
.dpm_levels
[i
].value
),
1265 "can not populate memory level as memory clock is zero",
1267 result
= fiji_populate_single_memory_level(hwmgr
,
1268 dpm_table
->mclk_table
.dpm_levels
[i
].value
,
1274 /* Only enable level 0 for now. */
1275 levels
[0].EnabledForActivity
= 1;
1277 /* in order to prevent MC activity from stutter mode to push DPM up.
1278 * the UVD change complements this by putting the MCLK in
1279 * a higher state by default such that we are not effected by
1280 * up threshold or and MCLK DPM latency.
1282 levels
[0].ActivityLevel
= (uint16_t)data
->mclk_dpm0_activity_target
;
1283 CONVERT_FROM_HOST_TO_SMC_US(levels
[0].ActivityLevel
);
1285 smu_data
->smc_state_table
.MemoryDpmLevelCount
=
1286 (uint8_t)dpm_table
->mclk_table
.count
;
1287 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
=
1288 phm_get_dpm_level_enable_mask_value(&dpm_table
->mclk_table
);
1289 /* set highest level watermark to high */
1290 levels
[dpm_table
->mclk_table
.count
- 1].DisplayWatermark
=
1291 PPSMC_DISPLAY_WATERMARK_HIGH
;
1293 /* level count will send to smc once at init smc table and never change */
1294 result
= smu7_copy_bytes_to_smc(hwmgr
, array
, (uint8_t *)levels
,
1295 (uint32_t)array_size
, SMC_RAM_END
);
1300 static int fiji_populate_mvdd_value(struct pp_hwmgr
*hwmgr
,
1301 uint32_t mclk
, SMIO_Pattern
*smio_pat
)
1303 const struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1304 struct phm_ppt_v1_information
*table_info
=
1305 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1308 if (SMU7_VOLTAGE_CONTROL_NONE
!= data
->mvdd_control
) {
1309 /* find mvdd value which clock is more than request */
1310 for (i
= 0; i
< table_info
->vdd_dep_on_mclk
->count
; i
++) {
1311 if (mclk
<= table_info
->vdd_dep_on_mclk
->entries
[i
].clk
) {
1312 smio_pat
->Voltage
= data
->mvdd_voltage_table
.entries
[i
].value
;
1316 PP_ASSERT_WITH_CODE(i
< table_info
->vdd_dep_on_mclk
->count
,
1317 "MVDD Voltage is outside the supported range.",
1325 static int fiji_populate_smc_acpi_level(struct pp_hwmgr
*hwmgr
,
1326 SMU73_Discrete_DpmTable
*table
)
1329 const struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1330 struct phm_ppt_v1_information
*table_info
=
1331 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1332 struct pp_atomctrl_clock_dividers_vi dividers
;
1333 SMIO_Pattern vol_level
;
1336 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
1337 uint32_t spll_func_cntl_2
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
;
1339 table
->ACPILevel
.Flags
&= ~PPSMC_SWSTATE_FLAG_DC
;
1341 if (!data
->sclk_dpm_key_disabled
) {
1342 /* Get MinVoltage and Frequency from DPM0,
1343 * already converted to SMC_UL */
1344 table
->ACPILevel
.SclkFrequency
=
1345 data
->dpm_table
.sclk_table
.dpm_levels
[0].value
;
1346 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
1347 table_info
->vdd_dep_on_sclk
,
1348 table
->ACPILevel
.SclkFrequency
,
1349 (uint32_t *)(&table
->ACPILevel
.MinVoltage
), &mvdd
);
1350 PP_ASSERT_WITH_CODE((0 == result
),
1351 "Cannot find ACPI VDDC voltage value " \
1352 "in Clock Dependency Table",
1355 table
->ACPILevel
.SclkFrequency
=
1356 data
->vbios_boot_state
.sclk_bootup_value
;
1357 table
->ACPILevel
.MinVoltage
=
1358 data
->vbios_boot_state
.vddc_bootup_value
* VOLTAGE_SCALE
;
1361 /* get the engine clock dividers for this clock value */
1362 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
,
1363 table
->ACPILevel
.SclkFrequency
, ÷rs
);
1364 PP_ASSERT_WITH_CODE(result
== 0,
1365 "Error retrieving Engine Clock dividers from VBIOS.",
1368 table
->ACPILevel
.SclkDid
= (uint8_t)dividers
.pll_post_divider
;
1369 table
->ACPILevel
.DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
1370 table
->ACPILevel
.DeepSleepDivId
= 0;
1372 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
1374 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
1376 spll_func_cntl_2
= PHM_SET_FIELD(spll_func_cntl_2
, CG_SPLL_FUNC_CNTL_2
,
1379 table
->ACPILevel
.CgSpllFuncCntl
= spll_func_cntl
;
1380 table
->ACPILevel
.CgSpllFuncCntl2
= spll_func_cntl_2
;
1381 table
->ACPILevel
.CgSpllFuncCntl3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
1382 table
->ACPILevel
.CgSpllFuncCntl4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
1383 table
->ACPILevel
.SpllSpreadSpectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
1384 table
->ACPILevel
.SpllSpreadSpectrum2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
1385 table
->ACPILevel
.CcPwrDynRm
= 0;
1386 table
->ACPILevel
.CcPwrDynRm1
= 0;
1388 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.Flags
);
1389 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SclkFrequency
);
1390 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.MinVoltage
);
1391 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl
);
1392 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl2
);
1393 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl3
);
1394 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl4
);
1395 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum
);
1396 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum2
);
1397 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm
);
1398 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm1
);
1400 if (!data
->mclk_dpm_key_disabled
) {
1401 /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
1402 table
->MemoryACPILevel
.MclkFrequency
=
1403 data
->dpm_table
.mclk_table
.dpm_levels
[0].value
;
1404 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
1405 table_info
->vdd_dep_on_mclk
,
1406 table
->MemoryACPILevel
.MclkFrequency
,
1407 (uint32_t *)(&table
->MemoryACPILevel
.MinVoltage
), &mvdd
);
1408 PP_ASSERT_WITH_CODE((0 == result
),
1409 "Cannot find ACPI VDDCI voltage value in Clock Dependency Table",
1412 table
->MemoryACPILevel
.MclkFrequency
=
1413 data
->vbios_boot_state
.mclk_bootup_value
;
1414 table
->MemoryACPILevel
.MinVoltage
=
1415 data
->vbios_boot_state
.vddci_bootup_value
* VOLTAGE_SCALE
;
1419 if ((SMU7_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
) ||
1420 (data
->mclk_dpm_key_disabled
))
1421 us_mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
1423 if (!fiji_populate_mvdd_value(hwmgr
,
1424 data
->dpm_table
.mclk_table
.dpm_levels
[0].value
,
1426 us_mvdd
= vol_level
.Voltage
;
1429 table
->MemoryACPILevel
.MinMvdd
=
1430 PP_HOST_TO_SMC_UL(us_mvdd
* VOLTAGE_SCALE
);
1432 table
->MemoryACPILevel
.EnabledForThrottle
= 0;
1433 table
->MemoryACPILevel
.EnabledForActivity
= 0;
1434 table
->MemoryACPILevel
.UpHyst
= 0;
1435 table
->MemoryACPILevel
.DownHyst
= 100;
1436 table
->MemoryACPILevel
.VoltageDownHyst
= 0;
1437 table
->MemoryACPILevel
.ActivityLevel
=
1438 PP_HOST_TO_SMC_US((uint16_t)data
->mclk_activity_target
);
1440 table
->MemoryACPILevel
.StutterEnable
= false;
1441 CONVERT_FROM_HOST_TO_SMC_UL(table
->MemoryACPILevel
.MclkFrequency
);
1442 CONVERT_FROM_HOST_TO_SMC_UL(table
->MemoryACPILevel
.MinVoltage
);
1447 static int fiji_populate_smc_vce_level(struct pp_hwmgr
*hwmgr
,
1448 SMU73_Discrete_DpmTable
*table
)
1450 int result
= -EINVAL
;
1452 struct pp_atomctrl_clock_dividers_vi dividers
;
1453 struct phm_ppt_v1_information
*table_info
=
1454 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1455 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
1456 table_info
->mm_dep_table
;
1458 table
->VceLevelCount
= (uint8_t)(mm_table
->count
);
1459 table
->VceBootLevel
= 0;
1461 for (count
= 0; count
< table
->VceLevelCount
; count
++) {
1462 table
->VceLevel
[count
].Frequency
= mm_table
->entries
[count
].eclk
;
1463 table
->VceLevel
[count
].MinVoltage
= 0;
1464 table
->VceLevel
[count
].MinVoltage
|=
1465 (mm_table
->entries
[count
].vddc
* VOLTAGE_SCALE
) << VDDC_SHIFT
;
1466 table
->VceLevel
[count
].MinVoltage
|=
1467 ((mm_table
->entries
[count
].vddc
- VDDC_VDDCI_DELTA
) *
1468 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1469 table
->VceLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
1471 /*retrieve divider value for VBIOS */
1472 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1473 table
->VceLevel
[count
].Frequency
, ÷rs
);
1474 PP_ASSERT_WITH_CODE((0 == result
),
1475 "can not find divide id for VCE engine clock",
1478 table
->VceLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1480 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].Frequency
);
1481 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].MinVoltage
);
1486 static int fiji_populate_smc_acp_level(struct pp_hwmgr
*hwmgr
,
1487 SMU73_Discrete_DpmTable
*table
)
1489 int result
= -EINVAL
;
1491 struct pp_atomctrl_clock_dividers_vi dividers
;
1492 struct phm_ppt_v1_information
*table_info
=
1493 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1494 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
1495 table_info
->mm_dep_table
;
1497 table
->AcpLevelCount
= (uint8_t)(mm_table
->count
);
1498 table
->AcpBootLevel
= 0;
1500 for (count
= 0; count
< table
->AcpLevelCount
; count
++) {
1501 table
->AcpLevel
[count
].Frequency
= mm_table
->entries
[count
].aclk
;
1502 table
->AcpLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
1503 VOLTAGE_SCALE
) << VDDC_SHIFT
;
1504 table
->AcpLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
1505 VDDC_VDDCI_DELTA
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1506 table
->AcpLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
1508 /* retrieve divider value for VBIOS */
1509 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1510 table
->AcpLevel
[count
].Frequency
, ÷rs
);
1511 PP_ASSERT_WITH_CODE((0 == result
),
1512 "can not find divide id for engine clock", return result
);
1514 table
->AcpLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1516 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].Frequency
);
1517 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].MinVoltage
);
1522 static int fiji_populate_smc_samu_level(struct pp_hwmgr
*hwmgr
,
1523 SMU73_Discrete_DpmTable
*table
)
1525 int result
= -EINVAL
;
1527 struct pp_atomctrl_clock_dividers_vi dividers
;
1528 struct phm_ppt_v1_information
*table_info
=
1529 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1530 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
1531 table_info
->mm_dep_table
;
1533 table
->SamuBootLevel
= 0;
1534 table
->SamuLevelCount
= (uint8_t)(mm_table
->count
);
1536 for (count
= 0; count
< table
->SamuLevelCount
; count
++) {
1537 /* not sure whether we need evclk or not */
1538 table
->SamuLevel
[count
].MinVoltage
= 0;
1539 table
->SamuLevel
[count
].Frequency
= mm_table
->entries
[count
].samclock
;
1540 table
->SamuLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
1541 VOLTAGE_SCALE
) << VDDC_SHIFT
;
1542 table
->SamuLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
1543 VDDC_VDDCI_DELTA
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1544 table
->SamuLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
1546 /* retrieve divider value for VBIOS */
1547 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1548 table
->SamuLevel
[count
].Frequency
, ÷rs
);
1549 PP_ASSERT_WITH_CODE((0 == result
),
1550 "can not find divide id for samu clock", return result
);
1552 table
->SamuLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1554 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].Frequency
);
1555 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].MinVoltage
);
1560 static int fiji_populate_memory_timing_parameters(struct pp_hwmgr
*hwmgr
,
1561 int32_t eng_clock
, int32_t mem_clock
,
1562 struct SMU73_Discrete_MCArbDramTimingTableEntry
*arb_regs
)
1564 uint32_t dram_timing
;
1565 uint32_t dram_timing2
;
1567 ULONG state
, trrds
, trrdl
;
1570 result
= atomctrl_set_engine_dram_timings_rv770(hwmgr
,
1571 eng_clock
, mem_clock
);
1572 PP_ASSERT_WITH_CODE(result
== 0,
1573 "Error calling VBIOS to set DRAM_TIMING.", return result
);
1575 dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
1576 dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
1577 burstTime
= cgs_read_register(hwmgr
->device
, mmMC_ARB_BURST_TIME
);
1579 state
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, STATE0
);
1580 trrds
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, TRRDS0
);
1581 trrdl
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, TRRDL0
);
1583 arb_regs
->McArbDramTiming
= PP_HOST_TO_SMC_UL(dram_timing
);
1584 arb_regs
->McArbDramTiming2
= PP_HOST_TO_SMC_UL(dram_timing2
);
1585 arb_regs
->McArbBurstTime
= (uint8_t)burstTime
;
1586 arb_regs
->TRRDS
= (uint8_t)trrds
;
1587 arb_regs
->TRRDL
= (uint8_t)trrdl
;
1592 static int fiji_program_memory_timing_parameters(struct pp_hwmgr
*hwmgr
)
1594 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1595 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
1596 struct SMU73_Discrete_MCArbDramTimingTable arb_regs
;
1600 for (i
= 0; i
< data
->dpm_table
.sclk_table
.count
; i
++) {
1601 for (j
= 0; j
< data
->dpm_table
.mclk_table
.count
; j
++) {
1602 result
= fiji_populate_memory_timing_parameters(hwmgr
,
1603 data
->dpm_table
.sclk_table
.dpm_levels
[i
].value
,
1604 data
->dpm_table
.mclk_table
.dpm_levels
[j
].value
,
1605 &arb_regs
.entries
[i
][j
]);
1612 result
= smu7_copy_bytes_to_smc(
1614 smu_data
->smu7_data
.arb_table_start
,
1615 (uint8_t *)&arb_regs
,
1616 sizeof(SMU73_Discrete_MCArbDramTimingTable
),
1621 static int fiji_populate_smc_uvd_level(struct pp_hwmgr
*hwmgr
,
1622 struct SMU73_Discrete_DpmTable
*table
)
1624 int result
= -EINVAL
;
1626 struct pp_atomctrl_clock_dividers_vi dividers
;
1627 struct phm_ppt_v1_information
*table_info
=
1628 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1629 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
1630 table_info
->mm_dep_table
;
1632 table
->UvdLevelCount
= (uint8_t)(mm_table
->count
);
1633 table
->UvdBootLevel
= 0;
1635 for (count
= 0; count
< table
->UvdLevelCount
; count
++) {
1636 table
->UvdLevel
[count
].MinVoltage
= 0;
1637 table
->UvdLevel
[count
].VclkFrequency
= mm_table
->entries
[count
].vclk
;
1638 table
->UvdLevel
[count
].DclkFrequency
= mm_table
->entries
[count
].dclk
;
1639 table
->UvdLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
1640 VOLTAGE_SCALE
) << VDDC_SHIFT
;
1641 table
->UvdLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
1642 VDDC_VDDCI_DELTA
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1643 table
->UvdLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
1645 /* retrieve divider value for VBIOS */
1646 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1647 table
->UvdLevel
[count
].VclkFrequency
, ÷rs
);
1648 PP_ASSERT_WITH_CODE((0 == result
),
1649 "can not find divide id for Vclk clock", return result
);
1651 table
->UvdLevel
[count
].VclkDivider
= (uint8_t)dividers
.pll_post_divider
;
1653 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1654 table
->UvdLevel
[count
].DclkFrequency
, ÷rs
);
1655 PP_ASSERT_WITH_CODE((0 == result
),
1656 "can not find divide id for Dclk clock", return result
);
1658 table
->UvdLevel
[count
].DclkDivider
= (uint8_t)dividers
.pll_post_divider
;
1660 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].VclkFrequency
);
1661 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].DclkFrequency
);
1662 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].MinVoltage
);
1668 static int fiji_populate_smc_boot_level(struct pp_hwmgr
*hwmgr
,
1669 struct SMU73_Discrete_DpmTable
*table
)
1672 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1674 table
->GraphicsBootLevel
= 0;
1675 table
->MemoryBootLevel
= 0;
1677 /* find boot level from dpm table */
1678 result
= phm_find_boot_level(&(data
->dpm_table
.sclk_table
),
1679 data
->vbios_boot_state
.sclk_bootup_value
,
1680 (uint32_t *)&(table
->GraphicsBootLevel
));
1682 result
= phm_find_boot_level(&(data
->dpm_table
.mclk_table
),
1683 data
->vbios_boot_state
.mclk_bootup_value
,
1684 (uint32_t *)&(table
->MemoryBootLevel
));
1686 table
->BootVddc
= data
->vbios_boot_state
.vddc_bootup_value
*
1688 table
->BootVddci
= data
->vbios_boot_state
.vddci_bootup_value
*
1690 table
->BootMVdd
= data
->vbios_boot_state
.mvdd_bootup_value
*
1693 CONVERT_FROM_HOST_TO_SMC_US(table
->BootVddc
);
1694 CONVERT_FROM_HOST_TO_SMC_US(table
->BootVddci
);
1695 CONVERT_FROM_HOST_TO_SMC_US(table
->BootMVdd
);
1700 static int fiji_populate_smc_initailial_state(struct pp_hwmgr
*hwmgr
)
1702 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1703 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
1704 struct phm_ppt_v1_information
*table_info
=
1705 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1706 uint8_t count
, level
;
1708 count
= (uint8_t)(table_info
->vdd_dep_on_sclk
->count
);
1709 for (level
= 0; level
< count
; level
++) {
1710 if (table_info
->vdd_dep_on_sclk
->entries
[level
].clk
>=
1711 data
->vbios_boot_state
.sclk_bootup_value
) {
1712 smu_data
->smc_state_table
.GraphicsBootLevel
= level
;
1717 count
= (uint8_t)(table_info
->vdd_dep_on_mclk
->count
);
1718 for (level
= 0; level
< count
; level
++) {
1719 if (table_info
->vdd_dep_on_mclk
->entries
[level
].clk
>=
1720 data
->vbios_boot_state
.mclk_bootup_value
) {
1721 smu_data
->smc_state_table
.MemoryBootLevel
= level
;
1729 static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr
*hwmgr
)
1731 uint32_t ro
, efuse
, efuse2
, clock_freq
, volt_without_cks
,
1732 volt_with_cks
, value
;
1733 uint16_t clock_freq_u16
;
1734 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
1735 uint8_t type
, i
, j
, cks_setting
, stretch_amount
, stretch_amount2
,
1737 struct phm_ppt_v1_information
*table_info
=
1738 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1739 struct phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
=
1740 table_info
->vdd_dep_on_sclk
;
1742 stretch_amount
= (uint8_t)table_info
->cac_dtp_table
->usClockStretchAmount
;
1744 /* Read SMU_Eefuse to read and calculate RO and determine
1745 * if the part is SS or FF. if RO >= 1660MHz, part is FF.
1747 efuse
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1748 ixSMU_EFUSE_0
+ (146 * 4));
1749 efuse2
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1750 ixSMU_EFUSE_0
+ (148 * 4));
1751 efuse
&= 0xFF000000;
1752 efuse
= efuse
>> 24;
1756 ro
= (2300 - 1350) * efuse
/ 255 + 1350;
1758 ro
= (2500 - 1000) * efuse
/ 255 + 1000;
1765 /* Populate Stretch amount */
1766 smu_data
->smc_state_table
.ClockStretcherAmount
= stretch_amount
;
1768 /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
1769 for (i
= 0; i
< sclk_table
->count
; i
++) {
1770 smu_data
->smc_state_table
.Sclk_CKS_masterEn0_7
|=
1771 sclk_table
->entries
[i
].cks_enable
<< i
;
1772 volt_without_cks
= (uint32_t)((14041 *
1773 (sclk_table
->entries
[i
].clk
/100) / 10000 + 3571 + 75 - ro
) * 1000 /
1774 (4026 - (13924 * (sclk_table
->entries
[i
].clk
/100) / 10000)));
1775 volt_with_cks
= (uint32_t)((13946 *
1776 (sclk_table
->entries
[i
].clk
/100) / 10000 + 3320 + 45 - ro
) * 1000 /
1777 (3664 - (11454 * (sclk_table
->entries
[i
].clk
/100) / 10000)));
1778 if (volt_without_cks
>= volt_with_cks
)
1779 volt_offset
= (uint8_t)(((volt_without_cks
- volt_with_cks
+
1780 sclk_table
->entries
[i
].cks_voffset
) * 100 / 625) + 1);
1781 smu_data
->smc_state_table
.Sclk_voltageOffset
[i
] = volt_offset
;
1784 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
1785 STRETCH_ENABLE
, 0x0);
1786 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
1788 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
1790 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
1793 /* Populate CKS Lookup Table */
1794 if (stretch_amount
== 1 || stretch_amount
== 2 || stretch_amount
== 5)
1795 stretch_amount2
= 0;
1796 else if (stretch_amount
== 3 || stretch_amount
== 4)
1797 stretch_amount2
= 1;
1799 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
1800 PHM_PlatformCaps_ClockStretcher
);
1801 PP_ASSERT_WITH_CODE(false,
1802 "Stretch Amount in PPTable not supported\n",
1806 value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1808 value
&= 0xFFC2FF87;
1809 smu_data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].minFreq
=
1810 fiji_clock_stretcher_lookup_table
[stretch_amount2
][0];
1811 smu_data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].maxFreq
=
1812 fiji_clock_stretcher_lookup_table
[stretch_amount2
][1];
1813 clock_freq_u16
= (uint16_t)(PP_SMC_TO_HOST_UL(smu_data
->smc_state_table
.
1814 GraphicsLevel
[smu_data
->smc_state_table
.GraphicsDpmLevelCount
- 1].
1815 SclkFrequency
) / 100);
1816 if (fiji_clock_stretcher_lookup_table
[stretch_amount2
][0] <
1818 fiji_clock_stretcher_lookup_table
[stretch_amount2
][1] >
1820 /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
1821 value
|= (fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]) << 16;
1822 /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
1823 value
|= (fiji_clock_stretcher_lookup_table
[stretch_amount2
][2]) << 18;
1824 /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
1825 value
|= (fiji_clock_stretch_amount_conversion
1826 [fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]]
1827 [stretch_amount
]) << 3;
1829 CONVERT_FROM_HOST_TO_SMC_US(smu_data
->smc_state_table
.CKS_LOOKUPTable
.
1830 CKS_LOOKUPTableEntry
[0].minFreq
);
1831 CONVERT_FROM_HOST_TO_SMC_US(smu_data
->smc_state_table
.CKS_LOOKUPTable
.
1832 CKS_LOOKUPTableEntry
[0].maxFreq
);
1833 smu_data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].setting
=
1834 fiji_clock_stretcher_lookup_table
[stretch_amount2
][2] & 0x7F;
1835 smu_data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].setting
|=
1836 (fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]) << 7;
1838 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1839 ixPWR_CKS_CNTL
, value
);
1841 /* Populate DDT Lookup Table */
1842 for (i
= 0; i
< 4; i
++) {
1843 /* Assign the minimum and maximum VID stored
1844 * in the last row of Clock Stretcher Voltage Table.
1846 smu_data
->smc_state_table
.ClockStretcherDataTable
.
1847 ClockStretcherDataTableEntry
[i
].minVID
=
1848 (uint8_t) fiji_clock_stretcher_ddt_table
[type
][i
][2];
1849 smu_data
->smc_state_table
.ClockStretcherDataTable
.
1850 ClockStretcherDataTableEntry
[i
].maxVID
=
1851 (uint8_t) fiji_clock_stretcher_ddt_table
[type
][i
][3];
1852 /* Loop through each SCLK and check the frequency
1853 * to see if it lies within the frequency for clock stretcher.
1855 for (j
= 0; j
< smu_data
->smc_state_table
.GraphicsDpmLevelCount
; j
++) {
1857 clock_freq
= PP_SMC_TO_HOST_UL(
1858 smu_data
->smc_state_table
.GraphicsLevel
[j
].SclkFrequency
);
1859 /* Check the allowed frequency against the sclk level[j].
1860 * Sclk's endianness has already been converted,
1861 * and it's in 10Khz unit,
1862 * as opposed to Data table, which is in Mhz unit.
1865 (fiji_clock_stretcher_ddt_table
[type
][i
][0]) * 100) {
1868 (fiji_clock_stretcher_ddt_table
[type
][i
][1]) * 100)
1871 smu_data
->smc_state_table
.ClockStretcherDataTable
.
1872 ClockStretcherDataTableEntry
[i
].setting
|= cks_setting
<< (j
* 2);
1874 CONVERT_FROM_HOST_TO_SMC_US(smu_data
->smc_state_table
.
1875 ClockStretcherDataTable
.
1876 ClockStretcherDataTableEntry
[i
].setting
);
1879 value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixPWR_CKS_CNTL
);
1880 value
&= 0xFFFFFFFE;
1881 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixPWR_CKS_CNTL
, value
);
1886 static int fiji_populate_vr_config(struct pp_hwmgr
*hwmgr
,
1887 struct SMU73_Discrete_DpmTable
*table
)
1889 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1892 config
= VR_MERGED_WITH_VDDC
;
1893 table
->VRConfig
|= (config
<< VRCONF_VDDGFX_SHIFT
);
1895 /* Set Vddc Voltage Controller */
1896 if (SMU7_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1897 config
= VR_SVI2_PLANE_1
;
1898 table
->VRConfig
|= config
;
1900 PP_ASSERT_WITH_CODE(false,
1901 "VDDC should be on SVI2 control in merged mode!",
1904 /* Set Vddci Voltage Controller */
1905 if (SMU7_VOLTAGE_CONTROL_BY_SVID2
== data
->vddci_control
) {
1906 config
= VR_SVI2_PLANE_2
; /* only in merged mode */
1907 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
1908 } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO
== data
->vddci_control
) {
1909 config
= VR_SMIO_PATTERN_1
;
1910 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
1912 config
= VR_STATIC_VOLTAGE
;
1913 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
1915 /* Set Mvdd Voltage Controller */
1916 if (SMU7_VOLTAGE_CONTROL_BY_SVID2
== data
->mvdd_control
) {
1917 config
= VR_SVI2_PLANE_2
;
1918 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
1919 } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1920 config
= VR_SMIO_PATTERN_2
;
1921 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
1923 config
= VR_STATIC_VOLTAGE
;
1924 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
1930 static int fiji_init_arb_table_index(struct pp_hwmgr
*hwmgr
)
1932 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
1936 /* This is a read-modify-write on the first byte of the ARB table.
1937 * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
1938 * is the field 'current'.
1939 * This solution is ugly, but we never write the whole table only
1940 * individual fields in it.
1941 * In reality this field should not be in that structure
1942 * but in a soft register.
1944 result
= smu7_read_smc_sram_dword(hwmgr
,
1945 smu_data
->smu7_data
.arb_table_start
, &tmp
, SMC_RAM_END
);
1951 tmp
|= ((uint32_t)MC_CG_ARB_FREQ_F1
) << 24;
1953 return smu7_write_smc_sram_dword(hwmgr
,
1954 smu_data
->smu7_data
.arb_table_start
, tmp
, SMC_RAM_END
);
1957 static int fiji_save_default_power_profile(struct pp_hwmgr
*hwmgr
)
1959 struct fiji_smumgr
*data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
1960 struct SMU73_Discrete_GraphicsLevel
*levels
=
1961 data
->smc_state_table
.GraphicsLevel
;
1962 unsigned min_level
= 1;
1964 hwmgr
->default_gfx_power_profile
.activity_threshold
=
1965 be16_to_cpu(levels
[0].ActivityLevel
);
1966 hwmgr
->default_gfx_power_profile
.up_hyst
= levels
[0].UpHyst
;
1967 hwmgr
->default_gfx_power_profile
.down_hyst
= levels
[0].DownHyst
;
1968 hwmgr
->default_gfx_power_profile
.type
= AMD_PP_GFX_PROFILE
;
1970 hwmgr
->default_compute_power_profile
= hwmgr
->default_gfx_power_profile
;
1971 hwmgr
->default_compute_power_profile
.type
= AMD_PP_COMPUTE_PROFILE
;
1973 /* Workaround compute SDMA instability: disable lowest SCLK
1974 * DPM level. Optimize compute power profile: Use only highest
1975 * 2 power levels (if more than 2 are available), Hysteresis:
1978 if (data
->smc_state_table
.GraphicsDpmLevelCount
> 2)
1979 min_level
= data
->smc_state_table
.GraphicsDpmLevelCount
- 2;
1980 else if (data
->smc_state_table
.GraphicsDpmLevelCount
== 2)
1984 hwmgr
->default_compute_power_profile
.min_sclk
=
1985 be32_to_cpu(levels
[min_level
].SclkFrequency
);
1986 hwmgr
->default_compute_power_profile
.up_hyst
= 0;
1987 hwmgr
->default_compute_power_profile
.down_hyst
= 5;
1989 hwmgr
->gfx_power_profile
= hwmgr
->default_gfx_power_profile
;
1990 hwmgr
->compute_power_profile
= hwmgr
->default_compute_power_profile
;
1995 static int fiji_setup_dpm_led_config(struct pp_hwmgr
*hwmgr
)
1997 pp_atomctrl_voltage_table param_led_dpm
;
2001 result
= atomctrl_get_voltage_table_v3(hwmgr
,
2002 VOLTAGE_TYPE_LEDDPM
, VOLTAGE_OBJ_GPIO_LUT
,
2006 u32 tmp
= param_led_dpm
.mask_low
;
2008 for (i
= 0, j
= 0; i
< 32; i
++) {
2010 mask
|= (i
<< (8 * j
));
2018 smum_send_msg_to_smc_with_parameter(hwmgr
,
2019 PPSMC_MSG_LedConfig
,
2024 static int fiji_init_smc_table(struct pp_hwmgr
*hwmgr
)
2027 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
2028 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
2029 struct phm_ppt_v1_information
*table_info
=
2030 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2031 struct SMU73_Discrete_DpmTable
*table
= &(smu_data
->smc_state_table
);
2033 struct pp_atomctrl_gpio_pin_assignment gpio_pin
;
2035 fiji_initialize_power_tune_defaults(hwmgr
);
2037 if (SMU7_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
)
2038 fiji_populate_smc_voltage_tables(hwmgr
, table
);
2040 table
->SystemFlags
= 0;
2042 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2043 PHM_PlatformCaps_AutomaticDCTransition
))
2044 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GPIO_DC
;
2046 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2047 PHM_PlatformCaps_StepVddc
))
2048 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_STEPVDDC
;
2050 if (data
->is_memory_gddr5
)
2051 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GDDR5
;
2053 if (data
->ulv_supported
&& table_info
->us_ulv_voltage_offset
) {
2054 result
= fiji_populate_ulv_state(hwmgr
, table
);
2055 PP_ASSERT_WITH_CODE(0 == result
,
2056 "Failed to initialize ULV state!", return result
);
2057 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
2058 ixCG_ULV_PARAMETER
, 0x40035);
2061 result
= fiji_populate_smc_link_level(hwmgr
, table
);
2062 PP_ASSERT_WITH_CODE(0 == result
,
2063 "Failed to initialize Link Level!", return result
);
2065 result
= fiji_populate_all_graphic_levels(hwmgr
);
2066 PP_ASSERT_WITH_CODE(0 == result
,
2067 "Failed to initialize Graphics Level!", return result
);
2069 result
= fiji_populate_all_memory_levels(hwmgr
);
2070 PP_ASSERT_WITH_CODE(0 == result
,
2071 "Failed to initialize Memory Level!", return result
);
2073 result
= fiji_populate_smc_acpi_level(hwmgr
, table
);
2074 PP_ASSERT_WITH_CODE(0 == result
,
2075 "Failed to initialize ACPI Level!", return result
);
2077 result
= fiji_populate_smc_vce_level(hwmgr
, table
);
2078 PP_ASSERT_WITH_CODE(0 == result
,
2079 "Failed to initialize VCE Level!", return result
);
2081 result
= fiji_populate_smc_acp_level(hwmgr
, table
);
2082 PP_ASSERT_WITH_CODE(0 == result
,
2083 "Failed to initialize ACP Level!", return result
);
2085 result
= fiji_populate_smc_samu_level(hwmgr
, table
);
2086 PP_ASSERT_WITH_CODE(0 == result
,
2087 "Failed to initialize SAMU Level!", return result
);
2089 /* Since only the initial state is completely set up at this point
2090 * (the other states are just copies of the boot state) we only
2091 * need to populate the ARB settings for the initial state.
2093 result
= fiji_program_memory_timing_parameters(hwmgr
);
2094 PP_ASSERT_WITH_CODE(0 == result
,
2095 "Failed to Write ARB settings for the initial state.", return result
);
2097 result
= fiji_populate_smc_uvd_level(hwmgr
, table
);
2098 PP_ASSERT_WITH_CODE(0 == result
,
2099 "Failed to initialize UVD Level!", return result
);
2101 result
= fiji_populate_smc_boot_level(hwmgr
, table
);
2102 PP_ASSERT_WITH_CODE(0 == result
,
2103 "Failed to initialize Boot Level!", return result
);
2105 result
= fiji_populate_smc_initailial_state(hwmgr
);
2106 PP_ASSERT_WITH_CODE(0 == result
,
2107 "Failed to initialize Boot State!", return result
);
2109 result
= fiji_populate_bapm_parameters_in_dpm_table(hwmgr
);
2110 PP_ASSERT_WITH_CODE(0 == result
,
2111 "Failed to populate BAPM Parameters!", return result
);
2113 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2114 PHM_PlatformCaps_ClockStretcher
)) {
2115 result
= fiji_populate_clock_stretcher_data_table(hwmgr
);
2116 PP_ASSERT_WITH_CODE(0 == result
,
2117 "Failed to populate Clock Stretcher Data Table!",
2121 table
->GraphicsVoltageChangeEnable
= 1;
2122 table
->GraphicsThermThrottleEnable
= 1;
2123 table
->GraphicsInterval
= 1;
2124 table
->VoltageInterval
= 1;
2125 table
->ThermalInterval
= 1;
2126 table
->TemperatureLimitHigh
=
2127 table_info
->cac_dtp_table
->usTargetOperatingTemp
*
2128 SMU7_Q88_FORMAT_CONVERSION_UNIT
;
2129 table
->TemperatureLimitLow
=
2130 (table_info
->cac_dtp_table
->usTargetOperatingTemp
- 1) *
2131 SMU7_Q88_FORMAT_CONVERSION_UNIT
;
2132 table
->MemoryVoltageChangeEnable
= 1;
2133 table
->MemoryInterval
= 1;
2134 table
->VoltageResponseTime
= 0;
2135 table
->PhaseResponseTime
= 0;
2136 table
->MemoryThermThrottleEnable
= 1;
2137 table
->PCIeBootLinkLevel
= 0; /* 0:Gen1 1:Gen2 2:Gen3*/
2138 table
->PCIeGenInterval
= 1;
2139 table
->VRConfig
= 0;
2141 result
= fiji_populate_vr_config(hwmgr
, table
);
2142 PP_ASSERT_WITH_CODE(0 == result
,
2143 "Failed to populate VRConfig setting!", return result
);
2145 table
->ThermGpio
= 17;
2146 table
->SclkStepSize
= 0x4000;
2148 if (atomctrl_get_pp_assign_pin(hwmgr
, VDDC_VRHOT_GPIO_PINID
, &gpio_pin
)) {
2149 table
->VRHotGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
2150 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
2151 PHM_PlatformCaps_RegulatorHot
);
2153 table
->VRHotGpio
= SMU7_UNUSED_GPIO_PIN
;
2154 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
2155 PHM_PlatformCaps_RegulatorHot
);
2158 if (atomctrl_get_pp_assign_pin(hwmgr
, PP_AC_DC_SWITCH_GPIO_PINID
,
2160 table
->AcDcGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
2161 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
2162 PHM_PlatformCaps_AutomaticDCTransition
);
2164 table
->AcDcGpio
= SMU7_UNUSED_GPIO_PIN
;
2165 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
2166 PHM_PlatformCaps_AutomaticDCTransition
);
2169 /* Thermal Output GPIO */
2170 if (atomctrl_get_pp_assign_pin(hwmgr
, THERMAL_INT_OUTPUT_GPIO_PINID
,
2172 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
2173 PHM_PlatformCaps_ThermalOutGPIO
);
2175 table
->ThermOutGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
2177 /* For porlarity read GPIOPAD_A with assigned Gpio pin
2178 * since VBIOS will program this register to set 'inactive state',
2179 * driver can then determine 'active state' from this and
2180 * program SMU with correct polarity
2182 table
->ThermOutPolarity
= (0 == (cgs_read_register(hwmgr
->device
, mmGPIOPAD_A
) &
2183 (1 << gpio_pin
.uc_gpio_pin_bit_shift
))) ? 1:0;
2184 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_ONLY
;
2186 /* if required, combine VRHot/PCC with thermal out GPIO */
2187 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2188 PHM_PlatformCaps_RegulatorHot
) &&
2189 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2190 PHM_PlatformCaps_CombinePCCWithThermalSignal
))
2191 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_VRHOT
;
2193 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
2194 PHM_PlatformCaps_ThermalOutGPIO
);
2195 table
->ThermOutGpio
= 17;
2196 table
->ThermOutPolarity
= 1;
2197 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_DISABLE
;
2200 for (i
= 0; i
< SMU73_MAX_ENTRIES_SMIO
; i
++)
2201 table
->Smio
[i
] = PP_HOST_TO_SMC_UL(table
->Smio
[i
]);
2203 CONVERT_FROM_HOST_TO_SMC_UL(table
->SystemFlags
);
2204 CONVERT_FROM_HOST_TO_SMC_UL(table
->VRConfig
);
2205 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask1
);
2206 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask2
);
2207 CONVERT_FROM_HOST_TO_SMC_UL(table
->SclkStepSize
);
2208 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitHigh
);
2209 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitLow
);
2210 CONVERT_FROM_HOST_TO_SMC_US(table
->VoltageResponseTime
);
2211 CONVERT_FROM_HOST_TO_SMC_US(table
->PhaseResponseTime
);
2213 /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
2214 result
= smu7_copy_bytes_to_smc(hwmgr
,
2215 smu_data
->smu7_data
.dpm_table_start
+
2216 offsetof(SMU73_Discrete_DpmTable
, SystemFlags
),
2217 (uint8_t *)&(table
->SystemFlags
),
2218 sizeof(SMU73_Discrete_DpmTable
) - 3 * sizeof(SMU73_PIDController
),
2220 PP_ASSERT_WITH_CODE(0 == result
,
2221 "Failed to upload dpm data to SMC memory!", return result
);
2223 result
= fiji_init_arb_table_index(hwmgr
);
2224 PP_ASSERT_WITH_CODE(0 == result
,
2225 "Failed to upload arb data to SMC memory!", return result
);
2227 result
= fiji_populate_pm_fuses(hwmgr
);
2228 PP_ASSERT_WITH_CODE(0 == result
,
2229 "Failed to populate PM fuses to SMC memory!", return result
);
2231 result
= fiji_setup_dpm_led_config(hwmgr
);
2232 PP_ASSERT_WITH_CODE(0 == result
,
2233 "Failed to setup dpm led config", return result
);
2235 fiji_save_default_power_profile(hwmgr
);
2240 static int fiji_thermal_setup_fan_table(struct pp_hwmgr
*hwmgr
)
2242 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
2244 SMU73_Discrete_FanTable fan_table
= { FDO_MODE_HARDWARE
};
2246 uint32_t t_diff1
, t_diff2
, pwm_diff1
, pwm_diff2
;
2247 uint16_t fdo_min
, slope1
, slope2
;
2248 uint32_t reference_clock
;
2252 if (hwmgr
->thermal_controller
.fanInfo
.bNoFan
) {
2253 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
2254 PHM_PlatformCaps_MicrocodeFanControl
);
2258 if (smu_data
->smu7_data
.fan_table_start
== 0) {
2259 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
2260 PHM_PlatformCaps_MicrocodeFanControl
);
2264 duty100
= PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
2265 CG_FDO_CTRL1
, FMAX_DUTY100
);
2268 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
2269 PHM_PlatformCaps_MicrocodeFanControl
);
2273 tmp64
= hwmgr
->thermal_controller
.advanceFanControlParameters
.
2275 do_div(tmp64
, 10000);
2276 fdo_min
= (uint16_t)tmp64
;
2278 t_diff1
= hwmgr
->thermal_controller
.advanceFanControlParameters
.usTMed
-
2279 hwmgr
->thermal_controller
.advanceFanControlParameters
.usTMin
;
2280 t_diff2
= hwmgr
->thermal_controller
.advanceFanControlParameters
.usTHigh
-
2281 hwmgr
->thermal_controller
.advanceFanControlParameters
.usTMed
;
2283 pwm_diff1
= hwmgr
->thermal_controller
.advanceFanControlParameters
.usPWMMed
-
2284 hwmgr
->thermal_controller
.advanceFanControlParameters
.usPWMMin
;
2285 pwm_diff2
= hwmgr
->thermal_controller
.advanceFanControlParameters
.usPWMHigh
-
2286 hwmgr
->thermal_controller
.advanceFanControlParameters
.usPWMMed
;
2288 slope1
= (uint16_t)((50 + ((16 * duty100
* pwm_diff1
) / t_diff1
)) / 100);
2289 slope2
= (uint16_t)((50 + ((16 * duty100
* pwm_diff2
) / t_diff2
)) / 100);
2291 fan_table
.TempMin
= cpu_to_be16((50 + hwmgr
->
2292 thermal_controller
.advanceFanControlParameters
.usTMin
) / 100);
2293 fan_table
.TempMed
= cpu_to_be16((50 + hwmgr
->
2294 thermal_controller
.advanceFanControlParameters
.usTMed
) / 100);
2295 fan_table
.TempMax
= cpu_to_be16((50 + hwmgr
->
2296 thermal_controller
.advanceFanControlParameters
.usTMax
) / 100);
2298 fan_table
.Slope1
= cpu_to_be16(slope1
);
2299 fan_table
.Slope2
= cpu_to_be16(slope2
);
2301 fan_table
.FdoMin
= cpu_to_be16(fdo_min
);
2303 fan_table
.HystDown
= cpu_to_be16(hwmgr
->
2304 thermal_controller
.advanceFanControlParameters
.ucTHyst
);
2306 fan_table
.HystUp
= cpu_to_be16(1);
2308 fan_table
.HystSlope
= cpu_to_be16(1);
2310 fan_table
.TempRespLim
= cpu_to_be16(5);
2312 reference_clock
= smu7_get_xclk(hwmgr
);
2314 fan_table
.RefreshPeriod
= cpu_to_be32((hwmgr
->
2315 thermal_controller
.advanceFanControlParameters
.ulCycleDelay
*
2316 reference_clock
) / 1600);
2318 fan_table
.FdoMax
= cpu_to_be16((uint16_t)duty100
);
2320 fan_table
.TempSrc
= (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
2321 hwmgr
->device
, CGS_IND_REG__SMC
,
2322 CG_MULT_THERMAL_CTRL
, TEMP_SEL
);
2324 res
= smu7_copy_bytes_to_smc(hwmgr
, smu_data
->smu7_data
.fan_table_start
,
2325 (uint8_t *)&fan_table
, (uint32_t)sizeof(fan_table
),
2328 if (!res
&& hwmgr
->thermal_controller
.
2329 advanceFanControlParameters
.ucMinimumPWMLimit
)
2330 res
= smum_send_msg_to_smc_with_parameter(hwmgr
,
2331 PPSMC_MSG_SetFanMinPwm
,
2332 hwmgr
->thermal_controller
.
2333 advanceFanControlParameters
.ucMinimumPWMLimit
);
2335 if (!res
&& hwmgr
->thermal_controller
.
2336 advanceFanControlParameters
.ulMinFanSCLKAcousticLimit
)
2337 res
= smum_send_msg_to_smc_with_parameter(hwmgr
,
2338 PPSMC_MSG_SetFanSclkTarget
,
2339 hwmgr
->thermal_controller
.
2340 advanceFanControlParameters
.ulMinFanSCLKAcousticLimit
);
2343 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
2344 PHM_PlatformCaps_MicrocodeFanControl
);
2350 static int fiji_thermal_avfs_enable(struct pp_hwmgr
*hwmgr
)
2353 struct smu7_smumgr
*smu_data
= (struct smu7_smumgr
*)(hwmgr
->smu_backend
);
2355 if (smu_data
->avfs
.avfs_btc_status
!= AVFS_BTC_ENABLEAVFS
)
2358 ret
= smum_send_msg_to_smc(hwmgr
, PPSMC_MSG_EnableAvfs
);
2361 /* If this param is not changed, this function could fire unnecessarily */
2362 smu_data
->avfs
.avfs_btc_status
= AVFS_BTC_COMPLETED_PREVIOUSLY
;
2367 static int fiji_program_mem_timing_parameters(struct pp_hwmgr
*hwmgr
)
2369 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
2371 if (data
->need_update_smu7_dpm_table
&
2372 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_OD_UPDATE_MCLK
))
2373 return fiji_program_memory_timing_parameters(hwmgr
);
2378 static int fiji_update_sclk_threshold(struct pp_hwmgr
*hwmgr
)
2380 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
2381 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
2384 uint32_t low_sclk_interrupt_threshold
= 0;
2386 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2387 PHM_PlatformCaps_SclkThrottleLowNotification
)
2388 && (hwmgr
->gfx_arbiter
.sclk_threshold
!=
2389 data
->low_sclk_interrupt_threshold
)) {
2390 data
->low_sclk_interrupt_threshold
=
2391 hwmgr
->gfx_arbiter
.sclk_threshold
;
2392 low_sclk_interrupt_threshold
=
2393 data
->low_sclk_interrupt_threshold
;
2395 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold
);
2397 result
= smu7_copy_bytes_to_smc(
2399 smu_data
->smu7_data
.dpm_table_start
+
2400 offsetof(SMU73_Discrete_DpmTable
,
2401 LowSclkInterruptThreshold
),
2402 (uint8_t *)&low_sclk_interrupt_threshold
,
2406 result
= fiji_program_mem_timing_parameters(hwmgr
);
2407 PP_ASSERT_WITH_CODE((result
== 0),
2408 "Failed to program memory timing parameters!",
2413 static uint32_t fiji_get_offsetof(uint32_t type
, uint32_t member
)
2416 case SMU_SoftRegisters
:
2418 case HandshakeDisables
:
2419 return offsetof(SMU73_SoftRegisters
, HandshakeDisables
);
2420 case VoltageChangeTimeout
:
2421 return offsetof(SMU73_SoftRegisters
, VoltageChangeTimeout
);
2422 case AverageGraphicsActivity
:
2423 return offsetof(SMU73_SoftRegisters
, AverageGraphicsActivity
);
2425 return offsetof(SMU73_SoftRegisters
, PreVBlankGap
);
2427 return offsetof(SMU73_SoftRegisters
, VBlankTimeout
);
2428 case UcodeLoadStatus
:
2429 return offsetof(SMU73_SoftRegisters
, UcodeLoadStatus
);
2430 case DRAM_LOG_ADDR_H
:
2431 return offsetof(SMU73_SoftRegisters
, DRAM_LOG_ADDR_H
);
2432 case DRAM_LOG_ADDR_L
:
2433 return offsetof(SMU73_SoftRegisters
, DRAM_LOG_ADDR_L
);
2434 case DRAM_LOG_PHY_ADDR_H
:
2435 return offsetof(SMU73_SoftRegisters
, DRAM_LOG_PHY_ADDR_H
);
2436 case DRAM_LOG_PHY_ADDR_L
:
2437 return offsetof(SMU73_SoftRegisters
, DRAM_LOG_PHY_ADDR_L
);
2438 case DRAM_LOG_BUFF_SIZE
:
2439 return offsetof(SMU73_SoftRegisters
, DRAM_LOG_BUFF_SIZE
);
2441 case SMU_Discrete_DpmTable
:
2444 return offsetof(SMU73_Discrete_DpmTable
, UvdBootLevel
);
2446 return offsetof(SMU73_Discrete_DpmTable
, VceBootLevel
);
2448 return offsetof(SMU73_Discrete_DpmTable
, SamuBootLevel
);
2449 case LowSclkInterruptThreshold
:
2450 return offsetof(SMU73_Discrete_DpmTable
, LowSclkInterruptThreshold
);
2453 pr_warn("can't get the offset of type %x member %x\n", type
, member
);
2457 static uint32_t fiji_get_mac_definition(uint32_t value
)
2460 case SMU_MAX_LEVELS_GRAPHICS
:
2461 return SMU73_MAX_LEVELS_GRAPHICS
;
2462 case SMU_MAX_LEVELS_MEMORY
:
2463 return SMU73_MAX_LEVELS_MEMORY
;
2464 case SMU_MAX_LEVELS_LINK
:
2465 return SMU73_MAX_LEVELS_LINK
;
2466 case SMU_MAX_ENTRIES_SMIO
:
2467 return SMU73_MAX_ENTRIES_SMIO
;
2468 case SMU_MAX_LEVELS_VDDC
:
2469 return SMU73_MAX_LEVELS_VDDC
;
2470 case SMU_MAX_LEVELS_VDDGFX
:
2471 return SMU73_MAX_LEVELS_VDDGFX
;
2472 case SMU_MAX_LEVELS_VDDCI
:
2473 return SMU73_MAX_LEVELS_VDDCI
;
2474 case SMU_MAX_LEVELS_MVDD
:
2475 return SMU73_MAX_LEVELS_MVDD
;
2478 pr_warn("can't get the mac of %x\n", value
);
2483 static int fiji_update_uvd_smc_table(struct pp_hwmgr
*hwmgr
)
2485 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
2486 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
2487 struct phm_ppt_v1_information
*table_info
=
2488 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2490 smu_data
->smc_state_table
.UvdBootLevel
= 0;
2491 if (table_info
->mm_dep_table
->count
> 0)
2492 smu_data
->smc_state_table
.UvdBootLevel
=
2493 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
2494 mm_boot_level_offset
= smu_data
->smu7_data
.dpm_table_start
+ offsetof(SMU73_Discrete_DpmTable
,
2496 mm_boot_level_offset
/= 4;
2497 mm_boot_level_offset
*= 4;
2498 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
2499 CGS_IND_REG__SMC
, mm_boot_level_offset
);
2500 mm_boot_level_value
&= 0x00FFFFFF;
2501 mm_boot_level_value
|= smu_data
->smc_state_table
.UvdBootLevel
<< 24;
2502 cgs_write_ind_register(hwmgr
->device
,
2503 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
2505 if (!phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2506 PHM_PlatformCaps_UVDDPM
) ||
2507 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2508 PHM_PlatformCaps_StablePState
))
2509 smum_send_msg_to_smc_with_parameter(hwmgr
,
2510 PPSMC_MSG_UVDDPM_SetEnabledMask
,
2511 (uint32_t)(1 << smu_data
->smc_state_table
.UvdBootLevel
));
2515 static int fiji_update_vce_smc_table(struct pp_hwmgr
*hwmgr
)
2517 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
2518 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
2519 struct phm_ppt_v1_information
*table_info
=
2520 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2522 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2523 PHM_PlatformCaps_StablePState
))
2524 smu_data
->smc_state_table
.VceBootLevel
=
2525 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
2527 smu_data
->smc_state_table
.VceBootLevel
= 0;
2529 mm_boot_level_offset
= smu_data
->smu7_data
.dpm_table_start
+
2530 offsetof(SMU73_Discrete_DpmTable
, VceBootLevel
);
2531 mm_boot_level_offset
/= 4;
2532 mm_boot_level_offset
*= 4;
2533 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
2534 CGS_IND_REG__SMC
, mm_boot_level_offset
);
2535 mm_boot_level_value
&= 0xFF00FFFF;
2536 mm_boot_level_value
|= smu_data
->smc_state_table
.VceBootLevel
<< 16;
2537 cgs_write_ind_register(hwmgr
->device
,
2538 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
2540 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
))
2541 smum_send_msg_to_smc_with_parameter(hwmgr
,
2542 PPSMC_MSG_VCEDPM_SetEnabledMask
,
2543 (uint32_t)1 << smu_data
->smc_state_table
.VceBootLevel
);
2547 static int fiji_update_samu_smc_table(struct pp_hwmgr
*hwmgr
)
2549 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
2550 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
2553 smu_data
->smc_state_table
.SamuBootLevel
= 0;
2554 mm_boot_level_offset
= smu_data
->smu7_data
.dpm_table_start
+
2555 offsetof(SMU73_Discrete_DpmTable
, SamuBootLevel
);
2557 mm_boot_level_offset
/= 4;
2558 mm_boot_level_offset
*= 4;
2559 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
2560 CGS_IND_REG__SMC
, mm_boot_level_offset
);
2561 mm_boot_level_value
&= 0xFFFFFF00;
2562 mm_boot_level_value
|= smu_data
->smc_state_table
.SamuBootLevel
<< 0;
2563 cgs_write_ind_register(hwmgr
->device
,
2564 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
2566 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2567 PHM_PlatformCaps_StablePState
))
2568 smum_send_msg_to_smc_with_parameter(hwmgr
,
2569 PPSMC_MSG_SAMUDPM_SetEnabledMask
,
2570 (uint32_t)(1 << smu_data
->smc_state_table
.SamuBootLevel
));
2574 static int fiji_update_smc_table(struct pp_hwmgr
*hwmgr
, uint32_t type
)
2578 fiji_update_uvd_smc_table(hwmgr
);
2581 fiji_update_vce_smc_table(hwmgr
);
2583 case SMU_SAMU_TABLE
:
2584 fiji_update_samu_smc_table(hwmgr
);
2592 static int fiji_process_firmware_header(struct pp_hwmgr
*hwmgr
)
2594 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
2595 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smu_backend
);
2600 result
= smu7_read_smc_sram_dword(hwmgr
,
2601 SMU7_FIRMWARE_HEADER_LOCATION
+
2602 offsetof(SMU73_Firmware_Header
, DpmTable
),
2606 smu_data
->smu7_data
.dpm_table_start
= tmp
;
2608 error
|= (0 != result
);
2610 result
= smu7_read_smc_sram_dword(hwmgr
,
2611 SMU7_FIRMWARE_HEADER_LOCATION
+
2612 offsetof(SMU73_Firmware_Header
, SoftRegisters
),
2616 data
->soft_regs_start
= tmp
;
2617 smu_data
->smu7_data
.soft_regs_start
= tmp
;
2620 error
|= (0 != result
);
2622 result
= smu7_read_smc_sram_dword(hwmgr
,
2623 SMU7_FIRMWARE_HEADER_LOCATION
+
2624 offsetof(SMU73_Firmware_Header
, mcRegisterTable
),
2628 smu_data
->smu7_data
.mc_reg_table_start
= tmp
;
2630 result
= smu7_read_smc_sram_dword(hwmgr
,
2631 SMU7_FIRMWARE_HEADER_LOCATION
+
2632 offsetof(SMU73_Firmware_Header
, FanTable
),
2636 smu_data
->smu7_data
.fan_table_start
= tmp
;
2638 error
|= (0 != result
);
2640 result
= smu7_read_smc_sram_dword(hwmgr
,
2641 SMU7_FIRMWARE_HEADER_LOCATION
+
2642 offsetof(SMU73_Firmware_Header
, mcArbDramTimingTable
),
2646 smu_data
->smu7_data
.arb_table_start
= tmp
;
2648 error
|= (0 != result
);
2650 result
= smu7_read_smc_sram_dword(hwmgr
,
2651 SMU7_FIRMWARE_HEADER_LOCATION
+
2652 offsetof(SMU73_Firmware_Header
, Version
),
2656 hwmgr
->microcode_version_info
.SMC
= tmp
;
2658 error
|= (0 != result
);
2660 return error
? -1 : 0;
2663 static int fiji_initialize_mc_reg_table(struct pp_hwmgr
*hwmgr
)
2666 /* Program additional LP registers
2667 * that are no longer programmed by VBIOS
2669 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING_LP
,
2670 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING
));
2671 cgs_write_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING_LP
,
2672 cgs_read_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING
));
2673 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2_LP
,
2674 cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2
));
2675 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1_LP
,
2676 cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1
));
2677 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0_LP
,
2678 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0
));
2679 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1_LP
,
2680 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1
));
2681 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING_LP
,
2682 cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING
));
2687 static bool fiji_is_dpm_running(struct pp_hwmgr
*hwmgr
)
2689 return (1 == PHM_READ_INDIRECT_FIELD(hwmgr
->device
,
2690 CGS_IND_REG__SMC
, FEATURE_STATUS
, VOLTAGE_CONTROLLER_ON
))
2694 static int fiji_populate_requested_graphic_levels(struct pp_hwmgr
*hwmgr
,
2695 struct amd_pp_profile
*request
)
2697 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)
2698 (hwmgr
->smu_backend
);
2699 struct SMU73_Discrete_GraphicsLevel
*levels
=
2700 smu_data
->smc_state_table
.GraphicsLevel
;
2701 uint32_t array
= smu_data
->smu7_data
.dpm_table_start
+
2702 offsetof(SMU73_Discrete_DpmTable
, GraphicsLevel
);
2703 uint32_t array_size
= sizeof(struct SMU73_Discrete_GraphicsLevel
) *
2704 SMU73_MAX_LEVELS_GRAPHICS
;
2707 for (i
= 0; i
< smu_data
->smc_state_table
.GraphicsDpmLevelCount
; i
++) {
2708 levels
[i
].ActivityLevel
=
2709 cpu_to_be16(request
->activity_threshold
);
2710 levels
[i
].EnabledForActivity
= 1;
2711 levels
[i
].UpHyst
= request
->up_hyst
;
2712 levels
[i
].DownHyst
= request
->down_hyst
;
2715 return smu7_copy_bytes_to_smc(hwmgr
, array
, (uint8_t *)levels
,
2716 array_size
, SMC_RAM_END
);
2719 const struct pp_smumgr_func fiji_smu_funcs
= {
2720 .smu_init
= &fiji_smu_init
,
2721 .smu_fini
= &smu7_smu_fini
,
2722 .start_smu
= &fiji_start_smu
,
2723 .check_fw_load_finish
= &smu7_check_fw_load_finish
,
2724 .request_smu_load_fw
= &smu7_reload_firmware
,
2725 .request_smu_load_specific_fw
= NULL
,
2726 .send_msg_to_smc
= &smu7_send_msg_to_smc
,
2727 .send_msg_to_smc_with_parameter
= &smu7_send_msg_to_smc_with_parameter
,
2728 .download_pptable_settings
= NULL
,
2729 .upload_pptable_settings
= NULL
,
2730 .update_smc_table
= fiji_update_smc_table
,
2731 .get_offsetof
= fiji_get_offsetof
,
2732 .process_firmware_header
= fiji_process_firmware_header
,
2733 .init_smc_table
= fiji_init_smc_table
,
2734 .update_sclk_threshold
= fiji_update_sclk_threshold
,
2735 .thermal_setup_fan_table
= fiji_thermal_setup_fan_table
,
2736 .thermal_avfs_enable
= fiji_thermal_avfs_enable
,
2737 .populate_all_graphic_levels
= fiji_populate_all_graphic_levels
,
2738 .populate_all_memory_levels
= fiji_populate_all_memory_levels
,
2739 .get_mac_definition
= fiji_get_mac_definition
,
2740 .initialize_mc_reg_table
= fiji_initialize_mc_reg_table
,
2741 .is_dpm_running
= fiji_is_dpm_running
,
2742 .populate_requested_graphic_levels
= fiji_populate_requested_graphic_levels
,
2743 .is_hw_avfs_present
= fiji_is_hw_avfs_present
,