aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/files/0681-drm-amd-dal-virtual-link-and-sink-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/files/0681-drm-amd-dal-virtual-link-and-sink-support.patch')
-rw-r--r--common/recipes-kernel/linux/files/0681-drm-amd-dal-virtual-link-and-sink-support.patch667
1 files changed, 667 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0681-drm-amd-dal-virtual-link-and-sink-support.patch b/common/recipes-kernel/linux/files/0681-drm-amd-dal-virtual-link-and-sink-support.patch
new file mode 100644
index 00000000..41509b3c
--- /dev/null
+++ b/common/recipes-kernel/linux/files/0681-drm-amd-dal-virtual-link-and-sink-support.patch
@@ -0,0 +1,667 @@
+From d2375cf918a6a0fe2d6dce2b480e8e094ab2d074 Mon Sep 17 00:00:00 2001
+From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
+Date: Thu, 7 Jan 2016 18:09:48 -0500
+Subject: [PATCH 0681/1110] drm/amd/dal: virtual link and sink support
+
+Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
+Acked-by: Jordan Lazare <Jordan.Lazare@amd.com>
+---
+ .../drm/amd/dal/amdgpu_dm/amdgpu_dm_mst_types.c | 4 +-
+ .../gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.c | 2 +
+ drivers/gpu/drm/amd/dal/dc/core/dc.c | 44 +++++++++-------
+ drivers/gpu/drm/amd/dal/dc/core/dc_link.c | 16 +++---
+ drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c | 10 ++--
+ drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c | 2 +-
+ drivers/gpu/drm/amd/dal/dc/core/dc_resource.c | 5 +-
+ drivers/gpu/drm/amd/dal/dc/core/dc_sink.c | 12 ++---
+ drivers/gpu/drm/amd/dal/dc/core/dc_target.c | 4 +-
+ drivers/gpu/drm/amd/dal/dc/dc.h | 6 ++-
+ .../drm/amd/dal/dc/dce110/dce110_hw_sequencer.c | 58 +++++++++++-----------
+ .../gpu/drm/amd/dal/dc/dce110/dce110_resource.c | 14 ++++--
+ .../drm/amd/dal/dc/dce_base/dce_base_resource.c | 26 ++++++----
+ drivers/gpu/drm/amd/dal/dc/inc/core_dc.h | 2 +-
+ drivers/gpu/drm/amd/dal/dc/inc/core_types.h | 7 +--
+ drivers/gpu/drm/amd/dal/include/dal_types.h | 1 +
+ drivers/gpu/drm/amd/dal/include/signal_types.h | 3 +-
+ 17 files changed, 124 insertions(+), 92 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_mst_types.c
+index 80bd0c6..61e12ad 100644
+--- a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_mst_types.c
++++ b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_mst_types.c
+@@ -119,7 +119,7 @@ static struct dc_sink *dm_dp_mst_add_mst_sink(
+ uint16_t len)
+ {
+ struct dc_sink *dc_sink;
+- struct sink_init_data init_params = {
++ struct dc_sink_init_data init_params = {
+ .link = dc_link,
+ .sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST};
+ enum dc_edid_status edid_status;
+@@ -139,7 +139,7 @@ static struct dc_sink *dm_dp_mst_add_mst_sink(
+ * dc_link->connector_signal;
+ */
+
+- dc_sink = sink_create(&init_params);
++ dc_sink = dc_sink_create(&init_params);
+
+ if (!dc_sink)
+ return NULL;
+diff --git a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.c b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.c
+index 00a0139..7df2d28 100644
+--- a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.c
++++ b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.c
+@@ -1605,6 +1605,8 @@ static int to_drm_connector_type(enum signal_type st)
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ return DRM_MODE_CONNECTOR_DVID;
++ case SIGNAL_TYPE_VIRTUAL:
++ return DRM_MODE_CONNECTOR_VIRTUAL;
+
+ default:
+ return DRM_MODE_CONNECTOR_Unknown;
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc.c b/drivers/gpu/drm/amd/dal/dc/core/dc.c
+index 96ec35f..397b664 100644
+--- a/drivers/gpu/drm/amd/dal/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc.c
+@@ -92,14 +92,6 @@ static bool create_links(struct dc *dc, const struct dc_init_data *init_params)
+ dal_output_to_console("%s: connectors_num:%d\n", __func__,
+ connectors_num);
+
+- dc->links = dc_service_alloc(
+- init_params->ctx, connectors_num * sizeof(struct core_link *));
+-
+- if (NULL == dc->links) {
+- dal_error("DC: failed to allocate 'links' storage!\n");
+- goto allocate_dc_links_storage_fail;
+- }
+-
+ for (i = 0; i < connectors_num; i++) {
+ struct link_init_data link_init_params = {0};
+ struct core_link *link;
+@@ -121,14 +113,28 @@ static bool create_links(struct dc *dc, const struct dc_init_data *init_params)
+ }
+ }
+
+- if (!dc->link_count) {
+- dal_error("DC: no 'links' were created!\n");
+- goto allocate_dc_links_storage_fail;
++ for (i = 0; i < init_params->num_virtual_links; i++) {
++ struct core_link *link =
++ dc_service_alloc(dc->ctx, sizeof(*link));
++
++ if (link == NULL) {
++ BREAK_TO_DEBUGGER();
++ goto failed_alloc;
++ }
++
++ link->adapter_srv = init_params->adapter_srv;
++ link->ctx = init_params->ctx;
++ link->dc = dc;
++ link->public.connector_signal = SIGNAL_TYPE_VIRTUAL;
++
++ link->public.link_index = dc->link_count;
++ dc->links[dc->link_count] = link;
++ dc->link_count++;
+ }
+
+ return true;
+
+-allocate_dc_links_storage_fail:
++failed_alloc:
+ return false;
+ }
+
+@@ -165,7 +171,8 @@ static void init_hw(struct dc *dc)
+ * required signal (which may be different from the
+ * default signal on connector). */
+ struct core_link *link = dc->links[i];
+- dc->hwss.encoder_hw_init(link->link_enc);
++ if (link->public.connector_signal != SIGNAL_TYPE_VIRTUAL)
++ dc->hwss.encoder_hw_init(link->link_enc);
+ }
+
+ for(i = 0; i < dc->res_pool.controller_count; i++) {
+@@ -291,6 +298,7 @@ static bool construct(struct dc *dc, const struct dal_init_data *init_params)
+ }
+ dc_init_data.ctx->driver_context = init_params->driver;
+ dc_init_data.ctx->cgs_device = init_params->cgs_device;
++ dc_init_data.num_virtual_links = init_params->num_virtual_links;
+ dc_init_data.ctx->dc = dc;
+
+ /* Create logger */
+@@ -359,7 +367,6 @@ ctx_fail:
+ static void destruct(struct dc *dc)
+ {
+ destroy_links(dc);
+- dc_service_free(dc->ctx, dc->links);
+ dc->hwss.destruct_resource_pool(&dc->res_pool);
+ dal_logger_destroy(&dc->ctx->logger);
+ dc_service_free(dc->ctx, dc->ctx);
+@@ -623,9 +630,9 @@ const struct audio **dc_get_audios(struct dc *dc)
+
+ void dc_get_caps(const struct dc *dc, struct dc_caps *caps)
+ {
+- caps->max_targets = dc->res_pool.controller_count;
+- caps->max_links = dc->link_count;
+- caps->max_audios = dc->res_pool.audio_count;
++ caps->max_targets = dc->res_pool.controller_count;
++ caps->max_links = dc->link_count;
++ caps->max_audios = dc->res_pool.audio_count;
+ }
+
+ void dc_flip_surface_addrs(struct dc* dc,
+@@ -843,6 +850,9 @@ bool dc_link_add_sink(const struct dc_link *link, struct dc_sink *sink)
+
+ dc_link->sink[link->sink_count] = sink;
+ dc_link->sink_count++;
++ if (sink->sink_signal == SIGNAL_TYPE_VIRTUAL
++ && link->connector_signal == SIGNAL_TYPE_VIRTUAL)
++ dc_link->type = dc_connection_single;
+
+ return true;
+ }
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_link.c b/drivers/gpu/drm/amd/dal/dc/core/dc_link.c
+index 794465e..2ef0451 100644
+--- a/drivers/gpu/drm/amd/dal/dc/core/dc_link.c
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link.c
+@@ -553,7 +553,7 @@ static void dc_link_detect_dp(
+ void dc_link_detect(const struct dc_link *dc_link)
+ {
+ struct core_link *link = DC_LINK_TO_LINK(dc_link);
+- struct sink_init_data sink_init_data = { 0 };
++ struct dc_sink_init_data sink_init_data = { 0 };
+ struct display_sink_capability sink_caps = { 0 };
+ uint8_t i;
+ bool converter_disable_audio = false;
+@@ -566,6 +566,9 @@ void dc_link_detect(const struct dc_link *dc_link)
+ struct core_sink *sink = NULL;
+ enum dc_connection_type new_connection_type = dc_connection_none;
+
++ if (link->public.connector_signal == SIGNAL_TYPE_VIRTUAL)
++ return;
++
+ if (false == detect_sink(link, &new_connection_type)) {
+ BREAK_TO_DEBUGGER();
+ return;
+@@ -647,7 +650,7 @@ void dc_link_detect(const struct dc_link *dc_link)
+ sink_init_data.converter_disable_audio =
+ converter_disable_audio;
+
+- dc_sink = sink_create(&sink_init_data);
++ dc_sink = dc_sink_create(&sink_init_data);
+ if (!dc_sink) {
+ DC_ERROR("Failed to create sink!\n");
+ return;
+@@ -835,7 +838,6 @@ static bool construct(
+
+ link->dc = init_params->dc;
+ link->adapter_srv = as;
+- link->connector_index = init_params->connector_index;
+ link->ctx = dc_ctx;
+ link->public.link_index = init_params->link_index;
+
+@@ -994,7 +996,6 @@ struct core_link *link_create(const struct link_init_data *init_params)
+ {
+ struct core_link *link =
+ dc_service_alloc(init_params->ctx, sizeof(*link));
+- link->ctx = init_params->ctx;
+
+ if (NULL == link)
+ goto alloc_fail;
+@@ -1063,9 +1064,9 @@ static void dpcd_configure_panel_mode(
+ }
+ dal_logger_write(link->ctx->logger, LOG_MAJOR_DETECTION,
+ LOG_MINOR_DETECTION_DP_CAPS,
+- "Connector: %d eDP panel mode supported: %d "
++ "Link: %d eDP panel mode supported: %d "
+ "eDP panel mode enabled: %d \n",
+- link->connector_index,
++ link->public.link_index,
+ link->dpcd_caps.panel_mode_edp,
+ panel_mode_edp);
+ }
+@@ -1268,7 +1269,8 @@ bool dc_link_set_backlight_level(const struct dc_link *public, uint32_t level)
+
+ void core_link_resume(struct core_link *link)
+ {
+- program_hpd_filter(link);
++ if (link->public.connector_signal != SIGNAL_TYPE_VIRTUAL)
++ program_hpd_filter(link);
+ }
+
+ static struct fixed31_32 get_pbn_per_slot(struct core_stream *stream)
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c
+index 787091f..4c17ff1 100644
+--- a/drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c
+@@ -1404,8 +1404,8 @@ bool dc_link_handle_hpd_rx_irq(const struct dc_link *dc_link)
+ dal_logger_write(link->ctx->logger,
+ LOG_MAJOR_HW_TRACE,
+ LOG_MINOR_HW_TRACE_HPD_IRQ,
+- "%s: Got short pulse HPD on connector %d\n",
+- __func__, link->connector_index);
++ "%s: Got short pulse HPD on link %d\n",
++ __func__, link->public.link_index);
+
+ /* All the "handle_hpd_irq_xxx()" methods
+ * should be called only after
+@@ -1582,16 +1582,16 @@ static void dp_wa_power_up_0010FA(struct core_link *link, uint8_t *dpcd_data,
+ * keep receiver powered all the time.*/
+ case DP_BRANCH_DEVICE_ID_1:
+ case DP_BRANCH_DEVICE_ID_4:
+- link->dp_wa.bits.KEEP_RECEIVER_POWERED = 1;
++ link->wa_flags.dp_keep_receiver_powered = true;
+ break;
+
+ /* TODO: May need work around for other dongles. */
+ default:
+- link->dp_wa.bits.KEEP_RECEIVER_POWERED = 0;
++ link->wa_flags.dp_keep_receiver_powered = false;
+ break;
+ }
+ } else
+- link->dp_wa.bits.KEEP_RECEIVER_POWERED = 0;
++ link->wa_flags.dp_keep_receiver_powered = false;
+ }
+
+ static void retrieve_link_cap(struct core_link *link)
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c
+index 27acac8..e9ae9e1 100644
+--- a/drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c
+@@ -72,7 +72,7 @@ void dp_enable_link_phy(
+
+ void dp_disable_link_phy(struct core_link *link, enum signal_type signal)
+ {
+- if (!link->dp_wa.bits.KEEP_RECEIVER_POWERED)
++ if (!link->wa_flags.dp_keep_receiver_powered)
+ dp_receiver_power_ctrl(link, false);
+
+ link->dc->hwss.encoder_disable_output(link->link_enc, signal);
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c b/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
+index 1ad317a..557f918 100644
+--- a/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
+@@ -457,8 +457,11 @@ static void fill_display_configs(
+ cfg->src_width = stream->public.src.width;
+ cfg->ddi_channel_mapping =
+ stream->sink->link->ddi_channel_mapping.raw;
+- cfg->transmitter =
++ if (stream->signal != SIGNAL_TYPE_VIRTUAL)
++ cfg->transmitter =
+ stream->sink->link->link_enc->transmitter;
++ else
++ cfg->transmitter = TRANSMITTER_UNKNOWN;
+ cfg->link_settings =
+ stream->sink->link->cur_link_settings;
+ cfg->sym_clock = stream->public.timing.pix_clk_khz;
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_sink.c b/drivers/gpu/drm/amd/dal/dc/core/dc_sink.c
+index 3d537d5..608fb99 100644
+--- a/drivers/gpu/drm/amd/dal/dc/core/dc_sink.c
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_sink.c
+@@ -48,7 +48,7 @@ static void destruct(struct sink *sink)
+
+ }
+
+-static bool construct(struct sink *sink, const struct sink_init_data *init_params)
++static bool construct(struct sink *sink, const struct dc_sink_init_data *init_params)
+ {
+
+ struct core_link *core_link = DC_LINK_TO_LINK(init_params->link);
+@@ -87,12 +87,7 @@ void dc_sink_release(const struct dc_sink *dc_sink)
+ }
+ }
+
+-
+-/*******************************************************************************
+- * Protected functions - visible only inside of DC (not visible in DM)
+- ******************************************************************************/
+-
+-struct dc_sink *sink_create(const struct sink_init_data *init_params)
++struct dc_sink *dc_sink_create(const struct dc_sink_init_data *init_params)
+ {
+ struct core_link *core_link = DC_LINK_TO_LINK(init_params->link);
+
+@@ -116,3 +111,6 @@ alloc_fail:
+ return NULL;
+ }
+
++/*******************************************************************************
++ * Protected functions - visible only inside of DC (not visible in DM)
++ ******************************************************************************/
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_target.c b/drivers/gpu/drm/amd/dal/dc/core/dc_target.c
+index 31374ab..b8420bf 100644
+--- a/drivers/gpu/drm/amd/dal/dc/core/dc_target.c
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_target.c
+@@ -497,7 +497,7 @@ void dc_target_log(
+ dal_logger_write(dal_logger,
+ log_major,
+ log_minor,
+- "\tconnector: %d",
+- core_stream->sink->link->connector_index);
++ "\tlink: %d",
++ core_stream->sink->link->public.link_index);
+ }
+ }
+diff --git a/drivers/gpu/drm/amd/dal/dc/dc.h b/drivers/gpu/drm/amd/dal/dc/dc.h
+index 007fdc4..bcfd96d 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dc.h
++++ b/drivers/gpu/drm/amd/dal/dc/dc.h
+@@ -40,6 +40,7 @@
+ struct dc_init_data {
+ struct dc_context *ctx;
+ struct adapter_service *adapter_srv;
++ uint8_t num_virtual_links;
+ };
+
+ struct dc_caps {
+@@ -311,6 +312,7 @@ void dc_link_remove_sink(
+ const struct dc_link *link,
+ const struct dc_sink *sink);
+
++
+ /*******************************************************************************
+ * Sink Interfaces - A sink corresponds to a display output device
+ ******************************************************************************/
+@@ -329,14 +331,14 @@ void dc_sink_release(const struct dc_sink *sink);
+
+ const struct audio **dc_get_audios(struct dc *dc);
+
+-struct sink_init_data {
++struct dc_sink_init_data {
+ enum signal_type sink_signal;
+ const struct dc_link *link;
+ uint32_t dongle_max_pix_clk;
+ bool converter_disable_audio;
+ };
+
+-struct dc_sink *sink_create(const struct sink_init_data *init_params);
++struct dc_sink *dc_sink_create(const struct dc_sink_init_data *init_params);
+
+
+ /*******************************************************************************
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
+index 0d8b050..4f37282 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
+@@ -802,8 +802,8 @@ static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx,
+ */
+ stream->tg->funcs->set_blank(stream->tg, true);
+
+- core_link_disable_stream(
+- stream->sink->link, stream);
++ if (stream->signal != SIGNAL_TYPE_VIRTUAL)
++ core_link_disable_stream(stream->sink->link, stream);
+
+ /*TODO: AUTO check if timing changed*/
+ if (false == dal_clock_source_program_pix_clk(
+@@ -822,9 +822,10 @@ static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx,
+ }
+
+ /*TODO: mst support - use total stream count*/
+- dce110_mem_input_allocate_dmif_buffer(stream->mi,
+- &stream->public.timing,
+- context->target_count);
++ dce110_mem_input_allocate_dmif_buffer(
++ stream->mi,
++ &stream->public.timing,
++ context->target_count);
+
+ if (timing_changed) {
+ if (false == stream->tg->funcs->enable_crtc(
+@@ -834,10 +835,11 @@ static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx,
+ }
+ }
+
+- if (DC_OK != bios_parser_crtc_source_select(stream)) {
+- BREAK_TO_DEBUGGER();
+- return DC_ERROR_UNEXPECTED;
+- }
++ if (stream->signal != SIGNAL_TYPE_VIRTUAL)
++ if (DC_OK != bios_parser_crtc_source_select(stream)) {
++ BREAK_TO_DEBUGGER();
++ return DC_ERROR_UNEXPECTED;
++ }
+
+ dce110_opp_set_dyn_expansion(
+ opp,
+@@ -845,14 +847,12 @@ static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx,
+ stream->public.timing.display_color_depth,
+ stream->sink->public.sink_signal);
+
+- program_fmt(
+- opp,
+- &stream->fmt_bit_depth,
+- &stream->clamping);
++ program_fmt(opp, &stream->fmt_bit_depth, &stream->clamping);
+
+- dce110_link_encoder_setup(
+- stream->sink->link->link_enc,
+- stream->signal);
++ if (stream->signal != SIGNAL_TYPE_VIRTUAL)
++ dce110_link_encoder_setup(
++ stream->sink->link->link_enc,
++ stream->signal);
+
+ if (dc_is_dp_signal(stream->signal))
+ stream->stream_enc->funcs->dp_set_stream_attribute(
+@@ -861,16 +861,16 @@ static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx,
+
+ if (dc_is_hdmi_signal(stream->signal))
+ stream->stream_enc->funcs->hdmi_set_stream_attribute(
+- stream->stream_enc,
+- &stream->public.timing,
+- stream->audio != NULL);
++ stream->stream_enc,
++ &stream->public.timing,
++ stream->audio != NULL);
+
+ if (dc_is_dvi_signal(stream->signal))
+ stream->stream_enc->funcs->dvi_set_stream_attribute(
+- stream->stream_enc,
+- &stream->public.timing,
+- (stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
+- true : false);
++ stream->stream_enc,
++ &stream->public.timing,
++ (stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
++ true : false);
+
+ if (stream->audio != NULL) {
+ if (AUDIO_RESULT_OK != dal_audio_setup(
+@@ -891,14 +891,12 @@ static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx,
+ &stream->audio_output.pll_info);
+
+ /* program blank color */
+- color_space = get_output_color_space(
+- &stream->public.timing);
+-
++ color_space = get_output_color_space(&stream->public.timing);
+ stream->tg->funcs->set_blank_color(
+ context->res_ctx.pool.timing_generators[controller_idx],
+ color_space);
+
+- if (timing_changed) {
++ if (timing_changed && stream->signal != SIGNAL_TYPE_VIRTUAL) {
+ core_link_enable_stream(stream->sink->link, stream);
+ } else {
+ core_link_update_stream(stream->sink->link, stream);
+@@ -918,7 +916,8 @@ static void power_down_encoders(struct dc *dc)
+ int i;
+
+ for (i = 0; i < dc->link_count; i++) {
+- dce110_link_encoder_disable_output(
++ if (dc->links[i]->public.connector_signal != SIGNAL_TYPE_VIRTUAL)
++ dce110_link_encoder_disable_output(
+ dc->links[i]->link_enc, SIGNAL_TYPE_NONE);
+ }
+ }
+@@ -1571,7 +1570,8 @@ static void reset_single_stream_hw_ctx(struct core_stream *stream,
+ stream->audio = NULL;
+ }
+
+- core_link_disable_stream(stream->sink->link, stream);
++ if (stream->signal != SIGNAL_TYPE_VIRTUAL)
++ core_link_disable_stream(stream->sink->link, stream);
+
+ stream->tg->funcs->set_blank(stream->tg, true);
+ stream->tg->funcs->disable_crtc(stream->tg);
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c
+index 266b761..f3610b4 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c
+@@ -528,14 +528,17 @@ static enum dc_status validate_mapped_resource(
+ DC_STREAM_TO_CORE(target->public.streams[j]);
+ struct core_link *link = stream->sink->link;
+
+- status = build_stream_hw_param(stream);
++ if (!stream->tg->funcs->validate_timing(
++ stream->tg, &stream->public.timing))
++ return DC_FAIL_CONTROLLER_VALIDATE;
+
+- if (status != DC_OK)
++ if (stream->signal == SIGNAL_TYPE_VIRTUAL)
+ return status;
+
+- if (!stream->tg->funcs->validate_timing(stream->tg, &stream->public.timing))
+- return DC_FAIL_CONTROLLER_VALIDATE;
++ status = build_stream_hw_param(stream);
+
++ if (status != DC_OK)
++ return status;
+
+ if (!dce110_link_encoder_validate_output_with_stream(
+ link->link_enc,
+@@ -781,7 +784,8 @@ static enum dc_status map_clock_resources(
+ struct core_stream *stream =
+ DC_STREAM_TO_CORE(target->public.streams[j]);
+
+- if (dc_is_dp_signal(stream->signal))
++ if (dc_is_dp_signal(stream->signal)
++ || stream->signal == SIGNAL_TYPE_VIRTUAL)
+ stream->clock_source = context->res_ctx.
+ pool.clock_sources[DCE110_CLK_SRC_EXT];
+ else
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce_base/dce_base_resource.c b/drivers/gpu/drm/amd/dal/dc/dce_base/dce_base_resource.c
+index 1b091be..85cff3b 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dce_base/dce_base_resource.c
++++ b/drivers/gpu/drm/amd/dal/dc/dce_base/dce_base_resource.c
+@@ -227,6 +227,23 @@ enum dc_status dce_base_map_resources(
+
+ attach_stream_to_controller(&context->res_ctx, stream);
+
++ set_stream_signal(stream);
++
++ curr_stream =
++ dc->current_context.res_ctx.controller_ctx
++ [stream->controller_idx].stream;
++ context->res_ctx.controller_ctx[stream->controller_idx]
++ .flags.timing_changed =
++ check_timing_change(curr_stream, stream);
++
++ /*
++ * we do not need stream encoder or audio resources
++ * when connecting to virtual link
++ */
++ if (stream->sink->link->public.connector_signal ==
++ SIGNAL_TYPE_VIRTUAL)
++ continue;
++
+ stream->stream_enc =
+ find_first_free_match_stream_enc_for_link(
+ &context->res_ctx,
+@@ -239,8 +256,6 @@ enum dc_status dce_base_map_resources(
+ &context->res_ctx,
+ stream->stream_enc);
+
+- set_stream_signal(stream);
+-
+ /* TODO: Add check if ASIC support and EDID audio */
+ if (!stream->sink->converter_disable_audio &&
+ dc_is_audio_capable_signal(
+@@ -254,13 +269,6 @@ enum dc_status dce_base_map_resources(
+ set_audio_in_use(&context->res_ctx,
+ stream->audio);
+ }
+- curr_stream =
+- dc->current_context.res_ctx.controller_ctx
+- [stream->controller_idx].stream;
+- context->res_ctx.controller_ctx[stream->controller_idx]
+- .flags.timing_changed =
+- check_timing_change(curr_stream, stream);
+-
+ }
+ }
+
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/core_dc.h b/drivers/gpu/drm/amd/dal/dc/inc/core_dc.h
+index 66f7544..9d62a24 100644
+--- a/drivers/gpu/drm/amd/dal/dc/inc/core_dc.h
++++ b/drivers/gpu/drm/amd/dal/dc/inc/core_dc.h
+@@ -17,7 +17,7 @@ struct dc {
+
+ /** link-related data - begin **/
+ uint8_t link_count;
+- struct core_link **links;
++ struct core_link *links[MAX_PIPES * 2];
+ /** link-related data - end **/
+
+ /* TODO: determine max number of targets*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/core_types.h b/drivers/gpu/drm/amd/dal/dc/inc/core_types.h
+index 5f918c1..192399b 100644
+--- a/drivers/gpu/drm/amd/dal/dc/inc/core_types.h
++++ b/drivers/gpu/drm/amd/dal/dc/inc/core_types.h
+@@ -202,8 +202,6 @@ struct core_link {
+
+ struct dc_context *ctx; /* TODO: AUTO remove 'dal' when DC is complete*/
+
+- uint8_t connector_index; /* this will be mapped to the HPD pins */
+-
+ struct adapter_service *adapter_srv;
+ struct link_encoder *link_enc;
+ struct ddc_service *ddc;
+@@ -221,10 +219,13 @@ struct core_link {
+ unsigned int dpcd_sink_count;
+
+ enum edp_revision edp_revision;
+- union dp_wa dp_wa;
+
+ /* MST record stream using this link */
+ struct dp_mst_stream_allocation_table stream_alloc_table;
++
++ struct link_flags {
++ bool dp_keep_receiver_powered;
++ } wa_flags;
+ };
+
+ #define DC_LINK_TO_LINK(dc_link) container_of(dc_link, struct core_link, public)
+diff --git a/drivers/gpu/drm/amd/dal/include/dal_types.h b/drivers/gpu/drm/amd/dal/include/dal_types.h
+index 5539c19..5ec4784 100644
+--- a/drivers/gpu/drm/amd/dal/include/dal_types.h
++++ b/drivers/gpu/drm/amd/dal/include/dal_types.h
+@@ -136,6 +136,7 @@ struct dal_init_data {
+ struct dal_override_parameters display_param;
+ void *driver; /* ctx */
+ void *cgs_device;
++ uint8_t num_virtual_links;
+ };
+
+ struct dal_dc_init_data {
+diff --git a/drivers/gpu/drm/amd/dal/include/signal_types.h b/drivers/gpu/drm/amd/dal/include/signal_types.h
+index e95e821..a50f7ed 100644
+--- a/drivers/gpu/drm/amd/dal/include/signal_types.h
++++ b/drivers/gpu/drm/amd/dal/include/signal_types.h
+@@ -37,8 +37,9 @@ enum signal_type {
+ SIGNAL_TYPE_DISPLAY_PORT_MST = (1 << 6),
+ SIGNAL_TYPE_EDP = (1 << 7),
+ SIGNAL_TYPE_WIRELESS = (1 << 8), /* Wireless Display */
++ SIGNAL_TYPE_VIRTUAL = (1 << 9), /* Virtual Display */
+
+- SIGNAL_TYPE_COUNT = 9,
++ SIGNAL_TYPE_COUNT = 10,
+ SIGNAL_TYPE_ALL = (1 << SIGNAL_TYPE_COUNT) - 1
+ };
+
+--
+2.7.4
+