1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright 2022 Advanced Micro Devices, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Authors: AMD
24  *
25  */
26 
27 
28 
29 #include "dcn314_clk_mgr.h"
30 
31 #include "dccg.h"
32 #include "clk_mgr_internal.h"
33 
34 // For dce12_get_dp_ref_freq_khz
35 #include "dce100/dce_clk_mgr.h"
36 
37 // For dcn20_update_clocks_update_dpp_dto
38 #include "dcn20/dcn20_clk_mgr.h"
39 
40 
41 
42 #include "reg_helper.h"
43 #include "core_types.h"
44 #include "dm_helpers.h"
45 
46 /* TODO: remove this include once we ported over remaining clk mgr functions*/
47 #include "dcn30/dcn30_clk_mgr.h"
48 #include "dcn31/dcn31_clk_mgr.h"
49 
50 #include "dc_dmub_srv.h"
51 #include "link.h"
52 #include "dcn314_smu.h"
53 
54 
55 #include "logger_types.h"
56 #undef DC_LOGGER
57 #define DC_LOGGER \
58 	clk_mgr->base.base.ctx->logger
59 
60 
61 #define MAX_INSTANCE                                        7
62 #define MAX_SEGMENT                                         8
63 
64 struct IP_BASE_INSTANCE {
65 	unsigned int segment[MAX_SEGMENT];
66 };
67 
68 struct IP_BASE {
69 	struct IP_BASE_INSTANCE instance[MAX_INSTANCE];
70 };
71 
72 static const struct IP_BASE CLK_BASE = { { { { 0x00016C00, 0x02401800, 0, 0, 0, 0, 0, 0 } },
73 					{ { 0x00016E00, 0x02401C00, 0, 0, 0, 0, 0, 0 } },
74 					{ { 0x00017000, 0x02402000, 0, 0, 0, 0, 0, 0 } },
75 					{ { 0x00017200, 0x02402400, 0, 0, 0, 0, 0, 0 } },
76 					{ { 0x0001B000, 0x0242D800, 0, 0, 0, 0, 0, 0 } },
77 					{ { 0x0001B200, 0x0242DC00, 0, 0, 0, 0, 0, 0 } },
78 					{ { 0x0001B400, 0x0242E000, 0, 0, 0, 0, 0, 0 } } } };
79 
80 #define regCLK1_CLK_PLL_REQ			0x0237
81 #define regCLK1_CLK_PLL_REQ_BASE_IDX		0
82 
83 #define CLK1_CLK_PLL_REQ__FbMult_int__SHIFT	0x0
84 #define CLK1_CLK_PLL_REQ__PllSpineDiv__SHIFT	0xc
85 #define CLK1_CLK_PLL_REQ__FbMult_frac__SHIFT	0x10
86 #define CLK1_CLK_PLL_REQ__FbMult_int_MASK	0x000001FFL
87 #define CLK1_CLK_PLL_REQ__PllSpineDiv_MASK	0x0000F000L
88 #define CLK1_CLK_PLL_REQ__FbMult_frac_MASK	0xFFFF0000L
89 
90 #define REG(reg_name) \
91 	(CLK_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
92 
93 #define TO_CLK_MGR_DCN314(clk_mgr)\
94 	container_of(clk_mgr, struct clk_mgr_dcn314, base)
95 
96 static int dcn314_get_active_display_cnt_wa(
97 		struct dc *dc,
98 		struct dc_state *context)
99 {
100 	int i, display_count;
101 	bool tmds_present = false;
102 
103 	display_count = 0;
104 	for (i = 0; i < context->stream_count; i++) {
105 		const struct dc_stream_state *stream = context->streams[i];
106 
107 		if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
108 				stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
109 				stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK)
110 			tmds_present = true;
111 
112 		/* Checking stream / link detection ensuring that PHY is active*/
113 		if (dc_is_dp_signal(stream->signal) && !stream->dpms_off)
114 			display_count++;
115 
116 	}
117 
118 	for (i = 0; i < dc->link_count; i++) {
119 		const struct dc_link *link = dc->links[i];
120 
121 		/* abusing the fact that the dig and phy are coupled to see if the phy is enabled */
122 		if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
123 				link->link_enc->funcs->is_dig_enabled(link->link_enc))
124 			display_count++;
125 	}
126 
127 	/* WA for hang on HDMI after display off back on*/
128 	if (display_count == 0 && tmds_present)
129 		display_count = 1;
130 
131 	return display_count;
132 }
133 
134 static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable)
135 {
136 	struct dc *dc = clk_mgr_base->ctx->dc;
137 	int i;
138 
139 	for (i = 0; i < dc->res_pool->pipe_count; ++i) {
140 		struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
141 
142 		if (pipe->top_pipe || pipe->prev_odm_pipe)
143 			continue;
144 		if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) {
145 			struct stream_encoder *stream_enc = pipe->stream_res.stream_enc;
146 
147 			if (disable) {
148 				if (stream_enc && stream_enc->funcs->disable_fifo)
149 					pipe->stream_res.stream_enc->funcs->disable_fifo(stream_enc);
150 
151 				pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
152 				reset_sync_context_for_pipe(dc, context, i);
153 			} else {
154 				pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
155 
156 				if (stream_enc && stream_enc->funcs->enable_fifo)
157 					pipe->stream_res.stream_enc->funcs->enable_fifo(stream_enc);
158 			}
159 		}
160 	}
161 }
162 
163 void dcn314_update_clocks(struct clk_mgr *clk_mgr_base,
164 			struct dc_state *context,
165 			bool safe_to_lower)
166 {
167 	union dmub_rb_cmd cmd;
168 	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
169 	struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
170 	struct dc *dc = clk_mgr_base->ctx->dc;
171 	int display_count;
172 	bool update_dppclk = false;
173 	bool update_dispclk = false;
174 	bool dpp_clock_lowered = false;
175 
176 	if (dc->work_arounds.skip_clock_update)
177 		return;
178 
179 	/*
180 	 * if it is safe to lower, but we are already in the lower state, we don't have to do anything
181 	 * also if safe to lower is false, we just go in the higher state
182 	 */
183 	if (safe_to_lower) {
184 		if (new_clocks->zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW &&
185 				new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
186 			dcn314_smu_set_zstate_support(clk_mgr, new_clocks->zstate_support);
187 			dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, true);
188 			clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
189 		}
190 
191 		if (clk_mgr_base->clks.dtbclk_en && !new_clocks->dtbclk_en) {
192 			dcn314_smu_set_dtbclk(clk_mgr, false);
193 			clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en;
194 		}
195 		/* check that we're not already in lower */
196 		if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
197 			display_count = dcn314_get_active_display_cnt_wa(dc, context);
198 			/* if we can go lower, go lower */
199 			if (display_count == 0) {
200 				union display_idle_optimization_u idle_info = { 0 };
201 				idle_info.idle_info.df_request_disabled = 1;
202 				idle_info.idle_info.phy_ref_clk_off = 1;
203 				idle_info.idle_info.s0i2_rdy = 1;
204 				dcn314_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
205 				/* update power state */
206 				clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
207 			}
208 		}
209 	} else {
210 		if (new_clocks->zstate_support == DCN_ZSTATE_SUPPORT_DISALLOW &&
211 				new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
212 			dcn314_smu_set_zstate_support(clk_mgr, DCN_ZSTATE_SUPPORT_DISALLOW);
213 			dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, false);
214 			clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
215 		}
216 
217 		if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) {
218 			dcn314_smu_set_dtbclk(clk_mgr, true);
219 			clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en;
220 		}
221 
222 		/* check that we're not already in D0 */
223 		if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) {
224 			union display_idle_optimization_u idle_info = { 0 };
225 
226 			dcn314_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
227 			/* update power state */
228 			clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE;
229 		}
230 	}
231 
232 	if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) {
233 		clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz;
234 		dcn314_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz);
235 	}
236 
237 	if (should_set_clock(safe_to_lower,
238 			new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) {
239 		clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
240 		dcn314_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz);
241 	}
242 
243 	// workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow.
244 	if (!IS_DIAG_DC(dc->ctx->dce_environment)) {
245 		if (new_clocks->dppclk_khz < 100000)
246 			new_clocks->dppclk_khz = 100000;
247 	}
248 
249 	if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
250 		if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
251 			dpp_clock_lowered = true;
252 		clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
253 		update_dppclk = true;
254 	}
255 
256 	if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
257 		dcn314_disable_otg_wa(clk_mgr_base, context, true);
258 
259 		clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
260 		dcn314_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
261 		dcn314_disable_otg_wa(clk_mgr_base, context, false);
262 
263 		update_dispclk = true;
264 	}
265 
266 	if (dpp_clock_lowered) {
267 		// increase per DPP DTO before lowering global dppclk
268 		dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
269 		dcn314_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
270 	} else {
271 		// increase global DPPCLK before lowering per DPP DTO
272 		if (update_dppclk || update_dispclk)
273 			dcn314_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
274 		// always update dtos unless clock is lowered and not safe to lower
275 		if (new_clocks->dppclk_khz >= dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz)
276 			dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
277 	}
278 
279 	// notify DMCUB of latest clocks
280 	memset(&cmd, 0, sizeof(cmd));
281 	cmd.notify_clocks.header.type = DMUB_CMD__CLK_MGR;
282 	cmd.notify_clocks.header.sub_type = DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS;
283 	cmd.notify_clocks.clocks.dcfclk_khz = clk_mgr_base->clks.dcfclk_khz;
284 	cmd.notify_clocks.clocks.dcfclk_deep_sleep_khz =
285 		clk_mgr_base->clks.dcfclk_deep_sleep_khz;
286 	cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz;
287 	cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz;
288 
289 	dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
290 	dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
291 	dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
292 }
293 
294 static int get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr)
295 {
296 	/* get FbMult value */
297 	struct fixed31_32 pll_req;
298 	unsigned int fbmult_frac_val = 0;
299 	unsigned int fbmult_int_val = 0;
300 
301 	/*
302 	 * Register value of fbmult is in 8.16 format, we are converting to 314.32
303 	 * to leverage the fix point operations available in driver
304 	 */
305 
306 	REG_GET(CLK1_CLK_PLL_REQ, FbMult_frac, &fbmult_frac_val); /* 16 bit fractional part*/
307 	REG_GET(CLK1_CLK_PLL_REQ, FbMult_int, &fbmult_int_val); /* 8 bit integer part */
308 
309 	pll_req = dc_fixpt_from_int(fbmult_int_val);
310 
311 	/*
312 	 * since fractional part is only 16 bit in register definition but is 32 bit
313 	 * in our fix point definiton, need to shift left by 16 to obtain correct value
314 	 */
315 	pll_req.value |= fbmult_frac_val << 16;
316 
317 	/* multiply by REFCLK period */
318 	pll_req = dc_fixpt_mul_int(pll_req, clk_mgr->dfs_ref_freq_khz);
319 
320 	/* integer part is now VCO frequency in kHz */
321 	return dc_fixpt_floor(pll_req);
322 }
323 
324 static void dcn314_enable_pme_wa(struct clk_mgr *clk_mgr_base)
325 {
326 	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
327 
328 	dcn314_smu_enable_pme_wa(clk_mgr);
329 }
330 
331 bool dcn314_are_clock_states_equal(struct dc_clocks *a,
332 		struct dc_clocks *b)
333 {
334 	if (a->dispclk_khz != b->dispclk_khz)
335 		return false;
336 	else if (a->dppclk_khz != b->dppclk_khz)
337 		return false;
338 	else if (a->dcfclk_khz != b->dcfclk_khz)
339 		return false;
340 	else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz)
341 		return false;
342 	else if (a->zstate_support != b->zstate_support)
343 		return false;
344 	else if (a->dtbclk_en != b->dtbclk_en)
345 		return false;
346 
347 	return true;
348 }
349 
350 static void dcn314_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
351 		struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
352 {
353 	return;
354 }
355 
356 static struct clk_bw_params dcn314_bw_params = {
357 	.vram_type = Ddr4MemType,
358 	.num_channels = 1,
359 	.clk_table = {
360 		.num_entries = 4,
361 	},
362 
363 };
364 
365 static struct wm_table ddr5_wm_table = {
366 	.entries = {
367 		{
368 			.wm_inst = WM_A,
369 			.wm_type = WM_TYPE_PSTATE_CHG,
370 			.pstate_latency_us = 11.72,
371 			.sr_exit_time_us = 12.5,
372 			.sr_enter_plus_exit_time_us = 14.5,
373 			.valid = true,
374 		},
375 		{
376 			.wm_inst = WM_B,
377 			.wm_type = WM_TYPE_PSTATE_CHG,
378 			.pstate_latency_us = 11.72,
379 			.sr_exit_time_us = 12.5,
380 			.sr_enter_plus_exit_time_us = 14.5,
381 			.valid = true,
382 		},
383 		{
384 			.wm_inst = WM_C,
385 			.wm_type = WM_TYPE_PSTATE_CHG,
386 			.pstate_latency_us = 11.72,
387 			.sr_exit_time_us = 12.5,
388 			.sr_enter_plus_exit_time_us = 14.5,
389 			.valid = true,
390 		},
391 		{
392 			.wm_inst = WM_D,
393 			.wm_type = WM_TYPE_PSTATE_CHG,
394 			.pstate_latency_us = 11.72,
395 			.sr_exit_time_us = 12.5,
396 			.sr_enter_plus_exit_time_us = 14.5,
397 			.valid = true,
398 		},
399 	}
400 };
401 
402 static struct wm_table lpddr5_wm_table = {
403 	.entries = {
404 		{
405 			.wm_inst = WM_A,
406 			.wm_type = WM_TYPE_PSTATE_CHG,
407 			.pstate_latency_us = 11.65333,
408 			.sr_exit_time_us = 16.5,
409 			.sr_enter_plus_exit_time_us = 18.5,
410 			.valid = true,
411 		},
412 		{
413 			.wm_inst = WM_B,
414 			.wm_type = WM_TYPE_PSTATE_CHG,
415 			.pstate_latency_us = 11.65333,
416 			.sr_exit_time_us = 16.5,
417 			.sr_enter_plus_exit_time_us = 18.5,
418 			.valid = true,
419 		},
420 		{
421 			.wm_inst = WM_C,
422 			.wm_type = WM_TYPE_PSTATE_CHG,
423 			.pstate_latency_us = 11.65333,
424 			.sr_exit_time_us = 16.5,
425 			.sr_enter_plus_exit_time_us = 18.5,
426 			.valid = true,
427 		},
428 		{
429 			.wm_inst = WM_D,
430 			.wm_type = WM_TYPE_PSTATE_CHG,
431 			.pstate_latency_us = 11.65333,
432 			.sr_exit_time_us = 16.5,
433 			.sr_enter_plus_exit_time_us = 18.5,
434 			.valid = true,
435 		},
436 	}
437 };
438 
439 static DpmClocks314_t dummy_clocks;
440 
441 static struct dcn314_watermarks dummy_wms = { 0 };
442 
443 static void dcn314_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn314_watermarks *table)
444 {
445 	int i, num_valid_sets;
446 
447 	num_valid_sets = 0;
448 
449 	for (i = 0; i < WM_SET_COUNT; i++) {
450 		/* skip empty entries, the smu array has no holes*/
451 		if (!bw_params->wm_table.entries[i].valid)
452 			continue;
453 
454 		table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmSetting = bw_params->wm_table.entries[i].wm_inst;
455 		table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType = bw_params->wm_table.entries[i].wm_type;
456 		/* We will not select WM based on fclk, so leave it as unconstrained */
457 		table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
458 		table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
459 
460 		if (table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType == WM_TYPE_PSTATE_CHG) {
461 			if (i == 0)
462 				table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 0;
463 			else {
464 				/* add 1 to make it non-overlapping with next lvl */
465 				table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk =
466 						bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1;
467 			}
468 			table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxMclk =
469 					bw_params->clk_table.entries[i].dcfclk_mhz;
470 
471 		} else {
472 			/* unconstrained for memory retraining */
473 			table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
474 			table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
475 
476 			/* Modify previous watermark range to cover up to max */
477 			table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
478 		}
479 		num_valid_sets++;
480 	}
481 
482 	ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */
483 
484 	/* modify the min and max to make sure we cover the whole range*/
485 	table->WatermarkRow[WM_DCFCLK][0].MinMclk = 0;
486 	table->WatermarkRow[WM_DCFCLK][0].MinClock = 0;
487 	table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxMclk = 0xFFFF;
488 	table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
489 
490 	/* This is for writeback only, does not matter currently as no writeback support*/
491 	table->WatermarkRow[WM_SOCCLK][0].WmSetting = WM_A;
492 	table->WatermarkRow[WM_SOCCLK][0].MinClock = 0;
493 	table->WatermarkRow[WM_SOCCLK][0].MaxClock = 0xFFFF;
494 	table->WatermarkRow[WM_SOCCLK][0].MinMclk = 0;
495 	table->WatermarkRow[WM_SOCCLK][0].MaxMclk = 0xFFFF;
496 }
497 
498 static void dcn314_notify_wm_ranges(struct clk_mgr *clk_mgr_base)
499 {
500 	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
501 	struct clk_mgr_dcn314 *clk_mgr_dcn314 = TO_CLK_MGR_DCN314(clk_mgr);
502 	struct dcn314_watermarks *table = clk_mgr_dcn314->smu_wm_set.wm_set;
503 
504 	if (!clk_mgr->smu_ver)
505 		return;
506 
507 	if (!table || clk_mgr_dcn314->smu_wm_set.mc_address.quad_part == 0)
508 		return;
509 
510 	memset(table, 0, sizeof(*table));
511 
512 	dcn314_build_watermark_ranges(clk_mgr_base->bw_params, table);
513 
514 	dcn314_smu_set_dram_addr_high(clk_mgr,
515 			clk_mgr_dcn314->smu_wm_set.mc_address.high_part);
516 	dcn314_smu_set_dram_addr_low(clk_mgr,
517 			clk_mgr_dcn314->smu_wm_set.mc_address.low_part);
518 	dcn314_smu_transfer_wm_table_dram_2_smu(clk_mgr);
519 }
520 
521 static void dcn314_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
522 		struct dcn314_smu_dpm_clks *smu_dpm_clks)
523 {
524 	DpmClocks314_t *table = smu_dpm_clks->dpm_clks;
525 
526 	if (!clk_mgr->smu_ver)
527 		return;
528 
529 	if (!table || smu_dpm_clks->mc_address.quad_part == 0)
530 		return;
531 
532 	memset(table, 0, sizeof(*table));
533 
534 	dcn314_smu_set_dram_addr_high(clk_mgr,
535 			smu_dpm_clks->mc_address.high_part);
536 	dcn314_smu_set_dram_addr_low(clk_mgr,
537 			smu_dpm_clks->mc_address.low_part);
538 	dcn314_smu_transfer_dpm_table_smu_2_dram(clk_mgr);
539 }
540 
541 static inline bool is_valid_clock_value(uint32_t clock_value)
542 {
543 	return clock_value > 1 && clock_value < 100000;
544 }
545 
546 static unsigned int convert_wck_ratio(uint8_t wck_ratio)
547 {
548 	switch (wck_ratio) {
549 	case WCK_RATIO_1_2:
550 		return 2;
551 
552 	case WCK_RATIO_1_4:
553 		return 4;
554 
555 	default:
556 		break;
557 	}
558 	return 1;
559 }
560 
561 static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks)
562 {
563 	uint32_t max = 0;
564 	int i;
565 
566 	for (i = 0; i < num_clocks; ++i) {
567 		if (clocks[i] > max)
568 			max = clocks[i];
569 	}
570 
571 	return max;
572 }
573 
574 static void dcn314_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk_mgr,
575 						    struct integrated_info *bios_info,
576 						    const DpmClocks314_t *clock_table)
577 {
578 	struct clk_bw_params *bw_params = clk_mgr->base.bw_params;
579 	struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1];
580 	uint32_t max_pstate = 0,  max_fclk = 0,  min_pstate = 0, max_dispclk = 0, max_dppclk = 0;
581 	int i;
582 
583 	/* Find highest valid fclk pstate */
584 	for (i = 0; i < clock_table->NumDfPstatesEnabled; i++) {
585 		if (is_valid_clock_value(clock_table->DfPstateTable[i].FClk) &&
586 		    clock_table->DfPstateTable[i].FClk > max_fclk) {
587 			max_fclk = clock_table->DfPstateTable[i].FClk;
588 			max_pstate = i;
589 		}
590 	}
591 
592 	/* We expect the table to contain at least one valid fclk entry. */
593 	ASSERT(is_valid_clock_value(max_fclk));
594 
595 	/* Dispclk and dppclk can be max at any voltage, same number of levels for both */
596 	if (clock_table->NumDispClkLevelsEnabled <= NUM_DISPCLK_DPM_LEVELS &&
597 	    clock_table->NumDispClkLevelsEnabled <= NUM_DPPCLK_DPM_LEVELS) {
598 		max_dispclk = find_max_clk_value(clock_table->DispClocks, clock_table->NumDispClkLevelsEnabled);
599 		max_dppclk = find_max_clk_value(clock_table->DppClocks, clock_table->NumDispClkLevelsEnabled);
600 	} else {
601 		/* Invalid number of entries in the table from PMFW. */
602 		ASSERT(0);
603 	}
604 
605 	/* Base the clock table on dcfclk, need at least one entry regardless of pmfw table */
606 	for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) {
607 		uint32_t min_fclk = clock_table->DfPstateTable[0].FClk;
608 		int j;
609 
610 		for (j = 1; j < clock_table->NumDfPstatesEnabled; j++) {
611 			if (is_valid_clock_value(clock_table->DfPstateTable[j].FClk) &&
612 			    clock_table->DfPstateTable[j].FClk < min_fclk &&
613 			    clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i]) {
614 				min_fclk = clock_table->DfPstateTable[j].FClk;
615 				min_pstate = j;
616 			}
617 		}
618 
619 		/* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */
620 		for (j = bw_params->clk_table.num_entries - 1; j > 0; j--)
621 			if (bw_params->clk_table.entries[j].dcfclk_mhz <= clock_table->DcfClocks[i])
622 				break;
623 
624 		bw_params->clk_table.entries[i].phyclk_mhz = bw_params->clk_table.entries[j].phyclk_mhz;
625 		bw_params->clk_table.entries[i].phyclk_d18_mhz = bw_params->clk_table.entries[j].phyclk_d18_mhz;
626 		bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz;
627 
628 		/* Now update clocks we do read */
629 		bw_params->clk_table.entries[i].fclk_mhz = min_fclk;
630 		bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[min_pstate].MemClk;
631 		bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[min_pstate].Voltage;
632 		bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i];
633 		bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i];
634 		bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk;
635 		bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk;
636 		bw_params->clk_table.entries[i].wck_ratio = convert_wck_ratio(
637 			clock_table->DfPstateTable[min_pstate].WckRatio);
638 	}
639 
640 	/* Make sure to include at least one entry at highest pstate */
641 	if (max_pstate != min_pstate || i == 0) {
642 		if (i > MAX_NUM_DPM_LVL - 1)
643 			i = MAX_NUM_DPM_LVL - 1;
644 
645 		bw_params->clk_table.entries[i].fclk_mhz = max_fclk;
646 		bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk;
647 		bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[max_pstate].Voltage;
648 		bw_params->clk_table.entries[i].dcfclk_mhz = find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS);
649 		bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS);
650 		bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk;
651 		bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk;
652 		bw_params->clk_table.entries[i].wck_ratio = convert_wck_ratio(
653 			clock_table->DfPstateTable[max_pstate].WckRatio);
654 		i++;
655 	}
656 	bw_params->clk_table.num_entries = i--;
657 
658 	/* Make sure all highest clocks are included*/
659 	bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS);
660 	bw_params->clk_table.entries[i].dispclk_mhz = find_max_clk_value(clock_table->DispClocks, NUM_DISPCLK_DPM_LEVELS);
661 	bw_params->clk_table.entries[i].dppclk_mhz = find_max_clk_value(clock_table->DppClocks, NUM_DPPCLK_DPM_LEVELS);
662 	ASSERT(clock_table->DcfClocks[i] == find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS));
663 	bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz;
664 	bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz;
665 	bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz;
666 
667 	/*
668 	 * Set any 0 clocks to max default setting. Not an issue for
669 	 * power since we aren't doing switching in such case anyway
670 	 */
671 	for (i = 0; i < bw_params->clk_table.num_entries; i++) {
672 		if (!bw_params->clk_table.entries[i].fclk_mhz) {
673 			bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz;
674 			bw_params->clk_table.entries[i].memclk_mhz = def_max.memclk_mhz;
675 			bw_params->clk_table.entries[i].voltage = def_max.voltage;
676 		}
677 		if (!bw_params->clk_table.entries[i].dcfclk_mhz)
678 			bw_params->clk_table.entries[i].dcfclk_mhz = def_max.dcfclk_mhz;
679 		if (!bw_params->clk_table.entries[i].socclk_mhz)
680 			bw_params->clk_table.entries[i].socclk_mhz = def_max.socclk_mhz;
681 		if (!bw_params->clk_table.entries[i].dispclk_mhz)
682 			bw_params->clk_table.entries[i].dispclk_mhz = def_max.dispclk_mhz;
683 		if (!bw_params->clk_table.entries[i].dppclk_mhz)
684 			bw_params->clk_table.entries[i].dppclk_mhz = def_max.dppclk_mhz;
685 		if (!bw_params->clk_table.entries[i].phyclk_mhz)
686 			bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz;
687 		if (!bw_params->clk_table.entries[i].phyclk_d18_mhz)
688 			bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz;
689 		if (!bw_params->clk_table.entries[i].dtbclk_mhz)
690 			bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz;
691 	}
692 	ASSERT(bw_params->clk_table.entries[i-1].dcfclk_mhz);
693 	bw_params->vram_type = bios_info->memory_type;
694 
695 	bw_params->dram_channel_width_bytes = bios_info->memory_type == 0x22 ? 8 : 4;
696 	bw_params->num_channels = bios_info->ma_channel_number ? bios_info->ma_channel_number : 4;
697 
698 	for (i = 0; i < WM_SET_COUNT; i++) {
699 		bw_params->wm_table.entries[i].wm_inst = i;
700 
701 		if (i >= bw_params->clk_table.num_entries) {
702 			bw_params->wm_table.entries[i].valid = false;
703 			continue;
704 		}
705 
706 		bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG;
707 		bw_params->wm_table.entries[i].valid = true;
708 	}
709 }
710 
711 static struct clk_mgr_funcs dcn314_funcs = {
712 	.get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
713 	.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
714 	.update_clocks = dcn314_update_clocks,
715 	.init_clocks = dcn31_init_clocks,
716 	.enable_pme_wa = dcn314_enable_pme_wa,
717 	.are_clock_states_equal = dcn314_are_clock_states_equal,
718 	.notify_wm_ranges = dcn314_notify_wm_ranges
719 };
720 extern struct clk_mgr_funcs dcn3_fpga_funcs;
721 
722 void dcn314_clk_mgr_construct(
723 		struct dc_context *ctx,
724 		struct clk_mgr_dcn314 *clk_mgr,
725 		struct pp_smu_funcs *pp_smu,
726 		struct dccg *dccg)
727 {
728 	struct dcn314_smu_dpm_clks smu_dpm_clks = { 0 };
729 
730 	clk_mgr->base.base.ctx = ctx;
731 	clk_mgr->base.base.funcs = &dcn314_funcs;
732 
733 	clk_mgr->base.pp_smu = pp_smu;
734 
735 	clk_mgr->base.dccg = dccg;
736 	clk_mgr->base.dfs_bypass_disp_clk = 0;
737 
738 	clk_mgr->base.dprefclk_ss_percentage = 0;
739 	clk_mgr->base.dprefclk_ss_divider = 1000;
740 	clk_mgr->base.ss_on_dprefclk = false;
741 	clk_mgr->base.dfs_ref_freq_khz = 48000;
742 
743 	clk_mgr->smu_wm_set.wm_set = (struct dcn314_watermarks *)dm_helpers_allocate_gpu_mem(
744 				clk_mgr->base.base.ctx,
745 				DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
746 				sizeof(struct dcn314_watermarks),
747 				&clk_mgr->smu_wm_set.mc_address.quad_part);
748 
749 	if (!clk_mgr->smu_wm_set.wm_set) {
750 		clk_mgr->smu_wm_set.wm_set = &dummy_wms;
751 		clk_mgr->smu_wm_set.mc_address.quad_part = 0;
752 	}
753 	ASSERT(clk_mgr->smu_wm_set.wm_set);
754 
755 	smu_dpm_clks.dpm_clks = (DpmClocks314_t *)dm_helpers_allocate_gpu_mem(
756 				clk_mgr->base.base.ctx,
757 				DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
758 				sizeof(DpmClocks314_t),
759 				&smu_dpm_clks.mc_address.quad_part);
760 
761 	if (smu_dpm_clks.dpm_clks == NULL) {
762 		smu_dpm_clks.dpm_clks = &dummy_clocks;
763 		smu_dpm_clks.mc_address.quad_part = 0;
764 	}
765 
766 	ASSERT(smu_dpm_clks.dpm_clks);
767 
768 	if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) {
769 		clk_mgr->base.base.funcs = &dcn3_fpga_funcs;
770 	} else {
771 		struct clk_log_info log_info = {0};
772 
773 		clk_mgr->base.smu_ver = dcn314_smu_get_smu_version(&clk_mgr->base);
774 
775 		if (clk_mgr->base.smu_ver)
776 			clk_mgr->base.smu_present = true;
777 
778 		/* TODO: Check we get what we expect during bringup */
779 		clk_mgr->base.base.dentist_vco_freq_khz = get_vco_frequency_from_reg(&clk_mgr->base);
780 
781 		if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType)
782 			dcn314_bw_params.wm_table = lpddr5_wm_table;
783 		else
784 			dcn314_bw_params.wm_table = ddr5_wm_table;
785 
786 		/* Saved clocks configured at boot for debug purposes */
787 		dcn314_dump_clk_registers(&clk_mgr->base.base.boot_snapshot,
788 					  &clk_mgr->base.base, &log_info);
789 
790 	}
791 
792 	clk_mgr->base.base.dprefclk_khz = 600000;
793 	clk_mgr->base.base.clks.ref_dtbclk_khz = 600000;
794 	dce_clock_read_ss_info(&clk_mgr->base);
795 	/*if bios enabled SS, driver needs to adjust dtb clock, only enable with correct bios*/
796 	//clk_mgr->base.dccg->ref_dtbclk_khz = dce_adjust_dp_ref_freq_for_ss(clk_mgr_internal, clk_mgr->base.base.dprefclk_khz);
797 
798 	clk_mgr->base.base.bw_params = &dcn314_bw_params;
799 
800 	if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) {
801 		int i;
802 
803 		dcn314_get_dpm_table_from_smu(&clk_mgr->base, &smu_dpm_clks);
804 		DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n"
805 				   "NumDispClkLevelsEnabled: %d\n"
806 				   "NumSocClkLevelsEnabled: %d\n"
807 				   "VcnClkLevelsEnabled: %d\n"
808 				   "NumDfPst atesEnabled: %d\n"
809 				   "MinGfxClk: %d\n"
810 				   "MaxGfxClk: %d\n",
811 				   smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled,
812 				   smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled,
813 				   smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled,
814 				   smu_dpm_clks.dpm_clks->VcnClkLevelsEnabled,
815 				   smu_dpm_clks.dpm_clks->NumDfPstatesEnabled,
816 				   smu_dpm_clks.dpm_clks->MinGfxClk,
817 				   smu_dpm_clks.dpm_clks->MaxGfxClk);
818 		for (i = 0; i < smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled; i++) {
819 			DC_LOG_SMU("smu_dpm_clks.dpm_clks->DcfClocks[%d] = %d\n",
820 					   i,
821 					   smu_dpm_clks.dpm_clks->DcfClocks[i]);
822 		}
823 		for (i = 0; i < smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled; i++) {
824 			DC_LOG_SMU("smu_dpm_clks.dpm_clks->DispClocks[%d] = %d\n",
825 					   i, smu_dpm_clks.dpm_clks->DispClocks[i]);
826 		}
827 		for (i = 0; i < smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled; i++) {
828 			DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocClocks[%d] = %d\n",
829 					   i, smu_dpm_clks.dpm_clks->SocClocks[i]);
830 		}
831 		for (i = 0; i < NUM_SOC_VOLTAGE_LEVELS; i++)
832 			DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocVoltage[%d] = %d\n",
833 					   i, smu_dpm_clks.dpm_clks->SocVoltage[i]);
834 
835 		for (i = 0; i < NUM_DF_PSTATE_LEVELS; i++) {
836 			DC_LOG_SMU("smu_dpm_clks.dpm_clks.DfPstateTable[%d].FClk = %d\n"
837 					   "smu_dpm_clks.dpm_clks->DfPstateTable[%d].MemClk= %d\n"
838 					   "smu_dpm_clks.dpm_clks->DfPstateTable[%d].Voltage = %d\n",
839 					   i, smu_dpm_clks.dpm_clks->DfPstateTable[i].FClk,
840 					   i, smu_dpm_clks.dpm_clks->DfPstateTable[i].MemClk,
841 					   i, smu_dpm_clks.dpm_clks->DfPstateTable[i].Voltage);
842 		}
843 
844 		if (ctx->dc_bios && ctx->dc_bios->integrated_info && ctx->dc->config.use_default_clock_table == false) {
845 			dcn314_clk_mgr_helper_populate_bw_params(
846 					&clk_mgr->base,
847 					ctx->dc_bios->integrated_info,
848 					smu_dpm_clks.dpm_clks);
849 		}
850 	}
851 
852 	if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0)
853 		dm_helpers_free_gpu_mem(clk_mgr->base.base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
854 				smu_dpm_clks.dpm_clks);
855 }
856 
857 void dcn314_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int)
858 {
859 	struct clk_mgr_dcn314 *clk_mgr = TO_CLK_MGR_DCN314(clk_mgr_int);
860 
861 	if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0)
862 		dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
863 				clk_mgr->smu_wm_set.wm_set);
864 }
865