]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c
Merge tag 'media/v4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[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                 smu8_nbdpm_pstate_enable_disable(hwmgr, true, true);
1233                 return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_UVDPowerOFF);
1234         }
1235         return 0;
1236 }
1237
1238 static int smu8_dpm_powerup_uvd(struct pp_hwmgr *hwmgr)
1239 {
1240         if (PP_CAP(PHM_PlatformCaps_UVDPowerGating)) {
1241                 smu8_nbdpm_pstate_enable_disable(hwmgr, false, true);
1242                 return smum_send_msg_to_smc_with_parameter(
1243                         hwmgr,
1244                         PPSMC_MSG_UVDPowerON,
1245                         PP_CAP(PHM_PlatformCaps_UVDDynamicPowerGating) ? 1 : 0);
1246         }
1247
1248         return 0;
1249 }
1250
1251 static int  smu8_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr)
1252 {
1253         struct smu8_hwmgr *data = hwmgr->backend;
1254         struct phm_vce_clock_voltage_dependency_table *ptable =
1255                 hwmgr->dyn_state.vce_clock_voltage_dependency_table;
1256
1257         /* Stable Pstate is enabled and we need to set the VCE DPM to highest level */
1258         if (PP_CAP(PHM_PlatformCaps_StablePState) ||
1259             hwmgr->en_umd_pstate) {
1260                 data->vce_dpm.hard_min_clk =
1261                                   ptable->entries[ptable->count - 1].ecclk;
1262
1263                 smum_send_msg_to_smc_with_parameter(hwmgr,
1264                         PPSMC_MSG_SetEclkHardMin,
1265                         smu8_get_eclk_level(hwmgr,
1266                                 data->vce_dpm.hard_min_clk,
1267                                 PPSMC_MSG_SetEclkHardMin));
1268         } else {
1269
1270                 smum_send_msg_to_smc_with_parameter(hwmgr,
1271                                         PPSMC_MSG_SetEclkHardMin, 0);
1272                 /* disable ECLK DPM 0. Otherwise VCE could hang if
1273                  * switching SCLK from DPM 0 to 6/7 */
1274                 smum_send_msg_to_smc_with_parameter(hwmgr,
1275                                         PPSMC_MSG_SetEclkSoftMin, 1);
1276         }
1277         return 0;
1278 }
1279
1280 static int smu8_dpm_powerdown_vce(struct pp_hwmgr *hwmgr)
1281 {
1282         if (PP_CAP(PHM_PlatformCaps_VCEPowerGating))
1283                 return smum_send_msg_to_smc(hwmgr,
1284                                                      PPSMC_MSG_VCEPowerOFF);
1285         return 0;
1286 }
1287
1288 static int smu8_dpm_powerup_vce(struct pp_hwmgr *hwmgr)
1289 {
1290         if (PP_CAP(PHM_PlatformCaps_VCEPowerGating))
1291                 return smum_send_msg_to_smc(hwmgr,
1292                                                      PPSMC_MSG_VCEPowerON);
1293         return 0;
1294 }
1295
1296 static uint32_t smu8_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
1297 {
1298         struct smu8_hwmgr *data = hwmgr->backend;
1299
1300         return data->sys_info.bootup_uma_clock;
1301 }
1302
1303 static uint32_t smu8_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
1304 {
1305         struct pp_power_state  *ps;
1306         struct smu8_power_state  *smu8_ps;
1307
1308         if (hwmgr == NULL)
1309                 return -EINVAL;
1310
1311         ps = hwmgr->request_ps;
1312
1313         if (ps == NULL)
1314                 return -EINVAL;
1315
1316         smu8_ps = cast_smu8_power_state(&ps->hardware);
1317
1318         if (low)
1319                 return smu8_ps->levels[0].engineClock;
1320         else
1321                 return smu8_ps->levels[smu8_ps->level-1].engineClock;
1322 }
1323
1324 static int smu8_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
1325                                         struct pp_hw_power_state *hw_ps)
1326 {
1327         struct smu8_hwmgr *data = hwmgr->backend;
1328         struct smu8_power_state *smu8_ps = cast_smu8_power_state(hw_ps);
1329
1330         smu8_ps->level = 1;
1331         smu8_ps->nbps_flags = 0;
1332         smu8_ps->bapm_flags = 0;
1333         smu8_ps->levels[0] = data->boot_power_level;
1334
1335         return 0;
1336 }
1337
1338 static int smu8_dpm_get_pp_table_entry_callback(
1339                                                      struct pp_hwmgr *hwmgr,
1340                                            struct pp_hw_power_state *hw_ps,
1341                                                           unsigned int index,
1342                                                      const void *clock_info)
1343 {
1344         struct smu8_power_state *smu8_ps = cast_smu8_power_state(hw_ps);
1345
1346         const ATOM_PPLIB_CZ_CLOCK_INFO *smu8_clock_info = clock_info;
1347
1348         struct phm_clock_voltage_dependency_table *table =
1349                                     hwmgr->dyn_state.vddc_dependency_on_sclk;
1350         uint8_t clock_info_index = smu8_clock_info->index;
1351
1352         if (clock_info_index > (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1))
1353                 clock_info_index = (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1);
1354
1355         smu8_ps->levels[index].engineClock = table->entries[clock_info_index].clk;
1356         smu8_ps->levels[index].vddcIndex = (uint8_t)table->entries[clock_info_index].v;
1357
1358         smu8_ps->level = index + 1;
1359
1360         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
1361                 smu8_ps->levels[index].dsDividerIndex = 5;
1362                 smu8_ps->levels[index].ssDividerIndex = 5;
1363         }
1364
1365         return 0;
1366 }
1367
1368 static int smu8_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr)
1369 {
1370         int result;
1371         unsigned long ret = 0;
1372
1373         result = pp_tables_get_num_of_entries(hwmgr, &ret);
1374
1375         return result ? 0 : ret;
1376 }
1377
1378 static int smu8_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr,
1379                     unsigned long entry, struct pp_power_state *ps)
1380 {
1381         int result;
1382         struct smu8_power_state *smu8_ps;
1383
1384         ps->hardware.magic = smu8_magic;
1385
1386         smu8_ps = cast_smu8_power_state(&(ps->hardware));
1387
1388         result = pp_tables_get_entry(hwmgr, entry, ps,
1389                         smu8_dpm_get_pp_table_entry_callback);
1390
1391         smu8_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK;
1392         smu8_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK;
1393
1394         return result;
1395 }
1396
1397 static int smu8_get_power_state_size(struct pp_hwmgr *hwmgr)
1398 {
1399         return sizeof(struct smu8_power_state);
1400 }
1401
1402 static void smu8_hw_print_display_cfg(
1403         const struct cc6_settings *cc6_settings)
1404 {
1405         PP_DBG_LOG("New Display Configuration:\n");
1406
1407         PP_DBG_LOG("   cpu_cc6_disable: %d\n",
1408                         cc6_settings->cpu_cc6_disable);
1409         PP_DBG_LOG("   cpu_pstate_disable: %d\n",
1410                         cc6_settings->cpu_pstate_disable);
1411         PP_DBG_LOG("   nb_pstate_switch_disable: %d\n",
1412                         cc6_settings->nb_pstate_switch_disable);
1413         PP_DBG_LOG("   cpu_pstate_separation_time: %d\n\n",
1414                         cc6_settings->cpu_pstate_separation_time);
1415 }
1416
1417  static int smu8_set_cpu_power_state(struct pp_hwmgr *hwmgr)
1418 {
1419         struct smu8_hwmgr *hw_data = hwmgr->backend;
1420         uint32_t data = 0;
1421
1422         if (hw_data->cc6_settings.cc6_setting_changed) {
1423
1424                 hw_data->cc6_settings.cc6_setting_changed = false;
1425
1426                 smu8_hw_print_display_cfg(&hw_data->cc6_settings);
1427
1428                 data |= (hw_data->cc6_settings.cpu_pstate_separation_time
1429                         & PWRMGT_SEPARATION_TIME_MASK)
1430                         << PWRMGT_SEPARATION_TIME_SHIFT;
1431
1432                 data |= (hw_data->cc6_settings.cpu_cc6_disable ? 0x1 : 0x0)
1433                         << PWRMGT_DISABLE_CPU_CSTATES_SHIFT;
1434
1435                 data |= (hw_data->cc6_settings.cpu_pstate_disable ? 0x1 : 0x0)
1436                         << PWRMGT_DISABLE_CPU_PSTATES_SHIFT;
1437
1438                 PP_DBG_LOG("SetDisplaySizePowerParams data: 0x%X\n",
1439                         data);
1440
1441                 smum_send_msg_to_smc_with_parameter(hwmgr,
1442                                                 PPSMC_MSG_SetDisplaySizePowerParams,
1443                                                 data);
1444         }
1445
1446         return 0;
1447 }
1448
1449
1450 static int smu8_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time,
1451                         bool cc6_disable, bool pstate_disable, bool pstate_switch_disable)
1452 {
1453         struct smu8_hwmgr *hw_data = hwmgr->backend;
1454
1455         if (separation_time !=
1456             hw_data->cc6_settings.cpu_pstate_separation_time ||
1457             cc6_disable != hw_data->cc6_settings.cpu_cc6_disable ||
1458             pstate_disable != hw_data->cc6_settings.cpu_pstate_disable ||
1459             pstate_switch_disable != hw_data->cc6_settings.nb_pstate_switch_disable) {
1460
1461                 hw_data->cc6_settings.cc6_setting_changed = true;
1462
1463                 hw_data->cc6_settings.cpu_pstate_separation_time =
1464                         separation_time;
1465                 hw_data->cc6_settings.cpu_cc6_disable =
1466                         cc6_disable;
1467                 hw_data->cc6_settings.cpu_pstate_disable =
1468                         pstate_disable;
1469                 hw_data->cc6_settings.nb_pstate_switch_disable =
1470                         pstate_switch_disable;
1471
1472         }
1473
1474         return 0;
1475 }
1476
1477 static int smu8_get_dal_power_level(struct pp_hwmgr *hwmgr,
1478                 struct amd_pp_simple_clock_info *info)
1479 {
1480         uint32_t i;
1481         const struct phm_clock_voltage_dependency_table *table =
1482                         hwmgr->dyn_state.vddc_dep_on_dal_pwrl;
1483         const struct phm_clock_and_voltage_limits *limits =
1484                         &hwmgr->dyn_state.max_clock_voltage_on_ac;
1485
1486         info->engine_max_clock = limits->sclk;
1487         info->memory_max_clock = limits->mclk;
1488
1489         for (i = table->count - 1; i > 0; i--) {
1490                 if (limits->vddc >= table->entries[i].v) {
1491                         info->level = table->entries[i].clk;
1492                         return 0;
1493                 }
1494         }
1495         return -EINVAL;
1496 }
1497
1498 static int smu8_force_clock_level(struct pp_hwmgr *hwmgr,
1499                 enum pp_clock_type type, uint32_t mask)
1500 {
1501         switch (type) {
1502         case PP_SCLK:
1503                 smum_send_msg_to_smc_with_parameter(hwmgr,
1504                                 PPSMC_MSG_SetSclkSoftMin,
1505                                 mask);
1506                 smum_send_msg_to_smc_with_parameter(hwmgr,
1507                                 PPSMC_MSG_SetSclkSoftMax,
1508                                 mask);
1509                 break;
1510         default:
1511                 break;
1512         }
1513
1514         return 0;
1515 }
1516
1517 static int smu8_print_clock_levels(struct pp_hwmgr *hwmgr,
1518                 enum pp_clock_type type, char *buf)
1519 {
1520         struct smu8_hwmgr *data = hwmgr->backend;
1521         struct phm_clock_voltage_dependency_table *sclk_table =
1522                         hwmgr->dyn_state.vddc_dependency_on_sclk;
1523         int i, now, size = 0;
1524
1525         switch (type) {
1526         case PP_SCLK:
1527                 now = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device,
1528                                 CGS_IND_REG__SMC,
1529                                 ixTARGET_AND_CURRENT_PROFILE_INDEX),
1530                                 TARGET_AND_CURRENT_PROFILE_INDEX,
1531                                 CURR_SCLK_INDEX);
1532
1533                 for (i = 0; i < sclk_table->count; i++)
1534                         size += sprintf(buf + size, "%d: %uMhz %s\n",
1535                                         i, sclk_table->entries[i].clk / 100,
1536                                         (i == now) ? "*" : "");
1537                 break;
1538         case PP_MCLK:
1539                 now = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device,
1540                                 CGS_IND_REG__SMC,
1541                                 ixTARGET_AND_CURRENT_PROFILE_INDEX),
1542                                 TARGET_AND_CURRENT_PROFILE_INDEX,
1543                                 CURR_MCLK_INDEX);
1544
1545                 for (i = SMU8_NUM_NBPMEMORYCLOCK; i > 0; i--)
1546                         size += sprintf(buf + size, "%d: %uMhz %s\n",
1547                                         SMU8_NUM_NBPMEMORYCLOCK-i, data->sys_info.nbp_memory_clock[i-1] / 100,
1548                                         (SMU8_NUM_NBPMEMORYCLOCK-i == now) ? "*" : "");
1549                 break;
1550         default:
1551                 break;
1552         }
1553         return size;
1554 }
1555
1556 static int smu8_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state,
1557                                 PHM_PerformanceLevelDesignation designation, uint32_t index,
1558                                 PHM_PerformanceLevel *level)
1559 {
1560         const struct smu8_power_state *ps;
1561         struct smu8_hwmgr *data;
1562         uint32_t level_index;
1563         uint32_t i;
1564
1565         if (level == NULL || hwmgr == NULL || state == NULL)
1566                 return -EINVAL;
1567
1568         data = hwmgr->backend;
1569         ps = cast_const_smu8_power_state(state);
1570
1571         level_index = index > ps->level - 1 ? ps->level - 1 : index;
1572         level->coreClock = ps->levels[level_index].engineClock;
1573
1574         if (designation == PHM_PerformanceLevelDesignation_PowerContainment) {
1575                 for (i = 1; i < ps->level; i++) {
1576                         if (ps->levels[i].engineClock > data->dce_slow_sclk_threshold) {
1577                                 level->coreClock = ps->levels[i].engineClock;
1578                                 break;
1579                         }
1580                 }
1581         }
1582
1583         if (level_index == 0)
1584                 level->memory_clock = data->sys_info.nbp_memory_clock[SMU8_NUM_NBPMEMORYCLOCK - 1];
1585         else
1586                 level->memory_clock = data->sys_info.nbp_memory_clock[0];
1587
1588         level->vddc = (smu8_convert_8Bit_index_to_voltage(hwmgr, ps->levels[level_index].vddcIndex) + 2) / 4;
1589         level->nonLocalMemoryFreq = 0;
1590         level->nonLocalMemoryWidth = 0;
1591
1592         return 0;
1593 }
1594
1595 static int smu8_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr,
1596         const struct pp_hw_power_state *state, struct pp_clock_info *clock_info)
1597 {
1598         const struct smu8_power_state *ps = cast_const_smu8_power_state(state);
1599
1600         clock_info->min_eng_clk = ps->levels[0].engineClock / (1 << (ps->levels[0].ssDividerIndex));
1601         clock_info->max_eng_clk = ps->levels[ps->level - 1].engineClock / (1 << (ps->levels[ps->level - 1].ssDividerIndex));
1602
1603         return 0;
1604 }
1605
1606 static int smu8_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type,
1607                                                 struct amd_pp_clocks *clocks)
1608 {
1609         struct smu8_hwmgr *data = hwmgr->backend;
1610         int i;
1611         struct phm_clock_voltage_dependency_table *table;
1612
1613         clocks->count = smu8_get_max_sclk_level(hwmgr);
1614         switch (type) {
1615         case amd_pp_disp_clock:
1616                 for (i = 0; i < clocks->count; i++)
1617                         clocks->clock[i] = data->sys_info.display_clock[i] * 10;
1618                 break;
1619         case amd_pp_sys_clock:
1620                 table = hwmgr->dyn_state.vddc_dependency_on_sclk;
1621                 for (i = 0; i < clocks->count; i++)
1622                         clocks->clock[i] = table->entries[i].clk * 10;
1623                 break;
1624         case amd_pp_mem_clock:
1625                 clocks->count = SMU8_NUM_NBPMEMORYCLOCK;
1626                 for (i = 0; i < clocks->count; i++)
1627                         clocks->clock[i] = data->sys_info.nbp_memory_clock[clocks->count - 1 - i] * 10;
1628                 break;
1629         default:
1630                 return -1;
1631         }
1632
1633         return 0;
1634 }
1635
1636 static int smu8_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks)
1637 {
1638         struct phm_clock_voltage_dependency_table *table =
1639                                         hwmgr->dyn_state.vddc_dependency_on_sclk;
1640         unsigned long level;
1641         const struct phm_clock_and_voltage_limits *limits =
1642                         &hwmgr->dyn_state.max_clock_voltage_on_ac;
1643
1644         if ((NULL == table) || (table->count <= 0) || (clocks == NULL))
1645                 return -EINVAL;
1646
1647         level = smu8_get_max_sclk_level(hwmgr) - 1;
1648
1649         if (level < table->count)
1650                 clocks->engine_max_clock = table->entries[level].clk;
1651         else
1652                 clocks->engine_max_clock = table->entries[table->count - 1].clk;
1653
1654         clocks->memory_max_clock = limits->mclk;
1655
1656         return 0;
1657 }
1658
1659 static int smu8_thermal_get_temperature(struct pp_hwmgr *hwmgr)
1660 {
1661         int actual_temp = 0;
1662         uint32_t val = cgs_read_ind_register(hwmgr->device,
1663                                              CGS_IND_REG__SMC, ixTHM_TCON_CUR_TMP);
1664         uint32_t temp = PHM_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP);
1665
1666         if (PHM_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP_RANGE_SEL))
1667                 actual_temp = ((temp / 8) - 49) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
1668         else
1669                 actual_temp = (temp / 8) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
1670
1671         return actual_temp;
1672 }
1673
1674 static int smu8_read_sensor(struct pp_hwmgr *hwmgr, int idx,
1675                           void *value, int *size)
1676 {
1677         struct smu8_hwmgr *data = hwmgr->backend;
1678
1679         struct phm_clock_voltage_dependency_table *table =
1680                                 hwmgr->dyn_state.vddc_dependency_on_sclk;
1681
1682         struct phm_vce_clock_voltage_dependency_table *vce_table =
1683                 hwmgr->dyn_state.vce_clock_voltage_dependency_table;
1684
1685         struct phm_uvd_clock_voltage_dependency_table *uvd_table =
1686                 hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
1687
1688         uint32_t sclk_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX),
1689                                         TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
1690         uint32_t uvd_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
1691                                         TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
1692         uint32_t vce_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
1693                                         TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
1694
1695         uint32_t sclk, vclk, dclk, ecclk, tmp, activity_percent;
1696         uint16_t vddnb, vddgfx;
1697         int result;
1698
1699         /* size must be at least 4 bytes for all sensors */
1700         if (*size < 4)
1701                 return -EINVAL;
1702         *size = 4;
1703
1704         switch (idx) {
1705         case AMDGPU_PP_SENSOR_GFX_SCLK:
1706                 if (sclk_index < NUM_SCLK_LEVELS) {
1707                         sclk = table->entries[sclk_index].clk;
1708                         *((uint32_t *)value) = sclk;
1709                         return 0;
1710                 }
1711                 return -EINVAL;
1712         case AMDGPU_PP_SENSOR_VDDNB:
1713                 tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) &
1714                         CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
1715                 vddnb = smu8_convert_8Bit_index_to_voltage(hwmgr, tmp) / 4;
1716                 *((uint32_t *)value) = vddnb;
1717                 return 0;
1718         case AMDGPU_PP_SENSOR_VDDGFX:
1719                 tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) &
1720                         CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
1721                 vddgfx = smu8_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp) / 4;
1722                 *((uint32_t *)value) = vddgfx;
1723                 return 0;
1724         case AMDGPU_PP_SENSOR_UVD_VCLK:
1725                 if (!data->uvd_power_gated) {
1726                         if (uvd_index >= SMU8_MAX_HARDWARE_POWERLEVELS) {
1727                                 return -EINVAL;
1728                         } else {
1729                                 vclk = uvd_table->entries[uvd_index].vclk;
1730                                 *((uint32_t *)value) = vclk;
1731                                 return 0;
1732                         }
1733                 }
1734                 *((uint32_t *)value) = 0;
1735                 return 0;
1736         case AMDGPU_PP_SENSOR_UVD_DCLK:
1737                 if (!data->uvd_power_gated) {
1738                         if (uvd_index >= SMU8_MAX_HARDWARE_POWERLEVELS) {
1739                                 return -EINVAL;
1740                         } else {
1741                                 dclk = uvd_table->entries[uvd_index].dclk;
1742                                 *((uint32_t *)value) = dclk;
1743                                 return 0;
1744                         }
1745                 }
1746                 *((uint32_t *)value) = 0;
1747                 return 0;
1748         case AMDGPU_PP_SENSOR_VCE_ECCLK:
1749                 if (!data->vce_power_gated) {
1750                         if (vce_index >= SMU8_MAX_HARDWARE_POWERLEVELS) {
1751                                 return -EINVAL;
1752                         } else {
1753                                 ecclk = vce_table->entries[vce_index].ecclk;
1754                                 *((uint32_t *)value) = ecclk;
1755                                 return 0;
1756                         }
1757                 }
1758                 *((uint32_t *)value) = 0;
1759                 return 0;
1760         case AMDGPU_PP_SENSOR_GPU_LOAD:
1761                 result = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetAverageGraphicsActivity);
1762                 if (0 == result) {
1763                         activity_percent = cgs_read_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0);
1764                         activity_percent = activity_percent > 100 ? 100 : activity_percent;
1765                 } else {
1766                         activity_percent = 50;
1767                 }
1768                 *((uint32_t *)value) = activity_percent;
1769                 return 0;
1770         case AMDGPU_PP_SENSOR_UVD_POWER:
1771                 *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1;
1772                 return 0;
1773         case AMDGPU_PP_SENSOR_VCE_POWER:
1774                 *((uint32_t *)value) = data->vce_power_gated ? 0 : 1;
1775                 return 0;
1776         case AMDGPU_PP_SENSOR_GPU_TEMP:
1777                 *((uint32_t *)value) = smu8_thermal_get_temperature(hwmgr);
1778                 return 0;
1779         default:
1780                 return -EINVAL;
1781         }
1782 }
1783
1784 static int smu8_notify_cac_buffer_info(struct pp_hwmgr *hwmgr,
1785                                         uint32_t virtual_addr_low,
1786                                         uint32_t virtual_addr_hi,
1787                                         uint32_t mc_addr_low,
1788                                         uint32_t mc_addr_hi,
1789                                         uint32_t size)
1790 {
1791         smum_send_msg_to_smc_with_parameter(hwmgr,
1792                                         PPSMC_MSG_DramAddrHiVirtual,
1793                                         mc_addr_hi);
1794         smum_send_msg_to_smc_with_parameter(hwmgr,
1795                                         PPSMC_MSG_DramAddrLoVirtual,
1796                                         mc_addr_low);
1797         smum_send_msg_to_smc_with_parameter(hwmgr,
1798                                         PPSMC_MSG_DramAddrHiPhysical,
1799                                         virtual_addr_hi);
1800         smum_send_msg_to_smc_with_parameter(hwmgr,
1801                                         PPSMC_MSG_DramAddrLoPhysical,
1802                                         virtual_addr_low);
1803
1804         smum_send_msg_to_smc_with_parameter(hwmgr,
1805                                         PPSMC_MSG_DramBufferSize,
1806                                         size);
1807         return 0;
1808 }
1809
1810 static int smu8_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
1811                 struct PP_TemperatureRange *thermal_data)
1812 {
1813         struct smu8_hwmgr *data = hwmgr->backend;
1814
1815         memcpy(thermal_data, &SMU7ThermalPolicy[0], sizeof(struct PP_TemperatureRange));
1816
1817         thermal_data->max = (data->thermal_auto_throttling_treshold +
1818                         data->sys_info.htc_hyst_lmt) *
1819                         PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
1820
1821         return 0;
1822 }
1823
1824 static int smu8_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable)
1825 {
1826         struct smu8_hwmgr *data = hwmgr->backend;
1827         uint32_t dpm_features = 0;
1828
1829         if (enable &&
1830                 phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1831                                   PHM_PlatformCaps_UVDDPM)) {
1832                 data->dpm_flags |= DPMFlags_UVD_Enabled;
1833                 dpm_features |= UVD_DPM_MASK;
1834                 smum_send_msg_to_smc_with_parameter(hwmgr,
1835                             PPSMC_MSG_EnableAllSmuFeatures, dpm_features);
1836         } else {
1837                 dpm_features |= UVD_DPM_MASK;
1838                 data->dpm_flags &= ~DPMFlags_UVD_Enabled;
1839                 smum_send_msg_to_smc_with_parameter(hwmgr,
1840                            PPSMC_MSG_DisableAllSmuFeatures, dpm_features);
1841         }
1842         return 0;
1843 }
1844
1845 int smu8_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
1846 {
1847         struct smu8_hwmgr *data = hwmgr->backend;
1848         struct phm_uvd_clock_voltage_dependency_table *ptable =
1849                 hwmgr->dyn_state.uvd_clock_voltage_dependency_table;
1850
1851         if (!bgate) {
1852                 /* Stable Pstate is enabled and we need to set the UVD DPM to highest level */
1853                 if (PP_CAP(PHM_PlatformCaps_StablePState) ||
1854                     hwmgr->en_umd_pstate) {
1855                         data->uvd_dpm.hard_min_clk =
1856                                    ptable->entries[ptable->count - 1].vclk;
1857
1858                         smum_send_msg_to_smc_with_parameter(hwmgr,
1859                                 PPSMC_MSG_SetUvdHardMin,
1860                                 smu8_get_uvd_level(hwmgr,
1861                                         data->uvd_dpm.hard_min_clk,
1862                                         PPSMC_MSG_SetUvdHardMin));
1863
1864                         smu8_enable_disable_uvd_dpm(hwmgr, true);
1865                 } else {
1866                         smu8_enable_disable_uvd_dpm(hwmgr, true);
1867                 }
1868         } else {
1869                 smu8_enable_disable_uvd_dpm(hwmgr, false);
1870         }
1871
1872         return 0;
1873 }
1874
1875 static int smu8_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
1876 {
1877         struct smu8_hwmgr *data = hwmgr->backend;
1878         uint32_t dpm_features = 0;
1879
1880         if (enable && phm_cap_enabled(
1881                                 hwmgr->platform_descriptor.platformCaps,
1882                                 PHM_PlatformCaps_VCEDPM)) {
1883                 data->dpm_flags |= DPMFlags_VCE_Enabled;
1884                 dpm_features |= VCE_DPM_MASK;
1885                 smum_send_msg_to_smc_with_parameter(hwmgr,
1886                             PPSMC_MSG_EnableAllSmuFeatures, dpm_features);
1887         } else {
1888                 dpm_features |= VCE_DPM_MASK;
1889                 data->dpm_flags &= ~DPMFlags_VCE_Enabled;
1890                 smum_send_msg_to_smc_with_parameter(hwmgr,
1891                            PPSMC_MSG_DisableAllSmuFeatures, dpm_features);
1892         }
1893
1894         return 0;
1895 }
1896
1897
1898 static void smu8_dpm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate)
1899 {
1900         struct smu8_hwmgr *data = hwmgr->backend;
1901
1902         if (data->acp_power_gated == bgate)
1903                 return;
1904
1905         if (bgate)
1906                 smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ACPPowerOFF);
1907         else
1908                 smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ACPPowerON);
1909 }
1910
1911 static void smu8_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
1912 {
1913         struct smu8_hwmgr *data = hwmgr->backend;
1914
1915         data->uvd_power_gated = bgate;
1916
1917         if (bgate) {
1918                 amdgpu_device_ip_set_powergating_state(hwmgr->adev,
1919                                                 AMD_IP_BLOCK_TYPE_UVD,
1920                                                 AMD_PG_STATE_GATE);
1921                 amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
1922                                                 AMD_IP_BLOCK_TYPE_UVD,
1923                                                 AMD_CG_STATE_GATE);
1924                 smu8_dpm_update_uvd_dpm(hwmgr, true);
1925                 smu8_dpm_powerdown_uvd(hwmgr);
1926         } else {
1927                 smu8_dpm_powerup_uvd(hwmgr);
1928                 amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
1929                                                 AMD_IP_BLOCK_TYPE_UVD,
1930                                                 AMD_CG_STATE_UNGATE);
1931                 amdgpu_device_ip_set_powergating_state(hwmgr->adev,
1932                                                 AMD_IP_BLOCK_TYPE_UVD,
1933                                                 AMD_PG_STATE_UNGATE);
1934                 smu8_dpm_update_uvd_dpm(hwmgr, false);
1935         }
1936
1937 }
1938
1939 static void smu8_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
1940 {
1941         struct smu8_hwmgr *data = hwmgr->backend;
1942
1943         if (bgate) {
1944                 amdgpu_device_ip_set_powergating_state(hwmgr->adev,
1945                                         AMD_IP_BLOCK_TYPE_VCE,
1946                                         AMD_PG_STATE_GATE);
1947                 amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
1948                                         AMD_IP_BLOCK_TYPE_VCE,
1949                                         AMD_CG_STATE_GATE);
1950                 smu8_enable_disable_vce_dpm(hwmgr, false);
1951                 smu8_dpm_powerdown_vce(hwmgr);
1952                 data->vce_power_gated = true;
1953         } else {
1954                 smu8_dpm_powerup_vce(hwmgr);
1955                 data->vce_power_gated = false;
1956                 amdgpu_device_ip_set_clockgating_state(hwmgr->adev,
1957                                         AMD_IP_BLOCK_TYPE_VCE,
1958                                         AMD_CG_STATE_UNGATE);
1959                 amdgpu_device_ip_set_powergating_state(hwmgr->adev,
1960                                         AMD_IP_BLOCK_TYPE_VCE,
1961                                         AMD_PG_STATE_UNGATE);
1962                 smu8_dpm_update_vce_dpm(hwmgr);
1963                 smu8_enable_disable_vce_dpm(hwmgr, true);
1964         }
1965 }
1966
1967 static const struct pp_hwmgr_func smu8_hwmgr_funcs = {
1968         .backend_init = smu8_hwmgr_backend_init,
1969         .backend_fini = smu8_hwmgr_backend_fini,
1970         .apply_state_adjust_rules = smu8_apply_state_adjust_rules,
1971         .force_dpm_level = smu8_dpm_force_dpm_level,
1972         .get_power_state_size = smu8_get_power_state_size,
1973         .powerdown_uvd = smu8_dpm_powerdown_uvd,
1974         .powergate_uvd = smu8_dpm_powergate_uvd,
1975         .powergate_vce = smu8_dpm_powergate_vce,
1976         .powergate_acp = smu8_dpm_powergate_acp,
1977         .get_mclk = smu8_dpm_get_mclk,
1978         .get_sclk = smu8_dpm_get_sclk,
1979         .patch_boot_state = smu8_dpm_patch_boot_state,
1980         .get_pp_table_entry = smu8_dpm_get_pp_table_entry,
1981         .get_num_of_pp_table_entries = smu8_dpm_get_num_of_pp_table_entries,
1982         .set_cpu_power_state = smu8_set_cpu_power_state,
1983         .store_cc6_data = smu8_store_cc6_data,
1984         .force_clock_level = smu8_force_clock_level,
1985         .print_clock_levels = smu8_print_clock_levels,
1986         .get_dal_power_level = smu8_get_dal_power_level,
1987         .get_performance_level = smu8_get_performance_level,
1988         .get_current_shallow_sleep_clocks = smu8_get_current_shallow_sleep_clocks,
1989         .get_clock_by_type = smu8_get_clock_by_type,
1990         .get_max_high_clocks = smu8_get_max_high_clocks,
1991         .read_sensor = smu8_read_sensor,
1992         .power_off_asic = smu8_power_off_asic,
1993         .asic_setup = smu8_setup_asic_task,
1994         .dynamic_state_management_enable = smu8_enable_dpm_tasks,
1995         .power_state_set = smu8_set_power_state_tasks,
1996         .dynamic_state_management_disable = smu8_disable_dpm_tasks,
1997         .notify_cac_buffer_info = smu8_notify_cac_buffer_info,
1998         .get_thermal_temperature_range = smu8_get_thermal_temperature_range,
1999 };
2000
2001 int smu8_init_function_pointers(struct pp_hwmgr *hwmgr)
2002 {
2003         hwmgr->hwmgr_func = &smu8_hwmgr_funcs;
2004         hwmgr->pptable_func = &pptable_funcs;
2005         return 0;
2006 }