drm/amd/display: Request usb4 bw for mst streams
authorjsg <jsg@openbsd.org>
Mon, 4 Mar 2024 02:21:40 +0000 (02:21 +0000)
committerjsg <jsg@openbsd.org>
Mon, 4 Mar 2024 02:21:40 +0000 (02:21 +0000)
From Peichen Huang
622c827544ef300899a757f5b1d61554c2c3abcc in linux-6.6.y/6.6.19
5f3bce13266e6fe2f7a46f94d8bc94d5274e276b in mainline linux

sys/dev/pci/drm/amd/display/dc/dc_types.h
sys/dev/pci/drm/amd/display/dc/link/link_dpms.c
sys/dev/pci/drm/amd/display/dc/link/link_validation.c
sys/dev/pci/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c
sys/dev/pci/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h

index 19b7314..cc173ec 100644 (file)
@@ -1110,23 +1110,25 @@ struct dc_panel_config {
        } ilr;
 };
 
+#define MAX_SINKS_PER_LINK 4
+
 /*
  *  USB4 DPIA BW ALLOCATION STRUCTS
  */
 struct dc_dpia_bw_alloc {
-       int sink_verified_bw;  // The Verified BW that sink can allocated and use that has been verified already
-       int sink_allocated_bw; // The Actual Allocated BW that sink currently allocated
-       int sink_max_bw;       // The Max BW that sink can require/support
+       int remote_sink_req_bw[MAX_SINKS_PER_LINK]; // BW requested by remote sinks
+       int link_verified_bw;  // The Verified BW that link can allocated and use that has been verified already
+       int link_max_bw;       // The Max BW that link can require/support
+       int allocated_bw;      // The Actual Allocated BW for this DPIA
        int estimated_bw;      // The estimated available BW for this DPIA
        int bw_granularity;    // BW Granularity
+       int dp_overhead;       // DP overhead in dp tunneling
        bool bw_alloc_enabled; // The BW Alloc Mode Support is turned ON for all 3:  DP-Tx & Dpia & CM
        bool response_ready;   // Response ready from the CM side
        uint8_t nrd_max_lane_count; // Non-reduced max lane count
        uint8_t nrd_max_link_rate; // Non-reduced max link rate
 };
 
-#define MAX_SINKS_PER_LINK 4
-
 enum dc_hpd_enable_select {
        HPD_EN_FOR_ALL_EDP = 0,
        HPD_EN_FOR_PRIMARY_EDP_ONLY,
index 4450fbf..731e03f 100644 (file)
@@ -2071,17 +2071,11 @@ static enum dc_status enable_link_dp(struct dc_state *state,
                }
        }
 
-       /*
-        * If the link is DP-over-USB4 do the following:
-        * - Train with fallback when enabling DPIA link. Conventional links are
+       /* Train with fallback when enabling DPIA link. Conventional links are
         * trained with fallback during sink detection.
-        * - Allocate only what the stream needs for bw in Gbps. Inform the CM
-        * in case stream needs more or less bw from what has been allocated
-        * earlier at plug time.
         */
-       if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
+       if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
                do_fallback = true;
