]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c
drm/amd/display: fix aviInfoFrame bar Info and add set_avMute
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / amd / display / dc / dce / dce_clocks.c
CommitLineData
9a70eba7
DL
1/*
2 * Copyright 2012-16 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 "dce_clocks.h"
27#include "dm_services.h"
28#include "reg_helper.h"
29#include "fixed32_32.h"
30#include "bios_parser_interface.h"
31#include "dc.h"
15a27de2
HW
32#include "core_dc.h"
33#include "dce_abm.h"
9f72f51d 34#include "dmcu.h"
ff5ef992
AD
35#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
36#include "dcn_calcs.h"
37#include "core_dc.h"
38#endif
9a70eba7 39
15a27de2
HW
40
41
e11b86ad
DL
42#define TO_DCE_CLOCKS(clocks)\
43 container_of(clocks, struct dce_disp_clk, base)
9a70eba7
DL
44
45#define REG(reg) \
46 (clk_dce->regs->reg)
47
48#undef FN
49#define FN(reg_name, field_name) \
50 clk_dce->clk_shift->field_name, clk_dce->clk_mask->field_name
51
52#define CTX \
53 clk_dce->base.ctx
54
e11b86ad
DL
55/* Max clock values for each state indexed by "enum clocks_state": */
56static struct state_dependent_clocks dce80_max_clks_by_state[] = {
57/* ClocksStateInvalid - should not be used */
58{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
59/* ClocksStateUltraLow - not expected to be used for DCE 8.0 */
60{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
61/* ClocksStateLow */
62{ .display_clk_khz = 352000, .pixel_clk_khz = 330000},
63/* ClocksStateNominal */
64{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 },
65/* ClocksStatePerformance */
66{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } };
67
68static struct state_dependent_clocks dce110_max_clks_by_state[] = {
69/*ClocksStateInvalid - should not be used*/
70{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
71/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
72{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
73/*ClocksStateLow*/
74{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
75/*ClocksStateNominal*/
76{ .display_clk_khz = 467000, .pixel_clk_khz = 400000 },
77/*ClocksStatePerformance*/
78{ .display_clk_khz = 643000, .pixel_clk_khz = 400000 } };
79
80static struct state_dependent_clocks dce112_max_clks_by_state[] = {
81/*ClocksStateInvalid - should not be used*/
82{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
83/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
84{ .display_clk_khz = 389189, .pixel_clk_khz = 346672 },
85/*ClocksStateLow*/
86{ .display_clk_khz = 459000, .pixel_clk_khz = 400000 },
87/*ClocksStateNominal*/
88{ .display_clk_khz = 667000, .pixel_clk_khz = 600000 },
89/*ClocksStatePerformance*/
90{ .display_clk_khz = 1132000, .pixel_clk_khz = 600000 } };
91
2c8ad2d5
AD
92static struct state_dependent_clocks dce120_max_clks_by_state[] = {
93/*ClocksStateInvalid - should not be used*/
94{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
95/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
96{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
97/*ClocksStateLow*/
98{ .display_clk_khz = 460000, .pixel_clk_khz = 400000 },
99/*ClocksStateNominal*/
100{ .display_clk_khz = 670000, .pixel_clk_khz = 600000 },
101/*ClocksStatePerformance*/
102{ .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } };
2c8ad2d5 103
9a70eba7 104/* Starting point for each divider range.*/
e11b86ad 105enum dce_divider_range_start {
9a70eba7
DL
106 DIVIDER_RANGE_01_START = 200, /* 2.00*/
107 DIVIDER_RANGE_02_START = 1600, /* 16.00*/
108 DIVIDER_RANGE_03_START = 3200, /* 32.00*/
109 DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/
110};
111
112/* Ranges for divider identifiers (Divider ID or DID)
113 mmDENTIST_DISPCLK_CNTL.DENTIST_DISPCLK_WDIVIDER*/
e11b86ad 114enum dce_divider_id_register_setting {
9a70eba7
DL
115 DIVIDER_RANGE_01_BASE_DIVIDER_ID = 0X08,
116 DIVIDER_RANGE_02_BASE_DIVIDER_ID = 0X40,
117 DIVIDER_RANGE_03_BASE_DIVIDER_ID = 0X60,
118 DIVIDER_RANGE_MAX_DIVIDER_ID = 0X80
119};
120
121/* Step size between each divider within a range.
122 Incrementing the DENTIST_DISPCLK_WDIVIDER by one
123 will increment the divider by this much.*/
e11b86ad 124enum dce_divider_range_step_size {
9a70eba7
DL
125 DIVIDER_RANGE_01_STEP_SIZE = 25, /* 0.25*/
126 DIVIDER_RANGE_02_STEP_SIZE = 50, /* 0.50*/
127 DIVIDER_RANGE_03_STEP_SIZE = 100 /* 1.00 */
128};
129
e11b86ad
DL
130static bool dce_divider_range_construct(
131 struct dce_divider_range *div_range,
132 int range_start,
133 int range_step,
134 int did_min,
135 int did_max)
136{
137 div_range->div_range_start = range_start;
138 div_range->div_range_step = range_step;
139 div_range->did_min = did_min;
140 div_range->did_max = did_max;
141
142 if (div_range->div_range_step == 0) {
143 div_range->div_range_step = 1;
144 /*div_range_step cannot be zero*/
145 BREAK_TO_DEBUGGER();
146 }
147 /* Calculate this based on the other inputs.*/
148 /* See DividerRange.h for explanation of */
149 /* the relationship between divider id (DID) and a divider.*/
150 /* Number of Divider IDs = (Maximum Divider ID - Minimum Divider ID)*/
151 /* Maximum divider identified in this range =
152 * (Number of Divider IDs)*Step size between dividers
153 * + The start of this range.*/
154 div_range->div_range_end = (did_max - did_min) * range_step
155 + range_start;
156 return true;
157}
158
159static int dce_divider_range_calc_divider(
160 struct dce_divider_range *div_range,
161 int did)
162{
163 /* Is this DID within our range?*/
164 if ((did < div_range->did_min) || (did >= div_range->did_max))
165 return INVALID_DIVIDER;
166
167 return ((did - div_range->did_min) * div_range->div_range_step)
168 + div_range->div_range_start;
169
170}
171
e11b86ad
DL
172static int dce_divider_range_get_divider(
173 struct dce_divider_range *div_range,
174 int ranges_num,
175 int did)
176{
177 int div = INVALID_DIVIDER;
178 int i;
9a70eba7 179
e11b86ad
DL
180 for (i = 0; i < ranges_num; i++) {
181 /* Calculate divider with given divider ID*/
182 div = dce_divider_range_calc_divider(&div_range[i], did);
183 /* Found a valid return divider*/
184 if (div != INVALID_DIVIDER)
185 break;
186 }
187 return div;
188}
189
e11b86ad 190static int dce_clocks_get_dp_ref_freq(struct display_clock *clk)
9a70eba7
DL
191{
192 struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
193 int dprefclk_wdivider;
194 int dprefclk_src_sel;
195 int dp_ref_clk_khz = 600000;
196 int target_div = INVALID_DIVIDER;
197
198 /* ASSERT DP Reference Clock source is from DFS*/
199 REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel);
200 ASSERT(dprefclk_src_sel == 0);
201
202 /* Read the mmDENTIST_DISPCLK_CNTL to get the currently
203 * programmed DID DENTIST_DPREFCLK_WDIVIDER*/
204 REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider);
205
206 /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
e11b86ad 207 target_div = dce_divider_range_get_divider(
9a70eba7
DL
208 clk_dce->divider_ranges,
209 DIVIDER_RANGE_MAX,
210 dprefclk_wdivider);
211
212 if (target_div != INVALID_DIVIDER) {
213 /* Calculate the current DFS clock, in kHz.*/
214 dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR
215 * clk_dce->dentist_vco_freq_khz) / target_div;
216 }
217
218 /* SW will adjust DP REF Clock average value for all purposes
219 * (DP DTO / DP Audio DTO and DP GTC)
220 if clock is spread for all cases:
221 -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
222 calculations for DS_INCR/DS_MODULO (this is planned to be default case)
223 -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
224 calculations (not planned to be used, but average clock should still
225 be valid)
226 -if SS enabled on DP Ref clock and HW de-spreading disabled
227 (should not be case with CIK) then SW should program all rates
228 generated according to average value (case as with previous ASICs)
229 */
7d091f7a 230 if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) {
9a70eba7
DL
231 struct fixed32_32 ss_percentage = dal_fixed32_32_div_int(
232 dal_fixed32_32_from_fraction(
7d091f7a
HW
233 clk_dce->dprefclk_ss_percentage,
234 clk_dce->dprefclk_ss_divider), 200);
9a70eba7
DL
235 struct fixed32_32 adj_dp_ref_clk_khz;
236
237 ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one,
238 ss_percentage);
239 adj_dp_ref_clk_khz =
240 dal_fixed32_32_mul_int(
241 ss_percentage,
242 dp_ref_clk_khz);
243 dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz);
244 }
245
246 return dp_ref_clk_khz;
247}
248
3f6d7435
HW
249/* TODO: This is DCN DPREFCLK: it could be program by DENTIST by VBIOS
250 * or CLK0_CLK11 by SMU. For DCE120, it is wlays 600Mhz. Will re-visit
251 * clock implementation
252 */
253static int dce_clocks_get_dp_ref_freq_wrkaround(struct display_clock *clk)
254{
255 struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
256 int dp_ref_clk_khz = 600000;
257
258 if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) {
259 struct fixed32_32 ss_percentage = dal_fixed32_32_div_int(
260 dal_fixed32_32_from_fraction(
261 clk_dce->dprefclk_ss_percentage,
262 clk_dce->dprefclk_ss_divider), 200);
263 struct fixed32_32 adj_dp_ref_clk_khz;
264
265 ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one,
266 ss_percentage);
267 adj_dp_ref_clk_khz =
268 dal_fixed32_32_mul_int(
269 ss_percentage,
270 dp_ref_clk_khz);
271 dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz);
272 }
273
274 return dp_ref_clk_khz;
275}
9a70eba7
DL
276static enum dm_pp_clocks_state dce_get_required_clocks_state(
277 struct display_clock *clk,
278 struct state_dependent_clocks *req_clocks)
279{
280 struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
281 int i;
282 enum dm_pp_clocks_state low_req_clk;
283
284 /* Iterate from highest supported to lowest valid state, and update
285 * lowest RequiredState with the lowest state that satisfies
286 * all required clocks
287 */
288 for (i = clk->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--)
289 if (req_clocks->display_clk_khz >
290 clk_dce->max_clks_by_state[i].display_clk_khz
291 || req_clocks->pixel_clk_khz >
292 clk_dce->max_clks_by_state[i].pixel_clk_khz)
293 break;
294
295 low_req_clk = i + 1;
296 if (low_req_clk > clk->max_clks_state) {
297 dm_logger_write(clk->ctx->logger, LOG_WARNING,
298 "%s: clocks unsupported", __func__);
299 low_req_clk = DM_PP_CLOCKS_STATE_INVALID;
300 }
301
302 return low_req_clk;
303}
304
305static bool dce_clock_set_min_clocks_state(
306 struct display_clock *clk,
307 enum dm_pp_clocks_state clocks_state)
308{
309 struct dm_pp_power_level_change_request level_change_req = {
310 clocks_state };
311
312 if (clocks_state > clk->max_clks_state) {
313 /*Requested state exceeds max supported state.*/
314 dm_logger_write(clk->ctx->logger, LOG_WARNING,
315 "Requested state exceeds max supported state");
316 return false;
317 } else if (clocks_state == clk->cur_min_clks_state) {
318 /*if we're trying to set the same state, we can just return
319 * since nothing needs to be done*/
320 return true;
321 }
322
323 /* get max clock state from PPLIB */
324 if (dm_pp_apply_power_level_change_request(clk->ctx, &level_change_req))
325 clk->cur_min_clks_state = clocks_state;
326
327 return true;
328}
329
330static void dce_set_clock(
331 struct display_clock *clk,
e11b86ad 332 int requested_clk_khz)
9a70eba7
DL
333{
334 struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
335 struct bp_pixel_clock_parameters pxl_clk_params = { 0 };
336 struct dc_bios *bp = clk->ctx->dc_bios;
337
338 /* Make sure requested clock isn't lower than minimum threshold*/
339 if (requested_clk_khz > 0)
7d7024ca 340 requested_clk_khz = max(requested_clk_khz,
9a70eba7
DL
341 clk_dce->dentist_vco_freq_khz / 64);
342
343 /* Prepare to program display clock*/
344 pxl_clk_params.target_pixel_clock = requested_clk_khz;
345 pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
346
347 bp->funcs->program_display_engine_pll(bp, &pxl_clk_params);
348
349 if (clk_dce->dfs_bypass_enabled) {
350
351 /* Cache the fixed display clock*/
352 clk_dce->dfs_bypass_disp_clk =
353 pxl_clk_params.dfs_bypass_display_clock;
354 }
355
356 /* from power down, we need mark the clock state as ClocksStateNominal
357 * from HWReset, so when resume we will call pplib voltage regulator.*/
358 if (requested_clk_khz == 0)
359 clk->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
360}
361
9a70eba7
DL
362static void dce_psr_set_clock(
363 struct display_clock *clk,
e11b86ad 364 int requested_clk_khz)
9a70eba7
DL
365{
366 struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
9f72f51d
AZ
367 struct dc_context *ctx = clk_dce->base.ctx;
368 struct core_dc *core_dc = DC_TO_CORE(ctx->dc);
369 struct dmcu *dmcu = core_dc->res_pool->dmcu;
9a70eba7
DL
370
371 dce_set_clock(clk, requested_clk_khz);
9f72f51d
AZ
372
373 dmcu->funcs->set_psr_wait_loop(dmcu, requested_clk_khz / 1000 / 7);
9a70eba7
DL
374}
375
e11b86ad 376static void dce112_set_clock(
9a70eba7 377 struct display_clock *clk,
e11b86ad 378 int requested_clk_khz)
9a70eba7
DL
379{
380 struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk);
381 struct bp_set_dce_clock_parameters dce_clk_params;
382 struct dc_bios *bp = clk->ctx->dc_bios;
15a27de2
HW
383 struct core_dc *core_dc = DC_TO_CORE(clk->ctx->dc);
384 struct abm *abm = core_dc->res_pool->abm;
9f72f51d 385 struct dmcu *dmcu = core_dc->res_pool->dmcu;
9a70eba7
DL
386
387 /* Prepare to program display clock*/
388 memset(&dce_clk_params, 0, sizeof(dce_clk_params));
389
390 /* Make sure requested clock isn't lower than minimum threshold*/
391 if (requested_clk_khz > 0)
7d7024ca 392 requested_clk_khz = max(requested_clk_khz,
e11b86ad 393 clk_dce->dentist_vco_freq_khz / 62);
9a70eba7
DL
394
395 dce_clk_params.target_clock_frequency = requested_clk_khz;
396 dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
397 dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
398
399 bp->funcs->set_dce_clock(bp, &dce_clk_params);
400
401 /* from power down, we need mark the clock state as ClocksStateNominal
402 * from HWReset, so when resume we will call pplib voltage regulator.*/
403 if (requested_clk_khz == 0)
404 clk->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
405
406 /*Program DP ref Clock*/
407 /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
408 dce_clk_params.target_clock_frequency = 0;
409 dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
e11b86ad
DL
410 dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
411 (dce_clk_params.pll_id ==
412 CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
9a70eba7
DL
413
414 bp->funcs->set_dce_clock(bp, &dce_clk_params);
ece4f358 415
15a27de2 416 if (abm->funcs->is_dmcu_initialized(abm))
9f72f51d
AZ
417 dmcu->funcs->set_psr_wait_loop(dmcu,
418 requested_clk_khz / 1000 / 7);
ff5ef992 419
9a70eba7
DL
420}
421
422static void dce_clock_read_integrated_info(struct dce_disp_clk *clk_dce)
423{
424 struct dc_debug *debug = &clk_dce->base.ctx->dc->debug;
425 struct dc_bios *bp = clk_dce->base.ctx->dc_bios;
c2e218dd
HW
426 struct integrated_info info = { { { 0 } } };
427 struct firmware_info fw_info = { { 0 } };
9a70eba7
DL
428 int i;
429
430 if (bp->integrated_info)
431 info = *bp->integrated_info;
432
433 clk_dce->dentist_vco_freq_khz = info.dentist_vco_freq;
434 if (clk_dce->dentist_vco_freq_khz == 0) {
435 bp->funcs->get_firmware_info(bp, &fw_info);
436 clk_dce->dentist_vco_freq_khz =
437 fw_info.smu_gpu_pll_output_freq;
438 if (clk_dce->dentist_vco_freq_khz == 0)
439 clk_dce->dentist_vco_freq_khz = 3600000;
440 }
441
442 /*update the maximum display clock for each power state*/
443 for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
444 enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID;
445
446 switch (i) {
447 case 0:
448 clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW;
449 break;
450
451 case 1:
452 clk_state = DM_PP_CLOCKS_STATE_LOW;
453 break;
454
455 case 2:
456 clk_state = DM_PP_CLOCKS_STATE_NOMINAL;
457 break;
458
459 case 3:
460 clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE;
461 break;
462
463 default:
464 clk_state = DM_PP_CLOCKS_STATE_INVALID;
465 break;
466 }
467
468 /*Do not allow bad VBIOS/SBIOS to override with invalid values,
469 * check for > 100MHz*/
470 if (info.disp_clk_voltage[i].max_supported_clk >= 100000)
471 clk_dce->max_clks_by_state[clk_state].display_clk_khz =
472 info.disp_clk_voltage[i].max_supported_clk;
473 }
474
85944914 475 if (!debug->disable_dfs_bypass && bp->integrated_info)
9a70eba7
DL
476 if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
477 clk_dce->dfs_bypass_enabled = true;
478
479 clk_dce->use_max_disp_clk = debug->max_disp_clk;
480}
481
482static void dce_clock_read_ss_info(struct dce_disp_clk *clk_dce)
483{
484 struct dc_bios *bp = clk_dce->base.ctx->dc_bios;
485 int ss_info_num = bp->funcs->get_ss_entry_number(
486 bp, AS_SIGNAL_TYPE_GPU_PLL);
487
488 if (ss_info_num) {
c2e218dd 489 struct spread_spectrum_info info = { { 0 } };
9a70eba7
DL
490 enum bp_result result = bp->funcs->get_spread_spectrum_info(
491 bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
492
493 /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
494 * even if SS not enabled and in that case
495 * SSInfo.spreadSpectrumPercentage !=0 would be sign
496 * that SS is enabled
497 */
498 if (result == BP_RESULT_OK &&
499 info.spread_spectrum_percentage != 0) {
7d091f7a
HW
500 clk_dce->ss_on_dprefclk = true;
501 clk_dce->dprefclk_ss_divider = info.spread_percentage_divider;
9a70eba7
DL
502
503 if (info.type.CENTER_MODE == 0) {
7d091f7a 504 /* TODO: Currently for DP Reference clock we
9a70eba7
DL
505 * need only SS percentage for
506 * downspread */
7d091f7a 507 clk_dce->dprefclk_ss_percentage =
9a70eba7
DL
508 info.spread_spectrum_percentage;
509 }
7d091f7a
HW
510
511 return;
9a70eba7
DL
512 }
513
7d091f7a
HW
514 result = bp->funcs->get_spread_spectrum_info(
515 bp, AS_SIGNAL_TYPE_DISPLAY_PORT, 0, &info);
516
517 /* Based on VBIOS, VBIOS will keep entry for DPREFCLK SS
518 * even if SS not enabled and in that case
519 * SSInfo.spreadSpectrumPercentage !=0 would be sign
520 * that SS is enabled
521 */
522 if (result == BP_RESULT_OK &&
523 info.spread_spectrum_percentage != 0) {
524 clk_dce->ss_on_dprefclk = true;
525 clk_dce->dprefclk_ss_divider = info.spread_percentage_divider;
526
527 if (info.type.CENTER_MODE == 0) {
528 /* Currently for DP Reference clock we
529 * need only SS percentage for
530 * downspread */
531 clk_dce->dprefclk_ss_percentage =
532 info.spread_spectrum_percentage;
533 }
534 }
9a70eba7
DL
535 }
536}
537
2c8ad2d5
AD
538static bool dce_apply_clock_voltage_request(
539 struct display_clock *clk,
540 enum dm_pp_clock_type clocks_type,
541 int clocks_in_khz,
542 bool pre_mode_set,
543 bool update_dp_phyclk)
544{
fd8cc371 545 bool send_request = false;
2c8ad2d5
AD
546 struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
547
548 switch (clocks_type) {
549 case DM_PP_CLOCK_TYPE_DISPLAY_CLK:
550 case DM_PP_CLOCK_TYPE_PIXELCLK:
551 case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK:
552 break;
553 default:
554 BREAK_TO_DEBUGGER();
555 return false;
556 }
557
558 clock_voltage_req.clk_type = clocks_type;
559 clock_voltage_req.clocks_in_khz = clocks_in_khz;
560
561 /* to pplib */
562 if (pre_mode_set) {
563 switch (clocks_type) {
564 case DM_PP_CLOCK_TYPE_DISPLAY_CLK:
565 if (clocks_in_khz > clk->cur_clocks_value.dispclk_in_khz) {
2c8ad2d5 566 clk->cur_clocks_value.dispclk_notify_pplib_done = true;
fd8cc371 567 send_request = true;
2c8ad2d5
AD
568 } else
569 clk->cur_clocks_value.dispclk_notify_pplib_done = false;
570 /* no matter incrase or decrase clock, update current clock value */
571 clk->cur_clocks_value.dispclk_in_khz = clocks_in_khz;
572 break;
573 case DM_PP_CLOCK_TYPE_PIXELCLK:
574 if (clocks_in_khz > clk->cur_clocks_value.max_pixelclk_in_khz) {
2c8ad2d5 575 clk->cur_clocks_value.pixelclk_notify_pplib_done = true;
fd8cc371 576 send_request = true;
2c8ad2d5
AD
577 } else
578 clk->cur_clocks_value.pixelclk_notify_pplib_done = false;
579 /* no matter incrase or decrase clock, update current clock value */
580 clk->cur_clocks_value.max_pixelclk_in_khz = clocks_in_khz;
581 break;
582 case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK:
583 if (clocks_in_khz > clk->cur_clocks_value.max_non_dp_phyclk_in_khz) {
2c8ad2d5 584 clk->cur_clocks_value.phyclk_notigy_pplib_done = true;
fd8cc371 585 send_request = true;
2c8ad2d5
AD
586 } else
587 clk->cur_clocks_value.phyclk_notigy_pplib_done = false;
588 /* no matter incrase or decrase clock, update current clock value */
589 clk->cur_clocks_value.max_non_dp_phyclk_in_khz = clocks_in_khz;
590 break;
591 default:
592 ASSERT(0);
593 break;
594 }
fd8cc371 595
2c8ad2d5
AD
596 } else {
597 switch (clocks_type) {
598 case DM_PP_CLOCK_TYPE_DISPLAY_CLK:
599 if (!clk->cur_clocks_value.dispclk_notify_pplib_done)
fd8cc371 600 send_request = true;
2c8ad2d5
AD
601 break;
602 case DM_PP_CLOCK_TYPE_PIXELCLK:
603 if (!clk->cur_clocks_value.pixelclk_notify_pplib_done)
fd8cc371 604 send_request = true;
2c8ad2d5
AD
605 break;
606 case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK:
607 if (!clk->cur_clocks_value.phyclk_notigy_pplib_done)
fd8cc371 608 send_request = true;
2c8ad2d5
AD
609 break;
610 default:
611 ASSERT(0);
612 break;
613 }
614 }
fd8cc371 615 if (send_request) {
ff5ef992 616#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
c8210d5a
HW
617 if (clk->ctx->dce_version == DCN_VERSION_1_0) {
618 struct core_dc *core_dc = DC_TO_CORE(clk->ctx->dc);
619 /*use dcfclk request voltage*/
620 clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
621 clock_voltage_req.clocks_in_khz =
ff5ef992 622 dcn_find_dcfclk_suits_all(core_dc, &clk->cur_clocks_value);
c8210d5a 623 }
ff5ef992 624#endif
fd8cc371
CL
625 dm_pp_apply_clock_for_voltage_request(
626 clk->ctx, &clock_voltage_req);
627 }
2c8ad2d5
AD
628 if (update_dp_phyclk && (clocks_in_khz >
629 clk->cur_clocks_value.max_dp_phyclk_in_khz))
630 clk->cur_clocks_value.max_dp_phyclk_in_khz = clocks_in_khz;
631
632 return true;
633}
634
fd8cc371 635
2c8ad2d5 636static const struct display_clock_funcs dce120_funcs = {
3f6d7435 637 .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq_wrkaround,
2c8ad2d5
AD
638 .apply_clock_voltage_request = dce_apply_clock_voltage_request,
639 .set_clock = dce112_set_clock
640};
2c8ad2d5 641
9a70eba7
DL
642static const struct display_clock_funcs dce112_funcs = {
643 .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq,
644 .get_required_clocks_state = dce_get_required_clocks_state,
645 .set_min_clocks_state = dce_clock_set_min_clocks_state,
e11b86ad 646 .set_clock = dce112_set_clock
9a70eba7
DL
647};
648
649static const struct display_clock_funcs dce110_funcs = {
650 .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq,
651 .get_required_clocks_state = dce_get_required_clocks_state,
652 .set_min_clocks_state = dce_clock_set_min_clocks_state,
653 .set_clock = dce_psr_set_clock
654};
655
656static const struct display_clock_funcs dce_funcs = {
657 .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq,
658 .get_required_clocks_state = dce_get_required_clocks_state,
659 .set_min_clocks_state = dce_clock_set_min_clocks_state,
660 .set_clock = dce_set_clock
661};
662
663static void dce_disp_clk_construct(
664 struct dce_disp_clk *clk_dce,
665 struct dc_context *ctx,
666 const struct dce_disp_clk_registers *regs,
667 const struct dce_disp_clk_shift *clk_shift,
668 const struct dce_disp_clk_mask *clk_mask)
669{
670 struct display_clock *base = &clk_dce->base;
671
672 base->ctx = ctx;
673 base->funcs = &dce_funcs;
674
675 clk_dce->regs = regs;
676 clk_dce->clk_shift = clk_shift;
677 clk_dce->clk_mask = clk_mask;
678
679 clk_dce->dfs_bypass_disp_clk = 0;
7d091f7a
HW
680
681 clk_dce->dprefclk_ss_percentage = 0;
682 clk_dce->dprefclk_ss_divider = 1000;
683 clk_dce->ss_on_dprefclk = false;
684
9a70eba7
DL
685 base->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
686 base->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID;
687
688 dce_clock_read_integrated_info(clk_dce);
689 dce_clock_read_ss_info(clk_dce);
690
e11b86ad 691 dce_divider_range_construct(
9a70eba7
DL
692 &clk_dce->divider_ranges[DIVIDER_RANGE_01],
693 DIVIDER_RANGE_01_START,
694 DIVIDER_RANGE_01_STEP_SIZE,
695 DIVIDER_RANGE_01_BASE_DIVIDER_ID,
696 DIVIDER_RANGE_02_BASE_DIVIDER_ID);
e11b86ad 697 dce_divider_range_construct(
9a70eba7
DL
698 &clk_dce->divider_ranges[DIVIDER_RANGE_02],
699 DIVIDER_RANGE_02_START,
700 DIVIDER_RANGE_02_STEP_SIZE,
701 DIVIDER_RANGE_02_BASE_DIVIDER_ID,
702 DIVIDER_RANGE_03_BASE_DIVIDER_ID);
e11b86ad 703 dce_divider_range_construct(
9a70eba7
DL
704 &clk_dce->divider_ranges[DIVIDER_RANGE_03],
705 DIVIDER_RANGE_03_START,
706 DIVIDER_RANGE_03_STEP_SIZE,
707 DIVIDER_RANGE_03_BASE_DIVIDER_ID,
708 DIVIDER_RANGE_MAX_DIVIDER_ID);
709}
710
711struct display_clock *dce_disp_clk_create(
712 struct dc_context *ctx,
713 const struct dce_disp_clk_registers *regs,
714 const struct dce_disp_clk_shift *clk_shift,
715 const struct dce_disp_clk_mask *clk_mask)
716{
717 struct dce_disp_clk *clk_dce = dm_alloc(sizeof(*clk_dce));
718
719 if (clk_dce == NULL) {
720 BREAK_TO_DEBUGGER();
721 return NULL;
722 }
723
e11b86ad
DL
724 memcpy(clk_dce->max_clks_by_state,
725 dce80_max_clks_by_state,
726 sizeof(dce80_max_clks_by_state));
727
9a70eba7
DL
728 dce_disp_clk_construct(
729 clk_dce, ctx, regs, clk_shift, clk_mask);
730
731 return &clk_dce->base;
732}
733
734struct display_clock *dce110_disp_clk_create(
735 struct dc_context *ctx,
736 const struct dce_disp_clk_registers *regs,
737 const struct dce_disp_clk_shift *clk_shift,
738 const struct dce_disp_clk_mask *clk_mask)
739{
740 struct dce_disp_clk *clk_dce = dm_alloc(sizeof(*clk_dce));
741
742 if (clk_dce == NULL) {
743 BREAK_TO_DEBUGGER();
744 return NULL;
745 }
746
e11b86ad
DL
747 memcpy(clk_dce->max_clks_by_state,
748 dce110_max_clks_by_state,
749 sizeof(dce110_max_clks_by_state));
750
9a70eba7
DL
751 dce_disp_clk_construct(
752 clk_dce, ctx, regs, clk_shift, clk_mask);
753
754 clk_dce->base.funcs = &dce110_funcs;
755
756 return &clk_dce->base;
757}
758
759struct display_clock *dce112_disp_clk_create(
760 struct dc_context *ctx,
761 const struct dce_disp_clk_registers *regs,
762 const struct dce_disp_clk_shift *clk_shift,
763 const struct dce_disp_clk_mask *clk_mask)
764{
765 struct dce_disp_clk *clk_dce = dm_alloc(sizeof(*clk_dce));
766
767 if (clk_dce == NULL) {
768 BREAK_TO_DEBUGGER();
769 return NULL;
770 }
771
e11b86ad
DL
772 memcpy(clk_dce->max_clks_by_state,
773 dce112_max_clks_by_state,
774 sizeof(dce112_max_clks_by_state));
775
9a70eba7
DL
776 dce_disp_clk_construct(
777 clk_dce, ctx, regs, clk_shift, clk_mask);
778
779 clk_dce->base.funcs = &dce112_funcs;
780
781 return &clk_dce->base;
782}
783
b1a4eb99 784struct display_clock *dce120_disp_clk_create(struct dc_context *ctx)
2c8ad2d5
AD
785{
786 struct dce_disp_clk *clk_dce = dm_alloc(sizeof(*clk_dce));
787 struct dm_pp_clock_levels_with_voltage clk_level_info = {0};
788
789 if (clk_dce == NULL) {
790 BREAK_TO_DEBUGGER();
791 return NULL;
792 }
793
794 memcpy(clk_dce->max_clks_by_state,
795 dce120_max_clks_by_state,
796 sizeof(dce120_max_clks_by_state));
797
798 dce_disp_clk_construct(
b1a4eb99 799 clk_dce, ctx, NULL, NULL, NULL);
2c8ad2d5
AD
800
801 clk_dce->base.funcs = &dce120_funcs;
802
803 /* new in dce120 */
804 if (!ctx->dc->debug.disable_pplib_clock_request &&
805 dm_pp_get_clock_levels_by_type_with_voltage(
806 ctx, DM_PP_CLOCK_TYPE_DISPLAY_CLK, &clk_level_info)
807 && clk_level_info.num_levels)
808 clk_dce->max_displ_clk_in_khz =
809 clk_level_info.data[clk_level_info.num_levels - 1].clocks_in_khz;
810 else
811 clk_dce->max_displ_clk_in_khz = 1133000;
812
813 return &clk_dce->base;
814}
2c8ad2d5 815
9a70eba7
DL
816void dce_disp_clk_destroy(struct display_clock **disp_clk)
817{
818 struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(*disp_clk);
819
820 dm_free(clk_dce);
821 *disp_clk = NULL;
822}