drm/amd/display: Add DP 2.0 MST DC Support
authorFangzhi Zuo <Jerry.Zuo@amd.com>
Mon, 25 Oct 2021 22:38:23 +0000 (18:38 -0400)
committerLyude Paul <lyude@redhat.com>
Tue, 26 Oct 2021 01:21:08 +0000 (21:21 -0400)
[Why]
configure/call DC interface for DP2 mst support. This is needed to make DP2
mst work.

[How]
- add encoding type, logging, mst update/reduce payload functions

Use the link encoding to determine the DP type (1.4 or 2.0) and add a
flag to dc_stream_update to determine whether to increase/reduce
payloads.

v2:
* add DP_UNKNOWN_ENCODING handling

Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Reviewed-by: "Lin, Wayne" <Wayne.Lin@amd.com>
Signed-off-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20211025223825.301703-4-lyude@redhat.com
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/dc_stream.h

index da942e9f5142d336441ead0a60841cb8275580b2..782141ba8ac5605254d973db02063901642a4b41 100644 (file)
@@ -2356,6 +2356,11 @@ static enum surface_update_type check_update_surfaces_for_stream(
                if (stream_update->dsc_config)
                        su_flags->bits.dsc_changed = 1;
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+               if (stream_update->mst_bw_update)
+                       su_flags->bits.mst_bw = 1;
+#endif
+
                if (su_flags->raw != 0)
                        overall_type = UPDATE_TYPE_FULL;
 
@@ -2741,6 +2746,15 @@ static void commit_planes_do_stream_update(struct dc *dc,
                        if (stream_update->dsc_config)
                                dp_update_dsc_config(pipe_ctx);
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+                       if (stream_update->mst_bw_update) {
+                               if (stream_update->mst_bw_update->is_increase)
+                                       dc_link_increase_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
+                               else
+                                       dc_link_reduce_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
+                       }
+#endif
+
                        if (stream_update->pending_test_pattern) {
                                dc_link_dp_set_test_pattern(stream->link,
                                        stream->test_pattern.type,
index ca5dc3c168ecf98dd03828697d7bf822b34127fe..fd12561b70ccb2ccb27973e0b40d08cea38b575d 100644 (file)
@@ -3272,6 +3272,9 @@ static struct fixed31_32 get_pbn_from_timing(struct pipe_ctx *pipe_ctx)
 static void update_mst_stream_alloc_table(
        struct dc_link *link,
        struct stream_encoder *stream_enc,
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       struct hpo_dp_stream_encoder *hpo_dp_stream_enc, // TODO: Rename stream_enc to dio_stream_enc?
+#endif
        const struct dp_mst_stream_allocation_table *proposed_table)
 {
        struct link_mst_stream_allocation work_table[MAX_CONTROLLER_NUM] = {
@@ -3308,6 +3311,9 @@ static void update_mst_stream_alloc_table(
                        work_table[i].slot_count =
                                proposed_table->stream_allocations[i].slot_count;
                        work_table[i].stream_enc = stream_enc;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+                       work_table[i].hpo_dp_stream_enc = hpo_dp_stream_enc;
+#endif
                }
        }
 
@@ -3430,6 +3436,10 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx)
        struct dc_link *link = stream->link;
        struct link_encoder *link_encoder = NULL;
        struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc;
+       struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc;
+#endif
        struct dp_mst_stream_allocation_table proposed_table = {0};
        struct fixed31_32 avg_time_slots_per_mtp;
        struct fixed31_32 pbn;
@@ -3457,7 +3467,14 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx)
                &proposed_table,
                true)) {
                update_mst_stream_alloc_table(
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+                                       link,
+                                       pipe_ctx->stream_res.stream_enc,
+                                       pipe_ctx->stream_res.hpo_dp_stream_enc,
+                                       &proposed_table);
+#else
                                        link, pipe_ctx->stream_res.stream_enc, &proposed_table);
+#endif
        }
        else
                DC_LOG_WARNING("Failed to update"
@@ -3471,23 +3488,56 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx)
                        link->mst_stream_alloc_table.stream_count);
 
        for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
                DC_LOG_MST("stream_enc[%d]: %p      "
+               "stream[%d].hpo_dp_stream_enc: %p      "
                "stream[%d].vcp_id: %d      "
                "stream[%d].slot_count: %d\n",
                i,
                (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
                i,
+               (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
+               i,
                link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
                i,
                link->mst_stream_alloc_table.stream_allocations[i].slot_count);
+#else
+               DC_LOG_MST("stream_enc[%d]: %p      "
+               "stream[%d].vcp_id: %d      "
+               "stream[%d].slot_count: %d\n",
+               i,
+               (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
+               i,
+               link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
+               i,
+               link->mst_stream_alloc_table.stream_allocations[i].slot_count);
+#endif
        }
 
        ASSERT(proposed_table.stream_count > 0);
 
        /* program DP source TX for payload */
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       switch (dp_get_link_encoding_format(&link->cur_link_settings)) {
+       case DP_8b_10b_ENCODING:
+               link_encoder->funcs->update_mst_stream_allocation_table(
+                       link_encoder,
+                       &link->mst_stream_alloc_table);
+               break;
+       case DP_128b_132b_ENCODING:
+               hpo_dp_link_encoder->funcs->update_stream_allocation_table(
+                               hpo_dp_link_encoder,
+                               &link->mst_stream_alloc_table);
+               break;
+       case DP_UNKNOWN_ENCODING:
+               DC_LOG_ERROR("Failure: unknown encoding format\n");
+               return DC_ERROR_UNEXPECTED;
+       }
+#else
        link_encoder->funcs->update_mst_stream_allocation_table(
                link_encoder,
                &link->mst_stream_alloc_table);
+#endif
 
        /* send down message */
        ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger(
@@ -3510,13 +3560,191 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx)
        pbn = get_pbn_from_timing(pipe_ctx);
        avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       switch (dp_get_link_encoding_format(&link->cur_link_settings)) {
+       case DP_8b_10b_ENCODING:
+               stream_encoder->funcs->set_throttled_vcp_size(
+                       stream_encoder,
+                       avg_time_slots_per_mtp);
+               break;
+       case DP_128b_132b_ENCODING:
+               hpo_dp_link_encoder->funcs->set_throttled_vcp_size(
+                               hpo_dp_link_encoder,
+                               hpo_dp_stream_encoder->inst,
+                               avg_time_slots_per_mtp);
+               break;
+       case DP_UNKNOWN_ENCODING:
+               DC_LOG_ERROR("Failure: unknown encoding format\n");
+               return DC_ERROR_UNEXPECTED;
+       }
+#else
        stream_encoder->funcs->set_throttled_vcp_size(
                stream_encoder,
                avg_time_slots_per_mtp);
+#endif
+
+       return DC_OK;
+
+}
+
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_in_kbps)
+{
+       struct dc_stream_state *stream = pipe_ctx->stream;
+       struct dc_link *link = stream->link;
+       struct fixed31_32 avg_time_slots_per_mtp;
+       struct fixed31_32 pbn;
+       struct fixed31_32 pbn_per_slot;
+       struct link_encoder *link_encoder = link->link_enc;
+       struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
+       struct dp_mst_stream_allocation_table proposed_table = {0};
+       uint8_t i;
+       enum act_return_status ret;
+       DC_LOGGER_INIT(link->ctx->logger);
+
+       /* decrease throttled vcp size */
+       pbn_per_slot = get_pbn_per_slot(stream);
+       pbn = get_pbn_from_bw_in_kbps(bw_in_kbps);
+       avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
+
+       stream_encoder->funcs->set_throttled_vcp_size(
+                               stream_encoder,
+                               avg_time_slots_per_mtp);
+
+       /* send ALLOCATE_PAYLOAD sideband message with updated pbn */
+       dm_helpers_dp_mst_send_payload_allocation(
+                       stream->ctx,
+                       stream,
+                       true);
+
+       /* notify immediate branch device table update */
+       if (dm_helpers_dp_mst_write_payload_allocation_table(
+                       stream->ctx,
+                       stream,
+                       &proposed_table,
+                       true)) {
+               /* update mst stream allocation table software state */
+               update_mst_stream_alloc_table(
+                               link,
+                               pipe_ctx->stream_res.stream_enc,
+                               pipe_ctx->stream_res.hpo_dp_stream_enc,
+                               &proposed_table);
+       } else {
+               DC_LOG_WARNING("Failed to update"
+                               "MST allocation table for"
+                               "pipe idx:%d\n",
+                               pipe_ctx->pipe_idx);
+       }
+
+       DC_LOG_MST("%s  "
+                       "stream_count: %d: \n ",
+                       __func__,
+                       link->mst_stream_alloc_table.stream_count);
+
+       for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
+               DC_LOG_MST("stream_enc[%d]: %p      "
+                               "stream[%d].vcp_id: %d      "
+                               "stream[%d].slot_count: %d\n",
+                               i,
+                               (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
+                               i,
+                               link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
+                               i,
+                               link->mst_stream_alloc_table.stream_allocations[i].slot_count);
+       }
+
+       ASSERT(proposed_table.stream_count > 0);
+
+       /* update mst stream allocation table hardware state */
+       link_encoder->funcs->update_mst_stream_allocation_table(
+                       link_encoder,
+                       &link->mst_stream_alloc_table);
+
+       /* poll for immediate branch device ACT handled */
+       ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger(
+                       stream->ctx,
+                       stream);
 
        return DC_OK;
+}
+
+enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_in_kbps)
+{
+       struct dc_stream_state *stream = pipe_ctx->stream;
+       struct dc_link *link = stream->link;
+       struct fixed31_32 avg_time_slots_per_mtp;
+       struct fixed31_32 pbn;
+       struct fixed31_32 pbn_per_slot;
+       struct link_encoder *link_encoder = link->link_enc;
+       struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
+       struct dp_mst_stream_allocation_table proposed_table = {0};
+       uint8_t i;
+       enum act_return_status ret;
+       DC_LOGGER_INIT(link->ctx->logger);
+
+       /* notify immediate branch device table update */
+       if (dm_helpers_dp_mst_write_payload_allocation_table(
+                               stream->ctx,
+                               stream,
+                               &proposed_table,
+                               true)) {
+               /* update mst stream allocation table software state */
+               update_mst_stream_alloc_table(
+                               link,
+                               pipe_ctx->stream_res.stream_enc,
+                               pipe_ctx->stream_res.hpo_dp_stream_enc,
+                               &proposed_table);
+       }
+
+       DC_LOG_MST("%s  "
+                       "stream_count: %d: \n ",
+                       __func__,
+                       link->mst_stream_alloc_table.stream_count);
+
+       for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
+               DC_LOG_MST("stream_enc[%d]: %p      "
+                               "stream[%d].vcp_id: %d      "
+                               "stream[%d].slot_count: %d\n",
+                               i,
+                               (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
+                               i,
+                               link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
+                               i,
+                               link->mst_stream_alloc_table.stream_allocations[i].slot_count);
+       }
+
+       ASSERT(proposed_table.stream_count > 0);
+
+       /* update mst stream allocation table hardware state */
+       link_encoder->funcs->update_mst_stream_allocation_table(
+                       link_encoder,
+                       &link->mst_stream_alloc_table);
+
+       /* poll for immediate branch device ACT handled */
+       ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger(
+                       stream->ctx,
+                       stream);
+
+       if (ret != ACT_LINK_LOST) {
+               /* send ALLOCATE_PAYLOAD sideband message with updated pbn */
+               dm_helpers_dp_mst_send_payload_allocation(
+                               stream->ctx,
+                               stream,
+                               true);
+       }
 
+       /* increase throttled vcp size */
+       pbn = get_pbn_from_bw_in_kbps(bw_in_kbps);
+       pbn_per_slot = get_pbn_per_slot(stream);
+       avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
+
+       stream_encoder->funcs->set_throttled_vcp_size(
+                               stream_encoder,
+                               avg_time_slots_per_mtp);
+
+       return DC_OK;
 }