-       }
 
        /*
         * Temporary w/a to get DP2.0 link rates to work with SST.
@@ -2263,6 +2257,32 @@ static enum dc_status enable_link(
        return status;
 }
 
+static bool allocate_usb4_bandwidth_for_stream(struct dc_stream_state *stream, int bw)
+{
+       return true;
+}
+
+static bool allocate_usb4_bandwidth(struct dc_stream_state *stream)
+{
+       bool ret;
+
+       int bw = dc_bandwidth_in_kbps_from_timing(&stream->timing,
+                       dc_link_get_highest_encoding_format(stream->sink->link));
+
+       ret = allocate_usb4_bandwidth_for_stream(stream, bw);
+
+       return ret;
+}
+
+static bool deallocate_usb4_bandwidth(struct dc_stream_state *stream)
+{
+       bool ret;
+
+       ret = allocate_usb4_bandwidth_for_stream(stream, 0);
+
+       return ret;
+}
+
 void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
 {
        struct dc  *dc = pipe_ctx->stream->ctx->dc;
@@ -2299,6 +2319,9 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
        update_psp_stream_config(pipe_ctx, true);
        dc->hwss.blank_stream(pipe_ctx);
 
+       if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+               deallocate_usb4_bandwidth(pipe_ctx->stream);
+
        if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
                deallocate_mst_payload(pipe_ctx);
        else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
@@ -2520,6 +2543,9 @@ void link_set_dpms_on(
                }
        }
 
+       if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+               allocate_usb4_bandwidth(pipe_ctx->stream);
+
        if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
                allocate_mst_payload(pipe_ctx);
        else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
index b45fda9..8fe66c3 100644 (file)
@@ -346,23 +346,61 @@ enum dc_status link_validate_mode_timing(
        return DC_OK;
 }
 
+/*
+ * This function calculates the bandwidth required for the stream timing
+ * and aggregates the stream bandwidth for the respective dpia link
+ *
+ * @stream: pointer to the dc_stream_state struct instance
+ * @num_streams: number of streams to be validated
+ *
+ * return: true if validation is succeeded
+ */
 bool link_validate_dpia_bandwidth(const struct dc_stream_state *stream, const unsigned int num_streams)
 {
-       bool ret = true;
-       int bw_needed[MAX_DPIA_NUM];
-       struct dc_link *link[MAX_DPIA_NUM];
-
-       if (!num_streams || num_streams > MAX_DPIA_NUM)
-               return ret;
+       int bw_needed[MAX_DPIA_NUM] = {0};
+       struct dc_link *dpia_link[MAX_DPIA_NUM] = {0};
+       int num_dpias = 0;
 
        for (uint8_t i = 0; i < num_streams; ++i) {
+               if (stream[i].signal == SIGNAL_TYPE_DISPLAY_PORT) {
+                       /* new dpia sst stream, check whether it exceeds max dpia */
+                       if (num_dpias >= MAX_DPIA_NUM)
+                               return false;
 
-               link[i] = stream[i].link;
-               bw_needed[i] = dc_bandwidth_in_kbps_from_timing(&stream[i].timing,
-                               dc_link_get_highest_encoding_format(link[i]));
+                       dpia_link[num_dpias] = stream[i].link;
+                       bw_needed[num_dpias] = dc_bandwidth_in_kbps_from_timing(&stream[i].timing,
+                                       dc_link_get_highest_encoding_format(dpia_link[num_dpias]));
+                       num_dpias++;
+               } else if (stream[i].signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+                       uint8_t j = 0;
+                       /* check whether its a known dpia link */
+                       for (; j < num_dpias; ++j) {
+                               if (dpia_link[j] == stream[i].link)
+                                       break;
+                       }
+
+                       if (j == num_dpias) {
+                               /* new dpia mst stream, check whether it exceeds max dpia */
+                               if (num_dpias >= MAX_DPIA_NUM)
+                                       return false;
+                               else {
+                                       dpia_link[j] = stream[i].link;
+                                       num_dpias++;
+                               }
+                       }
+
+                       bw_needed[j] += dc_bandwidth_in_kbps_from_timing(&stream[i].timing,
+                               dc_link_get_highest_encoding_format(dpia_link[j]));
+               }
        }
 
-       ret = dpia_validate_usb4_bw(link, bw_needed, num_streams);
+       /* Include dp overheads */
+       for (uint8_t i = 0; i < num_dpias; ++i) {
+               int dp_overhead = 0;
+
+               dp_overhead = link_dp_dpia_get_dp_overhead_in_dp_tunneling(dpia_link[i]);
+               bw_needed[i] += dp_overhead;
+       }
 
-       return ret;
+       return dpia_validate_usb4_bw(dpia_link, bw_needed, num_dpias);
 }
index 224498c..5269368 100644 (file)
@@ -54,12 +54,18 @@ static bool get_bw_alloc_proceed_flag(struct dc_link *tmp)
 static void reset_bw_alloc_struct(struct dc_link *link)
 {
        link->dpia_bw_alloc_config.bw_alloc_enabled = false;
-       link->dpia_bw_alloc_config.sink_verified_bw = 0;
-       link->dpia_bw_alloc_config.sink_max_bw = 0;
+       link->dpia_bw_alloc_config.link_verified_bw = 0;
+       link->dpia_bw_alloc_config.link_max_bw = 0;
+       link->dpia_bw_alloc_config.allocated_bw = 0;
        link->dpia_bw_alloc_config.estimated_bw = 0;
        link->dpia_bw_alloc_config.bw_granularity = 0;
+       link->dpia_bw_alloc_config.dp_overhead = 0;
        link->dpia_bw_alloc_config.response_ready = false;
-       link->dpia_bw_alloc_config.sink_allocated_bw = 0;
+       link->dpia_bw_alloc_config.nrd_max_lane_count = 0;
+       link->dpia_bw_alloc_config.nrd_max_link_rate = 0;
+       for (int i = 0; i < MAX_SINKS_PER_LINK; i++)
+               link->dpia_bw_alloc_config.remote_sink_req_bw[i] = 0;
+       DC_LOG_DEBUG("reset usb4 bw alloc of link(%d)\n", link->link_index);
 }
 
 #define BW_GRANULARITY_0 4 // 0.25 Gbps
