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.
25 #include "smu7_dyn_defaults.h"
27 #include "smu7_hwmgr.h"
28 #include "hardwaremanager.h"
29 #include "ppatomctrl.h"
31 #include "cgs_common.h"
33 #include "fiji_smumgr.h"
34 #include "pppcielanes.h"
35 #include "smu7_ppsmc.h"
37 #include "smu/smu_7_1_3_d.h"
38 #include "smu/smu_7_1_3_sh_mask.h"
39 #include "gmc/gmc_8_1_d.h"
40 #include "gmc/gmc_8_1_sh_mask.h"
41 #include "bif/bif_5_0_d.h"
42 #include "bif/bif_5_0_sh_mask.h"
43 #include "dce/dce_10_0_d.h"
44 #include "dce/dce_10_0_sh_mask.h"
45 #include "smu7_smumgr.h"
47 #define VOLTAGE_SCALE 4
48 #define POWERTUNE_DEFAULT_SET_MAX 1
49 #define VOLTAGE_VID_OFFSET_SCALE1 625
50 #define VOLTAGE_VID_OFFSET_SCALE2 100
51 #define VDDC_VDDCI_DELTA 300
52 #define MC_CG_ARB_FREQ_F1 0x0b
54 /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs
55 * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ]
57 static const uint16_t fiji_clock_stretcher_lookup_table
[2][4] = {
58 {600, 1050, 3, 0}, {600, 1050, 6, 1} };
60 /* [FF, SS] type, [] 4 voltage ranges, and
61 * [Floor Freq, Boundary Freq, VID min , VID max]
63 static const uint32_t fiji_clock_stretcher_ddt_table
[2][4][4] = {
64 { {265, 529, 120, 128}, {325, 650, 96, 119}, {430, 860, 32, 95}, {0, 0, 0, 31} },
65 { {275, 550, 104, 112}, {319, 638, 96, 103}, {360, 720, 64, 95}, {384, 768, 32, 63} } };
67 /* [Use_For_Low_freq] value, [0%, 5%, 10%, 7.14%, 14.28%, 20%]
68 * (coming from PWR_CKS_CNTL.stretch_amount reg spec)
70 static const uint8_t fiji_clock_stretch_amount_conversion
[2][6] = {
71 {0, 1, 3, 2, 4, 5}, {0, 2, 4, 5, 6, 5} };
73 static const struct fiji_pt_defaults fiji_power_tune_data_set_array
[POWERTUNE_DEFAULT_SET_MAX
] = {
74 /*sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc */
76 /* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase */
80 /* PPGen has the gain setting generated in x * 100 unit
81 * This function is to convert the unit to x * 4096(0x1000) unit.
82 * This is the unit expected by SMC firmware
84 static int fiji_get_dependency_volt_by_clk(struct pp_hwmgr
*hwmgr
,
85 struct phm_ppt_v1_clock_voltage_dependency_table
*dep_table
,
86 uint32_t clock
, uint32_t *voltage
, uint32_t *mvdd
)
90 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
94 /* clock - voltage dependency table is empty table */
95 if (dep_table
->count
== 0)
98 for (i
= 0; i
< dep_table
->count
; i
++) {
99 /* find first sclk bigger than request */
100 if (dep_table
->entries
[i
].clk
>= clock
) {
101 *voltage
|= (dep_table
->entries
[i
].vddc
*
102 VOLTAGE_SCALE
) << VDDC_SHIFT
;
103 if (SMU7_VOLTAGE_CONTROL_NONE
== data
->vddci_control
)
104 *voltage
|= (data
->vbios_boot_state
.vddci_bootup_value
*
105 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
106 else if (dep_table
->entries
[i
].vddci
)
107 *voltage
|= (dep_table
->entries
[i
].vddci
*
108 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
110 vddci
= phm_find_closest_vddci(&(data
->vddci_voltage_table
),
111 (dep_table
->entries
[i
].vddc
-
113 *voltage
|= (vddci
* VOLTAGE_SCALE
) << VDDCI_SHIFT
;
116 if (SMU7_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
)
117 *mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
*
119 else if (dep_table
->entries
[i
].mvdd
)
120 *mvdd
= (uint32_t) dep_table
->entries
[i
].mvdd
*
123 *voltage
|= 1 << PHASES_SHIFT
;
128 /* sclk is bigger than max sclk in the dependence table */
129 *voltage
|= (dep_table
->entries
[i
- 1].vddc
* VOLTAGE_SCALE
) << VDDC_SHIFT
;
131 if (SMU7_VOLTAGE_CONTROL_NONE
== data
->vddci_control
)
132 *voltage
|= (data
->vbios_boot_state
.vddci_bootup_value
*
133 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
134 else if (dep_table
->entries
[i
-1].vddci
) {
135 vddci
= phm_find_closest_vddci(&(data
->vddci_voltage_table
),
136 (dep_table
->entries
[i
].vddc
-
138 *voltage
|= (vddci
* VOLTAGE_SCALE
) << VDDCI_SHIFT
;
141 if (SMU7_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
)
142 *mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
* VOLTAGE_SCALE
;
143 else if (dep_table
->entries
[i
].mvdd
)
144 *mvdd
= (uint32_t) dep_table
->entries
[i
- 1].mvdd
* VOLTAGE_SCALE
;
150 static uint16_t scale_fan_gain_settings(uint16_t raw_setting
)
153 tmp
= raw_setting
* 4096 / 100;
154 return (uint16_t)tmp
;
157 static void get_scl_sda_value(uint8_t line
, uint8_t *scl
, uint8_t *sda
)
160 case SMU7_I2CLineID_DDC1
:
161 *scl
= SMU7_I2C_DDC1CLK
;
162 *sda
= SMU7_I2C_DDC1DATA
;
164 case SMU7_I2CLineID_DDC2
:
165 *scl
= SMU7_I2C_DDC2CLK
;
166 *sda
= SMU7_I2C_DDC2DATA
;
168 case SMU7_I2CLineID_DDC3
:
169 *scl
= SMU7_I2C_DDC3CLK
;
170 *sda
= SMU7_I2C_DDC3DATA
;
172 case SMU7_I2CLineID_DDC4
:
173 *scl
= SMU7_I2C_DDC4CLK
;
174 *sda
= SMU7_I2C_DDC4DATA
;
176 case SMU7_I2CLineID_DDC5
:
177 *scl
= SMU7_I2C_DDC5CLK
;
178 *sda
= SMU7_I2C_DDC5DATA
;
180 case SMU7_I2CLineID_DDC6
:
181 *scl
= SMU7_I2C_DDC6CLK
;
182 *sda
= SMU7_I2C_DDC6DATA
;
184 case SMU7_I2CLineID_SCLSDA
:
188 case SMU7_I2CLineID_DDCVGA
:
189 *scl
= SMU7_I2C_DDCVGACLK
;
190 *sda
= SMU7_I2C_DDCVGADATA
;
199 static void fiji_initialize_power_tune_defaults(struct pp_hwmgr
*hwmgr
)
201 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
202 struct phm_ppt_v1_information
*table_info
=
203 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
206 table_info
->cac_dtp_table
->usPowerTuneDataSetID
<= POWERTUNE_DEFAULT_SET_MAX
&&
207 table_info
->cac_dtp_table
->usPowerTuneDataSetID
)
208 smu_data
->power_tune_defaults
=
209 &fiji_power_tune_data_set_array
210 [table_info
->cac_dtp_table
->usPowerTuneDataSetID
- 1];
212 smu_data
->power_tune_defaults
= &fiji_power_tune_data_set_array
[0];
216 static int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr
*hwmgr
)
219 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
220 const struct fiji_pt_defaults
*defaults
= smu_data
->power_tune_defaults
;
222 SMU73_Discrete_DpmTable
*dpm_table
= &(smu_data
->smc_state_table
);
224 struct phm_ppt_v1_information
*table_info
=
225 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
226 struct phm_cac_tdp_table
*cac_dtp_table
= table_info
->cac_dtp_table
;
227 struct pp_advance_fan_control_parameters
*fan_table
=
228 &hwmgr
->thermal_controller
.advanceFanControlParameters
;
229 uint8_t uc_scl
, uc_sda
;
231 /* TDP number of fraction bits are changed from 8 to 7 for Fiji
232 * as requested by SMC team
234 dpm_table
->DefaultTdp
= PP_HOST_TO_SMC_US(
235 (uint16_t)(cac_dtp_table
->usTDP
* 128));
236 dpm_table
->TargetTdp
= PP_HOST_TO_SMC_US(
237 (uint16_t)(cac_dtp_table
->usTDP
* 128));
239 PP_ASSERT_WITH_CODE(cac_dtp_table
->usTargetOperatingTemp
<= 255,
240 "Target Operating Temp is out of Range!",
243 dpm_table
->GpuTjMax
= (uint8_t)(cac_dtp_table
->usTargetOperatingTemp
);
244 dpm_table
->GpuTjHyst
= 8;
246 dpm_table
->DTEAmbientTempBase
= defaults
->DTEAmbientTempBase
;
248 /* The following are for new Fiji Multi-input fan/thermal control */
249 dpm_table
->TemperatureLimitEdge
= PP_HOST_TO_SMC_US(
250 cac_dtp_table
->usTargetOperatingTemp
* 256);
251 dpm_table
->TemperatureLimitHotspot
= PP_HOST_TO_SMC_US(
252 cac_dtp_table
->usTemperatureLimitHotspot
* 256);
253 dpm_table
->TemperatureLimitLiquid1
= PP_HOST_TO_SMC_US(
254 cac_dtp_table
->usTemperatureLimitLiquid1
* 256);
255 dpm_table
->TemperatureLimitLiquid2
= PP_HOST_TO_SMC_US(
256 cac_dtp_table
->usTemperatureLimitLiquid2
* 256);
257 dpm_table
->TemperatureLimitVrVddc
= PP_HOST_TO_SMC_US(
258 cac_dtp_table
->usTemperatureLimitVrVddc
* 256);
259 dpm_table
->TemperatureLimitVrMvdd
= PP_HOST_TO_SMC_US(
260 cac_dtp_table
->usTemperatureLimitVrMvdd
* 256);
261 dpm_table
->TemperatureLimitPlx
= PP_HOST_TO_SMC_US(
262 cac_dtp_table
->usTemperatureLimitPlx
* 256);
264 dpm_table
->FanGainEdge
= PP_HOST_TO_SMC_US(
265 scale_fan_gain_settings(fan_table
->usFanGainEdge
));
266 dpm_table
->FanGainHotspot
= PP_HOST_TO_SMC_US(
267 scale_fan_gain_settings(fan_table
->usFanGainHotspot
));
268 dpm_table
->FanGainLiquid
= PP_HOST_TO_SMC_US(
269 scale_fan_gain_settings(fan_table
->usFanGainLiquid
));
270 dpm_table
->FanGainVrVddc
= PP_HOST_TO_SMC_US(
271 scale_fan_gain_settings(fan_table
->usFanGainVrVddc
));
272 dpm_table
->FanGainVrMvdd
= PP_HOST_TO_SMC_US(
273 scale_fan_gain_settings(fan_table
->usFanGainVrMvdd
));
274 dpm_table
->FanGainPlx
= PP_HOST_TO_SMC_US(
275 scale_fan_gain_settings(fan_table
->usFanGainPlx
));
276 dpm_table
->FanGainHbm
= PP_HOST_TO_SMC_US(
277 scale_fan_gain_settings(fan_table
->usFanGainHbm
));
279 dpm_table
->Liquid1_I2C_address
= cac_dtp_table
->ucLiquid1_I2C_address
;
280 dpm_table
->Liquid2_I2C_address
= cac_dtp_table
->ucLiquid2_I2C_address
;
281 dpm_table
->Vr_I2C_address
= cac_dtp_table
->ucVr_I2C_address
;
282 dpm_table
->Plx_I2C_address
= cac_dtp_table
->ucPlx_I2C_address
;
284 get_scl_sda_value(cac_dtp_table
->ucLiquid_I2C_Line
, &uc_scl
, &uc_sda
);
285 dpm_table
->Liquid_I2C_LineSCL
= uc_scl
;
286 dpm_table
->Liquid_I2C_LineSDA
= uc_sda
;
288 get_scl_sda_value(cac_dtp_table
->ucVr_I2C_Line
, &uc_scl
, &uc_sda
);
289 dpm_table
->Vr_I2C_LineSCL
= uc_scl
;
290 dpm_table
->Vr_I2C_LineSDA
= uc_sda
;
292 get_scl_sda_value(cac_dtp_table
->ucPlx_I2C_Line
, &uc_scl
, &uc_sda
);
293 dpm_table
->Plx_I2C_LineSCL
= uc_scl
;
294 dpm_table
->Plx_I2C_LineSDA
= uc_sda
;
300 static int fiji_populate_svi_load_line(struct pp_hwmgr
*hwmgr
)
302 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
303 const struct fiji_pt_defaults
*defaults
= smu_data
->power_tune_defaults
;
305 smu_data
->power_tune_table
.SviLoadLineEn
= defaults
->SviLoadLineEn
;
306 smu_data
->power_tune_table
.SviLoadLineVddC
= defaults
->SviLoadLineVddC
;
307 smu_data
->power_tune_table
.SviLoadLineTrimVddC
= 3;
308 smu_data
->power_tune_table
.SviLoadLineOffsetVddC
= 0;
314 static int fiji_populate_tdc_limit(struct pp_hwmgr
*hwmgr
)
317 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
318 struct phm_ppt_v1_information
*table_info
=
319 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
320 const struct fiji_pt_defaults
*defaults
= smu_data
->power_tune_defaults
;
322 /* TDC number of fraction bits are changed from 8 to 7
323 * for Fiji as requested by SMC team
325 tdc_limit
= (uint16_t)(table_info
->cac_dtp_table
->usTDC
* 128);
326 smu_data
->power_tune_table
.TDC_VDDC_PkgLimit
=
327 CONVERT_FROM_HOST_TO_SMC_US(tdc_limit
);
328 smu_data
->power_tune_table
.TDC_VDDC_ThrottleReleaseLimitPerc
=
329 defaults
->TDC_VDDC_ThrottleReleaseLimitPerc
;
330 smu_data
->power_tune_table
.TDC_MAWt
= defaults
->TDC_MAWt
;
335 static int fiji_populate_dw8(struct pp_hwmgr
*hwmgr
, uint32_t fuse_table_offset
)
337 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
338 const struct fiji_pt_defaults
*defaults
= smu_data
->power_tune_defaults
;
341 if (smu7_read_smc_sram_dword(hwmgr
->smumgr
,
343 offsetof(SMU73_Discrete_PmFuses
, TdcWaterfallCtl
),
344 (uint32_t *)&temp
, SMC_RAM_END
))
345 PP_ASSERT_WITH_CODE(false,
346 "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
349 smu_data
->power_tune_table
.TdcWaterfallCtl
= defaults
->TdcWaterfallCtl
;
350 smu_data
->power_tune_table
.LPMLTemperatureMin
=
351 (uint8_t)((temp
>> 16) & 0xff);
352 smu_data
->power_tune_table
.LPMLTemperatureMax
=
353 (uint8_t)((temp
>> 8) & 0xff);
354 smu_data
->power_tune_table
.Reserved
= (uint8_t)(temp
& 0xff);
359 static int fiji_populate_temperature_scaler(struct pp_hwmgr
*hwmgr
)
362 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
364 /* Currently not used. Set all to zero. */
365 for (i
= 0; i
< 16; i
++)
366 smu_data
->power_tune_table
.LPMLTemperatureScaler
[i
] = 0;
371 static int fiji_populate_fuzzy_fan(struct pp_hwmgr
*hwmgr
)
373 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
375 if ((hwmgr
->thermal_controller
.advanceFanControlParameters
.
376 usFanOutputSensitivity
& (1 << 15)) ||
377 0 == hwmgr
->thermal_controller
.advanceFanControlParameters
.
378 usFanOutputSensitivity
)
379 hwmgr
->thermal_controller
.advanceFanControlParameters
.
380 usFanOutputSensitivity
= hwmgr
->thermal_controller
.
381 advanceFanControlParameters
.usDefaultFanOutputSensitivity
;
383 smu_data
->power_tune_table
.FuzzyFan_PwmSetDelta
=
384 PP_HOST_TO_SMC_US(hwmgr
->thermal_controller
.
385 advanceFanControlParameters
.usFanOutputSensitivity
);
389 static int fiji_populate_gnb_lpml(struct pp_hwmgr
*hwmgr
)
392 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
394 /* Currently not used. Set all to zero. */
395 for (i
= 0; i
< 16; i
++)
396 smu_data
->power_tune_table
.GnbLPML
[i
] = 0;
401 static int fiji_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr
*hwmgr
)
406 static int fiji_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr
*hwmgr
)
408 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
409 struct phm_ppt_v1_information
*table_info
=
410 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
411 uint16_t HiSidd
= smu_data
->power_tune_table
.BapmVddCBaseLeakageHiSidd
;
412 uint16_t LoSidd
= smu_data
->power_tune_table
.BapmVddCBaseLeakageLoSidd
;
413 struct phm_cac_tdp_table
*cac_table
= table_info
->cac_dtp_table
;
415 HiSidd
= (uint16_t)(cac_table
->usHighCACLeakage
/ 100 * 256);
416 LoSidd
= (uint16_t)(cac_table
->usLowCACLeakage
/ 100 * 256);
418 smu_data
->power_tune_table
.BapmVddCBaseLeakageHiSidd
=
419 CONVERT_FROM_HOST_TO_SMC_US(HiSidd
);
420 smu_data
->power_tune_table
.BapmVddCBaseLeakageLoSidd
=
421 CONVERT_FROM_HOST_TO_SMC_US(LoSidd
);
426 static int fiji_populate_pm_fuses(struct pp_hwmgr
*hwmgr
)
428 uint32_t pm_fuse_table_offset
;
429 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
431 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
432 PHM_PlatformCaps_PowerContainment
)) {
433 if (smu7_read_smc_sram_dword(hwmgr
->smumgr
,
434 SMU7_FIRMWARE_HEADER_LOCATION
+
435 offsetof(SMU73_Firmware_Header
, PmFuseTable
),
436 &pm_fuse_table_offset
, SMC_RAM_END
))
437 PP_ASSERT_WITH_CODE(false,
438 "Attempt to get pm_fuse_table_offset Failed!",
442 if (fiji_populate_svi_load_line(hwmgr
))
443 PP_ASSERT_WITH_CODE(false,
444 "Attempt to populate SviLoadLine Failed!",
447 if (fiji_populate_tdc_limit(hwmgr
))
448 PP_ASSERT_WITH_CODE(false,
449 "Attempt to populate TDCLimit Failed!", return -EINVAL
);
451 if (fiji_populate_dw8(hwmgr
, pm_fuse_table_offset
))
452 PP_ASSERT_WITH_CODE(false,
453 "Attempt to populate TdcWaterfallCtl, "
454 "LPMLTemperature Min and Max Failed!",
458 if (0 != fiji_populate_temperature_scaler(hwmgr
))
459 PP_ASSERT_WITH_CODE(false,
460 "Attempt to populate LPMLTemperatureScaler Failed!",
464 if (fiji_populate_fuzzy_fan(hwmgr
))
465 PP_ASSERT_WITH_CODE(false,
466 "Attempt to populate Fuzzy Fan Control parameters Failed!",
470 if (fiji_populate_gnb_lpml(hwmgr
))
471 PP_ASSERT_WITH_CODE(false,
472 "Attempt to populate GnbLPML Failed!",
476 if (fiji_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr
))
477 PP_ASSERT_WITH_CODE(false,
478 "Attempt to populate GnbLPML Min and Max Vid Failed!",
482 if (fiji_populate_bapm_vddc_base_leakage_sidd(hwmgr
))
483 PP_ASSERT_WITH_CODE(false,
484 "Attempt to populate BapmVddCBaseLeakage Hi and Lo "
485 "Sidd Failed!", return -EINVAL
);
487 if (smu7_copy_bytes_to_smc(hwmgr
->smumgr
, pm_fuse_table_offset
,
488 (uint8_t *)&smu_data
->power_tune_table
,
489 sizeof(struct SMU73_Discrete_PmFuses
), SMC_RAM_END
))
490 PP_ASSERT_WITH_CODE(false,
491 "Attempt to download PmFuseTable Failed!",
498 * Preparation of vddc and vddgfx CAC tables for SMC.
500 * @param hwmgr the address of the hardware manager
501 * @param table the SMC DPM table structure to be populated
504 static int fiji_populate_cac_table(struct pp_hwmgr
*hwmgr
,
505 struct SMU73_Discrete_DpmTable
*table
)
509 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
510 struct phm_ppt_v1_information
*table_info
=
511 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
512 struct phm_ppt_v1_voltage_lookup_table
*lookup_table
=
513 table_info
->vddc_lookup_table
;
514 /* tables is already swapped, so in order to use the value from it,
515 * we need to swap it back.
516 * We are populating vddc CAC data to BapmVddc table
517 * in split and merged mode
520 for (count
= 0; count
< lookup_table
->count
; count
++) {
521 index
= phm_get_voltage_index(lookup_table
,
522 data
->vddc_voltage_table
.entries
[count
].value
);
523 table
->BapmVddcVidLoSidd
[count
] =
524 convert_to_vid(lookup_table
->entries
[index
].us_cac_low
);
525 table
->BapmVddcVidHiSidd
[count
] =
526 convert_to_vid(lookup_table
->entries
[index
].us_cac_high
);
533 * Preparation of voltage tables for SMC.
535 * @param hwmgr the address of the hardware manager
536 * @param table the SMC DPM table structure to be populated
540 static int fiji_populate_smc_voltage_tables(struct pp_hwmgr
*hwmgr
,
541 struct SMU73_Discrete_DpmTable
*table
)
545 result
= fiji_populate_cac_table(hwmgr
, table
);
546 PP_ASSERT_WITH_CODE(0 == result
,
547 "can not populate CAC voltage tables to SMC",
553 static int fiji_populate_ulv_level(struct pp_hwmgr
*hwmgr
,
554 struct SMU73_Discrete_Ulv
*state
)
558 struct phm_ppt_v1_information
*table_info
=
559 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
561 state
->CcPwrDynRm
= 0;
562 state
->CcPwrDynRm1
= 0;
564 state
->VddcOffset
= (uint16_t) table_info
->us_ulv_voltage_offset
;
565 state
->VddcOffsetVid
= (uint8_t)(table_info
->us_ulv_voltage_offset
*
566 VOLTAGE_VID_OFFSET_SCALE2
/ VOLTAGE_VID_OFFSET_SCALE1
);
568 state
->VddcPhase
= 1;
571 CONVERT_FROM_HOST_TO_SMC_UL(state
->CcPwrDynRm
);
572 CONVERT_FROM_HOST_TO_SMC_UL(state
->CcPwrDynRm1
);
573 CONVERT_FROM_HOST_TO_SMC_US(state
->VddcOffset
);
578 static int fiji_populate_ulv_state(struct pp_hwmgr
*hwmgr
,
579 struct SMU73_Discrete_DpmTable
*table
)
581 return fiji_populate_ulv_level(hwmgr
, &table
->Ulv
);
584 static int fiji_populate_smc_link_level(struct pp_hwmgr
*hwmgr
,
585 struct SMU73_Discrete_DpmTable
*table
)
587 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
588 struct smu7_dpm_table
*dpm_table
= &data
->dpm_table
;
589 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
592 /* Index (dpm_table->pcie_speed_table.count)
593 * is reserved for PCIE boot level. */
594 for (i
= 0; i
<= dpm_table
->pcie_speed_table
.count
; i
++) {
595 table
->LinkLevel
[i
].PcieGenSpeed
=
596 (uint8_t)dpm_table
->pcie_speed_table
.dpm_levels
[i
].value
;
597 table
->LinkLevel
[i
].PcieLaneCount
= (uint8_t)encode_pcie_lane_width(
598 dpm_table
->pcie_speed_table
.dpm_levels
[i
].param1
);
599 table
->LinkLevel
[i
].EnabledForActivity
= 1;
600 table
->LinkLevel
[i
].SPC
= (uint8_t)(data
->pcie_spc_cap
& 0xff);
601 table
->LinkLevel
[i
].DownThreshold
= PP_HOST_TO_SMC_UL(5);
602 table
->LinkLevel
[i
].UpThreshold
= PP_HOST_TO_SMC_UL(30);
605 smu_data
->smc_state_table
.LinkLevelCount
=
606 (uint8_t)dpm_table
->pcie_speed_table
.count
;
607 data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
=
608 phm_get_dpm_level_enable_mask_value(&dpm_table
->pcie_speed_table
);
615 * Calculates the SCLK dividers using the provided engine clock
617 * @param hwmgr the address of the hardware manager
618 * @param clock the engine clock to use to populate the structure
619 * @param sclk the SMC SCLK structure to be populated
621 static int fiji_calculate_sclk_params(struct pp_hwmgr
*hwmgr
,
622 uint32_t clock
, struct SMU73_Discrete_GraphicsLevel
*sclk
)
624 const struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
625 struct pp_atomctrl_clock_dividers_vi dividers
;
626 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
627 uint32_t spll_func_cntl_3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
628 uint32_t spll_func_cntl_4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
629 uint32_t cg_spll_spread_spectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
630 uint32_t cg_spll_spread_spectrum_2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
632 uint32_t ref_divider
;
636 /* get the engine clock dividers for this clock value */
637 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
, clock
, ÷rs
);
639 PP_ASSERT_WITH_CODE(result
== 0,
640 "Error retrieving Engine Clock dividers from VBIOS.",
643 /* To get FBDIV we need to multiply this by 16384 and divide it by Fref. */
644 ref_clock
= atomctrl_get_reference_clock(hwmgr
);
645 ref_divider
= 1 + dividers
.uc_pll_ref_div
;
647 /* low 14 bits is fraction and high 12 bits is divider */
648 fbdiv
= dividers
.ul_fb_div
.ul_fb_divider
& 0x3FFFFFF;
650 /* SPLL_FUNC_CNTL setup */
651 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
652 SPLL_REF_DIV
, dividers
.uc_pll_ref_div
);
653 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
654 SPLL_PDIV_A
, dividers
.uc_pll_post_div
);
656 /* SPLL_FUNC_CNTL_3 setup*/
657 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
, CG_SPLL_FUNC_CNTL_3
,
660 /* set to use fractional accumulation*/
661 spll_func_cntl_3
= PHM_SET_FIELD(spll_func_cntl_3
, CG_SPLL_FUNC_CNTL_3
,
664 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
665 PHM_PlatformCaps_EngineSpreadSpectrumSupport
)) {
666 struct pp_atomctrl_internal_ss_info ssInfo
;
668 uint32_t vco_freq
= clock
* dividers
.uc_pll_post_div
;
669 if (!atomctrl_get_engine_clock_spread_spectrum(hwmgr
,
670 vco_freq
, &ssInfo
)) {
672 * ss_info.speed_spectrum_percentage -- in unit of 0.01%
673 * ss_info.speed_spectrum_rate -- in unit of khz
675 * clks = reference_clock * 10 / (REFDIV + 1) / speed_spectrum_rate / 2
677 uint32_t clk_s
= ref_clock
* 5 /
678 (ref_divider
* ssInfo
.speed_spectrum_rate
);
679 /* clkv = 2 * D * fbdiv / NS */
680 uint32_t clk_v
= 4 * ssInfo
.speed_spectrum_percentage
*
681 fbdiv
/ (clk_s
* 10000);
683 cg_spll_spread_spectrum
= PHM_SET_FIELD(cg_spll_spread_spectrum
,
684 CG_SPLL_SPREAD_SPECTRUM
, CLKS
, clk_s
);
685 cg_spll_spread_spectrum
= PHM_SET_FIELD(cg_spll_spread_spectrum
,
686 CG_SPLL_SPREAD_SPECTRUM
, SSEN
, 1);
687 cg_spll_spread_spectrum_2
= PHM_SET_FIELD(cg_spll_spread_spectrum_2
,
688 CG_SPLL_SPREAD_SPECTRUM_2
, CLKV
, clk_v
);
692 sclk
->SclkFrequency
= clock
;
693 sclk
->CgSpllFuncCntl3
= spll_func_cntl_3
;
694 sclk
->CgSpllFuncCntl4
= spll_func_cntl_4
;
695 sclk
->SpllSpreadSpectrum
= cg_spll_spread_spectrum
;
696 sclk
->SpllSpreadSpectrum2
= cg_spll_spread_spectrum_2
;
697 sclk
->SclkDid
= (uint8_t)dividers
.pll_post_divider
;
703 * Populates single SMC SCLK structure using the provided engine clock
705 * @param hwmgr the address of the hardware manager
706 * @param clock the engine clock to use to populate the structure
707 * @param sclk the SMC SCLK structure to be populated
710 static int fiji_populate_single_graphic_level(struct pp_hwmgr
*hwmgr
,
711 uint32_t clock
, uint16_t sclk_al_threshold
,
712 struct SMU73_Discrete_GraphicsLevel
*level
)
715 /* PP_Clocks minClocks; */
716 uint32_t threshold
, mvdd
;
717 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
718 struct phm_ppt_v1_information
*table_info
=
719 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
721 result
= fiji_calculate_sclk_params(hwmgr
, clock
, level
);
723 /* populate graphics levels */
724 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
725 table_info
->vdd_dep_on_sclk
, clock
,
726 (uint32_t *)(&level
->MinVoltage
), &mvdd
);
727 PP_ASSERT_WITH_CODE((0 == result
),
728 "can not find VDDC voltage value for "
729 "VDDC engine clock dependency table",
732 level
->SclkFrequency
= clock
;
733 level
->ActivityLevel
= sclk_al_threshold
;
734 level
->CcPwrDynRm
= 0;
735 level
->CcPwrDynRm1
= 0;
736 level
->EnabledForActivity
= 0;
737 level
->EnabledForThrottle
= 1;
740 level
->VoltageDownHyst
= 0;
741 level
->PowerThrottle
= 0;
743 threshold
= clock
* data
->fast_watermark_threshold
/ 100;
745 data
->display_timing
.min_clock_in_sr
= hwmgr
->display_config
.min_core_set_clock_in_sr
;
747 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_SclkDeepSleep
))
748 level
->DeepSleepDivId
= smu7_get_sleep_divider_id_from_clock(clock
,
749 hwmgr
->display_config
.min_core_set_clock_in_sr
);
752 /* Default to slow, highest DPM level will be
753 * set to PPSMC_DISPLAY_WATERMARK_LOW later.
755 level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
757 CONVERT_FROM_HOST_TO_SMC_UL(level
->MinVoltage
);
758 CONVERT_FROM_HOST_TO_SMC_UL(level
->SclkFrequency
);
759 CONVERT_FROM_HOST_TO_SMC_US(level
->ActivityLevel
);
760 CONVERT_FROM_HOST_TO_SMC_UL(level
->CgSpllFuncCntl3
);
761 CONVERT_FROM_HOST_TO_SMC_UL(level
->CgSpllFuncCntl4
);
762 CONVERT_FROM_HOST_TO_SMC_UL(level
->SpllSpreadSpectrum
);
763 CONVERT_FROM_HOST_TO_SMC_UL(level
->SpllSpreadSpectrum2
);
764 CONVERT_FROM_HOST_TO_SMC_UL(level
->CcPwrDynRm
);
765 CONVERT_FROM_HOST_TO_SMC_UL(level
->CcPwrDynRm1
);
770 * Populates all SMC SCLK levels' structure based on the trimmed allowed dpm engine clock states
772 * @param hwmgr the address of the hardware manager
774 int fiji_populate_all_graphic_levels(struct pp_hwmgr
*hwmgr
)
776 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
777 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
779 struct smu7_dpm_table
*dpm_table
= &data
->dpm_table
;
780 struct phm_ppt_v1_information
*table_info
=
781 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
782 struct phm_ppt_v1_pcie_table
*pcie_table
= table_info
->pcie_table
;
783 uint8_t pcie_entry_cnt
= (uint8_t) data
->dpm_table
.pcie_speed_table
.count
;
785 uint32_t array
= smu_data
->smu7_data
.dpm_table_start
+
786 offsetof(SMU73_Discrete_DpmTable
, GraphicsLevel
);
787 uint32_t array_size
= sizeof(struct SMU73_Discrete_GraphicsLevel
) *
788 SMU73_MAX_LEVELS_GRAPHICS
;
789 struct SMU73_Discrete_GraphicsLevel
*levels
=
790 smu_data
->smc_state_table
.GraphicsLevel
;
791 uint32_t i
, max_entry
;
792 uint8_t hightest_pcie_level_enabled
= 0,
793 lowest_pcie_level_enabled
= 0,
794 mid_pcie_level_enabled
= 0,
797 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++) {
798 result
= fiji_populate_single_graphic_level(hwmgr
,
799 dpm_table
->sclk_table
.dpm_levels
[i
].value
,
800 (uint16_t)smu_data
->activity_target
[i
],
805 /* Making sure only DPM level 0-1 have Deep Sleep Div ID populated. */
807 levels
[i
].DeepSleepDivId
= 0;
810 /* Only enable level 0 for now.*/
811 levels
[0].EnabledForActivity
= 1;
813 /* set highest level watermark to high */
814 levels
[dpm_table
->sclk_table
.count
- 1].DisplayWatermark
=
815 PPSMC_DISPLAY_WATERMARK_HIGH
;
817 smu_data
->smc_state_table
.GraphicsDpmLevelCount
=
818 (uint8_t)dpm_table
->sclk_table
.count
;
819 data
->dpm_level_enable_mask
.sclk_dpm_enable_mask
=
820 phm_get_dpm_level_enable_mask_value(&dpm_table
->sclk_table
);
822 if (pcie_table
!= NULL
) {
823 PP_ASSERT_WITH_CODE((1 <= pcie_entry_cnt
),
824 "There must be 1 or more PCIE levels defined in PPTable.",
826 max_entry
= pcie_entry_cnt
- 1;
827 for (i
= 0; i
< dpm_table
->sclk_table
.count
; i
++)
828 levels
[i
].pcieDpmLevel
=
829 (uint8_t) ((i
< max_entry
) ? i
: max_entry
);
831 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
832 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
833 (1 << (hightest_pcie_level_enabled
+ 1))) != 0))
834 hightest_pcie_level_enabled
++;
836 while (data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&&
837 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
838 (1 << lowest_pcie_level_enabled
)) == 0))
839 lowest_pcie_level_enabled
++;
841 while ((count
< hightest_pcie_level_enabled
) &&
842 ((data
->dpm_level_enable_mask
.pcie_dpm_enable_mask
&
843 (1 << (lowest_pcie_level_enabled
+ 1 + count
))) == 0))
846 mid_pcie_level_enabled
= (lowest_pcie_level_enabled
+ 1 + count
) <
847 hightest_pcie_level_enabled
?
848 (lowest_pcie_level_enabled
+ 1 + count
) :
849 hightest_pcie_level_enabled
;
851 /* set pcieDpmLevel to hightest_pcie_level_enabled */
852 for (i
= 2; i
< dpm_table
->sclk_table
.count
; i
++)
853 levels
[i
].pcieDpmLevel
= hightest_pcie_level_enabled
;
855 /* set pcieDpmLevel to lowest_pcie_level_enabled */
856 levels
[0].pcieDpmLevel
= lowest_pcie_level_enabled
;
858 /* set pcieDpmLevel to mid_pcie_level_enabled */
859 levels
[1].pcieDpmLevel
= mid_pcie_level_enabled
;
861 /* level count will send to smc once at init smc table and never change */
862 result
= smu7_copy_bytes_to_smc(hwmgr
->smumgr
, array
, (uint8_t *)levels
,
863 (uint32_t)array_size
, SMC_RAM_END
);
870 * MCLK Frequency Ratio
871 * SEQ_CG_RESP Bit[31:24] - 0x0
872 * Bit[27:24] \96 DDR3 Frequency ratio
873 * 0x0 <= 100MHz, 450 < 0x8 <= 500MHz
874 * 100 < 0x1 <= 150MHz, 500 < 0x9 <= 550MHz
875 * 150 < 0x2 <= 200MHz, 550 < 0xA <= 600MHz
876 * 200 < 0x3 <= 250MHz, 600 < 0xB <= 650MHz
877 * 250 < 0x4 <= 300MHz, 650 < 0xC <= 700MHz
878 * 300 < 0x5 <= 350MHz, 700 < 0xD <= 750MHz
879 * 350 < 0x6 <= 400MHz, 750 < 0xE <= 800MHz
880 * 400 < 0x7 <= 450MHz, 800 < 0xF
882 static uint8_t fiji_get_mclk_frequency_ratio(uint32_t mem_clock
)
884 if (mem_clock
<= 10000)
886 if (mem_clock
<= 15000)
888 if (mem_clock
<= 20000)
890 if (mem_clock
<= 25000)
892 if (mem_clock
<= 30000)
894 if (mem_clock
<= 35000)
896 if (mem_clock
<= 40000)
898 if (mem_clock
<= 45000)
900 if (mem_clock
<= 50000)
902 if (mem_clock
<= 55000)
904 if (mem_clock
<= 60000)
906 if (mem_clock
<= 65000)
908 if (mem_clock
<= 70000)
910 if (mem_clock
<= 75000)
912 if (mem_clock
<= 80000)
914 /* mem_clock > 800MHz */
919 * Populates the SMC MCLK structure using the provided memory clock
921 * @param hwmgr the address of the hardware manager
922 * @param clock the memory clock to use to populate the structure
923 * @param sclk the SMC SCLK structure to be populated
925 static int fiji_calculate_mclk_params(struct pp_hwmgr
*hwmgr
,
926 uint32_t clock
, struct SMU73_Discrete_MemoryLevel
*mclk
)
928 struct pp_atomctrl_memory_clock_param mem_param
;
931 result
= atomctrl_get_memory_pll_dividers_vi(hwmgr
, clock
, &mem_param
);
932 PP_ASSERT_WITH_CODE((0 == result
),
933 "Failed to get Memory PLL Dividers.",
936 /* Save the result data to outpupt memory level structure */
937 mclk
->MclkFrequency
= clock
;
938 mclk
->MclkDivider
= (uint8_t)mem_param
.mpll_post_divider
;
939 mclk
->FreqRange
= fiji_get_mclk_frequency_ratio(clock
);
944 static int fiji_populate_single_memory_level(struct pp_hwmgr
*hwmgr
,
945 uint32_t clock
, struct SMU73_Discrete_MemoryLevel
*mem_level
)
947 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
948 struct phm_ppt_v1_information
*table_info
=
949 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
951 uint32_t mclk_stutter_mode_threshold
= 60000;
953 if (table_info
->vdd_dep_on_mclk
) {
954 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
955 table_info
->vdd_dep_on_mclk
, clock
,
956 (uint32_t *)(&mem_level
->MinVoltage
), &mem_level
->MinMvdd
);
957 PP_ASSERT_WITH_CODE((0 == result
),
958 "can not find MinVddc voltage value from memory "
959 "VDDC voltage dependency table", return result
);
962 mem_level
->EnabledForThrottle
= 1;
963 mem_level
->EnabledForActivity
= 0;
964 mem_level
->UpHyst
= 0;
965 mem_level
->DownHyst
= 100;
966 mem_level
->VoltageDownHyst
= 0;
967 mem_level
->ActivityLevel
= (uint16_t)data
->mclk_activity_target
;
968 mem_level
->StutterEnable
= false;
970 mem_level
->DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
972 /* enable stutter mode if all the follow condition applied
973 * PECI_GetNumberOfActiveDisplays(hwmgr->pPECI,
974 * &(data->DisplayTiming.numExistingDisplays));
976 data
->display_timing
.num_existing_displays
= 1;
978 if (mclk_stutter_mode_threshold
&&
979 (clock
<= mclk_stutter_mode_threshold
) &&
980 (!data
->is_uvd_enabled
) &&
981 (PHM_READ_FIELD(hwmgr
->device
, DPG_PIPE_STUTTER_CONTROL
,
982 STUTTER_ENABLE
) & 0x1))
983 mem_level
->StutterEnable
= true;
985 result
= fiji_calculate_mclk_params(hwmgr
, clock
, mem_level
);
987 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MinMvdd
);
988 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MclkFrequency
);
989 CONVERT_FROM_HOST_TO_SMC_US(mem_level
->ActivityLevel
);
990 CONVERT_FROM_HOST_TO_SMC_UL(mem_level
->MinVoltage
);
996 * Populates all SMC MCLK levels' structure based on the trimmed allowed dpm memory clock states
998 * @param hwmgr the address of the hardware manager
1000 int fiji_populate_all_memory_levels(struct pp_hwmgr
*hwmgr
)
1002 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1003 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
1004 struct smu7_dpm_table
*dpm_table
= &data
->dpm_table
;
1006 /* populate MCLK dpm table to SMU7 */
1007 uint32_t array
= smu_data
->smu7_data
.dpm_table_start
+
1008 offsetof(SMU73_Discrete_DpmTable
, MemoryLevel
);
1009 uint32_t array_size
= sizeof(SMU73_Discrete_MemoryLevel
) *
1010 SMU73_MAX_LEVELS_MEMORY
;
1011 struct SMU73_Discrete_MemoryLevel
*levels
=
1012 smu_data
->smc_state_table
.MemoryLevel
;
1015 for (i
= 0; i
< dpm_table
->mclk_table
.count
; i
++) {
1016 PP_ASSERT_WITH_CODE((0 != dpm_table
->mclk_table
.dpm_levels
[i
].value
),
1017 "can not populate memory level as memory clock is zero",
1019 result
= fiji_populate_single_memory_level(hwmgr
,
1020 dpm_table
->mclk_table
.dpm_levels
[i
].value
,
1026 /* Only enable level 0 for now. */
1027 levels
[0].EnabledForActivity
= 1;
1029 /* in order to prevent MC activity from stutter mode to push DPM up.
1030 * the UVD change complements this by putting the MCLK in
1031 * a higher state by default such that we are not effected by
1032 * up threshold or and MCLK DPM latency.
1034 levels
[0].ActivityLevel
= (uint16_t)data
->mclk_dpm0_activity_target
;
1035 CONVERT_FROM_HOST_TO_SMC_US(levels
[0].ActivityLevel
);
1037 smu_data
->smc_state_table
.MemoryDpmLevelCount
=
1038 (uint8_t)dpm_table
->mclk_table
.count
;
1039 data
->dpm_level_enable_mask
.mclk_dpm_enable_mask
=
1040 phm_get_dpm_level_enable_mask_value(&dpm_table
->mclk_table
);
1041 /* set highest level watermark to high */
1042 levels
[dpm_table
->mclk_table
.count
- 1].DisplayWatermark
=
1043 PPSMC_DISPLAY_WATERMARK_HIGH
;
1045 /* level count will send to smc once at init smc table and never change */
1046 result
= smu7_copy_bytes_to_smc(hwmgr
->smumgr
, array
, (uint8_t *)levels
,
1047 (uint32_t)array_size
, SMC_RAM_END
);
1054 * Populates the SMC MVDD structure using the provided memory clock.
1056 * @param hwmgr the address of the hardware manager
1057 * @param mclk the MCLK value to be used in the decision if MVDD should be high or low.
1058 * @param voltage the SMC VOLTAGE structure to be populated
1060 static int fiji_populate_mvdd_value(struct pp_hwmgr
*hwmgr
,
1061 uint32_t mclk
, SMIO_Pattern
*smio_pat
)
1063 const struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1064 struct phm_ppt_v1_information
*table_info
=
1065 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1068 if (SMU7_VOLTAGE_CONTROL_NONE
!= data
->mvdd_control
) {
1069 /* find mvdd value which clock is more than request */
1070 for (i
= 0; i
< table_info
->vdd_dep_on_mclk
->count
; i
++) {
1071 if (mclk
<= table_info
->vdd_dep_on_mclk
->entries
[i
].clk
) {
1072 smio_pat
->Voltage
= data
->mvdd_voltage_table
.entries
[i
].value
;
1076 PP_ASSERT_WITH_CODE(i
< table_info
->vdd_dep_on_mclk
->count
,
1077 "MVDD Voltage is outside the supported range.",
1085 static int fiji_populate_smc_acpi_level(struct pp_hwmgr
*hwmgr
,
1086 SMU73_Discrete_DpmTable
*table
)
1089 const struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1090 struct phm_ppt_v1_information
*table_info
=
1091 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1092 struct pp_atomctrl_clock_dividers_vi dividers
;
1093 SMIO_Pattern vol_level
;
1096 uint32_t spll_func_cntl
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL
;
1097 uint32_t spll_func_cntl_2
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_2
;
1099 table
->ACPILevel
.Flags
&= ~PPSMC_SWSTATE_FLAG_DC
;
1101 if (!data
->sclk_dpm_key_disabled
) {
1102 /* Get MinVoltage and Frequency from DPM0,
1103 * already converted to SMC_UL */
1104 table
->ACPILevel
.SclkFrequency
=
1105 data
->dpm_table
.sclk_table
.dpm_levels
[0].value
;
1106 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
1107 table_info
->vdd_dep_on_sclk
,
1108 table
->ACPILevel
.SclkFrequency
,
1109 (uint32_t *)(&table
->ACPILevel
.MinVoltage
), &mvdd
);
1110 PP_ASSERT_WITH_CODE((0 == result
),
1111 "Cannot find ACPI VDDC voltage value " \
1112 "in Clock Dependency Table",
1115 table
->ACPILevel
.SclkFrequency
=
1116 data
->vbios_boot_state
.sclk_bootup_value
;
1117 table
->ACPILevel
.MinVoltage
=
1118 data
->vbios_boot_state
.vddc_bootup_value
* VOLTAGE_SCALE
;
1121 /* get the engine clock dividers for this clock value */
1122 result
= atomctrl_get_engine_pll_dividers_vi(hwmgr
,
1123 table
->ACPILevel
.SclkFrequency
, ÷rs
);
1124 PP_ASSERT_WITH_CODE(result
== 0,
1125 "Error retrieving Engine Clock dividers from VBIOS.",
1128 table
->ACPILevel
.SclkDid
= (uint8_t)dividers
.pll_post_divider
;
1129 table
->ACPILevel
.DisplayWatermark
= PPSMC_DISPLAY_WATERMARK_LOW
;
1130 table
->ACPILevel
.DeepSleepDivId
= 0;
1132 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
1134 spll_func_cntl
= PHM_SET_FIELD(spll_func_cntl
, CG_SPLL_FUNC_CNTL
,
1136 spll_func_cntl_2
= PHM_SET_FIELD(spll_func_cntl_2
, CG_SPLL_FUNC_CNTL_2
,
1139 table
->ACPILevel
.CgSpllFuncCntl
= spll_func_cntl
;
1140 table
->ACPILevel
.CgSpllFuncCntl2
= spll_func_cntl_2
;
1141 table
->ACPILevel
.CgSpllFuncCntl3
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_3
;
1142 table
->ACPILevel
.CgSpllFuncCntl4
= data
->clock_registers
.vCG_SPLL_FUNC_CNTL_4
;
1143 table
->ACPILevel
.SpllSpreadSpectrum
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM
;
1144 table
->ACPILevel
.SpllSpreadSpectrum2
= data
->clock_registers
.vCG_SPLL_SPREAD_SPECTRUM_2
;
1145 table
->ACPILevel
.CcPwrDynRm
= 0;
1146 table
->ACPILevel
.CcPwrDynRm1
= 0;
1148 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.Flags
);
1149 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SclkFrequency
);
1150 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.MinVoltage
);
1151 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl
);
1152 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl2
);
1153 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl3
);
1154 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CgSpllFuncCntl4
);
1155 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum
);
1156 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.SpllSpreadSpectrum2
);
1157 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm
);
1158 CONVERT_FROM_HOST_TO_SMC_UL(table
->ACPILevel
.CcPwrDynRm1
);
1160 if (!data
->mclk_dpm_key_disabled
) {
1161 /* Get MinVoltage and Frequency from DPM0, already converted to SMC_UL */
1162 table
->MemoryACPILevel
.MclkFrequency
=
1163 data
->dpm_table
.mclk_table
.dpm_levels
[0].value
;
1164 result
= fiji_get_dependency_volt_by_clk(hwmgr
,
1165 table_info
->vdd_dep_on_mclk
,
1166 table
->MemoryACPILevel
.MclkFrequency
,
1167 (uint32_t *)(&table
->MemoryACPILevel
.MinVoltage
), &mvdd
);
1168 PP_ASSERT_WITH_CODE((0 == result
),
1169 "Cannot find ACPI VDDCI voltage value in Clock Dependency Table",
1172 table
->MemoryACPILevel
.MclkFrequency
=
1173 data
->vbios_boot_state
.mclk_bootup_value
;
1174 table
->MemoryACPILevel
.MinVoltage
=
1175 data
->vbios_boot_state
.vddci_bootup_value
* VOLTAGE_SCALE
;
1179 if ((SMU7_VOLTAGE_CONTROL_NONE
== data
->mvdd_control
) ||
1180 (data
->mclk_dpm_key_disabled
))
1181 us_mvdd
= data
->vbios_boot_state
.mvdd_bootup_value
;
1183 if (!fiji_populate_mvdd_value(hwmgr
,
1184 data
->dpm_table
.mclk_table
.dpm_levels
[0].value
,
1186 us_mvdd
= vol_level
.Voltage
;
1189 table
->MemoryACPILevel
.MinMvdd
=
1190 PP_HOST_TO_SMC_UL(us_mvdd
* VOLTAGE_SCALE
);
1192 table
->MemoryACPILevel
.EnabledForThrottle
= 0;
1193 table
->MemoryACPILevel
.EnabledForActivity
= 0;
1194 table
->MemoryACPILevel
.UpHyst
= 0;
1195 table
->MemoryACPILevel
.DownHyst
= 100;
1196 table
->MemoryACPILevel
.VoltageDownHyst
= 0;
1197 table
->MemoryACPILevel
.ActivityLevel
=
1198 PP_HOST_TO_SMC_US((uint16_t)data
->mclk_activity_target
);
1200 table
->MemoryACPILevel
.StutterEnable
= false;
1201 CONVERT_FROM_HOST_TO_SMC_UL(table
->MemoryACPILevel
.MclkFrequency
);
1202 CONVERT_FROM_HOST_TO_SMC_UL(table
->MemoryACPILevel
.MinVoltage
);
1207 static int fiji_populate_smc_vce_level(struct pp_hwmgr
*hwmgr
,
1208 SMU73_Discrete_DpmTable
*table
)
1210 int result
= -EINVAL
;
1212 struct pp_atomctrl_clock_dividers_vi dividers
;
1213 struct phm_ppt_v1_information
*table_info
=
1214 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1215 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
1216 table_info
->mm_dep_table
;
1218 table
->VceLevelCount
= (uint8_t)(mm_table
->count
);
1219 table
->VceBootLevel
= 0;
1221 for (count
= 0; count
< table
->VceLevelCount
; count
++) {
1222 table
->VceLevel
[count
].Frequency
= mm_table
->entries
[count
].eclk
;
1223 table
->VceLevel
[count
].MinVoltage
= 0;
1224 table
->VceLevel
[count
].MinVoltage
|=
1225 (mm_table
->entries
[count
].vddc
* VOLTAGE_SCALE
) << VDDC_SHIFT
;
1226 table
->VceLevel
[count
].MinVoltage
|=
1227 ((mm_table
->entries
[count
].vddc
- VDDC_VDDCI_DELTA
) *
1228 VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1229 table
->VceLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
1231 /*retrieve divider value for VBIOS */
1232 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1233 table
->VceLevel
[count
].Frequency
, ÷rs
);
1234 PP_ASSERT_WITH_CODE((0 == result
),
1235 "can not find divide id for VCE engine clock",
1238 table
->VceLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1240 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].Frequency
);
1241 CONVERT_FROM_HOST_TO_SMC_UL(table
->VceLevel
[count
].MinVoltage
);
1246 static int fiji_populate_smc_acp_level(struct pp_hwmgr
*hwmgr
,
1247 SMU73_Discrete_DpmTable
*table
)
1249 int result
= -EINVAL
;
1251 struct pp_atomctrl_clock_dividers_vi dividers
;
1252 struct phm_ppt_v1_information
*table_info
=
1253 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1254 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
1255 table_info
->mm_dep_table
;
1257 table
->AcpLevelCount
= (uint8_t)(mm_table
->count
);
1258 table
->AcpBootLevel
= 0;
1260 for (count
= 0; count
< table
->AcpLevelCount
; count
++) {
1261 table
->AcpLevel
[count
].Frequency
= mm_table
->entries
[count
].aclk
;
1262 table
->AcpLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
1263 VOLTAGE_SCALE
) << VDDC_SHIFT
;
1264 table
->AcpLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
1265 VDDC_VDDCI_DELTA
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1266 table
->AcpLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
1268 /* retrieve divider value for VBIOS */
1269 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1270 table
->AcpLevel
[count
].Frequency
, ÷rs
);
1271 PP_ASSERT_WITH_CODE((0 == result
),
1272 "can not find divide id for engine clock", return result
);
1274 table
->AcpLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1276 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].Frequency
);
1277 CONVERT_FROM_HOST_TO_SMC_UL(table
->AcpLevel
[count
].MinVoltage
);
1282 static int fiji_populate_smc_samu_level(struct pp_hwmgr
*hwmgr
,
1283 SMU73_Discrete_DpmTable
*table
)
1285 int result
= -EINVAL
;
1287 struct pp_atomctrl_clock_dividers_vi dividers
;
1288 struct phm_ppt_v1_information
*table_info
=
1289 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1290 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
1291 table_info
->mm_dep_table
;
1293 table
->SamuBootLevel
= 0;
1294 table
->SamuLevelCount
= (uint8_t)(mm_table
->count
);
1296 for (count
= 0; count
< table
->SamuLevelCount
; count
++) {
1297 /* not sure whether we need evclk or not */
1298 table
->SamuLevel
[count
].MinVoltage
= 0;
1299 table
->SamuLevel
[count
].Frequency
= mm_table
->entries
[count
].samclock
;
1300 table
->SamuLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
1301 VOLTAGE_SCALE
) << VDDC_SHIFT
;
1302 table
->SamuLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
1303 VDDC_VDDCI_DELTA
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1304 table
->SamuLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
1306 /* retrieve divider value for VBIOS */
1307 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1308 table
->SamuLevel
[count
].Frequency
, ÷rs
);
1309 PP_ASSERT_WITH_CODE((0 == result
),
1310 "can not find divide id for samu clock", return result
);
1312 table
->SamuLevel
[count
].Divider
= (uint8_t)dividers
.pll_post_divider
;
1314 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].Frequency
);
1315 CONVERT_FROM_HOST_TO_SMC_UL(table
->SamuLevel
[count
].MinVoltage
);
1320 static int fiji_populate_memory_timing_parameters(struct pp_hwmgr
*hwmgr
,
1321 int32_t eng_clock
, int32_t mem_clock
,
1322 struct SMU73_Discrete_MCArbDramTimingTableEntry
*arb_regs
)
1324 uint32_t dram_timing
;
1325 uint32_t dram_timing2
;
1327 ULONG state
, trrds
, trrdl
;
1330 result
= atomctrl_set_engine_dram_timings_rv770(hwmgr
,
1331 eng_clock
, mem_clock
);
1332 PP_ASSERT_WITH_CODE(result
== 0,
1333 "Error calling VBIOS to set DRAM_TIMING.", return result
);
1335 dram_timing
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING
);
1336 dram_timing2
= cgs_read_register(hwmgr
->device
, mmMC_ARB_DRAM_TIMING2
);
1337 burstTime
= cgs_read_register(hwmgr
->device
, mmMC_ARB_BURST_TIME
);
1339 state
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, STATE0
);
1340 trrds
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, TRRDS0
);
1341 trrdl
= PHM_GET_FIELD(burstTime
, MC_ARB_BURST_TIME
, TRRDL0
);
1343 arb_regs
->McArbDramTiming
= PP_HOST_TO_SMC_UL(dram_timing
);
1344 arb_regs
->McArbDramTiming2
= PP_HOST_TO_SMC_UL(dram_timing2
);
1345 arb_regs
->McArbBurstTime
= (uint8_t)burstTime
;
1346 arb_regs
->TRRDS
= (uint8_t)trrds
;
1347 arb_regs
->TRRDL
= (uint8_t)trrdl
;
1352 static int fiji_program_memory_timing_parameters(struct pp_hwmgr
*hwmgr
)
1354 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1355 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
1356 struct SMU73_Discrete_MCArbDramTimingTable arb_regs
;
1360 for (i
= 0; i
< data
->dpm_table
.sclk_table
.count
; i
++) {
1361 for (j
= 0; j
< data
->dpm_table
.mclk_table
.count
; j
++) {
1362 result
= fiji_populate_memory_timing_parameters(hwmgr
,
1363 data
->dpm_table
.sclk_table
.dpm_levels
[i
].value
,
1364 data
->dpm_table
.mclk_table
.dpm_levels
[j
].value
,
1365 &arb_regs
.entries
[i
][j
]);
1372 result
= smu7_copy_bytes_to_smc(
1374 smu_data
->smu7_data
.arb_table_start
,
1375 (uint8_t *)&arb_regs
,
1376 sizeof(SMU73_Discrete_MCArbDramTimingTable
),
1381 static int fiji_populate_smc_uvd_level(struct pp_hwmgr
*hwmgr
,
1382 struct SMU73_Discrete_DpmTable
*table
)
1384 int result
= -EINVAL
;
1386 struct pp_atomctrl_clock_dividers_vi dividers
;
1387 struct phm_ppt_v1_information
*table_info
=
1388 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1389 struct phm_ppt_v1_mm_clock_voltage_dependency_table
*mm_table
=
1390 table_info
->mm_dep_table
;
1392 table
->UvdLevelCount
= (uint8_t)(mm_table
->count
);
1393 table
->UvdBootLevel
= 0;
1395 for (count
= 0; count
< table
->UvdLevelCount
; count
++) {
1396 table
->UvdLevel
[count
].MinVoltage
= 0;
1397 table
->UvdLevel
[count
].VclkFrequency
= mm_table
->entries
[count
].vclk
;
1398 table
->UvdLevel
[count
].DclkFrequency
= mm_table
->entries
[count
].dclk
;
1399 table
->UvdLevel
[count
].MinVoltage
|= (mm_table
->entries
[count
].vddc
*
1400 VOLTAGE_SCALE
) << VDDC_SHIFT
;
1401 table
->UvdLevel
[count
].MinVoltage
|= ((mm_table
->entries
[count
].vddc
-
1402 VDDC_VDDCI_DELTA
) * VOLTAGE_SCALE
) << VDDCI_SHIFT
;
1403 table
->UvdLevel
[count
].MinVoltage
|= 1 << PHASES_SHIFT
;
1405 /* retrieve divider value for VBIOS */
1406 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1407 table
->UvdLevel
[count
].VclkFrequency
, ÷rs
);
1408 PP_ASSERT_WITH_CODE((0 == result
),
1409 "can not find divide id for Vclk clock", return result
);
1411 table
->UvdLevel
[count
].VclkDivider
= (uint8_t)dividers
.pll_post_divider
;
1413 result
= atomctrl_get_dfs_pll_dividers_vi(hwmgr
,
1414 table
->UvdLevel
[count
].DclkFrequency
, ÷rs
);
1415 PP_ASSERT_WITH_CODE((0 == result
),
1416 "can not find divide id for Dclk clock", return result
);
1418 table
->UvdLevel
[count
].DclkDivider
= (uint8_t)dividers
.pll_post_divider
;
1420 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].VclkFrequency
);
1421 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].DclkFrequency
);
1422 CONVERT_FROM_HOST_TO_SMC_UL(table
->UvdLevel
[count
].MinVoltage
);
1428 static int fiji_populate_smc_boot_level(struct pp_hwmgr
*hwmgr
,
1429 struct SMU73_Discrete_DpmTable
*table
)
1432 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1434 table
->GraphicsBootLevel
= 0;
1435 table
->MemoryBootLevel
= 0;
1437 /* find boot level from dpm table */
1438 result
= phm_find_boot_level(&(data
->dpm_table
.sclk_table
),
1439 data
->vbios_boot_state
.sclk_bootup_value
,
1440 (uint32_t *)&(table
->GraphicsBootLevel
));
1442 result
= phm_find_boot_level(&(data
->dpm_table
.mclk_table
),
1443 data
->vbios_boot_state
.mclk_bootup_value
,
1444 (uint32_t *)&(table
->MemoryBootLevel
));
1446 table
->BootVddc
= data
->vbios_boot_state
.vddc_bootup_value
*
1448 table
->BootVddci
= data
->vbios_boot_state
.vddci_bootup_value
*
1450 table
->BootMVdd
= data
->vbios_boot_state
.mvdd_bootup_value
*
1453 CONVERT_FROM_HOST_TO_SMC_US(table
->BootVddc
);
1454 CONVERT_FROM_HOST_TO_SMC_US(table
->BootVddci
);
1455 CONVERT_FROM_HOST_TO_SMC_US(table
->BootMVdd
);
1460 static int fiji_populate_smc_initailial_state(struct pp_hwmgr
*hwmgr
)
1462 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1463 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
1464 struct phm_ppt_v1_information
*table_info
=
1465 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1466 uint8_t count
, level
;
1468 count
= (uint8_t)(table_info
->vdd_dep_on_sclk
->count
);
1469 for (level
= 0; level
< count
; level
++) {
1470 if (table_info
->vdd_dep_on_sclk
->entries
[level
].clk
>=
1471 data
->vbios_boot_state
.sclk_bootup_value
) {
1472 smu_data
->smc_state_table
.GraphicsBootLevel
= level
;
1477 count
= (uint8_t)(table_info
->vdd_dep_on_mclk
->count
);
1478 for (level
= 0; level
< count
; level
++) {
1479 if (table_info
->vdd_dep_on_mclk
->entries
[level
].clk
>=
1480 data
->vbios_boot_state
.mclk_bootup_value
) {
1481 smu_data
->smc_state_table
.MemoryBootLevel
= level
;
1489 static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr
*hwmgr
)
1491 uint32_t ro
, efuse
, efuse2
, clock_freq
, volt_without_cks
,
1492 volt_with_cks
, value
;
1493 uint16_t clock_freq_u16
;
1494 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
1495 uint8_t type
, i
, j
, cks_setting
, stretch_amount
, stretch_amount2
,
1497 struct phm_ppt_v1_information
*table_info
=
1498 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1499 struct phm_ppt_v1_clock_voltage_dependency_table
*sclk_table
=
1500 table_info
->vdd_dep_on_sclk
;
1502 stretch_amount
= (uint8_t)table_info
->cac_dtp_table
->usClockStretchAmount
;
1504 /* Read SMU_Eefuse to read and calculate RO and determine
1505 * if the part is SS or FF. if RO >= 1660MHz, part is FF.
1507 efuse
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1508 ixSMU_EFUSE_0
+ (146 * 4));
1509 efuse2
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1510 ixSMU_EFUSE_0
+ (148 * 4));
1511 efuse
&= 0xFF000000;
1512 efuse
= efuse
>> 24;
1516 ro
= (2300 - 1350) * efuse
/ 255 + 1350;
1518 ro
= (2500 - 1000) * efuse
/ 255 + 1000;
1525 /* Populate Stretch amount */
1526 smu_data
->smc_state_table
.ClockStretcherAmount
= stretch_amount
;
1528 /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
1529 for (i
= 0; i
< sclk_table
->count
; i
++) {
1530 smu_data
->smc_state_table
.Sclk_CKS_masterEn0_7
|=
1531 sclk_table
->entries
[i
].cks_enable
<< i
;
1532 volt_without_cks
= (uint32_t)((14041 *
1533 (sclk_table
->entries
[i
].clk
/100) / 10000 + 3571 + 75 - ro
) * 1000 /
1534 (4026 - (13924 * (sclk_table
->entries
[i
].clk
/100) / 10000)));
1535 volt_with_cks
= (uint32_t)((13946 *
1536 (sclk_table
->entries
[i
].clk
/100) / 10000 + 3320 + 45 - ro
) * 1000 /
1537 (3664 - (11454 * (sclk_table
->entries
[i
].clk
/100) / 10000)));
1538 if (volt_without_cks
>= volt_with_cks
)
1539 volt_offset
= (uint8_t)(((volt_without_cks
- volt_with_cks
+
1540 sclk_table
->entries
[i
].cks_voffset
) * 100 / 625) + 1);
1541 smu_data
->smc_state_table
.Sclk_voltageOffset
[i
] = volt_offset
;
1544 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
1545 STRETCH_ENABLE
, 0x0);
1546 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
1548 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
1550 PHM_WRITE_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
, PWR_CKS_ENABLE
,
1553 /* Populate CKS Lookup Table */
1554 if (stretch_amount
== 1 || stretch_amount
== 2 || stretch_amount
== 5)
1555 stretch_amount2
= 0;
1556 else if (stretch_amount
== 3 || stretch_amount
== 4)
1557 stretch_amount2
= 1;
1559 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
1560 PHM_PlatformCaps_ClockStretcher
);
1561 PP_ASSERT_WITH_CODE(false,
1562 "Stretch Amount in PPTable not supported\n",
1566 value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1568 value
&= 0xFFC2FF87;
1569 smu_data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].minFreq
=
1570 fiji_clock_stretcher_lookup_table
[stretch_amount2
][0];
1571 smu_data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].maxFreq
=
1572 fiji_clock_stretcher_lookup_table
[stretch_amount2
][1];
1573 clock_freq_u16
= (uint16_t)(PP_SMC_TO_HOST_UL(smu_data
->smc_state_table
.
1574 GraphicsLevel
[smu_data
->smc_state_table
.GraphicsDpmLevelCount
- 1].
1575 SclkFrequency
) / 100);
1576 if (fiji_clock_stretcher_lookup_table
[stretch_amount2
][0] <
1578 fiji_clock_stretcher_lookup_table
[stretch_amount2
][1] >
1580 /* Program PWR_CKS_CNTL. CKS_USE_FOR_LOW_FREQ */
1581 value
|= (fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]) << 16;
1582 /* Program PWR_CKS_CNTL. CKS_LDO_REFSEL */
1583 value
|= (fiji_clock_stretcher_lookup_table
[stretch_amount2
][2]) << 18;
1584 /* Program PWR_CKS_CNTL. CKS_STRETCH_AMOUNT */
1585 value
|= (fiji_clock_stretch_amount_conversion
1586 [fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]]
1587 [stretch_amount
]) << 3;
1589 CONVERT_FROM_HOST_TO_SMC_US(smu_data
->smc_state_table
.CKS_LOOKUPTable
.
1590 CKS_LOOKUPTableEntry
[0].minFreq
);
1591 CONVERT_FROM_HOST_TO_SMC_US(smu_data
->smc_state_table
.CKS_LOOKUPTable
.
1592 CKS_LOOKUPTableEntry
[0].maxFreq
);
1593 smu_data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].setting
=
1594 fiji_clock_stretcher_lookup_table
[stretch_amount2
][2] & 0x7F;
1595 smu_data
->smc_state_table
.CKS_LOOKUPTable
.CKS_LOOKUPTableEntry
[0].setting
|=
1596 (fiji_clock_stretcher_lookup_table
[stretch_amount2
][3]) << 7;
1598 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1599 ixPWR_CKS_CNTL
, value
);
1601 /* Populate DDT Lookup Table */
1602 for (i
= 0; i
< 4; i
++) {
1603 /* Assign the minimum and maximum VID stored
1604 * in the last row of Clock Stretcher Voltage Table.
1606 smu_data
->smc_state_table
.ClockStretcherDataTable
.
1607 ClockStretcherDataTableEntry
[i
].minVID
=
1608 (uint8_t) fiji_clock_stretcher_ddt_table
[type
][i
][2];
1609 smu_data
->smc_state_table
.ClockStretcherDataTable
.
1610 ClockStretcherDataTableEntry
[i
].maxVID
=
1611 (uint8_t) fiji_clock_stretcher_ddt_table
[type
][i
][3];
1612 /* Loop through each SCLK and check the frequency
1613 * to see if it lies within the frequency for clock stretcher.
1615 for (j
= 0; j
< smu_data
->smc_state_table
.GraphicsDpmLevelCount
; j
++) {
1617 clock_freq
= PP_SMC_TO_HOST_UL(
1618 smu_data
->smc_state_table
.GraphicsLevel
[j
].SclkFrequency
);
1619 /* Check the allowed frequency against the sclk level[j].
1620 * Sclk's endianness has already been converted,
1621 * and it's in 10Khz unit,
1622 * as opposed to Data table, which is in Mhz unit.
1625 (fiji_clock_stretcher_ddt_table
[type
][i
][0]) * 100) {
1628 (fiji_clock_stretcher_ddt_table
[type
][i
][1]) * 100)
1631 smu_data
->smc_state_table
.ClockStretcherDataTable
.
1632 ClockStretcherDataTableEntry
[i
].setting
|= cks_setting
<< (j
* 2);
1634 CONVERT_FROM_HOST_TO_SMC_US(smu_data
->smc_state_table
.
1635 ClockStretcherDataTable
.
1636 ClockStretcherDataTableEntry
[i
].setting
);
1639 value
= cgs_read_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixPWR_CKS_CNTL
);
1640 value
&= 0xFFFFFFFE;
1641 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
, ixPWR_CKS_CNTL
, value
);
1647 * Populates the SMC VRConfig field in DPM table.
1649 * @param hwmgr the address of the hardware manager
1650 * @param table the SMC DPM table structure to be populated
1653 static int fiji_populate_vr_config(struct pp_hwmgr
*hwmgr
,
1654 struct SMU73_Discrete_DpmTable
*table
)
1656 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1659 config
= VR_MERGED_WITH_VDDC
;
1660 table
->VRConfig
|= (config
<< VRCONF_VDDGFX_SHIFT
);
1662 /* Set Vddc Voltage Controller */
1663 if (SMU7_VOLTAGE_CONTROL_BY_SVID2
== data
->voltage_control
) {
1664 config
= VR_SVI2_PLANE_1
;
1665 table
->VRConfig
|= config
;
1667 PP_ASSERT_WITH_CODE(false,
1668 "VDDC should be on SVI2 control in merged mode!",
1671 /* Set Vddci Voltage Controller */
1672 if (SMU7_VOLTAGE_CONTROL_BY_SVID2
== data
->vddci_control
) {
1673 config
= VR_SVI2_PLANE_2
; /* only in merged mode */
1674 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
1675 } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO
== data
->vddci_control
) {
1676 config
= VR_SMIO_PATTERN_1
;
1677 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
1679 config
= VR_STATIC_VOLTAGE
;
1680 table
->VRConfig
|= (config
<< VRCONF_VDDCI_SHIFT
);
1682 /* Set Mvdd Voltage Controller */
1683 if (SMU7_VOLTAGE_CONTROL_BY_SVID2
== data
->mvdd_control
) {
1684 config
= VR_SVI2_PLANE_2
;
1685 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
1686 } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO
== data
->mvdd_control
) {
1687 config
= VR_SMIO_PATTERN_2
;
1688 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
1690 config
= VR_STATIC_VOLTAGE
;
1691 table
->VRConfig
|= (config
<< VRCONF_MVDD_SHIFT
);
1697 static int fiji_init_arb_table_index(struct pp_smumgr
*smumgr
)
1699 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(smumgr
->backend
);
1703 /* This is a read-modify-write on the first byte of the ARB table.
1704 * The first byte in the SMU73_Discrete_MCArbDramTimingTable structure
1705 * is the field 'current'.
1706 * This solution is ugly, but we never write the whole table only
1707 * individual fields in it.
1708 * In reality this field should not be in that structure
1709 * but in a soft register.
1711 result
= smu7_read_smc_sram_dword(smumgr
,
1712 smu_data
->smu7_data
.arb_table_start
, &tmp
, SMC_RAM_END
);
1718 tmp
|= ((uint32_t)MC_CG_ARB_FREQ_F1
) << 24;
1720 return smu7_write_smc_sram_dword(smumgr
,
1721 smu_data
->smu7_data
.arb_table_start
, tmp
, SMC_RAM_END
);
1725 * Initializes the SMC table and uploads it
1727 * @param hwmgr the address of the powerplay hardware manager.
1728 * @param pInput the pointer to input data (PowerState)
1731 int fiji_init_smc_table(struct pp_hwmgr
*hwmgr
)
1734 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
1735 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
1736 struct phm_ppt_v1_information
*table_info
=
1737 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
1738 struct SMU73_Discrete_DpmTable
*table
= &(smu_data
->smc_state_table
);
1740 struct pp_atomctrl_gpio_pin_assignment gpio_pin
;
1742 fiji_initialize_power_tune_defaults(hwmgr
);
1744 if (SMU7_VOLTAGE_CONTROL_NONE
!= data
->voltage_control
)
1745 fiji_populate_smc_voltage_tables(hwmgr
, table
);
1747 table
->SystemFlags
= 0;
1749 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
1750 PHM_PlatformCaps_AutomaticDCTransition
))
1751 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GPIO_DC
;
1753 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
1754 PHM_PlatformCaps_StepVddc
))
1755 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_STEPVDDC
;
1757 if (data
->is_memory_gddr5
)
1758 table
->SystemFlags
|= PPSMC_SYSTEMFLAG_GDDR5
;
1760 if (data
->ulv_supported
&& table_info
->us_ulv_voltage_offset
) {
1761 result
= fiji_populate_ulv_state(hwmgr
, table
);
1762 PP_ASSERT_WITH_CODE(0 == result
,
1763 "Failed to initialize ULV state!", return result
);
1764 cgs_write_ind_register(hwmgr
->device
, CGS_IND_REG__SMC
,
1765 ixCG_ULV_PARAMETER
, 0x40035);
1768 result
= fiji_populate_smc_link_level(hwmgr
, table
);
1769 PP_ASSERT_WITH_CODE(0 == result
,
1770 "Failed to initialize Link Level!", return result
);
1772 result
= fiji_populate_all_graphic_levels(hwmgr
);
1773 PP_ASSERT_WITH_CODE(0 == result
,
1774 "Failed to initialize Graphics Level!", return result
);
1776 result
= fiji_populate_all_memory_levels(hwmgr
);
1777 PP_ASSERT_WITH_CODE(0 == result
,
1778 "Failed to initialize Memory Level!", return result
);
1780 result
= fiji_populate_smc_acpi_level(hwmgr
, table
);
1781 PP_ASSERT_WITH_CODE(0 == result
,
1782 "Failed to initialize ACPI Level!", return result
);
1784 result
= fiji_populate_smc_vce_level(hwmgr
, table
);
1785 PP_ASSERT_WITH_CODE(0 == result
,
1786 "Failed to initialize VCE Level!", return result
);
1788 result
= fiji_populate_smc_acp_level(hwmgr
, table
);
1789 PP_ASSERT_WITH_CODE(0 == result
,
1790 "Failed to initialize ACP Level!", return result
);
1792 result
= fiji_populate_smc_samu_level(hwmgr
, table
);
1793 PP_ASSERT_WITH_CODE(0 == result
,
1794 "Failed to initialize SAMU Level!", return result
);
1796 /* Since only the initial state is completely set up at this point
1797 * (the other states are just copies of the boot state) we only
1798 * need to populate the ARB settings for the initial state.
1800 result
= fiji_program_memory_timing_parameters(hwmgr
);
1801 PP_ASSERT_WITH_CODE(0 == result
,
1802 "Failed to Write ARB settings for the initial state.", return result
);
1804 result
= fiji_populate_smc_uvd_level(hwmgr
, table
);
1805 PP_ASSERT_WITH_CODE(0 == result
,
1806 "Failed to initialize UVD Level!", return result
);
1808 result
= fiji_populate_smc_boot_level(hwmgr
, table
);
1809 PP_ASSERT_WITH_CODE(0 == result
,
1810 "Failed to initialize Boot Level!", return result
);
1812 result
= fiji_populate_smc_initailial_state(hwmgr
);
1813 PP_ASSERT_WITH_CODE(0 == result
,
1814 "Failed to initialize Boot State!", return result
);
1816 result
= fiji_populate_bapm_parameters_in_dpm_table(hwmgr
);
1817 PP_ASSERT_WITH_CODE(0 == result
,
1818 "Failed to populate BAPM Parameters!", return result
);
1820 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
1821 PHM_PlatformCaps_ClockStretcher
)) {
1822 result
= fiji_populate_clock_stretcher_data_table(hwmgr
);
1823 PP_ASSERT_WITH_CODE(0 == result
,
1824 "Failed to populate Clock Stretcher Data Table!",
1828 table
->GraphicsVoltageChangeEnable
= 1;
1829 table
->GraphicsThermThrottleEnable
= 1;
1830 table
->GraphicsInterval
= 1;
1831 table
->VoltageInterval
= 1;
1832 table
->ThermalInterval
= 1;
1833 table
->TemperatureLimitHigh
=
1834 table_info
->cac_dtp_table
->usTargetOperatingTemp
*
1835 SMU7_Q88_FORMAT_CONVERSION_UNIT
;
1836 table
->TemperatureLimitLow
=
1837 (table_info
->cac_dtp_table
->usTargetOperatingTemp
- 1) *
1838 SMU7_Q88_FORMAT_CONVERSION_UNIT
;
1839 table
->MemoryVoltageChangeEnable
= 1;
1840 table
->MemoryInterval
= 1;
1841 table
->VoltageResponseTime
= 0;
1842 table
->PhaseResponseTime
= 0;
1843 table
->MemoryThermThrottleEnable
= 1;
1844 table
->PCIeBootLinkLevel
= 0; /* 0:Gen1 1:Gen2 2:Gen3*/
1845 table
->PCIeGenInterval
= 1;
1846 table
->VRConfig
= 0;
1848 result
= fiji_populate_vr_config(hwmgr
, table
);
1849 PP_ASSERT_WITH_CODE(0 == result
,
1850 "Failed to populate VRConfig setting!", return result
);
1852 table
->ThermGpio
= 17;
1853 table
->SclkStepSize
= 0x4000;
1855 if (atomctrl_get_pp_assign_pin(hwmgr
, VDDC_VRHOT_GPIO_PINID
, &gpio_pin
)) {
1856 table
->VRHotGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
1857 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
1858 PHM_PlatformCaps_RegulatorHot
);
1860 table
->VRHotGpio
= SMU7_UNUSED_GPIO_PIN
;
1861 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
1862 PHM_PlatformCaps_RegulatorHot
);
1865 if (atomctrl_get_pp_assign_pin(hwmgr
, PP_AC_DC_SWITCH_GPIO_PINID
,
1867 table
->AcDcGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
1868 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
1869 PHM_PlatformCaps_AutomaticDCTransition
);
1871 table
->AcDcGpio
= SMU7_UNUSED_GPIO_PIN
;
1872 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
1873 PHM_PlatformCaps_AutomaticDCTransition
);
1876 /* Thermal Output GPIO */
1877 if (atomctrl_get_pp_assign_pin(hwmgr
, THERMAL_INT_OUTPUT_GPIO_PINID
,
1879 phm_cap_set(hwmgr
->platform_descriptor
.platformCaps
,
1880 PHM_PlatformCaps_ThermalOutGPIO
);
1882 table
->ThermOutGpio
= gpio_pin
.uc_gpio_pin_bit_shift
;
1884 /* For porlarity read GPIOPAD_A with assigned Gpio pin
1885 * since VBIOS will program this register to set 'inactive state',
1886 * driver can then determine 'active state' from this and
1887 * program SMU with correct polarity
1889 table
->ThermOutPolarity
= (0 == (cgs_read_register(hwmgr
->device
, mmGPIOPAD_A
) &
1890 (1 << gpio_pin
.uc_gpio_pin_bit_shift
))) ? 1:0;
1891 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_ONLY
;
1893 /* if required, combine VRHot/PCC with thermal out GPIO */
1894 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
1895 PHM_PlatformCaps_RegulatorHot
) &&
1896 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
1897 PHM_PlatformCaps_CombinePCCWithThermalSignal
))
1898 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_THERM_VRHOT
;
1900 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
1901 PHM_PlatformCaps_ThermalOutGPIO
);
1902 table
->ThermOutGpio
= 17;
1903 table
->ThermOutPolarity
= 1;
1904 table
->ThermOutMode
= SMU7_THERM_OUT_MODE_DISABLE
;
1907 for (i
= 0; i
< SMU73_MAX_ENTRIES_SMIO
; i
++)
1908 table
->Smio
[i
] = PP_HOST_TO_SMC_UL(table
->Smio
[i
]);
1910 CONVERT_FROM_HOST_TO_SMC_UL(table
->SystemFlags
);
1911 CONVERT_FROM_HOST_TO_SMC_UL(table
->VRConfig
);
1912 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask1
);
1913 CONVERT_FROM_HOST_TO_SMC_UL(table
->SmioMask2
);
1914 CONVERT_FROM_HOST_TO_SMC_UL(table
->SclkStepSize
);
1915 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitHigh
);
1916 CONVERT_FROM_HOST_TO_SMC_US(table
->TemperatureLimitLow
);
1917 CONVERT_FROM_HOST_TO_SMC_US(table
->VoltageResponseTime
);
1918 CONVERT_FROM_HOST_TO_SMC_US(table
->PhaseResponseTime
);
1920 /* Upload all dpm data to SMC memory.(dpm level, dpm level count etc) */
1921 result
= smu7_copy_bytes_to_smc(hwmgr
->smumgr
,
1922 smu_data
->smu7_data
.dpm_table_start
+
1923 offsetof(SMU73_Discrete_DpmTable
, SystemFlags
),
1924 (uint8_t *)&(table
->SystemFlags
),
1925 sizeof(SMU73_Discrete_DpmTable
) - 3 * sizeof(SMU73_PIDController
),
1927 PP_ASSERT_WITH_CODE(0 == result
,
1928 "Failed to upload dpm data to SMC memory!", return result
);
1930 result
= fiji_init_arb_table_index(hwmgr
->smumgr
);
1931 PP_ASSERT_WITH_CODE(0 == result
,
1932 "Failed to upload arb data to SMC memory!", return result
);
1934 result
= fiji_populate_pm_fuses(hwmgr
);
1935 PP_ASSERT_WITH_CODE(0 == result
,
1936 "Failed to populate PM fuses to SMC memory!", return result
);
1941 * Set up the fan table to control the fan using the SMC.
1942 * @param hwmgr the address of the powerplay hardware manager.
1943 * @param pInput the pointer to input data
1944 * @param pOutput the pointer to output data
1945 * @param pStorage the pointer to temporary storage
1946 * @param Result the last failure code
1947 * @return result from set temperature range routine
1949 int fiji_thermal_setup_fan_table(struct pp_hwmgr
*hwmgr
)
1951 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
1953 SMU73_Discrete_FanTable fan_table
= { FDO_MODE_HARDWARE
};
1955 uint32_t t_diff1
, t_diff2
, pwm_diff1
, pwm_diff2
;
1956 uint16_t fdo_min
, slope1
, slope2
;
1957 uint32_t reference_clock
;
1961 if (hwmgr
->thermal_controller
.fanInfo
.bNoFan
) {
1962 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
1963 PHM_PlatformCaps_MicrocodeFanControl
);
1967 if (smu_data
->smu7_data
.fan_table_start
== 0) {
1968 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
1969 PHM_PlatformCaps_MicrocodeFanControl
);
1973 duty100
= PHM_READ_VFPF_INDIRECT_FIELD(hwmgr
->device
, CGS_IND_REG__SMC
,
1974 CG_FDO_CTRL1
, FMAX_DUTY100
);
1977 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
1978 PHM_PlatformCaps_MicrocodeFanControl
);
1982 tmp64
= hwmgr
->thermal_controller
.advanceFanControlParameters
.
1984 do_div(tmp64
, 10000);
1985 fdo_min
= (uint16_t)tmp64
;
1987 t_diff1
= hwmgr
->thermal_controller
.advanceFanControlParameters
.usTMed
-
1988 hwmgr
->thermal_controller
.advanceFanControlParameters
.usTMin
;
1989 t_diff2
= hwmgr
->thermal_controller
.advanceFanControlParameters
.usTHigh
-
1990 hwmgr
->thermal_controller
.advanceFanControlParameters
.usTMed
;
1992 pwm_diff1
= hwmgr
->thermal_controller
.advanceFanControlParameters
.usPWMMed
-
1993 hwmgr
->thermal_controller
.advanceFanControlParameters
.usPWMMin
;
1994 pwm_diff2
= hwmgr
->thermal_controller
.advanceFanControlParameters
.usPWMHigh
-
1995 hwmgr
->thermal_controller
.advanceFanControlParameters
.usPWMMed
;
1997 slope1
= (uint16_t)((50 + ((16 * duty100
* pwm_diff1
) / t_diff1
)) / 100);
1998 slope2
= (uint16_t)((50 + ((16 * duty100
* pwm_diff2
) / t_diff2
)) / 100);
2000 fan_table
.TempMin
= cpu_to_be16((50 + hwmgr
->
2001 thermal_controller
.advanceFanControlParameters
.usTMin
) / 100);
2002 fan_table
.TempMed
= cpu_to_be16((50 + hwmgr
->
2003 thermal_controller
.advanceFanControlParameters
.usTMed
) / 100);
2004 fan_table
.TempMax
= cpu_to_be16((50 + hwmgr
->
2005 thermal_controller
.advanceFanControlParameters
.usTMax
) / 100);
2007 fan_table
.Slope1
= cpu_to_be16(slope1
);
2008 fan_table
.Slope2
= cpu_to_be16(slope2
);
2010 fan_table
.FdoMin
= cpu_to_be16(fdo_min
);
2012 fan_table
.HystDown
= cpu_to_be16(hwmgr
->
2013 thermal_controller
.advanceFanControlParameters
.ucTHyst
);
2015 fan_table
.HystUp
= cpu_to_be16(1);
2017 fan_table
.HystSlope
= cpu_to_be16(1);
2019 fan_table
.TempRespLim
= cpu_to_be16(5);
2021 reference_clock
= smu7_get_xclk(hwmgr
);
2023 fan_table
.RefreshPeriod
= cpu_to_be32((hwmgr
->
2024 thermal_controller
.advanceFanControlParameters
.ulCycleDelay
*
2025 reference_clock
) / 1600);
2027 fan_table
.FdoMax
= cpu_to_be16((uint16_t)duty100
);
2029 fan_table
.TempSrc
= (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
2030 hwmgr
->device
, CGS_IND_REG__SMC
,
2031 CG_MULT_THERMAL_CTRL
, TEMP_SEL
);
2033 res
= smu7_copy_bytes_to_smc(hwmgr
->smumgr
, smu_data
->smu7_data
.fan_table_start
,
2034 (uint8_t *)&fan_table
, (uint32_t)sizeof(fan_table
),
2037 if (!res
&& hwmgr
->thermal_controller
.
2038 advanceFanControlParameters
.ucMinimumPWMLimit
)
2039 res
= smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
2040 PPSMC_MSG_SetFanMinPwm
,
2041 hwmgr
->thermal_controller
.
2042 advanceFanControlParameters
.ucMinimumPWMLimit
);
2044 if (!res
&& hwmgr
->thermal_controller
.
2045 advanceFanControlParameters
.ulMinFanSCLKAcousticLimit
)
2046 res
= smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
2047 PPSMC_MSG_SetFanSclkTarget
,
2048 hwmgr
->thermal_controller
.
2049 advanceFanControlParameters
.ulMinFanSCLKAcousticLimit
);
2052 phm_cap_unset(hwmgr
->platform_descriptor
.platformCaps
,
2053 PHM_PlatformCaps_MicrocodeFanControl
);
2058 static int fiji_program_mem_timing_parameters(struct pp_hwmgr
*hwmgr
)
2060 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
2062 if (data
->need_update_smu7_dpm_table
&
2063 (DPMTABLE_OD_UPDATE_SCLK
+ DPMTABLE_OD_UPDATE_MCLK
))
2064 return fiji_program_memory_timing_parameters(hwmgr
);
2069 int fiji_update_sclk_threshold(struct pp_hwmgr
*hwmgr
)
2071 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
2072 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
2075 uint32_t low_sclk_interrupt_threshold
= 0;
2077 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2078 PHM_PlatformCaps_SclkThrottleLowNotification
)
2079 && (hwmgr
->gfx_arbiter
.sclk_threshold
!=
2080 data
->low_sclk_interrupt_threshold
)) {
2081 data
->low_sclk_interrupt_threshold
=
2082 hwmgr
->gfx_arbiter
.sclk_threshold
;
2083 low_sclk_interrupt_threshold
=
2084 data
->low_sclk_interrupt_threshold
;
2086 CONVERT_FROM_HOST_TO_SMC_UL(low_sclk_interrupt_threshold
);
2088 result
= smu7_copy_bytes_to_smc(
2090 smu_data
->smu7_data
.dpm_table_start
+
2091 offsetof(SMU73_Discrete_DpmTable
,
2092 LowSclkInterruptThreshold
),
2093 (uint8_t *)&low_sclk_interrupt_threshold
,
2097 result
= fiji_program_mem_timing_parameters(hwmgr
);
2098 PP_ASSERT_WITH_CODE((result
== 0),
2099 "Failed to program memory timing parameters!",
2104 uint32_t fiji_get_offsetof(uint32_t type
, uint32_t member
)
2107 case SMU_SoftRegisters
:
2109 case HandshakeDisables
:
2110 return offsetof(SMU73_SoftRegisters
, HandshakeDisables
);
2111 case VoltageChangeTimeout
:
2112 return offsetof(SMU73_SoftRegisters
, VoltageChangeTimeout
);
2113 case AverageGraphicsActivity
:
2114 return offsetof(SMU73_SoftRegisters
, AverageGraphicsActivity
);
2116 return offsetof(SMU73_SoftRegisters
, PreVBlankGap
);
2118 return offsetof(SMU73_SoftRegisters
, VBlankTimeout
);
2119 case UcodeLoadStatus
:
2120 return offsetof(SMU73_SoftRegisters
, UcodeLoadStatus
);
2122 case SMU_Discrete_DpmTable
:
2125 return offsetof(SMU73_Discrete_DpmTable
, UvdBootLevel
);
2127 return offsetof(SMU73_Discrete_DpmTable
, VceBootLevel
);
2129 return offsetof(SMU73_Discrete_DpmTable
, SamuBootLevel
);
2130 case LowSclkInterruptThreshold
:
2131 return offsetof(SMU73_Discrete_DpmTable
, LowSclkInterruptThreshold
);
2134 printk(KERN_WARNING
"can't get the offset of type %x member %x\n", type
, member
);
2138 uint32_t fiji_get_mac_definition(uint32_t value
)
2141 case SMU_MAX_LEVELS_GRAPHICS
:
2142 return SMU73_MAX_LEVELS_GRAPHICS
;
2143 case SMU_MAX_LEVELS_MEMORY
:
2144 return SMU73_MAX_LEVELS_MEMORY
;
2145 case SMU_MAX_LEVELS_LINK
:
2146 return SMU73_MAX_LEVELS_LINK
;
2147 case SMU_MAX_ENTRIES_SMIO
:
2148 return SMU73_MAX_ENTRIES_SMIO
;
2149 case SMU_MAX_LEVELS_VDDC
:
2150 return SMU73_MAX_LEVELS_VDDC
;
2151 case SMU_MAX_LEVELS_VDDGFX
:
2152 return SMU73_MAX_LEVELS_VDDGFX
;
2153 case SMU_MAX_LEVELS_VDDCI
:
2154 return SMU73_MAX_LEVELS_VDDCI
;
2155 case SMU_MAX_LEVELS_MVDD
:
2156 return SMU73_MAX_LEVELS_MVDD
;
2159 printk(KERN_WARNING
"can't get the mac of %x\n", value
);
2164 static int fiji_update_uvd_smc_table(struct pp_hwmgr
*hwmgr
)
2166 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
2167 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
2168 struct phm_ppt_v1_information
*table_info
=
2169 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2171 smu_data
->smc_state_table
.UvdBootLevel
= 0;
2172 if (table_info
->mm_dep_table
->count
> 0)
2173 smu_data
->smc_state_table
.UvdBootLevel
=
2174 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
2175 mm_boot_level_offset
= smu_data
->smu7_data
.dpm_table_start
+ offsetof(SMU73_Discrete_DpmTable
,
2177 mm_boot_level_offset
/= 4;
2178 mm_boot_level_offset
*= 4;
2179 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
2180 CGS_IND_REG__SMC
, mm_boot_level_offset
);
2181 mm_boot_level_value
&= 0x00FFFFFF;
2182 mm_boot_level_value
|= smu_data
->smc_state_table
.UvdBootLevel
<< 24;
2183 cgs_write_ind_register(hwmgr
->device
,
2184 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
2186 if (!phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2187 PHM_PlatformCaps_UVDDPM
) ||
2188 phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2189 PHM_PlatformCaps_StablePState
))
2190 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
2191 PPSMC_MSG_UVDDPM_SetEnabledMask
,
2192 (uint32_t)(1 << smu_data
->smc_state_table
.UvdBootLevel
));
2196 static int fiji_update_vce_smc_table(struct pp_hwmgr
*hwmgr
)
2198 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
2199 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
2200 struct phm_ppt_v1_information
*table_info
=
2201 (struct phm_ppt_v1_information
*)(hwmgr
->pptable
);
2203 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2204 PHM_PlatformCaps_StablePState
))
2205 smu_data
->smc_state_table
.VceBootLevel
=
2206 (uint8_t) (table_info
->mm_dep_table
->count
- 1);
2208 smu_data
->smc_state_table
.VceBootLevel
= 0;
2210 mm_boot_level_offset
= smu_data
->smu7_data
.dpm_table_start
+
2211 offsetof(SMU73_Discrete_DpmTable
, VceBootLevel
);
2212 mm_boot_level_offset
/= 4;
2213 mm_boot_level_offset
*= 4;
2214 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
2215 CGS_IND_REG__SMC
, mm_boot_level_offset
);
2216 mm_boot_level_value
&= 0xFF00FFFF;
2217 mm_boot_level_value
|= smu_data
->smc_state_table
.VceBootLevel
<< 16;
2218 cgs_write_ind_register(hwmgr
->device
,
2219 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
2221 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
, PHM_PlatformCaps_StablePState
))
2222 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
2223 PPSMC_MSG_VCEDPM_SetEnabledMask
,
2224 (uint32_t)1 << smu_data
->smc_state_table
.VceBootLevel
);
2228 static int fiji_update_samu_smc_table(struct pp_hwmgr
*hwmgr
)
2230 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
2231 uint32_t mm_boot_level_offset
, mm_boot_level_value
;
2234 smu_data
->smc_state_table
.SamuBootLevel
= 0;
2235 mm_boot_level_offset
= smu_data
->smu7_data
.dpm_table_start
+
2236 offsetof(SMU73_Discrete_DpmTable
, SamuBootLevel
);
2238 mm_boot_level_offset
/= 4;
2239 mm_boot_level_offset
*= 4;
2240 mm_boot_level_value
= cgs_read_ind_register(hwmgr
->device
,
2241 CGS_IND_REG__SMC
, mm_boot_level_offset
);
2242 mm_boot_level_value
&= 0xFFFFFF00;
2243 mm_boot_level_value
|= smu_data
->smc_state_table
.SamuBootLevel
<< 0;
2244 cgs_write_ind_register(hwmgr
->device
,
2245 CGS_IND_REG__SMC
, mm_boot_level_offset
, mm_boot_level_value
);
2247 if (phm_cap_enabled(hwmgr
->platform_descriptor
.platformCaps
,
2248 PHM_PlatformCaps_StablePState
))
2249 smum_send_msg_to_smc_with_parameter(hwmgr
->smumgr
,
2250 PPSMC_MSG_SAMUDPM_SetEnabledMask
,
2251 (uint32_t)(1 << smu_data
->smc_state_table
.SamuBootLevel
));
2255 int fiji_update_smc_table(struct pp_hwmgr
*hwmgr
, uint32_t type
)
2259 fiji_update_uvd_smc_table(hwmgr
);
2262 fiji_update_vce_smc_table(hwmgr
);
2264 case SMU_SAMU_TABLE
:
2265 fiji_update_samu_smc_table(hwmgr
);
2275 * Get the location of various tables inside the FW image.
2277 * @param hwmgr the address of the powerplay hardware manager.
2280 int fiji_process_firmware_header(struct pp_hwmgr
*hwmgr
)
2282 struct smu7_hwmgr
*data
= (struct smu7_hwmgr
*)(hwmgr
->backend
);
2283 struct fiji_smumgr
*smu_data
= (struct fiji_smumgr
*)(hwmgr
->smumgr
->backend
);
2288 result
= smu7_read_smc_sram_dword(hwmgr
->smumgr
,
2289 SMU7_FIRMWARE_HEADER_LOCATION
+
2290 offsetof(SMU73_Firmware_Header
, DpmTable
),
2294 smu_data
->smu7_data
.dpm_table_start
= tmp
;
2296 error
|= (0 != result
);
2298 result
= smu7_read_smc_sram_dword(hwmgr
->smumgr
,
2299 SMU7_FIRMWARE_HEADER_LOCATION
+
2300 offsetof(SMU73_Firmware_Header
, SoftRegisters
),
2304 data
->soft_regs_start
= tmp
;
2305 smu_data
->smu7_data
.soft_regs_start
= tmp
;
2308 error
|= (0 != result
);
2310 result
= smu7_read_smc_sram_dword(hwmgr
->smumgr
,
2311 SMU7_FIRMWARE_HEADER_LOCATION
+
2312 offsetof(SMU73_Firmware_Header
, mcRegisterTable
),
2316 smu_data
->smu7_data
.mc_reg_table_start
= tmp
;
2318 result
= smu7_read_smc_sram_dword(hwmgr
->smumgr
,
2319 SMU7_FIRMWARE_HEADER_LOCATION
+
2320 offsetof(SMU73_Firmware_Header
, FanTable
),
2324 smu_data
->smu7_data
.fan_table_start
= tmp
;
2326 error
|= (0 != result
);
2328 result
= smu7_read_smc_sram_dword(hwmgr
->smumgr
,
2329 SMU7_FIRMWARE_HEADER_LOCATION
+
2330 offsetof(SMU73_Firmware_Header
, mcArbDramTimingTable
),
2334 smu_data
->smu7_data
.arb_table_start
= tmp
;
2336 error
|= (0 != result
);
2338 result
= smu7_read_smc_sram_dword(hwmgr
->smumgr
,
2339 SMU7_FIRMWARE_HEADER_LOCATION
+
2340 offsetof(SMU73_Firmware_Header
, Version
),
2344 hwmgr
->microcode_version_info
.SMC
= tmp
;
2346 error
|= (0 != result
);
2348 return error
? -1 : 0;
2351 int fiji_initialize_mc_reg_table(struct pp_hwmgr
*hwmgr
)
2354 /* Program additional LP registers
2355 * that are no longer programmed by VBIOS
2357 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING_LP
,
2358 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RAS_TIMING
));
2359 cgs_write_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING_LP
,
2360 cgs_read_register(hwmgr
->device
, mmMC_SEQ_CAS_TIMING
));
2361 cgs_write_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2_LP
,
2362 cgs_read_register(hwmgr
->device
, mmMC_SEQ_MISC_TIMING2
));
2363 cgs_write_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1_LP
,
2364 cgs_read_register(hwmgr
->device
, mmMC_SEQ_WR_CTL_D1
));
2365 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0_LP
,
2366 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D0
));
2367 cgs_write_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1_LP
,
2368 cgs_read_register(hwmgr
->device
, mmMC_SEQ_RD_CTL_D1
));
2369 cgs_write_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING_LP
,
2370 cgs_read_register(hwmgr
->device
, mmMC_SEQ_PMG_TIMING
));
2375 bool fiji_is_dpm_running(struct pp_hwmgr
*hwmgr
)
2377 return (1 == PHM_READ_INDIRECT_FIELD(hwmgr
->device
,
2378 CGS_IND_REG__SMC
, FEATURE_STATUS
, VOLTAGE_CONTROLLER_ON
))