+#endif
 
 static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
 {
@@ -3524,6 +3752,10 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
        struct dc_link *link = stream->link;
        struct link_encoder *link_encoder = NULL;
        struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc;
+       struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc;
+#endif
        struct dp_mst_stream_allocation_table proposed_table = {0};
        struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0);
        uint8_t i;
@@ -3545,9 +3777,28 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
         */
 
        /* slot X.Y */
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       switch (dp_get_link_encoding_format(&link->cur_link_settings)) {
+       case DP_8b_10b_ENCODING:
+               stream_encoder->funcs->set_throttled_vcp_size(
+                       stream_encoder,
+                       avg_time_slots_per_mtp);
+               break;
+       case DP_128b_132b_ENCODING:
+               hpo_dp_link_encoder->funcs->set_throttled_vcp_size(
+                               hpo_dp_link_encoder,
+                               hpo_dp_stream_encoder->inst,
+                               avg_time_slots_per_mtp);
+               break;
+       case DP_UNKNOWN_ENCODING:
+               DC_LOG_ERROR("Failure: unknown encoding format\n");
+               return DC_ERROR_UNEXPECTED;
+       }
+#else
        stream_encoder->funcs->set_throttled_vcp_size(
                stream_encoder,
                avg_time_slots_per_mtp);
