xref: /linux/drivers/gpu/drm/amd/display/dc/core/dc_resource.c (revision 87a7a99153f5c3636a40a5aef46dde82cd3a9ff4)
1 /*
2  * Copyright 2012-15 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 #include "dm_services.h"
27 
28 #include "resource.h"
29 #include "include/irq_service_interface.h"
30 #include "link_encoder.h"
31 #include "stream_encoder.h"
32 #include "opp.h"
33 #include "timing_generator.h"
34 #include "transform.h"
35 #include "dccg.h"
36 #include "dchubbub.h"
37 #include "dpp.h"
38 #include "core_types.h"
39 #include "set_mode_types.h"
40 #include "dio/virtual/virtual_stream_encoder.h"
41 #include "dpcd_defs.h"
42 #include "link_enc_cfg.h"
43 #include "link_service.h"
44 #include "clk_mgr.h"
45 #include "dc_state_priv.h"
46 #include "dc_stream_priv.h"
47 
48 #include "link/hwss/link_hwss_virtual.h"
49 #include "link/hwss/link_hwss_dio.h"
50 #include "link/hwss/link_hwss_dpia.h"
51 #include "link/hwss/link_hwss_hpo_dp.h"
52 #include "link/hwss/link_hwss_dio_fixed_vs_pe_retimer.h"
53 #include "link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.h"
54 
55 #if defined(CONFIG_DRM_AMD_DC_SI)
56 #include "dce60/dce60_resource.h"
57 #endif
58 #if defined(CONFIG_DRM_AMD_DC_DCE)
59 #include "dce80/dce80_resource.h"
60 #include "dce100/dce100_resource.h"
61 #include "dce110/dce110_resource.h"
62 #include "dce112/dce112_resource.h"
63 #include "dce120/dce120_resource.h"
64 #endif
65 #include "dcn10/dcn10_resource.h"
66 #include "dcn20/dcn20_resource.h"
67 #include "dcn21/dcn21_resource.h"
68 #include "dcn201/dcn201_resource.h"
69 #include "dcn30/dcn30_resource.h"
70 #include "dcn301/dcn301_resource.h"
71 #include "dcn302/dcn302_resource.h"
72 #include "dcn303/dcn303_resource.h"
73 #include "dcn31/dcn31_resource.h"
74 #include "dcn314/dcn314_resource.h"
75 #include "dcn315/dcn315_resource.h"
76 #include "dcn316/dcn316_resource.h"
77 #include "dcn32/dcn32_resource.h"
78 #include "dcn321/dcn321_resource.h"
79 #include "dcn35/dcn35_resource.h"
80 #include "dcn351/dcn351_resource.h"
81 #include "dcn36/dcn36_resource.h"
82 #include "dcn401/dcn401_resource.h"
83 #include "dcn42/dcn42_resource.h"
84 #include "dcn42b/dcn42b_resource.h"
85 #include "dcn60/dcn60_resource.h"
86 #if defined(CONFIG_DRM_AMD_DC_FP)
87 #include "dc_spl_translate.h"
88 #endif
89 
90 #define VISUAL_CONFIRM_BASE_DEFAULT 3
91 #define VISUAL_CONFIRM_BASE_MIN 1
92 #define VISUAL_CONFIRM_BASE_MAX 10
93 /* we choose 240 because it is a common denominator of common v addressable
94  * such as 2160, 1440, 1200, 960. So we take 1/240 portion of v addressable as
95  * the visual confirm dpp offset height. So visual confirm height can stay
96  * relatively the same independent from timing used.
97  */
98 #define VISUAL_CONFIRM_DPP_OFFSET_DENO 240
99 
100 #define DC_LOGGER \
101 	dc->ctx->logger
102 #define DC_LOGGER_INIT(logger)
103 #include "link/hwss/link_hwss_hpo_frl.h"
104 #include "dml/dml1_frl_cap_chk.h"
105 #include "dml2_wrapper/dml2_wrapper.h"
106 
107 #define UNABLE_TO_SPLIT -1
108 
109 static void capture_pipe_topology_data(struct dc *dc, int plane_idx, int slice_idx, int stream_idx,
110 									   int dpp_inst, int opp_inst, int tg_inst, bool is_phantom_pipe)
111 {
112 	struct pipe_topology_snapshot *current_snapshot = &dc->debug_data.topology_history.snapshots[dc->debug_data.topology_history.current_snapshot_index];
113 
114 	if (current_snapshot->line_count >= MAX_PIPES)
115 		return;
116 
117 	current_snapshot->pipe_log_lines[current_snapshot->line_count].is_phantom_pipe = is_phantom_pipe;
118 	current_snapshot->pipe_log_lines[current_snapshot->line_count].plane_idx = plane_idx;
119 	current_snapshot->pipe_log_lines[current_snapshot->line_count].slice_idx = slice_idx;
120 	current_snapshot->pipe_log_lines[current_snapshot->line_count].stream_idx = stream_idx;
121 	current_snapshot->pipe_log_lines[current_snapshot->line_count].dpp_inst = dpp_inst;
122 	current_snapshot->pipe_log_lines[current_snapshot->line_count].opp_inst = opp_inst;
123 	current_snapshot->pipe_log_lines[current_snapshot->line_count].tg_inst = tg_inst;
124 
125 	current_snapshot->line_count++;
126 }
127 
128 static void start_new_topology_snapshot(struct dc *dc, struct dc_state *state)
129 {
130 	// Move to next snapshot slot (circular buffer)
131 	dc->debug_data.topology_history.current_snapshot_index = (dc->debug_data.topology_history.current_snapshot_index + 1) % MAX_TOPOLOGY_SNAPSHOTS;
132 
133 	// Clear the new snapshot
134 	struct pipe_topology_snapshot *current_snapshot = &dc->debug_data.topology_history.snapshots[dc->debug_data.topology_history.current_snapshot_index];
135 	memset(current_snapshot, 0, sizeof(*current_snapshot));
136 
137 	// Set metadata
138 	current_snapshot->timestamp_us = dm_get_timestamp(dc->ctx);
139 	current_snapshot->stream_count = state->stream_count;
140 	current_snapshot->phantom_stream_count = state->phantom_stream_count;
141 }
142 
143 enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
144 {
145 	enum dce_version dc_version = DCE_VERSION_UNKNOWN;
146 
147 	switch (asic_id.chip_family) {
148 
149 #if defined(CONFIG_DRM_AMD_DC_SI)
150 	case FAMILY_SI:
151 		if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev) ||
152 		    ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev) ||
153 		    ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev))
154 			dc_version = DCE_VERSION_6_0;
155 		else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev))
156 			dc_version = DCE_VERSION_6_4;
157 		else
158 			dc_version = DCE_VERSION_6_1;
159 		break;
160 #endif
161 	case FAMILY_CI:
162 		dc_version = DCE_VERSION_8_0;
163 		break;
164 	case FAMILY_KV:
165 		if (ASIC_REV_IS_KALINDI(asic_id.hw_internal_rev) ||
166 		    ASIC_REV_IS_BHAVANI(asic_id.hw_internal_rev) ||
167 		    ASIC_REV_IS_GODAVARI(asic_id.hw_internal_rev))
168 			dc_version = DCE_VERSION_8_3;
169 		else
170 			dc_version = DCE_VERSION_8_1;
171 		break;
172 	case FAMILY_CZ:
173 		dc_version = DCE_VERSION_11_0;
174 		break;
175 
176 	case FAMILY_VI:
177 		if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev) ||
178 				ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)) {
179 			dc_version = DCE_VERSION_10_0;
180 			break;
181 		}
182 		if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) ||
183 				ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev) ||
184 				ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)) {
185 			dc_version = DCE_VERSION_11_2;
186 		}
187 		if (ASIC_REV_IS_VEGAM(asic_id.hw_internal_rev))
188 			dc_version = DCE_VERSION_11_22;
189 		break;
190 	case FAMILY_AI:
191 		if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev))
192 			dc_version = DCE_VERSION_12_1;
193 		else
194 			dc_version = DCE_VERSION_12_0;
195 		break;
196 	case FAMILY_RV:
197 		dc_version = DCN_VERSION_1_0;
198 		if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev))
199 			dc_version = DCN_VERSION_1_01;
200 		if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev))
201 			dc_version = DCN_VERSION_2_1;
202 		if (ASICREV_IS_GREEN_SARDINE(asic_id.hw_internal_rev))
203 			dc_version = DCN_VERSION_2_1;
204 		break;
205 
206 	case FAMILY_NV:
207 		dc_version = DCN_VERSION_2_0;
208 		if (asic_id.chip_id == DEVICE_ID_NV_13FE ||
209 		    asic_id.chip_id == DEVICE_ID_NV_143F ||
210 		    asic_id.chip_id == DEVICE_ID_NV_13F9 ||
211 		    asic_id.chip_id == DEVICE_ID_NV_13FA ||
212 		    asic_id.chip_id == DEVICE_ID_NV_13FB ||
213 		    asic_id.chip_id == DEVICE_ID_NV_13FC ||
214 		    asic_id.chip_id == DEVICE_ID_NV_13DB) {
215 			dc_version = DCN_VERSION_2_01;
216 			break;
217 		}
218 		if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev))
219 			dc_version = DCN_VERSION_3_0;
220 		if (ASICREV_IS_DIMGREY_CAVEFISH_P(asic_id.hw_internal_rev))
221 			dc_version = DCN_VERSION_3_02;
222 		if (ASICREV_IS_BEIGE_GOBY_P(asic_id.hw_internal_rev))
223 			dc_version = DCN_VERSION_3_03;
224 		break;
225 
226 	case FAMILY_VGH:
227 		dc_version = DCN_VERSION_3_01;
228 		break;
229 
230 	case FAMILY_YELLOW_CARP:
231 		if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev))
232 			dc_version = DCN_VERSION_3_1;
233 		break;
234 	case AMDGPU_FAMILY_GC_10_3_6:
235 		if (ASICREV_IS_GC_10_3_6(asic_id.hw_internal_rev))
236 			dc_version = DCN_VERSION_3_15;
237 		break;
238 	case AMDGPU_FAMILY_GC_10_3_7:
239 		if (ASICREV_IS_GC_10_3_7(asic_id.hw_internal_rev))
240 			dc_version = DCN_VERSION_3_16;
241 		break;
242 	case AMDGPU_FAMILY_GC_11_0_0:
243 		dc_version = DCN_VERSION_3_2;
244 		if (ASICREV_IS_GC_11_0_2(asic_id.hw_internal_rev))
245 			dc_version = DCN_VERSION_3_21;
246 		break;
247 	case AMDGPU_FAMILY_GC_11_0_1:
248 		dc_version = DCN_VERSION_3_14;
249 		break;
250 	case AMDGPU_FAMILY_GC_11_5_0:
251 		dc_version = DCN_VERSION_3_5;
252 		if (ASICREV_IS_DCN4A_SOC_VAR_B(asic_id.hw_internal_rev))
253 			dc_version = DCN_VERSION_4_2B;
254 		if (ASICREV_IS_GC_11_0_4(asic_id.hw_internal_rev))
255 			dc_version = DCN_VERSION_3_51;
256 		if (ASICREV_IS_DCN36(asic_id.hw_internal_rev))
257 			dc_version = DCN_VERSION_3_6;
258 		break;
259 	case AMDGPU_FAMILY_GC_12_0_0:
260 		if (ASICREV_IS_GC_12_0_1_A0(asic_id.hw_internal_rev) ||
261 			ASICREV_IS_GC_12_0_0_A0(asic_id.hw_internal_rev))
262 			dc_version = DCN_VERSION_4_01;
263 		break;
264 	case AMDGPU_FAMILY_GC_11_5_4:
265 			dc_version = DCN_VERSION_4_2;
266 	break;
267 	case AMDGPU_FAMILY_GC_13_0_1:
268 			dc_version = DCN_VERSION_6_0;
269 		break;
270 	default:
271 		dc_version = DCE_VERSION_UNKNOWN;
272 		break;
273 	}
274 	return dc_version;
275 }
276 
277 struct resource_pool *dc_create_resource_pool(struct dc  *dc,
278 					      const struct dc_init_data *init_data,
279 					      enum dce_version dc_version)
280 {
281 	struct resource_pool *res_pool = NULL;
282 
283 	switch (dc_version) {
284 #if defined(CONFIG_DRM_AMD_DC_SI)
285 	case DCE_VERSION_6_0:
286 		res_pool = dce60_create_resource_pool(
287 			init_data->num_virtual_links, dc);
288 		break;
289 	case DCE_VERSION_6_1:
290 		res_pool = dce61_create_resource_pool(
291 			init_data->num_virtual_links, dc);
292 		break;
293 	case DCE_VERSION_6_4:
294 		res_pool = dce64_create_resource_pool(
295 			init_data->num_virtual_links, dc);
296 		break;
297 #endif
298 #if defined(CONFIG_DRM_AMD_DC_DCE)
299 	case DCE_VERSION_8_0:
300 		res_pool = dce80_create_resource_pool(
301 				(uint8_t)init_data->num_virtual_links, dc);
302 		break;
303 	case DCE_VERSION_8_1:
304 		res_pool = dce81_create_resource_pool(
305 				(uint8_t)init_data->num_virtual_links, dc);
306 		break;
307 	case DCE_VERSION_8_3:
308 		res_pool = dce83_create_resource_pool(
309 				(uint8_t)init_data->num_virtual_links, dc);
310 		break;
311 	case DCE_VERSION_10_0:
312 		res_pool = dce100_create_resource_pool(
313 				(uint8_t)init_data->num_virtual_links, dc);
314 		break;
315 	case DCE_VERSION_11_0:
316 		res_pool = dce110_create_resource_pool(
317 				(uint8_t)init_data->num_virtual_links, dc,
318 				init_data->asic_id);
319 		break;
320 	case DCE_VERSION_11_2:
321 	case DCE_VERSION_11_22:
322 		res_pool = dce112_create_resource_pool(
323 				(uint8_t)init_data->num_virtual_links, dc);
324 		break;
325 	case DCE_VERSION_12_0:
326 	case DCE_VERSION_12_1:
327 		res_pool = dce120_create_resource_pool(
328 				(uint8_t)init_data->num_virtual_links, dc);
329 		break;
330 #endif
331 
332 #if defined(CONFIG_DRM_AMD_DC_FP)
333 	case DCN_VERSION_1_0:
334 	case DCN_VERSION_1_01:
335 		res_pool = dcn10_create_resource_pool(init_data, dc);
336 		break;
337 	case DCN_VERSION_2_0:
338 		res_pool = dcn20_create_resource_pool(init_data, dc);
339 		break;
340 	case DCN_VERSION_2_1:
341 		res_pool = dcn21_create_resource_pool(init_data, dc);
342 		break;
343 	case DCN_VERSION_2_01:
344 		res_pool = dcn201_create_resource_pool(init_data, dc);
345 		break;
346 	case DCN_VERSION_3_0:
347 		res_pool = dcn30_create_resource_pool(init_data, dc);
348 		break;
349 	case DCN_VERSION_3_01:
350 		res_pool = dcn301_create_resource_pool(init_data, dc);
351 		break;
352 	case DCN_VERSION_3_02:
353 		res_pool = dcn302_create_resource_pool(init_data, dc);
354 		break;
355 	case DCN_VERSION_3_03:
356 		res_pool = dcn303_create_resource_pool(init_data, dc);
357 		break;
358 	case DCN_VERSION_3_1:
359 		res_pool = dcn31_create_resource_pool(init_data, dc);
360 		break;
361 	case DCN_VERSION_3_14:
362 		res_pool = dcn314_create_resource_pool(init_data, dc);
363 		break;
364 	case DCN_VERSION_3_15:
365 		res_pool = dcn315_create_resource_pool(init_data, dc);
366 		break;
367 	case DCN_VERSION_3_16:
368 		res_pool = dcn316_create_resource_pool(init_data, dc);
369 		break;
370 	case DCN_VERSION_3_2:
371 		res_pool = dcn32_create_resource_pool(init_data, dc);
372 		break;
373 	case DCN_VERSION_3_21:
374 		res_pool = dcn321_create_resource_pool(init_data, dc);
375 		break;
376 	case DCN_VERSION_3_5:
377 		res_pool = dcn35_create_resource_pool(init_data, dc);
378 		break;
379 	case DCN_VERSION_3_51:
380 		res_pool = dcn351_create_resource_pool(init_data, dc);
381 		break;
382 	case DCN_VERSION_3_6:
383 		res_pool = dcn36_create_resource_pool(init_data, dc);
384 		break;
385 	case DCN_VERSION_4_01:
386 		res_pool = dcn401_create_resource_pool(init_data, dc);
387 		break;
388 	case DCN_VERSION_4_2:
389 		res_pool = dcn42_create_resource_pool(init_data, dc);
390 		break;
391 	case DCN_VERSION_4_2B:
392 		res_pool = dcn42b_create_resource_pool(init_data, dc);
393 		break;
394 	case DCN_VERSION_6_0:
395 		res_pool = dcn60_create_resource_pool(init_data, dc);
396 		break;
397 #endif /* CONFIG_DRM_AMD_DC_FP */
398 	default:
399 		break;
400 	}
401 
402 	if (res_pool != NULL) {
403 		if (dc->ctx->dc_bios->fw_info_valid) {
404 			res_pool->ref_clocks.xtalin_clock_inKhz =
405 				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
406 			/* initialize with firmware data first, no all
407 			 * ASIC have DCCG SW component. FPGA or
408 			 * simulation need initialization of
409 			 * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz
410 			 * with xtalin_clock_inKhz
411 			 */
412 			res_pool->ref_clocks.dccg_ref_clock_inKhz =
413 				res_pool->ref_clocks.xtalin_clock_inKhz;
414 			res_pool->ref_clocks.dchub_ref_clock_inKhz =
415 				res_pool->ref_clocks.xtalin_clock_inKhz;
416 		} else
417 			ASSERT_CRITICAL(false);
418 	}
419 
420 	return res_pool;
421 }
422 
423 void dc_destroy_resource_pool(struct dc *dc)
424 {
425 	if (dc) {
426 		if (dc->res_pool)
427 			dc->res_pool->funcs->destroy(&dc->res_pool);
428 
429 		kfree(dc->hwseq);
430 	}
431 }
432 
433 static void update_num_audio(
434 	const struct resource_straps *straps,
435 	unsigned int *num_audio,
436 	struct audio_support *aud_support)
437 {
438 	aud_support->dp_audio = true;
439 	aud_support->hdmi_audio_native = false;
440 	aud_support->hdmi_audio_on_dongle = false;
441 
442 	if (straps->hdmi_disable == 0) {
443 		if (straps->dc_pinstraps_audio & 0x2) {
444 			aud_support->hdmi_audio_on_dongle = true;
445 			aud_support->hdmi_audio_native = true;
446 		}
447 	}
448 
449 	switch (straps->audio_stream_number) {
450 	case 0: /* multi streams supported */
451 		break;
452 	case 1: /* multi streams not supported */
453 		*num_audio = 1;
454 		break;
455 	default:
456 		DC_ERR("DC: unexpected audio fuse!\n");
457 	}
458 }
459 
460 bool resource_construct(
461 	unsigned int num_virtual_links,
462 	struct dc  *dc,
463 	struct resource_pool *pool,
464 	const struct resource_create_funcs *create_funcs)
465 {
466 	struct dc_context *ctx = dc->ctx;
467 	const struct resource_caps *caps = pool->res_cap;
468 	unsigned int i;
469 	unsigned int num_audio = caps->num_audio;
470 	struct resource_straps straps = {0};
471 
472 	if (create_funcs->read_dce_straps)
473 		create_funcs->read_dce_straps(dc->ctx, &straps);
474 
475 	pool->audio_count = 0;
476 	if (create_funcs->create_audio) {
477 		/* find the total number of streams available via the
478 		 * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
479 		 * registers (one for each pin) starting from pin 1
480 		 * up to the max number of audio pins.
481 		 * We stop on the first pin where
482 		 * PORT_CONNECTIVITY == 1 (as instructed by HW team).
483 		 */
484 		update_num_audio(&straps, &num_audio, &pool->audio_support);
485 		for (i = 0; i < (unsigned int)caps->num_audio; i++) {
486 			struct audio *aud = create_funcs->create_audio(ctx, i);
487 
488 			if (aud == NULL) {
489 				DC_ERR("DC: failed to create audio!\n");
490 				return false;
491 			}
492 			if (!aud->funcs->endpoint_valid(aud)) {
493 				aud->funcs->destroy(&aud);
494 				break;
495 			}
496 			pool->audios[i] = aud;
497 			pool->audio_count++;
498 		}
499 	}
500 
501 	pool->stream_enc_count = 0;
502 	if (create_funcs->create_stream_encoder) {
503 		for (i = 0; i < (unsigned int)caps->num_stream_encoder; i++) {
504 			pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx);
505 			if (pool->stream_enc[i] == NULL)
506 				DC_ERR("DC: failed to create stream_encoder!\n");
507 			pool->stream_enc_count++;
508 		}
509 
510 		for (i = 0; i < (unsigned int)caps->num_analog_stream_encoder; i++) {
511 			pool->stream_enc[caps->num_stream_encoder + i] =
512 				create_funcs->create_stream_encoder(ENGINE_ID_DACA + i, ctx);
513 			if (pool->stream_enc[caps->num_stream_encoder + i] == NULL)
514 				DC_ERR("DC: failed to create analog stream_encoder %d!\n", i);
515 			pool->stream_enc_count++;
516 		}
517 	}
518 
519 	pool->hpo_frl_stream_enc_count = 0;
520 	if (create_funcs->create_hpo_frl_stream_encoder) {
521 		for (i = 0; i < (unsigned int)caps->num_hpo_frl; i++) {
522 			pool->hpo_frl_stream_enc[i] = create_funcs->create_hpo_frl_stream_encoder(i+ENGINE_ID_HPO_0, ctx);
523 			if (pool->hpo_frl_stream_enc[i] == NULL)
524 				DC_ERR("DC: failed to create HPO FRL stream encoder!\n");
525 			pool->hpo_frl_stream_enc_count++;
526 
527 		}
528 	}
529 	pool->hpo_frl_link_enc_count = 0;
530 	if (create_funcs->create_hpo_frl_link_encoder) {
531 		for (i = 0; i < (unsigned int)caps->num_hpo_frl; i++) {
532 			pool->hpo_frl_link_enc[i] = create_funcs->create_hpo_frl_link_encoder(i+ENGINE_ID_HPO_0, ctx);
533 			if (pool->hpo_frl_link_enc[i] == NULL)
534 				DC_ERR("DC: failed to create HPO FRL link encoder!\n");
535 			pool->hpo_frl_link_enc_count++;
536 		}
537 	}
538 	pool->hpo_dp_stream_enc_count = 0;
539 	if (create_funcs->create_hpo_dp_stream_encoder) {
540 		for (i = 0; i < (unsigned int)caps->num_hpo_dp_stream_encoder; i++) {
541 			pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx);
542 			if (pool->hpo_dp_stream_enc[i] == NULL)
543 				DC_ERR("DC: failed to create HPO DP stream encoder!\n");
544 			pool->hpo_dp_stream_enc_count++;
545 
546 		}
547 	}
548 
549 	pool->hpo_dp_link_enc_count = 0;
550 	if (create_funcs->create_hpo_dp_link_encoder) {
551 		for (i = 0; i < (unsigned int)caps->num_hpo_dp_link_encoder; i++) {
552 			pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder((uint8_t)i, ctx);
553 			if (pool->hpo_dp_link_enc[i] == NULL)
554 				DC_ERR("DC: failed to create HPO DP link encoder!\n");
555 			pool->hpo_dp_link_enc_count++;
556 		}
557 	}
558 
559 	for (i = 0; i < (unsigned int)caps->num_mpc_3dlut; i++) {
560 		pool->mpc_lut[i] = dc_create_3dlut_func();
561 		if (pool->mpc_lut[i] == NULL)
562 			DC_ERR("DC: failed to create MPC 3dlut!\n");
563 		pool->mpc_shaper[i] = dc_create_transfer_func();
564 		if (pool->mpc_shaper[i] == NULL)
565 			DC_ERR("DC: failed to create MPC shaper!\n");
566 	}
567 
568 	dc->caps.dynamic_audio = false;
569 	if (pool->audio_count < pool->stream_enc_count) {
570 		dc->caps.dynamic_audio = true;
571 	}
572 	for (i = 0; i < num_virtual_links; i++) {
573 		pool->stream_enc[pool->stream_enc_count] =
574 			virtual_stream_encoder_create(
575 					ctx, ctx->dc_bios);
576 		if (pool->stream_enc[pool->stream_enc_count] == NULL) {
577 			DC_ERR("DC: failed to create stream_encoder!\n");
578 			return false;
579 		}
580 		pool->stream_enc_count++;
581 	}
582 
583 	dc->hwseq = create_funcs->create_hwseq(ctx);
584 
585 	return true;
586 }
587 static int find_matching_clock_source(
588 		const struct resource_pool *pool,
589 		struct clock_source *clock_source)
590 {
591 
592 	unsigned int i;
593 
594 	for (i = 0; i < pool->clk_src_count; i++) {
595 		if (pool->clock_sources[i] == clock_source)
596 			return (int)i;
597 	}
598 	return -1;
599 }
600 
601 void resource_unreference_clock_source(
602 		struct resource_context *res_ctx,
603 		const struct resource_pool *pool,
604 		struct clock_source *clock_source)
605 {
606 	int i = find_matching_clock_source(pool, clock_source);
607 
608 	if (i > -1)
609 		res_ctx->clock_source_ref_count[i]--;
610 
611 	if (pool->dp_clock_source == clock_source)
612 		res_ctx->dp_clock_source_ref_count--;
613 }
614 
615 void resource_reference_clock_source(
616 		struct resource_context *res_ctx,
617 		const struct resource_pool *pool,
618 		struct clock_source *clock_source)
619 {
620 	int i = find_matching_clock_source(pool, clock_source);
621 
622 	if (i > -1)
623 		res_ctx->clock_source_ref_count[i]++;
624 
625 	if (pool->dp_clock_source == clock_source)
626 		res_ctx->dp_clock_source_ref_count++;
627 }
628 
629 int resource_get_clock_source_reference(
630 		struct resource_context *res_ctx,
631 		const struct resource_pool *pool,
632 		struct clock_source *clock_source)
633 {
634 	int i = find_matching_clock_source(pool, clock_source);
635 
636 	if (i > -1)
637 		return res_ctx->clock_source_ref_count[i];
638 
639 	if (pool->dp_clock_source == clock_source)
640 		return res_ctx->dp_clock_source_ref_count;
641 
642 	return -1;
643 }
644 
645 bool resource_are_vblanks_synchronizable(
646 	struct dc_stream_state *stream1,
647 	struct dc_stream_state *stream2)
648 {
649 	uint32_t base60_refresh_rates[] = {10, 20, 5};
650 	uint8_t i;
651 	uint8_t rr_count = (uint8_t)ARRAY_SIZE(base60_refresh_rates);
652 	uint64_t frame_time_diff;
653 
654 	if (stream1->ctx->dc->config.vblank_alignment_dto_params &&
655 		stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 &&
656 		dc_is_dp_signal(stream1->signal) &&
657 		dc_is_dp_signal(stream2->signal) &&
658 		false == stream1->has_non_synchronizable_pclk &&
659 		false == stream2->has_non_synchronizable_pclk &&
660 		stream1->timing.flags.VBLANK_SYNCHRONIZABLE &&
661 		stream2->timing.flags.VBLANK_SYNCHRONIZABLE) {
662 		/* disable refresh rates higher than 60Hz for now */
663 		if (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/
664 				stream1->timing.v_total > 60)
665 			return false;
666 		if (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/
667 				stream2->timing.v_total > 60)
668 			return false;
669 		frame_time_diff = (uint64_t)10000 *
670 			stream1->timing.h_total *
671 			stream1->timing.v_total *
672 			stream2->timing.pix_clk_100hz;
673 		frame_time_diff = div_u64(frame_time_diff, stream1->timing.pix_clk_100hz);
674 		frame_time_diff = div_u64(frame_time_diff, stream2->timing.h_total);
675 		frame_time_diff = div_u64(frame_time_diff, stream2->timing.v_total);
676 		for (i = 0; i < rr_count; i++) {
677 			int64_t diff = (int64_t)div_u64(frame_time_diff * base60_refresh_rates[i], 10) - 10000;
678 
679 			if (diff < 0)
680 				diff = -diff;
681 			if (diff < stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff)
682 				return true;
683 		}
684 	}
685 	return false;
686 }
687 
688 bool resource_are_streams_timing_synchronizable(
689 	struct dc_stream_state *stream1,
690 	struct dc_stream_state *stream2)
691 {
692 	if (stream1->timing.h_total != stream2->timing.h_total)
693 		return false;
694 
695 	if (stream1->timing.v_total != stream2->timing.v_total)
696 		return false;
697 
698 	if (stream1->timing.h_addressable
699 				!= stream2->timing.h_addressable)
700 		return false;
701 
702 	if (stream1->timing.v_addressable
703 				!= stream2->timing.v_addressable)
704 		return false;
705 
706 	if (stream1->timing.v_front_porch
707 				!= stream2->timing.v_front_porch)
708 		return false;
709 
710 	if (stream1->timing.pix_clk_100hz
711 				!= stream2->timing.pix_clk_100hz)
712 		return false;
713 
714 	if (stream1->clamping.c_depth != stream2->clamping.c_depth)
715 		return false;
716 
717 	if (stream1->phy_pix_clk != stream2->phy_pix_clk
718 			&& (!dc_is_dp_signal(stream1->signal)
719 			|| !dc_is_dp_signal(stream2->signal)))
720 		return false;
721 
722 	if (stream1->view_format != stream2->view_format)
723 		return false;
724 
725 	if (stream1->ignore_msa_timing_param || stream2->ignore_msa_timing_param)
726 		return false;
727 
728 	return true;
729 }
730 static bool is_dp_and_hdmi_sharable(
731 		struct dc_stream_state *stream1,
732 		struct dc_stream_state *stream2)
733 {
734 	if (stream1->ctx->dc->caps.disable_dp_clk_share)
735 		return false;
736 
737 	if (stream1->clamping.c_depth != COLOR_DEPTH_888 ||
738 		stream2->clamping.c_depth != COLOR_DEPTH_888)
739 		return false;
740 
741 	return true;
742 
743 }
744 
745 static bool is_sharable_clk_src(
746 	const struct pipe_ctx *pipe_with_clk_src,
747 	const struct pipe_ctx *pipe)
748 {
749 	if (pipe_with_clk_src->clock_source == NULL)
750 		return false;
751 
752 	if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL)
753 		return false;
754 
755 	if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) ||
756 		(dc_is_dp_signal(pipe->stream->signal) &&
757 		!is_dp_and_hdmi_sharable(pipe_with_clk_src->stream,
758 				     pipe->stream)))
759 		return false;
760 
761 	if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal)
762 			&& dc_is_dual_link_signal(pipe->stream->signal))
763 		return false;
764 
765 	if (dc_is_hdmi_signal(pipe->stream->signal)
766 			&& dc_is_dual_link_signal(pipe_with_clk_src->stream->signal))
767 		return false;
768 
769 	if (!resource_are_streams_timing_synchronizable(
770 			pipe_with_clk_src->stream, pipe->stream))
771 		return false;
772 
773 	return true;
774 }
775 
776 struct clock_source *resource_find_used_clk_src_for_sharing(
777 					struct resource_context *res_ctx,
778 					struct pipe_ctx *pipe_ctx)
779 {
780 	int i;
781 
782 	for (i = 0; i < MAX_PIPES; i++) {
783 		if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx))
784 			return res_ctx->pipe_ctx[i].clock_source;
785 	}
786 
787 	return NULL;
788 }
789 
790 static enum dc_pixel_format convert_pixel_format_to_dalsurface(
791 		enum surface_pixel_format surface_pixel_format)
792 {
793 	enum dc_pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
794 
795 	switch (surface_pixel_format) {
796 	case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
797 		dal_pixel_format = PIXEL_FORMAT_INDEX8;
798 		break;
799 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
800 		dal_pixel_format = PIXEL_FORMAT_RGB565;
801 		break;
802 	case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
803 		dal_pixel_format = PIXEL_FORMAT_RGB565;
804 		break;
805 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
806 		dal_pixel_format = PIXEL_FORMAT_ARGB8888;
807 		break;
808 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
809 		dal_pixel_format = PIXEL_FORMAT_ARGB8888;
810 		break;
811 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
812 		dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
813 		break;
814 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
815 		dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
816 		break;
817 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
818 		dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS;
819 		break;
820 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
821 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
822 		dal_pixel_format = PIXEL_FORMAT_FP16;
823 		break;
824 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
825 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
826 		dal_pixel_format = PIXEL_FORMAT_420BPP8;
827 		break;
828 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
829 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
830 		dal_pixel_format = PIXEL_FORMAT_420BPP10;
831 		break;
832 	case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P208:
833 	case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P208:
834 		dal_pixel_format = PIXEL_FORMAT_422BPP8;
835 		break;
836 	case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P210:
837 	case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P210:
838 		dal_pixel_format = PIXEL_FORMAT_422BPP10;
839 		break;
840 	case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P212:
841 	case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P212:
842 		dal_pixel_format = PIXEL_FORMAT_422BPP12;
843 		break;
844 	case SURFACE_PIXEL_FORMAT_VIDEO_422_YCrYCb:
845 	case SURFACE_PIXEL_FORMAT_VIDEO_422_YCbYCr:
846 	case SURFACE_PIXEL_FORMAT_VIDEO_422_CrYCbY:
847 	case SURFACE_PIXEL_FORMAT_VIDEO_422_CbYCrY:
848 		dal_pixel_format = PIXEL_FORMAT_422BPP8;
849 		break;
850 	case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCrYCb:
851 	case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCbYCr:
852 	case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CrYCbY:
853 	case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CbYCrY:
854 		dal_pixel_format = PIXEL_FORMAT_422BPP10;
855 		break;
856 	case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCrYCb:
857 	case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCbYCr:
858 	case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CrYCbY:
859 	case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CbYCrY:
860 		dal_pixel_format = PIXEL_FORMAT_422BPP12;
861 		break;
862 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
863 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
864 	default:
865 		dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
866 		break;
867 	}
868 	return dal_pixel_format;
869 }
870 
871 static inline void get_vp_scan_direction(
872 	enum dc_rotation_angle rotation,
873 	bool horizontal_mirror,
874 	bool *orthogonal_rotation,
875 	bool *flip_vert_scan_dir,
876 	bool *flip_horz_scan_dir)
877 {
878 	*orthogonal_rotation = false;
879 	*flip_vert_scan_dir = false;
880 	*flip_horz_scan_dir = false;
881 	if (rotation == ROTATION_ANGLE_180) {
882 		*flip_vert_scan_dir = true;
883 		*flip_horz_scan_dir = true;
884 	} else if (rotation == ROTATION_ANGLE_90) {
885 		*orthogonal_rotation = true;
886 		*flip_horz_scan_dir = true;
887 	} else if (rotation == ROTATION_ANGLE_270) {
888 		*orthogonal_rotation = true;
889 		*flip_vert_scan_dir = true;
890 	}
891 
892 	if (horizontal_mirror)
893 		*flip_horz_scan_dir = !*flip_horz_scan_dir;
894 }
895 
896 static struct rect intersect_rec(const struct rect *r0, const struct rect *r1)
897 {
898 	struct rect rec;
899 	int r0_x_end = r0->x + r0->width;
900 	int r1_x_end = r1->x + r1->width;
901 	int r0_y_end = r0->y + r0->height;
902 	int r1_y_end = r1->y + r1->height;
903 
904 	rec.x = r0->x > r1->x ? r0->x : r1->x;
905 	rec.width = r0_x_end > r1_x_end ? r1_x_end - rec.x : r0_x_end - rec.x;
906 	rec.y = r0->y > r1->y ? r0->y : r1->y;
907 	rec.height = r0_y_end > r1_y_end ? r1_y_end - rec.y : r0_y_end - rec.y;
908 
909 	/* in case that there is no intersection */
910 	if (rec.width < 0 || rec.height < 0)
911 		memset(&rec, 0, sizeof(rec));
912 
913 	return rec;
914 }
915 
916 static struct rect shift_rec(const struct rect *rec_in, int x, int y)
917 {
918 	struct rect rec_out = *rec_in;
919 
920 	rec_out.x += x;
921 	rec_out.y += y;
922 
923 	return rec_out;
924 }
925 
926 static struct rect calculate_plane_rec_in_timing_active(
927 		struct pipe_ctx *pipe_ctx,
928 		const struct rect *rec_in)
929 {
930 	/*
931 	 * The following diagram shows an example where we map a 1920x1200
932 	 * desktop to a 2560x1440 timing with a plane rect in the middle
933 	 * of the screen. To map a plane rect from Stream Source to Timing
934 	 * Active space, we first multiply stream scaling ratios (i.e 2304/1920
935 	 * horizontal and 1440/1200 vertical) to the plane's x and y, then
936 	 * we add stream destination offsets (i.e 128 horizontal, 0 vertical).
937 	 * This will give us a plane rect's position in Timing Active. However
938 	 * we have to remove the fractional. The rule is that we find left/right
939 	 * and top/bottom positions and round the value to the adjacent integer.
940 	 *
941 	 * Stream Source Space
942 	 * ------------
943 	 *        __________________________________________________
944 	 *       |Stream Source (1920 x 1200) ^                     |
945 	 *       |                            y                     |
946 	 *       |         <------- w --------|>                    |
947 	 *       |          __________________V                     |
948 	 *       |<-- x -->|Plane//////////////| ^                  |
949 	 *       |         |(pre scale)////////| |                  |
950 	 *       |         |///////////////////| |                  |
951 	 *       |         |///////////////////| h                  |
952 	 *       |         |///////////////////| |                  |
953 	 *       |         |///////////////////| |                  |
954 	 *       |         |///////////////////| V                  |
955 	 *       |                                                  |
956 	 *       |                                                  |
957 	 *       |__________________________________________________|
958 	 *
959 	 *
960 	 * Timing Active Space
961 	 * ---------------------------------
962 	 *
963 	 *       Timing Active (2560 x 1440)
964 	 *        __________________________________________________
965 	 *       |*****|  Stteam Destination (2304 x 1440)    |*****|
966 	 *       |*****|                                      |*****|
967 	 *       |<128>|                                      |*****|
968 	 *       |*****|     __________________               |*****|
969 	 *       |*****|    |Plane/////////////|              |*****|
970 	 *       |*****|    |(post scale)//////|              |*****|
971 	 *       |*****|    |//////////////////|              |*****|
972 	 *       |*****|    |//////////////////|              |*****|
973 	 *       |*****|    |//////////////////|              |*****|
974 	 *       |*****|    |//////////////////|              |*****|
975 	 *       |*****|                                      |*****|
976 	 *       |*****|                                      |*****|
977 	 *       |*****|                                      |*****|
978 	 *       |*****|______________________________________|*****|
979 	 *
980 	 * So the resulting formulas are shown below:
981 	 *
982 	 * recout_x = 128 + round(plane_x * 2304 / 1920)
983 	 * recout_w = 128 + round((plane_x + plane_w) * 2304 / 1920) - recout_x
984 	 * recout_y = 0 + round(plane_y * 1440 / 1280)
985 	 * recout_h = 0 + round((plane_y + plane_h) * 1440 / 1200) - recout_y
986 	 *
987 	 * NOTE: fixed point division is not error free. To reduce errors
988 	 * introduced by fixed point division, we divide only after
989 	 * multiplication is complete.
990 	 */
991 	const struct dc_stream_state *stream = pipe_ctx->stream;
992 	struct rect rec_out = {0};
993 	struct fixed31_32 temp;
994 
995 	temp = dc_fixpt_from_fraction(rec_in->x * (long long)stream->dst.width,
996 			stream->src.width);
997 	rec_out.x = stream->dst.x + dc_fixpt_round(temp);
998 
999 	temp = dc_fixpt_from_fraction(
1000 			(rec_in->x + rec_in->width) * (long long)stream->dst.width,
1001 			stream->src.width);
1002 	rec_out.width = stream->dst.x + dc_fixpt_round(temp) - rec_out.x;
1003 
1004 	temp = dc_fixpt_from_fraction(rec_in->y * (long long)stream->dst.height,
1005 			stream->src.height);
1006 	rec_out.y = stream->dst.y + dc_fixpt_round(temp);
1007 
1008 	temp = dc_fixpt_from_fraction(
1009 			(rec_in->y + rec_in->height) * (long long)stream->dst.height,
1010 			stream->src.height);
1011 	rec_out.height = stream->dst.y + dc_fixpt_round(temp) - rec_out.y;
1012 
1013 	return rec_out;
1014 }
1015 
1016 static struct rect calculate_mpc_slice_in_timing_active(
1017 		struct pipe_ctx *pipe_ctx,
1018 		struct rect *plane_clip_rec)
1019 {
1020 	const struct dc_stream_state *stream = pipe_ctx->stream;
1021 	int mpc_slice_count = resource_get_mpc_slice_count(pipe_ctx);
1022 	int mpc_slice_idx = resource_get_mpc_slice_index(pipe_ctx);
1023 	int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1;
1024 	struct rect mpc_rec;
1025 
1026 	mpc_rec.width = plane_clip_rec->width / mpc_slice_count;
1027 	mpc_rec.x = plane_clip_rec->x + mpc_rec.width * mpc_slice_idx;
1028 	mpc_rec.height = plane_clip_rec->height;
1029 	mpc_rec.y = plane_clip_rec->y;
1030 	ASSERT(mpc_slice_count == 1 ||
1031 			stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE ||
1032 			mpc_rec.width % 2 == 0);
1033 
1034 	if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
1035 		mpc_rec.x -= (mpc_rec.width * mpc_slice_idx);
1036 
1037 	/* extra pixels in the division remainder need to go to pipes after
1038 	 * the extra pixel index minus one(epimo) defined here as:
1039 	 */
1040 	if (mpc_slice_idx > epimo) {
1041 		mpc_rec.x += mpc_slice_idx - epimo - 1;
1042 		mpc_rec.width += 1;
1043 	}
1044 
1045 	if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) {
1046 		ASSERT(mpc_rec.height % 2 == 0);
1047 		mpc_rec.height /= 2;
1048 	}
1049 	return mpc_rec;
1050 }
1051 
1052 static void calculate_adjust_recout_for_visual_confirm(const struct pipe_ctx *pipe_ctx,
1053 	unsigned int *base_offset, unsigned int *dpp_offset)
1054 {
1055 	struct dc *dc = pipe_ctx->stream->ctx->dc;
1056 	*base_offset = 0;
1057 	*dpp_offset = 0;
1058 
1059 	if (dc->debug.visual_confirm == VISUAL_CONFIRM_DISABLE || !pipe_ctx->plane_res.dpp)
1060 		return;
1061 
1062 	*dpp_offset = pipe_ctx->stream->timing.v_addressable / VISUAL_CONFIRM_DPP_OFFSET_DENO;
1063 	*dpp_offset *= pipe_ctx->plane_res.dpp->inst;
1064 
1065 	if ((dc->debug.visual_confirm_rect_height >= VISUAL_CONFIRM_BASE_MIN) &&
1066 			dc->debug.visual_confirm_rect_height <= VISUAL_CONFIRM_BASE_MAX)
1067 		*base_offset = dc->debug.visual_confirm_rect_height;
1068 	else
1069 		*base_offset = VISUAL_CONFIRM_BASE_DEFAULT;
1070 }
1071 
1072 static void reverse_adjust_recout_for_visual_confirm(struct rect *recout,
1073 		const struct pipe_ctx *pipe_ctx)
1074 {
1075 	unsigned int dpp_offset, base_offset;
1076 
1077 	calculate_adjust_recout_for_visual_confirm(pipe_ctx, &base_offset,
1078 		&dpp_offset);
1079 	recout->height += base_offset;
1080 	recout->height += dpp_offset;
1081 }
1082 
1083 static void adjust_recout_for_visual_confirm(struct rect *recout,
1084 		struct pipe_ctx *pipe_ctx)
1085 {
1086 	unsigned int dpp_offset, base_offset;
1087 
1088 	calculate_adjust_recout_for_visual_confirm(pipe_ctx, &base_offset,
1089 		&dpp_offset);
1090 	recout->height -= base_offset;
1091 	recout->height -= dpp_offset;
1092 }
1093 
1094 /*
1095  * The function maps a plane clip from Stream Source Space to ODM Slice Space
1096  * and calculates the rec of the overlapping area of MPC slice of the plane
1097  * clip, ODM slice associated with the pipe context and stream destination rec.
1098  */
1099 static void calculate_recout(struct pipe_ctx *pipe_ctx)
1100 {
1101 	/*
1102 	 * A plane clip represents the desired plane size and position in Stream
1103 	 * Source Space. Stream Source is the destination where all planes are
1104 	 * blended (i.e. positioned, scaled and overlaid). It is a canvas where
1105 	 * all planes associated with the current stream are drawn together.
1106 	 * After Stream Source is completed, we will further scale and
1107 	 * reposition the entire canvas of the stream source to Stream
1108 	 * Destination in Timing Active Space. This could be due to display
1109 	 * overscan adjustment where we will need to rescale and reposition all
1110 	 * the planes so they can fit into a TV with overscan or downscale
1111 	 * upscale features such as GPU scaling or VSR.
1112 	 *
1113 	 * This two step blending is a virtual procedure in software. In
1114 	 * hardware there is no such thing as Stream Source. all planes are
1115 	 * blended once in Timing Active Space. Software virtualizes a Stream
1116 	 * Source space to decouple the math complicity so scaling param
1117 	 * calculation focuses on one step at a time.
1118 	 *
1119 	 * In the following two diagrams, user applied 10% overscan adjustment
1120 	 * so the Stream Source needs to be scaled down a little before mapping
1121 	 * to Timing Active Space. As a result the Plane Clip is also scaled
1122 	 * down by the same ratio, Plane Clip position (i.e. x and y) with
1123 	 * respect to Stream Source is also scaled down. To map it in Timing
1124 	 * Active Space additional x and y offsets from Stream Destination are
1125 	 * added to Plane Clip as well.
1126 	 *
1127 	 * Stream Source Space
1128 	 * ------------
1129 	 *        __________________________________________________
1130 	 *       |Stream Source (3840 x 2160) ^                     |
1131 	 *       |                            y                     |
1132 	 *       |                            |                     |
1133 	 *       |          __________________V                     |
1134 	 *       |<-- x -->|Plane Clip/////////|                    |
1135 	 *       |         |(pre scale)////////|                    |
1136 	 *       |         |///////////////////|                    |
1137 	 *       |         |///////////////////|                    |
1138 	 *       |         |///////////////////|                    |
1139 	 *       |         |///////////////////|                    |
1140 	 *       |         |///////////////////|                    |
1141 	 *       |                                                  |
1142 	 *       |                                                  |
1143 	 *       |__________________________________________________|
1144 	 *
1145 	 *
1146 	 * Timing Active Space (3840 x 2160)
1147 	 * ---------------------------------
1148 	 *
1149 	 *       Timing Active
1150 	 *        __________________________________________________
1151 	 *       | y_____________________________________________   |
1152 	 *       |x |Stream Destination (3456 x 1944)            |  |
1153 	 *       |  |                                            |  |
1154 	 *       |  |        __________________                  |  |
1155 	 *       |  |       |Plane Clip////////|                 |  |
1156 	 *       |  |       |(post scale)//////|                 |  |
1157 	 *       |  |       |//////////////////|                 |  |
1158 	 *       |  |       |//////////////////|                 |  |
1159 	 *       |  |       |//////////////////|                 |  |
1160 	 *       |  |       |//////////////////|                 |  |
1161 	 *       |  |                                            |  |
1162 	 *       |  |                                            |  |
1163 	 *       |  |____________________________________________|  |
1164 	 *       |__________________________________________________|
1165 	 *
1166 	 *
1167 	 * In Timing Active Space a plane clip could be further sliced into
1168 	 * pieces called MPC slices. Each Pipe Context is responsible for
1169 	 * processing only one MPC slice so the plane processing workload can be
1170 	 * distributed to multiple DPP Pipes. MPC slices could be blended
1171 	 * together to a single ODM slice. Each ODM slice is responsible for
1172 	 * processing a portion of Timing Active divided horizontally so the
1173 	 * output pixel processing workload can be distributed to multiple OPP
1174 	 * pipes. All ODM slices are mapped together in ODM block so all MPC
1175 	 * slices belong to different ODM slices could be pieced together to
1176 	 * form a single image in Timing Active. MPC slices must belong to
1177 	 * single ODM slice. If an MPC slice goes across ODM slice boundary, it
1178 	 * needs to be divided into two MPC slices one for each ODM slice.
1179 	 *
1180 	 * In the following diagram the output pixel processing workload is
1181 	 * divided horizontally into two ODM slices one for each OPP blend tree.
1182 	 * OPP0 blend tree is responsible for processing left half of Timing
1183 	 * Active, while OPP2 blend tree is responsible for processing right
1184 	 * half.
1185 	 *
1186 	 * The plane has two MPC slices. However since the right MPC slice goes
1187 	 * across ODM boundary, two DPP pipes are needed one for each OPP blend
1188 	 * tree. (i.e. DPP1 for OPP0 blend tree and DPP2 for OPP2 blend tree).
1189 	 *
1190 	 * Assuming that we have a Pipe Context associated with OPP0 and DPP1
1191 	 * working on processing the plane in the diagram. We want to know the
1192 	 * width and height of the shaded rectangle and its relative position
1193 	 * with respect to the ODM slice0. This is called the recout of the pipe
1194 	 * context.
1195 	 *
1196 	 * Planes can be at arbitrary size and position and there could be an
1197 	 * arbitrary number of MPC and ODM slices. The algorithm needs to take
1198 	 * all scenarios into account.
1199 	 *
1200 	 * Timing Active Space (3840 x 2160)
1201 	 * ---------------------------------
1202 	 *
1203 	 *       Timing Active
1204 	 *        __________________________________________________
1205 	 *       |OPP0(ODM slice0)^        |OPP2(ODM slice1)        |
1206 	 *       |                y        |                        |
1207 	 *       |                |  <- w ->                        |
1208 	 *       |           _____V________|____                    |
1209 	 *       |          |DPP0 ^  |DPP1 |DPP2|                   |
1210 	 *       |<------ x |-----|->|/////|    |                   |
1211 	 *       |          |     |  |/////|    |                   |
1212 	 *       |          |     h  |/////|    |                   |
1213 	 *       |          |     |  |/////|    |                   |
1214 	 *       |          |_____V__|/////|____|                   |
1215 	 *       |                         |                        |
1216 	 *       |                         |                        |
1217 	 *       |                         |                        |
1218 	 *       |_________________________|________________________|
1219 	 *
1220 	 *
1221 	 */
1222 	struct rect plane_clip;
1223 	struct rect mpc_slice_of_plane_clip;
1224 	struct rect odm_slice_src;
1225 	struct rect overlapping_area;
1226 
1227 	plane_clip = calculate_plane_rec_in_timing_active(pipe_ctx,
1228 			&pipe_ctx->plane_state->clip_rect);
1229 	/* guard plane clip from drawing beyond stream dst here */
1230 	plane_clip = intersect_rec(&plane_clip,
1231 				&pipe_ctx->stream->dst);
1232 	mpc_slice_of_plane_clip = calculate_mpc_slice_in_timing_active(
1233 			pipe_ctx, &plane_clip);
1234 	odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx);
1235 	overlapping_area = intersect_rec(&mpc_slice_of_plane_clip, &odm_slice_src);
1236 	if (overlapping_area.height > 0 &&
1237 			overlapping_area.width > 0) {
1238 		/* shift the overlapping area so it is with respect to current
1239 		 * ODM slice source's position
1240 		 */
1241 		pipe_ctx->plane_res.scl_data.recout = shift_rec(
1242 				&overlapping_area,
1243 				-odm_slice_src.x, -odm_slice_src.y);
1244 		adjust_recout_for_visual_confirm(
1245 				&pipe_ctx->plane_res.scl_data.recout,
1246 				pipe_ctx);
1247 	} else {
1248 		/* if there is no overlap, zero recout */
1249 		memset(&pipe_ctx->plane_res.scl_data.recout, 0,
1250 				sizeof(struct rect));
1251 	}
1252 
1253 }
1254 
1255 static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
1256 {
1257 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1258 	const struct dc_stream_state *stream = pipe_ctx->stream;
1259 	struct rect surf_src = plane_state->src_rect;
1260 	const int in_w = stream->src.width;
1261 	const int in_h = stream->src.height;
1262 	const int out_w = stream->dst.width;
1263 	const int out_h = stream->dst.height;
1264 
1265 	/*Swap surf_src height and width since scaling ratios are in recout rotation*/
1266 	if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
1267 			pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
1268 		swap(surf_src.height, surf_src.width);
1269 
1270 	pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction(
1271 					surf_src.width,
1272 					plane_state->dst_rect.width);
1273 	pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_from_fraction(
1274 					surf_src.height,
1275 					plane_state->dst_rect.height);
1276 
1277 	if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
1278 		pipe_ctx->plane_res.scl_data.ratios.horz.value *= 2;
1279 	else if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
1280 		pipe_ctx->plane_res.scl_data.ratios.vert.value *= 2;
1281 
1282 	pipe_ctx->plane_res.scl_data.ratios.vert.value = div64_s64(
1283 		pipe_ctx->plane_res.scl_data.ratios.vert.value * in_h, out_h);
1284 	pipe_ctx->plane_res.scl_data.ratios.horz.value = div64_s64(
1285 		pipe_ctx->plane_res.scl_data.ratios.horz.value * in_w, out_w);
1286 
1287 	pipe_ctx->plane_res.scl_data.ratios.horz_c = pipe_ctx->plane_res.scl_data.ratios.horz;
1288 	pipe_ctx->plane_res.scl_data.ratios.vert_c = pipe_ctx->plane_res.scl_data.ratios.vert;
1289 
1290 	if (pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP8
1291 			|| pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP10) {
1292 		pipe_ctx->plane_res.scl_data.ratios.horz_c.value /= 2;
1293 		pipe_ctx->plane_res.scl_data.ratios.vert_c.value /= 2;
1294 	}
1295 	pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_truncate(
1296 			pipe_ctx->plane_res.scl_data.ratios.horz, 19);
1297 	pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_truncate(
1298 			pipe_ctx->plane_res.scl_data.ratios.vert, 19);
1299 	pipe_ctx->plane_res.scl_data.ratios.horz_c = dc_fixpt_truncate(
1300 			pipe_ctx->plane_res.scl_data.ratios.horz_c, 19);
1301 	pipe_ctx->plane_res.scl_data.ratios.vert_c = dc_fixpt_truncate(
1302 			pipe_ctx->plane_res.scl_data.ratios.vert_c, 19);
1303 }
1304 
1305 
1306 /*
1307  * We completely calculate vp offset, size and inits here based entirely on scaling
1308  * ratios and recout for pixel perfect pipe combine.
1309  */
1310 static void calculate_init_and_vp(
1311 		bool flip_scan_dir,
1312 		int recout_offset_within_recout_full,
1313 		int recout_size,
1314 		int src_size,
1315 		int taps,
1316 		struct fixed31_32 ratio,
1317 		struct fixed31_32 *init,
1318 		int *vp_offset,
1319 		int *vp_size)
1320 {
1321 	struct fixed31_32 temp;
1322 	int int_part;
1323 
1324 	/*
1325 	 * First of the taps starts sampling pixel number <init_int_part> corresponding to recout
1326 	 * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on.
1327 	 * All following calculations are based on this logic.
1328 	 *
1329 	 * Init calculated according to formula:
1330 	 * 	init = (scaling_ratio + number_of_taps + 1) / 2
1331 	 * 	init_bot = init + scaling_ratio
1332 	 * 	to get pixel perfect combine add the fraction from calculating vp offset
1333 	 */
1334 	temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full);
1335 	*vp_offset = dc_fixpt_floor(temp);
1336 	temp.value &= 0xffffffff;
1337 	*init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int(
1338 			dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19);
1339 	/*
1340 	 * If viewport has non 0 offset and there are more taps than covered by init then
1341 	 * we should decrease the offset and increase init so we are never sampling
1342 	 * outside of viewport.
1343 	 */
1344 	int_part = dc_fixpt_floor(*init);
1345 	if (int_part < taps) {
1346 		int_part = taps - int_part;
1347 		if (int_part > *vp_offset)
1348 			int_part = *vp_offset;
1349 		*vp_offset -= int_part;
1350 		*init = dc_fixpt_add_int(*init, int_part);
1351 	}
1352 	/*
1353 	 * If taps are sampling outside of viewport at end of recout and there are more pixels
1354 	 * available in the surface we should increase the viewport size, regardless set vp to
1355 	 * only what is used.
1356 	 */
1357 	temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1));
1358 	*vp_size = dc_fixpt_floor(temp);
1359 	if (*vp_size + *vp_offset > src_size)
1360 		*vp_size = src_size - *vp_offset;
1361 
1362 	/* We did all the math assuming we are scanning same direction as display does,
1363 	 * however mirror/rotation changes how vp scans vs how it is offset. If scan direction
1364 	 * is flipped we simply need to calculate offset from the other side of plane.
1365 	 * Note that outside of viewport all scaling hardware works in recout space.
1366 	 */
1367 	if (flip_scan_dir)
1368 		*vp_offset = src_size - *vp_offset - *vp_size;
1369 }
1370 
1371 static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
1372 {
1373 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1374 	struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
1375 	struct rect src = plane_state->src_rect;
1376 	struct rect recout_dst_in_active_timing;
1377 	struct rect recout_clip_in_active_timing;
1378 	struct rect recout_clip_in_recout_dst;
1379 	struct rect overlap_in_active_timing;
1380 	struct rect odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx);
1381 	int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
1382 				|| data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
1383 	bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
1384 
1385 	recout_clip_in_active_timing = shift_rec(
1386 			&data->recout, odm_slice_src.x, odm_slice_src.y);
1387 	recout_dst_in_active_timing = calculate_plane_rec_in_timing_active(
1388 			pipe_ctx, &plane_state->dst_rect);
1389 	overlap_in_active_timing = intersect_rec(&recout_clip_in_active_timing,
1390 			&recout_dst_in_active_timing);
1391 	if (overlap_in_active_timing.width > 0 &&
1392 			overlap_in_active_timing.height > 0)
1393 		recout_clip_in_recout_dst = shift_rec(&overlap_in_active_timing,
1394 				-recout_dst_in_active_timing.x,
1395 				-recout_dst_in_active_timing.y);
1396 	else
1397 		memset(&recout_clip_in_recout_dst, 0, sizeof(struct rect));
1398 
1399 	/*
1400 	 * Work in recout rotation since that requires less transformations
1401 	 */
1402 	get_vp_scan_direction(
1403 			plane_state->rotation,
1404 			plane_state->horizontal_mirror,
1405 			&orthogonal_rotation,
1406 			&flip_vert_scan_dir,
1407 			&flip_horz_scan_dir);
1408 
1409 	if (orthogonal_rotation) {
1410 		swap(src.width, src.height);
1411 		swap(flip_vert_scan_dir, flip_horz_scan_dir);
1412 	}
1413 
1414 	calculate_init_and_vp(
1415 			flip_horz_scan_dir,
1416 			recout_clip_in_recout_dst.x,
1417 			data->recout.width,
1418 			src.width,
1419 			data->taps.h_taps,
1420 			data->ratios.horz,
1421 			&data->inits.h,
1422 			&data->viewport.x,
1423 			&data->viewport.width);
1424 	calculate_init_and_vp(
1425 			flip_horz_scan_dir,
1426 			recout_clip_in_recout_dst.x,
1427 			data->recout.width,
1428 			src.width / vpc_div,
1429 			data->taps.h_taps_c,
1430 			data->ratios.horz_c,
1431 			&data->inits.h_c,
1432 			&data->viewport_c.x,
1433 			&data->viewport_c.width);
1434 	calculate_init_and_vp(
1435 			flip_vert_scan_dir,
1436 			recout_clip_in_recout_dst.y,
1437 			data->recout.height,
1438 			src.height,
1439 			data->taps.v_taps,
1440 			data->ratios.vert,
1441 			&data->inits.v,
1442 			&data->viewport.y,
1443 			&data->viewport.height);
1444 	calculate_init_and_vp(
1445 			flip_vert_scan_dir,
1446 			recout_clip_in_recout_dst.y,
1447 			data->recout.height,
1448 			src.height / vpc_div,
1449 			data->taps.v_taps_c,
1450 			data->ratios.vert_c,
1451 			&data->inits.v_c,
1452 			&data->viewport_c.y,
1453 			&data->viewport_c.height);
1454 	if (orthogonal_rotation) {
1455 		swap(data->viewport.x, data->viewport.y);
1456 		swap(data->viewport.width, data->viewport.height);
1457 		swap(data->viewport_c.x, data->viewport_c.y);
1458 		swap(data->viewport_c.width, data->viewport_c.height);
1459 	}
1460 	data->viewport.x += src.x;
1461 	data->viewport.y += src.y;
1462 	ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0);
1463 	data->viewport_c.x += src.x / vpc_div;
1464 	data->viewport_c.y += src.y / vpc_div;
1465 }
1466 
1467 static enum controller_dp_test_pattern convert_dp_to_controller_test_pattern(
1468 				enum dp_test_pattern test_pattern)
1469 {
1470 	enum controller_dp_test_pattern controller_test_pattern;
1471 
1472 	switch (test_pattern) {
1473 	case DP_TEST_PATTERN_COLOR_SQUARES:
1474 		controller_test_pattern =
1475 				CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
1476 	break;
1477 	case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
1478 		controller_test_pattern =
1479 				CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA;
1480 	break;
1481 	case DP_TEST_PATTERN_VERTICAL_BARS:
1482 		controller_test_pattern =
1483 				CONTROLLER_DP_TEST_PATTERN_VERTICALBARS;
1484 	break;
1485 	case DP_TEST_PATTERN_HORIZONTAL_BARS:
1486 		controller_test_pattern =
1487 				CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS;
1488 	break;
1489 	case DP_TEST_PATTERN_COLOR_RAMP:
1490 		controller_test_pattern =
1491 				CONTROLLER_DP_TEST_PATTERN_COLORRAMP;
1492 	break;
1493 	default:
1494 		controller_test_pattern =
1495 				CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
1496 	break;
1497 	}
1498 
1499 	return controller_test_pattern;
1500 }
1501 
1502 static enum controller_dp_color_space convert_dp_to_controller_color_space(
1503 		enum dp_test_pattern_color_space color_space)
1504 {
1505 	enum controller_dp_color_space controller_color_space;
1506 
1507 	switch (color_space) {
1508 	case DP_TEST_PATTERN_COLOR_SPACE_RGB:
1509 		controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
1510 		break;
1511 	case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
1512 		controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601;
1513 		break;
1514 	case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
1515 		controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709;
1516 		break;
1517 	case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED:
1518 	default:
1519 		controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
1520 		break;
1521 	}
1522 
1523 	return controller_color_space;
1524 }
1525 
1526 void resource_build_test_pattern_params(struct resource_context *res_ctx,
1527 				struct pipe_ctx *otg_master)
1528 {
1529 	struct pipe_ctx *opp_heads[MAX_PIPES];
1530 	struct test_pattern_params *params;
1531 	int odm_cnt;
1532 	enum controller_dp_test_pattern controller_test_pattern;
1533 	enum controller_dp_color_space controller_color_space;
1534 	enum dc_color_depth color_depth = otg_master->stream->timing.display_color_depth;
1535 	struct rect odm_slice_src;
1536 	int i;
1537 
1538 	controller_test_pattern = convert_dp_to_controller_test_pattern(
1539 			otg_master->stream->test_pattern.type);
1540 	controller_color_space = convert_dp_to_controller_color_space(
1541 			otg_master->stream->test_pattern.color_space);
1542 
1543 	if (controller_test_pattern == CONTROLLER_DP_TEST_PATTERN_VIDEOMODE)
1544 		return;
1545 
1546 	odm_cnt = resource_get_opp_heads_for_otg_master(otg_master, res_ctx, opp_heads);
1547 
1548 	for (i = 0; i < odm_cnt; i++) {
1549 		odm_slice_src = resource_get_odm_slice_src_rect(opp_heads[i]);
1550 		params = &opp_heads[i]->stream_res.test_pattern_params;
1551 		params->test_pattern = controller_test_pattern;
1552 		params->color_space = controller_color_space;
1553 		params->color_depth = color_depth;
1554 		params->height = odm_slice_src.height;
1555 		params->offset = odm_slice_src.x;
1556 		params->width = odm_slice_src.width;
1557 	}
1558 }
1559 
1560 enum upsp_mode resource_is_upsp_required(enum surface_pixel_format format,
1561 		enum dc_scaling_linearity scaling_linearity)
1562 {
1563 	bool scaling_in_linear = (scaling_linearity == DC_SCALING_LINEARITY_LINEAR);
1564 	bool is_420_format = (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN &&
1565 			format <= SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb);
1566 	bool is_422_format = (format > SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb &&
1567 			format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END);
1568 
1569 	/* UPSP (chroma upsampling) is only needed when subsampled YUV is scaled in
1570 	 * linear space.
1571 	 */
1572 	if (scaling_in_linear && is_420_format)
1573 		return UPSP_HORIZONTAL_VERTICAL_UPSAMPLING;
1574 	if (scaling_in_linear && is_422_format)
1575 		return UPSP_HORIZONTAL_UPSAMPLING_ONLY;
1576 	return UPSP_BYPASS;
1577 }
1578 
1579 bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
1580 {
1581 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1582 	struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
1583 	const struct rect odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx);
1584 	struct scaling_taps temp = {0};
1585 	bool res = false;
1586 
1587 	DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
1588 
1589 	/* Invalid input */
1590 	if (!plane_state ||
1591 			!plane_state->dst_rect.width ||
1592 			!plane_state->dst_rect.height ||
1593 			!plane_state->src_rect.width ||
1594 			!plane_state->src_rect.height) {
1595 		ASSERT(0);
1596 		return false;
1597 	}
1598 
1599 	/* Timing borders are part of vactive that we are also supposed to skip in addition
1600 	 * to any stream dst offset. Since dm logic assumes dst is in addressable
1601 	 * space we need to add the left and top borders to dst offsets temporarily.
1602 	 * TODO: fix in DM, stream dst is supposed to be in vactive
1603 	 */
1604 	pipe_ctx->stream->dst.x += timing->h_border_left;
1605 	pipe_ctx->stream->dst.y += timing->v_border_top;
1606 
1607 	/* Calculate H and V active size */
1608 	pipe_ctx->plane_res.scl_data.h_active = odm_slice_src.width;
1609 	pipe_ctx->plane_res.scl_data.v_active = odm_slice_src.height;
1610 	pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
1611 			pipe_ctx->plane_state->format);
1612 
1613 #if defined(CONFIG_DRM_AMD_DC_FP)
1614 	if ((pipe_ctx->stream->ctx->dc->config.use_spl)	&& (!pipe_ctx->stream->ctx->dc->debug.disable_spl)) {
1615 		struct spl_in *spl_in = &pipe_ctx->plane_res.spl_in;
1616 		struct spl_out *spl_out = &pipe_ctx->plane_res.spl_out;
1617 
1618 		if (plane_state->ctx->dce_version > DCE_VERSION_MAX)
1619 			pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
1620 		else
1621 			pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1622 
1623 		pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
1624 		pipe_ctx->plane_res.scl_data.upsp = resource_is_upsp_required(plane_state->format, plane_state->scaling_linearity);
1625 
1626 		// Convert pipe_ctx to respective input params for SPL
1627 		translate_SPL_in_params_from_pipe_ctx(pipe_ctx, spl_in);
1628 		/* Pass visual confirm debug information */
1629 		calculate_adjust_recout_for_visual_confirm(pipe_ctx,
1630 			&spl_in->debug.visual_confirm_base_offset,
1631 			&spl_in->debug.visual_confirm_dpp_offset);
1632 		// Set SPL output parameters to dscl_prog_data to be used for hw registers
1633 		spl_out->dscl_prog_data = resource_get_dscl_prog_data(pipe_ctx);
1634 		// Calculate scaler parameters from SPL
1635 		res = spl_calculate_scaler_params(spl_in, spl_out);
1636 		// Convert respective out params from SPL to scaler data
1637 		translate_SPL_out_params_to_pipe_ctx(pipe_ctx, spl_out);
1638 
1639 		/* Ignore scaler failure if pipe context plane is phantom plane */
1640 		if (!res && plane_state->is_phantom)
1641 			res = true;
1642 	} else {
1643 #endif
1644 	/* depends on h_active */
1645 	calculate_recout(pipe_ctx);
1646 	/* depends on pixel format */
1647 	calculate_scaling_ratios(pipe_ctx);
1648 
1649 	/*
1650 	 * LB calculations depend on vp size, h/v_active and scaling ratios
1651 	 * Setting line buffer pixel depth to 24bpp yields banding
1652 	 * on certain displays, such as the Sharp 4k. 36bpp is needed
1653 	 * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and
1654 	 * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc
1655 	 * precision on DCN display engines, but apparently not for DCE, as
1656 	 * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have
1657 	 * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
1658 	 * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel
1659 	 * passthrough). Therefore only use 36 bpp on DCN where it is actually needed.
1660 	 */
1661 	if (plane_state->ctx->dce_version > DCE_VERSION_MAX)
1662 		pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
1663 	else
1664 		pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1665 
1666 	pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
1667 
1668 	// get TAP value with 100x100 dummy data for max scaling qualify, override
1669 	// if a new scaling quality required
1670 	pipe_ctx->plane_res.scl_data.viewport.width = 100;
1671 	pipe_ctx->plane_res.scl_data.viewport.height = 100;
1672 	pipe_ctx->plane_res.scl_data.viewport_c.width = 100;
1673 	pipe_ctx->plane_res.scl_data.viewport_c.height = 100;
1674 	if (pipe_ctx->plane_res.xfm != NULL)
1675 		res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1676 				pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1677 
1678 	if (pipe_ctx->plane_res.dpp != NULL)
1679 		res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1680 				pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1681 
1682 	temp = pipe_ctx->plane_res.scl_data.taps;
1683 
1684 	calculate_inits_and_viewports(pipe_ctx);
1685 
1686 	if (pipe_ctx->plane_res.xfm != NULL)
1687 		res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1688 				pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1689 
1690 	if (pipe_ctx->plane_res.dpp != NULL)
1691 		res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1692 				pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1693 
1694 
1695 	if (!res) {
1696 		/* Try 24 bpp linebuffer */
1697 		pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP;
1698 
1699 		if (pipe_ctx->plane_res.xfm != NULL)
1700 			res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1701 					pipe_ctx->plane_res.xfm,
1702 					&pipe_ctx->plane_res.scl_data,
1703 					&plane_state->scaling_quality);
1704 
1705 		if (pipe_ctx->plane_res.dpp != NULL)
1706 			res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1707 					pipe_ctx->plane_res.dpp,
1708 					&pipe_ctx->plane_res.scl_data,
1709 					&plane_state->scaling_quality);
1710 	}
1711 
1712 	/* Ignore scaler failure if pipe context plane is phantom plane */
1713 	if (!res && plane_state->is_phantom)
1714 		res = true;
1715 
1716 	if (res && (pipe_ctx->plane_res.scl_data.taps.v_taps != temp.v_taps ||
1717 		pipe_ctx->plane_res.scl_data.taps.h_taps != temp.h_taps ||
1718 		pipe_ctx->plane_res.scl_data.taps.v_taps_c != temp.v_taps_c ||
1719 		pipe_ctx->plane_res.scl_data.taps.h_taps_c != temp.h_taps_c))
1720 		calculate_inits_and_viewports(pipe_ctx);
1721 
1722 	/*
1723 	 * Handle side by side and top bottom 3d recout offsets after vp calculation
1724 	 * since 3d is special and needs to calculate vp as if there is no recout offset
1725 	 * This may break with rotation, good thing we aren't mixing hw rotation and 3d
1726 	 */
1727 	if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) {
1728 		ASSERT(plane_state->rotation == ROTATION_ANGLE_0 ||
1729 			(pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM &&
1730 				pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE));
1731 		if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
1732 			pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height;
1733 		else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
1734 			pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width;
1735 	}
1736 
1737 	/* Clamp minimum viewport size */
1738 	if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE)
1739 		pipe_ctx->plane_res.scl_data.viewport.height = MIN_VIEWPORT_SIZE;
1740 	if (pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE)
1741 		pipe_ctx->plane_res.scl_data.viewport.width = MIN_VIEWPORT_SIZE;
1742 #ifdef CONFIG_DRM_AMD_DC_FP
1743 	}
1744 #endif
1745 	DC_LOG_SCALER("%s pipe %d:\nViewport: height:%d width:%d x:%d y:%d  Recout: height:%d width:%d x:%d y:%d  HACTIVE:%d VACTIVE:%d\n"
1746 			"src_rect: height:%d width:%d x:%d y:%d  dst_rect: height:%d width:%d x:%d y:%d  clip_rect: height:%d width:%d x:%d y:%d\n",
1747 			__func__,
1748 			pipe_ctx->pipe_idx,
1749 			pipe_ctx->plane_res.scl_data.viewport.height,
1750 			pipe_ctx->plane_res.scl_data.viewport.width,
1751 			pipe_ctx->plane_res.scl_data.viewport.x,
1752 			pipe_ctx->plane_res.scl_data.viewport.y,
1753 			pipe_ctx->plane_res.scl_data.recout.height,
1754 			pipe_ctx->plane_res.scl_data.recout.width,
1755 			pipe_ctx->plane_res.scl_data.recout.x,
1756 			pipe_ctx->plane_res.scl_data.recout.y,
1757 			pipe_ctx->plane_res.scl_data.h_active,
1758 			pipe_ctx->plane_res.scl_data.v_active,
1759 			plane_state->src_rect.height,
1760 			plane_state->src_rect.width,
1761 			plane_state->src_rect.x,
1762 			plane_state->src_rect.y,
1763 			plane_state->dst_rect.height,
1764 			plane_state->dst_rect.width,
1765 			plane_state->dst_rect.x,
1766 			plane_state->dst_rect.y,
1767 			plane_state->clip_rect.height,
1768 			plane_state->clip_rect.width,
1769 			plane_state->clip_rect.x,
1770 			plane_state->clip_rect.y);
1771 
1772 	pipe_ctx->stream->dst.x -= timing->h_border_left;
1773 	pipe_ctx->stream->dst.y -= timing->v_border_top;
1774 
1775 	return res;
1776 }
1777 
1778 bool resource_can_pipe_disable_cursor(const struct pipe_ctx *pipe_ctx)
1779 {
1780 	struct pipe_ctx *test_pipe, *split_pipe;
1781 	struct rect r1 = pipe_ctx->plane_res.scl_data.recout;
1782 	int r1_right, r1_bottom;
1783 	unsigned int cur_layer = pipe_ctx->plane_state->layer_index;
1784 
1785 	reverse_adjust_recout_for_visual_confirm(&r1, pipe_ctx);
1786 	r1_right = r1.x + r1.width;
1787 	r1_bottom = r1.y + r1.height;
1788 
1789 	/**
1790 	 * Disable the cursor if there's another pipe above this with a
1791 	 * plane that contains this pipe's viewport to prevent double cursor
1792 	 * and incorrect scaling artifacts.
1793 	 */
1794 	for (test_pipe = pipe_ctx->top_pipe; test_pipe;
1795 	     test_pipe = test_pipe->top_pipe) {
1796 		struct rect r2;
1797 		int r2_right, r2_bottom;
1798 		// Skip invisible layer and pipe-split plane on same layer
1799 		if (!test_pipe->plane_state ||
1800 		    !test_pipe->plane_state->visible ||
1801 		    test_pipe->plane_state->layer_index == cur_layer)
1802 			continue;
1803 
1804 		r2 = test_pipe->plane_res.scl_data.recout;
1805 		reverse_adjust_recout_for_visual_confirm(&r2, test_pipe);
1806 		r2_right = r2.x + r2.width;
1807 		r2_bottom = r2.y + r2.height;
1808 
1809 		/**
1810 		 * There is another half plane on same layer because of
1811 		 * pipe-split, merge together per same height.
1812 		 */
1813 		for (split_pipe = pipe_ctx->top_pipe; split_pipe;
1814 		     split_pipe = split_pipe->top_pipe) {
1815 
1816 			if (split_pipe == test_pipe)
1817 				continue;
1818 
1819 			if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) {
1820 				struct rect r2_half;
1821 
1822 				r2_half = split_pipe->plane_res.scl_data.recout;
1823 				reverse_adjust_recout_for_visual_confirm(&r2_half, split_pipe);
1824 				r2.x = min(r2_half.x, r2.x);
1825 				r2.width = r2.width + r2_half.width;
1826 				r2_right = r2.x + r2.width;
1827 				r2_bottom = min(r2_bottom, r2_half.y + r2_half.height);
1828 				break;
1829 			}
1830 		}
1831 
1832 		if (r1.x >= r2.x && r1.y >= r2.y && r1_right <= r2_right && r1_bottom <= r2_bottom)
1833 			return true;
1834 	}
1835 
1836 	return false;
1837 }
1838 
1839 
1840 enum dc_status resource_build_scaling_params_for_context(
1841 	const struct dc  *dc,
1842 	struct dc_state *context)
1843 {
1844 	(void)dc;
1845 	int i;
1846 
1847 	for (i = 0; i < MAX_PIPES; i++) {
1848 		if (context->res_ctx.pipe_ctx[i].plane_state != NULL &&
1849 				context->res_ctx.pipe_ctx[i].stream != NULL)
1850 			if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i]))
1851 				return DC_FAIL_SCALING;
1852 	}
1853 
1854 	return DC_OK;
1855 }
1856 
1857 struct pipe_ctx *resource_find_free_secondary_pipe_legacy(
1858 		struct resource_context *res_ctx,
1859 		const struct resource_pool *pool,
1860 		const struct pipe_ctx *primary_pipe)
1861 {
1862 	int i;
1863 	struct pipe_ctx *secondary_pipe = NULL;
1864 
1865 	/*
1866 	 * We add a preferred pipe mapping to avoid the chance that
1867 	 * MPCCs already in use will need to be reassigned to other trees.
1868 	 * For example, if we went with the strict, assign backwards logic:
1869 	 *
1870 	 * (State 1)
1871 	 * Display A on, no surface, top pipe = 0
1872 	 * Display B on, no surface, top pipe = 1
1873 	 *
1874 	 * (State 2)
1875 	 * Display A on, no surface, top pipe = 0
1876 	 * Display B on, surface enable, top pipe = 1, bottom pipe = 5
1877 	 *
1878 	 * (State 3)
1879 	 * Display A on, surface enable, top pipe = 0, bottom pipe = 5
1880 	 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1881 	 *
1882 	 * The state 2->3 transition requires remapping MPCC 5 from display B
1883 	 * to display A.
1884 	 *
1885 	 * However, with the preferred pipe logic, state 2 would look like:
1886 	 *
1887 	 * (State 2)
1888 	 * Display A on, no surface, top pipe = 0
1889 	 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1890 	 *
1891 	 * This would then cause 2->3 to not require remapping any MPCCs.
1892 	 */
1893 	if (primary_pipe) {
1894 		int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx;
1895 		if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) {
1896 			secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
1897 			secondary_pipe->pipe_idx = (uint8_t)preferred_pipe_idx;
1898 		}
1899 	}
1900 
1901 	/*
1902 	 * search backwards for the second pipe to keep pipe
1903 	 * assignment more consistent
1904 	 */
1905 	if (!secondary_pipe)
1906 		for (i = pool->pipe_count - 1; i >= 0; i--) {
1907 			if (res_ctx->pipe_ctx[i].stream == NULL) {
1908 				secondary_pipe = &res_ctx->pipe_ctx[i];
1909 				secondary_pipe->pipe_idx = (uint8_t)i;
1910 				break;
1911 			}
1912 		}
1913 
1914 	return secondary_pipe;
1915 }
1916 
1917 int resource_find_free_pipe_used_as_sec_opp_head_by_cur_otg_master(
1918 		const struct resource_context *cur_res_ctx,
1919 		struct resource_context *new_res_ctx,
1920 		const struct pipe_ctx *cur_otg_master)
1921 {
1922 	(void)cur_res_ctx;
1923 	const struct pipe_ctx *cur_sec_opp_head = cur_otg_master->next_odm_pipe;
1924 	struct pipe_ctx *new_pipe;
1925 	int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1926 
1927 	while (cur_sec_opp_head) {
1928 		new_pipe = &new_res_ctx->pipe_ctx[cur_sec_opp_head->pipe_idx];
1929 		if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1930 			free_pipe_idx = cur_sec_opp_head->pipe_idx;
1931 			break;
1932 		}
1933 		cur_sec_opp_head = cur_sec_opp_head->next_odm_pipe;
1934 	}
1935 
1936 	return free_pipe_idx;
1937 }
1938 
1939 int resource_find_free_pipe_used_in_cur_mpc_blending_tree(
1940 		const struct resource_context *cur_res_ctx,
1941 		struct resource_context *new_res_ctx,
1942 		const struct pipe_ctx *cur_opp_head)
1943 {
1944 	(void)cur_res_ctx;
1945 	const struct pipe_ctx *cur_sec_dpp = cur_opp_head->bottom_pipe;
1946 	struct pipe_ctx *new_pipe;
1947 	int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1948 
1949 	while (cur_sec_dpp) {
1950 		/* find a free pipe used in current opp blend tree,
1951 		 * this is to avoid MPO pipe switching to different opp blending
1952 		 * tree
1953 		 */
1954 		new_pipe = &new_res_ctx->pipe_ctx[cur_sec_dpp->pipe_idx];
1955 		if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1956 			free_pipe_idx = cur_sec_dpp->pipe_idx;
1957 			break;
1958 		}
1959 		cur_sec_dpp = cur_sec_dpp->bottom_pipe;
1960 	}
1961 
1962 	return free_pipe_idx;
1963 }
1964 
1965 int recource_find_free_pipe_not_used_in_cur_res_ctx(
1966 		const struct resource_context *cur_res_ctx,
1967 		struct resource_context *new_res_ctx,
1968 		const struct resource_pool *pool)
1969 {
1970 	int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1971 	const struct pipe_ctx *new_pipe, *cur_pipe;
1972 	unsigned int i;
1973 
1974 	for (i = 0; i < pool->pipe_count; i++) {
1975 		cur_pipe = &cur_res_ctx->pipe_ctx[i];
1976 		new_pipe = &new_res_ctx->pipe_ctx[i];
1977 
1978 		if (resource_is_pipe_type(cur_pipe, FREE_PIPE) &&
1979 				resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1980 			free_pipe_idx = i;
1981 			break;
1982 		}
1983 	}
1984 
1985 	return free_pipe_idx;
1986 }
1987 
1988 int recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx(
1989 		const struct resource_context *cur_res_ctx,
1990 		struct resource_context *new_res_ctx,
1991 		const struct resource_pool *pool)
1992 {
1993 	int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1994 	const struct pipe_ctx *new_pipe, *cur_pipe;
1995 	unsigned int i;
1996 
1997 	for (i = 0; i < pool->pipe_count; i++) {
1998 		cur_pipe = &cur_res_ctx->pipe_ctx[i];
1999 		new_pipe = &new_res_ctx->pipe_ctx[i];
2000 
2001 		if (resource_is_pipe_type(cur_pipe, OTG_MASTER) &&
2002 				resource_is_pipe_type(new_pipe, FREE_PIPE)) {
2003 			free_pipe_idx = i;
2004 			break;
2005 		}
2006 	}
2007 
2008 	return free_pipe_idx;
2009 }
2010 
2011 int resource_find_free_pipe_used_as_cur_sec_dpp(
2012 		const struct resource_context *cur_res_ctx,
2013 		struct resource_context *new_res_ctx,
2014 		const struct resource_pool *pool)
2015 {
2016 	int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
2017 	const struct pipe_ctx *new_pipe, *cur_pipe;
2018 	unsigned int i;
2019 
2020 	for (i = 0; i < pool->pipe_count; i++) {
2021 		cur_pipe = &cur_res_ctx->pipe_ctx[i];
2022 		new_pipe = &new_res_ctx->pipe_ctx[i];
2023 
2024 		if (resource_is_pipe_type(cur_pipe, DPP_PIPE) &&
2025 				!resource_is_pipe_type(cur_pipe, OPP_HEAD) &&
2026 				resource_is_pipe_type(new_pipe, FREE_PIPE)) {
2027 			free_pipe_idx = i;
2028 			break;
2029 		}
2030 	}
2031 
2032 	return free_pipe_idx;
2033 }
2034 
2035 int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine(
2036 		const struct resource_context *cur_res_ctx,
2037 		struct resource_context *new_res_ctx,
2038 		const struct resource_pool *pool)
2039 {
2040 	int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
2041 	const struct pipe_ctx *new_pipe, *cur_pipe;
2042 	unsigned int i;
2043 
2044 	for (i = 0; i < pool->pipe_count; i++) {
2045 		cur_pipe = &cur_res_ctx->pipe_ctx[i];
2046 		new_pipe = &new_res_ctx->pipe_ctx[i];
2047 
2048 		if (resource_is_pipe_type(cur_pipe, DPP_PIPE) &&
2049 				!resource_is_pipe_type(cur_pipe, OPP_HEAD) &&
2050 				resource_get_mpc_slice_index(cur_pipe) > 0 &&
2051 				resource_is_pipe_type(new_pipe, FREE_PIPE)) {
2052 			free_pipe_idx = i;
2053 			break;
2054 		}
2055 	}
2056 
2057 	return free_pipe_idx;
2058 }
2059 
2060 int resource_find_any_free_pipe(struct resource_context *new_res_ctx,
2061 		const struct resource_pool *pool)
2062 {
2063 	int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
2064 	const struct pipe_ctx *new_pipe;
2065 	unsigned int i;
2066 
2067 	for (i = 0; i < pool->pipe_count; i++) {
2068 		new_pipe = &new_res_ctx->pipe_ctx[i];
2069 
2070 		if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
2071 			free_pipe_idx = i;
2072 			break;
2073 		}
2074 	}
2075 
2076 	return free_pipe_idx;
2077 }
2078 
2079 bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type)
2080 {
2081 	switch (type) {
2082 	case OTG_MASTER:
2083 		return !pipe_ctx->prev_odm_pipe &&
2084 				!pipe_ctx->top_pipe &&
2085 				pipe_ctx->stream;
2086 	case OPP_HEAD:
2087 		return !pipe_ctx->top_pipe && pipe_ctx->stream;
2088 	case DPP_PIPE:
2089 		return pipe_ctx->plane_state && pipe_ctx->stream;
2090 	case FREE_PIPE:
2091 		return !pipe_ctx->plane_state && !pipe_ctx->stream;
2092 	default:
2093 		return false;
2094 	}
2095 }
2096 
2097 struct pipe_ctx *resource_get_otg_master_for_stream(
2098 		struct resource_context *res_ctx,
2099 		const struct dc_stream_state *stream)
2100 {
2101 	int i;
2102 
2103 	for (i = 0; i < MAX_PIPES; i++) {
2104 		if (res_ctx->pipe_ctx[i].stream == stream &&
2105 				resource_is_pipe_type(&res_ctx->pipe_ctx[i], OTG_MASTER))
2106 			return &res_ctx->pipe_ctx[i];
2107 	}
2108 	return NULL;
2109 }
2110 
2111 int resource_get_opp_heads_for_otg_master(const struct pipe_ctx *otg_master,
2112 		struct resource_context *res_ctx,
2113 		struct pipe_ctx *opp_heads[MAX_PIPES])
2114 {
2115 	struct pipe_ctx *opp_head = &res_ctx->pipe_ctx[otg_master->pipe_idx];
2116 	struct dc *dc = otg_master->stream->ctx->dc;
2117 	int i = 0;
2118 
2119 	DC_LOGGER_INIT(dc->ctx->logger);
2120 
2121 	if (!resource_is_pipe_type(otg_master, OTG_MASTER)) {
2122 		DC_LOG_WARNING("%s called from a non OTG master, something "
2123 			       "is wrong in the pipe configuration",
2124 			       __func__);
2125 		ASSERT(0);
2126 		return 0;
2127 	}
2128 	while (opp_head) {
2129 		ASSERT(i < MAX_PIPES);
2130 		opp_heads[i++] = opp_head;
2131 		opp_head = opp_head->next_odm_pipe;
2132 	}
2133 	return i;
2134 }
2135 
2136 int resource_get_dpp_pipes_for_opp_head(const struct pipe_ctx *opp_head,
2137 		struct resource_context *res_ctx,
2138 		struct pipe_ctx *dpp_pipes[MAX_PIPES])
2139 {
2140 	struct pipe_ctx *pipe = &res_ctx->pipe_ctx[opp_head->pipe_idx];
2141 	int i = 0;
2142 
2143 	if (!resource_is_pipe_type(opp_head, OPP_HEAD)) {
2144 		ASSERT(0);
2145 		return 0;
2146 	}
2147 	while (pipe && resource_is_pipe_type(pipe, DPP_PIPE)) {
2148 		ASSERT(i < MAX_PIPES);
2149 		dpp_pipes[i++] = pipe;
2150 		pipe = pipe->bottom_pipe;
2151 	}
2152 	return i;
2153 }
2154 
2155 int resource_get_dpp_pipes_for_plane(const struct dc_plane_state *plane,
2156 		struct resource_context *res_ctx,
2157 		struct pipe_ctx *dpp_pipes[MAX_PIPES])
2158 {
2159 	int i = 0, j;
2160 	struct pipe_ctx *pipe;
2161 
2162 	for (j = 0; j < MAX_PIPES; j++) {
2163 		pipe = &res_ctx->pipe_ctx[j];
2164 		if (pipe->plane_state == plane && pipe->prev_odm_pipe == NULL) {
2165 			if (resource_is_pipe_type(pipe, OPP_HEAD) ||
2166 					pipe->top_pipe->plane_state != plane)
2167 				break;
2168 		}
2169 	}
2170 
2171 	if (j < MAX_PIPES) {
2172 		if (pipe->next_odm_pipe)
2173 			while (pipe) {
2174 				dpp_pipes[i++] = pipe;
2175 				pipe = pipe->next_odm_pipe;
2176 			}
2177 		else
2178 			while (pipe && pipe->plane_state == plane) {
2179 				dpp_pipes[i++] = pipe;
2180 				pipe = pipe->bottom_pipe;
2181 			}
2182 	}
2183 	return i;
2184 }
2185 
2186 struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx)
2187 {
2188 	struct pipe_ctx *otg_master = resource_get_opp_head(pipe_ctx);
2189 
2190 	while (otg_master->prev_odm_pipe)
2191 		otg_master = otg_master->prev_odm_pipe;
2192 	return otg_master;
2193 }
2194 
2195 struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx)
2196 {
2197 	struct pipe_ctx *opp_head = (struct pipe_ctx *) pipe_ctx;
2198 
2199 	ASSERT(!resource_is_pipe_type(opp_head, FREE_PIPE));
2200 	while (opp_head->top_pipe)
2201 		opp_head = opp_head->top_pipe;
2202 	return opp_head;
2203 }
2204 
2205 struct pipe_ctx *resource_get_primary_dpp_pipe(const struct pipe_ctx *dpp_pipe)
2206 {
2207 	struct pipe_ctx *pri_dpp_pipe = (struct pipe_ctx *) dpp_pipe;
2208 
2209 	ASSERT(resource_is_pipe_type(dpp_pipe, DPP_PIPE));
2210 	while (pri_dpp_pipe->prev_odm_pipe)
2211 		pri_dpp_pipe = pri_dpp_pipe->prev_odm_pipe;
2212 	while (pri_dpp_pipe->top_pipe &&
2213 			pri_dpp_pipe->top_pipe->plane_state == pri_dpp_pipe->plane_state)
2214 		pri_dpp_pipe = pri_dpp_pipe->top_pipe;
2215 	return pri_dpp_pipe;
2216 }
2217 
2218 
2219 int resource_get_mpc_slice_index(const struct pipe_ctx *pipe_ctx)
2220 {
2221 	struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
2222 	int index = 0;
2223 
2224 	while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
2225 		index++;
2226 		split_pipe = split_pipe->top_pipe;
2227 	}
2228 
2229 	return index;
2230 }
2231 
2232 int resource_get_mpc_slice_count(const struct pipe_ctx *pipe)
2233 {
2234 	int mpc_split_count = 1;
2235 	const struct pipe_ctx *other_pipe = pipe->bottom_pipe;
2236 
2237 	while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
2238 		mpc_split_count++;
2239 		other_pipe = other_pipe->bottom_pipe;
2240 	}
2241 	other_pipe = pipe->top_pipe;
2242 	while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
2243 		mpc_split_count++;
2244 		other_pipe = other_pipe->top_pipe;
2245 	}
2246 
2247 	return mpc_split_count;
2248 }
2249 
2250 int resource_get_odm_slice_count(const struct pipe_ctx *pipe)
2251 {
2252 	int odm_split_count = 1;
2253 
2254 	pipe = resource_get_otg_master(pipe);
2255 
2256 	while (pipe->next_odm_pipe) {
2257 		odm_split_count++;
2258 		pipe = pipe->next_odm_pipe;
2259 	}
2260 	return odm_split_count;
2261 }
2262 
2263 int resource_get_odm_slice_index(const struct pipe_ctx *pipe_ctx)
2264 {
2265 	int index = 0;
2266 
2267 	pipe_ctx = resource_get_opp_head(pipe_ctx);
2268 	if (!pipe_ctx)
2269 		return 0;
2270 
2271 	while (pipe_ctx->prev_odm_pipe) {
2272 		index++;
2273 		pipe_ctx = pipe_ctx->prev_odm_pipe;
2274 	}
2275 
2276 	return index;
2277 }
2278 
2279 int resource_get_odm_slice_dst_width(struct pipe_ctx *otg_master,
2280 		bool is_last_segment)
2281 {
2282 	const struct dc_crtc_timing *timing;
2283 	int count;
2284 	int h_active;
2285 	int width;
2286 	bool two_pixel_alignment_required = false;
2287 
2288 	if (!otg_master || !otg_master->stream)
2289 		return 0;
2290 
2291 	timing = &otg_master->stream->timing;
2292 	count = resource_get_odm_slice_count(otg_master);
2293 	h_active = timing->h_addressable +
2294 			timing->h_border_left +
2295 			timing->h_border_right +
2296 			otg_master->dsc_padding_params.dsc_hactive_padding;
2297 	width = h_active / count;
2298 
2299 	if (otg_master->stream_res.tg)
2300 		two_pixel_alignment_required =
2301 				otg_master->stream_res.tg->funcs->is_two_pixels_per_container(timing) ||
2302 				/*
2303 				 * 422 is sub-sampled horizontally. 1 set of chromas
2304 				 * (Cb/Cr) is shared for 2 lumas (i.e 2 Y values).
2305 				 * Therefore even if 422 is still 1 pixel per container,
2306 				 * ODM segment width still needs to be 2 pixel aligned.
2307 				 */
2308 				timing->pixel_encoding == PIXEL_ENCODING_YCBCR422;
2309 	if ((width % 2) && two_pixel_alignment_required)
2310 		width++;
2311 
2312 	return is_last_segment ?
2313 			h_active - width * (count - 1) :
2314 			width;
2315 }
2316 
2317 struct rect resource_get_odm_slice_dst_rect(struct pipe_ctx *pipe_ctx)
2318 {
2319 	const struct dc_stream_state *stream = pipe_ctx->stream;
2320 	bool is_last_odm_slice = pipe_ctx->next_odm_pipe == NULL;
2321 	struct pipe_ctx *otg_master = resource_get_otg_master(pipe_ctx);
2322 	int odm_slice_idx = resource_get_odm_slice_index(pipe_ctx);
2323 	int odm_segment_offset = resource_get_odm_slice_dst_width(otg_master, false);
2324 	struct rect odm_slice_dst;
2325 
2326 	odm_slice_dst.x = odm_segment_offset * odm_slice_idx;
2327 	odm_slice_dst.width = resource_get_odm_slice_dst_width(otg_master, is_last_odm_slice);
2328 	odm_slice_dst.y = 0;
2329 	odm_slice_dst.height = stream->timing.v_addressable +
2330 			stream->timing.v_border_bottom +
2331 			stream->timing.v_border_top;
2332 
2333 	return odm_slice_dst;
2334 }
2335 
2336 struct rect resource_get_odm_slice_src_rect(struct pipe_ctx *pipe_ctx)
2337 {
2338 	struct rect odm_slice_dst;
2339 	struct rect odm_slice_src;
2340 	struct pipe_ctx *opp_head = resource_get_opp_head(pipe_ctx);
2341 	struct output_pixel_processor *opp = opp_head->stream_res.opp;
2342 	uint32_t left_edge_extra_pixel_count;
2343 
2344 	odm_slice_dst = resource_get_odm_slice_dst_rect(opp_head);
2345 	odm_slice_src = odm_slice_dst;
2346 
2347 	if (opp && opp->funcs->opp_get_left_edge_extra_pixel_count)
2348 		left_edge_extra_pixel_count =
2349 				opp->funcs->opp_get_left_edge_extra_pixel_count(
2350 						opp, pipe_ctx->stream->timing.pixel_encoding,
2351 						resource_is_pipe_type(opp_head, OTG_MASTER));
2352 	else
2353 		left_edge_extra_pixel_count = 0;
2354 
2355 	odm_slice_src.x -= left_edge_extra_pixel_count;
2356 	odm_slice_src.width += left_edge_extra_pixel_count;
2357 
2358 	return odm_slice_src;
2359 }
2360 
2361 bool resource_is_pipe_topology_changed(const struct dc_state *state_a,
2362 		const struct dc_state *state_b)
2363 {
2364 	int i;
2365 	const struct pipe_ctx *pipe_a, *pipe_b;
2366 
2367 	if (state_a->stream_count != state_b->stream_count)
2368 		return true;
2369 
2370 	for (i = 0; i < MAX_PIPES; i++) {
2371 		pipe_a = &state_a->res_ctx.pipe_ctx[i];
2372 		pipe_b = &state_b->res_ctx.pipe_ctx[i];
2373 
2374 		if (pipe_a->stream && !pipe_b->stream)
2375 			return true;
2376 		else if (!pipe_a->stream && pipe_b->stream)
2377 			return true;
2378 
2379 		if (pipe_a->plane_state && !pipe_b->plane_state)
2380 			return true;
2381 		else if (!pipe_a->plane_state && pipe_b->plane_state)
2382 			return true;
2383 
2384 		if (pipe_a->bottom_pipe && pipe_b->bottom_pipe) {
2385 			if (pipe_a->bottom_pipe->pipe_idx != pipe_b->bottom_pipe->pipe_idx)
2386 				return true;
2387 			if ((pipe_a->bottom_pipe->plane_state == pipe_a->plane_state) &&
2388 					(pipe_b->bottom_pipe->plane_state != pipe_b->plane_state))
2389 				return true;
2390 			else if ((pipe_a->bottom_pipe->plane_state != pipe_a->plane_state) &&
2391 					(pipe_b->bottom_pipe->plane_state == pipe_b->plane_state))
2392 				return true;
2393 		} else if (pipe_a->bottom_pipe || pipe_b->bottom_pipe) {
2394 			return true;
2395 		}
2396 
2397 		if (pipe_a->next_odm_pipe && pipe_b->next_odm_pipe) {
2398 			if (pipe_a->next_odm_pipe->pipe_idx != pipe_b->next_odm_pipe->pipe_idx)
2399 				return true;
2400 		} else if (pipe_a->next_odm_pipe || pipe_b->next_odm_pipe) {
2401 			return true;
2402 		}
2403 	}
2404 	return false;
2405 }
2406 
2407 bool resource_is_odm_topology_changed(const struct pipe_ctx *otg_master_a,
2408 		const struct pipe_ctx *otg_master_b)
2409 {
2410 	const struct pipe_ctx *opp_head_a = otg_master_a;
2411 	const struct pipe_ctx *opp_head_b = otg_master_b;
2412 
2413 	if (!resource_is_pipe_type(otg_master_a, OTG_MASTER) ||
2414 			!resource_is_pipe_type(otg_master_b, OTG_MASTER))
2415 		return true;
2416 
2417 	while (opp_head_a && opp_head_b) {
2418 		if (opp_head_a->stream_res.opp != opp_head_b->stream_res.opp)
2419 			return true;
2420 		if ((opp_head_a->next_odm_pipe && !opp_head_b->next_odm_pipe) ||
2421 				(!opp_head_a->next_odm_pipe && opp_head_b->next_odm_pipe))
2422 			return true;
2423 		opp_head_a = opp_head_a->next_odm_pipe;
2424 		opp_head_b = opp_head_b->next_odm_pipe;
2425 	}
2426 
2427 	return false;
2428 }
2429 
2430 /*
2431  * Sample log:
2432  *    pipe topology update
2433  *  ________________________
2434  * | plane0  slice0  stream0|
2435  * |DPP0----OPP0----OTG0----| <--- case 0 (OTG master pipe with plane)
2436  * | plane1 |       |       |
2437  * |DPP1----|       |       | <--- case 5 (DPP pipe not in last slice)
2438  * | plane0  slice1 |       |
2439  * |DPP2----OPP2----|       | <--- case 2 (OPP head pipe with plane)
2440  * | plane1 |               |
2441  * |DPP3----|               | <--- case 4 (DPP pipe in last slice)
2442  * |         slice0  stream1|
2443  * |DPG4----OPP4----OTG4----| <--- case 1 (OTG master pipe without plane)
2444  * |         slice1 |       |
2445  * |DPG5----OPP5----|       | <--- case 3 (OPP head pipe without plane)
2446  * |________________________|
2447  */
2448 
2449 static void resource_log_pipe(struct dc *dc, struct pipe_ctx *pipe,
2450 		int stream_idx, int slice_idx, int plane_idx, int slice_count,
2451 		bool is_primary, bool is_phantom_pipe)
2452 {
2453 	DC_LOGGER_INIT(dc->ctx->logger);
2454 
2455 	// new format for logging: bit storing code
2456 	if (slice_idx == 0 && plane_idx == 0 && is_primary) {
2457 		/* case 0 (OTG master pipe with plane) */
2458 		DC_LOG_DC(" | plane%d  slice%d  stream%d|",
2459 				plane_idx, slice_idx, stream_idx);
2460 		DC_LOG_DC(" |DPP%d----OPP%d----OTG%d----|",
2461 				pipe->plane_res.dpp->inst,
2462 				pipe->stream_res.opp->inst,
2463 				pipe->stream_res.tg->inst);
2464 		capture_pipe_topology_data(dc, plane_idx, slice_idx, stream_idx,
2465 				pipe->plane_res.dpp->inst,
2466 				pipe->stream_res.opp->inst,
2467 				pipe->stream_res.tg->inst, is_phantom_pipe);
2468 	} else if (slice_idx == 0 && plane_idx == -1) {
2469 		/* case 1 (OTG master pipe without plane) */
2470 		DC_LOG_DC(" |         slice%d  stream%d|",
2471 				slice_idx, stream_idx);
2472 		DC_LOG_DC(" |DPG%d----OPP%d----OTG%d----|",
2473 				pipe->stream_res.opp->inst,
2474 				pipe->stream_res.opp->inst,
2475 				pipe->stream_res.tg->inst);
2476 		capture_pipe_topology_data(dc, 0xF, slice_idx, stream_idx,
2477 				pipe->plane_res.dpp->inst,
2478 				pipe->stream_res.opp->inst,
2479 				pipe->stream_res.tg->inst, is_phantom_pipe);
2480 	} else if (slice_idx != 0 && plane_idx == 0 && is_primary) {
2481 		/* case 2 (OPP head pipe with plane) */
2482 		DC_LOG_DC(" | plane%d  slice%d |       |",
2483 				plane_idx, slice_idx);
2484 		DC_LOG_DC(" |DPP%d----OPP%d----|       |",
2485 				pipe->plane_res.dpp->inst,
2486 				pipe->stream_res.opp->inst);
2487 		capture_pipe_topology_data(dc, plane_idx, slice_idx, stream_idx,
2488 				pipe->plane_res.dpp->inst,
2489 				pipe->stream_res.opp->inst,
2490 				pipe->stream_res.tg->inst, is_phantom_pipe);
2491 	} else if (slice_idx != 0 && plane_idx == -1) {
2492 		/* case 3 (OPP head pipe without plane) */
2493 		DC_LOG_DC(" |         slice%d |       |", slice_idx);
2494 		DC_LOG_DC(" |DPG%d----OPP%d----|       |",
2495 				pipe->plane_res.dpp->inst,
2496 				pipe->stream_res.opp->inst);
2497 		capture_pipe_topology_data(dc, 0xF, slice_idx, stream_idx,
2498 				pipe->plane_res.dpp->inst,
2499 				pipe->stream_res.opp->inst,
2500 				pipe->stream_res.tg->inst, is_phantom_pipe);
2501 	} else if (slice_idx == slice_count - 1) {
2502 		/* case 4 (DPP pipe in last slice) */
2503 		DC_LOG_DC(" | plane%d |               |", plane_idx);
2504 		DC_LOG_DC(" |DPP%d----|               |",
2505 				pipe->plane_res.dpp->inst);
2506 		capture_pipe_topology_data(dc, plane_idx, slice_idx, stream_idx,
2507 				pipe->plane_res.dpp->inst,
2508 				pipe->stream_res.opp->inst,
2509 				pipe->stream_res.tg->inst, is_phantom_pipe);
2510 	} else {
2511 		/* case 5 (DPP pipe not in last slice) */
2512 		DC_LOG_DC(" | plane%d |       |       |", plane_idx);
2513 		DC_LOG_DC(" |DPP%d----|       |       |",
2514 				pipe->plane_res.dpp->inst);
2515 		capture_pipe_topology_data(dc, plane_idx, slice_idx, stream_idx,
2516 				pipe->plane_res.dpp->inst,
2517 				pipe->stream_res.opp->inst,
2518 				pipe->stream_res.tg->inst, is_phantom_pipe);
2519 	}
2520 }
2521 
2522 static void resource_log_pipe_for_stream(struct dc *dc, struct dc_state *state,
2523 		struct pipe_ctx *otg_master, int stream_idx, bool is_phantom_pipe)
2524 {
2525 	struct pipe_ctx *opp_heads[MAX_PIPES];
2526 	struct pipe_ctx *dpp_pipes[MAX_PIPES];
2527 
2528 	int slice_idx, dpp_idx, plane_idx, slice_count, dpp_count;
2529 	bool is_primary;
2530 
2531 	slice_count = resource_get_opp_heads_for_otg_master(otg_master,
2532 			&state->res_ctx, opp_heads);
2533 	for (slice_idx = 0; slice_idx < slice_count; slice_idx++) {
2534 		plane_idx = -1;
2535 		if (opp_heads[slice_idx]->plane_state) {
2536 			dpp_count = resource_get_dpp_pipes_for_opp_head(
2537 					opp_heads[slice_idx],
2538 					&state->res_ctx,
2539 					dpp_pipes);
2540 			for (dpp_idx = 0; dpp_idx < dpp_count; dpp_idx++) {
2541 				is_primary = !dpp_pipes[dpp_idx]->top_pipe ||
2542 						dpp_pipes[dpp_idx]->top_pipe->plane_state != dpp_pipes[dpp_idx]->plane_state;
2543 				if (is_primary)
2544 					plane_idx++;
2545 				resource_log_pipe(dc, dpp_pipes[dpp_idx],
2546 						stream_idx, slice_idx,
2547 						plane_idx, slice_count,
2548 						is_primary, is_phantom_pipe);
2549 			}
2550 		} else {
2551 			resource_log_pipe(dc, opp_heads[slice_idx],
2552 					stream_idx, slice_idx, plane_idx,
2553 					slice_count, true, is_phantom_pipe);
2554 		}
2555 
2556 	}
2557 }
2558 
2559 static int resource_stream_to_stream_idx(struct dc_state *state,
2560 		struct dc_stream_state *stream)
2561 {
2562 	int i, stream_idx = -1;
2563 
2564 	for (i = 0; i < state->stream_count; i++)
2565 		if (state->streams[i] == stream) {
2566 			stream_idx = i;
2567 			break;
2568 		}
2569 
2570 	/* never return negative array index */
2571 	if (stream_idx == -1) {
2572 		ASSERT(0);
2573 		return 0;
2574 	}
2575 
2576 	return stream_idx;
2577 }
2578 
2579 void resource_log_pipe_topology_update(struct dc *dc, struct dc_state *state)
2580 {
2581 	struct pipe_ctx *otg_master;
2582 	int stream_idx, phantom_stream_idx;
2583 	DC_LOGGER_INIT(dc->ctx->logger);
2584 	bool is_phantom_pipe = false;
2585 
2586 	// Start a new snapshot for this topology update
2587 	start_new_topology_snapshot(dc, state);
2588 
2589 	DC_LOG_DC("    pipe topology update");
2590 	DC_LOG_DC("  ________________________");
2591 	for (stream_idx = 0; stream_idx < state->stream_count; stream_idx++) {
2592 		if (state->streams[stream_idx]->is_phantom)
2593 			continue;
2594 
2595 		otg_master = resource_get_otg_master_for_stream(
2596 				&state->res_ctx, state->streams[stream_idx]);
2597 
2598 		if (!otg_master)
2599 			continue;
2600 
2601 		resource_log_pipe_for_stream(dc, state, otg_master, stream_idx, is_phantom_pipe);
2602 	}
2603 	if (state->phantom_stream_count > 0) {
2604 		is_phantom_pipe = true;
2605 		DC_LOG_DC(" |    (phantom pipes)     |");
2606 		for (stream_idx = 0; stream_idx < state->stream_count; stream_idx++) {
2607 			if (state->stream_status[stream_idx].mall_stream_config.type != SUBVP_MAIN)
2608 				continue;
2609 
2610 			phantom_stream_idx = resource_stream_to_stream_idx(state,
2611 					state->stream_status[stream_idx].mall_stream_config.paired_stream);
2612 			otg_master = resource_get_otg_master_for_stream(
2613 					&state->res_ctx, state->streams[phantom_stream_idx]);
2614 			if (!otg_master)
2615 				continue;
2616 
2617 			resource_log_pipe_for_stream(dc, state, otg_master, stream_idx, is_phantom_pipe);
2618 		}
2619 	}
2620 	DC_LOG_DC(" |________________________|\n");
2621 }
2622 
2623 static struct pipe_ctx *get_tail_pipe(
2624 		struct pipe_ctx *head_pipe)
2625 {
2626 	struct pipe_ctx *tail_pipe = head_pipe->bottom_pipe;
2627 
2628 	while (tail_pipe) {
2629 		head_pipe = tail_pipe;
2630 		tail_pipe = tail_pipe->bottom_pipe;
2631 	}
2632 
2633 	return head_pipe;
2634 }
2635 
2636 static struct pipe_ctx *get_last_opp_head(
2637 		struct pipe_ctx *opp_head)
2638 {
2639 	ASSERT(resource_is_pipe_type(opp_head, OPP_HEAD));
2640 	while (opp_head->next_odm_pipe)
2641 		opp_head = opp_head->next_odm_pipe;
2642 	return opp_head;
2643 }
2644 
2645 static struct pipe_ctx *get_last_dpp_pipe_in_mpcc_combine(
2646 		struct pipe_ctx *dpp_pipe)
2647 {
2648 	ASSERT(resource_is_pipe_type(dpp_pipe, DPP_PIPE));
2649 	while (dpp_pipe->bottom_pipe &&
2650 			dpp_pipe->plane_state == dpp_pipe->bottom_pipe->plane_state)
2651 		dpp_pipe = dpp_pipe->bottom_pipe;
2652 	return dpp_pipe;
2653 }
2654 
2655 static bool update_pipe_params_after_odm_slice_count_change(
2656 		struct pipe_ctx *otg_master,
2657 		struct dc_state *context,
2658 		const struct resource_pool *pool)
2659 {
2660 	unsigned int i;
2661 	struct pipe_ctx *pipe;
2662 	bool result = true;
2663 
2664 	for (i = 0; i < pool->pipe_count && result; i++) {
2665 		pipe = &context->res_ctx.pipe_ctx[i];
2666 		if (pipe->stream == otg_master->stream && pipe->plane_state)
2667 			result = resource_build_scaling_params(pipe);
2668 	}
2669 
2670 	if (pool->funcs->build_pipe_pix_clk_params)
2671 		pool->funcs->build_pipe_pix_clk_params(otg_master);
2672 
2673 	resource_build_test_pattern_params(&context->res_ctx, otg_master);
2674 
2675 	return result;
2676 }
2677 
2678 static bool update_pipe_params_after_mpc_slice_count_change(
2679 		const struct dc_plane_state *plane,
2680 		struct dc_state *context,
2681 		const struct resource_pool *pool)
2682 {
2683 	unsigned int i;
2684 	struct pipe_ctx *pipe;
2685 	bool result = true;
2686 
2687 	for (i = 0; i < pool->pipe_count && result; i++) {
2688 		pipe = &context->res_ctx.pipe_ctx[i];
2689 		if (pipe->plane_state == plane)
2690 			result = resource_build_scaling_params(pipe);
2691 	}
2692 	return result;
2693 }
2694 
2695 static int acquire_first_split_pipe(
2696 		struct resource_context *res_ctx,
2697 		const struct resource_pool *pool,
2698 		struct dc_stream_state *stream)
2699 {
2700 	unsigned int i;
2701 
2702 	for (i = 0; i < pool->pipe_count; i++) {
2703 		struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i];
2704 
2705 		if (split_pipe->top_pipe &&
2706 				split_pipe->top_pipe->plane_state == split_pipe->plane_state) {
2707 			split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe;
2708 			if (split_pipe->bottom_pipe)
2709 				split_pipe->bottom_pipe->top_pipe = split_pipe->top_pipe;
2710 
2711 			if (split_pipe->top_pipe->plane_state)
2712 				resource_build_scaling_params(split_pipe->top_pipe);
2713 
2714 			memset(split_pipe, 0, sizeof(*split_pipe));
2715 			split_pipe->stream_res.tg = pool->timing_generators[i];
2716 			split_pipe->plane_res.hubp = pool->hubps[i];
2717 			split_pipe->plane_res.ipp = pool->ipps[i];
2718 			split_pipe->plane_res.dpp = pool->dpps[i];
2719 			split_pipe->stream_res.opp = pool->opps[i];
2720 			split_pipe->plane_res.mpcc_inst = (uint8_t)pool->dpps[i]->inst;
2721 			split_pipe->pipe_idx = (uint8_t)i;
2722 
2723 			split_pipe->stream = stream;
2724 			return (int)i;
2725 		}
2726 	}
2727 	return FREE_PIPE_INDEX_NOT_FOUND;
2728 }
2729 
2730 static void update_stream_engine_usage(
2731 		struct resource_context *res_ctx,
2732 		const struct resource_pool *pool,
2733 		struct stream_encoder *stream_enc,
2734 		bool acquired)
2735 {
2736 	unsigned int i;
2737 
2738 	for (i = 0; i < pool->stream_enc_count; i++) {
2739 		if (pool->stream_enc[i] == stream_enc)
2740 			res_ctx->is_stream_enc_acquired[i] = acquired;
2741 	}
2742 }
2743 
2744 static void update_hpo_frl_stream_engine_usage(
2745 		struct resource_context *res_ctx,
2746 		const struct resource_pool *pool,
2747 		struct hpo_frl_stream_encoder *hpo_frl_stream_enc,
2748 		bool acquired)
2749 {
2750 	unsigned int i;
2751 
2752 	for (i = 0; i < pool->hpo_frl_stream_enc_count; i++) {
2753 		if (pool->hpo_frl_stream_enc[i] == hpo_frl_stream_enc)
2754 			res_ctx->is_hpo_frl_stream_enc_acquired[i] = acquired;
2755 	}
2756 }
2757 
2758 static struct hpo_frl_stream_encoder *find_first_free_match_hpo_frl_stream_enc_for_link(
2759 		struct resource_context *res_ctx,
2760 		const struct resource_pool *pool,
2761 		struct dc_stream_state *stream)
2762 {
2763 	(void)stream;
2764 	unsigned int i;
2765 
2766 	for (i = 0; i < pool->hpo_frl_stream_enc_count; i++) {
2767 		if (!res_ctx->is_hpo_frl_stream_enc_acquired[i] &&
2768 				pool->hpo_frl_stream_enc[i]) {
2769 
2770 			return pool->hpo_frl_stream_enc[i];
2771 		}
2772 	}
2773 
2774 	return NULL;
2775 }
2776 
2777 static inline int find_acquired_hpo_frl_link_enc_for_link(
2778 		const struct resource_context *res_ctx,
2779 		const struct dc_link *link)
2780 {
2781 	int i;
2782 
2783 	for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_frl_link_enc_to_link_idx); i++)
2784 		if (res_ctx->hpo_frl_link_enc_ref_cnts[i] > 0 &&
2785 				res_ctx->hpo_frl_link_enc_to_link_idx[i] == link->link_index)
2786 			return i;
2787 
2788 	return -1;
2789 }
2790 
2791 static inline int find_free_hpo_frl_link_enc(const struct resource_context *res_ctx,
2792 		const struct resource_pool *pool)
2793 {
2794 	unsigned int i;
2795 
2796 	for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_frl_link_enc_ref_cnts); i++)
2797 		if (res_ctx->hpo_frl_link_enc_ref_cnts[i] == 0)
2798 			break;
2799 
2800 	return (i < ARRAY_SIZE(res_ctx->hpo_frl_link_enc_ref_cnts) &&
2801 			i < pool->hpo_frl_link_enc_count) ? (int)i : -1;
2802 }
2803 
2804 static inline void acquire_hpo_frl_link_enc(
2805 		struct resource_context *res_ctx,
2806 		unsigned int link_index,
2807 		int enc_index)
2808 {
2809 	res_ctx->hpo_frl_link_enc_to_link_idx[enc_index] = link_index;
2810 	res_ctx->hpo_frl_link_enc_ref_cnts[enc_index] = 1;
2811 }
2812 
2813 static inline void retain_hpo_frl_link_enc(
2814 		struct resource_context *res_ctx,
2815 		int enc_index)
2816 {
2817 	res_ctx->hpo_frl_link_enc_ref_cnts[enc_index]++;
2818 }
2819 
2820 static inline void release_hpo_frl_link_enc(
2821 		struct resource_context *res_ctx,
2822 		int enc_index)
2823 {
2824 	ASSERT(res_ctx->hpo_frl_link_enc_ref_cnts[enc_index] > 0);
2825 	res_ctx->hpo_frl_link_enc_ref_cnts[enc_index]--;
2826 }
2827 
2828 static bool add_hpo_frl_link_enc_to_ctx(struct resource_context *res_ctx,
2829 		const struct resource_pool *pool,
2830 		struct pipe_ctx *pipe_ctx,
2831 		struct dc_stream_state *stream)
2832 {
2833 	int enc_index;
2834 
2835 	enc_index = find_acquired_hpo_frl_link_enc_for_link(res_ctx, stream->link);
2836 
2837 	if (enc_index >= 0) {
2838 		retain_hpo_frl_link_enc(res_ctx, enc_index);
2839 	} else {
2840 		enc_index = find_free_hpo_frl_link_enc(res_ctx, pool);
2841 		if (enc_index >= 0)
2842 			acquire_hpo_frl_link_enc(res_ctx, stream->link->link_index, enc_index);
2843 	}
2844 
2845 	if (enc_index >= 0)
2846 		pipe_ctx->link_res.hpo_frl_link_enc = pool->hpo_frl_link_enc[enc_index];
2847 
2848 	return pipe_ctx->link_res.hpo_frl_link_enc != NULL;
2849 }
2850 
2851 static void remove_hpo_frl_link_enc_from_ctx(struct resource_context *res_ctx,
2852 		struct pipe_ctx *pipe_ctx,
2853 		struct dc_stream_state *stream)
2854 {
2855 	int enc_index;
2856 
2857 	enc_index = find_acquired_hpo_frl_link_enc_for_link(res_ctx, stream->link);
2858 
2859 	if (enc_index >= 0) {
2860 		release_hpo_frl_link_enc(res_ctx, enc_index);
2861 		pipe_ctx->link_res.hpo_frl_link_enc = NULL;
2862 	}
2863 }
2864 
2865 static struct hpo_frl_link_encoder *get_temp_hpo_frl_link_enc(
2866 		const struct resource_context *res_ctx,
2867 		const struct resource_pool *const pool,
2868 		const struct dc_link *link)
2869 {
2870 	struct hpo_frl_link_encoder *hpo_frl_link_enc = NULL;
2871 	int enc_index;
2872 
2873 	enc_index = find_acquired_hpo_frl_link_enc_for_link(res_ctx, link);
2874 
2875 	if (enc_index < 0)
2876 		enc_index = find_free_hpo_frl_link_enc(res_ctx, pool);
2877 
2878 	if (enc_index >= 0)
2879 		hpo_frl_link_enc = pool->hpo_frl_link_enc[enc_index];
2880 
2881 	return hpo_frl_link_enc;
2882 }
2883 
2884 bool get_temp_frl_link_res(struct dc_link *link,
2885 		struct link_resource *link_res)
2886 {
2887 	const struct dc *dc  = link->dc;
2888 	const struct resource_context *res_ctx = &dc->current_state->res_ctx;
2889 
2890 	memset(link_res, 0, sizeof(*link_res));
2891 	link_res->hpo_frl_link_enc = get_temp_hpo_frl_link_enc(res_ctx, dc->res_pool, link);
2892 	if (!link_res->hpo_frl_link_enc)
2893 		return false;
2894 
2895 	link_res->dio_link_enc = get_temp_dio_link_enc(res_ctx,
2896 			dc->res_pool, link);
2897 	if (!link_res->dio_link_enc)
2898 		return false;
2899 
2900 	return true;
2901 }
2902 static void update_hpo_dp_stream_engine_usage(
2903 		struct resource_context *res_ctx,
2904 		const struct resource_pool *pool,
2905 		struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
2906 		bool acquired)
2907 {
2908 	unsigned int i;
2909 
2910 	for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
2911 		if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc)
2912 			res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired;
2913 	}
2914 }
2915 
2916 static inline int find_acquired_hpo_dp_link_enc_for_link(
2917 		const struct resource_context *res_ctx,
2918 		const struct dc_link *link)
2919 {
2920 	int i;
2921 
2922 	for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++)
2923 		if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 &&
2924 				res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index)
2925 			return i;
2926 
2927 	return -1;
2928 }
2929 
2930 static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx,
2931 		const struct resource_pool *pool)
2932 {
2933 	unsigned int i;
2934 
2935 	for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++)
2936 		if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0)
2937 			break;
2938 
2939 	return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) &&
2940 			i < pool->hpo_dp_link_enc_count) ? (int)i : -1;
2941 }
2942 
2943 static inline void acquire_hpo_dp_link_enc(
2944 		struct resource_context *res_ctx,
2945 		unsigned int link_index,
2946 		int enc_index)
2947 {
2948 	res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index;
2949 	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1;
2950 }
2951 
2952 static inline void retain_hpo_dp_link_enc(
2953 		struct resource_context *res_ctx,
2954 		int enc_index)
2955 {
2956 	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++;
2957 }
2958 
2959 static inline void release_hpo_dp_link_enc(
2960 		struct resource_context *res_ctx,
2961 		int enc_index)
2962 {
2963 	ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0);
2964 	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--;
2965 }
2966 
2967 static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx,
2968 		const struct resource_pool *pool,
2969 		struct pipe_ctx *pipe_ctx,
2970 		struct dc_stream_state *stream)
2971 {
2972 	int enc_index;
2973 
2974 	enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
2975 
2976 	if (enc_index >= 0) {
2977 		retain_hpo_dp_link_enc(res_ctx, enc_index);
2978 	} else {
2979 		enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
2980 		if (enc_index >= 0)
2981 			acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index);
2982 	}
2983 
2984 	if (enc_index >= 0)
2985 		pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
2986 
2987 	return pipe_ctx->link_res.hpo_dp_link_enc != NULL;
2988 }
2989 
2990 static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx,
2991 		struct pipe_ctx *pipe_ctx,
2992 		struct dc_stream_state *stream)
2993 {
2994 	int enc_index;
2995 
2996 	enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
2997 
2998 	if (enc_index >= 0) {
2999 		release_hpo_dp_link_enc(res_ctx, enc_index);
3000 		pipe_ctx->link_res.hpo_dp_link_enc = NULL;
3001 	}
3002 }
3003 
3004 static inline int find_acquired_dio_link_enc_for_link(
3005 		const struct resource_context *res_ctx,
3006 		const struct dc_link *link)
3007 {
3008 	int i;
3009 
3010 	for (i = 0; i < ARRAY_SIZE(res_ctx->dio_link_enc_ref_cnts); i++)
3011 		if (res_ctx->dio_link_enc_ref_cnts[i] > 0 &&
3012 				res_ctx->dio_link_enc_to_link_idx[i] == link->link_index)
3013 			return i;
3014 
3015 	return -1;
3016 }
3017 
3018 static inline int find_fixed_dio_link_enc(const struct dc_link *link)
3019 {
3020 	/* virtual links own their link encoder directly and are never
3021 	 * registered into pool->link_encoders[]. */
3022 	if (link->link_id.id == CONNECTOR_ID_VIRTUAL)
3023 		return -1;
3024 
3025 	/* the 8b10b dp phy can only use fixed link encoder */
3026 	return link->eng_id;
3027 }
3028 
3029 static inline int find_free_dio_link_enc(const struct resource_context *res_ctx,
3030 		const struct dc_link *link, const struct resource_pool *pool, struct dc_stream_state *stream)
3031 {
3032 	unsigned int i;
3033 	int j = -1;
3034 	int stream_enc_inst = -1;
3035 	unsigned int enc_count = pool->dig_link_enc_count;
3036 
3037 	/* Find stream encoder instance for the stream */
3038 	if (stream) {
3039 		for (i = 0; i < pool->pipe_count; i++) {
3040 			if ((res_ctx->pipe_ctx[i].stream == stream) &&
3041 				(res_ctx->pipe_ctx[i].stream_res.stream_enc != NULL)) {
3042 				stream_enc_inst = res_ctx->pipe_ctx[i].stream_res.stream_enc->id;
3043 				break;
3044 			}
3045 		}
3046 	}
3047 
3048 	/* Assign dpia preferred > stream enc instance > available */
3049 	for (i = 0; i < enc_count; i++) {
3050 		if (res_ctx->dio_link_enc_ref_cnts[i] == 0) {
3051 			if (j == -1)
3052 				j = i;
3053 
3054 			if (link->dpia_preferred_eng_id == i) {
3055 				j = i;
3056 				break;
3057 			}
3058 
3059 			if (stream_enc_inst == i) {
3060 				j = stream_enc_inst;
3061 			}
3062 		}
3063 	}
3064 	return j;
3065 }
3066 
3067 static inline void acquire_dio_link_enc(
3068 		struct resource_context *res_ctx,
3069 		unsigned int link_index,
3070 		int enc_index)
3071 {
3072 	res_ctx->dio_link_enc_to_link_idx[enc_index] = link_index;
3073 	res_ctx->dio_link_enc_ref_cnts[enc_index] = 1;
3074 }
3075 
3076 static inline void retain_dio_link_enc(
3077 		struct resource_context *res_ctx,
3078 		int enc_index)
3079 {
3080 	res_ctx->dio_link_enc_ref_cnts[enc_index]++;
3081 }
3082 
3083 static inline void release_dio_link_enc(
3084 		struct resource_context *res_ctx,
3085 		int enc_index)
3086 {
3087 	ASSERT(res_ctx->dio_link_enc_ref_cnts[enc_index] > 0);
3088 	res_ctx->dio_link_enc_ref_cnts[enc_index]--;
3089 }
3090 
3091 static bool is_dio_enc_acquired_by_other_link(const struct dc_link *link,
3092 		int enc_index,
3093 		int *link_index)
3094 {
3095 	const struct dc *dc  = link->dc;
3096 	const struct resource_context *res_ctx = &dc->current_state->res_ctx;
3097 
3098 	/* pass the link_index that acquired the enc_index */
3099 	if (res_ctx->dio_link_enc_ref_cnts[enc_index] > 0 &&
3100 			res_ctx->dio_link_enc_to_link_idx[enc_index] != link->link_index) {
3101 		*link_index = res_ctx->dio_link_enc_to_link_idx[enc_index];
3102 		return true;
3103 	}
3104 
3105 	return false;
3106 }
3107 
3108 static void swap_dio_link_enc_to_muxable_ctx(struct dc_state *context,
3109 		const struct resource_pool *pool,
3110 		int new_encoder,
3111 		int old_encoder)
3112 {
3113 	struct resource_context *res_ctx = &context->res_ctx;
3114 	int stream_count = context->stream_count;
3115 	int i = 0;
3116 
3117 	res_ctx->dio_link_enc_ref_cnts[new_encoder] = res_ctx->dio_link_enc_ref_cnts[old_encoder];
3118 	res_ctx->dio_link_enc_to_link_idx[new_encoder] = res_ctx->dio_link_enc_to_link_idx[old_encoder];
3119 	res_ctx->dio_link_enc_ref_cnts[old_encoder] = 0;
3120 
3121 	for (i = 0; i < stream_count; i++) {
3122 		struct dc_stream_state *stream = context->streams[i];
3123 		struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
3124 
3125 		if (pipe_ctx && pipe_ctx->link_res.dio_link_enc == pool->link_encoders[old_encoder])
3126 			pipe_ctx->link_res.dio_link_enc = pool->link_encoders[new_encoder];
3127 	}
3128 }
3129 
3130 static bool add_dio_link_enc_to_ctx(const struct dc *dc,
3131 		struct dc_state *context,
3132 		const struct resource_pool *pool,
3133 		struct pipe_ctx *pipe_ctx,
3134 		struct dc_stream_state *stream)
3135 {
3136 	struct resource_context *res_ctx = &context->res_ctx;
3137 	int enc_index;
3138 
3139 	enc_index = find_acquired_dio_link_enc_for_link(res_ctx, stream->link);
3140 
3141 	if (enc_index >= 0) {
3142 		retain_dio_link_enc(res_ctx, enc_index);
3143 	} else {
3144 		if (stream->link->is_dig_mapping_flexible)
3145 			enc_index = find_free_dio_link_enc(res_ctx, stream->link, pool, stream);
3146 		else {
3147 			int link_index = 0;
3148 
3149 			enc_index = find_fixed_dio_link_enc(stream->link);
3150 			/* Fixed mapping link can only use its fixed link encoder.
3151 			 * If the encoder is acquired by other link then get a new free encoder and swap the new
3152 			 * one into the acquiring link.
3153 			 */
3154 			if (enc_index >= 0 && is_dio_enc_acquired_by_other_link(stream->link, enc_index, &link_index)) {
3155 				int new_enc_index = find_free_dio_link_enc(res_ctx, dc->links[link_index], pool, stream);
3156 
3157 				if (new_enc_index >= 0)
3158 					swap_dio_link_enc_to_muxable_ctx(context, pool, new_enc_index, enc_index);
3159 				else
3160 					return false;
3161 			}
3162 		}
3163 
3164 		if (enc_index >= 0)
3165 			acquire_dio_link_enc(res_ctx, stream->link->link_index, enc_index);
3166 	}
3167 
3168 	if (enc_index >= 0)
3169 		pipe_ctx->link_res.dio_link_enc = pool->link_encoders[enc_index];
3170 	else
3171 		pipe_ctx->link_res.dio_link_enc = stream->link->link_enc;
3172 
3173 	return pipe_ctx->link_res.dio_link_enc != NULL;
3174 }
3175 
3176 static void remove_dio_link_enc_from_ctx(struct resource_context *res_ctx,
3177 		struct pipe_ctx *pipe_ctx,
3178 		struct dc_stream_state *stream)
3179 {
3180 	int enc_index = -1;
3181 
3182 	if (stream->link)
3183 		enc_index = find_acquired_dio_link_enc_for_link(res_ctx, stream->link);
3184 
3185 	if (enc_index >= 0) {
3186 		release_dio_link_enc(res_ctx, enc_index);
3187 		pipe_ctx->link_res.dio_link_enc = NULL;
3188 	}
3189 }
3190 
3191 static int get_num_of_free_pipes(const struct resource_pool *pool, const struct dc_state *context)
3192 {
3193 	unsigned int i;
3194 	int count = 0;
3195 
3196 	for (i = 0; i < pool->pipe_count; i++)
3197 		if (resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], FREE_PIPE))
3198 			count++;
3199 	return count;
3200 }
3201 
3202 enum dc_status resource_add_otg_master_for_stream_output(struct dc_state *new_ctx,
3203 		const struct resource_pool *pool,
3204 		struct dc_stream_state *stream)
3205 {
3206 	(void)pool;
3207 	struct dc *dc = stream->ctx->dc;
3208 
3209 	return dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
3210 }
3211 
3212 void resource_remove_otg_master_for_stream_output(struct dc_state *context,
3213 		const struct resource_pool *pool,
3214 		struct dc_stream_state *stream)
3215 {
3216 	struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(
3217 			&context->res_ctx, stream);
3218 
3219 	if (!otg_master)
3220 		return;
3221 
3222 	ASSERT(resource_get_odm_slice_count(otg_master) == 1);
3223 	ASSERT(otg_master->plane_state == NULL);
3224 	ASSERT(otg_master->stream_res.stream_enc);
3225 	update_stream_engine_usage(
3226 			&context->res_ctx,
3227 			pool,
3228 			otg_master->stream_res.stream_enc,
3229 			false);
3230 
3231 	if (dc_is_hdmi_frl_signal(stream->signal)) {
3232 		update_hpo_frl_stream_engine_usage(
3233 			&context->res_ctx, pool,
3234 			otg_master->stream_res.hpo_frl_stream_enc,
3235 			false);
3236 		remove_hpo_frl_link_enc_from_ctx(
3237 			&context->res_ctx, otg_master, stream);
3238 		remove_dio_link_enc_from_ctx(&context->res_ctx, otg_master, stream);
3239 	}
3240 	if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(otg_master)) {
3241 		update_hpo_dp_stream_engine_usage(
3242 			&context->res_ctx, pool,
3243 			otg_master->stream_res.hpo_dp_stream_enc,
3244 			false);
3245 		remove_hpo_dp_link_enc_from_ctx(
3246 				&context->res_ctx, otg_master, stream);
3247 	}
3248 
3249 	if (stream->ctx->dc->config.unify_link_enc_assignment)
3250 		remove_dio_link_enc_from_ctx(&context->res_ctx, otg_master, stream);
3251 
3252 	if (otg_master->stream_res.audio)
3253 		update_audio_usage(
3254 			&context->res_ctx,
3255 			pool,
3256 			otg_master->stream_res.audio,
3257 			false);
3258 
3259 	resource_unreference_clock_source(&context->res_ctx,
3260 					  pool,
3261 					  otg_master->clock_source);
3262 
3263 	if (pool->funcs->remove_stream_from_ctx)
3264 		pool->funcs->remove_stream_from_ctx(
3265 				stream->ctx->dc, context, stream);
3266 
3267 	memset(otg_master, 0, sizeof(*otg_master));
3268 }
3269 
3270 /* For each OPP head of an OTG master, add top plane at plane index 0.
3271  *
3272  * In the following example, the stream has 2 ODM slices without a top plane.
3273  * By adding a plane 0 to OPP heads, we are configuring our hardware to render
3274  * plane 0 by using each OPP head's DPP.
3275  *
3276  *       Inter-pipe Relation (Before Adding Plane)
3277  *        __________________________________________________
3278  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3279  *       |        |               | slice 0   |             |
3280  *       |   0    |               |blank ----ODM----------- |
3281  *       |        |               | slice 1 | |             |
3282  *       |   1    |               |blank ---- |             |
3283  *       |________|_______________|___________|_____________|
3284  *
3285  *       Inter-pipe Relation (After Adding Plane)
3286  *        __________________________________________________
3287  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3288  *       |        |  plane 0      | slice 0   |             |
3289  *       |   0    | -------------------------ODM----------- |
3290  *       |        |  plane 0      | slice 1 | |             |
3291  *       |   1    | ------------------------- |             |
3292  *       |________|_______________|___________|_____________|
3293  */
3294 static bool add_plane_to_opp_head_pipes(struct pipe_ctx *otg_master_pipe,
3295 		struct dc_plane_state *plane_state,
3296 		struct dc_state *context)
3297 {
3298 	(void)context;
3299 	struct pipe_ctx *opp_head_pipe = otg_master_pipe;
3300 
3301 	while (opp_head_pipe) {
3302 		if (opp_head_pipe->plane_state) {
3303 			ASSERT(0);
3304 			return false;
3305 		}
3306 		opp_head_pipe->plane_state = plane_state;
3307 		opp_head_pipe = opp_head_pipe->next_odm_pipe;
3308 	}
3309 
3310 	return true;
3311 }
3312 
3313 /* For each OPP head of an OTG master, acquire a secondary DPP pipe and add
3314  * the plane. So the plane is added to all ODM slices associated with the OTG
3315  * master pipe in the bottom layer.
3316  *
3317  * In the following example, the stream has 2 ODM slices and a top plane 0.
3318  * By acquiring secondary DPP pipes and adding a plane 1, we are configuring our
3319  * hardware to render the plane 1 by acquiring a new pipe for each ODM slice and
3320  * render plane 1 using new pipes' DPP in the Z axis below plane 0.
3321  *
3322  *       Inter-pipe Relation (Before Adding Plane)
3323  *        __________________________________________________
3324  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3325  *       |        |  plane 0      | slice 0   |             |
3326  *       |   0    | -------------------------ODM----------- |
3327  *       |        |  plane 0      | slice 1 | |             |
3328  *       |   1    | ------------------------- |             |
3329  *       |________|_______________|___________|_____________|
3330  *
3331  *       Inter-pipe Relation (After Acquiring and Adding Plane)
3332  *        __________________________________________________
3333  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3334  *       |        |  plane 0      | slice 0   |             |
3335  *       |   0    | -------------MPC---------ODM----------- |
3336  *       |        |  plane 1    | |         | |             |
3337  *       |   2    | ------------- |         | |             |
3338  *       |        |  plane 0      | slice 1 | |             |
3339  *       |   1    | -------------MPC--------- |             |
3340  *       |        |  plane 1    | |           |             |
3341  *       |   3    | ------------- |           |             |
3342  *       |________|_______________|___________|_____________|
3343  */
3344 static bool acquire_secondary_dpp_pipes_and_add_plane(
3345 		struct pipe_ctx *otg_master_pipe,
3346 		struct dc_plane_state *plane_state,
3347 		struct dc_state *new_ctx,
3348 		struct dc_state *cur_ctx,
3349 		struct resource_pool *pool)
3350 {
3351 	struct pipe_ctx *sec_pipe, *tail_pipe;
3352 	struct pipe_ctx *opp_heads[MAX_PIPES];
3353 	int opp_head_count;
3354 	int i;
3355 
3356 	if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) {
3357 		ASSERT(0);
3358 		return false;
3359 	}
3360 
3361 	opp_head_count = resource_get_opp_heads_for_otg_master(otg_master_pipe,
3362 			&new_ctx->res_ctx, opp_heads);
3363 	if (get_num_of_free_pipes(pool, new_ctx) < opp_head_count)
3364 		/* not enough free pipes */
3365 		return false;
3366 
3367 	for (i = 0; i < opp_head_count; i++) {
3368 		sec_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
3369 				cur_ctx,
3370 				new_ctx,
3371 				pool,
3372 				opp_heads[i]);
3373 		ASSERT(sec_pipe);
3374 		sec_pipe->plane_state = plane_state;
3375 
3376 		/* establish pipe relationship */
3377 		tail_pipe = get_tail_pipe(opp_heads[i]);
3378 		tail_pipe->bottom_pipe = sec_pipe;
3379 		sec_pipe->top_pipe = tail_pipe;
3380 		sec_pipe->bottom_pipe = NULL;
3381 		if (tail_pipe->prev_odm_pipe) {
3382 			ASSERT(tail_pipe->prev_odm_pipe->bottom_pipe);
3383 			sec_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe;
3384 			tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = sec_pipe;
3385 		} else {
3386 			sec_pipe->prev_odm_pipe = NULL;
3387 		}
3388 	}
3389 	return true;
3390 }
3391 
3392 /*
3393  * resource_assign_rmcm() - Assign the RMCM instances for a whole context
3394  *
3395  * RMCM is pre-blend, so every pipe asking for one needs its own instance. Ownership is
3396  * tracked per instance in res_ctx->rmcm_in_use[]; the owning pipe is the one holding the
3397  * matching plane_res.rmcm pointer.
3398  *
3399  * A pipe that already drives an RMCM keeps it, so a plane that is only now asking never
3400  * evicts one that is already using an instance - it simply gets none when the pool is
3401  * exhausted. This has to see the finished context, hence one pass over all pipes rather
3402  * than one per appended plane.
3403  */
3404 void resource_assign_rmcm(
3405 		struct dc_state *new_ctx,
3406 		const struct dc_state *cur_ctx,
3407 		const struct resource_pool *pool)
3408 {
3409 	struct rmcm *held[MAX_PIPES] = { NULL };
3410 	unsigned int p;
3411 	int i;
3412 
3413 	/* new_ctx and cur_ctx can be the same object, so snapshot before clearing */
3414 	for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++)
3415 		held[p] = cur_ctx ? cur_ctx->res_ctx.pipe_ctx[p].plane_res.rmcm : NULL;
3416 
3417 	for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++)
3418 		new_ctx->res_ctx.pipe_ctx[p].plane_res.rmcm = NULL;
3419 
3420 	for (i = 0; i < MAX_RMCM_INST; i++)
3421 		new_ctx->res_ctx.rmcm_in_use[i] = false;
3422 
3423 	/* incumbents first, so a later pipe cannot take an instance out from under them */
3424 	for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++) {
3425 		struct pipe_ctx *pipe = &new_ctx->res_ctx.pipe_ctx[p];
3426 
3427 		if (!pipe->plane_state || !pipe->plane_state->cm.flags.bits.rmcm_enable)
3428 			continue;
3429 
3430 		if (!held[p] || new_ctx->res_ctx.rmcm_in_use[held[p]->inst])
3431 			continue;
3432 
3433 		pipe->plane_res.rmcm = held[p];
3434 		new_ctx->res_ctx.rmcm_in_use[held[p]->inst] = true;
3435 	}
3436 
3437 	for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++) {
3438 		struct pipe_ctx *pipe = &new_ctx->res_ctx.pipe_ctx[p];
3439 
3440 		if (!pipe->plane_state || !pipe->plane_state->cm.flags.bits.rmcm_enable)
3441 			continue;
3442 
3443 		if (pipe->plane_res.rmcm)
3444 			continue;
3445 
3446 		for (i = 0; i < pool->res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
3447 			if (!pool->rmcm[i] || new_ctx->res_ctx.rmcm_in_use[i])
3448 				continue;
3449 
3450 			pipe->plane_res.rmcm = pool->rmcm[i];
3451 			new_ctx->res_ctx.rmcm_in_use[i] = true;
3452 			break;
3453 		}
3454 	}
3455 }
3456 
3457 /*
3458  * resource_release_rmcm() - Release an RMCM instance for a pipe.
3459  *
3460  * Marks the instance free and NULLs the caller's pointer.
3461  */
3462 void resource_release_rmcm(
3463 		struct resource_context *res_ctx,
3464 		const struct resource_pool *pool,
3465 		struct rmcm **rmcm)
3466 {
3467 	int i;
3468 
3469 	if (!*rmcm)
3470 		return;
3471 
3472 	for (i = 0; i < pool->res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
3473 		if (pool->rmcm[i] == *rmcm) {
3474 			res_ctx->rmcm_in_use[i] = false;
3475 			*rmcm = NULL;
3476 			return;
3477 		}
3478 	}
3479 }
3480 
3481 bool resource_append_dpp_pipes_for_plane_composition(
3482 		struct dc_state *new_ctx,
3483 		struct dc_state *cur_ctx,
3484 		struct resource_pool *pool,
3485 		struct pipe_ctx *otg_master_pipe,
3486 		struct dc_plane_state *plane_state)
3487 {
3488 	bool success;
3489 
3490 	if (otg_master_pipe->plane_state == NULL)
3491 		success = add_plane_to_opp_head_pipes(otg_master_pipe,
3492 				plane_state, new_ctx);
3493 	else
3494 		success = acquire_secondary_dpp_pipes_and_add_plane(
3495 				otg_master_pipe, plane_state, new_ctx,
3496 				cur_ctx, pool);
3497 	if (success) {
3498 		/* when appending a plane mpc slice count changes from 0 to 1 */
3499 		success = update_pipe_params_after_mpc_slice_count_change(
3500 				plane_state, new_ctx, pool);
3501 		if (!success)
3502 			resource_remove_dpp_pipes_for_plane_composition(new_ctx,
3503 					pool, plane_state);
3504 	}
3505 
3506 	/* Idempotent, so the last append of a commit leaves the final assignment behind.
3507 	 * Releasing is driven by the MPC_RMCM_CNTL mirror (see dcn42_release_rmcm_from_mpcc).
3508 	 */
3509 	if (success)
3510 		resource_assign_rmcm(new_ctx, cur_ctx, pool);
3511 
3512 	return success;
3513 }
3514 
3515 void resource_remove_dpp_pipes_for_plane_composition(
3516 		struct dc_state *context,
3517 		const struct resource_pool *pool,
3518 		const struct dc_plane_state *plane_state)
3519 {
3520 	int i;
3521 
3522 	for (i = pool->pipe_count - 1; i >= 0; i--) {
3523 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
3524 
3525 		if (pipe_ctx->plane_state == plane_state) {
3526 			/* Release RMCM instance for this pipe */
3527 			if (pipe_ctx->plane_res.rmcm)
3528 				resource_release_rmcm(&context->res_ctx,
3529 						pool,
3530 						&pipe_ctx->plane_res.rmcm);
3531 
3532 			if (pipe_ctx->top_pipe)
3533 				pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
3534 
3535 			/* Second condition is to avoid setting NULL to top pipe
3536 			 * of tail pipe making it look like head pipe in subsequent
3537 			 * deletes
3538 			 */
3539 			if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe)
3540 				pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe;
3541 
3542 			/*
3543 			 * For head pipe detach surfaces from pipe for tail
3544 			 * pipe just zero it out
3545 			 */
3546 			if (!pipe_ctx->top_pipe)
3547 				pipe_ctx->plane_state = NULL;
3548 			else
3549 				memset(pipe_ctx, 0, sizeof(*pipe_ctx));
3550 		}
3551 	}
3552 }
3553 
3554 /*
3555  * Increase ODM slice count by 1 by acquiring pipes and adding a new ODM slice
3556  * at the last index.
3557  * return - true if a new ODM slice is added and required pipes are acquired.
3558  * false if new_ctx is no longer a valid state after new ODM slice is added.
3559  *
3560  * This is achieved by duplicating MPC blending tree from previous ODM slice.
3561  * In the following example, we have a single MPC tree and 1 ODM slice 0. We
3562  * want to add a new odm slice by duplicating the MPC blending tree and add
3563  * ODM slice 1.
3564  *
3565  *       Inter-pipe Relation (Before Acquiring and Adding ODM Slice)
3566  *        __________________________________________________
3567  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3568  *       |        |  plane 0      | slice 0   |             |
3569  *       |   0    | -------------MPC---------ODM----------- |
3570  *       |        |  plane 1    | |           |             |
3571  *       |   1    | ------------- |           |             |
3572  *       |________|_______________|___________|_____________|
3573  *
3574  *       Inter-pipe Relation (After Acquiring and Adding ODM Slice)
3575  *        __________________________________________________
3576  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3577  *       |        |  plane 0      | slice 0   |             |
3578  *       |   0    | -------------MPC---------ODM----------- |
3579  *       |        |  plane 1    | |         | |             |
3580  *       |   1    | ------------- |         | |             |
3581  *       |        |  plane 0      | slice 1 | |             |
3582  *       |   2    | -------------MPC--------- |             |
3583  *       |        |  plane 1    | |           |             |
3584  *       |   3    | ------------- |           |             |
3585  *       |________|_______________|___________|_____________|
3586  */
3587 static bool acquire_pipes_and_add_odm_slice(
3588 		struct pipe_ctx *otg_master_pipe,
3589 		struct dc_state *new_ctx,
3590 		const struct dc_state *cur_ctx,
3591 		const struct resource_pool *pool)
3592 {
3593 	struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe);
3594 	struct pipe_ctx *new_opp_head;
3595 	struct pipe_ctx *last_top_dpp_pipe, *last_bottom_dpp_pipe,
3596 			*new_top_dpp_pipe, *new_bottom_dpp_pipe;
3597 
3598 	if (!pool->funcs->acquire_free_pipe_as_secondary_opp_head) {
3599 		ASSERT(0);
3600 		return false;
3601 	}
3602 	new_opp_head = pool->funcs->acquire_free_pipe_as_secondary_opp_head(
3603 					cur_ctx, new_ctx, pool,
3604 					otg_master_pipe);
3605 	if (!new_opp_head)
3606 		return false;
3607 
3608 	last_opp_head->next_odm_pipe = new_opp_head;
3609 	new_opp_head->prev_odm_pipe = last_opp_head;
3610 	new_opp_head->next_odm_pipe = NULL;
3611 	new_opp_head->plane_state = last_opp_head->plane_state;
3612 	last_top_dpp_pipe = last_opp_head;
3613 	new_top_dpp_pipe = new_opp_head;
3614 
3615 	while (last_top_dpp_pipe->bottom_pipe) {
3616 		last_bottom_dpp_pipe = last_top_dpp_pipe->bottom_pipe;
3617 		new_bottom_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
3618 				cur_ctx, new_ctx, pool,
3619 				new_opp_head);
3620 		if (!new_bottom_dpp_pipe)
3621 			return false;
3622 
3623 		new_bottom_dpp_pipe->plane_state = last_bottom_dpp_pipe->plane_state;
3624 		new_top_dpp_pipe->bottom_pipe = new_bottom_dpp_pipe;
3625 		new_bottom_dpp_pipe->top_pipe = new_top_dpp_pipe;
3626 		last_bottom_dpp_pipe->next_odm_pipe = new_bottom_dpp_pipe;
3627 		new_bottom_dpp_pipe->prev_odm_pipe = last_bottom_dpp_pipe;
3628 		new_bottom_dpp_pipe->next_odm_pipe = NULL;
3629 		last_top_dpp_pipe = last_bottom_dpp_pipe;
3630 	}
3631 
3632 	return true;
3633 }
3634 
3635 /*
3636  * Decrease ODM slice count by 1 by releasing pipes and removing the ODM slice
3637  * at the last index.
3638  * return - true if the last ODM slice is removed and related pipes are
3639  * released. false if there is no removable ODM slice.
3640  *
3641  * In the following example, we have 2 MPC trees and ODM slice 0 and slice 1.
3642  * We want to remove the last ODM i.e slice 1. We are releasing secondary DPP
3643  * pipe 3 and OPP head pipe 2.
3644  *
3645  *       Inter-pipe Relation (Before Releasing and Removing ODM Slice)
3646  *        __________________________________________________
3647  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3648  *       |        |  plane 0      | slice 0   |             |
3649  *       |   0    | -------------MPC---------ODM----------- |
3650  *       |        |  plane 1    | |         | |             |
3651  *       |   1    | ------------- |         | |             |
3652  *       |        |  plane 0      | slice 1 | |             |
3653  *       |   2    | -------------MPC--------- |             |
3654  *       |        |  plane 1    | |           |             |
3655  *       |   3    | ------------- |           |             |
3656  *       |________|_______________|___________|_____________|
3657  *
3658  *       Inter-pipe Relation (After Releasing and Removing ODM Slice)
3659  *        __________________________________________________
3660  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3661  *       |        |  plane 0      | slice 0   |             |
3662  *       |   0    | -------------MPC---------ODM----------- |
3663  *       |        |  plane 1    | |           |             |
3664  *       |   1    | ------------- |           |             |
3665  *       |________|_______________|___________|_____________|
3666  */
3667 static bool release_pipes_and_remove_odm_slice(
3668 		struct pipe_ctx *otg_master_pipe,
3669 		struct dc_state *context,
3670 		const struct resource_pool *pool)
3671 {
3672 	struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe);
3673 	struct pipe_ctx *tail_pipe = get_tail_pipe(last_opp_head);
3674 
3675 	if (!pool->funcs->release_pipe) {
3676 		ASSERT(0);
3677 		return false;
3678 	}
3679 
3680 	if (resource_is_pipe_type(last_opp_head, OTG_MASTER))
3681 		return false;
3682 
3683 	while (tail_pipe->top_pipe) {
3684 		tail_pipe->prev_odm_pipe->next_odm_pipe = NULL;
3685 		tail_pipe = tail_pipe->top_pipe;
3686 		pool->funcs->release_pipe(context, tail_pipe->bottom_pipe, pool);
3687 		tail_pipe->bottom_pipe = NULL;
3688 	}
3689 	last_opp_head->prev_odm_pipe->next_odm_pipe = NULL;
3690 	pool->funcs->release_pipe(context, last_opp_head, pool);
3691 
3692 	return true;
3693 }
3694 
3695 /*
3696  * Increase MPC slice count by 1 by acquiring a new DPP pipe and add it as the
3697  * last MPC slice of the plane associated with dpp_pipe.
3698  *
3699  * return - true if a new MPC slice is added and required pipes are acquired.
3700  * false if new_ctx is no longer a valid state after new MPC slice is added.
3701  *
3702  * In the following example, we add a new MPC slice for plane 0 into the
3703  * new_ctx. To do so we pass pipe 0 as dpp_pipe. The function acquires a new DPP
3704  * pipe 2 for plane 0 as the bottom most pipe for plane 0.
3705  *
3706  *       Inter-pipe Relation (Before Acquiring and Adding MPC Slice)
3707  *        __________________________________________________
3708  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3709  *       |        |  plane 0      |           |             |
3710  *       |   0    | -------------MPC----------------------- |
3711  *       |        |  plane 1    | |           |             |
3712  *       |   1    | ------------- |           |             |
3713  *       |________|_______________|___________|_____________|
3714  *
3715  *       Inter-pipe Relation (After Acquiring and Adding MPC Slice)
3716  *        __________________________________________________
3717  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3718  *       |        |  plane 0      |           |             |
3719  *       |   0    | -------------MPC----------------------- |
3720  *       |        |  plane 0    | |           |             |
3721  *       |   2    | ------------- |           |             |
3722  *       |        |  plane 1    | |           |             |
3723  *       |   1    | ------------- |           |             |
3724  *       |________|_______________|___________|_____________|
3725  */
3726 static bool acquire_dpp_pipe_and_add_mpc_slice(
3727 		struct pipe_ctx *dpp_pipe,
3728 		struct dc_state *new_ctx,
3729 		const struct dc_state *cur_ctx,
3730 		const struct resource_pool *pool)
3731 {
3732 	struct pipe_ctx *last_dpp_pipe =
3733 			get_last_dpp_pipe_in_mpcc_combine(dpp_pipe);
3734 	struct pipe_ctx *opp_head = resource_get_opp_head(dpp_pipe);
3735 	struct pipe_ctx *new_dpp_pipe;
3736 
3737 	if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) {
3738 		ASSERT(0);
3739 		return false;
3740 	}
3741 	new_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
3742 			cur_ctx, new_ctx, pool, opp_head);
3743 	if (!new_dpp_pipe || resource_get_odm_slice_count(dpp_pipe) > 1)
3744 		return false;
3745 
3746 	new_dpp_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe;
3747 	if (new_dpp_pipe->bottom_pipe)
3748 		new_dpp_pipe->bottom_pipe->top_pipe = new_dpp_pipe;
3749 	new_dpp_pipe->top_pipe = last_dpp_pipe;
3750 	last_dpp_pipe->bottom_pipe = new_dpp_pipe;
3751 	new_dpp_pipe->plane_state = last_dpp_pipe->plane_state;
3752 
3753 	return true;
3754 }
3755 
3756 /*
3757  * Reduce MPC slice count by 1 by releasing the bottom DPP pipe in MPCC combine
3758  * with dpp_pipe and removing last MPC slice of the plane associated with
3759  * dpp_pipe.
3760  *
3761  * return - true if the last MPC slice of the plane associated with dpp_pipe is
3762  * removed and last DPP pipe in MPCC combine with dpp_pipe is released.
3763  * false if there is no removable MPC slice.
3764  *
3765  * In the following example, we remove an MPC slice for plane 0 from the
3766  * context. To do so we pass pipe 0 as dpp_pipe. The function releases pipe 1 as
3767  * it is the last pipe for plane 0.
3768  *
3769  *       Inter-pipe Relation (Before Releasing and Removing MPC Slice)
3770  *        __________________________________________________
3771  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3772  *       |        |  plane 0      |           |             |
3773  *       |   0    | -------------MPC----------------------- |
3774  *       |        |  plane 0    | |           |             |
3775  *       |   1    | ------------- |           |             |
3776  *       |        |  plane 1    | |           |             |
3777  *       |   2    | ------------- |           |             |
3778  *       |________|_______________|___________|_____________|
3779  *
3780  *       Inter-pipe Relation (After Releasing and Removing MPC Slice)
3781  *        __________________________________________________
3782  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3783  *       |        |  plane 0      |           |             |
3784  *       |   0    | -------------MPC----------------------- |
3785  *       |        |  plane 1    | |           |             |
3786  *       |   2    | ------------- |           |             |
3787  *       |________|_______________|___________|_____________|
3788  */
3789 static bool release_dpp_pipe_and_remove_mpc_slice(
3790 		struct pipe_ctx *dpp_pipe,
3791 		struct dc_state *context,
3792 		const struct resource_pool *pool)
3793 {
3794 	struct pipe_ctx *last_dpp_pipe =
3795 			get_last_dpp_pipe_in_mpcc_combine(dpp_pipe);
3796 
3797 	if (!pool->funcs->release_pipe) {
3798 		ASSERT(0);
3799 		return false;
3800 	}
3801 
3802 	if (resource_is_pipe_type(last_dpp_pipe, OPP_HEAD) ||
3803 			resource_get_odm_slice_count(dpp_pipe) > 1)
3804 		return false;
3805 
3806 	last_dpp_pipe->top_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe;
3807 	if (last_dpp_pipe->bottom_pipe)
3808 		last_dpp_pipe->bottom_pipe->top_pipe = last_dpp_pipe->top_pipe;
3809 	pool->funcs->release_pipe(context, last_dpp_pipe, pool);
3810 
3811 	return true;
3812 }
3813 
3814 bool resource_update_pipes_for_stream_with_slice_count(
3815 		struct dc_state *new_ctx,
3816 		const struct dc_state *cur_ctx,
3817 		const struct resource_pool *pool,
3818 		const struct dc_stream_state *stream,
3819 		int new_slice_count)
3820 {
3821 	int i;
3822 	struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(
3823 			&new_ctx->res_ctx, stream);
3824 	int cur_slice_count;
3825 	bool result = true;
3826 
3827 	if (!otg_master)
3828 		return false;
3829 
3830 	cur_slice_count = resource_get_odm_slice_count(otg_master);
3831 
3832 	if (new_slice_count == cur_slice_count)
3833 		return result;
3834 
3835 	if (new_slice_count > cur_slice_count)
3836 		for (i = 0; i < new_slice_count - cur_slice_count && result; i++)
3837 			result = acquire_pipes_and_add_odm_slice(
3838 					otg_master, new_ctx, cur_ctx, pool);
3839 	else
3840 		for (i = 0; i < cur_slice_count - new_slice_count && result; i++)
3841 			result = release_pipes_and_remove_odm_slice(
3842 					otg_master, new_ctx, pool);
3843 	if (result)
3844 		result = update_pipe_params_after_odm_slice_count_change(
3845 				otg_master, new_ctx, pool);
3846 	return result;
3847 }
3848 
3849 bool resource_update_pipes_for_plane_with_slice_count(
3850 		struct dc_state *new_ctx,
3851 		const struct dc_state *cur_ctx,
3852 		const struct resource_pool *pool,
3853 		const struct dc_plane_state *plane,
3854 		int new_slice_count)
3855 {
3856 	int i;
3857 	int dpp_pipe_count;
3858 	int cur_slice_count;
3859 	struct pipe_ctx *dpp_pipes[MAX_PIPES] = {0};
3860 	bool result = true;
3861 
3862 	dpp_pipe_count = resource_get_dpp_pipes_for_plane(plane,
3863 			&new_ctx->res_ctx, dpp_pipes);
3864 	ASSERT(dpp_pipe_count > 0);
3865 	cur_slice_count = resource_get_mpc_slice_count(dpp_pipes[0]);
3866 
3867 	if (new_slice_count == cur_slice_count)
3868 		return result;
3869 
3870 	if (new_slice_count > cur_slice_count)
3871 		for (i = 0; i < new_slice_count - cur_slice_count && result; i++)
3872 			result = acquire_dpp_pipe_and_add_mpc_slice(
3873 					dpp_pipes[0], new_ctx, cur_ctx, pool);
3874 	else
3875 		for (i = 0; i < cur_slice_count - new_slice_count && result; i++)
3876 			result = release_dpp_pipe_and_remove_mpc_slice(
3877 					dpp_pipes[0], new_ctx, pool);
3878 	if (result)
3879 		result = update_pipe_params_after_mpc_slice_count_change(
3880 				dpp_pipes[0]->plane_state, new_ctx, pool);
3881 	return result;
3882 }
3883 
3884 bool dc_is_timing_changed(struct dc_stream_state *cur_stream,
3885 		       struct dc_stream_state *new_stream)
3886 {
3887 	if (cur_stream == NULL)
3888 		return true;
3889 
3890 	/* If output color space is changed, need to reprogram info frames */
3891 	if (cur_stream->output_color_space != new_stream->output_color_space)
3892 		return true;
3893 
3894 	return memcmp(
3895 		&cur_stream->timing,
3896 		&new_stream->timing,
3897 		sizeof(struct dc_crtc_timing)) != 0;
3898 }
3899 
3900 static bool are_stream_backends_same(
3901 	struct dc_stream_state *stream_a, struct dc_stream_state *stream_b)
3902 {
3903 	if (stream_a == stream_b)
3904 		return true;
3905 
3906 	if (stream_a == NULL || stream_b == NULL)
3907 		return false;
3908 
3909 	if (dc_is_timing_changed(stream_a, stream_b))
3910 		return false;
3911 
3912 	if (stream_a->signal != stream_b->signal)
3913 		return false;
3914 
3915 	if (stream_a->dpms_off != stream_b->dpms_off)
3916 		return false;
3917 
3918 	return true;
3919 }
3920 
3921 /*
3922  * dc_is_stream_unchanged() - Compare two stream states for equivalence.
3923  *
3924  * Checks if there a difference between the two states
3925  * that would require a mode change.
3926  *
3927  * Does not compare cursor position or attributes.
3928  */
3929 bool dc_is_stream_unchanged(
3930 	struct dc_stream_state *old_stream, struct dc_stream_state *stream)
3931 {
3932 	if (!old_stream || !stream)
3933 		return false;
3934 
3935 	if (!are_stream_backends_same(old_stream, stream))
3936 		return false;
3937 
3938 	if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param)
3939 		return false;
3940 
3941 	/*compare audio info*/
3942 	if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0)
3943 		return false;
3944 
3945 	return true;
3946 }
3947 
3948 /*
3949  * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams.
3950  */
3951 bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream,
3952 				    struct dc_stream_state *stream)
3953 {
3954 	if (old_stream == stream)
3955 		return true;
3956 
3957 	if (old_stream == NULL || stream == NULL)
3958 		return false;
3959 
3960 	if (memcmp(&old_stream->src,
3961 			&stream->src,
3962 			sizeof(struct rect)) != 0)
3963 		return false;
3964 
3965 	if (memcmp(&old_stream->dst,
3966 			&stream->dst,
3967 			sizeof(struct rect)) != 0)
3968 		return false;
3969 
3970 	return true;
3971 }
3972 
3973 /* TODO: release audio object */
3974 void update_audio_usage(
3975 		struct resource_context *res_ctx,
3976 		const struct resource_pool *pool,
3977 		struct audio *audio,
3978 		bool acquired)
3979 {
3980 	unsigned int i;
3981 	for (i = 0; i < pool->audio_count; i++) {
3982 		if (pool->audios[i] == audio)
3983 			res_ctx->is_audio_acquired[i] = acquired;
3984 	}
3985 }
3986 
3987 static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link(
3988 		struct resource_context *res_ctx,
3989 		const struct resource_pool *pool,
3990 		struct dc_stream_state *stream)
3991 {
3992 	(void)stream;
3993 	unsigned int i;
3994 
3995 	for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
3996 		if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] &&
3997 				pool->hpo_dp_stream_enc[i]) {
3998 
3999 			return pool->hpo_dp_stream_enc[i];
4000 		}
4001 	}
4002 
4003 	return NULL;
4004 }
4005 
4006 static struct audio *find_first_free_audio(
4007 		struct resource_context *res_ctx,
4008 		const struct resource_pool *pool,
4009 		enum engine_id id,
4010 		enum dce_version dc_version)
4011 {
4012 	(void)dc_version;
4013 	int i, available_audio_count;
4014 
4015 	if (id == ENGINE_ID_UNKNOWN)
4016 		return NULL;
4017 
4018 	available_audio_count = pool->audio_count;
4019 
4020 	for (i = 0; i < available_audio_count; i++) {
4021 		if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) {
4022 			/*we have enough audio endpoint, find the matching inst*/
4023 			if (id != i)
4024 				continue;
4025 			return pool->audios[i];
4026 		}
4027 	}
4028 
4029 	/* use engine id to find free audio */
4030 	if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) {
4031 		return pool->audios[id];
4032 	}
4033 	/*not found the matching one, first come first serve*/
4034 	for (i = 0; i < available_audio_count; i++) {
4035 		if (res_ctx->is_audio_acquired[i] == false) {
4036 			return pool->audios[i];
4037 		}
4038 	}
4039 	return NULL;
4040 }
4041 
4042 static struct dc_stream_state *find_pll_sharable_stream(
4043 		struct dc_stream_state *stream_needs_pll,
4044 		struct dc_state *context)
4045 {
4046 	int i;
4047 
4048 	for (i = 0; i < context->stream_count; i++) {
4049 		struct dc_stream_state *stream_has_pll = context->streams[i];
4050 
4051 		/* We are looking for non dp, non virtual stream */
4052 		if (resource_are_streams_timing_synchronizable(
4053 			stream_needs_pll, stream_has_pll)
4054 			&& !dc_is_dp_signal(stream_has_pll->signal)
4055 			&& stream_has_pll->link->connector_signal
4056 			!= SIGNAL_TYPE_VIRTUAL)
4057 			return stream_has_pll;
4058 
4059 	}
4060 
4061 	return NULL;
4062 }
4063 
4064 static int get_norm_pix_clk(const struct dc_crtc_timing *timing)
4065 {
4066 	uint32_t pix_clk = timing->pix_clk_100hz;
4067 	uint32_t normalized_pix_clk = pix_clk;
4068 
4069 	if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
4070 		pix_clk /= 2;
4071 	if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
4072 		switch (timing->display_color_depth) {
4073 		case COLOR_DEPTH_666:
4074 		case COLOR_DEPTH_888:
4075 			normalized_pix_clk = pix_clk;
4076 			break;
4077 		case COLOR_DEPTH_101010:
4078 			normalized_pix_clk = (pix_clk * 30) / 24;
4079 			break;
4080 		case COLOR_DEPTH_121212:
4081 			normalized_pix_clk = (pix_clk * 36) / 24;
4082 			break;
4083 		case COLOR_DEPTH_141414:
4084 			normalized_pix_clk = (pix_clk * 42) / 24;
4085 			break;
4086 		case COLOR_DEPTH_161616:
4087 			normalized_pix_clk = (pix_clk * 48) / 24;
4088 			break;
4089 		default:
4090 			ASSERT(0);
4091 		break;
4092 		}
4093 	}
4094 	return normalized_pix_clk;
4095 }
4096 
4097 static void calculate_phy_pix_clks(struct dc_stream_state *stream)
4098 {
4099 	/* update actual pixel clock on all streams */
4100 	if (dc_is_hdmi_signal(stream->signal))
4101 		stream->phy_pix_clk = get_norm_pix_clk(
4102 			&stream->timing) / 10;
4103 	else
4104 		stream->phy_pix_clk =
4105 			stream->timing.pix_clk_100hz / 10;
4106 
4107 	if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
4108 		stream->phy_pix_clk *= 2;
4109 }
4110 
4111 static int acquire_resource_from_hw_enabled_state(
4112 		struct resource_context *res_ctx,
4113 		const struct resource_pool *pool,
4114 		struct dc_stream_state *stream)
4115 {
4116 	struct dc_link *link = stream->link;
4117 	unsigned int i, inst, tg_inst = 0;
4118 	uint32_t numPipes = 1;
4119 	uint32_t id_src[4] = {0};
4120 
4121 	/* Check for enabled DIG to identify enabled display */
4122 	if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
4123 		return -1;
4124 
4125 	inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
4126 
4127 	if (inst == ENGINE_ID_UNKNOWN)
4128 		return -1;
4129 
4130 	for (i = 0; i < pool->stream_enc_count; i++) {
4131 		if (pool->stream_enc[i]->id == inst) {
4132 			tg_inst = pool->stream_enc[i]->funcs->dig_source_otg(
4133 				pool->stream_enc[i]);
4134 			break;
4135 		}
4136 	}
4137 
4138 	// tg_inst not found
4139 	if (i == pool->stream_enc_count)
4140 		return -1;
4141 
4142 	if (tg_inst >= pool->timing_generator_count)
4143 		return -1;
4144 
4145 	if (!res_ctx->pipe_ctx[tg_inst].stream) {
4146 		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];
4147 
4148 		pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
4149 		id_src[0] = tg_inst;
4150 
4151 		if (pipe_ctx->stream_res.tg->funcs->get_optc_source)
4152 			pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg,
4153 						&numPipes, &id_src[0], &id_src[1]);
4154 
4155 		if (id_src[0] == 0xf && id_src[1] == 0xf) {
4156 			id_src[0] = tg_inst;
4157 			numPipes = 1;
4158 		}
4159 
4160 		for (i = 0; i < numPipes; i++) {
4161 			//Check if src id invalid
4162 			if (id_src[i] == 0xf)
4163 				return -1;
4164 
4165 			pipe_ctx = &res_ctx->pipe_ctx[id_src[i]];
4166 
4167 			pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
4168 			pipe_ctx->plane_res.mi = pool->mis[id_src[i]];
4169 			pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]];
4170 			pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]];
4171 			pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]];
4172 			pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]];
4173 			pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
4174 
4175 			if (pool->dpps[id_src[i]]) {
4176 				pipe_ctx->plane_res.mpcc_inst = (uint8_t)pool->dpps[id_src[i]]->inst;
4177 
4178 				if (pool->mpc->funcs->read_mpcc_state) {
4179 					struct mpcc_state s = {0};
4180 
4181 					pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);
4182 
4183 					if (s.dpp_id < MAX_MPCC)
4184 						pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id =
4185 								s.dpp_id;
4186 
4187 					if (s.bot_mpcc_id < MAX_MPCC)
4188 						pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
4189 								&pool->mpc->mpcc_array[s.bot_mpcc_id];
4190 
4191 					if (s.opp_id < MAX_OPP)
4192 						pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
4193 				}
4194 			}
4195 			pipe_ctx->pipe_idx = (uint8_t)id_src[i];
4196 
4197 			if (id_src[i] >= pool->timing_generator_count) {
4198 				id_src[i] = pool->timing_generator_count - 1;
4199 
4200 				pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]];
4201 				pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
4202 			}
4203 
4204 			pipe_ctx->stream = stream;
4205 		}
4206 
4207 		if (numPipes == 2) {
4208 			stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1;
4209 			res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]];
4210 			res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL;
4211 			res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL;
4212 			res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]];
4213 		} else
4214 			stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled;
4215 
4216 		return id_src[0];
4217 	}
4218 
4219 	return -1;
4220 }
4221 
4222 static void mark_seamless_boot_stream(const struct dc  *dc,
4223 				      struct dc_stream_state *stream)
4224 {
4225 	struct dc_bios *dcb = dc->ctx->dc_bios;
4226 
4227 	DC_LOGGER_INIT(dc->ctx->logger);
4228 
4229 	if (stream->apply_seamless_boot_optimization)
4230 		return;
4231 	if (!dc->config.allow_seamless_boot_optimization)
4232 		return;
4233 	if (dcb->funcs->is_accelerated_mode(dcb))
4234 		return;
4235 	if (dc_validate_boot_timing(dc, stream->sink, &stream->timing)) {
4236 		stream->apply_seamless_boot_optimization = true;
4237 		DC_LOG_DC("Marked stream for seamless boot optimization\n");
4238 	}
4239 }
4240 
4241 /*
4242  * Acquire a pipe as OTG master and assign to the stream in new dc context.
4243  * return - true if OTG master pipe is acquired and new dc context is updated.
4244  * false if it fails to acquire an OTG master pipe for this stream.
4245  *
4246  * In the example below, we acquired pipe 0 as OTG master pipe for the stream.
4247  * After the function its Inter-pipe Relation is represented by the diagram
4248  * below.
4249  *
4250  *       Inter-pipe Relation
4251  *        __________________________________________________
4252  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
4253  *       |        |               |           |             |
4254  *       |   0    |               |blank ------------------ |
4255  *       |________|_______________|___________|_____________|
4256  */
4257 static bool acquire_otg_master_pipe_for_stream(
4258 		const struct dc_state *cur_ctx,
4259 		struct dc_state *new_ctx,
4260 		const struct resource_pool *pool,
4261 		struct dc_stream_state *stream)
4262 {
4263 	/* TODO: Move this function to DCN specific resource file and acquire
4264 	 * DSC resource here. The reason is that the function should have the
4265 	 * same level of responsibility as when we acquire secondary OPP head.
4266 	 * We acquire DSC when we acquire secondary OPP head, so we should
4267 	 * acquire DSC when we acquire OTG master.
4268 	 */
4269 	int pipe_idx;
4270 	struct pipe_ctx *pipe_ctx = NULL;
4271 
4272 	/*
4273 	 * Upper level code is responsible to optimize unnecessary addition and
4274 	 * removal for unchanged streams. So unchanged stream will keep the same
4275 	 * OTG master instance allocated. When current stream is removed and a
4276 	 * new stream is added, we want to reuse the OTG instance made available
4277 	 * by the removed stream first. If not found, we try to avoid of using
4278 	 * any free pipes already used in current context as this could tear
4279 	 * down exiting ODM/MPC/MPO configuration unnecessarily.
4280 	 */
4281 
4282 	/*
4283 	 * Try to acquire the same OTG master already in use. This is not
4284 	 * optimal because resetting an enabled OTG master pipe for a new stream
4285 	 * requires an extra frame of wait. However there are test automation
4286 	 * and eDP assumptions that rely on reusing the same OTG master pipe
4287 	 * during mode change. We have to keep this logic as is for now.
4288 	 */
4289 	pipe_idx = recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx(
4290 			&cur_ctx->res_ctx, &new_ctx->res_ctx, pool);
4291 	/*
4292 	 * Try to acquire a pipe not used in current resource context to avoid
4293 	 * pipe swapping.
4294 	 */
4295 	if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)
4296 		pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx(
4297 				&cur_ctx->res_ctx, &new_ctx->res_ctx, pool);
4298 	/*
4299 	 * If pipe swapping is unavoidable, try to acquire pipe used as
4300 	 * secondary DPP pipe in current state as we prioritize to support more
4301 	 * streams over supporting MPO planes.
4302 	 */
4303 	if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)
4304 		pipe_idx = resource_find_free_pipe_used_as_cur_sec_dpp(
4305 				&cur_ctx->res_ctx, &new_ctx->res_ctx, pool);
4306 	if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)
4307 		pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool);
4308 	if (pipe_idx != FREE_PIPE_INDEX_NOT_FOUND) {
4309 		pipe_ctx = &new_ctx->res_ctx.pipe_ctx[pipe_idx];
4310 		memset(pipe_ctx, 0, sizeof(*pipe_ctx));
4311 		pipe_ctx->pipe_idx = (uint8_t)pipe_idx;
4312 		pipe_ctx->stream_res.tg = pool->timing_generators[pipe_idx];
4313 		pipe_ctx->plane_res.mi = pool->mis[pipe_idx];
4314 		pipe_ctx->plane_res.hubp = pool->hubps[pipe_idx];
4315 		pipe_ctx->plane_res.ipp = pool->ipps[pipe_idx];
4316 		pipe_ctx->plane_res.xfm = pool->transforms[pipe_idx];
4317 		pipe_ctx->plane_res.dpp = pool->dpps[pipe_idx];
4318 		pipe_ctx->stream_res.opp = pool->opps[pipe_idx];
4319 		if (pool->dpps[pipe_idx])
4320 			pipe_ctx->plane_res.mpcc_inst = (uint8_t)pool->dpps[pipe_idx]->inst;
4321 
4322 		if ((unsigned int)pipe_idx >= pool->timing_generator_count && pool->timing_generator_count != 0) {
4323 			int tg_inst = pool->timing_generator_count - 1;
4324 
4325 			pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
4326 			pipe_ctx->stream_res.opp = pool->opps[tg_inst];
4327 		}
4328 
4329 		pipe_ctx->stream = stream;
4330 	} else {
4331 		pipe_idx = acquire_first_split_pipe(&new_ctx->res_ctx, pool, stream);
4332 	}
4333 
4334 	return pipe_idx != FREE_PIPE_INDEX_NOT_FOUND;
4335 }
4336 
4337 enum dc_status resource_map_pool_resources(
4338 		const struct dc  *dc,
4339 		struct dc_state *context,
4340 		struct dc_stream_state *stream)
4341 {
4342 	const struct resource_pool *pool = dc->res_pool;
4343 	int i;
4344 	struct dc_context *dc_ctx = dc->ctx;
4345 	struct pipe_ctx *pipe_ctx = NULL;
4346 	int pipe_idx = -1;
4347 	bool acquired = false;
4348 	bool is_dio_encoder = true;
4349 
4350 	calculate_phy_pix_clks(stream);
4351 
4352 	mark_seamless_boot_stream(dc, stream);
4353 
4354 	if (stream->apply_seamless_boot_optimization) {
4355 		pipe_idx = acquire_resource_from_hw_enabled_state(
4356 				&context->res_ctx,
4357 				pool,
4358 				stream);
4359 		if (pipe_idx < 0)
4360 			/* hw resource was assigned to other stream */
4361 			stream->apply_seamless_boot_optimization = false;
4362 		else
4363 			acquired = true;
4364 	}
4365 
4366 	if (!acquired)
4367 		/* acquire new resources */
4368 		acquired = acquire_otg_master_pipe_for_stream(dc->current_state,
4369 				context, pool, stream);
4370 
4371 	pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
4372 
4373 	if (!pipe_ctx || pipe_ctx->stream_res.tg == NULL)
4374 		return DC_NO_CONTROLLER_RESOURCE;
4375 
4376 	pipe_ctx->stream_res.stream_enc =
4377 		dc->res_pool->funcs->find_first_free_match_stream_enc_for_link(
4378 			&context->res_ctx, pool, stream);
4379 
4380 	if (!pipe_ctx->stream_res.stream_enc)
4381 		return DC_NO_STREAM_ENC_RESOURCE;
4382 
4383 	update_stream_engine_usage(
4384 		&context->res_ctx, pool,
4385 		pipe_ctx->stream_res.stream_enc,
4386 		true);
4387 
4388 	if (dc_is_hdmi_frl_signal(stream->signal)) {
4389 		is_dio_encoder = false;
4390 		pipe_ctx->stream_res.hpo_frl_stream_enc =
4391 			find_first_free_match_hpo_frl_stream_enc_for_link(
4392 				&context->res_ctx, pool, stream);
4393 
4394 		if (!pipe_ctx->stream_res.hpo_frl_stream_enc)
4395 			if (stream->timing.pix_clk_100hz < 6000000)
4396 				stream->signal = SIGNAL_TYPE_HDMI_TYPE_A;
4397 			else
4398 				return DC_NO_STREAM_ENC_RESOURCE;
4399 		else {
4400 			update_hpo_frl_stream_engine_usage(
4401 				&context->res_ctx, pool,
4402 				pipe_ctx->stream_res.hpo_frl_stream_enc,
4403 				true);
4404 			pipe_ctx->link_res.hpo_frl_link_enc =
4405 				pipe_ctx->stream->link->hpo_frl_link_enc;
4406 			if (!pipe_ctx->link_res.hpo_frl_link_enc) {
4407 				if (!add_hpo_frl_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream))
4408 					return DC_NO_LINK_ENC_RESOURCE;
4409 			}
4410 			if (!add_dio_link_enc_to_ctx(dc, context, pool, pipe_ctx, stream))
4411 				return DC_NO_LINK_ENC_RESOURCE;
4412 		}
4413 	}
4414 
4415 	/* Allocate DP HPO Stream Encoder based on signal, hw capabilities
4416 	 * and link settings
4417 	 */
4418 	if (dc_is_dp_signal(stream->signal) ||
4419 			dc_is_virtual_signal(stream->signal)) {
4420 		if (!dc->link_srv->dp_decide_link_settings(stream,
4421 				&pipe_ctx->link_config.dp_link_settings))
4422 			return DC_FAIL_DP_LINK_BANDWIDTH;
4423 
4424 		dc->link_srv->dp_decide_tunnel_settings(stream,
4425 				&pipe_ctx->link_config.dp_tunnel_settings);
4426 
4427 		if (dc->link_srv->dp_get_encoding_format(
4428 				&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
4429 			pipe_ctx->stream_res.hpo_dp_stream_enc =
4430 					find_first_free_match_hpo_dp_stream_enc_for_link(
4431 							&context->res_ctx, pool, stream);
4432 
4433 			if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
4434 				return DC_NO_STREAM_ENC_RESOURCE;
4435 
4436 			update_hpo_dp_stream_engine_usage(
4437 					&context->res_ctx, pool,
4438 					pipe_ctx->stream_res.hpo_dp_stream_enc,
4439 					true);
4440 			if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream))
4441 				return DC_NO_LINK_ENC_RESOURCE;
4442 		}
4443 	}
4444 
4445 	if (dc->config.unify_link_enc_assignment && is_dio_encoder)
4446 		if (!add_dio_link_enc_to_ctx(dc, context, pool, pipe_ctx, stream))
4447 			return DC_NO_LINK_ENC_RESOURCE;
4448 
4449 	/* TODO: Add check if ASIC support and EDID audio */
4450 	if (!stream->converter_disable_audio &&
4451 	    dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
4452 	    stream->audio_info.mode_count &&
4453 		(stream->audio_info.flags.all ||
4454 		(stream->sink && stream->sink->edid_caps.panel_patch.skip_audio_sab_check))) {
4455 		pipe_ctx->stream_res.audio = find_first_free_audio(
4456 		&context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id, dc_ctx->dce_version);
4457 
4458 		/*
4459 		 * Audio assigned in order first come first get.
4460 		 * There are asics which has number of audio
4461 		 * resources less then number of pipes
4462 		 */
4463 		if (pipe_ctx->stream_res.audio)
4464 			update_audio_usage(&context->res_ctx, pool,
4465 					   pipe_ctx->stream_res.audio, true);
4466 	}
4467 
4468 	/* Add ABM to the resource if on EDP */
4469 	if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) {
4470 		if (pool->abm)
4471 			pipe_ctx->stream_res.abm = pool->abm;
4472 		else
4473 			pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst];
4474 	}
4475 
4476 	for (i = 0; i < context->stream_count; i++)
4477 		if (context->streams[i] == stream) {
4478 			context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst;
4479 			context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->stream_enc_inst;
4480 			if (pipe_ctx->stream_res.hpo_frl_stream_enc != NULL)
4481 				context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.hpo_frl_stream_enc->stream_enc_inst;
4482 			context->stream_status[i].audio_inst =
4483 				pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1;
4484 
4485 			return DC_OK;
4486 		}
4487 
4488 	DC_ERROR("Stream %p not found in new ctx!\n", stream);
4489 	return DC_ERROR_UNEXPECTED;
4490 }
4491 
4492 bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
4493 {
4494 	if (dc->res_pool == NULL)
4495 		return false;
4496 
4497 	return dc->res_pool->res_cap->num_dsc > 0;
4498 }
4499 
4500 static bool planes_changed_for_existing_stream(struct dc_state *context,
4501 					       struct dc_stream_state *stream,
4502 					       const struct dc_validation_set *set)
4503 {
4504 	unsigned int i, j;
4505 	struct dc_stream_status *stream_status = NULL;
4506 
4507 	for (i = 0; i < context->stream_count; i++) {
4508 		if (context->streams[i] == stream) {
4509 			stream_status = &context->stream_status[i];
4510 			break;
4511 		}
4512 	}
4513 
4514 	if (!stream_status) {
4515 		ASSERT(0);
4516 		return false;
4517 	}
4518 
4519 	for (i = 0; i < set->stream_count; i++)
4520 		if (set->streams[i].stream == stream)
4521 			break;
4522 
4523 	if (i == set->stream_count)
4524 		ASSERT(0);
4525 
4526 	if (set->streams[i].plane_count != stream_status->plane_count)
4527 		return true;
4528 
4529 	for (j = 0; j < set->streams[i].plane_count; j++)
4530 		if (set->streams[i].plane_states[j] != stream_status->plane_states[j])
4531 			return true;
4532 
4533 	return false;
4534 }
4535 
4536 static bool add_all_planes_for_stream(
4537 		const struct dc *dc,
4538 		struct dc_stream_state *stream,
4539 		const struct dc_validation_set *set,
4540 		struct dc_state *state)
4541 {
4542 	unsigned int i, j;
4543 
4544 	for (i = 0; i < set->stream_count; i++)
4545 		if (set->streams[i].stream == stream)
4546 			break;
4547 
4548 	if (i == set->stream_count) {
4549 		dm_error("Stream %p not found in set!\n", stream);
4550 		return false;
4551 	}
4552 
4553 	for (j = 0; j < set->streams[i].plane_count; j++)
4554 		if (!dc_state_add_plane(dc, stream, set->streams[i].plane_states[j], state))
4555 			return false;
4556 
4557 	return true;
4558 }
4559 
4560 /**
4561  * resource_validate_probe_set - Validate a probe descriptor set against the ASIC.
4562  * @dc:          DC instance providing the HWSS capability hooks
4563  * @probes:      desired probe descriptors
4564  * @probe_count: number of valid entries in @probes
4565  *
4566  * Return: DC_OK if achievable, otherwise a DC error.
4567  */
4568 enum dc_status resource_validate_probe_set(struct dc *dc,
4569 		const struct dc_probe_state *probes,
4570 		uint8_t probe_count)
4571 {
4572 	uint8_t i;
4573 
4574 	if (probe_count == 0)
4575 		return DC_OK;
4576 
4577 	if (!dc->hwss.program_perfmon)
4578 		return DC_NOT_SUPPORTED;
4579 
4580 	if (probe_count > MAX_PROBES)
4581 		return DC_NOT_SUPPORTED;
4582 
4583 	for (i = 0; i < probe_count; i++) {
4584 		switch (probes[i].type) {
4585 		/* These global probes support a one-frame measurement and reset. */
4586 		case DC_PROBE_PEAK_MEM_BW:
4587 		case DC_PROBE_PEAK_MEM_BW_STRESSED:
4588 		case DC_PROBE_AVG_MEM_BW:
4589 		case DC_PROBE_MEM_LATENCY:
4590 		case DC_PROBE_PREFETCH_DATA_SIZE:
4591 			if (probes[i].scope.type != DC_PROBE_SCOPE_GLOBAL)
4592 				return DC_NOT_SUPPORTED;
4593 			if (probes[i].target_state != DC_PROBE_NOT_MEASURING &&
4594 					probes[i].target_state != DC_PROBE_MEASURED)
4595 				return DC_NOT_SUPPORTED;
4596 			break;
4597 		/* The global urgent assertion counter additionally supports polling. */
4598 		case DC_PROBE_URGENT_ASSERTION_COUNT:
4599 			if (probes[i].scope.type != DC_PROBE_SCOPE_GLOBAL)
4600 				return DC_NOT_SUPPORTED;
4601 			if (probes[i].target_state != DC_PROBE_NOT_MEASURING &&
4602 					probes[i].target_state != DC_PROBE_MEASURING &&
4603 					probes[i].target_state != DC_PROBE_MEASURED)
4604 				return DC_NOT_SUPPORTED;
4605 			break;
4606 		default:
4607 			return DC_NOT_SUPPORTED;
4608 		}
4609 
4610 		if (probes[i].type == DC_PROBE_PEAK_MEM_BW_STRESSED &&
4611 				!dc->res_pool->lsdma_scratch.buffer)
4612 			return DC_NO_DRAM_BUFFER_RESOURCE;
4613 	}
4614 
4615 	return DC_OK;
4616 }
4617 
4618 /**
4619  * dc_validate_with_context - Validate and update the potential new stream in the context object
4620  *
4621  * @dc: Used to get the current state status
4622  * @set: Root validation object holding all streams and their planes
4623  * @context: New context
4624  * @validate_mode: identify the validation mode
4625  *
4626  * This function updates the potential new stream in the context object. It
4627  * creates multiple lists for the add, remove, and unchanged streams. In
4628  * particular, if the unchanged streams have a plane that changed, it is
4629  * necessary to remove all planes from the unchanged streams. In summary, this
4630  * function is responsible for validating the new context.
4631  *
4632  * Return:
4633  * In case of success, return DC_OK (1), otherwise, return a DC error.
4634  */
4635 enum dc_status dc_validate_with_context(struct dc *dc,
4636 					const struct dc_validation_set *set,
4637 					struct dc_state *context,
4638 					enum dc_validate_mode validate_mode)
4639 {
4640 	struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 };
4641 	struct dc_stream_state *del_streams[MAX_PIPES] = { 0 };
4642 	struct dc_stream_state *add_streams[MAX_PIPES] = { 0 };
4643 	unsigned int old_stream_count = context->stream_count;
4644 	enum dc_status res = DC_ERROR_UNEXPECTED;
4645 	unsigned int unchanged_streams_count = 0;
4646 	unsigned int del_streams_count = 0;
4647 	unsigned int add_streams_count = 0;
4648 	bool found = false;
4649 	unsigned int i, j, k;
4650 
4651 	DC_LOGGER_INIT(dc->ctx->logger);
4652 
4653 	/* First build a list of streams to be remove from current context */
4654 	for (i = 0; i < old_stream_count; i++) {
4655 		struct dc_stream_state *stream = context->streams[i];
4656 
4657 		for (j = 0; j < set->stream_count; j++) {
4658 			if (stream == set->streams[j].stream) {
4659 				found = true;
4660 				break;
4661 			}
4662 		}
4663 
4664 		if (!found)
4665 			del_streams[del_streams_count++] = stream;
4666 
4667 		found = false;
4668 	}
4669 
4670 	/* Second, build a list of new streams */
4671 	for (i = 0; i < set->stream_count; i++) {
4672 		struct dc_stream_state *stream = set->streams[i].stream;
4673 
4674 		for (j = 0; j < old_stream_count; j++) {
4675 			if (stream == context->streams[j]) {
4676 				found = true;
4677 				break;
4678 			}
4679 		}
4680 
4681 		if (!found)
4682 			add_streams[add_streams_count++] = stream;
4683 
4684 		found = false;
4685 	}
4686 
4687 	/* Build a list of unchanged streams which is necessary for handling
4688 	 * planes change such as added, removed, and updated.
4689 	 */
4690 	for (i = 0; i < set->stream_count; i++) {
4691 		/* Check if stream is part of the delete list */
4692 		for (j = 0; j < del_streams_count; j++) {
4693 			if (set->streams[i].stream == del_streams[j]) {
4694 				found = true;
4695 				break;
4696 			}
4697 		}
4698 
4699 		if (!found) {
4700 			/* Check if stream is part of the add list */
4701 			for (j = 0; j < add_streams_count; j++) {
4702 				if (set->streams[i].stream == add_streams[j]) {
4703 					found = true;
4704 					break;
4705 				}
4706 			}
4707 		}
4708 
4709 		if (!found)
4710 			unchanged_streams[unchanged_streams_count++] = set->streams[i].stream;
4711 
4712 		found = false;
4713 	}
4714 
4715 	/* Remove all planes for unchanged streams if planes changed */
4716 	for (i = 0; i < unchanged_streams_count; i++) {
4717 		if (planes_changed_for_existing_stream(context,
4718 						       unchanged_streams[i],
4719 						       set)) {
4720 
4721 			if (!dc_state_rem_all_planes_for_stream(dc,
4722 							  unchanged_streams[i],
4723 							  context)) {
4724 				res = DC_FAIL_DETACH_SURFACES;
4725 				goto fail;
4726 			}
4727 		}
4728 	}
4729 
4730 	/* Remove all planes for removed streams and then remove the streams */
4731 	for (i = 0; i < del_streams_count; i++) {
4732 		/* Need to cpy the dwb data from the old stream in order to efc to work */
4733 		if (del_streams[i]->num_wb_info > 0) {
4734 			for (j = 0; j < add_streams_count; j++) {
4735 				if (del_streams[i]->sink == add_streams[j]->sink) {
4736 					add_streams[j]->num_wb_info = del_streams[i]->num_wb_info;
4737 					for (k = 0; k < del_streams[i]->num_wb_info; k++)
4738 						add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k];
4739 				}
4740 			}
4741 		}
4742 
4743 		if (dc_state_get_stream_subvp_type(context, del_streams[i]) == SUBVP_PHANTOM) {
4744 			/* remove phantoms specifically */
4745 			if (!dc_state_rem_all_phantom_planes_for_stream(dc, del_streams[i], context, true)) {
4746 				res = DC_FAIL_DETACH_SURFACES;
4747 				goto fail;
4748 			}
4749 
4750 			res = dc_state_remove_phantom_stream(dc, context, del_streams[i]);
4751 			dc_state_release_phantom_stream(dc, context, del_streams[i]);
4752 		} else {
4753 			if (!dc_state_rem_all_planes_for_stream(dc, del_streams[i], context)) {
4754 				res = DC_FAIL_DETACH_SURFACES;
4755 				goto fail;
4756 			}
4757 
4758 			res = dc_state_remove_stream(dc, context, del_streams[i]);
4759 		}
4760 
4761 		if (res != DC_OK)
4762 			goto fail;
4763 	}
4764 
4765 	/* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx
4766 	 * matches. This may change in the future if seamless_boot_stream can be
4767 	 * multiple.
4768 	 */
4769 	for (i = 0; i < add_streams_count; i++) {
4770 		mark_seamless_boot_stream(dc, add_streams[i]);
4771 		if (add_streams[i]->apply_seamless_boot_optimization && i != 0) {
4772 			struct dc_stream_state *temp = add_streams[0];
4773 
4774 			add_streams[0] = add_streams[i];
4775 			add_streams[i] = temp;
4776 			break;
4777 		}
4778 	}
4779 
4780 	/* Add new streams and then add all planes for the new stream */
4781 	for (i = 0; i < add_streams_count; i++) {
4782 		calculate_phy_pix_clks(add_streams[i]);
4783 		res = dc_state_add_stream(dc, context, add_streams[i]);
4784 		if (res != DC_OK)
4785 			goto fail;
4786 
4787 		if (!add_all_planes_for_stream(dc, add_streams[i], set, context)) {
4788 			res = DC_FAIL_ATTACH_SURFACES;
4789 			goto fail;
4790 		}
4791 	}
4792 
4793 	/* Add all planes for unchanged streams if planes changed */
4794 	for (i = 0; i < unchanged_streams_count; i++) {
4795 		if (planes_changed_for_existing_stream(context,
4796 						       unchanged_streams[i],
4797 						       set)) {
4798 			if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, context)) {
4799 				res = DC_FAIL_ATTACH_SURFACES;
4800 				goto fail;
4801 			}
4802 		}
4803 	}
4804 
4805 	/* clear subvp cursor limitations */
4806 	for (i = 0; i < context->stream_count; i++) {
4807 		dc_state_set_stream_subvp_cursor_limit(context->streams[i], context, false);
4808 	}
4809 
4810 	res = dc_validate_global_state(dc, context, validate_mode);
4811 
4812 	/* calculate pixel rate divider after deciding pxiel clock & odm combine  */
4813 	if ((dc->hwss.calculate_pix_rate_divider) && (res == DC_OK)) {
4814 		for (i = 0; i < add_streams_count; i++)
4815 			dc->hwss.calculate_pix_rate_divider(dc, context, add_streams[i]);
4816 	}
4817 
4818 fail:
4819 	if (res != DC_OK)
4820 		DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n",
4821 			       __func__,
4822 			       res);
4823 
4824 	return res;
4825 }
4826 
4827 #if defined(CONFIG_DRM_AMD_DC_FP)
4828 /**
4829  * dc_update_modified_pix_clock_for_dsc_with_padding() - update pix_clk for dsc with padding
4830  *
4831  * @stream: Pointer to the stream structure.
4832  * @timing: Pointer to the stream dc_crtc_timing structure.
4833  * @dsc_padding_params: Pointer to the DSC padding parameters structure.
4834  *
4835  * This function updated the pix_clk for dsc with padding stored in pipe_ctx
4836  * such that the OTG h_active time fits withing the expected compressed active
4837  * time calculated according to HDMI spec. H_total is then increased to
4838  * maintain the same OTG line time as before the increased pix_clk.
4839  */
4840 static void dc_update_modified_pix_clock_for_dsc_with_padding(const struct dc_stream_state *stream,
4841 		const struct dc_crtc_timing *timing, struct dsc_padding_params *dsc_padding_params)
4842 {
4843 	DC_FP_START();
4844 	frl_modified_pix_clock_for_dsc_padding(stream->link->frl_verified_link_cap.borrow_params.hc_active_target,
4845 	stream->link->frl_verified_link_cap.borrow_params.hc_blank_target,
4846 	stream->link->frl_verified_link_cap.frl_num_lanes,
4847 	timing->pix_clk_100hz,
4848 	stream->link->frl_verified_link_cap.frl_link_rate,
4849 	timing->h_addressable,
4850 	timing->h_border_left,
4851 	timing->h_border_right,
4852 	timing->h_total,
4853 	(timing->h_addressable + dsc_padding_params->dsc_hactive_padding),
4854 	&dsc_padding_params->dsc_pix_clk_100hz,
4855 	&dsc_padding_params->dsc_htotal_padding);
4856 	DC_FP_END();
4857 
4858 	dsc_padding_params->dsc_htotal_padding = dsc_padding_params->dsc_htotal_padding - timing->h_total;
4859 }
4860 #endif /* CONFIG_DRM_AMD_DC_FP */
4861 
4862 /**
4863  * calculate_timing_params_for_dsc_with_padding - Calculates timing parameters for DSC with padding.
4864  * @pipe_ctx: Pointer to the pipe context structure.
4865  *
4866  * This function calculates the timing parameters for a given pipe context based on the
4867  * display stream compression (DSC) configuration. If the horizontal active pixels (hactive) are less
4868  * than the total width of the DSC slices, it sets the dsc_hactive_padding value to the difference. If the
4869  * total horizontal timing minus the dsc_hactive_padding value is less than 32, it resets the dsc_hactive_padding
4870  * value to 0.
4871  */
4872 static void calculate_timing_params_for_dsc_with_padding(struct pipe_ctx *pipe_ctx)
4873 {
4874 	struct dc_stream_state *stream = NULL;
4875 
4876 	if (!pipe_ctx)
4877 		return;
4878 
4879 	stream = pipe_ctx->stream;
4880 	pipe_ctx->dsc_padding_params.dsc_hactive_padding = 0;
4881 	pipe_ctx->dsc_padding_params.dsc_htotal_padding = 0;
4882 
4883 	if (stream)
4884 		pipe_ctx->dsc_padding_params.dsc_pix_clk_100hz = stream->timing.pix_clk_100hz;
4885 
4886 #if defined(CONFIG_DRM_AMD_DC_FP)
4887 	uint32_t hactive;
4888 	uint32_t ceil_slice_width;
4889 	if (stream && stream->timing.flags.DSC && stream->signal == SIGNAL_TYPE_HDMI_FRL) {
4890 		hactive = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
4891 
4892 		/* Assume if determined slices does not divide Hactive evenly, Hborrow is needed for padding*/
4893 		if (hactive % stream->timing.dsc_cfg.num_slices_h != 0) {
4894 			ceil_slice_width = (hactive / stream->timing.dsc_cfg.num_slices_h) + 1;
4895 
4896 			/* If YCBCR420 slice width must be even */
4897 			if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420 && ceil_slice_width % 2 != 0)
4898 				ceil_slice_width++;
4899 
4900 			pipe_ctx->dsc_padding_params.dsc_hactive_padding =
4901 				(uint8_t)(ceil_slice_width * stream->timing.dsc_cfg.num_slices_h - hactive);
4902 
4903 			if (stream->timing.h_total - hactive - pipe_ctx->dsc_padding_params.dsc_hactive_padding < 32)
4904 				pipe_ctx->dsc_padding_params.dsc_hactive_padding = 0;
4905 
4906 			dc_update_modified_pix_clock_for_dsc_with_padding(stream, &stream->timing, &pipe_ctx->dsc_padding_params);
4907 		}
4908 	}
4909 #endif
4910 }
4911 
4912 /**
4913  * dc_validate_global_state() - Determine if hardware can support a given state
4914  *
4915  * @dc: dc struct for this driver
4916  * @new_ctx: state to be validated
4917  * @validate_mode: identify the validation mode
4918  *
4919  * Checks hardware resource availability and bandwidth requirement.
4920  *
4921  * Return:
4922  * DC_OK if the result can be programmed. Otherwise, an error code.
4923  */
4924 enum dc_status dc_validate_global_state(
4925 		struct dc *dc,
4926 		struct dc_state *new_ctx,
4927 		enum dc_validate_mode validate_mode)
4928 {
4929 	enum dc_status result = DC_ERROR_UNEXPECTED;
4930 	int i;
4931 	unsigned int j;
4932 
4933 	if (!new_ctx)
4934 		return DC_ERROR_UNEXPECTED;
4935 
4936 	if (dc->res_pool->funcs->validate_global) {
4937 		result = dc->res_pool->funcs->validate_global(dc, new_ctx);
4938 		if (result != DC_OK)
4939 			return result;
4940 	}
4941 
4942 	for (i = 0; i < new_ctx->stream_count; i++) {
4943 		struct dc_stream_state *stream = new_ctx->streams[i];
4944 
4945 		for (j = 0; j < dc->res_pool->pipe_count; j++) {
4946 			struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j];
4947 
4948 			if (pipe_ctx->stream != stream)
4949 				continue;
4950 
4951 			/* Decide whether hblank borrow is needed and save it in pipe_ctx */
4952 			if (dc->debug.enable_hblank_borrow)
4953 				calculate_timing_params_for_dsc_with_padding(pipe_ctx);
4954 
4955 			if (dc->res_pool->funcs->patch_unknown_plane_state &&
4956 					pipe_ctx->plane_state &&
4957 					pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) {
4958 				result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state);
4959 				if (result != DC_OK)
4960 					return result;
4961 			}
4962 
4963 			/* Switch to dp clock source only if there is
4964 			 * no non dp stream that shares the same timing
4965 			 * with the dp stream.
4966 			 */
4967 			if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
4968 				!find_pll_sharable_stream(stream, new_ctx)) {
4969 
4970 				resource_unreference_clock_source(
4971 						&new_ctx->res_ctx,
4972 						dc->res_pool,
4973 						pipe_ctx->clock_source);
4974 
4975 				pipe_ctx->clock_source = dc->res_pool->dp_clock_source;
4976 				resource_reference_clock_source(
4977 						&new_ctx->res_ctx,
4978 						dc->res_pool,
4979 						 pipe_ctx->clock_source);
4980 			}
4981 		}
4982 	}
4983 
4984 	result = resource_build_scaling_params_for_context(dc, new_ctx);
4985 
4986 	if (result == DC_OK)
4987 		result = dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, validate_mode);
4988 
4989 	if (result == DC_OK)
4990 		result = resource_validate_probe_set(dc, new_ctx->probes,
4991 				(uint8_t)new_ctx->probe_count);
4992 
4993 	return result;
4994 }
4995 
4996 static void patch_gamut_packet_checksum(
4997 		struct dc_info_packet *gamut_packet)
4998 {
4999 	/* For gamut we recalc checksum */
5000 	if (gamut_packet->valid) {
5001 		uint8_t chk_sum = 0;
5002 		uint8_t *ptr;
5003 		uint8_t i;
5004 
5005 		/*start of the Gamut data. */
5006 		ptr = &gamut_packet->sb[3];
5007 
5008 		for (i = 0; i <= gamut_packet->sb[1]; i++)
5009 			chk_sum += ptr[i];
5010 
5011 		gamut_packet->sb[2] = (uint8_t)(0x100 - chk_sum);
5012 	}
5013 }
5014 
5015 static void set_avi_info_frame(
5016 		struct dc_info_packet *info_packet,
5017 		struct pipe_ctx *pipe_ctx)
5018 {
5019 	struct dc_stream_state *stream = pipe_ctx->stream;
5020 	enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
5021 	uint32_t pixel_encoding = 0;
5022 	enum scanning_type scan_type = SCANNING_TYPE_NODATA;
5023 	enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA;
5024 	uint8_t *check_sum = NULL;
5025 	uint8_t byte_index = 0;
5026 	union hdmi_info_packet hdmi_info;
5027 	unsigned int vic = pipe_ctx->stream->timing.vic;
5028 	unsigned int rid = pipe_ctx->stream->timing.rid;
5029 	unsigned int fr_ind = pipe_ctx->stream->timing.fr_index;
5030 	enum dc_timing_3d_format format;
5031 
5032 	if (stream->avi_infopacket.valid) {
5033 		*info_packet = stream->avi_infopacket;
5034 		return;
5035 	}
5036 
5037 	memset(&hdmi_info, 0, sizeof(union hdmi_info_packet));
5038 
5039 
5040 	color_space = pipe_ctx->stream->output_color_space;
5041 	if (color_space == COLOR_SPACE_UNKNOWN)
5042 		color_space = (stream->timing.pixel_encoding == PIXEL_ENCODING_RGB) ?
5043 			COLOR_SPACE_SRGB:COLOR_SPACE_YCBCR709;
5044 
5045 	/* Initialize header */
5046 	hdmi_info.bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI;
5047 	/* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall
5048 	* not be used in HDMI 2.0 (Section 10.1) */
5049 	hdmi_info.bits.header.version = 2;
5050 	hdmi_info.bits.header.length = HDMI_AVI_INFOFRAME_SIZE;
5051 
5052 	/*
5053 	 * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built
5054 	 * according to HDMI 2.0 spec (Section 10.1)
5055 	 */
5056 
5057 	switch (stream->timing.pixel_encoding) {
5058 	case PIXEL_ENCODING_YCBCR422:
5059 		pixel_encoding = 1;
5060 		break;
5061 
5062 	case PIXEL_ENCODING_YCBCR444:
5063 		pixel_encoding = 2;
5064 		break;
5065 	case PIXEL_ENCODING_YCBCR420:
5066 		pixel_encoding = 3;
5067 		break;
5068 
5069 	case PIXEL_ENCODING_RGB:
5070 	default:
5071 		pixel_encoding = 0;
5072 	}
5073 
5074 	/* Y0_Y1_Y2 : The pixel encoding */
5075 	/* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */
5076 	hdmi_info.bits.Y0_Y1_Y2 = (uint8_t)pixel_encoding;
5077 
5078 	/* A0 = 1 Active Format Information valid */
5079 	hdmi_info.bits.A0 = ACTIVE_FORMAT_VALID;
5080 
5081 	/* B0, B1 = 3; Bar info data is valid */
5082 	hdmi_info.bits.B0_B1 = BAR_INFO_BOTH_VALID;
5083 
5084 	hdmi_info.bits.SC0_SC1 = PICTURE_SCALING_UNIFORM;
5085 
5086 	/* S0, S1 : Underscan / Overscan */
5087 	/* TODO: un-hardcode scan type */
5088 	scan_type = SCANNING_TYPE_UNDERSCAN;
5089 	hdmi_info.bits.S0_S1 = scan_type;
5090 
5091 	/* C0, C1 : Colorimetry */
5092 	switch (color_space) {
5093 	case COLOR_SPACE_YCBCR709:
5094 	case COLOR_SPACE_YCBCR709_LIMITED:
5095 		hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
5096 		break;
5097 	case COLOR_SPACE_YCBCR601:
5098 	case COLOR_SPACE_YCBCR601_LIMITED:
5099 		hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601;
5100 		break;
5101 	case COLOR_SPACE_2020_RGB_FULLRANGE:
5102 	case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
5103 	case COLOR_SPACE_2020_YCBCR_LIMITED:
5104 		hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR;
5105 		hdmi_info.bits.C0_C1   = COLORIMETRY_EXTENDED;
5106 		break;
5107 	case COLOR_SPACE_ADOBERGB:
5108 		hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB;
5109 		hdmi_info.bits.C0_C1   = COLORIMETRY_EXTENDED;
5110 		break;
5111 	case COLOR_SPACE_SRGB:
5112 	default:
5113 		hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA;
5114 		break;
5115 	}
5116 
5117 	if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR_LIMITED &&
5118 			stream->out_transfer_func.tf == TRANSFER_FUNCTION_GAMMA22) {
5119 		hdmi_info.bits.EC0_EC2 = 0;
5120 		hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
5121 	}
5122 
5123 	/* TODO: un-hardcode aspect ratio */
5124 	aspect = stream->timing.aspect_ratio;
5125 
5126 	switch (aspect) {
5127 	case ASPECT_RATIO_4_3:
5128 	case ASPECT_RATIO_16_9:
5129 		hdmi_info.bits.M0_M1 = aspect;
5130 		break;
5131 
5132 	case ASPECT_RATIO_NO_DATA:
5133 	case ASPECT_RATIO_64_27:
5134 	case ASPECT_RATIO_256_135:
5135 	default:
5136 		hdmi_info.bits.M0_M1 = 0;
5137 	}
5138 
5139 	/* Active Format Aspect ratio - same as Picture Aspect Ratio. */
5140 	hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE;
5141 
5142 	switch (stream->content_type) {
5143 	case DISPLAY_CONTENT_TYPE_NO_DATA:
5144 		hdmi_info.bits.CN0_CN1 = 0;
5145 		hdmi_info.bits.ITC = 1;
5146 		break;
5147 	case DISPLAY_CONTENT_TYPE_GRAPHICS:
5148 		hdmi_info.bits.CN0_CN1 = 0;
5149 		hdmi_info.bits.ITC = 1;
5150 		break;
5151 	case DISPLAY_CONTENT_TYPE_PHOTO:
5152 		hdmi_info.bits.CN0_CN1 = 1;
5153 		hdmi_info.bits.ITC = 1;
5154 		break;
5155 	case DISPLAY_CONTENT_TYPE_CINEMA:
5156 		hdmi_info.bits.CN0_CN1 = 2;
5157 		hdmi_info.bits.ITC = 1;
5158 		break;
5159 	case DISPLAY_CONTENT_TYPE_GAME:
5160 		hdmi_info.bits.CN0_CN1 = 3;
5161 		hdmi_info.bits.ITC = 1;
5162 		break;
5163 	}
5164 
5165 	if (stream->qs_bit == 1) {
5166 		if (color_space == COLOR_SPACE_SRGB ||
5167 			color_space == COLOR_SPACE_2020_RGB_FULLRANGE)
5168 			hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_FULL_RANGE;
5169 		else if (color_space == COLOR_SPACE_SRGB_LIMITED ||
5170 					color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)
5171 			hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_LIMITED_RANGE;
5172 		else
5173 			hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_DEFAULT_RANGE;
5174 	} else
5175 		hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_DEFAULT_RANGE;
5176 
5177 	/* TODO : We should handle YCC quantization */
5178 	/* but we do not have matrix calculation */
5179 	hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
5180 
5181 	///VIC
5182 	if (pipe_ctx->stream->timing.hdmi_vic != 0)
5183 		vic = 0;
5184 	format = stream->timing.timing_3d_format;
5185 	/*todo, add 3DStereo support*/
5186 	if (format != TIMING_3D_FORMAT_NONE) {
5187 		// Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
5188 		switch (pipe_ctx->stream->timing.hdmi_vic) {
5189 		case 1:
5190 			vic = 95;
5191 			break;
5192 		case 2:
5193 			vic = 94;
5194 			break;
5195 		case 3:
5196 			vic = 93;
5197 			break;
5198 		case 4:
5199 			vic = 98;
5200 			break;
5201 		default:
5202 			break;
5203 		}
5204 	}
5205 	/* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/
5206 	hdmi_info.bits.VIC0_VIC7 = (uint8_t)vic;
5207 	if (vic >= 128)
5208 		hdmi_info.bits.header.version = 3;
5209 	/* If (C1, C0)=(1, 1) and (EC2, EC1, EC0)=(1, 1, 1),
5210 	 * the Source shall use 20 AVI InfoFrame Version 4
5211 	 */
5212 	if (hdmi_info.bits.C0_C1 == COLORIMETRY_EXTENDED &&
5213 			hdmi_info.bits.EC0_EC2 == COLORIMETRYEX_RESERVED) {
5214 		hdmi_info.bits.header.version = 4;
5215 		hdmi_info.bits.header.length = 14;
5216 	}
5217 
5218 	if (rid != 0 && fr_ind != 0) {
5219 		hdmi_info.bits.header.version = 4;
5220 		hdmi_info.bits.header.length = 15;
5221 
5222 		hdmi_info.bits.FR0_FR3 = fr_ind & 0xF;
5223 		hdmi_info.bits.FR4 = (fr_ind >> 4) & 0x1;
5224 		hdmi_info.bits.RID0_RID5 = (uint8_t)rid;
5225 	}
5226 
5227 	/* pixel repetition
5228 	 * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel
5229 	 * repetition start from 1 */
5230 	hdmi_info.bits.PR0_PR3 = 0;
5231 
5232 	/* Bar Info
5233 	 * barTop:    Line Number of End of Top Bar.
5234 	 * barBottom: Line Number of Start of Bottom Bar.
5235 	 * barLeft:   Pixel Number of End of Left Bar.
5236 	 * barRight:  Pixel Number of Start of Right Bar. */
5237 	hdmi_info.bits.bar_top = (uint16_t)stream->timing.v_border_top;
5238 	hdmi_info.bits.bar_bottom = (uint16_t)(stream->timing.v_total
5239 			- stream->timing.v_border_bottom + 1);
5240 	hdmi_info.bits.bar_left  = (uint16_t)stream->timing.h_border_left;
5241 	hdmi_info.bits.bar_right = (uint16_t)(stream->timing.h_total
5242 			- stream->timing.h_border_right + 1);
5243 
5244     /* Additional Colorimetry Extension
5245      * Used in conduction with C0-C1 and EC0-EC2
5246      * 0 = DCI-P3 RGB (D65)
5247      * 1 = DCI-P3 RGB (theater)
5248      */
5249 	hdmi_info.bits.ACE0_ACE3 = 0;
5250 
5251 	/* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */
5252 	check_sum = &hdmi_info.packet_raw_data.sb[0];
5253 
5254 	*check_sum = HDMI_INFOFRAME_TYPE_AVI + hdmi_info.bits.header.length + hdmi_info.bits.header.version;
5255 
5256 	for (byte_index = 1; byte_index <= hdmi_info.bits.header.length; byte_index++)
5257 		*check_sum += hdmi_info.packet_raw_data.sb[byte_index];
5258 
5259 	/* one byte complement */
5260 	*check_sum = (uint8_t)(0x100 - *check_sum);
5261 
5262 	/* Store in hw_path_mode */
5263 	info_packet->hb0 = hdmi_info.packet_raw_data.hb0;
5264 	info_packet->hb1 = hdmi_info.packet_raw_data.hb1;
5265 	info_packet->hb2 = hdmi_info.packet_raw_data.hb2;
5266 
5267 	for (byte_index = 0; byte_index < sizeof(hdmi_info.packet_raw_data.sb); byte_index++)
5268 		info_packet->sb[byte_index] = hdmi_info.packet_raw_data.sb[byte_index];
5269 
5270 	info_packet->valid = true;
5271 }
5272 
5273 static void set_vendor_info_packet(
5274 		struct dc_info_packet *info_packet,
5275 		struct dc_stream_state *stream)
5276 {
5277 	/* SPD info packet for FreeSync */
5278 
5279 	/* Check if Freesync is supported. Return if false. If true,
5280 	 * set the corresponding bit in the info packet
5281 	 */
5282 	if (!stream->vsp_infopacket.valid)
5283 		return;
5284 
5285 	*info_packet = stream->vsp_infopacket;
5286 }
5287 
5288 static void set_spd_info_packet(
5289 		struct dc_info_packet *info_packet,
5290 		struct dc_stream_state *stream)
5291 {
5292 	/* SPD info packet for FreeSync */
5293 
5294 	/* Check if Freesync is supported. Return if false. If true,
5295 	 * set the corresponding bit in the info packet
5296 	 */
5297 	if (!stream->vrr_infopacket.valid)
5298 		return;
5299 
5300 	*info_packet = stream->vrr_infopacket;
5301 }
5302 
5303 static void set_hdr_static_info_packet(
5304 		struct dc_info_packet *info_packet,
5305 		struct dc_stream_state *stream)
5306 {
5307 	/* HDR Static Metadata info packet for HDR10 */
5308 
5309 	if (!stream->hdr_static_metadata.valid ||
5310 			stream->use_dynamic_meta)
5311 		return;
5312 
5313 	*info_packet = stream->hdr_static_metadata;
5314 }
5315 
5316 static void set_vsc_info_packet(
5317 		struct dc_info_packet *info_packet,
5318 		struct dc_stream_state *stream)
5319 {
5320 	if (!stream->vsc_infopacket.valid)
5321 		return;
5322 
5323 	*info_packet = stream->vsc_infopacket;
5324 }
5325 static void set_hfvs_info_packet(
5326 		struct dc_info_packet *info_packet,
5327 		struct dc_stream_state *stream)
5328 {
5329 	if (!stream->hfvsif_infopacket.valid)
5330 		return;
5331 
5332 	*info_packet = stream->hfvsif_infopacket;
5333 }
5334 
5335 static void adaptive_sync_override_dp_info_packets_sdp_line_num(
5336 		const struct dc_crtc_timing *timing,
5337 		struct enc_sdp_line_num *sdp_line_num,
5338 		unsigned int vstartup_start)
5339 {
5340 	uint32_t asic_blank_start = 0;
5341 	uint32_t asic_blank_end   = 0;
5342 	uint32_t v_update = 0;
5343 
5344 	const struct dc_crtc_timing *tg = timing;
5345 
5346 	/* blank_start = frame end - front porch */
5347 	asic_blank_start = tg->v_total - tg->v_front_porch;
5348 
5349 	/* blank_end = blank_start - active */
5350 	asic_blank_end = (asic_blank_start - tg->v_border_bottom -
5351 						tg->v_addressable - tg->v_border_top);
5352 
5353 	if (vstartup_start > asic_blank_end) {
5354 		v_update = (tg->v_total - (vstartup_start - asic_blank_end));
5355 		sdp_line_num->adaptive_sync_line_num_valid = true;
5356 		sdp_line_num->adaptive_sync_line_num = (tg->v_total - v_update - 1);
5357 	} else {
5358 		sdp_line_num->adaptive_sync_line_num_valid = false;
5359 		sdp_line_num->adaptive_sync_line_num = 0;
5360 	}
5361 }
5362 
5363 static void set_adaptive_sync_info_packet(
5364 		struct dc_info_packet *info_packet,
5365 		const struct dc_stream_state *stream,
5366 		struct encoder_info_frame *info_frame,
5367 		unsigned int vstartup_start)
5368 {
5369 	if (!stream->adaptive_sync_infopacket.valid)
5370 		return;
5371 
5372 	adaptive_sync_override_dp_info_packets_sdp_line_num(
5373 			&stream->timing,
5374 			&info_frame->sdp_line_num,
5375 			vstartup_start);
5376 
5377 	*info_packet = stream->adaptive_sync_infopacket;
5378 }
5379 
5380 static void set_vtem_info_packet(
5381 		struct dc_info_packet *info_packet,
5382 		struct dc_stream_state *stream)
5383 {
5384 	if (!stream->vtem_infopacket.valid)
5385 		return;
5386 
5387 	*info_packet = stream->vtem_infopacket;
5388 }
5389 
5390 struct clock_source *dc_resource_find_first_free_pll(
5391 		struct resource_context *res_ctx,
5392 		const struct resource_pool *pool)
5393 {
5394 	unsigned int i;
5395 
5396 	for (i = 0; i < pool->clk_src_count; ++i) {
5397 		if (res_ctx->clock_source_ref_count[i] == 0)
5398 			return pool->clock_sources[i];
5399 	}
5400 
5401 	return NULL;
5402 }
5403 
5404 void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
5405 {
5406 	enum signal_type signal = SIGNAL_TYPE_NONE;
5407 	struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame;
5408 	unsigned int vstartup_start = 0;
5409 
5410 	/* default all packets to invalid */
5411 	info->avi.valid = false;
5412 	info->gamut.valid = false;
5413 	info->vendor.valid = false;
5414 	info->spd.valid = false;
5415 	info->hdrsmd.valid = false;
5416 	info->vsc.valid = false;
5417 	info->hfvsif.valid = false;
5418 	info->vtem.valid = false;
5419 	info->adaptive_sync.valid = false;
5420 	signal = pipe_ctx->stream->signal;
5421 
5422 	if (pipe_ctx->stream->ctx->dc->res_pool->funcs->get_vstartup_for_pipe)
5423 		vstartup_start = pipe_ctx->stream->ctx->dc->res_pool->funcs->get_vstartup_for_pipe(pipe_ctx);
5424 
5425 	/* HDMi and DP have different info packets*/
5426 	if (dc_is_hdmi_signal(signal)) {
5427 		set_avi_info_frame(&info->avi, pipe_ctx);
5428 
5429 		set_vendor_info_packet(&info->vendor, pipe_ctx->stream);
5430 		set_hfvs_info_packet(&info->hfvsif, pipe_ctx->stream);
5431 		set_vtem_info_packet(&info->vtem, pipe_ctx->stream);
5432 
5433 		set_spd_info_packet(&info->spd, pipe_ctx->stream);
5434 
5435 		set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
5436 
5437 		if (dc_is_hdmi_frl_signal(signal)) {
5438 			/* TODO: additional packets for HDMI 2.1 */
5439 		}
5440 	} else if (dc_is_dp_signal(signal)) {
5441 		set_vsc_info_packet(&info->vsc, pipe_ctx->stream);
5442 
5443 		set_spd_info_packet(&info->spd, pipe_ctx->stream);
5444 
5445 		set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
5446 		set_adaptive_sync_info_packet(&info->adaptive_sync,
5447 										pipe_ctx->stream,
5448 										info,
5449 										vstartup_start);
5450 	}
5451 
5452 	patch_gamut_packet_checksum(&info->gamut);
5453 }
5454 
5455 /*
5456  * Physical-clock resource mapping used by the DCE and DCN resource pools.
5457  * Unit tests provide their own stub (see dc_resource_ut_helpers.c).
5458  */
5459 enum {
5460 	CLK_SRC_PLL0 = 0,
5461 	CLK_SRC_PLL1,
5462 	CLK_SRC_PLL2,
5463 	CLK_SRC_PLL3,
5464 	CLK_SRC_PLL4,
5465 	CLK_SRC_PLL5,
5466 };
5467 
5468 static struct clock_source *find_matching_pll(
5469 		struct resource_context *res_ctx,
5470 		const struct resource_pool *pool,
5471 		const struct dc_stream_state *const stream)
5472 {
5473 	(void)res_ctx;
5474 	switch (stream->link->link_enc->transmitter) {
5475 	case TRANSMITTER_UNIPHY_A:
5476 		return pool->clock_sources[CLK_SRC_PLL0];
5477 	case TRANSMITTER_UNIPHY_B:
5478 		return pool->clock_sources[CLK_SRC_PLL1];
5479 	case TRANSMITTER_UNIPHY_C:
5480 		return pool->clock_sources[CLK_SRC_PLL2];
5481 	case TRANSMITTER_UNIPHY_D:
5482 		return pool->clock_sources[CLK_SRC_PLL3];
5483 	case TRANSMITTER_UNIPHY_E:
5484 		return pool->clock_sources[CLK_SRC_PLL4];
5485 	case TRANSMITTER_UNIPHY_F:
5486 		return pool->clock_sources[CLK_SRC_PLL5];
5487 	default:
5488 		return NULL;
5489 	}
5490 }
5491 
5492 enum dc_status resource_map_phy_clock_resources(
5493 		const struct dc *dc,
5494 		struct dc_state *context,
5495 		struct dc_stream_state *stream)
5496 {
5497 
5498 	/* acquire new resources */
5499 	struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(
5500 			&context->res_ctx, stream);
5501 
5502 	if (!pipe_ctx)
5503 		return DC_ERROR_UNEXPECTED;
5504 
5505 	if (dc_is_dp_signal(pipe_ctx->stream->signal)
5506 		|| dc_is_virtual_signal(pipe_ctx->stream->signal))
5507 		pipe_ctx->clock_source =
5508 				dc->res_pool->dp_clock_source;
5509 	else if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL)
5510 			pipe_ctx->clock_source =
5511 				dc->res_pool->dp_clock_source;
5512 	else {
5513 		if (stream && stream->link && stream->link->link_enc)
5514 			pipe_ctx->clock_source = find_matching_pll(
5515 				&context->res_ctx, dc->res_pool,
5516 				stream);
5517 	}
5518 
5519 	if (pipe_ctx->clock_source == NULL)
5520 		return DC_NO_CLOCK_SOURCE_RESOURCE;
5521 
5522 	resource_reference_clock_source(
5523 		&context->res_ctx,
5524 		dc->res_pool,
5525 		pipe_ctx->clock_source);
5526 
5527 	return DC_OK;
5528 }
5529 
5530 enum dc_status resource_map_clock_resources(
5531 		const struct dc  *dc,
5532 		struct dc_state *context,
5533 		struct dc_stream_state *stream)
5534 {
5535 	/* acquire new resources */
5536 	const struct resource_pool *pool = dc->res_pool;
5537 	struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(
5538 				&context->res_ctx, stream);
5539 
5540 	if (!pipe_ctx)
5541 		return DC_ERROR_UNEXPECTED;
5542 
5543 	if (dc_is_dp_signal(pipe_ctx->stream->signal)
5544 		|| pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
5545 		pipe_ctx->clock_source = pool->dp_clock_source;
5546 	else {
5547 		pipe_ctx->clock_source = NULL;
5548 
5549 		if (!dc->config.disable_disp_pll_sharing)
5550 			pipe_ctx->clock_source = resource_find_used_clk_src_for_sharing(
5551 				&context->res_ctx,
5552 				pipe_ctx);
5553 
5554 		if (pipe_ctx->clock_source == NULL)
5555 			pipe_ctx->clock_source =
5556 				dc_resource_find_first_free_pll(
5557 					&context->res_ctx,
5558 					pool);
5559 	}
5560 
5561 	if (pipe_ctx->clock_source == NULL)
5562 		return DC_NO_CLOCK_SOURCE_RESOURCE;
5563 
5564 	resource_reference_clock_source(
5565 		&context->res_ctx, pool,
5566 		pipe_ctx->clock_source);
5567 
5568 	return DC_OK;
5569 }
5570 
5571 /*
5572  * Note: We need to disable output if clock sources change,
5573  * since bios does optimization and doesn't apply if changing
5574  * PHY when not already disabled.
5575  */
5576 bool pipe_need_reprogram(
5577 		struct pipe_ctx *pipe_ctx_old,
5578 		struct pipe_ctx *pipe_ctx)
5579 {
5580 	if (!pipe_ctx_old->stream)
5581 		return false;
5582 
5583 	if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink)
5584 		return true;
5585 
5586 	if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal)
5587 		return true;
5588 
5589 	if (pipe_ctx_old->stream_res.audio != pipe_ctx->stream_res.audio)
5590 		return true;
5591 
5592 	if (pipe_ctx_old->clock_source != pipe_ctx->clock_source
5593 			&& pipe_ctx_old->stream != pipe_ctx->stream)
5594 		return true;
5595 
5596 	if (pipe_ctx_old->stream_res.stream_enc != pipe_ctx->stream_res.stream_enc)
5597 		return true;
5598 
5599 	if (dc_is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream))
5600 		return true;
5601 
5602 	if (pipe_ctx_old->stream->dpms_off != pipe_ctx->stream->dpms_off)
5603 		return true;
5604 
5605 	if (false == pipe_ctx_old->stream->link->link_state_valid &&
5606 		false == pipe_ctx_old->stream->dpms_off)
5607 		return true;
5608 
5609 	if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc)
5610 		return true;
5611 
5612 	if (pipe_ctx_old->stream_res.hpo_frl_stream_enc != pipe_ctx->stream_res.hpo_frl_stream_enc)
5613 		return true;
5614 	if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc)
5615 		return true;
5616 	if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc)
5617 		return true;
5618 
5619 	/* DIG link encoder resource assignment for stream changed. */
5620 	if (pipe_ctx_old->stream->ctx->dc->config.unify_link_enc_assignment) {
5621 		if (pipe_ctx_old->link_res.dio_link_enc != pipe_ctx->link_res.dio_link_enc)
5622 			return true;
5623 	} else if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
5624 		bool need_reprogram = false;
5625 		struct dc *dc = pipe_ctx_old->stream->ctx->dc;
5626 		struct link_encoder *link_enc_prev =
5627 			link_enc_cfg_get_link_enc_used_by_stream_current(dc, pipe_ctx_old->stream);
5628 
5629 		if (link_enc_prev != pipe_ctx->stream->link_enc)
5630 			need_reprogram = true;
5631 
5632 		return need_reprogram;
5633 	}
5634 
5635 	return false;
5636 }
5637 
5638 void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream,
5639 		struct bit_depth_reduction_params *fmt_bit_depth)
5640 {
5641 	enum dc_dither_option option = stream->dither_option;
5642 	enum dc_pixel_encoding pixel_encoding =
5643 			stream->timing.pixel_encoding;
5644 
5645 	memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth));
5646 
5647 	if (option == DITHER_OPTION_DEFAULT) {
5648 		switch (stream->timing.display_color_depth) {
5649 		case COLOR_DEPTH_666:
5650 			option = DITHER_OPTION_SPATIAL6;
5651 			break;
5652 		case COLOR_DEPTH_888:
5653 			option = DITHER_OPTION_SPATIAL8;
5654 			break;
5655 		case COLOR_DEPTH_101010:
5656 			option = DITHER_OPTION_SPATIAL10;
5657 			break;
5658 		default:
5659 			option = DITHER_OPTION_DISABLE;
5660 		}
5661 	}
5662 
5663 	if (stream->ctx->dce_version < DCE_VERSION_8_0 &&
5664 	    stream->timing.display_color_depth >= COLOR_DEPTH_101010) {
5665 		/* DCE 6.x doesn't support 10-bit truncation or dither options. */
5666 		option = DITHER_OPTION_DISABLE;
5667 	}
5668 
5669 	if (option == DITHER_OPTION_DISABLE)
5670 		return;
5671 
5672 	if (option == DITHER_OPTION_TRUN6) {
5673 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
5674 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 0;
5675 	} else if (option == DITHER_OPTION_TRUN8 ||
5676 			option == DITHER_OPTION_TRUN8_SPATIAL6 ||
5677 			option == DITHER_OPTION_TRUN8_FM6) {
5678 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
5679 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 1;
5680 	} else if (option == DITHER_OPTION_TRUN10        ||
5681 			option == DITHER_OPTION_TRUN10_SPATIAL6   ||
5682 			option == DITHER_OPTION_TRUN10_SPATIAL8   ||
5683 			option == DITHER_OPTION_TRUN10_FM8     ||
5684 			option == DITHER_OPTION_TRUN10_FM6     ||
5685 			option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
5686 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
5687 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
5688 		if (option == DITHER_OPTION_TRUN10)
5689 			fmt_bit_depth->flags.TRUNCATE_MODE = 1;
5690 	}
5691 
5692 	/* special case - Formatter can only reduce by 4 bits at most.
5693 	 * When reducing from 12 to 6 bits,
5694 	 * HW recommends we use trunc with round mode
5695 	 * (if we did nothing, trunc to 10 bits would be used)
5696 	 * note that any 12->10 bit reduction is ignored prior to DCE8,
5697 	 * as the input was 10 bits.
5698 	 */
5699 	if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM ||
5700 			option == DITHER_OPTION_SPATIAL6 ||
5701 			option == DITHER_OPTION_FM6) {
5702 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
5703 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
5704 		fmt_bit_depth->flags.TRUNCATE_MODE = 1;
5705 	}
5706 
5707 	/* spatial dither
5708 	 * note that spatial modes 1-3 are never used
5709 	 */
5710 	if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM            ||
5711 			option == DITHER_OPTION_SPATIAL6 ||
5712 			option == DITHER_OPTION_TRUN10_SPATIAL6      ||
5713 			option == DITHER_OPTION_TRUN8_SPATIAL6) {
5714 		fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
5715 		fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 0;
5716 		fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
5717 		fmt_bit_depth->flags.RGB_RANDOM =
5718 				(pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
5719 	} else if (option == DITHER_OPTION_SPATIAL8_FRAME_RANDOM            ||
5720 			option == DITHER_OPTION_SPATIAL8 ||
5721 			option == DITHER_OPTION_SPATIAL8_FM6        ||
5722 			option == DITHER_OPTION_TRUN10_SPATIAL8      ||
5723 			option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
5724 		fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
5725 		fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1;
5726 		fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
5727 		fmt_bit_depth->flags.RGB_RANDOM =
5728 				(pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
5729 	} else if (option == DITHER_OPTION_SPATIAL10_FRAME_RANDOM ||
5730 			option == DITHER_OPTION_SPATIAL10 ||
5731 			option == DITHER_OPTION_SPATIAL10_FM8 ||
5732 			option == DITHER_OPTION_SPATIAL10_FM6) {
5733 		fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
5734 		fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 2;
5735 		fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
5736 		fmt_bit_depth->flags.RGB_RANDOM =
5737 				(pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
5738 	}
5739 
5740 	if (option == DITHER_OPTION_SPATIAL6 ||
5741 			option == DITHER_OPTION_SPATIAL8 ||
5742 			option == DITHER_OPTION_SPATIAL10) {
5743 		fmt_bit_depth->flags.FRAME_RANDOM = 0;
5744 	} else {
5745 		fmt_bit_depth->flags.FRAME_RANDOM = 1;
5746 	}
5747 
5748 	//////////////////////
5749 	//// temporal dither
5750 	//////////////////////
5751 	if (option == DITHER_OPTION_FM6           ||
5752 			option == DITHER_OPTION_SPATIAL8_FM6     ||
5753 			option == DITHER_OPTION_SPATIAL10_FM6     ||
5754 			option == DITHER_OPTION_TRUN10_FM6     ||
5755 			option == DITHER_OPTION_TRUN8_FM6      ||
5756 			option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
5757 		fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
5758 		fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 0;
5759 	} else if (option == DITHER_OPTION_FM8        ||
5760 			option == DITHER_OPTION_SPATIAL10_FM8  ||
5761 			option == DITHER_OPTION_TRUN10_FM8) {
5762 		fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
5763 		fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 1;
5764 	} else if (option == DITHER_OPTION_FM10) {
5765 		fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
5766 		fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 2;
5767 	}
5768 
5769 	fmt_bit_depth->pixel_encoding = pixel_encoding;
5770 }
5771 
5772 enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
5773 {
5774 	if (dc == NULL || stream == NULL)
5775 		return DC_ERROR_UNEXPECTED;
5776 
5777 	struct dc_link *link = stream->link;
5778 	struct timing_generator *tg = dc->res_pool->timing_generators[0];
5779 	enum dc_status res = DC_OK;
5780 
5781 	calculate_phy_pix_clks(stream);
5782 
5783 	if (!tg->funcs->validate_timing(tg, &stream->timing))
5784 		res = DC_FAIL_CONTROLLER_VALIDATE;
5785 
5786 	if (res == DC_OK) {
5787 		if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
5788 				!link->link_enc->funcs->validate_output_with_stream(
5789 						link->link_enc, stream))
5790 			res = DC_FAIL_ENC_VALIDATE;
5791 	}
5792 
5793 	/* TODO: validate audio ASIC caps, encoder */
5794 
5795 	if (res == DC_OK)
5796 		res = dc->link_srv->validate_mode_timing(stream,
5797 		      link,
5798 		      &stream->timing);
5799 
5800 	return res;
5801 }
5802 
5803 enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state)
5804 {
5805 	enum dc_status res = DC_OK;
5806 
5807 	/* check if surface has invalid dimensions */
5808 	if (plane_state->src_rect.width == 0 || plane_state->src_rect.height == 0 ||
5809 		plane_state->dst_rect.width == 0 || plane_state->dst_rect.height == 0)
5810 		return DC_FAIL_SURFACE_VALIDATE;
5811 
5812 	/* TODO For now validates pixel format only */
5813 	if (dc->res_pool->funcs->validate_plane)
5814 		return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps);
5815 
5816 	return res;
5817 }
5818 
5819 unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format)
5820 {
5821 	switch (format) {
5822 	case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
5823 		return 8;
5824 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
5825 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
5826 		return 12;
5827 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
5828 	case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
5829 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
5830 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
5831 		return 16;
5832 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
5833 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
5834 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
5835 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
5836 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
5837 	case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
5838 	case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
5839 		return 32;
5840 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
5841 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
5842 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
5843 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
5844 		return 64;
5845 	default:
5846 		ASSERT_CRITICAL(false);
5847 		return UINT_MAX;
5848 	}
5849 }
5850 static unsigned int get_max_audio_sample_rate(struct audio_mode *modes)
5851 {
5852 	if (modes) {
5853 		if (modes->sample_rates.rate.RATE_192)
5854 			return 192000;
5855 		if (modes->sample_rates.rate.RATE_176_4)
5856 			return 176400;
5857 		if (modes->sample_rates.rate.RATE_96)
5858 			return 96000;
5859 		if (modes->sample_rates.rate.RATE_88_2)
5860 			return 88200;
5861 		if (modes->sample_rates.rate.RATE_48)
5862 			return 48000;
5863 		if (modes->sample_rates.rate.RATE_44_1)
5864 			return 44100;
5865 		if (modes->sample_rates.rate.RATE_32)
5866 			return 32000;
5867 	}
5868 	/*original logic when no audio info*/
5869 	return 441000;
5870 }
5871 
5872 void get_audio_check(struct audio_info *aud_modes,
5873 	struct audio_check *audio_chk)
5874 {
5875 	unsigned int i;
5876 	unsigned int max_sample_rate = 0;
5877 
5878 	if (aud_modes) {
5879 		audio_chk->audio_packet_type = 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/
5880 
5881 		audio_chk->max_audiosample_rate = 0;
5882 		audio_chk->max_channel_count = 0;
5883 		for (i = 0; i < aud_modes->mode_count; i++) {
5884 			max_sample_rate = get_max_audio_sample_rate(&aud_modes->modes[i]);
5885 			if (audio_chk->max_audiosample_rate < max_sample_rate)
5886 				audio_chk->max_audiosample_rate = max_sample_rate;
5887 			if (audio_chk->max_channel_count < aud_modes->modes[i].channel_count)
5888 				audio_chk->max_channel_count = aud_modes->modes[i].channel_count;
5889 			/*dts takes the same as type 2: AP = 0.25*/
5890 		}
5891 		/*check which one take more bandwidth*/
5892 		if (audio_chk->max_audiosample_rate > 192000)
5893 			audio_chk->audio_packet_type = 0x9;/*AP =1*/
5894 		audio_chk->acat = 0;/*not support*/
5895 	}
5896 }
5897 
5898 struct link_encoder *get_temp_dio_link_enc(
5899 		const struct resource_context *res_ctx,
5900 		const struct resource_pool *const pool,
5901 		const struct dc_link *link)
5902 {
5903 	struct link_encoder *link_enc = NULL;
5904 	int enc_index;
5905 
5906 	if (link->is_dig_mapping_flexible)
5907 		enc_index = find_acquired_dio_link_enc_for_link(res_ctx, link);
5908 	else
5909 		enc_index = link->eng_id;
5910 
5911 	if (enc_index < 0)
5912 		enc_index = find_free_dio_link_enc(res_ctx, link, pool, NULL);
5913 
5914 	if (enc_index >= 0)
5915 		link_enc = pool->link_encoders[enc_index];
5916 
5917 	return link_enc;
5918 }
5919 
5920 static struct hpo_dp_link_encoder *get_temp_hpo_dp_link_enc(
5921 		const struct resource_context *res_ctx,
5922 		const struct resource_pool *const pool,
5923 		const struct dc_link *link)
5924 {
5925 	struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL;
5926 	int enc_index;
5927 
5928 	enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, link);
5929 
5930 	if (enc_index < 0)
5931 		enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
5932 
5933 	if (enc_index >= 0)
5934 		hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
5935 
5936 	return hpo_dp_link_enc;
5937 }
5938 
5939 bool get_temp_dp_link_res(struct dc_link *link,
5940 		struct link_resource *link_res,
5941 		struct dc_link_settings *link_settings)
5942 {
5943 	const struct dc *dc  = link->dc;
5944 	const struct resource_context *res_ctx = &dc->current_state->res_ctx;
5945 
5946 	memset(link_res, 0, sizeof(*link_res));
5947 
5948 	if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
5949 		link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx, dc->res_pool, link);
5950 		if (!link_res->hpo_dp_link_enc)
5951 			return false;
5952 	} else if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
5953 				dc->config.unify_link_enc_assignment) {
5954 		link_res->dio_link_enc = get_temp_dio_link_enc(res_ctx,
5955 				dc->res_pool, link);
5956 		if (!link_res->dio_link_enc)
5957 			return false;
5958 	}
5959 
5960 	return true;
5961 }
5962 
5963 void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
5964 		struct dc_state *context)
5965 {
5966 	uint8_t i, j;
5967 	struct pipe_ctx *pipe_ctx_old, *pipe_ctx, *pipe_ctx_syncd;
5968 
5969 	/* If pipe backend is reset, need to reset pipe syncd status */
5970 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
5971 		pipe_ctx_old =	&dc->current_state->res_ctx.pipe_ctx[i];
5972 		pipe_ctx = &context->res_ctx.pipe_ctx[i];
5973 
5974 		if (!resource_is_pipe_type(pipe_ctx_old, OTG_MASTER))
5975 			continue;
5976 
5977 		if (!pipe_ctx->stream ||
5978 				pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
5979 
5980 			/* Reset all the syncd pipes from the disabled pipe */
5981 			for (j = 0; j < dc->res_pool->pipe_count; j++) {
5982 				pipe_ctx_syncd = &context->res_ctx.pipe_ctx[j];
5983 				if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_syncd) == pipe_ctx_old->pipe_idx) ||
5984 					!IS_PIPE_SYNCD_VALID(pipe_ctx_syncd))
5985 					SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_syncd, j);
5986 			}
5987 		}
5988 	}
5989 }
5990 
5991 void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
5992 	struct dc_state *context,
5993 	uint8_t disabled_master_pipe_idx)
5994 {
5995 	unsigned int i;
5996 	struct pipe_ctx *pipe_ctx, *pipe_ctx_check;
5997 
5998 	pipe_ctx = &context->res_ctx.pipe_ctx[disabled_master_pipe_idx];
5999 	if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx) != disabled_master_pipe_idx) ||
6000 		!IS_PIPE_SYNCD_VALID(pipe_ctx))
6001 		SET_PIPE_SYNCD_TO_PIPE(pipe_ctx, disabled_master_pipe_idx);
6002 
6003 	/* for the pipe disabled, check if any slave pipe exists and assert */
6004 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
6005 		pipe_ctx_check = &context->res_ctx.pipe_ctx[i];
6006 
6007 		if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) &&
6008 		    IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx)) {
6009 			struct pipe_ctx *first_pipe = pipe_ctx_check;
6010 
6011 			while (first_pipe->prev_odm_pipe)
6012 				first_pipe = first_pipe->prev_odm_pipe;
6013 			/* When ODM combine is enabled, this case is expected. If the disabled pipe
6014 			 * is part of the ODM tree, then we should not print an error.
6015 			 * */
6016 			if (first_pipe->pipe_idx == disabled_master_pipe_idx)
6017 				continue;
6018 
6019 			DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n",
6020 				   i, disabled_master_pipe_idx);
6021 		}
6022 	}
6023 }
6024 
6025 void reset_sync_context_for_pipe(const struct dc *dc,
6026 	struct dc_state *context,
6027 	uint8_t pipe_idx)
6028 {
6029 	uint8_t i;
6030 	struct pipe_ctx *pipe_ctx_reset;
6031 
6032 	/* reset the otg sync context for the pipe and its slave pipes if any */
6033 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
6034 		pipe_ctx_reset = &context->res_ctx.pipe_ctx[i];
6035 
6036 		if (((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_reset) == pipe_idx) &&
6037 			IS_PIPE_SYNCD_VALID(pipe_ctx_reset)) || (i == pipe_idx))
6038 			SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_reset, i);
6039 	}
6040 }
6041 
6042 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter)
6043 {
6044 	/* TODO - get transmitter to phy idx mapping from DMUB */
6045 	uint8_t phy_idx = (uint8_t)(transmitter - TRANSMITTER_UNIPHY_A);
6046 
6047 	if (dc->ctx->dce_version == DCN_VERSION_3_1 &&
6048 			dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) {
6049 		switch (transmitter) {
6050 		case TRANSMITTER_UNIPHY_A:
6051 			phy_idx = 0;
6052 			break;
6053 		case TRANSMITTER_UNIPHY_B:
6054 			phy_idx = 1;
6055 			break;
6056 		case TRANSMITTER_UNIPHY_C:
6057 			phy_idx = 5;
6058 			break;
6059 		case TRANSMITTER_UNIPHY_D:
6060 			phy_idx = 6;
6061 			break;
6062 		case TRANSMITTER_UNIPHY_E:
6063 			phy_idx = 4;
6064 			break;
6065 		default:
6066 			phy_idx = 0;
6067 			break;
6068 		}
6069 	}
6070 
6071 	return phy_idx;
6072 }
6073 
6074 const struct link_hwss *get_link_hwss(const struct dc_link *link,
6075 		const struct link_resource *link_res)
6076 {
6077 	/* Link_hwss is only accessible by getter function instead of accessing
6078 	 * by pointers in dc with the intent to protect against breaking polymorphism.
6079 	 */
6080 	if (can_use_hpo_dp_link_hwss(link, link_res))
6081 		/* TODO: some assumes that if decided link settings is 128b/132b
6082 		 * channel coding format hpo_dp_link_enc should be used.
6083 		 * Others believe that if hpo_dp_link_enc is available in link
6084 		 * resource then hpo_dp_link_enc must be used. This bound between
6085 		 * hpo_dp_link_enc != NULL and decided link settings is loosely coupled
6086 		 * with a premise that both hpo_dp_link_enc pointer and decided link
6087 		 * settings are determined based on single policy function like
6088 		 * "decide_link_settings" from upper layer. This "convention"
6089 		 * cannot be maintained and enforced at current level.
6090 		 * Therefore a refactor is due so we can enforce a strong bound
6091 		 * between those two parameters at this level.
6092 		 *
6093 		 * To put it simple, we want to make enforcement at low level so that
6094 		 * we will not return link hwss if caller plans to do 8b/10b
6095 		 * with an hpo encoder. Or we can return a very dummy one that doesn't
6096 		 * do work for all functions
6097 		 */
6098 		return (requires_fixed_vs_pe_retimer_hpo_link_hwss(link) ?
6099 				get_hpo_fixed_vs_pe_retimer_dp_link_hwss() : get_hpo_dp_link_hwss());
6100 	else if (can_use_hpo_frl_link_hwss(link, link_res))
6101 		return get_hpo_frl_link_hwss();
6102 	else if (can_use_dpia_link_hwss(link, link_res))
6103 		return get_dpia_link_hwss();
6104 	else if (can_use_dio_link_hwss(link, link_res))
6105 		return (requires_fixed_vs_pe_retimer_dio_link_hwss(link)) ?
6106 				get_dio_fixed_vs_pe_retimer_link_hwss() : get_dio_link_hwss();
6107 	else
6108 		return get_virtual_link_hwss();
6109 }
6110 
6111 bool is_h_timing_divisible_by_2(struct dc_stream_state *stream)
6112 {
6113 	bool divisible = false;
6114 	uint32_t h_blank_start = 0;
6115 	uint32_t h_blank_end = 0;
6116 
6117 	if (stream) {
6118 		h_blank_start = stream->timing.h_total - stream->timing.h_front_porch;
6119 		h_blank_end = h_blank_start - stream->timing.h_addressable;
6120 
6121 		/* HTOTAL, Hblank start/end, and Hsync start/end all must be
6122 		 * divisible by 2 in order for the horizontal timing params
6123 		 * to be considered divisible by 2. Hsync start is always 0.
6124 		 */
6125 		divisible = (stream->timing.h_total % 2 == 0) &&
6126 				(h_blank_start % 2 == 0) &&
6127 				(h_blank_end % 2 == 0) &&
6128 				(stream->timing.h_sync_width % 2 == 0);
6129 	}
6130 	return divisible;
6131 }
6132 
6133 /* This interface is deprecated for new DCNs. It is replaced by the following
6134  * new interfaces. These two interfaces encapsulate pipe selection priority
6135  * with DCN specific minimum hardware transition optimization algorithm. With
6136  * the new interfaces caller no longer needs to know the implementation detail
6137  * of a pipe topology.
6138  *
6139  * resource_update_pipes_with_odm_slice_count
6140  * resource_update_pipes_with_mpc_slice_count
6141  *
6142  */
6143 bool dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy(
6144 		const struct dc *dc,
6145 		struct dc_state *state,
6146 		struct pipe_ctx *pri_pipe,
6147 		struct pipe_ctx *sec_pipe,
6148 		bool odm)
6149 {
6150 	int pipe_idx = sec_pipe->pipe_idx;
6151 	struct pipe_ctx *sec_top, *sec_bottom, *sec_next, *sec_prev;
6152 	const struct resource_pool *pool = dc->res_pool;
6153 
6154 	sec_top = sec_pipe->top_pipe;
6155 	sec_bottom = sec_pipe->bottom_pipe;
6156 	sec_next = sec_pipe->next_odm_pipe;
6157 	sec_prev = sec_pipe->prev_odm_pipe;
6158 
6159 	if (pri_pipe == NULL)
6160 		return false;
6161 
6162 	*sec_pipe = *pri_pipe;
6163 
6164 	sec_pipe->top_pipe = sec_top;
6165 	sec_pipe->bottom_pipe = sec_bottom;
6166 	sec_pipe->next_odm_pipe = sec_next;
6167 	sec_pipe->prev_odm_pipe = sec_prev;
6168 
6169 	sec_pipe->pipe_idx = (uint8_t)pipe_idx;
6170 	sec_pipe->plane_res.mi = pool->mis[pipe_idx];
6171 	sec_pipe->plane_res.hubp = pool->hubps[pipe_idx];
6172 	sec_pipe->plane_res.ipp = pool->ipps[pipe_idx];
6173 	sec_pipe->plane_res.xfm = pool->transforms[pipe_idx];
6174 	sec_pipe->plane_res.dpp = pool->dpps[pipe_idx];
6175 	sec_pipe->plane_res.mpcc_inst = (uint8_t)pool->dpps[pipe_idx]->inst;
6176 	sec_pipe->stream_res.dsc = NULL;
6177 	if (odm) {
6178 		if (!sec_pipe->top_pipe)
6179 			sec_pipe->stream_res.opp = pool->opps[pipe_idx];
6180 		else
6181 			sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp;
6182 		if (sec_pipe->stream->timing.flags.DSC == 1) {
6183 #if defined(CONFIG_DRM_AMD_DC_FP)
6184 			dcn20_acquire_dsc(dc, &state->res_ctx, &sec_pipe->stream_res.dsc, sec_pipe->stream_res.opp->inst);
6185 #endif
6186 			ASSERT(sec_pipe->stream_res.dsc);
6187 			if (sec_pipe->stream_res.dsc == NULL)
6188 				return false;
6189 		}
6190 #if defined(CONFIG_DRM_AMD_DC_FP)
6191 		dcn20_build_mapped_resource(dc, state, sec_pipe->stream);
6192 #endif
6193 	}
6194 
6195 	return true;
6196 }
6197 
6198 enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc,
6199 		struct dc_state *context,
6200 		struct pipe_ctx *pipe_ctx)
6201 {
6202 	if (dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
6203 		if (pipe_ctx->stream_res.hpo_dp_stream_enc == NULL) {
6204 			pipe_ctx->stream_res.hpo_dp_stream_enc =
6205 					find_first_free_match_hpo_dp_stream_enc_for_link(
6206 							&context->res_ctx, dc->res_pool, pipe_ctx->stream);
6207 
6208 			if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
6209 				return DC_NO_STREAM_ENC_RESOURCE;
6210 
6211 			update_hpo_dp_stream_engine_usage(
6212 					&context->res_ctx, dc->res_pool,
6213 					pipe_ctx->stream_res.hpo_dp_stream_enc,
6214 					true);
6215 		}
6216 
6217 		if (pipe_ctx->link_res.hpo_dp_link_enc == NULL) {
6218 			if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, dc->res_pool, pipe_ctx, pipe_ctx->stream))
6219 				return DC_NO_LINK_ENC_RESOURCE;
6220 		}
6221 	} else {
6222 		if (pipe_ctx->stream_res.hpo_dp_stream_enc) {
6223 			update_hpo_dp_stream_engine_usage(
6224 					&context->res_ctx, dc->res_pool,
6225 					pipe_ctx->stream_res.hpo_dp_stream_enc,
6226 					false);
6227 			pipe_ctx->stream_res.hpo_dp_stream_enc = NULL;
6228 		}
6229 		if (pipe_ctx->link_res.hpo_dp_link_enc)
6230 			remove_hpo_dp_link_enc_from_ctx(&context->res_ctx, pipe_ctx, pipe_ctx->stream);
6231 	}
6232 
6233 	if (pipe_ctx->link_res.dio_link_enc == NULL && dc->config.unify_link_enc_assignment)
6234 		if (!add_dio_link_enc_to_ctx(dc, context, dc->res_pool, pipe_ctx, pipe_ctx->stream))
6235 			return DC_NO_LINK_ENC_RESOURCE;
6236 
6237 	return DC_OK;
6238 }
6239 
6240 struct dscl_prog_data *resource_get_dscl_prog_data(struct pipe_ctx *pipe_ctx)
6241 {
6242 	return &pipe_ctx->plane_res.scl_data.dscl_prog_data;
6243 }
6244 
6245 static bool resource_allocate_mcache(struct dc_state *context, const struct  dc_mcache_params *mcache_params)
6246 {
6247 	if (context->clk_mgr->ctx->dc->res_pool->funcs->program_mcache_pipe_config)
6248 		context->clk_mgr->ctx->dc->res_pool->funcs->program_mcache_pipe_config(context, mcache_params);
6249 
6250 	return true;
6251 }
6252 
6253 void resource_init_common_dml2_callbacks(struct dc *dc, struct dml2_configuration_options *dml2_options)
6254 {
6255 	dml2_options->callbacks.dc = dc;
6256 	dml2_options->callbacks.build_scaling_params = &resource_build_scaling_params;
6257 	dml2_options->callbacks.build_test_pattern_params = &resource_build_test_pattern_params;
6258 	dml2_options->callbacks.acquire_secondary_pipe_for_mpc_odm = &dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy;
6259 	dml2_options->callbacks.update_pipes_for_stream_with_slice_count = &resource_update_pipes_for_stream_with_slice_count;
6260 	dml2_options->callbacks.update_pipes_for_plane_with_slice_count = &resource_update_pipes_for_plane_with_slice_count;
6261 	dml2_options->callbacks.get_mpc_slice_index = &resource_get_mpc_slice_index;
6262 	dml2_options->callbacks.get_mpc_slice_count = &resource_get_mpc_slice_count;
6263 	dml2_options->callbacks.get_odm_slice_index = &resource_get_odm_slice_index;
6264 	dml2_options->callbacks.get_odm_slice_count = &resource_get_odm_slice_count;
6265 	dml2_options->callbacks.get_opp_head = &resource_get_opp_head;
6266 	dml2_options->callbacks.get_otg_master_for_stream = &resource_get_otg_master_for_stream;
6267 	dml2_options->callbacks.get_opp_heads_for_otg_master = &resource_get_opp_heads_for_otg_master;
6268 	dml2_options->callbacks.get_dpp_pipes_for_plane = &resource_get_dpp_pipes_for_plane;
6269 	dml2_options->callbacks.get_stream_status = &dc_state_get_stream_status;
6270 	dml2_options->callbacks.get_stream_from_id = &dc_state_get_stream_from_id;
6271 	dml2_options->callbacks.get_max_flickerless_instant_vtotal_increase = &dc_stream_get_max_flickerless_instant_vtotal_increase;
6272 	dml2_options->callbacks.allocate_mcache = &resource_allocate_mcache;
6273 
6274 	dml2_options->svp_pstate.callbacks.dc = dc;
6275 	dml2_options->svp_pstate.callbacks.add_phantom_plane = &dc_state_add_phantom_plane;
6276 	dml2_options->svp_pstate.callbacks.add_phantom_stream = &dc_state_add_phantom_stream;
6277 	dml2_options->svp_pstate.callbacks.build_scaling_params = &resource_build_scaling_params;
6278 	dml2_options->svp_pstate.callbacks.create_phantom_plane = &dc_state_create_phantom_plane;
6279 	dml2_options->svp_pstate.callbacks.remove_phantom_plane = &dc_state_remove_phantom_plane;
6280 	dml2_options->svp_pstate.callbacks.remove_phantom_stream = &dc_state_remove_phantom_stream;
6281 	dml2_options->svp_pstate.callbacks.create_phantom_stream = &dc_state_create_phantom_stream;
6282 	dml2_options->svp_pstate.callbacks.release_phantom_plane = &dc_state_release_phantom_plane;
6283 	dml2_options->svp_pstate.callbacks.release_phantom_stream = &dc_state_release_phantom_stream;
6284 	dml2_options->svp_pstate.callbacks.get_pipe_subvp_type = &dc_state_get_pipe_subvp_type;
6285 	dml2_options->svp_pstate.callbacks.get_stream_subvp_type = &dc_state_get_stream_subvp_type;
6286 	dml2_options->svp_pstate.callbacks.get_paired_subvp_stream = &dc_state_get_paired_subvp_stream;
6287 	dml2_options->svp_pstate.callbacks.remove_phantom_streams_and_planes = &dc_state_remove_phantom_streams_and_planes;
6288 	dml2_options->svp_pstate.callbacks.release_phantom_streams_and_planes = &dc_state_release_phantom_streams_and_planes;
6289 }
6290 
6291 /* Returns number of DET segments allocated for a given OTG_MASTER pipe */
6292 int resource_calculate_det_for_stream(struct dc_state *state, struct pipe_ctx *otg_master)
6293 {
6294 	struct pipe_ctx *opp_heads[MAX_PIPES];
6295 	struct pipe_ctx *dpp_pipes[MAX_PIPES];
6296 
6297 	int dpp_count = 0;
6298 	int det_segments = 0;
6299 
6300 	if (!otg_master->stream)
6301 		return 0;
6302 
6303 	int slice_count = resource_get_opp_heads_for_otg_master(otg_master,
6304 			&state->res_ctx, opp_heads);
6305 
6306 	for (int slice_idx = 0; slice_idx < slice_count; slice_idx++) {
6307 		if (opp_heads[slice_idx]->plane_state) {
6308 			dpp_count = resource_get_dpp_pipes_for_opp_head(
6309 					opp_heads[slice_idx],
6310 					&state->res_ctx,
6311 					dpp_pipes);
6312 			for (int dpp_idx = 0; dpp_idx < dpp_count; dpp_idx++)
6313 				det_segments += dpp_pipes[dpp_idx]->hubp_regs.det_size;
6314 		}
6315 	}
6316 	return det_segments;
6317 }
6318 
6319 bool resource_is_hpo_acquired(struct dc_state *context)
6320 {
6321 	int i;
6322 
6323 	for (i = 0; i < MAX_HPO_DP2_ENCODERS; i++) {
6324 		if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i]) {
6325 			return true;
6326 		}
6327 	}
6328 
6329 	for (i = 0; i < MAX_HDMI_FRL_ENCODERS; i++) {
6330 		if (context->res_ctx.is_hpo_frl_stream_enc_acquired[i]) {
6331 			return true;
6332 		}
6333 	}
6334 
6335 	return false;
6336 }
6337