blob: 9f3f3b8cf64f23a573f6e826154ab41189ef2e37 [file] [log] [blame]
Alex Deucher1f7371b2015-12-02 17:46:21 -05001/*
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 */
Huang Rui7bd55422016-12-26 14:05:30 +080023#include "pp_debug.h"
Alex Deucher1f7371b2015-12-02 17:46:21 -050024#include <linux/types.h>
25#include <linux/kernel.h>
26#include <linux/gfp.h>
Jammy Zhouac885b32015-07-21 17:43:02 +080027#include <linux/slab.h>
Alex Deucher1f7371b2015-12-02 17:46:21 -050028#include "amd_shared.h"
29#include "amd_powerplay.h"
Jammy Zhouac885b32015-07-21 17:43:02 +080030#include "pp_instance.h"
Rex Zhu577bbe02015-08-28 12:56:43 +080031#include "power_state.h"
Alex Deucher1f7371b2015-12-02 17:46:21 -050032
Rex Zhu1c863802016-12-28 19:43:23 +080033static inline int pp_check(struct pp_instance *handle)
34{
35 if (handle == NULL || handle->pp_valid != PP_VALID)
36 return -EINVAL;
Rex Zhua969e162015-12-29 13:56:03 +080037
Rex Zhub3b03052017-09-26 13:28:27 -040038 if (handle->hwmgr == NULL || handle->hwmgr->smumgr_funcs == NULL)
Rex Zhu1c863802016-12-28 19:43:23 +080039 return -EINVAL;
40
41 if (handle->pm_en == 0)
42 return PP_DPM_DISABLED;
43
Rex Zhub3b03052017-09-26 13:28:27 -040044 if (handle->hwmgr->hwmgr_func == NULL)
Rex Zhu1c863802016-12-28 19:43:23 +080045 return PP_DPM_DISABLED;
46
47 return 0;
48}
Rex Zhu7383bcb2016-03-30 11:35:50 +080049
Alex Deucher1f7371b2015-12-02 17:46:21 -050050static int pp_early_init(void *handle)
51{
Rex Zhu1c863802016-12-28 19:43:23 +080052 int ret;
53 struct pp_instance *pp_handle = (struct pp_instance *)handle;
54
Rex Zhub3b03052017-09-26 13:28:27 -040055 ret = hwmgr_early_init(pp_handle);
Rex Zhu1c863802016-12-28 19:43:23 +080056 if (ret)
Rex Zhub3b03052017-09-26 13:28:27 -040057 return -EINVAL;
Rex Zhu1c863802016-12-28 19:43:23 +080058
59 if ((pp_handle->pm_en == 0)
60 || cgs_is_virtualization_enabled(pp_handle->device))
61 return PP_DPM_DISABLED;
62
Alex Deucher1f7371b2015-12-02 17:46:21 -050063 return 0;
64}
65
66static int pp_sw_init(void *handle)
67{
Rex Zhub3b03052017-09-26 13:28:27 -040068 struct pp_hwmgr *hwmgr;
Jammy Zhou3bace352015-07-21 21:18:15 +080069 int ret = 0;
Rex Zhu1c863802016-12-28 19:43:23 +080070 struct pp_instance *pp_handle = (struct pp_instance *)handle;
Jammy Zhou3bace352015-07-21 21:18:15 +080071
Rex Zhu1c863802016-12-28 19:43:23 +080072 ret = pp_check(pp_handle);
Jammy Zhou3bace352015-07-21 21:18:15 +080073
Rex Zhu1c863802016-12-28 19:43:23 +080074 if (ret == 0 || ret == PP_DPM_DISABLED) {
Rex Zhub3b03052017-09-26 13:28:27 -040075 hwmgr = pp_handle->hwmgr;
Jammy Zhou3bace352015-07-21 21:18:15 +080076
Rex Zhub3b03052017-09-26 13:28:27 -040077 if (hwmgr->smumgr_funcs->smu_init == NULL)
Rex Zhu1c863802016-12-28 19:43:23 +080078 return -EINVAL;
Rex Zhu7383bcb2016-03-30 11:35:50 +080079
Rex Zhub3b03052017-09-26 13:28:27 -040080 ret = hwmgr->smumgr_funcs->smu_init(hwmgr);
Jammy Zhou3bace352015-07-21 21:18:15 +080081
Rex Zhu1c863802016-12-28 19:43:23 +080082 pr_info("amdgpu: powerplay sw initialized\n");
Huang Rui167112b2016-12-14 16:26:54 +080083 }
Jammy Zhou3bace352015-07-21 21:18:15 +080084 return ret;
Alex Deucher1f7371b2015-12-02 17:46:21 -050085}
86
87static int pp_sw_fini(void *handle)
88{
Rex Zhub3b03052017-09-26 13:28:27 -040089 struct pp_hwmgr *hwmgr;
Jammy Zhou3bace352015-07-21 21:18:15 +080090 int ret = 0;
Rex Zhu1c863802016-12-28 19:43:23 +080091 struct pp_instance *pp_handle = (struct pp_instance *)handle;
Jammy Zhou3bace352015-07-21 21:18:15 +080092
Rex Zhu1c863802016-12-28 19:43:23 +080093 ret = pp_check(pp_handle);
94 if (ret == 0 || ret == PP_DPM_DISABLED) {
Rex Zhub3b03052017-09-26 13:28:27 -040095 hwmgr = pp_handle->hwmgr;
Jammy Zhou3bace352015-07-21 21:18:15 +080096
Rex Zhub3b03052017-09-26 13:28:27 -040097 if (hwmgr->smumgr_funcs->smu_fini == NULL)
Rex Zhu1c863802016-12-28 19:43:23 +080098 return -EINVAL;
Jammy Zhou3bace352015-07-21 21:18:15 +080099
Rex Zhub3b03052017-09-26 13:28:27 -0400100 ret = hwmgr->smumgr_funcs->smu_fini(pp_handle->hwmgr);
Rex Zhu1c863802016-12-28 19:43:23 +0800101 }
Jammy Zhou3bace352015-07-21 21:18:15 +0800102 return ret;
Alex Deucher1f7371b2015-12-02 17:46:21 -0500103}
104
105static int pp_hw_init(void *handle)
106{
Jammy Zhouac885b32015-07-21 17:43:02 +0800107 int ret = 0;
Rex Zhu1c863802016-12-28 19:43:23 +0800108 struct pp_instance *pp_handle = (struct pp_instance *)handle;
Rex Zhub3b03052017-09-26 13:28:27 -0400109 struct pp_hwmgr *hwmgr;
Jammy Zhouac885b32015-07-21 17:43:02 +0800110
Rex Zhu1c863802016-12-28 19:43:23 +0800111 ret = pp_check(pp_handle);
Jammy Zhouac885b32015-07-21 17:43:02 +0800112
Rex Zhu1c863802016-12-28 19:43:23 +0800113 if (ret == 0 || ret == PP_DPM_DISABLED) {
Rex Zhub3b03052017-09-26 13:28:27 -0400114 hwmgr = pp_handle->hwmgr;
Jammy Zhouac885b32015-07-21 17:43:02 +0800115
Rex Zhub3b03052017-09-26 13:28:27 -0400116 if (hwmgr->smumgr_funcs->start_smu == NULL)
Rex Zhu1c863802016-12-28 19:43:23 +0800117 return -EINVAL;
Jammy Zhouac885b32015-07-21 17:43:02 +0800118
Rex Zhub3b03052017-09-26 13:28:27 -0400119 if(hwmgr->smumgr_funcs->start_smu(pp_handle->hwmgr)) {
Rex Zhu1c863802016-12-28 19:43:23 +0800120 pr_err("smc start failed\n");
Rex Zhub3b03052017-09-26 13:28:27 -0400121 hwmgr->smumgr_funcs->smu_fini(pp_handle->hwmgr);
Rex Zhu1c863802016-12-28 19:43:23 +0800122 return -EINVAL;;
123 }
124 if (ret == PP_DPM_DISABLED)
125 return PP_DPM_DISABLED;
Jammy Zhouac885b32015-07-21 17:43:02 +0800126 }
127
Rex Zhu1c863802016-12-28 19:43:23 +0800128 ret = hwmgr_hw_init(pp_handle);
129 if (ret)
130 goto err;
Alex Deucher1f7371b2015-12-02 17:46:21 -0500131 return 0;
Rex Zhu1c863802016-12-28 19:43:23 +0800132err:
133 pp_handle->pm_en = 0;
Rex Zhu1c863802016-12-28 19:43:23 +0800134 return PP_DPM_DISABLED;
Alex Deucher1f7371b2015-12-02 17:46:21 -0500135}
136
137static int pp_hw_fini(void *handle)
138{
Rex Zhu1c863802016-12-28 19:43:23 +0800139 struct pp_instance *pp_handle = (struct pp_instance *)handle;
140 int ret = 0;
Jammy Zhouac885b32015-07-21 17:43:02 +0800141
Rex Zhu1c863802016-12-28 19:43:23 +0800142 ret = pp_check(pp_handle);
Rex Zhudf1e6392017-09-01 13:46:20 +0800143 if (ret == 0)
Rex Zhu1c863802016-12-28 19:43:23 +0800144 hwmgr_hw_fini(pp_handle);
Rex Zhudf1e6392017-09-01 13:46:20 +0800145
Alex Deucher1f7371b2015-12-02 17:46:21 -0500146 return 0;
147}
148
149static bool pp_is_idle(void *handle)
150{
Edward O'Callaghaned5121a2016-07-12 10:17:52 +1000151 return false;
Alex Deucher1f7371b2015-12-02 17:46:21 -0500152}
153
154static int pp_wait_for_idle(void *handle)
155{
156 return 0;
157}
158
159static int pp_sw_reset(void *handle)
160{
161 return 0;
162}
163
Alex Deucher1f7371b2015-12-02 17:46:21 -0500164
Rex Zhu465f96e2016-09-18 16:52:03 +0800165int amd_set_clockgating_by_smu(void *handle, uint32_t msg_id)
Alex Deucher1f7371b2015-12-02 17:46:21 -0500166{
Eric Huang03e39052016-02-09 16:26:00 -0500167 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800168 struct pp_instance *pp_handle = (struct pp_instance *)handle;
169 int ret = 0;
Eric Huang03e39052016-02-09 16:26:00 -0500170
Rex Zhu1c863802016-12-28 19:43:23 +0800171 ret = pp_check(pp_handle);
Eric Huang03e39052016-02-09 16:26:00 -0500172
Rex Zhu1c863802016-12-28 19:43:23 +0800173 if (ret != 0)
174 return ret;
Eric Huang03e39052016-02-09 16:26:00 -0500175
Rex Zhu1c863802016-12-28 19:43:23 +0800176 hwmgr = pp_handle->hwmgr;
Eric Huang03e39052016-02-09 16:26:00 -0500177
Rex Zhu7383bcb2016-03-30 11:35:50 +0800178 if (hwmgr->hwmgr_func->update_clock_gatings == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800179 pr_info("%s was not implemented.\n", __func__);
Flora Cui538333f2016-02-15 15:45:59 +0800180 return 0;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800181 }
Flora Cui538333f2016-02-15 15:45:59 +0800182
Rex Zhu465f96e2016-09-18 16:52:03 +0800183 return hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500184}
185
186static int pp_set_powergating_state(void *handle,
187 enum amd_powergating_state state)
188{
Eric Huang65f85e72016-02-11 15:54:45 -0500189 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800190 struct pp_instance *pp_handle = (struct pp_instance *)handle;
191 int ret = 0;
Eric Huang65f85e72016-02-11 15:54:45 -0500192
Rex Zhu1c863802016-12-28 19:43:23 +0800193 ret = pp_check(pp_handle);
Eric Huang65f85e72016-02-11 15:54:45 -0500194
Rex Zhu1c863802016-12-28 19:43:23 +0800195 if (ret != 0)
196 return ret;
Eric Huang65f85e72016-02-11 15:54:45 -0500197
Rex Zhu1c863802016-12-28 19:43:23 +0800198 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800199
200 if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800201 pr_info("%s was not implemented.\n", __func__);
Rex Zhu7383bcb2016-03-30 11:35:50 +0800202 return 0;
203 }
Eric Huang65f85e72016-02-11 15:54:45 -0500204
205 /* Enable/disable GFX per cu powergating through SMU */
206 return hwmgr->hwmgr_func->enable_per_cu_power_gating(hwmgr,
Andrew F. Davis93a4aec2017-03-15 11:20:24 -0500207 state == AMD_PG_STATE_GATE);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500208}
209
210static int pp_suspend(void *handle)
211{
Rex Zhu1c863802016-12-28 19:43:23 +0800212 struct pp_instance *pp_handle = (struct pp_instance *)handle;
213 int ret = 0;
Rex Zhu577bbe02015-08-28 12:56:43 +0800214
Rex Zhu1c863802016-12-28 19:43:23 +0800215 ret = pp_check(pp_handle);
Rex Zhu577bbe02015-08-28 12:56:43 +0800216
Huang Rui4573f0f2017-04-10 14:40:51 +0800217 if (ret == PP_DPM_DISABLED)
218 return 0;
219 else if (ret != 0)
Rex Zhu1c863802016-12-28 19:43:23 +0800220 return ret;
221
Rex Zhudf1e6392017-09-01 13:46:20 +0800222 return hwmgr_hw_suspend(pp_handle);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500223}
224
225static int pp_resume(void *handle)
226{
Rex Zhub3b03052017-09-26 13:28:27 -0400227 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800228 int ret, ret1;
229 struct pp_instance *pp_handle = (struct pp_instance *)handle;
Rex Zhu577bbe02015-08-28 12:56:43 +0800230
Rex Zhu1c863802016-12-28 19:43:23 +0800231 ret1 = pp_check(pp_handle);
Rex Zhu577bbe02015-08-28 12:56:43 +0800232
Rex Zhu1c863802016-12-28 19:43:23 +0800233 if (ret1 != 0 && ret1 != PP_DPM_DISABLED)
234 return ret1;
235
Rex Zhub3b03052017-09-26 13:28:27 -0400236 hwmgr = pp_handle->hwmgr;
Rex Zhue0b71a72015-12-29 10:25:19 +0800237
Rex Zhub3b03052017-09-26 13:28:27 -0400238 if (hwmgr->smumgr_funcs->start_smu == NULL)
Rex Zhue0b71a72015-12-29 10:25:19 +0800239 return -EINVAL;
240
Rex Zhub3b03052017-09-26 13:28:27 -0400241 ret = hwmgr->smumgr_funcs->start_smu(pp_handle->hwmgr);
Rex Zhue0b71a72015-12-29 10:25:19 +0800242 if (ret) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800243 pr_err("smc start failed\n");
Rex Zhub3b03052017-09-26 13:28:27 -0400244 hwmgr->smumgr_funcs->smu_fini(pp_handle->hwmgr);
Rex Zhue0b71a72015-12-29 10:25:19 +0800245 return ret;
246 }
247
Rex Zhu1c863802016-12-28 19:43:23 +0800248 if (ret1 == PP_DPM_DISABLED)
Monk Liu8fdf2692017-01-25 15:55:30 +0800249 return 0;
Rex Zhu1c863802016-12-28 19:43:23 +0800250
Rex Zhudf1e6392017-09-01 13:46:20 +0800251 return hwmgr_hw_resume(pp_handle);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500252}
253
254const struct amd_ip_funcs pp_ip_funcs = {
Tom St Denis88a907d2016-05-04 14:28:35 -0400255 .name = "powerplay",
Alex Deucher1f7371b2015-12-02 17:46:21 -0500256 .early_init = pp_early_init,
257 .late_init = NULL,
258 .sw_init = pp_sw_init,
259 .sw_fini = pp_sw_fini,
260 .hw_init = pp_hw_init,
261 .hw_fini = pp_hw_fini,
262 .suspend = pp_suspend,
263 .resume = pp_resume,
264 .is_idle = pp_is_idle,
265 .wait_for_idle = pp_wait_for_idle,
266 .soft_reset = pp_sw_reset,
Rex Zhu465f96e2016-09-18 16:52:03 +0800267 .set_clockgating_state = NULL,
Alex Deucher1f7371b2015-12-02 17:46:21 -0500268 .set_powergating_state = pp_set_powergating_state,
269};
270
271static int pp_dpm_load_fw(void *handle)
272{
273 return 0;
274}
275
276static int pp_dpm_fw_loading_complete(void *handle)
277{
278 return 0;
279}
280
Rex Zhu9947f702017-08-29 16:08:56 +0800281static void pp_dpm_en_umd_pstate(struct pp_hwmgr *hwmgr,
282 enum amd_dpm_forced_level *level)
283{
284 uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
285 AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
286 AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
287 AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
288
289 if (!(hwmgr->dpm_level & profile_mode_mask)) {
290 /* enter umd pstate, save current level, disable gfx cg*/
291 if (*level & profile_mode_mask) {
292 hwmgr->saved_dpm_level = hwmgr->dpm_level;
293 hwmgr->en_umd_pstate = true;
294 cgs_set_clockgating_state(hwmgr->device,
295 AMD_IP_BLOCK_TYPE_GFX,
296 AMD_CG_STATE_UNGATE);
297 cgs_set_powergating_state(hwmgr->device,
298 AMD_IP_BLOCK_TYPE_GFX,
299 AMD_PG_STATE_UNGATE);
300 }
301 } else {
302 /* exit umd pstate, restore level, enable gfx cg*/
303 if (!(*level & profile_mode_mask)) {
304 if (*level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT)
305 *level = hwmgr->saved_dpm_level;
306 hwmgr->en_umd_pstate = false;
307 cgs_set_clockgating_state(hwmgr->device,
308 AMD_IP_BLOCK_TYPE_GFX,
309 AMD_CG_STATE_GATE);
310 cgs_set_powergating_state(hwmgr->device,
311 AMD_IP_BLOCK_TYPE_GFX,
312 AMD_PG_STATE_GATE);
313 }
314 }
315}
316
Alex Deucher1f7371b2015-12-02 17:46:21 -0500317static int pp_dpm_force_performance_level(void *handle,
318 enum amd_dpm_forced_level level)
319{
Rex Zhu577bbe02015-08-28 12:56:43 +0800320 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800321 struct pp_instance *pp_handle = (struct pp_instance *)handle;
322 int ret = 0;
Rex Zhu577bbe02015-08-28 12:56:43 +0800323
Rex Zhu1c863802016-12-28 19:43:23 +0800324 ret = pp_check(pp_handle);
Rex Zhu577bbe02015-08-28 12:56:43 +0800325
Rex Zhu1c863802016-12-28 19:43:23 +0800326 if (ret != 0)
327 return ret;
Rex Zhu577bbe02015-08-28 12:56:43 +0800328
329 hwmgr = pp_handle->hwmgr;
330
Rex Zhu9947f702017-08-29 16:08:56 +0800331 if (level == hwmgr->dpm_level)
332 return 0;
333
Rex Zhu7383bcb2016-03-30 11:35:50 +0800334 if (hwmgr->hwmgr_func->force_dpm_level == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800335 pr_info("%s was not implemented.\n", __func__);
Rex Zhu7383bcb2016-03-30 11:35:50 +0800336 return 0;
337 }
Rex Zhu577bbe02015-08-28 12:56:43 +0800338
Rex Zhu2a507102017-02-20 17:07:36 +0800339 mutex_lock(&pp_handle->pp_lock);
Rex Zhu9947f702017-08-29 16:08:56 +0800340 pp_dpm_en_umd_pstate(hwmgr, &level);
341 hwmgr->request_dpm_level = level;
Rex Zhudf1e6392017-09-01 13:46:20 +0800342 hwmgr_handle_task(pp_handle, AMD_PP_TASK_READJUST_POWER_STATE, NULL, NULL);
Rex Zhu9947f702017-08-29 16:08:56 +0800343 ret = hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);
344 if (!ret)
345 hwmgr->dpm_level = hwmgr->request_dpm_level;
346
Rex Zhu2a507102017-02-20 17:07:36 +0800347 mutex_unlock(&pp_handle->pp_lock);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500348 return 0;
349}
Rex Zhu577bbe02015-08-28 12:56:43 +0800350
Alex Deucher1f7371b2015-12-02 17:46:21 -0500351static enum amd_dpm_forced_level pp_dpm_get_performance_level(
352 void *handle)
353{
Rex Zhu577bbe02015-08-28 12:56:43 +0800354 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800355 struct pp_instance *pp_handle = (struct pp_instance *)handle;
356 int ret = 0;
Rex Zhu2a507102017-02-20 17:07:36 +0800357 enum amd_dpm_forced_level level;
Rex Zhu577bbe02015-08-28 12:56:43 +0800358
Rex Zhu1c863802016-12-28 19:43:23 +0800359 ret = pp_check(pp_handle);
Rex Zhu577bbe02015-08-28 12:56:43 +0800360
Rex Zhu1c863802016-12-28 19:43:23 +0800361 if (ret != 0)
362 return ret;
Rex Zhu577bbe02015-08-28 12:56:43 +0800363
Rex Zhu1c863802016-12-28 19:43:23 +0800364 hwmgr = pp_handle->hwmgr;
Rex Zhu2a507102017-02-20 17:07:36 +0800365 mutex_lock(&pp_handle->pp_lock);
366 level = hwmgr->dpm_level;
367 mutex_unlock(&pp_handle->pp_lock);
368 return level;
Alex Deucher1f7371b2015-12-02 17:46:21 -0500369}
Rex Zhu577bbe02015-08-28 12:56:43 +0800370
Rex Zhuf93f0c32017-09-06 16:08:03 +0800371static uint32_t pp_dpm_get_sclk(void *handle, bool low)
Alex Deucher1f7371b2015-12-02 17:46:21 -0500372{
Rex Zhu577bbe02015-08-28 12:56:43 +0800373 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800374 struct pp_instance *pp_handle = (struct pp_instance *)handle;
375 int ret = 0;
Rex Zhuf93f0c32017-09-06 16:08:03 +0800376 uint32_t clk = 0;
Rex Zhu577bbe02015-08-28 12:56:43 +0800377
Rex Zhu1c863802016-12-28 19:43:23 +0800378 ret = pp_check(pp_handle);
Rex Zhu577bbe02015-08-28 12:56:43 +0800379
Rex Zhu1c863802016-12-28 19:43:23 +0800380 if (ret != 0)
381 return ret;
Rex Zhu577bbe02015-08-28 12:56:43 +0800382
Rex Zhu1c863802016-12-28 19:43:23 +0800383 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800384
385 if (hwmgr->hwmgr_func->get_sclk == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800386 pr_info("%s was not implemented.\n", __func__);
Rex Zhu7383bcb2016-03-30 11:35:50 +0800387 return 0;
388 }
Rex Zhu2a507102017-02-20 17:07:36 +0800389 mutex_lock(&pp_handle->pp_lock);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800390 clk = hwmgr->hwmgr_func->get_sclk(hwmgr, low);
Rex Zhu2a507102017-02-20 17:07:36 +0800391 mutex_unlock(&pp_handle->pp_lock);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800392 return clk;
Alex Deucher1f7371b2015-12-02 17:46:21 -0500393}
Rex Zhu577bbe02015-08-28 12:56:43 +0800394
Rex Zhuf93f0c32017-09-06 16:08:03 +0800395static uint32_t pp_dpm_get_mclk(void *handle, bool low)
Alex Deucher1f7371b2015-12-02 17:46:21 -0500396{
Rex Zhu577bbe02015-08-28 12:56:43 +0800397 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800398 struct pp_instance *pp_handle = (struct pp_instance *)handle;
399 int ret = 0;
Rex Zhuf93f0c32017-09-06 16:08:03 +0800400 uint32_t clk = 0;
Rex Zhu577bbe02015-08-28 12:56:43 +0800401
Rex Zhu1c863802016-12-28 19:43:23 +0800402 ret = pp_check(pp_handle);
Rex Zhu577bbe02015-08-28 12:56:43 +0800403
Rex Zhu1c863802016-12-28 19:43:23 +0800404 if (ret != 0)
405 return ret;
Rex Zhu577bbe02015-08-28 12:56:43 +0800406
Rex Zhu1c863802016-12-28 19:43:23 +0800407 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800408
409 if (hwmgr->hwmgr_func->get_mclk == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800410 pr_info("%s was not implemented.\n", __func__);
Rex Zhu7383bcb2016-03-30 11:35:50 +0800411 return 0;
412 }
Rex Zhu2a507102017-02-20 17:07:36 +0800413 mutex_lock(&pp_handle->pp_lock);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800414 clk = hwmgr->hwmgr_func->get_mclk(hwmgr, low);
Rex Zhu2a507102017-02-20 17:07:36 +0800415 mutex_unlock(&pp_handle->pp_lock);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800416 return clk;
Alex Deucher1f7371b2015-12-02 17:46:21 -0500417}
Rex Zhu577bbe02015-08-28 12:56:43 +0800418
Rex Zhuf93f0c32017-09-06 16:08:03 +0800419static void pp_dpm_powergate_vce(void *handle, bool gate)
Alex Deucher1f7371b2015-12-02 17:46:21 -0500420{
Rex Zhu577bbe02015-08-28 12:56:43 +0800421 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800422 struct pp_instance *pp_handle = (struct pp_instance *)handle;
423 int ret = 0;
Rex Zhu577bbe02015-08-28 12:56:43 +0800424
Rex Zhu1c863802016-12-28 19:43:23 +0800425 ret = pp_check(pp_handle);
Rex Zhu577bbe02015-08-28 12:56:43 +0800426
Rex Zhu1c863802016-12-28 19:43:23 +0800427 if (ret != 0)
Rex Zhuf93f0c32017-09-06 16:08:03 +0800428 return;
Rex Zhu577bbe02015-08-28 12:56:43 +0800429
Rex Zhu1c863802016-12-28 19:43:23 +0800430 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800431
432 if (hwmgr->hwmgr_func->powergate_vce == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800433 pr_info("%s was not implemented.\n", __func__);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800434 return;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800435 }
Rex Zhu2a507102017-02-20 17:07:36 +0800436 mutex_lock(&pp_handle->pp_lock);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800437 hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
Rex Zhu2a507102017-02-20 17:07:36 +0800438 mutex_unlock(&pp_handle->pp_lock);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500439}
Rex Zhu577bbe02015-08-28 12:56:43 +0800440
Rex Zhuf93f0c32017-09-06 16:08:03 +0800441static void pp_dpm_powergate_uvd(void *handle, bool gate)
Alex Deucher1f7371b2015-12-02 17:46:21 -0500442{
Rex Zhu577bbe02015-08-28 12:56:43 +0800443 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800444 struct pp_instance *pp_handle = (struct pp_instance *)handle;
445 int ret = 0;
Rex Zhu577bbe02015-08-28 12:56:43 +0800446
Rex Zhu1c863802016-12-28 19:43:23 +0800447 ret = pp_check(pp_handle);
Rex Zhu577bbe02015-08-28 12:56:43 +0800448
Rex Zhu1c863802016-12-28 19:43:23 +0800449 if (ret != 0)
Rex Zhuf93f0c32017-09-06 16:08:03 +0800450 return;
Rex Zhu577bbe02015-08-28 12:56:43 +0800451
Rex Zhu1c863802016-12-28 19:43:23 +0800452 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800453
454 if (hwmgr->hwmgr_func->powergate_uvd == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800455 pr_info("%s was not implemented.\n", __func__);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800456 return;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800457 }
Rex Zhu2a507102017-02-20 17:07:36 +0800458 mutex_lock(&pp_handle->pp_lock);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800459 hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
Rex Zhu2a507102017-02-20 17:07:36 +0800460 mutex_unlock(&pp_handle->pp_lock);
Rex Zhu577bbe02015-08-28 12:56:43 +0800461}
462
Rex Zhudf1e6392017-09-01 13:46:20 +0800463static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_task task_id,
Baoyou Xief8a4c112016-09-30 17:58:42 +0800464 void *input, void *output)
Alex Deucher1f7371b2015-12-02 17:46:21 -0500465{
Rex Zhu577bbe02015-08-28 12:56:43 +0800466 int ret = 0;
Rex Zhu1c863802016-12-28 19:43:23 +0800467 struct pp_instance *pp_handle = (struct pp_instance *)handle;
Rex Zhu577bbe02015-08-28 12:56:43 +0800468
Rex Zhu1c863802016-12-28 19:43:23 +0800469 ret = pp_check(pp_handle);
Rex Zhu577bbe02015-08-28 12:56:43 +0800470
Rex Zhu1c863802016-12-28 19:43:23 +0800471 if (ret != 0)
472 return ret;
Rex Zhudf1e6392017-09-01 13:46:20 +0800473
Rex Zhu2a507102017-02-20 17:07:36 +0800474 mutex_lock(&pp_handle->pp_lock);
Rex Zhudf1e6392017-09-01 13:46:20 +0800475 ret = hwmgr_handle_task(pp_handle, task_id, input, output);
Rex Zhu2a507102017-02-20 17:07:36 +0800476 mutex_unlock(&pp_handle->pp_lock);
Rex Zhudf1e6392017-09-01 13:46:20 +0800477
Rex Zhu577bbe02015-08-28 12:56:43 +0800478 return ret;
Alex Deucher1f7371b2015-12-02 17:46:21 -0500479}
Rex Zhu577bbe02015-08-28 12:56:43 +0800480
Baoyou Xief8a4c112016-09-30 17:58:42 +0800481static enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
Alex Deucher1f7371b2015-12-02 17:46:21 -0500482{
Rex Zhu577bbe02015-08-28 12:56:43 +0800483 struct pp_hwmgr *hwmgr;
484 struct pp_power_state *state;
Rex Zhu1c863802016-12-28 19:43:23 +0800485 struct pp_instance *pp_handle = (struct pp_instance *)handle;
486 int ret = 0;
Rex Zhu2a507102017-02-20 17:07:36 +0800487 enum amd_pm_state_type pm_type;
Rex Zhu577bbe02015-08-28 12:56:43 +0800488
Rex Zhu1c863802016-12-28 19:43:23 +0800489 ret = pp_check(pp_handle);
Rex Zhu577bbe02015-08-28 12:56:43 +0800490
Rex Zhu1c863802016-12-28 19:43:23 +0800491 if (ret != 0)
492 return ret;
Rex Zhu577bbe02015-08-28 12:56:43 +0800493
Rex Zhu1c863802016-12-28 19:43:23 +0800494 hwmgr = pp_handle->hwmgr;
495
496 if (hwmgr->current_ps == NULL)
Rex Zhu577bbe02015-08-28 12:56:43 +0800497 return -EINVAL;
498
Rex Zhu2a507102017-02-20 17:07:36 +0800499 mutex_lock(&pp_handle->pp_lock);
500
Rex Zhu577bbe02015-08-28 12:56:43 +0800501 state = hwmgr->current_ps;
502
503 switch (state->classification.ui_label) {
504 case PP_StateUILabel_Battery:
Rex Zhu2a507102017-02-20 17:07:36 +0800505 pm_type = POWER_STATE_TYPE_BATTERY;
Dan Carpenter0f987cd2017-04-03 21:41:47 +0300506 break;
Rex Zhu577bbe02015-08-28 12:56:43 +0800507 case PP_StateUILabel_Balanced:
Rex Zhu2a507102017-02-20 17:07:36 +0800508 pm_type = POWER_STATE_TYPE_BALANCED;
Dan Carpenter0f987cd2017-04-03 21:41:47 +0300509 break;
Rex Zhu577bbe02015-08-28 12:56:43 +0800510 case PP_StateUILabel_Performance:
Rex Zhu2a507102017-02-20 17:07:36 +0800511 pm_type = POWER_STATE_TYPE_PERFORMANCE;
Dan Carpenter0f987cd2017-04-03 21:41:47 +0300512 break;
Rex Zhu577bbe02015-08-28 12:56:43 +0800513 default:
Eric Huangf3898ea2015-12-11 16:24:34 -0500514 if (state->classification.flags & PP_StateClassificationFlag_Boot)
Rex Zhu2a507102017-02-20 17:07:36 +0800515 pm_type = POWER_STATE_TYPE_INTERNAL_BOOT;
Eric Huangf3898ea2015-12-11 16:24:34 -0500516 else
Rex Zhu2a507102017-02-20 17:07:36 +0800517 pm_type = POWER_STATE_TYPE_DEFAULT;
Dan Carpenter0f987cd2017-04-03 21:41:47 +0300518 break;
Rex Zhu577bbe02015-08-28 12:56:43 +0800519 }
Rex Zhu2a507102017-02-20 17:07:36 +0800520 mutex_unlock(&pp_handle->pp_lock);
521
522 return pm_type;
Alex Deucher1f7371b2015-12-02 17:46:21 -0500523}
Rex Zhu577bbe02015-08-28 12:56:43 +0800524
Rex Zhuf93f0c32017-09-06 16:08:03 +0800525static void pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
Rex Zhucac9a192015-10-16 11:48:21 +0800526{
527 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800528 struct pp_instance *pp_handle = (struct pp_instance *)handle;
529 int ret = 0;
Rex Zhucac9a192015-10-16 11:48:21 +0800530
Rex Zhu1c863802016-12-28 19:43:23 +0800531 ret = pp_check(pp_handle);
Rex Zhucac9a192015-10-16 11:48:21 +0800532
Rex Zhu1c863802016-12-28 19:43:23 +0800533 if (ret != 0)
Rex Zhuf93f0c32017-09-06 16:08:03 +0800534 return;
Rex Zhucac9a192015-10-16 11:48:21 +0800535
Rex Zhu1c863802016-12-28 19:43:23 +0800536 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800537
538 if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800539 pr_info("%s was not implemented.\n", __func__);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800540 return;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800541 }
Rex Zhu2a507102017-02-20 17:07:36 +0800542 mutex_lock(&pp_handle->pp_lock);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800543 hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode);
Rex Zhu2a507102017-02-20 17:07:36 +0800544 mutex_unlock(&pp_handle->pp_lock);
Rex Zhucac9a192015-10-16 11:48:21 +0800545}
546
Rex Zhuf93f0c32017-09-06 16:08:03 +0800547static uint32_t pp_dpm_get_fan_control_mode(void *handle)
Rex Zhucac9a192015-10-16 11:48:21 +0800548{
549 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800550 struct pp_instance *pp_handle = (struct pp_instance *)handle;
551 int ret = 0;
Rex Zhuf93f0c32017-09-06 16:08:03 +0800552 uint32_t mode = 0;
Rex Zhucac9a192015-10-16 11:48:21 +0800553
Rex Zhu1c863802016-12-28 19:43:23 +0800554 ret = pp_check(pp_handle);
Rex Zhucac9a192015-10-16 11:48:21 +0800555
Rex Zhu1c863802016-12-28 19:43:23 +0800556 if (ret != 0)
557 return ret;
Rex Zhucac9a192015-10-16 11:48:21 +0800558
Rex Zhu1c863802016-12-28 19:43:23 +0800559 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800560
561 if (hwmgr->hwmgr_func->get_fan_control_mode == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800562 pr_info("%s was not implemented.\n", __func__);
Rex Zhu7383bcb2016-03-30 11:35:50 +0800563 return 0;
564 }
Rex Zhu2a507102017-02-20 17:07:36 +0800565 mutex_lock(&pp_handle->pp_lock);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800566 mode = hwmgr->hwmgr_func->get_fan_control_mode(hwmgr);
Rex Zhu2a507102017-02-20 17:07:36 +0800567 mutex_unlock(&pp_handle->pp_lock);
Rex Zhuf93f0c32017-09-06 16:08:03 +0800568 return mode;
Rex Zhucac9a192015-10-16 11:48:21 +0800569}
570
571static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
572{
573 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800574 struct pp_instance *pp_handle = (struct pp_instance *)handle;
575 int ret = 0;
Rex Zhucac9a192015-10-16 11:48:21 +0800576
Rex Zhu1c863802016-12-28 19:43:23 +0800577 ret = pp_check(pp_handle);
Rex Zhucac9a192015-10-16 11:48:21 +0800578
Rex Zhu1c863802016-12-28 19:43:23 +0800579 if (ret != 0)
580 return ret;
Rex Zhucac9a192015-10-16 11:48:21 +0800581
Rex Zhu1c863802016-12-28 19:43:23 +0800582 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800583
584 if (hwmgr->hwmgr_func->set_fan_speed_percent == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800585 pr_info("%s was not implemented.\n", __func__);
Rex Zhu7383bcb2016-03-30 11:35:50 +0800586 return 0;
587 }
Rex Zhu2a507102017-02-20 17:07:36 +0800588 mutex_lock(&pp_handle->pp_lock);
589 ret = hwmgr->hwmgr_func->set_fan_speed_percent(hwmgr, percent);
590 mutex_unlock(&pp_handle->pp_lock);
591 return ret;
Rex Zhucac9a192015-10-16 11:48:21 +0800592}
593
594static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
595{
596 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800597 struct pp_instance *pp_handle = (struct pp_instance *)handle;
598 int ret = 0;
Rex Zhucac9a192015-10-16 11:48:21 +0800599
Rex Zhu1c863802016-12-28 19:43:23 +0800600 ret = pp_check(pp_handle);
Rex Zhucac9a192015-10-16 11:48:21 +0800601
Rex Zhu1c863802016-12-28 19:43:23 +0800602 if (ret != 0)
603 return ret;
Rex Zhucac9a192015-10-16 11:48:21 +0800604
Rex Zhu1c863802016-12-28 19:43:23 +0800605 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800606
607 if (hwmgr->hwmgr_func->get_fan_speed_percent == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800608 pr_info("%s was not implemented.\n", __func__);
Rex Zhu7383bcb2016-03-30 11:35:50 +0800609 return 0;
610 }
Rex Zhucac9a192015-10-16 11:48:21 +0800611
Rex Zhu2a507102017-02-20 17:07:36 +0800612 mutex_lock(&pp_handle->pp_lock);
613 ret = hwmgr->hwmgr_func->get_fan_speed_percent(hwmgr, speed);
614 mutex_unlock(&pp_handle->pp_lock);
615 return ret;
Rex Zhucac9a192015-10-16 11:48:21 +0800616}
617
Grazvydas Ignotas72a16a92016-10-29 23:28:58 +0300618static int pp_dpm_get_fan_speed_rpm(void *handle, uint32_t *rpm)
619{
620 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800621 struct pp_instance *pp_handle = (struct pp_instance *)handle;
622 int ret = 0;
Grazvydas Ignotas72a16a92016-10-29 23:28:58 +0300623
Rex Zhu1c863802016-12-28 19:43:23 +0800624 ret = pp_check(pp_handle);
Grazvydas Ignotas72a16a92016-10-29 23:28:58 +0300625
Rex Zhu1c863802016-12-28 19:43:23 +0800626 if (ret != 0)
627 return ret;
Grazvydas Ignotas72a16a92016-10-29 23:28:58 +0300628
Rex Zhu1c863802016-12-28 19:43:23 +0800629 hwmgr = pp_handle->hwmgr;
Grazvydas Ignotas72a16a92016-10-29 23:28:58 +0300630
631 if (hwmgr->hwmgr_func->get_fan_speed_rpm == NULL)
632 return -EINVAL;
633
Rex Zhu2a507102017-02-20 17:07:36 +0800634 mutex_lock(&pp_handle->pp_lock);
635 ret = hwmgr->hwmgr_func->get_fan_speed_rpm(hwmgr, rpm);
636 mutex_unlock(&pp_handle->pp_lock);
637 return ret;
Grazvydas Ignotas72a16a92016-10-29 23:28:58 +0300638}
639
Rex Zhucac9a192015-10-16 11:48:21 +0800640static int pp_dpm_get_temperature(void *handle)
641{
642 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800643 struct pp_instance *pp_handle = (struct pp_instance *)handle;
644 int ret = 0;
Rex Zhucac9a192015-10-16 11:48:21 +0800645
Rex Zhu1c863802016-12-28 19:43:23 +0800646 ret = pp_check(pp_handle);
Rex Zhucac9a192015-10-16 11:48:21 +0800647
Rex Zhu1c863802016-12-28 19:43:23 +0800648 if (ret != 0)
649 return ret;
Rex Zhucac9a192015-10-16 11:48:21 +0800650
Rex Zhu1c863802016-12-28 19:43:23 +0800651 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800652
653 if (hwmgr->hwmgr_func->get_temperature == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800654 pr_info("%s was not implemented.\n", __func__);
Rex Zhu7383bcb2016-03-30 11:35:50 +0800655 return 0;
656 }
Rex Zhu2a507102017-02-20 17:07:36 +0800657 mutex_lock(&pp_handle->pp_lock);
658 ret = hwmgr->hwmgr_func->get_temperature(hwmgr);
659 mutex_unlock(&pp_handle->pp_lock);
660 return ret;
Rex Zhucac9a192015-10-16 11:48:21 +0800661}
Rex Zhu577bbe02015-08-28 12:56:43 +0800662
Eric Huangf3898ea2015-12-11 16:24:34 -0500663static int pp_dpm_get_pp_num_states(void *handle,
664 struct pp_states_info *data)
665{
666 struct pp_hwmgr *hwmgr;
667 int i;
Rex Zhu1c863802016-12-28 19:43:23 +0800668 struct pp_instance *pp_handle = (struct pp_instance *)handle;
669 int ret = 0;
Eric Huangf3898ea2015-12-11 16:24:34 -0500670
Rex Zhu1c863802016-12-28 19:43:23 +0800671 ret = pp_check(pp_handle);
Eric Huangf3898ea2015-12-11 16:24:34 -0500672
Rex Zhu1c863802016-12-28 19:43:23 +0800673 if (ret != 0)
674 return ret;
Eric Huangf3898ea2015-12-11 16:24:34 -0500675
Rex Zhu1c863802016-12-28 19:43:23 +0800676 hwmgr = pp_handle->hwmgr;
677
678 if (hwmgr->ps == NULL)
Eric Huangf3898ea2015-12-11 16:24:34 -0500679 return -EINVAL;
680
Rex Zhu2a507102017-02-20 17:07:36 +0800681 mutex_lock(&pp_handle->pp_lock);
682
Eric Huangf3898ea2015-12-11 16:24:34 -0500683 data->nums = hwmgr->num_ps;
684
685 for (i = 0; i < hwmgr->num_ps; i++) {
686 struct pp_power_state *state = (struct pp_power_state *)
687 ((unsigned long)hwmgr->ps + i * hwmgr->ps_size);
688 switch (state->classification.ui_label) {
689 case PP_StateUILabel_Battery:
690 data->states[i] = POWER_STATE_TYPE_BATTERY;
691 break;
692 case PP_StateUILabel_Balanced:
693 data->states[i] = POWER_STATE_TYPE_BALANCED;
694 break;
695 case PP_StateUILabel_Performance:
696 data->states[i] = POWER_STATE_TYPE_PERFORMANCE;
697 break;
698 default:
699 if (state->classification.flags & PP_StateClassificationFlag_Boot)
700 data->states[i] = POWER_STATE_TYPE_INTERNAL_BOOT;
701 else
702 data->states[i] = POWER_STATE_TYPE_DEFAULT;
703 }
704 }
Rex Zhu2a507102017-02-20 17:07:36 +0800705 mutex_unlock(&pp_handle->pp_lock);
Eric Huangf3898ea2015-12-11 16:24:34 -0500706 return 0;
707}
708
709static int pp_dpm_get_pp_table(void *handle, char **table)
710{
711 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800712 struct pp_instance *pp_handle = (struct pp_instance *)handle;
713 int ret = 0;
Rex Zhu2a507102017-02-20 17:07:36 +0800714 int size = 0;
Eric Huangf3898ea2015-12-11 16:24:34 -0500715
Rex Zhu1c863802016-12-28 19:43:23 +0800716 ret = pp_check(pp_handle);
Eric Huangf3898ea2015-12-11 16:24:34 -0500717
Rex Zhu1c863802016-12-28 19:43:23 +0800718 if (ret != 0)
719 return ret;
Eric Huangf3898ea2015-12-11 16:24:34 -0500720
Rex Zhu1c863802016-12-28 19:43:23 +0800721 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800722
Eric Huang4dcf9e62016-06-01 17:08:07 -0400723 if (!hwmgr->soft_pp_table)
724 return -EINVAL;
Eric Huangf3898ea2015-12-11 16:24:34 -0500725
Rex Zhu2a507102017-02-20 17:07:36 +0800726 mutex_lock(&pp_handle->pp_lock);
Eric Huang4dcf9e62016-06-01 17:08:07 -0400727 *table = (char *)hwmgr->soft_pp_table;
Rex Zhu2a507102017-02-20 17:07:36 +0800728 size = hwmgr->soft_pp_table_size;
729 mutex_unlock(&pp_handle->pp_lock);
730 return size;
Eric Huangf3898ea2015-12-11 16:24:34 -0500731}
732
733static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
734{
735 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800736 struct pp_instance *pp_handle = (struct pp_instance *)handle;
737 int ret = 0;
Eric Huangf3898ea2015-12-11 16:24:34 -0500738
Rex Zhu1c863802016-12-28 19:43:23 +0800739 ret = pp_check(pp_handle);
Eric Huangf3898ea2015-12-11 16:24:34 -0500740
Rex Zhu1c863802016-12-28 19:43:23 +0800741 if (ret != 0)
742 return ret;
Eric Huangf3898ea2015-12-11 16:24:34 -0500743
Rex Zhu1c863802016-12-28 19:43:23 +0800744 hwmgr = pp_handle->hwmgr;
Rex Zhu2a507102017-02-20 17:07:36 +0800745 mutex_lock(&pp_handle->pp_lock);
Eric Huang4dcf9e62016-06-01 17:08:07 -0400746 if (!hwmgr->hardcode_pp_table) {
Edward O'Callaghanefdf7a932016-09-04 12:36:19 +1000747 hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table,
748 hwmgr->soft_pp_table_size,
749 GFP_KERNEL);
Rex Zhu2a507102017-02-20 17:07:36 +0800750 if (!hwmgr->hardcode_pp_table) {
751 mutex_unlock(&pp_handle->pp_lock);
Eric Huang4dcf9e62016-06-01 17:08:07 -0400752 return -ENOMEM;
Rex Zhu2a507102017-02-20 17:07:36 +0800753 }
Rex Zhu7383bcb2016-03-30 11:35:50 +0800754 }
Eric Huangf3898ea2015-12-11 16:24:34 -0500755
Eric Huang4dcf9e62016-06-01 17:08:07 -0400756 memcpy(hwmgr->hardcode_pp_table, buf, size);
757
758 hwmgr->soft_pp_table = hwmgr->hardcode_pp_table;
Rex Zhu2a507102017-02-20 17:07:36 +0800759 mutex_unlock(&pp_handle->pp_lock);
Eric Huang4dcf9e62016-06-01 17:08:07 -0400760
Eric Huangdd4bdf32017-03-01 15:49:31 -0500761 ret = amd_powerplay_reset(handle);
762 if (ret)
763 return ret;
764
765 if (hwmgr->hwmgr_func->avfs_control) {
766 ret = hwmgr->hwmgr_func->avfs_control(hwmgr, false);
767 if (ret)
768 return ret;
769 }
770
771 return 0;
Eric Huangf3898ea2015-12-11 16:24:34 -0500772}
773
774static int pp_dpm_force_clock_level(void *handle,
Eric Huang56327082016-04-12 14:57:23 -0400775 enum pp_clock_type type, uint32_t mask)
Eric Huangf3898ea2015-12-11 16:24:34 -0500776{
777 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800778 struct pp_instance *pp_handle = (struct pp_instance *)handle;
779 int ret = 0;
Eric Huangf3898ea2015-12-11 16:24:34 -0500780
Rex Zhu1c863802016-12-28 19:43:23 +0800781 ret = pp_check(pp_handle);
Eric Huangf3898ea2015-12-11 16:24:34 -0500782
Rex Zhu1c863802016-12-28 19:43:23 +0800783 if (ret != 0)
784 return ret;
Eric Huangf3898ea2015-12-11 16:24:34 -0500785
Rex Zhu1c863802016-12-28 19:43:23 +0800786 hwmgr = pp_handle->hwmgr;
Rex Zhu7383bcb2016-03-30 11:35:50 +0800787
788 if (hwmgr->hwmgr_func->force_clock_level == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800789 pr_info("%s was not implemented.\n", __func__);
Rex Zhu7383bcb2016-03-30 11:35:50 +0800790 return 0;
791 }
Rex Zhu2a507102017-02-20 17:07:36 +0800792 mutex_lock(&pp_handle->pp_lock);
793 hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask);
794 mutex_unlock(&pp_handle->pp_lock);
795 return ret;
Eric Huangf3898ea2015-12-11 16:24:34 -0500796}
797
798static int pp_dpm_print_clock_levels(void *handle,
799 enum pp_clock_type type, char *buf)
800{
801 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800802 struct pp_instance *pp_handle = (struct pp_instance *)handle;
803 int ret = 0;
Eric Huangf3898ea2015-12-11 16:24:34 -0500804
Rex Zhu1c863802016-12-28 19:43:23 +0800805 ret = pp_check(pp_handle);
Eric Huangf3898ea2015-12-11 16:24:34 -0500806
Rex Zhu1c863802016-12-28 19:43:23 +0800807 if (ret != 0)
808 return ret;
Eric Huangf3898ea2015-12-11 16:24:34 -0500809
Rex Zhu1c863802016-12-28 19:43:23 +0800810 hwmgr = pp_handle->hwmgr;
Eric Huangf3898ea2015-12-11 16:24:34 -0500811
Rex Zhu7383bcb2016-03-30 11:35:50 +0800812 if (hwmgr->hwmgr_func->print_clock_levels == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800813 pr_info("%s was not implemented.\n", __func__);
Rex Zhu7383bcb2016-03-30 11:35:50 +0800814 return 0;
815 }
Rex Zhu2a507102017-02-20 17:07:36 +0800816 mutex_lock(&pp_handle->pp_lock);
817 ret = hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf);
818 mutex_unlock(&pp_handle->pp_lock);
819 return ret;
Eric Huangf3898ea2015-12-11 16:24:34 -0500820}
821
Eric Huang428bafa2016-05-12 14:51:21 -0400822static int pp_dpm_get_sclk_od(void *handle)
823{
824 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800825 struct pp_instance *pp_handle = (struct pp_instance *)handle;
826 int ret = 0;
Eric Huang428bafa2016-05-12 14:51:21 -0400827
Rex Zhu1c863802016-12-28 19:43:23 +0800828 ret = pp_check(pp_handle);
Eric Huang428bafa2016-05-12 14:51:21 -0400829
Rex Zhu1c863802016-12-28 19:43:23 +0800830 if (ret != 0)
831 return ret;
Eric Huang428bafa2016-05-12 14:51:21 -0400832
Rex Zhu1c863802016-12-28 19:43:23 +0800833 hwmgr = pp_handle->hwmgr;
Eric Huang428bafa2016-05-12 14:51:21 -0400834
835 if (hwmgr->hwmgr_func->get_sclk_od == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800836 pr_info("%s was not implemented.\n", __func__);
Eric Huang428bafa2016-05-12 14:51:21 -0400837 return 0;
838 }
Rex Zhu2a507102017-02-20 17:07:36 +0800839 mutex_lock(&pp_handle->pp_lock);
840 ret = hwmgr->hwmgr_func->get_sclk_od(hwmgr);
841 mutex_unlock(&pp_handle->pp_lock);
842 return ret;
Eric Huang428bafa2016-05-12 14:51:21 -0400843}
844
845static int pp_dpm_set_sclk_od(void *handle, uint32_t value)
846{
847 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800848 struct pp_instance *pp_handle = (struct pp_instance *)handle;
849 int ret = 0;
Eric Huang428bafa2016-05-12 14:51:21 -0400850
Rex Zhu1c863802016-12-28 19:43:23 +0800851 ret = pp_check(pp_handle);
Eric Huang428bafa2016-05-12 14:51:21 -0400852
Rex Zhu1c863802016-12-28 19:43:23 +0800853 if (ret != 0)
854 return ret;
Eric Huang428bafa2016-05-12 14:51:21 -0400855
Rex Zhu1c863802016-12-28 19:43:23 +0800856 hwmgr = pp_handle->hwmgr;
Eric Huang428bafa2016-05-12 14:51:21 -0400857
858 if (hwmgr->hwmgr_func->set_sclk_od == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800859 pr_info("%s was not implemented.\n", __func__);
Eric Huang428bafa2016-05-12 14:51:21 -0400860 return 0;
861 }
862
Rex Zhu2a507102017-02-20 17:07:36 +0800863 mutex_lock(&pp_handle->pp_lock);
864 ret = hwmgr->hwmgr_func->set_sclk_od(hwmgr, value);
Alex Deucherad4febd2017-03-31 10:51:29 -0400865 mutex_unlock(&pp_handle->pp_lock);
Rex Zhu2a507102017-02-20 17:07:36 +0800866 return ret;
Eric Huang428bafa2016-05-12 14:51:21 -0400867}
868
Eric Huangf2bdc052016-05-24 15:11:17 -0400869static int pp_dpm_get_mclk_od(void *handle)
870{
871 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800872 struct pp_instance *pp_handle = (struct pp_instance *)handle;
873 int ret = 0;
Eric Huangf2bdc052016-05-24 15:11:17 -0400874
Rex Zhu1c863802016-12-28 19:43:23 +0800875 ret = pp_check(pp_handle);
Eric Huangf2bdc052016-05-24 15:11:17 -0400876
Rex Zhu1c863802016-12-28 19:43:23 +0800877 if (ret != 0)
878 return ret;
Eric Huangf2bdc052016-05-24 15:11:17 -0400879
Rex Zhu1c863802016-12-28 19:43:23 +0800880 hwmgr = pp_handle->hwmgr;
Eric Huangf2bdc052016-05-24 15:11:17 -0400881
882 if (hwmgr->hwmgr_func->get_mclk_od == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800883 pr_info("%s was not implemented.\n", __func__);
Eric Huangf2bdc052016-05-24 15:11:17 -0400884 return 0;
885 }
Rex Zhu2a507102017-02-20 17:07:36 +0800886 mutex_lock(&pp_handle->pp_lock);
887 ret = hwmgr->hwmgr_func->get_mclk_od(hwmgr);
888 mutex_unlock(&pp_handle->pp_lock);
889 return ret;
Eric Huangf2bdc052016-05-24 15:11:17 -0400890}
891
892static int pp_dpm_set_mclk_od(void *handle, uint32_t value)
893{
894 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800895 struct pp_instance *pp_handle = (struct pp_instance *)handle;
896 int ret = 0;
Eric Huangf2bdc052016-05-24 15:11:17 -0400897
Rex Zhu1c863802016-12-28 19:43:23 +0800898 ret = pp_check(pp_handle);
Eric Huangf2bdc052016-05-24 15:11:17 -0400899
Rex Zhu1c863802016-12-28 19:43:23 +0800900 if (ret != 0)
901 return ret;
Eric Huangf2bdc052016-05-24 15:11:17 -0400902
Rex Zhu1c863802016-12-28 19:43:23 +0800903 hwmgr = pp_handle->hwmgr;
Eric Huangf2bdc052016-05-24 15:11:17 -0400904
905 if (hwmgr->hwmgr_func->set_mclk_od == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800906 pr_info("%s was not implemented.\n", __func__);
Eric Huangf2bdc052016-05-24 15:11:17 -0400907 return 0;
908 }
Rex Zhu2a507102017-02-20 17:07:36 +0800909 mutex_lock(&pp_handle->pp_lock);
910 ret = hwmgr->hwmgr_func->set_mclk_od(hwmgr, value);
911 mutex_unlock(&pp_handle->pp_lock);
912 return ret;
Eric Huangf2bdc052016-05-24 15:11:17 -0400913}
914
Tom St Denis9f8df7d2017-02-09 14:29:01 -0500915static int pp_dpm_read_sensor(void *handle, int idx,
916 void *value, int *size)
Tom St Denisa6e36952016-09-15 10:07:34 -0400917{
918 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800919 struct pp_instance *pp_handle = (struct pp_instance *)handle;
920 int ret = 0;
Tom St Denisa6e36952016-09-15 10:07:34 -0400921
Rex Zhu1c863802016-12-28 19:43:23 +0800922 ret = pp_check(pp_handle);
Tom St Denisa6e36952016-09-15 10:07:34 -0400923
Rex Zhu1c863802016-12-28 19:43:23 +0800924 if (ret != 0)
925 return ret;
Tom St Denisa6e36952016-09-15 10:07:34 -0400926
Rex Zhu1c863802016-12-28 19:43:23 +0800927 hwmgr = pp_handle->hwmgr;
Tom St Denisa6e36952016-09-15 10:07:34 -0400928
929 if (hwmgr->hwmgr_func->read_sensor == NULL) {
Huang Rui0fb829d2016-12-26 14:24:05 +0800930 pr_info("%s was not implemented.\n", __func__);
Tom St Denisa6e36952016-09-15 10:07:34 -0400931 return 0;
932 }
933
Rex Zhu2a507102017-02-20 17:07:36 +0800934 mutex_lock(&pp_handle->pp_lock);
935 ret = hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value, size);
936 mutex_unlock(&pp_handle->pp_lock);
937
938 return ret;
Tom St Denisa6e36952016-09-15 10:07:34 -0400939}
940
Alex Deucher597be302016-10-07 13:52:43 -0400941static struct amd_vce_state*
942pp_dpm_get_vce_clock_state(void *handle, unsigned idx)
943{
944 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +0800945 struct pp_instance *pp_handle = (struct pp_instance *)handle;
946 int ret = 0;
Alex Deucher597be302016-10-07 13:52:43 -0400947
Rex Zhu1c863802016-12-28 19:43:23 +0800948 ret = pp_check(pp_handle);
Alex Deucher597be302016-10-07 13:52:43 -0400949
Rex Zhu1c863802016-12-28 19:43:23 +0800950 if (ret != 0)
951 return NULL;
952
953 hwmgr = pp_handle->hwmgr;
954
955 if (hwmgr && idx < hwmgr->num_vce_state_tables)
956 return &hwmgr->vce_states[idx];
Alex Deucher597be302016-10-07 13:52:43 -0400957 return NULL;
958}
959
Eric Huang34bb2732016-09-12 16:17:44 -0400960static int pp_dpm_reset_power_profile_state(void *handle,
961 struct amd_pp_profile *request)
962{
963 struct pp_hwmgr *hwmgr;
964 struct pp_instance *pp_handle = (struct pp_instance *)handle;
965
966 if (!request || pp_check(pp_handle))
967 return -EINVAL;
968
969 hwmgr = pp_handle->hwmgr;
970
971 if (hwmgr->hwmgr_func->set_power_profile_state == NULL) {
972 pr_info("%s was not implemented.\n", __func__);
973 return 0;
974 }
975
976 if (request->type == AMD_PP_GFX_PROFILE) {
977 hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile;
978 return hwmgr->hwmgr_func->set_power_profile_state(hwmgr,
979 &hwmgr->gfx_power_profile);
980 } else if (request->type == AMD_PP_COMPUTE_PROFILE) {
981 hwmgr->compute_power_profile =
982 hwmgr->default_compute_power_profile;
983 return hwmgr->hwmgr_func->set_power_profile_state(hwmgr,
984 &hwmgr->compute_power_profile);
985 } else
986 return -EINVAL;
987}
988
989static int pp_dpm_get_power_profile_state(void *handle,
990 struct amd_pp_profile *query)
991{
992 struct pp_hwmgr *hwmgr;
993 struct pp_instance *pp_handle = (struct pp_instance *)handle;
994
995 if (!query || pp_check(pp_handle))
996 return -EINVAL;
997
998 hwmgr = pp_handle->hwmgr;
999
1000 if (query->type == AMD_PP_GFX_PROFILE)
1001 memcpy(query, &hwmgr->gfx_power_profile,
1002 sizeof(struct amd_pp_profile));
1003 else if (query->type == AMD_PP_COMPUTE_PROFILE)
1004 memcpy(query, &hwmgr->compute_power_profile,
1005 sizeof(struct amd_pp_profile));
1006 else
1007 return -EINVAL;
1008
1009 return 0;
1010}
1011
1012static int pp_dpm_set_power_profile_state(void *handle,
1013 struct amd_pp_profile *request)
1014{
1015 struct pp_hwmgr *hwmgr;
1016 struct pp_instance *pp_handle = (struct pp_instance *)handle;
1017 int ret = -1;
1018
1019 if (!request || pp_check(pp_handle))
1020 return -EINVAL;
1021
1022 hwmgr = pp_handle->hwmgr;
1023
1024 if (hwmgr->hwmgr_func->set_power_profile_state == NULL) {
1025 pr_info("%s was not implemented.\n", __func__);
1026 return 0;
1027 }
1028
1029 if (request->min_sclk ||
1030 request->min_mclk ||
1031 request->activity_threshold ||
1032 request->up_hyst ||
1033 request->down_hyst) {
1034 if (request->type == AMD_PP_GFX_PROFILE)
1035 memcpy(&hwmgr->gfx_power_profile, request,
1036 sizeof(struct amd_pp_profile));
1037 else if (request->type == AMD_PP_COMPUTE_PROFILE)
1038 memcpy(&hwmgr->compute_power_profile, request,
1039 sizeof(struct amd_pp_profile));
1040 else
1041 return -EINVAL;
1042
1043 if (request->type == hwmgr->current_power_profile)
1044 ret = hwmgr->hwmgr_func->set_power_profile_state(
1045 hwmgr,
1046 request);
1047 } else {
1048 /* set power profile if it exists */
1049 switch (request->type) {
1050 case AMD_PP_GFX_PROFILE:
1051 ret = hwmgr->hwmgr_func->set_power_profile_state(
1052 hwmgr,
1053 &hwmgr->gfx_power_profile);
1054 break;
1055 case AMD_PP_COMPUTE_PROFILE:
1056 ret = hwmgr->hwmgr_func->set_power_profile_state(
1057 hwmgr,
1058 &hwmgr->compute_power_profile);
1059 break;
1060 default:
1061 return -EINVAL;
1062 }
1063 }
1064
1065 if (!ret)
1066 hwmgr->current_power_profile = request->type;
1067
1068 return 0;
1069}
1070
1071static int pp_dpm_switch_power_profile(void *handle,
1072 enum amd_pp_profile_type type)
1073{
1074 struct pp_hwmgr *hwmgr;
1075 struct amd_pp_profile request = {0};
1076 struct pp_instance *pp_handle = (struct pp_instance *)handle;
1077
1078 if (pp_check(pp_handle))
1079 return -EINVAL;
1080
1081 hwmgr = pp_handle->hwmgr;
1082
1083 if (hwmgr->current_power_profile != type) {
1084 request.type = type;
1085 pp_dpm_set_power_profile_state(handle, &request);
1086 }
1087
1088 return 0;
1089}
1090
Rex Zhuf93f0c32017-09-06 16:08:03 +08001091const struct amd_pm_funcs pp_dpm_funcs = {
Rex Zhucac9a192015-10-16 11:48:21 +08001092 .get_temperature = pp_dpm_get_temperature,
Alex Deucher1f7371b2015-12-02 17:46:21 -05001093 .load_firmware = pp_dpm_load_fw,
1094 .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
1095 .force_performance_level = pp_dpm_force_performance_level,
1096 .get_performance_level = pp_dpm_get_performance_level,
1097 .get_current_power_state = pp_dpm_get_current_power_state,
1098 .get_sclk = pp_dpm_get_sclk,
1099 .get_mclk = pp_dpm_get_mclk,
1100 .powergate_vce = pp_dpm_powergate_vce,
1101 .powergate_uvd = pp_dpm_powergate_uvd,
1102 .dispatch_tasks = pp_dpm_dispatch_tasks,
Rex Zhucac9a192015-10-16 11:48:21 +08001103 .set_fan_control_mode = pp_dpm_set_fan_control_mode,
1104 .get_fan_control_mode = pp_dpm_get_fan_control_mode,
1105 .set_fan_speed_percent = pp_dpm_set_fan_speed_percent,
1106 .get_fan_speed_percent = pp_dpm_get_fan_speed_percent,
Grazvydas Ignotas72a16a92016-10-29 23:28:58 +03001107 .get_fan_speed_rpm = pp_dpm_get_fan_speed_rpm,
Eric Huangf3898ea2015-12-11 16:24:34 -05001108 .get_pp_num_states = pp_dpm_get_pp_num_states,
1109 .get_pp_table = pp_dpm_get_pp_table,
1110 .set_pp_table = pp_dpm_set_pp_table,
1111 .force_clock_level = pp_dpm_force_clock_level,
1112 .print_clock_levels = pp_dpm_print_clock_levels,
Eric Huang428bafa2016-05-12 14:51:21 -04001113 .get_sclk_od = pp_dpm_get_sclk_od,
1114 .set_sclk_od = pp_dpm_set_sclk_od,
Eric Huangf2bdc052016-05-24 15:11:17 -04001115 .get_mclk_od = pp_dpm_get_mclk_od,
1116 .set_mclk_od = pp_dpm_set_mclk_od,
Tom St Denisa6e36952016-09-15 10:07:34 -04001117 .read_sensor = pp_dpm_read_sensor,
Alex Deucher597be302016-10-07 13:52:43 -04001118 .get_vce_clock_state = pp_dpm_get_vce_clock_state,
Eric Huang34bb2732016-09-12 16:17:44 -04001119 .reset_power_profile_state = pp_dpm_reset_power_profile_state,
1120 .get_power_profile_state = pp_dpm_get_power_profile_state,
1121 .set_power_profile_state = pp_dpm_set_power_profile_state,
1122 .switch_power_profile = pp_dpm_switch_power_profile,
Alex Deucher1f7371b2015-12-02 17:46:21 -05001123};
1124
Rex Zhu1c863802016-12-28 19:43:23 +08001125int amd_powerplay_create(struct amd_pp_init *pp_init,
1126 void **handle)
Jammy Zhouac885b32015-07-21 17:43:02 +08001127{
Rex Zhu1c863802016-12-28 19:43:23 +08001128 struct pp_instance *instance;
Jammy Zhouac885b32015-07-21 17:43:02 +08001129
Rex Zhu1c863802016-12-28 19:43:23 +08001130 if (pp_init == NULL || handle == NULL)
1131 return -EINVAL;
1132
1133 instance = kzalloc(sizeof(struct pp_instance), GFP_KERNEL);
1134 if (instance == NULL)
Jammy Zhouac885b32015-07-21 17:43:02 +08001135 return -ENOMEM;
1136
Rex Zhu1c863802016-12-28 19:43:23 +08001137 instance->pp_valid = PP_VALID;
1138 instance->chip_family = pp_init->chip_family;
1139 instance->chip_id = pp_init->chip_id;
1140 instance->pm_en = pp_init->pm_en;
1141 instance->feature_mask = pp_init->feature_mask;
1142 instance->device = pp_init->device;
Rex Zhu2a507102017-02-20 17:07:36 +08001143 mutex_init(&instance->pp_lock);
Rex Zhu1c863802016-12-28 19:43:23 +08001144 *handle = instance;
Jammy Zhouac885b32015-07-21 17:43:02 +08001145 return 0;
1146}
1147
Rex Zhu1c863802016-12-28 19:43:23 +08001148int amd_powerplay_destroy(void *handle)
Jammy Zhouac885b32015-07-21 17:43:02 +08001149{
1150 struct pp_instance *instance = (struct pp_instance *)handle;
Rex Zhue92a0372015-09-23 15:14:54 +08001151
Rex Zhub3b03052017-09-26 13:28:27 -04001152 kfree(instance->hwmgr);
1153 instance->hwmgr = NULL;
Jammy Zhou3bace352015-07-21 21:18:15 +08001154
Rex Zhu1c863802016-12-28 19:43:23 +08001155 kfree(instance);
1156 instance = NULL;
Alex Deucher1f7371b2015-12-02 17:46:21 -05001157 return 0;
1158}
Rex Zhu7fb72a12015-11-19 13:35:30 +08001159
Eric Huang4dcf9e62016-06-01 17:08:07 -04001160int amd_powerplay_reset(void *handle)
1161{
1162 struct pp_instance *instance = (struct pp_instance *)handle;
Eric Huang4dcf9e62016-06-01 17:08:07 -04001163 int ret;
1164
Rex Zhub3b03052017-09-26 13:28:27 -04001165 if (cgs_is_virtualization_enabled(instance->hwmgr->device))
Rex Zhu1c863802016-12-28 19:43:23 +08001166 return PP_DPM_DISABLED;
1167
1168 ret = pp_check(instance);
1169 if (ret != 0)
1170 return ret;
1171
Rex Zhudf1e6392017-09-01 13:46:20 +08001172 ret = pp_hw_fini(instance);
Rex Zhu1c863802016-12-28 19:43:23 +08001173 if (ret)
1174 return ret;
1175
1176 ret = hwmgr_hw_init(instance);
1177 if (ret)
1178 return PP_DPM_DISABLED;
Eric Huang4dcf9e62016-06-01 17:08:07 -04001179
Rex Zhudf1e6392017-09-01 13:46:20 +08001180 return hwmgr_handle_task(instance, AMD_PP_TASK_COMPLETE_INIT, NULL, NULL);
Eric Huang4dcf9e62016-06-01 17:08:07 -04001181}
1182
Rex Zhu7fb72a12015-11-19 13:35:30 +08001183/* export this function to DAL */
1184
David Rokhvarg155f1127c2015-12-14 10:51:39 -05001185int amd_powerplay_display_configuration_change(void *handle,
1186 const struct amd_pp_display_configuration *display_config)
Rex Zhu7fb72a12015-11-19 13:35:30 +08001187{
1188 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +08001189 struct pp_instance *pp_handle = (struct pp_instance *)handle;
1190 int ret = 0;
Rex Zhu7fb72a12015-11-19 13:35:30 +08001191
Rex Zhu1c863802016-12-28 19:43:23 +08001192 ret = pp_check(pp_handle);
Rex Zhu7fb72a12015-11-19 13:35:30 +08001193
Rex Zhu1c863802016-12-28 19:43:23 +08001194 if (ret != 0)
1195 return ret;
Rex Zhu7fb72a12015-11-19 13:35:30 +08001196
Rex Zhu1c863802016-12-28 19:43:23 +08001197 hwmgr = pp_handle->hwmgr;
Rex Zhu2a507102017-02-20 17:07:36 +08001198 mutex_lock(&pp_handle->pp_lock);
Rex Zhu7fb72a12015-11-19 13:35:30 +08001199 phm_store_dal_configuration_data(hwmgr, display_config);
Rex Zhu2a507102017-02-20 17:07:36 +08001200 mutex_unlock(&pp_handle->pp_lock);
Rex Zhu7fb72a12015-11-19 13:35:30 +08001201 return 0;
1202}
Vitaly Prosyakc4dd2062015-11-30 16:39:53 -05001203
Vitaly Prosyak1c9a9082015-12-03 10:27:57 -05001204int amd_powerplay_get_display_power_level(void *handle,
Rex Zhu47329132015-12-10 16:49:50 +08001205 struct amd_pp_simple_clock_info *output)
Vitaly Prosyakc4dd2062015-11-30 16:39:53 -05001206{
1207 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +08001208 struct pp_instance *pp_handle = (struct pp_instance *)handle;
1209 int ret = 0;
Vitaly Prosyakc4dd2062015-11-30 16:39:53 -05001210
Rex Zhu1c863802016-12-28 19:43:23 +08001211 ret = pp_check(pp_handle);
1212
1213 if (ret != 0)
1214 return ret;
1215
1216 hwmgr = pp_handle->hwmgr;
Rex Zhua969e162015-12-29 13:56:03 +08001217
1218 if (output == NULL)
Vitaly Prosyakc4dd2062015-11-30 16:39:53 -05001219 return -EINVAL;
1220
Rex Zhu2a507102017-02-20 17:07:36 +08001221 mutex_lock(&pp_handle->pp_lock);
1222 ret = phm_get_dal_power_level(hwmgr, output);
1223 mutex_unlock(&pp_handle->pp_lock);
1224 return ret;
Vitaly Prosyakc4dd2062015-11-30 16:39:53 -05001225}
Rex Zhue273b042015-12-07 18:44:23 +08001226
1227int amd_powerplay_get_current_clocks(void *handle,
David Rokhvarg155f1127c2015-12-14 10:51:39 -05001228 struct amd_pp_clock_info *clocks)
Rex Zhue273b042015-12-07 18:44:23 +08001229{
Rex Zhue273b042015-12-07 18:44:23 +08001230 struct amd_pp_simple_clock_info simple_clocks;
1231 struct pp_clock_info hw_clocks;
Rex Zhu1c863802016-12-28 19:43:23 +08001232 struct pp_hwmgr *hwmgr;
1233 struct pp_instance *pp_handle = (struct pp_instance *)handle;
1234 int ret = 0;
Rex Zhue273b042015-12-07 18:44:23 +08001235
Rex Zhu1c863802016-12-28 19:43:23 +08001236 ret = pp_check(pp_handle);
Rex Zhufa9e6992015-12-29 13:56:03 +08001237
Rex Zhu1c863802016-12-28 19:43:23 +08001238 if (ret != 0)
1239 return ret;
Rex Zhue273b042015-12-07 18:44:23 +08001240
Rex Zhu1c863802016-12-28 19:43:23 +08001241 hwmgr = pp_handle->hwmgr;
Rex Zhuba5f8842016-10-27 15:29:57 +08001242
Rex Zhu2a507102017-02-20 17:07:36 +08001243 mutex_lock(&pp_handle->pp_lock);
1244
Rex Zhue273b042015-12-07 18:44:23 +08001245 phm_get_dal_power_level(hwmgr, &simple_clocks);
1246
Rex Zhu2a507102017-02-20 17:07:36 +08001247 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1248 PHM_PlatformCaps_PowerContainment))
1249 ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware,
1250 &hw_clocks, PHM_PerformanceLevelDesignation_PowerContainment);
1251 else
1252 ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware,
1253 &hw_clocks, PHM_PerformanceLevelDesignation_Activity);
1254
1255 if (ret != 0) {
1256 pr_info("Error in phm_get_clock_info \n");
1257 mutex_unlock(&pp_handle->pp_lock);
1258 return -EINVAL;
Rex Zhue273b042015-12-07 18:44:23 +08001259 }
1260
1261 clocks->min_engine_clock = hw_clocks.min_eng_clk;
1262 clocks->max_engine_clock = hw_clocks.max_eng_clk;
1263 clocks->min_memory_clock = hw_clocks.min_mem_clk;
1264 clocks->max_memory_clock = hw_clocks.max_mem_clk;
1265 clocks->min_bus_bandwidth = hw_clocks.min_bus_bandwidth;
1266 clocks->max_bus_bandwidth = hw_clocks.max_bus_bandwidth;
1267
1268 clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
1269 clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
1270
1271 clocks->max_clocks_state = simple_clocks.level;
1272
1273 if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) {
1274 clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
1275 clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
1276 }
Rex Zhu2a507102017-02-20 17:07:36 +08001277 mutex_unlock(&pp_handle->pp_lock);
Rex Zhue273b042015-12-07 18:44:23 +08001278 return 0;
Rex Zhue273b042015-12-07 18:44:23 +08001279}
1280
1281int amd_powerplay_get_clock_by_type(void *handle, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks)
1282{
Rex Zhu1c863802016-12-28 19:43:23 +08001283 struct pp_hwmgr *hwmgr;
1284 struct pp_instance *pp_handle = (struct pp_instance *)handle;
1285 int ret = 0;
Rex Zhue273b042015-12-07 18:44:23 +08001286
Rex Zhu1c863802016-12-28 19:43:23 +08001287 ret = pp_check(pp_handle);
Rex Zhue273b042015-12-07 18:44:23 +08001288
Rex Zhu1c863802016-12-28 19:43:23 +08001289 if (ret != 0)
1290 return ret;
1291
1292 hwmgr = pp_handle->hwmgr;
Rex Zhufa9e6992015-12-29 13:56:03 +08001293
1294 if (clocks == NULL)
Rex Zhue273b042015-12-07 18:44:23 +08001295 return -EINVAL;
1296
Rex Zhu2a507102017-02-20 17:07:36 +08001297 mutex_lock(&pp_handle->pp_lock);
1298 ret = phm_get_clock_by_type(hwmgr, type, clocks);
1299 mutex_unlock(&pp_handle->pp_lock);
1300 return ret;
Rex Zhue273b042015-12-07 18:44:23 +08001301}
1302
Eric Huangd0187722017-03-06 13:13:48 -05001303int amd_powerplay_get_clock_by_type_with_latency(void *handle,
1304 enum amd_pp_clock_type type,
1305 struct pp_clock_levels_with_latency *clocks)
1306{
1307 struct pp_hwmgr *hwmgr;
1308 struct pp_instance *pp_handle = (struct pp_instance *)handle;
1309 int ret = 0;
1310
1311 ret = pp_check(pp_handle);
1312 if (ret != 0)
1313 return ret;
1314
1315 if (!clocks)
1316 return -EINVAL;
1317
1318 mutex_lock(&pp_handle->pp_lock);
1319 hwmgr = ((struct pp_instance *)handle)->hwmgr;
1320 ret = phm_get_clock_by_type_with_latency(hwmgr, type, clocks);
1321 mutex_unlock(&pp_handle->pp_lock);
1322 return ret;
1323}
1324
1325int amd_powerplay_get_clock_by_type_with_voltage(void *handle,
1326 enum amd_pp_clock_type type,
1327 struct pp_clock_levels_with_voltage *clocks)
1328{
1329 struct pp_hwmgr *hwmgr;
1330 struct pp_instance *pp_handle = (struct pp_instance *)handle;
1331 int ret = 0;
1332
1333 ret = pp_check(pp_handle);
1334 if (ret != 0)
1335 return ret;
1336
1337 if (!clocks)
1338 return -EINVAL;
1339
1340 hwmgr = ((struct pp_instance *)handle)->hwmgr;
1341
1342 mutex_lock(&pp_handle->pp_lock);
1343
1344 ret = phm_get_clock_by_type_with_voltage(hwmgr, type, clocks);
1345
1346 mutex_unlock(&pp_handle->pp_lock);
1347 return ret;
1348}
1349
1350int amd_powerplay_set_watermarks_for_clocks_ranges(void *handle,
1351 struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges)
1352{
1353 struct pp_hwmgr *hwmgr;
1354 struct pp_instance *pp_handle = (struct pp_instance *)handle;
1355 int ret = 0;
1356
1357 ret = pp_check(pp_handle);
1358 if (ret != 0)
1359 return ret;
1360
1361 if (!wm_with_clock_ranges)
1362 return -EINVAL;
1363
1364 hwmgr = ((struct pp_instance *)handle)->hwmgr;
1365
1366 mutex_lock(&pp_handle->pp_lock);
1367 ret = phm_set_watermarks_for_clocks_ranges(hwmgr,
1368 wm_with_clock_ranges);
1369 mutex_unlock(&pp_handle->pp_lock);
1370
1371 return ret;
1372}
1373
1374int amd_powerplay_display_clock_voltage_request(void *handle,
1375 struct pp_display_clock_request *clock)
1376{
1377 struct pp_hwmgr *hwmgr;
1378 struct pp_instance *pp_handle = (struct pp_instance *)handle;
1379 int ret = 0;
1380
1381 ret = pp_check(pp_handle);
1382 if (ret != 0)
1383 return ret;
1384
1385 if (!clock)
1386 return -EINVAL;
1387
1388 hwmgr = ((struct pp_instance *)handle)->hwmgr;
1389
1390 mutex_lock(&pp_handle->pp_lock);
1391 ret = phm_display_clock_voltage_request(hwmgr, clock);
1392 mutex_unlock(&pp_handle->pp_lock);
1393
1394 return ret;
1395}
1396
David Rokhvarg155f1127c2015-12-14 10:51:39 -05001397int amd_powerplay_get_display_mode_validation_clocks(void *handle,
1398 struct amd_pp_simple_clock_info *clocks)
Rex Zhue273b042015-12-07 18:44:23 +08001399{
Rex Zhue273b042015-12-07 18:44:23 +08001400 struct pp_hwmgr *hwmgr;
Rex Zhu1c863802016-12-28 19:43:23 +08001401 struct pp_instance *pp_handle = (struct pp_instance *)handle;
1402 int ret = 0;
Rex Zhue273b042015-12-07 18:44:23 +08001403
Rex Zhu1c863802016-12-28 19:43:23 +08001404 ret = pp_check(pp_handle);
1405
1406 if (ret != 0)
1407 return ret;
1408
1409 hwmgr = pp_handle->hwmgr;
1410
Rex Zhufa9e6992015-12-29 13:56:03 +08001411 if (clocks == NULL)
Rex Zhue273b042015-12-07 18:44:23 +08001412 return -EINVAL;
1413
Rex Zhu2a507102017-02-20 17:07:36 +08001414 mutex_lock(&pp_handle->pp_lock);
1415
Rex Zhue273b042015-12-07 18:44:23 +08001416 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
Rex Zhu1c863802016-12-28 19:43:23 +08001417 ret = phm_get_max_high_clocks(hwmgr, clocks);
Rex Zhue273b042015-12-07 18:44:23 +08001418
Rex Zhu2a507102017-02-20 17:07:36 +08001419 mutex_unlock(&pp_handle->pp_lock);
Rex Zhu1c863802016-12-28 19:43:23 +08001420 return ret;
Rex Zhue273b042015-12-07 18:44:23 +08001421}
1422