]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c
Merge branch 'vmwgfx-next' of git://people.freedesktop.org/~thomash/linux into drm-next
[linux.git] / drivers / gpu / drm / amd / powerplay / hwmgr / smu8_hwmgr.c
1 /*
2  * Copyright 2015 Advanced Micro Devices, Inc.
3  *
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:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
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.
21  *
22  */
23 #include "pp_debug.h"
24 #include <linux/types.h>
25 #include <linux/kernel.h>
26 #include <linux/slab.h>
27 #include "atom-types.h"
28 #include "atombios.h"
29 #include "processpptables.h"
30 #include "cgs_common.h"
31 #include "smu/smu_8_0_d.h"
32 #include "smu8_fusion.h"
33 #include "smu/smu_8_0_sh_mask.h"
34 #include "smumgr.h"
35 #include "hwmgr.h"
36 #include "hardwaremanager.h"
37 #include "cz_ppsmc.h"
38 #include "smu8_hwmgr.h"
39 #include "power_state.h"
40 #include "pp_thermal.h"
41
42 #define ixSMUSVI_NB_CURRENTVID 0xD8230044
43 #define CURRENT_NB_VID_MASK 0xff000000
44 #define CURRENT_NB_VID__SHIFT 24
45 #define ixSMUSVI_GFX_CURRENTVID  0xD8230048
46 #define CURRENT_GFX_VID_MASK 0xff000000
47 #define CURRENT_GFX_VID__SHIFT 24
48
49 static const unsigned long smu8_magic = (unsigned long) PHM_Cz_Magic;
50
51 static struct smu8_power_state *cast_smu8_power_state(struct pp_hw_power_state *hw_ps)
52 {
53         if (smu8_magic != hw_ps->magic)
54                 return NULL;
55
56         return (struct smu8_power_state *)hw_ps;
57 }
58
59 static const struct smu8_power_state *cast_const_smu8_power_state(
60                                 const struct pp_hw_power_state *hw_ps)
61 {
62         if (smu8_magic != hw_ps->magic)
63                 return NULL;
64
65         return (struct smu8_power_state *)hw_ps;
66 }
67
68 static uint32_t smu8_get_eclk_level(struct pp_hwmgr *hwmgr,
69                                         uint32_t clock, uint32_t msg)
70 {
71         int i = 0;
72         struct phm_vce_clock_voltage_dependency_table *ptable =
73                 hwmgr->dyn_state.vce_clock_voltage_dependency_table;
74
75         switch (msg) {
76         case PPSMC_MSG_SetEclkSoftMin:
77         case PPSMC_MSG_SetEclkHardMin:
78                 for (i = 0; i < (int)ptable->count; i++) {
79                         if (clock <= ptable->entries[i].ecclk)
80                                 break;
81                 }
82                 break;
83
84         case PPSMC_MSG_SetEclkSoftMax:
85         case PPSMC_MSG_SetEclkHardMax:
86                 for (i = ptable->count - 1; i >= 0; i--) {
87                         if (clock >= ptable->entries[i].ecclk)
88                                 break;
89                 }
90                 break;
91
92         default:
93                 break;
94         }
95
96         return i;
97 }
98
99 static uint32_t smu8_get_sclk_level(struct pp_hwmgr *hwmgr,
100                                 uint32_t clock, uint32_t msg)
101 {
102         int i = 0;
103         struct phm_clock_voltage_dependency_table *table =
104                                 hwmgr->dyn_state.vddc_dependency_on_sclk;
105
106         switch (msg) {
107         case PPSMC_MSG_SetSclkSoftMin:
108         case PPSMC_MSG_SetSclkHardMin:
109                 for (i = 0; i < (int)table->count; i++) {
110                         if (clock <= table->entries[i].clk)
111                                 break;
112                 }
113                 break;
114
115         case PPSMC_MSG_SetSclkSoftMax:
116         case PPSMC_MSG_SetSclkHardMax:
117                 for (i = table->count - 1; i >= 0; i--) {
118                         if (clock >= table->entries[i].clk)
119                                 break;
120                 }
121                 break;
122
123         default:
124                 break;
125         }
126         return i;
127 }
128
129 static uint32_t smu8_get_uvd_level(struct pp_hwmgr *hwmgr,
130                                         uint32_t clock, uint32_t msg)
131 {
132         int i = 0;
133         struct phm_uvd_clock_voltage_dependency_table *ptable =
134                 hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
135
136         switch (msg) {
137         case PPSMC_MSG_SetUvdSoftMin:
138         case PPSMC_MSG_SetUvdHardMin:
139                 for (i = 0; i < (int)ptable->count; i++) {
140                         if (clock <= ptable->entries[i].vclk)
141                                 break;
142                 }
143                 break;
144
145         case PPSMC_MSG_SetUvdSoftMax:
146         case PPSMC_MSG_SetUvdHardMax:
147                 for (i = ptable->count - 1; i >= 0; i--) {
148                         if (clock >= ptable->entries[i].vclk)
149                                 break;
150                 }
151                 break;
152
153         default:
154                 break;
155         }
156
157         return i;
158 }
159
160 static uint32_t smu8_get_max_sclk_level(struct pp_hwmgr *hwmgr)
161 {
162         struct smu8_hwmgr *data = hwmgr->backend;
163
164         if (data->max_sclk_level == 0) {
165                 smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxSclkLevel);
166                 data->max_sclk_level = smum_get_argument(hwmgr) + 1;
167         }
168
169         return data->max_sclk_level;
170 }
171
172 static int smu8_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
173 {
174         struct smu8_hwmgr *data = hwmgr->backend;
175         struct amdgpu_device *adev = hwmgr->adev;
176
177         data->gfx_ramp_step = 256*25/100;
178         data->gfx_ramp_delay = 1; /* by default, we delay 1us */
179
180         data->mgcg_cgtt_local0 = 0x00000000;
181         data->mgcg_cgtt_local1 = 0x00000000;
182         data->clock_slow_down_freq = 25000;
183         data->skip_clock_slow_down = 1;
184         data->enable_nb_ps_policy = 1; /* disable until UNB is ready, Enabled */
185         data->voltage_drop_in_dce_power_gating = 0; /* disable until fully verified */
186         data->voting_rights_clients = 0x00C00033;
187         data->static_screen_threshold = 8;
188         data->ddi_power_gating_disabled = 0;
189         data->bapm_enabled = 1;
190         data->voltage_drop_threshold = 0;
191         data->gfx_power_gating_threshold = 500;
192         data->vce_slow_sclk_threshold = 20000;
193         data->dce_slow_sclk_threshold = 30000;
194         data->disable_driver_thermal_policy = 1;
195         data->disable_nb_ps3_in_battery = 0;
196
197         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
198                                                         PHM_PlatformCaps_ABM);
199
200         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
201                                     PHM_PlatformCaps_NonABMSupportInPPLib);
202
203         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
204                                         PHM_PlatformCaps_DynamicM3Arbiter);
205
206         data->override_dynamic_mgpg = 1;
207
208         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
209                                   PHM_PlatformCaps_DynamicPatchPowerState);
210
211         data->thermal_auto_throttling_treshold = 0;
212         data->tdr_clock = 0;
213         data->disable_gfx_power_gating_in_uvd = 0;
214
215         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
216                                         PHM_PlatformCaps_DynamicUVDState);
217
218         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
219                         PHM_PlatformCaps_UVDDPM);
220         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
221                         PHM_PlatformCaps_VCEDPM);
222
223         data->cc6_settings.cpu_cc6_disable = false;
224         data->cc6_settings.cpu_pstate_disable = false;
225         data->cc6_settings.nb_pstate_switch_disable = false;
226         data->cc6_settings.cpu_pstate_separation_time = 0;
227
228         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
229                                    PHM_PlatformCaps_DisableVoltageIsland);
230
231         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
232                       PHM_PlatformCaps_UVDPowerGating);
233         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
234                       PHM_PlatformCaps_VCEPowerGating);
235
236         if (adev->pg_flags & AMD_PG_SUPPORT_UVD)
237                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
238                               PHM_PlatformCaps_UVDPowerGating);
239         if (adev->pg_flags & AMD_PG_SUPPORT_VCE)
240                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
241                               PHM_PlatformCaps_VCEPowerGating);
242
243
244         return 0;
245 }
246
247 /* convert form 8bit vid to real voltage in mV*4 */
248 static uint32_t smu8_convert_8Bit_index_to_voltage(
249                         struct pp_hwmgr *hwmgr, uint16_t voltage)
250 {
251         return 6200 - (voltage * 25);
252 }
253
254 static int smu8_construct_max_power_limits_table(struct pp_hwmgr *hwmgr,
255                         struct phm_clock_and_voltage_limits *table)
256 {
257         struct smu8_hwmgr *data = hwmgr->backend;
258         struct smu8_sys_info *sys_info = &data->sys_info;
259         struct phm_clock_voltage_dependency_table *dep_table =
260                                 hwmgr->dyn_state.vddc_dependency_on_sclk;
261
262         if (dep_table->count > 0) {
263                 table->sclk = dep_table->entries[dep_table->count-1].clk;
264                 table->vddc = smu8_convert_8Bit_index_to_voltage(hwmgr,
265                    (uint16_t)dep_table->entries[dep_table->count-1].v);
266         }
267         table->mclk = sys_info->nbp_memory_clock[0];
268         return 0;
269 }
270
271 static int smu8_init_dynamic_state_adjustment_rule_settings(
272                         struct pp_hwmgr *hwmgr,
273                         ATOM_CLK_VOLT_CAPABILITY *disp_voltage_table)
274 {
275         uint32_t table_size =
276                 sizeof(struct phm_clock_voltage_dependency_table) +
277                 (7 * sizeof(struct phm_clock_voltage_dependency_record));
278
279         struct phm_clock_voltage_dependency_table *table_clk_vlt =
280                                         kzalloc(table_size, GFP_KERNEL);
281
282         if (NULL == table_clk_vlt) {
283                 pr_err("Can not allocate memory!\n");
284                 return -ENOMEM;
285         }
286
287         table_clk_vlt->count = 8;
288         table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0;
289         table_clk_vlt->entries[0].v = 0;
290         table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1;
291         table_clk_vlt->entries[1].v = 1;
292         table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2;
293         table_clk_vlt->entries[2].v = 2;
294         table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3;
295         table_clk_vlt->entries[3].v = 3;
296         table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4;
297         table_clk_vlt->entries[4].v = 4;
298         table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5;
299         table_clk_vlt->entries[5].v = 5;
300         table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6;
301         table_clk_vlt->entries[6].v = 6;
302         table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7;
303         table_clk_vlt->entries[7].v = 7;
304         hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
305
306         return 0;
307 }
308
309 static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr)
310 {
311         struct smu8_hwmgr *data = hwmgr->backend;
312         ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info = NULL;
313         uint32_t i;
314         int result = 0;
315         uint8_t frev, crev;
316         uint16_t size;
317
318         info = (ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *)smu_atom_get_data_table(hwmgr->adev,
319                         GetIndexIntoMasterTable(DATA, IntegratedSystemInfo),
320                         &size, &frev, &crev);
321
322         if (info == NULL) {
323                 pr_err("Could not retrieve the Integrated System Info Table!\n");
324                 return -EINVAL;
325         }
326
327         if (crev != 9) {
328                 pr_err("Unsupported IGP table: %d %d\n", frev, crev);
329                 return -EINVAL;
330         }
331
332         data->sys_info.bootup_uma_clock =
333                                    le32_to_cpu(info->ulBootUpUMAClock);
334
335         data->sys_info.bootup_engine_clock =
336                                 le32_to_cpu(info->ulBootUpEngineClock);
337
338         data->sys_info.dentist_vco_freq =
339                                    le32_to_cpu(info->ulDentistVCOFreq);
340
341         data->sys_info.system_config =
342                                      le32_to_cpu(info->ulSystemConfig);
343
344         data->sys_info.bootup_nb_voltage_index =
345                                   le16_to_cpu(info->usBootUpNBVoltage);
346
347         data->sys_info.htc_hyst_lmt =
348                         (info->ucHtcHystLmt == 0) ? 5 : info->ucHtcHystLmt;
349
350         data->sys_info.htc_tmp_lmt =
351                         (info->ucHtcTmpLmt == 0) ? 203 : info->ucHtcTmpLmt;
352
353         if (data->sys_info.htc_tmp_lmt <=
354                         data->sys_info.htc_hyst_lmt) {
355                 pr_err("The htcTmpLmt should be larger than htcHystLmt.\n");
356                 return -EINVAL;
357         }
358
359         data->sys_info.nb_dpm_enable =
360                                 data->enable_nb_ps_policy &&
361                                 (le32_to_cpu(info->ulSystemConfig) >> 3 & 0x1);
362
363         for (i = 0; i < SMU8_NUM_NBPSTATES; i++) {
364                 if (i < SMU8_NUM_NBPMEMORYCLOCK) {
365                         data->sys_info.nbp_memory_clock[i] =
366                           le32_to_cpu(info->ulNbpStateMemclkFreq[i]);
367                 }
368                 data->sys_info.nbp_n_clock[i] =
369                             le32_to_cpu(info->ulNbpStateNClkFreq[i]);
370         }
371
372         for (i = 0; i < MAX_DISPLAY_CLOCK_LEVEL; i++) {
373                 data->sys_info.display_clock[i] =
374                                         le32_to_cpu(info->sDispClkVoltageMapping[i].ulMaximumSupportedCLK);
375         }
376
377         /* Here use 4 levels, make sure not exceed */
378         for (i = 0; i < SMU8_NUM_NBPSTATES; i++) {
379                 data->sys_info.nbp_voltage_index[i] =
380                              le16_to_cpu(info->usNBPStateVoltage[i]);
381         }
382
383         if (!data->sys_info.nb_dpm_enable) {
384                 for (i = 1; i < SMU8_NUM_NBPSTATES; i++) {
385                         if (i < SMU8_NUM_NBPMEMORYCLOCK) {
386                                 data->sys_info.nbp_memory_clock[i] =
387                                     data->sys_info.nbp_memory_clock[0];
388                         }
389                         data->sys_info.nbp_n_clock[i] =
390                                     data->sys_info.nbp_n_clock[0];
391                         data->sys_info.nbp_voltage_index[i] =
392                                     data->sys_info.nbp_voltage_index[0];
393                 }
394         }
395
396         if (le32_to_cpu(info->ulGPUCapInfo) &
397                 SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) {
398                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
399                                     PHM_PlatformCaps_EnableDFSBypass);
400         }
401
402         data->sys_info.uma_channel_number = info->ucUMAChannelNumber;
403
404         smu8_construct_max_power_limits_table (hwmgr,
405                                     &hwmgr->dyn_state.max_clock_voltage_on_ac);
406
407         smu8_init_dynamic_state_adjustment_rule_settings(hwmgr,
408                                     &info->sDISPCLK_Voltage[0]);
409
410         return result;
411 }
412
413 static int smu8_construct_boot_state(struct pp_hwmgr *hwmgr)
414 {
415         struct smu8_hwmgr *data = hwmgr->backend;
416
417         data->boot_power_level.engineClock =
418                                 data->sys_info.bootup_engine_clock;
419
420         data->boot_power_level.vddcIndex =
421                         (uint8_t)data->sys_info.bootup_nb_voltage_index;
422
423         data->boot_power_level.dsDividerIndex = 0;
424         data->boot_power_level.ssDividerIndex = 0;
425         data->boot_power_level.allowGnbSlow = 1;
426         data->boot_power_level.forceNBPstate = 0;
427         data->boot_power_level.hysteresis_up = 0;
428         data->boot_power_level.numSIMDToPowerDown = 0;
429         data->boot_power_level.display_wm = 0;
430         data->boot_power_level.vce_wm = 0;
431
432         return 0;
433 }
434
435 static int smu8_upload_pptable_to_smu(struct pp_hwmgr *hwmgr)
436 {
437         struct SMU8_Fusion_ClkTable *clock_table;
438         int ret;
439         uint32_t i;
440         void *table = NULL;
441         pp_atomctrl_clock_dividers_kong dividers;
442
443         struct phm_clock_voltage_dependency_table *vddc_table =
444                 hwmgr->dyn_state.vddc_dependency_on_sclk;
445         struct phm_clock_voltage_dependency_table *vdd_gfx_table =
446                 hwmgr->dyn_state.vdd_gfx_dependency_on_sclk;
447         struct phm_acp_clock_voltage_dependency_table *acp_table =
448                 hwmgr->dyn_state.acp_clock_voltage_dependency_table;
449         struct phm_uvd_clock_voltage_dependency_table *uvd_table =
450                 hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
451         struct phm_vce_clock_voltage_dependency_table *vce_table =
452                 hwmgr->dyn_state.vce_clock_voltage_dependency_table;
453
454         if (!hwmgr->need_pp_table_upload)
455                 return 0;
456
457         ret = smum_download_powerplay_table(hwmgr, &table);
458
459         PP_ASSERT_WITH_CODE((0 == ret && NULL != table),
460                             "Fail to get clock table from SMU!", return -EINVAL;);
461
462         clock_table = (struct SMU8_Fusion_ClkTable *)table;
463
464         /* patch clock table */
465         PP_ASSERT_WITH_CODE((vddc_table->count <= SMU8_MAX_HARDWARE_POWERLEVELS),
466                             "Dependency table entry exceeds max limit!", return -EINVAL;);
467         PP_ASSERT_WITH_CODE((vdd_gfx_table->count <= SMU8_MAX_HARDWARE_POWERLEVELS),
468                             "Dependency table entry exceeds max limit!", return -EINVAL;);
469         PP_ASSERT_WITH_CODE((acp_table->count <= SMU8_MAX_HARDWARE_POWERLEVELS),
470                             "Dependency table entry exceeds max limit!", return -EINVAL;);
471         PP_ASSERT_WITH_CODE((uvd_table->count <= SMU8_MAX_HARDWARE_POWERLEVELS),
472                             "Dependency table entry exceeds max limit!", return -EINVAL;);
473         PP_ASSERT_WITH_CODE((vce_table->count <= SMU8_MAX_HARDWARE_POWERLEVELS),
474                             "Dependency table entry exceeds max limit!", return -EINVAL;);
475
476         for (i = 0; i < SMU8_MAX_HARDWARE_POWERLEVELS; i++) {
477
478                 /* vddc_sclk */
479                 clock_table->SclkBreakdownTable.ClkLevel[i].GnbVid =
480                         (i < vddc_table->count) ? (uint8_t)vddc_table->entries[i].v : 0;
481                 clock_table->SclkBreakdownTable.ClkLevel[i].Frequency =
482                         (i < vddc_table->count) ? vddc_table->entries[i].clk : 0;
483
484                 atomctrl_get_engine_pll_dividers_kong(hwmgr,
485                                                       clock_table->SclkBreakdownTable.ClkLevel[i].Frequency,
486                                                       &dividers);
487
488                 clock_table->SclkBreakdownTable.ClkLevel[i].DfsDid =
489                         (uint8_t)dividers.pll_post_divider;
490
491                 /* vddgfx_sclk */
492                 clock_table->SclkBreakdownTable.ClkLevel[i].GfxVid =
493                         (i < vdd_gfx_table->count) ? (uint8_t)vdd_gfx_table->entries[i].v : 0;
494
495                 /* acp breakdown */
496                 clock_table->AclkBreakdownTable.ClkLevel[i].GfxVid =
497                         (i < acp_table->count) ? (uint8_t)acp_table->entries[i].v : 0;
498                 clock_table->AclkBreakdownTable.ClkLevel[i].Frequency =
499                         (i < acp_table->count) ? acp_table->entries[i].acpclk : 0;
500
501                 atomctrl_get_engine_pll_dividers_kong(hwmgr,
502                                                       clock_table->AclkBreakdownTable.ClkLevel[i].Frequency,
503                                                       &dividers);
504
505                 clock_table->AclkBreakdownTable.ClkLevel[i].DfsDid =
506                         (uint8_t)dividers.pll_post_divider;
507
508
509                 /* uvd breakdown */
510                 clock_table->VclkBreakdownTable.ClkLevel[i].GfxVid =
511                         (i < uvd_table->count) ? (uint8_t)uvd_table->entries[i].v : 0;
512                 clock_table->VclkBreakdownTable.ClkLevel[i].Frequency =
513                         (i < uvd_table->count) ? uvd_table->entries[i].vclk : 0;
514
515                 atomctrl_get_engine_pll_dividers_kong(hwmgr,
516                                                       clock_table->VclkBreakdownTable.ClkLevel[i].Frequency,
517                                                       &dividers);
518
519                 clock_table->VclkBreakdownTable.ClkLevel[i].DfsDid =
520                         (uint8_t)dividers.pll_post_divider;
521
522                 clock_table->DclkBreakdownTable.ClkLevel[i].GfxVid =
523                         (i < uvd_table->count) ? (uint8_t)uvd_table->entries[i].v : 0;
524                 clock_table->DclkBreakdownTable.ClkLevel[i].Frequency =
525                         (i < uvd_table->count) ? uvd_table->entries[i].dclk : 0;
526
527                 atomctrl_get_engine_pll_dividers_kong(hwmgr,
528                                                       clock_table->DclkBreakdownTable.ClkLevel[i].Frequency,
529                                                       &dividers);
530
531                 clock_table->DclkBreakdownTable.ClkLevel[i].DfsDid =
532                         (uint8_t)dividers.pll_post_divider;
533
534                 /* vce breakdown */
535                 clock_table->EclkBreakdownTable.ClkLevel[i].GfxVid =
536                         (i < vce_table->count) ? (uint8_t)vce_table->entries[i].v : 0;
537                 clock_table->EclkBreakdownTable.ClkLevel[i].Frequency =
538                         (i < vce_table->count) ? vce_table->entries[i].ecclk : 0;
539
540
541                 atomctrl_get_engine_pll_dividers_kong(hwmgr,
542                                                       clock_table->EclkBreakdownTable.ClkLevel[i].Frequency,
543                                                       &dividers);
544
545                 clock_table->EclkBreakdownTable.ClkLevel[i].DfsDid =
546                         (uint8_t)dividers.pll_post_divider;
547
548         }
549         ret = smum_upload_powerplay_table(hwmgr);
550
551         return ret;
552 }
553
554 static int smu8_init_sclk_limit(struct pp_hwmgr *hwmgr)
555 {
556         struct smu8_hwmgr *data = hwmgr->backend;
557         struct phm_clock_voltage_dependency_table *table =
558                                         hwmgr->dyn_state.vddc_dependency_on_sclk;
559         unsigned long clock = 0, level;
560
561         if (NULL == table || table->count <= 0)
562                 return -EINVAL;
563
564         data->sclk_dpm.soft_min_clk = table->entries[0].clk;
565         data->sclk_dpm.hard_min_clk = table->entries[0].clk;
566
567         level = smu8_get_max_sclk_level(hwmgr) - 1;
568
569         if (level < table->count)
570                 clock = table->entries[level].clk;
571         else
572                 clock = table->entries[table->count - 1].clk;
573
574         data->sclk_dpm.soft_max_clk = clock;
575         data->sclk_dpm.hard_max_clk = clock;
576
577         return 0;
578 }
579
580 static int smu8_init_uvd_limit(struct pp_hwmgr *hwmgr)
581 {
582         struct smu8_hwmgr *data = hwmgr->backend;
583         struct phm_uvd_clock_voltage_dependency_table *table =
584                                 hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
585         unsigned long clock = 0, level;
586
587         if (NULL == table || table->count <= 0)
588                 return -EINVAL;
589
590         data->uvd_dpm.soft_min_clk = 0;
591         data->uvd_dpm.hard_min_clk = 0;
592
593         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxUvdLevel);
594         level = smum_get_argument(hwmgr);
595
596         if (level < table->count)
597                 clock = table->entries[level].vclk;
598         else
599                 clock = table->entries[table->count - 1].vclk;
600
601         data->uvd_dpm.soft_max_clk = clock;
602         data->uvd_dpm.hard_max_clk = clock;
603
604         return 0;
605 }
606
607 static int smu8_init_vce_limit(struct pp_hwmgr *hwmgr)
608 {
609         struct smu8_hwmgr *data = hwmgr->backend;
610         struct phm_vce_clock_voltage_dependency_table *table =
611                                 hwmgr->dyn_state.vce_clock_voltage_dependency_table;
612         unsigned long clock = 0, level;
613
614         if (NULL == table || table->count <= 0)
615                 return -EINVAL;
616
617         data->vce_dpm.soft_min_clk = 0;
618         data->vce_dpm.hard_min_clk = 0;
619
620         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxEclkLevel);
621         level = smum_get_argument(hwmgr);
622
623         if (level < table->count)
624                 clock = table->entries[level].ecclk;
625         else
626                 clock = table->entries[table->count - 1].ecclk;
627
628         data->vce_dpm.soft_max_clk = clock;
629         data->vce_dpm.hard_max_clk = clock;
630
631         return 0;
632 }
633
634 static int smu8_init_acp_limit(struct pp_hwmgr *hwmgr)
635 {
636         struct smu8_hwmgr *data = hwmgr->backend;
637         struct phm_acp_clock_voltage_dependency_table *table =
638                                 hwmgr->dyn_state.acp_clock_voltage_dependency_table;
639         unsigned long clock = 0, level;
640
641         if (NULL == table || table->count <= 0)
642                 return -EINVAL;
643
644         data->acp_dpm.soft_min_clk = 0;
645         data->acp_dpm.hard_min_clk = 0;
646
647         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxAclkLevel);
648         level = smum_get_argument(hwmgr);
649
650         if (level < table->count)
651                 clock = table->entries[level].acpclk;
652         else
653                 clock = table->entries[table->count - 1].acpclk;
654
655         data->acp_dpm.soft_max_clk = clock;
656         data->acp_dpm.hard_max_clk = clock;
657         return 0;
658 }
659
660 static void smu8_init_power_gate_state(struct pp_hwmgr *hwmgr)
661 {
662         struct smu8_hwmgr *data = hwmgr->backend;
663
664         data->uvd_power_gated = false;
665         data->vce_power_gated = false;
666         data->samu_power_gated = false;
667 #ifdef CONFIG_DRM_AMD_ACP
668         data->acp_power_gated = false;
669 #else
670         smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ACPPowerOFF);
671         data->acp_power_gated = true;
672 #endif
673
674 }
675
676 static void smu8_init_sclk_threshold(struct pp_hwmgr *hwmgr)
677 {
678         struct smu8_hwmgr *data = hwmgr->backend;
679
680         data->low_sclk_interrupt_threshold = 0;
681 }
682
683 static int smu8_update_sclk_limit(struct pp_hwmgr *hwmgr)
684 {
685         struct smu8_hwmgr *data = hwmgr->backend;
686         struct phm_clock_voltage_dependency_table *table =
687                                         hwmgr->dyn_state.vddc_dependency_on_sclk;
688
689         unsigned long clock = 0;
690         unsigned long level;
691         unsigned long stable_pstate_sclk;
692         unsigned long percentage;
693
694         data->sclk_dpm.soft_min_clk = table->entries[0].clk;
695         level = smu8_get_max_sclk_level(hwmgr) - 1;
696
697         if (level < table->count)
698                 data->sclk_dpm.soft_max_clk  = table->entries[level].clk;
699         else
700                 data->sclk_dpm.soft_max_clk  = table->entries[table->count - 1].clk;
701
702         clock = hwmgr->display_config->min_core_set_clock;
703         if (clock == 0)
704                 pr_debug("min_core_set_clock not set\n");
705
706         if (data->sclk_dpm.hard_min_clk != clock) {
707                 data->sclk_dpm.hard_min_clk = clock;
708
709                 smum_send_msg_to_smc_with_parameter(hwmgr,
710                                                 PPSMC_MSG_SetSclkHardMin,
711                                                  smu8_get_sclk_level(hwmgr,
712                                         data->sclk_dpm.hard_min_clk,
713                                              PPSMC_MSG_SetSclkHardMin));
714         }
715
716         clock = data->sclk_dpm.soft_min_clk;
717
718         /* update minimum clocks for Stable P-State feature */
719         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
720                                      PHM_PlatformCaps_StablePState)) {
721                 percentage = 75;
722                 /*Sclk - calculate sclk value based on percentage and find FLOOR sclk from VddcDependencyOnSCLK table  */
723                 stable_pstate_sclk = (hwmgr->dyn_state.max_clock_voltage_on_ac.mclk *
724                                         percentage) / 100;
725
726                 if (clock < stable_pstate_sclk)
727                         clock = stable_pstate_sclk;
728         }
729
730         if (data->sclk_dpm.soft_min_clk != clock) {
731                 data->sclk_dpm.soft_min_clk = clock;
732                 smum_send_msg_to_smc_with_parameter(hwmgr,
733                                                 PPSMC_MSG_SetSclkSoftMin,
734                                                 smu8_get_sclk_level(hwmgr,
735                                         data->sclk_dpm.soft_min_clk,
736                                              PPSMC_MSG_SetSclkSoftMin));
737         }
738
739         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
740                                     PHM_PlatformCaps_StablePState) &&
741                          data->sclk_dpm.soft_max_clk != clock) {
742                 data->sclk_dpm.soft_max_clk = clock;
743                 smum_send_msg_to_smc_with_parameter(hwmgr,
744                                                 PPSMC_MSG_SetSclkSoftMax,
745                                                 smu8_get_sclk_level(hwmgr,
746                                         data->sclk_dpm.soft_max_clk,
747                                         PPSMC_MSG_SetSclkSoftMax));
748         }
749
750         return 0;
751 }
752
753 static int smu8_set_deep_sleep_sclk_threshold(struct pp_hwmgr *hwmgr)
754 {
755         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
756                                 PHM_PlatformCaps_SclkDeepSleep)) {
757                 uint32_t clks = hwmgr->display_config->min_core_set_clock_in_sr;
758                 if (clks == 0)
759                         clks = SMU8_MIN_DEEP_SLEEP_SCLK;
760
761                 PP_DBG_LOG("Setting Deep Sleep Clock: %d\n", clks);
762
763                 smum_send_msg_to_smc_with_parameter(hwmgr,
764                                 PPSMC_MSG_SetMinDeepSleepSclk,
765                                 clks);
766         }
767
768         return 0;
769 }
770
771 static int smu8_set_watermark_threshold(struct pp_hwmgr *hwmgr)
772 {
773         struct smu8_hwmgr *data =
774                                   hwmgr->backend;
775
776         smum_send_msg_to_smc_with_parameter(hwmgr,
777                                         PPSMC_MSG_SetWatermarkFrequency,
778                                         data->sclk_dpm.soft_max_clk);
779
780         return 0;
781 }
782
783 static int smu8_nbdpm_pstate_enable_disable(struct pp_hwmgr *hwmgr, bool enable, bool lock)
784 {
785         struct smu8_hwmgr *hw_data = hwmgr->backend;
786
787         if (hw_data->is_nb_dpm_enabled) {
788                 if (enable) {
789                         PP_DBG_LOG("enable Low Memory PState.\n");
790
791                         return smum_send_msg_to_smc_with_parameter(hwmgr,
792                                                 PPSMC_MSG_EnableLowMemoryPstate,
793                                                 (lock ? 1 : 0));
794                 } else {
795                         PP_DBG_LOG("disable Low Memory PState.\n");
796
797                         return smum_send_msg_to_smc_with_parameter(hwmgr,
798                                                 PPSMC_MSG_DisableLowMemoryPstate,
799                                                 (lock ? 1 : 0));
800                 }
801         }
802
803         return 0;
804 }
805
806 static int smu8_disable_nb_dpm(struct pp_hwmgr *hwmgr)
807 {
808         int ret = 0;
809
810         struct smu8_hwmgr *data = hwmgr->backend;
811         unsigned long dpm_features = 0;
812
813         if (data->is_nb_dpm_enabled) {
814                 smu8_nbdpm_pstate_enable_disable(hwmgr, true, true);
815                 dpm_features |= NB_DPM_MASK;
816                 ret = smum_send_msg_to_smc_with_parameter(
817                                                           hwmgr,
818                                                           PPSMC_MSG_DisableAllSmuFeatures,
819                                                           dpm_features);
820                 if (ret == 0)
821                         data->is_nb_dpm_enabled = false;
822         }
823
824         return ret;
825 }
826
827 static int smu8_enable_nb_dpm(struct pp_hwmgr *hwmgr)
828 {
829         int ret = 0;
830
831         struct smu8_hwmgr *data = hwmgr->backend;
832         unsigned long dpm_features = 0;
833
834         if (!data->is_nb_dpm_enabled) {
835                 PP_DBG_LOG("enabling ALL SMU features.\n");
836                 dpm_features |= NB_DPM_MASK;
837                 ret = smum_send_msg_to_smc_with_parameter(
838                                                           hwmgr,
839                                                           PPSMC_MSG_EnableAllSmuFeatures,
840                                                           dpm_features);
841                 if (ret == 0)
842                         data->is_nb_dpm_enabled = true;
843         }
844
845         return ret;
846 }
847
848 static int smu8_update_low_mem_pstate(struct pp_hwmgr *hwmgr, const void *input)
849 {
850         bool disable_switch;
851         bool enable_low_mem_state;
852         struct smu8_hwmgr *hw_data = hwmgr->backend;
853         const struct phm_set_power_state_input *states = (struct phm_set_power_state_input *)input;
854         const struct smu8_power_state *pnew_state = cast_const_smu8_power_state(states->pnew_state);
855
856         if (hw_data->sys_info.nb_dpm_enable) {
857                 disable_switch = hw_data->cc6_settings.nb_pstate_switch_disable ? true : false;
858                 enable_low_mem_state = hw_data->cc6_settings.nb_pstate_switch_disable ? false : true;
859
860                 if (pnew_state->action == FORCE_HIGH)
861                         smu8_nbdpm_pstate_enable_disable(hwmgr, false, disable_switch);
862                 else if (pnew_state->action == CANCEL_FORCE_HIGH)
863                         smu8_nbdpm_pstate_enable_disable(hwmgr, true, disable_switch);
864                 else
865                         smu8_nbdpm_pstate_enable_disable(hwmgr, enable_low_mem_state, disable_switch);
866         }
867         return 0;
868 }
869
870 static int smu8_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input)
871 {
872         int ret = 0;
873
874         smu8_update_sclk_limit(hwmgr);
875         smu8_set_deep_sleep_sclk_threshold(hwmgr);
876         smu8_set_watermark_threshold(hwmgr);
877         ret = smu8_enable_nb_dpm(hwmgr);
878         if (ret)
879                 return ret;
880         smu8_update_low_mem_pstate(hwmgr, input);
881
882         return 0;
883 }
884
885
886 static int smu8_setup_asic_task(struct pp_hwmgr *hwmgr)
887 {
888         int ret;
889
890         ret = smu8_upload_pptable_to_smu(hwmgr);
891         if (ret)
892                 return ret;
893         ret = smu8_init_sclk_limit(hwmgr);
894         if (ret)
895                 return ret;
896         ret = smu8_init_uvd_limit(hwmgr);
897         if (ret)
898                 return ret;
899         ret = smu8_init_vce_limit(hwmgr);
900         if (ret)
901                 return ret;
902         ret = smu8_init_acp_limit(hwmgr);
903         if (ret)
904                 return ret;
905
906         smu8_init_power_gate_state(hwmgr);
907         smu8_init_sclk_threshold(hwmgr);
908
909         return 0;
910 }
911
912 static void smu8_power_up_display_clock_sys_pll(struct pp_hwmgr *hwmgr)
913 {
914         struct smu8_hwmgr *hw_data = hwmgr->backend;
915
916         hw_data->disp_clk_bypass_pending = false;
917         hw_data->disp_clk_bypass = false;
918 }
919
920 static void smu8_clear_nb_dpm_flag(struct pp_hwmgr *hwmgr)
921 {
922         struct smu8_hwmgr *hw_data = hwmgr->backend;
923
924         hw_data->is_nb_dpm_enabled = false;
925 }
926
927 static void smu8_reset_cc6_data(struct pp_hwmgr *hwmgr)
928 {
929         struct smu8_hwmgr *hw_data = hwmgr->backend;
930
931         hw_data->cc6_settings.cc6_setting_changed = false;
932         hw_data->cc6_settings.cpu_pstate_separation_time = 0;
933         hw_data->cc6_settings.cpu_cc6_disable = false;
934         hw_data->cc6_settings.cpu_pstate_disable = false;
935 }
936
937 static void smu8_program_voting_clients(struct pp_hwmgr *hwmgr)
938 {
939         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
940                                 ixCG_FREQ_TRAN_VOTING_0,
941                                 SMU8_VOTINGRIGHTSCLIENTS_DFLT0);
942 }
943
944 static void smu8_clear_voting_clients(struct pp_hwmgr *hwmgr)
945 {
946         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
947                                 ixCG_FREQ_TRAN_VOTING_0, 0);
948 }
949
950 static int smu8_start_dpm(struct pp_hwmgr *hwmgr)
951 {
952         struct smu8_hwmgr *data = hwmgr->backend;
953
954         data->dpm_flags |= DPMFlags_SCLK_Enabled;
955
956         return smum_send_msg_to_smc_with_parameter(hwmgr,
957                                 PPSMC_MSG_EnableAllSmuFeatures,
958                                 SCLK_DPM_MASK);
959 }
960
961 static int smu8_stop_dpm(struct pp_hwmgr *hwmgr)
962 {
963         int ret = 0;
964         struct smu8_hwmgr *data = hwmgr->backend;
965         unsigned long dpm_features = 0;
966
967         if (data->dpm_flags & DPMFlags_SCLK_Enabled) {
968                 dpm_features |= SCLK_DPM_MASK;
969                 data->dpm_flags &= ~DPMFlags_SCLK_Enabled;
970                 ret = smum_send_msg_to_smc_with_parameter(hwmgr,
971                                         PPSMC_MSG_DisableAllSmuFeatures,
972                                         dpm_features);
973         }
974         return ret;
975 }
976
977 static int smu8_program_bootup_state(struct pp_hwmgr *hwmgr)
978 {
979         struct smu8_hwmgr *data = hwmgr->backend;
980
981         data->sclk_dpm.soft_min_clk = data->sys_info.bootup_engine_clock;
982         data->sclk_dpm.soft_max_clk = data->sys_info.bootup_engine_clock;
983
984         smum_send_msg_to_smc_with_parameter(hwmgr,
985                                 PPSMC_MSG_SetSclkSoftMin,
986                                 smu8_get_sclk_level(hwmgr,
987                                 data->sclk_dpm.soft_min_clk,
988                                 PPSMC_MSG_SetSclkSoftMin));
989
990         smum_send_msg_to_smc_with_parameter(hwmgr,
991                                 PPSMC_MSG_SetSclkSoftMax,
992                                 smu8_get_sclk_level(hwmgr,
993                                 data->sclk_dpm.soft_max_clk,
994                                 PPSMC_MSG_SetSclkSoftMax));
995
996         return 0;
997 }
998
999 static void smu8_reset_acp_boot_level(struct pp_hwmgr *hwmgr)
1000 {
1001         struct smu8_hwmgr *data = hwmgr->backend;
1002
1003         data->acp_boot_level = 0xff;
1004 }
1005
1006 static int smu8_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
1007 {
1008         smu8_program_voting_clients(hwmgr);
1009         if (smu8_start_dpm(hwmgr))
1010                 return -EINVAL;
1011         smu8_program_bootup_state(hwmgr);
1012         smu8_reset_acp_boot_level(hwmgr);
1013
1014         return 0;
1015 }
1016
1017 static int smu8_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
1018 {
1019         smu8_disable_nb_dpm(hwmgr);
1020
1021         smu8_clear_voting_clients(hwmgr);
1022         if (smu8_stop_dpm(hwmgr))
1023                 return -EINVAL;
1024
1025         return 0;
1026 }
1027
1028 static int smu8_power_off_asic(struct pp_hwmgr *hwmgr)
1029 {
1030         smu8_disable_dpm_tasks(hwmgr);
1031         smu8_power_up_display_clock_sys_pll(hwmgr);
1032         smu8_clear_nb_dpm_flag(hwmgr);
1033         smu8_reset_cc6_data(hwmgr);
1034         return 0;
1035 }
1036
1037 static int smu8_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
1038                                 struct pp_power_state  *prequest_ps,
1039                         const struct pp_power_state *pcurrent_ps)
1040 {
1041         struct smu8_power_state *smu8_ps =
1042                                 cast_smu8_power_state(&prequest_ps->hardware);
1043
1044         const struct smu8_power_state *smu8_current_ps =
1045                                 cast_const_smu8_power_state(&pcurrent_ps->hardware);
1046
1047         struct smu8_hwmgr *data = hwmgr->backend;
1048         struct PP_Clocks clocks = {0, 0, 0, 0};
1049         bool force_high;
1050
1051         smu8_ps->need_dfs_bypass = true;
1052
1053         data->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label);
1054
1055         clocks.memoryClock = hwmgr->display_config->min_mem_set_clock != 0 ?
1056                                 hwmgr->display_config->min_mem_set_clock :
1057                                 data->sys_info.nbp_memory_clock[1];
1058
1059
1060         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
1061                 clocks.memoryClock = hwmgr->dyn_state.max_clock_voltage_on_ac.mclk;
1062
1063         force_high = (clocks.memoryClock > data->sys_info.nbp_memory_clock[SMU8_NUM_NBPMEMORYCLOCK - 1])
1064                         || (hwmgr->display_config->num_display >= 3);
1065
1066         smu8_ps->action = smu8_current_ps->action;
1067
1068         if (hwmgr->request_dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
1069                 smu8_nbdpm_pstate_enable_disable(hwmgr, false, false);
1070         else if (hwmgr->request_dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD)
1071                 smu8_nbdpm_pstate_enable_disable(hwmgr, false, true);
1072         else if (!force_high && (smu8_ps->action == FORCE_HIGH))
1073                 smu8_ps->action = CANCEL_FORCE_HIGH;
1074         else if (force_high && (smu8_ps->action != FORCE_HIGH))
1075                 smu8_ps->action = FORCE_HIGH;
1076         else
1077                 smu8_ps->action = DO_NOTHING;
1078
1079         return 0;
1080 }
1081
1082 static int smu8_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
1083 {
1084         int result = 0;
1085         struct smu8_hwmgr *data;
1086
1087         data = kzalloc(sizeof(struct smu8_hwmgr), GFP_KERNEL);
1088         if (data == NULL)
1089                 return -ENOMEM;
1090
1091         hwmgr->backend = data;
1092
1093         result = smu8_initialize_dpm_defaults(hwmgr);
1094         if (result != 0) {
1095                 pr_err("smu8_initialize_dpm_defaults failed\n");
1096                 return result;
1097         }
1098
1099         result = smu8_get_system_info_data(hwmgr);
1100         if (result != 0) {
1101                 pr_err("smu8_get_system_info_data failed\n");
1102                 return result;
1103         }
1104
1105         smu8_construct_boot_state(hwmgr);
1106
1107         hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =  SMU8_MAX_HARDWARE_POWERLEVELS;
1108
1109         return result;
1110 }
1111
1112 static int smu8_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
1113 {
1114         if (hwmgr != NULL) {
1115                 kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
1116                 hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
1117
1118                 kfree(hwmgr->backend);
1119                 hwmgr->backend = NULL;
1120         }
1121         return 0;
1122 }
1123
1124 static int smu8_phm_force_dpm_highest(struct pp_hwmgr *hwmgr)
1125 {
1126         struct smu8_hwmgr *data = hwmgr->backend;
1127
1128         smum_send_msg_to_smc_with_parameter(hwmgr,
1129                                         PPSMC_MSG_SetSclkSoftMin,
1130                                         smu8_get_sclk_level(hwmgr,
1131                                         data->sclk_dpm.soft_max_clk,
1132                                         PPSMC_MSG_SetSclkSoftMin));
1133
1134         smum_send_msg_to_smc_with_parameter(hwmgr,
1135                                 PPSMC_MSG_SetSclkSoftMax,
1136                                 smu8_get_sclk_level(hwmgr,
1137                                 data->sclk_dpm.soft_max_clk,
1138                                 PPSMC_MSG_SetSclkSoftMax));
1139
1140         return 0;
1141 }
1142
1143 static int smu8_phm_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
1144 {
1145         struct smu8_hwmgr *data = hwmgr->backend;
1146         struct phm_clock_voltage_dependency_table *table =
1147                                 hwmgr->dyn_state.vddc_dependency_on_sclk;
1148         unsigned long clock = 0, level;
1149
1150         if (NULL == table || table->count <= 0)
1151                 return -EINVAL;
1152
1153         data->sclk_dpm.soft_min_clk = table->entries[0].clk;
1154         data->sclk_dpm.hard_min_clk = table->entries[0].clk;
1155         hwmgr->pstate_sclk = table->entries[0].clk;
1156         hwmgr->pstate_mclk = 0;
1157
1158         level = smu8_get_max_sclk_level(hwmgr) - 1;
1159
1160         if (level < table->count)
1161                 clock = table->entries[level].clk;
1162         else
1163                 clock = table->entries[table->count - 1].clk;
1164
1165         data->sclk_dpm.soft_max_clk = clock;
1166         data->sclk_dpm.hard_max_clk = clock;
1167
1168         smum_send_msg_to_smc_with_parameter(hwmgr,
1169                                 PPSMC_MSG_SetSclkSoftMin,
1170                                 smu8_get_sclk_level(hwmgr,
1171                                 data->sclk_dpm.soft_min_clk,
1172                                 PPSMC_MSG_SetSclkSoftMin));
1173
1174         smum_send_msg_to_smc_with_parameter(hwmgr,
1175                                 PPSMC_MSG_SetSclkSoftMax,
1176                                 smu8_get_sclk_level(hwmgr,
1177                                 data->sclk_dpm.soft_max_clk,
1178                                 PPSMC_MSG_SetSclkSoftMax));
1179
1180         return 0;
1181 }
1182
1183 static int smu8_phm_force_dpm_lowest(struct pp_hwmgr *hwmgr)
1184 {
1185         struct smu8_hwmgr *data = hwmgr->backend;
1186
1187         smum_send_msg_to_smc_with_parameter(hwmgr,
1188                         PPSMC_MSG_SetSclkSoftMax,
1189                         smu8_get_sclk_level(hwmgr,
1190                         data->sclk_dpm.soft_min_clk,
1191                         PPSMC_MSG_SetSclkSoftMax));
1192
1193         smum_send_msg_to_smc_with_parameter(hwmgr,
1194                                 PPSMC_MSG_SetSclkSoftMin,
1195                                 smu8_get_sclk_level(hwmgr,
1196                                 data->sclk_dpm.soft_min_clk,
1197                                 PPSMC_MSG_SetSclkSoftMin));
1198
1199         return 0;
1200 }
1201
1202 static int smu8_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
1203                                 enum amd_dpm_forced_level level)
1204 {
1205         int ret = 0;
1206
1207         switch (level) {
1208         case AMD_DPM_FORCED_LEVEL_HIGH:
1209         case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
1210                 ret = smu8_phm_force_dpm_highest(hwmgr);
1211                 break;
1212         case AMD_DPM_FORCED_LEVEL_LOW:
1213         case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
1214         case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
1215                 ret = smu8_phm_force_dpm_lowest(hwmgr);
1216                 break;
1217         case AMD_DPM_FORCED_LEVEL_AUTO:
1218                 ret = smu8_phm_unforce_dpm_levels(hwmgr);
1219                 break;
1220         case AMD_DPM_FORCED_LEVEL_MANUAL:
1221         case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
1222         default:
1223                 break;
1224         }
1225
1226         return ret;
1227 }
1228
1229 static int smu8_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr)
1230 {
1231         if (PP_CAP(PHM_PlatformCaps_UVDPowerGating))
1232                 return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_UVDPowerOFF);
1233         return 0;
1234 }
1235
1236 static int smu8_dpm_powerup_uvd(struct pp_hwmgr *hwmgr)
1237 {
1238         if (PP_CAP(PHM_PlatformCaps_UVDPowerGating)) {
1239                 return smum_send_msg_to_smc_with_parameter(
1240                         hwmgr,
1241                         PPSMC_MSG_UVDPowerON,
1242                         PP_CAP(PHM_PlatformCaps_UVDDynamicPowerGating) ? 1 : 0);
1243         }
1244
1245         return 0;
1246 }
1247
1248 static int  smu8_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr)
1249 {
1250         struct smu8_hwmgr *data = hwmgr->backend;
1251         struct phm_vce_clock_voltage_dependency_table *ptable =
1252                 hwmgr->dyn_state.vce_clock_voltage_dependency_table;
1253
1254         /* Stable Pstate is enabled and we need to set the VCE DPM to highest level */
1255         if (PP_CAP(PHM_PlatformCaps_StablePState) ||
1256             hwmgr->en_umd_pstate) {
1257                 data->vce_dpm.hard_min_clk =
1258                                   ptable->entries[ptable->count - 1].ecclk;
1259
1260                 smum_send_msg_to_smc_with_parameter(hwmgr,
1261                         PPSMC_MSG_SetEclkHardMin,
1262                         smu8_get_eclk_level(hwmgr,
1263                                 data->vce_dpm.hard_min_clk,
1264                                 PPSMC_MSG_SetEclkHardMin));
1265         } else {
1266
1267                 smum_send_msg_to_smc_with_parameter(hwmgr,
1268                                         PPSMC_MSG_SetEclkHardMin, 0);
1269                 /* disable ECLK DPM 0. Otherwise VCE could hang if
1270                  * switching SCLK from DPM 0 to 6/7 */
1271                 smum_send_msg_to_smc_with_parameter(hwmgr,
1272                                         PPSMC_MSG_SetEclkSoftMin, 1);
1273         }
1274         return 0;
1275 }
1276
1277 static int smu8_dpm_powerdown_vce(struct pp_hwmgr *hwmgr)
1278 {
1279         if (PP_CAP(PHM_PlatformCaps_VCEPowerGating))
1280                 return smum_send_msg_to_smc(hwmgr,
1281                                                      PPSMC_MSG_VCEPowerOFF);
1282         return 0;
1283 }
1284
1285 static int smu8_dpm_powerup_vce(struct pp_hwmgr *hwmgr)
1286 {
1287         if (PP_CAP(PHM_PlatformCaps_VCEPowerGating))
1288                 return smum_send_msg_to_smc(hwmgr,
1289                                                      PPSMC_MSG_VCEPowerON);
1290         return 0;
1291 }
1292
1293 static uint32_t smu8_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
1294 {
1295         struct smu8_hwmgr *data = hwmgr->backend;
1296
1297         return data->sys_info.bootup_uma_clock;
1298 }
1299
1300 static uint32_t smu8_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
1301 {
1302         struct pp_power_state  *ps;
1303         struct smu8_power_state  *smu8_ps;
1304
1305         if (hwmgr == NULL)
1306                 return -EINVAL;
1307
1308         ps = hwmgr->request_ps;
1309
1310         if (ps == NULL)
1311                 return -EINVAL;
1312
1313         smu8_ps = cast_smu8_power_state(&ps->hardware);
1314
1315         if (low)
1316                 return smu8_ps->levels[0].engineClock;
1317         else
1318                 return smu8_ps->levels[smu8_ps->level-1].engineClock;
1319 }
1320
1321 static int smu8_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
1322                                         struct pp_hw_power_state *hw_ps)
1323 {
1324         struct smu8_hwmgr *data = hwmgr->backend;
1325         struct smu8_power_state *smu8_ps = cast_smu8_power_state(hw_ps);
1326
1327         smu8_ps->level = 1;
1328         smu8_ps->nbps_flags = 0;
1329         smu8_ps->bapm_flags = 0;
1330         smu8_ps->levels[0] = data->boot_power_level;
1331
1332         return 0;
1333 }
1334
1335 static int smu8_dpm_get_pp_table_entry_callback(
1336                                                      struct pp_hwmgr *hwmgr,
1337                                            struct pp_hw_power_state *hw_ps,
1338                                                           unsigned int index,
1339                                                      const void *clock_info)
1340 {
1341         struct smu8_power_state *smu8_ps = cast_smu8_power_state(hw_ps);
1342
1343         const ATOM_PPLIB_CZ_CLOCK_INFO *smu8_clock_info = clock_info;
1344
1345         struct phm_clock_voltage_dependency_table *table =
1346                                     hwmgr->dyn_state.vddc_dependency_on_sclk;
1347         uint8_t clock_info_index = smu8_clock_info->index;
1348
1349         if (clock_info_index > (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1))
1350                 clock_info_index = (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1);
1351
1352         smu8_ps->levels[index].engineClock = table->entries[clock_info_index].clk;
1353         smu8_ps->levels[index].vddcIndex = (uint8_t)table->entries[clock_info_index].v;
1354
1355         smu8_ps->level = index + 1;
1356
1357         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
1358                 smu8_ps->levels[index].dsDividerIndex = 5;
1359                 smu8_ps->levels[index].ssDividerIndex = 5;
1360         }
1361
1362         return 0;
1363 }
1364
1365 static int smu8_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr)
1366 {
1367         int result;
1368         unsigned long ret = 0;
1369
1370         result = pp_tables_get_num_of_entries(hwmgr, &ret);
1371
1372         return result ? 0 : ret;
1373 }
1374
1375 static int smu8_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr,
1376                     unsigned long entry, struct pp_power_state *ps)
1377 {
1378         int result;
1379         struct smu8_power_state *smu8_ps;
1380
1381         ps->hardware.magic = smu8_magic;
1382
1383         smu8_ps = cast_smu8_power_state(&(ps->hardware));
1384
1385         result = pp_tables_get_entry(hwmgr, entry, ps,
1386                         smu8_dpm_get_pp_table_entry_callback);
1387
1388         smu8_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK;
1389         smu8_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK;
1390
1391         return result;
1392 }
1393
1394 static int smu8_get_power_state_size(struct pp_hwmgr *hwmgr)
1395 {
1396         return sizeof(struct smu8_power_state);
1397 }
1398
1399 static void smu8_hw_print_display_cfg(
1400         const struct cc6_settings *cc6_settings)
1401 {
1402         PP_DBG_LOG("New Display Configuration:\n");
1403
1404         PP_DBG_LOG("   cpu_cc6_disable: %d\n",
1405                         cc6_settings->cpu_cc6_disable);
1406         PP_DBG_LOG("   cpu_pstate_disable: %d\n",
1407                         cc6_settings->cpu_pstate_disable);
1408         PP_DBG_LOG("   nb_pstate_switch_disable: %d\n",
1409                         cc6_settings->nb_pstate_switch_disable);
1410         PP_DBG_LOG("   cpu_pstate_separation_time: %d\n\n",
1411                         cc6_settings->cpu_pstate_separation_time);
1412 }
1413
1414  static int smu8_set_cpu_power_state(struct pp_hwmgr *hwmgr)
1415 {
1416         struct smu8_hwmgr *hw_data = hwmgr->backend;
1417         uint32_t data = 0;
1418
1419         if (hw_data->cc6_settings.cc6_setting_changed) {
1420
1421                 hw_data->cc6_settings.cc6_setting_changed = false;
1422
1423                 smu8_hw_print_display_cfg(&hw_data->cc6_settings);
1424
1425                 data |= (hw_data->cc6_settings.cpu_pstate_separation_time
1426                         & PWRMGT_SEPARATION_TIME_MASK)
1427                         << PWRMGT_SEPARATION_TIME_SHIFT;
1428
1429                 data |= (hw_data->cc6_settings.cpu_cc6_disable ? 0x1 : 0x0)
1430                         << PWRMGT_DISABLE_CPU_CSTATES_SHIFT;
1431
1432                 data |= (hw_data->cc6_settings.cpu_pstate_disable ? 0x1 : 0x0)
1433                         << PWRMGT_DISABLE_CPU_PSTATES_SHIFT;
1434
1435                 PP_DBG_LOG("SetDisplaySizePowerParams data: 0x%X\n",
1436                         data);
1437
1438                 smum_send_msg_to_smc_with_parameter(hwmgr,
1439                                                 PPSMC_MSG_SetDisplaySizePowerParams,
1440                                                 data);
1441         }
1442
1443         return 0;
1444 }
1445
1446
1447 static int smu8_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time,
1448                         bool cc6_disable, bool pstate_disable, bool pstate_switch_disable)
1449 {
1450         struct smu8_hwmgr *hw_data = hwmgr->backend;
1451
1452         if (separation_time !=
1453             hw_data->cc6_settings.cpu_pstate_separation_time ||
1454             cc6_disable != hw_data->cc6_settings.cpu_cc6_disable ||
1455             pstate_disable != hw_data->cc6_settings.cpu_pstate_disable ||
1456             pstate_switch_disable != hw_data->cc6_settings.nb_pstate_switch_disable) {
1457
1458                 hw_data->cc6_settings.cc6_setting_changed = true;
1459
1460                 hw_data->cc6_settings.cpu_pstate_separation_time =
1461                         separation_time;
1462                 hw_data->cc6_settings.cpu_cc6_disable =
1463                         cc6_disable;
1464                 hw_data->cc6_settings.cpu_pstate_disable =
1465                         pstate_disable;
1466                 hw_data->cc6_settings.nb_pstate_switch_disable =
1467                         pstate_switch_disable;
1468
1469         }
1470
1471         return 0;
1472 }
1473
1474 static int smu8_get_dal_power_level(struct pp_hwmgr *hwmgr,
1475                 struct amd_pp_simple_clock_info *info)
1476 {
1477         uint32_t i;
1478         const struct phm_clock_voltage_dependency_table *table =
1479                         hwmgr->dyn_state.vddc_dep_on_dal_pwrl;
1480         const struct phm_clock_and_voltage_limits *limits =
1481                         &hwmgr->dyn_state.max_clock_voltage_on_ac;
1482
1483         info->engine_max_clock = limits->sclk;
1484         info->memory_max_clock = limits->mclk;
1485
1486         for (i = table->count - 1; i > 0; i--) {
1487                 if (limits->vddc >= table->entries[i].v) {
1488                         info->level = table->entries[i].clk;
1489                         return 0;
1490                 }
1491         }
1492         return -EINVAL;
1493 }
1494
1495 static int smu8_force_clock_level(struct pp_hwmgr *hwmgr,
1496                 enum pp_clock_type type, uint32_t mask)
1497 {
1498         switch (type) {
1499         case PP_SCLK:
1500                 smum_send_msg_to_smc_with_parameter(hwmgr,
1501                                 PPSMC_MSG_SetSclkSoftMin,
1502                                 mask);
1503                 smum_send_msg_to_smc_with_parameter(hwmgr,
1504                                 PPSMC_MSG_SetSclkSoftMax,
1505                                 mask);
1506                 break;
1507         default:
1508                 break;
1509         }
1510
1511         return 0;
1512 }
1513
1514 static int smu8_print_clock_levels(struct pp_hwmgr *hwmgr,
1515                 enum pp_clock_type type, char *buf)
1516 {
1517         struct smu8_hwmgr *data = hwmgr->backend;
1518         struct phm_clock_voltage_dependency_table *sclk_table =
1519                         hwmgr->dyn_state.vddc_dependency_on_sclk;
1520         int i, now, size = 0;
1521
1522         switch (type) {
1523         case PP_SCLK:
1524                 now = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device,
1525                                 CGS_IND_REG__SMC,
1526                                 ixTARGET_AND_CURRENT_PROFILE_INDEX),
1527                                 TARGET_AND_CURRENT_PROFILE_INDEX,
1528                                 CURR_SCLK_INDEX);
1529
1530                 for (i = 0; i < sclk_table->count; i++)
1531                         size += sprintf(buf + size, "%d: %uMhz %s\n",
1532                                         i, sclk_table->entries[i].clk / 100,
1533                                         (i == now) ? "*" : "");
1534                 break;
1535         case PP_MCLK:
1536                 now = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device,
1537                                 CGS_IND_REG__SMC,
1538                                 ixTARGET_AND_CURRENT_PROFILE_INDEX),
1539                                 TARGET_AND_CURRENT_PROFILE_INDEX,
1540                                 CURR_MCLK_INDEX);
1541
1542                 for (i = SMU8_NUM_NBPMEMORYCLOCK; i > 0; i--)
1543                         size += sprintf(buf + size, "%d: %uMhz %s\n",
1544                                         SMU8_NUM_NBPMEMORYCLOCK-i, data->sys_info.nbp_memory_clock[i-1] / 100,
1545                                         (SMU8_NUM_NBPMEMORYCLOCK-i == now) ? "*" : "");
1546                 break;
1547         default:
1548                 break;
1549         }
1550         return size;
1551 }
1552
1553 static int smu8_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state,
1554                                 PHM_PerformanceLevelDesignation designation, uint32_t index,
1555                                 PHM_PerformanceLevel *level)
1556 {
1557         const struct smu8_power_state *ps;
1558         struct smu8_hwmgr *data;
1559         uint32_t level_index;
1560         uint32_t i;
1561
1562         if (level == NULL || hwmgr == NULL || state == NULL)
1563                 return -EINVAL;
1564
1565         data = hwmgr->backend;
1566         ps = cast_const_smu8_power_state(state);
1567
1568         level_index = index > ps->level - 1 ? ps->level - 1 : index;
1569         level->coreClock = ps->levels[level_index].engineClock;
1570
1571         if (designation == PHM_PerformanceLevelDesignation_PowerContainment) {
1572                 for (i = 1; i < ps->level; i++) {
1573                         if (ps->levels[i].engineClock > data->dce_slow_sclk_threshold) {
1574                                 level->coreClock = ps->levels[i].engineClock;
1575                                 break;
1576                         }
1577                 }
1578         }
1579
1580         if (level_index == 0)
1581                 level->memory_clock = data->sys_info.nbp_memory_clock[SMU8_NUM_NBPMEMORYCLOCK - 1];
1582         else
1583                 level->memory_clock = data->sys_info.nbp_memory_clock[0];
1584
1585         level->vddc = (smu8_convert_8Bit_index_to_voltage(hwmgr, ps->levels[level_index].vddcIndex) + 2) / 4;
1586         level->nonLocalMemoryFreq = 0;
1587         level->nonLocalMemoryWidth = 0;
1588
1589         return 0;
1590 }
1591
1592 static int smu8_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr,
1593         const struct pp_hw_power_state *state, struct pp_clock_info *clock_info)
1594 {
1595         const struct smu8_power_state *ps = cast_const_smu8_power_state(state);
1596
1597         clock_info->min_eng_clk = ps->levels[0].engineClock / (1 << (ps->levels[0].ssDividerIndex));
1598         clock_info->max_eng_clk = ps->levels[ps->level - 1].engineClock / (1 << (ps->levels[ps->level - 1].ssDividerIndex));
1599
1600         return 0;
1601 }
1602
1603 static int smu8_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type,
1604                                                 struct amd_pp_clocks *clocks)
1605 {
1606         struct smu8_hwmgr *data = hwmgr->backend;
1607         int i;
1608         struct phm_clock_voltage_dependency_table *table;
1609
1610         clocks->count = smu8_get_max_sclk_level(hwmgr);
1611         switch (type) {
1612         case amd_pp_disp_clock:
1613                 for (i = 0; i < clocks->count; i++)
1614                         clocks->clock[i] = data->sys_info.display_clock[i] * 10;
1615                 break;
1616         case amd_pp_sys_clock:
1617                 table = hwmgr->dyn_state.vddc_dependency_on_sclk;
1618                 for (i = 0; i < clocks->count; i++)
1619                         clocks->clock[i] = table->entries[i].clk * 10;
1620                 break;
1621         case amd_pp_mem_clock:
1622                 clocks->count = SMU8_NUM_NBPMEMORYCLOCK;
1623                 for (i = 0; i < clocks->count; i++)
1624                         clocks->clock[i] = data->sys_info.nbp_memory_clock[clocks->count - 1 - i] * 10;
1625                 break;
1626         default:
1627                 return -1;
1628         }
1629
1630         return 0;
1631 }
1632
1633 static int smu8_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks)
1634 {
1635         struct phm_clock_voltage_dependency_table *table =
1636                                         hwmgr->dyn_state.vddc_dependency_on_sclk;
1637         unsigned long level;
1638         const struct phm_clock_and_voltage_limits *limits =
1639                         &hwmgr->dyn_state.max_clock_voltage_on_ac;
1640
1641         if ((NULL == table) || (table->count <= 0) || (clocks == NULL))
1642                 return -EINVAL;
1643
1644         level = smu8_get_max_sclk_level(hwmgr) - 1;
1645
1646         if (level < table->count)
1647                 clocks->engine_max_clock = table->entries[level].clk;
1648         else
1649                 clocks->engine_max_clock = table->entries[table->count - 1].clk;
1650
1651         clocks->memory_max_clock = limits->mclk;
1652
1653         return 0;
1654 }
1655
1656 static int smu8_thermal_get_temperature(struct pp_hwmgr *hwmgr)
1657 {
1658         int actual_temp = 0;
1659         uint32_t val = cgs_read_ind_register(hwmgr->device,
1660                                              CGS_IND_REG__SMC, ixTHM_TCON_CUR_TMP);
1661         uint32_t temp = PHM_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP);
1662
1663         if (PHM_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP_RANGE_SEL))
1664                 actual_temp = ((temp / 8) - 49) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
1665         else
1666                 actual_temp = (temp / 8) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
1667
1668         return actual_temp;
1669 }
1670
1671 static int smu8_read_sensor(struct pp_hwmgr *hwmgr, int idx,
1672                           void *value, int *size)
1673 {
1674         struct smu8_hwmgr *data = hwmgr->backend;
1675
1676         struct phm_clock_voltage_dependency_table *table =
1677                                 hwmgr->dyn_state.vddc_dependency_on_sclk;
1678
1679         struct phm_vce_clock_voltage_dependency_table *vce_table =
1680                 hwmgr->dyn_state.vce_clock_voltage_dependency_table;
1681
1682         struct phm_uvd_clock_voltage_dependency_table *uvd_table =
1683                 hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
1684
1685         uint32_t sclk_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX),
1686                                         TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
1687         uint32_t uvd_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
1688                                         TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
1689         uint32_t vce_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
1690                                         TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
1691
1692         uint32_t sclk, vclk, dclk, ecclk, tmp, activity_percent;
1693         uint16_t vddnb, vddgfx;
1694         int result;
1695
1696         /* size must be at least 4 bytes for all sensors */
1697         if (*size < 4)
1698                 return -EINVAL;
1699         *size = 4;
1700
1701         switch (idx) {
1702         case AMDGPU_PP_SENSOR_GFX_SCLK:
1703                 if (sclk_index < NUM_SCLK_LEVELS) {
1704                         sclk = table->entries[sclk_index].clk;
1705                         *((uint32_t *)value) = sclk;
1706                         return 0;
1707                 }
1708                 return -EINVAL;
1709         case AMDGPU_PP_SENSOR_VDDNB:
1710                 tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) &
1711                         CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
1712                 vddnb = smu8_convert_8Bit_index_to_voltage(hwmgr, tmp) / 4;
1713                 *((uint32_t *)value) = vddnb;
1714                 return 0;
1715         case AMDGPU_PP_SENSOR_VDDGFX:
1716                 tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) &
1717                         CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
1718                 vddgfx = smu8_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp) / 4;
1719                 *((uint32_t *)value) = vddgfx;
1720                 return 0;
1721         case AMDGPU_PP_SENSOR_UVD_VCLK:
1722                 if (!data->uvd_power_gated) {
1723                         if (uvd_index >= SMU8_MAX_HARDWARE_POWERLEVELS) {
1724                                 return -EINVAL;
1725                         } else {
1726                                 vclk = uvd_table->entries[uvd_index].vclk;
1727                                 *((uint32_t *)value) = vclk;
1728                                 return 0;
1729                         }
1730                 }
1731                 *((uint32_t *)value) = 0;
1732                 return 0;
1733         case AMDGPU_PP_SENSOR_UVD_DCLK:
1734                 if (!data->uvd_power_gated) {
1735                         if (uvd_index >= SMU8_MAX_HARDWARE_POWERLEVELS) {
1736                                 return -EINVAL;
1737                         } else {
1738                                 dclk = uvd_table->entries[uvd_index].dclk;
1739                                 *((uint32_t *)value) = dclk;
1740                                 return 0;
1741                         }
1742                 }
1743                 *((uint32_t *)value) = 0;
1744                 return 0;
1745         case AMDGPU_PP_SENSOR_VCE_ECCLK:
1746                 if (!data->vce_power_gated) {
1747                         if (vce_index >= SMU8_MAX_HARDWARE_POWERLEVELS) {
1748                                 return -EINVAL;
1749                         } else {
1750                                 ecclk = vce_table->entries[vce_index].ecclk;
1751                                 *((uint32_t *)value) = ecclk;
1752                                 return 0;
1753                         }
1754                 }
1755                 *((uint32_t *)value) = 0;
1756                 return 0;
1757         case AMDGPU_PP_SENSOR_GPU_LOAD:
1758                 result = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetAverageGraphicsActivity);
1759                 if (0 == result) {
1760                         activity_percent = cgs_read_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0);
1761                         activity_percent = activity_percent > 100 ? 100 : activity_percent;
1762                 } else {
1763                         activity_percent = 50;
1764                 }
1765                 *((uint32_t *)value) = activity_percent;
1766                 return 0;
1767         case AMDGPU_PP_SENSOR_UVD_POWER:
1768                 *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1;
1769                 return 0;
1770         case AMDGPU_PP_SENSOR_VCE_POWER:
1771                 *((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
1772                 return 0;
1773         case AMDGPU_PP_SENSOR_GPU_TEMP:
1774                 *((uint32_t *)value) = smu8_thermal_get_temperature(hwmgr);
1775                 return 0;
1776         default:
1777                 return -EINVAL;
1778         }
1779 }
1780
1781 static int smu8_notify_cac_buffer_info(struct pp_hwmgr *hwmgr,
1782                                         uint32_t virtual_addr_low,
1783                                         uint32_t virtual_addr_hi,
1784                                         uint32_t mc_addr_low,
1785                                         uint32_t mc_addr_hi,
1786                                         uint32_t size)
1787 {
1788         smum_send_msg_to_smc_with_parameter(hwmgr,
1789                                         PPSMC_MSG_DramAddrHiVirtual,
1790                                         mc_addr_hi);
1791         smum_send_msg_to_smc_with_parameter(hwmgr,
1792                                         PPSMC_MSG_DramAddrLoVirtual,
1793                                         mc_addr_low);
1794         smum_send_msg_to_smc_with_parameter(hwmgr,
1795                                         PPSMC_MSG_DramAddrHiPhysical,
1796                                         virtual_addr_hi);
1797         smum_send_msg_to_smc_with_parameter(hwmgr,
1798                                         PPSMC_MSG_DramAddrLoPhysical,
1799                                         virtual_addr_low);
1800
1801         smum_send_msg_to_smc_with_parameter(hwmgr,
1802                                         PPSMC_MSG_DramBufferSize,
1803                                         size);
1804         return 0;
1805 }
1806
1807 static int smu8_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
1808                 struct PP_TemperatureRange *thermal_data)
1809 {
1810         struct smu8_hwmgr *data = hwmgr->backend;
1811
1812         memcpy(thermal_data, &SMU7ThermalPolicy[0], sizeof(struct PP_TemperatureRange));
1813
1814         thermal_data->max = (data->thermal_auto_throttling_treshold +
1815                         data->sys_info.htc_hyst_lmt) *
1816                         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
1817
1818         return 0;
1819 }
1820
1821 static int smu8_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
1822 {
1823         struct smu8_hwmgr *data = hwmgr->backend;
1824         uint32_t dpm_features = 0;
1825
1826         if (enable &&
1827                 phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1828                                   PHM_PlatformCaps_UVDDPM)) {
1829                 data->dpm_flags |= DPMFlags_UVD_Enabled;
1830                 dpm_features |= UVD_DPM_MASK;
1831                 smum_send_msg_to_smc_with_parameter(hwmgr,
1832                             PPSMC_MSG_EnableAllSmuFeatures, dpm_features);
1833         } else {
1834                 dpm_features |= UVD_DPM_MASK;
1835                 data->dpm_flags &= ~DPMFlags_UVD_Enabled;
1836                 smum_send_msg_to_smc_with_parameter(hwmgr,
1837                            PPSMC_MSG_DisableAllSmuFeatures, dpm_features);
1838         }
1839         return 0;
1840 }
1841
1842 int smu8_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
1843 {
1844         struct smu8_hwmgr *data = hwmgr->backend;
1845         struct phm_uvd_clock_voltage_dependency_table *ptable =
1846                 hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
1847
1848         if (!bgate) {
1849                 /* Stable Pstate is enabled and we need to set the UVD DPM to highest level */
1850                 if (PP_CAP(PHM_PlatformCaps_StablePState) ||
1851                     hwmgr->en_umd_pstate) {
1852                         data->uvd_dpm.hard_min_clk =
1853                                    ptable->entries[ptable->count - 1].vclk;
1854
1855                         smum_send_msg_to_smc_with_parameter(hwmgr,
1856                                 PPSMC_MSG_SetUvdHardMin,
1857                                 smu8_get_uvd_level(hwmgr,
1858                                         data->uvd_dpm.hard_min_clk,
1859                                         PPSMC_MSG_SetUvdHardMin));
1860
1861                         smu8_enable_disable_uvd_dpm(hwmgr, true);
1862                 } else {
1863                         smu8_enable_disable_uvd_dpm(hwmgr, true);
1864                 }
1865         } else {
1866                 smu8_enable_disable_uvd_dpm(hwmgr, false);
1867         }
1868
1869         return 0;
1870 }
1871
1872 static int smu8_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
1873 {
1874         struct smu8_hwmgr *data = hwmgr->backend;
1875         uint32_t dpm_features = 0;
1876
1877         if (enable && phm_cap_enabled(
1878                                 hwmgr->platform_descriptor.platformCaps,
1879                                 PHM_PlatformCaps_VCEDPM)) {
1880                 data->dpm_flags |= DPMFlags_VCE_Enabled;
1881                 dpm_features |= VCE_DPM_MASK;
1882                 smum_send_msg_to_smc_with_parameter(hwmgr,
1883                             PPSMC_MSG_EnableAllSmuFeatures, dpm_features);
1884         } else {
1885                 dpm_features |= VCE_DPM_MASK;
1886                 data->dpm_flags &= ~DPMFlags_VCE_Enabled;
1887                 smum_send_msg_to_smc_with_parameter(hwmgr,
1888                            PPSMC_MSG_DisableAllSmuFeatures, dpm_features);
1889         }
1890
1891         return 0;
1892 }
1893
1894
1895 static void smu8_dpm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate)
1896 {
1897         struct smu8_hwmgr *data = hwmgr->backend;
1898
1899         if (data->acp_power_gated == bgate)
1900                 return;
1901
1902         if (bgate)
1903                 smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ACPPowerOFF);
1904         else
1905                 smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ACPPowerON);
1906 }
1907
1908 static void smu8_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
1909 {
1910         struct smu8_hwmgr *data = hwmgr->backend;
1911
1912         data->uvd_power_gated = bgate;
1913
1914         if (bgate) {
1915                 amdgpu_device_ip_set_powergating_state(hwmgr->adev,
1916                                                 AMD_IP_BLOCK_TYPE_UVD,
1917                                                 AMD_PG_STATE_GATE);
1918                 amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
1919                                                 AMD_IP_BLOCK_TYPE_UVD,
1920                                                 AMD_CG_STATE_GATE);
1921                 smu8_dpm_update_uvd_dpm(hwmgr, true);
1922                 smu8_dpm_powerdown_uvd(hwmgr);
1923         } else {
1924                 smu8_dpm_powerup_uvd(hwmgr);
1925                 amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
1926                                                 AMD_IP_BLOCK_TYPE_UVD,
1927                                                 AMD_CG_STATE_UNGATE);
1928                 amdgpu_device_ip_set_powergating_state(hwmgr->adev,
1929                                                 AMD_IP_BLOCK_TYPE_UVD,
1930                                                 AMD_PG_STATE_UNGATE);
1931                 smu8_dpm_update_uvd_dpm(hwmgr, false);
1932         }
1933
1934 }
1935
1936 static void smu8_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
1937 {
1938         struct smu8_hwmgr *data = hwmgr->backend;
1939
1940         if (bgate) {
1941                 amdgpu_device_ip_set_powergating_state(hwmgr->adev,
1942                                         AMD_IP_BLOCK_TYPE_VCE,
1943                                         AMD_PG_STATE_GATE);
1944                 amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
1945                                         AMD_IP_BLOCK_TYPE_VCE,
1946                                         AMD_CG_STATE_GATE);
1947                 smu8_enable_disable_vce_dpm(hwmgr, false);
1948                 smu8_dpm_powerdown_vce(hwmgr);
1949                 data->vce_power_gated = true;
1950         } else {
1951                 smu8_dpm_powerup_vce(hwmgr);
1952                 data->vce_power_gated = false;
1953                 amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
1954                                         AMD_IP_BLOCK_TYPE_VCE,
1955                                         AMD_CG_STATE_UNGATE);
1956                 amdgpu_device_ip_set_powergating_state(hwmgr->adev,
1957                                         AMD_IP_BLOCK_TYPE_VCE,
1958                                         AMD_PG_STATE_UNGATE);
1959                 smu8_dpm_update_vce_dpm(hwmgr);
1960                 smu8_enable_disable_vce_dpm(hwmgr, true);
1961         }
1962 }
1963
1964 static const struct pp_hwmgr_func smu8_hwmgr_funcs = {
1965         .backend_init = smu8_hwmgr_backend_init,
1966         .backend_fini = smu8_hwmgr_backend_fini,
1967         .apply_state_adjust_rules = smu8_apply_state_adjust_rules,
1968         .force_dpm_level = smu8_dpm_force_dpm_level,
1969         .get_power_state_size = smu8_get_power_state_size,
1970         .powerdown_uvd = smu8_dpm_powerdown_uvd,
1971         .powergate_uvd = smu8_dpm_powergate_uvd,
1972         .powergate_vce = smu8_dpm_powergate_vce,
1973         .powergate_acp = smu8_dpm_powergate_acp,
1974         .get_mclk = smu8_dpm_get_mclk,
1975         .get_sclk = smu8_dpm_get_sclk,
1976         .patch_boot_state = smu8_dpm_patch_boot_state,
1977         .get_pp_table_entry = smu8_dpm_get_pp_table_entry,
1978         .get_num_of_pp_table_entries = smu8_dpm_get_num_of_pp_table_entries,
1979         .set_cpu_power_state = smu8_set_cpu_power_state,
1980         .store_cc6_data = smu8_store_cc6_data,
1981         .force_clock_level = smu8_force_clock_level,
1982         .print_clock_levels = smu8_print_clock_levels,
1983         .get_dal_power_level = smu8_get_dal_power_level,
1984         .get_performance_level = smu8_get_performance_level,
1985         .get_current_shallow_sleep_clocks = smu8_get_current_shallow_sleep_clocks,
1986         .get_clock_by_type = smu8_get_clock_by_type,
1987         .get_max_high_clocks = smu8_get_max_high_clocks,
1988         .read_sensor = smu8_read_sensor,
1989         .power_off_asic = smu8_power_off_asic,
1990         .asic_setup = smu8_setup_asic_task,
1991         .dynamic_state_management_enable = smu8_enable_dpm_tasks,
1992         .power_state_set = smu8_set_power_state_tasks,
1993         .dynamic_state_management_disable = smu8_disable_dpm_tasks,
1994         .notify_cac_buffer_info = smu8_notify_cac_buffer_info,
1995         .get_thermal_temperature_range = smu8_get_thermal_temperature_range,
1996 };
1997
1998 int smu8_init_function_pointers(struct pp_hwmgr *hwmgr)
1999 {
2000         hwmgr->hwmgr_func = &smu8_hwmgr_funcs;
2001         hwmgr->pptable_func = &pptable_funcs;
2002         return 0;
2003 }