aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/files/0833-drm-amd-dal-MST-two-monitors-light-up-add-PHY-payloa.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/files/0833-drm-amd-dal-MST-two-monitors-light-up-add-PHY-payloa.patch')
-rw-r--r--common/recipes-kernel/linux/files/0833-drm-amd-dal-MST-two-monitors-light-up-add-PHY-payloa.patch501
1 files changed, 501 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0833-drm-amd-dal-MST-two-monitors-light-up-add-PHY-payloa.patch b/common/recipes-kernel/linux/files/0833-drm-amd-dal-MST-two-monitors-light-up-add-PHY-payloa.patch
new file mode 100644
index 00000000..bfc57e0d
--- /dev/null
+++ b/common/recipes-kernel/linux/files/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
+