diff options
Diffstat (limited to 'meta-amdfalconx86/recipes-kernel/linux/linux-yocto/0833-drm-amd-dal-MST-two-monitors-light-up-add-PHY-payloa.patch')
-rw-r--r-- | meta-amdfalconx86/recipes-kernel/linux/linux-yocto/0833-drm-amd-dal-MST-two-monitors-light-up-add-PHY-payloa.patch | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/meta-amdfalconx86/recipes-kernel/linux/linux-yocto/0833-drm-amd-dal-MST-two-monitors-light-up-add-PHY-payloa.patch b/meta-amdfalconx86/recipes-kernel/linux/linux-yocto/0833-drm-amd-dal-MST-two-monitors-light-up-add-PHY-payloa.patch new file mode 100644 index 00000000..bfc57e0d --- /dev/null +++ b/meta-amdfalconx86/recipes-kernel/linux/linux-yocto/0833-drm-amd-dal-MST-two-monitors-light-up-add-PHY-payloa.patch @@ -0,0 +1,501 @@ +From d24bfe14dd3238ae4622babb9139ffd5b781f8cb Mon Sep 17 00:00:00 2001 +From: Hersen Wu <hersenxs.wu@amd.com> +Date: Mon, 23 Nov 2015 15:44:57 -0500 +Subject: [PATCH 0833/1050] drm/amd/dal: MST two monitors light up add PHY + payload alloaction 2 + +Change-Id: I21466fbb56ce870c922f7c6cedca31b897418afa +Signed-off-by: Hersen Wu <hersenxs.wu@amd.com> +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Acked-by: Harry Wentland <harry.wentland@amd.com> +--- + .../gpu/drm/amd/dal/amdgpu_dm/amdgpu_dc_helpers.c | 116 ++++++++++++++++++++- + drivers/gpu/drm/amd/dal/dc/core/dc_link.c | 63 ++++++++++- + drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c | 17 ++- + drivers/gpu/drm/amd/dal/dc/dc_helpers.h | 2 +- + .../drm/amd/dal/dc/dce110/dce110_hw_sequencer.c | 40 ++++--- + .../drm/amd/dal/dc/dce110/dce110_link_encoder.c | 7 +- + drivers/gpu/drm/amd/dal/dc/inc/core_types.h | 3 + + drivers/gpu/drm/amd/dal/dc/inc/link_hwss.h | 2 + + .../gpu/drm/amd/dal/include/link_service_types.h | 9 +- + 9 files changed, 228 insertions(+), 31 deletions(-) + +diff --git a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dc_helpers.c b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dc_helpers.c +index c3b6715..7a07af5 100644 +--- a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dc_helpers.c ++++ b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dc_helpers.c +@@ -32,6 +32,8 @@ + #include <drm/drm_edid.h> + + #include "dc_types.h" ++#include "core_types.h" ++#include "stream_encoder_types.h" + #include "amdgpu.h" + #include "dc.h" + #include "dc_services.h" +@@ -167,12 +169,14 @@ static struct amdgpu_connector *get_connector_for_link( + bool dc_helpers_dp_mst_write_payload_allocation_table( + struct dc_context *ctx, + const struct dc_sink *sink, +- struct dp_mst_stream_allocation *alloc_entity, ++ struct dp_mst_stream_allocation_table *table, + bool enable) + { + struct amdgpu_device *adev = ctx->driver_context; + struct drm_device *dev = adev->ddev; + struct amdgpu_connector *aconnector; ++ struct drm_connector *connector; ++ struct amdgpu_crtc *amdgpu_crtc; + struct drm_crtc *crtc; + struct drm_dp_mst_topology_mgr *mst_mgr; + struct drm_dp_mst_port *mst_port; +@@ -181,10 +185,16 @@ bool dc_helpers_dp_mst_write_payload_allocation_table( + int clock; + int bpp; + int pbn = 0; ++ uint8_t i; ++ uint8_t vcid; ++ bool find_stream_for_sink; + + aconnector = get_connector_for_sink(dev, sink); + crtc = aconnector->base.state->crtc; + ++ if (!crtc) ++ return false; ++ + if (!aconnector->mst_port) + return false; + +@@ -201,6 +211,8 @@ bool dc_helpers_dp_mst_write_payload_allocation_table( + pbn = drm_dp_calc_pbn_mode(clock, bpp); + + ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port, pbn, &slots); ++ /* mst_port->vcpi.vcpi is vc_id for this stream.*/ ++ vcid = mst_port->vcpi.vcpi; + + if (!ret) + return false; +@@ -209,11 +221,105 @@ bool dc_helpers_dp_mst_write_payload_allocation_table( + drm_dp_mst_reset_vcpi_slots(mst_mgr, mst_port); + } + +- alloc_entity->slot_count = slots; +- alloc_entity->pbn = pbn; +- alloc_entity->pbn_per_slot = mst_mgr->pbn_div; +- + ret = drm_dp_update_payload_part1(mst_mgr); ++ ++ /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or ++ * AUX message. The sequence is slot 1-63 allocated sequence for each ++ * stream. AMD ASIC stream slot allocation should follow the same ++ * sequence. copy DRM MST allocation to dc */ ++ ++ mutex_lock(&mst_mgr->payload_lock); ++ ++ /* number of active streams */ ++ for (i = 0; i < mst_mgr->max_payloads; i++) { ++ if (mst_mgr->payloads[i].num_slots == 0) ++ break; ++ table->stream_count++; ++ } ++ ++ for (i = 0; i < table->stream_count; i++) { ++ table->stream_allocations[i].slot_count = ++ mst_mgr->proposed_vcpis[i]->num_slots; ++ /* mst_mgr->pbn_div is fixed value after link training for ++ * current link PHY */ ++ table->stream_allocations[i].pbn_per_slot = mst_mgr->pbn_div; ++ ++ /* find which payload is for current stream ++ * after drm_dp_update_payload_part1, payload and proposed_vcpis ++ * are sync to the same allocation sequence. vcpi is not saved ++ * into payload by drm_dp_update_payload_part1. In order to ++ * find sequence of a payload within allocation sequence, we ++ * need check vcpi from proposed_vcpis*/ ++ ++ table->stream_allocations[i].pbn = ++ mst_mgr->proposed_vcpis[i]->pbn; ++ ++ if (mst_mgr->proposed_vcpis[i]->vcpi == vcid) ++ table->cur_stream_payload_idx = i; ++ ++ find_stream_for_sink = false; ++ ++ list_for_each_entry(connector, ++ &dev->mode_config.connector_list, head) { ++ ++ aconnector = to_amdgpu_connector(connector); ++ ++ /* not mst connector */ ++ if (!aconnector->mst_port) ++ continue; ++ mst_port = aconnector->port; ++ ++ if (mst_port->vcpi.vcpi == ++ mst_mgr->proposed_vcpis[i]->vcpi) { ++ /* find connector with same vcid as payload */ ++ ++ const struct dc_sink *dc_sink_connector; ++ struct core_sink *core_sink; ++ struct dc_target *dc_target; ++ struct core_target *core_target; ++ struct stream_encoder *stream_enc; ++ uint8_t j; ++ ++ dc_sink_connector = aconnector->dc_sink; ++ core_sink = DC_SINK_TO_CORE(dc_sink_connector); ++ ++ /* find stream to drive this sink ++ * crtc -> target -> stream -> sink */ ++ crtc = aconnector->base.state->crtc; ++ amdgpu_crtc = to_amdgpu_crtc(crtc); ++ dc_target = amdgpu_crtc->target; ++ core_target = DC_TARGET_TO_CORE(dc_target); ++ ++ for (j = 0; j < core_target->stream_count; ++ j++) { ++ if (core_target->streams[j]->sink == ++ core_sink) ++ break; ++ } ++ ++ if (j < core_target->stream_count) { ++ /* find sink --> stream --> target --> ++ * connector*/ ++ stream_enc = ++ core_target->streams[j]->stream_enc; ++ table->stream_allocations[i].engine = ++ stream_enc->id; ++ /* exit loop connector */ ++ find_stream_for_sink = true; ++ break; ++ } ++ } ++ } ++ if (!find_stream_for_sink) { ++ /* TODO: do not find stream for sink. This should not ++ * happen ++ */ ++ ASSERT(0); ++ } ++ } ++ ++ mutex_unlock(&mst_mgr->payload_lock); ++ + if (ret) + return false; + +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 a0a131e..54766ae 100644 +--- a/drivers/gpu/drm/amd/dal/dc/core/dc_link.c ++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link.c +@@ -708,6 +708,7 @@ static bool construct( + dal_adapter_service_release_irq( + init_params->adapter_srv, hpd_gpio); + } ++ + break; + case CONNECTOR_ID_EDP: + link->public.connector_signal = SIGNAL_TYPE_EDP; +@@ -915,6 +916,51 @@ static enum dc_status enable_link_dp(struct core_stream *stream) + return status; + } + ++static enum dc_status enable_link_dp_mst(struct core_stream *stream) ++{ ++ enum dc_status status; ++ bool skip_video_pattern; ++ struct core_link *link = stream->sink->link; ++ struct link_settings link_settings = {0}; ++ enum dp_panel_mode panel_mode; ++ ++ /* sink signal type after MST branch is MST. Multiple MST sinks ++ * share one link. Link DP PHY is enable or training only once. ++ */ ++ if (link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) ++ return DC_OK; ++ ++ /* get link settings for video mode timing */ ++ decide_link_settings(stream, &link_settings); ++ status = dp_enable_link_phy( ++ stream->sink->link, ++ stream->signal, ++ stream->stream_enc->id, ++ &link_settings); ++ ++ panel_mode = dp_get_panel_mode(link); ++ dpcd_configure_panel_mode(link, panel_mode); ++ ++ skip_video_pattern = true; ++ ++ if (link_settings.link_rate == LINK_RATE_LOW) ++ skip_video_pattern = false; ++ ++ if (perform_link_training(link, &link_settings, skip_video_pattern)) { ++ link->cur_link_settings = link_settings; ++ ++ /* TODO MST link shared by stream. counter? */ ++ if (link->stream_count < 4) ++ link->stream_count++; ++ ++ status = DC_OK; ++ } ++ else ++ status = DC_ERROR_UNEXPECTED; ++ ++ return status; ++} ++ + static enum dc_status enable_link_hdmi(struct core_stream *stream) + { + struct core_link *link = stream->sink->link; +@@ -977,11 +1023,13 @@ enum dc_status core_link_enable(struct core_stream *stream) + { + enum dc_status status; + switch (stream->signal) { +- case SIGNAL_TYPE_DISPLAY_PORT_MST: + case SIGNAL_TYPE_DISPLAY_PORT: + case SIGNAL_TYPE_EDP: + status = enable_link_dp(stream); + break; ++ case SIGNAL_TYPE_DISPLAY_PORT_MST: ++ status = enable_link_dp_mst(stream); ++ break; + case SIGNAL_TYPE_DVI_SINGLE_LINK: + case SIGNAL_TYPE_DVI_DUAL_LINK: + case SIGNAL_TYPE_HDMI_TYPE_A: +@@ -1019,8 +1067,17 @@ enum dc_status core_link_disable(struct core_stream *stream) + * it will lead to querying dynamic link capabilities + * which should be done before enable output */ + +- if (dc_is_dp_signal(stream->signal)) +- dp_disable_link_phy(stream->sink->link, stream->signal); ++ if (dc_is_dp_signal(stream->signal)) { ++ /* SST DP, eDP */ ++ if (dc_is_dp_sst_signal(stream->signal)) ++ dp_disable_link_phy( ++ stream->sink->link, stream->signal); ++ else { ++ dp_disable_link_phy_mst( ++ stream->sink->link, stream->signal); ++ } ++ } ++ + else if (ENCODER_RESULT_OK != dc->hwss.encoder_disable_output( + stream->sink->link->link_enc, stream->signal)) + status = DC_ERROR_UNEXPECTED; +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 164cdeb..3d6e2ea 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 +@@ -73,7 +73,22 @@ enum dc_status dp_enable_link_phy( + + void dp_disable_link_phy(struct core_link *link, enum signal_type signal) + { +- if(!link) ++ if (!link->dp_wa.bits.KEEP_RECEIVER_POWERED) ++ dp_receiver_power_ctrl(link, false); ++ ++ link->dc->hwss.encoder_disable_output(link->link_enc, signal); ++ ++ /* Clear current link setting.*/ ++ dc_service_memset(&link->cur_link_settings, 0, ++ sizeof(link->cur_link_settings)); ++} ++ ++void dp_disable_link_phy_mst(struct core_link *link, enum signal_type signal) ++{ ++ /* MST disable link only when no stream use the link */ ++ if (link->stream_count > 0) ++ link->stream_count--; ++ if (link->stream_count > 0) + return; + + if (!link->dp_wa.bits.KEEP_RECEIVER_POWERED) +diff --git a/drivers/gpu/drm/amd/dal/dc/dc_helpers.h b/drivers/gpu/drm/amd/dal/dc/dc_helpers.h +index c06eb8c..874c839 100644 +--- a/drivers/gpu/drm/amd/dal/dc/dc_helpers.h ++++ b/drivers/gpu/drm/amd/dal/dc/dc_helpers.h +@@ -44,7 +44,7 @@ enum dc_edid_status dc_helpers_parse_edid_caps( + bool dc_helpers_dp_mst_write_payload_allocation_table( + struct dc_context *ctx, + const struct dc_sink *sink, +- struct dp_mst_stream_allocation *alloc_entity, ++ struct dp_mst_stream_allocation_table *table, + bool enable); + + /* +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 dddc6e2..e631593 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 +@@ -780,25 +780,31 @@ static enum color_space get_output_color_space( + + static enum dc_status allocate_mst_payload(struct core_stream *stream) + { +- struct link_encoder *link_encoder = stream->sink->link->link_enc; ++ struct core_link *link = stream->sink->link; ++ struct link_encoder *link_encoder = link->link_enc; + struct stream_encoder *stream_encoder = stream->stream_enc; +- struct dp_mst_stream_allocation_table table; ++ struct dp_mst_stream_allocation_table table = {0}; + struct fixed31_32 avg_time_slots_per_mtp; ++ uint8_t cur_stream_payload_idx; + +- /* TODO: remove hardcode */ +- table.stream_count = 1; +- table.stream_allocations[0].engine = stream_encoder->id; ++ if (stream_encoder->id == ENGINE_ID_UNKNOWN) { ++ /* TODO ASSERT */ ++ return DC_ERROR_UNEXPECTED; ++ } + ++ /* get calculate VC payload for stream: stream_alloc */ + dc_helpers_dp_mst_write_payload_allocation_table( + stream->ctx, + &stream->sink->public, +- &table.stream_allocations[0], ++ &table, + true); + ++ /* program DP source TX for payload */ + dce110_link_encoder_update_mst_stream_allocation_table( + link_encoder, + &table); + ++ /* send down message */ + dc_helpers_dp_mst_poll_for_allocation_change_trigger( + stream->ctx, + &stream->sink->public); +@@ -808,9 +814,11 @@ static enum dc_status allocate_mst_payload(struct core_stream *stream) + &stream->sink->public, + true); + ++ /* slot X.Y for only current stream */ ++ cur_stream_payload_idx = table.cur_stream_payload_idx; + avg_time_slots_per_mtp = dal_fixed31_32_from_fraction( +- table.stream_allocations[0].pbn, +- table.stream_allocations[0].pbn_per_slot); ++ table.stream_allocations[cur_stream_payload_idx].pbn, ++ table.stream_allocations[cur_stream_payload_idx].pbn_per_slot); + + dce110_stream_encoder_set_mst_bandwidth( + stream_encoder, +@@ -823,24 +831,28 @@ static enum dc_status allocate_mst_payload(struct core_stream *stream) + + static enum dc_status deallocate_mst_payload(struct core_stream *stream) + { +- struct link_encoder *link_encoder = stream->sink->link->link_enc; ++ struct core_link *link = stream->sink->link; ++ struct link_encoder *link_encoder = link->link_enc; + struct stream_encoder *stream_encoder = stream->stream_enc; +- struct dp_mst_stream_allocation_table table; ++ struct dp_mst_stream_allocation_table table = {0}; + struct fixed31_32 avg_time_slots_per_mtp = dal_fixed31_32_from_int(0); + +- /* TODO: remove hardcode */ +- table.stream_count = 1; +- table.stream_allocations[0].slot_count = 0; ++ if (stream_encoder->id == ENGINE_ID_UNKNOWN) { ++ /* TODO ASSERT */ ++ return DC_ERROR_UNEXPECTED; ++ } + ++ /* slot X.Y */ + dce110_stream_encoder_set_mst_bandwidth( + stream_encoder, + stream_encoder->id, + avg_time_slots_per_mtp); + ++ /* TODO: which component is responsible for remove payload table? */ + dc_helpers_dp_mst_write_payload_allocation_table( + stream->ctx, + &stream->sink->public, +- &table.stream_allocations[0], ++ &table, + false); + + dce110_link_encoder_update_mst_stream_allocation_table( +diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c +index 0ad582b..c2c201f 100644 +--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c ++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c +@@ -1591,8 +1591,8 @@ void dce110_link_encoder_update_mst_stream_allocation_table( + const struct dp_mst_stream_allocation_table *table) + { + int32_t addr_offset = enc->be_engine_offset; +- uint32_t value0; +- uint32_t value1; ++ uint32_t value0 = 0; ++ uint32_t value1 = 0; + uint32_t retries = 0; + + /* For CZ, there are only 3 pipes. So Virtual channel is up 3.*/ +@@ -1602,9 +1602,6 @@ void dce110_link_encoder_update_mst_stream_allocation_table( + * Issue allocation change trigger + * to commit payload on both tx and rx side */ + +- value0 = dal_read_reg(enc->ctx, mmDP_MSE_SAT0 + addr_offset); +- value1 = dal_read_reg(enc->ctx, mmDP_MSE_SAT1 + addr_offset); +- + if (table->stream_count >= 1) { + set_reg_field_value( + value0, +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 22ab6cb..0b06314 100644 +--- a/drivers/gpu/drm/amd/dal/dc/inc/core_types.h ++++ b/drivers/gpu/drm/amd/dal/dc/inc/core_types.h +@@ -225,6 +225,9 @@ struct core_link { + + enum edp_revision edp_revision; + union dp_wa dp_wa; ++ ++ /* MST record stream using this link */ ++ uint8_t stream_count; + }; + + #define DC_LINK_TO_LINK(dc_link) container_of(dc_link, struct core_link, public) +diff --git a/drivers/gpu/drm/amd/dal/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/dal/dc/inc/link_hwss.h +index 7110357..a008544 100644 +--- a/drivers/gpu/drm/amd/dal/dc/inc/link_hwss.h ++++ b/drivers/gpu/drm/amd/dal/dc/inc/link_hwss.h +@@ -50,6 +50,8 @@ void dp_receiver_power_ctrl(struct core_link *link, bool on); + + void dp_disable_link_phy(struct core_link *link, enum signal_type signal); + ++void dp_disable_link_phy_mst(struct core_link *link, enum signal_type signal); ++ + bool dp_set_hw_training_pattern( + struct core_link *link, + enum hw_dp_training_pattern pattern); +diff --git a/drivers/gpu/drm/amd/dal/include/link_service_types.h b/drivers/gpu/drm/amd/dal/include/link_service_types.h +index 0df5687..bd3dd6d 100644 +--- a/drivers/gpu/drm/amd/dal/include/link_service_types.h ++++ b/drivers/gpu/drm/amd/dal/include/link_service_types.h +@@ -37,6 +37,10 @@ + struct ddc; + struct irq_manager; + ++enum { ++ MAX_CONTROLLER_NUM = 6 ++}; ++ + enum link_service_type { + LINK_SERVICE_TYPE_LEGACY = 0, + LINK_SERVICE_TYPE_DP_SST, +@@ -399,9 +403,10 @@ struct dp_mst_stream_allocation { + /* DP MST stream allocation table */ + struct dp_mst_stream_allocation_table { + /* number of DP video streams */ +- uint32_t stream_count; ++ uint8_t stream_count; ++ uint8_t cur_stream_payload_idx; + /* array of stream allocations */ +- struct dp_mst_stream_allocation stream_allocations[1]; ++ struct dp_mst_stream_allocation stream_allocations[MAX_CONTROLLER_NUM]; + }; + + struct dp_test_event_data { +-- +1.9.1 + |