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 "virtual/virtual_stream_encoder.h"
41 #include "dpcd_defs.h"
42 #include "link_enc_cfg.h"
43 #include "link.h"
44 #include "virtual/virtual_link_hwss.h"
45 #include "link/hwss/link_hwss_dio.h"
46 #include "link/hwss/link_hwss_dpia.h"
47 #include "link/hwss/link_hwss_hpo_dp.h"
48 
49 #if defined(CONFIG_DRM_AMD_DC_SI)
50 #include "dce60/dce60_resource.h"
51 #endif
52 #include "dce80/dce80_resource.h"
53 #include "dce100/dce100_resource.h"
54 #include "dce110/dce110_resource.h"
55 #include "dce112/dce112_resource.h"
56 #include "dce120/dce120_resource.h"
57 #include "dcn10/dcn10_resource.h"
58 #include "dcn20/dcn20_resource.h"
59 #include "dcn21/dcn21_resource.h"
60 #include "dcn201/dcn201_resource.h"
61 #include "dcn30/dcn30_resource.h"
62 #include "dcn301/dcn301_resource.h"
63 #include "dcn302/dcn302_resource.h"
64 #include "dcn303/dcn303_resource.h"
65 #include "dcn31/dcn31_resource.h"
66 #include "dcn314/dcn314_resource.h"
67 #include "dcn315/dcn315_resource.h"
68 #include "dcn316/dcn316_resource.h"
69 #include "../dcn32/dcn32_resource.h"
70 #include "../dcn321/dcn321_resource.h"
71 
72 
73 #define DC_LOGGER_INIT(logger)
74 
75 enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
76 {
77 	enum dce_version dc_version = DCE_VERSION_UNKNOWN;
78 
79 	switch (asic_id.chip_family) {
80 
81 #if defined(CONFIG_DRM_AMD_DC_SI)
82 	case FAMILY_SI:
83 		if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev) ||
84 		    ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev) ||
85 		    ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev))
86 			dc_version = DCE_VERSION_6_0;
87 		else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev))
88 			dc_version = DCE_VERSION_6_4;
89 		else
90 			dc_version = DCE_VERSION_6_1;
91 		break;
92 #endif
93 	case FAMILY_CI:
94 		dc_version = DCE_VERSION_8_0;
95 		break;
96 	case FAMILY_KV:
97 		if (ASIC_REV_IS_KALINDI(asic_id.hw_internal_rev) ||
98 		    ASIC_REV_IS_BHAVANI(asic_id.hw_internal_rev) ||
99 		    ASIC_REV_IS_GODAVARI(asic_id.hw_internal_rev))
100 			dc_version = DCE_VERSION_8_3;
101 		else
102 			dc_version = DCE_VERSION_8_1;
103 		break;
104 	case FAMILY_CZ:
105 		dc_version = DCE_VERSION_11_0;
106 		break;
107 
108 	case FAMILY_VI:
109 		if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev) ||
110 				ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)) {
111 			dc_version = DCE_VERSION_10_0;
112 			break;
113 		}
114 		if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) ||
115 				ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev) ||
116 				ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)) {
117 			dc_version = DCE_VERSION_11_2;
118 		}
119 		if (ASIC_REV_IS_VEGAM(asic_id.hw_internal_rev))
120 			dc_version = DCE_VERSION_11_22;
121 		break;
122 	case FAMILY_AI:
123 		if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev))
124 			dc_version = DCE_VERSION_12_1;
125 		else
126 			dc_version = DCE_VERSION_12_0;
127 		break;
128 	case FAMILY_RV:
129 		dc_version = DCN_VERSION_1_0;
130 		if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev))
131 			dc_version = DCN_VERSION_1_01;
132 		if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev))
133 			dc_version = DCN_VERSION_2_1;
134 		if (ASICREV_IS_GREEN_SARDINE(asic_id.hw_internal_rev))
135 			dc_version = DCN_VERSION_2_1;
136 		break;
137 
138 	case FAMILY_NV:
139 		dc_version = DCN_VERSION_2_0;
140 		if (asic_id.chip_id == DEVICE_ID_NV_13FE || asic_id.chip_id == DEVICE_ID_NV_143F) {
141 			dc_version = DCN_VERSION_2_01;
142 			break;
143 		}
144 		if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev))
145 			dc_version = DCN_VERSION_3_0;
146 		if (ASICREV_IS_DIMGREY_CAVEFISH_P(asic_id.hw_internal_rev))
147 			dc_version = DCN_VERSION_3_02;
148 		if (ASICREV_IS_BEIGE_GOBY_P(asic_id.hw_internal_rev))
149 			dc_version = DCN_VERSION_3_03;
150 		break;
151 
152 	case FAMILY_VGH:
153 		dc_version = DCN_VERSION_3_01;
154 		break;
155 
156 	case FAMILY_YELLOW_CARP:
157 		if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev))
158 			dc_version = DCN_VERSION_3_1;
159 		break;
160 	case AMDGPU_FAMILY_GC_10_3_6:
161 		if (ASICREV_IS_GC_10_3_6(asic_id.hw_internal_rev))
162 			dc_version = DCN_VERSION_3_15;
163 		break;
164 	case AMDGPU_FAMILY_GC_10_3_7:
165 		if (ASICREV_IS_GC_10_3_7(asic_id.hw_internal_rev))
166 			dc_version = DCN_VERSION_3_16;
167 		break;
168 	case AMDGPU_FAMILY_GC_11_0_0:
169 		dc_version = DCN_VERSION_3_2;
170 		if (ASICREV_IS_GC_11_0_2(asic_id.hw_internal_rev))
171 			dc_version = DCN_VERSION_3_21;
172 		break;
173 	case AMDGPU_FAMILY_GC_11_0_1:
174 		dc_version = DCN_VERSION_3_14;
175 		break;
176 	default:
177 		dc_version = DCE_VERSION_UNKNOWN;
178 		break;
179 	}
180 	return dc_version;
181 }
182 
183 struct resource_pool *dc_create_resource_pool(struct dc  *dc,
184 					      const struct dc_init_data *init_data,
185 					      enum dce_version dc_version)
186 {
187 	struct resource_pool *res_pool = NULL;
188 
189 	switch (dc_version) {
190 #if defined(CONFIG_DRM_AMD_DC_SI)
191 	case DCE_VERSION_6_0:
192 		res_pool = dce60_create_resource_pool(
193 			init_data->num_virtual_links, dc);
194 		break;
195 	case DCE_VERSION_6_1:
196 		res_pool = dce61_create_resource_pool(
197 			init_data->num_virtual_links, dc);
198 		break;
199 	case DCE_VERSION_6_4:
200 		res_pool = dce64_create_resource_pool(
201 			init_data->num_virtual_links, dc);
202 		break;
203 #endif
204 	case DCE_VERSION_8_0:
205 		res_pool = dce80_create_resource_pool(
206 				init_data->num_virtual_links, dc);
207 		break;
208 	case DCE_VERSION_8_1:
209 		res_pool = dce81_create_resource_pool(
210 				init_data->num_virtual_links, dc);
211 		break;
212 	case DCE_VERSION_8_3:
213 		res_pool = dce83_create_resource_pool(
214 				init_data->num_virtual_links, dc);
215 		break;
216 	case DCE_VERSION_10_0:
217 		res_pool = dce100_create_resource_pool(
218 				init_data->num_virtual_links, dc);
219 		break;
220 	case DCE_VERSION_11_0:
221 		res_pool = dce110_create_resource_pool(
222 				init_data->num_virtual_links, dc,
223 				init_data->asic_id);
224 		break;
225 	case DCE_VERSION_11_2:
226 	case DCE_VERSION_11_22:
227 		res_pool = dce112_create_resource_pool(
228 				init_data->num_virtual_links, dc);
229 		break;
230 	case DCE_VERSION_12_0:
231 	case DCE_VERSION_12_1:
232 		res_pool = dce120_create_resource_pool(
233 				init_data->num_virtual_links, dc);
234 		break;
235 
236 #if defined(CONFIG_DRM_AMD_DC_FP)
237 	case DCN_VERSION_1_0:
238 	case DCN_VERSION_1_01:
239 		res_pool = dcn10_create_resource_pool(init_data, dc);
240 		break;
241 	case DCN_VERSION_2_0:
242 		res_pool = dcn20_create_resource_pool(init_data, dc);
243 		break;
244 	case DCN_VERSION_2_1:
245 		res_pool = dcn21_create_resource_pool(init_data, dc);
246 		break;
247 	case DCN_VERSION_2_01:
248 		res_pool = dcn201_create_resource_pool(init_data, dc);
249 		break;
250 	case DCN_VERSION_3_0:
251 		res_pool = dcn30_create_resource_pool(init_data, dc);
252 		break;
253 	case DCN_VERSION_3_01:
254 		res_pool = dcn301_create_resource_pool(init_data, dc);
255 		break;
256 	case DCN_VERSION_3_02:
257 		res_pool = dcn302_create_resource_pool(init_data, dc);
258 		break;
259 	case DCN_VERSION_3_03:
260 		res_pool = dcn303_create_resource_pool(init_data, dc);
261 		break;
262 	case DCN_VERSION_3_1:
263 		res_pool = dcn31_create_resource_pool(init_data, dc);
264 		break;
265 	case DCN_VERSION_3_14:
266 		res_pool = dcn314_create_resource_pool(init_data, dc);
267 		break;
268 	case DCN_VERSION_3_15:
269 		res_pool = dcn315_create_resource_pool(init_data, dc);
270 		break;
271 	case DCN_VERSION_3_16:
272 		res_pool = dcn316_create_resource_pool(init_data, dc);
273 		break;
274 	case DCN_VERSION_3_2:
275 		res_pool = dcn32_create_resource_pool(init_data, dc);
276 		break;
277 	case DCN_VERSION_3_21:
278 		res_pool = dcn321_create_resource_pool(init_data, dc);
279 		break;
280 #endif /* CONFIG_DRM_AMD_DC_FP */
281 	default:
282 		break;
283 	}
284 
285 	if (res_pool != NULL) {
286 		if (dc->ctx->dc_bios->fw_info_valid) {
287 			res_pool->ref_clocks.xtalin_clock_inKhz =
288 				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
289 			/* initialize with firmware data first, no all
290 			 * ASIC have DCCG SW component. FPGA or
291 			 * simulation need initialization of
292 			 * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz
293 			 * with xtalin_clock_inKhz
294 			 */
295 			res_pool->ref_clocks.dccg_ref_clock_inKhz =
296 				res_pool->ref_clocks.xtalin_clock_inKhz;
297 			res_pool->ref_clocks.dchub_ref_clock_inKhz =
298 				res_pool->ref_clocks.xtalin_clock_inKhz;
299 		} else
300 			ASSERT_CRITICAL(false);
301 	}
302 
303 	return res_pool;
304 }
305 
306 void dc_destroy_resource_pool(struct dc  *dc)
307 {
308 	if (dc) {
309 		if (dc->res_pool)
310 			dc->res_pool->funcs->destroy(&dc->res_pool);
311 
312 		kfree(dc->hwseq);
313 	}
314 }
315 
316 static void update_num_audio(
317 	const struct resource_straps *straps,
318 	unsigned int *num_audio,
319 	struct audio_support *aud_support)
320 {
321 	aud_support->dp_audio = true;
322 	aud_support->hdmi_audio_native = false;
323 	aud_support->hdmi_audio_on_dongle = false;
324 
325 	if (straps->hdmi_disable == 0) {
326 		if (straps->dc_pinstraps_audio & 0x2) {
327 			aud_support->hdmi_audio_on_dongle = true;
328 			aud_support->hdmi_audio_native = true;
329 		}
330 	}
331 
332 	switch (straps->audio_stream_number) {
333 	case 0: /* multi streams supported */
334 		break;
335 	case 1: /* multi streams not supported */
336 		*num_audio = 1;
337 		break;
338 	default:
339 		DC_ERR("DC: unexpected audio fuse!\n");
340 	}
341 }
342 
343 bool resource_construct(
344 	unsigned int num_virtual_links,
345 	struct dc  *dc,
346 	struct resource_pool *pool,
347 	const struct resource_create_funcs *create_funcs)
348 {
349 	struct dc_context *ctx = dc->ctx;
350 	const struct resource_caps *caps = pool->res_cap;
351 	int i;
352 	unsigned int num_audio = caps->num_audio;
353 	struct resource_straps straps = {0};
354 
355 	if (create_funcs->read_dce_straps)
356 		create_funcs->read_dce_straps(dc->ctx, &straps);
357 
358 	pool->audio_count = 0;
359 	if (create_funcs->create_audio) {
360 		/* find the total number of streams available via the
361 		 * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
362 		 * registers (one for each pin) starting from pin 1
363 		 * up to the max number of audio pins.
364 		 * We stop on the first pin where
365 		 * PORT_CONNECTIVITY == 1 (as instructed by HW team).
366 		 */
367 		update_num_audio(&straps, &num_audio, &pool->audio_support);
368 		for (i = 0; i < caps->num_audio; i++) {
369 			struct audio *aud = create_funcs->create_audio(ctx, i);
370 
371 			if (aud == NULL) {
372 				DC_ERR("DC: failed to create audio!\n");
373 				return false;
374 			}
375 			if (!aud->funcs->endpoint_valid(aud)) {
376 				aud->funcs->destroy(&aud);
377 				break;
378 			}
379 			pool->audios[i] = aud;
380 			pool->audio_count++;
381 		}
382 	}
383 
384 	pool->stream_enc_count = 0;
385 	if (create_funcs->create_stream_encoder) {
386 		for (i = 0; i < caps->num_stream_encoder; i++) {
387 			pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx);
388 			if (pool->stream_enc[i] == NULL)
389 				DC_ERR("DC: failed to create stream_encoder!\n");
390 			pool->stream_enc_count++;
391 		}
392 	}
393 
394 	pool->hpo_dp_stream_enc_count = 0;
395 	if (create_funcs->create_hpo_dp_stream_encoder) {
396 		for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) {
397 			pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx);
398 			if (pool->hpo_dp_stream_enc[i] == NULL)
399 				DC_ERR("DC: failed to create HPO DP stream encoder!\n");
400 			pool->hpo_dp_stream_enc_count++;
401 
402 		}
403 	}
404 
405 	pool->hpo_dp_link_enc_count = 0;
406 	if (create_funcs->create_hpo_dp_link_encoder) {
407 		for (i = 0; i < caps->num_hpo_dp_link_encoder; i++) {
408 			pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder(i, ctx);
409 			if (pool->hpo_dp_link_enc[i] == NULL)
410 				DC_ERR("DC: failed to create HPO DP link encoder!\n");
411 			pool->hpo_dp_link_enc_count++;
412 		}
413 	}
414 
415 	for (i = 0; i < caps->num_mpc_3dlut; i++) {
416 		pool->mpc_lut[i] = dc_create_3dlut_func();
417 		if (pool->mpc_lut[i] == NULL)
418 			DC_ERR("DC: failed to create MPC 3dlut!\n");
419 		pool->mpc_shaper[i] = dc_create_transfer_func();
420 		if (pool->mpc_shaper[i] == NULL)
421 			DC_ERR("DC: failed to create MPC shaper!\n");
422 	}
423 
424 	dc->caps.dynamic_audio = false;
425 	if (pool->audio_count < pool->stream_enc_count) {
426 		dc->caps.dynamic_audio = true;
427 	}
428 	for (i = 0; i < num_virtual_links; i++) {
429 		pool->stream_enc[pool->stream_enc_count] =
430 			virtual_stream_encoder_create(
431 					ctx, ctx->dc_bios);
432 		if (pool->stream_enc[pool->stream_enc_count] == NULL) {
433 			DC_ERR("DC: failed to create stream_encoder!\n");
434 			return false;
435 		}
436 		pool->stream_enc_count++;
437 	}
438 
439 	dc->hwseq = create_funcs->create_hwseq(ctx);
440 
441 	return true;
442 }
443 static int find_matching_clock_source(
444 		const struct resource_pool *pool,
445 		struct clock_source *clock_source)
446 {
447 
448 	int i;
449 
450 	for (i = 0; i < pool->clk_src_count; i++) {
451 		if (pool->clock_sources[i] == clock_source)
452 			return i;
453 	}
454 	return -1;
455 }
456 
457 void resource_unreference_clock_source(
458 		struct resource_context *res_ctx,
459 		const struct resource_pool *pool,
460 		struct clock_source *clock_source)
461 {
462 	int i = find_matching_clock_source(pool, clock_source);
463 
464 	if (i > -1)
465 		res_ctx->clock_source_ref_count[i]--;
466 
467 	if (pool->dp_clock_source == clock_source)
468 		res_ctx->dp_clock_source_ref_count--;
469 }
470 
471 void resource_reference_clock_source(
472 		struct resource_context *res_ctx,
473 		const struct resource_pool *pool,
474 		struct clock_source *clock_source)
475 {
476 	int i = find_matching_clock_source(pool, clock_source);
477 
478 	if (i > -1)
479 		res_ctx->clock_source_ref_count[i]++;
480 
481 	if (pool->dp_clock_source == clock_source)
482 		res_ctx->dp_clock_source_ref_count++;
483 }
484 
485 int resource_get_clock_source_reference(
486 		struct resource_context *res_ctx,
487 		const struct resource_pool *pool,
488 		struct clock_source *clock_source)
489 {
490 	int i = find_matching_clock_source(pool, clock_source);
491 
492 	if (i > -1)
493 		return res_ctx->clock_source_ref_count[i];
494 
495 	if (pool->dp_clock_source == clock_source)
496 		return res_ctx->dp_clock_source_ref_count;
497 
498 	return -1;
499 }
500 
501 bool resource_are_vblanks_synchronizable(
502 	struct dc_stream_state *stream1,
503 	struct dc_stream_state *stream2)
504 {
505 	uint32_t base60_refresh_rates[] = {10, 20, 5};
506 	uint8_t i;
507 	uint8_t rr_count = ARRAY_SIZE(base60_refresh_rates);
508 	uint64_t frame_time_diff;
509 
510 	if (stream1->ctx->dc->config.vblank_alignment_dto_params &&
511 		stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 &&
512 		dc_is_dp_signal(stream1->signal) &&
513 		dc_is_dp_signal(stream2->signal) &&
514 		false == stream1->has_non_synchronizable_pclk &&
515 		false == stream2->has_non_synchronizable_pclk &&
516 		stream1->timing.flags.VBLANK_SYNCHRONIZABLE &&
517 		stream2->timing.flags.VBLANK_SYNCHRONIZABLE) {
518 		/* disable refresh rates higher than 60Hz for now */
519 		if (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/
520 				stream1->timing.v_total > 60)
521 			return false;
522 		if (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/
523 				stream2->timing.v_total > 60)
524 			return false;
525 		frame_time_diff = (uint64_t)10000 *
526 			stream1->timing.h_total *
527 			stream1->timing.v_total *
528 			stream2->timing.pix_clk_100hz;
529 		frame_time_diff = div_u64(frame_time_diff, stream1->timing.pix_clk_100hz);
530 		frame_time_diff = div_u64(frame_time_diff, stream2->timing.h_total);
531 		frame_time_diff = div_u64(frame_time_diff, stream2->timing.v_total);
532 		for (i = 0; i < rr_count; i++) {
533 			int64_t diff = (int64_t)div_u64(frame_time_diff * base60_refresh_rates[i], 10) - 10000;
534 
535 			if (diff < 0)
536 				diff = -diff;
537 			if (diff < stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff)
538 				return true;
539 		}
540 	}
541 	return false;
542 }
543 
544 bool resource_are_streams_timing_synchronizable(
545 	struct dc_stream_state *stream1,
546 	struct dc_stream_state *stream2)
547 {
548 	if (stream1->timing.h_total != stream2->timing.h_total)
549 		return false;
550 
551 	if (stream1->timing.v_total != stream2->timing.v_total)
552 		return false;
553 
554 	if (stream1->timing.h_addressable
555 				!= stream2->timing.h_addressable)
556 		return false;
557 
558 	if (stream1->timing.v_addressable
559 				!= stream2->timing.v_addressable)
560 		return false;
561 
562 	if (stream1->timing.v_front_porch
563 				!= stream2->timing.v_front_porch)
564 		return false;
565 
566 	if (stream1->timing.pix_clk_100hz
567 				!= stream2->timing.pix_clk_100hz)
568 		return false;
569 
570 	if (stream1->clamping.c_depth != stream2->clamping.c_depth)
571 		return false;
572 
573 	if (stream1->phy_pix_clk != stream2->phy_pix_clk
574 			&& (!dc_is_dp_signal(stream1->signal)
575 			|| !dc_is_dp_signal(stream2->signal)))
576 		return false;
577 
578 	if (stream1->view_format != stream2->view_format)
579 		return false;
580 
581 	if (stream1->ignore_msa_timing_param || stream2->ignore_msa_timing_param)
582 		return false;
583 
584 	return true;
585 }
586 static bool is_dp_and_hdmi_sharable(
587 		struct dc_stream_state *stream1,
588 		struct dc_stream_state *stream2)
589 {
590 	if (stream1->ctx->dc->caps.disable_dp_clk_share)
591 		return false;
592 
593 	if (stream1->clamping.c_depth != COLOR_DEPTH_888 ||
594 		stream2->clamping.c_depth != COLOR_DEPTH_888)
595 		return false;
596 
597 	return true;
598 
599 }
600 
601 static bool is_sharable_clk_src(
602 	const struct pipe_ctx *pipe_with_clk_src,
603 	const struct pipe_ctx *pipe)
604 {
605 	if (pipe_with_clk_src->clock_source == NULL)
606 		return false;
607 
608 	if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL)
609 		return false;
610 
611 	if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) ||
612 		(dc_is_dp_signal(pipe->stream->signal) &&
613 		!is_dp_and_hdmi_sharable(pipe_with_clk_src->stream,
614 				     pipe->stream)))
615 		return false;
616 
617 	if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal)
618 			&& dc_is_dual_link_signal(pipe->stream->signal))
619 		return false;
620 
621 	if (dc_is_hdmi_signal(pipe->stream->signal)
622 			&& dc_is_dual_link_signal(pipe_with_clk_src->stream->signal))
623 		return false;
624 
625 	if (!resource_are_streams_timing_synchronizable(
626 			pipe_with_clk_src->stream, pipe->stream))
627 		return false;
628 
629 	return true;
630 }
631 
632 struct clock_source *resource_find_used_clk_src_for_sharing(
633 					struct resource_context *res_ctx,
634 					struct pipe_ctx *pipe_ctx)
635 {
636 	int i;
637 
638 	for (i = 0; i < MAX_PIPES; i++) {
639 		if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx))
640 			return res_ctx->pipe_ctx[i].clock_source;
641 	}
642 
643 	return NULL;
644 }
645 
646 static enum pixel_format convert_pixel_format_to_dalsurface(
647 		enum surface_pixel_format surface_pixel_format)
648 {
649 	enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
650 
651 	switch (surface_pixel_format) {
652 	case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
653 		dal_pixel_format = PIXEL_FORMAT_INDEX8;
654 		break;
655 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
656 		dal_pixel_format = PIXEL_FORMAT_RGB565;
657 		break;
658 	case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
659 		dal_pixel_format = PIXEL_FORMAT_RGB565;
660 		break;
661 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
662 		dal_pixel_format = PIXEL_FORMAT_ARGB8888;
663 		break;
664 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
665 		dal_pixel_format = PIXEL_FORMAT_ARGB8888;
666 		break;
667 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
668 		dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
669 		break;
670 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
671 		dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
672 		break;
673 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
674 		dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS;
675 		break;
676 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
677 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
678 		dal_pixel_format = PIXEL_FORMAT_FP16;
679 		break;
680 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
681 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
682 		dal_pixel_format = PIXEL_FORMAT_420BPP8;
683 		break;
684 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
685 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
686 		dal_pixel_format = PIXEL_FORMAT_420BPP10;
687 		break;
688 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
689 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
690 	default:
691 		dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
692 		break;
693 	}
694 	return dal_pixel_format;
695 }
696 
697 static inline void get_vp_scan_direction(
698 	enum dc_rotation_angle rotation,
699 	bool horizontal_mirror,
700 	bool *orthogonal_rotation,
701 	bool *flip_vert_scan_dir,
702 	bool *flip_horz_scan_dir)
703 {
704 	*orthogonal_rotation = false;
705 	*flip_vert_scan_dir = false;
706 	*flip_horz_scan_dir = false;
707 	if (rotation == ROTATION_ANGLE_180) {
708 		*flip_vert_scan_dir = true;
709 		*flip_horz_scan_dir = true;
710 	} else if (rotation == ROTATION_ANGLE_90) {
711 		*orthogonal_rotation = true;
712 		*flip_horz_scan_dir = true;
713 	} else if (rotation == ROTATION_ANGLE_270) {
714 		*orthogonal_rotation = true;
715 		*flip_vert_scan_dir = true;
716 	}
717 
718 	if (horizontal_mirror)
719 		*flip_horz_scan_dir = !*flip_horz_scan_dir;
720 }
721 
722 int get_num_mpc_splits(struct pipe_ctx *pipe)
723 {
724 	int mpc_split_count = 0;
725 	struct pipe_ctx *other_pipe = pipe->bottom_pipe;
726 
727 	while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
728 		mpc_split_count++;
729 		other_pipe = other_pipe->bottom_pipe;
730 	}
731 	other_pipe = pipe->top_pipe;
732 	while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
733 		mpc_split_count++;
734 		other_pipe = other_pipe->top_pipe;
735 	}
736 
737 	return mpc_split_count;
738 }
739 
740 int get_num_odm_splits(struct pipe_ctx *pipe)
741 {
742 	int odm_split_count = 0;
743 	struct pipe_ctx *next_pipe = pipe->next_odm_pipe;
744 	while (next_pipe) {
745 		odm_split_count++;
746 		next_pipe = next_pipe->next_odm_pipe;
747 	}
748 	pipe = pipe->prev_odm_pipe;
749 	while (pipe) {
750 		odm_split_count++;
751 		pipe = pipe->prev_odm_pipe;
752 	}
753 	return odm_split_count;
754 }
755 
756 static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *split_count, int *split_idx)
757 {
758 	*split_count = get_num_odm_splits(pipe_ctx);
759 	*split_idx = 0;
760 	if (*split_count == 0) {
761 		/*Check for mpc split*/
762 		struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
763 
764 		*split_count = get_num_mpc_splits(pipe_ctx);
765 		while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
766 			(*split_idx)++;
767 			split_pipe = split_pipe->top_pipe;
768 		}
769 
770 		/* MPO window on right side of ODM split */
771 		if (split_pipe && split_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe)
772 			(*split_idx)++;
773 	} else {
774 		/*Get odm split index*/
775 		struct pipe_ctx *split_pipe = pipe_ctx->prev_odm_pipe;
776 
777 		while (split_pipe) {
778 			(*split_idx)++;
779 			split_pipe = split_pipe->prev_odm_pipe;
780 		}
781 	}
782 }
783 
784 /*
785  * This is a preliminary vp size calculation to allow us to check taps support.
786  * The result is completely overridden afterwards.
787  */
788 static void calculate_viewport_size(struct pipe_ctx *pipe_ctx)
789 {
790 	struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
791 
792 	data->viewport.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz, data->recout.width));
793 	data->viewport.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert, data->recout.height));
794 	data->viewport_c.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz_c, data->recout.width));
795 	data->viewport_c.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert_c, data->recout.height));
796 	if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
797 			pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
798 		swap(data->viewport.width, data->viewport.height);
799 		swap(data->viewport_c.width, data->viewport_c.height);
800 	}
801 }
802 
803 static void calculate_recout(struct pipe_ctx *pipe_ctx)
804 {
805 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
806 	const struct dc_stream_state *stream = pipe_ctx->stream;
807 	struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
808 	struct rect surf_clip = plane_state->clip_rect;
809 	bool split_tb = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM;
810 	int split_count, split_idx;
811 
812 	calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
813 	if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
814 		split_idx = 0;
815 
816 	/*
817 	 * Only the leftmost ODM pipe should be offset by a nonzero distance
818 	 */
819 	if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe) {
820 		/* MPO window on right side of ODM split */
821 		data->recout.x = stream->dst.x + (surf_clip.x - stream->src.x - stream->src.width/2) *
822 				stream->dst.width / stream->src.width;
823 	} else if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) {
824 		data->recout.x = stream->dst.x;
825 		if (stream->src.x < surf_clip.x)
826 			data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width
827 						/ stream->src.width;
828 	} else
829 		data->recout.x = 0;
830 
831 	if (stream->src.x > surf_clip.x)
832 		surf_clip.width -= stream->src.x - surf_clip.x;
833 	data->recout.width = surf_clip.width * stream->dst.width / stream->src.width;
834 	if (data->recout.width + data->recout.x > stream->dst.x + stream->dst.width)
835 		data->recout.width = stream->dst.x + stream->dst.width - data->recout.x;
836 
837 	data->recout.y = stream->dst.y;
838 	if (stream->src.y < surf_clip.y)
839 		data->recout.y += (surf_clip.y - stream->src.y) * stream->dst.height
840 						/ stream->src.height;
841 	else if (stream->src.y > surf_clip.y)
842 		surf_clip.height -= stream->src.y - surf_clip.y;
843 
844 	data->recout.height = surf_clip.height * stream->dst.height / stream->src.height;
845 	if (data->recout.height + data->recout.y > stream->dst.y + stream->dst.height)
846 		data->recout.height = stream->dst.y + stream->dst.height - data->recout.y;
847 
848 	/* Handle h & v split */
849 	if (split_tb) {
850 		ASSERT(data->recout.height % 2 == 0);
851 		data->recout.height /= 2;
852 	} else if (split_count) {
853 		if (!pipe_ctx->next_odm_pipe && !pipe_ctx->prev_odm_pipe) {
854 			/* extra pixels in the division remainder need to go to pipes after
855 			 * the extra pixel index minus one(epimo) defined here as:
856 			 */
857 			int epimo = split_count - data->recout.width % (split_count + 1);
858 
859 			data->recout.x += (data->recout.width / (split_count + 1)) * split_idx;
860 			if (split_idx > epimo)
861 				data->recout.x += split_idx - epimo - 1;
862 			ASSERT(stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || data->recout.width % 2 == 0);
863 			data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0);
864 		} else {
865 			/* odm */
866 			if (split_idx == split_count) {
867 				/* rightmost pipe is the remainder recout */
868 				data->recout.width -= data->h_active * split_count - data->recout.x;
869 
870 				/* ODM combine cases with MPO we can get negative widths */
871 				if (data->recout.width < 0)
872 					data->recout.width = 0;
873 
874 				data->recout.x = 0;
875 			} else
876 				data->recout.width = data->h_active - data->recout.x;
877 		}
878 	}
879 }
880 
881 static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
882 {
883 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
884 	const struct dc_stream_state *stream = pipe_ctx->stream;
885 	struct rect surf_src = plane_state->src_rect;
886 	const int in_w = stream->src.width;
887 	const int in_h = stream->src.height;
888 	const int out_w = stream->dst.width;
889 	const int out_h = stream->dst.height;
890 
891 	/*Swap surf_src height and width since scaling ratios are in recout rotation*/
892 	if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
893 			pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
894 		swap(surf_src.height, surf_src.width);
895 
896 	pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction(
897 					surf_src.width,
898 					plane_state->dst_rect.width);
899 	pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_from_fraction(
900 					surf_src.height,
901 					plane_state->dst_rect.height);
902 
903 	if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
904 		pipe_ctx->plane_res.scl_data.ratios.horz.value *= 2;
905 	else if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
906 		pipe_ctx->plane_res.scl_data.ratios.vert.value *= 2;
907 
908 	pipe_ctx->plane_res.scl_data.ratios.vert.value = div64_s64(
909 		pipe_ctx->plane_res.scl_data.ratios.vert.value * in_h, out_h);
910 	pipe_ctx->plane_res.scl_data.ratios.horz.value = div64_s64(
911 		pipe_ctx->plane_res.scl_data.ratios.horz.value * in_w, out_w);
912 
913 	pipe_ctx->plane_res.scl_data.ratios.horz_c = pipe_ctx->plane_res.scl_data.ratios.horz;
914 	pipe_ctx->plane_res.scl_data.ratios.vert_c = pipe_ctx->plane_res.scl_data.ratios.vert;
915 
916 	if (pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP8
917 			|| pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP10) {
918 		pipe_ctx->plane_res.scl_data.ratios.horz_c.value /= 2;
919 		pipe_ctx->plane_res.scl_data.ratios.vert_c.value /= 2;
920 	}
921 	pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_truncate(
922 			pipe_ctx->plane_res.scl_data.ratios.horz, 19);
923 	pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_truncate(
924 			pipe_ctx->plane_res.scl_data.ratios.vert, 19);
925 	pipe_ctx->plane_res.scl_data.ratios.horz_c = dc_fixpt_truncate(
926 			pipe_ctx->plane_res.scl_data.ratios.horz_c, 19);
927 	pipe_ctx->plane_res.scl_data.ratios.vert_c = dc_fixpt_truncate(
928 			pipe_ctx->plane_res.scl_data.ratios.vert_c, 19);
929 }
930 
931 
932 /*
933  * We completely calculate vp offset, size and inits here based entirely on scaling
934  * ratios and recout for pixel perfect pipe combine.
935  */
936 static void calculate_init_and_vp(
937 		bool flip_scan_dir,
938 		int recout_offset_within_recout_full,
939 		int recout_size,
940 		int src_size,
941 		int taps,
942 		struct fixed31_32 ratio,
943 		struct fixed31_32 *init,
944 		int *vp_offset,
945 		int *vp_size)
946 {
947 	struct fixed31_32 temp;
948 	int int_part;
949 
950 	/*
951 	 * First of the taps starts sampling pixel number <init_int_part> corresponding to recout
952 	 * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on.
953 	 * All following calculations are based on this logic.
954 	 *
955 	 * Init calculated according to formula:
956 	 * 	init = (scaling_ratio + number_of_taps + 1) / 2
957 	 * 	init_bot = init + scaling_ratio
958 	 * 	to get pixel perfect combine add the fraction from calculating vp offset
959 	 */
960 	temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full);
961 	*vp_offset = dc_fixpt_floor(temp);
962 	temp.value &= 0xffffffff;
963 	*init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int(
964 			dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19);
965 	/*
966 	 * If viewport has non 0 offset and there are more taps than covered by init then
967 	 * we should decrease the offset and increase init so we are never sampling
968 	 * outside of viewport.
969 	 */
970 	int_part = dc_fixpt_floor(*init);
971 	if (int_part < taps) {
972 		int_part = taps - int_part;
973 		if (int_part > *vp_offset)
974 			int_part = *vp_offset;
975 		*vp_offset -= int_part;
976 		*init = dc_fixpt_add_int(*init, int_part);
977 	}
978 	/*
979 	 * If taps are sampling outside of viewport at end of recout and there are more pixels
980 	 * available in the surface we should increase the viewport size, regardless set vp to
981 	 * only what is used.
982 	 */
983 	temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1));
984 	*vp_size = dc_fixpt_floor(temp);
985 	if (*vp_size + *vp_offset > src_size)
986 		*vp_size = src_size - *vp_offset;
987 
988 	/* We did all the math assuming we are scanning same direction as display does,
989 	 * however mirror/rotation changes how vp scans vs how it is offset. If scan direction
990 	 * is flipped we simply need to calculate offset from the other side of plane.
991 	 * Note that outside of viewport all scaling hardware works in recout space.
992 	 */
993 	if (flip_scan_dir)
994 		*vp_offset = src_size - *vp_offset - *vp_size;
995 }
996 
997 static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
998 {
999 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1000 	const struct dc_stream_state *stream = pipe_ctx->stream;
1001 	struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
1002 	struct rect src = plane_state->src_rect;
1003 	int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
1004 				|| data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
1005 	int split_count, split_idx, ro_lb, ro_tb, recout_full_x, recout_full_y;
1006 	bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
1007 
1008 	calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
1009 	/*
1010 	 * recout full is what the recout would have been if we didnt clip
1011 	 * the source plane at all. We only care about left(ro_lb) and top(ro_tb)
1012 	 * offsets of recout within recout full because those are the directions
1013 	 * we scan from and therefore the only ones that affect inits.
1014 	 */
1015 	recout_full_x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x)
1016 			* stream->dst.width / stream->src.width;
1017 	recout_full_y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y)
1018 			* stream->dst.height / stream->src.height;
1019 	if (pipe_ctx->prev_odm_pipe && split_idx)
1020 		ro_lb = data->h_active * split_idx - recout_full_x;
1021 	else if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe)
1022 		ro_lb = data->h_active * split_idx - recout_full_x + data->recout.x;
1023 	else
1024 		ro_lb = data->recout.x - recout_full_x;
1025 	ro_tb = data->recout.y - recout_full_y;
1026 	ASSERT(ro_lb >= 0 && ro_tb >= 0);
1027 
1028 	/*
1029 	 * Work in recout rotation since that requires less transformations
1030 	 */
1031 	get_vp_scan_direction(
1032 			plane_state->rotation,
1033 			plane_state->horizontal_mirror,
1034 			&orthogonal_rotation,
1035 			&flip_vert_scan_dir,
1036 			&flip_horz_scan_dir);
1037 
1038 	if (orthogonal_rotation) {
1039 		swap(src.width, src.height);
1040 		swap(flip_vert_scan_dir, flip_horz_scan_dir);
1041 	}
1042 
1043 	calculate_init_and_vp(
1044 			flip_horz_scan_dir,
1045 			ro_lb,
1046 			data->recout.width,
1047 			src.width,
1048 			data->taps.h_taps,
1049 			data->ratios.horz,
1050 			&data->inits.h,
1051 			&data->viewport.x,
1052 			&data->viewport.width);
1053 	calculate_init_and_vp(
1054 			flip_horz_scan_dir,
1055 			ro_lb,
1056 			data->recout.width,
1057 			src.width / vpc_div,
1058 			data->taps.h_taps_c,
1059 			data->ratios.horz_c,
1060 			&data->inits.h_c,
1061 			&data->viewport_c.x,
1062 			&data->viewport_c.width);
1063 	calculate_init_and_vp(
1064 			flip_vert_scan_dir,
1065 			ro_tb,
1066 			data->recout.height,
1067 			src.height,
1068 			data->taps.v_taps,
1069 			data->ratios.vert,
1070 			&data->inits.v,
1071 			&data->viewport.y,
1072 			&data->viewport.height);
1073 	calculate_init_and_vp(
1074 			flip_vert_scan_dir,
1075 			ro_tb,
1076 			data->recout.height,
1077 			src.height / vpc_div,
1078 			data->taps.v_taps_c,
1079 			data->ratios.vert_c,
1080 			&data->inits.v_c,
1081 			&data->viewport_c.y,
1082 			&data->viewport_c.height);
1083 	if (orthogonal_rotation) {
1084 		swap(data->viewport.x, data->viewport.y);
1085 		swap(data->viewport.width, data->viewport.height);
1086 		swap(data->viewport_c.x, data->viewport_c.y);
1087 		swap(data->viewport_c.width, data->viewport_c.height);
1088 	}
1089 	data->viewport.x += src.x;
1090 	data->viewport.y += src.y;
1091 	ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0);
1092 	data->viewport_c.x += src.x / vpc_div;
1093 	data->viewport_c.y += src.y / vpc_div;
1094 }
1095 
1096 bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
1097 {
1098 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1099 	struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
1100 	bool res = false;
1101 	DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
1102 
1103 	/* Invalid input */
1104 	if (!plane_state->dst_rect.width ||
1105 			!plane_state->dst_rect.height ||
1106 			!plane_state->src_rect.width ||
1107 			!plane_state->src_rect.height) {
1108 		ASSERT(0);
1109 		return false;
1110 	}
1111 
1112 	pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
1113 			pipe_ctx->plane_state->format);
1114 
1115 	/* Timing borders are part of vactive that we are also supposed to skip in addition
1116 	 * to any stream dst offset. Since dm logic assumes dst is in addressable
1117 	 * space we need to add the left and top borders to dst offsets temporarily.
1118 	 * TODO: fix in DM, stream dst is supposed to be in vactive
1119 	 */
1120 	pipe_ctx->stream->dst.x += timing->h_border_left;
1121 	pipe_ctx->stream->dst.y += timing->v_border_top;
1122 
1123 	/* Calculate H and V active size */
1124 	pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable +
1125 			timing->h_border_left + timing->h_border_right;
1126 	pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable +
1127 		timing->v_border_top + timing->v_border_bottom;
1128 	if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe) {
1129 		pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1;
1130 
1131 		DC_LOG_SCALER("%s pipe %d: next_odm_pipe:%d   prev_odm_pipe:%d\n",
1132 				__func__,
1133 				pipe_ctx->pipe_idx,
1134 				pipe_ctx->next_odm_pipe ? pipe_ctx->next_odm_pipe->pipe_idx : -1,
1135 				pipe_ctx->prev_odm_pipe ? pipe_ctx->prev_odm_pipe->pipe_idx : -1);
1136 	}	/* ODM + windows MPO, where window is on either right or left ODM half */
1137 	else if (pipe_ctx->top_pipe && (pipe_ctx->top_pipe->next_odm_pipe || pipe_ctx->top_pipe->prev_odm_pipe)) {
1138 
1139 		pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx->top_pipe) + 1;
1140 
1141 		DC_LOG_SCALER("%s ODM + windows MPO: pipe:%d top_pipe:%d   top_pipe->next_odm_pipe:%d   top_pipe->prev_odm_pipe:%d\n",
1142 				__func__,
1143 				pipe_ctx->pipe_idx,
1144 				pipe_ctx->top_pipe->pipe_idx,
1145 				pipe_ctx->top_pipe->next_odm_pipe ? pipe_ctx->top_pipe->next_odm_pipe->pipe_idx : -1,
1146 				pipe_ctx->top_pipe->prev_odm_pipe ? pipe_ctx->top_pipe->prev_odm_pipe->pipe_idx : -1);
1147 	}
1148 	/* depends on h_active */
1149 	calculate_recout(pipe_ctx);
1150 	/* depends on pixel format */
1151 	calculate_scaling_ratios(pipe_ctx);
1152 	/* depends on scaling ratios and recout, does not calculate offset yet */
1153 	calculate_viewport_size(pipe_ctx);
1154 
1155 	if (!pipe_ctx->stream->ctx->dc->config.enable_windowed_mpo_odm) {
1156 		/* Stopgap for validation of ODM + MPO on one side of screen case */
1157 		if (pipe_ctx->plane_res.scl_data.viewport.height < 1 ||
1158 				pipe_ctx->plane_res.scl_data.viewport.width < 1)
1159 			return false;
1160 	}
1161 
1162 	/*
1163 	 * LB calculations depend on vp size, h/v_active and scaling ratios
1164 	 * Setting line buffer pixel depth to 24bpp yields banding
1165 	 * on certain displays, such as the Sharp 4k. 36bpp is needed
1166 	 * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and
1167 	 * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc
1168 	 * precision on DCN display engines, but apparently not for DCE, as
1169 	 * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have
1170 	 * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
1171 	 * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel
1172 	 * passthrough). Therefore only use 36 bpp on DCN where it is actually needed.
1173 	 */
1174 	if (plane_state->ctx->dce_version > DCE_VERSION_MAX)
1175 		pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
1176 	else
1177 		pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1178 
1179 	pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
1180 
1181 	if (pipe_ctx->plane_res.xfm != NULL)
1182 		res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1183 				pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1184 
1185 	if (pipe_ctx->plane_res.dpp != NULL)
1186 		res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1187 				pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1188 
1189 
1190 	if (!res) {
1191 		/* Try 24 bpp linebuffer */
1192 		pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP;
1193 
1194 		if (pipe_ctx->plane_res.xfm != NULL)
1195 			res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1196 					pipe_ctx->plane_res.xfm,
1197 					&pipe_ctx->plane_res.scl_data,
1198 					&plane_state->scaling_quality);
1199 
1200 		if (pipe_ctx->plane_res.dpp != NULL)
1201 			res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1202 					pipe_ctx->plane_res.dpp,
1203 					&pipe_ctx->plane_res.scl_data,
1204 					&plane_state->scaling_quality);
1205 	}
1206 
1207 	/*
1208 	 * Depends on recout, scaling ratios, h_active and taps
1209 	 * May need to re-check lb size after this in some obscure scenario
1210 	 */
1211 	if (res)
1212 		calculate_inits_and_viewports(pipe_ctx);
1213 
1214 	/*
1215 	 * Handle side by side and top bottom 3d recout offsets after vp calculation
1216 	 * since 3d is special and needs to calculate vp as if there is no recout offset
1217 	 * This may break with rotation, good thing we aren't mixing hw rotation and 3d
1218 	 */
1219 	if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) {
1220 		ASSERT(plane_state->rotation == ROTATION_ANGLE_0 ||
1221 			(pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM &&
1222 				pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE));
1223 		if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
1224 			pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height;
1225 		else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
1226 			pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width;
1227 	}
1228 
1229 	if (!pipe_ctx->stream->ctx->dc->config.enable_windowed_mpo_odm) {
1230 		if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE ||
1231 				pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE)
1232 			res = false;
1233 	} else {
1234 		/* Clamp minimum viewport size */
1235 		if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE)
1236 			pipe_ctx->plane_res.scl_data.viewport.height = MIN_VIEWPORT_SIZE;
1237 		if (pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE)
1238 			pipe_ctx->plane_res.scl_data.viewport.width = MIN_VIEWPORT_SIZE;
1239 	}
1240 
1241 	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"
1242 			"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",
1243 			__func__,
1244 			pipe_ctx->pipe_idx,
1245 			pipe_ctx->plane_res.scl_data.viewport.height,
1246 			pipe_ctx->plane_res.scl_data.viewport.width,
1247 			pipe_ctx->plane_res.scl_data.viewport.x,
1248 			pipe_ctx->plane_res.scl_data.viewport.y,
1249 			pipe_ctx->plane_res.scl_data.recout.height,
1250 			pipe_ctx->plane_res.scl_data.recout.width,
1251 			pipe_ctx->plane_res.scl_data.recout.x,
1252 			pipe_ctx->plane_res.scl_data.recout.y,
1253 			pipe_ctx->plane_res.scl_data.h_active,
1254 			pipe_ctx->plane_res.scl_data.v_active,
1255 			plane_state->src_rect.height,
1256 			plane_state->src_rect.width,
1257 			plane_state->src_rect.x,
1258 			plane_state->src_rect.y,
1259 			plane_state->dst_rect.height,
1260 			plane_state->dst_rect.width,
1261 			plane_state->dst_rect.x,
1262 			plane_state->dst_rect.y,
1263 			plane_state->clip_rect.height,
1264 			plane_state->clip_rect.width,
1265 			plane_state->clip_rect.x,
1266 			plane_state->clip_rect.y);
1267 
1268 	pipe_ctx->stream->dst.x -= timing->h_border_left;
1269 	pipe_ctx->stream->dst.y -= timing->v_border_top;
1270 
1271 	return res;
1272 }
1273 
1274 
1275 enum dc_status resource_build_scaling_params_for_context(
1276 	const struct dc  *dc,
1277 	struct dc_state *context)
1278 {
1279 	int i;
1280 
1281 	for (i = 0; i < MAX_PIPES; i++) {
1282 		if (context->res_ctx.pipe_ctx[i].plane_state != NULL &&
1283 				context->res_ctx.pipe_ctx[i].stream != NULL)
1284 			if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i]))
1285 				return DC_FAIL_SCALING;
1286 	}
1287 
1288 	return DC_OK;
1289 }
1290 
1291 struct pipe_ctx *find_idle_secondary_pipe(
1292 		struct resource_context *res_ctx,
1293 		const struct resource_pool *pool,
1294 		const struct pipe_ctx *primary_pipe)
1295 {
1296 	int i;
1297 	struct pipe_ctx *secondary_pipe = NULL;
1298 
1299 	/*
1300 	 * We add a preferred pipe mapping to avoid the chance that
1301 	 * MPCCs already in use will need to be reassigned to other trees.
1302 	 * For example, if we went with the strict, assign backwards logic:
1303 	 *
1304 	 * (State 1)
1305 	 * Display A on, no surface, top pipe = 0
1306 	 * Display B on, no surface, top pipe = 1
1307 	 *
1308 	 * (State 2)
1309 	 * Display A on, no surface, top pipe = 0
1310 	 * Display B on, surface enable, top pipe = 1, bottom pipe = 5
1311 	 *
1312 	 * (State 3)
1313 	 * Display A on, surface enable, top pipe = 0, bottom pipe = 5
1314 	 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1315 	 *
1316 	 * The state 2->3 transition requires remapping MPCC 5 from display B
1317 	 * to display A.
1318 	 *
1319 	 * However, with the preferred pipe logic, state 2 would look like:
1320 	 *
1321 	 * (State 2)
1322 	 * Display A on, no surface, top pipe = 0
1323 	 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1324 	 *
1325 	 * This would then cause 2->3 to not require remapping any MPCCs.
1326 	 */
1327 	if (primary_pipe) {
1328 		int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx;
1329 		if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) {
1330 			secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
1331 			secondary_pipe->pipe_idx = preferred_pipe_idx;
1332 		}
1333 	}
1334 
1335 	/*
1336 	 * search backwards for the second pipe to keep pipe
1337 	 * assignment more consistent
1338 	 */
1339 	if (!secondary_pipe)
1340 		for (i = pool->pipe_count - 1; i >= 0; i--) {
1341 			if (res_ctx->pipe_ctx[i].stream == NULL) {
1342 				secondary_pipe = &res_ctx->pipe_ctx[i];
1343 				secondary_pipe->pipe_idx = i;
1344 				break;
1345 			}
1346 		}
1347 
1348 	return secondary_pipe;
1349 }
1350 
1351 struct pipe_ctx *resource_get_head_pipe_for_stream(
1352 		struct resource_context *res_ctx,
1353 		struct dc_stream_state *stream)
1354 {
1355 	int i;
1356 
1357 	for (i = 0; i < MAX_PIPES; i++) {
1358 		if (res_ctx->pipe_ctx[i].stream == stream
1359 				&& !res_ctx->pipe_ctx[i].top_pipe
1360 				&& !res_ctx->pipe_ctx[i].prev_odm_pipe)
1361 			return &res_ctx->pipe_ctx[i];
1362 	}
1363 	return NULL;
1364 }
1365 
1366 static struct pipe_ctx *resource_get_tail_pipe(
1367 		struct resource_context *res_ctx,
1368 		struct pipe_ctx *head_pipe)
1369 {
1370 	struct pipe_ctx *tail_pipe;
1371 
1372 	tail_pipe = head_pipe->bottom_pipe;
1373 
1374 	while (tail_pipe) {
1375 		head_pipe = tail_pipe;
1376 		tail_pipe = tail_pipe->bottom_pipe;
1377 	}
1378 
1379 	return head_pipe;
1380 }
1381 
1382 /*
1383  * A free_pipe for a stream is defined here as a pipe
1384  * that has no surface attached yet
1385  */
1386 static struct pipe_ctx *acquire_free_pipe_for_head(
1387 		struct dc_state *context,
1388 		const struct resource_pool *pool,
1389 		struct pipe_ctx *head_pipe)
1390 {
1391 	int i;
1392 	struct resource_context *res_ctx = &context->res_ctx;
1393 
1394 	if (!head_pipe->plane_state)
1395 		return head_pipe;
1396 
1397 	/* Re-use pipe already acquired for this stream if available*/
1398 	for (i = pool->pipe_count - 1; i >= 0; i--) {
1399 		if (res_ctx->pipe_ctx[i].stream == head_pipe->stream &&
1400 				!res_ctx->pipe_ctx[i].plane_state) {
1401 			return &res_ctx->pipe_ctx[i];
1402 		}
1403 	}
1404 
1405 	/*
1406 	 * At this point we have no re-useable pipe for this stream and we need
1407 	 * to acquire an idle one to satisfy the request
1408 	 */
1409 
1410 	if (!pool->funcs->acquire_idle_pipe_for_layer) {
1411 		if (!pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer)
1412 			return NULL;
1413 		else
1414 			return pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer(context, pool, head_pipe->stream, head_pipe);
1415 	}
1416 
1417 	return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream);
1418 }
1419 
1420 static int acquire_first_split_pipe(
1421 		struct resource_context *res_ctx,
1422 		const struct resource_pool *pool,
1423 		struct dc_stream_state *stream)
1424 {
1425 	int i;
1426 
1427 	for (i = 0; i < pool->pipe_count; i++) {
1428 		struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i];
1429 
1430 		if (split_pipe->top_pipe &&
1431 				split_pipe->top_pipe->plane_state == split_pipe->plane_state) {
1432 			split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe;
1433 			if (split_pipe->bottom_pipe)
1434 				split_pipe->bottom_pipe->top_pipe = split_pipe->top_pipe;
1435 
1436 			if (split_pipe->top_pipe->plane_state)
1437 				resource_build_scaling_params(split_pipe->top_pipe);
1438 
1439 			memset(split_pipe, 0, sizeof(*split_pipe));
1440 			split_pipe->stream_res.tg = pool->timing_generators[i];
1441 			split_pipe->plane_res.hubp = pool->hubps[i];
1442 			split_pipe->plane_res.ipp = pool->ipps[i];
1443 			split_pipe->plane_res.dpp = pool->dpps[i];
1444 			split_pipe->stream_res.opp = pool->opps[i];
1445 			split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
1446 			split_pipe->pipe_idx = i;
1447 
1448 			split_pipe->stream = stream;
1449 			return i;
1450 		} else if (split_pipe->prev_odm_pipe &&
1451 				split_pipe->prev_odm_pipe->plane_state == split_pipe->plane_state) {
1452 			split_pipe->prev_odm_pipe->next_odm_pipe = split_pipe->next_odm_pipe;
1453 			if (split_pipe->next_odm_pipe)
1454 				split_pipe->next_odm_pipe->prev_odm_pipe = split_pipe->prev_odm_pipe;
1455 
1456 			if (split_pipe->prev_odm_pipe->plane_state)
1457 				resource_build_scaling_params(split_pipe->prev_odm_pipe);
1458 
1459 			memset(split_pipe, 0, sizeof(*split_pipe));
1460 			split_pipe->stream_res.tg = pool->timing_generators[i];
1461 			split_pipe->plane_res.hubp = pool->hubps[i];
1462 			split_pipe->plane_res.ipp = pool->ipps[i];
1463 			split_pipe->plane_res.dpp = pool->dpps[i];
1464 			split_pipe->stream_res.opp = pool->opps[i];
1465 			split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
1466 			split_pipe->pipe_idx = i;
1467 
1468 			split_pipe->stream = stream;
1469 			return i;
1470 		}
1471 	}
1472 	return -1;
1473 }
1474 
1475 bool dc_add_plane_to_context(
1476 		const struct dc *dc,
1477 		struct dc_stream_state *stream,
1478 		struct dc_plane_state *plane_state,
1479 		struct dc_state *context)
1480 {
1481 	int i;
1482 	struct resource_pool *pool = dc->res_pool;
1483 	struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe;
1484 	struct dc_stream_status *stream_status = NULL;
1485 	struct pipe_ctx *prev_right_head = NULL;
1486 	struct pipe_ctx *free_right_pipe = NULL;
1487 	struct pipe_ctx *prev_left_head = NULL;
1488 
1489 	DC_LOGGER_INIT(stream->ctx->logger);
1490 	for (i = 0; i < context->stream_count; i++)
1491 		if (context->streams[i] == stream) {
1492 			stream_status = &context->stream_status[i];
1493 			break;
1494 		}
1495 	if (stream_status == NULL) {
1496 		dm_error("Existing stream not found; failed to attach surface!\n");
1497 		return false;
1498 	}
1499 
1500 
1501 	if (stream_status->plane_count == MAX_SURFACE_NUM) {
1502 		dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",
1503 				plane_state, MAX_SURFACE_NUM);
1504 		return false;
1505 	}
1506 
1507 	head_pipe = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
1508 
1509 	if (!head_pipe) {
1510 		dm_error("Head pipe not found for stream_state %p !\n", stream);
1511 		return false;
1512 	}
1513 
1514 	/* retain new surface, but only once per stream */
1515 	dc_plane_state_retain(plane_state);
1516 
1517 	while (head_pipe) {
1518 		free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
1519 
1520 		if (!free_pipe) {
1521 			int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
1522 			if (pipe_idx >= 0)
1523 				free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
1524 		}
1525 
1526 		if (!free_pipe) {
1527 			dc_plane_state_release(plane_state);
1528 			return false;
1529 		}
1530 
1531 		free_pipe->plane_state = plane_state;
1532 
1533 		if (head_pipe != free_pipe) {
1534 			tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe);
1535 			ASSERT(tail_pipe);
1536 
1537 			/* ODM + window MPO, where MPO window is on right half only */
1538 			if (free_pipe->plane_state &&
1539 				(free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2) &&
1540 				tail_pipe->next_odm_pipe) {
1541 
1542 				/* For ODM + window MPO, in 3 plane case, if we already have a MPO window on
1543 				 *  the right side, then we will invalidate a 2nd one on the right side
1544 				 */
1545 				if (head_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) {
1546 					dc_plane_state_release(plane_state);
1547 					return false;
1548 				}
1549 
1550 				DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d  tail_pipe->next_odm_pipe:%d\n",
1551 						__func__,
1552 						free_pipe->pipe_idx,
1553 						tail_pipe->next_odm_pipe ? tail_pipe->next_odm_pipe->pipe_idx : -1);
1554 
1555 				/*
1556 				 * We want to avoid the case where the right side already has a pipe assigned to
1557 				 *  it and is different from free_pipe ( which would cause trigger a pipe
1558 				 *  reallocation ).
1559 				 * Check the old context to see if the right side already has a pipe allocated
1560 				 * - If not, continue to use free_pipe
1561 				 * - If the right side already has a pipe, use that pipe instead if its available
1562 				 */
1563 
1564 				/*
1565 				 * We also want to avoid the case where with three plane ( 2 MPO videos ), we have
1566 				 *  both videos on the left side so one of the videos is invalidated.  Then we
1567 				 *  move the invalidated video back to the right side.  If the order of the plane
1568 				 *  states is such that the right MPO plane is processed first, the free pipe
1569 				 *  selected by the head will be the left MPO pipe. But since there was no right
1570 				 *  MPO pipe, it will assign the free pipe to the right MPO pipe instead and
1571 				 *  a pipe reallocation will occur.
1572 				 * Check the old context to see if the left side already has a pipe allocated
1573 				 * - If not, continue to use free_pipe
1574 				 * - If the left side is already using this pipe, then pick another pipe for right
1575 				 */
1576 
1577 				prev_right_head = &dc->current_state->res_ctx.pipe_ctx[tail_pipe->next_odm_pipe->pipe_idx];
1578 				if ((prev_right_head->bottom_pipe) &&
1579 					(free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) {
1580 					free_right_pipe = acquire_free_pipe_for_head(context, pool, tail_pipe->next_odm_pipe);
1581 				} else {
1582 					prev_left_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->pipe_idx];
1583 					if ((prev_left_head->bottom_pipe) &&
1584 						(free_pipe->pipe_idx == prev_left_head->bottom_pipe->pipe_idx)) {
1585 						free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
1586 					}
1587 				}
1588 
1589 				if (free_right_pipe) {
1590 					free_pipe->stream = NULL;
1591 					memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource));
1592 					memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource));
1593 					free_pipe->plane_state = NULL;
1594 					free_pipe->pipe_idx = 0;
1595 					free_right_pipe->plane_state = plane_state;
1596 					free_pipe = free_right_pipe;
1597 				}
1598 
1599 				free_pipe->stream_res.tg = tail_pipe->next_odm_pipe->stream_res.tg;
1600 				free_pipe->stream_res.abm = tail_pipe->next_odm_pipe->stream_res.abm;
1601 				free_pipe->stream_res.opp = tail_pipe->next_odm_pipe->stream_res.opp;
1602 				free_pipe->stream_res.stream_enc = tail_pipe->next_odm_pipe->stream_res.stream_enc;
1603 				free_pipe->stream_res.audio = tail_pipe->next_odm_pipe->stream_res.audio;
1604 				free_pipe->clock_source = tail_pipe->next_odm_pipe->clock_source;
1605 
1606 				free_pipe->top_pipe = tail_pipe->next_odm_pipe;
1607 				tail_pipe->next_odm_pipe->bottom_pipe = free_pipe;
1608 			} else if (free_pipe->plane_state &&
1609 				(free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2)
1610 				&& head_pipe->next_odm_pipe) {
1611 
1612 				/* For ODM + window MPO, support 3 plane ( 2 MPO ) case.
1613 				 * Here we have a desktop ODM + left window MPO and a new MPO window appears
1614 				 *  on the right side only.  It fails the first case, because tail_pipe is the
1615 				 *  left window MPO, so it has no next_odm_pipe.  So in this scenario, we check
1616 				 *  for head_pipe->next_odm_pipe instead
1617 				 */
1618 				DC_LOG_SCALER("%s - ODM + win MPO (left) + win MPO (right). free_pipe:%d  head_pipe->next_odm:%d\n",
1619 						__func__,
1620 						free_pipe->pipe_idx,
1621 						head_pipe->next_odm_pipe ? head_pipe->next_odm_pipe->pipe_idx : -1);
1622 
1623 				/*
1624 				 * We want to avoid the case where the right side already has a pipe assigned to
1625 				 *  it and is different from free_pipe ( which would cause trigger a pipe
1626 				 *  reallocation ).
1627 				 * Check the old context to see if the right side already has a pipe allocated
1628 				 * - If not, continue to use free_pipe
1629 				 * - If the right side already has a pipe, use that pipe instead if its available
1630 				 */
1631 				prev_right_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->next_odm_pipe->pipe_idx];
1632 				if ((prev_right_head->bottom_pipe) &&
1633 					(free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) {
1634 					free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe->next_odm_pipe);
1635 					if (free_right_pipe) {
1636 						free_pipe->stream = NULL;
1637 						memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource));
1638 						memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource));
1639 						free_pipe->plane_state = NULL;
1640 						free_pipe->pipe_idx = 0;
1641 						free_right_pipe->plane_state = plane_state;
1642 						free_pipe = free_right_pipe;
1643 					}
1644 				}
1645 
1646 				free_pipe->stream_res.tg = head_pipe->next_odm_pipe->stream_res.tg;
1647 				free_pipe->stream_res.abm = head_pipe->next_odm_pipe->stream_res.abm;
1648 				free_pipe->stream_res.opp = head_pipe->next_odm_pipe->stream_res.opp;
1649 				free_pipe->stream_res.stream_enc = head_pipe->next_odm_pipe->stream_res.stream_enc;
1650 				free_pipe->stream_res.audio = head_pipe->next_odm_pipe->stream_res.audio;
1651 				free_pipe->clock_source = head_pipe->next_odm_pipe->clock_source;
1652 
1653 				free_pipe->top_pipe = head_pipe->next_odm_pipe;
1654 				head_pipe->next_odm_pipe->bottom_pipe = free_pipe;
1655 			} else {
1656 
1657 				/* For ODM + window MPO, in 3 plane case, if we already have a MPO window on
1658 				 *  the left side, then we will invalidate a 2nd one on the left side
1659 				 */
1660 				if (head_pipe->next_odm_pipe && tail_pipe->top_pipe) {
1661 					dc_plane_state_release(plane_state);
1662 					return false;
1663 				}
1664 
1665 				free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
1666 				free_pipe->stream_res.abm = tail_pipe->stream_res.abm;
1667 				free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
1668 				free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
1669 				free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
1670 				free_pipe->clock_source = tail_pipe->clock_source;
1671 
1672 				free_pipe->top_pipe = tail_pipe;
1673 				tail_pipe->bottom_pipe = free_pipe;
1674 
1675 				/* Connect MPO pipes together if MPO window is in the centre */
1676 				if (!(free_pipe->plane_state &&
1677 						(free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <=
1678 						free_pipe->stream->src.x + free_pipe->stream->src.width/2))) {
1679 					if (!free_pipe->next_odm_pipe &&
1680 						tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) {
1681 						free_pipe->next_odm_pipe = tail_pipe->next_odm_pipe->bottom_pipe;
1682 						tail_pipe->next_odm_pipe->bottom_pipe->prev_odm_pipe = free_pipe;
1683 					}
1684 					if (!free_pipe->prev_odm_pipe &&
1685 						tail_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe->bottom_pipe) {
1686 						free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe;
1687 						tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe;
1688 					}
1689 				}
1690 			}
1691 		}
1692 
1693 		/* ODM + window MPO, where MPO window is on left half only */
1694 		if (free_pipe->plane_state &&
1695 			(free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <=
1696 			free_pipe->stream->src.x + free_pipe->stream->src.width/2)) {
1697 			DC_LOG_SCALER("%s - ODM + window MPO(left). free_pipe:%d\n",
1698 					__func__,
1699 					free_pipe->pipe_idx);
1700 			break;
1701 		}
1702 		/* ODM + window MPO, where MPO window is on right half only */
1703 		if (free_pipe->plane_state &&
1704 			(free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2)) {
1705 			DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d\n",
1706 					__func__,
1707 					free_pipe->pipe_idx);
1708 			break;
1709 		}
1710 
1711 		head_pipe = head_pipe->next_odm_pipe;
1712 	}
1713 	/* assign new surfaces*/
1714 	stream_status->plane_states[stream_status->plane_count] = plane_state;
1715 
1716 	stream_status->plane_count++;
1717 
1718 	return true;
1719 }
1720 
1721 bool dc_remove_plane_from_context(
1722 		const struct dc *dc,
1723 		struct dc_stream_state *stream,
1724 		struct dc_plane_state *plane_state,
1725 		struct dc_state *context)
1726 {
1727 	int i;
1728 	struct dc_stream_status *stream_status = NULL;
1729 	struct resource_pool *pool = dc->res_pool;
1730 
1731 	if (!plane_state)
1732 		return true;
1733 
1734 	for (i = 0; i < context->stream_count; i++)
1735 		if (context->streams[i] == stream) {
1736 			stream_status = &context->stream_status[i];
1737 			break;
1738 		}
1739 
1740 	if (stream_status == NULL) {
1741 		dm_error("Existing stream not found; failed to remove plane.\n");
1742 		return false;
1743 	}
1744 
1745 	/* release pipe for plane*/
1746 	for (i = pool->pipe_count - 1; i >= 0; i--) {
1747 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1748 
1749 		if (pipe_ctx->plane_state == plane_state) {
1750 			if (pipe_ctx->top_pipe)
1751 				pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
1752 
1753 			/* Second condition is to avoid setting NULL to top pipe
1754 			 * of tail pipe making it look like head pipe in subsequent
1755 			 * deletes
1756 			 */
1757 			if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe)
1758 				pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe;
1759 
1760 			/*
1761 			 * For head pipe detach surfaces from pipe for tail
1762 			 * pipe just zero it out
1763 			 */
1764 			if (!pipe_ctx->top_pipe)
1765 				pipe_ctx->plane_state = NULL;
1766 			else
1767 				memset(pipe_ctx, 0, sizeof(*pipe_ctx));
1768 		}
1769 	}
1770 
1771 
1772 	for (i = 0; i < stream_status->plane_count; i++) {
1773 		if (stream_status->plane_states[i] == plane_state) {
1774 			dc_plane_state_release(stream_status->plane_states[i]);
1775 			break;
1776 		}
1777 	}
1778 
1779 	if (i == stream_status->plane_count) {
1780 		dm_error("Existing plane_state not found; failed to detach it!\n");
1781 		return false;
1782 	}
1783 
1784 	stream_status->plane_count--;
1785 
1786 	/* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */
1787 	for (; i < stream_status->plane_count; i++)
1788 		stream_status->plane_states[i] = stream_status->plane_states[i + 1];
1789 
1790 	stream_status->plane_states[stream_status->plane_count] = NULL;
1791 
1792 	return true;
1793 }
1794 
1795 /**
1796  * dc_rem_all_planes_for_stream - Remove planes attached to the target stream.
1797  *
1798  * @dc: Current dc state.
1799  * @stream: Target stream, which we want to remove the attached plans.
1800  * @context: New context.
1801  *
1802  * Return:
1803  * Return true if DC was able to remove all planes from the target
1804  * stream, otherwise, return false.
1805  */
1806 bool dc_rem_all_planes_for_stream(
1807 		const struct dc *dc,
1808 		struct dc_stream_state *stream,
1809 		struct dc_state *context)
1810 {
1811 	int i, old_plane_count;
1812 	struct dc_stream_status *stream_status = NULL;
1813 	struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 };
1814 
1815 	for (i = 0; i < context->stream_count; i++)
1816 			if (context->streams[i] == stream) {
1817 				stream_status = &context->stream_status[i];
1818 				break;
1819 			}
1820 
1821 	if (stream_status == NULL) {
1822 		dm_error("Existing stream %p not found!\n", stream);
1823 		return false;
1824 	}
1825 
1826 	old_plane_count = stream_status->plane_count;
1827 
1828 	for (i = 0; i < old_plane_count; i++)
1829 		del_planes[i] = stream_status->plane_states[i];
1830 
1831 	for (i = 0; i < old_plane_count; i++)
1832 		if (!dc_remove_plane_from_context(dc, stream, del_planes[i], context))
1833 			return false;
1834 
1835 	return true;
1836 }
1837 
1838 static bool add_all_planes_for_stream(
1839 		const struct dc *dc,
1840 		struct dc_stream_state *stream,
1841 		const struct dc_validation_set set[],
1842 		int set_count,
1843 		struct dc_state *context)
1844 {
1845 	int i, j;
1846 
1847 	for (i = 0; i < set_count; i++)
1848 		if (set[i].stream == stream)
1849 			break;
1850 
1851 	if (i == set_count) {
1852 		dm_error("Stream %p not found in set!\n", stream);
1853 		return false;
1854 	}
1855 
1856 	for (j = 0; j < set[i].plane_count; j++)
1857 		if (!dc_add_plane_to_context(dc, stream, set[i].plane_states[j], context))
1858 			return false;
1859 
1860 	return true;
1861 }
1862 
1863 bool dc_add_all_planes_for_stream(
1864 		const struct dc *dc,
1865 		struct dc_stream_state *stream,
1866 		struct dc_plane_state * const *plane_states,
1867 		int plane_count,
1868 		struct dc_state *context)
1869 {
1870 	struct dc_validation_set set;
1871 	int i;
1872 
1873 	set.stream = stream;
1874 	set.plane_count = plane_count;
1875 
1876 	for (i = 0; i < plane_count; i++)
1877 		set.plane_states[i] = plane_states[i];
1878 
1879 	return add_all_planes_for_stream(dc, stream, &set, 1, context);
1880 }
1881 
1882 bool dc_is_timing_changed(struct dc_stream_state *cur_stream,
1883 		       struct dc_stream_state *new_stream)
1884 {
1885 	if (cur_stream == NULL)
1886 		return true;
1887 
1888 	/* If output color space is changed, need to reprogram info frames */
1889 	if (cur_stream->output_color_space != new_stream->output_color_space)
1890 		return true;
1891 
1892 	return memcmp(
1893 		&cur_stream->timing,
1894 		&new_stream->timing,
1895 		sizeof(struct dc_crtc_timing)) != 0;
1896 }
1897 
1898 static bool are_stream_backends_same(
1899 	struct dc_stream_state *stream_a, struct dc_stream_state *stream_b)
1900 {
1901 	if (stream_a == stream_b)
1902 		return true;
1903 
1904 	if (stream_a == NULL || stream_b == NULL)
1905 		return false;
1906 
1907 	if (dc_is_timing_changed(stream_a, stream_b))
1908 		return false;
1909 
1910 	if (stream_a->signal != stream_b->signal)
1911 		return false;
1912 
1913 	if (stream_a->dpms_off != stream_b->dpms_off)
1914 		return false;
1915 
1916 	return true;
1917 }
1918 
1919 /*
1920  * dc_is_stream_unchanged() - Compare two stream states for equivalence.
1921  *
1922  * Checks if there a difference between the two states
1923  * that would require a mode change.
1924  *
1925  * Does not compare cursor position or attributes.
1926  */
1927 bool dc_is_stream_unchanged(
1928 	struct dc_stream_state *old_stream, struct dc_stream_state *stream)
1929 {
1930 
1931 	if (!are_stream_backends_same(old_stream, stream))
1932 		return false;
1933 
1934 	if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param)
1935 		return false;
1936 
1937 	/*compare audio info*/
1938 	if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0)
1939 		return false;
1940 
1941 	return true;
1942 }
1943 
1944 /*
1945  * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams.
1946  */
1947 bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream,
1948 				    struct dc_stream_state *stream)
1949 {
1950 	if (old_stream == stream)
1951 		return true;
1952 
1953 	if (old_stream == NULL || stream == NULL)
1954 		return false;
1955 
1956 	if (memcmp(&old_stream->src,
1957 			&stream->src,
1958 			sizeof(struct rect)) != 0)
1959 		return false;
1960 
1961 	if (memcmp(&old_stream->dst,
1962 			&stream->dst,
1963 			sizeof(struct rect)) != 0)
1964 		return false;
1965 
1966 	return true;
1967 }
1968 
1969 static void update_stream_engine_usage(
1970 		struct resource_context *res_ctx,
1971 		const struct resource_pool *pool,
1972 		struct stream_encoder *stream_enc,
1973 		bool acquired)
1974 {
1975 	int i;
1976 
1977 	for (i = 0; i < pool->stream_enc_count; i++) {
1978 		if (pool->stream_enc[i] == stream_enc)
1979 			res_ctx->is_stream_enc_acquired[i] = acquired;
1980 	}
1981 }
1982 
1983 static void update_hpo_dp_stream_engine_usage(
1984 		struct resource_context *res_ctx,
1985 		const struct resource_pool *pool,
1986 		struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
1987 		bool acquired)
1988 {
1989 	int i;
1990 
1991 	for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
1992 		if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc)
1993 			res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired;
1994 	}
1995 }
1996 
1997 static inline int find_acquired_hpo_dp_link_enc_for_link(
1998 		const struct resource_context *res_ctx,
1999 		const struct dc_link *link)
2000 {
2001 	int i;
2002 
2003 	for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++)
2004 		if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 &&
2005 				res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index)
2006 			return i;
2007 
2008 	return -1;
2009 }
2010 
2011 static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx,
2012 		const struct resource_pool *pool)
2013 {
2014 	int i;
2015 
2016 	for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++)
2017 		if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0)
2018 			break;
2019 
2020 	return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) &&
2021 			i < pool->hpo_dp_link_enc_count) ? i : -1;
2022 }
2023 
2024 static inline void acquire_hpo_dp_link_enc(
2025 		struct resource_context *res_ctx,
2026 		unsigned int link_index,
2027 		int enc_index)
2028 {
2029 	res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index;
2030 	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1;
2031 }
2032 
2033 static inline void retain_hpo_dp_link_enc(
2034 		struct resource_context *res_ctx,
2035 		int enc_index)
2036 {
2037 	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++;
2038 }
2039 
2040 static inline void release_hpo_dp_link_enc(
2041 		struct resource_context *res_ctx,
2042 		int enc_index)
2043 {
2044 	ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0);
2045 	res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--;
2046 }
2047 
2048 static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx,
2049 		const struct resource_pool *pool,
2050 		struct pipe_ctx *pipe_ctx,
2051 		struct dc_stream_state *stream)
2052 {
2053 	int enc_index;
2054 
2055 	enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
2056 
2057 	if (enc_index >= 0) {
2058 		retain_hpo_dp_link_enc(res_ctx, enc_index);
2059 	} else {
2060 		enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
2061 		if (enc_index >= 0)
2062 			acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index);
2063 	}
2064 
2065 	if (enc_index >= 0)
2066 		pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
2067 
2068 	return pipe_ctx->link_res.hpo_dp_link_enc != NULL;
2069 }
2070 
2071 static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx,
2072 		struct pipe_ctx *pipe_ctx,
2073 		struct dc_stream_state *stream)
2074 {
2075 	int enc_index;
2076 
2077 	enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
2078 
2079 	if (enc_index >= 0) {
2080 		release_hpo_dp_link_enc(res_ctx, enc_index);
2081 		pipe_ctx->link_res.hpo_dp_link_enc = NULL;
2082 	}
2083 }
2084 
2085 /* TODO: release audio object */
2086 void update_audio_usage(
2087 		struct resource_context *res_ctx,
2088 		const struct resource_pool *pool,
2089 		struct audio *audio,
2090 		bool acquired)
2091 {
2092 	int i;
2093 	for (i = 0; i < pool->audio_count; i++) {
2094 		if (pool->audios[i] == audio)
2095 			res_ctx->is_audio_acquired[i] = acquired;
2096 	}
2097 }
2098 
2099 static int acquire_first_free_pipe(
2100 		struct resource_context *res_ctx,
2101 		const struct resource_pool *pool,
2102 		struct dc_stream_state *stream)
2103 {
2104 	int i;
2105 
2106 	for (i = 0; i < pool->pipe_count; i++) {
2107 		if (!res_ctx->pipe_ctx[i].stream) {
2108 			struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
2109 
2110 			pipe_ctx->stream_res.tg = pool->timing_generators[i];
2111 			pipe_ctx->plane_res.mi = pool->mis[i];
2112 			pipe_ctx->plane_res.hubp = pool->hubps[i];
2113 			pipe_ctx->plane_res.ipp = pool->ipps[i];
2114 			pipe_ctx->plane_res.xfm = pool->transforms[i];
2115 			pipe_ctx->plane_res.dpp = pool->dpps[i];
2116 			pipe_ctx->stream_res.opp = pool->opps[i];
2117 			if (pool->dpps[i])
2118 				pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst;
2119 			pipe_ctx->pipe_idx = i;
2120 
2121 			if (i >= pool->timing_generator_count) {
2122 				int tg_inst = pool->timing_generator_count - 1;
2123 
2124 				pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
2125 				pipe_ctx->stream_res.opp = pool->opps[tg_inst];
2126 			}
2127 
2128 			pipe_ctx->stream = stream;
2129 			return i;
2130 		}
2131 	}
2132 	return -1;
2133 }
2134 
2135 static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link(
2136 		struct resource_context *res_ctx,
2137 		const struct resource_pool *pool,
2138 		struct dc_stream_state *stream)
2139 {
2140 	int i;
2141 
2142 	for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
2143 		if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] &&
2144 				pool->hpo_dp_stream_enc[i]) {
2145 
2146 			return pool->hpo_dp_stream_enc[i];
2147 		}
2148 	}
2149 
2150 	return NULL;
2151 }
2152 
2153 static struct audio *find_first_free_audio(
2154 		struct resource_context *res_ctx,
2155 		const struct resource_pool *pool,
2156 		enum engine_id id,
2157 		enum dce_version dc_version)
2158 {
2159 	int i, available_audio_count;
2160 
2161 	available_audio_count = pool->audio_count;
2162 
2163 	for (i = 0; i < available_audio_count; i++) {
2164 		if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) {
2165 			/*we have enough audio endpoint, find the matching inst*/
2166 			if (id != i)
2167 				continue;
2168 			return pool->audios[i];
2169 		}
2170 	}
2171 
2172 	/* use engine id to find free audio */
2173 	if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) {
2174 		return pool->audios[id];
2175 	}
2176 	/*not found the matching one, first come first serve*/
2177 	for (i = 0; i < available_audio_count; i++) {
2178 		if (res_ctx->is_audio_acquired[i] == false) {
2179 			return pool->audios[i];
2180 		}
2181 	}
2182 	return NULL;
2183 }
2184 
2185 /*
2186  * dc_add_stream_to_ctx() - Add a new dc_stream_state to a dc_state.
2187  */
2188 enum dc_status dc_add_stream_to_ctx(
2189 		struct dc *dc,
2190 		struct dc_state *new_ctx,
2191 		struct dc_stream_state *stream)
2192 {
2193 	enum dc_status res;
2194 	DC_LOGGER_INIT(dc->ctx->logger);
2195 
2196 	if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) {
2197 		DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream);
2198 		return DC_ERROR_UNEXPECTED;
2199 	}
2200 
2201 	new_ctx->streams[new_ctx->stream_count] = stream;
2202 	dc_stream_retain(stream);
2203 	new_ctx->stream_count++;
2204 
2205 	res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
2206 	if (res != DC_OK)
2207 		DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res);
2208 
2209 	return res;
2210 }
2211 
2212 /*
2213  * dc_remove_stream_from_ctx() - Remove a stream from a dc_state.
2214  */
2215 enum dc_status dc_remove_stream_from_ctx(
2216 			struct dc *dc,
2217 			struct dc_state *new_ctx,
2218 			struct dc_stream_state *stream)
2219 {
2220 	int i;
2221 	struct dc_context *dc_ctx = dc->ctx;
2222 	struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream);
2223 	struct pipe_ctx *odm_pipe;
2224 
2225 	if (!del_pipe) {
2226 		DC_ERROR("Pipe not found for stream %p !\n", stream);
2227 		return DC_ERROR_UNEXPECTED;
2228 	}
2229 
2230 	odm_pipe = del_pipe->next_odm_pipe;
2231 
2232 	/* Release primary pipe */
2233 	ASSERT(del_pipe->stream_res.stream_enc);
2234 	update_stream_engine_usage(
2235 			&new_ctx->res_ctx,
2236 				dc->res_pool,
2237 			del_pipe->stream_res.stream_enc,
2238 			false);
2239 
2240 	if (dc->link_srv->dp_is_128b_132b_signal(del_pipe)) {
2241 		update_hpo_dp_stream_engine_usage(
2242 			&new_ctx->res_ctx, dc->res_pool,
2243 			del_pipe->stream_res.hpo_dp_stream_enc,
2244 			false);
2245 		remove_hpo_dp_link_enc_from_ctx(&new_ctx->res_ctx, del_pipe, del_pipe->stream);
2246 	}
2247 
2248 	if (del_pipe->stream_res.audio)
2249 		update_audio_usage(
2250 			&new_ctx->res_ctx,
2251 			dc->res_pool,
2252 			del_pipe->stream_res.audio,
2253 			false);
2254 
2255 	resource_unreference_clock_source(&new_ctx->res_ctx,
2256 					  dc->res_pool,
2257 					  del_pipe->clock_source);
2258 
2259 	if (dc->res_pool->funcs->remove_stream_from_ctx)
2260 		dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream);
2261 
2262 	while (odm_pipe) {
2263 		struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe;
2264 
2265 		memset(odm_pipe, 0, sizeof(*odm_pipe));
2266 		odm_pipe = next_odm_pipe;
2267 	}
2268 	memset(del_pipe, 0, sizeof(*del_pipe));
2269 
2270 	for (i = 0; i < new_ctx->stream_count; i++)
2271 		if (new_ctx->streams[i] == stream)
2272 			break;
2273 
2274 	if (new_ctx->streams[i] != stream) {
2275 		DC_ERROR("Context doesn't have stream %p !\n", stream);
2276 		return DC_ERROR_UNEXPECTED;
2277 	}
2278 
2279 	dc_stream_release(new_ctx->streams[i]);
2280 	new_ctx->stream_count--;
2281 
2282 	/* Trim back arrays */
2283 	for (; i < new_ctx->stream_count; i++) {
2284 		new_ctx->streams[i] = new_ctx->streams[i + 1];
2285 		new_ctx->stream_status[i] = new_ctx->stream_status[i + 1];
2286 	}
2287 
2288 	new_ctx->streams[new_ctx->stream_count] = NULL;
2289 	memset(
2290 			&new_ctx->stream_status[new_ctx->stream_count],
2291 			0,
2292 			sizeof(new_ctx->stream_status[0]));
2293 
2294 	return DC_OK;
2295 }
2296 
2297 static struct dc_stream_state *find_pll_sharable_stream(
2298 		struct dc_stream_state *stream_needs_pll,
2299 		struct dc_state *context)
2300 {
2301 	int i;
2302 
2303 	for (i = 0; i < context->stream_count; i++) {
2304 		struct dc_stream_state *stream_has_pll = context->streams[i];
2305 
2306 		/* We are looking for non dp, non virtual stream */
2307 		if (resource_are_streams_timing_synchronizable(
2308 			stream_needs_pll, stream_has_pll)
2309 			&& !dc_is_dp_signal(stream_has_pll->signal)
2310 			&& stream_has_pll->link->connector_signal
2311 			!= SIGNAL_TYPE_VIRTUAL)
2312 			return stream_has_pll;
2313 
2314 	}
2315 
2316 	return NULL;
2317 }
2318 
2319 static int get_norm_pix_clk(const struct dc_crtc_timing *timing)
2320 {
2321 	uint32_t pix_clk = timing->pix_clk_100hz;
2322 	uint32_t normalized_pix_clk = pix_clk;
2323 
2324 	if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
2325 		pix_clk /= 2;
2326 	if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
2327 		switch (timing->display_color_depth) {
2328 		case COLOR_DEPTH_666:
2329 		case COLOR_DEPTH_888:
2330 			normalized_pix_clk = pix_clk;
2331 			break;
2332 		case COLOR_DEPTH_101010:
2333 			normalized_pix_clk = (pix_clk * 30) / 24;
2334 			break;
2335 		case COLOR_DEPTH_121212:
2336 			normalized_pix_clk = (pix_clk * 36) / 24;
2337 		break;
2338 		case COLOR_DEPTH_161616:
2339 			normalized_pix_clk = (pix_clk * 48) / 24;
2340 		break;
2341 		default:
2342 			ASSERT(0);
2343 		break;
2344 		}
2345 	}
2346 	return normalized_pix_clk;
2347 }
2348 
2349 static void calculate_phy_pix_clks(struct dc_stream_state *stream)
2350 {
2351 	/* update actual pixel clock on all streams */
2352 	if (dc_is_hdmi_signal(stream->signal))
2353 		stream->phy_pix_clk = get_norm_pix_clk(
2354 			&stream->timing) / 10;
2355 	else
2356 		stream->phy_pix_clk =
2357 			stream->timing.pix_clk_100hz / 10;
2358 
2359 	if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
2360 		stream->phy_pix_clk *= 2;
2361 }
2362 
2363 static int acquire_resource_from_hw_enabled_state(
2364 		struct resource_context *res_ctx,
2365 		const struct resource_pool *pool,
2366 		struct dc_stream_state *stream)
2367 {
2368 	struct dc_link *link = stream->link;
2369 	unsigned int i, inst, tg_inst = 0;
2370 	uint32_t numPipes = 1;
2371 	uint32_t id_src[4] = {0};
2372 
2373 	/* Check for enabled DIG to identify enabled display */
2374 	if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
2375 		return -1;
2376 
2377 	inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
2378 
2379 	if (inst == ENGINE_ID_UNKNOWN)
2380 		return -1;
2381 
2382 	for (i = 0; i < pool->stream_enc_count; i++) {
2383 		if (pool->stream_enc[i]->id == inst) {
2384 			tg_inst = pool->stream_enc[i]->funcs->dig_source_otg(
2385 				pool->stream_enc[i]);
2386 			break;
2387 		}
2388 	}
2389 
2390 	// tg_inst not found
2391 	if (i == pool->stream_enc_count)
2392 		return -1;
2393 
2394 	if (tg_inst >= pool->timing_generator_count)
2395 		return -1;
2396 
2397 	if (!res_ctx->pipe_ctx[tg_inst].stream) {
2398 		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];
2399 
2400 		pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
2401 		id_src[0] = tg_inst;
2402 
2403 		if (pipe_ctx->stream_res.tg->funcs->get_optc_source)
2404 			pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg,
2405 						&numPipes, &id_src[0], &id_src[1]);
2406 
2407 		if (id_src[0] == 0xf && id_src[1] == 0xf) {
2408 			id_src[0] = tg_inst;
2409 			numPipes = 1;
2410 		}
2411 
2412 		for (i = 0; i < numPipes; i++) {
2413 			//Check if src id invalid
2414 			if (id_src[i] == 0xf)
2415 				return -1;
2416 
2417 			pipe_ctx = &res_ctx->pipe_ctx[id_src[i]];
2418 
2419 			pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
2420 			pipe_ctx->plane_res.mi = pool->mis[id_src[i]];
2421 			pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]];
2422 			pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]];
2423 			pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]];
2424 			pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]];
2425 			pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
2426 
2427 			if (pool->dpps[id_src[i]]) {
2428 				pipe_ctx->plane_res.mpcc_inst = pool->dpps[id_src[i]]->inst;
2429 
2430 				if (pool->mpc->funcs->read_mpcc_state) {
2431 					struct mpcc_state s = {0};
2432 
2433 					pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);
2434 
2435 					if (s.dpp_id < MAX_MPCC)
2436 						pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id =
2437 								s.dpp_id;
2438 
2439 					if (s.bot_mpcc_id < MAX_MPCC)
2440 						pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
2441 								&pool->mpc->mpcc_array[s.bot_mpcc_id];
2442 
2443 					if (s.opp_id < MAX_OPP)
2444 						pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
2445 				}
2446 			}
2447 			pipe_ctx->pipe_idx = id_src[i];
2448 
2449 			if (id_src[i] >= pool->timing_generator_count) {
2450 				id_src[i] = pool->timing_generator_count - 1;
2451 
2452 				pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]];
2453 				pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
2454 			}
2455 
2456 			pipe_ctx->stream = stream;
2457 		}
2458 
2459 		if (numPipes == 2) {
2460 			stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1;
2461 			res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]];
2462 			res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL;
2463 			res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL;
2464 			res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]];
2465 		} else
2466 			stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled;
2467 
2468 		return id_src[0];
2469 	}
2470 
2471 	return -1;
2472 }
2473 
2474 static void mark_seamless_boot_stream(
2475 		const struct dc  *dc,
2476 		struct dc_stream_state *stream)
2477 {
2478 	struct dc_bios *dcb = dc->ctx->dc_bios;
2479 
2480 	if (dc->config.allow_seamless_boot_optimization &&
2481 			!dcb->funcs->is_accelerated_mode(dcb)) {
2482 		if (dc_validate_boot_timing(dc, stream->sink, &stream->timing))
2483 			stream->apply_seamless_boot_optimization = true;
2484 	}
2485 }
2486 
2487 enum dc_status resource_map_pool_resources(
2488 		const struct dc  *dc,
2489 		struct dc_state *context,
2490 		struct dc_stream_state *stream)
2491 {
2492 	const struct resource_pool *pool = dc->res_pool;
2493 	int i;
2494 	struct dc_context *dc_ctx = dc->ctx;
2495 	struct pipe_ctx *pipe_ctx = NULL;
2496 	int pipe_idx = -1;
2497 
2498 	calculate_phy_pix_clks(stream);
2499 
2500 	mark_seamless_boot_stream(dc, stream);
2501 
2502 	if (stream->apply_seamless_boot_optimization) {
2503 		pipe_idx = acquire_resource_from_hw_enabled_state(
2504 				&context->res_ctx,
2505 				pool,
2506 				stream);
2507 		if (pipe_idx < 0)
2508 			/* hw resource was assigned to other stream */
2509 			stream->apply_seamless_boot_optimization = false;
2510 	}
2511 
2512 	if (pipe_idx < 0)
2513 		/* acquire new resources */
2514 		pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream);
2515 
2516 	if (pipe_idx < 0)
2517 		pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
2518 
2519 	if (pipe_idx < 0 || context->res_ctx.pipe_ctx[pipe_idx].stream_res.tg == NULL)
2520 		return DC_NO_CONTROLLER_RESOURCE;
2521 
2522 	pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
2523 
2524 	pipe_ctx->stream_res.stream_enc =
2525 		dc->res_pool->funcs->find_first_free_match_stream_enc_for_link(
2526 			&context->res_ctx, pool, stream);
2527 
2528 	if (!pipe_ctx->stream_res.stream_enc)
2529 		return DC_NO_STREAM_ENC_RESOURCE;
2530 
2531 	update_stream_engine_usage(
2532 		&context->res_ctx, pool,
2533 		pipe_ctx->stream_res.stream_enc,
2534 		true);
2535 
2536 	/* Allocate DP HPO Stream Encoder based on signal, hw capabilities
2537 	 * and link settings
2538 	 */
2539 	if (dc_is_dp_signal(stream->signal)) {
2540 		if (!dc->link_srv->dp_decide_link_settings(stream, &pipe_ctx->link_config.dp_link_settings))
2541 			return DC_FAIL_DP_LINK_BANDWIDTH;
2542 		if (dc->link_srv->dp_get_encoding_format(
2543 				&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
2544 			pipe_ctx->stream_res.hpo_dp_stream_enc =
2545 					find_first_free_match_hpo_dp_stream_enc_for_link(
2546 							&context->res_ctx, pool, stream);
2547 
2548 			if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
2549 				return DC_NO_STREAM_ENC_RESOURCE;
2550 
2551 			update_hpo_dp_stream_engine_usage(
2552 					&context->res_ctx, pool,
2553 					pipe_ctx->stream_res.hpo_dp_stream_enc,
2554 					true);
2555 			if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream))
2556 				return DC_NO_LINK_ENC_RESOURCE;
2557 		}
2558 	}
2559 
2560 	/* TODO: Add check if ASIC support and EDID audio */
2561 	if (!stream->converter_disable_audio &&
2562 	    dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
2563 	    stream->audio_info.mode_count && stream->audio_info.flags.all) {
2564 		pipe_ctx->stream_res.audio = find_first_free_audio(
2565 		&context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id, dc_ctx->dce_version);
2566 
2567 		/*
2568 		 * Audio assigned in order first come first get.
2569 		 * There are asics which has number of audio
2570 		 * resources less then number of pipes
2571 		 */
2572 		if (pipe_ctx->stream_res.audio)
2573 			update_audio_usage(&context->res_ctx, pool,
2574 					   pipe_ctx->stream_res.audio, true);
2575 	}
2576 
2577 	/* Add ABM to the resource if on EDP */
2578 	if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) {
2579 		if (pool->abm)
2580 			pipe_ctx->stream_res.abm = pool->abm;
2581 		else
2582 			pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst];
2583 	}
2584 
2585 	for (i = 0; i < context->stream_count; i++)
2586 		if (context->streams[i] == stream) {
2587 			context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst;
2588 			context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->stream_enc_inst;
2589 			context->stream_status[i].audio_inst =
2590 				pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1;
2591 
2592 			return DC_OK;
2593 		}
2594 
2595 	DC_ERROR("Stream %p not found in new ctx!\n", stream);
2596 	return DC_ERROR_UNEXPECTED;
2597 }
2598 
2599 /**
2600  * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state
2601  *
2602  * @dc: copy out of dc->current_state
2603  * @dst_ctx: copy into this
2604  *
2605  * This function makes a shallow copy of the current DC state and increments
2606  * refcounts on existing streams and planes.
2607  */
2608 void dc_resource_state_copy_construct_current(
2609 		const struct dc *dc,
2610 		struct dc_state *dst_ctx)
2611 {
2612 	dc_resource_state_copy_construct(dc->current_state, dst_ctx);
2613 }
2614 
2615 
2616 void dc_resource_state_construct(
2617 		const struct dc *dc,
2618 		struct dc_state *dst_ctx)
2619 {
2620 	dst_ctx->clk_mgr = dc->clk_mgr;
2621 
2622 	/* Initialise DIG link encoder resource tracking variables. */
2623 	link_enc_cfg_init(dc, dst_ctx);
2624 }
2625 
2626 
2627 bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
2628 {
2629 	if (dc->res_pool == NULL)
2630 		return false;
2631 
2632 	return dc->res_pool->res_cap->num_dsc > 0;
2633 }
2634 
2635 static bool planes_changed_for_existing_stream(struct dc_state *context,
2636 					       struct dc_stream_state *stream,
2637 					       const struct dc_validation_set set[],
2638 					       int set_count)
2639 {
2640 	int i, j;
2641 	struct dc_stream_status *stream_status = NULL;
2642 
2643 	for (i = 0; i < context->stream_count; i++) {
2644 		if (context->streams[i] == stream) {
2645 			stream_status = &context->stream_status[i];
2646 			break;
2647 		}
2648 	}
2649 
2650 	if (!stream_status)
2651 		ASSERT(0);
2652 
2653 	for (i = 0; i < set_count; i++)
2654 		if (set[i].stream == stream)
2655 			break;
2656 
2657 	if (i == set_count)
2658 		ASSERT(0);
2659 
2660 	if (set[i].plane_count != stream_status->plane_count)
2661 		return true;
2662 
2663 	for (j = 0; j < set[i].plane_count; j++)
2664 		if (set[i].plane_states[j] != stream_status->plane_states[j])
2665 			return true;
2666 
2667 	return false;
2668 }
2669 
2670 /**
2671  * dc_validate_with_context - Validate and update the potential new stream in the context object
2672  *
2673  * @dc: Used to get the current state status
2674  * @set: An array of dc_validation_set with all the current streams reference
2675  * @set_count: Total of streams
2676  * @context: New context
2677  * @fast_validate: Enable or disable fast validation
2678  *
2679  * This function updates the potential new stream in the context object. It
2680  * creates multiple lists for the add, remove, and unchanged streams. In
2681  * particular, if the unchanged streams have a plane that changed, it is
2682  * necessary to remove all planes from the unchanged streams. In summary, this
2683  * function is responsible for validating the new context.
2684  *
2685  * Return:
2686  * In case of success, return DC_OK (1), otherwise, return a DC error.
2687  */
2688 enum dc_status dc_validate_with_context(struct dc *dc,
2689 					const struct dc_validation_set set[],
2690 					int set_count,
2691 					struct dc_state *context,
2692 					bool fast_validate)
2693 {
2694 	struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 };
2695 	struct dc_stream_state *del_streams[MAX_PIPES] = { 0 };
2696 	struct dc_stream_state *add_streams[MAX_PIPES] = { 0 };
2697 	int old_stream_count = context->stream_count;
2698 	enum dc_status res = DC_ERROR_UNEXPECTED;
2699 	int unchanged_streams_count = 0;
2700 	int del_streams_count = 0;
2701 	int add_streams_count = 0;
2702 	bool found = false;
2703 	int i, j, k;
2704 
2705 	DC_LOGGER_INIT(dc->ctx->logger);
2706 
2707 	/* First build a list of streams to be remove from current context */
2708 	for (i = 0; i < old_stream_count; i++) {
2709 		struct dc_stream_state *stream = context->streams[i];
2710 
2711 		for (j = 0; j < set_count; j++) {
2712 			if (stream == set[j].stream) {
2713 				found = true;
2714 				break;
2715 			}
2716 		}
2717 
2718 		if (!found)
2719 			del_streams[del_streams_count++] = stream;
2720 
2721 		found = false;
2722 	}
2723 
2724 	/* Second, build a list of new streams */
2725 	for (i = 0; i < set_count; i++) {
2726 		struct dc_stream_state *stream = set[i].stream;
2727 
2728 		for (j = 0; j < old_stream_count; j++) {
2729 			if (stream == context->streams[j]) {
2730 				found = true;
2731 				break;
2732 			}
2733 		}
2734 
2735 		if (!found)
2736 			add_streams[add_streams_count++] = stream;
2737 
2738 		found = false;
2739 	}
2740 
2741 	/* Build a list of unchanged streams which is necessary for handling
2742 	 * planes change such as added, removed, and updated.
2743 	 */
2744 	for (i = 0; i < set_count; i++) {
2745 		/* Check if stream is part of the delete list */
2746 		for (j = 0; j < del_streams_count; j++) {
2747 			if (set[i].stream == del_streams[j]) {
2748 				found = true;
2749 				break;
2750 			}
2751 		}
2752 
2753 		if (!found) {
2754 			/* Check if stream is part of the add list */
2755 			for (j = 0; j < add_streams_count; j++) {
2756 				if (set[i].stream == add_streams[j]) {
2757 					found = true;
2758 					break;
2759 				}
2760 			}
2761 		}
2762 
2763 		if (!found)
2764 			unchanged_streams[unchanged_streams_count++] = set[i].stream;
2765 
2766 		found = false;
2767 	}
2768 
2769 	/* Remove all planes for unchanged streams if planes changed */
2770 	for (i = 0; i < unchanged_streams_count; i++) {
2771 		if (planes_changed_for_existing_stream(context,
2772 						       unchanged_streams[i],
2773 						       set,
2774 						       set_count)) {
2775 			if (!dc_rem_all_planes_for_stream(dc,
2776 							  unchanged_streams[i],
2777 							  context)) {
2778 				res = DC_FAIL_DETACH_SURFACES;
2779 				goto fail;
2780 			}
2781 		}
2782 	}
2783 
2784 	/* Remove all planes for removed streams and then remove the streams */
2785 	for (i = 0; i < del_streams_count; i++) {
2786 		/* Need to cpy the dwb data from the old stream in order to efc to work */
2787 		if (del_streams[i]->num_wb_info > 0) {
2788 			for (j = 0; j < add_streams_count; j++) {
2789 				if (del_streams[i]->sink == add_streams[j]->sink) {
2790 					add_streams[j]->num_wb_info = del_streams[i]->num_wb_info;
2791 					for (k = 0; k < del_streams[i]->num_wb_info; k++)
2792 						add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k];
2793 				}
2794 			}
2795 		}
2796 
2797 		if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) {
2798 			res = DC_FAIL_DETACH_SURFACES;
2799 			goto fail;
2800 		}
2801 
2802 		res = dc_remove_stream_from_ctx(dc, context, del_streams[i]);
2803 		if (res != DC_OK)
2804 			goto fail;
2805 	}
2806 
2807 	/* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx
2808 	 * matches. This may change in the future if seamless_boot_stream can be
2809 	 * multiple.
2810 	 */
2811 	for (i = 0; i < add_streams_count; i++) {
2812 		mark_seamless_boot_stream(dc, add_streams[i]);
2813 		if (add_streams[i]->apply_seamless_boot_optimization && i != 0) {
2814 			struct dc_stream_state *temp = add_streams[0];
2815 
2816 			add_streams[0] = add_streams[i];
2817 			add_streams[i] = temp;
2818 			break;
2819 		}
2820 	}
2821 
2822 	/* Add new streams and then add all planes for the new stream */
2823 	for (i = 0; i < add_streams_count; i++) {
2824 		calculate_phy_pix_clks(add_streams[i]);
2825 		res = dc_add_stream_to_ctx(dc, context, add_streams[i]);
2826 		if (res != DC_OK)
2827 			goto fail;
2828 
2829 		if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) {
2830 			res = DC_FAIL_ATTACH_SURFACES;
2831 			goto fail;
2832 		}
2833 	}
2834 
2835 	/* Add all planes for unchanged streams if planes changed */
2836 	for (i = 0; i < unchanged_streams_count; i++) {
2837 		if (planes_changed_for_existing_stream(context,
2838 						       unchanged_streams[i],
2839 						       set,
2840 						       set_count)) {
2841 			if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) {
2842 				res = DC_FAIL_ATTACH_SURFACES;
2843 				goto fail;
2844 			}
2845 		}
2846 	}
2847 
2848 	res = dc_validate_global_state(dc, context, fast_validate);
2849 
2850 fail:
2851 	if (res != DC_OK)
2852 		DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n",
2853 			       __func__,
2854 			       res);
2855 
2856 	return res;
2857 }
2858 
2859 /**
2860  * dc_validate_global_state() - Determine if hardware can support a given state
2861  *
2862  * @dc: dc struct for this driver
2863  * @new_ctx: state to be validated
2864  * @fast_validate: set to true if only yes/no to support matters
2865  *
2866  * Checks hardware resource availability and bandwidth requirement.
2867  *
2868  * Return:
2869  * DC_OK if the result can be programmed. Otherwise, an error code.
2870  */
2871 enum dc_status dc_validate_global_state(
2872 		struct dc *dc,
2873 		struct dc_state *new_ctx,
2874 		bool fast_validate)
2875 {
2876 	enum dc_status result = DC_ERROR_UNEXPECTED;
2877 	int i, j;
2878 
2879 	if (!new_ctx)
2880 		return DC_ERROR_UNEXPECTED;
2881 
2882 	if (dc->res_pool->funcs->validate_global) {
2883 		result = dc->res_pool->funcs->validate_global(dc, new_ctx);
2884 		if (result != DC_OK)
2885 			return result;
2886 	}
2887 
2888 	for (i = 0; i < new_ctx->stream_count; i++) {
2889 		struct dc_stream_state *stream = new_ctx->streams[i];
2890 
2891 		for (j = 0; j < dc->res_pool->pipe_count; j++) {
2892 			struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j];
2893 
2894 			if (pipe_ctx->stream != stream)
2895 				continue;
2896 
2897 			if (dc->res_pool->funcs->patch_unknown_plane_state &&
2898 					pipe_ctx->plane_state &&
2899 					pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) {
2900 				result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state);
2901 				if (result != DC_OK)
2902 					return result;
2903 			}
2904 
2905 			/* Switch to dp clock source only if there is
2906 			 * no non dp stream that shares the same timing
2907 			 * with the dp stream.
2908 			 */
2909 			if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
2910 				!find_pll_sharable_stream(stream, new_ctx)) {
2911 
2912 				resource_unreference_clock_source(
2913 						&new_ctx->res_ctx,
2914 						dc->res_pool,
2915 						pipe_ctx->clock_source);
2916 
2917 				pipe_ctx->clock_source = dc->res_pool->dp_clock_source;
2918 				resource_reference_clock_source(
2919 						&new_ctx->res_ctx,
2920 						dc->res_pool,
2921 						 pipe_ctx->clock_source);
2922 			}
2923 		}
2924 	}
2925 
2926 	result = resource_build_scaling_params_for_context(dc, new_ctx);
2927 
2928 	if (result == DC_OK)
2929 		if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, fast_validate))
2930 			result = DC_FAIL_BANDWIDTH_VALIDATE;
2931 
2932 	/*
2933 	 * Only update link encoder to stream assignment after bandwidth validation passed.
2934 	 * TODO: Split out assignment and validation.
2935 	 */
2936 	if (result == DC_OK && dc->res_pool->funcs->link_encs_assign && fast_validate == false)
2937 		dc->res_pool->funcs->link_encs_assign(
2938 			dc, new_ctx, new_ctx->streams, new_ctx->stream_count);
2939 
2940 	return result;
2941 }
2942 
2943 static void patch_gamut_packet_checksum(
2944 		struct dc_info_packet *gamut_packet)
2945 {
2946 	/* For gamut we recalc checksum */
2947 	if (gamut_packet->valid) {
2948 		uint8_t chk_sum = 0;
2949 		uint8_t *ptr;
2950 		uint8_t i;
2951 
2952 		/*start of the Gamut data. */
2953 		ptr = &gamut_packet->sb[3];
2954 
2955 		for (i = 0; i <= gamut_packet->sb[1]; i++)
2956 			chk_sum += ptr[i];
2957 
2958 		gamut_packet->sb[2] = (uint8_t) (0x100 - chk_sum);
2959 	}
2960 }
2961 
2962 static void set_avi_info_frame(
2963 		struct dc_info_packet *info_packet,
2964 		struct pipe_ctx *pipe_ctx)
2965 {
2966 	struct dc_stream_state *stream = pipe_ctx->stream;
2967 	enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
2968 	uint32_t pixel_encoding = 0;
2969 	enum scanning_type scan_type = SCANNING_TYPE_NODATA;
2970 	enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA;
2971 	bool itc = false;
2972 	uint8_t itc_value = 0;
2973 	uint8_t cn0_cn1 = 0;
2974 	unsigned int cn0_cn1_value = 0;
2975 	uint8_t *check_sum = NULL;
2976 	uint8_t byte_index = 0;
2977 	union hdmi_info_packet hdmi_info;
2978 	union display_content_support support = {0};
2979 	unsigned int vic = pipe_ctx->stream->timing.vic;
2980 	unsigned int rid = pipe_ctx->stream->timing.rid;
2981 	unsigned int fr_ind = pipe_ctx->stream->timing.fr_index;
2982 	enum dc_timing_3d_format format;
2983 
2984 	memset(&hdmi_info, 0, sizeof(union hdmi_info_packet));
2985 
2986 	color_space = pipe_ctx->stream->output_color_space;
2987 	if (color_space == COLOR_SPACE_UNKNOWN)
2988 		color_space = (stream->timing.pixel_encoding == PIXEL_ENCODING_RGB) ?
2989 			COLOR_SPACE_SRGB:COLOR_SPACE_YCBCR709;
2990 
2991 	/* Initialize header */
2992 	hdmi_info.bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI;
2993 	/* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall
2994 	* not be used in HDMI 2.0 (Section 10.1) */
2995 	hdmi_info.bits.header.version = 2;
2996 	hdmi_info.bits.header.length = HDMI_AVI_INFOFRAME_SIZE;
2997 
2998 	/*
2999 	 * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built
3000 	 * according to HDMI 2.0 spec (Section 10.1)
3001 	 */
3002 
3003 	switch (stream->timing.pixel_encoding) {
3004 	case PIXEL_ENCODING_YCBCR422:
3005 		pixel_encoding = 1;
3006 		break;
3007 
3008 	case PIXEL_ENCODING_YCBCR444:
3009 		pixel_encoding = 2;
3010 		break;
3011 	case PIXEL_ENCODING_YCBCR420:
3012 		pixel_encoding = 3;
3013 		break;
3014 
3015 	case PIXEL_ENCODING_RGB:
3016 	default:
3017 		pixel_encoding = 0;
3018 	}
3019 
3020 	/* Y0_Y1_Y2 : The pixel encoding */
3021 	/* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */
3022 	hdmi_info.bits.Y0_Y1_Y2 = pixel_encoding;
3023 
3024 	/* A0 = 1 Active Format Information valid */
3025 	hdmi_info.bits.A0 = ACTIVE_FORMAT_VALID;
3026 
3027 	/* B0, B1 = 3; Bar info data is valid */
3028 	hdmi_info.bits.B0_B1 = BAR_INFO_BOTH_VALID;
3029 
3030 	hdmi_info.bits.SC0_SC1 = PICTURE_SCALING_UNIFORM;
3031 
3032 	/* S0, S1 : Underscan / Overscan */
3033 	/* TODO: un-hardcode scan type */
3034 	scan_type = SCANNING_TYPE_UNDERSCAN;
3035 	hdmi_info.bits.S0_S1 = scan_type;
3036 
3037 	/* C0, C1 : Colorimetry */
3038 	switch (color_space) {
3039 	case COLOR_SPACE_YCBCR709:
3040 	case COLOR_SPACE_YCBCR709_LIMITED:
3041 		hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
3042 		break;
3043 	case COLOR_SPACE_YCBCR601:
3044 	case COLOR_SPACE_YCBCR601_LIMITED:
3045 		hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601;
3046 		break;
3047 	case COLOR_SPACE_2020_RGB_FULLRANGE:
3048 	case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
3049 	case COLOR_SPACE_2020_YCBCR:
3050 		hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR;
3051 		hdmi_info.bits.C0_C1   = COLORIMETRY_EXTENDED;
3052 		break;
3053 	case COLOR_SPACE_ADOBERGB:
3054 		hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB;
3055 		hdmi_info.bits.C0_C1   = COLORIMETRY_EXTENDED;
3056 		break;
3057 	case COLOR_SPACE_SRGB:
3058 	default:
3059 		hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA;
3060 		break;
3061 	}
3062 
3063 	if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR &&
3064 			stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) {
3065 		hdmi_info.bits.EC0_EC2 = 0;
3066 		hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
3067 	}
3068 
3069 	/* TODO: un-hardcode aspect ratio */
3070 	aspect = stream->timing.aspect_ratio;
3071 
3072 	switch (aspect) {
3073 	case ASPECT_RATIO_4_3:
3074 	case ASPECT_RATIO_16_9:
3075 		hdmi_info.bits.M0_M1 = aspect;
3076 		break;
3077 
3078 	case ASPECT_RATIO_NO_DATA:
3079 	case ASPECT_RATIO_64_27:
3080 	case ASPECT_RATIO_256_135:
3081 	default:
3082 		hdmi_info.bits.M0_M1 = 0;
3083 	}
3084 
3085 	/* Active Format Aspect ratio - same as Picture Aspect Ratio. */
3086 	hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE;
3087 
3088 	/* TODO: un-hardcode cn0_cn1 and itc */
3089 
3090 	cn0_cn1 = 0;
3091 	cn0_cn1_value = 0;
3092 
3093 	itc = true;
3094 	itc_value = 1;
3095 
3096 	support = stream->content_support;
3097 
3098 	if (itc) {
3099 		if (!support.bits.valid_content_type) {
3100 			cn0_cn1_value = 0;
3101 		} else {
3102 			if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GRAPHICS) {
3103 				if (support.bits.graphics_content == 1) {
3104 					cn0_cn1_value = 0;
3105 				}
3106 			} else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_PHOTO) {
3107 				if (support.bits.photo_content == 1) {
3108 					cn0_cn1_value = 1;
3109 				} else {
3110 					cn0_cn1_value = 0;
3111 					itc_value = 0;
3112 				}
3113 			} else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_CINEMA) {
3114 				if (support.bits.cinema_content == 1) {
3115 					cn0_cn1_value = 2;
3116 				} else {
3117 					cn0_cn1_value = 0;
3118 					itc_value = 0;
3119 				}
3120 			} else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GAME) {
3121 				if (support.bits.game_content == 1) {
3122 					cn0_cn1_value = 3;
3123 				} else {
3124 					cn0_cn1_value = 0;
3125 					itc_value = 0;
3126 				}
3127 			}
3128 		}
3129 		hdmi_info.bits.CN0_CN1 = cn0_cn1_value;
3130 		hdmi_info.bits.ITC = itc_value;
3131 	}
3132 
3133 	if (stream->qs_bit == 1) {
3134 		if (color_space == COLOR_SPACE_SRGB ||
3135 			color_space == COLOR_SPACE_2020_RGB_FULLRANGE)
3136 			hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_FULL_RANGE;
3137 		else if (color_space == COLOR_SPACE_SRGB_LIMITED ||
3138 					color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)
3139 			hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_LIMITED_RANGE;
3140 		else
3141 			hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_DEFAULT_RANGE;
3142 	} else
3143 		hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_DEFAULT_RANGE;
3144 
3145 	/* TODO : We should handle YCC quantization */
3146 	/* but we do not have matrix calculation */
3147 	hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
3148 
3149 	///VIC
3150 	if (pipe_ctx->stream->timing.hdmi_vic != 0)
3151 		vic = 0;
3152 	format = stream->timing.timing_3d_format;
3153 	/*todo, add 3DStereo support*/
3154 	if (format != TIMING_3D_FORMAT_NONE) {
3155 		// Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
3156 		switch (pipe_ctx->stream->timing.hdmi_vic) {
3157 		case 1:
3158 			vic = 95;
3159 			break;
3160 		case 2:
3161 			vic = 94;
3162 			break;
3163 		case 3:
3164 			vic = 93;
3165 			break;
3166 		case 4:
3167 			vic = 98;
3168 			break;
3169 		default:
3170 			break;
3171 		}
3172 	}
3173 	/* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/
3174 	hdmi_info.bits.VIC0_VIC7 = vic;
3175 	if (vic >= 128)
3176 		hdmi_info.bits.header.version = 3;
3177 	/* If (C1, C0)=(1, 1) and (EC2, EC1, EC0)=(1, 1, 1),
3178 	 * the Source shall use 20 AVI InfoFrame Version 4
3179 	 */
3180 	if (hdmi_info.bits.C0_C1 == COLORIMETRY_EXTENDED &&
3181 			hdmi_info.bits.EC0_EC2 == COLORIMETRYEX_RESERVED) {
3182 		hdmi_info.bits.header.version = 4;
3183 		hdmi_info.bits.header.length = 14;
3184 	}
3185 
3186 	if (rid != 0 && fr_ind != 0) {
3187 		hdmi_info.bits.header.version = 5;
3188 		hdmi_info.bits.header.length = 15;
3189 
3190 		hdmi_info.bits.FR0_FR3 = fr_ind & 0xF;
3191 		hdmi_info.bits.FR4 = (fr_ind >> 4) & 0x1;
3192 		hdmi_info.bits.RID0_RID5 = rid;
3193 	}
3194 
3195 	/* pixel repetition
3196 	 * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel
3197 	 * repetition start from 1 */
3198 	hdmi_info.bits.PR0_PR3 = 0;
3199 
3200 	/* Bar Info
3201 	 * barTop:    Line Number of End of Top Bar.
3202 	 * barBottom: Line Number of Start of Bottom Bar.
3203 	 * barLeft:   Pixel Number of End of Left Bar.
3204 	 * barRight:  Pixel Number of Start of Right Bar. */
3205 	hdmi_info.bits.bar_top = stream->timing.v_border_top;
3206 	hdmi_info.bits.bar_bottom = (stream->timing.v_total
3207 			- stream->timing.v_border_bottom + 1);
3208 	hdmi_info.bits.bar_left  = stream->timing.h_border_left;
3209 	hdmi_info.bits.bar_right = (stream->timing.h_total
3210 			- stream->timing.h_border_right + 1);
3211 
3212     /* Additional Colorimetry Extension
3213      * Used in conduction with C0-C1 and EC0-EC2
3214      * 0 = DCI-P3 RGB (D65)
3215      * 1 = DCI-P3 RGB (theater)
3216      */
3217 	hdmi_info.bits.ACE0_ACE3 = 0;
3218 
3219 	/* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */
3220 	check_sum = &hdmi_info.packet_raw_data.sb[0];
3221 
3222 	*check_sum = HDMI_INFOFRAME_TYPE_AVI + hdmi_info.bits.header.length + hdmi_info.bits.header.version;
3223 
3224 	for (byte_index = 1; byte_index <= hdmi_info.bits.header.length; byte_index++)
3225 		*check_sum += hdmi_info.packet_raw_data.sb[byte_index];
3226 
3227 	/* one byte complement */
3228 	*check_sum = (uint8_t) (0x100 - *check_sum);
3229 
3230 	/* Store in hw_path_mode */
3231 	info_packet->hb0 = hdmi_info.packet_raw_data.hb0;
3232 	info_packet->hb1 = hdmi_info.packet_raw_data.hb1;
3233 	info_packet->hb2 = hdmi_info.packet_raw_data.hb2;
3234 
3235 	for (byte_index = 0; byte_index < sizeof(hdmi_info.packet_raw_data.sb); byte_index++)
3236 		info_packet->sb[byte_index] = hdmi_info.packet_raw_data.sb[byte_index];
3237 
3238 	info_packet->valid = true;
3239 }
3240 
3241 static void set_vendor_info_packet(
3242 		struct dc_info_packet *info_packet,
3243 		struct dc_stream_state *stream)
3244 {
3245 	/* SPD info packet for FreeSync */
3246 
3247 	/* Check if Freesync is supported. Return if false. If true,
3248 	 * set the corresponding bit in the info packet
3249 	 */
3250 	if (!stream->vsp_infopacket.valid)
3251 		return;
3252 
3253 	*info_packet = stream->vsp_infopacket;
3254 }
3255 
3256 static void set_spd_info_packet(
3257 		struct dc_info_packet *info_packet,
3258 		struct dc_stream_state *stream)
3259 {
3260 	/* SPD info packet for FreeSync */
3261 
3262 	/* Check if Freesync is supported. Return if false. If true,
3263 	 * set the corresponding bit in the info packet
3264 	 */
3265 	if (!stream->vrr_infopacket.valid)
3266 		return;
3267 
3268 	*info_packet = stream->vrr_infopacket;
3269 }
3270 
3271 static void set_hdr_static_info_packet(
3272 		struct dc_info_packet *info_packet,
3273 		struct dc_stream_state *stream)
3274 {
3275 	/* HDR Static Metadata info packet for HDR10 */
3276 
3277 	if (!stream->hdr_static_metadata.valid ||
3278 			stream->use_dynamic_meta)
3279 		return;
3280 
3281 	*info_packet = stream->hdr_static_metadata;
3282 }
3283 
3284 static void set_vsc_info_packet(
3285 		struct dc_info_packet *info_packet,
3286 		struct dc_stream_state *stream)
3287 {
3288 	if (!stream->vsc_infopacket.valid)
3289 		return;
3290 
3291 	*info_packet = stream->vsc_infopacket;
3292 }
3293 static void set_hfvs_info_packet(
3294 		struct dc_info_packet *info_packet,
3295 		struct dc_stream_state *stream)
3296 {
3297 	if (!stream->hfvsif_infopacket.valid)
3298 		return;
3299 
3300 	*info_packet = stream->hfvsif_infopacket;
3301 }
3302 
3303 static void adaptive_sync_override_dp_info_packets_sdp_line_num(
3304 		const struct dc_crtc_timing *timing,
3305 		struct enc_sdp_line_num *sdp_line_num,
3306 		struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
3307 {
3308 	uint32_t asic_blank_start = 0;
3309 	uint32_t asic_blank_end   = 0;
3310 	uint32_t v_update = 0;
3311 
3312 	const struct dc_crtc_timing *tg = timing;
3313 
3314 	/* blank_start = frame end - front porch */
3315 	asic_blank_start = tg->v_total - tg->v_front_porch;
3316 
3317 	/* blank_end = blank_start - active */
3318 	asic_blank_end = (asic_blank_start - tg->v_border_bottom -
3319 						tg->v_addressable - tg->v_border_top);
3320 
3321 	if (pipe_dlg_param->vstartup_start > asic_blank_end) {
3322 		v_update = (tg->v_total - (pipe_dlg_param->vstartup_start - asic_blank_end));
3323 		sdp_line_num->adaptive_sync_line_num_valid = true;
3324 		sdp_line_num->adaptive_sync_line_num = (tg->v_total - v_update - 1);
3325 	} else {
3326 		sdp_line_num->adaptive_sync_line_num_valid = false;
3327 		sdp_line_num->adaptive_sync_line_num = 0;
3328 	}
3329 }
3330 
3331 static void set_adaptive_sync_info_packet(
3332 		struct dc_info_packet *info_packet,
3333 		const struct dc_stream_state *stream,
3334 		struct encoder_info_frame *info_frame,
3335 		struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
3336 {
3337 	if (!stream->adaptive_sync_infopacket.valid)
3338 		return;
3339 
3340 	adaptive_sync_override_dp_info_packets_sdp_line_num(
3341 			&stream->timing,
3342 			&info_frame->sdp_line_num,
3343 			pipe_dlg_param);
3344 
3345 	*info_packet = stream->adaptive_sync_infopacket;
3346 }
3347 
3348 static void set_vtem_info_packet(
3349 		struct dc_info_packet *info_packet,
3350 		struct dc_stream_state *stream)
3351 {
3352 	if (!stream->vtem_infopacket.valid)
3353 		return;
3354 
3355 	*info_packet = stream->vtem_infopacket;
3356 }
3357 
3358 void dc_resource_state_destruct(struct dc_state *context)
3359 {
3360 	int i, j;
3361 
3362 	for (i = 0; i < context->stream_count; i++) {
3363 		for (j = 0; j < context->stream_status[i].plane_count; j++)
3364 			dc_plane_state_release(
3365 				context->stream_status[i].plane_states[j]);
3366 
3367 		context->stream_status[i].plane_count = 0;
3368 		dc_stream_release(context->streams[i]);
3369 		context->streams[i] = NULL;
3370 	}
3371 	context->stream_count = 0;
3372 }
3373 
3374 void dc_resource_state_copy_construct(
3375 		const struct dc_state *src_ctx,
3376 		struct dc_state *dst_ctx)
3377 {
3378 	int i, j;
3379 	struct kref refcount = dst_ctx->refcount;
3380 
3381 	*dst_ctx = *src_ctx;
3382 
3383 	for (i = 0; i < MAX_PIPES; i++) {
3384 		struct pipe_ctx *cur_pipe = &dst_ctx->res_ctx.pipe_ctx[i];
3385 
3386 		if (cur_pipe->top_pipe)
3387 			cur_pipe->top_pipe =  &dst_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx];
3388 
3389 		if (cur_pipe->bottom_pipe)
3390 			cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
3391 
3392 		if (cur_pipe->next_odm_pipe)
3393 			cur_pipe->next_odm_pipe =  &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];
3394 
3395 		if (cur_pipe->prev_odm_pipe)
3396 			cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
3397 	}
3398 
3399 	for (i = 0; i < dst_ctx->stream_count; i++) {
3400 		dc_stream_retain(dst_ctx->streams[i]);
3401 		for (j = 0; j < dst_ctx->stream_status[i].plane_count; j++)
3402 			dc_plane_state_retain(
3403 				dst_ctx->stream_status[i].plane_states[j]);
3404 	}
3405 
3406 	/* context refcount should not be overridden */
3407 	dst_ctx->refcount = refcount;
3408 
3409 }
3410 
3411 struct clock_source *dc_resource_find_first_free_pll(
3412 		struct resource_context *res_ctx,
3413 		const struct resource_pool *pool)
3414 {
3415 	int i;
3416 
3417 	for (i = 0; i < pool->clk_src_count; ++i) {
3418 		if (res_ctx->clock_source_ref_count[i] == 0)
3419 			return pool->clock_sources[i];
3420 	}
3421 
3422 	return NULL;
3423 }
3424 
3425 void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
3426 {
3427 	enum signal_type signal = SIGNAL_TYPE_NONE;
3428 	struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame;
3429 
3430 	/* default all packets to invalid */
3431 	info->avi.valid = false;
3432 	info->gamut.valid = false;
3433 	info->vendor.valid = false;
3434 	info->spd.valid = false;
3435 	info->hdrsmd.valid = false;
3436 	info->vsc.valid = false;
3437 	info->hfvsif.valid = false;
3438 	info->vtem.valid = false;
3439 	info->adaptive_sync.valid = false;
3440 	signal = pipe_ctx->stream->signal;
3441 
3442 	/* HDMi and DP have different info packets*/
3443 	if (dc_is_hdmi_signal(signal)) {
3444 		set_avi_info_frame(&info->avi, pipe_ctx);
3445 
3446 		set_vendor_info_packet(&info->vendor, pipe_ctx->stream);
3447 		set_hfvs_info_packet(&info->hfvsif, pipe_ctx->stream);
3448 		set_vtem_info_packet(&info->vtem, pipe_ctx->stream);
3449 
3450 		set_spd_info_packet(&info->spd, pipe_ctx->stream);
3451 
3452 		set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
3453 
3454 	} else if (dc_is_dp_signal(signal)) {
3455 		set_vsc_info_packet(&info->vsc, pipe_ctx->stream);
3456 
3457 		set_spd_info_packet(&info->spd, pipe_ctx->stream);
3458 
3459 		set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
3460 		set_adaptive_sync_info_packet(&info->adaptive_sync,
3461 										pipe_ctx->stream,
3462 										info,
3463 										&pipe_ctx->pipe_dlg_param);
3464 	}
3465 
3466 	patch_gamut_packet_checksum(&info->gamut);
3467 }
3468 
3469 enum dc_status resource_map_clock_resources(
3470 		const struct dc  *dc,
3471 		struct dc_state *context,
3472 		struct dc_stream_state *stream)
3473 {
3474 	/* acquire new resources */
3475 	const struct resource_pool *pool = dc->res_pool;
3476 	struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(
3477 				&context->res_ctx, stream);
3478 
3479 	if (!pipe_ctx)
3480 		return DC_ERROR_UNEXPECTED;
3481 
3482 	if (dc_is_dp_signal(pipe_ctx->stream->signal)
3483 		|| pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
3484 		pipe_ctx->clock_source = pool->dp_clock_source;
3485 	else {
3486 		pipe_ctx->clock_source = NULL;
3487 
3488 		if (!dc->config.disable_disp_pll_sharing)
3489 			pipe_ctx->clock_source = resource_find_used_clk_src_for_sharing(
3490 				&context->res_ctx,
3491 				pipe_ctx);
3492 
3493 		if (pipe_ctx->clock_source == NULL)
3494 			pipe_ctx->clock_source =
3495 				dc_resource_find_first_free_pll(
3496 					&context->res_ctx,
3497 					pool);
3498 	}
3499 
3500 	if (pipe_ctx->clock_source == NULL)
3501 		return DC_NO_CLOCK_SOURCE_RESOURCE;
3502 
3503 	resource_reference_clock_source(
3504 		&context->res_ctx, pool,
3505 		pipe_ctx->clock_source);
3506 
3507 	return DC_OK;
3508 }
3509 
3510 /*
3511  * Note: We need to disable output if clock sources change,
3512  * since bios does optimization and doesn't apply if changing
3513  * PHY when not already disabled.
3514  */
3515 bool pipe_need_reprogram(
3516 		struct pipe_ctx *pipe_ctx_old,
3517 		struct pipe_ctx *pipe_ctx)
3518 {
3519 	if (!pipe_ctx_old->stream)
3520 		return false;
3521 
3522 	if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink)
3523 		return true;
3524 
3525 	if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal)
3526 		return true;
3527 
3528 	if (pipe_ctx_old->stream_res.audio != pipe_ctx->stream_res.audio)
3529 		return true;
3530 
3531 	if (pipe_ctx_old->clock_source != pipe_ctx->clock_source
3532 			&& pipe_ctx_old->stream != pipe_ctx->stream)
3533 		return true;
3534 
3535 	if (pipe_ctx_old->stream_res.stream_enc != pipe_ctx->stream_res.stream_enc)
3536 		return true;
3537 
3538 	if (dc_is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream))
3539 		return true;
3540 
3541 	if (pipe_ctx_old->stream->dpms_off != pipe_ctx->stream->dpms_off)
3542 		return true;
3543 
3544 	if (false == pipe_ctx_old->stream->link->link_state_valid &&
3545 		false == pipe_ctx_old->stream->dpms_off)
3546 		return true;
3547 
3548 	if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc)
3549 		return true;
3550 
3551 	if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc)
3552 		return true;
3553 	if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc)
3554 		return true;
3555 
3556 	/* DIG link encoder resource assignment for stream changed. */
3557 	if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
3558 		bool need_reprogram = false;
3559 		struct dc *dc = pipe_ctx_old->stream->ctx->dc;
3560 		struct link_encoder *link_enc_prev =
3561 			link_enc_cfg_get_link_enc_used_by_stream_current(dc, pipe_ctx_old->stream);
3562 
3563 		if (link_enc_prev != pipe_ctx->stream->link_enc)
3564 			need_reprogram = true;
3565 
3566 		return need_reprogram;
3567 	}
3568 
3569 	return false;
3570 }
3571 
3572 void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream,
3573 		struct bit_depth_reduction_params *fmt_bit_depth)
3574 {
3575 	enum dc_dither_option option = stream->dither_option;
3576 	enum dc_pixel_encoding pixel_encoding =
3577 			stream->timing.pixel_encoding;
3578 
3579 	memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth));
3580 
3581 	if (option == DITHER_OPTION_DEFAULT) {
3582 		switch (stream->timing.display_color_depth) {
3583 		case COLOR_DEPTH_666:
3584 			option = DITHER_OPTION_SPATIAL6;
3585 			break;
3586 		case COLOR_DEPTH_888:
3587 			option = DITHER_OPTION_SPATIAL8;
3588 			break;
3589 		case COLOR_DEPTH_101010:
3590 			option = DITHER_OPTION_SPATIAL10;
3591 			break;
3592 		default:
3593 			option = DITHER_OPTION_DISABLE;
3594 		}
3595 	}
3596 
3597 	if (option == DITHER_OPTION_DISABLE)
3598 		return;
3599 
3600 	if (option == DITHER_OPTION_TRUN6) {
3601 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
3602 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 0;
3603 	} else if (option == DITHER_OPTION_TRUN8 ||
3604 			option == DITHER_OPTION_TRUN8_SPATIAL6 ||
3605 			option == DITHER_OPTION_TRUN8_FM6) {
3606 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
3607 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 1;
3608 	} else if (option == DITHER_OPTION_TRUN10        ||
3609 			option == DITHER_OPTION_TRUN10_SPATIAL6   ||
3610 			option == DITHER_OPTION_TRUN10_SPATIAL8   ||
3611 			option == DITHER_OPTION_TRUN10_FM8     ||
3612 			option == DITHER_OPTION_TRUN10_FM6     ||
3613 			option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
3614 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
3615 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
3616 	}
3617 
3618 	/* special case - Formatter can only reduce by 4 bits at most.
3619 	 * When reducing from 12 to 6 bits,
3620 	 * HW recommends we use trunc with round mode
3621 	 * (if we did nothing, trunc to 10 bits would be used)
3622 	 * note that any 12->10 bit reduction is ignored prior to DCE8,
3623 	 * as the input was 10 bits.
3624 	 */
3625 	if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM ||
3626 			option == DITHER_OPTION_SPATIAL6 ||
3627 			option == DITHER_OPTION_FM6) {
3628 		fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
3629 		fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
3630 		fmt_bit_depth->flags.TRUNCATE_MODE = 1;
3631 	}
3632 
3633 	/* spatial dither
3634 	 * note that spatial modes 1-3 are never used
3635 	 */
3636 	if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM            ||
3637 			option == DITHER_OPTION_SPATIAL6 ||
3638 			option == DITHER_OPTION_TRUN10_SPATIAL6      ||
3639 			option == DITHER_OPTION_TRUN8_SPATIAL6) {
3640 		fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
3641 		fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 0;
3642 		fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
3643 		fmt_bit_depth->flags.RGB_RANDOM =
3644 				(pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
3645 	} else if (option == DITHER_OPTION_SPATIAL8_FRAME_RANDOM            ||
3646 			option == DITHER_OPTION_SPATIAL8 ||
3647 			option == DITHER_OPTION_SPATIAL8_FM6        ||
3648 			option == DITHER_OPTION_TRUN10_SPATIAL8      ||
3649 			option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
3650 		fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
3651 		fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1;
3652 		fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
3653 		fmt_bit_depth->flags.RGB_RANDOM =
3654 				(pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
3655 	} else if (option == DITHER_OPTION_SPATIAL10_FRAME_RANDOM ||
3656 			option == DITHER_OPTION_SPATIAL10 ||
3657 			option == DITHER_OPTION_SPATIAL10_FM8 ||
3658 			option == DITHER_OPTION_SPATIAL10_FM6) {
3659 		fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
3660 		fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 2;
3661 		fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
3662 		fmt_bit_depth->flags.RGB_RANDOM =
3663 				(pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
3664 	}
3665 
3666 	if (option == DITHER_OPTION_SPATIAL6 ||
3667 			option == DITHER_OPTION_SPATIAL8 ||
3668 			option == DITHER_OPTION_SPATIAL10) {
3669 		fmt_bit_depth->flags.FRAME_RANDOM = 0;
3670 	} else {
3671 		fmt_bit_depth->flags.FRAME_RANDOM = 1;
3672 	}
3673 
3674 	//////////////////////
3675 	//// temporal dither
3676 	//////////////////////
3677 	if (option == DITHER_OPTION_FM6           ||
3678 			option == DITHER_OPTION_SPATIAL8_FM6     ||
3679 			option == DITHER_OPTION_SPATIAL10_FM6     ||
3680 			option == DITHER_OPTION_TRUN10_FM6     ||
3681 			option == DITHER_OPTION_TRUN8_FM6      ||
3682 			option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
3683 		fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
3684 		fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 0;
3685 	} else if (option == DITHER_OPTION_FM8        ||
3686 			option == DITHER_OPTION_SPATIAL10_FM8  ||
3687 			option == DITHER_OPTION_TRUN10_FM8) {
3688 		fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
3689 		fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 1;
3690 	} else if (option == DITHER_OPTION_FM10) {
3691 		fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
3692 		fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 2;
3693 	}
3694 
3695 	fmt_bit_depth->pixel_encoding = pixel_encoding;
3696 }
3697 
3698 enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
3699 {
3700 	struct dc_link *link = stream->link;
3701 	struct timing_generator *tg = dc->res_pool->timing_generators[0];
3702 	enum dc_status res = DC_OK;
3703 
3704 	calculate_phy_pix_clks(stream);
3705 
3706 	if (!tg->funcs->validate_timing(tg, &stream->timing))
3707 		res = DC_FAIL_CONTROLLER_VALIDATE;
3708 
3709 	if (res == DC_OK) {
3710 		if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
3711 				!link->link_enc->funcs->validate_output_with_stream(
3712 						link->link_enc, stream))
3713 			res = DC_FAIL_ENC_VALIDATE;
3714 	}
3715 
3716 	/* TODO: validate audio ASIC caps, encoder */
3717 
3718 	if (res == DC_OK)
3719 		res = dc->link_srv->validate_mode_timing(stream,
3720 		      link,
3721 		      &stream->timing);
3722 
3723 	return res;
3724 }
3725 
3726 enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state)
3727 {
3728 	enum dc_status res = DC_OK;
3729 
3730 	/* check if surface has invalid dimensions */
3731 	if (plane_state->src_rect.width == 0 || plane_state->src_rect.height == 0 ||
3732 		plane_state->dst_rect.width == 0 || plane_state->dst_rect.height == 0)
3733 		return DC_FAIL_SURFACE_VALIDATE;
3734 
3735 	/* TODO For now validates pixel format only */
3736 	if (dc->res_pool->funcs->validate_plane)
3737 		return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps);
3738 
3739 	return res;
3740 }
3741 
3742 unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format)
3743 {
3744 	switch (format) {
3745 	case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
3746 		return 8;
3747 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
3748 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
3749 		return 12;
3750 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
3751 	case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
3752 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
3753 	case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
3754 		return 16;
3755 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
3756 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
3757 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
3758 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
3759 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
3760 	case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
3761 	case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
3762 		return 32;
3763 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
3764 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
3765 	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
3766 	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
3767 		return 64;
3768 	default:
3769 		ASSERT_CRITICAL(false);
3770 		return -1;
3771 	}
3772 }
3773 static unsigned int get_max_audio_sample_rate(struct audio_mode *modes)
3774 {
3775 	if (modes) {
3776 		if (modes->sample_rates.rate.RATE_192)
3777 			return 192000;
3778 		if (modes->sample_rates.rate.RATE_176_4)
3779 			return 176400;
3780 		if (modes->sample_rates.rate.RATE_96)
3781 			return 96000;
3782 		if (modes->sample_rates.rate.RATE_88_2)
3783 			return 88200;
3784 		if (modes->sample_rates.rate.RATE_48)
3785 			return 48000;
3786 		if (modes->sample_rates.rate.RATE_44_1)
3787 			return 44100;
3788 		if (modes->sample_rates.rate.RATE_32)
3789 			return 32000;
3790 	}
3791 	/*original logic when no audio info*/
3792 	return 441000;
3793 }
3794 
3795 void get_audio_check(struct audio_info *aud_modes,
3796 	struct audio_check *audio_chk)
3797 {
3798 	unsigned int i;
3799 	unsigned int max_sample_rate = 0;
3800 
3801 	if (aud_modes) {
3802 		audio_chk->audio_packet_type = 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/
3803 
3804 		audio_chk->max_audiosample_rate = 0;
3805 		for (i = 0; i < aud_modes->mode_count; i++) {
3806 			max_sample_rate = get_max_audio_sample_rate(&aud_modes->modes[i]);
3807 			if (audio_chk->max_audiosample_rate < max_sample_rate)
3808 				audio_chk->max_audiosample_rate = max_sample_rate;
3809 			/*dts takes the same as type 2: AP = 0.25*/
3810 		}
3811 		/*check which one take more bandwidth*/
3812 		if (audio_chk->max_audiosample_rate > 192000)
3813 			audio_chk->audio_packet_type = 0x9;/*AP =1*/
3814 		audio_chk->acat = 0;/*not support*/
3815 	}
3816 }
3817 
3818 static struct hpo_dp_link_encoder *get_temp_hpo_dp_link_enc(
3819 		const struct resource_context *res_ctx,
3820 		const struct resource_pool *const pool,
3821 		const struct dc_link *link)
3822 {
3823 	struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL;
3824 	int enc_index;
3825 
3826 	enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, link);
3827 
3828 	if (enc_index < 0)
3829 		enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
3830 
3831 	if (enc_index >= 0)
3832 		hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
3833 
3834 	return hpo_dp_link_enc;
3835 }
3836 
3837 bool get_temp_dp_link_res(struct dc_link *link,
3838 		struct link_resource *link_res,
3839 		struct dc_link_settings *link_settings)
3840 {
3841 	const struct dc *dc  = link->dc;
3842 	const struct resource_context *res_ctx = &dc->current_state->res_ctx;
3843 
3844 	memset(link_res, 0, sizeof(*link_res));
3845 
3846 	if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
3847 		link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx,
3848 				dc->res_pool, link);
3849 		if (!link_res->hpo_dp_link_enc)
3850 			return false;
3851 	}
3852 	return true;
3853 }
3854 
3855 void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
3856 		struct dc_state *context)
3857 {
3858 	int i, j;
3859 	struct pipe_ctx *pipe_ctx_old, *pipe_ctx, *pipe_ctx_syncd;
3860 
3861 	/* If pipe backend is reset, need to reset pipe syncd status */
3862 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
3863 		pipe_ctx_old =	&dc->current_state->res_ctx.pipe_ctx[i];
3864 		pipe_ctx = &context->res_ctx.pipe_ctx[i];
3865 
3866 		if (!pipe_ctx_old->stream)
3867 			continue;
3868 
3869 		if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
3870 			continue;
3871 
3872 		if (!pipe_ctx->stream ||
3873 				pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
3874 
3875 			/* Reset all the syncd pipes from the disabled pipe */
3876 			for (j = 0; j < dc->res_pool->pipe_count; j++) {
3877 				pipe_ctx_syncd = &context->res_ctx.pipe_ctx[j];
3878 				if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_syncd) == pipe_ctx_old->pipe_idx) ||
3879 					!IS_PIPE_SYNCD_VALID(pipe_ctx_syncd))
3880 					SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_syncd, j);
3881 			}
3882 		}
3883 	}
3884 }
3885 
3886 void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
3887 	struct dc_state *context,
3888 	uint8_t disabled_master_pipe_idx)
3889 {
3890 	int i;
3891 	struct pipe_ctx *pipe_ctx, *pipe_ctx_check;
3892 
3893 	pipe_ctx = &context->res_ctx.pipe_ctx[disabled_master_pipe_idx];
3894 	if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx) != disabled_master_pipe_idx) ||
3895 		!IS_PIPE_SYNCD_VALID(pipe_ctx))
3896 		SET_PIPE_SYNCD_TO_PIPE(pipe_ctx, disabled_master_pipe_idx);
3897 
3898 	/* for the pipe disabled, check if any slave pipe exists and assert */
3899 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
3900 		pipe_ctx_check = &context->res_ctx.pipe_ctx[i];
3901 
3902 		if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) &&
3903 		    IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx)) {
3904 			struct pipe_ctx *first_pipe = pipe_ctx_check;
3905 
3906 			while (first_pipe->prev_odm_pipe)
3907 				first_pipe = first_pipe->prev_odm_pipe;
3908 			/* When ODM combine is enabled, this case is expected. If the disabled pipe
3909 			 * is part of the ODM tree, then we should not print an error.
3910 			 * */
3911 			if (first_pipe->pipe_idx == disabled_master_pipe_idx)
3912 				continue;
3913 
3914 			DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n",
3915 				   i, disabled_master_pipe_idx);
3916 		}
3917 	}
3918 }
3919 
3920 void reset_sync_context_for_pipe(const struct dc *dc,
3921 	struct dc_state *context,
3922 	uint8_t pipe_idx)
3923 {
3924 	int i;
3925 	struct pipe_ctx *pipe_ctx_reset;
3926 
3927 	/* reset the otg sync context for the pipe and its slave pipes if any */
3928 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
3929 		pipe_ctx_reset = &context->res_ctx.pipe_ctx[i];
3930 
3931 		if (((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_reset) == pipe_idx) &&
3932 			IS_PIPE_SYNCD_VALID(pipe_ctx_reset)) || (i == pipe_idx))
3933 			SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_reset, i);
3934 	}
3935 }
3936 
3937 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter)
3938 {
3939 	/* TODO - get transmitter to phy idx mapping from DMUB */
3940 	uint8_t phy_idx = transmitter - TRANSMITTER_UNIPHY_A;
3941 
3942 	if (dc->ctx->dce_version == DCN_VERSION_3_1 &&
3943 			dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) {
3944 		switch (transmitter) {
3945 		case TRANSMITTER_UNIPHY_A:
3946 			phy_idx = 0;
3947 			break;
3948 		case TRANSMITTER_UNIPHY_B:
3949 			phy_idx = 1;
3950 			break;
3951 		case TRANSMITTER_UNIPHY_C:
3952 			phy_idx = 5;
3953 			break;
3954 		case TRANSMITTER_UNIPHY_D:
3955 			phy_idx = 6;
3956 			break;
3957 		case TRANSMITTER_UNIPHY_E:
3958 			phy_idx = 4;
3959 			break;
3960 		default:
3961 			phy_idx = 0;
3962 			break;
3963 		}
3964 	}
3965 
3966 	return phy_idx;
3967 }
3968 
3969 const struct link_hwss *get_link_hwss(const struct dc_link *link,
3970 		const struct link_resource *link_res)
3971 {
3972 	/* Link_hwss is only accessible by getter function instead of accessing
3973 	 * by pointers in dc with the intent to protect against breaking polymorphism.
3974 	 */
3975 	if (can_use_hpo_dp_link_hwss(link, link_res))
3976 		/* TODO: some assumes that if decided link settings is 128b/132b
3977 		 * channel coding format hpo_dp_link_enc should be used.
3978 		 * Others believe that if hpo_dp_link_enc is available in link
3979 		 * resource then hpo_dp_link_enc must be used. This bound between
3980 		 * hpo_dp_link_enc != NULL and decided link settings is loosely coupled
3981 		 * with a premise that both hpo_dp_link_enc pointer and decided link
3982 		 * settings are determined based on single policy function like
3983 		 * "decide_link_settings" from upper layer. This "convention"
3984 		 * cannot be maintained and enforced at current level.
3985 		 * Therefore a refactor is due so we can enforce a strong bound
3986 		 * between those two parameters at this level.
3987 		 *
3988 		 * To put it simple, we want to make enforcement at low level so that
3989 		 * we will not return link hwss if caller plans to do 8b/10b
3990 		 * with an hpo encoder. Or we can return a very dummy one that doesn't
3991 		 * do work for all functions
3992 		 */
3993 		return get_hpo_dp_link_hwss();
3994 	else if (can_use_dpia_link_hwss(link, link_res))
3995 		return get_dpia_link_hwss();
3996 	else if (can_use_dio_link_hwss(link, link_res))
3997 		return get_dio_link_hwss();
3998 	else
3999 		return get_virtual_link_hwss();
4000 }
4001 
4002 bool is_h_timing_divisible_by_2(struct dc_stream_state *stream)
4003 {
4004 	bool divisible = false;
4005 	uint16_t h_blank_start = 0;
4006 	uint16_t h_blank_end = 0;
4007 
4008 	if (stream) {
4009 		h_blank_start = stream->timing.h_total - stream->timing.h_front_porch;
4010 		h_blank_end = h_blank_start - stream->timing.h_addressable;
4011 
4012 		/* HTOTAL, Hblank start/end, and Hsync start/end all must be
4013 		 * divisible by 2 in order for the horizontal timing params
4014 		 * to be considered divisible by 2. Hsync start is always 0.
4015 		 */
4016 		divisible = (stream->timing.h_total % 2 == 0) &&
4017 				(h_blank_start % 2 == 0) &&
4018 				(h_blank_end % 2 == 0) &&
4019 				(stream->timing.h_sync_width % 2 == 0);
4020 	}
4021 	return divisible;
4022 }
4023 
4024 bool dc_resource_acquire_secondary_pipe_for_mpc_odm(
4025 		const struct dc *dc,
4026 		struct dc_state *state,
4027 		struct pipe_ctx *pri_pipe,
4028 		struct pipe_ctx *sec_pipe,
4029 		bool odm)
4030 {
4031 	int pipe_idx = sec_pipe->pipe_idx;
4032 	struct pipe_ctx *sec_top, *sec_bottom, *sec_next, *sec_prev;
4033 	const struct resource_pool *pool = dc->res_pool;
4034 
4035 	sec_top = sec_pipe->top_pipe;
4036 	sec_bottom = sec_pipe->bottom_pipe;
4037 	sec_next = sec_pipe->next_odm_pipe;
4038 	sec_prev = sec_pipe->prev_odm_pipe;
4039 
4040 	*sec_pipe = *pri_pipe;
4041 
4042 	sec_pipe->top_pipe = sec_top;
4043 	sec_pipe->bottom_pipe = sec_bottom;
4044 	sec_pipe->next_odm_pipe = sec_next;
4045 	sec_pipe->prev_odm_pipe = sec_prev;
4046 
4047 	sec_pipe->pipe_idx = pipe_idx;
4048 	sec_pipe->plane_res.mi = pool->mis[pipe_idx];
4049 	sec_pipe->plane_res.hubp = pool->hubps[pipe_idx];
4050 	sec_pipe->plane_res.ipp = pool->ipps[pipe_idx];
4051 	sec_pipe->plane_res.xfm = pool->transforms[pipe_idx];
4052 	sec_pipe->plane_res.dpp = pool->dpps[pipe_idx];
4053 	sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst;
4054 	sec_pipe->stream_res.dsc = NULL;
4055 	if (odm) {
4056 		if (!sec_pipe->top_pipe)
4057 			sec_pipe->stream_res.opp = pool->opps[pipe_idx];
4058 		else
4059 			sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp;
4060 		if (sec_pipe->stream->timing.flags.DSC == 1) {
4061 #if defined(CONFIG_DRM_AMD_DC_FP)
4062 			dcn20_acquire_dsc(dc, &state->res_ctx, &sec_pipe->stream_res.dsc, pipe_idx);
4063 #endif
4064 			ASSERT(sec_pipe->stream_res.dsc);
4065 			if (sec_pipe->stream_res.dsc == NULL)
4066 				return false;
4067 		}
4068 #if defined(CONFIG_DRM_AMD_DC_FP)
4069 		dcn20_build_mapped_resource(dc, state, sec_pipe->stream);
4070 #endif
4071 	}
4072 
4073 	return true;
4074 }
4075 
4076 enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc,
4077 		struct dc_state *context,
4078 		struct pipe_ctx *pipe_ctx)
4079 {
4080 	if (dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
4081 		if (pipe_ctx->stream_res.hpo_dp_stream_enc == NULL) {
4082 			pipe_ctx->stream_res.hpo_dp_stream_enc =
4083 					find_first_free_match_hpo_dp_stream_enc_for_link(
4084 							&context->res_ctx, dc->res_pool, pipe_ctx->stream);
4085 
4086 			if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
4087 				return DC_NO_STREAM_ENC_RESOURCE;
4088 
4089 			update_hpo_dp_stream_engine_usage(
4090 					&context->res_ctx, dc->res_pool,
4091 					pipe_ctx->stream_res.hpo_dp_stream_enc,
4092 					true);
4093 		}
4094 
4095 		if (pipe_ctx->link_res.hpo_dp_link_enc == NULL) {
4096 			if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, dc->res_pool, pipe_ctx, pipe_ctx->stream))
4097 				return DC_NO_LINK_ENC_RESOURCE;
4098 		}
4099 	} else {
4100 		if (pipe_ctx->stream_res.hpo_dp_stream_enc) {
4101 			update_hpo_dp_stream_engine_usage(
4102 					&context->res_ctx, dc->res_pool,
4103 					pipe_ctx->stream_res.hpo_dp_stream_enc,
4104 					false);
4105 			pipe_ctx->stream_res.hpo_dp_stream_enc = NULL;
4106 		}
4107 		if (pipe_ctx->link_res.hpo_dp_link_enc)
4108 			remove_hpo_dp_link_enc_from_ctx(&context->res_ctx, pipe_ctx, pipe_ctx->stream);
4109 	}
4110 
4111 	return DC_OK;
4112 }
4113 
4114