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 */
25
26 #include "dccg.h"
27 #include "clk_mgr_internal.h"
28
29 #include "dce100/dce_clk_mgr.h"
30 #include "dcn20_clk_mgr.h"
31 #include "reg_helper.h"
32 #include "core_types.h"
33 #include "dm_helpers.h"
34
35 #include "navi10_ip_offset.h"
36 #include "dcn/dcn_2_0_0_offset.h"
37 #include "dcn/dcn_2_0_0_sh_mask.h"
38 #include "clk/clk_11_0_0_offset.h"
39 #include "clk/clk_11_0_0_sh_mask.h"
40
41 #include "irq/dcn20/irq_service_dcn20.h"
42
43 #undef FN
44 #define FN(reg_name, field_name) \
45 clk_mgr->clk_mgr_shift->field_name, clk_mgr->clk_mgr_mask->field_name
46
47 #define REG(reg) \
48 (clk_mgr->regs->reg)
49
50 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
51
52 #define BASE(seg) BASE_INNER(seg)
53
54 #define SR(reg_name)\
55 .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \
56 mm ## reg_name
57
58 #define CLK_BASE_INNER(seg) \
59 CLK_BASE__INST0_SEG ## seg
60
61
62 static const struct clk_mgr_registers clk_mgr_regs = {
63 CLK_REG_LIST_NV10()
64 };
65
66 static const struct clk_mgr_shift clk_mgr_shift = {
67 CLK_MASK_SH_LIST_NV10(__SHIFT)
68 };
69
70 static const struct clk_mgr_mask clk_mgr_mask = {
71 CLK_MASK_SH_LIST_NV10(_MASK)
72 };
73
dentist_get_did_from_divider(int divider)74 uint32_t dentist_get_did_from_divider(int divider)
75 {
76 uint32_t divider_id;
77
78 /* we want to floor here to get higher clock than required rather than lower */
79 if (divider < DENTIST_DIVIDER_RANGE_2_START) {
80 if (divider < DENTIST_DIVIDER_RANGE_1_START)
81 divider_id = DENTIST_BASE_DID_1;
82 else
83 divider_id = DENTIST_BASE_DID_1
84 + (divider - DENTIST_DIVIDER_RANGE_1_START)
85 / DENTIST_DIVIDER_RANGE_1_STEP;
86 } else if (divider < DENTIST_DIVIDER_RANGE_3_START) {
87 divider_id = DENTIST_BASE_DID_2
88 + (divider - DENTIST_DIVIDER_RANGE_2_START)
89 / DENTIST_DIVIDER_RANGE_2_STEP;
90 } else if (divider < DENTIST_DIVIDER_RANGE_4_START) {
91 divider_id = DENTIST_BASE_DID_3
92 + (divider - DENTIST_DIVIDER_RANGE_3_START)
93 / DENTIST_DIVIDER_RANGE_3_STEP;
94 } else {
95 divider_id = DENTIST_BASE_DID_4
96 + (divider - DENTIST_DIVIDER_RANGE_4_START)
97 / DENTIST_DIVIDER_RANGE_4_STEP;
98 if (divider_id > DENTIST_MAX_DID)
99 divider_id = DENTIST_MAX_DID;
100 }
101
102 return divider_id;
103 }
104
dcn20_update_clocks_update_dpp_dto(struct clk_mgr_internal * clk_mgr,struct dc_state * context,bool safe_to_lower)105 void dcn20_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr,
106 struct dc_state *context, bool safe_to_lower)
107 {
108 int i;
109
110 clk_mgr->dccg->ref_dppclk = clk_mgr->base.clks.dppclk_khz;
111 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
112 int dpp_inst, dppclk_khz, prev_dppclk_khz;
113
114 /* Loop index will match dpp->inst if resource exists,
115 * and we want to avoid dependency on dpp object
116 */
117 dpp_inst = i;
118 dppclk_khz = context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz;
119
120 prev_dppclk_khz = clk_mgr->dccg->pipe_dppclk_khz[i];
121
122 if (safe_to_lower || prev_dppclk_khz < dppclk_khz)
123 clk_mgr->dccg->funcs->update_dpp_dto(
124 clk_mgr->dccg, dpp_inst, dppclk_khz);
125 }
126 }
127
dcn20_update_clocks_update_dentist(struct clk_mgr_internal * clk_mgr,struct dc_state * context)128 void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr, struct dc_state *context)
129 {
130 int dpp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR
131 * clk_mgr->base.dentist_vco_freq_khz / clk_mgr->base.clks.dppclk_khz;
132 int disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR
133 * clk_mgr->base.dentist_vco_freq_khz / clk_mgr->base.clks.dispclk_khz;
134
135 uint32_t dppclk_wdivider = dentist_get_did_from_divider(dpp_divider);
136 uint32_t dispclk_wdivider = dentist_get_did_from_divider(disp_divider);
137 uint32_t current_dispclk_wdivider;
138 uint32_t i;
139
140 REG_GET(DENTIST_DISPCLK_CNTL,
141 DENTIST_DISPCLK_WDIVIDER, ¤t_dispclk_wdivider);
142
143 /* When changing divider to or from 127, some extra programming is required to prevent corruption */
144 if (current_dispclk_wdivider == 127 && dispclk_wdivider != 127) {
145 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
146 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
147 uint32_t fifo_level;
148 struct dccg *dccg = clk_mgr->base.ctx->dc->res_pool->dccg;
149 struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
150 int32_t N;
151 int32_t j;
152
153 if (!pipe_ctx->stream)
154 continue;
155 /* Virtual encoders don't have this function */
156 if (!stream_enc->funcs->get_fifo_cal_average_level)
157 continue;
158 fifo_level = stream_enc->funcs->get_fifo_cal_average_level(
159 stream_enc);
160 N = fifo_level / 4;
161 dccg->funcs->set_fifo_errdet_ovr_en(
162 dccg,
163 true);
164 for (j = 0; j < N - 4; j++)
165 dccg->funcs->otg_drop_pixel(
166 dccg,
167 pipe_ctx->stream_res.tg->inst);
168 dccg->funcs->set_fifo_errdet_ovr_en(
169 dccg,
170 false);
171 }
172 } else if (dispclk_wdivider == 127 && current_dispclk_wdivider != 127) {
173 REG_UPDATE(DENTIST_DISPCLK_CNTL,
174 DENTIST_DISPCLK_WDIVIDER, 126);
175 REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, 1, 50, 100);
176 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
177 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
178 struct dccg *dccg = clk_mgr->base.ctx->dc->res_pool->dccg;
179 struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
180 uint32_t fifo_level;
181 int32_t N;
182 int32_t j;
183
184 if (!pipe_ctx->stream)
185 continue;
186 /* Virtual encoders don't have this function */
187 if (!stream_enc->funcs->get_fifo_cal_average_level)
188 continue;
189 fifo_level = stream_enc->funcs->get_fifo_cal_average_level(
190 stream_enc);
191 N = fifo_level / 4;
192 dccg->funcs->set_fifo_errdet_ovr_en(dccg, true);
193 for (j = 0; j < 12 - N; j++)
194 dccg->funcs->otg_add_pixel(dccg,
195 pipe_ctx->stream_res.tg->inst);
196 dccg->funcs->set_fifo_errdet_ovr_en(dccg, false);
197 }
198 }
199
200 REG_UPDATE(DENTIST_DISPCLK_CNTL,
201 DENTIST_DISPCLK_WDIVIDER, dispclk_wdivider);
202 REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, 1, 50, 1000);
203 REG_UPDATE(DENTIST_DISPCLK_CNTL,
204 DENTIST_DPPCLK_WDIVIDER, dppclk_wdivider);
205 REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, 1, 5, 100);
206 }
207
208
dcn2_update_clocks(struct clk_mgr * clk_mgr_base,struct dc_state * context,bool safe_to_lower)209 void dcn2_update_clocks(struct clk_mgr *clk_mgr_base,
210 struct dc_state *context,
211 bool safe_to_lower)
212 {
213 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
214 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
215 struct dc *dc = clk_mgr_base->ctx->dc;
216 struct pp_smu_funcs_nv *pp_smu = NULL;
217 int display_count;
218 bool update_dppclk = false;
219 bool update_dispclk = false;
220 bool enter_display_off = false;
221 bool dpp_clock_lowered = false;
222 struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;
223 bool force_reset = false;
224 bool p_state_change_support;
225 int total_plane_count;
226 int irq_src;
227 uint32_t hpd_state;
228
229 if (dc->work_arounds.skip_clock_update)
230 return;
231
232 if (clk_mgr_base->clks.dispclk_khz == 0 ||
233 dc->debug.force_clock_mode & 0x1) {
234 //this is from resume or boot up, if forced_clock cfg option used, we bypass program dispclk and DPPCLK, but need set them for S3.
235 force_reset = true;
236
237 dcn2_read_clocks_from_hw_dentist(clk_mgr_base);
238
239 //force_clock_mode 0x1: force reset the clock even it is the same clock as long as it is in Passive level.
240 }
241 display_count = clk_mgr_helper_get_active_display_cnt(dc, context);
242 if (dc->res_pool->pp_smu)
243 pp_smu = &dc->res_pool->pp_smu->nv_funcs;
244
245 for (irq_src = DC_IRQ_SOURCE_HPD1; irq_src <= DC_IRQ_SOURCE_HPD6; irq_src++) {
246 hpd_state = dc_get_hpd_state_dcn20(dc->res_pool->irqs, irq_src);
247 if (hpd_state)
248 break;
249 }
250
251 if (display_count == 0 && !hpd_state)
252 enter_display_off = true;
253
254 if (enter_display_off == safe_to_lower) {
255 if (pp_smu && pp_smu->set_display_count)
256 pp_smu->set_display_count(&pp_smu->pp_smu, display_count);
257 }
258
259 if (dc->debug.force_min_dcfclk_mhz > 0)
260 new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > (dc->debug.force_min_dcfclk_mhz * 1000)) ?
261 new_clocks->dcfclk_khz : (dc->debug.force_min_dcfclk_mhz * 1000);
262
263 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) {
264 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz;
265 if (pp_smu && pp_smu->set_hard_min_dcfclk_by_freq)
266 pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_khz));
267 }
268
269 if (should_set_clock(safe_to_lower,
270 new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) {
271 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
272 if (pp_smu && pp_smu->set_min_deep_sleep_dcfclk)
273 pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_deep_sleep_khz));
274 }
275
276 if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr_base->clks.socclk_khz)) {
277 clk_mgr_base->clks.socclk_khz = new_clocks->socclk_khz;
278 if (pp_smu && pp_smu->set_hard_min_socclk_by_freq)
279 pp_smu->set_hard_min_socclk_by_freq(&pp_smu->pp_smu, khz_to_mhz_ceil(clk_mgr_base->clks.socclk_khz));
280 }
281
282 total_plane_count = clk_mgr_helper_get_active_plane_cnt(dc, context);
283 p_state_change_support = new_clocks->p_state_change_support || (total_plane_count == 0);
284 if (should_update_pstate_support(safe_to_lower, p_state_change_support, clk_mgr_base->clks.p_state_change_support)) {
285 clk_mgr_base->clks.prev_p_state_change_support = clk_mgr_base->clks.p_state_change_support;
286 clk_mgr_base->clks.p_state_change_support = p_state_change_support;
287 if (pp_smu && pp_smu->set_pstate_handshake_support)
288 pp_smu->set_pstate_handshake_support(&pp_smu->pp_smu, clk_mgr_base->clks.p_state_change_support);
289 }
290
291 if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr_base->clks.dramclk_khz)) {
292 clk_mgr_base->clks.dramclk_khz = new_clocks->dramclk_khz;
293 if (pp_smu && pp_smu->set_hard_min_uclk_by_freq)
294 pp_smu->set_hard_min_uclk_by_freq(&pp_smu->pp_smu, khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz));
295 }
296
297 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
298 if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
299 dpp_clock_lowered = true;
300 clk_mgr->base.clks.dppclk_khz = new_clocks->dppclk_khz;
301
302 update_dppclk = true;
303 }
304
305 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
306 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
307
308 update_dispclk = true;
309 }
310
311 if (update_dppclk || update_dispclk) {
312 new_clocks->disp_dpp_voltage_level_khz = new_clocks->dppclk_khz;
313
314 if (update_dispclk)
315 new_clocks->disp_dpp_voltage_level_khz = new_clocks->dispclk_khz > new_clocks->dppclk_khz ? new_clocks->dispclk_khz : new_clocks->dppclk_khz;
316
317 clk_mgr_base->clks.disp_dpp_voltage_level_khz = new_clocks->disp_dpp_voltage_level_khz;
318 if (pp_smu && pp_smu->set_voltage_by_freq)
319 pp_smu->set_voltage_by_freq(&pp_smu->pp_smu, PP_SMU_NV_DISPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.disp_dpp_voltage_level_khz));
320 }
321
322 if (dc->config.forced_clocks == false || (force_reset && safe_to_lower)) {
323 if (dpp_clock_lowered) {
324 // if clock is being lowered, increase DTO before lowering refclk
325 dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
326 dcn20_update_clocks_update_dentist(clk_mgr, context);
327 } else {
328 // if clock is being raised, increase refclk before lowering DTO
329 if (update_dppclk || update_dispclk)
330 dcn20_update_clocks_update_dentist(clk_mgr, context);
331 // always update dtos unless clock is lowered and not safe to lower
332 dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
333 }
334 }
335
336 if (update_dispclk &&
337 dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
338 /*update dmcu for wait_loop count*/
339 dmcu->funcs->set_psr_wait_loop(dmcu,
340 clk_mgr_base->clks.dispclk_khz / 1000 / 7);
341 }
342 }
343
dcn2_update_clocks_fpga(struct clk_mgr * clk_mgr,struct dc_state * context,bool safe_to_lower)344 void dcn2_update_clocks_fpga(struct clk_mgr *clk_mgr,
345 struct dc_state *context,
346 bool safe_to_lower)
347 {
348 struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr);
349
350 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
351 /* Min fclk = 1.2GHz since all the extra scemi logic seems to run off of it */
352 int fclk_adj = new_clocks->fclk_khz > 1200000 ? new_clocks->fclk_khz : 1200000;
353
354 if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr->clks.phyclk_khz)) {
355 clk_mgr->clks.phyclk_khz = new_clocks->phyclk_khz;
356 }
357
358 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr->clks.dcfclk_khz)) {
359 clk_mgr->clks.dcfclk_khz = new_clocks->dcfclk_khz;
360 }
361
362 if (should_set_clock(safe_to_lower,
363 new_clocks->dcfclk_deep_sleep_khz, clk_mgr->clks.dcfclk_deep_sleep_khz)) {
364 clk_mgr->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
365 }
366
367 if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr->clks.socclk_khz)) {
368 clk_mgr->clks.socclk_khz = new_clocks->socclk_khz;
369 }
370
371 if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr->clks.dramclk_khz)) {
372 clk_mgr->clks.dramclk_khz = new_clocks->dramclk_khz;
373 }
374
375 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->clks.dppclk_khz)) {
376 clk_mgr->clks.dppclk_khz = new_clocks->dppclk_khz;
377 }
378
379 if (should_set_clock(safe_to_lower, fclk_adj, clk_mgr->clks.fclk_khz)) {
380 clk_mgr->clks.fclk_khz = fclk_adj;
381 }
382
383 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr->clks.dispclk_khz)) {
384 clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz;
385 }
386
387 /* Both fclk and ref_dppclk run on the same scemi clock.
388 * So take the higher value since the DPP DTO is typically programmed
389 * such that max dppclk is 1:1 with ref_dppclk.
390 */
391 if (clk_mgr->clks.fclk_khz > clk_mgr->clks.dppclk_khz)
392 clk_mgr->clks.dppclk_khz = clk_mgr->clks.fclk_khz;
393 if (clk_mgr->clks.dppclk_khz > clk_mgr->clks.fclk_khz)
394 clk_mgr->clks.fclk_khz = clk_mgr->clks.dppclk_khz;
395
396 // Both fclk and ref_dppclk run on the same scemi clock.
397 clk_mgr_int->dccg->ref_dppclk = clk_mgr->clks.fclk_khz;
398
399 /* TODO: set dtbclk in correct place */
400 clk_mgr->clks.dtbclk_en = false;
401 dm_set_dcn_clocks(clk_mgr->ctx, &clk_mgr->clks);
402 }
403
dcn2_init_clocks(struct clk_mgr * clk_mgr)404 void dcn2_init_clocks(struct clk_mgr *clk_mgr)
405 {
406 memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
407 // Assumption is that boot state always supports pstate
408 clk_mgr->clks.p_state_change_support = true;
409 clk_mgr->clks.prev_p_state_change_support = true;
410 }
411
dcn2_enable_pme_wa(struct clk_mgr * clk_mgr_base)412 void dcn2_enable_pme_wa(struct clk_mgr *clk_mgr_base)
413 {
414 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
415 struct pp_smu_funcs_nv *pp_smu = NULL;
416
417 if (clk_mgr->pp_smu) {
418 pp_smu = &clk_mgr->pp_smu->nv_funcs;
419
420 if (pp_smu->set_pme_wa_enable)
421 pp_smu->set_pme_wa_enable(&pp_smu->pp_smu);
422 }
423 }
424
425
dcn2_read_clocks_from_hw_dentist(struct clk_mgr * clk_mgr_base)426 void dcn2_read_clocks_from_hw_dentist(struct clk_mgr *clk_mgr_base)
427 {
428 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
429 uint32_t dispclk_wdivider;
430 uint32_t dppclk_wdivider;
431 int disp_divider;
432 int dpp_divider;
433
434 REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, &dispclk_wdivider);
435 REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, &dppclk_wdivider);
436
437 disp_divider = dentist_get_divider_from_did(dispclk_wdivider);
438 dpp_divider = dentist_get_divider_from_did(dppclk_wdivider);
439
440 if (disp_divider && dpp_divider) {
441 /* Calculate the current DFS clock, in kHz.*/
442 clk_mgr_base->clks.dispclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
443 * clk_mgr->base.dentist_vco_freq_khz) / disp_divider;
444
445 clk_mgr_base->clks.dppclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
446 * clk_mgr->base.dentist_vco_freq_khz) / dpp_divider;
447 }
448
449 }
450
dcn2_get_clock(struct clk_mgr * clk_mgr,struct dc_state * context,enum dc_clock_type clock_type,struct dc_clock_config * clock_cfg)451 void dcn2_get_clock(struct clk_mgr *clk_mgr,
452 struct dc_state *context,
453 enum dc_clock_type clock_type,
454 struct dc_clock_config *clock_cfg)
455 {
456
457 if (clock_type == DC_CLOCK_TYPE_DISPCLK) {
458 clock_cfg->max_clock_khz = context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz;
459 clock_cfg->min_clock_khz = DCN_MINIMUM_DISPCLK_Khz;
460 clock_cfg->current_clock_khz = clk_mgr->clks.dispclk_khz;
461 clock_cfg->bw_requirequired_clock_khz = context->bw_ctx.bw.dcn.clk.bw_dispclk_khz;
462 }
463 if (clock_type == DC_CLOCK_TYPE_DPPCLK) {
464 clock_cfg->max_clock_khz = context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz;
465 clock_cfg->min_clock_khz = DCN_MINIMUM_DPPCLK_Khz;
466 clock_cfg->current_clock_khz = clk_mgr->clks.dppclk_khz;
467 clock_cfg->bw_requirequired_clock_khz = context->bw_ctx.bw.dcn.clk.bw_dppclk_khz;
468 }
469 }
470
dcn2_are_clock_states_equal(struct dc_clocks * a,struct dc_clocks * b)471 static bool dcn2_are_clock_states_equal(struct dc_clocks *a,
472 struct dc_clocks *b)
473 {
474 if (a->dispclk_khz != b->dispclk_khz)
475 return false;
476 else if (a->dppclk_khz != b->dppclk_khz)
477 return false;
478 else if (a->disp_dpp_voltage_level_khz != b->disp_dpp_voltage_level_khz)
479 return false;
480 else if (a->dcfclk_khz != b->dcfclk_khz)
481 return false;
482 else if (a->socclk_khz != b->socclk_khz)
483 return false;
484 else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz)
485 return false;
486 else if (a->dramclk_khz != b->dramclk_khz)
487 return false;
488 else if (a->p_state_change_support != b->p_state_change_support)
489 return false;
490
491 return true;
492 }
493
494 /* Notify clk_mgr of a change in link rate, update phyclk frequency if necessary */
dcn2_notify_link_rate_change(struct clk_mgr * clk_mgr_base,struct dc_link * link)495 static void dcn2_notify_link_rate_change(struct clk_mgr *clk_mgr_base, struct dc_link *link)
496 {
497 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
498 unsigned int i, max_phyclk_req = 0;
499 struct pp_smu_funcs_nv *pp_smu = NULL;
500
501 if (!clk_mgr->pp_smu || !clk_mgr->pp_smu->nv_funcs.set_voltage_by_freq)
502 return;
503
504 pp_smu = &clk_mgr->pp_smu->nv_funcs;
505
506 clk_mgr->cur_phyclk_req_table[link->link_index] = link->cur_link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
507
508 for (i = 0; i < MAX_PIPES * 2; i++) {
509 if (clk_mgr->cur_phyclk_req_table[i] > max_phyclk_req)
510 max_phyclk_req = clk_mgr->cur_phyclk_req_table[i];
511 }
512
513 if (max_phyclk_req != clk_mgr_base->clks.phyclk_khz) {
514 clk_mgr_base->clks.phyclk_khz = max_phyclk_req;
515 pp_smu->set_voltage_by_freq(&pp_smu->pp_smu, PP_SMU_NV_PHYCLK, khz_to_mhz_ceil(clk_mgr_base->clks.phyclk_khz));
516 }
517 }
518
519 static struct clk_mgr_funcs dcn2_funcs = {
520 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
521 .update_clocks = dcn2_update_clocks,
522 .init_clocks = dcn2_init_clocks,
523 .enable_pme_wa = dcn2_enable_pme_wa,
524 .get_clock = dcn2_get_clock,
525 .are_clock_states_equal = dcn2_are_clock_states_equal,
526 .notify_link_rate_change = dcn2_notify_link_rate_change,
527 };
528
529
dcn20_clk_mgr_construct(struct dc_context * ctx,struct clk_mgr_internal * clk_mgr,struct pp_smu_funcs * pp_smu,struct dccg * dccg)530 void dcn20_clk_mgr_construct(
531 struct dc_context *ctx,
532 struct clk_mgr_internal *clk_mgr,
533 struct pp_smu_funcs *pp_smu,
534 struct dccg *dccg)
535 {
536 clk_mgr->base.ctx = ctx;
537 clk_mgr->pp_smu = pp_smu;
538 clk_mgr->base.funcs = &dcn2_funcs;
539 clk_mgr->regs = &clk_mgr_regs;
540 clk_mgr->clk_mgr_shift = &clk_mgr_shift;
541 clk_mgr->clk_mgr_mask = &clk_mgr_mask;
542
543 clk_mgr->dccg = dccg;
544 clk_mgr->dfs_bypass_disp_clk = 0;
545
546 clk_mgr->dprefclk_ss_percentage = 0;
547 clk_mgr->dprefclk_ss_divider = 1000;
548 clk_mgr->ss_on_dprefclk = false;
549
550 clk_mgr->base.dprefclk_khz = 700000; // 700 MHz planned if VCO is 3.85 GHz, will be retrieved
551
552 if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) {
553 dcn2_funcs.update_clocks = dcn2_update_clocks_fpga;
554 clk_mgr->base.dentist_vco_freq_khz = 3850000;
555
556 } else {
557 /* DFS Slice 2 should be used for DPREFCLK */
558 int dprefclk_did = REG_READ(CLK3_CLK2_DFS_CNTL);
559 /* Convert DPREFCLK DFS Slice DID to actual divider*/
560 int target_div = dentist_get_divider_from_did(dprefclk_did);
561
562 /* get FbMult value */
563 uint32_t pll_req_reg = REG_READ(CLK3_CLK_PLL_REQ);
564 struct fixed31_32 pll_req;
565
566 /* set up a fixed-point number
567 * this works because the int part is on the right edge of the register
568 * and the frac part is on the left edge
569 */
570
571 pll_req = dc_fixpt_from_int(pll_req_reg & clk_mgr->clk_mgr_mask->FbMult_int);
572 pll_req.value |= pll_req_reg & clk_mgr->clk_mgr_mask->FbMult_frac;
573
574 /* multiply by REFCLK period */
575 pll_req = dc_fixpt_mul_int(pll_req, 100000);
576
577 /* integer part is now VCO frequency in kHz */
578 clk_mgr->base.dentist_vco_freq_khz = dc_fixpt_floor(pll_req);
579
580 /* in case we don't get a value from the register, use default */
581 if (clk_mgr->base.dentist_vco_freq_khz == 0)
582 clk_mgr->base.dentist_vco_freq_khz = 3850000;
583
584 /* Calculate the DPREFCLK in kHz.*/
585 clk_mgr->base.dprefclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
586 * clk_mgr->base.dentist_vco_freq_khz) / target_div;
587 }
588 //Integrated_info table does not exist on dGPU projects so should not be referenced
589 //anywhere in code for dGPUs.
590 //Also there is no plan for now that DFS BYPASS will be used on NV10/12/14.
591 clk_mgr->dfs_bypass_enabled = false;
592
593 dce_clock_read_ss_info(clk_mgr);
594 }
595
596