@@ -210,8 +216,8 @@ static int get_host_router_total_dp_tunnel_bw(const struct dc *dc, uint8_t hr_in
                                link_dpia_primary->dpia_bw_alloc_config.bw_alloc_enabled) &&
                                (link_dpia_secondary->hpd_status &&
                                link_dpia_secondary->dpia_bw_alloc_config.bw_alloc_enabled)) {
-                               total_bw += link_dpia_primary->dpia_bw_alloc_config.estimated_bw +
-                                       link_dpia_secondary->dpia_bw_alloc_config.sink_allocated_bw;
+                                       total_bw += link_dpia_primary->dpia_bw_alloc_config.estimated_bw +
+                                               link_dpia_secondary->dpia_bw_alloc_config.allocated_bw;
                        } else if (link_dpia_primary->hpd_status &&
                                        link_dpia_primary->dpia_bw_alloc_config.bw_alloc_enabled) {
                                total_bw = link_dpia_primary->dpia_bw_alloc_config.estimated_bw;
@@ -264,7 +270,7 @@ static void set_usb4_req_bw_req(struct dc_link *link, int req_bw)
 
        /* Error check whether requested and allocated are equal */
        req_bw = requested_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
-       if (req_bw == link->dpia_bw_alloc_config.sink_allocated_bw) {
+       if (req_bw == link->dpia_bw_alloc_config.allocated_bw) {
                DC_LOG_ERROR("%s: Request bw equals to allocated bw for link(%d)\n",
                        __func__, link->link_index);
        }
@@ -387,9 +393,9 @@ void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t res
                DC_LOG_DEBUG("%s: BW REQ SUCCESS for DP-TX Request for link(%d)\n",
                        __func__, link->link_index);
                DC_LOG_DEBUG("%s: current allocated_bw(%d), new allocated_bw(%d)\n",
-                       __func__, link->dpia_bw_alloc_config.sink_allocated_bw, bw_needed);
+                       __func__, link->dpia_bw_alloc_config.allocated_bw, bw_needed);
 
-               link->dpia_bw_alloc_config.sink_allocated_bw = bw_needed;
+               link->dpia_bw_alloc_config.allocated_bw = bw_needed;
 
                link->dpia_bw_alloc_config.response_ready = true;
                break;
@@ -427,8 +433,8 @@ int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int pea
        if (link->hpd_status && peak_bw > 0) {
 
                // If DP over USB4 then we need to check BW allocation
-               link->dpia_bw_alloc_config.sink_max_bw = peak_bw;
-               set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.sink_max_bw);
+               link->dpia_bw_alloc_config.link_max_bw = peak_bw;
+               set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.link_max_bw);
 
                do {
                        if (timeout > 0)
@@ -440,8 +446,8 @@ int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int pea
 
                if (!timeout)
                        ret = 0;// ERROR TIMEOUT waiting for response for allocating bw
-               else if (link->dpia_bw_alloc_config.sink_allocated_bw > 0)
-                       ret = link->dpia_bw_alloc_config.sink_allocated_bw;
+               else if (link->dpia_bw_alloc_config.allocated_bw > 0)
+                       ret = link->dpia_bw_alloc_config.allocated_bw;
        }
        //2. Cold Unplug
        else if (!link->hpd_status)
@@ -450,7 +456,6 @@ int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int pea
 out:
        return ret;
 }
-
 bool link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw)
 {
        bool ret = false;
@@ -458,7 +463,7 @@ bool link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int r
 
        DC_LOG_DEBUG("%s: ENTER: link(%d), hpd_status(%d), current allocated_bw(%d), req_bw(%d)\n",
                __func__, link->link_index, link->hpd_status,
-               link->dpia_bw_alloc_config.sink_allocated_bw, req_bw);
+               link->dpia_bw_alloc_config.allocated_bw, req_bw);
 
        if (!get_bw_alloc_proceed_flag(link))
                goto out;
@@ -523,3 +528,29 @@ bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed_per_dpia, const
 
        return ret;
 }
+
+int link_dp_dpia_get_dp_overhead_in_dp_tunneling(struct dc_link *link)
+{
+       int dp_overhead = 0, link_mst_overhead = 0;
+
+       if (!get_bw_alloc_proceed_flag((link)))
+               return dp_overhead;
+
+       /* if its mst link, add MTPH overhead */
+       if ((link->type == dc_connection_mst_branch) &&
+               !link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
+               /* For 8b/10b encoding: MTP is 64 time slots long, slot 0 is used for MTPH
+                * MST overhead is 1/64 of link bandwidth (excluding any overhead)
+                */
+               const struct dc_link_settings *link_cap =
+                       dc_link_get_link_cap(link);
+               uint32_t link_bw_in_kbps =
+                       link_cap->link_rate * link_cap->lane_count * LINK_RATE_REF_FREQ_IN_KHZ * 8;
+               link_mst_overhead = (link_bw_in_kbps / 64) + ((link_bw_in_kbps % 64) ? 1 : 0);
+       }
+
+       /* add all the overheads */
+       dp_overhead = link_mst_overhead;
+
+       return dp_overhead;
+}
index 981bc4e..3b6d849 100644 (file)
@@ -99,4 +99,13 @@ void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t res
  */
 bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed, const unsigned int num_dpias);
 
+/*
+ * Obtain all the DP overheads in dp tunneling for the dpia link
+ *
+ * @link: pointer to the dc_link struct instance
+ *
+ * return: DP overheads in DP tunneling
+ */
+int link_dp_dpia_get_dp_overhead_in_dp_tunneling(struct dc_link *link);
+
 #endif /* DC_INC_LINK_DP_DPIA_BW_H_ */