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 | ||
fcd70cd3 | 27 | #include <drm/drm_probe_helper.h> |
f7c1ed34 ML |
28 | #include <drm/amdgpu_drm.h> |
29 | #include "dm_services.h" | |
30 | #include "amdgpu.h" | |
31 | #include "amdgpu_dm.h" | |
32 | #include "amdgpu_dm_irq.h" | |
33 | #include "amdgpu_pm.h" | |
34 | #include "dm_pp_smu.h" | |
f7c1ed34 ML |
35 | |
36 | bool dm_pp_apply_display_requirements( | |
37 | const struct dc_context *ctx, | |
38 | const struct dm_pp_display_configuration *pp_display_cfg) | |
39 | { | |
40 | struct amdgpu_device *adev = ctx->driver_context; | |
d4d5eace | 41 | int i; |
f7c1ed34 ML |
42 | |
43 | if (adev->pm.dpm_enabled) { | |
44 | ||
45 | memset(&adev->pm.pm_display_cfg, 0, | |
46 | sizeof(adev->pm.pm_display_cfg)); | |
47 | ||
48 | adev->pm.pm_display_cfg.cpu_cc6_disable = | |
49 | pp_display_cfg->cpu_cc6_disable; | |
50 | ||
51 | adev->pm.pm_display_cfg.cpu_pstate_disable = | |
52 | pp_display_cfg->cpu_pstate_disable; | |
53 | ||
54 | adev->pm.pm_display_cfg.cpu_pstate_separation_time = | |
55 | pp_display_cfg->cpu_pstate_separation_time; | |
56 | ||
57 | adev->pm.pm_display_cfg.nb_pstate_switch_disable = | |
58 | pp_display_cfg->nb_pstate_switch_disable; | |
59 | ||
60 | adev->pm.pm_display_cfg.num_display = | |
61 | pp_display_cfg->display_count; | |
62 | adev->pm.pm_display_cfg.num_path_including_non_display = | |
63 | pp_display_cfg->display_count; | |
64 | ||
65 | adev->pm.pm_display_cfg.min_core_set_clock = | |
66 | pp_display_cfg->min_engine_clock_khz/10; | |
67 | adev->pm.pm_display_cfg.min_core_set_clock_in_sr = | |
68 | pp_display_cfg->min_engine_clock_deep_sleep_khz/10; | |
69 | adev->pm.pm_display_cfg.min_mem_set_clock = | |
70 | pp_display_cfg->min_memory_clock_khz/10; | |
71 | ||
3180fb67 | 72 | adev->pm.pm_display_cfg.min_dcef_deep_sleep_set_clk = |
73 | pp_display_cfg->min_engine_clock_deep_sleep_khz/10; | |
74 | adev->pm.pm_display_cfg.min_dcef_set_clk = | |
75 | pp_display_cfg->min_dcfclock_khz/10; | |
76 | ||
f7c1ed34 ML |
77 | adev->pm.pm_display_cfg.multi_monitor_in_sync = |
78 | pp_display_cfg->all_displays_in_sync; | |
79 | adev->pm.pm_display_cfg.min_vblank_time = | |
80 | pp_display_cfg->avail_mclk_switch_time_us; | |
81 | ||
82 | adev->pm.pm_display_cfg.display_clk = | |
83 | pp_display_cfg->disp_clk_khz/10; | |
84 | ||
85 | adev->pm.pm_display_cfg.dce_tolerable_mclk_in_active_latency = | |
86 | pp_display_cfg->avail_mclk_switch_time_in_disp_active_us; | |
87 | ||
88 | adev->pm.pm_display_cfg.crtc_index = pp_display_cfg->crtc_index; | |
89 | adev->pm.pm_display_cfg.line_time_in_us = | |
90 | pp_display_cfg->line_time_in_us; | |
91 | ||
92 | adev->pm.pm_display_cfg.vrefresh = pp_display_cfg->disp_configs[0].v_refresh; | |
93 | adev->pm.pm_display_cfg.crossfire_display_index = -1; | |
94 | adev->pm.pm_display_cfg.min_bus_bandwidth = 0; | |
95 | ||
d4d5eace | 96 | for (i = 0; i < pp_display_cfg->display_count; i++) { |
97 | const struct dm_pp_single_disp_config *dc_cfg = | |
98 | &pp_display_cfg->disp_configs[i]; | |
99 | adev->pm.pm_display_cfg.displays[i].controller_id = dc_cfg->pipe_idx + 1; | |
100 | } | |
101 | ||
13f5dbd6 | 102 | amdgpu_dpm_display_configuration_change(adev, &adev->pm.pm_display_cfg); |
40d0ebd9 | 103 | |
84176663 | 104 | amdgpu_dpm_compute_clocks(adev); |
f7c1ed34 ML |
105 | } |
106 | ||
107 | return true; | |
108 | } | |
109 | ||
110 | static void get_default_clock_levels( | |
111 | enum dm_pp_clock_type clk_type, | |
112 | struct dm_pp_clock_levels *clks) | |
113 | { | |
114 | uint32_t disp_clks_in_khz[6] = { | |
115 | 300000, 400000, 496560, 626090, 685720, 757900 }; | |
116 | uint32_t sclks_in_khz[6] = { | |
117 | 300000, 360000, 423530, 514290, 626090, 720000 }; | |
118 | uint32_t mclks_in_khz[2] = { 333000, 800000 }; | |
119 | ||
120 | switch (clk_type) { | |
121 | case DM_PP_CLOCK_TYPE_DISPLAY_CLK: | |
122 | clks->num_levels = 6; | |
123 | memmove(clks->clocks_in_khz, disp_clks_in_khz, | |
124 | sizeof(disp_clks_in_khz)); | |
125 | break; | |
126 | case DM_PP_CLOCK_TYPE_ENGINE_CLK: | |
127 | clks->num_levels = 6; | |
128 | memmove(clks->clocks_in_khz, sclks_in_khz, | |
129 | sizeof(sclks_in_khz)); | |
130 | break; | |
131 | case DM_PP_CLOCK_TYPE_MEMORY_CLK: | |
132 | clks->num_levels = 2; | |
133 | memmove(clks->clocks_in_khz, mclks_in_khz, | |
134 | sizeof(mclks_in_khz)); | |
135 | break; | |
136 | default: | |
137 | clks->num_levels = 0; | |
138 | break; | |
139 | } | |
140 | } | |
141 | ||
142 | static enum amd_pp_clock_type dc_to_pp_clock_type( | |
143 | enum dm_pp_clock_type dm_pp_clk_type) | |
144 | { | |
145 | enum amd_pp_clock_type amd_pp_clk_type = 0; | |
146 | ||
147 | switch (dm_pp_clk_type) { | |
148 | case DM_PP_CLOCK_TYPE_DISPLAY_CLK: | |
149 | amd_pp_clk_type = amd_pp_disp_clock; | |
150 | break; | |
151 | case DM_PP_CLOCK_TYPE_ENGINE_CLK: | |
152 | amd_pp_clk_type = amd_pp_sys_clock; | |
153 | break; | |
154 | case DM_PP_CLOCK_TYPE_MEMORY_CLK: | |
155 | amd_pp_clk_type = amd_pp_mem_clock; | |
156 | break; | |
157 | case DM_PP_CLOCK_TYPE_DCEFCLK: | |
158 | amd_pp_clk_type = amd_pp_dcef_clock; | |
159 | break; | |
160 | case DM_PP_CLOCK_TYPE_DCFCLK: | |
161 | amd_pp_clk_type = amd_pp_dcf_clock; | |
162 | break; | |
163 | case DM_PP_CLOCK_TYPE_PIXELCLK: | |
164 | amd_pp_clk_type = amd_pp_pixel_clock; | |
165 | break; | |
166 | case DM_PP_CLOCK_TYPE_FCLK: | |
167 | amd_pp_clk_type = amd_pp_f_clock; | |
168 | break; | |
169 | case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: | |
66917e56 | 170 | amd_pp_clk_type = amd_pp_phy_clock; |
171 | break; | |
172 | case DM_PP_CLOCK_TYPE_DPPCLK: | |
f7c1ed34 ML |
173 | amd_pp_clk_type = amd_pp_dpp_clock; |
174 | break; | |
175 | default: | |
176 | DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", | |
177 | dm_pp_clk_type); | |
178 | break; | |
179 | } | |
180 | ||
181 | return amd_pp_clk_type; | |
182 | } | |
183 | ||
c2c09ed5 ML |
184 | static enum dm_pp_clocks_state pp_to_dc_powerlevel_state( |
185 | enum PP_DAL_POWERLEVEL max_clocks_state) | |
186 | { | |
187 | switch (max_clocks_state) { | |
188 | case PP_DAL_POWERLEVEL_0: | |
189 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_0; | |
190 | case PP_DAL_POWERLEVEL_1: | |
191 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_1; | |
192 | case PP_DAL_POWERLEVEL_2: | |
193 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_2; | |
194 | case PP_DAL_POWERLEVEL_3: | |
195 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_3; | |
196 | case PP_DAL_POWERLEVEL_4: | |
197 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_4; | |
198 | case PP_DAL_POWERLEVEL_5: | |
199 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_5; | |
200 | case PP_DAL_POWERLEVEL_6: | |
201 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_6; | |
202 | case PP_DAL_POWERLEVEL_7: | |
203 | return DM_PP_CLOCKS_DPM_STATE_LEVEL_7; | |
204 | default: | |
205 | DRM_ERROR("DM_PPLIB: invalid powerlevel state: %d!\n", | |
206 | max_clocks_state); | |
207 | return DM_PP_CLOCKS_STATE_INVALID; | |
208 | } | |
209 | } | |
210 | ||
f7c1ed34 ML |
211 | static void pp_to_dc_clock_levels( |
212 | const struct amd_pp_clocks *pp_clks, | |
213 | struct dm_pp_clock_levels *dc_clks, | |
214 | enum dm_pp_clock_type dc_clk_type) | |
215 | { | |
216 | uint32_t i; | |
217 | ||
218 | if (pp_clks->count > DM_PP_MAX_CLOCK_LEVELS) { | |
219 | DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", | |
220 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), | |
221 | pp_clks->count, | |
222 | DM_PP_MAX_CLOCK_LEVELS); | |
223 | ||
224 | dc_clks->num_levels = DM_PP_MAX_CLOCK_LEVELS; | |
225 | } else | |
226 | dc_clks->num_levels = pp_clks->count; | |
227 | ||
228 | DRM_INFO("DM_PPLIB: values for %s clock\n", | |
229 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); | |
230 | ||
231 | for (i = 0; i < dc_clks->num_levels; i++) { | |
232 | DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]); | |
23ec3d14 | 233 | dc_clks->clocks_in_khz[i] = pp_clks->clock[i]; |
f7c1ed34 ML |
234 | } |
235 | } | |
236 | ||
237 | static void pp_to_dc_clock_levels_with_latency( | |
238 | const struct pp_clock_levels_with_latency *pp_clks, | |
239 | struct dm_pp_clock_levels_with_latency *clk_level_info, | |
240 | enum dm_pp_clock_type dc_clk_type) | |
241 | { | |
242 | uint32_t i; | |
243 | ||
244 | if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { | |
245 | DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", | |
246 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), | |
247 | pp_clks->num_levels, | |
248 | DM_PP_MAX_CLOCK_LEVELS); | |
249 | ||
250 | clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; | |
251 | } else | |
252 | clk_level_info->num_levels = pp_clks->num_levels; | |
253 | ||
254 | DRM_DEBUG("DM_PPLIB: values for %s clock\n", | |
255 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); | |
256 | ||
257 | for (i = 0; i < clk_level_info->num_levels; i++) { | |
23ec3d14 RZ |
258 | DRM_DEBUG("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); |
259 | clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; | |
f7c1ed34 ML |
260 | clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; |
261 | } | |
262 | } | |
263 | ||
264 | static void pp_to_dc_clock_levels_with_voltage( | |
265 | const struct pp_clock_levels_with_voltage *pp_clks, | |
266 | struct dm_pp_clock_levels_with_voltage *clk_level_info, | |
267 | enum dm_pp_clock_type dc_clk_type) | |
268 | { | |
269 | uint32_t i; | |
270 | ||
271 | if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { | |
272 | DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", | |
273 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), | |
274 | pp_clks->num_levels, | |
275 | DM_PP_MAX_CLOCK_LEVELS); | |
276 | ||
277 | clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; | |
278 | } else | |
279 | clk_level_info->num_levels = pp_clks->num_levels; | |
280 | ||
281 | DRM_INFO("DM_PPLIB: values for %s clock\n", | |
282 | DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); | |
283 | ||
284 | for (i = 0; i < clk_level_info->num_levels; i++) { | |
5f0f531c PM |
285 | DRM_INFO("DM_PPLIB:\t %d in kHz, %d in mV\n", pp_clks->data[i].clocks_in_khz, |
286 | pp_clks->data[i].voltage_in_mv); | |
23ec3d14 | 287 | clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; |
f7c1ed34 ML |
288 | clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; |
289 | } | |
290 | } | |
291 | ||
292 | bool dm_pp_get_clock_levels_by_type( | |
293 | const struct dc_context *ctx, | |
294 | enum dm_pp_clock_type clk_type, | |
295 | struct dm_pp_clock_levels *dc_clks) | |
296 | { | |
297 | struct amdgpu_device *adev = ctx->driver_context; | |
f7c1ed34 ML |
298 | struct amd_pp_clocks pp_clks = { 0 }; |
299 | struct amd_pp_simple_clock_info validation_clks = { 0 }; | |
300 | uint32_t i; | |
301 | ||
13f5dbd6 EQ |
302 | if (amdgpu_dpm_get_clock_by_type(adev, |
303 | dc_to_pp_clock_type(clk_type), &pp_clks)) { | |
304 | /* Error in pplib. Provide default values. */ | |
305 | get_default_clock_levels(clk_type, dc_clks); | |
306 | return true; | |
f7c1ed34 ML |
307 | } |
308 | ||
309 | pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type); | |
310 | ||
13f5dbd6 EQ |
311 | if (amdgpu_dpm_get_display_mode_validation_clks(adev, &validation_clks)) { |
312 | /* Error in pplib. Provide default values. */ | |
313 | DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); | |
314 | validation_clks.engine_max_clock = 72000; | |
315 | validation_clks.memory_max_clock = 80000; | |
316 | validation_clks.level = 0; | |
f7c1ed34 ML |
317 | } |
318 | ||
319 | DRM_INFO("DM_PPLIB: Validation clocks:\n"); | |
320 | DRM_INFO("DM_PPLIB: engine_max_clock: %d\n", | |
321 | validation_clks.engine_max_clock); | |
322 | DRM_INFO("DM_PPLIB: memory_max_clock: %d\n", | |
323 | validation_clks.memory_max_clock); | |
324 | DRM_INFO("DM_PPLIB: level : %d\n", | |
325 | validation_clks.level); | |
326 | ||
327 | /* Translate 10 kHz to kHz. */ | |
328 | validation_clks.engine_max_clock *= 10; | |
329 | validation_clks.memory_max_clock *= 10; | |
330 | ||
331 | /* Determine the highest non-boosted level from the Validation Clocks */ | |
332 | if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { | |
333 | for (i = 0; i < dc_clks->num_levels; i++) { | |
334 | if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) { | |
335 | /* This clock is higher the validation clock. | |
336 | * Than means the previous one is the highest | |
337 | * non-boosted one. */ | |
338 | DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", | |
339 | dc_clks->num_levels, i); | |
340 | dc_clks->num_levels = i > 0 ? i : 1; | |
341 | break; | |
342 | } | |
343 | } | |
344 | } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { | |
345 | for (i = 0; i < dc_clks->num_levels; i++) { | |
346 | if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) { | |
347 | DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", | |
348 | dc_clks->num_levels, i); | |
349 | dc_clks->num_levels = i > 0 ? i : 1; | |
350 | break; | |
351 | } | |
352 | } | |
353 | } | |
354 | ||
355 | return true; | |
356 | } | |
357 | ||
358 | bool dm_pp_get_clock_levels_by_type_with_latency( | |
359 | const struct dc_context *ctx, | |
360 | enum dm_pp_clock_type clk_type, | |
361 | struct dm_pp_clock_levels_with_latency *clk_level_info) | |
362 | { | |
363 | struct amdgpu_device *adev = ctx->driver_context; | |
f7c1ed34 | 364 | struct pp_clock_levels_with_latency pp_clks = { 0 }; |
e5e4e223 HR |
365 | int ret; |
366 | ||
13f5dbd6 EQ |
367 | ret = amdgpu_dpm_get_clock_by_type_with_latency(adev, |
368 | dc_to_pp_clock_type(clk_type), | |
369 | &pp_clks); | |
370 | if (ret) | |
371 | return false; | |
f7c1ed34 | 372 | |
f7c1ed34 ML |
373 | pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type); |
374 | ||
375 | return true; | |
376 | } | |
377 | ||
378 | bool dm_pp_get_clock_levels_by_type_with_voltage( | |
379 | const struct dc_context *ctx, | |
380 | enum dm_pp_clock_type clk_type, | |
381 | struct dm_pp_clock_levels_with_voltage *clk_level_info) | |
382 | { | |
383 | struct amdgpu_device *adev = ctx->driver_context; | |
f7c1ed34 | 384 | struct pp_clock_levels_with_voltage pp_clk_info = {0}; |
1e33d4d4 | 385 | int ret; |
f7c1ed34 | 386 | |
13f5dbd6 EQ |
387 | ret = amdgpu_dpm_get_clock_by_type_with_voltage(adev, |
388 | dc_to_pp_clock_type(clk_type), | |
389 | &pp_clk_info); | |
390 | if (ret) | |
391 | return false; | |
f7c1ed34 ML |
392 | |
393 | pp_to_dc_clock_levels_with_voltage(&pp_clk_info, clk_level_info, clk_type); | |
394 | ||
395 | return true; | |
396 | } | |
397 | ||
398 | bool dm_pp_notify_wm_clock_changes( | |
399 | const struct dc_context *ctx, | |
400 | struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges) | |
401 | { | |
b03fd3e7 | 402 | struct amdgpu_device *adev = ctx->driver_context; |
b03fd3e7 | 403 | |
adc9da64 EQ |
404 | /* |
405 | * Limit this watermark setting for Polaris for now | |
406 | * TODO: expand this to other ASICs | |
407 | */ | |
13f5dbd6 EQ |
408 | if ((adev->asic_type >= CHIP_POLARIS10) && |
409 | (adev->asic_type <= CHIP_VEGAM) && | |
410 | !amdgpu_dpm_set_watermarks_for_clocks_ranges(adev, | |
b03fd3e7 EQ |
411 | (void *)wm_with_clock_ranges)) |
412 | return true; | |
b03fd3e7 | 413 | |
f7c1ed34 ML |
414 | return false; |
415 | } | |
416 | ||
417 | bool dm_pp_apply_power_level_change_request( | |
418 | const struct dc_context *ctx, | |
419 | struct dm_pp_power_level_change_request *level_change_req) | |
420 | { | |
421 | /* TODO: to be implemented */ | |
422 | return false; | |
423 | } | |
424 | ||
425 | bool dm_pp_apply_clock_for_voltage_request( | |
426 | const struct dc_context *ctx, | |
427 | struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) | |
428 | { | |
429 | struct amdgpu_device *adev = ctx->driver_context; | |
430 | struct pp_display_clock_request pp_clock_request = {0}; | |
431 | int ret = 0; | |
432 | ||
433 | pp_clock_request.clock_type = dc_to_pp_clock_type(clock_for_voltage_req->clk_type); | |
434 | pp_clock_request.clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; | |
435 | ||
436 | if (!pp_clock_request.clock_type) | |
437 | return false; | |
438 | ||
13f5dbd6 EQ |
439 | ret = amdgpu_dpm_display_clock_voltage_request(adev, &pp_clock_request); |
440 | if (ret && (ret != -EOPNOTSUPP)) | |
f7c1ed34 | 441 | return false; |
13f5dbd6 | 442 | |
f7c1ed34 ML |
443 | return true; |
444 | } | |
445 | ||
446 | bool dm_pp_get_static_clocks( | |
447 | const struct dc_context *ctx, | |
448 | struct dm_pp_static_clock_info *static_clk_info) | |
449 | { | |
450 | struct amdgpu_device *adev = ctx->driver_context; | |
451 | struct amd_pp_clock_info pp_clk_info = {0}; | |
f7c1ed34 | 452 | |
13f5dbd6 | 453 | if (amdgpu_dpm_get_current_clocks(adev, &pp_clk_info)) |
f7c1ed34 ML |
454 | return false; |
455 | ||
c2c09ed5 | 456 | static_clk_info->max_clocks_state = pp_to_dc_powerlevel_state(pp_clk_info.max_clocks_state); |
3dbd823e RZ |
457 | static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock * 10; |
458 | static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock * 10; | |
f7c1ed34 ML |
459 | |
460 | return true; | |
461 | } | |
462 | ||
3d3e9cdd | 463 | static void pp_rv_set_wm_ranges(struct pp_smu *pp, |
f7c1ed34 ML |
464 | struct pp_smu_wm_range_sets *ranges) |
465 | { | |
265f5ba6 | 466 | const struct dc_context *ctx = pp->dm; |
b0a634ac | 467 | struct amdgpu_device *adev = ctx->driver_context; |
b0a634ac RZ |
468 | struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; |
469 | struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = wm_with_clock_ranges.wm_dmif_clocks_ranges; | |
470 | struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = wm_with_clock_ranges.wm_mcif_clocks_ranges; | |
471 | int32_t i; | |
f7c1ed34 | 472 | |
b0a634ac RZ |
473 | wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets; |
474 | wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets; | |
f7c1ed34 | 475 | |
b0a634ac | 476 | for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) { |
f7c1ed34 | 477 | if (ranges->reader_wm_sets[i].wm_inst > 3) |
b0a634ac | 478 | wm_dce_clocks[i].wm_set_id = WM_SET_A; |
f7c1ed34 | 479 | else |
b0a634ac | 480 | wm_dce_clocks[i].wm_set_id = |
f7c1ed34 | 481 | ranges->reader_wm_sets[i].wm_inst; |
b0a634ac | 482 | wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz = |
ba7b267a | 483 | ranges->reader_wm_sets[i].max_drain_clk_mhz * 1000; |
b0a634ac | 484 | wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz = |
ba7b267a | 485 | ranges->reader_wm_sets[i].min_drain_clk_mhz * 1000; |
b0a634ac | 486 | wm_dce_clocks[i].wm_max_mem_clk_in_khz = |
ba7b267a | 487 | ranges->reader_wm_sets[i].max_fill_clk_mhz * 1000; |
b0a634ac | 488 | wm_dce_clocks[i].wm_min_mem_clk_in_khz = |
ba7b267a | 489 | ranges->reader_wm_sets[i].min_fill_clk_mhz * 1000; |
f7c1ed34 ML |
490 | } |
491 | ||
b0a634ac | 492 | for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) { |
f7c1ed34 | 493 | if (ranges->writer_wm_sets[i].wm_inst > 3) |
b0a634ac | 494 | wm_soc_clocks[i].wm_set_id = WM_SET_A; |
f7c1ed34 | 495 | else |
b0a634ac | 496 | wm_soc_clocks[i].wm_set_id = |
f7c1ed34 | 497 | ranges->writer_wm_sets[i].wm_inst; |
b0a634ac | 498 | wm_soc_clocks[i].wm_max_socclk_clk_in_khz = |
ba7b267a | 499 | ranges->writer_wm_sets[i].max_fill_clk_mhz * 1000; |
b0a634ac | 500 | wm_soc_clocks[i].wm_min_socclk_clk_in_khz = |
ba7b267a | 501 | ranges->writer_wm_sets[i].min_fill_clk_mhz * 1000; |
b0a634ac | 502 | wm_soc_clocks[i].wm_max_mem_clk_in_khz = |
ba7b267a | 503 | ranges->writer_wm_sets[i].max_drain_clk_mhz * 1000; |
b0a634ac | 504 | wm_soc_clocks[i].wm_min_mem_clk_in_khz = |
ba7b267a | 505 | ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000; |
f7c1ed34 ML |
506 | } |
507 | ||
13f5dbd6 EQ |
508 | amdgpu_dpm_set_watermarks_for_clocks_ranges(adev, |
509 | &wm_with_clock_ranges); | |
f7c1ed34 ML |
510 | } |
511 | ||
3d3e9cdd | 512 | static void pp_rv_set_pme_wa_enable(struct pp_smu *pp) |
f7c1ed34 | 513 | { |
265f5ba6 | 514 | const struct dc_context *ctx = pp->dm; |
b0a634ac | 515 | struct amdgpu_device *adev = ctx->driver_context; |
b0a634ac | 516 | |
13f5dbd6 | 517 | amdgpu_dpm_notify_smu_enable_pwe(adev); |
f7c1ed34 ML |
518 | } |
519 | ||
3d3e9cdd | 520 | static void pp_rv_set_active_display_count(struct pp_smu *pp, int count) |
588715bd | 521 | { |
522 | const struct dc_context *ctx = pp->dm; | |
523 | struct amdgpu_device *adev = ctx->driver_context; | |
588715bd | 524 | |
13f5dbd6 | 525 | amdgpu_dpm_set_active_display_count(adev, count); |
588715bd | 526 | } |
527 | ||
3d3e9cdd | 528 | static void pp_rv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int clock) |
588715bd | 529 | { |
530 | const struct dc_context *ctx = pp->dm; | |
531 | struct amdgpu_device *adev = ctx->driver_context; | |
588715bd | 532 | |
13f5dbd6 | 533 | amdgpu_dpm_set_min_deep_sleep_dcefclk(adev, clock); |
588715bd | 534 | } |
535 | ||
3d3e9cdd | 536 | static void pp_rv_set_hard_min_dcefclk_by_freq(struct pp_smu *pp, int clock) |
588715bd | 537 | { |
538 | const struct dc_context *ctx = pp->dm; | |
539 | struct amdgpu_device *adev = ctx->driver_context; | |
588715bd | 540 | |
13f5dbd6 | 541 | amdgpu_dpm_set_hard_min_dcefclk_by_freq(adev, clock); |
588715bd | 542 | } |
543 | ||
3d3e9cdd | 544 | static void pp_rv_set_hard_min_fclk_by_freq(struct pp_smu *pp, int mhz) |
588715bd | 545 | { |
546 | const struct dc_context *ctx = pp->dm; | |
547 | struct amdgpu_device *adev = ctx->driver_context; | |
588715bd | 548 | |
13f5dbd6 | 549 | amdgpu_dpm_set_hard_min_fclk_by_freq(adev, mhz); |
588715bd | 550 | } |
551 | ||
dfd84d90 | 552 | static enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp, |
79a7b060 | 553 | struct pp_smu_wm_range_sets *ranges) |
554 | { | |
555 | const struct dc_context *ctx = pp->dm; | |
556 | struct amdgpu_device *adev = ctx->driver_context; | |
79a7b060 | 557 | |
13f5dbd6 | 558 | amdgpu_dpm_set_watermarks_for_clocks_ranges(adev, ranges); |
79a7b060 | 559 | |
560 | return PP_SMU_RESULT_OK; | |
561 | } | |
562 | ||
dfd84d90 | 563 | static enum pp_smu_status pp_nv_set_display_count(struct pp_smu *pp, int count) |
79a7b060 | 564 | { |
565 | const struct dc_context *ctx = pp->dm; | |
566 | struct amdgpu_device *adev = ctx->driver_context; | |
13f5dbd6 | 567 | int ret = 0; |
79a7b060 | 568 | |
13f5dbd6 EQ |
569 | ret = amdgpu_dpm_set_active_display_count(adev, count); |
570 | if (ret == -EOPNOTSUPP) | |
79a7b060 | 571 | return PP_SMU_RESULT_UNSUPPORTED; |
13f5dbd6 EQ |
572 | else if (ret) |
573 | /* 0: successful or smu.ppt_funcs->set_display_count = NULL; 1: fail */ | |
79a7b060 | 574 | return PP_SMU_RESULT_FAIL; |
575 | ||
576 | return PP_SMU_RESULT_OK; | |
577 | } | |
578 | ||
dfd84d90 ND |
579 | static enum pp_smu_status |
580 | pp_nv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int mhz) | |
79a7b060 | 581 | { |
582 | const struct dc_context *ctx = pp->dm; | |
583 | struct amdgpu_device *adev = ctx->driver_context; | |
13f5dbd6 | 584 | int ret = 0; |
79a7b060 | 585 | |
6c45e480 | 586 | /* 0: successful or smu.ppt_funcs->set_deep_sleep_dcefclk = NULL;1: fail */ |
13f5dbd6 EQ |
587 | ret = amdgpu_dpm_set_min_deep_sleep_dcefclk(adev, mhz); |
588 | if (ret == -EOPNOTSUPP) | |
589 | return PP_SMU_RESULT_UNSUPPORTED; | |
590 | else if (ret) | |
79a7b060 | 591 | return PP_SMU_RESULT_FAIL; |
592 | ||
593 | return PP_SMU_RESULT_OK; | |
594 | } | |
595 | ||
dfd84d90 | 596 | static enum pp_smu_status pp_nv_set_hard_min_dcefclk_by_freq( |
79a7b060 | 597 | struct pp_smu *pp, int mhz) |
598 | { | |
599 | const struct dc_context *ctx = pp->dm; | |
600 | struct amdgpu_device *adev = ctx->driver_context; | |
79a7b060 | 601 | struct pp_display_clock_request clock_req; |
13f5dbd6 | 602 | int ret = 0; |
79a7b060 | 603 | |
604 | clock_req.clock_type = amd_pp_dcef_clock; | |
605 | clock_req.clock_freq_in_khz = mhz * 1000; | |
606 | ||
6c45e480 | 607 | /* 0: successful or smu.ppt_funcs->display_clock_voltage_request = NULL |
79a7b060 | 608 | * 1: fail |
609 | */ | |
13f5dbd6 EQ |
610 | ret = amdgpu_dpm_display_clock_voltage_request(adev, &clock_req); |
611 | if (ret == -EOPNOTSUPP) | |
612 | return PP_SMU_RESULT_UNSUPPORTED; | |
613 | else if (ret) | |
79a7b060 | 614 | return PP_SMU_RESULT_FAIL; |
615 | ||
616 | return PP_SMU_RESULT_OK; | |
617 | } | |
618 | ||
dfd84d90 ND |
619 | static enum pp_smu_status |
620 | pp_nv_set_hard_min_uclk_by_freq(struct pp_smu *pp, int mhz) | |
79a7b060 | 621 | { |
622 | const struct dc_context *ctx = pp->dm; | |
623 | struct amdgpu_device *adev = ctx->driver_context; | |
79a7b060 | 624 | struct pp_display_clock_request clock_req; |
13f5dbd6 | 625 | int ret = 0; |
79a7b060 | 626 | |
627 | clock_req.clock_type = amd_pp_mem_clock; | |
628 | clock_req.clock_freq_in_khz = mhz * 1000; | |
629 | ||
6c45e480 | 630 | /* 0: successful or smu.ppt_funcs->display_clock_voltage_request = NULL |
79a7b060 | 631 | * 1: fail |
632 | */ | |
13f5dbd6 EQ |
633 | ret = amdgpu_dpm_display_clock_voltage_request(adev, &clock_req); |
634 | if (ret == -EOPNOTSUPP) | |
635 | return PP_SMU_RESULT_UNSUPPORTED; | |
636 | else if (ret) | |
79a7b060 | 637 | return PP_SMU_RESULT_FAIL; |
638 | ||
639 | return PP_SMU_RESULT_OK; | |
640 | } | |
641 | ||
dfd84d90 | 642 | static enum pp_smu_status pp_nv_set_pstate_handshake_support( |
26652cd8 | 643 | struct pp_smu *pp, bool pstate_handshake_supported) |
6e92e156 KF |
644 | { |
645 | const struct dc_context *ctx = pp->dm; | |
646 | struct amdgpu_device *adev = ctx->driver_context; | |
6e92e156 | 647 | |
13f5dbd6 EQ |
648 | if (amdgpu_dpm_display_disable_memory_clock_switch(adev, |
649 | !pstate_handshake_supported)) | |
650 | return PP_SMU_RESULT_FAIL; | |
6e92e156 KF |
651 | |
652 | return PP_SMU_RESULT_OK; | |
653 | } | |
654 | ||
dfd84d90 | 655 | static enum pp_smu_status pp_nv_set_voltage_by_freq(struct pp_smu *pp, |
79a7b060 | 656 | enum pp_smu_nv_clock_id clock_id, int mhz) |
657 | { | |
658 | const struct dc_context *ctx = pp->dm; | |
659 | struct amdgpu_device *adev = ctx->driver_context; | |
79a7b060 | 660 | struct pp_display_clock_request clock_req; |
13f5dbd6 | 661 | int ret = 0; |
79a7b060 | 662 | |
663 | switch (clock_id) { | |
664 | case PP_SMU_NV_DISPCLK: | |
665 | clock_req.clock_type = amd_pp_disp_clock; | |
666 | break; | |
667 | case PP_SMU_NV_PHYCLK: | |
668 | clock_req.clock_type = amd_pp_phy_clock; | |
669 | break; | |
670 | case PP_SMU_NV_PIXELCLK: | |
671 | clock_req.clock_type = amd_pp_pixel_clock; | |
672 | break; | |
673 | default: | |
674 | break; | |
675 | } | |
676 | clock_req.clock_freq_in_khz = mhz * 1000; | |
677 | ||
6c45e480 | 678 | /* 0: successful or smu.ppt_funcs->display_clock_voltage_request = NULL |
79a7b060 | 679 | * 1: fail |
680 | */ | |
13f5dbd6 EQ |
681 | ret = amdgpu_dpm_display_clock_voltage_request(adev, &clock_req); |
682 | if (ret == -EOPNOTSUPP) | |
683 | return PP_SMU_RESULT_UNSUPPORTED; | |
684 | else if (ret) | |
79a7b060 | 685 | return PP_SMU_RESULT_FAIL; |
686 | ||
687 | return PP_SMU_RESULT_OK; | |
688 | } | |
689 | ||
dfd84d90 | 690 | static enum pp_smu_status pp_nv_get_maximum_sustainable_clocks( |
79a7b060 | 691 | struct pp_smu *pp, struct pp_smu_nv_clock_table *max_clocks) |
692 | { | |
693 | const struct dc_context *ctx = pp->dm; | |
694 | struct amdgpu_device *adev = ctx->driver_context; | |
13f5dbd6 | 695 | int ret = 0; |
79a7b060 | 696 | |
13f5dbd6 EQ |
697 | ret = amdgpu_dpm_get_max_sustainable_clocks_by_dc(adev, |
698 | max_clocks); | |
699 | if (ret == -EOPNOTSUPP) | |
79a7b060 | 700 | return PP_SMU_RESULT_UNSUPPORTED; |
13f5dbd6 EQ |
701 | else if (ret) |
702 | return PP_SMU_RESULT_FAIL; | |
79a7b060 | 703 | |
13f5dbd6 | 704 | return PP_SMU_RESULT_OK; |
79a7b060 | 705 | } |
706 | ||
dfd84d90 | 707 | static enum pp_smu_status pp_nv_get_uclk_dpm_states(struct pp_smu *pp, |
79a7b060 | 708 | unsigned int *clock_values_in_khz, unsigned int *num_states) |
709 | { | |
710 | const struct dc_context *ctx = pp->dm; | |
711 | struct amdgpu_device *adev = ctx->driver_context; | |
13f5dbd6 | 712 | int ret = 0; |
79a7b060 | 713 | |
13f5dbd6 EQ |
714 | ret = amdgpu_dpm_get_uclk_dpm_states(adev, |
715 | clock_values_in_khz, | |
716 | num_states); | |
717 | if (ret == -EOPNOTSUPP) | |
79a7b060 | 718 | return PP_SMU_RESULT_UNSUPPORTED; |
13f5dbd6 EQ |
719 | else if (ret) |
720 | return PP_SMU_RESULT_FAIL; | |
79a7b060 | 721 | |
13f5dbd6 | 722 | return PP_SMU_RESULT_OK; |
79a7b060 | 723 | } |
724 | ||
dfd84d90 | 725 | static enum pp_smu_status pp_rn_get_dpm_clock_table( |
71a0df4b HW |
726 | struct pp_smu *pp, struct dpm_clocks *clock_table) |
727 | { | |
728 | const struct dc_context *ctx = pp->dm; | |
729 | struct amdgpu_device *adev = ctx->driver_context; | |
13f5dbd6 | 730 | int ret = 0; |
71a0df4b | 731 | |
13f5dbd6 EQ |
732 | ret = amdgpu_dpm_get_dpm_clock_table(adev, clock_table); |
733 | if (ret == -EOPNOTSUPP) | |
71a0df4b | 734 | return PP_SMU_RESULT_UNSUPPORTED; |
13f5dbd6 EQ |
735 | else if (ret) |
736 | return PP_SMU_RESULT_FAIL; | |
71a0df4b | 737 | |
13f5dbd6 | 738 | return PP_SMU_RESULT_OK; |
71a0df4b HW |
739 | } |
740 | ||
dfd84d90 | 741 | static enum pp_smu_status pp_rn_set_wm_ranges(struct pp_smu *pp, |
71a0df4b HW |
742 | struct pp_smu_wm_range_sets *ranges) |
743 | { | |
744 | const struct dc_context *ctx = pp->dm; | |
745 | struct amdgpu_device *adev = ctx->driver_context; | |
71a0df4b | 746 | |
13f5dbd6 | 747 | amdgpu_dpm_set_watermarks_for_clocks_ranges(adev, ranges); |
71a0df4b HW |
748 | |
749 | return PP_SMU_RESULT_OK; | |
750 | } | |
71a0df4b | 751 | |
0f1a6ad7 | 752 | void dm_pp_get_funcs( |
f7c1ed34 | 753 | struct dc_context *ctx, |
0f1a6ad7 | 754 | struct pp_smu_funcs *funcs) |
f7c1ed34 | 755 | { |
79a7b060 | 756 | switch (ctx->dce_version) { |
757 | case DCN_VERSION_1_0: | |
758 | case DCN_VERSION_1_01: | |
759 | funcs->ctx.ver = PP_SMU_VER_RV; | |
760 | funcs->rv_funcs.pp_smu.dm = ctx; | |
761 | funcs->rv_funcs.set_wm_ranges = pp_rv_set_wm_ranges; | |
762 | funcs->rv_funcs.set_pme_wa_enable = pp_rv_set_pme_wa_enable; | |
763 | funcs->rv_funcs.set_display_count = | |
764 | pp_rv_set_active_display_count; | |
765 | funcs->rv_funcs.set_min_deep_sleep_dcfclk = | |
766 | pp_rv_set_min_deep_sleep_dcfclk; | |
767 | funcs->rv_funcs.set_hard_min_dcfclk_by_freq = | |
768 | pp_rv_set_hard_min_dcefclk_by_freq; | |
769 | funcs->rv_funcs.set_hard_min_fclk_by_freq = | |
770 | pp_rv_set_hard_min_fclk_by_freq; | |
771 | break; | |
79a7b060 | 772 | case DCN_VERSION_2_0: |
773 | funcs->ctx.ver = PP_SMU_VER_NV; | |
774 | funcs->nv_funcs.pp_smu.dm = ctx; | |
775 | funcs->nv_funcs.set_display_count = pp_nv_set_display_count; | |
776 | funcs->nv_funcs.set_hard_min_dcfclk_by_freq = | |
777 | pp_nv_set_hard_min_dcefclk_by_freq; | |
778 | funcs->nv_funcs.set_min_deep_sleep_dcfclk = | |
779 | pp_nv_set_min_deep_sleep_dcfclk; | |
780 | funcs->nv_funcs.set_voltage_by_freq = | |
781 | pp_nv_set_voltage_by_freq; | |
782 | funcs->nv_funcs.set_wm_ranges = pp_nv_set_wm_ranges; | |
783 | ||
784 | /* todo set_pme_wa_enable cause 4k@6ohz display not light up */ | |
785 | funcs->nv_funcs.set_pme_wa_enable = NULL; | |
786 | /* todo debug waring message */ | |
02316e96 | 787 | funcs->nv_funcs.set_hard_min_uclk_by_freq = pp_nv_set_hard_min_uclk_by_freq; |
79a7b060 | 788 | /* todo compare data with window driver*/ |
02316e96 | 789 | funcs->nv_funcs.get_maximum_sustainable_clocks = pp_nv_get_maximum_sustainable_clocks; |
79a7b060 | 790 | /*todo compare data with window driver */ |
02316e96 | 791 | funcs->nv_funcs.get_uclk_dpm_states = pp_nv_get_uclk_dpm_states; |
6e92e156 | 792 | funcs->nv_funcs.set_pstate_handshake_support = pp_nv_set_pstate_handshake_support; |
79a7b060 | 793 | break; |
71a0df4b | 794 | |
71a0df4b HW |
795 | case DCN_VERSION_2_1: |
796 | funcs->ctx.ver = PP_SMU_VER_RN; | |
797 | funcs->rn_funcs.pp_smu.dm = ctx; | |
798 | funcs->rn_funcs.set_wm_ranges = pp_rn_set_wm_ranges; | |
799 | funcs->rn_funcs.get_dpm_clock_table = pp_rn_get_dpm_clock_table; | |
800 | break; | |
79a7b060 | 801 | default: |
802 | DRM_ERROR("smu version is not supported !\n"); | |
803 | break; | |
804 | } | |
f7c1ed34 | 805 | } |