/* Copyright 2021 Advanced Micro Devices, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: AMD *
*/
/* Check whether stream is supported by DIG link encoders. */ staticbool is_dig_link_enc_stream(struct dc_stream_state *stream)
{ bool is_dig_stream = false; struct link_encoder *link_enc = NULL; int i;
/* Loop over created link encoder objects. */ if (stream) { for (i = 0; i < stream->ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) {
link_enc = stream->ctx->dc->res_pool->link_encoders[i];
/* Need to check link signal type rather than stream signal type which may not * yet match.
*/ if (link_enc && ((uint32_t)stream->link->connector_signal & link_enc->output_signals)) {
is_dig_stream = true; break;
}
}
} return is_dig_stream;
}
staticstruct link_enc_assignment get_assignment(struct dc *dc, int i)
{ struct link_enc_assignment assignment;
staticvoid remove_link_enc_assignment( struct dc_state *state, struct dc_stream_state *stream, enum engine_id eng_id)
{ int eng_idx; int i;
if (eng_id != ENGINE_ID_UNKNOWN) {
eng_idx = eng_id - ENGINE_ID_DIGA;
/* stream ptr of stream in dc_state used to update correct entry in * link_enc_assignments table.
*/ for (i = 0; i < MAX_PIPES; i++) { struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
if (assignment.valid && assignment.stream == stream) {
state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].valid = false; /* Only add link encoder back to availability pool if not being * used by any other stream (i.e. removing SST stream or last MST stream).
*/ if (get_stream_using_link_enc(state, eng_id) == NULL)
state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] = eng_id;
staticvoid add_link_enc_assignment( struct dc_state *state, struct dc_stream_state *stream, enum engine_id eng_id)
{ int eng_idx; int i;
if (eng_id != ENGINE_ID_UNKNOWN) {
eng_idx = eng_id - ENGINE_ID_DIGA;
/* stream ptr of stream in dc_state used to update correct entry in * link_enc_assignments table.
*/ for (i = 0; i < state->stream_count; i++) { if (stream == state->streams[i]) {
state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i] = (struct link_enc_assignment){
.valid = true,
.ep_id = (struct display_endpoint_id) {
.link_id = stream->link->link_id,
.ep_type = stream->link->ep_type},
.eng_id = eng_id,
.stream = stream};
dc_stream_retain(stream);
state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] = ENGINE_ID_UNKNOWN;
stream->link_enc = stream->ctx->dc->res_pool->link_encoders[eng_idx]; break;
}
}
/* Attempted to add an encoder assignment for a stream not in dc_state. */
ASSERT(i != state->stream_count);
}
}
/* Return first available DIG link encoder. */ staticenum engine_id find_first_avail_link_enc( conststruct dc_context *ctx, conststruct dc_state *state, enum engine_id eng_id_requested)
{ enum engine_id eng_id = ENGINE_ID_UNKNOWN; int i;
if (eng_id_requested != ENGINE_ID_UNKNOWN) {
for (i = 0; i < ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) {
eng_id = state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i]; if (eng_id == eng_id_requested) return eng_id;
}
}
eng_id = ENGINE_ID_UNKNOWN;
for (i = 0; i < ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) {
eng_id = state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i]; if (eng_id != ENGINE_ID_UNKNOWN) break;
}
return eng_id;
}
/* Check for availability of link encoder eng_id. */ staticbool is_avail_link_enc(struct dc_state *state, enum engine_id eng_id, struct dc_stream_state *stream)
{ bool is_avail = false; int eng_idx = eng_id - ENGINE_ID_DIGA;
/* An encoder is available if it is still in the availability pool. */ if (eng_id != ENGINE_ID_UNKNOWN && state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] != ENGINE_ID_UNKNOWN) {
is_avail = true;
} else { struct dc_stream_state *stream_assigned = NULL;
/* MST streams share the same link and should share the same encoder. * If a stream that has already been assigned a link encoder uses as the * same link as the stream checking for availability, it is an MST stream * and should use the same link encoder.
*/
stream_assigned = get_stream_using_link_enc(state, eng_id); if (stream_assigned && stream != stream_assigned && stream->link == stream_assigned->link)
is_avail = true;
}
return is_avail;
}
/* Test for display_endpoint_id equality. */ staticbool are_ep_ids_equal(struct display_endpoint_id *lhs, struct display_endpoint_id *rhs)
{ bool are_equal = false;
for (i = 0; i < MAX_PIPES; i++) { struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; if (assignment.eng_id == ENGINE_ID_UNKNOWN) continue;
/* Release DIG link encoder resources before running assignment algorithm. */ for (i = 0; i < dc->current_state->stream_count; i++)
dc->res_pool->funcs->link_enc_unassign(state, dc->current_state->streams[i]);
for (i = 0; i < MAX_PIPES; i++)
ASSERT(state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].valid == false);
/* (a) Assign DIG link encoders to physical (unmappable) endpoints first. */ for (i = 0; i < stream_count; i++) { struct dc_stream_state *stream = streams[i];
/* skip it if the link is mappable endpoint. */ if (stream->link->is_dig_mapping_flexible) continue;
/* Skip stream if not supported by DIG link encoder. */ if (!is_dig_link_enc_stream(stream)) continue;
/* Physical endpoints have a fixed mapping to DIG link encoders. */
eng_id = stream->link->eng_id;
add_link_enc_assignment(state, stream, eng_id);
}
/* (b) Retain previous assignments for mappable endpoints if encoders still available. */
eng_id = ENGINE_ID_UNKNOWN;
if (state != dc->current_state) { struct dc_state *prev_state = dc->current_state;
for (i = 0; i < stream_count; i++) { struct dc_stream_state *stream = state->streams[i];
/* Skip it if the link is NOT mappable endpoint. */ if (!stream->link->is_dig_mapping_flexible) continue;
/* Skip stream if not supported by DIG link encoder. */ if (!is_dig_link_enc_stream(stream)) continue;
/* (c) Then assign encoders to remaining mappable endpoints. */
eng_id = ENGINE_ID_UNKNOWN;
for (i = 0; i < stream_count; i++) { struct dc_stream_state *stream = streams[i]; struct link_encoder *link_enc = NULL;
/* Skip it if the link is NOT mappable endpoint. */ if (!stream->link->is_dig_mapping_flexible) continue;
/* Skip if encoder assignment retained in step (b) above. */ if (stream->link_enc) continue;
/* Skip stream if not supported by DIG link encoder. */ if (!is_dig_link_enc_stream(stream)) {
ASSERT(stream->link->is_dig_mapping_flexible != true); continue;
}
/* Mappable endpoints have a flexible mapping to DIG link encoders. */
/* For MST, multiple streams will share the same link / display * endpoint. These streams should use the same link encoder * assigned to that endpoint.
*/
link_enc = get_link_enc_used_by_link(state, stream->link); if (link_enc == NULL) {
/* Links supporting dynamically assigned link encoder will be assigned next * available encoder if one not already assigned.
*/ if (link->is_dig_mapping_flexible &&
link->dc->res_pool->funcs->link_encs_assign) {
link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link); if (link_enc == NULL)
link_enc = link_enc_cfg_get_next_avail_link_enc(
link->ctx->dc);
} else
link_enc = link->link_enc;
return link_enc;
}
struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream_current( struct dc *dc, conststruct dc_stream_state *stream)
{ struct link_encoder *link_enc = NULL; struct display_endpoint_id ep_id; int i;
bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id, struct dc_link *link)
{ bool is_avail = true; int i;
/* An encoder is not available if it has already been assigned to a different endpoint. */ for (i = 0; i < MAX_PIPES; i++) { struct link_enc_assignment assignment = get_assignment(dc, i); struct display_endpoint_id ep_id = (struct display_endpoint_id) {
.link_id = link->link_id,
.ep_type = link->ep_type};
bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state)
{ bool is_valid = false; bool valid_entries = true; bool valid_stream_ptrs = true; bool valid_uniqueness = true; bool valid_avail = true; bool valid_streams = true; int i, j;
uint8_t valid_count = 0;
uint8_t dig_stream_count = 0; int eng_ids_per_ep_id[MAX_PIPES] = {0}; int ep_ids_per_eng_id[MAX_PIPES] = {0}; int valid_bitmap = 0;
/* (1) No. valid entries same as stream count. */ for (i = 0; i < MAX_PIPES; i++) { struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
if (assignment.valid)
valid_count++;
if (is_dig_link_enc_stream(state->streams[i]))
dig_stream_count++;
} if (valid_count != dig_stream_count)
valid_entries = false;
/* (2) Matching stream ptrs. */ for (i = 0; i < MAX_PIPES; i++) { struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
if (assignment.valid) { if (assignment.stream != state->streams[i])
valid_stream_ptrs = false;
}
}
/* (3) Each endpoint assigned unique encoder. */ for (i = 0; i < MAX_PIPES; i++) { struct link_enc_assignment assignment_i = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
if (assignment_i.valid) { struct display_endpoint_id ep_id_i = assignment_i.ep_id;
/* (4) Assigned encoders not in available pool. */ for (i = 0; i < MAX_PIPES; i++) { struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
if (assignment.valid) { for (j = 0; j < dc->res_pool->res_cap->num_dig_link_enc; j++) { if (state->res_ctx.link_enc_cfg_ctx.link_enc_avail[j] == assignment.eng_id) {
valid_avail = false; break;
}
}
}
}
/* (5) All streams have valid link encoders. */ for (i = 0; i < state->stream_count; i++) { struct dc_stream_state *stream = state->streams[i];
void link_enc_cfg_set_transient_mode(struct dc *dc, struct dc_state *current_state, struct dc_state *new_state)
{ int i = 0; int num_transient_assignments = 0;
for (i = 0; i < MAX_PIPES; i++) { if (current_state->res_ctx.link_enc_cfg_ctx.transient_assignments[i].valid)
num_transient_assignments++;
}
/* Only enter transient mode if the new encoder assignments are valid. */ if (new_state->stream_count == num_transient_assignments) {
current_state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_TRANSIENT;
DC_LOG_DEBUG("%s: current_state(%p) mode(%d)\n", __func__, current_state, LINK_ENC_CFG_TRANSIENT);
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.