xref: /linux/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c (revision ed0bb5c4bd143422b5e149054e00d2d091ead7b1)
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 
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 
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 
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 
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 	uint32_t 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 
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 		int force_min_dcfclk_khz = dc->debug.force_min_dcfclk_mhz * 1000;
287 
288 		new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > force_min_dcfclk_khz) ?
289 				new_clocks->dcfclk_khz : force_min_dcfclk_khz;
290 	}
291 
292 	if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) {
293 		clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz;
294 		clk_mgr_base->clks.fclk_khz = new_clocks->fclk_khz;
295 		clk_mgr_base->clks.dramclk_khz = new_clocks->dramclk_khz;
296 		dcn42_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz);
297 	}
298 
299 	if (should_set_clock(safe_to_lower,
300 			new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) {
301 		clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
302 
303 		/* Clamp the requested clock to PMFW based on DCN limit. */
304 		if (dc->debug.min_deep_sleep_dcfclk_khz > 0 &&
305 			clk_mgr_base->clks.dcfclk_deep_sleep_khz < (int)dc->debug.min_deep_sleep_dcfclk_khz)
306 			clk_mgr_base->clks.dcfclk_deep_sleep_khz = (int)dc->debug.min_deep_sleep_dcfclk_khz;
307 
308 		dcn42_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz);
309 	}
310 
311 	// workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow.
312 	if (new_clocks->dppclk_khz < 100000)
313 		new_clocks->dppclk_khz = 100000;
314 
315 	if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
316 		if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
317 			dpp_clock_lowered = true;
318 		clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
319 		update_dppclk = true;
320 	}
321 
322 	if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) &&
323 	    (new_clocks->dispclk_khz > 0 || (safe_to_lower && has_active_display == false))) {
324 		uint32_t requested_dispclk_khz = new_clocks->dispclk_khz;
325 
326 		dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true);
327 
328 		/* Clamp the requested clock to PMFW based on their limit. */
329 		if (dc->debug.min_disp_clk_khz > 0 && requested_dispclk_khz < (uint32_t)dc->debug.min_disp_clk_khz)
330 			requested_dispclk_khz = (uint32_t)dc->debug.min_disp_clk_khz;
331 
332 		dcn42_smu_set_dispclk(clk_mgr, requested_dispclk_khz);
333 		clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
334 		dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false);
335 
336 		update_dispclk = true;
337 	}
338 
339 	/* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */
340 	if (!dc->debug.disable_dtb_ref_clk_switch && new_clocks->dtbclk_en &&
341 	    should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000,
342 			     clk_mgr_base->clks.ref_dtbclk_khz / 1000)) {
343 		dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz);
344 		clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz;
345 	}
346 
347 	if (dpp_clock_lowered) {
348 		// increase per DPP DTO before lowering global dppclk
349 		dcn42_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
350 		dcn42_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
351 	} else {
352 		// increase global DPPCLK before lowering per DPP DTO
353 		if (update_dppclk || update_dispclk)
354 			dcn42_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
355 		dcn42_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
356 	}
357 	// notify DMCUB of latest clocks
358 	memset(&cmd, 0, sizeof(cmd));
359 	cmd.notify_clocks.header.type = DMUB_CMD__CLK_MGR;
360 	cmd.notify_clocks.header.sub_type = DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS;
361 	cmd.notify_clocks.clocks.dcfclk_khz = clk_mgr_base->clks.dcfclk_khz;
362 	cmd.notify_clocks.clocks.dcfclk_deep_sleep_khz =
363 		clk_mgr_base->clks.dcfclk_deep_sleep_khz;
364 	cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz;
365 	cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz;
366 
367 	dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
368 }
369 
370 
371 void dcn42_enable_pme_wa(struct clk_mgr *clk_mgr_base)
372 {
373 	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
374 
375 	dcn42_smu_enable_pme_wa(clk_mgr);
376 }
377 
378 
379 bool dcn42_are_clock_states_equal(struct dc_clocks *a,
380 		struct dc_clocks *b)
381 {
382 	if (a->dispclk_khz != b->dispclk_khz)
383 		return false;
384 	else if (a->dppclk_khz != b->dppclk_khz)
385 		return false;
386 	else if (a->dcfclk_khz != b->dcfclk_khz)
387 		return false;
388 	else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz)
389 		return false;
390 	else if (a->zstate_support != b->zstate_support)
391 		return false;
392 	else if (a->dtbclk_en != b->dtbclk_en)
393 		return false;
394 
395 	return true;
396 }
397 
398 static void dcn42_dump_clk_registers_internal(struct dcn42_clk_internal *internal, struct clk_mgr *clk_mgr_base)
399 {
400 	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
401 
402 	REG_GET(CLK8_CLK_TICK_CNT_CONFIG_REG, TIMER_THRESHOLD, &internal->CLK8_CLK_TICK_CNT__TIMER_THRESHOLD);
403 
404 	// read dcf deep sleep divider
405 	internal->CLK8_CLK0_DS_CNTL = REG_READ(CLK8_CLK0_DS_CNTL);
406 	internal->CLK8_CLK3_DS_CNTL = REG_READ(CLK8_CLK3_DS_CNTL);
407 	// read dispclk
408 	internal->CLK8_CLK0_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dispclk);
409 	internal->CLK8_CLK0_BYPASS_CNTL = REG_READ(CLK8_CLK0_BYPASS_CNTL);
410 	// read dppclk
411 	internal->CLK8_CLK1_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dppclk);
412 	internal->CLK8_CLK1_BYPASS_CNTL = REG_READ(CLK8_CLK1_BYPASS_CNTL);
413 	// read dprefclk
414 	internal->CLK8_CLK2_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dprefclk);
415 	internal->CLK8_CLK2_BYPASS_CNTL = REG_READ(CLK8_CLK2_BYPASS_CNTL);
416 	// read dcfclk
417 	internal->CLK8_CLK3_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dcfclk);
418 	internal->CLK8_CLK3_BYPASS_CNTL = REG_READ(CLK8_CLK3_BYPASS_CNTL);
419 	// read dtbclk
420 	internal->CLK8_CLK4_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk);
421 	internal->CLK8_CLK4_BYPASS_CNTL = REG_READ(CLK8_CLK4_BYPASS_CNTL);
422 }
423 
424 static void dcn42_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
425 		struct clk_mgr_dcn42 *clk_mgr)
426 {
427 	struct dcn42_clk_internal internal = {0};
428 	char *bypass_clks[5] = {"0x0 DFS", "0x1 REFCLK", "0x2 ERROR", "0x3 400 FCH", "0x4 600 FCH"};
429 
430 	DC_LOGGER_INIT(clk_mgr->base.base.ctx->logger);
431 	(void)dc_logger;
432 
433 	dcn42_dump_clk_registers_internal(&internal, &clk_mgr->base.base);
434 	regs_and_bypass->timer_threshold = internal.CLK8_CLK_TICK_CNT__TIMER_THRESHOLD;
435 	regs_and_bypass->dcfclk = internal.CLK8_CLK3_CURRENT_CNT / 10;
436 	regs_and_bypass->dcf_deep_sleep_divider = internal.CLK8_CLK3_DS_CNTL / 10;
437 	regs_and_bypass->dcf_deep_sleep_allow = internal.CLK8_CLK3_DS_CNTL & 0x10; /*bit 4: CLK0_ALLOW_DS*/
438 	regs_and_bypass->dprefclk = internal.CLK8_CLK2_CURRENT_CNT / 10;
439 	regs_and_bypass->dispclk = internal.CLK8_CLK0_CURRENT_CNT / 10;
440 	regs_and_bypass->dppclk = internal.CLK8_CLK1_CURRENT_CNT / 10;
441 	regs_and_bypass->dtbclk = internal.CLK8_CLK4_CURRENT_CNT / 10;
442 
443 	regs_and_bypass->dispclk_bypass = get_reg_field_value(internal.CLK8_CLK0_BYPASS_CNTL, CLK8_CLK0_BYPASS_CNTL, CLK0_BYPASS_SEL);
444 	regs_and_bypass->dppclk_bypass = get_reg_field_value(internal.CLK8_CLK1_BYPASS_CNTL, CLK8_CLK1_BYPASS_CNTL, CLK1_BYPASS_SEL);
445 	regs_and_bypass->dprefclk_bypass = get_reg_field_value(internal.CLK8_CLK2_BYPASS_CNTL, CLK8_CLK2_BYPASS_CNTL, CLK2_BYPASS_SEL);
446 	regs_and_bypass->dcfclk_bypass = get_reg_field_value(internal.CLK8_CLK3_BYPASS_CNTL, CLK8_CLK3_BYPASS_CNTL, CLK3_BYPASS_SEL);
447 
448 	if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) {
449 		DC_LOG_SMU("clk_type,clk_value,deepsleep_cntl,deepsleep_allow,bypass\n");
450 
451 		DC_LOG_SMU("dcfclk,%d,%d,%d,%s\n",
452 				   regs_and_bypass->dcfclk,
453 				   regs_and_bypass->dcf_deep_sleep_divider,
454 				   regs_and_bypass->dcf_deep_sleep_allow,
455 				   bypass_clks[(int) regs_and_bypass->dcfclk_bypass]);
456 
457 		DC_LOG_SMU("dprefclk,%d,N/A,N/A,%s\n",
458 			regs_and_bypass->dprefclk,
459 			bypass_clks[(int) regs_and_bypass->dprefclk_bypass]);
460 
461 		DC_LOG_SMU("dispclk,%d,N/A,N/A,%s\n",
462 			regs_and_bypass->dispclk,
463 			bypass_clks[(int) regs_and_bypass->dispclk_bypass]);
464 
465 		//split
466 		DC_LOG_SMU("SPLIT\n");
467 
468 		// REGISTER VALUES
469 		DC_LOG_SMU("reg_name,value,clk_type\n");
470 		DC_LOG_SMU("CLK1_CLK3_CURRENT_CNT,%d,dcfclk\n",
471 				internal.CLK8_CLK3_CURRENT_CNT);
472 
473 		DC_LOG_SMU("CLK1_CLK3_DS_CNTL,%d,dcf_deep_sleep_divider\n",
474 					internal.CLK8_CLK3_DS_CNTL);
475 
476 		DC_LOG_SMU("CLK1_CLK3_ALLOW_DS,%d,dcf_deep_sleep_allow\n",
477 					(internal.CLK8_CLK3_DS_CNTL & 0x10));
478 
479 		DC_LOG_SMU("CLK1_CLK2_CURRENT_CNT,%d,dprefclk\n",
480 					internal.CLK8_CLK2_CURRENT_CNT);
481 
482 		DC_LOG_SMU("CLK1_CLK0_CURRENT_CNT,%d,dispclk\n",
483 					internal.CLK8_CLK0_CURRENT_CNT);
484 
485 		DC_LOG_SMU("CLK1_CLK1_CURRENT_CNT,%d,dppclk\n",
486 					internal.CLK8_CLK1_CURRENT_CNT);
487 
488 		DC_LOG_SMU("CLK1_CLK4_CURRENT_CNT,%d,dtbclk\n",
489 					internal.CLK8_CLK4_CURRENT_CNT);
490 
491 		DC_LOG_SMU("CLK1_CLK3_BYPASS_CNTL,%d,dcfclk_bypass\n",
492 					internal.CLK8_CLK3_BYPASS_CNTL);
493 
494 		DC_LOG_SMU("CLK1_CLK2_BYPASS_CNTL,%d,dprefclk_bypass\n",
495 					internal.CLK8_CLK2_BYPASS_CNTL);
496 
497 		DC_LOG_SMU("CLK1_CLK0_BYPASS_CNTL,%d,dispclk_bypass\n",
498 					internal.CLK8_CLK0_BYPASS_CNTL);
499 
500 		DC_LOG_SMU("CLK1_CLK1_BYPASS_CNTL,%d,dppclk_bypass\n",
501 					internal.CLK8_CLK1_BYPASS_CNTL);
502 	}
503 }
504 
505 bool dcn42_is_spll_ssc_enabled(struct clk_mgr *clk_mgr_base)
506 {
507 	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
508 	struct dc_context *ctx = clk_mgr->base.ctx;
509 
510 
511 	if (ctx->dc->config.ignore_dpref_ss) {
512 		/*revert bios's ss info for test only*/
513 		return (clk_mgr->dprefclk_ss_percentage == 0);
514 	}
515 	/*need to update after BU*/
516 	return false;
517 }
518 
519 static void init_clk_states(struct clk_mgr *clk_mgr)
520 {
521 	uint32_t ref_dtbclk = clk_mgr->clks.ref_dtbclk_khz;
522 
523 	memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
524 
525 	clk_mgr->clks.dtbclk_en = true; // request DTBCLK disable on first commit
526 	clk_mgr->clks.ref_dtbclk_khz = ref_dtbclk;      // restore ref_dtbclk
527 	clk_mgr->clks.p_state_change_support = true;
528 	clk_mgr->clks.prev_p_state_change_support = true;
529 	clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN;
530 	clk_mgr->clks.zstate_support = DCN_ZSTATE_SUPPORT_UNKNOWN;
531 }
532 
533 void dcn42_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
534 		struct dcn42_smu_dpm_clks *smu_dpm_clks)
535 {
536 	DpmClocks_t_dcn42 *table = smu_dpm_clks->dpm_clks;
537 
538 	if (!clk_mgr->smu_ver)
539 		return;
540 
541 	if (!table || smu_dpm_clks->mc_address.quad_part == 0)
542 		return;
543 
544 	memset(table, 0, sizeof(*table));
545 
546 	dcn42_smu_set_dram_addr_high(clk_mgr,
547 			smu_dpm_clks->mc_address.high_part);
548 	dcn42_smu_set_dram_addr_low(clk_mgr,
549 			smu_dpm_clks->mc_address.low_part);
550 	dcn42_smu_transfer_dpm_table_smu_2_dram(clk_mgr);
551 }
552 
553 void dcn42_init_single_clock(unsigned int *entry_0,
554 		uint32_t *smu_entry_0,
555 		uint8_t num_levels)
556 {
557 	int i;
558 	char *entry_i = (char *)entry_0;
559 
560 	ASSERT(num_levels <= MAX_NUM_DPM_LVL);
561 	if (num_levels > MAX_NUM_DPM_LVL)
562 		num_levels = MAX_NUM_DPM_LVL;
563 
564 
565 	for (i = 0; i < num_levels; i++) {
566 		*((unsigned int *)entry_i) = smu_entry_0[i];
567 		entry_i += sizeof(struct clk_limit_table_entry);
568 	}
569 }
570 
571 unsigned int dcn42_convert_wck_ratio(uint8_t wck_ratio)
572 {
573 	switch (wck_ratio) {
574 	case WCK_RATIO_1_2:
575 		return 2;
576 
577 	case WCK_RATIO_1_4:
578 		return 4;
579 
580 	default:
581 			break;
582 	}
583 
584 	return 1;
585 }
586 
587 void dcn42_init_clocks(struct clk_mgr *clk_mgr_base)
588 {
589 	struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr_base);
590 	struct clk_mgr_dcn42 *clk_mgr = TO_CLK_MGR_DCN42(clk_mgr_int);
591 
592 	DC_LOGGER_INIT(clk_mgr_base->ctx->logger);
593 	(void)dc_logger;
594 
595 	init_clk_states(clk_mgr_base);
596 
597 	// to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk
598 	if (dcn42_is_spll_ssc_enabled(clk_mgr_base))
599 		clk_mgr_base->dp_dto_source_clock_in_khz =
600 			dce_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr_base->dprefclk_khz);
601 	else
602 		clk_mgr_base->dp_dto_source_clock_in_khz = clk_mgr_base->dprefclk_khz;
603 
604 	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);
605 	dcn42_dump_clk_registers(&clk_mgr_base->boot_snapshot, clk_mgr);
606 
607 	clk_mgr_base->clks.ref_dtbclk_khz =  clk_mgr_base->boot_snapshot.dtbclk * 10;
608 	clk_mgr_base->clks.dtbclk_en = clk_mgr_base->boot_snapshot.dtbclk > 59000;
609 }
610 
611 static struct clk_bw_params dcn42_bw_params = {
612 	.vram_type = Ddr4MemType,
613 	.num_channels = 1,
614 	.clk_table = {
615 		.num_entries = 4,
616 	},
617 
618 };
619 
620 struct dcn42_ss_info_table dcn42_ss_info_table = {
621 	.ss_divider = 1000,
622 	.ss_percentage = {0, 0, 375, 375, 375}
623 };
624 
625 static void dcn42_read_ss_info_from_lut(struct clk_mgr_internal *clk_mgr)
626 {
627 	uint32_t clock_source;
628 
629 	clock_source = (REG_READ(CLK8_CLK2_BYPASS_CNTL) & CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL_MASK);
630 	// If it's DFS mode, clock_source is 0.
631 	if (dcn42_is_spll_ssc_enabled(&clk_mgr->base) && (clock_source < ARRAY_SIZE(dcn42_ss_info_table.ss_percentage))) {
632 		clk_mgr->dprefclk_ss_percentage = dcn42_ss_info_table.ss_percentage[clock_source];
633 
634 		if (clk_mgr->dprefclk_ss_percentage != 0) {
635 			clk_mgr->ss_on_dprefclk = true;
636 			clk_mgr->dprefclk_ss_divider = dcn42_ss_info_table.ss_divider;
637 		}
638 	}
639 }
640 
641 void dcn42_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn42_watermarks *table)
642 {
643 	uint8_t i, num_valid_sets;
644 
645 	num_valid_sets = 0;
646 
647 	for (i = 0; i < WM_SET_COUNT; i++) {
648 		/* skip empty entries, the smu array has no holes*/
649 		if (!bw_params->wm_table.entries[i].valid)
650 			continue;
651 
652 		table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmSetting =
653 			(uint8_t)bw_params->wm_table.entries[i].wm_inst;
654 		table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType =
655 			(uint8_t)bw_params->wm_table.entries[i].wm_type;
656 		/* We will not select WM based on fclk, so leave it as unconstrained */
657 		table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
658 		table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
659 
660 		if (table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType == WM_TYPE_PSTATE_CHG) {
661 			if (i == 0)
662 				table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 0;
663 			else {
664 				/* add 1 to make it non-overlapping with next lvl */
665 				table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk =
666 						(uint16_t)(bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1);
667 			}
668 			table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxMclk =
669 					(uint16_t)bw_params->clk_table.entries[i].dcfclk_mhz;
670 
671 		} else {
672 			/* unconstrained for memory retraining */
673 			table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
674 			table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
675 
676 			/* Modify previous watermark range to cover up to max */
677 			if (num_valid_sets > 0)
678 				table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
679 		}
680 		num_valid_sets++;
681 	}
682 
683 	ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */
684 
685 	/* modify the min and max to make sure we cover the whole range*/
686 	table->WatermarkRow[WM_DCFCLK][0].MinMclk = 0;
687 	table->WatermarkRow[WM_DCFCLK][0].MinClock = 0;
688 	table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxMclk = 0xFFFF;
689 	table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
690 
691 	/* This is for writeback only, does not matter currently as no writeback support*/
692 	table->WatermarkRow[WM_SOCCLK][0].WmSetting = WM_A;
693 	table->WatermarkRow[WM_SOCCLK][0].MinClock = 0;
694 	table->WatermarkRow[WM_SOCCLK][0].MaxClock = 0xFFFF;
695 	table->WatermarkRow[WM_SOCCLK][0].MinMclk = 0;
696 	table->WatermarkRow[WM_SOCCLK][0].MaxMclk = 0xFFFF;
697 }
698 
699 void dcn42_notify_wm_ranges(struct clk_mgr *clk_mgr_base)
700 {
701 	unsigned int i = 0;
702 	struct dcn42_watermarks *table = NULL;
703 	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
704 	struct clk_mgr_dcn42 *clk_mgr_dcn42 = TO_CLK_MGR_DCN42(clk_mgr);
705 
706 	if (!clk_mgr->smu_ver)
707 		return;
708 	/*send once already skip*/
709 	if (clk_mgr_base->bw_params->wm_table.entries[WM_A].valid == true)
710 		return;
711 	clk_mgr_dcn42->smu_wm_set.wm_set = (struct dcn42_watermarks *)dm_helpers_allocate_gpu_mem(
712 				clk_mgr->base.ctx,
713 				DC_MEM_ALLOC_TYPE_GART,
714 				sizeof(struct dcn42_watermarks),
715 				&clk_mgr_dcn42->smu_wm_set.mc_address.quad_part);
716 
717 	ASSERT(clk_mgr_dcn42->smu_wm_set.wm_set);
718 
719 	table = clk_mgr_dcn42->smu_wm_set.wm_set;
720 
721 	if (!table || clk_mgr_dcn42->smu_wm_set.mc_address.quad_part == 0)
722 		return;
723 
724 	memset(table, 0, sizeof(*table));
725 	/*same as previous asic, set wm valid before building watermark ranges*/
726 	for (i = 0; i < WM_SET_COUNT; i++) {
727 		clk_mgr_base->bw_params->wm_table.entries[i].wm_inst = i;
728 
729 		if (i >= clk_mgr_base->bw_params->clk_table.num_entries) {
730 			clk_mgr_base->bw_params->wm_table.entries[i].valid = false;
731 			continue;
732 		}
733 		clk_mgr_base->bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG;
734 		clk_mgr_base->bw_params->wm_table.entries[i].valid = true;
735 	}
736 	/* build watermark_range will check this valid range*/
737 	dcn42_build_watermark_ranges(clk_mgr_base->bw_params, table);
738 
739 	dcn42_smu_set_dram_addr_high(clk_mgr,
740 			clk_mgr_dcn42->smu_wm_set.mc_address.high_part);
741 	dcn42_smu_set_dram_addr_low(clk_mgr,
742 			clk_mgr_dcn42->smu_wm_set.mc_address.low_part);
743 	dcn42_smu_transfer_wm_table_dram_2_smu(clk_mgr);
744 
745 	if (clk_mgr_dcn42->smu_wm_set.wm_set && clk_mgr_dcn42->smu_wm_set.mc_address.quad_part != 0) {
746 		dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART,
747 				clk_mgr_dcn42->smu_wm_set.wm_set);
748 		clk_mgr_dcn42->smu_wm_set.wm_set = NULL;
749 		clk_mgr_dcn42->smu_wm_set.mc_address.quad_part = 0;
750 	}
751 
752 }
753 
754 void dcn42_set_low_power_state(struct clk_mgr *clk_mgr_base)
755 {
756 	struct dc *dc = clk_mgr_base->ctx->dc;
757 	struct dc_state *context = dc->current_state;
758 
759 	if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
760 		/* if we can go lower, go lower */
761 		if (dcn42_has_active_display(dc, context) == false)
762 			clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
763 	}
764 
765 	if (clk_mgr_base->clks.pwr_state == DCN_PWR_STATE_LOW_POWER) {
766 		union display_idle_optimization_u idle_info = { 0 };
767 		struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
768 
769 		idle_info.idle_info.df_request_disabled = 1;
770 		idle_info.idle_info.phy_ref_clk_off = 1;
771 		idle_info.idle_info.s0i2_rdy = 1;
772 		dcn42_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
773 	}
774 }
775 
776 void dcn42_exit_low_power_state(struct clk_mgr *clk_mgr_base)
777 {
778 	(void)clk_mgr_base;
779 
780 }
781 
782 static void dcn42_init_clocks_fpga(struct clk_mgr *clk_mgr)
783 {
784 	init_clk_states(clk_mgr);
785 
786 }
787 
788 void dcn42_update_clocks_fpga(struct clk_mgr *clk_mgr,
789 		struct dc_state *context,
790 		bool safe_to_lower)
791 {
792 	struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr);
793 	struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
794 	int fclk_adj = new_clocks->fclk_khz;
795 
796 	/* TODO: remove this after correctly set by DML */
797 	new_clocks->dcfclk_khz = 400000;
798 	new_clocks->socclk_khz = 400000;
799 
800 	/* Min fclk = 1.2GHz since all the extra scemi logic seems to run off of it */
801 	//int fclk_adj = new_clocks->fclk_khz > 1200000 ? new_clocks->fclk_khz : 1200000;
802 	new_clocks->fclk_khz = 4320000;
803 
804 	if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr->clks.phyclk_khz))
805 		clk_mgr->clks.phyclk_khz = new_clocks->phyclk_khz;
806 
807 	if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr->clks.dcfclk_khz))
808 		clk_mgr->clks.dcfclk_khz = new_clocks->dcfclk_khz;
809 
810 	if (should_set_clock(safe_to_lower,
811 			new_clocks->dcfclk_deep_sleep_khz, clk_mgr->clks.dcfclk_deep_sleep_khz))
812 		clk_mgr->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
813 
814 	if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr->clks.socclk_khz))
815 		clk_mgr->clks.socclk_khz = new_clocks->socclk_khz;
816 
817 	if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr->clks.dramclk_khz))
818 		clk_mgr->clks.dramclk_khz = new_clocks->dramclk_khz;
819 
820 	if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->clks.dppclk_khz))
821 		clk_mgr->clks.dppclk_khz = new_clocks->dppclk_khz;
822 
823 	if (should_set_clock(safe_to_lower, fclk_adj, clk_mgr->clks.fclk_khz))
824 		clk_mgr->clks.fclk_khz = fclk_adj;
825 
826 	if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr->clks.dispclk_khz))
827 		clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz;
828 
829 	/* Both fclk and ref_dppclk run on the same scemi clock.
830 	 * So take the higher value since the DPP DTO is typically programmed
831 	 * such that max dppclk is 1:1 with ref_dppclk.
832 	 */
833 	if (clk_mgr->clks.fclk_khz > clk_mgr->clks.dppclk_khz)
834 		clk_mgr->clks.dppclk_khz = clk_mgr->clks.fclk_khz;
835 	if (clk_mgr->clks.dppclk_khz > clk_mgr->clks.fclk_khz)
836 		clk_mgr->clks.fclk_khz = clk_mgr->clks.dppclk_khz;
837 
838 	// Both fclk and ref_dppclk run on the same scemi clock.
839 	clk_mgr_int->dccg->ref_dppclk = clk_mgr->clks.fclk_khz;
840 
841 	dm_set_dcn_clocks(clk_mgr->ctx, &clk_mgr->clks);
842 	if (clk_mgr->clks.dtbclk_en) {
843 		dcn42_update_clocks_update_dtb_dto(clk_mgr_int, context, clk_mgr->clks.ref_dtbclk_khz);
844 	} else {
845 		clk_mgr->clks.ref_dtbclk_khz = 0;
846 	}
847 	dcn42_update_clocks_update_dpp_dto(clk_mgr_int, context, safe_to_lower);
848 }
849 
850 unsigned int dcn42_get_max_clock_khz(struct clk_mgr *clk_mgr_base, enum clk_type clk_type)
851 {
852 	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
853 
854 	unsigned int num_clk_levels;
855 
856 	switch (clk_type) {
857 	case CLK_TYPE_DISPCLK:
858 		num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dispclk_levels;
859 		return num_clk_levels ?
860 				clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dispclk_mhz * 1000 :
861 				clk_mgr->base.boot_snapshot.dispclk;
862 	case CLK_TYPE_DPPCLK:
863 		num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dppclk_levels;
864 		return num_clk_levels ?
865 				clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dppclk_mhz * 1000 :
866 				clk_mgr->base.boot_snapshot.dppclk;
867 	case CLK_TYPE_DSCCLK:
868 		num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dispclk_levels;
869 		return num_clk_levels ?
870 				clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dispclk_mhz * 1000 / 3 :
871 				clk_mgr->base.boot_snapshot.dispclk / 3;
872 	default:
873 		break;
874 	}
875 
876 	return 0;
877 }
878 
879 int dcn42_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base)
880 {
881 	(void)clk_mgr_base;
882 	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
883 	uint32_t dispclk_wdivider;
884 	unsigned int disp_divider;
885 
886 	REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, &dispclk_wdivider);
887 	disp_divider = dentist_get_divider_from_did(dispclk_wdivider);
888 
889 	/* Return DISPCLK freq in Khz */
890 	if (disp_divider)
891 		return (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / disp_divider;
892 
893 	return 0;
894 }
895 bool dcn42_is_smu_present(struct clk_mgr *clk_mgr_base)
896 {
897 	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
898 	return clk_mgr->smu_present;
899 }
900 
901 void dcn42_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int)
902 {
903 	struct clk_mgr *clk_mgr_base = &clk_mgr_int->base;
904 	struct dcn42_smu_dpm_clks smu_dpm_clks = { 0 };
905 
906 	DC_LOGGER_INIT(clk_mgr_base->ctx->logger);
907 	(void)dc_logger;
908 
909 	smu_dpm_clks.dpm_clks = (DpmClocks_t_dcn42 *)dm_helpers_allocate_gpu_mem(
910 				clk_mgr_base->ctx,
911 				DC_MEM_ALLOC_TYPE_GART,
912 				sizeof(DpmClocks_t_dcn42),
913 				&smu_dpm_clks.mc_address.quad_part);
914 
915 	ASSERT(smu_dpm_clks.dpm_clks);
916 	if (clk_mgr_base->ctx->dc->debug.pstate_enabled && smu_dpm_clks.mc_address.quad_part != 0) {
917 		int i;
918 		DpmClocks_t_dcn42 *dpm_clks = smu_dpm_clks.dpm_clks;
919 
920 		dcn42_get_dpm_table_from_smu(clk_mgr_int, &smu_dpm_clks);
921 		DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n"
922 				   "NumDispClkLevelsEnabled: %d\n"
923 				   "NumSocClkLevelsEnabled: %d\n"
924 				   "VcnClkLevelsEnabled: %d\n"
925 				   "FClkLevelsEnabled: %d\n"
926 				   "NumMemPstatesEnabled: %d\n"
927 				   "MinGfxClk: %d\n"
928 				   "MaxGfxClk: %d\n",
929 				   dpm_clks->NumDcfClkLevelsEnabled,
930 				   dpm_clks->NumDispClkLevelsEnabled,
931 				   dpm_clks->NumSocClkLevelsEnabled,
932 				   dpm_clks->VcnClkLevelsEnabled,
933 				   dpm_clks->NumFclkLevelsEnabled,
934 				   dpm_clks->NumMemPstatesEnabled,
935 				   dpm_clks->MinGfxClk,
936 				   dpm_clks->MaxGfxClk);
937 
938 		for (i = 0; i < NUM_DCFCLK_DPM_LEVELS; i++) {
939 			DC_LOG_SMU("dpm_clks->DcfClocks[%d] = %d\n",
940 					   i,
941 					   dpm_clks->DcfClocks[i]);
942 		}
943 		for (i = 0; i < NUM_DISPCLK_DPM_LEVELS; i++) {
944 			DC_LOG_SMU("dpm_clks->DispClocks[%d] = %d\n",
945 					   i, dpm_clks->DispClocks[i]);
946 		}
947 		for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) {
948 			DC_LOG_SMU("dpm_clks->SocClocks[%d] = %d\n",
949 					   i, dpm_clks->SocClocks[i]);
950 		}
951 		for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) {
952 			DC_LOG_SMU("dpm_clks->FclkClocks_Freq[%d] = %d\n",
953 					   i, dpm_clks->FclkClocks_Freq[i]);
954 			DC_LOG_SMU("dpm_clks->FclkClocks_Voltage[%d] = %d\n",
955 					   i, dpm_clks->FclkClocks_Voltage[i]);
956 		}
957 		for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++)
958 			DC_LOG_SMU("dpm_clks->SocVoltage[%d] = %d\n",
959 					   i, dpm_clks->SocVoltage[i]);
960 
961 		for (i = 0; i < NUM_MEM_PSTATE_LEVELS; i++) {
962 			DC_LOG_SMU("dpm_clks.MemPstateTable[%d].UClk = %d\n"
963 					   "dpm_clks->MemPstateTable[%d].MemClk= %d\n"
964 					   "dpm_clks->MemPstateTable[%d].Voltage = %d\n",
965 					   i, dpm_clks->MemPstateTable[i].UClk,
966 					   i, dpm_clks->MemPstateTable[i].MemClk,
967 					   i, dpm_clks->MemPstateTable[i].Voltage);
968 		}
969 
970 		if (clk_mgr_base->ctx->dc_bios->integrated_info && clk_mgr_base->ctx->dc->config.use_default_clock_table == false) {
971 			/* DCFCLK */
972 			dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dcfclk_mhz,
973 					dpm_clks->DcfClocks,
974 					dpm_clks->NumDcfClkLevelsEnabled);
975 			clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels = dpm_clks->NumDcfClkLevelsEnabled;
976 
977 			/* SOCCLK */
978 			dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].socclk_mhz,
979 					dpm_clks->SocClocks,
980 					dpm_clks->NumSocClkLevelsEnabled);
981 			clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_socclk_levels = dpm_clks->NumSocClkLevelsEnabled;
982 
983 			/* DISPCLK */
984 			dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dispclk_mhz,
985 					dpm_clks->DispClocks,
986 					dpm_clks->NumDispClkLevelsEnabled);
987 			clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dispclk_levels = dpm_clks->NumDispClkLevelsEnabled;
988 
989 			/* DPPCLK */
990 			dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dppclk_mhz,
991 					dpm_clks->DppClocks,
992 					dpm_clks->NumDispClkLevelsEnabled);
993 			clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dppclk_levels = dpm_clks->NumDispClkLevelsEnabled;
994 
995 			/* FCLK */
996 			dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].fclk_mhz,
997 					dpm_clks->FclkClocks_Freq,
998 					NUM_FCLK_DPM_LEVELS);
999 			clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_fclk_levels = dpm_clks->NumFclkLevelsEnabled;
1000 			clk_mgr_base->bw_params->clk_table.num_entries = dpm_clks->NumFclkLevelsEnabled;
1001 
1002 			/* Memory Pstate table is in reverse order*/
1003 			ASSERT(dpm_clks->NumMemPstatesEnabled <= NUM_MEM_PSTATE_LEVELS);
1004 			if (dpm_clks->NumMemPstatesEnabled > NUM_MEM_PSTATE_LEVELS)
1005 				dpm_clks->NumMemPstatesEnabled = NUM_MEM_PSTATE_LEVELS;
1006 			for (i = 0; i < dpm_clks->NumMemPstatesEnabled; i++) {
1007 				clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].memclk_mhz = dpm_clks->MemPstateTable[i].MemClk;
1008 				clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].wck_ratio = dcn42_convert_wck_ratio(dpm_clks->MemPstateTable[i].WckRatio)	;
1009 			}
1010 			clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_memclk_levels = dpm_clks->NumMemPstatesEnabled;
1011 
1012 			/* DTBCLK*/
1013 			clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz = 600; /* Fixed on platform */
1014 			clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels = 1;
1015 		}
1016 	}
1017 	if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0)
1018 		dm_helpers_free_gpu_mem(clk_mgr_base->ctx, DC_MEM_ALLOC_TYPE_GART,
1019 				smu_dpm_clks.dpm_clks);
1020 }
1021 
1022 static struct clk_mgr_funcs dcn42_funcs = {
1023 	.get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
1024 	.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
1025 	.update_clocks = dcn42_update_clocks,
1026 	.init_clocks = dcn42_init_clocks,
1027 	.enable_pme_wa = dcn42_enable_pme_wa,
1028 	.are_clock_states_equal = dcn42_are_clock_states_equal,
1029 	.notify_wm_ranges = NULL,
1030 	.set_low_power_state = dcn42_set_low_power_state,
1031 	.exit_low_power_state = dcn42_exit_low_power_state,
1032 	.get_max_clock_khz = dcn42_get_max_clock_khz,
1033 	.get_dispclk_from_dentist = dcn42_get_dispclk_from_dentist,
1034 	.is_smu_present = dcn42_is_smu_present,
1035 };
1036 
1037 struct clk_mgr_funcs dcn42_fpga_funcs = {
1038 	.get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
1039 	.update_clocks = dcn42_update_clocks_fpga,
1040 	.init_clocks = dcn42_init_clocks_fpga,
1041 	.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
1042 };
1043 
1044 void dcn42_clk_mgr_construct(
1045 		struct dc_context *ctx,
1046 		struct clk_mgr_dcn42 *clk_mgr,
1047 		struct pp_smu_funcs *pp_smu,
1048 		struct dccg *dccg)
1049 {
1050 	clk_mgr->base.base.ctx = ctx;
1051 	clk_mgr->base.base.funcs = &dcn42_funcs;
1052 	clk_mgr->base.regs = &clk_mgr_regs_dcn42;
1053 	clk_mgr->base.clk_mgr_shift = &clk_mgr_shift_dcn42;
1054 	clk_mgr->base.clk_mgr_mask = &clk_mgr_mask_dcn42;
1055 
1056 	clk_mgr->base.pp_smu = pp_smu;
1057 
1058 	clk_mgr->base.dccg = dccg;
1059 	clk_mgr->base.dfs_bypass_disp_clk = 0;
1060 
1061 	clk_mgr->base.dprefclk_ss_percentage = 0;
1062 	clk_mgr->base.dprefclk_ss_divider = 1000;
1063 	clk_mgr->base.ss_on_dprefclk = false;
1064 	clk_mgr->base.dfs_ref_freq_khz = 48000; /*sync with pmfw*/
1065 	clk_mgr->base.base.clks.ref_dtbclk_khz = 600000;
1066 
1067 	/* Changed from DCN3.2_clock_frequency doc to match
1068 	 * dcn32_dump_clk_registers from 4 * dentist_vco_freq_khz /
1069 	 * dprefclk DID divider
1070 	 */
1071 	clk_mgr->base.base.dprefclk_khz = 600000;
1072 
1073 		clk_mgr->base.smu_present = false;
1074 		clk_mgr->base.smu_ver = dcn42_smu_get_pmfw_version(&clk_mgr->base);
1075 		if (clk_mgr->base.smu_ver && clk_mgr->base.smu_ver != -1)
1076 			clk_mgr->base.smu_present = true;
1077 
1078 		if (ctx->dc_bios->integrated_info) {
1079 			clk_mgr->base.base.dentist_vco_freq_khz = ctx->dc_bios->integrated_info->dentist_vco_freq;
1080 
1081 			dcn42_bw_params.vram_type = ctx->dc_bios->integrated_info->memory_type;
1082 			dcn42_bw_params.dram_channel_width_bytes = ctx->dc_bios->integrated_info->memory_type == 0x22 ? 8 : 4;
1083 			dcn42_bw_params.num_channels = ctx->dc_bios->integrated_info->ma_channel_number ? ctx->dc_bios->integrated_info->ma_channel_number : 2;
1084 			if (clk_mgr->base.smu_present) {
1085 				clk_mgr->base.base.clks.ref_dtbclk_khz = dcn42_smu_get_dtbclk(&clk_mgr->base);
1086 				clk_mgr->base.base.dprefclk_khz = dcn42_smu_get_dprefclk(&clk_mgr->base);
1087 			}
1088 			clk_mgr->base.base.bw_params = &dcn42_bw_params;
1089 
1090 			if (clk_mgr->base.smu_present)
1091 				dcn42_get_smu_clocks(&clk_mgr->base);
1092 		}
1093 		/* in case we don't get a value from the BIOS, use default */
1094 		if (clk_mgr->base.base.dentist_vco_freq_khz == 0)
1095 			clk_mgr->base.base.dentist_vco_freq_khz = 3000000; /* 3000MHz */
1096 
1097 		/* Saved clocks configured at boot for debug purposes */
1098 		dcn42_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, clk_mgr);
1099 
1100 	dce_clock_read_ss_info(&clk_mgr->base);
1101 	/*when clk src is from FCH, it could have ss, same clock src as DPREF clk*/
1102 
1103 	dcn42_read_ss_info_from_lut(&clk_mgr->base);
1104 
1105 	clk_mgr->base.base.bw_params = &dcn42_bw_params;
1106 	if (clk_mgr->base.smu_present)
1107 		dcn42_get_smu_clocks(&clk_mgr->base);
1108 }
1109 
1110 void dcn42_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int)
1111 {
1112 	struct clk_mgr_dcn42 *clk_mgr = TO_CLK_MGR_DCN42(clk_mgr_int);
1113 
1114 	if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0) {
1115 		dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_GART,
1116 				clk_mgr->smu_wm_set.wm_set);
1117 		clk_mgr->smu_wm_set.wm_set = NULL;
1118 		clk_mgr->smu_wm_set.mc_address.quad_part = 0;
1119 	}
1120 }
1121