e187b3f1a903b3c64c20e691c98ce6efc9865567
[linux-2.6-block.git] / drivers / gpu / drm / amd / powerplay / hwmgr / cz_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 <linux/types.h>
24 #include <linux/kernel.h>
25 #include <linux/slab.h>
26 #include "atom-types.h"
27 #include "atombios.h"
28 #include "processpptables.h"
29 #include "cgs_common.h"
30 #include "smu/smu_8_0_d.h"
31 #include "smu8_fusion.h"
32 #include "smu/smu_8_0_sh_mask.h"
33 #include "smumgr.h"
34 #include "hwmgr.h"
35 #include "hardwaremanager.h"
36 #include "cz_ppsmc.h"
37 #include "cz_hwmgr.h"
38 #include "power_state.h"
39 #include "cz_clockpowergating.h"
40
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 PhwCz_Magic = (unsigned long) PHM_Cz_Magic;
50
51 static struct cz_power_state *cast_PhwCzPowerState(struct pp_hw_power_state *hw_ps)
52 {
53         if (PhwCz_Magic != hw_ps->magic)
54                 return NULL;
55
56         return (struct cz_power_state *)hw_ps;
57 }
58
59 static const struct cz_power_state *cast_const_PhwCzPowerState(
60                                 const struct pp_hw_power_state *hw_ps)
61 {
62         if (PhwCz_Magic != hw_ps->magic)
63                 return NULL;
64
65         return (struct cz_power_state *)hw_ps;
66 }
67
68 uint32_t cz_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_clocl_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 cz_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 cz_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_clocl_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 cz_get_max_sclk_level(struct pp_hwmgr *hwmgr)
161 {
162         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
163
164         if (cz_hwmgr->max_sclk_level == 0) {
165                 smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxSclkLevel);
166                 cz_hwmgr->max_sclk_level = smum_get_argument(hwmgr->smumgr) + 1;
167         }
168
169         return cz_hwmgr->max_sclk_level;
170 }
171
172 static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
173 {
174         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
175         uint32_t i;
176
177         cz_hwmgr->gfx_ramp_step = 256*25/100;
178
179         cz_hwmgr->gfx_ramp_delay = 1; /* by default, we delay 1us */
180
181         for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++)
182                 cz_hwmgr->activity_target[i] = CZ_AT_DFLT;
183
184         cz_hwmgr->mgcg_cgtt_local0 = 0x00000000;
185         cz_hwmgr->mgcg_cgtt_local1 = 0x00000000;
186
187         cz_hwmgr->clock_slow_down_freq = 25000;
188
189         cz_hwmgr->skip_clock_slow_down = 1;
190
191         cz_hwmgr->enable_nb_ps_policy = 1; /* disable until UNB is ready, Enabled */
192
193         cz_hwmgr->voltage_drop_in_dce_power_gating = 0; /* disable until fully verified */
194
195         cz_hwmgr->voting_rights_clients = 0x00C00033;
196
197         cz_hwmgr->static_screen_threshold = 8;
198
199         cz_hwmgr->ddi_power_gating_disabled = 0;
200
201         cz_hwmgr->bapm_enabled = 1;
202
203         cz_hwmgr->voltage_drop_threshold = 0;
204
205         cz_hwmgr->gfx_power_gating_threshold = 500;
206
207         cz_hwmgr->vce_slow_sclk_threshold = 20000;
208
209         cz_hwmgr->dce_slow_sclk_threshold = 30000;
210
211         cz_hwmgr->disable_driver_thermal_policy = 1;
212
213         cz_hwmgr->disable_nb_ps3_in_battery = 0;
214
215         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
216                                                         PHM_PlatformCaps_ABM);
217
218         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
219                                     PHM_PlatformCaps_NonABMSupportInPPLib);
220
221         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
222                                            PHM_PlatformCaps_SclkDeepSleep);
223
224         phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
225                                         PHM_PlatformCaps_DynamicM3Arbiter);
226
227         cz_hwmgr->override_dynamic_mgpg = 1;
228
229         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
230                                   PHM_PlatformCaps_DynamicPatchPowerState);
231
232         cz_hwmgr->thermal_auto_throttling_treshold = 0;
233
234         cz_hwmgr->tdr_clock = 0;
235
236         cz_hwmgr->disable_gfx_power_gating_in_uvd = 0;
237
238         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
239                                         PHM_PlatformCaps_DynamicUVDState);
240
241         cz_hwmgr->is_nb_dpm_enabled_by_driver = 1;
242
243         phm_cap_set(hwmgr->platform_descriptor.platformCaps,
244                                    PHM_PlatformCaps_DisableVoltageIsland);
245
246         return 0;
247 }
248
249 static uint32_t cz_convert_8Bit_index_to_voltage(
250                         struct pp_hwmgr *hwmgr, uint16_t voltage)
251 {
252         return 6200 - (voltage * 25);
253 }
254
255 static int cz_construct_max_power_limits_table(struct pp_hwmgr *hwmgr,
256                         struct phm_clock_and_voltage_limits *table)
257 {
258         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)hwmgr->backend;
259         struct cz_sys_info *sys_info = &cz_hwmgr->sys_info;
260         struct phm_clock_voltage_dependency_table *dep_table =
261                                 hwmgr->dyn_state.vddc_dependency_on_sclk;
262
263         if (dep_table->count > 0) {
264                 table->sclk = dep_table->entries[dep_table->count-1].clk;
265                 table->vddc = cz_convert_8Bit_index_to_voltage(hwmgr,
266                    (uint16_t)dep_table->entries[dep_table->count-1].v);
267         }
268         table->mclk = sys_info->nbp_memory_clock[0];
269         return 0;
270 }
271
272 static int cz_init_dynamic_state_adjustment_rule_settings(
273                         struct pp_hwmgr *hwmgr,
274                         ATOM_CLK_VOLT_CAPABILITY *disp_voltage_table)
275 {
276         uint32_t table_size =
277                 sizeof(struct phm_clock_voltage_dependency_table) +
278                 (7 * sizeof(struct phm_clock_voltage_dependency_record));
279
280         struct phm_clock_voltage_dependency_table *table_clk_vlt =
281                                         kzalloc(table_size, GFP_KERNEL);
282
283         if (NULL == table_clk_vlt) {
284                 printk(KERN_ERR "[ powerplay ] Can not allocate memory!\n");
285                 return -ENOMEM;
286         }
287
288         table_clk_vlt->count = 8;
289         table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0;
290         table_clk_vlt->entries[0].v = 0;
291         table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1;
292         table_clk_vlt->entries[1].v = 1;
293         table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2;
294         table_clk_vlt->entries[2].v = 2;
295         table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3;
296         table_clk_vlt->entries[3].v = 3;
297         table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4;
298         table_clk_vlt->entries[4].v = 4;
299         table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5;
300         table_clk_vlt->entries[5].v = 5;
301         table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6;
302         table_clk_vlt->entries[6].v = 6;
303         table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7;
304         table_clk_vlt->entries[7].v = 7;
305         hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
306
307         return 0;
308 }
309
310 static int cz_get_system_info_data(struct pp_hwmgr *hwmgr)
311 {
312         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)hwmgr->backend;
313         ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info = NULL;
314         uint32_t i;
315         int result = 0;
316         uint8_t frev, crev;
317         uint16_t size;
318
319         info = (ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *) cgs_atom_get_data_table(
320                         hwmgr->device,
321                         GetIndexIntoMasterTable(DATA, IntegratedSystemInfo),
322                         &size, &frev, &crev);
323
324         if (crev != 9) {
325                 printk(KERN_ERR "[ powerplay ] Unsupported IGP table: %d %d\n", frev, crev);
326                 return -EINVAL;
327         }
328
329         if (info == NULL) {
330                 printk(KERN_ERR "[ powerplay ] Could not retrieve the Integrated System Info Table!\n");
331                 return -EINVAL;
332         }
333
334         cz_hwmgr->sys_info.bootup_uma_clock =
335                                    le32_to_cpu(info->ulBootUpUMAClock);
336
337         cz_hwmgr->sys_info.bootup_engine_clock =
338                                 le32_to_cpu(info->ulBootUpEngineClock);
339
340         cz_hwmgr->sys_info.dentist_vco_freq =
341                                    le32_to_cpu(info->ulDentistVCOFreq);
342
343         cz_hwmgr->sys_info.system_config =
344                                      le32_to_cpu(info->ulSystemConfig);
345
346         cz_hwmgr->sys_info.bootup_nb_voltage_index =
347                                   le16_to_cpu(info->usBootUpNBVoltage);
348
349         cz_hwmgr->sys_info.htc_hyst_lmt =
350                         (info->ucHtcHystLmt == 0) ? 5 : info->ucHtcHystLmt;
351
352         cz_hwmgr->sys_info.htc_tmp_lmt =
353                         (info->ucHtcTmpLmt == 0) ? 203 : info->ucHtcTmpLmt;
354
355         if (cz_hwmgr->sys_info.htc_tmp_lmt <=
356                         cz_hwmgr->sys_info.htc_hyst_lmt) {
357                 printk(KERN_ERR "[ powerplay ] The htcTmpLmt should be larger than htcHystLmt.\n");
358                 return -EINVAL;
359         }
360
361         cz_hwmgr->sys_info.nb_dpm_enable =
362                                 cz_hwmgr->enable_nb_ps_policy &&
363                                 (le32_to_cpu(info->ulSystemConfig) >> 3 & 0x1);
364
365         for (i = 0; i < CZ_NUM_NBPSTATES; i++) {
366                 if (i < CZ_NUM_NBPMEMORYCLOCK) {
367                         cz_hwmgr->sys_info.nbp_memory_clock[i] =
368                           le32_to_cpu(info->ulNbpStateMemclkFreq[i]);
369                 }
370                 cz_hwmgr->sys_info.nbp_n_clock[i] =
371                             le32_to_cpu(info->ulNbpStateNClkFreq[i]);
372         }
373
374         for (i = 0; i < MAX_DISPLAY_CLOCK_LEVEL; i++) {
375                 cz_hwmgr->sys_info.display_clock[i] =
376                                         le32_to_cpu(info->sDispClkVoltageMapping[i].ulMaximumSupportedCLK);
377         }
378
379         /* Here use 4 levels, make sure not exceed */
380         for (i = 0; i < CZ_NUM_NBPSTATES; i++) {
381                 cz_hwmgr->sys_info.nbp_voltage_index[i] =
382                              le16_to_cpu(info->usNBPStateVoltage[i]);
383         }
384
385         if (!cz_hwmgr->sys_info.nb_dpm_enable) {
386                 for (i = 1; i < CZ_NUM_NBPSTATES; i++) {
387                         if (i < CZ_NUM_NBPMEMORYCLOCK) {
388                                 cz_hwmgr->sys_info.nbp_memory_clock[i] =
389                                     cz_hwmgr->sys_info.nbp_memory_clock[0];
390                         }
391                         cz_hwmgr->sys_info.nbp_n_clock[i] =
392                                     cz_hwmgr->sys_info.nbp_n_clock[0];
393                         cz_hwmgr->sys_info.nbp_voltage_index[i] =
394                                     cz_hwmgr->sys_info.nbp_voltage_index[0];
395                 }
396         }
397
398         if (le32_to_cpu(info->ulGPUCapInfo) &
399                 SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) {
400                 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
401                                     PHM_PlatformCaps_EnableDFSBypass);
402         }
403
404         cz_hwmgr->sys_info.uma_channel_number = info->ucUMAChannelNumber;
405
406         cz_construct_max_power_limits_table (hwmgr,
407                                     &hwmgr->dyn_state.max_clock_voltage_on_ac);
408
409         cz_init_dynamic_state_adjustment_rule_settings(hwmgr,
410                                     &info->sDISPCLK_Voltage[0]);
411
412         return result;
413 }
414
415 static int cz_construct_boot_state(struct pp_hwmgr *hwmgr)
416 {
417         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
418
419         cz_hwmgr->boot_power_level.engineClock =
420                                 cz_hwmgr->sys_info.bootup_engine_clock;
421
422         cz_hwmgr->boot_power_level.vddcIndex =
423                         (uint8_t)cz_hwmgr->sys_info.bootup_nb_voltage_index;
424
425         cz_hwmgr->boot_power_level.dsDividerIndex = 0;
426
427         cz_hwmgr->boot_power_level.ssDividerIndex = 0;
428
429         cz_hwmgr->boot_power_level.allowGnbSlow = 1;
430
431         cz_hwmgr->boot_power_level.forceNBPstate = 0;
432
433         cz_hwmgr->boot_power_level.hysteresis_up = 0;
434
435         cz_hwmgr->boot_power_level.numSIMDToPowerDown = 0;
436
437         cz_hwmgr->boot_power_level.display_wm = 0;
438
439         cz_hwmgr->boot_power_level.vce_wm = 0;
440
441         return 0;
442 }
443
444 static int cz_tf_reset_active_process_mask(struct pp_hwmgr *hwmgr, void *input,
445                                         void *output, void *storage, int result)
446 {
447         return 0;
448 }
449
450 static int cz_tf_upload_pptable_to_smu(struct pp_hwmgr *hwmgr, void *input,
451                                         void *output, void *storage, int result)
452 {
453         return 0;
454 }
455
456 static int cz_tf_init_sclk_limit(struct pp_hwmgr *hwmgr, void *input,
457                                  void *output, void *storage, int result)
458 {
459         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
460         struct phm_clock_voltage_dependency_table *table =
461                                         hwmgr->dyn_state.vddc_dependency_on_sclk;
462         unsigned long clock = 0, level;
463
464         if (NULL == table && table->count <= 0)
465                 return -EINVAL;
466
467         cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk;
468         cz_hwmgr->sclk_dpm.hard_min_clk = table->entries[0].clk;
469
470         level = cz_get_max_sclk_level(hwmgr) - 1;
471
472         if (level < table->count)
473                 clock = table->entries[level].clk;
474         else
475                 clock = table->entries[table->count - 1].clk;
476
477         cz_hwmgr->sclk_dpm.soft_max_clk = clock;
478         cz_hwmgr->sclk_dpm.hard_max_clk = clock;
479
480         return 0;
481 }
482
483 static int cz_tf_init_uvd_limit(struct pp_hwmgr *hwmgr, void *input,
484                                 void *output, void *storage, int result)
485 {
486         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
487         struct phm_uvd_clock_voltage_dependency_table *table =
488                                 hwmgr->dyn_state.uvd_clocl_voltage_dependency_table;
489         unsigned long clock = 0, level;
490
491         if (NULL == table && table->count <= 0)
492                 return -EINVAL;
493
494         cz_hwmgr->uvd_dpm.soft_min_clk = 0;
495         cz_hwmgr->uvd_dpm.hard_min_clk = 0;
496
497         smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxUvdLevel);
498         level = smum_get_argument(hwmgr->smumgr);
499
500         if (level < table->count)
501                 clock = table->entries[level].vclk;
502         else
503                 clock = table->entries[table->count - 1].vclk;
504
505         cz_hwmgr->uvd_dpm.soft_max_clk = clock;
506         cz_hwmgr->uvd_dpm.hard_max_clk = clock;
507
508         return 0;
509 }
510
511 static int cz_tf_init_vce_limit(struct pp_hwmgr *hwmgr, void *input,
512                                 void *output, void *storage, int result)
513 {
514         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
515         struct phm_vce_clock_voltage_dependency_table *table =
516                                 hwmgr->dyn_state.vce_clocl_voltage_dependency_table;
517         unsigned long clock = 0, level;
518
519         if (NULL == table && table->count <= 0)
520                 return -EINVAL;
521
522         cz_hwmgr->vce_dpm.soft_min_clk = 0;
523         cz_hwmgr->vce_dpm.hard_min_clk = 0;
524
525         smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxEclkLevel);
526         level = smum_get_argument(hwmgr->smumgr);
527
528         if (level < table->count)
529                 clock = table->entries[level].ecclk;
530         else
531                 clock = table->entries[table->count - 1].ecclk;
532
533         cz_hwmgr->vce_dpm.soft_max_clk = clock;
534         cz_hwmgr->vce_dpm.hard_max_clk = clock;
535
536         return 0;
537 }
538
539 static int cz_tf_init_acp_limit(struct pp_hwmgr *hwmgr, void *input,
540                                 void *output, void *storage, int result)
541 {
542         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
543         struct phm_acp_clock_voltage_dependency_table *table =
544                                 hwmgr->dyn_state.acp_clock_voltage_dependency_table;
545         unsigned long clock = 0, level;
546
547         if (NULL == table && table->count <= 0)
548                 return -EINVAL;
549
550         cz_hwmgr->acp_dpm.soft_min_clk = 0;
551         cz_hwmgr->acp_dpm.hard_min_clk = 0;
552
553         smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetMaxAclkLevel);
554         level = smum_get_argument(hwmgr->smumgr);
555
556         if (level < table->count)
557                 clock = table->entries[level].acpclk;
558         else
559                 clock = table->entries[table->count - 1].acpclk;
560
561         cz_hwmgr->acp_dpm.soft_max_clk = clock;
562         cz_hwmgr->acp_dpm.hard_max_clk = clock;
563         return 0;
564 }
565
566 static int cz_tf_init_power_gate_state(struct pp_hwmgr *hwmgr, void *input,
567                                 void *output, void *storage, int result)
568 {
569         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
570
571         cz_hwmgr->uvd_power_gated = false;
572         cz_hwmgr->vce_power_gated = false;
573         cz_hwmgr->samu_power_gated = false;
574         cz_hwmgr->acp_power_gated = false;
575         cz_hwmgr->pgacpinit = true;
576
577         return 0;
578 }
579
580 static int cz_tf_init_sclk_threshold(struct pp_hwmgr *hwmgr, void *input,
581                                 void *output, void *storage, int result)
582 {
583         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
584
585         cz_hwmgr->low_sclk_interrupt_threshold = 0;
586
587         return 0;
588 }
589 static int cz_tf_update_sclk_limit(struct pp_hwmgr *hwmgr,
590                                         void *input, void *output,
591                                         void *storage, int result)
592 {
593         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
594         struct phm_clock_voltage_dependency_table *table =
595                                         hwmgr->dyn_state.vddc_dependency_on_sclk;
596
597         unsigned long clock = 0;
598         unsigned long level;
599         unsigned long stable_pstate_sclk;
600         struct PP_Clocks clocks;
601         unsigned long percentage;
602
603         cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk;
604         level = cz_get_max_sclk_level(hwmgr) - 1;
605
606         if (level < table->count)
607                 cz_hwmgr->sclk_dpm.soft_max_clk  = table->entries[level].clk;
608         else
609                 cz_hwmgr->sclk_dpm.soft_max_clk  = table->entries[table->count - 1].clk;
610
611         /*PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks);*/
612         clock = clocks.engineClock;
613
614         if (cz_hwmgr->sclk_dpm.hard_min_clk != clock) {
615                 cz_hwmgr->sclk_dpm.hard_min_clk = clock;
616
617                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
618                                                 PPSMC_MSG_SetSclkHardMin,
619                                                  cz_get_sclk_level(hwmgr,
620                                         cz_hwmgr->sclk_dpm.hard_min_clk,
621                                              PPSMC_MSG_SetSclkHardMin));
622         }
623
624         clock = cz_hwmgr->sclk_dpm.soft_min_clk;
625
626         /* update minimum clocks for Stable P-State feature */
627         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
628                                      PHM_PlatformCaps_StablePState)) {
629                 percentage = 75;
630                 /*Sclk - calculate sclk value based on percentage and find FLOOR sclk from VddcDependencyOnSCLK table  */
631                 stable_pstate_sclk = (hwmgr->dyn_state.max_clock_voltage_on_ac.mclk *
632                                         percentage) / 100;
633
634                 if (clock < stable_pstate_sclk)
635                         clock = stable_pstate_sclk;
636         } else {
637                 if (clock < hwmgr->gfx_arbiter.sclk)
638                         clock = hwmgr->gfx_arbiter.sclk;
639         }
640
641         if (cz_hwmgr->sclk_dpm.soft_min_clk != clock) {
642                 cz_hwmgr->sclk_dpm.soft_min_clk = clock;
643                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
644                                                 PPSMC_MSG_SetSclkSoftMin,
645                                                 cz_get_sclk_level(hwmgr,
646                                         cz_hwmgr->sclk_dpm.soft_min_clk,
647                                              PPSMC_MSG_SetSclkSoftMin));
648         }
649
650         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
651                                     PHM_PlatformCaps_StablePState) &&
652                          cz_hwmgr->sclk_dpm.soft_max_clk != clock) {
653                 cz_hwmgr->sclk_dpm.soft_max_clk = clock;
654                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
655                                                 PPSMC_MSG_SetSclkSoftMax,
656                                                 cz_get_sclk_level(hwmgr,
657                                         cz_hwmgr->sclk_dpm.soft_max_clk,
658                                         PPSMC_MSG_SetSclkSoftMax));
659         }
660
661         return 0;
662 }
663
664 static int cz_tf_set_deep_sleep_sclk_threshold(struct pp_hwmgr *hwmgr,
665                                         void *input, void *output,
666                                         void *storage, int result)
667 {
668         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
669                                     PHM_PlatformCaps_SclkDeepSleep)) {
670                 /* TO DO get from dal PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks); */
671                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
672                                           PPSMC_MSG_SetMinDeepSleepSclk,
673                                                 CZ_MIN_DEEP_SLEEP_SCLK);
674         }
675
676         return 0;
677 }
678
679 static int cz_tf_set_watermark_threshold(struct pp_hwmgr *hwmgr,
680                                         void *input, void *output,
681                                         void *storage, int result)
682 {
683         struct cz_hwmgr *cz_hwmgr =
684                                   (struct cz_hwmgr *)(hwmgr->backend);
685
686         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
687                                         PPSMC_MSG_SetWatermarkFrequency,
688                                       cz_hwmgr->sclk_dpm.soft_max_clk);
689
690         return 0;
691 }
692
693 static int cz_tf_set_enabled_levels(struct pp_hwmgr *hwmgr,
694                                         void *input, void *output,
695                                         void *storage, int result)
696 {
697         return 0;
698 }
699
700 static int cz_tf_enable_nb_dpm(struct pp_hwmgr *hwmgr,
701                                         void *input, void *output,
702                                         void *storage, int result)
703 {
704         int ret = 0;
705         struct cz_hwmgr *cz_hwmgr =
706                                   (struct cz_hwmgr *)(hwmgr->backend);
707         unsigned long dpm_features = 0;
708
709         if (!cz_hwmgr->is_nb_dpm_enabled &&
710                 cz_hwmgr->is_nb_dpm_enabled_by_driver) {                /* also depend on dal NBPStateDisableRequired */
711                 dpm_features |= NB_DPM_MASK;
712                 ret = smum_send_msg_to_smc_with_parameter(
713                                                              hwmgr->smumgr,
714                                          PPSMC_MSG_EnableAllSmuFeatures,
715                                                              dpm_features);
716                 if (ret == 0)
717                         cz_hwmgr->is_nb_dpm_enabled = true;
718         }
719         return ret;
720 }
721
722 static int cz_tf_update_low_mem_pstate(struct pp_hwmgr *hwmgr,
723                                         void *input, void *output,
724                                         void *storage, int result)
725 {
726
727         struct cz_hwmgr *cz_hwmgr =
728                                   (struct cz_hwmgr *)(hwmgr->backend);
729         const struct phm_set_power_state_input *states = (struct phm_set_power_state_input *)input;
730         const struct cz_power_state *pnew_state = cast_const_PhwCzPowerState(states->pnew_state);
731
732         if (cz_hwmgr->sys_info.nb_dpm_enable) {
733                 if (pnew_state->action == FORCE_HIGH)
734                         smum_send_msg_to_smc(hwmgr->smumgr,
735                                     PPSMC_MSG_DisableLowMemoryPstate);
736                 else
737                         smum_send_msg_to_smc(hwmgr->smumgr,
738                                      PPSMC_MSG_EnableLowMemoryPstate);
739         }
740         return 0;
741 }
742
743 static struct phm_master_table_item cz_set_power_state_list[] = {
744         {NULL, cz_tf_update_sclk_limit},
745         {NULL, cz_tf_set_deep_sleep_sclk_threshold},
746         {NULL, cz_tf_set_watermark_threshold},
747         {NULL, cz_tf_set_enabled_levels},
748         {NULL, cz_tf_enable_nb_dpm},
749         {NULL, cz_tf_update_low_mem_pstate},
750         {NULL, NULL}
751 };
752
753 static struct phm_master_table_header cz_set_power_state_master = {
754         0,
755         PHM_MasterTableFlag_None,
756         cz_set_power_state_list
757 };
758
759 static struct phm_master_table_item cz_setup_asic_list[] = {
760         {NULL, cz_tf_reset_active_process_mask},
761         {NULL, cz_tf_upload_pptable_to_smu},
762         {NULL, cz_tf_init_sclk_limit},
763         {NULL, cz_tf_init_uvd_limit},
764         {NULL, cz_tf_init_vce_limit},
765         {NULL, cz_tf_init_acp_limit},
766         {NULL, cz_tf_init_power_gate_state},
767         {NULL, cz_tf_init_sclk_threshold},
768         {NULL, NULL}
769 };
770
771 static struct phm_master_table_header cz_setup_asic_master = {
772         0,
773         PHM_MasterTableFlag_None,
774         cz_setup_asic_list
775 };
776
777 static int cz_tf_program_voting_clients(struct pp_hwmgr *hwmgr, void *input,
778                                 void *output, void *storage, int result)
779 {
780         PHMCZ_WRITE_SMC_REGISTER(hwmgr->device, CG_FREQ_TRAN_VOTING_0,
781                                 PPCZ_VOTINGRIGHTSCLIENTS_DFLT0);
782         return 0;
783 }
784
785 static int cz_tf_start_dpm(struct pp_hwmgr *hwmgr, void *input, void *output,
786                            void *storage, int result)
787 {
788         int res = 0xff;
789         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
790         unsigned long dpm_features = 0;
791
792         cz_hwmgr->dpm_flags |= DPMFlags_SCLK_Enabled;
793         dpm_features |= SCLK_DPM_MASK;
794
795         res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
796                                 PPSMC_MSG_EnableAllSmuFeatures,
797                                 dpm_features);
798
799         return res;
800 }
801
802 static int cz_tf_program_bootup_state(struct pp_hwmgr *hwmgr, void *input,
803                                 void *output, void *storage, int result)
804 {
805         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
806
807         cz_hwmgr->sclk_dpm.soft_min_clk = cz_hwmgr->sys_info.bootup_engine_clock;
808         cz_hwmgr->sclk_dpm.soft_max_clk = cz_hwmgr->sys_info.bootup_engine_clock;
809
810         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
811                                 PPSMC_MSG_SetSclkSoftMin,
812                                 cz_get_sclk_level(hwmgr,
813                                 cz_hwmgr->sclk_dpm.soft_min_clk,
814                                 PPSMC_MSG_SetSclkSoftMin));
815
816         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
817                                 PPSMC_MSG_SetSclkSoftMax,
818                                 cz_get_sclk_level(hwmgr,
819                                 cz_hwmgr->sclk_dpm.soft_max_clk,
820                                 PPSMC_MSG_SetSclkSoftMax));
821
822         return 0;
823 }
824
825 int cz_tf_reset_acp_boot_level(struct pp_hwmgr *hwmgr, void *input,
826                                 void *output, void *storage, int result)
827 {
828         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
829
830         cz_hwmgr->acp_boot_level = 0xff;
831         return 0;
832 }
833
834 static bool cz_dpm_check_smu_features(struct pp_hwmgr *hwmgr,
835                                 unsigned long check_feature)
836 {
837         int result;
838         unsigned long features;
839
840         result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_GetFeatureStatus, 0);
841         if (result == 0) {
842                 features = smum_get_argument(hwmgr->smumgr);
843                 if (features & check_feature)
844                         return true;
845         }
846
847         return result;
848 }
849
850 static int cz_tf_check_for_dpm_disabled(struct pp_hwmgr *hwmgr, void *input,
851                                 void *output, void *storage, int result)
852 {
853         if (cz_dpm_check_smu_features(hwmgr, SMU_EnabledFeatureScoreboard_SclkDpmOn))
854                 return PP_Result_TableImmediateExit;
855         return 0;
856 }
857
858 static int cz_tf_enable_didt(struct pp_hwmgr *hwmgr, void *input,
859                                 void *output, void *storage, int result)
860 {
861         /* TO DO */
862         return 0;
863 }
864
865 static int cz_tf_check_for_dpm_enabled(struct pp_hwmgr *hwmgr,
866                                                 void *input, void *output,
867                                                 void *storage, int result)
868 {
869         if (!cz_dpm_check_smu_features(hwmgr,
870                              SMU_EnabledFeatureScoreboard_SclkDpmOn))
871                 return PP_Result_TableImmediateExit;
872         return 0;
873 }
874
875 static struct phm_master_table_item cz_disable_dpm_list[] = {
876         { NULL, cz_tf_check_for_dpm_enabled},
877         {NULL, NULL},
878 };
879
880
881 static struct phm_master_table_header cz_disable_dpm_master = {
882         0,
883         PHM_MasterTableFlag_None,
884         cz_disable_dpm_list
885 };
886
887 static struct phm_master_table_item cz_enable_dpm_list[] = {
888         { NULL, cz_tf_check_for_dpm_disabled },
889         { NULL, cz_tf_program_voting_clients },
890         { NULL, cz_tf_start_dpm},
891         { NULL, cz_tf_program_bootup_state},
892         { NULL, cz_tf_enable_didt },
893         { NULL, cz_tf_reset_acp_boot_level },
894         {NULL, NULL},
895 };
896
897 static struct phm_master_table_header cz_enable_dpm_master = {
898         0,
899         PHM_MasterTableFlag_None,
900         cz_enable_dpm_list
901 };
902
903 static int cz_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
904                                 struct pp_power_state  *prequest_ps,
905                         const struct pp_power_state *pcurrent_ps)
906 {
907         struct cz_power_state *cz_ps =
908                                 cast_PhwCzPowerState(&prequest_ps->hardware);
909
910         const struct cz_power_state *cz_current_ps =
911                                 cast_const_PhwCzPowerState(&pcurrent_ps->hardware);
912
913         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
914         struct PP_Clocks clocks;
915         bool force_high;
916         unsigned long  num_of_active_displays = 4;
917
918         cz_ps->evclk = hwmgr->vce_arbiter.evclk;
919         cz_ps->ecclk = hwmgr->vce_arbiter.ecclk;
920
921         cz_ps->need_dfs_bypass = true;
922
923         cz_hwmgr->video_start = (hwmgr->uvd_arbiter.vclk != 0 || hwmgr->uvd_arbiter.dclk != 0 ||
924                                 hwmgr->vce_arbiter.evclk != 0 || hwmgr->vce_arbiter.ecclk != 0);
925
926         cz_hwmgr->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label);
927
928         /* to do PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks); */
929         /* PECI_GetNumberOfActiveDisplays(pHwMgr->pPECI, &numOfActiveDisplays); */
930         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
931                 clocks.memoryClock = hwmgr->dyn_state.max_clock_voltage_on_ac.mclk;
932         else
933                 clocks.memoryClock = 0;
934
935         if (clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
936                 clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
937
938         force_high = (clocks.memoryClock > cz_hwmgr->sys_info.nbp_memory_clock[CZ_NUM_NBPMEMORYCLOCK - 1])
939                         || (num_of_active_displays >= 3);
940
941         cz_ps->action = cz_current_ps->action;
942
943         if ((force_high == false) && (cz_ps->action == FORCE_HIGH))
944                 cz_ps->action = CANCEL_FORCE_HIGH;
945         else if ((force_high == true) && (cz_ps->action != FORCE_HIGH))
946                 cz_ps->action = FORCE_HIGH;
947         else
948                 cz_ps->action = DO_NOTHING;
949
950         return 0;
951 }
952
953 static int cz_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
954 {
955         int result = 0;
956
957         result = cz_initialize_dpm_defaults(hwmgr);
958         if (result != 0) {
959                 printk(KERN_ERR "[ powerplay ] cz_initialize_dpm_defaults failed\n");
960                 return result;
961         }
962
963         result = cz_get_system_info_data(hwmgr);
964         if (result != 0) {
965                 printk(KERN_ERR "[ powerplay ] cz_get_system_info_data failed\n");
966                 return result;
967         }
968
969         cz_construct_boot_state(hwmgr);
970
971         result = phm_construct_table(hwmgr, &cz_setup_asic_master,
972                                 &(hwmgr->setup_asic));
973         if (result != 0) {
974                 printk(KERN_ERR "[ powerplay ] Fail to construct setup ASIC\n");
975                 return result;
976         }
977
978         result = phm_construct_table(hwmgr, &cz_disable_dpm_master,
979                                 &(hwmgr->disable_dynamic_state_management));
980         if (result != 0) {
981                 printk(KERN_ERR "[ powerplay ] Fail to disable_dynamic_state\n");
982                 return result;
983         }
984         result = phm_construct_table(hwmgr, &cz_enable_dpm_master,
985                                 &(hwmgr->enable_dynamic_state_management));
986         if (result != 0) {
987                 printk(KERN_ERR "[ powerplay ] Fail to enable_dynamic_state\n");
988                 return result;
989         }
990         result = phm_construct_table(hwmgr, &cz_set_power_state_master,
991                                 &(hwmgr->set_power_state));
992         if (result != 0) {
993                 printk(KERN_ERR "[ powerplay ] Fail to construct set_power_state\n");
994                 return result;
995         }
996
997         result = phm_construct_table(hwmgr, &cz_phm_enable_clock_power_gatings_master, &(hwmgr->enable_clock_power_gatings));
998         if (result != 0) {
999                 printk(KERN_ERR "[ powerplay ] Fail to construct enable_clock_power_gatings\n");
1000                 return result;
1001         }
1002         return result;
1003 }
1004
1005 static int cz_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
1006 {
1007         if (hwmgr != NULL || hwmgr->backend != NULL) {
1008                 kfree(hwmgr->backend);
1009                 kfree(hwmgr);
1010         }
1011         return 0;
1012 }
1013
1014 int cz_phm_force_dpm_highest(struct pp_hwmgr *hwmgr)
1015 {
1016         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
1017
1018         if (cz_hwmgr->sclk_dpm.soft_min_clk !=
1019                                 cz_hwmgr->sclk_dpm.soft_max_clk)
1020                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
1021                                                 PPSMC_MSG_SetSclkSoftMin,
1022                                                 cz_get_sclk_level(hwmgr,
1023                                                 cz_hwmgr->sclk_dpm.soft_max_clk,
1024                                                 PPSMC_MSG_SetSclkSoftMin));
1025         return 0;
1026 }
1027
1028 int cz_phm_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
1029 {
1030         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
1031         struct phm_clock_voltage_dependency_table *table =
1032                                 hwmgr->dyn_state.vddc_dependency_on_sclk;
1033         unsigned long clock = 0, level;
1034
1035         if (NULL == table && table->count <= 0)
1036                 return -EINVAL;
1037
1038         cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk;
1039         cz_hwmgr->sclk_dpm.hard_min_clk = table->entries[0].clk;
1040
1041         level = cz_get_max_sclk_level(hwmgr) - 1;
1042
1043         if (level < table->count)
1044                 clock = table->entries[level].clk;
1045         else
1046                 clock = table->entries[table->count - 1].clk;
1047
1048         cz_hwmgr->sclk_dpm.soft_max_clk = clock;
1049         cz_hwmgr->sclk_dpm.hard_max_clk = clock;
1050
1051         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
1052                                 PPSMC_MSG_SetSclkSoftMin,
1053                                 cz_get_sclk_level(hwmgr,
1054                                 cz_hwmgr->sclk_dpm.soft_min_clk,
1055                                 PPSMC_MSG_SetSclkSoftMin));
1056
1057         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
1058                                 PPSMC_MSG_SetSclkSoftMax,
1059                                 cz_get_sclk_level(hwmgr,
1060                                 cz_hwmgr->sclk_dpm.soft_max_clk,
1061                                 PPSMC_MSG_SetSclkSoftMax));
1062
1063         return 0;
1064 }
1065
1066 int cz_phm_force_dpm_lowest(struct pp_hwmgr *hwmgr)
1067 {
1068         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
1069
1070         if (cz_hwmgr->sclk_dpm.soft_min_clk !=
1071                                 cz_hwmgr->sclk_dpm.soft_max_clk) {
1072                 cz_hwmgr->sclk_dpm.soft_max_clk =
1073                         cz_hwmgr->sclk_dpm.soft_min_clk;
1074
1075                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
1076                                 PPSMC_MSG_SetSclkSoftMax,
1077                                 cz_get_sclk_level(hwmgr,
1078                                 cz_hwmgr->sclk_dpm.soft_max_clk,
1079                                 PPSMC_MSG_SetSclkSoftMax));
1080         }
1081
1082         return 0;
1083 }
1084
1085 static int cz_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
1086                                 enum amd_dpm_forced_level level)
1087 {
1088         int ret = 0;
1089
1090         switch (level) {
1091         case AMD_DPM_FORCED_LEVEL_HIGH:
1092                 ret = cz_phm_force_dpm_highest(hwmgr);
1093                 if (ret)
1094                         return ret;
1095                 break;
1096         case AMD_DPM_FORCED_LEVEL_LOW:
1097                 ret = cz_phm_force_dpm_lowest(hwmgr);
1098                 if (ret)
1099                         return ret;
1100                 break;
1101         case AMD_DPM_FORCED_LEVEL_AUTO:
1102                 ret = cz_phm_unforce_dpm_levels(hwmgr);
1103                 if (ret)
1104                         return ret;
1105                 break;
1106         default:
1107                 break;
1108         }
1109
1110         hwmgr->dpm_level = level;
1111
1112         return ret;
1113 }
1114
1115 int cz_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr)
1116 {
1117         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1118                                          PHM_PlatformCaps_UVDPowerGating))
1119                 return smum_send_msg_to_smc(hwmgr->smumgr,
1120                                                      PPSMC_MSG_UVDPowerOFF);
1121         return 0;
1122 }
1123
1124 int cz_dpm_powerup_uvd(struct pp_hwmgr *hwmgr)
1125 {
1126         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1127                                          PHM_PlatformCaps_UVDPowerGating)) {
1128                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1129                                   PHM_PlatformCaps_UVDDynamicPowerGating)) {
1130                         return smum_send_msg_to_smc_with_parameter(
1131                                                                 hwmgr->smumgr,
1132                                                    PPSMC_MSG_UVDPowerON, 1);
1133                 } else {
1134                         return smum_send_msg_to_smc_with_parameter(
1135                                                                 hwmgr->smumgr,
1136                                                    PPSMC_MSG_UVDPowerON, 0);
1137                 }
1138         }
1139
1140         return 0;
1141 }
1142
1143 int cz_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
1144 {
1145         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
1146         struct phm_uvd_clock_voltage_dependency_table *ptable =
1147                 hwmgr->dyn_state.uvd_clocl_voltage_dependency_table;
1148
1149         if (!bgate) {
1150                 /* Stable Pstate is enabled and we need to set the UVD DPM to highest level */
1151                 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1152                                          PHM_PlatformCaps_StablePState)) {
1153                         cz_hwmgr->uvd_dpm.hard_min_clk =
1154                                    ptable->entries[ptable->count - 1].vclk;
1155
1156                         smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
1157                                                      PPSMC_MSG_SetUvdHardMin,
1158                                                       cz_get_uvd_level(hwmgr,
1159                                              cz_hwmgr->uvd_dpm.hard_min_clk,
1160                                                    PPSMC_MSG_SetUvdHardMin));
1161
1162                         cz_enable_disable_uvd_dpm(hwmgr, true);
1163                 } else
1164                         cz_enable_disable_uvd_dpm(hwmgr, true);
1165         } else
1166                 cz_enable_disable_uvd_dpm(hwmgr, false);
1167
1168         return 0;
1169 }
1170
1171 int  cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr)
1172 {
1173         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
1174         struct phm_vce_clock_voltage_dependency_table *ptable =
1175                 hwmgr->dyn_state.vce_clocl_voltage_dependency_table;
1176
1177         /* Stable Pstate is enabled and we need to set the VCE DPM to highest level */
1178         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1179                                          PHM_PlatformCaps_StablePState)) {
1180                 cz_hwmgr->vce_dpm.hard_min_clk =
1181                                   ptable->entries[ptable->count - 1].ecclk;
1182
1183                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
1184                                         PPSMC_MSG_SetEclkHardMin,
1185                                         cz_get_eclk_level(hwmgr,
1186                                              cz_hwmgr->vce_dpm.hard_min_clk,
1187                                                 PPSMC_MSG_SetEclkHardMin));
1188         } else {
1189                 /*EPR# 419220 -HW limitation to to */
1190                 cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk;
1191                 smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
1192                                             PPSMC_MSG_SetEclkHardMin,
1193                                             cz_get_eclk_level(hwmgr,
1194                                      cz_hwmgr->vce_dpm.hard_min_clk,
1195                                           PPSMC_MSG_SetEclkHardMin));
1196
1197         }
1198         return 0;
1199 }
1200
1201 int cz_dpm_powerdown_vce(struct pp_hwmgr *hwmgr)
1202 {
1203         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1204                                          PHM_PlatformCaps_VCEPowerGating))
1205                 return smum_send_msg_to_smc(hwmgr->smumgr,
1206                                                      PPSMC_MSG_VCEPowerOFF);
1207         return 0;
1208 }
1209
1210 int cz_dpm_powerup_vce(struct pp_hwmgr *hwmgr)
1211 {
1212         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1213                                          PHM_PlatformCaps_VCEPowerGating))
1214                 return smum_send_msg_to_smc(hwmgr->smumgr,
1215                                                      PPSMC_MSG_VCEPowerON);
1216         return 0;
1217 }
1218
1219 static int cz_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
1220 {
1221         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
1222
1223         return cz_hwmgr->sys_info.bootup_uma_clock;
1224 }
1225
1226 static int cz_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
1227 {
1228         struct pp_power_state  *ps;
1229         struct cz_power_state  *cz_ps;
1230
1231         if (hwmgr == NULL)
1232                 return -EINVAL;
1233
1234         ps = hwmgr->request_ps;
1235
1236         if (ps == NULL)
1237                 return -EINVAL;
1238
1239         cz_ps = cast_PhwCzPowerState(&ps->hardware);
1240
1241         if (low)
1242                 return cz_ps->levels[0].engineClock;
1243         else
1244                 return cz_ps->levels[cz_ps->level-1].engineClock;
1245 }
1246
1247 static int cz_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
1248                                         struct pp_hw_power_state *hw_ps)
1249 {
1250         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
1251         struct cz_power_state *cz_ps = cast_PhwCzPowerState(hw_ps);
1252
1253         cz_ps->level = 1;
1254         cz_ps->nbps_flags = 0;
1255         cz_ps->bapm_flags = 0;
1256         cz_ps->levels[0] = cz_hwmgr->boot_power_level;
1257
1258         return 0;
1259 }
1260
1261 static int cz_dpm_get_pp_table_entry_callback(
1262                                                      struct pp_hwmgr *hwmgr,
1263                                            struct pp_hw_power_state *hw_ps,
1264                                                           unsigned int index,
1265                                                      const void *clock_info)
1266 {
1267         struct cz_power_state *cz_ps = cast_PhwCzPowerState(hw_ps);
1268
1269         const ATOM_PPLIB_CZ_CLOCK_INFO *cz_clock_info = clock_info;
1270
1271         struct phm_clock_voltage_dependency_table *table =
1272                                     hwmgr->dyn_state.vddc_dependency_on_sclk;
1273         uint8_t clock_info_index = cz_clock_info->index;
1274
1275         if (clock_info_index > (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1))
1276                 clock_info_index = (uint8_t)(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1);
1277
1278         cz_ps->levels[index].engineClock = table->entries[clock_info_index].clk;
1279         cz_ps->levels[index].vddcIndex = (uint8_t)table->entries[clock_info_index].v;
1280
1281         cz_ps->level = index + 1;
1282
1283         if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) {
1284                 cz_ps->levels[index].dsDividerIndex = 5;
1285                 cz_ps->levels[index].ssDividerIndex = 5;
1286         }
1287
1288         return 0;
1289 }
1290
1291 static int cz_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr)
1292 {
1293         int result;
1294         unsigned long ret = 0;
1295
1296         result = pp_tables_get_num_of_entries(hwmgr, &ret);
1297
1298         return result ? 0 : ret;
1299 }
1300
1301 static int cz_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr,
1302                     unsigned long entry, struct pp_power_state *ps)
1303 {
1304         int result;
1305         struct cz_power_state *cz_ps;
1306
1307         ps->hardware.magic = PhwCz_Magic;
1308
1309         cz_ps = cast_PhwCzPowerState(&(ps->hardware));
1310
1311         result = pp_tables_get_entry(hwmgr, entry, ps,
1312                         cz_dpm_get_pp_table_entry_callback);
1313
1314         cz_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK;
1315         cz_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK;
1316
1317         return result;
1318 }
1319
1320 int cz_get_power_state_size(struct pp_hwmgr *hwmgr)
1321 {
1322         return sizeof(struct cz_power_state);
1323 }
1324
1325 static void
1326 cz_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m)
1327 {
1328         struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
1329
1330         struct phm_clock_voltage_dependency_table *table =
1331                                 hwmgr->dyn_state.vddc_dependency_on_sclk;
1332
1333         struct phm_vce_clock_voltage_dependency_table *vce_table =
1334                 hwmgr->dyn_state.vce_clocl_voltage_dependency_table;
1335
1336         struct phm_uvd_clock_voltage_dependency_table *uvd_table =
1337                 hwmgr->dyn_state.uvd_clocl_voltage_dependency_table;
1338
1339         uint32_t sclk_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX),
1340                                         TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
1341         uint32_t uvd_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
1342                                         TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
1343         uint32_t vce_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
1344                                         TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
1345
1346         uint32_t sclk, vclk, dclk, ecclk, tmp;
1347         uint16_t vddnb, vddgfx;
1348
1349         if (sclk_index >= NUM_SCLK_LEVELS) {
1350                 seq_printf(m, "\n invalid sclk dpm profile %d\n", sclk_index);
1351         } else {
1352                 sclk = table->entries[sclk_index].clk;
1353                 seq_printf(m, "\n index: %u sclk: %u MHz\n", sclk_index, sclk/100);
1354         }
1355
1356         tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) &
1357                 CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
1358         vddnb = cz_convert_8Bit_index_to_voltage(hwmgr, tmp);
1359         tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) &
1360                 CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
1361         vddgfx = cz_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp);
1362         seq_printf(m, "\n vddnb: %u vddgfx: %u\n", vddnb, vddgfx);
1363
1364         seq_printf(m, "\n uvd    %sabled\n", cz_hwmgr->uvd_power_gated ? "dis" : "en");
1365         if (!cz_hwmgr->uvd_power_gated) {
1366                 if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
1367                         seq_printf(m, "\n invalid uvd dpm level %d\n", uvd_index);
1368                 } else {
1369                         vclk = uvd_table->entries[uvd_index].vclk;
1370                         dclk = uvd_table->entries[uvd_index].dclk;
1371                         seq_printf(m, "\n index: %u uvd vclk: %u MHz dclk: %u MHz\n", uvd_index, vclk/100, dclk/100);
1372                 }
1373         }
1374
1375         seq_printf(m, "\n vce    %sabled\n", cz_hwmgr->vce_power_gated ? "dis" : "en");
1376         if (!cz_hwmgr->vce_power_gated) {
1377                 if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
1378                         seq_printf(m, "\n invalid vce dpm level %d\n", vce_index);
1379                 } else {
1380                         ecclk = vce_table->entries[vce_index].ecclk;
1381                         seq_printf(m, "\n index: %u vce ecclk: %u MHz\n", vce_index, ecclk/100);
1382                 }
1383         }
1384 }
1385
1386 static const struct pp_hwmgr_func cz_hwmgr_funcs = {
1387         .backend_init = cz_hwmgr_backend_init,
1388         .backend_fini = cz_hwmgr_backend_fini,
1389         .asic_setup = NULL,
1390         .apply_state_adjust_rules = cz_apply_state_adjust_rules,
1391         .force_dpm_level = cz_dpm_force_dpm_level,
1392         .get_power_state_size = cz_get_power_state_size,
1393         .powerdown_uvd = cz_dpm_powerdown_uvd,
1394         .powergate_uvd = cz_dpm_powergate_uvd,
1395         .powergate_vce = cz_dpm_powergate_vce,
1396         .get_mclk = cz_dpm_get_mclk,
1397         .get_sclk = cz_dpm_get_sclk,
1398         .patch_boot_state = cz_dpm_patch_boot_state,
1399         .get_pp_table_entry = cz_dpm_get_pp_table_entry,
1400         .get_num_of_pp_table_entries = cz_dpm_get_num_of_pp_table_entries,
1401         .print_current_perforce_level = cz_print_current_perforce_level,
1402 };
1403
1404 int cz_hwmgr_init(struct pp_hwmgr *hwmgr)
1405 {
1406         struct cz_hwmgr *cz_hwmgr;
1407         int ret = 0;
1408
1409         cz_hwmgr = kzalloc(sizeof(struct cz_hwmgr), GFP_KERNEL);
1410         if (cz_hwmgr == NULL)
1411                 return -ENOMEM;
1412
1413         hwmgr->backend = cz_hwmgr;
1414         hwmgr->hwmgr_func = &cz_hwmgr_funcs;
1415         hwmgr->pptable_func = &pptable_funcs;
1416         return ret;
1417 }