+#endif
 
        /* TODO: which component is responsible for remove payload table? */
        if (mst_mode) {
@@ -3557,8 +3808,16 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
                                &proposed_table,
                                false)) {
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+                       update_mst_stream_alloc_table(
+                                               link,
+                                               pipe_ctx->stream_res.stream_enc,
+                                               pipe_ctx->stream_res.hpo_dp_stream_enc,
+                                               &proposed_table);
+#else
                        update_mst_stream_alloc_table(
                                link, pipe_ctx->stream_res.stream_enc, &proposed_table);
+#endif
                }
                else {
                                DC_LOG_WARNING("Failed to update"
@@ -3574,6 +3833,20 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
                        link->mst_stream_alloc_table.stream_count);
 
        for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+               DC_LOG_MST("stream_enc[%d]: %p      "
+               "stream[%d].hpo_dp_stream_enc: %p      "
+               "stream[%d].vcp_id: %d      "
+               "stream[%d].slot_count: %d\n",
+               i,
+               (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
+               i,
+               (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
+               i,
+               link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
+               i,
+               link->mst_stream_alloc_table.stream_allocations[i].slot_count);
+#else
                DC_LOG_MST("stream_enc[%d]: %p      "
                "stream[%d].vcp_id: %d      "
                "stream[%d].slot_count: %d\n",
@@ -3583,11 +3856,30 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
                link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
                i,
                link->mst_stream_alloc_table.stream_allocations[i].slot_count);
+#endif
        }
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       switch (dp_get_link_encoding_format(&link->cur_link_settings)) {
+       case DP_8b_10b_ENCODING:
+               link_encoder->funcs->update_mst_stream_allocation_table(
+                       link_encoder,
+                       &link->mst_stream_alloc_table);
+               break;
+       case DP_128b_132b_ENCODING:
+               hpo_dp_link_encoder->funcs->update_stream_allocation_table(
+                               hpo_dp_link_encoder,
+                               &link->mst_stream_alloc_table);
+               break;
+       case DP_UNKNOWN_ENCODING:
+               DC_LOG_ERROR("Failure: unknown encoding format\n");
+               return DC_ERROR_UNEXPECTED;
+       }
+#else
        link_encoder->funcs->update_mst_stream_allocation_table(
                link_encoder,
                &link->mst_stream_alloc_table);
+#endif
 
        if (mst_mode) {
                dm_helpers_dp_mst_poll_for_allocation_change_trigger(
index 54662d74c65acfdd07ca5e1844b8cc8a1013cd88..ab13d2304f3e7f16dbb451e64a4369e3b45ac64f 100644 (file)
@@ -5993,6 +5993,25 @@ enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings
 }
 
 #if defined(CONFIG_DRM_AMD_DC_DCN)
+enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link)
+{
+       struct dc_link_settings link_settings = {0};
+
+       if (!dc_is_dp_signal(link->connector_signal))
+               return DP_UNKNOWN_ENCODING;
+
+       if (link->preferred_link_setting.lane_count !=
+                       LANE_COUNT_UNKNOWN &&
+                       link->preferred_link_setting.link_rate !=
+                                       LINK_RATE_UNKNOWN) {
+               link_settings = link->preferred_link_setting;
+       } else {
+               decide_mst_link_settings(link, &link_settings);
+       }
+
+       return dp_get_link_encoding_format(&link_settings);
+}
+
 // TODO - DP2.0 Link: Fix get_lane_status to handle LTTPR offset (SST and MST)
 static void get_lane_status(
        struct dc_link *link,
index 69b008bafbbcd480cafab63f2e146ad8f557eb47..d9fb43d99dc09e7a570afbcfb68e277f95bd9cd5 100644 (file)
@@ -296,6 +296,10 @@ enum dc_detect_reason {
 bool dc_link_detect(struct dc_link *dc_link, enum dc_detect_reason reason);
 bool dc_link_get_hpd_state(struct dc_link *dc_link);
 enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
+enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
+#endif
 
 /* Notify DC about DP RX Interrupt (aka Short Pulse Interrupt).
  * Return:
@@ -425,4 +429,7 @@ uint32_t dc_bandwidth_in_kbps_from_timing(
 bool dc_link_is_fec_supported(const struct dc_link *link);
 bool dc_link_should_enable_fec(const struct dc_link *link);
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link);
+#endif
 #endif /* DC_LINK_H_ */
index b8ebc1f09538995e61e794da70149451a6ff0648..e37c4a10bfd5e5ca7a4b66c5f15ae0d9f77e4811 100644 (file)
@@ -115,6 +115,13 @@ struct periodic_interrupt_config {
        int lines_offset;
 };
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+struct dc_mst_stream_bw_update {
+       bool is_increase; // is bandwidth reduced or increased
+       uint32_t mst_stream_bw; // new mst bandwidth in kbps
+};
+#endif
+
 union stream_update_flags {
        struct {
                uint32_t scaling:1;
@@ -125,6 +132,9 @@ union stream_update_flags {
                uint32_t gamut_remap:1;
                uint32_t wb_update:1;
                uint32_t dsc_changed : 1;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+               uint32_t mst_bw : 1;
+#endif
        } bits;
 
        uint32_t raw;
@@ -278,6 +288,9 @@ struct dc_stream_update {
 
        struct dc_writeback_update *wb_update;
        struct dc_dsc_config *dsc_config;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       struct dc_mst_stream_bw_update *mst_bw_update;
+#endif
        struct dc_transfer_func *func_shaper;
        struct dc_3dlut *lut3d_func;