]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/amd/powerplay/renoir_ppt.c
drm/amd/powerplay: split out those internal used swSMU APIs V2
[linux.git] / drivers / gpu / drm / amd / powerplay / renoir_ppt.c
1 /*
2  * Copyright 2019 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
24 #include "amdgpu.h"
25 #include "amdgpu_smu.h"
26 #include "smu_internal.h"
27 #include "soc15_common.h"
28 #include "smu_v12_0_ppsmc.h"
29 #include "smu12_driver_if.h"
30 #include "smu_v12_0.h"
31 #include "renoir_ppt.h"
32
33
34 #define MSG_MAP(msg, index) \
35         [SMU_MSG_##msg] = {1, (index)}
36
37 #define TAB_MAP_VALID(tab) \
38         [SMU_TABLE_##tab] = {1, TABLE_##tab}
39
40 #define TAB_MAP_INVALID(tab) \
41         [SMU_TABLE_##tab] = {0, TABLE_##tab}
42
43 static struct smu_12_0_cmn2aisc_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = {
44         MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage),
45         MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion),
46         MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion),
47         MSG_MAP(PowerUpGfx,                     PPSMC_MSG_PowerUpGfx),
48         MSG_MAP(AllowGfxOff,                    PPSMC_MSG_EnableGfxOff),
49         MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisableGfxOff),
50         MSG_MAP(PowerDownIspByTile,             PPSMC_MSG_PowerDownIspByTile),
51         MSG_MAP(PowerUpIspByTile,               PPSMC_MSG_PowerUpIspByTile),
52         MSG_MAP(PowerDownVcn,                   PPSMC_MSG_PowerDownVcn),
53         MSG_MAP(PowerUpVcn,                     PPSMC_MSG_PowerUpVcn),
54         MSG_MAP(PowerDownSdma,                  PPSMC_MSG_PowerDownSdma),
55         MSG_MAP(PowerUpSdma,                    PPSMC_MSG_PowerUpSdma),
56         MSG_MAP(SetHardMinIspclkByFreq,         PPSMC_MSG_SetHardMinIspclkByFreq),
57         MSG_MAP(SetHardMinVcn,                  PPSMC_MSG_SetHardMinVcn),
58         MSG_MAP(Spare1,                         PPSMC_MSG_spare1),
59         MSG_MAP(Spare2,                         PPSMC_MSG_spare2),
60         MSG_MAP(SetAllowFclkSwitch,             PPSMC_MSG_SetAllowFclkSwitch),
61         MSG_MAP(SetMinVideoGfxclkFreq,          PPSMC_MSG_SetMinVideoGfxclkFreq),
62         MSG_MAP(ActiveProcessNotify,            PPSMC_MSG_ActiveProcessNotify),
63         MSG_MAP(SetCustomPolicy,                PPSMC_MSG_SetCustomPolicy),
64         MSG_MAP(SetVideoFps,                    PPSMC_MSG_SetVideoFps),
65         MSG_MAP(NumOfDisplays,                  PPSMC_MSG_SetDisplayCount),
66         MSG_MAP(QueryPowerLimit,                PPSMC_MSG_QueryPowerLimit),
67         MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverDramAddrHigh),
68         MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverDramAddrLow),
69         MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram),
70         MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu),
71         MSG_MAP(GfxDeviceDriverReset,           PPSMC_MSG_GfxDeviceDriverReset),
72         MSG_MAP(SetGfxclkOverdriveByFreqVid,    PPSMC_MSG_SetGfxclkOverdriveByFreqVid),
73         MSG_MAP(SetHardMinDcfclkByFreq,         PPSMC_MSG_SetHardMinDcfclkByFreq),
74         MSG_MAP(SetHardMinSocclkByFreq,         PPSMC_MSG_SetHardMinSocclkByFreq),
75         MSG_MAP(ControlIgpuATS,                 PPSMC_MSG_ControlIgpuATS),
76         MSG_MAP(SetMinVideoFclkFreq,            PPSMC_MSG_SetMinVideoFclkFreq),
77         MSG_MAP(SetMinDeepSleepDcfclk,          PPSMC_MSG_SetMinDeepSleepDcfclk),
78         MSG_MAP(ForcePowerDownGfx,              PPSMC_MSG_ForcePowerDownGfx),
79         MSG_MAP(SetPhyclkVoltageByFreq,         PPSMC_MSG_SetPhyclkVoltageByFreq),
80         MSG_MAP(SetDppclkVoltageByFreq,         PPSMC_MSG_SetDppclkVoltageByFreq),
81         MSG_MAP(SetSoftMinVcn,                  PPSMC_MSG_SetSoftMinVcn),
82         MSG_MAP(EnablePostCode,                 PPSMC_MSG_EnablePostCode),
83         MSG_MAP(GetGfxclkFrequency,             PPSMC_MSG_GetGfxclkFrequency),
84         MSG_MAP(GetFclkFrequency,               PPSMC_MSG_GetFclkFrequency),
85         MSG_MAP(GetMinGfxclkFrequency,          PPSMC_MSG_GetMinGfxclkFrequency),
86         MSG_MAP(GetMaxGfxclkFrequency,          PPSMC_MSG_GetMaxGfxclkFrequency),
87         MSG_MAP(SoftReset,                      PPSMC_MSG_SoftReset),
88         MSG_MAP(SetGfxCGPG,                     PPSMC_MSG_SetGfxCGPG),
89         MSG_MAP(SetSoftMaxGfxClk,               PPSMC_MSG_SetSoftMaxGfxClk),
90         MSG_MAP(SetHardMinGfxClk,               PPSMC_MSG_SetHardMinGfxClk),
91         MSG_MAP(SetSoftMaxSocclkByFreq,         PPSMC_MSG_SetSoftMaxSocclkByFreq),
92         MSG_MAP(SetSoftMaxFclkByFreq,           PPSMC_MSG_SetSoftMaxFclkByFreq),
93         MSG_MAP(SetSoftMaxVcn,                  PPSMC_MSG_SetSoftMaxVcn),
94         MSG_MAP(PowerGateMmHub,                 PPSMC_MSG_PowerGateMmHub),
95         MSG_MAP(UpdatePmeRestore,               PPSMC_MSG_UpdatePmeRestore),
96         MSG_MAP(GpuChangeState,                 PPSMC_MSG_GpuChangeState),
97         MSG_MAP(SetPowerLimitPercentage,        PPSMC_MSG_SetPowerLimitPercentage),
98         MSG_MAP(ForceGfxContentSave,            PPSMC_MSG_ForceGfxContentSave),
99         MSG_MAP(EnableTmdp48MHzRefclkPwrDown,   PPSMC_MSG_EnableTmdp48MHzRefclkPwrDown),
100         MSG_MAP(PowerDownJpeg,                  PPSMC_MSG_PowerDownJpeg),
101         MSG_MAP(PowerUpJpeg,                    PPSMC_MSG_PowerUpJpeg),
102         MSG_MAP(PowerGateAtHub,                 PPSMC_MSG_PowerGateAtHub),
103         MSG_MAP(SetSoftMinJpeg,                 PPSMC_MSG_SetSoftMinJpeg),
104         MSG_MAP(SetHardMinFclkByFreq,           PPSMC_MSG_SetHardMinFclkByFreq),
105 };
106
107 static struct smu_12_0_cmn2aisc_mapping renoir_table_map[SMU_TABLE_COUNT] = {
108         TAB_MAP_VALID(WATERMARKS),
109         TAB_MAP_INVALID(CUSTOM_DPM),
110         TAB_MAP_VALID(DPMCLOCKS),
111         TAB_MAP_VALID(SMU_METRICS),
112 };
113
114 static int renoir_get_smu_msg_index(struct smu_context *smc, uint32_t index)
115 {
116         struct smu_12_0_cmn2aisc_mapping mapping;
117
118         if (index >= SMU_MSG_MAX_COUNT)
119                 return -EINVAL;
120
121         mapping = renoir_message_map[index];
122         if (!(mapping.valid_mapping))
123                 return -EINVAL;
124
125         return mapping.map_to;
126 }
127
128 static int renoir_get_smu_table_index(struct smu_context *smc, uint32_t index)
129 {
130         struct smu_12_0_cmn2aisc_mapping mapping;
131
132         if (index >= SMU_TABLE_COUNT)
133                 return -EINVAL;
134
135         mapping = renoir_table_map[index];
136         if (!(mapping.valid_mapping))
137                 return -EINVAL;
138
139         return mapping.map_to;
140 }
141
142 static int renoir_tables_init(struct smu_context *smu, struct smu_table *tables)
143 {
144         struct smu_table_context *smu_table = &smu->smu_table;
145
146         SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
147                 PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
148         SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
149                 PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
150         SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
151                 PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
152
153         smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL);
154         if (!smu_table->clocks_table)
155                 return -ENOMEM;
156
157         return 0;
158 }
159
160 /**
161  * This interface just for getting uclk ultimate freq and should't introduce
162  * other likewise function result in overmuch callback.
163  */
164 static int renoir_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type,
165                                                 uint32_t dpm_level, uint32_t *freq)
166 {
167         DpmClocks_t *clk_table = smu->smu_table.clocks_table;
168
169         if (!clk_table || clk_type >= SMU_CLK_COUNT)
170                 return -EINVAL;
171
172         GET_DPM_CUR_FREQ(clk_table, clk_type, dpm_level, *freq);
173
174         return 0;
175 }
176
177 static int renoir_print_clk_levels(struct smu_context *smu,
178                         enum smu_clk_type clk_type, char *buf)
179 {
180         int i, size = 0, ret = 0;
181         uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0;
182         DpmClocks_t *clk_table = smu->smu_table.clocks_table;
183         SmuMetrics_t metrics = {0};
184
185         if (!clk_table || clk_type >= SMU_CLK_COUNT)
186                 return -EINVAL;
187
188         ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
189                                (void *)&metrics, false);
190         if (ret)
191                 return ret;
192
193         switch (clk_type) {
194         case SMU_GFXCLK:
195         case SMU_SCLK:
196                 /* retirve table returned paramters unit is MHz */
197                 cur_value = metrics.ClockFrequency[CLOCK_GFXCLK];
198                 ret = smu_get_dpm_freq_range(smu, SMU_GFXCLK, &min, &max, false);
199                 if (!ret) {
200                         /* driver only know min/max gfx_clk, Add level 1 for all other gfx clks */
201                         if (cur_value  == max)
202                                 i = 2;
203                         else if (cur_value == min)
204                                 i = 0;
205                         else
206                                 i = 1;
207
208                         size += sprintf(buf + size, "0: %uMhz %s\n", min,
209                                         i == 0 ? "*" : "");
210                         size += sprintf(buf + size, "1: %uMhz %s\n",
211                                         i == 1 ? cur_value : RENOIR_UMD_PSTATE_GFXCLK,
212                                         i == 1 ? "*" : "");
213                         size += sprintf(buf + size, "2: %uMhz %s\n", max,
214                                         i == 2 ? "*" : "");
215                 }
216                 return size;
217         case SMU_SOCCLK:
218                 count = NUM_SOCCLK_DPM_LEVELS;
219                 cur_value = metrics.ClockFrequency[CLOCK_SOCCLK];
220                 break;
221         case SMU_MCLK:
222                 count = NUM_MEMCLK_DPM_LEVELS;
223                 cur_value = metrics.ClockFrequency[CLOCK_UMCCLK];
224                 break;
225         case SMU_DCEFCLK:
226                 count = NUM_DCFCLK_DPM_LEVELS;
227                 cur_value = metrics.ClockFrequency[CLOCK_DCFCLK];
228                 break;
229         case SMU_FCLK:
230                 count = NUM_FCLK_DPM_LEVELS;
231                 cur_value = metrics.ClockFrequency[CLOCK_FCLK];
232                 break;
233         default:
234                 return -EINVAL;
235         }
236
237         for (i = 0; i < count; i++) {
238                 GET_DPM_CUR_FREQ(clk_table, clk_type, i, value);
239                 size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
240                                 cur_value == value ? "*" : "");
241         }
242
243         return size;
244 }
245
246 static enum amd_pm_state_type renoir_get_current_power_state(struct smu_context *smu)
247 {
248         enum amd_pm_state_type pm_type;
249         struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
250
251         if (!smu_dpm_ctx->dpm_context ||
252             !smu_dpm_ctx->dpm_current_power_state)
253                 return -EINVAL;
254
255         switch (smu_dpm_ctx->dpm_current_power_state->classification.ui_label) {
256         case SMU_STATE_UI_LABEL_BATTERY:
257                 pm_type = POWER_STATE_TYPE_BATTERY;
258                 break;
259         case SMU_STATE_UI_LABEL_BALLANCED:
260                 pm_type = POWER_STATE_TYPE_BALANCED;
261                 break;
262         case SMU_STATE_UI_LABEL_PERFORMANCE:
263                 pm_type = POWER_STATE_TYPE_PERFORMANCE;
264                 break;
265         default:
266                 if (smu_dpm_ctx->dpm_current_power_state->classification.flags & SMU_STATE_CLASSIFICATION_FLAG_BOOT)
267                         pm_type = POWER_STATE_TYPE_INTERNAL_BOOT;
268                 else
269                         pm_type = POWER_STATE_TYPE_DEFAULT;
270                 break;
271         }
272
273         return pm_type;
274 }
275
276 static int renoir_dpm_set_uvd_enable(struct smu_context *smu, bool enable)
277 {
278         struct smu_power_context *smu_power = &smu->smu_power;
279         struct smu_power_gate *power_gate = &smu_power->power_gate;
280         int ret = 0;
281
282         if (enable) {
283                 /* vcn dpm on is a prerequisite for vcn power gate messages */
284                 if (smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
285                         ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 1);
286                         if (ret)
287                                 return ret;
288                 }
289                 power_gate->vcn_gated = false;
290         } else {
291                 if (smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
292                         ret = smu_send_smc_msg(smu, SMU_MSG_PowerDownVcn);
293                         if (ret)
294                                 return ret;
295                 }
296                 power_gate->vcn_gated = true;
297         }
298
299         return ret;
300 }
301
302 static int renoir_force_dpm_limit_value(struct smu_context *smu, bool highest)
303 {
304         int ret = 0, i = 0;
305         uint32_t min_freq, max_freq, force_freq;
306         enum smu_clk_type clk_type;
307
308         enum smu_clk_type clks[] = {
309                 SMU_GFXCLK,
310                 SMU_MCLK,
311                 SMU_SOCCLK,
312         };
313
314         for (i = 0; i < ARRAY_SIZE(clks); i++) {
315                 clk_type = clks[i];
316                 ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false);
317                 if (ret)
318                         return ret;
319
320                 force_freq = highest ? max_freq : min_freq;
321                 ret = smu_set_soft_freq_range(smu, clk_type, force_freq, force_freq);
322                 if (ret)
323                         return ret;
324         }
325
326         return ret;
327 }
328
329 static int renoir_unforce_dpm_levels(struct smu_context *smu) {
330
331         int ret = 0, i = 0;
332         uint32_t min_freq, max_freq;
333         enum smu_clk_type clk_type;
334
335         struct clk_feature_map {
336                 enum smu_clk_type clk_type;
337                 uint32_t        feature;
338         } clk_feature_map[] = {
339                 {SMU_GFXCLK, SMU_FEATURE_DPM_GFXCLK_BIT},
340                 {SMU_MCLK,   SMU_FEATURE_DPM_UCLK_BIT},
341                 {SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT},
342         };
343
344         for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) {
345                 if (!smu_feature_is_enabled(smu, clk_feature_map[i].feature))
346                     continue;
347
348                 clk_type = clk_feature_map[i].clk_type;
349
350                 ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false);
351                 if (ret)
352                         return ret;
353
354                 ret = smu_set_soft_freq_range(smu, clk_type, min_freq, max_freq);
355                 if (ret)
356                         return ret;
357         }
358
359         return ret;
360 }
361
362 static int renoir_get_workload_type(struct smu_context *smu, uint32_t profile)
363 {
364
365         uint32_t  pplib_workload = 0;
366
367         switch (profile) {
368         case PP_SMC_POWER_PROFILE_FULLSCREEN3D:
369                 pplib_workload = WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT;
370                 break;
371         case PP_SMC_POWER_PROFILE_CUSTOM:
372                 pplib_workload = WORKLOAD_PPLIB_COUNT;
373                 break;
374         case PP_SMC_POWER_PROFILE_VIDEO:
375                 pplib_workload = WORKLOAD_PPLIB_VIDEO_BIT;
376                 break;
377         case PP_SMC_POWER_PROFILE_VR:
378                 pplib_workload = WORKLOAD_PPLIB_VR_BIT;
379                 break;
380         case PP_SMC_POWER_PROFILE_COMPUTE:
381                 pplib_workload = WORKLOAD_PPLIB_COMPUTE_BIT;
382                 break;
383         default:
384                 return -EINVAL;
385         }
386
387         return pplib_workload;
388 }
389
390 static int renoir_get_profiling_clk_mask(struct smu_context *smu,
391                                          enum amd_dpm_forced_level level,
392                                          uint32_t *sclk_mask,
393                                          uint32_t *mclk_mask,
394                                          uint32_t *soc_mask)
395 {
396
397         if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
398                 if (sclk_mask)
399                         *sclk_mask = 0;
400         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
401                 if (mclk_mask)
402                         *mclk_mask = 0;
403         } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
404                 if(sclk_mask)
405                         /* The sclk as gfxclk and has three level about max/min/current */
406                         *sclk_mask = 3 - 1;
407
408                 if(mclk_mask)
409                         *mclk_mask = NUM_MEMCLK_DPM_LEVELS - 1;
410
411                 if(soc_mask)
412                         *soc_mask = NUM_SOCCLK_DPM_LEVELS - 1;
413         }
414
415         return 0;
416 }
417
418 /**
419  * This interface get dpm clock table for dc
420  */
421 static int renoir_get_dpm_clock_table(struct smu_context *smu, struct dpm_clocks *clock_table)
422 {
423         DpmClocks_t *table = smu->smu_table.clocks_table;
424         int i;
425
426         if (!clock_table || !table)
427                 return -EINVAL;
428
429         for (i = 0; i < NUM_DCFCLK_DPM_LEVELS; i++) {
430                 clock_table->DcfClocks[i].Freq = table->DcfClocks[i].Freq;
431                 clock_table->DcfClocks[i].Vol = table->DcfClocks[i].Vol;
432         }
433
434         for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) {
435                 clock_table->SocClocks[i].Freq = table->SocClocks[i].Freq;
436                 clock_table->SocClocks[i].Vol = table->SocClocks[i].Vol;
437         }
438
439         for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
440                 clock_table->FClocks[i].Freq = table->FClocks[i].Freq;
441                 clock_table->FClocks[i].Vol = table->FClocks[i].Vol;
442         }
443
444         for (i = 0; i<  NUM_MEMCLK_DPM_LEVELS; i++) {
445                 clock_table->MemClocks[i].Freq = table->MemClocks[i].Freq;
446                 clock_table->MemClocks[i].Vol = table->MemClocks[i].Vol;
447         }
448
449         return 0;
450 }
451
452 static int renoir_force_clk_levels(struct smu_context *smu,
453                                    enum smu_clk_type clk_type, uint32_t mask)
454 {
455
456         int ret = 0 ;
457         uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, max_freq = 0;
458         DpmClocks_t *clk_table = smu->smu_table.clocks_table;
459
460         soft_min_level = mask ? (ffs(mask) - 1) : 0;
461         soft_max_level = mask ? (fls(mask) - 1) : 0;
462
463         switch (clk_type) {
464         case SMU_GFXCLK:
465         case SMU_SCLK:
466                 if (soft_min_level > 2 || soft_max_level > 2) {
467                         pr_info("Currently sclk only support 3 levels on APU\n");
468                         return -EINVAL;
469                 }
470
471                 ret = smu_get_dpm_freq_range(smu, SMU_GFXCLK, &min_freq, &max_freq, false);
472                 if (ret)
473                         return ret;
474                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk,
475                                         soft_max_level == 0 ? min_freq :
476                                         soft_max_level == 1 ? RENOIR_UMD_PSTATE_GFXCLK : max_freq);
477                 if (ret)
478                         return ret;
479                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk,
480                                         soft_min_level == 2 ? max_freq :
481                                         soft_min_level == 1 ? RENOIR_UMD_PSTATE_GFXCLK : min_freq);
482                 if (ret)
483                         return ret;
484                 break;
485         case SMU_SOCCLK:
486                 GET_DPM_CUR_FREQ(clk_table, clk_type, soft_min_level, min_freq);
487                 GET_DPM_CUR_FREQ(clk_table, clk_type, soft_max_level, max_freq);
488                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max_freq);
489                 if (ret)
490                         return ret;
491                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min_freq);
492                 if (ret)
493                         return ret;
494                 break;
495         case SMU_MCLK:
496         case SMU_FCLK:
497                 GET_DPM_CUR_FREQ(clk_table, clk_type, soft_min_level, min_freq);
498                 GET_DPM_CUR_FREQ(clk_table, clk_type, soft_max_level, max_freq);
499                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max_freq);
500                 if (ret)
501                         return ret;
502                 ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min_freq);
503                 if (ret)
504                         return ret;
505                 break;
506         default:
507                 break;
508         }
509
510         return ret;
511 }
512
513 static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
514 {
515         int workload_type, ret;
516         uint32_t profile_mode = input[size];
517
518         if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
519                 pr_err("Invalid power profile mode %d\n", smu->power_profile_mode);
520                 return -EINVAL;
521         }
522
523         /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
524         workload_type = smu_workload_get_type(smu, smu->power_profile_mode);
525         if (workload_type < 0) {
526                 pr_err("Unsupported power profile mode %d on RENOIR\n",smu->power_profile_mode);
527                 return -EINVAL;
528         }
529
530         ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
531                                     1 << workload_type);
532         if (ret) {
533                 pr_err("Fail to set workload type %d\n", workload_type);
534                 return ret;
535         }
536
537         smu->power_profile_mode = profile_mode;
538
539         return 0;
540 }
541
542 static int renoir_set_peak_clock_by_device(struct smu_context *smu)
543 {
544         int ret = 0;
545         uint32_t sclk_freq = 0, uclk_freq = 0;
546
547         ret = smu_get_dpm_freq_range(smu, SMU_SCLK, NULL, &sclk_freq, false);
548         if (ret)
549                 return ret;
550
551         ret = smu_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq);
552         if (ret)
553                 return ret;
554
555         ret = smu_get_dpm_freq_range(smu, SMU_UCLK, NULL, &uclk_freq, false);
556         if (ret)
557                 return ret;
558
559         ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq);
560         if (ret)
561                 return ret;
562
563         return ret;
564 }
565
566 static int renoir_set_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level)
567 {
568         int ret = 0;
569
570         switch (level) {
571         case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
572                 ret = renoir_set_peak_clock_by_device(smu);
573                 break;
574         default:
575                 ret = -EINVAL;
576                 break;
577         }
578
579         return ret;
580 }
581
582 /* save watermark settings into pplib smu structure,
583  * also pass data to smu controller
584  */
585 static int renoir_set_watermarks_table(
586                 struct smu_context *smu,
587                 void *watermarks,
588                 struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges)
589 {
590         int i;
591         int ret = 0;
592         Watermarks_t *table = watermarks;
593
594         if (!table || !clock_ranges)
595                 return -EINVAL;
596
597         if (clock_ranges->num_wm_dmif_sets > 4 ||
598                         clock_ranges->num_wm_mcif_sets > 4)
599                 return -EINVAL;
600
601         /* save into smu->smu_table.tables[SMU_TABLE_WATERMARKS]->cpu_addr*/
602         for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) {
603                 table->WatermarkRow[WM_DCFCLK][i].MinClock =
604                         cpu_to_le16((uint16_t)
605                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz));
606                 table->WatermarkRow[WM_DCFCLK][i].MaxClock =
607                         cpu_to_le16((uint16_t)
608                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz));
609                 table->WatermarkRow[WM_DCFCLK][i].MinMclk =
610                         cpu_to_le16((uint16_t)
611                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz));
612                 table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
613                         cpu_to_le16((uint16_t)
614                         (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz));
615                 table->WatermarkRow[WM_DCFCLK][i].WmSetting = (uint8_t)
616                                 clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
617         }
618
619         for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) {
620                 table->WatermarkRow[WM_SOCCLK][i].MinClock =
621                         cpu_to_le16((uint16_t)
622                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz));
623                 table->WatermarkRow[WM_SOCCLK][i].MaxClock =
624                         cpu_to_le16((uint16_t)
625                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz));
626                 table->WatermarkRow[WM_SOCCLK][i].MinMclk =
627                         cpu_to_le16((uint16_t)
628                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz));
629                 table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
630                         cpu_to_le16((uint16_t)
631                         (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz));
632                 table->WatermarkRow[WM_SOCCLK][i].WmSetting = (uint8_t)
633                                 clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
634         }
635
636         /* pass data to smu controller */
637         ret = smu_write_watermarks_table(smu);
638
639         return ret;
640 }
641
642 static int renoir_get_power_profile_mode(struct smu_context *smu,
643                                            char *buf)
644 {
645         static const char *profile_name[] = {
646                                         "BOOTUP_DEFAULT",
647                                         "3D_FULL_SCREEN",
648                                         "POWER_SAVING",
649                                         "VIDEO",
650                                         "VR",
651                                         "COMPUTE",
652                                         "CUSTOM"};
653         uint32_t i, size = 0;
654         int16_t workload_type = 0;
655
656         if (!smu->pm_enabled || !buf)
657                 return -EINVAL;
658
659         for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
660                 /*
661                  * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
662                  * Not all profile modes are supported on arcturus.
663                  */
664                 workload_type = smu_workload_get_type(smu, i);
665                 if (workload_type < 0)
666                         continue;
667
668                 size += sprintf(buf + size, "%2d %14s%s\n",
669                         i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
670         }
671
672         return size;
673 }
674
675 static const struct pptable_funcs renoir_ppt_funcs = {
676         .get_smu_msg_index = renoir_get_smu_msg_index,
677         .get_smu_table_index = renoir_get_smu_table_index,
678         .tables_init = renoir_tables_init,
679         .set_power_state = NULL,
680         .get_dpm_clk_limited = renoir_get_dpm_clk_limited,
681         .print_clk_levels = renoir_print_clk_levels,
682         .get_current_power_state = renoir_get_current_power_state,
683         .dpm_set_uvd_enable = renoir_dpm_set_uvd_enable,
684         .force_dpm_limit_value = renoir_force_dpm_limit_value,
685         .unforce_dpm_levels = renoir_unforce_dpm_levels,
686         .get_workload_type = renoir_get_workload_type,
687         .get_profiling_clk_mask = renoir_get_profiling_clk_mask,
688         .force_clk_levels = renoir_force_clk_levels,
689         .set_power_profile_mode = renoir_set_power_profile_mode,
690         .set_performance_level = renoir_set_performance_level,
691         .get_dpm_clock_table = renoir_get_dpm_clock_table,
692         .set_watermarks_table = renoir_set_watermarks_table,
693         .get_power_profile_mode = renoir_get_power_profile_mode,
694 };
695
696 void renoir_set_ppt_funcs(struct smu_context *smu)
697 {
698         smu->ppt_funcs = &renoir_ppt_funcs;
699         smu->smc_if_version = SMU12_DRIVER_IF_VERSION;
700         smu->is_apu = true;
701 }