From: George Shen <george.s...@amd.com>

[Why]
Some features, such as HBlank expansion/reduction, needs to know how
much HBlank is required to support basic audio.

[How]
Add interface to link to calculate required HBlank size for a given
link + timing combination to support basic audio (i.e. 2-channel 48KHz).

Reviewed-by: Wenjing Liu <wenjing....@amd.com>
Signed-off-by: George Shen <george.s...@amd.com>
Signed-off-by: Roman Li <roman...@amd.com>
Tested-by: Daniel Wheeler <daniel.whee...@amd.com>
---
 .../drm/amd/display/dc/core/dc_link_exports.c |   8 +
 drivers/gpu/drm/amd/display/dc/dc.h           |  18 ++
 drivers/gpu/drm/amd/display/dc/inc/link.h     |   4 +
 .../drm/amd/display/dc/link/link_factory.c    |   1 +
 .../drm/amd/display/dc/link/link_validation.c | 179 ++++++++++++++++++
 .../drm/amd/display/dc/link/link_validation.h |   5 +
 6 files changed, 215 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c 
b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c
index 457d60eeb486..c1b79b379447 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c
@@ -125,6 +125,14 @@ uint32_t dc_link_bandwidth_kbps(
        return link->dc->link_srv->dp_link_bandwidth_kbps(link, link_settings);
 }
 
