diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dce/dce_audio.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce/dce_audio.c | 293 |
1 files changed, 280 insertions, 13 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c index f0458b8f00af..12f3c35b3a34 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -239,27 +239,294 @@ static void check_audio_bandwidth_hdmi( } } } +static struct fixed31_32 get_link_symbol_clk_freq_mhz(enum dc_link_rate link_rate) +{ + switch (link_rate) { + case LINK_RATE_LOW: + return dc_fixpt_from_int(162); /* 162 MHz */ + case LINK_RATE_HIGH: + return dc_fixpt_from_int(270); /* 270 MHz */ + case LINK_RATE_HIGH2: + return dc_fixpt_from_int(540); /* 540 MHz */ + case LINK_RATE_HIGH3: + return dc_fixpt_from_int(810); /* 810 MHz */ + case LINK_RATE_UHBR10: + return dc_fixpt_from_fraction(3125, 10); /* 312.5 MHz */ + case LINK_RATE_UHBR13_5: + return dc_fixpt_from_fraction(421875, 1000); /* 421.875 MHz */ + case LINK_RATE_UHBR20: + return dc_fixpt_from_int(625); /* 625 MHz */ + default: + /* Unexpected case, this requires debug if encountered. */ + ASSERT(0); + return dc_fixpt_from_int(0); + } +} + +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) +{ + /* 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; + } + } +} -/*For DP SST, calculate if specified sample rates can fit into a given timing */ -static void check_audio_bandwidth_dpsst( +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; +} + +static uint32_t calculate_required_audio_bw_in_symbols( const struct audio_crtc_info *crtc_info, + const struct dp_audio_layout_config *layout_config, uint32_t channel_count, - union audio_sample_rates *sample_rates) + uint32_t sample_rate_hz, + uint32_t av_stream_map_lane_count, + uint32_t audio_sdp_overhead) +{ + /* 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( + crtc_info->requested_pixel_clock_100Hz, crtc_info->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; + + 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); + + 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; + } + + return required_symbols_per_hblank; +} + +/* Current calculation only applicable for 8b/10b MST and 128b/132b SST/MST. + */ +static uint32_t calculate_available_hblank_bw_in_symbols( + const struct audio_crtc_info *crtc_info, + const struct audio_dp_link_info *dp_link_info) { - /* do nothing */ + uint64_t hblank = crtc_info->h_total - crtc_info->h_active; + struct fixed31_32 hblank_time_msec = + dc_fixpt_from_fraction(hblank * 10, crtc_info->requested_pixel_clock_100Hz); + struct fixed31_32 lsclkfreq_mhz = + get_link_symbol_clk_freq_mhz(dp_link_info->link_rate); + struct fixed31_32 average_stream_sym_bw_frac; + struct fixed31_32 peak_stream_bw_kbps; + struct fixed31_32 bits_per_pixel; + struct fixed31_32 link_bw_kbps; + struct fixed31_32 available_stream_sym_count; + uint32_t available_hblank_bw = 0; /* in stream symbols */ + + if (crtc_info->dsc_bits_per_pixel) { + bits_per_pixel = dc_fixpt_from_fraction(crtc_info->dsc_bits_per_pixel, 16); + } else { + switch (crtc_info->color_depth) { + case COLOR_DEPTH_666: + bits_per_pixel = dc_fixpt_from_int(6); + break; + case COLOR_DEPTH_888: + bits_per_pixel = dc_fixpt_from_int(8); + break; + case COLOR_DEPTH_101010: + bits_per_pixel = dc_fixpt_from_int(10); + break; + case COLOR_DEPTH_121212: + bits_per_pixel = dc_fixpt_from_int(12); + break; + default: + /* Default to commonly supported color depth. */ + bits_per_pixel = dc_fixpt_from_int(8); + break; + } + + bits_per_pixel = dc_fixpt_mul_int(bits_per_pixel, 3); + + if (crtc_info->pixel_encoding == PIXEL_ENCODING_YCBCR422) { + bits_per_pixel = dc_fixpt_div_int(bits_per_pixel, 3); + bits_per_pixel = dc_fixpt_mul_int(bits_per_pixel, 2); + } else if (crtc_info->pixel_encoding == PIXEL_ENCODING_YCBCR420) { + bits_per_pixel = dc_fixpt_div_int(bits_per_pixel, 2); + } + } + + /* Use simple stream BW calculation because mainlink overhead is + * accounted for separately in the audio BW calculations. + */ + peak_stream_bw_kbps = dc_fixpt_from_fraction(crtc_info->requested_pixel_clock_100Hz, 10); + peak_stream_bw_kbps = dc_fixpt_mul(peak_stream_bw_kbps, bits_per_pixel); + link_bw_kbps = dc_fixpt_from_int(dp_link_info->link_bandwidth_kbps); + average_stream_sym_bw_frac = dc_fixpt_div(peak_stream_bw_kbps, link_bw_kbps); + + available_stream_sym_count = dc_fixpt_mul_int(hblank_time_msec, 1000); + available_stream_sym_count = dc_fixpt_mul(available_stream_sym_count, lsclkfreq_mhz); + available_stream_sym_count = dc_fixpt_mul(available_stream_sym_count, average_stream_sym_bw_frac); + available_hblank_bw = dc_fixpt_floor(available_stream_sym_count); + available_hblank_bw *= dp_link_info->lane_count; + available_hblank_bw -= crtc_info->dsc_num_slices * 4; /* EOC overhead */ + + if (available_hblank_bw < dp_link_info->hblank_min_symbol_width) + available_hblank_bw = dp_link_info->hblank_min_symbol_width; + + if (available_hblank_bw < 12) + available_hblank_bw = 0; + else + available_hblank_bw -= 12; /* Main link overhead */ + + return available_hblank_bw; } -/*For DP MST, calculate if specified sample rates can fit into a given timing */ -static void check_audio_bandwidth_dpmst( +static void check_audio_bandwidth_dp( const struct audio_crtc_info *crtc_info, + const struct audio_dp_link_info *dp_link_info, uint32_t channel_count, union audio_sample_rates *sample_rates) { - /* do nothing */ + struct dp_audio_layout_config layout_config = {0}; + uint32_t available_hblank_bw; + uint32_t av_stream_map_lane_count; + uint32_t audio_sdp_overhead; + + /* TODO: Add validation for SST 8b/10 case */ + if (!dp_link_info->is_mst && dp_link_info->encoding == DP_8b_10b_ENCODING) + return; + + available_hblank_bw = calculate_available_hblank_bw_in_symbols( + crtc_info, dp_link_info); + av_stream_map_lane_count = get_av_stream_map_lane_count( + dp_link_info->encoding, dp_link_info->lane_count, dp_link_info->is_mst); + audio_sdp_overhead = get_audio_sdp_overhead( + dp_link_info->encoding, dp_link_info->lane_count, dp_link_info->is_mst); + get_audio_layout_config( + channel_count, dp_link_info->encoding, &layout_config); + + if (layout_config.max_layouts_per_audio_sdp == 0 || + layout_config.symbols_per_layout == 0 || + layout_config.layouts_per_sample_denom == 0) { + return; + } + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 192000, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_192 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 176400, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_176_4 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 96000, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_96 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 88200, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_88_2 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 48000, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_48 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 44100, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_44_1 = 0; + if (available_hblank_bw < calculate_required_audio_bw_in_symbols( + crtc_info, &layout_config, channel_count, 32000, + av_stream_map_lane_count, audio_sdp_overhead)) + sample_rates->rate.RATE_32 = 0; } static void check_audio_bandwidth( const struct audio_crtc_info *crtc_info, + const struct audio_dp_link_info *dp_link_info, uint32_t channel_count, enum signal_type signal, union audio_sample_rates *sample_rates) @@ -271,12 +538,9 @@ static void check_audio_bandwidth( break; case SIGNAL_TYPE_EDP: case SIGNAL_TYPE_DISPLAY_PORT: - check_audio_bandwidth_dpsst( - crtc_info, channel_count, sample_rates); - break; case SIGNAL_TYPE_DISPLAY_PORT_MST: - check_audio_bandwidth_dpmst( - crtc_info, channel_count, sample_rates); + check_audio_bandwidth_dp( + crtc_info, dp_link_info, channel_count, sample_rates); break; default: break; @@ -394,7 +658,8 @@ void dce_aud_az_configure( struct audio *audio, enum signal_type signal, const struct audio_crtc_info *crtc_info, - const struct audio_info *audio_info) + const struct audio_info *audio_info, + const struct audio_dp_link_info *dp_link_info) { struct dce_audio *aud = DCE_AUD(audio); @@ -529,6 +794,7 @@ void dce_aud_az_configure( check_audio_bandwidth( crtc_info, + dp_link_info, channel_count, signal, &sample_rates); @@ -588,6 +854,7 @@ void dce_aud_az_configure( check_audio_bandwidth( crtc_info, + dp_link_info, 8, signal, &sample_rate); |