blob: 32a6a6f8ffcb5884f6190fb4572ca2d6637d5cd6 [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 */
23#include <linux/types.h>
24#include <linux/kernel.h>
25#include <linux/gfp.h>
Jammy Zhouac885b32015-07-21 17:43:02 +080026#include <linux/slab.h>
Alex Deucher1f7371b2015-12-02 17:46:21 -050027#include "amd_shared.h"
28#include "amd_powerplay.h"
Jammy Zhouac885b32015-07-21 17:43:02 +080029#include "pp_instance.h"
Rex Zhu577bbe02015-08-28 12:56:43 +080030#include "power_state.h"
31#include "eventmanager.h"
Rex Zhue273b042015-12-07 18:44:23 +080032#include "pp_debug.h"
Alex Deucher1f7371b2015-12-02 17:46:21 -050033
Rex Zhua969e162015-12-29 13:56:03 +080034#define PP_CHECK(handle) \
35 do { \
36 if ((handle) == NULL || (handle)->pp_valid != PP_VALID) \
37 return -EINVAL; \
38 } while (0)
39
Alex Deucher1f7371b2015-12-02 17:46:21 -050040static int pp_early_init(void *handle)
41{
42 return 0;
43}
44
45static int pp_sw_init(void *handle)
46{
Jammy Zhou3bace352015-07-21 21:18:15 +080047 struct pp_instance *pp_handle;
48 struct pp_hwmgr *hwmgr;
49 int ret = 0;
50
51 if (handle == NULL)
52 return -EINVAL;
53
54 pp_handle = (struct pp_instance *)handle;
55 hwmgr = pp_handle->hwmgr;
56
57 if (hwmgr == NULL || hwmgr->pptable_func == NULL ||
58 hwmgr->hwmgr_func == NULL ||
59 hwmgr->pptable_func->pptable_init == NULL ||
60 hwmgr->hwmgr_func->backend_init == NULL)
61 return -EINVAL;
62
63 ret = hwmgr->pptable_func->pptable_init(hwmgr);
Rex Zhue92a0372015-09-23 15:14:54 +080064
Jammy Zhou3bace352015-07-21 21:18:15 +080065 if (ret == 0)
66 ret = hwmgr->hwmgr_func->backend_init(hwmgr);
67
Alex Deucher9441f962016-01-20 12:15:09 -050068 if (ret)
69 printk("amdgpu: powerplay initialization failed\n");
70 else
71 printk("amdgpu: powerplay initialized\n");
72
Jammy Zhou3bace352015-07-21 21:18:15 +080073 return ret;
Alex Deucher1f7371b2015-12-02 17:46:21 -050074}
75
76static int pp_sw_fini(void *handle)
77{
Jammy Zhou3bace352015-07-21 21:18:15 +080078 struct pp_instance *pp_handle;
79 struct pp_hwmgr *hwmgr;
80 int ret = 0;
81
82 if (handle == NULL)
83 return -EINVAL;
84
85 pp_handle = (struct pp_instance *)handle;
86 hwmgr = pp_handle->hwmgr;
87
88 if (hwmgr != NULL || hwmgr->hwmgr_func != NULL ||
89 hwmgr->hwmgr_func->backend_fini != NULL)
90 ret = hwmgr->hwmgr_func->backend_fini(hwmgr);
91
92 return ret;
Alex Deucher1f7371b2015-12-02 17:46:21 -050093}
94
95static int pp_hw_init(void *handle)
96{
Jammy Zhouac885b32015-07-21 17:43:02 +080097 struct pp_instance *pp_handle;
98 struct pp_smumgr *smumgr;
Rex Zhue92a0372015-09-23 15:14:54 +080099 struct pp_eventmgr *eventmgr;
Jammy Zhouac885b32015-07-21 17:43:02 +0800100 int ret = 0;
101
102 if (handle == NULL)
103 return -EINVAL;
104
105 pp_handle = (struct pp_instance *)handle;
106 smumgr = pp_handle->smu_mgr;
107
108 if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
109 smumgr->smumgr_funcs->smu_init == NULL ||
110 smumgr->smumgr_funcs->start_smu == NULL)
111 return -EINVAL;
112
113 ret = smumgr->smumgr_funcs->smu_init(smumgr);
114 if (ret) {
115 printk(KERN_ERR "[ powerplay ] smc initialization failed\n");
116 return ret;
117 }
118
119 ret = smumgr->smumgr_funcs->start_smu(smumgr);
120 if (ret) {
121 printk(KERN_ERR "[ powerplay ] smc start failed\n");
122 smumgr->smumgr_funcs->smu_fini(smumgr);
123 return ret;
124 }
Jammy Zhou3bace352015-07-21 21:18:15 +0800125
Rex Zhue92a0372015-09-23 15:14:54 +0800126 hw_init_power_state_table(pp_handle->hwmgr);
127 eventmgr = pp_handle->eventmgr;
128
129 if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
130 return -EINVAL;
131
132 ret = eventmgr->pp_eventmgr_init(eventmgr);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500133 return 0;
134}
135
136static int pp_hw_fini(void *handle)
137{
Jammy Zhouac885b32015-07-21 17:43:02 +0800138 struct pp_instance *pp_handle;
139 struct pp_smumgr *smumgr;
Rex Zhue92a0372015-09-23 15:14:54 +0800140 struct pp_eventmgr *eventmgr;
Jammy Zhouac885b32015-07-21 17:43:02 +0800141
142 if (handle == NULL)
143 return -EINVAL;
144
145 pp_handle = (struct pp_instance *)handle;
Rex Zhue92a0372015-09-23 15:14:54 +0800146 eventmgr = pp_handle->eventmgr;
147
148 if (eventmgr != NULL || eventmgr->pp_eventmgr_fini != NULL)
149 eventmgr->pp_eventmgr_fini(eventmgr);
150
Jammy Zhouac885b32015-07-21 17:43:02 +0800151 smumgr = pp_handle->smu_mgr;
152
153 if (smumgr != NULL || smumgr->smumgr_funcs != NULL ||
154 smumgr->smumgr_funcs->smu_fini != NULL)
155 smumgr->smumgr_funcs->smu_fini(smumgr);
156
Alex Deucher1f7371b2015-12-02 17:46:21 -0500157 return 0;
158}
159
160static bool pp_is_idle(void *handle)
161{
162 return 0;
163}
164
165static int pp_wait_for_idle(void *handle)
166{
167 return 0;
168}
169
170static int pp_sw_reset(void *handle)
171{
172 return 0;
173}
174
175static void pp_print_status(void *handle)
176{
177
178}
179
180static int pp_set_clockgating_state(void *handle,
181 enum amd_clockgating_state state)
182{
Eric Huang03e39052016-02-09 16:26:00 -0500183 struct pp_hwmgr *hwmgr;
184 uint32_t msg_id, pp_state;
185
186 if (handle == NULL)
187 return -EINVAL;
188
189 hwmgr = ((struct pp_instance *)handle)->hwmgr;
190
Flora Cui538333f2016-02-15 15:45:59 +0800191 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL)
Eric Huang03e39052016-02-09 16:26:00 -0500192 return -EINVAL;
193
Flora Cui538333f2016-02-15 15:45:59 +0800194 if (hwmgr->hwmgr_func->update_clock_gatings == NULL)
195 return 0;
196
Eric Huang03e39052016-02-09 16:26:00 -0500197 if (state == AMD_CG_STATE_UNGATE)
198 pp_state = 0;
199 else
200 pp_state = PP_STATE_CG | PP_STATE_LS;
201
202 /* Enable/disable GFX blocks clock gating through SMU */
203 msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
204 PP_BLOCK_GFX_CG,
205 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
206 pp_state);
207 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
208 msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
209 PP_BLOCK_GFX_3D,
210 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
211 pp_state);
212 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
213 msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
214 PP_BLOCK_GFX_RLC,
215 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
216 pp_state);
217 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
218 msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
219 PP_BLOCK_GFX_CP,
220 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
221 pp_state);
222 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
223 msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
224 PP_BLOCK_GFX_MG,
225 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
226 pp_state);
227 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
228
229 /* Enable/disable System blocks clock gating through SMU */
230 msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
231 PP_BLOCK_SYS_BIF,
232 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
233 pp_state);
234 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
235 msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
236 PP_BLOCK_SYS_BIF,
237 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
238 pp_state);
239 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
240 msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
241 PP_BLOCK_SYS_MC,
242 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
243 pp_state);
244 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
245 msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
246 PP_BLOCK_SYS_ROM,
247 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
248 pp_state);
249 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
250 msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
251 PP_BLOCK_SYS_DRM,
252 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
253 pp_state);
254 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
255 msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
256 PP_BLOCK_SYS_HDP,
257 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
258 pp_state);
259 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
260 msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
261 PP_BLOCK_SYS_SDMA,
262 PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
263 pp_state);
264 hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
265
Alex Deucher1f7371b2015-12-02 17:46:21 -0500266 return 0;
267}
268
269static int pp_set_powergating_state(void *handle,
270 enum amd_powergating_state state)
271{
Eric Huang65f85e72016-02-11 15:54:45 -0500272 struct pp_hwmgr *hwmgr;
273
274 if (handle == NULL)
275 return -EINVAL;
276
277 hwmgr = ((struct pp_instance *)handle)->hwmgr;
278
279 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
280 hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL)
281 return -EINVAL;
282
283 /* Enable/disable GFX per cu powergating through SMU */
284 return hwmgr->hwmgr_func->enable_per_cu_power_gating(hwmgr,
285 state == AMD_PG_STATE_GATE ? true : false);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500286}
287
288static int pp_suspend(void *handle)
289{
Rex Zhu577bbe02015-08-28 12:56:43 +0800290 struct pp_instance *pp_handle;
291 struct pp_eventmgr *eventmgr;
292 struct pem_event_data event_data = { {0} };
293
294 if (handle == NULL)
295 return -EINVAL;
296
297 pp_handle = (struct pp_instance *)handle;
298 eventmgr = pp_handle->eventmgr;
299 pem_handle_event(eventmgr, AMD_PP_EVENT_SUSPEND, &event_data);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500300 return 0;
301}
302
303static int pp_resume(void *handle)
304{
Rex Zhu577bbe02015-08-28 12:56:43 +0800305 struct pp_instance *pp_handle;
306 struct pp_eventmgr *eventmgr;
307 struct pem_event_data event_data = { {0} };
Rex Zhue0b71a72015-12-29 10:25:19 +0800308 struct pp_smumgr *smumgr;
309 int ret;
Rex Zhu577bbe02015-08-28 12:56:43 +0800310
311 if (handle == NULL)
312 return -EINVAL;
313
314 pp_handle = (struct pp_instance *)handle;
Rex Zhue0b71a72015-12-29 10:25:19 +0800315 smumgr = pp_handle->smu_mgr;
316
317 if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
318 smumgr->smumgr_funcs->start_smu == NULL)
319 return -EINVAL;
320
321 ret = smumgr->smumgr_funcs->start_smu(smumgr);
322 if (ret) {
323 printk(KERN_ERR "[ powerplay ] smc start failed\n");
324 smumgr->smumgr_funcs->smu_fini(smumgr);
325 return ret;
326 }
327
Rex Zhu577bbe02015-08-28 12:56:43 +0800328 eventmgr = pp_handle->eventmgr;
329 pem_handle_event(eventmgr, AMD_PP_EVENT_RESUME, &event_data);
Rex Zhue0b71a72015-12-29 10:25:19 +0800330
Alex Deucher1f7371b2015-12-02 17:46:21 -0500331 return 0;
332}
333
334const struct amd_ip_funcs pp_ip_funcs = {
335 .early_init = pp_early_init,
336 .late_init = NULL,
337 .sw_init = pp_sw_init,
338 .sw_fini = pp_sw_fini,
339 .hw_init = pp_hw_init,
340 .hw_fini = pp_hw_fini,
341 .suspend = pp_suspend,
342 .resume = pp_resume,
343 .is_idle = pp_is_idle,
344 .wait_for_idle = pp_wait_for_idle,
345 .soft_reset = pp_sw_reset,
346 .print_status = pp_print_status,
347 .set_clockgating_state = pp_set_clockgating_state,
348 .set_powergating_state = pp_set_powergating_state,
349};
350
351static int pp_dpm_load_fw(void *handle)
352{
353 return 0;
354}
355
356static int pp_dpm_fw_loading_complete(void *handle)
357{
358 return 0;
359}
360
361static int pp_dpm_force_performance_level(void *handle,
362 enum amd_dpm_forced_level level)
363{
Rex Zhu577bbe02015-08-28 12:56:43 +0800364 struct pp_instance *pp_handle;
365 struct pp_hwmgr *hwmgr;
366
367 if (handle == NULL)
368 return -EINVAL;
369
370 pp_handle = (struct pp_instance *)handle;
371
372 hwmgr = pp_handle->hwmgr;
373
374 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
375 hwmgr->hwmgr_func->force_dpm_level == NULL)
376 return -EINVAL;
377
378 hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);
379
Alex Deucher1f7371b2015-12-02 17:46:21 -0500380 return 0;
381}
Rex Zhu577bbe02015-08-28 12:56:43 +0800382
Alex Deucher1f7371b2015-12-02 17:46:21 -0500383static enum amd_dpm_forced_level pp_dpm_get_performance_level(
384 void *handle)
385{
Rex Zhu577bbe02015-08-28 12:56:43 +0800386 struct pp_hwmgr *hwmgr;
387
388 if (handle == NULL)
389 return -EINVAL;
390
391 hwmgr = ((struct pp_instance *)handle)->hwmgr;
392
393 if (hwmgr == NULL)
394 return -EINVAL;
395
396 return (((struct pp_instance *)handle)->hwmgr->dpm_level);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500397}
Rex Zhu577bbe02015-08-28 12:56:43 +0800398
Alex Deucher1f7371b2015-12-02 17:46:21 -0500399static int pp_dpm_get_sclk(void *handle, bool low)
400{
Rex Zhu577bbe02015-08-28 12:56:43 +0800401 struct pp_hwmgr *hwmgr;
402
403 if (handle == NULL)
404 return -EINVAL;
405
406 hwmgr = ((struct pp_instance *)handle)->hwmgr;
407
408 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
409 hwmgr->hwmgr_func->get_sclk == NULL)
410 return -EINVAL;
411
412 return hwmgr->hwmgr_func->get_sclk(hwmgr, low);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500413}
Rex Zhu577bbe02015-08-28 12:56:43 +0800414
Alex Deucher1f7371b2015-12-02 17:46:21 -0500415static int pp_dpm_get_mclk(void *handle, bool low)
416{
Rex Zhu577bbe02015-08-28 12:56:43 +0800417 struct pp_hwmgr *hwmgr;
418
419 if (handle == NULL)
420 return -EINVAL;
421
422 hwmgr = ((struct pp_instance *)handle)->hwmgr;
423
424 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
425 hwmgr->hwmgr_func->get_mclk == NULL)
426 return -EINVAL;
427
428 return hwmgr->hwmgr_func->get_mclk(hwmgr, low);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500429}
Rex Zhu577bbe02015-08-28 12:56:43 +0800430
Alex Deucher1f7371b2015-12-02 17:46:21 -0500431static int pp_dpm_powergate_vce(void *handle, bool gate)
432{
Rex Zhu577bbe02015-08-28 12:56:43 +0800433 struct pp_hwmgr *hwmgr;
434
435 if (handle == NULL)
436 return -EINVAL;
437
438 hwmgr = ((struct pp_instance *)handle)->hwmgr;
439
440 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
441 hwmgr->hwmgr_func->powergate_vce == NULL)
442 return -EINVAL;
443
444 return hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500445}
Rex Zhu577bbe02015-08-28 12:56:43 +0800446
Alex Deucher1f7371b2015-12-02 17:46:21 -0500447static int pp_dpm_powergate_uvd(void *handle, bool gate)
448{
Rex Zhu577bbe02015-08-28 12:56:43 +0800449 struct pp_hwmgr *hwmgr;
450
451 if (handle == NULL)
452 return -EINVAL;
453
454 hwmgr = ((struct pp_instance *)handle)->hwmgr;
455
456 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
457 hwmgr->hwmgr_func->powergate_uvd == NULL)
458 return -EINVAL;
459
460 return hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
461}
462
463static enum PP_StateUILabel power_state_convert(enum amd_pm_state_type state)
464{
465 switch (state) {
466 case POWER_STATE_TYPE_BATTERY:
467 return PP_StateUILabel_Battery;
468 case POWER_STATE_TYPE_BALANCED:
469 return PP_StateUILabel_Balanced;
470 case POWER_STATE_TYPE_PERFORMANCE:
471 return PP_StateUILabel_Performance;
472 default:
473 return PP_StateUILabel_None;
474 }
Alex Deucher1f7371b2015-12-02 17:46:21 -0500475}
476
477int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id, void *input, void *output)
478{
Rex Zhu577bbe02015-08-28 12:56:43 +0800479 int ret = 0;
480 struct pp_instance *pp_handle;
481 struct pem_event_data data = { {0} };
482
483 pp_handle = (struct pp_instance *)handle;
484
485 if (pp_handle == NULL)
486 return -EINVAL;
487
488 switch (event_id) {
489 case AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE:
490 ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
491 break;
492 case AMD_PP_EVENT_ENABLE_USER_STATE:
493 {
494 enum amd_pm_state_type ps;
495
496 if (input == NULL)
497 return -EINVAL;
498 ps = *(unsigned long *)input;
499
500 data.requested_ui_label = power_state_convert(ps);
501 ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
Rex Zhudc26a2a2016-02-25 17:16:52 +0800502 break;
Rex Zhu577bbe02015-08-28 12:56:43 +0800503 }
Rex Zhudc26a2a2016-02-25 17:16:52 +0800504 case AMD_PP_EVENT_COMPLETE_INIT:
505 ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
506 break;
Rex Zhu577bbe02015-08-28 12:56:43 +0800507 default:
508 break;
509 }
510 return ret;
Alex Deucher1f7371b2015-12-02 17:46:21 -0500511}
Rex Zhu577bbe02015-08-28 12:56:43 +0800512
Alex Deucher1f7371b2015-12-02 17:46:21 -0500513enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
514{
Rex Zhu577bbe02015-08-28 12:56:43 +0800515 struct pp_hwmgr *hwmgr;
516 struct pp_power_state *state;
517
518 if (handle == NULL)
519 return -EINVAL;
520
521 hwmgr = ((struct pp_instance *)handle)->hwmgr;
522
523 if (hwmgr == NULL || hwmgr->current_ps == NULL)
524 return -EINVAL;
525
526 state = hwmgr->current_ps;
527
528 switch (state->classification.ui_label) {
529 case PP_StateUILabel_Battery:
530 return POWER_STATE_TYPE_BATTERY;
531 case PP_StateUILabel_Balanced:
532 return POWER_STATE_TYPE_BALANCED;
533 case PP_StateUILabel_Performance:
534 return POWER_STATE_TYPE_PERFORMANCE;
535 default:
Eric Huangf3898ea2015-12-11 16:24:34 -0500536 if (state->classification.flags & PP_StateClassificationFlag_Boot)
537 return POWER_STATE_TYPE_INTERNAL_BOOT;
538 else
539 return POWER_STATE_TYPE_DEFAULT;
Rex Zhu577bbe02015-08-28 12:56:43 +0800540 }
Alex Deucher1f7371b2015-12-02 17:46:21 -0500541}
Rex Zhu577bbe02015-08-28 12:56:43 +0800542
Alex Deucher1f7371b2015-12-02 17:46:21 -0500543static void
544pp_debugfs_print_current_performance_level(void *handle,
545 struct seq_file *m)
546{
Rex Zhu577bbe02015-08-28 12:56:43 +0800547 struct pp_hwmgr *hwmgr;
548
549 if (handle == NULL)
550 return;
551
552 hwmgr = ((struct pp_instance *)handle)->hwmgr;
553
554 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
555 hwmgr->hwmgr_func->print_current_perforce_level == NULL)
556 return;
557
558 hwmgr->hwmgr_func->print_current_perforce_level(hwmgr, m);
Alex Deucher1f7371b2015-12-02 17:46:21 -0500559}
Jammy Zhou3bace352015-07-21 21:18:15 +0800560
Rex Zhucac9a192015-10-16 11:48:21 +0800561static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
562{
563 struct pp_hwmgr *hwmgr;
564
565 if (handle == NULL)
566 return -EINVAL;
567
568 hwmgr = ((struct pp_instance *)handle)->hwmgr;
569
570 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
571 hwmgr->hwmgr_func->set_fan_control_mode == NULL)
572 return -EINVAL;
573
574 return hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode);
575}
576
577static int pp_dpm_get_fan_control_mode(void *handle)
578{
579 struct pp_hwmgr *hwmgr;
580
581 if (handle == NULL)
582 return -EINVAL;
583
584 hwmgr = ((struct pp_instance *)handle)->hwmgr;
585
586 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
587 hwmgr->hwmgr_func->get_fan_control_mode == NULL)
588 return -EINVAL;
589
590 return hwmgr->hwmgr_func->get_fan_control_mode(hwmgr);
591}
592
593static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
594{
595 struct pp_hwmgr *hwmgr;
596
597 if (handle == NULL)
598 return -EINVAL;
599
600 hwmgr = ((struct pp_instance *)handle)->hwmgr;
601
602 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
603 hwmgr->hwmgr_func->set_fan_speed_percent == NULL)
604 return -EINVAL;
605
606 return hwmgr->hwmgr_func->set_fan_speed_percent(hwmgr, percent);
607}
608
609static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
610{
611 struct pp_hwmgr *hwmgr;
612
613 if (handle == NULL)
614 return -EINVAL;
615
616 hwmgr = ((struct pp_instance *)handle)->hwmgr;
617
618 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
619 hwmgr->hwmgr_func->get_fan_speed_percent == NULL)
620 return -EINVAL;
621
622 return hwmgr->hwmgr_func->get_fan_speed_percent(hwmgr, speed);
623}
624
625static int pp_dpm_get_temperature(void *handle)
626{
627 struct pp_hwmgr *hwmgr;
628
629 if (handle == NULL)
630 return -EINVAL;
631
632 hwmgr = ((struct pp_instance *)handle)->hwmgr;
633
634 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
635 hwmgr->hwmgr_func->get_temperature == NULL)
636 return -EINVAL;
637
638 return hwmgr->hwmgr_func->get_temperature(hwmgr);
639}
Rex Zhu577bbe02015-08-28 12:56:43 +0800640
Eric Huangf3898ea2015-12-11 16:24:34 -0500641static int pp_dpm_get_pp_num_states(void *handle,
642 struct pp_states_info *data)
643{
644 struct pp_hwmgr *hwmgr;
645 int i;
646
647 if (!handle)
648 return -EINVAL;
649
650 hwmgr = ((struct pp_instance *)handle)->hwmgr;
651
652 if (hwmgr == NULL || hwmgr->ps == NULL)
653 return -EINVAL;
654
655 data->nums = hwmgr->num_ps;
656
657 for (i = 0; i < hwmgr->num_ps; i++) {
658 struct pp_power_state *state = (struct pp_power_state *)
659 ((unsigned long)hwmgr->ps + i * hwmgr->ps_size);
660 switch (state->classification.ui_label) {
661 case PP_StateUILabel_Battery:
662 data->states[i] = POWER_STATE_TYPE_BATTERY;
663 break;
664 case PP_StateUILabel_Balanced:
665 data->states[i] = POWER_STATE_TYPE_BALANCED;
666 break;
667 case PP_StateUILabel_Performance:
668 data->states[i] = POWER_STATE_TYPE_PERFORMANCE;
669 break;
670 default:
671 if (state->classification.flags & PP_StateClassificationFlag_Boot)
672 data->states[i] = POWER_STATE_TYPE_INTERNAL_BOOT;
673 else
674 data->states[i] = POWER_STATE_TYPE_DEFAULT;
675 }
676 }
677
678 return 0;
679}
680
681static int pp_dpm_get_pp_table(void *handle, char **table)
682{
683 struct pp_hwmgr *hwmgr;
684
685 if (!handle)
686 return -EINVAL;
687
688 hwmgr = ((struct pp_instance *)handle)->hwmgr;
689
690 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
691 hwmgr->hwmgr_func->get_pp_table == NULL)
692 return -EINVAL;
693
694 return hwmgr->hwmgr_func->get_pp_table(hwmgr, table);
695}
696
697static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
698{
699 struct pp_hwmgr *hwmgr;
700
701 if (!handle)
702 return -EINVAL;
703
704 hwmgr = ((struct pp_instance *)handle)->hwmgr;
705
706 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
707 hwmgr->hwmgr_func->set_pp_table == NULL)
Rex Zhu0994c092016-02-25 17:48:24 +0800708 return -EINVAL;
Eric Huangf3898ea2015-12-11 16:24:34 -0500709
710 return hwmgr->hwmgr_func->set_pp_table(hwmgr, buf, size);
711}
712
713static int pp_dpm_force_clock_level(void *handle,
714 enum pp_clock_type type, int level)
715{
716 struct pp_hwmgr *hwmgr;
717
718 if (!handle)
719 return -EINVAL;
720
721 hwmgr = ((struct pp_instance *)handle)->hwmgr;
722
723 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
724 hwmgr->hwmgr_func->force_clock_level == NULL)
Rex Zhu0994c092016-02-25 17:48:24 +0800725 return -EINVAL;
Eric Huangf3898ea2015-12-11 16:24:34 -0500726
727 return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, level);
728}
729
730static int pp_dpm_print_clock_levels(void *handle,
731 enum pp_clock_type type, char *buf)
732{
733 struct pp_hwmgr *hwmgr;
734
735 if (!handle)
736 return -EINVAL;
737
738 hwmgr = ((struct pp_instance *)handle)->hwmgr;
739
740 if (hwmgr == NULL || hwmgr->hwmgr_func == NULL ||
741 hwmgr->hwmgr_func->print_clock_levels == NULL)
742 return -EINVAL;
743
744 return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf);
745}
746
Alex Deucher1f7371b2015-12-02 17:46:21 -0500747const struct amd_powerplay_funcs pp_dpm_funcs = {
Rex Zhucac9a192015-10-16 11:48:21 +0800748 .get_temperature = pp_dpm_get_temperature,
Alex Deucher1f7371b2015-12-02 17:46:21 -0500749 .load_firmware = pp_dpm_load_fw,
750 .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
751 .force_performance_level = pp_dpm_force_performance_level,
752 .get_performance_level = pp_dpm_get_performance_level,
753 .get_current_power_state = pp_dpm_get_current_power_state,
754 .get_sclk = pp_dpm_get_sclk,
755 .get_mclk = pp_dpm_get_mclk,
756 .powergate_vce = pp_dpm_powergate_vce,
757 .powergate_uvd = pp_dpm_powergate_uvd,
758 .dispatch_tasks = pp_dpm_dispatch_tasks,
759 .print_current_performance_level = pp_debugfs_print_current_performance_level,
Rex Zhucac9a192015-10-16 11:48:21 +0800760 .set_fan_control_mode = pp_dpm_set_fan_control_mode,
761 .get_fan_control_mode = pp_dpm_get_fan_control_mode,
762 .set_fan_speed_percent = pp_dpm_set_fan_speed_percent,
763 .get_fan_speed_percent = pp_dpm_get_fan_speed_percent,
Eric Huangf3898ea2015-12-11 16:24:34 -0500764 .get_pp_num_states = pp_dpm_get_pp_num_states,
765 .get_pp_table = pp_dpm_get_pp_table,
766 .set_pp_table = pp_dpm_set_pp_table,
767 .force_clock_level = pp_dpm_force_clock_level,
768 .print_clock_levels = pp_dpm_print_clock_levels,
Alex Deucher1f7371b2015-12-02 17:46:21 -0500769};
770
Jammy Zhouac885b32015-07-21 17:43:02 +0800771static int amd_pp_instance_init(struct amd_pp_init *pp_init,
772 struct amd_powerplay *amd_pp)
773{
774 int ret;
775 struct pp_instance *handle;
776
777 handle = kzalloc(sizeof(struct pp_instance), GFP_KERNEL);
778 if (handle == NULL)
779 return -ENOMEM;
780
Rex Zhua969e162015-12-29 13:56:03 +0800781 handle->pp_valid = PP_VALID;
782
Jammy Zhouac885b32015-07-21 17:43:02 +0800783 ret = smum_init(pp_init, handle);
784 if (ret)
Jammy Zhou3bace352015-07-21 21:18:15 +0800785 goto fail_smum;
786
787 ret = hwmgr_init(pp_init, handle);
788 if (ret)
789 goto fail_hwmgr;
Jammy Zhouac885b32015-07-21 17:43:02 +0800790
Rex Zhue92a0372015-09-23 15:14:54 +0800791 ret = eventmgr_init(handle);
792 if (ret)
793 goto fail_eventmgr;
794
Jammy Zhouac885b32015-07-21 17:43:02 +0800795 amd_pp->pp_handle = handle;
796 return 0;
Jammy Zhou3bace352015-07-21 21:18:15 +0800797
Rex Zhue92a0372015-09-23 15:14:54 +0800798fail_eventmgr:
799 hwmgr_fini(handle->hwmgr);
Jammy Zhou3bace352015-07-21 21:18:15 +0800800fail_hwmgr:
801 smum_fini(handle->smu_mgr);
802fail_smum:
803 kfree(handle);
804 return ret;
Jammy Zhouac885b32015-07-21 17:43:02 +0800805}
806
807static int amd_pp_instance_fini(void *handle)
808{
809 struct pp_instance *instance = (struct pp_instance *)handle;
Rex Zhue92a0372015-09-23 15:14:54 +0800810
Jammy Zhouac885b32015-07-21 17:43:02 +0800811 if (instance == NULL)
812 return -EINVAL;
813
Rex Zhue92a0372015-09-23 15:14:54 +0800814 eventmgr_fini(instance->eventmgr);
815
Jammy Zhou3bace352015-07-21 21:18:15 +0800816 hwmgr_fini(instance->hwmgr);
817
Jammy Zhouac885b32015-07-21 17:43:02 +0800818 smum_fini(instance->smu_mgr);
819
820 kfree(handle);
821 return 0;
822}
823
Alex Deucher1f7371b2015-12-02 17:46:21 -0500824int amd_powerplay_init(struct amd_pp_init *pp_init,
825 struct amd_powerplay *amd_pp)
826{
Jammy Zhouac885b32015-07-21 17:43:02 +0800827 int ret;
828
Alex Deucher1f7371b2015-12-02 17:46:21 -0500829 if (pp_init == NULL || amd_pp == NULL)
830 return -EINVAL;
831
Jammy Zhouac885b32015-07-21 17:43:02 +0800832 ret = amd_pp_instance_init(pp_init, amd_pp);
833
834 if (ret)
835 return ret;
836
Alex Deucher1f7371b2015-12-02 17:46:21 -0500837 amd_pp->ip_funcs = &pp_ip_funcs;
838 amd_pp->pp_funcs = &pp_dpm_funcs;
839
840 return 0;
841}
842
843int amd_powerplay_fini(void *handle)
844{
Jammy Zhouac885b32015-07-21 17:43:02 +0800845 amd_pp_instance_fini(handle);
846
Alex Deucher1f7371b2015-12-02 17:46:21 -0500847 return 0;
848}
Rex Zhu7fb72a12015-11-19 13:35:30 +0800849
850/* export this function to DAL */
851
David Rokhvarg155f1127c2015-12-14 10:51:39 -0500852int amd_powerplay_display_configuration_change(void *handle,
853 const struct amd_pp_display_configuration *display_config)
Rex Zhu7fb72a12015-11-19 13:35:30 +0800854{
855 struct pp_hwmgr *hwmgr;
Rex Zhu7fb72a12015-11-19 13:35:30 +0800856
Rex Zhua969e162015-12-29 13:56:03 +0800857 PP_CHECK((struct pp_instance *)handle);
Rex Zhu7fb72a12015-11-19 13:35:30 +0800858
859 hwmgr = ((struct pp_instance *)handle)->hwmgr;
860
861 phm_store_dal_configuration_data(hwmgr, display_config);
Rex Zhue0b71a72015-12-29 10:25:19 +0800862
Rex Zhu7fb72a12015-11-19 13:35:30 +0800863 return 0;
864}
Vitaly Prosyakc4dd2062015-11-30 16:39:53 -0500865
Vitaly Prosyak1c9a9082015-12-03 10:27:57 -0500866int amd_powerplay_get_display_power_level(void *handle,
Rex Zhu47329132015-12-10 16:49:50 +0800867 struct amd_pp_simple_clock_info *output)
Vitaly Prosyakc4dd2062015-11-30 16:39:53 -0500868{
869 struct pp_hwmgr *hwmgr;
870
Rex Zhua969e162015-12-29 13:56:03 +0800871 PP_CHECK((struct pp_instance *)handle);
872
873 if (output == NULL)
Vitaly Prosyakc4dd2062015-11-30 16:39:53 -0500874 return -EINVAL;
875
876 hwmgr = ((struct pp_instance *)handle)->hwmgr;
877
Vitaly Prosyak1c9a9082015-12-03 10:27:57 -0500878 return phm_get_dal_power_level(hwmgr, output);
Vitaly Prosyakc4dd2062015-11-30 16:39:53 -0500879}
Rex Zhue273b042015-12-07 18:44:23 +0800880
881int amd_powerplay_get_current_clocks(void *handle,
David Rokhvarg155f1127c2015-12-14 10:51:39 -0500882 struct amd_pp_clock_info *clocks)
Rex Zhue273b042015-12-07 18:44:23 +0800883{
884 struct pp_hwmgr *hwmgr;
885 struct amd_pp_simple_clock_info simple_clocks;
886 struct pp_clock_info hw_clocks;
Rex Zhue273b042015-12-07 18:44:23 +0800887
Rex Zhufa9e6992015-12-29 13:56:03 +0800888 PP_CHECK((struct pp_instance *)handle);
889
890 if (clocks == NULL)
Rex Zhue273b042015-12-07 18:44:23 +0800891 return -EINVAL;
892
893 hwmgr = ((struct pp_instance *)handle)->hwmgr;
894
895 phm_get_dal_power_level(hwmgr, &simple_clocks);
896
897 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PowerContainment)) {
898 if (0 != phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks, PHM_PerformanceLevelDesignation_PowerContainment))
899 PP_ASSERT_WITH_CODE(0, "Error in PHM_GetPowerContainmentClockInfo", return -1);
900 } else {
901 if (0 != phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks, PHM_PerformanceLevelDesignation_Activity))
902 PP_ASSERT_WITH_CODE(0, "Error in PHM_GetClockInfo", return -1);
903 }
904
905 clocks->min_engine_clock = hw_clocks.min_eng_clk;
906 clocks->max_engine_clock = hw_clocks.max_eng_clk;
907 clocks->min_memory_clock = hw_clocks.min_mem_clk;
908 clocks->max_memory_clock = hw_clocks.max_mem_clk;
909 clocks->min_bus_bandwidth = hw_clocks.min_bus_bandwidth;
910 clocks->max_bus_bandwidth = hw_clocks.max_bus_bandwidth;
911
912 clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
913 clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
914
915 clocks->max_clocks_state = simple_clocks.level;
916
917 if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) {
918 clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
919 clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
920 }
921
922 return 0;
923
924}
925
926int amd_powerplay_get_clock_by_type(void *handle, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks)
927{
928 int result = -1;
929
930 struct pp_hwmgr *hwmgr;
931
Rex Zhufa9e6992015-12-29 13:56:03 +0800932 PP_CHECK((struct pp_instance *)handle);
933
934 if (clocks == NULL)
Rex Zhue273b042015-12-07 18:44:23 +0800935 return -EINVAL;
936
937 hwmgr = ((struct pp_instance *)handle)->hwmgr;
938
939 result = phm_get_clock_by_type(hwmgr, type, clocks);
940
941 return result;
942}
943
David Rokhvarg155f1127c2015-12-14 10:51:39 -0500944int amd_powerplay_get_display_mode_validation_clocks(void *handle,
945 struct amd_pp_simple_clock_info *clocks)
Rex Zhue273b042015-12-07 18:44:23 +0800946{
947 int result = -1;
Rex Zhue273b042015-12-07 18:44:23 +0800948 struct pp_hwmgr *hwmgr;
949
Rex Zhufa9e6992015-12-29 13:56:03 +0800950 PP_CHECK((struct pp_instance *)handle);
951
952 if (clocks == NULL)
Rex Zhue273b042015-12-07 18:44:23 +0800953 return -EINVAL;
954
955 hwmgr = ((struct pp_instance *)handle)->hwmgr;
956
957 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
958 result = phm_get_max_high_clocks(hwmgr, clocks);
959
960 return result;
961}
962