aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/display/dc/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/core')
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c186
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_debug.c40
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link.c249
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c689
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c204
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_resource.c305
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stream.c27
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_surface.c3
9 files changed, 1146 insertions, 559 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index fa20201eef3a..5d1adeda4d90 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -23,6 +23,7 @@
*/
#include <linux/slab.h>
+#include <linux/mm.h>
#include "dm_services.h"
@@ -180,13 +181,25 @@ static bool create_links(
link = link_create(&link_init_params);
if (link) {
- if (dc->config.edp_not_connected &&
- link->connector_signal == SIGNAL_TYPE_EDP) {
- link_destroy(&link);
- } else {
+ bool should_destory_link = false;
+
+ if (link->connector_signal == SIGNAL_TYPE_EDP) {
+ if (dc->config.edp_not_connected)
+ should_destory_link = true;
+ else if (dc->debug.remove_disconnect_edp) {
+ enum dc_connection_type type;
+ dc_link_detect_sink(link, &type);
+ if (type == dc_connection_none)
+ should_destory_link = true;
+ }
+ }
+
+ if (!should_destory_link) {
dc->links[dc->link_count] = link;
link->dc = dc;
++dc->link_count;
+ } else {
+ link_destroy(&link);
}
}
}
@@ -278,7 +291,9 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
dc->hwss.set_drr(&pipe,
1,
adjust->v_total_min,
- adjust->v_total_max);
+ adjust->v_total_max,
+ adjust->v_total_mid,
+ adjust->v_total_mid_frame_num);
ret = true;
}
@@ -674,6 +689,11 @@ static bool construct(struct dc *dc,
if (!dc->clk_mgr)
goto fail;
+#ifdef CONFIG_DRM_AMD_DC_DCN2_1
+ if (dc->res_pool->funcs->update_bw_bounding_box)
+ dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params);
+#endif
+
/* Creation of current_state must occur after dc->dml
* is initialized in dc_create_resource_pool because
* on creation it copies the contents of dc->dml
@@ -947,7 +967,7 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc,
{
struct timing_generator *tg;
struct dc_link *link = sink->link;
- unsigned int inst;
+ unsigned int enc_inst, tg_inst;
/* Check for enabled DIG to identify enabled display */
if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
@@ -959,13 +979,22 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc,
* current implementation always map 1-to-1, so this code makes
* the same assumption and doesn't check OTG source.
*/
- inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1;
+ enc_inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
/* Instance should be within the range of the pool */
- if (inst >= dc->res_pool->pipe_count)
+ if (enc_inst >= dc->res_pool->pipe_count)
+ return false;
+
+ if (enc_inst >= dc->res_pool->stream_enc_count)
+ return false;
+
+ tg_inst = dc->res_pool->stream_enc[enc_inst]->funcs->dig_source_otg(
+ dc->res_pool->stream_enc[enc_inst]);
+
+ if (tg_inst >= dc->res_pool->timing_generator_count)
return false;
- tg = dc->res_pool->timing_generators[inst];
+ tg = dc->res_pool->timing_generators[tg_inst];
if (!tg->funcs->is_matching_timing)
return false;
@@ -978,10 +1007,11 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc,
dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
dc->res_pool->dp_clock_source,
- inst, &pix_clk_100hz);
+ tg_inst, &pix_clk_100hz);
if (crtc_timing->pix_clk_100hz != pix_clk_100hz)
return false;
+
}
return true;
@@ -1064,7 +1094,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
if (result != DC_OK)
return result;
- if (context->stream_count > 1) {
+ if (context->stream_count > 1 && !dc->debug.disable_timing_sync) {
enable_timing_multisync(dc, context);
program_timing_sync(dc, context);
}
@@ -1171,8 +1201,8 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
struct dc_state *dc_create_state(struct dc *dc)
{
- struct dc_state *context = kzalloc(sizeof(struct dc_state),
- GFP_KERNEL);
+ struct dc_state *context = kvzalloc(sizeof(struct dc_state),
+ GFP_KERNEL);
if (!context)
return NULL;
@@ -1192,11 +1222,11 @@ struct dc_state *dc_create_state(struct dc *dc)
struct dc_state *dc_copy_state(struct dc_state *src_ctx)
{
int i, j;
- struct dc_state *new_ctx = kmemdup(src_ctx,
- sizeof(struct dc_state), GFP_KERNEL);
+ struct dc_state *new_ctx = kvmalloc(sizeof(struct dc_state), GFP_KERNEL);
if (!new_ctx)
return NULL;
+ memcpy(new_ctx, src_ctx, sizeof(struct dc_state));
for (i = 0; i < MAX_PIPES; i++) {
struct pipe_ctx *cur_pipe = &new_ctx->res_ctx.pipe_ctx[i];
@@ -1207,6 +1237,12 @@ struct dc_state *dc_copy_state(struct dc_state *src_ctx)
if (cur_pipe->bottom_pipe)
cur_pipe->bottom_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
+ if (cur_pipe->prev_odm_pipe)
+ cur_pipe->prev_odm_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
+
+ if (cur_pipe->next_odm_pipe)
+ cur_pipe->next_odm_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];
+
}
for (i = 0; i < new_ctx->stream_count; i++) {
@@ -1230,7 +1266,7 @@ static void dc_state_free(struct kref *kref)
{
struct dc_state *context = container_of(kref, struct dc_state, refcount);
dc_resource_state_destruct(context);
- kfree(context);
+ kvfree(context);
}
void dc_release_state(struct dc_state *context)
@@ -1238,6 +1274,55 @@ void dc_release_state(struct dc_state *context)
kref_put(&context->refcount, dc_state_free);
}
+bool dc_set_generic_gpio_for_stereo(bool enable,
+ struct gpio_service *gpio_service)
+{
+ enum gpio_result gpio_result = GPIO_RESULT_NON_SPECIFIC_ERROR;
+ struct gpio_pin_info pin_info;
+ struct gpio *generic;
+ struct gpio_generic_mux_config *config = kzalloc(sizeof(struct gpio_generic_mux_config),
+ GFP_KERNEL);
+
+ if (!config)
+ return false;
+ pin_info = dal_gpio_get_generic_pin_info(gpio_service, GPIO_ID_GENERIC, 0);
+
+ if (pin_info.mask == 0xFFFFFFFF || pin_info.offset == 0xFFFFFFFF) {
+ kfree(config);
+ return false;
+ } else {
+ generic = dal_gpio_service_create_generic_mux(
+ gpio_service,
+ pin_info.offset,
+ pin_info.mask);
+ }
+
+ if (!generic) {
+ kfree(config);
+ return false;
+ }
+
+ gpio_result = dal_gpio_open(generic, GPIO_MODE_OUTPUT);
+
+ config->enable_output_from_mux = enable;
+ config->mux_select = GPIO_SIGNAL_SOURCE_PASS_THROUGH_STEREO_SYNC;
+
+ if (gpio_result == GPIO_RESULT_OK)
+ gpio_result = dal_mux_setup_config(generic, config);
+
+ if (gpio_result == GPIO_RESULT_OK) {
+ dal_gpio_close(generic);
+ dal_gpio_destroy_generic_mux(&generic);
+ kfree(config);
+ return true;
+ } else {
+ dal_gpio_close(generic);
+ dal_gpio_destroy_generic_mux(&generic);
+ kfree(config);
+ return false;
+ }
+}
+
static bool is_surface_in_context(
const struct dc_state *context,
const struct dc_plane_state *plane_state)
@@ -1304,8 +1389,8 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa
}
if (u->plane_info->dcc.enable != u->surface->dcc.enable
- || u->plane_info->dcc.grph.independent_64b_blks != u->surface->dcc.grph.independent_64b_blks
- || u->plane_info->dcc.grph.meta_pitch != u->surface->dcc.grph.meta_pitch) {
+ || u->plane_info->dcc.independent_64b_blks != u->surface->dcc.independent_64b_blks
+ || u->plane_info->dcc.meta_pitch != u->surface->dcc.meta_pitch) {
update_flags->bits.dcc_change = 1;
elevate_update_type(&update_type, UPDATE_TYPE_MED);
}
@@ -1319,9 +1404,9 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa
elevate_update_type(&update_type, UPDATE_TYPE_FULL);
}
- if (u->plane_info->plane_size.grph.surface_pitch != u->surface->plane_size.grph.surface_pitch
- || u->plane_info->plane_size.video.luma_pitch != u->surface->plane_size.video.luma_pitch
- || u->plane_info->plane_size.video.chroma_pitch != u->surface->plane_size.video.chroma_pitch) {
+ if (u->plane_info->plane_size.surface_pitch != u->surface->plane_size.surface_pitch
+ || u->plane_info->plane_size.surface_pitch != u->surface->plane_size.surface_pitch
+ || u->plane_info->plane_size.chroma_pitch != u->surface->plane_size.chroma_pitch) {
update_flags->bits.plane_size_change = 1;
elevate_update_type(&update_type, UPDATE_TYPE_MED);
}
@@ -1541,6 +1626,9 @@ enum surface_update_type dc_check_update_surfaces_for_stream(
for (i = 0; i < surface_count; i++)
updates[i].surface->update_flags.raw = 0xFFFFFFFF;
+ if (type == UPDATE_TYPE_FAST && memcmp(&dc->current_state->bw_ctx.bw.dcn.clk, &dc->clk_mgr->clks, offsetof(struct dc_clocks, prev_p_state_change_support)) != 0)
+ dc->optimized_required = true;
+
return type;
}
@@ -1617,6 +1705,8 @@ static void copy_surface_update_to_plane(
srf_update->plane_info->dcc;
surface->sdr_white_level =
srf_update->plane_info->sdr_white_level;
+ surface->layer_index =
+ srf_update->plane_info->layer_index;
}
if (srf_update->gamma &&
@@ -1783,9 +1873,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
for (j = 0; j < dc->res_pool->pipe_count; j++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
- if (!pipe_ctx->top_pipe &&
- pipe_ctx->stream &&
- pipe_ctx->stream == stream) {
+ if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->stream == stream) {
if (stream_update->periodic_interrupt0 &&
dc->hwss.setup_periodic_interrupt)
@@ -1811,7 +1899,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
if (stream_update->dither_option) {
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
- struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
+ struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
#endif
resource_build_bit_depth_reduction_params(pipe_ctx->stream,
&pipe_ctx->stream->bit_depth_params);
@@ -1819,10 +1907,12 @@ static void commit_planes_do_stream_update(struct dc *dc,
&stream->bit_depth_params,
&stream->clamping);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
- if (odm_pipe)
+ while (odm_pipe) {
odm_pipe->stream_res.opp->funcs->opp_program_fmt(odm_pipe->stream_res.opp,
&stream->bit_depth_params,
&stream->clamping);
+ odm_pipe = odm_pipe->next_odm_pipe;
+ }
#endif
}
@@ -1839,13 +1929,21 @@ static void commit_planes_do_stream_update(struct dc *dc,
if (stream_update->dpms_off) {
dc->hwss.pipe_control_lock(dc, pipe_ctx, true);
+
if (*stream_update->dpms_off) {
- core_link_disable_stream(pipe_ctx, KEEP_ACQUIRED_RESOURCE);
+ core_link_disable_stream(pipe_ctx);
+ /* for dpms, keep acquired resources*/
+ if (pipe_ctx->stream_res.audio && !dc->debug.az_endpoint_mute_only)
+ pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
+
dc->hwss.optimize_bandwidth(dc, dc->current_state);
} else {
- dc->hwss.prepare_bandwidth(dc, dc->current_state);
+ if (!dc->optimize_seamless_boot)
+ dc->hwss.prepare_bandwidth(dc, dc->current_state);
+
core_link_enable_stream(dc->current_state, pipe_ctx);
}
+
dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
}
@@ -1935,6 +2033,7 @@ static void commit_planes_for_stream(struct dc *dc,
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
if (!pipe_ctx->top_pipe &&
+ !pipe_ctx->prev_odm_pipe &&
pipe_ctx->stream &&
pipe_ctx->stream == stream) {
struct dc_stream_status *stream_status = NULL;
@@ -2049,7 +2148,7 @@ void dc_commit_updates_for_stream(struct dc *dc,
enum surface_update_type update_type;
struct dc_state *context;
struct dc_context *dc_ctx = dc->ctx;
- int i, j;
+ int i;
stream_status = dc_stream_get_status(stream);
context = dc->current_state;
@@ -2087,16 +2186,6 @@ void dc_commit_updates_for_stream(struct dc *dc,
copy_surface_update_to_plane(surface, &srf_updates[i]);
- if (update_type >= UPDATE_TYPE_MED) {
- for (j = 0; j < dc->res_pool->pipe_count; j++) {
- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
-
- if (pipe_ctx->plane_state != surface)
- continue;
-
- resource_build_scaling_params(pipe_ctx);
- }
- }
}
copy_stream_update_to_stream(dc, context, stream, stream_update);
@@ -2186,6 +2275,14 @@ void dc_set_power_state(
dc_resource_state_construct(dc, dc->current_state);
dc->hwss.init_hw(dc);
+
+#ifdef CONFIG_DRM_AMD_DC_DCN2_0
+ if (dc->hwss.init_sys_ctx != NULL &&
+ dc->vm_pa_config.valid) {
+ dc->hwss.init_sys_ctx(dc->hwseq, dc, &dc->vm_pa_config);
+ }
+#endif
+
break;
default:
ASSERT(dc->current_state->stream_count == 0);
@@ -2386,3 +2483,14 @@ void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx
info->fClock = (unsigned int)state->bw_ctx.bw.dcn.clk.fclk_khz;
info->phyClock = (unsigned int)state->bw_ctx.bw.dcn.clk.phyclk_khz;
}
+enum dc_status dc_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, uint32_t stepping)
+{
+ if (dc->hwss.set_clock)
+ return dc->hwss.set_clock(dc, clock_type, clk_khz, stepping);
+ return DC_ERROR_UNEXPECTED;
+}
+void dc_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_config *clock_cfg)
+{
+ if (dc->hwss.get_clock)
+ dc->hwss.get_clock(dc, clock_type, clock_cfg);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
index 5903e7822f98..b9227d5de3a3 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
@@ -115,16 +115,16 @@ void pre_surface_trace(
plane_state->clip_rect.height);
SURFACE_TRACE(
- "plane_state->plane_size.grph.surface_size.x = %d;\n"
- "plane_state->plane_size.grph.surface_size.y = %d;\n"
- "plane_state->plane_size.grph.surface_size.width = %d;\n"
- "plane_state->plane_size.grph.surface_size.height = %d;\n"
- "plane_state->plane_size.grph.surface_pitch = %d;\n",
- plane_state->plane_size.grph.surface_size.x,
- plane_state->plane_size.grph.surface_size.y,
- plane_state->plane_size.grph.surface_size.width,
- plane_state->plane_size.grph.surface_size.height,
- plane_state->plane_size.grph.surface_pitch);
+ "plane_state->plane_size.surface_size.x = %d;\n"
+ "plane_state->plane_size.surface_size.y = %d;\n"
+ "plane_state->plane_size.surface_size.width = %d;\n"
+ "plane_state->plane_size.surface_size.height = %d;\n"
+ "plane_state->plane_size.surface_pitch = %d;\n",
+ plane_state->plane_size.surface_size.x,
+ plane_state->plane_size.surface_size.y,
+ plane_state->plane_size.surface_size.width,
+ plane_state->plane_size.surface_size.height,
+ plane_state->plane_size.surface_pitch);
SURFACE_TRACE(
@@ -202,20 +202,20 @@ void update_surface_trace(
SURFACE_TRACE(
"plane_info->color_space = %d;\n"
"plane_info->format = %d;\n"
- "plane_info->plane_size.grph.surface_pitch = %d;\n"
- "plane_info->plane_size.grph.surface_size.height = %d;\n"
- "plane_info->plane_size.grph.surface_size.width = %d;\n"
- "plane_info->plane_size.grph.surface_size.x = %d;\n"
- "plane_info->plane_size.grph.surface_size.y = %d;\n"
+ "plane_info->plane_size.surface_pitch = %d;\n"
+ "plane_info->plane_size.surface_size.height = %d;\n"
+ "plane_info->plane_size.surface_size.width = %d;\n"
+ "plane_info->plane_size.surface_size.x = %d;\n"
+ "plane_info->plane_size.surface_size.y = %d;\n"
"plane_info->rotation = %d;\n"
"plane_info->stereo_format = %d;\n",
update->plane_info->color_space,
update->plane_info->format,
- update->plane_info->plane_size.grph.surface_pitch,
- update->plane_info->plane_size.grph.surface_size.height,
- update->plane_info->plane_size.grph.surface_size.width,
- update->plane_info->plane_size.grph.surface_size.x,
- update->plane_info->plane_size.grph.surface_size.y,
+ update->plane_info->plane_size.surface_pitch,
+ update->plane_info->plane_size.surface_size.height,
+ update->plane_info->plane_size.surface_size.width,
+ update->plane_info->plane_size.surface_size.x,
+ update->plane_info->plane_size.surface_size.y,
update->plane_info->rotation,
update->plane_info->stereo_format);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index 355b4ba12796..ca20b150afcc 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -45,10 +45,6 @@
#include "dpcd_defs.h"
#include "dmcu.h"
#include "hw/clk_mgr.h"
-#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
-#include "resource.h"
-#endif
-#include "hw/clk_mgr.h"
#define DC_LOGGER_INIT(logger)
@@ -684,6 +680,56 @@ static bool is_same_edid(struct dc_edid *old_edid, struct dc_edid *new_edid)
return (memcmp(old_edid->raw_edid, new_edid->raw_edid, new_edid->length) == 0);
}
+bool wait_for_alt_mode(struct dc_link *link)
+{
+
+ /**
+ * something is terribly wrong if time out is > 200ms. (5Hz)
+ * 500 microseconds * 400 tries us 200 ms
+ **/
+ unsigned int sleep_time_in_microseconds = 500;
+ unsigned int tries_allowed = 400;
+ bool is_in_alt_mode;
+ unsigned long long enter_timestamp;
+ unsigned long long finish_timestamp;
+ unsigned long long time_taken_in_ns;
+ int tries_taken;
+
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ if (link->link_enc->funcs->is_in_alt_mode == NULL)
+ return true;
+
+ is_in_alt_mode = link->link_enc->funcs->is_in_alt_mode(link->link_enc);
+ DC_LOG_WARNING("DP Alt mode state on HPD: %d\n", is_in_alt_mode);
+
+ if (is_in_alt_mode)
+ return true;
+
+ enter_timestamp = dm_get_timestamp(link->ctx);
+
+ for (tries_taken = 0; tries_taken < tries_allowed; tries_taken++) {
+ udelay(sleep_time_in_microseconds);
+ /* ask the link if alt mode is enabled, if so return ok */
+ if (link->link_enc->funcs->is_in_alt_mode(link->link_enc)) {
+
+ finish_timestamp = dm_get_timestamp(link->ctx);
+ time_taken_in_ns = dm_get_elapse_time_in_ns(
+ link->ctx, finish_timestamp, enter_timestamp);
+ DC_LOG_WARNING("Alt mode entered finished after %llu ms\n",
+ div_u64(time_taken_in_ns, 1000000));
+ return true;
+ }
+
+ }
+ finish_timestamp = dm_get_timestamp(link->ctx);
+ time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp,
+ enter_timestamp);
+ DC_LOG_WARNING("Alt mode has timed out after %llu ms\n",
+ div_u64(time_taken_in_ns, 1000000));
+ return false;
+}
+
/**
* dc_link_detect() - Detect if a sink is attached to a given link
*
@@ -772,6 +818,15 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
}
case SIGNAL_TYPE_DISPLAY_PORT: {
+ /* wa HPD high coming too early*/
+ if (link->link_enc->features.flags.bits.DP_IS_USB_C == 1) {
+
+ /* if alt mode times out, return false */
+ if (wait_for_alt_mode(link) == false) {
+ return false;
+ }
+ }
+
if (!detect_dp(
link,
&sink_caps,
@@ -795,16 +850,9 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
dc_sink_release(prev_sink);
} else {
/* Empty dongle plug in */
- for (i = 0; i < LINK_TRAINING_MAX_VERIFY_RETRY; i++) {
- int fail_count = 0;
-
- dp_verify_link_cap(link,
- &link->reported_link_cap,
- &fail_count);
-
- if (fail_count == 0)
- break;
- }
+ dp_verify_link_cap_with_retries(link,
+ &link->reported_link_cap,
+ LINK_TRAINING_MAX_VERIFY_RETRY);
}
return true;
}
@@ -908,17 +956,9 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
*/
/* deal with non-mst cases */
- for (i = 0; i < LINK_TRAINING_MAX_VERIFY_RETRY; i++) {
- int fail_count = 0;
-
- dp_verify_link_cap(link,
- &link->reported_link_cap,
- &fail_count);
-
- if (fail_count == 0)
- break;
- }
-
+ dp_verify_link_cap_with_retries(link,
+ &link->reported_link_cap,
+ LINK_TRAINING_MAX_VERIFY_RETRY);
} else {
// If edid is the same, then discard new sink and revert back to original sink
if (same_edid) {
@@ -1188,6 +1228,9 @@ static bool construct(
link->ctx = dc_ctx;
link->link_index = init_params->link_index;
+ memset(&link->preferred_training_settings, 0, sizeof(struct dc_link_training_overrides));
+ memset(&link->preferred_link_setting, 0, sizeof(struct dc_link_settings));
+
link->link_id = bios->funcs->get_connector_id(bios, init_params->connector_index);
if (link->link_id.type != OBJECT_TYPE_CONNECTOR) {
@@ -1384,57 +1427,6 @@ void link_destroy(struct dc_link **link)
*link = NULL;
}
-static void dpcd_configure_panel_mode(
- struct dc_link *link,
- enum dp_panel_mode panel_mode)
-{
- union dpcd_edp_config edp_config_set;
- bool panel_mode_edp = false;
- DC_LOGGER_INIT(link->ctx->logger);
-
- memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config));
-
- if (DP_PANEL_MODE_DEFAULT != panel_mode) {
-
- switch (panel_mode) {
- case DP_PANEL_MODE_EDP:
- case DP_PANEL_MODE_SPECIAL:
- panel_mode_edp = true;
- break;
-
- default:
- break;
- }
-
- /*set edp panel mode in receiver*/
- core_link_read_dpcd(
- link,
- DP_EDP_CONFIGURATION_SET,
- &edp_config_set.raw,
- sizeof(edp_config_set.raw));
-
- if (edp_config_set.bits.PANEL_MODE_EDP
- != panel_mode_edp) {
- enum ddc_result result = DDC_RESULT_UNKNOWN;
-
- edp_config_set.bits.PANEL_MODE_EDP =
- panel_mode_edp;
- result = core_link_write_dpcd(
- link,
- DP_EDP_CONFIGURATION_SET,
- &edp_config_set.raw,
- sizeof(edp_config_set.raw));
-
- ASSERT(result == DDC_RESULT_SUCESSFULL);
- }
- }
- DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d "
- "eDP panel mode enabled: %d \n",
- link->link_index,
- link->dpcd_caps.panel_mode_edp,
- panel_mode_edp);
-}
-
static void enable_stream_features(struct pipe_ctx *pipe_ctx)
{
struct dc_stream_state *stream = pipe_ctx->stream;
@@ -1466,6 +1458,19 @@ static enum dc_status enable_link_dp(
struct dc_link *link = stream->link;
struct dc_link_settings link_settings = {0};
enum dp_panel_mode panel_mode;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ bool fec_enable;
+#endif
+ int i;
+ bool apply_seamless_boot_optimization = false;
+
+ // check for seamless boot
+ for (i = 0; i < state->stream_count; i++) {
+ if (state->streams[i]->apply_seamless_boot_optimization) {
+ apply_seamless_boot_optimization = true;
+ break;
+ }
+ }
/* get link settings for video mode timing */
decide_link_settings(stream, &link_settings);
@@ -1487,7 +1492,8 @@ static enum dc_status enable_link_dp(
pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
- state->clk_mgr->funcs->update_clocks(state->clk_mgr, state, false);
+ if (!apply_seamless_boot_optimization)
+ state->clk_mgr->funcs->update_clocks(state->clk_mgr, state, false);
dp_enable_link_phy(
link,
@@ -1502,18 +1508,19 @@ static enum dc_status enable_link_dp(
}
panel_mode = dp_get_panel_mode(link);
- dpcd_configure_panel_mode(link, panel_mode);
+ dp_set_panel_mode(link, panel_mode);
skip_video_pattern = true;
if (link_settings.link_rate == LINK_RATE_LOW)
skip_video_pattern = false;
-#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
- dp_set_fec_ready(link, true);
-#endif
+ if (link->aux_access_disabled) {
+ dc_link_dp_perform_link_training_skip_aux(link, &link_settings);
- if (perform_link_training_with_retries(
+ link->cur_link_settings = link_settings;
+ status = DC_OK;
+ } else if (perform_link_training_with_retries(
link,
&link_settings,
skip_video_pattern,
@@ -1525,7 +1532,12 @@ static enum dc_status enable_link_dp(
status = DC_FAIL_DP_LINK_TRAINING;
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
- dp_set_fec_enable(link, true);
+ if (link->preferred_training_settings.fec_enable != NULL)
+ fec_enable = *link->preferred_training_settings.fec_enable;
+ else
+ fec_enable = true;
+
+ dp_set_fec_enable(link, fec_enable);
#endif
return status;
}
@@ -2755,21 +2767,27 @@ void core_link_enable_stream(
CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
COLOR_DEPTH_UNDEFINED);
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ if (pipe_ctx->stream->timing.flags.DSC) {
+ if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
+ dc_is_virtual_signal(pipe_ctx->stream->signal))
+ dp_set_dsc_enable(pipe_ctx, true);
+ }
+#endif
core_dc->hwss.enable_stream(pipe_ctx);
- if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
- allocate_mst_payload(pipe_ctx);
-
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
- if (pipe_ctx->stream->timing.flags.DSC &&
- (dc_is_dp_signal(pipe_ctx->stream->signal) ||
- dc_is_virtual_signal(pipe_ctx->stream->signal))) {
- dp_set_dsc_enable(pipe_ctx, true);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(
- pipe_ctx->stream_res.tg,
- CRTC_STATE_VBLANK);
+ /* Set DPS PPS SDP (AKA "info frames") */
+ if (pipe_ctx->stream->timing.flags.DSC) {
+ if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
+ dc_is_virtual_signal(pipe_ctx->stream->signal))
+ dp_set_dsc_pps_sdp(pipe_ctx, true);
}
#endif
+
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
+ allocate_mst_payload(pipe_ctx);
+
core_dc->hwss.unblank_stream(pipe_ctx,
&pipe_ctx->stream->link->cur_link_settings);
@@ -2786,7 +2804,7 @@ void core_link_enable_stream(
#endif
}
-void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option)
+void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
{
struct dc *core_dc = pipe_ctx->stream->ctx->dc;
struct dc_stream_state *stream = pipe_ctx->stream;
@@ -2821,13 +2839,13 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option)
write_i2c_redriver_setting(pipe_ctx, false);
}
}
- core_dc->hwss.disable_stream(pipe_ctx, option);
+ core_dc->hwss.disable_stream(pipe_ctx);
disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal);
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
- if (pipe_ctx->stream->timing.flags.DSC &&
- dc_is_dp_signal(pipe_ctx->stream->signal)) {
- dp_set_dsc_enable(pipe_ctx, false);
+ if (pipe_ctx->stream->timing.flags.DSC) {
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ dp_set_dsc_enable(pipe_ctx, false);
}
#endif
}
@@ -2836,7 +2854,7 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
{
struct dc *core_dc = pipe_ctx->stream->ctx->dc;
- if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A)
+ if (!dc_is_hdmi_signal(pipe_ctx->stream->signal))
return;
core_dc->hwss.set_avmute(pipe_ctx, enable);
@@ -2999,8 +3017,10 @@ void dc_link_set_preferred_link_settings(struct dc *dc,
for (i = 0; i < MAX_PIPES; i++) {
pipe = &dc->current_state->res_ctx.pipe_ctx[i];
if (pipe->stream && pipe->stream->link) {
- if (pipe->stream->link == link)
+ if (pipe->stream->link == link) {
+ link_stream = pipe->stream;
break;
+ }
}
}
@@ -3008,20 +3028,40 @@ void dc_link_set_preferred_link_settings(struct dc *dc,
if (i == MAX_PIPES)
return;
- link_stream = link->dc->current_state->res_ctx.pipe_ctx[i].stream;
-
/* Cannot retrain link if backend is off */
if (link_stream->dpms_off)
return;
- if (link_stream)
- decide_link_settings(link_stream, &store_settings);
+ decide_link_settings(link_stream, &store_settings);
if ((store_settings.lane_count != LANE_COUNT_UNKNOWN) &&
(store_settings.link_rate != LINK_RATE_UNKNOWN))
dp_retrain_link_dp_test(link, &store_settings, false);
}
+void dc_link_set_preferred_training_settings(struct dc *dc,
+ struct dc_link_settings *link_setting,
+ struct dc_link_training_overrides *lt_overrides,
+ struct dc_link *link,
+ bool skip_immediate_retrain)
+{
+ if (lt_overrides != NULL)
+ link->preferred_training_settings = *lt_overrides;
+ else
+ memset(&link->preferred_training_settings, 0, sizeof(link->preferred_training_settings));
+
+ if (link_setting != NULL) {
+ link->preferred_link_setting = *link_setting;
+ } else {
+ link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN;
+ link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
+ }
+
+ /* Retrain now, or wait until next stream update to apply */
+ if (skip_immediate_retrain == false)
+ dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link);
+}
+
void dc_link_enable_hpd(const struct dc_link *link)
{
dc_link_dp_enable_hpd(link);
@@ -3032,7 +3072,6 @@ void dc_link_disable_hpd(const struct dc_link *link)
dc_link_dp_disable_hpd(link);
}
-
void dc_link_set_test_pattern(struct dc_link *link,
enum dp_test_pattern test_pattern,
const struct link_training_settings *p_link_settings,
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
index e6da8506128b..505967b48e14 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
@@ -294,7 +294,7 @@ static uint32_t defer_delay_converter_wa(
{
struct dc_link *link = ddc->link;
- if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_4 &&
+ if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 &&
!memcmp(link->dpcd_caps.branch_dev_name,
DP_DVI_CONVERTER_ID_4,
sizeof(link->dpcd_caps.branch_dev_name)))
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
index 2c7aaed907b9..f5742719b5d9 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
@@ -49,7 +49,7 @@ static struct dc_link_settings get_common_supported_link_settings(
struct dc_link_settings link_setting_a,
struct dc_link_settings link_setting_b);
-static void wait_for_training_aux_rd_interval(
+static uint32_t get_training_aux_rd_interval(
struct dc_link *link,
uint32_t default_wait_in_micro_secs)
{
@@ -68,15 +68,21 @@ static void wait_for_training_aux_rd_interval(
sizeof(training_rd_interval));
if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
- default_wait_in_micro_secs =
- training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
+ default_wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
}
- udelay(default_wait_in_micro_secs);
+ return default_wait_in_micro_secs;
+}
+
+static void wait_for_training_aux_rd_interval(
+ struct dc_link *link,
+ uint32_t wait_in_micro_secs)
+{
+ udelay(wait_in_micro_secs);
DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
__func__,
- default_wait_in_micro_secs);
+ wait_in_micro_secs);
}
static void dpcd_set_training_pattern(
@@ -95,27 +101,27 @@ static void dpcd_set_training_pattern(
dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
}
-static enum hw_dp_training_pattern get_supported_tp(struct dc_link *link)
+static enum dc_dp_training_pattern get_supported_tp(struct dc_link *link)
{
- enum hw_dp_training_pattern highest_tp = HW_DP_TRAINING_PATTERN_2;
+ enum dc_dp_training_pattern highest_tp = DP_TRAINING_PATTERN_SEQUENCE_2;
struct encoder_feature_support *features = &link->link_enc->features;
struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
if (features->flags.bits.IS_TPS3_CAPABLE)
- highest_tp = HW_DP_TRAINING_PATTERN_3;
+ highest_tp = DP_TRAINING_PATTERN_SEQUENCE_3;
if (features->flags.bits.IS_TPS4_CAPABLE)
- highest_tp = HW_DP_TRAINING_PATTERN_4;
+ highest_tp = DP_TRAINING_PATTERN_SEQUENCE_4;
if (dpcd_caps->max_down_spread.bits.TPS4_SUPPORTED &&
- highest_tp >= HW_DP_TRAINING_PATTERN_4)
- return HW_DP_TRAINING_PATTERN_4;
+ highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_4)
+ return DP_TRAINING_PATTERN_SEQUENCE_4;
if (dpcd_caps->max_ln_count.bits.TPS3_SUPPORTED &&
- highest_tp >= HW_DP_TRAINING_PATTERN_3)
- return HW_DP_TRAINING_PATTERN_3;
+ highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_3)
+ return DP_TRAINING_PATTERN_SEQUENCE_3;
- return HW_DP_TRAINING_PATTERN_2;
+ return DP_TRAINING_PATTERN_SEQUENCE_2;
}
static void dpcd_set_link_settings(
@@ -126,7 +132,7 @@ static void dpcd_set_link_settings(
union down_spread_ctrl downspread = { {0} };
union lane_count_set lane_count_set = { {0} };
- enum hw_dp_training_pattern hw_tr_pattern;
+ enum dc_dp_training_pattern dp_tr_pattern;
downspread.raw = (uint8_t)
(lt_settings->link_settings.link_spread);
@@ -134,21 +140,21 @@ static void dpcd_set_link_settings(
lane_count_set.bits.LANE_COUNT_SET =
lt_settings->link_settings.lane_count;
- lane_count_set.bits.ENHANCED_FRAMING = 1;
-
+ lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
- hw_tr_pattern = get_supported_tp(link);
- if (hw_tr_pattern != HW_DP_TRAINING_PATTERN_4) {
+ dp_tr_pattern = get_supported_tp(link);
+
+ if (dp_tr_pattern != DP_TRAINING_PATTERN_SEQUENCE_4) {
lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
}
core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
- &downspread.raw, sizeof(downspread));
+ &downspread.raw, sizeof(downspread));
core_link_write_dpcd(link, DP_LANE_COUNT_SET,
- &lane_count_set.raw, 1);
+ &lane_count_set.raw, 1);
if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 &&
lt_settings->link_settings.use_link_rate_set == true) {
@@ -162,46 +168,47 @@ static void dpcd_set_link_settings(
}
if (rate) {
- DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n",
+ DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
__func__,
DP_LINK_BW_SET,
lt_settings->link_settings.link_rate,
DP_LANE_COUNT_SET,
lt_settings->link_settings.lane_count,
+ lt_settings->enhanced_framing,
DP_DOWNSPREAD_CTRL,
lt_settings->link_settings.link_spread);
} else {
- DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x\n %x spread = %x\n",
+ DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
__func__,
DP_LINK_RATE_SET,
lt_settings->link_settings.link_rate_set,
DP_LANE_COUNT_SET,
lt_settings->link_settings.lane_count,
+ lt_settings->enhanced_framing,
DP_DOWNSPREAD_CTRL,
lt_settings->link_settings.link_spread);
}
-
}
static enum dpcd_training_patterns
- hw_training_pattern_to_dpcd_training_pattern(
+ dc_dp_training_pattern_to_dpcd_training_pattern(
struct dc_link *link,
- enum hw_dp_training_pattern pattern)
+ enum dc_dp_training_pattern pattern)
{
enum dpcd_training_patterns dpcd_tr_pattern =
DPCD_TRAINING_PATTERN_VIDEOIDLE;
switch (pattern) {
- case HW_DP_TRAINING_PATTERN_1:
+ case DP_TRAINING_PATTERN_SEQUENCE_1:
dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1;
break;
- case HW_DP_TRAINING_PATTERN_2:
+ case DP_TRAINING_PATTERN_SEQUENCE_2:
dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2;
break;
- case HW_DP_TRAINING_PATTERN_3:
+ case DP_TRAINING_PATTERN_SEQUENCE_3:
dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3;
break;
- case HW_DP_TRAINING_PATTERN_4:
+ case DP_TRAINING_PATTERN_SEQUENCE_4:
dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
break;
default:
@@ -212,13 +219,12 @@ static enum dpcd_training_patterns
}
return dpcd_tr_pattern;
-
}
static void dpcd_set_lt_pattern_and_lane_settings(
struct dc_link *link,
const struct link_training_settings *lt_settings,
- enum hw_dp_training_pattern pattern)
+ enum dc_dp_training_pattern pattern)
{
union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = { { {0} } };
const uint32_t dpcd_base_lt_offset =
@@ -233,7 +239,7 @@ static void dpcd_set_lt_pattern_and_lane_settings(
* DpcdAddress_TrainingPatternSet
*****************************************************************/
dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
- hw_training_pattern_to_dpcd_training_pattern(link, pattern);
+ dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern);
dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - dpcd_base_lt_offset]
= dpcd_pattern.raw;
@@ -346,12 +352,20 @@ static void update_drive_settings(
{
uint32_t lane;
for (lane = 0; lane < src.link_settings.lane_count; lane++) {
- dest->lane_settings[lane].VOLTAGE_SWING =
- src.lane_settings[lane].VOLTAGE_SWING;
- dest->lane_settings[lane].PRE_EMPHASIS =
- src.lane_settings[lane].PRE_EMPHASIS;
- dest->lane_settings[lane].POST_CURSOR2 =
- src.lane_settings[lane].POST_CURSOR2;
+ if (dest->voltage_swing == NULL)
+ dest->lane_settings[lane].VOLTAGE_SWING = src.lane_settings[lane].VOLTAGE_SWING;
+ else
+ dest->lane_settings[lane].VOLTAGE_SWING = *dest->voltage_swing;
+
+ if (dest->pre_emphasis == NULL)
+ dest->lane_settings[lane].PRE_EMPHASIS = src.lane_settings[lane].PRE_EMPHASIS;
+ else
+ dest->lane_settings[lane].PRE_EMPHASIS = *dest->pre_emphasis;
+
+ if (dest->post_cursor2 == NULL)
+ dest->lane_settings[lane].POST_CURSOR2 = src.lane_settings[lane].POST_CURSOR2;
+ else
+ dest->lane_settings[lane].POST_CURSOR2 = *dest->post_cursor2;
}
}
@@ -754,15 +768,15 @@ static enum link_training_result perform_channel_equalization_sequence(
struct link_training_settings *lt_settings)
{
struct link_training_settings req_settings;
- enum hw_dp_training_pattern hw_tr_pattern;
+ enum dc_dp_training_pattern tr_pattern;
uint32_t retries_ch_eq;
enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
union lane_align_status_updated dpcd_lane_status_updated = { {0} };
union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } };
- hw_tr_pattern = get_supported_tp(link);
+ tr_pattern = lt_settings->pattern_for_eq;
- dp_set_hw_training_pattern(link, hw_tr_pattern);
+ dp_set_hw_training_pattern(link, tr_pattern);
for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
retries_ch_eq++) {
@@ -776,12 +790,12 @@ static enum link_training_result perform_channel_equalization_sequence(
dpcd_set_lt_pattern_and_lane_settings(
link,
lt_settings,
- hw_tr_pattern);
+ tr_pattern);
else
dpcd_set_lane_settings(link, lt_settings);
/* 3. wait for receiver to lock-on*/
- wait_for_training_aux_rd_interval(link, 400);
+ wait_for_training_aux_rd_interval(link, lt_settings->eq_pattern_time);
/* 4. Read lane status and requested
* drive settings as set by the sink*/
@@ -817,27 +831,16 @@ static enum link_training_result perform_clock_recovery_sequence(
{
uint32_t retries_cr;
uint32_t retry_count;
- uint32_t lane;
struct link_training_settings req_settings;
- enum dc_lane_count lane_count =
- lt_settings->link_settings.lane_count;
- enum hw_dp_training_pattern hw_tr_pattern = HW_DP_TRAINING_PATTERN_1;
+ enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+ enum dc_dp_training_pattern tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_1;
union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
union lane_align_status_updated dpcd_lane_status_updated;
retries_cr = 0;
retry_count = 0;
- /* initial drive setting (VS/PE/PC2)*/
- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
- lt_settings->lane_settings[lane].VOLTAGE_SWING =
- VOLTAGE_SWING_LEVEL0;
- lt_settings->lane_settings[lane].PRE_EMPHASIS =
- PRE_EMPHASIS_DISABLED;
- lt_settings->lane_settings[lane].POST_CURSOR2 =
- POST_CURSOR2_DISABLED;
- }
- dp_set_hw_training_pattern(link, hw_tr_pattern);
+ dp_set_hw_training_pattern(link, tr_pattern);
/* najeeb - The synaptics MST hub can put the LT in
* infinite loop by switching the VS
@@ -845,7 +848,7 @@ static enum link_training_result perform_clock_recovery_sequence(
/* between level 0 and level 1 continuously, here
* we try for CR lock for LinkTrainingMaxCRRetry count*/
while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
- (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+ (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
memset(&dpcd_lane_status_updated, '\0',
@@ -863,7 +866,7 @@ static enum link_training_result perform_clock_recovery_sequence(
dpcd_set_lt_pattern_and_lane_settings(
link,
lt_settings,
- hw_tr_pattern);
+ tr_pattern);
else
dpcd_set_lane_settings(
link,
@@ -872,7 +875,7 @@ static enum link_training_result perform_clock_recovery_sequence(
/* 3. wait receiver to lock-on*/
wait_for_training_aux_rd_interval(
link,
- 100);
+ lt_settings->cr_pattern_time);
/* 4. Read lane status and requested drive
* settings as set by the sink
@@ -939,7 +942,7 @@ static inline enum link_training_result perform_link_training_int(
* TPS4 must be used instead of POST_LT_ADJ_REQ.
*/
if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
- get_supported_tp(link) == HW_DP_TRAINING_PATTERN_4)
+ get_supported_tp(link) == DP_TRAINING_PATTERN_SEQUENCE_4)
return status;
if (status == LINK_TRAINING_SUCCESS &&
@@ -947,7 +950,7 @@ static inline enum link_training_result perform_link_training_int(
status = LINK_TRAINING_LQA_FAIL;
lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
- lane_count_set.bits.ENHANCED_FRAMING = 1;
+ lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
core_link_write_dpcd(
@@ -959,24 +962,29 @@ static inline enum link_training_result perform_link_training_int(
return status;
}
-enum link_training_result dc_link_dp_perform_link_training(
- struct dc_link *link,
+static void initialize_training_settings(
+ struct dc_link *link,
const struct dc_link_settings *link_setting,
- bool skip_video_pattern)
+ const struct dc_link_training_overrides *overrides,
+ struct link_training_settings *lt_settings)
{
- enum link_training_result status = LINK_TRAINING_SUCCESS;
+ uint32_t lane;
- char *link_rate = "Unknown";
- char *lt_result = "Unknown";
+ memset(lt_settings, '\0', sizeof(struct link_training_settings));
- struct link_training_settings lt_settings;
+ /* Initialize link settings */
+ lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set;
+ lt_settings->link_settings.link_rate_set = link_setting->link_rate_set;
- memset(&lt_settings, '\0', sizeof(lt_settings));
+ if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN)
+ lt_settings->link_settings.link_rate = link->preferred_link_setting.link_rate;
+ else
+ lt_settings->link_settings.link_rate = link_setting->link_rate;
- lt_settings.link_settings.link_rate = link_setting->link_rate;
- lt_settings.link_settings.lane_count = link_setting->lane_count;
- lt_settings.link_settings.use_link_rate_set = link_setting->use_link_rate_set;
- lt_settings.link_settings.link_rate_set = link_setting->link_rate_set;
+ if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN)
+ lt_settings->link_settings.lane_count = link->preferred_link_setting.lane_count;
+ else
+ lt_settings->link_settings.lane_count = link_setting->lane_count;
/*@todo[vdevulap] move SS to LS, should not be handled by displaypath*/
@@ -987,31 +995,75 @@ enum link_training_result dc_link_dp_perform_link_training(
* LINK_SPREAD_05_DOWNSPREAD_30KHZ :
* LINK_SPREAD_DISABLED;
*/
+ /* Initialize link spread */
if (link->dp_ss_off)
- lt_settings.link_settings.link_spread = LINK_SPREAD_DISABLED;
+ lt_settings->link_settings.link_spread = LINK_SPREAD_DISABLED;
+ else if (overrides->downspread != NULL)
+ lt_settings->link_settings.link_spread
+ = *overrides->downspread
+ ? LINK_SPREAD_05_DOWNSPREAD_30KHZ
+ : LINK_SPREAD_DISABLED;
else
- lt_settings.link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ;
+ lt_settings->link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ;
- /* 1. set link rate, lane count and spread*/
- dpcd_set_link_settings(link, &lt_settings);
+ /* Initialize lane settings overrides */
+ if (overrides->voltage_swing != NULL)
+ lt_settings->voltage_swing = overrides->voltage_swing;
- /* 2. perform link training (set link training done
- * to false is done as well)*/
- status = perform_clock_recovery_sequence(link, &lt_settings);
- if (status == LINK_TRAINING_SUCCESS) {
- status = perform_channel_equalization_sequence(link,
- &lt_settings);
- }
+ if (overrides->pre_emphasis != NULL)
+ lt_settings->pre_emphasis = overrides->pre_emphasis;
- if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) {
- status = perform_link_training_int(link,
- &lt_settings,
- status);
+ if (overrides->post_cursor2 != NULL)
+ lt_settings->post_cursor2 = overrides->post_cursor2;
+
+ /* Initialize lane settings (VS/PE/PC2) */
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+ lt_settings->lane_settings[lane].VOLTAGE_SWING =
+ lt_settings->voltage_swing != NULL ?
+ *lt_settings->voltage_swing :
+ VOLTAGE_SWING_LEVEL0;
+ lt_settings->lane_settings[lane].PRE_EMPHASIS =
+ lt_settings->pre_emphasis != NULL ?
+ *lt_settings->pre_emphasis
+ : PRE_EMPHASIS_DISABLED;
+ lt_settings->lane_settings[lane].POST_CURSOR2 =
+ lt_settings->post_cursor2 != NULL ?
+ *lt_settings->post_cursor2
+ : POST_CURSOR2_DISABLED;
}
- /* 6. print status message*/
- switch (lt_settings.link_settings.link_rate) {
+ /* Initialize training timings */
+ if (overrides->cr_pattern_time != NULL)
+ lt_settings->cr_pattern_time = *overrides->cr_pattern_time;
+ else
+ lt_settings->cr_pattern_time = get_training_aux_rd_interval(link, 100);
+
+ if (overrides->eq_pattern_time != NULL)
+ lt_settings->eq_pattern_time = *overrides->eq_pattern_time;
+ else
+ lt_settings->eq_pattern_time = get_training_aux_rd_interval(link, 400);
+
+ if (overrides->pattern_for_eq != NULL)
+ lt_settings->pattern_for_eq = *overrides->pattern_for_eq;
+ else
+ lt_settings->pattern_for_eq = get_supported_tp(link);
+
+ if (overrides->enhanced_framing != NULL)
+ lt_settings->enhanced_framing = *overrides->enhanced_framing;
+ else
+ lt_settings->enhanced_framing = 1;
+}
+
+static void print_status_message(
+ struct dc_link *link,
+ const struct link_training_settings *lt_settings,
+ enum link_training_result status)
+{
+ char *link_rate = "Unknown";
+ char *lt_result = "Unknown";
+ char *lt_spread = "Disabled";
+ switch (lt_settings->link_settings.link_rate) {
case LINK_RATE_LOW:
link_rate = "RBR";
break;
@@ -1057,13 +1109,122 @@ enum link_training_result dc_link_dp_perform_link_training(
break;
}
+ switch (lt_settings->link_settings.link_spread) {
+ case LINK_SPREAD_DISABLED:
+ lt_spread = "Disabled";
+ break;
+ case LINK_SPREAD_05_DOWNSPREAD_30KHZ:
+ lt_spread = "0.5% 30KHz";
+ break;
+ case LINK_SPREAD_05_DOWNSPREAD_33KHZ:
+ lt_spread = "0.5% 33KHz";
+ break;
+ default:
+ break;
+ }
+
/* Connectivity log: link training */
- CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d",
- link_rate,
- lt_settings.link_settings.lane_count,
- lt_result,
- lt_settings.lane_settings[0].VOLTAGE_SWING,
- lt_settings.lane_settings[0].PRE_EMPHASIS);
+ CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
+ link_rate,
+ lt_settings->link_settings.lane_count,
+ lt_result,
+ lt_settings->lane_settings[0].VOLTAGE_SWING,
+ lt_settings->lane_settings[0].PRE_EMPHASIS,
+ lt_spread);
+}
+
+bool dc_link_dp_perform_link_training_skip_aux(
+ struct dc_link *link,
+ const struct dc_link_settings *link_setting)
+{
+ struct link_training_settings lt_settings;
+ enum dc_dp_training_pattern pattern_for_cr = DP_TRAINING_PATTERN_SEQUENCE_1;
+
+ initialize_training_settings(
+ link,
+ link_setting,
+ &link->preferred_training_settings,
+ &lt_settings);
+
+ /* 1. Perform_clock_recovery_sequence. */
+
+ /* transmit training pattern for clock recovery */
+ dp_set_hw_training_pattern(link, pattern_for_cr);
+
+ /* call HWSS to set lane settings*/
+ dp_set_hw_lane_settings(link, &lt_settings);
+
+ /* wait receiver to lock-on*/
+ wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time);
+
+ /* 2. Perform_channel_equalization_sequence. */
+
+ /* transmit training pattern for channel equalization. */
+ dp_set_hw_training_pattern(link, lt_settings.pattern_for_eq);
+
+ /* call HWSS to set lane settings*/
+ dp_set_hw_lane_settings(link, &lt_settings);
+
+ /* wait receiver to lock-on. */
+ wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time);
+
+ /* 3. Perform_link_training_int. */
+
+ /* Mainlink output idle pattern. */
+ dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
+
+ print_status_message(link, &lt_settings, LINK_TRAINING_SUCCESS);
+
+ return true;
+}
+
+enum link_training_result dc_link_dp_perform_link_training(
+ struct dc_link *link,
+ const struct dc_link_settings *link_setting,
+ bool skip_video_pattern)
+{
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+ struct link_training_settings lt_settings;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ bool fec_enable;
+#endif
+
+ initialize_training_settings(
+ link,
+ link_setting,
+ &link->preferred_training_settings,
+ &lt_settings);
+
+ /* 1. set link rate, lane count and spread. */
+ dpcd_set_link_settings(link, &lt_settings);
+
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ if (link->preferred_training_settings.fec_enable != NULL)
+ fec_enable = *link->preferred_training_settings.fec_enable;
+ else
+ fec_enable = true;
+
+ dp_set_fec_ready(link, fec_enable);
+#endif
+
+
+ /* 2. perform link training (set link training done
+ * to false is done as well)
+ */
+ status = perform_clock_recovery_sequence(link, &lt_settings);
+ if (status == LINK_TRAINING_SUCCESS) {
+ status = perform_channel_equalization_sequence(link,
+ &lt_settings);
+ }
+
+ if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) {
+ status = perform_link_training_int(link,
+ &lt_settings,
+ status);
+ }
+
+ /* 6. print status message*/
+ print_status_message(link, &lt_settings, status);
if (status != LINK_TRAINING_SUCCESS)
link->ctx->dc->debug_data.ltFailCount++;
@@ -1071,7 +1232,6 @@ enum link_training_result dc_link_dp_perform_link_training(
return status;
}
-
bool perform_link_training_with_retries(
struct dc_link *link,
const struct dc_link_settings *link_setting,
@@ -1096,6 +1256,146 @@ bool perform_link_training_with_retries(
return false;
}
+static enum clock_source_id get_clock_source_id(struct dc_link *link)
+{
+ enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_UNDEFINED;
+ struct clock_source *dp_cs = link->dc->res_pool->dp_clock_source;
+
+ if (dp_cs != NULL) {
+ dp_cs_id = dp_cs->id;
+ } else {
+ /*
+ * dp clock source is not initialized for some reason.
+ * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used
+ */
+ ASSERT(dp_cs);
+ }
+
+ return dp_cs_id;
+}
+
+static void set_dp_mst_mode(struct dc_link *link, bool mst_enable)
+{
+ if (mst_enable == false &&
+ link->type == dc_connection_mst_branch) {
+ /* Disable MST on link. Use only local sink. */
+ dp_disable_link_phy_mst(link, link->connector_signal);
+
+ link->type = dc_connection_single;
+ link->local_sink = link->remote_sinks[0];
+ link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
+ } else if (mst_enable == true &&
+ link->type == dc_connection_single &&
+ link->remote_sinks[0] != NULL) {
+ /* Re-enable MST on link. */
+ dp_disable_link_phy(link, link->connector_signal);
+ dp_enable_mst_on_sink(link, true);
+
+ link->type = dc_connection_mst_branch;
+ link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+ }
+}
+
+bool dc_link_dp_sync_lt_begin(struct dc_link *link)
+{
+ /* Begin Sync LT. During this time,
+ * DPCD:600h must not be powered down.
+ */
+ link->sync_lt_in_progress = true;
+
+ /*Clear any existing preferred settings.*/
+ memset(&link->preferred_training_settings, 0,
+ sizeof(struct dc_link_training_overrides));
+ memset(&link->preferred_link_setting, 0,
+ sizeof(struct dc_link_settings));
+
+ return true;
+}
+
+enum link_training_result dc_link_dp_sync_lt_attempt(
+ struct dc_link *link,
+ struct dc_link_settings *link_settings,
+ struct dc_link_training_overrides *lt_overrides)
+{
+ struct link_training_settings lt_settings;
+ enum link_training_result lt_status = LINK_TRAINING_SUCCESS;
+ enum dp_panel_mode panel_mode = DP_PANEL_MODE_DEFAULT;
+ enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ bool fec_enable = false;
+#endif
+
+ initialize_training_settings(
+ link,
+ link_settings,
+ lt_overrides,
+ &lt_settings);
+
+ /* Setup MST Mode */
+ if (lt_overrides->mst_enable)
+ set_dp_mst_mode(link, *lt_overrides->mst_enable);
+
+ /* Disable link */
+ dp_disable_link_phy(link, link->connector_signal);
+
+ /* Enable link */
+ dp_cs_id = get_clock_source_id(link);
+ dp_enable_link_phy(link, link->connector_signal,
+ dp_cs_id, link_settings);
+
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ /* Set FEC enable */
+ fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable;
+ dp_set_fec_ready(link, fec_enable);
+#endif
+
+ if (lt_overrides->alternate_scrambler_reset) {
+ if (*lt_overrides->alternate_scrambler_reset)
+ panel_mode = DP_PANEL_MODE_EDP;
+ else
+ panel_mode = DP_PANEL_MODE_DEFAULT;
+ } else
+ panel_mode = dp_get_panel_mode(link);
+
+ dp_set_panel_mode(link, panel_mode);
+
+ /* Attempt to train with given link training settings */
+
+ /* Set link rate, lane count and spread. */
+ dpcd_set_link_settings(link, &lt_settings);
+
+ /* 2. perform link training (set link training done
+ * to false is done as well)
+ */
+ lt_status = perform_clock_recovery_sequence(link, &lt_settings);
+ if (lt_status == LINK_TRAINING_SUCCESS) {
+ lt_status = perform_channel_equalization_sequence(link,
+ &lt_settings);
+ }
+
+ /* 3. Sync LT must skip TRAINING_PATTERN_SET:0 (video pattern)*/
+ /* 4. print status message*/
+ print_status_message(link, &lt_settings, lt_status);
+
+ return lt_status;
+}
+
+bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down)
+{
+ /* If input parameter is set, shut down phy.
+ * Still shouldn't turn off dp_receiver (DPCD:600h)
+ */
+ if (link_down == true) {
+ dp_disable_link_phy(link, link->connector_signal);
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ dp_set_fec_ready(link, false);
+#endif
+ }
+
+ link->sync_lt_in_progress = false;
+ return true;
+}
+
static struct dc_link_settings get_max_link_cap(struct dc_link *link)
{
/* Set Default link settings */
@@ -1250,7 +1550,6 @@ bool dp_verify_link_cap(
bool success;
bool skip_link_training;
bool skip_video_pattern;
- struct clock_source *dp_cs;
enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL;
enum link_training_result status;
union hpd_irq_data irq_data;
@@ -1274,17 +1573,7 @@ bool dp_verify_link_cap(
/* disable PHY done possible by BIOS, will be done by driver itself */
dp_disable_link_phy(link, link->connector_signal);
- dp_cs = link->dc->res_pool->dp_clock_source;
-
- if (dp_cs)
- dp_cs_id = dp_cs->id;
- else {
- /*
- * dp clock source is not initialized for some reason.
- * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used
- */
- ASSERT(dp_cs);
- }
+ dp_cs_id = get_clock_source_id(link);
/* link training starts with the maximum common settings
* supported by both sink and ASIC.
@@ -1354,6 +1643,33 @@ bool dp_verify_link_cap(
return success;
}
+bool dp_verify_link_cap_with_retries(
+ struct dc_link *link,
+ struct dc_link_settings *known_limit_link_setting,
+ int attempts)
+{
+ uint8_t i = 0;
+ bool success = false;
+
+ for (i = 0; i < attempts; i++) {
+ int fail_count = 0;
+ enum dc_connection_type type;
+
+ memset(&link->verified_link_cap, 0,
+ sizeof(struct dc_link_settings));
+ if (!dc_link_detect_sink(link, &type)) {
+ break;
+ } else if (dp_verify_link_cap(link,
+ &link->reported_link_cap,
+ &fail_count) && fail_count == 0) {
+ success = true;
+ break;
+ }
+ msleep(10);
+ }
+ return success;
+}
+
static struct dc_link_settings get_common_supported_link_settings(
struct dc_link_settings link_setting_a,
struct dc_link_settings link_setting_b)
@@ -2156,6 +2472,11 @@ bool is_mst_supported(struct dc_link *link)
union dpcd_rev rev;
union mstm_cap cap;
+ if (link->preferred_training_settings.mst_enable &&
+ *link->preferred_training_settings.mst_enable == false) {
+ return false;
+ }
+
rev.raw = 0;
cap.raw = 0;
@@ -2363,13 +2684,13 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data,
if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) {
switch (link->dpcd_caps.branch_dev_id) {
- /* Some active dongles (DP-VGA, DP-DLDVI converters) power down
+ /* 0010FA active dongles (DP-VGA, DP-DLDVI converters) power down
* all internal circuits including AUX communication preventing
* reading DPCD table and EDID (spec violation).
* Encoder will skip DP RX power down on disable_output to
* keep receiver powered all the time.*/
- case DP_BRANCH_DEVICE_ID_1:
- case DP_BRANCH_DEVICE_ID_4:
+ case DP_BRANCH_DEVICE_ID_0010FA:
+ case DP_BRANCH_DEVICE_ID_0080E1:
link->wa_flags.dp_keep_receiver_powered = true;
break;
@@ -2774,14 +3095,19 @@ static void set_crtc_test_pattern(struct dc_link *link,
controller_test_pattern, color_depth);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
else if (opp->funcs->opp_set_disp_pattern_generator) {
- struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
+ struct pipe_ctx *odm_pipe;
+ int opp_cnt = 1;
+
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ opp_cnt++;
- if (bot_odm_pipe) {
- struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.opp;
+ width /= opp_cnt;
- bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, &params);
- width /= 2;
- bot_opp->funcs->opp_set_disp_pattern_generator(bot_opp,
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+ struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
+
+ odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
+ odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp,
controller_test_pattern,
color_depth,
NULL,
@@ -2810,14 +3136,18 @@ static void set_crtc_test_pattern(struct dc_link *link,
color_depth);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
else if (opp->funcs->opp_set_disp_pattern_generator) {
- struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
+ struct pipe_ctx *odm_pipe;
+ int opp_cnt = 1;
+
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ opp_cnt++;
- if (bot_odm_pipe) {
- struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.opp;
+ width /= opp_cnt;
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+ struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
- bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, &params);
- width /= 2;
- bot_opp->funcs->opp_set_disp_pattern_generator(bot_opp,
+ odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
+ odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp,
CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
color_depth,
NULL,
@@ -2858,7 +3188,7 @@ bool dc_link_dp_set_test_pattern(
memset(&training_pattern, 0, sizeof(training_pattern));
for (i = 0; i < MAX_PIPES; i++) {
- if (pipes[i].stream->link == link) {
+ if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
pipe_ctx = &pipes[i];
break;
}
@@ -3007,6 +3337,105 @@ void dp_enable_mst_on_sink(struct dc_link *link, bool enable)
core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
}
+void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode)
+{
+ union dpcd_edp_config edp_config_set;
+ bool panel_mode_edp = false;
+
+ memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config));
+
+ if (panel_mode != DP_PANEL_MODE_DEFAULT) {
+
+ switch (panel_mode) {
+ case DP_PANEL_MODE_EDP:
+ case DP_PANEL_MODE_SPECIAL:
+ panel_mode_edp = true;
+ break;
+
+ default:
+ break;
+ }
+
+ /*set edp panel mode in receiver*/
+ core_link_read_dpcd(
+ link,
+ DP_EDP_CONFIGURATION_SET,
+ &edp_config_set.raw,
+ sizeof(edp_config_set.raw));
+
+ if (edp_config_set.bits.PANEL_MODE_EDP
+ != panel_mode_edp) {
+ enum ddc_result result = DDC_RESULT_UNKNOWN;
+
+ edp_config_set.bits.PANEL_MODE_EDP =
+ panel_mode_edp;
+ result = core_link_write_dpcd(
+ link,
+ DP_EDP_CONFIGURATION_SET,
+ &edp_config_set.raw,
+ sizeof(edp_config_set.raw));
+
+ ASSERT(result == DDC_RESULT_SUCESSFULL);
+ }
+ }
+ DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d "
+ "eDP panel mode enabled: %d \n",
+ link->link_index,
+ link->dpcd_caps.panel_mode_edp,
+ panel_mode_edp);
+}
+
+enum dp_panel_mode dp_get_panel_mode(struct dc_link *link)
+{
+ /* We need to explicitly check that connector
+ * is not DP. Some Travis_VGA get reported
+ * by video bios as DP.
+ */
+ if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
+
+ switch (link->dpcd_caps.branch_dev_id) {
+ case DP_BRANCH_DEVICE_ID_0022B9:
+ /* alternate scrambler reset is required for Travis
+ * for the case when external chip does not
+ * provide sink device id, alternate scrambler
+ * scheme will be overriden later by querying
+ * Encoder features
+ */
+ if (strncmp(
+ link->dpcd_caps.branch_dev_name,
+ DP_VGA_LVDS_CONVERTER_ID_2,
+ sizeof(
+ link->dpcd_caps.
+ branch_dev_name)) == 0) {
+ return DP_PANEL_MODE_SPECIAL;
+ }
+ break;
+ case DP_BRANCH_DEVICE_ID_00001A:
+ /* alternate scrambler reset is required for Travis
+ * for the case when external chip does not provide
+ * sink device id, alternate scrambler scheme will
+ * be overriden later by querying Encoder feature
+ */
+ if (strncmp(link->dpcd_caps.branch_dev_name,
+ DP_VGA_LVDS_CONVERTER_ID_3,
+ sizeof(
+ link->dpcd_caps.
+ branch_dev_name)) == 0) {
+ return DP_PANEL_MODE_SPECIAL;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (link->dpcd_caps.panel_mode_edp) {
+ return DP_PANEL_MODE_EDP;
+ }
+
+ return DP_PANEL_MODE_DEFAULT;
+}
+
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
void dp_set_fec_ready(struct dc_link *link, bool ready)
{
@@ -3024,7 +3453,7 @@ void dp_set_fec_ready(struct dc_link *link, bool ready)
if (link_enc->funcs->fec_set_ready &&
link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
- if (link->fec_state == dc_link_fec_not_ready && ready) {
+ if (ready) {
fec_config = 1;
if (core_link_write_dpcd(link,
DP_FEC_CONFIGURATION,
@@ -3033,9 +3462,11 @@ void dp_set_fec_ready(struct dc_link *link, bool ready)
link_enc->funcs->fec_set_ready(link_enc, true);
link->fec_state = dc_link_fec_ready;
} else {
+ link->link_enc->funcs->fec_set_ready(link->link_enc, false);
+ link->fec_state = dc_link_fec_not_ready;
dm_error("dpcd write failed to set fec_ready");
}
- } else if (link->fec_state == dc_link_fec_ready && !ready) {
+ } else if (link->fec_state == dc_link_fec_ready) {
fec_config = 0;
core_link_write_dpcd(link,
DP_FEC_CONFIGURATION,
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
index 2d019e1f6135..79438c4f1e20 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
@@ -25,10 +25,11 @@ enum dc_status core_link_read_dpcd(
uint8_t *data,
uint32_t size)
{
- if (!dm_helpers_dp_read_dpcd(link->ctx,
- link,
- address, data, size))
- return DC_ERROR_UNEXPECTED;
+ if (!link->aux_access_disabled &&
+ !dm_helpers_dp_read_dpcd(link->ctx,
+ link, address, data, size)) {
+ return DC_ERROR_UNEXPECTED;
+ }
return DC_OK;
}
@@ -39,10 +40,11 @@ enum dc_status core_link_write_dpcd(
const uint8_t *data,
uint32_t size)
{
- if (!dm_helpers_dp_write_dpcd(link->ctx,
- link,
- address, data, size))
- return DC_ERROR_UNEXPECTED;
+ if (!link->aux_access_disabled &&
+ !dm_helpers_dp_write_dpcd(link->ctx,
+ link, address, data, size)) {
+ return DC_ERROR_UNEXPECTED;
+ }
return DC_OK;
}
@@ -53,6 +55,9 @@ void dp_receiver_power_ctrl(struct dc_link *link, bool on)
state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
+ if (link->sync_lt_in_progress)
+ return;
+
core_link_write_dpcd(link, DP_SET_POWER, &state,
sizeof(state));
}
@@ -160,6 +165,10 @@ bool edp_receiver_ready_T7(struct dc_link *link)
break;
udelay(25); //MAx T7 is 50ms
} while (++tries < 300);
+
+ if (link->local_sink->edid_caps.panel_patch.extra_t7_ms > 0)
+ udelay(link->local_sink->edid_caps.panel_patch.extra_t7_ms * 1000);
+
return result;
}
@@ -203,21 +212,21 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal)
bool dp_set_hw_training_pattern(
struct dc_link *link,
- enum hw_dp_training_pattern pattern)
+ enum dc_dp_training_pattern pattern)
{
enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
switch (pattern) {
- case HW_DP_TRAINING_PATTERN_1:
+ case DP_TRAINING_PATTERN_SEQUENCE_1:
test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
break;
- case HW_DP_TRAINING_PATTERN_2:
+ case DP_TRAINING_PATTERN_SEQUENCE_2:
test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
break;
- case HW_DP_TRAINING_PATTERN_3:
+ case DP_TRAINING_PATTERN_SEQUENCE_3:
test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
break;
- case HW_DP_TRAINING_PATTERN_4:
+ case DP_TRAINING_PATTERN_SEQUENCE_4:
test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
break;
default:
@@ -239,46 +248,6 @@ void dp_set_hw_lane_settings(
encoder->funcs->dp_set_lane_settings(encoder, link_settings);
}
-enum dp_panel_mode dp_get_panel_mode(struct dc_link *link)
-{
- /* We need to explicitly check that connector
- * is not DP. Some Travis_VGA get reported
- * by video bios as DP.
- */
- if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
-
- switch (link->dpcd_caps.branch_dev_id) {
- case DP_BRANCH_DEVICE_ID_2:
- if (strncmp(
- link->dpcd_caps.branch_dev_name,
- DP_VGA_LVDS_CONVERTER_ID_2,
- sizeof(
- link->dpcd_caps.
- branch_dev_name)) == 0) {
- return DP_PANEL_MODE_SPECIAL;
- }
- break;
- case DP_BRANCH_DEVICE_ID_3:
- if (strncmp(link->dpcd_caps.branch_dev_name,
- DP_VGA_LVDS_CONVERTER_ID_3,
- sizeof(
- link->dpcd_caps.
- branch_dev_name)) == 0) {
- return DP_PANEL_MODE_SPECIAL;
- }
- break;
- default:
- break;
- }
- }
-
- if (link->dpcd_caps.panel_mode_edp) {
- return DP_PANEL_MODE_EDP;
- }
-
- return DP_PANEL_MODE_DEFAULT;
-}
-
void dp_set_hw_test_pattern(
struct dc_link *link,
enum dp_test_pattern test_pattern,
@@ -306,7 +275,7 @@ void dp_retrain_link_dp_test(struct dc_link *link,
for (i = 0; i < MAX_PIPES; i++) {
if (pipes[i].stream != NULL &&
- !pipes[i].top_pipe &&
+ !pipes[i].top_pipe && !pipes[i].prev_odm_pipe &&
pipes[i].stream->link != NULL &&
pipes[i].stream_res.stream_enc != NULL) {
udelay(100);
@@ -320,7 +289,9 @@ void dp_retrain_link_dp_test(struct dc_link *link,
dp_receiver_power_ctrl(link, false);
- link->dc->hwss.disable_stream(&pipes[i], KEEP_ACQUIRED_RESOURCE);
+ link->dc->hwss.disable_stream(&pipes[i]);
+ if ((&pipes[i])->stream_res.audio && !link->dc->debug.az_endpoint_mute_only)
+ (&pipes[i])->stream_res.audio->funcs->az_disable((&pipes[i])->stream_res.audio);
link->link_enc->funcs->disable_output(
link->link_enc,
@@ -373,10 +344,22 @@ void dp_retrain_link_dp_test(struct dc_link *link,
static void dsc_optc_config_log(struct display_stream_compressor *dsc,
struct dsc_optc_config *config)
{
- DC_LOG_DSC("Setting optc DSC config at DSC inst %d", dsc->inst);
- DC_LOG_DSC("\n\tbytes_per_pixel %d\n\tis_pixel_format_444 %d\n\tslice_width %d",
- config->bytes_per_pixel,
- config->is_pixel_format_444, config->slice_width);
+ uint32_t precision = 1 << 28;
+ uint32_t bytes_per_pixel_int = config->bytes_per_pixel / precision;
+ uint32_t bytes_per_pixel_mod = config->bytes_per_pixel % precision;
+ uint64_t ll_bytes_per_pix_fraq = bytes_per_pixel_mod;
+
+ /* 7 fractional digits decimal precision for bytes per pixel is enough because DSC
+ * bits per pixel precision is 1/16th of a pixel, which means bytes per pixel precision is
+ * 1/16/8 = 1/128 of a byte, or 0.0078125 decimal
+ */
+ ll_bytes_per_pix_fraq *= 10000000;
+ ll_bytes_per_pix_fraq /= precision;
+
+ DC_LOG_DSC("\tbytes_per_pixel 0x%08x (%d.%07d)",
+ config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t)ll_bytes_per_pix_fraq);
+ DC_LOG_DSC("\tis_pixel_format_444 %d", config->is_pixel_format_444);
+ DC_LOG_DSC("\tslice_width %d", config->slice_width);
}
static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
@@ -392,55 +375,62 @@ static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
return result;
}
-/* This has to be done after DSC was enabled on RX first, i.e. after dp_enable_dsc_on_rx() had been called
+/* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first,
+ * i.e. after dp_enable_dsc_on_rx() had been called
*/
-static void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
+void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
{
struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
struct dc *core_dc = pipe_ctx->stream->ctx->dc;
struct dc_stream_state *stream = pipe_ctx->stream;
- struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
+ struct pipe_ctx *odm_pipe;
+ int opp_cnt = 1;
+
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ opp_cnt++;
if (enable) {
- /* TODO proper function */
struct dsc_config dsc_cfg;
struct dsc_optc_config dsc_optc_cfg;
enum optc_dsc_mode optc_dsc_mode;
- uint8_t dsc_packed_pps[128];
/* Enable DSC hw block */
- dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
+ dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
dsc_cfg.color_depth = stream->timing.display_color_depth;
dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
+ ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
+ dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
- dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps[0]);
- if (odm_pipe) {
- struct display_stream_compressor *bot_dsc = odm_pipe->stream_res.dsc;
- uint8_t dsc_packed_pps_odm[128];
-
- dsc_cfg.pic_width /= 2;
- ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % 2 == 0);
- dsc_cfg.dc_dsc_cfg.num_slices_h /= 2;
- dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps_odm[0]);
- bot_dsc->funcs->dsc_set_config(bot_dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps_odm[0]);
- bot_dsc->funcs->dsc_enable(bot_dsc, odm_pipe->stream_res.opp->inst);
- }
+ dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+ struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
+
+ odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
+ odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
+ }
+ dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
+ dsc_cfg.pic_width *= opp_cnt;
optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
- dsc_optc_config_log(dsc, &dsc_optc_cfg);
/* Enable DSC in encoder */
- if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment) && pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config)
+ if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
+ DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id);
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
optc_dsc_mode,
dsc_optc_cfg.bytes_per_pixel,
- dsc_optc_cfg.slice_width,
- &dsc_packed_pps[0]);
+ dsc_optc_cfg.slice_width);
+
+ /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */
+ }
/* Enable DSC in OPTC */
+ DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
optc_dsc_mode,
dsc_optc_cfg.bytes_per_pixel,
@@ -452,15 +442,18 @@ static void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
OPTC_DSC_DISABLED, 0, 0);
/* disable DSC in stream encoder */
- if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
+ if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
pipe_ctx->stream_res.stream_enc,
- OPTC_DSC_DISABLED, 0, 0, NULL);
+ OPTC_DSC_DISABLED, 0, 0);
+
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc, false, NULL);
}
/* disable DSC block */
pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
- if (odm_pipe)
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
}
}
@@ -489,6 +482,47 @@ out:
return result;
}
+bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ struct dc *core_dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+
+ if (!pipe_ctx->stream->timing.flags.DSC || !dsc)
+ return false;
+
+ if (enable) {
+ struct dsc_config dsc_cfg;
+ uint8_t dsc_packed_pps[128];
+
+ /* Enable DSC hw block */
+ dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
+ dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
+ dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
+ dsc_cfg.color_depth = stream->timing.display_color_depth;
+ dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
+
+ DC_LOG_DSC(" ");
+ dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]);
+ if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
+ DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id);
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc,
+ true,
+ &dsc_packed_pps[0]);
+ }
+ } else {
+ /* disable DSC PPS in stream encoder */
+ if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc, false, NULL);
+ }
+ }
+
+ return true;
+}
+
+
bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx)
{
struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
@@ -499,8 +533,8 @@ bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx)
return false;
dp_set_dsc_on_stream(pipe_ctx, true);
+ dp_set_dsc_pps_sdp(pipe_ctx, true);
return true;
}
-
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index 2ceaab4fb5de..8f70295179ff 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -52,6 +52,9 @@
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
#include "dcn20/dcn20_resource.h"
#endif
+#if defined(CONFIG_DRM_AMD_DC_DCN2_1)
+#include "dcn21/dcn21_resource.h"
+#endif
#include "dce120/dce120_resource.h"
#define DC_LOGGER_INIT(logger)
@@ -101,6 +104,10 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
dc_version = DCN_VERSION_1_0;
if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev))
dc_version = DCN_VERSION_1_01;
+#if defined(CONFIG_DRM_AMD_DC_DCN2_1)
+ if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev))
+ dc_version = DCN_VERSION_2_1;
+#endif
break;
#endif
@@ -168,17 +175,20 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc,
res_pool = dcn20_create_resource_pool(init_data, dc);
break;
#endif
+#if defined(CONFIG_DRM_AMD_DC_DCN2_1)
+ case DCN_VERSION_2_1:
+ res_pool = dcn21_create_resource_pool(init_data, dc);
+ break;
+#endif
default:
break;
}
- if (res_pool != NULL) {
- struct dc_firmware_info fw_info = { { 0 } };
- if (dc->ctx->dc_bios->funcs->get_firmware_info(dc->ctx->dc_bios,
- &fw_info) == BP_RESULT_OK) {
+ if (res_pool != NULL) {
+ if (dc->ctx->dc_bios->fw_info_valid) {
res_pool->ref_clocks.xtalin_clock_inKhz =
- fw_info.pll_info.crystal_frequency;
+ dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
/* initialize with firmware data first, no all
* ASIC have DCCG SW component. FPGA or
* simulation need initialization of
@@ -265,12 +275,10 @@ bool resource_construct(
DC_ERR("DC: failed to create audio!\n");
return false;
}
-
if (!aud->funcs->endpoint_valid(aud)) {
aud->funcs->destroy(&aud);
break;
}
-
pool->audios[i] = aud;
pool->audio_count++;
}
@@ -940,7 +948,14 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx)
data->inits.v_c_bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c);
}
+static bool are_rect_integer_multiples(struct rect src, struct rect dest)
+{
+ if (dest.width >= src.width && dest.width % src.width == 0 &&
+ dest.height >= src.height && dest.height % src.height == 0)
+ return true;
+ return false;
+}
bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
{
const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
@@ -983,6 +998,15 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
if (pipe_ctx->plane_res.dpp != NULL)
res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
+
+ if (res &&
+ plane_state->scaling_quality.integer_scaling &&
+ are_rect_integer_multiples(pipe_ctx->plane_res.scl_data.viewport,
+ pipe_ctx->plane_res.scl_data.recout)) {
+ pipe_ctx->plane_res.scl_data.taps.v_taps = 1;
+ pipe_ctx->plane_res.scl_data.taps.h_taps = 1;
+ }
+
if (!res) {
/* Try 24 bpp linebuffer */
pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP;
@@ -1103,25 +1127,21 @@ struct pipe_ctx *resource_get_head_pipe_for_stream(
struct dc_stream_state *stream)
{
int i;
+
for (i = 0; i < MAX_PIPES; i++) {
- if (res_ctx->pipe_ctx[i].stream == stream &&
- !res_ctx->pipe_ctx[i].top_pipe) {
+ if (res_ctx->pipe_ctx[i].stream == stream
+ && !res_ctx->pipe_ctx[i].top_pipe
+ && !res_ctx->pipe_ctx[i].prev_odm_pipe)
return &res_ctx->pipe_ctx[i];
- break;
- }
}
return NULL;
}
-static struct pipe_ctx *resource_get_tail_pipe_for_stream(
+static struct pipe_ctx *resource_get_tail_pipe(
struct resource_context *res_ctx,
- struct dc_stream_state *stream)
+ struct pipe_ctx *head_pipe)
{
- struct pipe_ctx *head_pipe, *tail_pipe;
- head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
-
- if (!head_pipe)
- return NULL;
+ struct pipe_ctx *tail_pipe;
tail_pipe = head_pipe->bottom_pipe;
@@ -1137,31 +1157,20 @@ static struct pipe_ctx *resource_get_tail_pipe_for_stream(
* A free_pipe for a stream is defined here as a pipe
* that has no surface attached yet
*/
-static struct pipe_ctx *acquire_free_pipe_for_stream(
+static struct pipe_ctx *acquire_free_pipe_for_head(
struct dc_state *context,
const struct resource_pool *pool,
- struct dc_stream_state *stream)
+ struct pipe_ctx *head_pipe)
{
int i;
struct resource_context *res_ctx = &context->res_ctx;
- struct pipe_ctx *head_pipe = NULL;
-
- /* Find head pipe, which has the back end set up*/
-
- head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
-
- if (!head_pipe) {
- ASSERT(0);
- return NULL;
- }
-
if (!head_pipe->plane_state)
return head_pipe;
/* Re-use pipe already acquired for this stream if available*/
for (i = pool->pipe_count - 1; i >= 0; i--) {
- if (res_ctx->pipe_ctx[i].stream == stream &&
+ if (res_ctx->pipe_ctx[i].stream == head_pipe->stream &&
!res_ctx->pipe_ctx[i].plane_state) {
return &res_ctx->pipe_ctx[i];
}
@@ -1175,8 +1184,7 @@ static struct pipe_ctx *acquire_free_pipe_for_stream(
if (!pool->funcs->acquire_idle_pipe_for_layer)
return NULL;
- return pool->funcs->acquire_idle_pipe_for_layer(context, pool, stream);
-
+ return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream);
}
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
@@ -1190,7 +1198,7 @@ static int acquire_first_split_pipe(
for (i = 0; i < pool->pipe_count; i++) {
struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i];
- if (split_pipe->top_pipe && !dc_res_is_odm_head_pipe(split_pipe) &&
+ if (split_pipe->top_pipe &&
split_pipe->top_pipe->plane_state == split_pipe->plane_state) {
split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe;
if (split_pipe->bottom_pipe)
@@ -1251,39 +1259,41 @@ bool dc_add_plane_to_context(
return false;
}
- tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream);
- ASSERT(tail_pipe);
+ /* retain new surface, but only once per stream */
+ dc_plane_state_retain(plane_state);
- free_pipe = acquire_free_pipe_for_stream(context, pool, stream);
+ while (head_pipe) {
+ tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe);
+ ASSERT(tail_pipe);
-#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
- if (!free_pipe) {
- int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
- if (pipe_idx >= 0)
- free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
- }
-#endif
- if (!free_pipe)
- return false;
+ free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
- /* retain new surfaces */
- dc_plane_state_retain(plane_state);
- free_pipe->plane_state = plane_state;
-
- if (head_pipe != free_pipe) {
- free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
- free_pipe->stream_res.abm = tail_pipe->stream_res.abm;
- free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
- free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
- free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
- free_pipe->clock_source = tail_pipe->clock_source;
- free_pipe->top_pipe = tail_pipe;
- tail_pipe->bottom_pipe = free_pipe;
- } else if (free_pipe->bottom_pipe && free_pipe->bottom_pipe->plane_state == NULL) {
- ASSERT(free_pipe->bottom_pipe->stream_res.opp != free_pipe->stream_res.opp);
- free_pipe->bottom_pipe->plane_state = plane_state;
- }
+ #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+ if (!free_pipe) {
+ int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
+ if (pipe_idx >= 0)
+ free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
+ }
+ #endif
+ if (!free_pipe) {
+ dc_plane_state_release(plane_state);
+ return false;
+ }
+ free_pipe->plane_state = plane_state;
+
+ if (head_pipe != free_pipe) {
+ free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
+ free_pipe->stream_res.abm = tail_pipe->stream_res.abm;
+ free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
+ free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
+ free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
+ free_pipe->clock_source = tail_pipe->clock_source;
+ free_pipe->top_pipe = tail_pipe;
+ tail_pipe->bottom_pipe = free_pipe;
+ }
+ head_pipe = head_pipe->next_odm_pipe;
+ }
/* assign new surfaces*/
stream_status->plane_states[stream_status->plane_count] = plane_state;
@@ -1292,35 +1302,6 @@ bool dc_add_plane_to_context(
return true;
}
-struct pipe_ctx *dc_res_get_odm_bottom_pipe(struct pipe_ctx *pipe_ctx)
-{
- struct pipe_ctx *bottom_pipe = pipe_ctx->bottom_pipe;
-
- /* ODM should only be updated once per otg */
- if (pipe_ctx->top_pipe)
- return NULL;
-
- while (bottom_pipe) {
- if (bottom_pipe->stream_res.opp != pipe_ctx->stream_res.opp)
- break;
- bottom_pipe = bottom_pipe->bottom_pipe;
- }
-
- return bottom_pipe;
-}
-
-bool dc_res_is_odm_head_pipe(struct pipe_ctx *pipe_ctx)
-{
- struct pipe_ctx *top_pipe = pipe_ctx->top_pipe;
-
- if (!top_pipe)
- return false;
- if (top_pipe && top_pipe->stream_res.opp == pipe_ctx->stream_res.opp)
- return false;
-
- return true;
-}
-
bool dc_remove_plane_from_context(
const struct dc *dc,
struct dc_stream_state *stream,
@@ -1347,12 +1328,6 @@ bool dc_remove_plane_from_context(
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
if (pipe_ctx->plane_state == plane_state) {
- if (dc_res_is_odm_head_pipe(pipe_ctx)) {
- pipe_ctx->plane_state = NULL;
- pipe_ctx->bottom_pipe = NULL;
- continue;
- }
-
if (pipe_ctx->top_pipe)
pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
@@ -1367,13 +1342,10 @@ bool dc_remove_plane_from_context(
* For head pipe detach surfaces from pipe for tail
* pipe just zero it out
*/
- if (!pipe_ctx->top_pipe) {
+ if (!pipe_ctx->top_pipe)
pipe_ctx->plane_state = NULL;
- if (!dc_res_get_odm_bottom_pipe(pipe_ctx))
- pipe_ctx->bottom_pipe = NULL;
- } else {
+ else
memset(pipe_ctx, 0, sizeof(*pipe_ctx));
- }
}
}
@@ -1659,24 +1631,25 @@ static struct audio *find_first_free_audio(
const struct resource_pool *pool,
enum engine_id id)
{
- int i;
- for (i = 0; i < pool->audio_count; i++) {
+ int i, available_audio_count;
+
+ available_audio_count = pool->audio_count;
+
+ for (i = 0; i < available_audio_count; i++) {
if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) {
/*we have enough audio endpoint, find the matching inst*/
if (id != i)
continue;
-
return pool->audios[i];
}
}
- /* use engine id to find free audio */
- if ((id < pool->audio_count) && (res_ctx->is_audio_acquired[id] == false)) {
+ /* use engine id to find free audio */
+ if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) {
return pool->audios[id];
}
-
/*not found the matching one, first come first serve*/
- for (i = 0; i < pool->audio_count; i++) {
+ for (i = 0; i < available_audio_count; i++) {
if (res_ctx->is_audio_acquired[i] == false) {
return pool->audios[i];
}
@@ -1736,50 +1709,45 @@ enum dc_status dc_remove_stream_from_ctx(
{
int i;
struct dc_context *dc_ctx = dc->ctx;
- struct pipe_ctx *del_pipe = NULL;
+ struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream);
+ struct pipe_ctx *odm_pipe;
- /* Release primary pipe */
- for (i = 0; i < MAX_PIPES; i++) {
- if (new_ctx->res_ctx.pipe_ctx[i].stream == stream &&
- !new_ctx->res_ctx.pipe_ctx[i].top_pipe) {
- struct pipe_ctx *odm_pipe =
- dc_res_get_odm_bottom_pipe(&new_ctx->res_ctx.pipe_ctx[i]);
+ if (!del_pipe) {
+ DC_ERROR("Pipe not found for stream %p !\n", stream);
+ return DC_ERROR_UNEXPECTED;
+ }
- del_pipe = &new_ctx->res_ctx.pipe_ctx[i];
+ odm_pipe = del_pipe->next_odm_pipe;
- ASSERT(del_pipe->stream_res.stream_enc);
- update_stream_engine_usage(
- &new_ctx->res_ctx,
- dc->res_pool,
- del_pipe->stream_res.stream_enc,
- false);
+ /* Release primary pipe */
+ ASSERT(del_pipe->stream_res.stream_enc);
+ update_stream_engine_usage(
+ &new_ctx->res_ctx,
+ dc->res_pool,
+ del_pipe->stream_res.stream_enc,
+ false);
- if (del_pipe->stream_res.audio)
- update_audio_usage(
- &new_ctx->res_ctx,
- dc->res_pool,
- del_pipe->stream_res.audio,
- false);
+ if (del_pipe->stream_res.audio)
+ update_audio_usage(
+ &new_ctx->res_ctx,
+ dc->res_pool,
+ del_pipe->stream_res.audio,
+ false);
- resource_unreference_clock_source(&new_ctx->res_ctx,
- dc->res_pool,
- del_pipe->clock_source);
+ resource_unreference_clock_source(&new_ctx->res_ctx,
+ dc->res_pool,
+ del_pipe->clock_source);
- if (dc->res_pool->funcs->remove_stream_from_ctx)
- dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream);
+ if (dc->res_pool->funcs->remove_stream_from_ctx)
+ dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream);
- memset(del_pipe, 0, sizeof(*del_pipe));
- if (odm_pipe)
- memset(odm_pipe, 0, sizeof(*odm_pipe));
+ while (odm_pipe) {
+ struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe;
- break;
- }
- }
-
- if (!del_pipe) {
- DC_ERROR("Pipe not found for stream %p !\n", stream);
- return DC_ERROR_UNEXPECTED;
+ memset(odm_pipe, 0, sizeof(*odm_pipe));
+ odm_pipe = next_odm_pipe;
}
+ memset(del_pipe, 0, sizeof(*del_pipe));
for (i = 0; i < new_ctx->stream_count; i++)
if (new_ctx->streams[i] == stream)
@@ -1880,7 +1848,7 @@ static int acquire_resource_from_hw_enabled_state(
struct dc_stream_state *stream)
{
struct dc_link *link = stream->link;
- unsigned int inst;
+ unsigned int inst, tg_inst;
/* Check for enabled DIG to identify enabled display */
if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
@@ -1892,28 +1860,37 @@ static int acquire_resource_from_hw_enabled_state(
* current implementation always map 1-to-1, so this code makes
* the same assumption and doesn't check OTG source.
*/
- inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1;
+ inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
/* Instance should be within the range of the pool */
if (inst >= pool->pipe_count)
return -1;
- if (!res_ctx->pipe_ctx[inst].stream) {
- struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[inst];
+ if (inst >= pool->stream_enc_count)
+ return -1;
+
+ tg_inst = pool->stream_enc[inst]->funcs->dig_source_otg(pool->stream_enc[inst]);
- pipe_ctx->stream_res.tg = pool->timing_generators[inst];
- pipe_ctx->plane_res.mi = pool->mis[inst];
- pipe_ctx->plane_res.hubp = pool->hubps[inst];
- pipe_ctx->plane_res.ipp = pool->ipps[inst];
- pipe_ctx->plane_res.xfm = pool->transforms[inst];
- pipe_ctx->plane_res.dpp = pool->dpps[inst];
- pipe_ctx->stream_res.opp = pool->opps[inst];
- if (pool->dpps[inst])
- pipe_ctx->plane_res.mpcc_inst = pool->dpps[inst]->inst;
- pipe_ctx->pipe_idx = inst;
+ if (tg_inst >= pool->timing_generator_count)
+ return false;
+
+ if (!res_ctx->pipe_ctx[tg_inst].stream) {
+ struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];
+
+ pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
+ pipe_ctx->plane_res.mi = pool->mis[tg_inst];
+ pipe_ctx->plane_res.hubp = pool->hubps[tg_inst];
+ pipe_ctx->plane_res.ipp = pool->ipps[tg_inst];
+ pipe_ctx->plane_res.xfm = pool->transforms[tg_inst];
+ pipe_ctx->plane_res.dpp = pool->dpps[tg_inst];
+ pipe_ctx->stream_res.opp = pool->opps[tg_inst];
+
+ if (pool->dpps[tg_inst])
+ pipe_ctx->plane_res.mpcc_inst = pool->dpps[tg_inst]->inst;
+ pipe_ctx->pipe_idx = tg_inst;
pipe_ctx->stream = stream;
- return inst;
+ return tg_inst;
}
return -1;
@@ -2475,6 +2452,12 @@ void dc_resource_state_copy_construct(
if (cur_pipe->bottom_pipe)
cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
+
+ if (cur_pipe->next_odm_pipe)
+ cur_pipe->next_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];
+
+ if (cur_pipe->prev_odm_pipe)
+ cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
}
for (i = 0; i < dst_ctx->stream_count; i++) {
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index 352862370390..bf1d7bb90e0f 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -566,6 +566,7 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream,
return ret;
}
+
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream)
{
@@ -597,6 +598,14 @@ bool dc_stream_set_dynamic_metadata(struct dc *dc,
struct hubp *hubp;
int i;
+ /* Dynamic metadata is only supported on HDMI or DP */
+ if (!dc_is_hdmi_signal(stream->signal) && !dc_is_dp_signal(stream->signal))
+ return false;
+
+ /* Check hardware support */
+ if (!dc->hwss.program_dmdata_engine)
+ return false;
+
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx->stream == stream)
@@ -612,23 +621,7 @@ bool dc_stream_set_dynamic_metadata(struct dc *dc,
pipe_ctx->stream->dmdata_address = attr->address;
- if (pipe_ctx->stream_res.stream_enc &&
- pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata != NULL) {
- if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
- /* if using dynamic meta, don't set up generic infopackets */
- pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
- pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata(
- pipe_ctx->stream_res.stream_enc,
- true, pipe_ctx->plane_res.hubp->inst,
- dc_is_dp_signal(pipe_ctx->stream->signal) ?
- dmdata_dp : dmdata_hdmi);
- } else
- pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata(
- pipe_ctx->stream_res.stream_enc,
- false, pipe_ctx->plane_res.hubp->inst,
- dc_is_dp_signal(pipe_ctx->stream->signal) ?
- dmdata_dp : dmdata_hdmi);
- }
+ dc->hwss.program_dmdata_engine(pipe_ctx);
if (hubp->funcs->dmdata_set_attributes != NULL &&
pipe_ctx->stream->dmdata_address.quad_part != 0) {
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
index f40e4fd52fa2..b9d6a5bd8522 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
@@ -60,7 +60,6 @@ static void construct(struct dc_context *ctx, struct dc_plane_state *plane_state
plane_state->lut3d_func = dc_create_3dlut_func();
if (plane_state->lut3d_func != NULL) {
plane_state->lut3d_func->ctx = ctx;
- plane_state->lut3d_func->initialized = false;
}
plane_state->blend_tf = dc_create_transfer_func();
if (plane_state->blend_tf != NULL) {
@@ -279,7 +278,7 @@ struct dc_3dlut *dc_create_3dlut_func(void)
goto alloc_fail;
kref_init(&lut->refcount);
- lut->initialized = false;
+ lut->state.raw = 0;
return lut;