1 /* Copyright 2021 Advanced Micro Devices, Inc. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a
4  * copy of this software and associated documentation files (the "Software"),
5  * to deal in the Software without restriction, including without limitation
6  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7  * and/or sell copies of the Software, and to permit persons to whom the
8  * Software is furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
16  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
17  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19  * OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Authors: AMD
22  *
23  */
24 
25 #include "link_enc_cfg.h"
26 #include "resource.h"
27 #include "dc_link_dp.h"
28 
29 /* Check whether stream is supported by DIG link encoders. */
is_dig_link_enc_stream(struct dc_stream_state * stream)30 static bool is_dig_link_enc_stream(struct dc_stream_state *stream)
31 {
32 	bool is_dig_stream = false;
33 	struct link_encoder *link_enc = NULL;
34 	int i;
35 
36 	/* Loop over created link encoder objects. */
37 	if (stream) {
38 		for (i = 0; i < stream->ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) {
39 			link_enc = stream->ctx->dc->res_pool->link_encoders[i];
40 
41 			/* Need to check link signal type rather than stream signal type which may not
42 			 * yet match.
43 			 */
44 			if (link_enc && ((uint32_t)stream->link->connector_signal & link_enc->output_signals)) {
45 				if (dc_is_dp_signal(stream->signal)) {
46 					/* DIGs do not support DP2.0 streams with 128b/132b encoding. */
47 					struct dc_link_settings link_settings = {0};
48 
49 					decide_link_settings(stream, &link_settings);
50 					if ((link_settings.link_rate >= LINK_RATE_LOW) &&
51 							link_settings.link_rate <= LINK_RATE_HIGH3) {
52 						is_dig_stream = true;
53 						break;
54 					}
55 				} else {
56 					is_dig_stream = true;
57 					break;
58 				}
59 			}
60 		}
61 	}
62 	return is_dig_stream;
63 }
64 
get_assignment(struct dc * dc,int i)65 static struct link_enc_assignment get_assignment(struct dc *dc, int i)
66 {
67 	struct link_enc_assignment assignment;
68 
69 	if (dc->current_state->res_ctx.link_enc_cfg_ctx.mode == LINK_ENC_CFG_TRANSIENT)
70 		assignment = dc->current_state->res_ctx.link_enc_cfg_ctx.transient_assignments[i];
71 	else /* LINK_ENC_CFG_STEADY */
72 		assignment = dc->current_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
73 
74 	return assignment;
75 }
76 
77 /* Return stream using DIG link encoder resource. NULL if unused. */
get_stream_using_link_enc(struct dc_state * state,enum engine_id eng_id)78 static struct dc_stream_state *get_stream_using_link_enc(
79 		struct dc_state *state,
80 		enum engine_id eng_id)
81 {
82 	struct dc_stream_state *stream = NULL;
83 	int i;
84 
85 	for (i = 0; i < state->stream_count; i++) {
86 		struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
87 
88 		if ((assignment.valid == true) && (assignment.eng_id == eng_id)) {
89 			stream = state->streams[i];
90 			break;
91 		}
92 	}
93 
94 	return stream;
95 }
96 
remove_link_enc_assignment(struct dc_state * state,struct dc_stream_state * stream,enum engine_id eng_id)97 static void remove_link_enc_assignment(
98 		struct dc_state *state,
99 		struct dc_stream_state *stream,
100 		enum engine_id eng_id)
101 {
102 	int eng_idx;
103 	int i;
104 
105 	if (eng_id != ENGINE_ID_UNKNOWN) {
106 		eng_idx = eng_id - ENGINE_ID_DIGA;
107 
108 		/* stream ptr of stream in dc_state used to update correct entry in
109 		 * link_enc_assignments table.
110 		 */
111 		for (i = 0; i < MAX_PIPES; i++) {
112 			struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
113 
114 			if (assignment.valid && assignment.stream == stream) {
115 				state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].valid = false;
116 				/* Only add link encoder back to availability pool if not being
117 				 * used by any other stream (i.e. removing SST stream or last MST stream).
118 				 */
119 				if (get_stream_using_link_enc(state, eng_id) == NULL)
120 					state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] = eng_id;
121 				stream->link_enc = NULL;
122 				break;
123 			}
124 		}
125 	}
126 }
127 
add_link_enc_assignment(struct dc_state * state,struct dc_stream_state * stream,enum engine_id eng_id)128 static void add_link_enc_assignment(
129 		struct dc_state *state,
130 		struct dc_stream_state *stream,
131 		enum engine_id eng_id)
132 {
133 	int eng_idx;
134 	int i;
135 
136 	if (eng_id != ENGINE_ID_UNKNOWN) {
137 		eng_idx = eng_id - ENGINE_ID_DIGA;
138 
139 		/* stream ptr of stream in dc_state used to update correct entry in
140 		 * link_enc_assignments table.
141 		 */
142 		for (i = 0; i < state->stream_count; i++) {
143 			if (stream == state->streams[i]) {
144 				state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i] = (struct link_enc_assignment){
145 					.valid = true,
146 					.ep_id = (struct display_endpoint_id) {
147 						.link_id = stream->link->link_id,
148 						.ep_type = stream->link->ep_type},
149 					.eng_id = eng_id,
150 					.stream = stream};
151 				state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] = ENGINE_ID_UNKNOWN;
152 				stream->link_enc = stream->ctx->dc->res_pool->link_encoders[eng_idx];
153 				break;
154 			}
155 		}
156 
157 		/* Attempted to add an encoder assignment for a stream not in dc_state. */
158 		ASSERT(i != state->stream_count);
159 	}
160 }
161 
162 /* Return first available DIG link encoder. */
find_first_avail_link_enc(const struct dc_context * ctx,const struct dc_state * state)163 static enum engine_id find_first_avail_link_enc(
164 		const struct dc_context *ctx,
165 		const struct dc_state *state)
166 {
167 	enum engine_id eng_id = ENGINE_ID_UNKNOWN;
168 	int i;
169 
170 	for (i = 0; i < ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) {
171 		eng_id = state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i];
172 		if (eng_id != ENGINE_ID_UNKNOWN)
173 			break;
174 	}
175 
176 	return eng_id;
177 }
178 
179 /* Check for availability of link encoder eng_id. */
is_avail_link_enc(struct dc_state * state,enum engine_id eng_id,struct dc_stream_state * stream)180 static bool is_avail_link_enc(struct dc_state *state, enum engine_id eng_id, struct dc_stream_state *stream)
181 {
182 	bool is_avail = false;
183 	int eng_idx = eng_id - ENGINE_ID_DIGA;
184 
185 	/* An encoder is available if it is still in the availability pool. */
186 	if (eng_id != ENGINE_ID_UNKNOWN && state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] != ENGINE_ID_UNKNOWN) {
187 		is_avail = true;
188 	} else {
189 		struct dc_stream_state *stream_assigned = NULL;
190 
191 		/* MST streams share the same link and should share the same encoder.
192 		 * If a stream that has already been assigned a link encoder uses as the
193 		 * same link as the stream checking for availability, it is an MST stream
194 		 * and should use the same link encoder.
195 		 */
196 		stream_assigned = get_stream_using_link_enc(state, eng_id);
197 		if (stream_assigned && stream != stream_assigned && stream->link == stream_assigned->link)
198 			is_avail = true;
199 	}
200 
201 	return is_avail;
202 }
203 
204 /* Test for display_endpoint_id equality. */
are_ep_ids_equal(struct display_endpoint_id * lhs,struct display_endpoint_id * rhs)205 static bool are_ep_ids_equal(struct display_endpoint_id *lhs, struct display_endpoint_id *rhs)
206 {
207 	bool are_equal = false;
208 
209 	if (lhs->link_id.id == rhs->link_id.id &&
210 			lhs->link_id.enum_id == rhs->link_id.enum_id &&
211 			lhs->link_id.type == rhs->link_id.type &&
212 			lhs->ep_type == rhs->ep_type)
213 		are_equal = true;
214 
215 	return are_equal;
216 }
217 
get_link_enc_used_by_link(struct dc_state * state,const struct dc_link * link)218 static struct link_encoder *get_link_enc_used_by_link(
219 		struct dc_state *state,
220 		const struct dc_link *link)
221 {
222 	struct link_encoder *link_enc = NULL;
223 	struct display_endpoint_id ep_id;
224 	int i;
225 
226 	ep_id = (struct display_endpoint_id) {
227 		.link_id = link->link_id,
228 		.ep_type = link->ep_type};
229 
230 	for (i = 0; i < state->stream_count; i++) {
231 		struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
232 
233 		if (assignment.valid == true && are_ep_ids_equal(&assignment.ep_id, &ep_id))
234 			link_enc = link->dc->res_pool->link_encoders[assignment.eng_id - ENGINE_ID_DIGA];
235 	}
236 
237 	return link_enc;
238 }
239 /* Clear all link encoder assignments. */
clear_enc_assignments(struct dc_state * state)240 static void clear_enc_assignments(struct dc_state *state)
241 {
242 	int i;
243 	enum engine_id eng_id;
244 	struct dc_stream_state *stream;
245 
246 	for (i = 0; i < MAX_PIPES; i++) {
247 		state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].valid = false;
248 		eng_id = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].eng_id;
249 		stream = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].stream;
250 		if (eng_id != ENGINE_ID_UNKNOWN)
251 			state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_id - ENGINE_ID_DIGA] = eng_id;
252 		if (stream)
253 			stream->link_enc = NULL;
254 	}
255 }
256 
link_enc_cfg_init(struct dc * dc,struct dc_state * state)257 void link_enc_cfg_init(
258 		struct dc *dc,
259 		struct dc_state *state)
260 {
261 	int i;
262 
263 	for (i = 0; i < dc->res_pool->res_cap->num_dig_link_enc; i++) {
264 		if (dc->res_pool->link_encoders[i])
265 			state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i] = (enum engine_id) i;
266 		else
267 			state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i] = ENGINE_ID_UNKNOWN;
268 	}
269 
270 	clear_enc_assignments(state);
271 
272 	state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY;
273 }
274 
link_enc_cfg_link_encs_assign(struct dc * dc,struct dc_state * state,struct dc_stream_state * streams[],uint8_t stream_count)275 void link_enc_cfg_link_encs_assign(
276 		struct dc *dc,
277 		struct dc_state *state,
278 		struct dc_stream_state *streams[],
279 		uint8_t stream_count)
280 {
281 	enum engine_id eng_id = ENGINE_ID_UNKNOWN;
282 	int i;
283 	int j;
284 
285 	ASSERT(state->stream_count == stream_count);
286 
287 	if (stream_count == 0)
288 		clear_enc_assignments(state);
289 
290 	/* Release DIG link encoder resources before running assignment algorithm. */
291 	for (i = 0; i < stream_count; i++)
292 		dc->res_pool->funcs->link_enc_unassign(state, streams[i]);
293 
294 	for (i = 0; i < MAX_PIPES; i++)
295 		ASSERT(state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].valid == false);
296 
297 	/* (a) Assign DIG link encoders to physical (unmappable) endpoints first. */
298 	for (i = 0; i < stream_count; i++) {
299 		struct dc_stream_state *stream = streams[i];
300 
301 		/* Skip stream if not supported by DIG link encoder. */
302 		if (!is_dig_link_enc_stream(stream))
303 			continue;
304 
305 		/* Physical endpoints have a fixed mapping to DIG link encoders. */
306 		if (!stream->link->is_dig_mapping_flexible) {
307 			eng_id = stream->link->eng_id;
308 			add_link_enc_assignment(state, stream, eng_id);
309 		}
310 	}
311 
312 	/* (b) Retain previous assignments for mappable endpoints if encoders still available. */
313 	eng_id = ENGINE_ID_UNKNOWN;
314 
315 	if (state != dc->current_state) {
316 		struct dc_state *prev_state = dc->current_state;
317 
318 		for (i = 0; i < stream_count; i++) {
319 			struct dc_stream_state *stream = state->streams[i];
320 
321 			/* Skip stream if not supported by DIG link encoder. */
322 			if (!is_dig_link_enc_stream(stream))
323 				continue;
324 
325 			if (!stream->link->is_dig_mapping_flexible)
326 				continue;
327 
328 			for (j = 0; j < prev_state->stream_count; j++) {
329 				struct dc_stream_state *prev_stream = prev_state->streams[j];
330 
331 				if (stream == prev_stream && stream->link == prev_stream->link &&
332 						prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].valid) {
333 					eng_id = prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].eng_id;
334 					if (is_avail_link_enc(state, eng_id, stream))
335 						add_link_enc_assignment(state, stream, eng_id);
336 				}
337 			}
338 		}
339 	}
340 
341 	/* (c) Then assign encoders to remaining mappable endpoints. */
342 	eng_id = ENGINE_ID_UNKNOWN;
343 
344 	for (i = 0; i < stream_count; i++) {
345 		struct dc_stream_state *stream = streams[i];
346 
347 		/* Skip stream if not supported by DIG link encoder. */
348 		if (!is_dig_link_enc_stream(stream)) {
349 			ASSERT(stream->link->is_dig_mapping_flexible != true);
350 			continue;
351 		}
352 
353 		/* Mappable endpoints have a flexible mapping to DIG link encoders. */
354 		if (stream->link->is_dig_mapping_flexible) {
355 			struct link_encoder *link_enc = NULL;
356 
357 			/* Skip if encoder assignment retained in step (b) above. */
358 			if (stream->link_enc)
359 				continue;
360 
361 			/* For MST, multiple streams will share the same link / display
362 			 * endpoint. These streams should use the same link encoder
363 			 * assigned to that endpoint.
364 			 */
365 			link_enc = get_link_enc_used_by_link(state, stream->link);
366 			if (link_enc == NULL)
367 				eng_id = find_first_avail_link_enc(stream->ctx, state);
368 			else
369 				eng_id =  link_enc->preferred_engine;
370 			add_link_enc_assignment(state, stream, eng_id);
371 		}
372 	}
373 
374 	link_enc_cfg_validate(dc, state);
375 
376 	/* Update transient assignments. */
377 	for (i = 0; i < MAX_PIPES; i++) {
378 		dc->current_state->res_ctx.link_enc_cfg_ctx.transient_assignments[i] =
379 			state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
380 	}
381 
382 	/* Current state mode will be set to steady once this state committed. */
383 	state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY;
384 }
385 
link_enc_cfg_link_enc_unassign(struct dc_state * state,struct dc_stream_state * stream)386 void link_enc_cfg_link_enc_unassign(
387 		struct dc_state *state,
388 		struct dc_stream_state *stream)
389 {
390 	enum engine_id eng_id = ENGINE_ID_UNKNOWN;
391 
392 	/* Only DIG link encoders. */
393 	if (!is_dig_link_enc_stream(stream))
394 		return;
395 
396 	if (stream->link_enc)
397 		eng_id = stream->link_enc->preferred_engine;
398 
399 	remove_link_enc_assignment(state, stream, eng_id);
400 }
401 
link_enc_cfg_is_transmitter_mappable(struct dc * dc,struct link_encoder * link_enc)402 bool link_enc_cfg_is_transmitter_mappable(
403 		struct dc *dc,
404 		struct link_encoder *link_enc)
405 {
406 	bool is_mappable = false;
407 	enum engine_id eng_id = link_enc->preferred_engine;
408 	struct dc_stream_state *stream = link_enc_cfg_get_stream_using_link_enc(dc, eng_id);
409 
410 	if (stream)
411 		is_mappable = stream->link->is_dig_mapping_flexible;
412 
413 	return is_mappable;
414 }
415 
link_enc_cfg_get_stream_using_link_enc(struct dc * dc,enum engine_id eng_id)416 struct dc_stream_state *link_enc_cfg_get_stream_using_link_enc(
417 		struct dc *dc,
418 		enum engine_id eng_id)
419 {
420 	struct dc_stream_state *stream = NULL;
421 	int i;
422 
423 	for (i = 0; i < MAX_PIPES; i++) {
424 		struct link_enc_assignment assignment = get_assignment(dc, i);
425 
426 		if ((assignment.valid == true) && (assignment.eng_id == eng_id)) {
427 			stream = assignment.stream;
428 			break;
429 		}
430 	}
431 
432 	return stream;
433 }
434 
link_enc_cfg_get_link_using_link_enc(struct dc * dc,enum engine_id eng_id)435 struct dc_link *link_enc_cfg_get_link_using_link_enc(
436 		struct dc *dc,
437 		enum engine_id eng_id)
438 {
439 	struct dc_link *link = NULL;
440 	struct dc_stream_state *stream = NULL;
441 
442 	stream = link_enc_cfg_get_stream_using_link_enc(dc, eng_id);
443 
444 	if (stream)
445 		link = stream->link;
446 
447 	// dm_output_to_console("%s: No link using DIG(%d).\n", __func__, eng_id);
448 	return link;
449 }
450 
link_enc_cfg_get_link_enc_used_by_link(struct dc * dc,const struct dc_link * link)451 struct link_encoder *link_enc_cfg_get_link_enc_used_by_link(
452 		struct dc *dc,
453 		const struct dc_link *link)
454 {
455 	struct link_encoder *link_enc = NULL;
456 	struct display_endpoint_id ep_id;
457 	int i;
458 
459 	ep_id = (struct display_endpoint_id) {
460 		.link_id = link->link_id,
461 		.ep_type = link->ep_type};
462 
463 	for (i = 0; i < MAX_PIPES; i++) {
464 		struct link_enc_assignment assignment = get_assignment(dc, i);
465 
466 		if (assignment.valid == true && are_ep_ids_equal(&assignment.ep_id, &ep_id)) {
467 			link_enc = link->dc->res_pool->link_encoders[assignment.eng_id - ENGINE_ID_DIGA];
468 			break;
469 		}
470 	}
471 
472 	return link_enc;
473 }
474 
link_enc_cfg_get_next_avail_link_enc(struct dc * dc)475 struct link_encoder *link_enc_cfg_get_next_avail_link_enc(struct dc *dc)
476 {
477 	struct link_encoder *link_enc = NULL;
478 	enum engine_id encs_assigned[MAX_DIG_LINK_ENCODERS];
479 	int i;
480 
481 	for (i = 0; i < MAX_DIG_LINK_ENCODERS; i++)
482 		encs_assigned[i] = ENGINE_ID_UNKNOWN;
483 
484 	/* Add assigned encoders to list. */
485 	for (i = 0; i < MAX_PIPES; i++) {
486 		struct link_enc_assignment assignment = get_assignment(dc, i);
487 
488 		if (assignment.valid)
489 			encs_assigned[assignment.eng_id - ENGINE_ID_DIGA] = assignment.eng_id;
490 	}
491 
492 	for (i = 0; i < dc->res_pool->res_cap->num_dig_link_enc; i++) {
493 		if (encs_assigned[i] == ENGINE_ID_UNKNOWN) {
494 			link_enc = dc->res_pool->link_encoders[i];
495 			break;
496 		}
497 	}
498 
499 	return link_enc;
500 }
501 
link_enc_cfg_get_link_enc_used_by_stream(struct dc * dc,const struct dc_stream_state * stream)502 struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream(
503 		struct dc *dc,
504 		const struct dc_stream_state *stream)
505 {
506 	struct link_encoder *link_enc;
507 
508 	link_enc = link_enc_cfg_get_link_enc_used_by_link(dc, stream->link);
509 
510 	return link_enc;
511 }
512 
link_enc_cfg_is_link_enc_avail(struct dc * dc,enum engine_id eng_id,struct dc_link * link)513 bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id, struct dc_link *link)
514 {
515 	bool is_avail = true;
516 	int i;
517 
518 	/* An encoder is not available if it has already been assigned to a different endpoint. */
519 	for (i = 0; i < MAX_PIPES; i++) {
520 		struct link_enc_assignment assignment = get_assignment(dc, i);
521 		struct display_endpoint_id ep_id = (struct display_endpoint_id) {
522 				.link_id = link->link_id,
523 				.ep_type = link->ep_type};
524 
525 		if (assignment.valid && assignment.eng_id == eng_id && !are_ep_ids_equal(&ep_id, &assignment.ep_id)) {
526 			is_avail = false;
527 			break;
528 		}
529 	}
530 
531 	return is_avail;
532 }
533 
link_enc_cfg_validate(struct dc * dc,struct dc_state * state)534 bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state)
535 {
536 	bool is_valid = false;
537 	bool valid_entries = true;
538 	bool valid_stream_ptrs = true;
539 	bool valid_uniqueness = true;
540 	bool valid_avail = true;
541 	bool valid_streams = true;
542 	int i, j;
543 	uint8_t valid_count = 0;
544 	uint8_t dig_stream_count = 0;
545 	int matching_stream_ptrs = 0;
546 	int eng_ids_per_ep_id[MAX_PIPES] = {0};
547 
548 	/* (1) No. valid entries same as stream count. */
549 	for (i = 0; i < MAX_PIPES; i++) {
550 		struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
551 
552 		if (assignment.valid)
553 			valid_count++;
554 
555 		if (is_dig_link_enc_stream(state->streams[i]))
556 			dig_stream_count++;
557 	}
558 	if (valid_count != dig_stream_count)
559 		valid_entries = false;
560 
561 	/* (2) Matching stream ptrs. */
562 	for (i = 0; i < MAX_PIPES; i++) {
563 		struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
564 
565 		if (assignment.valid) {
566 			if (assignment.stream == state->streams[i])
567 				matching_stream_ptrs++;
568 			else
569 				valid_stream_ptrs = false;
570 		}
571 	}
572 
573 	/* (3) Each endpoint assigned unique encoder. */
574 	for (i = 0; i < MAX_PIPES; i++) {
575 		struct link_enc_assignment assignment_i = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
576 
577 		if (assignment_i.valid) {
578 			struct display_endpoint_id ep_id_i = assignment_i.ep_id;
579 
580 			eng_ids_per_ep_id[i]++;
581 			for (j = 0; j < MAX_PIPES; j++) {
582 				struct link_enc_assignment assignment_j =
583 					state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j];
584 
585 				if (j == i)
586 					continue;
587 
588 				if (assignment_j.valid) {
589 					struct display_endpoint_id ep_id_j = assignment_j.ep_id;
590 
591 					if (are_ep_ids_equal(&ep_id_i, &ep_id_j) &&
592 							assignment_i.eng_id != assignment_j.eng_id) {
593 						valid_uniqueness = false;
594 						eng_ids_per_ep_id[i]++;
595 					}
596 				}
597 			}
598 		}
599 	}
600 
601 	/* (4) Assigned encoders not in available pool. */
602 	for (i = 0; i < MAX_PIPES; i++) {
603 		struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
604 
605 		if (assignment.valid) {
606 			for (j = 0; j < dc->res_pool->res_cap->num_dig_link_enc; j++) {
607 				if (state->res_ctx.link_enc_cfg_ctx.link_enc_avail[j] == assignment.eng_id) {
608 					valid_avail = false;
609 					break;
610 				}
611 			}
612 		}
613 	}
614 
615 	/* (5) All streams have valid link encoders. */
616 	for (i = 0; i < state->stream_count; i++) {
617 		struct dc_stream_state *stream = state->streams[i];
618 
619 		if (is_dig_link_enc_stream(stream) && stream->link_enc == NULL) {
620 			valid_streams = false;
621 			break;
622 		}
623 	}
624 
625 	is_valid = valid_entries && valid_stream_ptrs && valid_uniqueness && valid_avail && valid_streams;
626 	ASSERT(is_valid);
627 
628 	return is_valid;
629 }
630