• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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 "link_enc_cfg.h"
27 #include "resource.h"
28 #include "dc_link_dp.h"
29 
30 /* Check whether stream is supported by DIG link encoders. */
is_dig_link_enc_stream(struct dc_stream_state * stream)31 static bool is_dig_link_enc_stream(struct dc_stream_state *stream)
32 {
33 	bool is_dig_stream = false;
34 	struct link_encoder *link_enc = NULL;
35 	int i;
36 
37 	/* Loop over created link encoder objects. */
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 		if (link_enc &&
42 				((uint32_t)stream->signal & link_enc->output_signals)) {
43 			if (dc_is_dp_signal(stream->signal)) {
44 				/* DIGs do not support DP2.0 streams with 128b/132b encoding. */
45 				struct dc_link_settings link_settings = {0};
46 
47 				decide_link_settings(stream, &link_settings);
48 				if ((link_settings.link_rate >= LINK_RATE_LOW) &&
49 						link_settings.link_rate <= LINK_RATE_HIGH3) {
50 					is_dig_stream = true;
51 					break;
52 				}
53 			} else {
54 				is_dig_stream = true;
55 				break;
56 			}
57 		}
58 	}
59 
60 	return is_dig_stream;
61 }
62 
63 /* Update DIG link encoder resource tracking variables in dc_state. */
update_link_enc_assignment(struct dc_state * state,struct dc_stream_state * stream,enum engine_id eng_id,bool add_enc)64 static void update_link_enc_assignment(
65 		struct dc_state *state,
66 		struct dc_stream_state *stream,
67 		enum engine_id eng_id,
68 		bool add_enc)
69 {
70 	int eng_idx;
71 	int stream_idx;
72 	int i;
73 
74 	if (eng_id != ENGINE_ID_UNKNOWN) {
75 		eng_idx = eng_id - ENGINE_ID_DIGA;
76 		stream_idx = -1;
77 
78 		/* Index of stream in dc_state used to update correct entry in
79 		 * link_enc_assignments table.
80 		 */
81 		for (i = 0; i < state->stream_count; i++) {
82 			if (stream == state->streams[i]) {
83 				stream_idx = i;
84 				break;
85 			}
86 		}
87 
88 		/* Update link encoder assignments table, link encoder availability
89 		 * pool and link encoder assigned to stream in state.
90 		 * Add/remove encoder resource to/from stream.
91 		 */
92 		if (stream_idx != -1) {
93 			if (add_enc) {
94 				state->res_ctx.link_enc_assignments[stream_idx] = (struct link_enc_assignment){
95 					.valid = true,
96 					.ep_id = (struct display_endpoint_id) {
97 						.link_id = stream->link->link_id,
98 						.ep_type = stream->link->ep_type},
99 					.eng_id = eng_id};
100 				state->res_ctx.link_enc_avail[eng_idx] = ENGINE_ID_UNKNOWN;
101 				stream->link_enc = stream->ctx->dc->res_pool->link_encoders[eng_idx];
102 			} else {
103 				state->res_ctx.link_enc_assignments[stream_idx].valid = false;
104 				state->res_ctx.link_enc_avail[eng_idx] = eng_id;
105 				stream->link_enc = NULL;
106 			}
107 		} else {
108 			dm_output_to_console("%s: Stream not found in dc_state.\n", __func__);
109 		}
110 	}
111 }
112 
113 /* Return first available DIG link encoder. */
find_first_avail_link_enc(const struct dc_context * ctx,const struct dc_state * state)114 static enum engine_id find_first_avail_link_enc(
115 		const struct dc_context *ctx,
116 		const struct dc_state *state)
117 {
118 	enum engine_id eng_id = ENGINE_ID_UNKNOWN;
119 	int i;
120 
121 	for (i = 0; i < ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) {
122 		eng_id = state->res_ctx.link_enc_avail[i];
123 		if (eng_id != ENGINE_ID_UNKNOWN)
124 			break;
125 	}
126 
127 	return eng_id;
128 }
129 
130 /* Return stream using DIG link encoder resource. NULL if unused. */
get_stream_using_link_enc(struct dc_state * state,enum engine_id eng_id)131 static struct dc_stream_state *get_stream_using_link_enc(
132 		struct dc_state *state,
133 		enum engine_id eng_id)
134 {
135 	struct dc_stream_state *stream = NULL;
136 	int stream_idx = -1;
137 	int i;
138 
139 	for (i = 0; i < state->stream_count; i++) {
140 		struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i];
141 
142 		if (assignment.valid && (assignment.eng_id == eng_id)) {
143 			stream_idx = i;
144 			break;
145 		}
146 	}
147 
148 	if (stream_idx != -1)
149 		stream = state->streams[stream_idx];
150 	else
151 		dm_output_to_console("%s: No stream using DIG(%d).\n", __func__, eng_id);
152 
153 	return stream;
154 }
155 
link_enc_cfg_init(struct dc * dc,struct dc_state * state)156 void link_enc_cfg_init(
157 		struct dc *dc,
158 		struct dc_state *state)
159 {
160 	int i;
161 
162 	for (i = 0; i < dc->res_pool->res_cap->num_dig_link_enc; i++) {
163 		if (dc->res_pool->link_encoders[i])
164 			state->res_ctx.link_enc_avail[i] = (enum engine_id) i;
165 		else
166 			state->res_ctx.link_enc_avail[i] = ENGINE_ID_UNKNOWN;
167 	}
168 }
169 
link_enc_cfg_link_encs_assign(struct dc * dc,struct dc_state * state,struct dc_stream_state * streams[],uint8_t stream_count)170 void link_enc_cfg_link_encs_assign(
171 		struct dc *dc,
172 		struct dc_state *state,
173 		struct dc_stream_state *streams[],
174 		uint8_t stream_count)
175 {
176 	enum engine_id eng_id = ENGINE_ID_UNKNOWN;
177 	int i;
178 
179 	/* Release DIG link encoder resources before running assignment algorithm. */
180 	for (i = 0; i < stream_count; i++)
181 		dc->res_pool->funcs->link_enc_unassign(state, streams[i]);
182 
183 	/* (a) Assign DIG link encoders to physical (unmappable) endpoints first. */
184 	for (i = 0; i < stream_count; i++) {
185 		struct dc_stream_state *stream = streams[i];
186 
187 		/* Skip stream if not supported by DIG link encoder. */
188 		if (!is_dig_link_enc_stream(stream))
189 			continue;
190 
191 		/* Physical endpoints have a fixed mapping to DIG link encoders. */
192 		if (!stream->link->is_dig_mapping_flexible) {
193 			eng_id = stream->link->eng_id;
194 			update_link_enc_assignment(state, stream, eng_id, true);
195 		}
196 	}
197 
198 	/* (b) Then assign encoders to mappable endpoints. */
199 	eng_id = ENGINE_ID_UNKNOWN;
200 
201 	for (i = 0; i < stream_count; i++) {
202 		struct dc_stream_state *stream = streams[i];
203 
204 		/* Skip stream if not supported by DIG link encoder. */
205 		if (!is_dig_link_enc_stream(stream))
206 			continue;
207 
208 		/* Mappable endpoints have a flexible mapping to DIG link encoders. */
209 		if (stream->link->is_dig_mapping_flexible) {
210 			eng_id = find_first_avail_link_enc(stream->ctx, state);
211 			update_link_enc_assignment(state, stream, eng_id, true);
212 		}
213 	}
214 }
215 
link_enc_cfg_link_enc_unassign(struct dc_state * state,struct dc_stream_state * stream)216 void link_enc_cfg_link_enc_unassign(
217 		struct dc_state *state,
218 		struct dc_stream_state *stream)
219 {
220 	enum engine_id eng_id = ENGINE_ID_UNKNOWN;
221 
222 	/* Only DIG link encoders. */
223 	if (!is_dig_link_enc_stream(stream))
224 		return;
225 
226 	if (stream->link_enc)
227 		eng_id = stream->link_enc->preferred_engine;
228 
229 	update_link_enc_assignment(state, stream, eng_id, false);
230 }
231 
link_enc_cfg_is_transmitter_mappable(struct dc_state * state,struct link_encoder * link_enc)232 bool link_enc_cfg_is_transmitter_mappable(
233 		struct dc_state *state,
234 		struct link_encoder *link_enc)
235 {
236 	bool is_mappable = false;
237 	enum engine_id eng_id = link_enc->preferred_engine;
238 	struct dc_stream_state *stream = get_stream_using_link_enc(state, eng_id);
239 
240 	if (stream)
241 		is_mappable = stream->link->is_dig_mapping_flexible;
242 
243 	return is_mappable;
244 }
245 
link_enc_cfg_get_link_using_link_enc(struct dc_state * state,enum engine_id eng_id)246 struct dc_link *link_enc_cfg_get_link_using_link_enc(
247 		struct dc_state *state,
248 		enum engine_id eng_id)
249 {
250 	struct dc_link *link = NULL;
251 	int stream_idx = -1;
252 	int i;
253 
254 	for (i = 0; i < state->stream_count; i++) {
255 		struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i];
256 
257 		if (assignment.valid && (assignment.eng_id == eng_id)) {
258 			stream_idx = i;
259 			break;
260 		}
261 	}
262 
263 	if (stream_idx != -1)
264 		link = state->streams[stream_idx]->link;
265 	else
266 		dm_output_to_console("%s: No link using DIG(%d).\n", __func__, eng_id);
267 
268 	return link;
269 }
270 
link_enc_cfg_get_link_enc_used_by_link(struct dc_state * state,const struct dc_link * link)271 struct link_encoder *link_enc_cfg_get_link_enc_used_by_link(
272 		struct dc_state *state,
273 		const struct dc_link *link)
274 {
275 	struct link_encoder *link_enc = NULL;
276 	struct display_endpoint_id ep_id;
277 	int stream_idx = -1;
278 	int i;
279 
280 	ep_id = (struct display_endpoint_id) {
281 		.link_id = link->link_id,
282 		.ep_type = link->ep_type};
283 
284 	for (i = 0; i < state->stream_count; i++) {
285 		struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i];
286 
287 		if (assignment.valid &&
288 				assignment.ep_id.link_id.id == ep_id.link_id.id &&
289 				assignment.ep_id.link_id.enum_id == ep_id.link_id.enum_id &&
290 				assignment.ep_id.link_id.type == ep_id.link_id.type &&
291 				assignment.ep_id.ep_type == ep_id.ep_type) {
292 			stream_idx = i;
293 			break;
294 		}
295 	}
296 
297 	if (stream_idx != -1)
298 		link_enc = state->streams[stream_idx]->link_enc;
299 
300 	return link_enc;
301 }
302 
link_enc_cfg_get_next_avail_link_enc(const struct dc * dc,const struct dc_state * state)303 struct link_encoder *link_enc_cfg_get_next_avail_link_enc(
304 	const struct dc *dc,
305 	const struct dc_state *state)
306 {
307 	struct link_encoder *link_enc = NULL;
308 	enum engine_id eng_id;
309 
310 	eng_id = find_first_avail_link_enc(dc->ctx, state);
311 	if (eng_id != ENGINE_ID_UNKNOWN)
312 		link_enc = dc->res_pool->link_encoders[eng_id - ENGINE_ID_DIGA];
313 
314 	return link_enc;
315 }
316