+uint32_t dc_link_required_hblank_size_bytes(
+       const struct dc_link *link,
+       struct dp_audio_bandwidth_params *audio_params)
+{
+       return link->dc->link_srv->dp_required_hblank_size_bytes(link,
+                       audio_params);
+}
+
 void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map)
 {
        dc->link_srv->get_cur_res_map(dc, map);
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h 
b/drivers/gpu/drm/amd/display/dc/dc.h
index 01f22706d27c..96594ec6a1d6 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -2024,6 +2024,24 @@ uint32_t dc_link_bandwidth_kbps(
        const struct dc_link *link,
        const struct dc_link_settings *link_setting);
 
+struct dp_audio_bandwidth_params {
+       const struct dc_crtc_timing *crtc_timing;
+       enum dp_link_encoding link_encoding;
+       uint32_t channel_count;
+       uint32_t sample_rate_hz;
+};
+
+/* The function calculates the minimum size of hblank (in bytes) needed to
+ * support the specified channel count and sample rate combination, given the
+ * link encoding and timing to be used. This calculation is not supported
+ * for 8b/10b SST.
+ *
+ * return - min hblank size in bytes, 0 if 8b/10b SST.
+ */
+uint32_t dc_link_required_hblank_size_bytes(
+       const struct dc_link *link,
+       struct dp_audio_bandwidth_params *audio_params);
+
 /* The function takes a snapshot of current link resource allocation state
  * @dc: pointer to dc of the dm calling this
  * @map: a dc link resource snapshot defined internally to dc.
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link.h 
b/drivers/gpu/drm/amd/display/dc/inc/link.h
index f04292086c08..fd1f9d3db039 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/link.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/link.h
@@ -148,6 +148,10 @@ struct link_service {
                        const struct dc_stream_state *stream,
                        const unsigned int num_streams);
 
+       uint32_t (*dp_required_hblank_size_bytes)(
+               const struct dc_link *link,
+               struct dp_audio_bandwidth_params *audio_params);
+
 
        /*************************** DPMS *************************************/
        void (*set_dpms_on)(struct dc_state *state, struct pipe_ctx *pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c 
b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
index 5e1b5ab9fbc6..334f985186d2 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
@@ -101,6 +101,7 @@ static void construct_link_service_validation(struct 
link_service *link_srv)
        link_srv->validate_mode_timing = link_validate_mode_timing;
        link_srv->dp_link_bandwidth_kbps = dp_link_bandwidth_kbps;
        link_srv->validate_dpia_bandwidth = link_validate_dpia_bandwidth;
+       link_srv->dp_required_hblank_size_bytes = dp_required_hblank_size_bytes;
 }
 
 /* link dpms owns the programming sequence of stream's dpms state associated
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.c 
b/drivers/gpu/drm/amd/display/dc/link/link_validation.c
index 60f15a9ba7a5..29606fda029d 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_validation.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.c
@@ -409,3 +409,182 @@ bool link_validate_dpia_bandwidth(const struct 
dc_stream_state *stream, const un
 
        return dpia_validate_usb4_bw(dpia_link, bw_needed, num_dpias);
 }
+
+struct dp_audio_layout_config {
+       uint8_t layouts_per_sample_denom;
+       uint8_t symbols_per_layout;
+       uint8_t max_layouts_per_audio_sdp;
+};
+
+static void get_audio_layout_config(
+       uint32_t channel_count,
+       enum dp_link_encoding encoding,
+       struct dp_audio_layout_config *output)
+{
+       memset(output, 0, sizeof(struct dp_audio_layout_config));
+
+       /* Assuming L-PCM audio. Current implementation uses max 1 layout per 
SDP,
+        * with each layout being the same size (8ch layout).
+        */
+       if (encoding == DP_8b_10b_ENCODING) {
+               if (channel_count == 2) {
+                       output->layouts_per_sample_denom = 4;
+                       output->symbols_per_layout = 40;
+                       output->max_layouts_per_audio_sdp = 1;
+               } else if (channel_count == 8 || channel_count == 6) {
+                       output->layouts_per_sample_denom = 1;
+                       output->symbols_per_layout = 40;
+                       output->max_layouts_per_audio_sdp = 1;
+               }
+       } else if (encoding == DP_128b_132b_ENCODING) {
+               if (channel_count == 2) {
+                       output->layouts_per_sample_denom = 4;
+                       output->symbols_per_layout = 10;
+                       output->max_layouts_per_audio_sdp = 1;
+               } else if (channel_count == 8 || channel_count == 6) {
+                       output->layouts_per_sample_denom = 1;
+                       output->symbols_per_layout = 10;
+                       output->max_layouts_per_audio_sdp = 1;
+               }
+       }
+}
+
+static uint32_t get_av_stream_map_lane_count(
+       enum dp_link_encoding encoding,
+       enum dc_lane_count lane_count,
+       bool is_mst)
+{
+       uint32_t av_stream_map_lane_count = 0;
+
+       if (encoding == DP_8b_10b_ENCODING) {
+               if (!is_mst)
+                       av_stream_map_lane_count = lane_count;
+               else
+                       av_stream_map_lane_count = 4;
+       } else if (encoding == DP_128b_132b_ENCODING) {
+               av_stream_map_lane_count = 4;
+       }
+
+       ASSERT(av_stream_map_lane_count != 0);
+
+       return av_stream_map_lane_count;
+}
+
+static uint32_t get_audio_sdp_overhead(
+       enum dp_link_encoding encoding,
+       enum dc_lane_count lane_count,
+       bool is_mst)
+{
+       uint32_t audio_sdp_overhead = 0;
+
+       if (encoding == DP_8b_10b_ENCODING) {
+               if (is_mst)
+                       audio_sdp_overhead = 16; /* 4 * 2 + 8 */
+               else
+                       audio_sdp_overhead = lane_count * 2 + 8;
+       } else if (encoding == DP_128b_132b_ENCODING) {
+               audio_sdp_overhead = 10; /* 4 x 2.5 */
+       }
+
+       ASSERT(audio_sdp_overhead != 0);
+
+       return audio_sdp_overhead;
+}
+
+/* Current calculation only applicable for 8b/10b MST and 128b/132b SST/MST.
+ */
+static uint32_t calculate_overhead_hblank_bw_in_symbols(
+       uint32_t max_slice_h)
+{
+       uint32_t overhead_hblank_bw = 0; /* in stream symbols */
+
+       overhead_hblank_bw += max_slice_h * 4; /* EOC overhead */
+       overhead_hblank_bw += 12; /* Main link overhead (VBID, BS/BE) */
+
+       return overhead_hblank_bw;
+}
+
+uint32_t dp_required_hblank_size_bytes(
+       const struct dc_link *link,
+       struct dp_audio_bandwidth_params *audio_params)
+{
+       /* Main logic from dce_audio is duplicated here, with the main
+        * difference being:
+        * - Pre-determined lane count of 4
+        * - Assumed 16 dsc slices for worst case
+        * - Assumed SDP split disabled for worst case
+        * TODO: Unify logic from dce_audio to prevent duplicated logic.
+        */
+
+       const struct dc_crtc_timing *timing = audio_params->crtc_timing;
+       const uint32_t channel_count = audio_params->channel_count;
+       const uint32_t sample_rate_hz = audio_params->sample_rate_hz;
+       const enum dp_link_encoding link_encoding = audio_params->link_encoding;
+
+       // 8b/10b MST and 128b/132b are always 4 logical lanes.
+       const uint32_t lane_count = 4;
+       const bool is_mst = (link->connector_signal == 
SIGNAL_TYPE_DISPLAY_PORT);
+       // Maximum slice count is with ODM 4:1, 4 slices per DSC
+       const uint32_t max_slices_h = 16;
+
+       const uint32_t av_stream_map_lane_count = get_av_stream_map_lane_count(
+                       link_encoding, lane_count, is_mst);
+       const uint32_t audio_sdp_overhead = get_audio_sdp_overhead(
+                       link_encoding, lane_count, is_mst);
+       struct dp_audio_layout_config layout_config;
+
+       if (link_encoding == DP_8b_10b_ENCODING && link->connector_signal == 
SIGNAL_TYPE_DISPLAY_PORT)
+               return 0;
+
+       get_audio_layout_config(
+                       channel_count, link_encoding, &layout_config);
+
+       /* DP spec recommends between 1.05 to 1.1 safety margin to prevent 
sample under-run */
+       struct fixed31_32 audio_sdp_margin = dc_fixpt_from_fraction(110, 100);
+       struct fixed31_32 horizontal_line_freq_khz = dc_fixpt_from_fraction(
+                       timing->pix_clk_100hz, (long long)timing->h_total * 10);
+       struct fixed31_32 samples_per_line;
+       struct fixed31_32 layouts_per_line;
+       struct fixed31_32 symbols_per_sdp_max_layout;
+       struct fixed31_32 remainder;
+       uint32_t num_sdp_with_max_layouts;
+       uint32_t required_symbols_per_hblank;
+       uint32_t required_bytes_per_hblank = 0;
+
+       samples_per_line = dc_fixpt_from_fraction(sample_rate_hz, 1000);
+       samples_per_line = dc_fixpt_div(samples_per_line, 
horizontal_line_freq_khz);
+       layouts_per_line = dc_fixpt_div_int(samples_per_line, 
layout_config.layouts_per_sample_denom);
+       // HBlank expansion usage assumes SDP split disabled to allow for worst 
case.
+       layouts_per_line = dc_fixpt_from_int(dc_fixpt_ceil(layouts_per_line));
+
+       num_sdp_with_max_layouts = dc_fixpt_floor(
+                       dc_fixpt_div_int(layouts_per_line, 
layout_config.max_layouts_per_audio_sdp));
+       symbols_per_sdp_max_layout = dc_fixpt_from_int(
+                       layout_config.max_layouts_per_audio_sdp * 
layout_config.symbols_per_layout);
+       symbols_per_sdp_max_layout = 
dc_fixpt_add_int(symbols_per_sdp_max_layout, audio_sdp_overhead);
+       symbols_per_sdp_max_layout = dc_fixpt_mul(symbols_per_sdp_max_layout, 
audio_sdp_margin);
+       required_symbols_per_hblank = num_sdp_with_max_layouts;
+       required_symbols_per_hblank *= 
((dc_fixpt_ceil(symbols_per_sdp_max_layout) + av_stream_map_lane_count) /
+                       av_stream_map_lane_count) *     
av_stream_map_lane_count;
+
+       if (num_sdp_with_max_layouts != dc_fixpt_ceil(
+                       dc_fixpt_div_int(layouts_per_line, 
layout_config.max_layouts_per_audio_sdp))) {
+               remainder = dc_fixpt_sub_int(layouts_per_line,
+                               num_sdp_with_max_layouts * 
layout_config.max_layouts_per_audio_sdp);
+               remainder = dc_fixpt_mul_int(remainder, 
layout_config.symbols_per_layout);
+               remainder = dc_fixpt_add_int(remainder, audio_sdp_overhead);
+               remainder = dc_fixpt_mul(remainder, audio_sdp_margin);
+               required_symbols_per_hblank += ((dc_fixpt_ceil(remainder) + 
av_stream_map_lane_count) /
+                               av_stream_map_lane_count) * 
av_stream_map_lane_count;
+       }
+
+       required_symbols_per_hblank += 
calculate_overhead_hblank_bw_in_symbols(max_slices_h);
+
+       if (link_encoding == DP_8b_10b_ENCODING)
+               required_bytes_per_hblank = required_symbols_per_hblank; // 8 
bits per 8b/10b symbol
+       else if (link_encoding == DP_128b_132b_ENCODING)
+               required_bytes_per_hblank = required_symbols_per_hblank * 4; // 
32 bits per 128b/132b symbol
+
+       return required_bytes_per_hblank;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.h 
b/drivers/gpu/drm/amd/display/dc/link/link_validation.h
index 595fb05946e9..bf398c49c3e8 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_validation.h
+++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.h
@@ -37,4 +37,9 @@ uint32_t dp_link_bandwidth_kbps(
        const struct dc_link *link,
        const struct dc_link_settings *link_settings);
 
+
+uint32_t dp_required_hblank_size_bytes(
+       const struct dc_link *link,
+       struct dp_audio_bandwidth_params *audio_params);
+
 #endif /* __LINK_VALIDATION_H__ */
-- 
2.34.1

Reply via email to