File Index
Files and directories
Sign in
FILE

hardwaremanager.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c C
  1/*
  2 * Copyright 2015 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a
  5 * copy of this software and associated documentation files (the "Software"),
  6 * to deal in the Software without restriction, including without limitation
  7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 * and/or sell copies of the Software, and to permit persons to whom the
  9 * Software is furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 20 * OTHER DEALINGS IN THE SOFTWARE.
 21 *
 22 */
 23#include "pp_debug.h"
 24#include <linux/errno.h>
 25#include "hwmgr.h"
 26#include "hardwaremanager.h"
 27#include "power_state.h"
 28
 29
 30#define TEMP_RANGE_MIN (0)
 31#define TEMP_RANGE_MAX (80 * 1000)
 32
 33#define PHM_FUNC_CHECK(hw) \
 34	do {							\
 35		if ((hw) == NULL || (hw)->hwmgr_func == NULL)	\
 36			return -EINVAL;				\
 37	} while (0)
 38
 39int phm_setup_asic(struct pp_hwmgr *hwmgr)
 40{
 41	PHM_FUNC_CHECK(hwmgr);
 42
 43	if (NULL != hwmgr->hwmgr_func->asic_setup)
 44		return hwmgr->hwmgr_func->asic_setup(hwmgr);
 45
 46	return 0;
 47}
 48
 49int phm_power_down_asic(struct pp_hwmgr *hwmgr)
 50{
 51	PHM_FUNC_CHECK(hwmgr);
 52
 53	if (NULL != hwmgr->hwmgr_func->power_off_asic)
 54		return hwmgr->hwmgr_func->power_off_asic(hwmgr);
 55
 56	return 0;
 57}
 58
 59int phm_set_power_state(struct pp_hwmgr *hwmgr,
 60		    const struct pp_hw_power_state *pcurrent_state,
 61		    const struct pp_hw_power_state *pnew_power_state)
 62{
 63	struct phm_set_power_state_input states;
 64
 65	PHM_FUNC_CHECK(hwmgr);
 66
 67	states.pcurrent_state = pcurrent_state;
 68	states.pnew_state = pnew_power_state;
 69
 70	if (NULL != hwmgr->hwmgr_func->power_state_set)
 71		return hwmgr->hwmgr_func->power_state_set(hwmgr, &states);
 72
 73	return 0;
 74}
 75
 76int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr)
 77{
 78	struct amdgpu_device *adev = NULL;
 79	int ret = -EINVAL;
 80	PHM_FUNC_CHECK(hwmgr);
 81	adev = hwmgr->adev;
 82
 83	/* Skip for suspend/resume case */
 84	if (!hwmgr->pp_one_vf && smum_is_dpm_running(hwmgr)
 85	    && !amdgpu_passthrough(adev) && adev->in_suspend
 86		&& adev->asic_type != CHIP_RAVEN) {
 87		pr_info("dpm has been enabled\n");
 88		return 0;
 89	}
 90
 91	if (NULL != hwmgr->hwmgr_func->dynamic_state_management_enable)
 92		ret = hwmgr->hwmgr_func->dynamic_state_management_enable(hwmgr);
 93
 94	return ret;
 95}
 96
 97int phm_disable_dynamic_state_management(struct pp_hwmgr *hwmgr)
 98{
 99	int ret = -EINVAL;
100
101	PHM_FUNC_CHECK(hwmgr);
102
103	if (!hwmgr->not_vf)
104		return 0;
105
106	if (!smum_is_dpm_running(hwmgr)) {
107		pr_info("dpm has been disabled\n");
108		return 0;
109	}
110
111	if (hwmgr->hwmgr_func->dynamic_state_management_disable)
112		ret = hwmgr->hwmgr_func->dynamic_state_management_disable(hwmgr);
113
114	return ret;
115}
116
117int phm_force_dpm_levels(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level)
118{
119	int ret = 0;
120
121	PHM_FUNC_CHECK(hwmgr);
122
123	if (hwmgr->hwmgr_func->force_dpm_level != NULL)
124		ret = hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);
125
126	return ret;
127}
128
129int phm_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
130				   struct pp_power_state *adjusted_ps,
131			     const struct pp_power_state *current_ps)
132{
133	PHM_FUNC_CHECK(hwmgr);
134
135	if (hwmgr->hwmgr_func->apply_state_adjust_rules != NULL)
136		return hwmgr->hwmgr_func->apply_state_adjust_rules(
137									hwmgr,
138								 adjusted_ps,
139								 current_ps);
140	return 0;
141}
142
143int phm_apply_clock_adjust_rules(struct pp_hwmgr *hwmgr)
144{
145	PHM_FUNC_CHECK(hwmgr);
146
147	if (hwmgr->hwmgr_func->apply_clocks_adjust_rules != NULL)
148		return hwmgr->hwmgr_func->apply_clocks_adjust_rules(hwmgr);
149	return 0;
150}
151
152int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr)
153{
154	PHM_FUNC_CHECK(hwmgr);
155
156	if (NULL != hwmgr->hwmgr_func->disable_clock_power_gating)
157		return hwmgr->hwmgr_func->disable_clock_power_gating(hwmgr);
158
159	return 0;
160}
161
162int phm_pre_display_configuration_changed(struct pp_hwmgr *hwmgr)
163{
164	PHM_FUNC_CHECK(hwmgr);
165
166	if (NULL != hwmgr->hwmgr_func->pre_display_config_changed)
167		hwmgr->hwmgr_func->pre_display_config_changed(hwmgr);
168
169	return 0;
170
171}
172
173int phm_display_configuration_changed(struct pp_hwmgr *hwmgr)
174{
175	PHM_FUNC_CHECK(hwmgr);
176
177	if (NULL != hwmgr->hwmgr_func->display_config_changed)
178		hwmgr->hwmgr_func->display_config_changed(hwmgr);
179
180	return 0;
181}
182
183int phm_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr)
184{
185	PHM_FUNC_CHECK(hwmgr);
186
187	if (NULL != hwmgr->hwmgr_func->notify_smc_display_config_after_ps_adjustment)
188			hwmgr->hwmgr_func->notify_smc_display_config_after_ps_adjustment(hwmgr);
189
190	return 0;
191}
192
193int phm_stop_thermal_controller(struct pp_hwmgr *hwmgr)
194{
195	PHM_FUNC_CHECK(hwmgr);
196
197	if (!hwmgr->not_vf)
198		return 0;
199
200	if (hwmgr->hwmgr_func->stop_thermal_controller == NULL)
201		return -EINVAL;
202
203	return hwmgr->hwmgr_func->stop_thermal_controller(hwmgr);
204}
205
206int phm_register_irq_handlers(struct pp_hwmgr *hwmgr)
207{
208	PHM_FUNC_CHECK(hwmgr);
209
210	if (hwmgr->hwmgr_func->register_irq_handlers != NULL)
211		return hwmgr->hwmgr_func->register_irq_handlers(hwmgr);
212
213	return 0;
214}
215
216/**
217 * phm_start_thermal_controller - Initializes the thermal controller subsystem.
218 *
219 * @hwmgr:   the address of the powerplay hardware manager.
220 * Exception PP_Result_Failed if any of the paramters is NULL, otherwise the return value from the dispatcher.
221 */
222int phm_start_thermal_controller(struct pp_hwmgr *hwmgr)
223{
224	int ret = 0;
225	struct PP_TemperatureRange range = {
226		TEMP_RANGE_MIN,
227		TEMP_RANGE_MAX,
228		TEMP_RANGE_MAX,
229		TEMP_RANGE_MIN,
230		TEMP_RANGE_MAX,
231		TEMP_RANGE_MAX,
232		TEMP_RANGE_MIN,
233		TEMP_RANGE_MAX,
234		TEMP_RANGE_MAX,
235		0};
236	struct amdgpu_device *adev = hwmgr->adev;
237
238	if (!hwmgr->not_vf)
239		return 0;
240
241	if (hwmgr->hwmgr_func->get_thermal_temperature_range)
242		hwmgr->hwmgr_func->get_thermal_temperature_range(
243				hwmgr, &range);
244
245	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
246			PHM_PlatformCaps_ThermalController)
247			&& hwmgr->hwmgr_func->start_thermal_controller != NULL)
248		ret = hwmgr->hwmgr_func->start_thermal_controller(hwmgr, &range);
249
250	adev->pm.dpm.thermal.min_temp = range.min;
251	adev->pm.dpm.thermal.max_temp = range.max;
252	adev->pm.dpm.thermal.max_edge_emergency_temp = range.edge_emergency_max;
253	adev->pm.dpm.thermal.min_hotspot_temp = range.hotspot_min;
254	adev->pm.dpm.thermal.max_hotspot_crit_temp = range.hotspot_crit_max;
255	adev->pm.dpm.thermal.max_hotspot_emergency_temp = range.hotspot_emergency_max;
256	adev->pm.dpm.thermal.min_mem_temp = range.mem_min;
257	adev->pm.dpm.thermal.max_mem_crit_temp = range.mem_crit_max;
258	adev->pm.dpm.thermal.max_mem_emergency_temp = range.mem_emergency_max;
259	adev->pm.dpm.thermal.sw_ctf_threshold = range.sw_ctf_threshold;
260
261	return ret;
262}
263
264
265bool phm_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr)
266{
267	if (hwmgr == NULL ||
268	    hwmgr->hwmgr_func == NULL)
269		return false;
270
271	if (hwmgr->pp_one_vf)
272		return false;
273
274	if (hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration == NULL)
275		return false;
276
277	return hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration(hwmgr);
278}
279
280
281int phm_check_states_equal(struct pp_hwmgr *hwmgr,
282				 const struct pp_hw_power_state *pstate1,
283				 const struct pp_hw_power_state *pstate2,
284				 bool *equal)
285{
286	PHM_FUNC_CHECK(hwmgr);
287
288	if (hwmgr->hwmgr_func->check_states_equal == NULL)
289		return -EINVAL;
290
291	return hwmgr->hwmgr_func->check_states_equal(hwmgr, pstate1, pstate2, equal);
292}
293
294int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,
295		    const struct amd_pp_display_configuration *display_config)
296{
297	int index = 0;
298	int number_of_active_display = 0;
299
300	PHM_FUNC_CHECK(hwmgr);
301
302	if (display_config == NULL)
303		return -EINVAL;
304
305	if (NULL != hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk)
306		hwmgr->hwmgr_func->set_min_deep_sleep_dcefclk(hwmgr, display_config->min_dcef_deep_sleep_set_clk);
307
308	for (index = 0; index < display_config->num_path_including_non_display; index++) {
309		if (display_config->displays[index].controller_id != 0)
310			number_of_active_display++;
311	}
312
313	if (NULL != hwmgr->hwmgr_func->set_active_display_count)
314		hwmgr->hwmgr_func->set_active_display_count(hwmgr, number_of_active_display);
315
316	if (hwmgr->hwmgr_func->store_cc6_data == NULL)
317		return -EINVAL;
318
319	/* TODO: pass other display configuration in the future */
320
321	if (hwmgr->hwmgr_func->store_cc6_data)
322		hwmgr->hwmgr_func->store_cc6_data(hwmgr,
323				display_config->cpu_pstate_separation_time,
324				display_config->cpu_cc6_disable,
325				display_config->cpu_pstate_disable,
326				display_config->nb_pstate_switch_disable);
327
328	return 0;
329}
330
331int phm_get_dal_power_level(struct pp_hwmgr *hwmgr,
332		struct amd_pp_simple_clock_info *info)
333{
334	PHM_FUNC_CHECK(hwmgr);
335
336	if (info == NULL || hwmgr->hwmgr_func->get_dal_power_level == NULL)
337		return -EINVAL;
338	return hwmgr->hwmgr_func->get_dal_power_level(hwmgr, info);
339}
340
341int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr)
342{
343	PHM_FUNC_CHECK(hwmgr);
344
345	if (hwmgr->hwmgr_func->set_cpu_power_state != NULL)
346		return hwmgr->hwmgr_func->set_cpu_power_state(hwmgr);
347
348	return 0;
349}
350
351
352int phm_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state,
353				PHM_PerformanceLevelDesignation designation, uint32_t index,
354				PHM_PerformanceLevel *level)
355{
356	PHM_FUNC_CHECK(hwmgr);
357	if (hwmgr->hwmgr_func->get_performance_level == NULL)
358		return -EINVAL;
359
360	return hwmgr->hwmgr_func->get_performance_level(hwmgr, state, designation, index, level);
361
362
363}
364
365
366/**
367 * phm_get_clock_info
368 *
369 * @hwmgr:  the address of the powerplay hardware manager.
370 * @state: the address of the Power State structure.
371 * @pclock_info: the address of PP_ClockInfo structure where the result will be returned.
372 * @designation: PHM performance level designation
373 * Exception PP_Result_Failed if any of the paramters is NULL, otherwise the return value from the back-end.
374 */
375int phm_get_clock_info(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, struct pp_clock_info *pclock_info,
376			PHM_PerformanceLevelDesignation designation)
377{
378	int result;
379	PHM_PerformanceLevel performance_level = {0};
380
381	PHM_FUNC_CHECK(hwmgr);
382
383	PP_ASSERT_WITH_CODE((NULL != state), "Invalid Input!", return -EINVAL);
384	PP_ASSERT_WITH_CODE((NULL != pclock_info), "Invalid Input!", return -EINVAL);
385
386	result = phm_get_performance_level(hwmgr, state, PHM_PerformanceLevelDesignation_Activity, 0, &performance_level);
387
388	PP_ASSERT_WITH_CODE((0 == result), "Failed to retrieve minimum clocks.", return result);
389
390
391	pclock_info->min_mem_clk = performance_level.memory_clock;
392	pclock_info->min_eng_clk = performance_level.coreClock;
393	pclock_info->min_bus_bandwidth = performance_level.nonLocalMemoryFreq * performance_level.nonLocalMemoryWidth;
394
395
396	result = phm_get_performance_level(hwmgr, state, designation,
397					(hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1), &performance_level);
398
399	PP_ASSERT_WITH_CODE((0 == result), "Failed to retrieve maximum clocks.", return result);
400
401	pclock_info->max_mem_clk = performance_level.memory_clock;
402	pclock_info->max_eng_clk = performance_level.coreClock;
403	pclock_info->max_bus_bandwidth = performance_level.nonLocalMemoryFreq * performance_level.nonLocalMemoryWidth;
404
405	return 0;
406}
407
408int phm_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, struct pp_clock_info *clock_info)
409{
410	PHM_FUNC_CHECK(hwmgr);
411
412	if (hwmgr->hwmgr_func->get_current_shallow_sleep_clocks == NULL)
413		return -EINVAL;
414
415	return hwmgr->hwmgr_func->get_current_shallow_sleep_clocks(hwmgr, state, clock_info);
416
417}
418
419int phm_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks)
420{
421	PHM_FUNC_CHECK(hwmgr);
422
423	if (hwmgr->hwmgr_func->get_clock_by_type == NULL)
424		return -EINVAL;
425
426	return hwmgr->hwmgr_func->get_clock_by_type(hwmgr, type, clocks);
427
428}
429
430int phm_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr,
431		enum amd_pp_clock_type type,
432		struct pp_clock_levels_with_latency *clocks)
433{
434	PHM_FUNC_CHECK(hwmgr);
435
436	if (hwmgr->hwmgr_func->get_clock_by_type_with_latency == NULL)
437		return -EINVAL;
438
439	return hwmgr->hwmgr_func->get_clock_by_type_with_latency(hwmgr, type, clocks);
440
441}
442
443int phm_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr,
444		enum amd_pp_clock_type type,
445		struct pp_clock_levels_with_voltage *clocks)
446{
447	PHM_FUNC_CHECK(hwmgr);
448
449	if (hwmgr->hwmgr_func->get_clock_by_type_with_voltage == NULL)
450		return -EINVAL;
451
452	return hwmgr->hwmgr_func->get_clock_by_type_with_voltage(hwmgr, type, clocks);
453
454}
455
456int phm_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,
457					void *clock_ranges)
458{
459	PHM_FUNC_CHECK(hwmgr);
460
461	if (!hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges)
462		return -EINVAL;
463
464	return hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges(hwmgr,
465								clock_ranges);
466}
467
468int phm_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
469		struct pp_display_clock_request *clock)
470{
471	PHM_FUNC_CHECK(hwmgr);
472
473	if (!hwmgr->hwmgr_func->display_clock_voltage_request)
474		return -EINVAL;
475
476	return hwmgr->hwmgr_func->display_clock_voltage_request(hwmgr, clock);
477}
478
479int phm_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks)
480{
481	PHM_FUNC_CHECK(hwmgr);
482
483	if (hwmgr->hwmgr_func->get_max_high_clocks == NULL)
484		return -EINVAL;
485
486	return hwmgr->hwmgr_func->get_max_high_clocks(hwmgr, clocks);
487}
488
489int phm_disable_smc_firmware_ctf(struct pp_hwmgr *hwmgr)
490{
491	PHM_FUNC_CHECK(hwmgr);
492
493	if (!hwmgr->not_vf)
494		return 0;
495
496	if (hwmgr->hwmgr_func->disable_smc_firmware_ctf == NULL)
497		return -EINVAL;
498
499	return hwmgr->hwmgr_func->disable_smc_firmware_ctf(hwmgr);
500}
501
502int phm_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count)
503{
504	PHM_FUNC_CHECK(hwmgr);
505
506	if (!hwmgr->hwmgr_func->set_active_display_count)
507		return -EINVAL;
508
509	return hwmgr->hwmgr_func->set_active_display_count(hwmgr, count);
510}
~/ Read-only file preview.