From 7bf1102eda7d1e5ef2eeec7a04fe9e91bf321dfa Mon Sep 17 00:00:00 2001 From: Hersen Wu Date: Mon, 23 Nov 2015 15:44:57 -0500 Subject: [PATCH 0526/1110] drm/amd/dal: MST two monitors light up add PHY payload alloaction 2 Signed-off-by: Hersen Wu Signed-off-by: Harry Wentland Acked-by: Harry Wentland --- .../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 #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 { -- 2.7.4