xref: /linux/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c (revision 40288c9206c17eb66a603262e06a58d300d0f279)
1 /*
2  * Copyright 2020 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 
27 #include "dm_services.h"
28 #include "dm_helpers.h"
29 #include "core_types.h"
30 #include "resource.h"
31 #include "dcn30_hwseq.h"
32 #include "dccg.h"
33 #include "dce/dce_hwseq.h"
34 #include "dcn30/dcn30_mpc.h"
35 #include "dcn30/dcn30_dpp.h"
36 #include "dcn10/dcn10_cm_common.h"
37 #include "dcn30/dcn30_cm_common.h"
38 #include "reg_helper.h"
39 #include "dcn10/dcn10_hubbub.h"
40 #include "abm.h"
41 #include "clk_mgr.h"
42 #include "hubp.h"
43 #include "dchubbub.h"
44 #include "timing_generator.h"
45 #include "opp.h"
46 #include "ipp.h"
47 #include "mpc.h"
48 #include "mcif_wb.h"
49 #include "dc_dmub_srv.h"
50 #include "link_hwss.h"
51 #include "dpcd_defs.h"
52 #include "dcn20/dcn20_hwseq.h"
53 #include "dcn30/dcn30_resource.h"
54 #include "link_service.h"
55 #include "dc_state_priv.h"
56 #include "dio/dcn10/dcn10_dio.h"
57 
58 #define TO_DCN_DCCG(dccg)\
59 	container_of(dccg, struct dcn_dccg, base)
60 
61 #define DC_LOGGER_INIT(logger)
62 
63 #define CTX \
64 	hws->ctx
65 #define REG(reg)\
66 	hws->regs->reg
67 #define DC_LOGGER \
68 		dc->ctx->logger
69 
70 
71 #undef FN
72 #define FN(reg_name, field_name) \
73 	hws->shifts->field_name, hws->masks->field_name
74 
dcn30_log_color_state(struct dc * dc,struct dc_log_buffer_ctx * log_ctx)75 void dcn30_log_color_state(struct dc *dc,
76 			   struct dc_log_buffer_ctx *log_ctx)
77 {
78 	(void)log_ctx;
79 	struct dc_context *dc_ctx = dc->ctx;
80 	struct resource_pool *pool = dc->res_pool;
81 	bool is_gamut_remap_available = false;
82 	unsigned int i;
83 
84 	DTN_INFO("DPP:  DGAM ROM  DGAM ROM type  DGAM LUT  SHAPER mode"
85 		 "  3DLUT mode  3DLUT bit depth  3DLUT size  RGAM mode"
86 		 "  GAMUT adjust  "
87 		 "C11        C12        C13        C14        "
88 		 "C21        C22        C23        C24        "
89 		 "C31        C32        C33        C34        \n");
90 
91 	for (i = 0; i < pool->pipe_count; i++) {
92 		struct dpp *dpp = pool->dpps[i];
93 		struct dcn_dpp_state s = {0};
94 
95 		dpp->funcs->dpp_read_state(dpp, &s);
96 
97 		if (dpp->funcs->dpp_get_gamut_remap) {
98 			dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap);
99 			is_gamut_remap_available = true;
100 		}
101 
102 		if (!s.is_enabled)
103 			continue;
104 
105 		DTN_INFO("[%2d]:  %7x  %13s  %8s  %11s  %10s  %15s  %10s  %9s",
106 			dpp->inst,
107 			s.pre_dgam_mode,
108 			(s.pre_dgam_select == 0) ? "sRGB" :
109 			 ((s.pre_dgam_select == 1) ? "Gamma 2.2" :
110 			 ((s.pre_dgam_select == 2) ? "Gamma 2.4" :
111 			 ((s.pre_dgam_select == 3) ? "Gamma 2.6" :
112 			 ((s.pre_dgam_select == 4) ? "BT.709" :
113 			 ((s.pre_dgam_select == 5) ? "PQ" :
114 			 ((s.pre_dgam_select == 6) ? "HLG" :
115 						     "Unknown")))))),
116 			(s.gamcor_mode == 0) ? "Bypass" :
117 			 ((s.gamcor_mode == 1) ? "RAM A" :
118 						 "RAM B"),
119 			(s.shaper_lut_mode == 1) ? "RAM A" :
120 			 ((s.shaper_lut_mode == 2) ? "RAM B" :
121 						     "Bypass"),
122 			(s.lut3d_mode == 1) ? "RAM A" :
123 			 ((s.lut3d_mode == 2) ? "RAM B" :
124 						"Bypass"),
125 			(s.lut3d_bit_depth <= 0) ? "12-bit" : "10-bit",
126 			(s.lut3d_size == 0) ? "17x17x17" : "9x9x9",
127 			(s.rgam_lut_mode == 0) ? "Bypass" :
128 			 ((s.rgam_lut_mode == 1) ? "RAM A" :
129 						   "RAM B"));
130 
131 		if (is_gamut_remap_available) {
132 			DTN_INFO("  %12s  "
133 				 "%010lld %010lld %010lld %010lld "
134 				 "%010lld %010lld %010lld %010lld "
135 				 "%010lld %010lld %010lld %010lld",
136 
137 			(s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" :
138 				((s.gamut_remap.gamut_adjust_type == 1) ? "HW" :
139 									  "SW"),
140 			s.gamut_remap.temperature_matrix[0].value,
141 			s.gamut_remap.temperature_matrix[1].value,
142 			s.gamut_remap.temperature_matrix[2].value,
143 			s.gamut_remap.temperature_matrix[3].value,
144 			s.gamut_remap.temperature_matrix[4].value,
145 			s.gamut_remap.temperature_matrix[5].value,
146 			s.gamut_remap.temperature_matrix[6].value,
147 			s.gamut_remap.temperature_matrix[7].value,
148 			s.gamut_remap.temperature_matrix[8].value,
149 			s.gamut_remap.temperature_matrix[9].value,
150 			s.gamut_remap.temperature_matrix[10].value,
151 			s.gamut_remap.temperature_matrix[11].value);
152 		}
153 
154 		DTN_INFO("\n");
155 	}
156 	DTN_INFO("\n");
157 	DTN_INFO("DPP Color Caps: input_lut_shared:%d  icsc:%d"
158 		 "  dgam_ram:%d  dgam_rom: srgb:%d,bt2020:%d,gamma2_2:%d,pq:%d,hlg:%d"
159 		 "  post_csc:%d  gamcor:%d  dgam_rom_for_yuv:%d  3d_lut:%d"
160 		 "  upsp_pre_scaler:%d  blnd_lut:%d  oscs:%d\n\n",
161 		 dc->caps.color.dpp.input_lut_shared,
162 		 dc->caps.color.dpp.icsc,
163 		 dc->caps.color.dpp.dgam_ram,
164 		 dc->caps.color.dpp.dgam_rom_caps.srgb,
165 		 dc->caps.color.dpp.dgam_rom_caps.bt2020,
166 		 dc->caps.color.dpp.dgam_rom_caps.gamma2_2,
167 		 dc->caps.color.dpp.dgam_rom_caps.pq,
168 		 dc->caps.color.dpp.dgam_rom_caps.hlg,
169 		 dc->caps.color.dpp.post_csc,
170 		 dc->caps.color.dpp.gamma_corr,
171 		 dc->caps.color.dpp.dgam_rom_for_yuv,
172 		 dc->caps.color.dpp.hw_3d_lut,
173 		 dc->caps.color.dpp.upsp_pre_scaler,
174 		 dc->caps.color.dpp.ogam_ram,
175 		 dc->caps.color.dpp.ocsc);
176 
177 	DTN_INFO("MPCC:  OPP  DPP  MPCCBOT  MODE  ALPHA_MODE  PREMULT  OVERLAP_ONLY  IDLE"
178 		 "  SHAPER mode  3DLUT mode  3DLUT bit-depth  3DLUT size  OGAM mode  OGAM LUT"
179 		 "  GAMUT adjust  "
180 		 "C11        C12        C13        C14        "
181 		 "C21        C22        C23        C24        "
182 		 "C31        C32        C33        C34        \n");
183 
184 	for (i = 0; i < pool->mpcc_count; i++) {
185 		struct mpcc_state s = {0};
186 
187 		pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s);
188 		mpc3_get_gamut_remap(pool->mpc, i,  &s.gamut_remap);
189 
190 		if (s.opp_id != 0xf)
191 			DTN_INFO("[%2d]:  %2xh  %2xh  %6xh  %4d  %10d  %7d  %12d  %4d  %11s %11s %16s %11s %10s %9s"
192 				 "  %-12s  "
193 				 "%010lld %010lld %010lld %010lld "
194 				 "%010lld %010lld %010lld %010lld "
195 				 "%010lld %010lld %010lld %010lld\n",
196 				i, s.opp_id, s.dpp_id, s.bot_mpcc_id,
197 				s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only,
198 				s.idle,
199 				(s.shaper_lut_mode == 1) ? "RAM A" :
200 				 ((s.shaper_lut_mode == 2) ? "RAM B" :
201 							     "Bypass"),
202 				(s.lut3d_mode == 1) ? "RAM A" :
203 				 ((s.lut3d_mode == 2) ? "RAM B" :
204 							"Bypass"),
205 				(s.lut3d_bit_depth <= 0) ? "12-bit" : "10-bit",
206 				(s.lut3d_size == 0) ? "17x17x17" : "9x9x9",
207 				(s.rgam_mode == 0) ? "Bypass" :
208 				 ((s.rgam_mode == 2) ? "RAM" :
209 						       "Unknown"),
210 				(s.rgam_mode == 1) ? "B" : "A",
211 				(s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" :
212 					((s.gamut_remap.gamut_adjust_type == 1) ? "HW" :
213 										  "SW"),
214 				s.gamut_remap.temperature_matrix[0].value,
215 				s.gamut_remap.temperature_matrix[1].value,
216 				s.gamut_remap.temperature_matrix[2].value,
217 				s.gamut_remap.temperature_matrix[3].value,
218 				s.gamut_remap.temperature_matrix[4].value,
219 				s.gamut_remap.temperature_matrix[5].value,
220 				s.gamut_remap.temperature_matrix[6].value,
221 				s.gamut_remap.temperature_matrix[7].value,
222 				s.gamut_remap.temperature_matrix[8].value,
223 				s.gamut_remap.temperature_matrix[9].value,
224 				s.gamut_remap.temperature_matrix[10].value,
225 				s.gamut_remap.temperature_matrix[11].value);
226 
227 	}
228 	DTN_INFO("\n");
229 	DTN_INFO("MPC Color Caps: gamut_remap:%d, 3dlut:%d, ogam_ram:%d, ocsc:%d\n\n",
230 		 dc->caps.color.mpc.gamut_remap,
231 		 dc->caps.color.mpc.num_3dluts,
232 		 dc->caps.color.mpc.ogam_ram,
233 		 dc->caps.color.mpc.ocsc);
234 }
235 
dcn30_set_blend_lut(struct pipe_ctx * pipe_ctx,const struct dc_plane_state * plane_state)236 bool dcn30_set_blend_lut(
237 	struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
238 {
239 	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
240 	bool result = true;
241 	const struct pwl_params *blend_lut = NULL;
242 
243 	if (plane_state->cm.blend_func.type == TF_TYPE_HWPWL)
244 		blend_lut = &plane_state->cm.blend_func.pwl;
245 	else if (plane_state->cm.blend_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
246 		result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
247 				&plane_state->cm.blend_func,
248 				&dpp_base->regamma_params,
249 				false);
250 		if (!result)
251 			return result;
252 
253 		blend_lut = &dpp_base->regamma_params;
254 	}
255 	result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut);
256 
257 	return result;
258 }
259 
dcn30_set_mpc_shaper_3dlut(struct dpp * dpp,struct mpc * mpc,int mpcc_id,const struct dc_stream_state * stream)260 static bool dcn30_set_mpc_shaper_3dlut(struct dpp *dpp, struct mpc *mpc,
261 				       int mpcc_id, const struct dc_stream_state *stream)
262 {
263 	struct dc *dc = dpp->ctx->dc;
264 	bool result = false;
265 	uint32_t acquired_rmu = 0;
266 	int mpcc_id_projected = 0;
267 
268 	const struct pwl_params *shaper_lut = NULL;
269 	//get the shaper lut params
270 	if (stream->func_shaper) {
271 		if (stream->func_shaper->type == TF_TYPE_HWPWL) {
272 			shaper_lut = &stream->func_shaper->pwl;
273 		} else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
274 			cm_helper_translate_curve_to_hw_format(stream->ctx, stream->func_shaper,
275 							       &dpp->shaper_params, true);
276 			shaper_lut = &dpp->shaper_params;
277 		}
278 	}
279 
280 	if (stream->lut3d_func &&
281 	    stream->lut3d_func->state.bits.initialized == 1 &&
282 	    stream->lut3d_func->state.bits.rmu_idx_valid == 1) {
283 		if (stream->lut3d_func->state.bits.rmu_mux_num == 0)
284 			mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu0_mux;
285 		else if (stream->lut3d_func->state.bits.rmu_mux_num == 1)
286 			mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu1_mux;
287 		else if (stream->lut3d_func->state.bits.rmu_mux_num == 2)
288 			mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu2_mux;
289 		if (mpcc_id_projected != mpcc_id)
290 			BREAK_TO_DEBUGGER();
291 		/* find the reason why logical layer assigned a different
292 		 * mpcc_id into acquire_post_bldn_3dlut
293 		 */
294 		acquired_rmu = mpc->funcs->acquire_rmu(mpc, mpcc_id,
295 						       stream->lut3d_func->state.bits.rmu_mux_num);
296 		if (acquired_rmu != stream->lut3d_func->state.bits.rmu_mux_num)
297 			BREAK_TO_DEBUGGER();
298 
299 		result = mpc->funcs->program_3dlut(mpc, &stream->lut3d_func->lut_3d,
300 						   stream->lut3d_func->state.bits.rmu_mux_num);
301 		if (!result)
302 			DC_LOG_ERROR("%s: program_3dlut failed\n", __func__);
303 
304 		result = mpc->funcs->program_shaper(mpc, shaper_lut,
305 						    stream->lut3d_func->state.bits.rmu_mux_num);
306 		if (!result)
307 			DC_LOG_ERROR("%s: program_shaper failed\n", __func__);
308 
309 	} else {
310 		// loop through the available mux and release the requested mpcc_id
311 		mpc->funcs->release_rmu(mpc, mpcc_id);
312 	}
313 
314 	return result;
315 }
316 
dcn30_set_input_transfer_func(struct dc * dc,struct pipe_ctx * pipe_ctx,const struct dc_plane_state * plane_state)317 bool dcn30_set_input_transfer_func(struct dc *dc,
318 				struct pipe_ctx *pipe_ctx,
319 				const struct dc_plane_state *plane_state)
320 {
321 	struct dce_hwseq *hws = dc->hwseq;
322 	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
323 	enum dc_transfer_func_predefined tf;
324 	bool result = true;
325 	const struct pwl_params *params = NULL;
326 
327 	if (dpp_base == NULL || plane_state == NULL)
328 		return false;
329 
330 	tf = TRANSFER_FUNCTION_UNITY;
331 
332 	if (plane_state->in_transfer_func.type == TF_TYPE_PREDEFINED)
333 		tf = plane_state->in_transfer_func.tf;
334 
335 	dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf);
336 
337 	if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL)
338 		params = &plane_state->in_transfer_func.pwl;
339 	else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS &&
340 		cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
341 							&plane_state->in_transfer_func,
342 							&dpp_base->degamma_params, false))
343 		params = &dpp_base->degamma_params;
344 
345 	result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
346 
347 	if (pipe_ctx->stream_res.opp && pipe_ctx->stream_res.opp->ctx) {
348 		if (dpp_base->funcs->dpp_program_blnd_lut)
349 			hws->funcs.set_blend_lut(pipe_ctx, plane_state);
350 		if (dpp_base->funcs->dpp_program_shaper_lut &&
351 				dpp_base->funcs->dpp_program_3dlut)
352 			hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state);
353 	}
354 
355 	return result;
356 }
357 
dcn30_program_gamut_remap(struct program_gamut_remap_params * params)358 void dcn30_program_gamut_remap(struct program_gamut_remap_params *params)
359 {
360 	struct dpp *dpp = params->dpp;
361 	struct mpc *mpc = params->mpc;
362 	int mpcc_id = params->mpcc_id;
363 	const struct dc_stream_state *stream = params->stream;
364 	const struct dc_plane_state *plane = params->plane;
365 	bool is_top_pipe = params->is_top_pipe;
366 	int i = 0;
367 	struct dpp_grph_csc_adjustment dpp_adjust;
368 	struct mpc_grph_gamut_adjustment mpc_adjust;
369 
370 	memset(&dpp_adjust, 0, sizeof(dpp_adjust));
371 	dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
372 
373 	if (plane &&
374 	    plane->gamut_remap_matrix.enable_remap == true) {
375 		dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
376 		for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
377 			dpp_adjust.temperature_matrix[i] =
378 				plane->gamut_remap_matrix.matrix[i];
379 	}
380 
381 	dpp->funcs->dpp_set_gamut_remap(dpp,
382 							    &dpp_adjust);
383 
384 	memset(&mpc_adjust, 0, sizeof(mpc_adjust));
385 	mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
386 
387 	if (is_top_pipe) {
388 		if (stream->gamut_remap_matrix.enable_remap == true) {
389 			mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
390 			for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
391 				mpc_adjust.temperature_matrix[i] =
392 					stream->gamut_remap_matrix.matrix[i];
393 		}
394 	}
395 
396 	mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
397 }
398 
dcn30_set_output_transfer_func(struct set_output_transfer_func_params * otf_params)399 bool dcn30_set_output_transfer_func(struct set_output_transfer_func_params *otf_params)
400 {
401 	struct dpp *dpp = otf_params->dpp;
402 	struct mpc *mpc = otf_params->mpc;
403 	int mpcc_id = otf_params->mpcc_id;
404 	bool is_top_pipe = otf_params->is_top_pipe;
405 	const struct dc_stream_state *stream = otf_params->stream;
406 	struct dc *dc = dpp->ctx->dc;
407 	const struct pwl_params *params = NULL;
408 	bool ret = false;
409 
410 	/* program OGAM or 3DLUT only for the top pipe*/
411 	if (is_top_pipe) {
412 		/*program rmu shaper and 3dlut in MPC*/
413 		ret = dcn30_set_mpc_shaper_3dlut(dpp, mpc, mpcc_id, stream);
414 		if (ret == false && mpc->funcs->set_output_gamma) {
415 			if (stream->out_transfer_func.type == TF_TYPE_HWPWL)
416 				params = &stream->out_transfer_func.pwl;
417 			else if (stream->out_transfer_func.type ==
418 					TF_TYPE_DISTRIBUTED_POINTS &&
419 					cm3_helper_translate_curve_to_hw_format(stream->ctx,
420 					&stream->out_transfer_func,
421 					&mpc->blender_params, false))
422 				params = &mpc->blender_params;
423 			 /* there are no ROM LUTs in OUTGAM */
424 			if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED)
425 				BREAK_TO_DEBUGGER();
426 		}
427 	}
428 
429 	if (mpc->funcs->set_output_gamma)
430 		mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
431 	else
432 		DC_LOG_ERROR("%s: set_output_gamma function pointer is NULL.\n", __func__);
433 
434 	return ret;
435 }
436 
dcn30_set_writeback(struct dc * dc,struct dc_writeback_info * wb_info,struct dc_state * context)437 static void dcn30_set_writeback(
438 		struct dc *dc,
439 		struct dc_writeback_info *wb_info,
440 		struct dc_state *context)
441 {
442 	struct mcif_wb *mcif_wb;
443 	struct mcif_buf_params *mcif_buf_params;
444 
445 	ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES);
446 	ASSERT(wb_info->wb_enabled);
447 	ASSERT(wb_info->mpcc_inst >= 0);
448 	ASSERT(wb_info->mpcc_inst < (int)dc->res_pool->mpcc_count);
449 	mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
450 	mcif_buf_params = &wb_info->mcif_buf_params;
451 
452 	/* set DWB MPC mux */
453 	dc->res_pool->mpc->funcs->set_dwb_mux(dc->res_pool->mpc,
454 			wb_info->dwb_pipe_inst, wb_info->mpcc_inst);
455 	/* set MCIF_WB buffer and arbitration configuration */
456 	mcif_wb->funcs->config_mcif_buf(mcif_wb, mcif_buf_params, wb_info->dwb_params.dest_height);
457 	mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);
458 }
459 
dcn30_update_writeback(struct dc * dc,struct dc_writeback_info * wb_info,struct dc_state * context)460 void dcn30_update_writeback(
461 		struct dc *dc,
462 		struct dc_writeback_info *wb_info,
463 		struct dc_state *context)
464 {
465 	struct dwbc *dwb;
466 	dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
467 	DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\
468 		__func__, wb_info->dwb_pipe_inst,\
469 		wb_info->mpcc_inst);
470 
471 	dcn30_set_writeback(dc, wb_info, context);
472 
473 	/* update DWB */
474 	dwb->funcs->update(dwb, &wb_info->dwb_params);
475 }
476 
dcn30_mmhubbub_warmup(struct dc * dc,unsigned int num_dwb,struct dc_writeback_info * wb_info)477 bool dcn30_mmhubbub_warmup(
478 	struct dc *dc,
479 	unsigned int num_dwb,
480 	struct dc_writeback_info *wb_info)
481 {
482 	struct dwbc *dwb;
483 	struct mcif_wb *mcif_wb;
484 	struct mcif_warmup_params warmup_params = {0};
485 	unsigned int  i, i_buf;
486 	/* make sure there is no active DWB enabled */
487 	for (i = 0; i < num_dwb; i++) {
488 		dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst];
489 		if (dwb->dwb_is_efc_transition || dwb->dwb_is_drc) {
490 			/*can not do warmup while any dwb enabled*/
491 			return false;
492 		}
493 	}
494 
495 	if (wb_info->mcif_warmup_params.p_vmid == 0)
496 		return false;
497 
498 	/*check whether this is new interface: warmup big buffer once*/
499 	if (wb_info->mcif_warmup_params.start_address.quad_part != 0 &&
500 		wb_info->mcif_warmup_params.region_size != 0) {
501 		/*mmhubbub is shared, so it does not matter which MCIF*/
502 		mcif_wb = dc->res_pool->mcif_wb[0];
503 		/*warmup a big chunk of VM buffer at once*/
504 		warmup_params.start_address.quad_part = wb_info->mcif_warmup_params.start_address.quad_part;
505 		warmup_params.address_increment =  wb_info->mcif_warmup_params.region_size;
506 		warmup_params.region_size = wb_info->mcif_warmup_params.region_size;
507 		warmup_params.p_vmid = wb_info->mcif_warmup_params.p_vmid;
508 
509 		if (warmup_params.address_increment == 0)
510 			warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes;
511 
512 		mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params);
513 		return true;
514 	}
515 	/*following is the original: warmup each DWB's mcif buffer*/
516 	for (i = 0; i < num_dwb; i++) {
517 		mcif_wb = dc->res_pool->mcif_wb[wb_info[i].dwb_pipe_inst];
518 		/*warmup is for VM mode only*/
519 		if (wb_info[i].mcif_buf_params.p_vmid == 0)
520 			return false;
521 
522 		/* Warmup MCIF_WB */
523 		for (i_buf = 0; i_buf < MCIF_BUF_COUNT; i_buf++) {
524 			warmup_params.start_address.quad_part = wb_info[i].mcif_buf_params.luma_address[i_buf];
525 			warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes;
526 			warmup_params.region_size = wb_info[i].mcif_buf_params.luma_pitch * wb_info[i].dwb_params.dest_height;
527 			warmup_params.p_vmid = wb_info[i].mcif_buf_params.p_vmid;
528 			mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params);
529 		}
530 	}
531 	return true;
532 }
533 
dcn30_enable_writeback(struct dc * dc,struct dc_writeback_info * wb_info,struct dc_state * context)534 void dcn30_enable_writeback(
535 		struct dc *dc,
536 		struct dc_writeback_info *wb_info,
537 		struct dc_state *context)
538 {
539 	struct dwbc *dwb;
540 	struct mcif_wb *mcif_wb;
541 
542 	dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
543 	mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
544 
545 	DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\
546 		__func__, wb_info->dwb_pipe_inst,\
547 		wb_info->mpcc_inst);
548 
549 	/* Warmup interface */
550 	dcn30_mmhubbub_warmup(dc, 1, wb_info);
551 
552 	/* Update writeback pipe */
553 	dcn30_set_writeback(dc, wb_info, context);
554 
555 	/* Enable MCIF_WB */
556 	mcif_wb->funcs->enable_mcif(mcif_wb);
557 	/* Enable DWB */
558 	dwb->funcs->enable(dwb, &wb_info->dwb_params);
559 }
560 
dcn30_disable_writeback(struct dc * dc,unsigned int dwb_pipe_inst)561 void dcn30_disable_writeback(
562 		struct dc *dc,
563 		unsigned int dwb_pipe_inst)
564 {
565 	struct dwbc *dwb;
566 	struct mcif_wb *mcif_wb;
567 
568 	ASSERT(dwb_pipe_inst < MAX_DWB_PIPES);
569 	dwb = dc->res_pool->dwbc[dwb_pipe_inst];
570 	mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst];
571 	DC_LOG_DWB("%s dwb_pipe_inst = %d",\
572 		__func__, dwb_pipe_inst);
573 
574 	/* disable DWB */
575 	dwb->funcs->disable(dwb);
576 	/* disable MCIF */
577 	mcif_wb->funcs->disable_mcif(mcif_wb);
578 	/* disable MPC DWB mux */
579 	dc->res_pool->mpc->funcs->disable_dwb_mux(dc->res_pool->mpc, dwb_pipe_inst);
580 }
581 
dcn30_program_all_writeback_pipes_in_tree(struct dc * dc,const struct dc_stream_state * stream,struct dc_state * context)582 void dcn30_program_all_writeback_pipes_in_tree(
583 		struct dc *dc,
584 		const struct dc_stream_state *stream,
585 		struct dc_state *context)
586 {
587 	struct dc_writeback_info wb_info;
588 	struct dwbc *dwb;
589 	struct dc_stream_status *stream_status = NULL;
590 	unsigned int i_wb, i_pipe, i_stream;
591 	DC_LOG_DWB("%s", __func__);
592 
593 	ASSERT(stream);
594 	for (i_stream = 0; i_stream < context->stream_count; i_stream++) {
595 		if (context->streams[i_stream] == stream) {
596 			stream_status = &context->stream_status[i_stream];
597 			break;
598 		}
599 	}
600 	ASSERT(stream_status);
601 
602 	// Assert non-negative signed capacity first.
603 	ASSERT(dc->res_pool->res_cap->num_dwb >= 0);
604 	ASSERT(stream->num_wb_info <= (unsigned int)dc->res_pool->res_cap->num_dwb);
605 	/* For each writeback pipe */
606 	for (i_wb = 0; i_wb < stream->num_wb_info; i_wb++) {
607 
608 		/* copy writeback info to local non-const so mpcc_inst can be set */
609 		wb_info = stream->writeback_info[i_wb];
610 		if (wb_info.wb_enabled) {
611 
612 			/* get the MPCC instance for writeback_source_plane */
613 			wb_info.mpcc_inst = -1;
614 			for (i_pipe = 0; i_pipe < dc->res_pool->pipe_count; i_pipe++) {
615 				struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i_pipe];
616 
617 				if (!pipe_ctx->plane_state)
618 					continue;
619 
620 				if (pipe_ctx->plane_state == wb_info.writeback_source_plane) {
621 					wb_info.mpcc_inst = pipe_ctx->plane_res.mpcc_inst;
622 					break;
623 				}
624 			}
625 
626 			if (wb_info.mpcc_inst == -1) {
627 				/* Disable writeback pipe and disconnect from MPCC
628 				 * if source plane has been removed
629 				 */
630 				dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst);
631 				continue;
632 			}
633 
634 			ASSERT(wb_info.dwb_pipe_inst < dc->res_pool->res_cap->num_dwb);
635 			dwb = dc->res_pool->dwbc[wb_info.dwb_pipe_inst];
636 			if (dwb->funcs->is_enabled(dwb)) {
637 				/* writeback pipe already enabled, only need to update */
638 				dc->hwss.update_writeback(dc, &wb_info, context);
639 			} else {
640 				/* Enable writeback pipe and connect to MPCC */
641 				dc->hwss.enable_writeback(dc, &wb_info, context);
642 			}
643 		} else {
644 			/* Disable writeback pipe and disconnect from MPCC */
645 			dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst);
646 		}
647 	}
648 }
649 
dcn30_init_hw(struct dc * dc)650 void dcn30_init_hw(struct dc *dc)
651 {
652 	struct abm **abms = dc->res_pool->multiple_abms;
653 	struct dce_hwseq *hws = dc->hwseq;
654 	struct dc_bios *dcb = dc->ctx->dc_bios;
655 	struct resource_pool *res_pool = dc->res_pool;
656 	unsigned int i;
657 	unsigned int edp_num;
658 	uint32_t backlight = MAX_BACKLIGHT_LEVEL;
659 	uint32_t user_level = MAX_BACKLIGHT_LEVEL;
660 
661 	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks)
662 		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
663 
664 	// Initialize the dccg
665 	if (res_pool->dccg->funcs->dccg_init)
666 		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
667 
668 	if (!dcb->funcs->is_accelerated_mode(dcb)) {
669 		hws->funcs.bios_golden_init(dc);
670 		hws->funcs.disable_vga(dc->hwseq);
671 	}
672 
673 	if (dc->debug.enable_mem_low_power.bits.dmcu) {
674 		// Force ERAM to shutdown if DMCU is not enabled
675 		if (dc->debug.disable_dmcu || dc->config.disable_dmcu) {
676 			REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3);
677 		}
678 	}
679 
680 	// Set default OPTC memory power states
681 	if (dc->debug.enable_mem_low_power.bits.optc) {
682 		// Shutdown when unassigned and light sleep in VBLANK
683 		REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
684 	}
685 
686 	if (dc->debug.enable_mem_low_power.bits.vga) {
687 		// Power down VGA memory
688 		REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
689 	}
690 
691 	if (dc->ctx->dc_bios->fw_info_valid) {
692 		res_pool->ref_clocks.xtalin_clock_inKhz =
693 				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
694 
695 		if (res_pool->hubbub) {
696 
697 			(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
698 					dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
699 					&res_pool->ref_clocks.dccg_ref_clock_inKhz);
700 
701 			(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
702 					res_pool->ref_clocks.dccg_ref_clock_inKhz,
703 					&res_pool->ref_clocks.dchub_ref_clock_inKhz);
704 		} else {
705 			// Not all ASICs have DCCG sw component
706 			res_pool->ref_clocks.dccg_ref_clock_inKhz =
707 					res_pool->ref_clocks.xtalin_clock_inKhz;
708 			res_pool->ref_clocks.dchub_ref_clock_inKhz =
709 					res_pool->ref_clocks.xtalin_clock_inKhz;
710 		}
711 	} else
712 		ASSERT_CRITICAL(false);
713 
714 	for (i = 0; i < dc->link_count; i++) {
715 		/* Power up AND update implementation according to the
716 		 * required signal (which may be different from the
717 		 * default signal on connector).
718 		 */
719 		struct dc_link *link = dc->links[i];
720 
721 		link->link_enc->funcs->hw_init(link->link_enc);
722 
723 		/* Check for enabled DIG to identify enabled display */
724 		if (link->link_enc->funcs->is_dig_enabled &&
725 			link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
726 			link->link_status.link_active = true;
727 			if (link->link_enc->funcs->fec_is_active &&
728 					link->link_enc->funcs->fec_is_active(link->link_enc))
729 				link->fec_state = dc_link_fec_enabled;
730 		}
731 	}
732 
733 	/* we want to turn off all dp displays before doing detection */
734 	dc->link_srv->blank_all_dp_displays(dc);
735 
736 	if (hws->funcs.enable_power_gating_plane)
737 		hws->funcs.enable_power_gating_plane(dc->hwseq, true);
738 
739 	/* If taking control over from VBIOS, we may want to optimize our first
740 	 * mode set, so we need to skip powering down pipes until we know which
741 	 * pipes we want to use.
742 	 * Otherwise, if taking control is not possible, we need to power
743 	 * everything down.
744 	 */
745 	if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
746 		hws->funcs.init_pipes(dc, dc->current_state);
747 		if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
748 			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
749 					!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
750 	}
751 
752 	/* In headless boot cases, DIG may be turned
753 	 * on which causes HW/SW discrepancies.
754 	 * To avoid this, power down hardware on boot
755 	 * if DIG is turned on and seamless boot not enabled
756 	 */
757 	if (!dc->config.seamless_boot_edp_requested) {
758 		struct dc_link *edp_links[MAX_NUM_EDP];
759 		struct dc_link *edp_link = NULL;
760 
761 		dc_get_edp_links(dc, edp_links, &edp_num);
762 		if (edp_num)
763 			edp_link = edp_links[0];
764 		if (edp_link && edp_link->link_enc->funcs->is_dig_enabled &&
765 				edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
766 				dc->hwss.edp_backlight_control &&
767 				hws->funcs.power_down &&
768 				dc->hwss.edp_power_control) {
769 			dc->hwss.edp_backlight_control(edp_link, false);
770 			hws->funcs.power_down(dc);
771 			dc->hwss.edp_power_control(edp_link, false);
772 		} else {
773 			for (i = 0; i < dc->link_count; i++) {
774 				struct dc_link *link = dc->links[i];
775 
776 				if (link->link_enc->funcs->is_dig_enabled &&
777 						link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
778 						hws->funcs.power_down) {
779 					hws->funcs.power_down(dc);
780 					break;
781 				}
782 
783 			}
784 		}
785 	}
786 
787 	for (i = 0; i < res_pool->audio_count; i++) {
788 		struct audio *audio = res_pool->audios[i];
789 
790 		audio->funcs->hw_init(audio);
791 	}
792 
793 	for (i = 0; i < dc->link_count; i++) {
794 		struct dc_link *link = dc->links[i];
795 
796 		if (link->panel_cntl) {
797 			backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
798 			user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;
799 		}
800 	}
801 
802 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
803 		if (abms[i] != NULL)
804 			abms[i]->funcs->abm_init(abms[i], backlight, user_level);
805 	}
806 
807 	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
808 	if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
809 		dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false);
810 
811 	if (!dc->debug.disable_clock_gate) {
812 		/* enable all DCN clock gating */
813 		if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating)
814 			dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true);
815 
816 		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
817 	}
818 
819 	if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
820 		dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
821 
822 	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
823 		dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
824 
825 	//if softmax is enabled then hardmax will be set by a different call
826 	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->set_hard_max_memclk &&
827 	    !dc->clk_mgr->dc_mode_softmax_enabled)
828 		dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
829 
830 	if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
831 		dc->res_pool->hubbub->funcs->force_pstate_change_control(
832 				dc->res_pool->hubbub, false, false);
833 	if (dc->res_pool->hubbub->funcs->init_crb)
834 		dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
835 
836 	// Get DMCUB capabilities
837 	dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);
838 	dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
839 	dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
840 }
841 
dcn30_set_avmute(struct pipe_ctx * pipe_ctx,bool enable)842 void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
843 {
844 	if (pipe_ctx == NULL)
845 		return;
846 
847 	if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.hpo_frl_stream_enc != NULL)
848 		pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->set_avmute(
849 				pipe_ctx->stream_res.hpo_frl_stream_enc,
850 				enable);
851 	if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL) {
852 		pipe_ctx->stream_res.stream_enc->funcs->set_avmute(
853 				pipe_ctx->stream_res.stream_enc,
854 				enable);
855 
856 		/* Wait for three frames to make sure AV mute is sent out.
857 		 * Some HDMI sinks need additional GCP packets to properly
858 		 * process the mute state, especially after link re-establishment
859 		 * with HDMI 2.0 scrambling enabled.
860 		 */
861 		if (enable && pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) {
862 			int i;
863 
864 			pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
865 			for (i = 0; i < 3; i++) {
866 				pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
867 				pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
868 			}
869 		}
870 	}
871 }
872 
dcn30_update_info_frame(struct pipe_ctx * pipe_ctx)873 void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx)
874 {
875 	bool is_hdmi_tmds;
876 	bool is_dp;
877 	bool is_hdmi_frl;
878 
879 	ASSERT(pipe_ctx->stream);
880 
881 	if (pipe_ctx->stream_res.stream_enc == NULL &&
882 			pipe_ctx->stream_res.hpo_frl_stream_enc == NULL)
883 		return;  /* this is not root pipe */
884 
885 	is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal);
886 	is_dp = dc_is_dp_signal(pipe_ctx->stream->signal);
887 
888 	is_hdmi_frl = dc_is_hdmi_frl_signal(pipe_ctx->stream->signal);
889 	if (!is_hdmi_tmds && !is_dp && !is_hdmi_frl)
890 		return;
891 
892 	if (is_hdmi_tmds)
893 		pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
894 			pipe_ctx->stream_res.stream_enc,
895 			&pipe_ctx->stream_res.encoder_info_frame);
896 	else if (is_hdmi_frl)
897 		pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->update_hdmi_info_packets(
898 			pipe_ctx->stream_res.hpo_frl_stream_enc,
899 			&pipe_ctx->stream_res.encoder_info_frame);
900 	else {
901 		if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num)
902 			pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num(
903 				pipe_ctx->stream_res.stream_enc,
904 				&pipe_ctx->stream_res.encoder_info_frame);
905 
906 		pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
907 			pipe_ctx->stream_res.stream_enc,
908 			&pipe_ctx->stream_res.encoder_info_frame);
909 	}
910 }
911 
dcn30_program_dmdata_engine(struct pipe_ctx * pipe_ctx)912 void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
913 {
914 	struct dc_stream_state    *stream     = pipe_ctx->stream;
915 	struct hubp               *hubp       = pipe_ctx->plane_res.hubp;
916 	bool                       enable     = false;
917 	struct stream_encoder     *stream_enc = pipe_ctx->stream_res.stream_enc;
918 	struct hpo_frl_stream_encoder *hpo_enc    = pipe_ctx->stream_res.hpo_frl_stream_enc;
919 	enum dynamic_metadata_mode mode       = dc_is_dp_signal(stream->signal)
920 							? dmdata_dp
921 							: dmdata_hdmi;
922 
923 	/* if using dynamic meta, don't set up generic infopackets */
924 	if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
925 		pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
926 		enable = true;
927 	}
928 
929 	if (!hubp)
930 		return;
931 
932 	if (dc_is_hdmi_frl_signal(stream->signal)) {
933 		ASSERT(mode == dmdata_hdmi);
934 
935 		if (!hpo_enc || !hpo_enc->funcs->set_dynamic_metadata)
936 			return;
937 
938 		hpo_enc->funcs->set_dynamic_metadata(hpo_enc, enable,
939 						     hubp->inst, dmdata_hdmi);
940 	} else {
941 	if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata)
942 		return;
943 
944 	stream_enc->funcs->set_dynamic_metadata(stream_enc, enable,
945 							hubp->inst, mode);
946 	}
947 }
dcn30_setup_hdmi_frl_link(struct dc_link * link,int hpo_inst,enum clock_source_id frl_phy_clock_source_id)948 enum dc_status dcn30_setup_hdmi_frl_link(
949 		struct dc_link *link,
950 		int hpo_inst,
951 		enum clock_source_id frl_phy_clock_source_id)
952 {
953 	(void)hpo_inst;
954 	enum dc_status status = DC_OK;
955 	struct dc *dc = link->ctx->dc;
956 
957 	if ((!link->link_enc) ||
958 			(!link->hpo_frl_link_enc) ||
959 			(!dc->res_pool->dccg->funcs->enable_hdmicharclk))
960 		return DC_ERROR_UNEXPECTED;
961 
962 	//Enable phy output for FRL case
963 	link->hpo_frl_link_enc->funcs->enable_frl_phy_output(
964 		link->hpo_frl_link_enc,
965 		link->link_enc,
966 		frl_phy_clock_source_id,
967 		link->frl_link_settings.frl_link_rate);
968 	link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
969 	return status;
970 }
971 
dcn30_apply_idle_power_optimizations(struct dc * dc,bool enable)972 bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
973 {
974 	union dmub_rb_cmd cmd;
975 	uint32_t tmr_delay = 0, tmr_scale = 0;
976 	struct dc_cursor_attributes cursor_attr = {0};
977 	bool cursor_cache_enable = false;
978 	struct dc_stream_state *stream = NULL;
979 	struct dc_plane_state *plane = NULL;
980 
981 	if (!dc->ctx->dmub_srv)
982 		return false;
983 
984 	if (enable) {
985 		if (dc->current_state) {
986 			int i;
987 
988 			/* First, check no-memory-requests case */
989 			for (i = 0; i < dc->current_state->stream_count; i++) {
990 				if (dc->current_state->stream_status[i].plane_count)
991 					/* Fail eligibility on a visible stream */
992 					break;
993 			}
994 
995 			if (i == dc->current_state->stream_count) {
996 				/* Enable no-memory-requests case */
997 				memset(&cmd, 0, sizeof(cmd));
998 				cmd.mall.header.type = DMUB_CMD__MALL;
999 				cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_NO_DF_REQ;
1000 				cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header);
1001 
1002 				dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT);
1003 
1004 				return true;
1005 			}
1006 
1007 			stream = dc->current_state->streams[0];
1008 			plane = (stream ? dc->current_state->stream_status[0].plane_states[0] : NULL);
1009 
1010 			if (!stream || !plane)
1011 				return false;
1012 
1013 			if (stream && plane) {
1014 				cursor_cache_enable = stream->cursor_position.enable &&
1015 						plane->address.grph.cursor_cache_addr.quad_part;
1016 				cursor_attr = stream->cursor_attributes;
1017 			}
1018 
1019 			/*
1020 			 * Second, check MALL eligibility
1021 			 *
1022 			 * single display only, single surface only, 8 and 16 bit formats only, no VM,
1023 			 * do not use MALL for displays that support PSR as they use D0i3.2 in DMCUB FW
1024 			 *
1025 			 * TODO: When we implement multi-display, PSR displays will be allowed if there is
1026 			 * a non-PSR display present, since in that case we can't do D0i3.2
1027 			 */
1028 			if (dc->current_state->stream_count == 1 &&
1029 					stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED &&
1030 					dc->current_state->stream_status[0].plane_count == 1 &&
1031 					plane->format <= SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F &&
1032 					plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB8888 &&
1033 					plane->address.page_table_base.quad_part == 0 &&
1034 					dc->hwss.does_plane_fit_in_mall &&
1035 					dc->hwss.does_plane_fit_in_mall(dc, plane->plane_size.surface_pitch,
1036 							plane->plane_size.surface_size.height, plane->format,
1037 							cursor_cache_enable ? &cursor_attr : NULL)) {
1038 				unsigned int v_total = stream->adjust.v_total_max ?
1039 						stream->adjust.v_total_max : stream->timing.v_total;
1040 				unsigned int refresh_hz = (unsigned int)div_u64((unsigned long long)stream->timing.pix_clk_100hz *
1041 						100LL, (v_total * stream->timing.h_total));
1042 
1043 				/*
1044 				 * one frame time in microsec:
1045 				 * Delay_Us = 1000000 / refresh
1046 				 * dynamic_delay_us = 1000000 / refresh + 2 * stutter_period
1047 				 *
1048 				 * one frame time modified by 'additional timer percent' (p):
1049 				 * Delay_Us_modified = dynamic_delay_us + dynamic_delay_us * p / 100
1050 				 *                   = dynamic_delay_us * (1 + p / 100)
1051 				 *                   = (1000000 / refresh + 2 * stutter_period) * (100 + p) / 100
1052 				 *                   = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh)
1053 				 *
1054 				 * formula for timer duration based on parameters, from regspec:
1055 				 * dynamic_delay_us = 65.28 * (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale
1056 				 *
1057 				 * dynamic_delay_us / 65.28 = (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale
1058 				 * (dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale = 64 + MallFrameCacheTmrDly
1059 				 * MallFrameCacheTmrDly = ((dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale) - 64
1060 				 *                      = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh) / 65.28 / 2^MallFrameCacheTmrScale - 64
1061 				 *                      = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (refresh * 6528 * 2^MallFrameCacheTmrScale) - 64
1062 				 *
1063 				 * need to round up the result of the division before the subtraction
1064 				 */
1065 				unsigned int denom = refresh_hz * 6528;
1066 				unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us;
1067 				uint64_t num = (1000000LL + 2 * stutter_period * refresh_hz) *
1068 					(100LL + dc->debug.mall_additional_timer_percent);
1069 				uint64_t tmr_ticks;
1070 
1071 				tmr_ticks = div_u64(num + denom - 1, denom);
1072 				tmr_delay = tmr_ticks > 64 ? (uint32_t)(tmr_ticks - 64) : 0;
1073 
1074 				/* In some cases the stutter period is really big (tiny modes) in these
1075 				 * cases MALL cant be enabled, So skip these cases to avoid a ASSERT()
1076 				 *
1077 				 * We can check if stutter_period is more than 1/10th the frame time to
1078 				 * consider if we can actually meet the range of hysteresis timer
1079 				 */
1080 				if (stutter_period > 100000/refresh_hz)
1081 					return false;
1082 
1083 				/* scale should be increased until it fits into 6 bits */
1084 				while (tmr_delay & ~0x3F) {
1085 					tmr_scale++;
1086 
1087 					if (tmr_scale > 3) {
1088 						/* Delay exceeds range of hysteresis timer */
1089 						ASSERT(false);
1090 						return false;
1091 					}
1092 
1093 					denom *= 2;
1094 					tmr_ticks = div_u64(num + denom - 1, denom);
1095 					tmr_delay = tmr_ticks > 64 ? (uint32_t)(tmr_ticks - 64) : 0;
1096 				}
1097 
1098 				/* Copy HW cursor */
1099 				if (cursor_cache_enable) {
1100 					memset(&cmd, 0, sizeof(cmd));
1101 					cmd.mall.header.type = DMUB_CMD__MALL;
1102 					cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_COPY_CURSOR;
1103 					cmd.mall.header.payload_bytes =
1104 							sizeof(cmd.mall) - sizeof(cmd.mall.header);
1105 
1106 					switch (cursor_attr.color_format) {
1107 					case CURSOR_MODE_MONO:
1108 						cmd.mall.cursor_bpp = 2;
1109 						break;
1110 					case CURSOR_MODE_COLOR_1BIT_AND:
1111 					case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
1112 					case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
1113 						cmd.mall.cursor_bpp = 32;
1114 						break;
1115 
1116 					case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
1117 					case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
1118 						cmd.mall.cursor_bpp = 64;
1119 						break;
1120 					}
1121 
1122 					cmd.mall.cursor_copy_src.quad_part = cursor_attr.address.quad_part;
1123 					cmd.mall.cursor_copy_dst.quad_part =
1124 							(plane->address.grph.cursor_cache_addr.quad_part + 2047) & ~2047;
1125 					cmd.mall.cursor_width = (uint16_t)cursor_attr.width;
1126 					cmd.mall.cursor_height = (uint16_t)cursor_attr.height;
1127 					cmd.mall.cursor_pitch = (uint16_t)cursor_attr.pitch;
1128 
1129 					dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
1130 
1131 					/* Use copied cursor, and it's okay to not switch back */
1132 					cursor_attr.address.quad_part = cmd.mall.cursor_copy_dst.quad_part;
1133 					dc_stream_program_cursor_attributes(stream, &cursor_attr);
1134 				}
1135 
1136 				/* Enable MALL */
1137 				memset(&cmd, 0, sizeof(cmd));
1138 				cmd.mall.header.type = DMUB_CMD__MALL;
1139 				cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_ALLOW;
1140 				cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header);
1141 				cmd.mall.tmr_delay = tmr_delay;
1142 				cmd.mall.tmr_scale = tmr_scale;
1143 				cmd.mall.debug_bits = dc->debug.mall_error_as_fatal;
1144 
1145 				dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT);
1146 
1147 				return true;
1148 			}
1149 		}
1150 
1151 		/* No applicable optimizations */
1152 		return false;
1153 	}
1154 
1155 	/* Disable MALL */
1156 	memset(&cmd, 0, sizeof(cmd));
1157 	cmd.mall.header.type = DMUB_CMD__MALL;
1158 	cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_DISALLOW;
1159 	cmd.mall.header.payload_bytes =
1160 		sizeof(cmd.mall) - sizeof(cmd.mall.header);
1161 
1162 	dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
1163 
1164 	return true;
1165 }
1166 
dcn30_does_plane_fit_in_mall(struct dc * dc,unsigned int pitch,unsigned int height,enum surface_pixel_format format,struct dc_cursor_attributes * cursor_attr)1167 bool dcn30_does_plane_fit_in_mall(struct dc *dc,
1168 		unsigned int pitch,
1169 		unsigned int height,
1170 		enum surface_pixel_format format,
1171 		struct dc_cursor_attributes *cursor_attr)
1172 {
1173 	// add meta size?
1174 	unsigned int surface_size = pitch * height *
1175 			(format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4);
1176 	unsigned int mall_size = dc->caps.mall_size_total;
1177 	unsigned int cursor_size = 0;
1178 
1179 	if (dc->debug.mall_size_override)
1180 		mall_size = 1024 * 1024 * dc->debug.mall_size_override;
1181 
1182 	if (cursor_attr) {
1183 		cursor_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size;
1184 
1185 		switch (cursor_attr->color_format) {
1186 		case CURSOR_MODE_MONO:
1187 			cursor_size /= 2;
1188 			break;
1189 		case CURSOR_MODE_COLOR_1BIT_AND:
1190 		case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
1191 		case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
1192 			cursor_size *= 4;
1193 			break;
1194 
1195 		case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
1196 		case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
1197 			cursor_size *= 8;
1198 			break;
1199 		}
1200 	}
1201 
1202 	return (surface_size + cursor_size) < mall_size;
1203 }
1204 
dcn30_hardware_release(struct dc * dc)1205 void dcn30_hardware_release(struct dc *dc)
1206 {
1207 	bool subvp_in_use = false;
1208 	uint32_t i;
1209 
1210 	dc_dmub_srv_p_state_delegate(dc, false, NULL);
1211 	dc_dmub_setup_subvp_dmub_command(dc, dc->current_state, false);
1212 
1213 	/* SubVP treated the same way as FPO. If driver disable and
1214 	 * we are using a SubVP config, disable and force on DCN side
1215 	 * to prevent P-State hang on driver enable.
1216 	 */
1217 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
1218 		struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
1219 
1220 		if (!pipe->stream)
1221 			continue;
1222 
1223 		if (dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_MAIN) {
1224 			subvp_in_use = true;
1225 			break;
1226 		}
1227 	}
1228 	/* If pstate unsupported, or still supported
1229 	 * by firmware, force it supported by dcn
1230 	 */
1231 	if (dc->current_state)
1232 		if ((!dc->clk_mgr->clks.p_state_change_support || subvp_in_use ||
1233 				dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) &&
1234 				dc->res_pool->hubbub->funcs->force_pstate_change_control)
1235 			dc->res_pool->hubbub->funcs->force_pstate_change_control(
1236 					dc->res_pool->hubbub, true, true);
1237 }
1238 
dcn30_set_disp_pattern_generator(const struct dc * dc,struct pipe_ctx * pipe_ctx,enum controller_dp_test_pattern test_pattern,enum controller_dp_color_space color_space,enum dc_color_depth color_depth,const struct tg_color * solid_color,int width,int height,int offset)1239 void dcn30_set_disp_pattern_generator(const struct dc *dc,
1240 		struct pipe_ctx *pipe_ctx,
1241 		enum controller_dp_test_pattern test_pattern,
1242 		enum controller_dp_color_space color_space,
1243 		enum dc_color_depth color_depth,
1244 		const struct tg_color *solid_color,
1245 		int width, int height, int offset)
1246 {
1247 	(void)dc;
1248 	pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern,
1249 			color_space, color_depth, solid_color, width, height, offset);
1250 }
1251 
dcn30_prepare_bandwidth(struct dc * dc,struct dc_state * context)1252 void dcn30_prepare_bandwidth(struct dc *dc,
1253 	struct dc_state *context)
1254 {
1255 	if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching && !dc->clk_mgr->clks.fw_based_mclk_switching) {
1256 		dc->optimized_required = true;
1257 		context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
1258 	}
1259 
1260 	if (dc->clk_mgr->dc_mode_softmax_enabled) {
1261 		int softmax_memclk_khz = dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000;
1262 
1263 		if (dc->clk_mgr->clks.dramclk_khz <= softmax_memclk_khz &&
1264 				context->bw_ctx.bw.dcn.clk.dramclk_khz > softmax_memclk_khz)
1265 			dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz);
1266 	}
1267 
1268 	dcn20_prepare_bandwidth(dc, context);
1269 
1270 	if (!dc->clk_mgr->clks.fw_based_mclk_switching)
1271 		dc_dmub_srv_p_state_delegate(dc, false, context);
1272 }
1273 
dcn30_wait_for_all_pending_updates(const struct pipe_ctx * pipe_ctx)1274 void dcn30_wait_for_all_pending_updates(const struct pipe_ctx *pipe_ctx)
1275 {
1276 	struct timing_generator *tg = pipe_ctx->stream_res.tg;
1277 	bool pending_updates = false;
1278 	unsigned int i;
1279 
1280 	if (tg && tg->funcs->is_tg_enabled(tg)) {
1281 		// Poll for 100ms maximum
1282 		for (i = 0; i < 100000; i++) {
1283 			pending_updates = false;
1284 			if (tg->funcs->get_optc_double_buffer_pending)
1285 				pending_updates |= tg->funcs->get_optc_double_buffer_pending(tg);
1286 
1287 			if (tg->funcs->get_otg_double_buffer_pending)
1288 				pending_updates |= tg->funcs->get_otg_double_buffer_pending(tg);
1289 
1290 			if (tg->funcs->get_pipe_update_pending && pipe_ctx->plane_state)
1291 				pending_updates |= tg->funcs->get_pipe_update_pending(tg);
1292 
1293 			if (!pending_updates)
1294 				break;
1295 
1296 			udelay(1);
1297 		}
1298 	}
1299 }
1300 
dcn30_get_underflow_debug_data(const struct dc * dc,struct timing_generator * tg,struct dc_underflow_debug_data * out_data)1301 void dcn30_get_underflow_debug_data(const struct dc *dc,
1302 	struct timing_generator *tg,
1303 	struct dc_underflow_debug_data *out_data)
1304 {
1305 	(void)tg;
1306 	struct hubbub *hubbub = dc->res_pool->hubbub;
1307 
1308 	if (hubbub) {
1309 		if (hubbub->funcs->hubbub_read_reg_state) {
1310 			hubbub->funcs->hubbub_read_reg_state(hubbub, out_data->hubbub_reg_state);
1311 		}
1312 	}
1313 
1314 	for (int i = 0; i < MAX_PIPES; i++) {
1315 		struct hubp *hubp = dc->res_pool->hubps[i];
1316 		struct dpp *dpp = dc->res_pool->dpps[i];
1317 		struct output_pixel_processor *opp = dc->res_pool->opps[i];
1318 		struct display_stream_compressor *dsc = dc->res_pool->dscs[i];
1319 		struct mpc *mpc = dc->res_pool->mpc;
1320 		struct timing_generator *optc = dc->res_pool->timing_generators[i];
1321 		struct dccg *dccg = dc->res_pool->dccg;
1322 
1323 		if (hubp)
1324 			if (hubp->funcs->hubp_read_reg_state)
1325 				hubp->funcs->hubp_read_reg_state(hubp, out_data->hubp_reg_state[i]);
1326 
1327 		if (dpp)
1328 			if (dpp->funcs->dpp_read_reg_state)
1329 				dpp->funcs->dpp_read_reg_state(dpp, out_data->dpp_reg_state[i]);
1330 
1331 		if (opp)
1332 			if (opp->funcs->opp_read_reg_state)
1333 				opp->funcs->opp_read_reg_state(opp, out_data->opp_reg_state[i]);
1334 
1335 		if (dsc)
1336 			if (dsc->funcs->dsc_read_reg_state)
1337 				dsc->funcs->dsc_read_reg_state(dsc, out_data->dsc_reg_state[i]);
1338 
1339 		if (mpc)
1340 			if (mpc->funcs->mpc_read_reg_state)
1341 				mpc->funcs->mpc_read_reg_state(mpc, i, out_data->mpc_reg_state[i]);
1342 
1343 		if (optc)
1344 			if (optc->funcs->optc_read_reg_state)
1345 				optc->funcs->optc_read_reg_state(optc, out_data->optc_reg_state[i]);
1346 
1347 		if (dccg)
1348 			if (dccg->funcs->dccg_read_reg_state)
1349 				dccg->funcs->dccg_read_reg_state(dccg, out_data->dccg_reg_state[i]);
1350 	}
1351 }
1352