1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2026 Advanced Micro Devices, Inc.
4
5 #include "dcn42_clk_mgr.h"
6
7 #include "dccg.h"
8 #include "clk_mgr_internal.h"
9
10 // For dce12_get_dp_ref_freq_khz
11 #include "dce100/dce_clk_mgr.h"
12
13 // For dcn20_update_clocks_update_dpp_dto
14 #include "dcn20/dcn20_clk_mgr.h"
15
16
17
18
19 #include "reg_helper.h"
20 #include "core_types.h"
21 #include "dcn42_smu.h"
22 #include "dm_helpers.h"
23
24 /* TODO: remove this include once we ported over remaining clk mgr functions*/
25 #include "dcn30/dcn30_clk_mgr.h"
26 #include "dcn31/dcn31_clk_mgr.h"
27
28 #include "dcn35/dcn35_clk_mgr.h"
29
30 #include "dc_dmub_srv.h"
31 #include "link_service.h"
32 #include "logger_types.h"
33
34 #include "clk/clk_15_0_0_offset.h"
35 #include "clk/clk_15_0_0_sh_mask.h"
36 #include "dcn/dcn_4_2_0_offset.h"
37 #include "dcn/dcn_4_2_0_sh_mask.h"
38
39
40 #undef DC_LOGGER
41 #define DC_LOGGER \
42 dc_logger
43 #define DC_LOGGER_INIT(logger) \
44 struct dal_logger *dc_logger = logger
45
46 #undef FN
47 #define FN(reg_name, field_name) \
48 clk_mgr->clk_mgr_shift->field_name, clk_mgr->clk_mgr_mask->field_name
49
50 #define REG(reg) \
51 (clk_mgr->regs->reg)
52
53 // for DCN register access
54 #define DCN_BASE__INST0_SEG0 0x00000012
55 #define DCN_BASE__INST0_SEG1 0x000000C0
56
57 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
58
59 #define BASE(seg) BASE_INNER(seg)
60
61 #define SR(reg_name) \
62 .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name
63
64 // for CLKIP register access
65 #define CLK_BASE__INST0_SEG0 0x00016C00
66
67 #define CLK_BASE_INNER(seg) \
68 CLK_BASE__INST0_SEG ## seg
69
70 #define CLK_SR_DCN42(reg_name) \
71 .reg_name = CLK_BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name
72
73 static const struct clk_mgr_registers clk_mgr_regs_dcn42 = {
74 CLK_REG_LIST_DCN42()
75 };
76
77 static const struct clk_mgr_shift clk_mgr_shift_dcn42 = {
78 CLK_COMMON_MASK_SH_LIST_DCN42(__SHIFT)
79 };
80
81 static const struct clk_mgr_mask clk_mgr_mask_dcn42 = {
82 CLK_COMMON_MASK_SH_LIST_DCN42(_MASK)
83 };
84
85 #define TO_CLK_MGR_DCN42(clk_mgr_int)\
86 container_of(clk_mgr_int, struct clk_mgr_dcn42, base)
87
dcn42_has_active_display(struct dc * dc,const struct dc_state * context)88 bool dcn42_has_active_display(struct dc *dc, const struct dc_state *context)
89 {
90 int i, active_count = 0;
91
92 for (i = 0; i < context->stream_count; i++) {
93 const struct dc_stream_state *stream = context->streams[i];
94
95 /* Checking stream / link detection ensuring that PHY is active*/
96 if (dc_is_hdmi_signal(stream->signal) ||
97 dc_is_dvi_signal(stream->signal) ||
98 (dc_is_dp_signal(stream->signal) && !stream->dpms_off))
99 active_count++;
100 }
101
102 for (i = 0; i < dc->link_count; i++) {
103 const struct dc_link *link = dc->links[i];
104
105 /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */
106 if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
107 link->link_enc->funcs->is_dig_enabled(link->link_enc))
108 active_count++;
109 }
110
111 return active_count > 0;
112 }
113
dcn42_get_clock_freq_from_clkip(struct clk_mgr * clk_mgr_base,enum clock_type clock)114 static uint32_t dcn42_get_clock_freq_from_clkip(struct clk_mgr *clk_mgr_base, enum clock_type clock)
115 {
116 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
117 uint64_t clock_freq_mhz = 0;
118 uint32_t timer_threshold = 0;
119
120 // always safer to read the timer threshold instead of using cached value
121 REG_GET(CLK8_CLK_TICK_CNT_CONFIG_REG, TIMER_THRESHOLD, &timer_threshold);
122
123 if (timer_threshold == 0) {
124 BREAK_TO_DEBUGGER();
125 return 0;
126 }
127
128 switch (clock) {
129 case clock_type_dispclk:
130 clock_freq_mhz = REG_READ(CLK8_CLK0_CURRENT_CNT);
131 break;
132 case clock_type_dppclk:
133 clock_freq_mhz = REG_READ(CLK8_CLK1_CURRENT_CNT);
134 break;
135 case clock_type_dprefclk:
136 clock_freq_mhz = REG_READ(CLK8_CLK2_CURRENT_CNT);
137 break;
138 case clock_type_dcfclk:
139 clock_freq_mhz = REG_READ(CLK8_CLK3_CURRENT_CNT);
140 break;
141 case clock_type_dtbclk:
142 clock_freq_mhz = REG_READ(CLK8_CLK4_CURRENT_CNT);
143 break;
144 default:
145 break;
146 }
147
148 clock_freq_mhz *= DCN42_CLKIP_REFCLK;
149 clock_freq_mhz = div_u64(clock_freq_mhz, timer_threshold);
150
151 // there are no DCN clocks over 0xFFFFFFFF MHz
152 ASSERT(clock_freq_mhz <= 0xFFFFFFFF);
153
154 return (uint32_t)clock_freq_mhz;
155 }
156
dcn42_update_clocks_update_dtb_dto(struct clk_mgr_internal * clk_mgr,struct dc_state * context,int ref_dtbclk_khz)157 void dcn42_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
158 struct dc_state *context,
159 int ref_dtbclk_khz)
160 {
161 (void)clk_mgr;
162 (void)context;
163 (void)ref_dtbclk_khz;
164 /* DCN42 does not implement set_dtbclk_dto function, so this is a no-op */
165 }
166
dcn42_update_clocks_update_dpp_dto(struct clk_mgr_internal * clk_mgr,struct dc_state * context,bool safe_to_lower)167 void dcn42_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr,
168 struct dc_state *context, bool safe_to_lower)
169 {
170 int i;
171 bool dppclk_active[MAX_PIPES] = {0};
172
173
174 clk_mgr->dccg->ref_dppclk = clk_mgr->base.clks.dppclk_khz;
175 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
176 int dpp_inst = 0, dppclk_khz, prev_dppclk_khz;
177
178 dppclk_khz = context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz;
179
180 if (context->res_ctx.pipe_ctx[i].plane_res.dpp)
181 dpp_inst = context->res_ctx.pipe_ctx[i].plane_res.dpp->inst;
182 else if (!context->res_ctx.pipe_ctx[i].plane_res.dpp && dppclk_khz == 0) {
183 /* dpp == NULL && dppclk_khz == 0 is valid because of pipe harvesting.
184 * In this case just continue in loop
185 */
186 continue;
187 } else if (!context->res_ctx.pipe_ctx[i].plane_res.dpp && dppclk_khz > 0) {
188 /* The software state is not valid if dpp resource is NULL and
189 * dppclk_khz > 0.
190 */
191 ASSERT(false);
192 continue;
193 }
194
195 prev_dppclk_khz = clk_mgr->dccg->pipe_dppclk_khz[i];
196
197 if (safe_to_lower || prev_dppclk_khz < dppclk_khz)
198 clk_mgr->dccg->funcs->update_dpp_dto(
199 clk_mgr->dccg, dpp_inst, dppclk_khz);
200 dppclk_active[dpp_inst] = true;
201 }
202 if (safe_to_lower)
203 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
204 struct dpp *old_dpp = clk_mgr->base.ctx->dc->current_state->res_ctx.pipe_ctx[i].plane_res.dpp;
205
206 if (old_dpp && !dppclk_active[old_dpp->inst])
207 clk_mgr->dccg->funcs->update_dpp_dto(clk_mgr->dccg, old_dpp->inst, 0);
208 }
209 }
210
dcn42_update_clocks(struct clk_mgr * clk_mgr_base,struct dc_state * context,bool safe_to_lower)211 void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
212 struct dc_state *context,
213 bool safe_to_lower)
214 {
215 union dmub_rb_cmd cmd;
216 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
217 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
218 struct dc *dc = clk_mgr_base->ctx->dc;
219 bool update_dppclk = false;
220 bool update_dispclk = false;
221 bool dpp_clock_lowered = false;
222 bool has_active_display;
223
224 if (dc->work_arounds.skip_clock_update)
225 return;
226
227 has_active_display = dcn42_has_active_display(dc, context);
228
229 if (new_clocks->dtbclk_en && new_clocks->ref_dtbclk_khz < 590000)
230 new_clocks->ref_dtbclk_khz = 600000;
231 /*
232 * if it is safe to lower, but we are already in the lower state, we don't have to do anything
233 * also if safe to lower is false, we just go in the higher state
234 */
235 if (safe_to_lower) {
236 if (new_clocks->zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW &&
237 new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
238 dcn42_smu_set_zstate_support(clk_mgr, new_clocks->zstate_support);
239 clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
240 }
241
242 if (clk_mgr_base->clks.dtbclk_en && !new_clocks->dtbclk_en) {
243 if (clk_mgr->base.ctx->dc->config.allow_0_dtb_clk)
244 dcn42_smu_set_dtbclk(clk_mgr, false);
245 clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en;
246 }
247 /* check that we're not already in lower */
248 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
249 /* if we can go lower, go lower */
250 if (has_active_display == false)
251 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
252 }
253 } else {
254 if (new_clocks->zstate_support == DCN_ZSTATE_SUPPORT_DISALLOW &&
255 new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
256 dcn42_smu_set_zstate_support(clk_mgr, DCN_ZSTATE_SUPPORT_DISALLOW);
257 clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
258 }
259 /* Only attempt to enable dtbclk if currently disabled AND new state requests it.
260 * For dcn42b (no dtbclk hardware), init_clk_states sets dtbclk_en=false and
261 * new_clocks->dtbclk_en should always be false, so this block never executes.
262 */
263 if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) {
264 int actual_dtbclk = 0;
265
266 dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz);
267 dcn42_smu_set_dtbclk(clk_mgr, true);
268 actual_dtbclk = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk);
269
270 if (actual_dtbclk > 590000) {
271 clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz;
272 clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en;
273 }
274 }
275
276 /* check that we're not already in D0 */
277 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) {
278 union display_idle_optimization_u idle_info = { 0 };
279
280 dcn42_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
281 /* update power state */
282 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE;
283 }
284 }
285 if (dc->debug.force_min_dcfclk_mhz > 0)
286 new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > (dc->debug.force_min_dcfclk_mhz * 1000)) ?
287 new_clocks->dcfclk_khz : (dc->debug.force_min_dcfclk_mhz * 1000);
288
289 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) {
290 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz;
291 clk_mgr_base->clks.fclk_khz = new_clocks->fclk_khz;
292 clk_mgr_base->clks.dramclk_khz = new_clocks->dramclk_khz;
293 dcn42_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz);
294 }
295
296 if (should_set_clock(safe_to_lower,
297 new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) {
298 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
299
300 /* Clamp the requested clock to PMFW based on DCN limit. */
301 if (dc->debug.min_deep_sleep_dcfclk_khz > 0 && clk_mgr_base->clks.dcfclk_deep_sleep_khz < dc->debug.min_deep_sleep_dcfclk_khz)
302 clk_mgr_base->clks.dcfclk_deep_sleep_khz = dc->debug.min_deep_sleep_dcfclk_khz;
303
304 dcn42_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz);
305 }
306
307 // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow.
308
309 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
310 if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
311 dpp_clock_lowered = true;
312 clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
313 update_dppclk = true;
314 }
315
316 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) &&
317 (new_clocks->dispclk_khz > 0 || (safe_to_lower && has_active_display == false))) {
318 int requested_dispclk_khz = new_clocks->dispclk_khz;
319
320 dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true);
321
322 /* Clamp the requested clock to PMFW based on their limit. */
323 if (dc->debug.min_disp_clk_khz > 0 && requested_dispclk_khz < dc->debug.min_disp_clk_khz)
324 requested_dispclk_khz = dc->debug.min_disp_clk_khz;
325
326 dcn42_smu_set_dispclk(clk_mgr, requested_dispclk_khz);
327 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
328 dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false);
329
330 update_dispclk = true;
331 }
332
333 /* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */
334 if (!dc->debug.disable_dtb_ref_clk_switch && new_clocks->dtbclk_en &&
335 should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000,
336 clk_mgr_base->clks.ref_dtbclk_khz / 1000)) {
337 dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz);
338 clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz;
339 }
340
341 if (dpp_clock_lowered) {
342 // increase per DPP DTO before lowering global dppclk
343 dcn42_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
344 dcn42_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
345 } else {
346 // increase global DPPCLK before lowering per DPP DTO
347 if (update_dppclk || update_dispclk)
348 dcn42_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
349 dcn42_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
350 }
351 // notify DMCUB of latest clocks
352 memset(&cmd, 0, sizeof(cmd));
353 cmd.notify_clocks.header.type = DMUB_CMD__CLK_MGR;
354 cmd.notify_clocks.header.sub_type = DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS;
355 cmd.notify_clocks.clocks.dcfclk_khz = clk_mgr_base->clks.dcfclk_khz;
356 cmd.notify_clocks.clocks.dcfclk_deep_sleep_khz =
357 clk_mgr_base->clks.dcfclk_deep_sleep_khz;
358 cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz;
359 cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz;
360
361 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
362 }
363
364
dcn42_enable_pme_wa(struct clk_mgr * clk_mgr_base)365 void dcn42_enable_pme_wa(struct clk_mgr *clk_mgr_base)
366 {
367 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
368
369 dcn42_smu_enable_pme_wa(clk_mgr);
370 }
371
372
dcn42_are_clock_states_equal(struct dc_clocks * a,struct dc_clocks * b)373 bool dcn42_are_clock_states_equal(struct dc_clocks *a,
374 struct dc_clocks *b)
375 {
376 if (a->dispclk_khz != b->dispclk_khz)
377 return false;
378 else if (a->dppclk_khz != b->dppclk_khz)
379 return false;
380 else if (a->dcfclk_khz != b->dcfclk_khz)
381 return false;
382 else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz)
383 return false;
384 else if (a->zstate_support != b->zstate_support)
385 return false;
386 else if (a->dtbclk_en != b->dtbclk_en)
387 return false;
388
389 return true;
390 }
391
dcn42_dump_clk_registers_internal(struct dcn42_clk_internal * internal,struct clk_mgr * clk_mgr_base)392 static void dcn42_dump_clk_registers_internal(struct dcn42_clk_internal *internal, struct clk_mgr *clk_mgr_base)
393 {
394 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
395
396 REG_GET(CLK8_CLK_TICK_CNT_CONFIG_REG, TIMER_THRESHOLD, &internal->CLK8_CLK_TICK_CNT__TIMER_THRESHOLD);
397
398 // read dcf deep sleep divider
399 internal->CLK8_CLK0_DS_CNTL = REG_READ(CLK8_CLK0_DS_CNTL);
400 internal->CLK8_CLK3_DS_CNTL = REG_READ(CLK8_CLK3_DS_CNTL);
401 // read dispclk
402 internal->CLK8_CLK0_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dispclk);
403 internal->CLK8_CLK0_BYPASS_CNTL = REG_READ(CLK8_CLK0_BYPASS_CNTL);
404 // read dppclk
405 internal->CLK8_CLK1_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dppclk);
406 internal->CLK8_CLK1_BYPASS_CNTL = REG_READ(CLK8_CLK1_BYPASS_CNTL);
407 // read dprefclk
408 internal->CLK8_CLK2_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dprefclk);
409 internal->CLK8_CLK2_BYPASS_CNTL = REG_READ(CLK8_CLK2_BYPASS_CNTL);
410 // read dcfclk
411 internal->CLK8_CLK3_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dcfclk);
412 internal->CLK8_CLK3_BYPASS_CNTL = REG_READ(CLK8_CLK3_BYPASS_CNTL);
413 // read dtbclk
414 internal->CLK8_CLK4_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk);
415 internal->CLK8_CLK4_BYPASS_CNTL = REG_READ(CLK8_CLK4_BYPASS_CNTL);
416 }
417
dcn42_dump_clk_registers(struct clk_state_registers_and_bypass * regs_and_bypass,struct clk_mgr_dcn42 * clk_mgr)418 static void dcn42_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
419 struct clk_mgr_dcn42 *clk_mgr)
420 {
421 struct dcn42_clk_internal internal = {0};
422 char *bypass_clks[5] = {"0x0 DFS", "0x1 REFCLK", "0x2 ERROR", "0x3 400 FCH", "0x4 600 FCH"};
423
424 DC_LOGGER_INIT(clk_mgr->base.base.ctx->logger);
425 (void)dc_logger;
426
427 dcn42_dump_clk_registers_internal(&internal, &clk_mgr->base.base);
428 regs_and_bypass->timer_threshold = internal.CLK8_CLK_TICK_CNT__TIMER_THRESHOLD;
429 regs_and_bypass->dcfclk = internal.CLK8_CLK3_CURRENT_CNT / 10;
430 regs_and_bypass->dcf_deep_sleep_divider = internal.CLK8_CLK3_DS_CNTL / 10;
431 regs_and_bypass->dcf_deep_sleep_allow = internal.CLK8_CLK3_DS_CNTL & 0x10; /*bit 4: CLK0_ALLOW_DS*/
432 regs_and_bypass->dprefclk = internal.CLK8_CLK2_CURRENT_CNT / 10;
433 regs_and_bypass->dispclk = internal.CLK8_CLK0_CURRENT_CNT / 10;
434 regs_and_bypass->dppclk = internal.CLK8_CLK1_CURRENT_CNT / 10;
435 regs_and_bypass->dtbclk = internal.CLK8_CLK4_CURRENT_CNT / 10;
436
437 regs_and_bypass->dispclk_bypass = get_reg_field_value(internal.CLK8_CLK0_BYPASS_CNTL, CLK8_CLK0_BYPASS_CNTL, CLK0_BYPASS_SEL);
438 regs_and_bypass->dppclk_bypass = get_reg_field_value(internal.CLK8_CLK1_BYPASS_CNTL, CLK8_CLK1_BYPASS_CNTL, CLK1_BYPASS_SEL);
439 regs_and_bypass->dprefclk_bypass = get_reg_field_value(internal.CLK8_CLK2_BYPASS_CNTL, CLK8_CLK2_BYPASS_CNTL, CLK2_BYPASS_SEL);
440 regs_and_bypass->dcfclk_bypass = get_reg_field_value(internal.CLK8_CLK3_BYPASS_CNTL, CLK8_CLK3_BYPASS_CNTL, CLK3_BYPASS_SEL);
441
442 if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) {
443 DC_LOG_SMU("clk_type,clk_value,deepsleep_cntl,deepsleep_allow,bypass\n");
444
445 DC_LOG_SMU("dcfclk,%d,%d,%d,%s\n",
446 regs_and_bypass->dcfclk,
447 regs_and_bypass->dcf_deep_sleep_divider,
448 regs_and_bypass->dcf_deep_sleep_allow,
449 bypass_clks[(int) regs_and_bypass->dcfclk_bypass]);
450
451 DC_LOG_SMU("dprefclk,%d,N/A,N/A,%s\n",
452 regs_and_bypass->dprefclk,
453 bypass_clks[(int) regs_and_bypass->dprefclk_bypass]);
454
455 DC_LOG_SMU("dispclk,%d,N/A,N/A,%s\n",
456 regs_and_bypass->dispclk,
457 bypass_clks[(int) regs_and_bypass->dispclk_bypass]);
458
459 //split
460 DC_LOG_SMU("SPLIT\n");
461
462 // REGISTER VALUES
463 DC_LOG_SMU("reg_name,value,clk_type\n");
464 DC_LOG_SMU("CLK1_CLK3_CURRENT_CNT,%d,dcfclk\n",
465 internal.CLK8_CLK3_CURRENT_CNT);
466
467 DC_LOG_SMU("CLK1_CLK3_DS_CNTL,%d,dcf_deep_sleep_divider\n",
468 internal.CLK8_CLK3_DS_CNTL);
469
470 DC_LOG_SMU("CLK1_CLK3_ALLOW_DS,%d,dcf_deep_sleep_allow\n",
471 (internal.CLK8_CLK3_DS_CNTL & 0x10));
472
473 DC_LOG_SMU("CLK1_CLK2_CURRENT_CNT,%d,dprefclk\n",
474 internal.CLK8_CLK2_CURRENT_CNT);
475
476 DC_LOG_SMU("CLK1_CLK0_CURRENT_CNT,%d,dispclk\n",
477 internal.CLK8_CLK0_CURRENT_CNT);
478
479 DC_LOG_SMU("CLK1_CLK1_CURRENT_CNT,%d,dppclk\n",
480 internal.CLK8_CLK1_CURRENT_CNT);
481
482 DC_LOG_SMU("CLK1_CLK4_CURRENT_CNT,%d,dtbclk\n",
483 internal.CLK8_CLK4_CURRENT_CNT);
484
485 DC_LOG_SMU("CLK1_CLK3_BYPASS_CNTL,%d,dcfclk_bypass\n",
486 internal.CLK8_CLK3_BYPASS_CNTL);
487
488 DC_LOG_SMU("CLK1_CLK2_BYPASS_CNTL,%d,dprefclk_bypass\n",
489 internal.CLK8_CLK2_BYPASS_CNTL);
490
491 DC_LOG_SMU("CLK1_CLK0_BYPASS_CNTL,%d,dispclk_bypass\n",
492 internal.CLK8_CLK0_BYPASS_CNTL);
493
494 DC_LOG_SMU("CLK1_CLK1_BYPASS_CNTL,%d,dppclk_bypass\n",
495 internal.CLK8_CLK1_BYPASS_CNTL);
496 }
497 }
498
dcn42_is_spll_ssc_enabled(struct clk_mgr * clk_mgr_base)499 bool dcn42_is_spll_ssc_enabled(struct clk_mgr *clk_mgr_base)
500 {
501 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
502 struct dc_context *ctx = clk_mgr->base.ctx;
503
504
505 if (ctx->dc->config.ignore_dpref_ss) {
506 /*revert bios's ss info for test only*/
507 return (clk_mgr->dprefclk_ss_percentage == 0);
508 }
509 /*need to update after BU*/
510 return false;
511 }
512
init_clk_states(struct clk_mgr * clk_mgr)513 static void init_clk_states(struct clk_mgr *clk_mgr)
514 {
515 uint32_t ref_dtbclk = clk_mgr->clks.ref_dtbclk_khz;
516
517 memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
518
519 clk_mgr->clks.dtbclk_en = true; // request DTBCLK disable on first commit
520 clk_mgr->clks.ref_dtbclk_khz = ref_dtbclk; // restore ref_dtbclk
521 clk_mgr->clks.p_state_change_support = true;
522 clk_mgr->clks.prev_p_state_change_support = true;
523 clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN;
524 clk_mgr->clks.zstate_support = DCN_ZSTATE_SUPPORT_UNKNOWN;
525 }
526
dcn42_get_dpm_table_from_smu(struct clk_mgr_internal * clk_mgr,struct dcn42_smu_dpm_clks * smu_dpm_clks)527 void dcn42_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
528 struct dcn42_smu_dpm_clks *smu_dpm_clks)
529 {
530 DpmClocks_t_dcn42 *table = smu_dpm_clks->dpm_clks;
531
532 if (!clk_mgr->smu_ver)
533 return;
534
535 if (!table || smu_dpm_clks->mc_address.quad_part == 0)
536 return;
537
538 memset(table, 0, sizeof(*table));
539
540 dcn42_smu_set_dram_addr_high(clk_mgr,
541 smu_dpm_clks->mc_address.high_part);
542 dcn42_smu_set_dram_addr_low(clk_mgr,
543 smu_dpm_clks->mc_address.low_part);
544 dcn42_smu_transfer_dpm_table_smu_2_dram(clk_mgr);
545 }
546
dcn42_init_single_clock(unsigned int * entry_0,uint32_t * smu_entry_0,uint8_t num_levels)547 void dcn42_init_single_clock(unsigned int *entry_0,
548 uint32_t *smu_entry_0,
549 uint8_t num_levels)
550 {
551 int i;
552 char *entry_i = (char *)entry_0;
553
554 ASSERT(num_levels <= MAX_NUM_DPM_LVL);
555 if (num_levels > MAX_NUM_DPM_LVL)
556 num_levels = MAX_NUM_DPM_LVL;
557
558
559 for (i = 0; i < num_levels; i++) {
560 *((unsigned int *)entry_i) = smu_entry_0[i];
561 entry_i += sizeof(struct clk_limit_table_entry);
562 }
563 }
564
dcn42_convert_wck_ratio(uint8_t wck_ratio)565 unsigned int dcn42_convert_wck_ratio(uint8_t wck_ratio)
566 {
567 switch (wck_ratio) {
568 case WCK_RATIO_1_2:
569 return 2;
570
571 case WCK_RATIO_1_4:
572 return 4;
573
574 default:
575 break;
576 }
577
578 return 1;
579 }
580
dcn42_init_clocks(struct clk_mgr * clk_mgr_base)581 void dcn42_init_clocks(struct clk_mgr *clk_mgr_base)
582 {
583 struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr_base);
584 struct clk_mgr_dcn42 *clk_mgr = TO_CLK_MGR_DCN42(clk_mgr_int);
585
586 DC_LOGGER_INIT(clk_mgr_base->ctx->logger);
587 (void)dc_logger;
588
589 init_clk_states(clk_mgr_base);
590
591 // to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk
592 if (dcn42_is_spll_ssc_enabled(clk_mgr_base))
593 clk_mgr_base->dp_dto_source_clock_in_khz =
594 dce_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr_base->dprefclk_khz);
595 else
596 clk_mgr_base->dp_dto_source_clock_in_khz = clk_mgr_base->dprefclk_khz;
597
598 DC_LOG_SMU("dp_dto_source_clock %d, dprefclk %d\n", clk_mgr_base->dp_dto_source_clock_in_khz, clk_mgr_base->dprefclk_khz);
599 dcn42_dump_clk_registers(&clk_mgr_base->boot_snapshot, clk_mgr);
600
601 clk_mgr_base->clks.ref_dtbclk_khz = clk_mgr_base->boot_snapshot.dtbclk * 10;
602 clk_mgr_base->clks.dtbclk_en = clk_mgr_base->boot_snapshot.dtbclk > 59000;
603 }
604
605 static struct clk_bw_params dcn42_bw_params = {
606 .vram_type = Ddr4MemType,
607 .num_channels = 1,
608 .clk_table = {
609 .num_entries = 4,
610 },
611
612 };
613
614 struct dcn42_ss_info_table dcn42_ss_info_table = {
615 .ss_divider = 1000,
616 .ss_percentage = {0, 0, 375, 375, 375}
617 };
618
dcn42_read_ss_info_from_lut(struct clk_mgr_internal * clk_mgr)619 static void dcn42_read_ss_info_from_lut(struct clk_mgr_internal *clk_mgr)
620 {
621 uint32_t clock_source;
622
623 clock_source = (REG_READ(CLK8_CLK2_BYPASS_CNTL) & CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL_MASK);
624 // If it's DFS mode, clock_source is 0.
625 if (dcn42_is_spll_ssc_enabled(&clk_mgr->base) && (clock_source < ARRAY_SIZE(dcn42_ss_info_table.ss_percentage))) {
626 clk_mgr->dprefclk_ss_percentage = dcn42_ss_info_table.ss_percentage[clock_source];
627
628 if (clk_mgr->dprefclk_ss_percentage != 0) {
629 clk_mgr->ss_on_dprefclk = true;
630 clk_mgr->dprefclk_ss_divider = dcn42_ss_info_table.ss_divider;
631 }
632 }
633 }
634
dcn42_build_watermark_ranges(struct clk_bw_params * bw_params,struct dcn42_watermarks * table)635 void dcn42_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn42_watermarks *table)
636 {
637 int i, num_valid_sets;
638
639 num_valid_sets = 0;
640
641 for (i = 0; i < WM_SET_COUNT; i++) {
642 /* skip empty entries, the smu array has no holes*/
643 if (!bw_params->wm_table.entries[i].valid)
644 continue;
645
646 table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmSetting = bw_params->wm_table.entries[i].wm_inst;
647 table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType = bw_params->wm_table.entries[i].wm_type;
648 /* We will not select WM based on fclk, so leave it as unconstrained */
649 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
650 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
651
652 if (table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType == WM_TYPE_PSTATE_CHG) {
653 if (i == 0)
654 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 0;
655 else {
656 /* add 1 to make it non-overlapping with next lvl */
657 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk =
658 bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1;
659 }
660 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxMclk =
661 bw_params->clk_table.entries[i].dcfclk_mhz;
662
663 } else {
664 /* unconstrained for memory retraining */
665 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
666 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
667
668 /* Modify previous watermark range to cover up to max */
669 if (num_valid_sets > 0)
670 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
671 }
672 num_valid_sets++;
673 }
674
675 ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */
676
677 /* modify the min and max to make sure we cover the whole range*/
678 table->WatermarkRow[WM_DCFCLK][0].MinMclk = 0;
679 table->WatermarkRow[WM_DCFCLK][0].MinClock = 0;
680 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxMclk = 0xFFFF;
681 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
682
683 /* This is for writeback only, does not matter currently as no writeback support*/
684 table->WatermarkRow[WM_SOCCLK][0].WmSetting = WM_A;
685 table->WatermarkRow[WM_SOCCLK][0].MinClock = 0;
686 table->WatermarkRow[WM_SOCCLK][0].MaxClock = 0xFFFF;
687 table->WatermarkRow[WM_SOCCLK][0].MinMclk = 0;
688 table->WatermarkRow[WM_SOCCLK][0].MaxMclk = 0xFFFF;
689 }
690
dcn42_notify_wm_ranges(struct clk_mgr * clk_mgr_base)691 void dcn42_notify_wm_ranges(struct clk_mgr *clk_mgr_base)
692 {
693 int i = 0;
694 struct dcn42_watermarks *table = NULL;
695 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
696 struct clk_mgr_dcn42 *clk_mgr_dcn42 = TO_CLK_MGR_DCN42(clk_mgr);
697
698 if (!clk_mgr->smu_ver)
699 return;
700 /*send once already skip*/
701 if (clk_mgr_base->bw_params->wm_table.entries[WM_A].valid == true)
702 return;
703 clk_mgr_dcn42->smu_wm_set.wm_set = (struct dcn42_watermarks *)dm_helpers_allocate_gpu_mem(
704 clk_mgr->base.ctx,
705 DC_MEM_ALLOC_TYPE_GART,
706 sizeof(struct dcn42_watermarks),
707 &clk_mgr_dcn42->smu_wm_set.mc_address.quad_part);
708
709 ASSERT(clk_mgr_dcn42->smu_wm_set.wm_set);
710
711 table = clk_mgr_dcn42->smu_wm_set.wm_set;
712
713 if (!table || clk_mgr_dcn42->smu_wm_set.mc_address.quad_part == 0)
714 return;
715
716 memset(table, 0, sizeof(*table));
717 /*same as previous asic, set wm valid before building watermark ranges*/
718 for (i = 0; i < WM_SET_COUNT; i++) {
719 clk_mgr_base->bw_params->wm_table.entries[i].wm_inst = i;
720
721 if (i >= clk_mgr_base->bw_params->clk_table.num_entries) {
722 clk_mgr_base->bw_params->wm_table.entries[i].valid = false;
723 continue;
724 }
725 clk_mgr_base->bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG;
726 clk_mgr_base->bw_params->wm_table.entries[i].valid = true;
727 }
728 /* build watermark_range will check this valid range*/
729 dcn42_build_watermark_ranges(clk_mgr_base->bw_params, table);
730
731 dcn42_smu_set_dram_addr_high(clk_mgr,
732 clk_mgr_dcn42->smu_wm_set.mc_address.high_part);
733 dcn42_smu_set_dram_addr_low(clk_mgr,
734 clk_mgr_dcn42->smu_wm_set.mc_address.low_part);
735 dcn42_smu_transfer_wm_table_dram_2_smu(clk_mgr);
736
737 if (clk_mgr_dcn42->smu_wm_set.wm_set && clk_mgr_dcn42->smu_wm_set.mc_address.quad_part != 0)
738 dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART,
739 clk_mgr_dcn42->smu_wm_set.wm_set);
740
741 }
742
dcn42_set_low_power_state(struct clk_mgr * clk_mgr_base)743 void dcn42_set_low_power_state(struct clk_mgr *clk_mgr_base)
744 {
745 struct dc *dc = clk_mgr_base->ctx->dc;
746 struct dc_state *context = dc->current_state;
747
748 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
749 /* if we can go lower, go lower */
750 if (dcn42_has_active_display(dc, context) == false)
751 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
752 }
753
754 if (clk_mgr_base->clks.pwr_state == DCN_PWR_STATE_LOW_POWER) {
755 union display_idle_optimization_u idle_info = { 0 };
756 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
757
758 idle_info.idle_info.df_request_disabled = 1;
759 idle_info.idle_info.phy_ref_clk_off = 1;
760 idle_info.idle_info.s0i2_rdy = 1;
761 dcn42_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
762 }
763 }
764
dcn42_exit_low_power_state(struct clk_mgr * clk_mgr_base)765 void dcn42_exit_low_power_state(struct clk_mgr *clk_mgr_base)
766 {
767 (void)clk_mgr_base;
768
769 }
770
dcn42_init_clocks_fpga(struct clk_mgr * clk_mgr)771 static void dcn42_init_clocks_fpga(struct clk_mgr *clk_mgr)
772 {
773 init_clk_states(clk_mgr);
774
775 }
776
dcn42_update_clocks_fpga(struct clk_mgr * clk_mgr,struct dc_state * context,bool safe_to_lower)777 void dcn42_update_clocks_fpga(struct clk_mgr *clk_mgr,
778 struct dc_state *context,
779 bool safe_to_lower)
780 {
781 struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr);
782 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
783 int fclk_adj = new_clocks->fclk_khz;
784
785 /* TODO: remove this after correctly set by DML */
786 new_clocks->dcfclk_khz = 400000;
787 new_clocks->socclk_khz = 400000;
788
789 /* Min fclk = 1.2GHz since all the extra scemi logic seems to run off of it */
790 //int fclk_adj = new_clocks->fclk_khz > 1200000 ? new_clocks->fclk_khz : 1200000;
791 new_clocks->fclk_khz = 4320000;
792
793 if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr->clks.phyclk_khz))
794 clk_mgr->clks.phyclk_khz = new_clocks->phyclk_khz;
795
796 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr->clks.dcfclk_khz))
797 clk_mgr->clks.dcfclk_khz = new_clocks->dcfclk_khz;
798
799 if (should_set_clock(safe_to_lower,
800 new_clocks->dcfclk_deep_sleep_khz, clk_mgr->clks.dcfclk_deep_sleep_khz))
801 clk_mgr->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
802
803 if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr->clks.socclk_khz))
804 clk_mgr->clks.socclk_khz = new_clocks->socclk_khz;
805
806 if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr->clks.dramclk_khz))
807 clk_mgr->clks.dramclk_khz = new_clocks->dramclk_khz;
808
809 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->clks.dppclk_khz))
810 clk_mgr->clks.dppclk_khz = new_clocks->dppclk_khz;
811
812 if (should_set_clock(safe_to_lower, fclk_adj, clk_mgr->clks.fclk_khz))
813 clk_mgr->clks.fclk_khz = fclk_adj;
814
815 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr->clks.dispclk_khz))
816 clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz;
817
818 /* Both fclk and ref_dppclk run on the same scemi clock.
819 * So take the higher value since the DPP DTO is typically programmed
820 * such that max dppclk is 1:1 with ref_dppclk.
821 */
822 if (clk_mgr->clks.fclk_khz > clk_mgr->clks.dppclk_khz)
823 clk_mgr->clks.dppclk_khz = clk_mgr->clks.fclk_khz;
824 if (clk_mgr->clks.dppclk_khz > clk_mgr->clks.fclk_khz)
825 clk_mgr->clks.fclk_khz = clk_mgr->clks.dppclk_khz;
826
827 // Both fclk and ref_dppclk run on the same scemi clock.
828 clk_mgr_int->dccg->ref_dppclk = clk_mgr->clks.fclk_khz;
829
830 dm_set_dcn_clocks(clk_mgr->ctx, &clk_mgr->clks);
831 if (clk_mgr->clks.dtbclk_en) {
832 dcn42_update_clocks_update_dtb_dto(clk_mgr_int, context, clk_mgr->clks.ref_dtbclk_khz);
833 } else {
834 clk_mgr->clks.ref_dtbclk_khz = 0;
835 }
836 dcn42_update_clocks_update_dpp_dto(clk_mgr_int, context, safe_to_lower);
837 }
838
dcn42_get_max_clock_khz(struct clk_mgr * clk_mgr_base,enum clk_type clk_type)839 unsigned int dcn42_get_max_clock_khz(struct clk_mgr *clk_mgr_base, enum clk_type clk_type)
840 {
841 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
842
843 unsigned int num_clk_levels;
844
845 switch (clk_type) {
846 case CLK_TYPE_DISPCLK:
847 num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dispclk_levels;
848 return num_clk_levels ?
849 clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dispclk_mhz * 1000 :
850 clk_mgr->base.boot_snapshot.dispclk;
851 case CLK_TYPE_DPPCLK:
852 num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dppclk_levels;
853 return num_clk_levels ?
854 clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dppclk_mhz * 1000 :
855 clk_mgr->base.boot_snapshot.dppclk;
856 case CLK_TYPE_DSCCLK:
857 num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dispclk_levels;
858 return num_clk_levels ?
859 clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dispclk_mhz * 1000 / 3 :
860 clk_mgr->base.boot_snapshot.dispclk / 3;
861 default:
862 break;
863 }
864
865 return 0;
866 }
867
dcn42_get_dispclk_from_dentist(struct clk_mgr * clk_mgr_base)868 int dcn42_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base)
869 {
870 (void)clk_mgr_base;
871 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
872 uint32_t dispclk_wdivider;
873 int disp_divider;
874
875 REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, &dispclk_wdivider);
876 disp_divider = dentist_get_divider_from_did(dispclk_wdivider);
877
878 /* Return DISPCLK freq in Khz */
879 if (disp_divider)
880 return (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / disp_divider;
881
882 return 0;
883 }
dcn42_is_smu_present(struct clk_mgr * clk_mgr_base)884 bool dcn42_is_smu_present(struct clk_mgr *clk_mgr_base)
885 {
886 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
887 return clk_mgr->smu_present;
888 }
889
dcn42_get_smu_clocks(struct clk_mgr_internal * clk_mgr_int)890 void dcn42_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int)
891 {
892 struct clk_mgr *clk_mgr_base = &clk_mgr_int->base;
893 struct dcn42_smu_dpm_clks smu_dpm_clks = { 0 };
894
895 DC_LOGGER_INIT(clk_mgr_base->ctx->logger);
896 (void)dc_logger;
897
898 smu_dpm_clks.dpm_clks = (DpmClocks_t_dcn42 *)dm_helpers_allocate_gpu_mem(
899 clk_mgr_base->ctx,
900 DC_MEM_ALLOC_TYPE_GART,
901 sizeof(DpmClocks_t_dcn42),
902 &smu_dpm_clks.mc_address.quad_part);
903
904 ASSERT(smu_dpm_clks.dpm_clks);
905 if (clk_mgr_base->ctx->dc->debug.pstate_enabled && smu_dpm_clks.mc_address.quad_part != 0) {
906 int i;
907 DpmClocks_t_dcn42 *dpm_clks = smu_dpm_clks.dpm_clks;
908
909 dcn42_get_dpm_table_from_smu(clk_mgr_int, &smu_dpm_clks);
910 DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n"
911 "NumDispClkLevelsEnabled: %d\n"
912 "NumSocClkLevelsEnabled: %d\n"
913 "VcnClkLevelsEnabled: %d\n"
914 "FClkLevelsEnabled: %d\n"
915 "NumMemPstatesEnabled: %d\n"
916 "MinGfxClk: %d\n"
917 "MaxGfxClk: %d\n",
918 dpm_clks->NumDcfClkLevelsEnabled,
919 dpm_clks->NumDispClkLevelsEnabled,
920 dpm_clks->NumSocClkLevelsEnabled,
921 dpm_clks->VcnClkLevelsEnabled,
922 dpm_clks->NumFclkLevelsEnabled,
923 dpm_clks->NumMemPstatesEnabled,
924 dpm_clks->MinGfxClk,
925 dpm_clks->MaxGfxClk);
926
927 for (i = 0; i < NUM_DCFCLK_DPM_LEVELS; i++) {
928 DC_LOG_SMU("dpm_clks->DcfClocks[%d] = %d\n",
929 i,
930 dpm_clks->DcfClocks[i]);
931 }
932 for (i = 0; i < NUM_DISPCLK_DPM_LEVELS; i++) {
933 DC_LOG_SMU("dpm_clks->DispClocks[%d] = %d\n",
934 i, dpm_clks->DispClocks[i]);
935 }
936 for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) {
937 DC_LOG_SMU("dpm_clks->SocClocks[%d] = %d\n",
938 i, dpm_clks->SocClocks[i]);
939 }
940 for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
941 DC_LOG_SMU("dpm_clks->FclkClocks_Freq[%d] = %d\n",
942 i, dpm_clks->FclkClocks_Freq[i]);
943 DC_LOG_SMU("dpm_clks->FclkClocks_Voltage[%d] = %d\n",
944 i, dpm_clks->FclkClocks_Voltage[i]);
945 }
946 for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++)
947 DC_LOG_SMU("dpm_clks->SocVoltage[%d] = %d\n",
948 i, dpm_clks->SocVoltage[i]);
949
950 for (i = 0; i < NUM_MEM_PSTATE_LEVELS; i++) {
951 DC_LOG_SMU("dpm_clks.MemPstateTable[%d].UClk = %d\n"
952 "dpm_clks->MemPstateTable[%d].MemClk= %d\n"
953 "dpm_clks->MemPstateTable[%d].Voltage = %d\n",
954 i, dpm_clks->MemPstateTable[i].UClk,
955 i, dpm_clks->MemPstateTable[i].MemClk,
956 i, dpm_clks->MemPstateTable[i].Voltage);
957 }
958
959 if (clk_mgr_base->ctx->dc_bios->integrated_info && clk_mgr_base->ctx->dc->config.use_default_clock_table == false) {
960 /* DCFCLK */
961 dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dcfclk_mhz,
962 dpm_clks->DcfClocks,
963 dpm_clks->NumDcfClkLevelsEnabled);
964 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels = dpm_clks->NumDcfClkLevelsEnabled;
965
966 /* SOCCLK */
967 dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].socclk_mhz,
968 dpm_clks->SocClocks,
969 dpm_clks->NumSocClkLevelsEnabled);
970 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_socclk_levels = dpm_clks->NumSocClkLevelsEnabled;
971
972 /* DISPCLK */
973 dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dispclk_mhz,
974 dpm_clks->DispClocks,
975 dpm_clks->NumDispClkLevelsEnabled);
976 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dispclk_levels = dpm_clks->NumDispClkLevelsEnabled;
977
978 /* DPPCLK */
979 dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dppclk_mhz,
980 dpm_clks->DppClocks,
981 dpm_clks->NumDispClkLevelsEnabled);
982 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dppclk_levels = dpm_clks->NumDispClkLevelsEnabled;
983
984 /* FCLK */
985 dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].fclk_mhz,
986 dpm_clks->FclkClocks_Freq,
987 NUM_FCLK_DPM_LEVELS);
988 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_fclk_levels = dpm_clks->NumFclkLevelsEnabled;
989 clk_mgr_base->bw_params->clk_table.num_entries = dpm_clks->NumFclkLevelsEnabled;
990
991 /* Memory Pstate table is in reverse order*/
992 ASSERT(dpm_clks->NumMemPstatesEnabled <= NUM_MEM_PSTATE_LEVELS);
993 if (dpm_clks->NumMemPstatesEnabled > NUM_MEM_PSTATE_LEVELS)
994 dpm_clks->NumMemPstatesEnabled = NUM_MEM_PSTATE_LEVELS;
995 for (i = 0; i < dpm_clks->NumMemPstatesEnabled; i++) {
996 clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].memclk_mhz = dpm_clks->MemPstateTable[i].MemClk;
997 clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].wck_ratio = dcn42_convert_wck_ratio(dpm_clks->MemPstateTable[i].WckRatio) ;
998 }
999 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_memclk_levels = dpm_clks->NumMemPstatesEnabled;
1000
1001 /* DTBCLK*/
1002 clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz = 600; /* Fixed on platform */
1003 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels = 1;
1004 }
1005 }
1006 if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0)
1007 dm_helpers_free_gpu_mem(clk_mgr_base->ctx, DC_MEM_ALLOC_TYPE_GART,
1008 smu_dpm_clks.dpm_clks);
1009 }
1010
1011 static struct clk_mgr_funcs dcn42_funcs = {
1012 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
1013 .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
1014 .update_clocks = dcn42_update_clocks,
1015 .init_clocks = dcn42_init_clocks,
1016 .enable_pme_wa = dcn42_enable_pme_wa,
1017 .are_clock_states_equal = dcn42_are_clock_states_equal,
1018 .notify_wm_ranges = dcn42_notify_wm_ranges,
1019 .set_low_power_state = dcn42_set_low_power_state,
1020 .exit_low_power_state = dcn42_exit_low_power_state,
1021 .get_max_clock_khz = dcn42_get_max_clock_khz,
1022 .get_dispclk_from_dentist = dcn42_get_dispclk_from_dentist,
1023 .is_smu_present = dcn42_is_smu_present,
1024 };
1025
1026 struct clk_mgr_funcs dcn42_fpga_funcs = {
1027 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
1028 .update_clocks = dcn42_update_clocks_fpga,
1029 .init_clocks = dcn42_init_clocks_fpga,
1030 .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
1031 };
1032
dcn42_clk_mgr_construct(struct dc_context * ctx,struct clk_mgr_dcn42 * clk_mgr,struct pp_smu_funcs * pp_smu,struct dccg * dccg)1033 void dcn42_clk_mgr_construct(
1034 struct dc_context *ctx,
1035 struct clk_mgr_dcn42 *clk_mgr,
1036 struct pp_smu_funcs *pp_smu,
1037 struct dccg *dccg)
1038 {
1039 clk_mgr->base.base.ctx = ctx;
1040 clk_mgr->base.base.funcs = &dcn42_funcs;
1041 clk_mgr->base.regs = &clk_mgr_regs_dcn42;
1042 clk_mgr->base.clk_mgr_shift = &clk_mgr_shift_dcn42;
1043 clk_mgr->base.clk_mgr_mask = &clk_mgr_mask_dcn42;
1044
1045 clk_mgr->base.pp_smu = pp_smu;
1046
1047 clk_mgr->base.dccg = dccg;
1048 clk_mgr->base.dfs_bypass_disp_clk = 0;
1049
1050 clk_mgr->base.dprefclk_ss_percentage = 0;
1051 clk_mgr->base.dprefclk_ss_divider = 1000;
1052 clk_mgr->base.ss_on_dprefclk = false;
1053 clk_mgr->base.dfs_ref_freq_khz = 48000; /*sync with pmfw*/
1054 clk_mgr->base.base.clks.ref_dtbclk_khz = 600000;
1055
1056 /* Changed from DCN3.2_clock_frequency doc to match
1057 * dcn32_dump_clk_registers from 4 * dentist_vco_freq_khz /
1058 * dprefclk DID divider
1059 */
1060 clk_mgr->base.base.dprefclk_khz = 600000;
1061
1062 clk_mgr->base.smu_present = false;
1063 clk_mgr->base.smu_ver = dcn42_smu_get_pmfw_version(&clk_mgr->base);
1064 if (clk_mgr->base.smu_ver && clk_mgr->base.smu_ver != -1)
1065 clk_mgr->base.smu_present = true;
1066
1067 if (ctx->dc_bios->integrated_info) {
1068 clk_mgr->base.base.dentist_vco_freq_khz = ctx->dc_bios->integrated_info->dentist_vco_freq;
1069
1070 dcn42_bw_params.vram_type = ctx->dc_bios->integrated_info->memory_type;
1071 dcn42_bw_params.dram_channel_width_bytes = ctx->dc_bios->integrated_info->memory_type == 0x22 ? 8 : 4;
1072 dcn42_bw_params.num_channels = ctx->dc_bios->integrated_info->ma_channel_number ? ctx->dc_bios->integrated_info->ma_channel_number : 1;
1073 clk_mgr->base.base.dprefclk_khz = dcn42_smu_get_dprefclk(&clk_mgr->base);
1074 clk_mgr->base.base.clks.ref_dtbclk_khz = dcn42_smu_get_dtbclk(&clk_mgr->base);
1075
1076 clk_mgr->base.base.bw_params = &dcn42_bw_params;
1077
1078 if (clk_mgr->base.smu_present)
1079 dcn42_get_smu_clocks(&clk_mgr->base);
1080 }
1081 /* in case we don't get a value from the BIOS, use default */
1082 if (clk_mgr->base.base.dentist_vco_freq_khz == 0)
1083 clk_mgr->base.base.dentist_vco_freq_khz = 3000000; /* 3000MHz */
1084
1085 /* Saved clocks configured at boot for debug purposes */
1086 dcn42_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, clk_mgr);
1087
1088 dce_clock_read_ss_info(&clk_mgr->base);
1089 /*when clk src is from FCH, it could have ss, same clock src as DPREF clk*/
1090
1091 dcn42_read_ss_info_from_lut(&clk_mgr->base);
1092
1093 clk_mgr->base.base.bw_params = &dcn42_bw_params;
1094 if (clk_mgr->base.smu_present)
1095 dcn42_get_smu_clocks(&clk_mgr->base);
1096 }
1097
dcn42_clk_mgr_destroy(struct clk_mgr_internal * clk_mgr_int)1098 void dcn42_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int)
1099 {
1100 struct clk_mgr_dcn42 *clk_mgr = TO_CLK_MGR_DCN42(clk_mgr_int);
1101
1102 if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0)
1103 dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_GART,
1104 clk_mgr->smu_wm_set.wm_set);
1105 }
1106