drm/amd/display: Add DP required HBlank size calc to link interface

[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.liu@amd.com>
Signed-off-by: George Shen <george.shen@amd.com>
Signed-off-by: Roman Li <roman.li@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
George Shen 2024-12-09 10:29:31 -05:00 committed by Alex Deucher
parent e79cba63de
commit 3ed56d9e8f
6 changed files with 215 additions and 0 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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__ */