Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
v6.9.4
 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 * Authors: AMD
23 *
24 */
25
26#include <linux/string.h>
27#include <linux/acpi.h>
28
29#include <drm/drm_probe_helper.h>
 
30#include <drm/amdgpu_drm.h>
31#include "dm_services.h"
32#include "amdgpu.h"
33#include "amdgpu_dm.h"
34#include "amdgpu_dm_irq.h"
35#include "amdgpu_pm.h"
36#include "amdgpu_dm_trace.h"
37
38	unsigned long long
39	dm_get_elapse_time_in_ns(struct dc_context *ctx,
40				 unsigned long long current_time_stamp,
41				 unsigned long long last_time_stamp)
42{
43	return current_time_stamp - last_time_stamp;
 
44}
45
46void dm_perf_trace_timestamp(const char *func_name, unsigned int line, struct dc_context *ctx)
47{
48	trace_amdgpu_dc_performance(ctx->perf_trace->read_count,
49				    ctx->perf_trace->write_count,
50				    &ctx->perf_trace->last_entry_read,
51				    &ctx->perf_trace->last_entry_write,
52				    func_name, line);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53}
54
55/**** power component interfaces ****/
v4.17
  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 * Authors: AMD
 23 *
 24 */
 25
 26#include <linux/string.h>
 27#include <linux/acpi.h>
 28
 29#include <drm/drmP.h>
 30#include <drm/drm_crtc_helper.h>
 31#include <drm/amdgpu_drm.h>
 32#include "dm_services.h"
 33#include "amdgpu.h"
 34#include "amdgpu_dm.h"
 35#include "amdgpu_dm_irq.h"
 36#include "amdgpu_pm.h"
 
 37
 38unsigned long long dm_get_timestamp(struct dc_context *ctx)
 
 
 
 39{
 40	/* TODO: return actual timestamp */
 41	return 0;
 42}
 43
 44void dm_perf_trace_timestamp(const char *func_name, unsigned int line)
 45{
 46}
 47
 48bool dm_write_persistent_data(struct dc_context *ctx,
 49		const struct dc_sink *sink,
 50		const char *module_name,
 51		const char *key_name,
 52		void *params,
 53		unsigned int size,
 54		struct persistent_data_flag *flag)
 55{
 56	/*TODO implement*/
 57	return false;
 58}
 59
 60bool dm_read_persistent_data(struct dc_context *ctx,
 61				const struct dc_sink *sink,
 62				const char *module_name,
 63				const char *key_name,
 64				void *params,
 65				unsigned int size,
 66				struct persistent_data_flag *flag)
 67{
 68	/*TODO implement*/
 69	return false;
 70}
 71
 72/**** power component interfaces ****/
 73
 74bool dm_pp_apply_display_requirements(
 75		const struct dc_context *ctx,
 76		const struct dm_pp_display_configuration *pp_display_cfg)
 77{
 78	struct amdgpu_device *adev = ctx->driver_context;
 79
 80	if (adev->pm.dpm_enabled) {
 81
 82		memset(&adev->pm.pm_display_cfg, 0,
 83				sizeof(adev->pm.pm_display_cfg));
 84
 85		adev->pm.pm_display_cfg.cpu_cc6_disable =
 86			pp_display_cfg->cpu_cc6_disable;
 87
 88		adev->pm.pm_display_cfg.cpu_pstate_disable =
 89			pp_display_cfg->cpu_pstate_disable;
 90
 91		adev->pm.pm_display_cfg.cpu_pstate_separation_time =
 92			pp_display_cfg->cpu_pstate_separation_time;
 93
 94		adev->pm.pm_display_cfg.nb_pstate_switch_disable =
 95			pp_display_cfg->nb_pstate_switch_disable;
 96
 97		adev->pm.pm_display_cfg.num_display =
 98				pp_display_cfg->display_count;
 99		adev->pm.pm_display_cfg.num_path_including_non_display =
100				pp_display_cfg->display_count;
101
102		adev->pm.pm_display_cfg.min_core_set_clock =
103				pp_display_cfg->min_engine_clock_khz/10;
104		adev->pm.pm_display_cfg.min_core_set_clock_in_sr =
105				pp_display_cfg->min_engine_clock_deep_sleep_khz/10;
106		adev->pm.pm_display_cfg.min_mem_set_clock =
107				pp_display_cfg->min_memory_clock_khz/10;
108
109		adev->pm.pm_display_cfg.multi_monitor_in_sync =
110				pp_display_cfg->all_displays_in_sync;
111		adev->pm.pm_display_cfg.min_vblank_time =
112				pp_display_cfg->avail_mclk_switch_time_us;
113
114		adev->pm.pm_display_cfg.display_clk =
115				pp_display_cfg->disp_clk_khz/10;
116
117		adev->pm.pm_display_cfg.dce_tolerable_mclk_in_active_latency =
118				pp_display_cfg->avail_mclk_switch_time_in_disp_active_us;
119
120		adev->pm.pm_display_cfg.crtc_index = pp_display_cfg->crtc_index;
121		adev->pm.pm_display_cfg.line_time_in_us =
122				pp_display_cfg->line_time_in_us;
123
124		adev->pm.pm_display_cfg.vrefresh = pp_display_cfg->disp_configs[0].v_refresh;
125		adev->pm.pm_display_cfg.crossfire_display_index = -1;
126		adev->pm.pm_display_cfg.min_bus_bandwidth = 0;
127
128		/* TODO: complete implementation of
129		 * pp_display_configuration_change().
130		 * Follow example of:
131		 * PHM_StoreDALConfigurationData - powerplay\hwmgr\hardwaremanager.c
132		 * PP_IRI_DisplayConfigurationChange - powerplay\eventmgr\iri.c */
133		if (adev->powerplay.pp_funcs->display_configuration_change)
134			adev->powerplay.pp_funcs->display_configuration_change(
135				adev->powerplay.pp_handle,
136				&adev->pm.pm_display_cfg);
137
138		/* TODO: replace by a separate call to 'apply display cfg'? */
139		amdgpu_pm_compute_clocks(adev);
140	}
141
142	return true;
143}
144
145static void get_default_clock_levels(
146		enum dm_pp_clock_type clk_type,
147		struct dm_pp_clock_levels *clks)
148{
149	uint32_t disp_clks_in_khz[6] = {
150			300000, 400000, 496560, 626090, 685720, 757900 };
151	uint32_t sclks_in_khz[6] = {
152			300000, 360000, 423530, 514290, 626090, 720000 };
153	uint32_t mclks_in_khz[2] = { 333000, 800000 };
154
155	switch (clk_type) {
156	case DM_PP_CLOCK_TYPE_DISPLAY_CLK:
157		clks->num_levels = 6;
158		memmove(clks->clocks_in_khz, disp_clks_in_khz,
159				sizeof(disp_clks_in_khz));
160		break;
161	case DM_PP_CLOCK_TYPE_ENGINE_CLK:
162		clks->num_levels = 6;
163		memmove(clks->clocks_in_khz, sclks_in_khz,
164				sizeof(sclks_in_khz));
165		break;
166	case DM_PP_CLOCK_TYPE_MEMORY_CLK:
167		clks->num_levels = 2;
168		memmove(clks->clocks_in_khz, mclks_in_khz,
169				sizeof(mclks_in_khz));
170		break;
171	default:
172		clks->num_levels = 0;
173		break;
174	}
175}
176
177static enum amd_pp_clock_type dc_to_pp_clock_type(
178		enum dm_pp_clock_type dm_pp_clk_type)
179{
180	enum amd_pp_clock_type amd_pp_clk_type = 0;
181
182	switch (dm_pp_clk_type) {
183	case DM_PP_CLOCK_TYPE_DISPLAY_CLK:
184		amd_pp_clk_type = amd_pp_disp_clock;
185		break;
186	case DM_PP_CLOCK_TYPE_ENGINE_CLK:
187		amd_pp_clk_type = amd_pp_sys_clock;
188		break;
189	case DM_PP_CLOCK_TYPE_MEMORY_CLK:
190		amd_pp_clk_type = amd_pp_mem_clock;
191		break;
192	default:
193		DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n",
194				dm_pp_clk_type);
195		break;
196	}
197
198	return amd_pp_clk_type;
199}
200
201static void pp_to_dc_clock_levels(
202		const struct amd_pp_clocks *pp_clks,
203		struct dm_pp_clock_levels *dc_clks,
204		enum dm_pp_clock_type dc_clk_type)
205{
206	uint32_t i;
207
208	if (pp_clks->count > DM_PP_MAX_CLOCK_LEVELS) {
209		DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n",
210				DC_DECODE_PP_CLOCK_TYPE(dc_clk_type),
211				pp_clks->count,
212				DM_PP_MAX_CLOCK_LEVELS);
213
214		dc_clks->num_levels = DM_PP_MAX_CLOCK_LEVELS;
215	} else
216		dc_clks->num_levels = pp_clks->count;
217
218	DRM_INFO("DM_PPLIB: values for %s clock\n",
219			DC_DECODE_PP_CLOCK_TYPE(dc_clk_type));
220
221	for (i = 0; i < dc_clks->num_levels; i++) {
222		DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]);
223		/* translate 10kHz to kHz */
224		dc_clks->clocks_in_khz[i] = pp_clks->clock[i] * 10;
225	}
226}
227
228bool dm_pp_get_clock_levels_by_type(
229		const struct dc_context *ctx,
230		enum dm_pp_clock_type clk_type,
231		struct dm_pp_clock_levels *dc_clks)
232{
233	struct amdgpu_device *adev = ctx->driver_context;
234	void *pp_handle = adev->powerplay.pp_handle;
235	struct amd_pp_clocks pp_clks = { 0 };
236	struct amd_pp_simple_clock_info validation_clks = { 0 };
237	uint32_t i;
238
239	if (adev->powerplay.pp_funcs->get_clock_by_type) {
240		if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle,
241			dc_to_pp_clock_type(clk_type), &pp_clks)) {
242		/* Error in pplib. Provide default values. */
243			get_default_clock_levels(clk_type, dc_clks);
244			return true;
245		}
246	}
247
248	pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type);
249
250	if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks) {
251		if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks(
252						pp_handle, &validation_clks)) {
253			/* Error in pplib. Provide default values. */
254			DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n");
255			validation_clks.engine_max_clock = 72000;
256			validation_clks.memory_max_clock = 80000;
257			validation_clks.level = 0;
258		}
259	}
260
261	DRM_INFO("DM_PPLIB: Validation clocks:\n");
262	DRM_INFO("DM_PPLIB:    engine_max_clock: %d\n",
263			validation_clks.engine_max_clock);
264	DRM_INFO("DM_PPLIB:    memory_max_clock: %d\n",
265			validation_clks.memory_max_clock);
266	DRM_INFO("DM_PPLIB:    level           : %d\n",
267			validation_clks.level);
268
269	/* Translate 10 kHz to kHz. */
270	validation_clks.engine_max_clock *= 10;
271	validation_clks.memory_max_clock *= 10;
272
273	/* Determine the highest non-boosted level from the Validation Clocks */
274	if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) {
275		for (i = 0; i < dc_clks->num_levels; i++) {
276			if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) {
277				/* This clock is higher the validation clock.
278				 * Than means the previous one is the highest
279				 * non-boosted one. */
280				DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n",
281						dc_clks->num_levels, i);
282				dc_clks->num_levels = i > 0 ? i : 1;
283				break;
284			}
285		}
286	} else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) {
287		for (i = 0; i < dc_clks->num_levels; i++) {
288			if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) {
289				DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n",
290						dc_clks->num_levels, i);
291				dc_clks->num_levels = i > 0 ? i : 1;
292				break;
293			}
294		}
295	}
296
297	return true;
298}
299
300bool dm_pp_get_clock_levels_by_type_with_latency(
301	const struct dc_context *ctx,
302	enum dm_pp_clock_type clk_type,
303	struct dm_pp_clock_levels_with_latency *clk_level_info)
304{
305	/* TODO: to be implemented */
306	return false;
307}
308
309bool dm_pp_get_clock_levels_by_type_with_voltage(
310	const struct dc_context *ctx,
311	enum dm_pp_clock_type clk_type,
312	struct dm_pp_clock_levels_with_voltage *clk_level_info)
313{
314	/* TODO: to be implemented */
315	return false;
316}
317
318bool dm_pp_notify_wm_clock_changes(
319	const struct dc_context *ctx,
320	struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges)
321{
322	/* TODO: to be implemented */
323	return false;
324}
325
326bool dm_pp_apply_power_level_change_request(
327	const struct dc_context *ctx,
328	struct dm_pp_power_level_change_request *level_change_req)
329{
330	/* TODO: to be implemented */
331	return false;
332}
333
334bool dm_pp_apply_clock_for_voltage_request(
335	const struct dc_context *ctx,
336	struct dm_pp_clock_for_voltage_req *clock_for_voltage_req)
337{
338	/* TODO: to be implemented */
339	return false;
340}
341
342bool dm_pp_get_static_clocks(
343	const struct dc_context *ctx,
344	struct dm_pp_static_clock_info *static_clk_info)
345{
346	/* TODO: to be implemented */
347	return false;
348}
349
350void dm_pp_get_funcs_rv(
351		struct dc_context *ctx,
352		struct pp_smu_funcs_rv *funcs)
353{}
354
355/**** end of power component interfaces ****/