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