@@ -3339,11 +3339,8 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
link_enc = pipe_ctx->stream->link->link_enc;
config.phy_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
} else if (pipe_ctx->stream->link->dc->res_pool->funcs->link_encs_assign) {
- /* Use link encoder assignment from current DC state - which may differ from the DC state to be
- * committed - when updating PSP config.
- */
link_enc = link_enc_cfg_get_link_enc_used_by_stream(
- pipe_ctx->stream->link->dc->current_state,
+ pipe_ctx->stream->ctx->dc,
pipe_ctx->stream);
config.phy_idx = 0; /* Clear phy_idx for non-physical display endpoints. */
}
@@ -3379,6 +3376,12 @@ void core_link_enable_stream(
dc_is_virtual_signal(pipe_ctx->stream->signal))
return;
+ if (dc->res_pool->funcs->link_encs_assign && stream->link->ep_type != DISPLAY_ENDPOINT_PHY)
+ link_enc = link_enc_cfg_get_link_enc_used_by_stream(dc, stream);
+ else
+ link_enc = stream->link->link_enc;
+ ASSERT(link_enc);
+
if (!dc_is_virtual_signal(pipe_ctx->stream->signal)) {
if (link_enc)
link_enc->funcs->setup(
@@ -3849,14 +3852,14 @@ bool dc_link_is_fec_supported(const struct dc_link *link)
*/
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->dc->current_state, link);
+ 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->dc, link->dc->current_state);
+ link_enc = link_enc_cfg_get_next_avail_link_enc(link->ctx->dc);
} else
link_enc = link->link_enc;
ASSERT(link_enc);
- return (dc_is_dp_signal(link->connector_signal) &&
+ return (dc_is_dp_signal(link->connector_signal) && link_enc &&
link_enc->features.fec_supported &&
link->dpcd_caps.fec_cap.bits.FEC_CAPABLE &&
!IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment));
@@ -198,7 +198,7 @@ static enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *li
*/
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->dc->current_state, link);
+ link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
else
link_enc = link->link_enc;
ASSERT(link_enc);
@@ -1803,7 +1803,7 @@ bool perform_link_training_with_retries(
* link.
*/
if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign)
- link_enc = stream->link_enc;
+ link_enc = link_enc_cfg_get_link_enc_used_by_stream(link->ctx->dc, pipe_ctx->stream);
else
link_enc = link->link_enc;
@@ -2067,9 +2067,9 @@ bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_
*/
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->dc->current_state, link);
+ 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->dc, link->dc->current_state);
+ link_enc = link_enc_cfg_get_next_avail_link_enc(link->ctx->dc);
} else
link_enc = link->link_enc;
ASSERT(link_enc);
@@ -2095,9 +2095,9 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link)
*/
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->dc->current_state, link);
+ 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->dc, link->dc->current_state);
+ link_enc = link_enc_cfg_get_next_avail_link_enc(link->ctx->dc);
} else
link_enc = link->link_enc;
ASSERT(link_enc);
@@ -2267,7 +2267,13 @@ bool dp_verify_link_cap(
enum link_training_result status;
union hpd_irq_data irq_data;
- if (link->dc->debug.skip_detection_link_training) {
+ /* Accept reported capabilities if link supports flexible encoder mapping or encoder already in use. */
+ if (link->dc->debug.skip_detection_link_training ||
+ link->is_dig_mapping_flexible) {
+ link->verified_link_cap = *known_limit_link_setting;
+ return true;
+ } else if (link->link_enc && link->dc->res_pool->funcs->link_encs_assign &&
+ !link_enc_cfg_is_link_enc_avail(link->ctx->dc, link->link_enc->preferred_engine)) {
link->verified_link_cap = *known_limit_link_setting;
return true;
}
@@ -4740,7 +4746,7 @@ enum dc_status dp_set_fec_ready(struct dc_link *link, bool ready)
*/
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->dc->current_state, link);
+ link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
else
link_enc = link->link_enc;
ASSERT(link_enc);
@@ -4787,8 +4793,7 @@ void dp_set_fec_enable(struct dc_link *link, bool enable)
*/
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->dc->current_state, link);
+ link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
else
link_enc = link->link_enc;
ASSERT(link_enc);
@@ -63,6 +63,18 @@ static bool is_dig_link_enc_stream(struct dc_stream_state *stream)
return is_dig_stream;
}
+static struct link_enc_assignment get_assignment(struct dc *dc, int i)
+{
+ struct link_enc_assignment assignment;
+
+ if (dc->current_state->res_ctx.link_enc_cfg_ctx.mode == LINK_ENC_CFG_TRANSIENT)
+ assignment = dc->current_state->res_ctx.link_enc_cfg_ctx.transient_assignments[i];
+ else /* LINK_ENC_CFG_STEADY */
+ assignment = dc->current_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
+
+ return assignment;
+}
+
/* Return stream using DIG link encoder resource. NULL if unused. */
static struct dc_stream_state *get_stream_using_link_enc(
struct dc_state *state,
@@ -72,7 +84,7 @@ static struct dc_stream_state *get_stream_using_link_enc(
int i;
for (i = 0; i < state->stream_count; i++) {
- struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i];
+ struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
if ((assignment.valid == true) && (assignment.eng_id == eng_id)) {
stream = state->streams[i];
@@ -98,15 +110,15 @@ static void remove_link_enc_assignment(
* link_enc_assignments table.
*/
for (i = 0; i < MAX_PIPES; i++) {
- struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[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_assignments[i].valid = false;
+ 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_avail[eng_idx] = eng_id;
+ state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] = eng_id;
stream->link_enc = NULL;
break;
}
@@ -130,14 +142,14 @@ static void add_link_enc_assignment(
*/
for (i = 0; i < state->stream_count; i++) {
if (stream == state->streams[i]) {
- state->res_ctx.link_enc_assignments[i] = (struct link_enc_assignment){
+ 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};
- state->res_ctx.link_enc_avail[eng_idx] = ENGINE_ID_UNKNOWN;
+ 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;
}
@@ -157,7 +169,7 @@ static enum engine_id find_first_avail_link_enc(
int i;
for (i = 0; i < ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) {
- eng_id = state->res_ctx.link_enc_avail[i];
+ eng_id = state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i];
if (eng_id != ENGINE_ID_UNKNOWN)
break;
}
@@ -170,7 +182,7 @@ static bool is_avail_link_enc(struct dc_state *state, enum engine_id eng_id)
bool is_avail = false;
int eng_idx = eng_id - ENGINE_ID_DIGA;
- if (eng_id != ENGINE_ID_UNKNOWN && state->res_ctx.link_enc_avail[eng_idx] != ENGINE_ID_UNKNOWN)
+ if (eng_id != ENGINE_ID_UNKNOWN && state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] != ENGINE_ID_UNKNOWN)
is_avail = true;
return is_avail;
@@ -190,6 +202,28 @@ static bool are_ep_ids_equal(struct display_endpoint_id *lhs, struct display_end
return are_equal;
}
+static struct link_encoder *get_link_enc_used_by_link(
+ struct dc_state *state,
+ const struct dc_link *link)
+{
+ struct link_encoder *link_enc = NULL;
+ struct display_endpoint_id ep_id;
+ int i;
+
+ ep_id = (struct display_endpoint_id) {
+ .link_id = link->link_id,
+ .ep_type = link->ep_type};
+
+ for (i = 0; i < state->stream_count; i++) {
+ struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
+
+ if (assignment.valid == true && are_ep_ids_equal(&assignment.ep_id, &ep_id))
+ link_enc = link->dc->res_pool->link_encoders[assignment.eng_id - ENGINE_ID_DIGA];
+ }
+
+ return link_enc;
+}
+
void link_enc_cfg_init(
struct dc *dc,
struct dc_state *state)
@@ -198,10 +232,12 @@ void link_enc_cfg_init(
for (i = 0; i < dc->res_pool->res_cap->num_dig_link_enc; i++) {
if (dc->res_pool->link_encoders[i])
- state->res_ctx.link_enc_avail[i] = (enum engine_id) i;
+ state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i] = (enum engine_id) i;
else
- state->res_ctx.link_enc_avail[i] = ENGINE_ID_UNKNOWN;
+ state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i] = ENGINE_ID_UNKNOWN;
}
+
+ state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY;
}
void link_enc_cfg_link_encs_assign(
@@ -221,7 +257,7 @@ void link_enc_cfg_link_encs_assign(
dc->res_pool->funcs->link_enc_unassign(state, streams[i]);
for (i = 0; i < MAX_PIPES; i++)
- ASSERT(state->res_ctx.link_enc_assignments[i].valid == false);
+ 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++) {
@@ -258,8 +294,8 @@ void link_enc_cfg_link_encs_assign(
struct dc_stream_state *prev_stream = prev_state->streams[j];
if (stream == prev_stream && stream->link == prev_stream->link &&
- prev_state->res_ctx.link_enc_assignments[j].valid) {
- eng_id = prev_state->res_ctx.link_enc_assignments[j].eng_id;
+ prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].valid) {
+ eng_id = prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].eng_id;
if (is_avail_link_enc(state, eng_id))
add_link_enc_assignment(state, stream, eng_id);
}
@@ -291,7 +327,7 @@ void link_enc_cfg_link_encs_assign(
* endpoint. These streams should use the same link encoder
* assigned to that endpoint.
*/
- link_enc = link_enc_cfg_get_link_enc_used_by_link(state, stream->link);
+ link_enc = get_link_enc_used_by_link(state, stream->link);
if (link_enc == NULL)
eng_id = find_first_avail_link_enc(stream->ctx, state);
else
@@ -301,6 +337,15 @@ void link_enc_cfg_link_encs_assign(
}
link_enc_cfg_validate(dc, state);
+
+ /* Update transient assignments. */
+ for (i = 0; i < MAX_PIPES; i++) {
+ dc->current_state->res_ctx.link_enc_cfg_ctx.transient_assignments[i] =
+ state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
+ }
+
+ /* Current state mode will be set to steady once this state committed. */
+ state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY;
}
void link_enc_cfg_link_enc_unassign(
@@ -320,12 +365,12 @@ void link_enc_cfg_link_enc_unassign(
}
bool link_enc_cfg_is_transmitter_mappable(
- struct dc_state *state,
+ struct dc *dc,
struct link_encoder *link_enc)
{
bool is_mappable = false;
enum engine_id eng_id = link_enc->preferred_engine;
- struct dc_stream_state *stream = get_stream_using_link_enc(state, eng_id);
+ struct dc_stream_state *stream = link_enc_cfg_get_stream_using_link_enc(dc, eng_id);
if (stream)
is_mappable = stream->link->is_dig_mapping_flexible;
@@ -333,30 +378,43 @@ bool link_enc_cfg_is_transmitter_mappable(
return is_mappable;
}
-struct dc_link *link_enc_cfg_get_link_using_link_enc(
- struct dc_state *state,
+struct dc_stream_state *link_enc_cfg_get_stream_using_link_enc(
+ struct dc *dc,
enum engine_id eng_id)
{
- struct dc_link *link = NULL;
+ struct dc_stream_state *stream = NULL;
int i;
- for (i = 0; i < state->stream_count; i++) {
- struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i];
+ for (i = 0; i < MAX_PIPES; i++) {
+ struct link_enc_assignment assignment = get_assignment(dc, i);
if ((assignment.valid == true) && (assignment.eng_id == eng_id)) {
- link = state->streams[i]->link;
+ stream = assignment.stream;
break;
}
}
- if (link == NULL)
- dm_output_to_console("%s: No link using DIG(%d).\n", __func__, eng_id);
+ return stream;
+}
+struct dc_link *link_enc_cfg_get_link_using_link_enc(
+ struct dc *dc,
+ enum engine_id eng_id)
+{
+ struct dc_link *link = NULL;
+ struct dc_stream_state *stream = NULL;
+
+ stream = link_enc_cfg_get_stream_using_link_enc(dc, eng_id);
+
+ if (stream)
+ link = stream->link;
+
+ // dm_output_to_console("%s: No link using DIG(%d).\n", __func__, eng_id);
return link;
}
struct link_encoder *link_enc_cfg_get_link_enc_used_by_link(
- struct dc_state *state,
+ struct dc *dc,
const struct dc_link *link)
{
struct link_encoder *link_enc = NULL;
@@ -367,41 +425,74 @@ struct link_encoder *link_enc_cfg_get_link_enc_used_by_link(
.link_id = link->link_id,
.ep_type = link->ep_type};
- for (i = 0; i < state->stream_count; i++) {
- struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i];
+ for (i = 0; i < MAX_PIPES; i++) {
+ struct link_enc_assignment assignment = get_assignment(dc, i);
- if (assignment.valid == true && are_ep_ids_equal(&assignment.ep_id, &ep_id))
+ if (assignment.valid == true && are_ep_ids_equal(&assignment.ep_id, &ep_id)) {
link_enc = link->dc->res_pool->link_encoders[assignment.eng_id - ENGINE_ID_DIGA];
+ break;
+ }
}
return link_enc;
}
-struct link_encoder *link_enc_cfg_get_next_avail_link_enc(
- const struct dc *dc,
- const struct dc_state *state)
+struct link_encoder *link_enc_cfg_get_next_avail_link_enc(struct dc *dc)
{
struct link_encoder *link_enc = NULL;
- enum engine_id eng_id;
+ enum engine_id encs_assigned[MAX_DIG_LINK_ENCODERS];
+ int i;
+
+ for (i = 0; i < MAX_DIG_LINK_ENCODERS; i++)
+ encs_assigned[i] = ENGINE_ID_UNKNOWN;
- eng_id = find_first_avail_link_enc(dc->ctx, state);
- if (eng_id != ENGINE_ID_UNKNOWN)
- link_enc = dc->res_pool->link_encoders[eng_id - ENGINE_ID_DIGA];
+ /* Add assigned encoders to list. */
+ for (i = 0; i < MAX_PIPES; i++) {
+ struct link_enc_assignment assignment = get_assignment(dc, i);
+
+ if (assignment.valid)
+ encs_assigned[assignment.eng_id - ENGINE_ID_DIGA] = assignment.eng_id;
+ }
+
+ for (i = 0; i < dc->res_pool->res_cap->num_dig_link_enc; i++) {
+ if (encs_assigned[i] == ENGINE_ID_UNKNOWN) {
+ link_enc = dc->res_pool->link_encoders[i];
+ break;
+ }
+ }
return link_enc;
}
struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream(
- struct dc_state *state,
+ struct dc *dc,
const struct dc_stream_state *stream)
{
struct link_encoder *link_enc;
- link_enc = link_enc_cfg_get_link_enc_used_by_link(state, stream->link);
+ link_enc = link_enc_cfg_get_link_enc_used_by_link(dc, stream->link);
return link_enc;
}
+bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id)
+{
+ bool is_avail = true;
+ int i;
+
+ /* Add assigned encoders to list. */
+ for (i = 0; i < MAX_PIPES; i++) {
+ struct link_enc_assignment assignment = get_assignment(dc, i);
+
+ if (assignment.valid && assignment.eng_id == eng_id) {
+ is_avail = false;
+ break;
+ }
+ }
+
+ return is_avail;
+}
+
bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state)
{
bool is_valid = false;
@@ -418,7 +509,7 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state)
/* (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_assignments[i];
+ struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
if (assignment.valid)
valid_count++;
@@ -431,7 +522,7 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state)
/* (2) Matching stream ptrs. */
for (i = 0; i < MAX_PIPES; i++) {
- struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[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])
@@ -443,14 +534,15 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state)
/* (3) Each endpoint assigned unique encoder. */
for (i = 0; i < MAX_PIPES; i++) {
- struct link_enc_assignment assignment_i = state->res_ctx.link_enc_assignments[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;
eng_ids_per_ep_id[i]++;
for (j = 0; j < MAX_PIPES; j++) {
- struct link_enc_assignment assignment_j = state->res_ctx.link_enc_assignments[j];
+ struct link_enc_assignment assignment_j =
+ state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j];
if (j == i)
continue;
@@ -470,11 +562,11 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state)
/* (4) Assigned encoders not in available pool. */
for (i = 0; i < MAX_PIPES; i++) {
- struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[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_avail[j] == assignment.eng_id) {
+ if (state->res_ctx.link_enc_cfg_ctx.link_enc_avail[j] == assignment.eng_id) {
valid_avail = false;
break;
}
@@ -86,7 +86,7 @@ void dp_enable_link_phy(
/* Link should always be assigned encoder when en-/disabling. */
if (link->is_dig_mapping_flexible && dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link);
+ link_enc = link_enc_cfg_get_link_enc_used_by_link(dc, link);
else
link_enc = link->link_enc;
ASSERT(link_enc);
@@ -218,7 +218,7 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal)
/* Link should always be assigned encoder when en-/disabling. */
if (link->is_dig_mapping_flexible && dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link);
+ link_enc = link_enc_cfg_get_link_enc_used_by_link(dc, link);
else
link_enc = link->link_enc;
ASSERT(link_enc);
@@ -320,7 +320,7 @@ void dp_set_hw_test_pattern(
*/
if (link->is_dig_mapping_flexible &&
link->dc->res_pool->funcs->link_encs_assign)
- encoder = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link);
+ encoder = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
else
encoder = link->link_enc;
@@ -41,6 +41,7 @@
#include "set_mode_types.h"
#include "virtual/virtual_stream_encoder.h"
#include "dpcd_defs.h"
+#include "link_enc_cfg.h"
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/dce60_resource.h"
@@ -2727,8 +2728,18 @@ bool pipe_need_reprogram(
return true;
/* DIG link encoder resource assignment for stream changed. */
- if (pipe_ctx_old->stream->link_enc != pipe_ctx->stream->link_enc)
- return true;
+ if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
+ bool need_reprogram = false;
+ struct dc *dc = pipe_ctx_old->stream->ctx->dc;
+ enum link_enc_cfg_mode mode = dc->current_state->res_ctx.link_enc_cfg_ctx.mode;
+
+ dc->current_state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY;
+ if (link_enc_cfg_get_link_enc_used_by_stream(dc, pipe_ctx_old->stream) != pipe_ctx->stream->link_enc)
+ need_reprogram = true;
+ dc->current_state->res_ctx.link_enc_cfg_ctx.mode = mode;
+
+ return need_reprogram;
+ }
return false;
}
@@ -1181,6 +1181,13 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
dc->hwss.disable_audio_stream(pipe_ctx);
+ /* Link encoder may have been dynamically assigned to non-physical display endpoint. */
+ if (link->ep_type == DISPLAY_ENDPOINT_PHY)
+ link_enc = link->link_enc;
+ else if (dc->res_pool->funcs->link_encs_assign)
+ link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
+ ASSERT(link_enc);
+
if (link_enc)
link_enc->funcs->connect_dig_be_to_fe(
link->link_enc,
@@ -54,6 +54,7 @@
#include "hw_sequencer.h"
#include "inc/link_dpcd.h"
#include "dpcd_defs.h"
+#include "inc/link_enc_cfg.h"
#define DC_LOGGER_INIT(logger)
@@ -2380,9 +2381,10 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
if (link->is_dig_mapping_flexible &&
link->dc->res_pool->funcs->link_encs_assign)
- link_enc = pipe_ctx->stream->link_enc;
+ link_enc = link_enc_cfg_get_link_enc_used_by_stream(link->ctx->dc, pipe_ctx->stream);
else
link_enc = link->link_enc;
+ ASSERT(link_enc);
/* For MST, there are multiply stream go to only one link.
* connect DIG back_end to front_end while enable_stream and
@@ -1609,10 +1609,9 @@ static void get_pixel_clock_parameters(
*/
if (link->is_dig_mapping_flexible &&
link->dc->res_pool->funcs->link_encs_assign) {
- link_enc = link_enc_cfg_get_link_enc_used_by_stream(stream->link->dc->current_state, stream);
+ link_enc = link_enc_cfg_get_link_enc_used_by_stream(stream->ctx->dc, stream);
if (link_enc == NULL)
- link_enc = link_enc_cfg_get_next_avail_link_enc(stream->link->dc,
- stream->link->dc->current_state);
+ link_enc = link_enc_cfg_get_next_avail_link_enc(stream->ctx->dc);
} else
link_enc = stream->link->link_enc;
ASSERT(link_enc);
@@ -401,7 +401,7 @@ void dcn31_link_encoder_enable_dp_output(
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
/* Enable transmitter and encoder. */
- if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc->current_state, enc)) {
+ if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc, enc)) {
dcn20_link_encoder_enable_dp_output(enc, link_settings, clock_source);
@@ -446,7 +446,7 @@ void dcn31_link_encoder_enable_dp_mst_output(
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
/* Enable transmitter and encoder. */
- if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc->current_state, enc)) {
+ if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc, enc)) {
dcn10_link_encoder_enable_dp_mst_output(enc, link_settings, clock_source);
@@ -490,7 +490,7 @@ void dcn31_link_encoder_disable_output(
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
/* Disable transmitter and encoder. */
- if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc->current_state, enc)) {
+ if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc, enc)) {
dcn10_link_encoder_disable_output(enc, signal);
@@ -48,6 +48,7 @@
#include "dc_link_dp.h"
#include "inc/link_dpcd.h"
#include "dcn10/dcn10_hw_sequencer.h"
+#include "inc/link_enc_cfg.h"
#define DC_LOGGER_INIT(logger)
@@ -572,6 +573,9 @@ void dcn31_reset_hw_ctx_wrap(
old_clk->funcs->cs_power_down(old_clk);
}
}
+
+ /* New dc_state in the process of being applied to hardware. */
+ dc->current_state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_TRANSIENT;
}
bool dcn31_is_abm_supported(struct dc *dc,
@@ -378,6 +378,17 @@ struct pipe_ctx {
bool vtp_locked;
};
+/* Data used for dynamic link encoder assignment.
+ * Tracks current and future assignments; available link encoders;
+ * and mode of operation (whether to use current or future assignments).
+ */
+struct link_enc_cfg_context {
+ enum link_enc_cfg_mode mode;
+ struct link_enc_assignment link_enc_assignments[MAX_PIPES];
+ enum engine_id link_enc_avail[MAX_DIG_LINK_ENCODERS];
+ struct link_enc_assignment transient_assignments[MAX_PIPES];
+};
+
struct resource_context {
struct pipe_ctx pipe_ctx[MAX_PIPES];
bool is_stream_enc_acquired[MAX_PIPES * 2];
@@ -385,12 +396,7 @@ struct resource_context {
uint8_t clock_source_ref_count[MAX_CLOCK_SOURCES];
uint8_t dp_clock_source_ref_count;
bool is_dsc_acquired[MAX_PIPES];
- /* A table/array of encoder-to-link assignments. One entry per stream.
- * Indexed by stream index in dc_state.
- */
- struct link_enc_assignment link_enc_assignments[MAX_PIPES];
- /* List of available link encoders. Uses engine ID as encoder identifier. */
- enum engine_id link_enc_avail[MAX_DIG_LINK_ENCODERS];
+ struct link_enc_cfg_context link_enc_cfg_ctx;
#if defined(CONFIG_DRM_AMD_DC_DCN)
bool is_mpc_3dlut_acquired[MAX_PIPES];
#endif
@@ -211,4 +211,9 @@ struct link_enc_assignment {
struct dc_stream_state *stream;
};
+enum link_enc_cfg_mode {
+ LINK_ENC_CFG_STEADY, /* Normal operation - use current_state. */
+ LINK_ENC_CFG_TRANSIENT /* During commit state - use state to be committed. */
+};
+
#endif /* LINK_ENCODER_H_ */
@@ -70,29 +70,35 @@ void link_enc_cfg_link_enc_unassign(
* endpoint.
*/
bool link_enc_cfg_is_transmitter_mappable(
- struct dc_state *state,
+ struct dc *dc,
struct link_encoder *link_enc);
+/* Return stream using DIG link encoder resource. NULL if unused. */
+struct dc_stream_state *link_enc_cfg_get_stream_using_link_enc(
+ struct dc *dc,
+ enum engine_id eng_id);
+
/* Return link using DIG link encoder resource. NULL if unused. */
struct dc_link *link_enc_cfg_get_link_using_link_enc(
- struct dc_state *state,
+ struct dc *dc,
enum engine_id eng_id);
/* Return DIG link encoder used by link. NULL if unused. */
struct link_encoder *link_enc_cfg_get_link_enc_used_by_link(
- struct dc_state *state,
+ struct dc *dc,
const struct dc_link *link);
/* Return next available DIG link encoder. NULL if none available. */
-struct link_encoder *link_enc_cfg_get_next_avail_link_enc(
- const struct dc *dc,
- const struct dc_state *state);
+struct link_encoder *link_enc_cfg_get_next_avail_link_enc(struct dc *dc);
/* Return DIG link encoder used by stream. NULL if unused. */
struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream(
- struct dc_state *state,
+ struct dc *dc,
const struct dc_stream_state *stream);
+/* Return true if encoder available to use. */
+bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id);
+
/* Returns true if encoder assignments in supplied state pass validity checks. */
bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state);