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> | |
fcd70cd3 | 28 | #include <drm/drm_probe_helper.h> |
f7c1ed34 ML |
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 | ||
6f059c64 | 104 | if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->display_configuration_change) |
f7c1ed34 ML |
105 | adev->powerplay.pp_funcs->display_configuration_change( |
106 | adev->powerplay.pp_handle, | |
107 | &adev->pm.pm_display_cfg); | |
40d0ebd9 RZ |
108 | |
109 | amdgpu_pm_compute_clocks(adev); | |
f7c1ed34 ML |
110 | } |
111 | ||
112 | return true; | |
113 | } | |
114 | ||
115 | static void get_default_clock_levels( | |
116 | enum dm_pp_clock_type clk_type, | |
117 | struct dm_pp_clock_levels *clks) | |
118 | { | |
119 | uint32_t disp_clks_in_khz[6] = { | |
120 | 300000, 400000, 496560, 626090, 685720, 757900 }; | |
121 | uint32_t sclks_in_khz[6] = { | |
122 | 300000, 360000, 423530, 514290, 626090, 720000 }; | |
123 | uint32_t mclks_in_khz[2] = { 333000, 800000 }; | |
124 | ||
125 | switch (clk_type) { | |
126 | case DM_PP_CLOCK_TYPE_DISPLAY_CLK: | |
127 | clks->num_levels = 6; | |
128 | memmove(clks->clocks_in_khz, disp_clks_in_khz, | |
129 | sizeof(disp_clks_in_khz)); | |
130 | break; | |
131 | case DM_PP_CLOCK_TYPE_ENGINE_CLK: | |
132 | clks->num_levels = 6; | |
133 | memmove(clks->clocks_in_khz, sclks_in_khz, | |
134 | sizeof(sclks_in_khz)); | |
135 | break; | |
136 | case DM_PP_CLOCK_TYPE_MEMORY_CLK: | |
137 | clks->num_levels = 2; | |
138 | memmove(clks->clocks_in_khz, mclks_in_khz, | |
139 | sizeof(mclks_in_khz)); | |
140 | break; | |
141 | default: | |
142 | clks->num_levels = 0; | |
143 | break; | |
144 | } | |
145 | } | |
146 | ||
147 | static enum amd_pp_clock_type dc_to_pp_clock_type( | |
148 | enum dm_pp_clock_type dm_pp_clk_type) | |
149 | { | |
150 | enum amd_pp_clock_type amd_pp_clk_type = 0; | |
151 | ||
152 | switch (dm_pp_clk_type) { | |
153 | case DM_PP_CLOCK_TYPE_DISPLAY_CLK: | |
154 | amd_pp_clk_type = amd_pp_disp_clock; | |
155 | break; | |
156 | case DM_PP_CLOCK_TYPE_ENGINE_CLK: | |
157 | amd_pp_clk_type = amd_pp_sys_clock; | |
158 | break; | |
159 | case DM_PP_CLOCK_TYPE_MEMORY_CLK: | |
160 | amd_pp_clk_type = amd_pp_mem_clock; | |
161 | break; | |
162 | case DM_PP_CLOCK_TYPE_DCEFCLK: | |
163 | amd_pp_clk_type = amd_pp_dcef_clock; | |
164 | break; | |
165 | case DM_PP_CLOCK_TYPE_DCFCLK: | |
166 | amd_pp_clk_type = amd_pp_dcf_clock; | |
167 | break; | |
168 | case DM_PP_CLOCK_TYPE_PIXELCLK: | |
169 | amd_pp_clk_type = amd_pp_pixel_clock; | |
170 | break; | |
171 | case DM_PP_CLOCK_TYPE_FCLK: | |
172 | amd_pp_clk_type = amd_pp_f_clock; | |
173 | break; | |
174 | case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: | |
66917e56 | 175 | amd_pp_clk_type = amd_pp_phy_clock; |
176 | break; | |
177 | case DM_PP_CLOCK_TYPE_DPPCLK: | |
f7c1ed34 ML |
178 | amd_pp_clk_type = amd_pp_dpp_clock; |
179 | break; | |
180 | default: | |
181 | DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", | |
182 | dm_pp_clk_type); | |
183 | break; | |
184 | } | |
185 | ||
186 | return amd_pp_clk_type; | |
187 | } | |
188 | ||
c2c09ed5 ML |
189 | static enum dm_pp_clocks_state pp_to_dc_powerlevel_state( |
190 | enum PP_DAL_POWERLEVEL max_clocks_state) | |
191 | { | |
192 | switch (max_clocks_state) { | |
193 | case PP_DAL_POWERLEVEL_0: | |
194 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_0; | |
195 | case PP_DAL_POWERLEVEL_1: | |
196 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_1; | |
197 | case PP_DAL_POWERLEVEL_2: | |
198 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_2; | |
199 | case PP_DAL_POWERLEVEL_3: | |
200 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_3; | |
201 | case PP_DAL_POWERLEVEL_4: | |
202 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_4; | |
203 | case PP_DAL_POWERLEVEL_5: | |
204 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_5; | |
205 | case PP_DAL_POWERLEVEL_6: | |
206 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_6; | |
207 | case PP_DAL_POWERLEVEL_7: | |
208 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_7; | |
209 | default: | |
210 | DRM_ERROR("DM_PPLIB: invalid powerlevel state: %d!\n", | |
211 | max_clocks_state); | |
212 | return DM_PP_CLOCKS_STATE_INVALID; | |
213 | } | |
214 | } | |
215 | ||
f7c1ed34 ML |
216 | static void pp_to_dc_clock_levels( |
217 | const struct amd_pp_clocks *pp_clks, | |
218 | struct dm_pp_clock_levels *dc_clks, | |
219 | enum dm_pp_clock_type dc_clk_type) | |
220 | { | |
221 | uint32_t i; | |
222 | ||
223 | if (pp_clks->count > DM_PP_MAX_CLOCK_LEVELS) { | |
224 | DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", | |
225 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), | |
226 | pp_clks->count, | |
227 | DM_PP_MAX_CLOCK_LEVELS); | |
228 | ||
229 | dc_clks->num_levels = DM_PP_MAX_CLOCK_LEVELS; | |
230 | } else | |
231 | dc_clks->num_levels = pp_clks->count; | |
232 | ||
233 | DRM_INFO("DM_PPLIB: values for %s clock\n", | |
234 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); | |
235 | ||
236 | for (i = 0; i < dc_clks->num_levels; i++) { | |
237 | DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]); | |
23ec3d14 | 238 | dc_clks->clocks_in_khz[i] = pp_clks->clock[i]; |
f7c1ed34 ML |
239 | } |
240 | } | |
241 | ||
242 | static void pp_to_dc_clock_levels_with_latency( | |
243 | const struct pp_clock_levels_with_latency *pp_clks, | |
244 | struct dm_pp_clock_levels_with_latency *clk_level_info, | |
245 | enum dm_pp_clock_type dc_clk_type) | |
246 | { | |
247 | uint32_t i; | |
248 | ||
249 | if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { | |
250 | DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", | |
251 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), | |
252 | pp_clks->num_levels, | |
253 | DM_PP_MAX_CLOCK_LEVELS); | |
254 | ||
255 | clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; | |
256 | } else | |
257 | clk_level_info->num_levels = pp_clks->num_levels; | |
258 | ||
259 | DRM_DEBUG("DM_PPLIB: values for %s clock\n", | |
260 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); | |
261 | ||
262 | for (i = 0; i < clk_level_info->num_levels; i++) { | |
23ec3d14 RZ |
263 | DRM_DEBUG("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); |
264 | clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; | |
f7c1ed34 ML |
265 | clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; |
266 | } | |
267 | } | |
268 | ||
269 | static void pp_to_dc_clock_levels_with_voltage( | |
270 | const struct pp_clock_levels_with_voltage *pp_clks, | |
271 | struct dm_pp_clock_levels_with_voltage *clk_level_info, | |
272 | enum dm_pp_clock_type dc_clk_type) | |
273 | { | |
274 | uint32_t i; | |
275 | ||
276 | if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { | |
277 | DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", | |
278 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), | |
279 | pp_clks->num_levels, | |
280 | DM_PP_MAX_CLOCK_LEVELS); | |
281 | ||
282 | clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; | |
283 | } else | |
284 | clk_level_info->num_levels = pp_clks->num_levels; | |
285 | ||
286 | DRM_INFO("DM_PPLIB: values for %s clock\n", | |
287 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); | |
288 | ||
289 | for (i = 0; i < clk_level_info->num_levels; i++) { | |
23ec3d14 RZ |
290 | DRM_INFO("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); |
291 | clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; | |
f7c1ed34 ML |
292 | clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; |
293 | } | |
294 | } | |
295 | ||
296 | bool dm_pp_get_clock_levels_by_type( | |
297 | const struct dc_context *ctx, | |
298 | enum dm_pp_clock_type clk_type, | |
299 | struct dm_pp_clock_levels *dc_clks) | |
300 | { | |
301 | struct amdgpu_device *adev = ctx->driver_context; | |
302 | void *pp_handle = adev->powerplay.pp_handle; | |
303 | struct amd_pp_clocks pp_clks = { 0 }; | |
304 | struct amd_pp_simple_clock_info validation_clks = { 0 }; | |
305 | uint32_t i; | |
306 | ||
6f059c64 | 307 | if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_clock_by_type) { |
f7c1ed34 ML |
308 | if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle, |
309 | dc_to_pp_clock_type(clk_type), &pp_clks)) { | |
310 | /* Error in pplib. Provide default values. */ | |
311 | get_default_clock_levels(clk_type, dc_clks); | |
312 | return true; | |
313 | } | |
314 | } | |
315 | ||
316 | pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type); | |
317 | ||
6f059c64 | 318 | if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_display_mode_validation_clocks) { |
f7c1ed34 ML |
319 | if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks( |
320 | pp_handle, &validation_clks)) { | |
321 | /* Error in pplib. Provide default values. */ | |
322 | DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); | |
323 | validation_clks.engine_max_clock = 72000; | |
324 | validation_clks.memory_max_clock = 80000; | |
325 | validation_clks.level = 0; | |
326 | } | |
327 | } | |
328 | ||
329 | DRM_INFO("DM_PPLIB: Validation clocks:\n"); | |
330 | DRM_INFO("DM_PPLIB: engine_max_clock: %d\n", | |
331 | validation_clks.engine_max_clock); | |
332 | DRM_INFO("DM_PPLIB: memory_max_clock: %d\n", | |
333 | validation_clks.memory_max_clock); | |
334 | DRM_INFO("DM_PPLIB: level : %d\n", | |
335 | validation_clks.level); | |
336 | ||
337 | /* Translate 10 kHz to kHz. */ | |
338 | validation_clks.engine_max_clock *= 10; | |
339 | validation_clks.memory_max_clock *= 10; | |
340 | ||
341 | /* Determine the highest non-boosted level from the Validation Clocks */ | |
342 | if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { | |
343 | for (i = 0; i < dc_clks->num_levels; i++) { | |
344 | if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) { | |
345 | /* This clock is higher the validation clock. | |
346 | * Than means the previous one is the highest | |
347 | * non-boosted one. */ | |
348 | DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", | |
349 | dc_clks->num_levels, i); | |
350 | dc_clks->num_levels = i > 0 ? i : 1; | |
351 | break; | |
352 | } | |
353 | } | |
354 | } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { | |
355 | for (i = 0; i < dc_clks->num_levels; i++) { | |
356 | if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) { | |
357 | DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", | |
358 | dc_clks->num_levels, i); | |
359 | dc_clks->num_levels = i > 0 ? i : 1; | |
360 | break; | |
361 | } | |
362 | } | |
363 | } | |
364 | ||
365 | return true; | |
366 | } | |
367 | ||
368 | bool dm_pp_get_clock_levels_by_type_with_latency( | |
369 | const struct dc_context *ctx, | |
370 | enum dm_pp_clock_type clk_type, | |
371 | struct dm_pp_clock_levels_with_latency *clk_level_info) | |
372 | { | |
373 | struct amdgpu_device *adev = ctx->driver_context; | |
374 | void *pp_handle = adev->powerplay.pp_handle; | |
375 | struct pp_clock_levels_with_latency pp_clks = { 0 }; | |
376 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; | |
377 | ||
378 | if (!pp_funcs || !pp_funcs->get_clock_by_type_with_latency) | |
379 | return false; | |
380 | ||
381 | if (pp_funcs->get_clock_by_type_with_latency(pp_handle, | |
382 | dc_to_pp_clock_type(clk_type), | |
383 | &pp_clks)) | |
384 | return false; | |
385 | ||
386 | pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type); | |
387 | ||
388 | return true; | |
389 | } | |
390 | ||
391 | bool dm_pp_get_clock_levels_by_type_with_voltage( | |
392 | const struct dc_context *ctx, | |
393 | enum dm_pp_clock_type clk_type, | |
394 | struct dm_pp_clock_levels_with_voltage *clk_level_info) | |
395 | { | |
396 | struct amdgpu_device *adev = ctx->driver_context; | |
397 | void *pp_handle = adev->powerplay.pp_handle; | |
398 | struct pp_clock_levels_with_voltage pp_clk_info = {0}; | |
399 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; | |
400 | ||
6f059c64 RZ |
401 | if (!pp_funcs || !pp_funcs->get_clock_by_type_with_voltage) |
402 | return false; | |
403 | ||
f7c1ed34 ML |
404 | if (pp_funcs->get_clock_by_type_with_voltage(pp_handle, |
405 | dc_to_pp_clock_type(clk_type), | |
406 | &pp_clk_info)) | |
407 | return false; | |
408 | ||
409 | pp_to_dc_clock_levels_with_voltage(&pp_clk_info, clk_level_info, clk_type); | |
410 | ||
411 | return true; | |
412 | } | |
413 | ||
414 | bool dm_pp_notify_wm_clock_changes( | |
415 | const struct dc_context *ctx, | |
416 | struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges) | |
417 | { | |
418 | /* TODO: to be implemented */ | |
419 | return false; | |
420 | } | |
421 | ||
422 | bool dm_pp_apply_power_level_change_request( | |
423 | const struct dc_context *ctx, | |
424 | struct dm_pp_power_level_change_request *level_change_req) | |
425 | { | |
426 | /* TODO: to be implemented */ | |
427 | return false; | |
428 | } | |
429 | ||
430 | bool dm_pp_apply_clock_for_voltage_request( | |
431 | const struct dc_context *ctx, | |
432 | struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) | |
433 | { | |
434 | struct amdgpu_device *adev = ctx->driver_context; | |
435 | struct pp_display_clock_request pp_clock_request = {0}; | |
436 | int ret = 0; | |
437 | ||
438 | pp_clock_request.clock_type = dc_to_pp_clock_type(clock_for_voltage_req->clk_type); | |
439 | pp_clock_request.clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; | |
440 | ||
441 | if (!pp_clock_request.clock_type) | |
442 | return false; | |
443 | ||
6f059c64 | 444 | if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->display_clock_voltage_request) |
f7c1ed34 ML |
445 | ret = adev->powerplay.pp_funcs->display_clock_voltage_request( |
446 | adev->powerplay.pp_handle, | |
447 | &pp_clock_request); | |
448 | if (ret) | |
449 | return false; | |
450 | return true; | |
451 | } | |
452 | ||
453 | bool dm_pp_get_static_clocks( | |
454 | const struct dc_context *ctx, | |
455 | struct dm_pp_static_clock_info *static_clk_info) | |
456 | { | |
457 | struct amdgpu_device *adev = ctx->driver_context; | |
458 | struct amd_pp_clock_info pp_clk_info = {0}; | |
459 | int ret = 0; | |
460 | ||
6f059c64 | 461 | if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_current_clocks) |
f7c1ed34 ML |
462 | ret = adev->powerplay.pp_funcs->get_current_clocks( |
463 | adev->powerplay.pp_handle, | |
464 | &pp_clk_info); | |
465 | if (ret) | |
466 | return false; | |
467 | ||
c2c09ed5 | 468 | static_clk_info->max_clocks_state = pp_to_dc_powerlevel_state(pp_clk_info.max_clocks_state); |
3dbd823e RZ |
469 | static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock * 10; |
470 | static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock * 10; | |
f7c1ed34 ML |
471 | |
472 | return true; | |
473 | } | |
474 | ||
475 | void pp_rv_set_display_requirement(struct pp_smu *pp, | |
476 | struct pp_smu_display_requirement_rv *req) | |
477 | { | |
265f5ba6 | 478 | const struct dc_context *ctx = pp->dm; |
b0a634ac | 479 | struct amdgpu_device *adev = ctx->driver_context; |
9650205a | 480 | void *pp_handle = adev->powerplay.pp_handle; |
b0a634ac | 481 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; |
9650205a | 482 | struct pp_display_clock_request clock = {0}; |
b0a634ac | 483 | |
9650205a | 484 | if (!pp_funcs || !pp_funcs->display_clock_voltage_request) |
b0a634ac | 485 | return; |
f7c1ed34 | 486 | |
9650205a | 487 | clock.clock_type = amd_pp_dcf_clock; |
ba7b267a | 488 | clock.clock_freq_in_khz = req->hard_min_dcefclk_mhz * 1000; |
9650205a RZ |
489 | pp_funcs->display_clock_voltage_request(pp_handle, &clock); |
490 | ||
491 | clock.clock_type = amd_pp_f_clock; | |
ba7b267a | 492 | clock.clock_freq_in_khz = req->hard_min_fclk_mhz * 1000; |
9650205a | 493 | pp_funcs->display_clock_voltage_request(pp_handle, &clock); |
f7c1ed34 ML |
494 | } |
495 | ||
496 | void pp_rv_set_wm_ranges(struct pp_smu *pp, | |
497 | struct pp_smu_wm_range_sets *ranges) | |
498 | { | |
265f5ba6 | 499 | const struct dc_context *ctx = pp->dm; |
b0a634ac RZ |
500 | struct amdgpu_device *adev = ctx->driver_context; |
501 | void *pp_handle = adev->powerplay.pp_handle; | |
502 | const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; | |
503 | struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; | |
504 | struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = wm_with_clock_ranges.wm_dmif_clocks_ranges; | |
505 | struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = wm_with_clock_ranges.wm_mcif_clocks_ranges; | |
506 | int32_t i; | |
f7c1ed34 | 507 | |
b0a634ac RZ |
508 | wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets; |
509 | wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets; | |
f7c1ed34 | 510 | |
6f059c64 RZ |
511 | if (!pp_funcs || !pp_funcs->set_watermarks_for_clocks_ranges) |
512 | return; | |
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 = |
ba7b267a | 521 | ranges->reader_wm_sets[i].max_drain_clk_mhz * 1000; |
b0a634ac | 522 | wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz = |
ba7b267a | 523 | ranges->reader_wm_sets[i].min_drain_clk_mhz * 1000; |
b0a634ac | 524 | wm_dce_clocks[i].wm_max_mem_clk_in_khz = |
ba7b267a | 525 | ranges->reader_wm_sets[i].max_fill_clk_mhz * 1000; |
b0a634ac | 526 | wm_dce_clocks[i].wm_min_mem_clk_in_khz = |
ba7b267a | 527 | ranges->reader_wm_sets[i].min_fill_clk_mhz * 1000; |
f7c1ed34 ML |
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 = |
ba7b267a | 537 | ranges->writer_wm_sets[i].max_fill_clk_mhz * 1000; |
b0a634ac | 538 | wm_soc_clocks[i].wm_min_socclk_clk_in_khz = |
ba7b267a | 539 | ranges->writer_wm_sets[i].min_fill_clk_mhz * 1000; |
b0a634ac | 540 | wm_soc_clocks[i].wm_max_mem_clk_in_khz = |
ba7b267a | 541 | ranges->writer_wm_sets[i].max_drain_clk_mhz * 1000; |
b0a634ac | 542 | wm_soc_clocks[i].wm_min_mem_clk_in_khz = |
ba7b267a | 543 | ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000; |
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 | { | |
265f5ba6 | 551 | const struct dc_context *ctx = pp->dm; |
b0a634ac RZ |
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 | { | |
265f5ba6 | 566 | funcs->pp_smu.dm = ctx; |
f7c1ed34 ML |
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 | } |