Commit | Line | Data |
---|---|---|
f7c1ed34 ML |
1 | /* |
2 | * Copyright 2018 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 | #include <linux/string.h> | |
25 | #include <linux/acpi.h> | |
26 | ||
27 | #include <drm/drmP.h> | |
28 | #include <drm/drm_crtc_helper.h> | |
29 | #include <drm/amdgpu_drm.h> | |
30 | #include "dm_services.h" | |
31 | #include "amdgpu.h" | |
32 | #include "amdgpu_dm.h" | |
33 | #include "amdgpu_dm_irq.h" | |
34 | #include "amdgpu_pm.h" | |
35 | #include "dm_pp_smu.h" | |
f7c1ed34 ML |
36 | |
37 | ||
38 | bool dm_pp_apply_display_requirements( | |
39 | const struct dc_context *ctx, | |
40 | const struct dm_pp_display_configuration *pp_display_cfg) | |
41 | { | |
42 | struct amdgpu_device *adev = ctx->driver_context; | |
d4d5eace | 43 | int i; |
f7c1ed34 ML |
44 | |
45 | if (adev->pm.dpm_enabled) { | |
46 | ||
47 | memset(&adev->pm.pm_display_cfg, 0, | |
48 | sizeof(adev->pm.pm_display_cfg)); | |
49 | ||
50 | adev->pm.pm_display_cfg.cpu_cc6_disable = | |
51 | pp_display_cfg->cpu_cc6_disable; | |
52 | ||
53 | adev->pm.pm_display_cfg.cpu_pstate_disable = | |
54 | pp_display_cfg->cpu_pstate_disable; | |
55 | ||
56 | adev->pm.pm_display_cfg.cpu_pstate_separation_time = | |
57 | pp_display_cfg->cpu_pstate_separation_time; | |
58 | ||
59 | adev->pm.pm_display_cfg.nb_pstate_switch_disable = | |
60 | pp_display_cfg->nb_pstate_switch_disable; | |
61 | ||
62 | adev->pm.pm_display_cfg.num_display = | |
63 | pp_display_cfg->display_count; | |
64 | adev->pm.pm_display_cfg.num_path_including_non_display = | |
65 | pp_display_cfg->display_count; | |
66 | ||
67 | adev->pm.pm_display_cfg.min_core_set_clock = | |
68 | pp_display_cfg->min_engine_clock_khz/10; | |
69 | adev->pm.pm_display_cfg.min_core_set_clock_in_sr = | |
70 | pp_display_cfg->min_engine_clock_deep_sleep_khz/10; | |
71 | adev->pm.pm_display_cfg.min_mem_set_clock = | |
72 | pp_display_cfg->min_memory_clock_khz/10; | |
73 | ||
3180fb67 | 74 | adev->pm.pm_display_cfg.min_dcef_deep_sleep_set_clk = |
75 | pp_display_cfg->min_engine_clock_deep_sleep_khz/10; | |
76 | adev->pm.pm_display_cfg.min_dcef_set_clk = | |
77 | pp_display_cfg->min_dcfclock_khz/10; | |
78 | ||
f7c1ed34 ML |
79 | adev->pm.pm_display_cfg.multi_monitor_in_sync = |
80 | pp_display_cfg->all_displays_in_sync; | |
81 | adev->pm.pm_display_cfg.min_vblank_time = | |
82 | pp_display_cfg->avail_mclk_switch_time_us; | |
83 | ||
84 | adev->pm.pm_display_cfg.display_clk = | |
85 | pp_display_cfg->disp_clk_khz/10; | |
86 | ||
87 | adev->pm.pm_display_cfg.dce_tolerable_mclk_in_active_latency = | |
88 | pp_display_cfg->avail_mclk_switch_time_in_disp_active_us; | |
89 | ||
90 | adev->pm.pm_display_cfg.crtc_index = pp_display_cfg->crtc_index; | |
91 | adev->pm.pm_display_cfg.line_time_in_us = | |
92 | pp_display_cfg->line_time_in_us; | |
93 | ||
94 | adev->pm.pm_display_cfg.vrefresh = pp_display_cfg->disp_configs[0].v_refresh; | |
95 | adev->pm.pm_display_cfg.crossfire_display_index = -1; | |
96 | adev->pm.pm_display_cfg.min_bus_bandwidth = 0; | |
97 | ||
d4d5eace | 98 | for (i = 0; i < pp_display_cfg->display_count; i++) { |
99 | const struct dm_pp_single_disp_config *dc_cfg = | |
100 | &pp_display_cfg->disp_configs[i]; | |
101 | adev->pm.pm_display_cfg.displays[i].controller_id = dc_cfg->pipe_idx + 1; | |
102 | } | |
103 | ||
f7c1ed34 ML |
104 | /* TODO: complete implementation of |
105 | * pp_display_configuration_change(). | |
106 | * Follow example of: | |
107 | * PHM_StoreDALConfigurationData - powerplay\hwmgr\hardwaremanager.c | |
108 | * PP_IRI_DisplayConfigurationChange - powerplay\eventmgr\iri.c */ | |
109 | if (adev->powerplay.pp_funcs->display_configuration_change) | |
110 | adev->powerplay.pp_funcs->display_configuration_change( | |
111 | adev->powerplay.pp_handle, | |
112 | &adev->pm.pm_display_cfg); | |
113 | ||
114 | /* TODO: replace by a separate call to 'apply display cfg'? */ | |
115 | amdgpu_pm_compute_clocks(adev); | |
116 | } | |
117 | ||
118 | return true; | |
119 | } | |
120 | ||
121 | static void get_default_clock_levels( | |
122 | enum dm_pp_clock_type clk_type, | |
123 | struct dm_pp_clock_levels *clks) | |
124 | { | |
125 | uint32_t disp_clks_in_khz[6] = { | |
126 | 300000, 400000, 496560, 626090, 685720, 757900 }; | |
127 | uint32_t sclks_in_khz[6] = { | |
128 | 300000, 360000, 423530, 514290, 626090, 720000 }; | |
129 | uint32_t mclks_in_khz[2] = { 333000, 800000 }; | |
130 | ||
131 | switch (clk_type) { | |
132 | case DM_PP_CLOCK_TYPE_DISPLAY_CLK: | |
133 | clks->num_levels = 6; | |
134 | memmove(clks->clocks_in_khz, disp_clks_in_khz, | |
135 | sizeof(disp_clks_in_khz)); | |
136 | break; | |
137 | case DM_PP_CLOCK_TYPE_ENGINE_CLK: | |
138 | clks->num_levels = 6; | |
139 | memmove(clks->clocks_in_khz, sclks_in_khz, | |
140 | sizeof(sclks_in_khz)); | |
141 | break; | |
142 | case DM_PP_CLOCK_TYPE_MEMORY_CLK: | |
143 | clks->num_levels = 2; | |
144 | memmove(clks->clocks_in_khz, mclks_in_khz, | |
145 | sizeof(mclks_in_khz)); | |
146 | break; | |
147 | default: | |
148 | clks->num_levels = 0; | |
149 | break; | |
150 | } | |
151 | } | |
152 | ||
153 | static enum amd_pp_clock_type dc_to_pp_clock_type( | |
154 | enum dm_pp_clock_type dm_pp_clk_type) | |
155 | { | |
156 | enum amd_pp_clock_type amd_pp_clk_type = 0; | |
157 | ||
158 | switch (dm_pp_clk_type) { | |
159 | case DM_PP_CLOCK_TYPE_DISPLAY_CLK: | |
160 | amd_pp_clk_type = amd_pp_disp_clock; | |
161 | break; | |
162 | case DM_PP_CLOCK_TYPE_ENGINE_CLK: | |
163 | amd_pp_clk_type = amd_pp_sys_clock; | |
164 | break; | |
165 | case DM_PP_CLOCK_TYPE_MEMORY_CLK: | |
166 | amd_pp_clk_type = amd_pp_mem_clock; | |
167 | break; | |
168 | case DM_PP_CLOCK_TYPE_DCEFCLK: | |
169 | amd_pp_clk_type = amd_pp_dcef_clock; | |
170 | break; | |
171 | case DM_PP_CLOCK_TYPE_DCFCLK: | |
172 | amd_pp_clk_type = amd_pp_dcf_clock; | |
173 | break; | |
174 | case DM_PP_CLOCK_TYPE_PIXELCLK: | |
175 | amd_pp_clk_type = amd_pp_pixel_clock; | |
176 | break; | |
177 | case DM_PP_CLOCK_TYPE_FCLK: | |
178 | amd_pp_clk_type = amd_pp_f_clock; | |
179 | break; | |
180 | case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: | |
66917e56 | 181 | amd_pp_clk_type = amd_pp_phy_clock; |
182 | break; | |
183 | case DM_PP_CLOCK_TYPE_DPPCLK: | |
f7c1ed34 ML |
184 | amd_pp_clk_type = amd_pp_dpp_clock; |
185 | break; | |
186 | default: | |
187 | DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", | |
188 | dm_pp_clk_type); | |
189 | break; | |
190 | } | |
191 | ||
192 | return amd_pp_clk_type; | |
193 | } | |
194 | ||
c2c09ed5 ML |
195 | static enum dm_pp_clocks_state pp_to_dc_powerlevel_state( |
196 | enum PP_DAL_POWERLEVEL max_clocks_state) | |
197 | { | |
198 | switch (max_clocks_state) { | |
199 | case PP_DAL_POWERLEVEL_0: | |
200 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_0; | |
201 | case PP_DAL_POWERLEVEL_1: | |
202 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_1; | |
203 | case PP_DAL_POWERLEVEL_2: | |
204 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_2; | |
205 | case PP_DAL_POWERLEVEL_3: | |
206 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_3; | |
207 | case PP_DAL_POWERLEVEL_4: | |
208 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_4; | |
209 | case PP_DAL_POWERLEVEL_5: | |
210 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_5; | |
211 | case PP_DAL_POWERLEVEL_6: | |
212 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_6; | |
213 | case PP_DAL_POWERLEVEL_7: | |
214 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_7; | |
215 | default: | |
216 | DRM_ERROR("DM_PPLIB: invalid powerlevel state: %d!\n", | |
217 | max_clocks_state); | |
218 | return DM_PP_CLOCKS_STATE_INVALID; | |
219 | } | |
220 | } | |
221 | ||
f7c1ed34 ML |
222 | static void pp_to_dc_clock_levels( |
223 | const struct amd_pp_clocks *pp_clks, | |
224 | struct dm_pp_clock_levels *dc_clks, | |
225 | enum dm_pp_clock_type dc_clk_type) | |
226 | { | |
227 | uint32_t i; | |
228 | ||
229 | if (pp_clks->count > DM_PP_MAX_CLOCK_LEVELS) { | |
230 | DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", | |
231 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), | |
232 | pp_clks->count, | |
233 | DM_PP_MAX_CLOCK_LEVELS); | |
234 | ||
235 | dc_clks->num_levels = DM_PP_MAX_CLOCK_LEVELS; | |
236 | } else | |
237 | dc_clks->num_levels = pp_clks->count; | |
238 | ||
239 | DRM_INFO("DM_PPLIB: values for %s clock\n", | |
240 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); | |
241 | ||
242 | for (i = 0; i < dc_clks->num_levels; i++) { | |
243 | DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]); | |
23ec3d14 | 244 | dc_clks->clocks_in_khz[i] = pp_clks->clock[i]; |
f7c1ed34 ML |
245 | } |
246 | } | |
247 | ||
248 | static void pp_to_dc_clock_levels_with_latency( | |
249 | const struct pp_clock_levels_with_latency *pp_clks, | |
250 | struct dm_pp_clock_levels_with_latency *clk_level_info, | |
251 | enum dm_pp_clock_type dc_clk_type) | |
252 | { | |
253 | uint32_t i; | |
254 | ||
255 | if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { | |
256 | DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", | |
257 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), | |
258 | pp_clks->num_levels, | |
259 | DM_PP_MAX_CLOCK_LEVELS); | |
260 | ||
261 | clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; | |
262 | } else | |
263 | clk_level_info->num_levels = pp_clks->num_levels; | |
264 | ||
265 | DRM_DEBUG("DM_PPLIB: values for %s clock\n", | |
266 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); | |
267 | ||
268 | for (i = 0; i < clk_level_info->num_levels; i++) { | |
23ec3d14 RZ |
269 | DRM_DEBUG("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); |
270 | clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; | |
f7c1ed34 ML |
271 | clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; |
272 | } | |
273 | } | |
274 | ||
275 | static void pp_to_dc_clock_levels_with_voltage( | |
276 | const struct pp_clock_levels_with_voltage *pp_clks, | |
277 | struct dm_pp_clock_levels_with_voltage *clk_level_info, | |
278 | enum dm_pp_clock_type dc_clk_type) | |
279 | { | |
280 | uint32_t i; | |
281 | ||
282 | if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { | |
283 | DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", | |
284 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), | |
285 | pp_clks->num_levels, | |
286 | DM_PP_MAX_CLOCK_LEVELS); | |
287 | ||
288 | clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; | |
289 | } else | |
290 | clk_level_info->num_levels = pp_clks->num_levels; | |
291 | ||
292 | DRM_INFO("DM_PPLIB: values for %s clock\n", | |
293 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); | |
294 | ||
295 | for (i = 0; i < clk_level_info->num_levels; i++) { | |
23ec3d14 RZ |
296 | DRM_INFO("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); |
297 | clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; | |
f7c1ed34 ML |
298 | clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; |
299 | } | |
300 | } | |
301 | ||
302 | bool dm_pp_get_clock_levels_by_type( | |
303 | const struct dc_context *ctx, | |
304 | enum dm_pp_clock_type clk_type, | |
305 | struct dm_pp_clock_levels *dc_clks) | |
306 | { | |
307 | struct amdgpu_device *adev = ctx->driver_context; | |
308 | void *pp_handle = adev->powerplay.pp_handle; | |
309 | struct amd_pp_clocks pp_clks = { 0 }; | |
310 | struct amd_pp_simple_clock_info validation_clks = { 0 }; | |
311 | uint32_t i; | |
312 | ||
313 | if (adev->powerplay.pp_funcs->get_clock_by_type) { | |
314 | if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle, | |
315 | dc_to_pp_clock_type(clk_type), &pp_clks)) { | |
316 | /* Error in pplib. Provide default values. */ | |
317 | get_default_clock_levels(clk_type, dc_clks); | |
318 | return true; | |
319 | } | |
320 | } | |
321 | ||
322 | pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type); | |
323 | ||
324 | if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks) { | |
325 | if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks( | |
326 | pp_handle, &validation_clks)) { | |
327 | /* Error in pplib. Provide default values. */ | |
328 | DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); | |
329 | validation_clks.engine_max_clock = 72000; | |
330 | validation_clks.memory_max_clock = 80000; | |
331 | validation_clks.level = 0; | |
332 | } | |
333 | } | |
334 | ||
335 | DRM_INFO("DM_PPLIB: Validation clocks:\n"); | |
336 | DRM_INFO("DM_PPLIB: engine_max_clock: %d\n", | |
337 | validation_clks.engine_max_clock); | |
338 | DRM_INFO("DM_PPLIB: memory_max_clock: %d\n", | |
339 | validation_clks.memory_max_clock); | |
340 | DRM_INFO("DM_PPLIB: level : %d\n", | |
341 | validation_clks.level); | |
342 | ||
343 | /* Translate 10 kHz to kHz. */ | |
344 | validation_clks.engine_max_clock *= 10; | |
345 | validation_clks.memory_max_clock *= 10; | |
346 | ||
347 | /* Determine the highest non-boosted level from the Validation Clocks */ | |
348 | if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { | |
349 | for (i = 0; i < dc_clks->num_levels; i++) { | |
350 | if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) { | |
351 | /* This clock is higher the validation clock. | |
352 | * Than means the previous one is the highest | |
353 | * non-boosted one. */ | |
354 | DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", | |
355 | dc_clks->num_levels, i); | |
356 | dc_clks->num_levels = i > 0 ? i : 1; | |
357 | break; | |
358 | } | |
359 | } | |
360 | } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { | |
361 | for (i = 0; i < dc_clks->num_levels; i++) { | |
362 | if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) { | |
363 | DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", | |
364 | dc_clks->num_levels, i); | |
365 | dc_clks->num_levels = i > 0 ? i : 1; | |
366 | break; | |
367 | } | |
368 | } | |
369 | } | |
370 | ||
371 | return true; | |
372 | } | |
373 | ||
374 | bool dm_pp_get_clock_levels_by_type_with_latency( | |
375 | const struct dc_context *ctx, | |
376 | enum dm_pp_clock_type clk_type, | |
377 | struct dm_pp_clock_levels_with_latency *clk_level_info) | |
378 | { | |
379 | struct amdgpu_device *adev = ctx->driver_context; | |
380 | void *pp_handle = adev->powerplay.pp_handle; | |
381 | struct pp_clock_levels_with_latency pp_clks = { 0 }; | |
382 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; | |
383 | ||
384 | if (!pp_funcs || !pp_funcs->get_clock_by_type_with_latency) | |
385 | return false; | |
386 | ||
387 | if (pp_funcs->get_clock_by_type_with_latency(pp_handle, | |
388 | dc_to_pp_clock_type(clk_type), | |
389 | &pp_clks)) | |
390 | return false; | |
391 | ||
392 | pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type); | |
393 | ||
394 | return true; | |
395 | } | |
396 | ||
397 | bool dm_pp_get_clock_levels_by_type_with_voltage( | |
398 | const struct dc_context *ctx, | |
399 | enum dm_pp_clock_type clk_type, | |
400 | struct dm_pp_clock_levels_with_voltage *clk_level_info) | |
401 | { | |
402 | struct amdgpu_device *adev = ctx->driver_context; | |
403 | void *pp_handle = adev->powerplay.pp_handle; | |
404 | struct pp_clock_levels_with_voltage pp_clk_info = {0}; | |
405 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; | |
406 | ||
407 | if (pp_funcs->get_clock_by_type_with_voltage(pp_handle, | |
408 | dc_to_pp_clock_type(clk_type), | |
409 | &pp_clk_info)) | |
410 | return false; | |
411 | ||
412 | pp_to_dc_clock_levels_with_voltage(&pp_clk_info, clk_level_info, clk_type); | |
413 | ||
414 | return true; | |
415 | } | |
416 | ||
417 | bool dm_pp_notify_wm_clock_changes( | |
418 | const struct dc_context *ctx, | |
419 | struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges) | |
420 | { | |
421 | /* TODO: to be implemented */ | |
422 | return false; | |
423 | } | |
424 | ||
425 | bool dm_pp_apply_power_level_change_request( | |
426 | const struct dc_context *ctx, | |
427 | struct dm_pp_power_level_change_request *level_change_req) | |
428 | { | |
429 | /* TODO: to be implemented */ | |
430 | return false; | |
431 | } | |
432 | ||
433 | bool dm_pp_apply_clock_for_voltage_request( | |
434 | const struct dc_context *ctx, | |
435 | struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) | |
436 | { | |
437 | struct amdgpu_device *adev = ctx->driver_context; | |
438 | struct pp_display_clock_request pp_clock_request = {0}; | |
439 | int ret = 0; | |
440 | ||
441 | pp_clock_request.clock_type = dc_to_pp_clock_type(clock_for_voltage_req->clk_type); | |
442 | pp_clock_request.clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; | |
443 | ||
444 | if (!pp_clock_request.clock_type) | |
445 | return false; | |
446 | ||
447 | if (adev->powerplay.pp_funcs->display_clock_voltage_request) | |
448 | ret = adev->powerplay.pp_funcs->display_clock_voltage_request( | |
449 | adev->powerplay.pp_handle, | |
450 | &pp_clock_request); | |
451 | if (ret) | |
452 | return false; | |
453 | return true; | |
454 | } | |
455 | ||
456 | bool dm_pp_get_static_clocks( | |
457 | const struct dc_context *ctx, | |
458 | struct dm_pp_static_clock_info *static_clk_info) | |
459 | { | |
460 | struct amdgpu_device *adev = ctx->driver_context; | |
461 | struct amd_pp_clock_info pp_clk_info = {0}; | |
462 | int ret = 0; | |
463 | ||
464 | if (adev->powerplay.pp_funcs->get_current_clocks) | |
465 | ret = adev->powerplay.pp_funcs->get_current_clocks( | |
466 | adev->powerplay.pp_handle, | |
467 | &pp_clk_info); | |
468 | if (ret) | |
469 | return false; | |
470 | ||
c2c09ed5 | 471 | static_clk_info->max_clocks_state = pp_to_dc_powerlevel_state(pp_clk_info.max_clocks_state); |
3dbd823e RZ |
472 | static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock * 10; |
473 | static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock * 10; | |
f7c1ed34 ML |
474 | |
475 | return true; | |
476 | } | |
477 | ||
478 | void pp_rv_set_display_requirement(struct pp_smu *pp, | |
479 | struct pp_smu_display_requirement_rv *req) | |
480 | { | |
b0a634ac RZ |
481 | struct dc_context *ctx = pp->ctx; |
482 | struct amdgpu_device *adev = ctx->driver_context; | |
a296b162 | 483 | void *pp_handle = adev->powerplay.pp_handle; |
b0a634ac | 484 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
a296b162 | 485 | struct pp_display_clock_request clock = {0}; |
b0a634ac | 486 | |
a296b162 | 487 | if (!pp_funcs || !pp_funcs->display_clock_voltage_request) |
b0a634ac | 488 | return; |
f7c1ed34 | 489 | |
a296b162 RZ |
490 | clock.clock_type = amd_pp_dcf_clock; |
491 | clock.clock_freq_in_khz = req->hard_min_dcefclk_khz; | |
492 | pp_funcs->display_clock_voltage_request(pp_handle, &clock); | |
493 | ||
494 | clock.clock_type = amd_pp_f_clock; | |
495 | clock.clock_freq_in_khz = req->hard_min_fclk_khz; | |
496 | pp_funcs->display_clock_voltage_request(pp_handle, &clock); | |
f7c1ed34 ML |
497 | } |
498 | ||
499 | void pp_rv_set_wm_ranges(struct pp_smu *pp, | |
500 | struct pp_smu_wm_range_sets *ranges) | |
501 | { | |
b0a634ac RZ |
502 | struct dc_context *ctx = pp->ctx; |
503 | struct amdgpu_device *adev = ctx->driver_context; | |
504 | void *pp_handle = adev->powerplay.pp_handle; | |
505 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; | |
506 | struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; | |
507 | struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = wm_with_clock_ranges.wm_dmif_clocks_ranges; | |
508 | struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = wm_with_clock_ranges.wm_mcif_clocks_ranges; | |
509 | int32_t i; | |
f7c1ed34 | 510 | |
b0a634ac RZ |
511 | wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets; |
512 | wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets; | |
f7c1ed34 | 513 | |
b0a634ac | 514 | for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) { |
f7c1ed34 | 515 | if (ranges->reader_wm_sets[i].wm_inst > 3) |
b0a634ac | 516 | wm_dce_clocks[i].wm_set_id = WM_SET_A; |
f7c1ed34 | 517 | else |
b0a634ac | 518 | wm_dce_clocks[i].wm_set_id = |
f7c1ed34 | 519 | ranges->reader_wm_sets[i].wm_inst; |
b0a634ac | 520 | wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz = |
f7c1ed34 | 521 | ranges->reader_wm_sets[i].max_drain_clk_khz; |
b0a634ac | 522 | wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz = |
f7c1ed34 | 523 | ranges->reader_wm_sets[i].min_drain_clk_khz; |
b0a634ac | 524 | wm_dce_clocks[i].wm_max_mem_clk_in_khz = |
f7c1ed34 | 525 | ranges->reader_wm_sets[i].max_fill_clk_khz; |
b0a634ac | 526 | wm_dce_clocks[i].wm_min_mem_clk_in_khz = |
f7c1ed34 ML |
527 | ranges->reader_wm_sets[i].min_fill_clk_khz; |
528 | } | |
529 | ||
b0a634ac | 530 | for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) { |
f7c1ed34 | 531 | if (ranges->writer_wm_sets[i].wm_inst > 3) |
b0a634ac | 532 | wm_soc_clocks[i].wm_set_id = WM_SET_A; |
f7c1ed34 | 533 | else |
b0a634ac | 534 | wm_soc_clocks[i].wm_set_id = |
f7c1ed34 | 535 | ranges->writer_wm_sets[i].wm_inst; |
b0a634ac | 536 | wm_soc_clocks[i].wm_max_socclk_clk_in_khz = |
f7c1ed34 | 537 | ranges->writer_wm_sets[i].max_fill_clk_khz; |
b0a634ac | 538 | wm_soc_clocks[i].wm_min_socclk_clk_in_khz = |
f7c1ed34 | 539 | ranges->writer_wm_sets[i].min_fill_clk_khz; |
b0a634ac | 540 | wm_soc_clocks[i].wm_max_mem_clk_in_khz = |
70b63170 | 541 | ranges->writer_wm_sets[i].max_drain_clk_khz; |
b0a634ac | 542 | wm_soc_clocks[i].wm_min_mem_clk_in_khz = |
70b63170 | 543 | ranges->writer_wm_sets[i].min_drain_clk_khz; |
f7c1ed34 ML |
544 | } |
545 | ||
b0a634ac | 546 | pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, &wm_with_clock_ranges); |
f7c1ed34 ML |
547 | } |
548 | ||
549 | void pp_rv_set_pme_wa_enable(struct pp_smu *pp) | |
550 | { | |
b0a634ac RZ |
551 | struct dc_context *ctx = pp->ctx; |
552 | struct amdgpu_device *adev = ctx->driver_context; | |
553 | void *pp_handle = adev->powerplay.pp_handle; | |
554 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; | |
555 | ||
556 | if (!pp_funcs || !pp_funcs->notify_smu_enable_pwe) | |
557 | return; | |
f7c1ed34 | 558 | |
b0a634ac | 559 | pp_funcs->notify_smu_enable_pwe(pp_handle); |
f7c1ed34 ML |
560 | } |
561 | ||
562 | void dm_pp_get_funcs_rv( | |
563 | struct dc_context *ctx, | |
564 | struct pp_smu_funcs_rv *funcs) | |
565 | { | |
566 | funcs->pp_smu.ctx = ctx; | |
567 | funcs->set_display_requirement = pp_rv_set_display_requirement; | |
568 | funcs->set_wm_ranges = pp_rv_set_wm_ranges; | |
569 | funcs->set_pme_wa_enable = pp_rv_set_pme_wa_enable; | |
570 | } |