[Intel-gfx] [PATCH 3/3] drm/i915/display: Configure and initialize HDMI audio capabilities
Kandpal, Suraj
suraj.kandpal at intel.com
Tue Sep 5 09:17:00 UTC 2023
> Subject: [Intel-gfx] [PATCH 3/3] drm/i915/display: Configure and initialize HDMI
> audio capabilities
>
> Initialize the source audio capabilities in the crtc_state property, setting them to
Nit: maybe mention the above as intel_crtc_state rather than crtc_state property as
property usually refer to as drm_property and it just seems a little weird to
read. I have seen this in some of your previous patches in this series you can make the
changes there as well.
> their maximum supported values for max_channel and max_rate. This
> initialization enables the calculation of audio source capabilities concerning the
> available mode bandwidth. These capabilities encompass parameters such as
> supported rate and channel configurations.
>
> Additionally, introduces a wrapper function for computing Short Audio
> Descriptors (SADs). The wrapper function incorporates logic for determining
Typo * introduce
> supported rates and channels according to the capabilities of the audio source.
> It returns a set of SADs that are compatible with the audio source's capabilities.
>
> --v1:
> - Refactor max_channel and max_rate to this commit as it is being initialised
> here
> - Remove call for intel_audio_compute_eld to avoid any regression while
> merge. instead call it in different commit when it is defined.
> - Use int instead of unsigned int for max_channel and max_frequecy
> - Update commit message and header
>
> --v2:
> - Use signed instead of unsigned variables.
> - Avoid using magic numbers and give them proper name.
>
> --v3:
> - Move defines to intel_audio.c.
> - use consistent naming convention for rate and channel.
> - declare num_of_channel and aud_rate separately.
> - Declare index value outside of for loop.
> - Move Bandwidth calculation to intel_Audio.c as it is common for both DP and
> HDMI. Also use static.
>
> --v10:
> - Merged patch 2 and 3 to deduplicate function calls.
> - Instead using Calibrate and calculated functions separately, removed code
> duplication and merged functions.[Nikula, Jani]
> - Remove magic value for SAD Channel mask. [Nikula, Jani]
> - Corrected rate values based on HDMI Spec [Nikula, Jani]
> - Update drm function to extract SAD from ELD [Nikula, Jani]
>
> Signed-off-by: Mitul Golani <mitulkumar.ajitkumar.golani at intel.com>
> ---
> drivers/gpu/drm/i915/display/intel_audio.c | 127 ++++++++++++++++++
> .../drm/i915/display/intel_display_types.h | 6 +
> 2 files changed, 133 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_audio.c
> b/drivers/gpu/drm/i915/display/intel_audio.c
> index e20ffc8e9654..2584096d80a4 100644
> --- a/drivers/gpu/drm/i915/display/intel_audio.c
> +++ b/drivers/gpu/drm/i915/display/intel_audio.c
> @@ -64,6 +64,10 @@
> * struct &i915_audio_component_audio_ops @audio_ops is called from i915
> driver.
> */
>
> +#define AUDIO_SAMPLE_CONTAINER_SIZE 32
> +#define MAX_CHANNEL_COUNT 8
> +#define ELD_SAD_CHANNELS_MASK 0x7
Use REG_GENMASK() to create masks should look cleaner
> +
> struct intel_audio_funcs {
> void (*audio_codec_enable)(struct intel_encoder *encoder,
> const struct intel_crtc_state *crtc_state, @@
> -770,6 +774,127 @@ void intel_audio_sdp_split_update(struct intel_encoder
> *encoder,
> crtc_state->sdp_split_enable ?
> AUD_ENABLE_SDP_SPLIT : 0); }
>
> +static int sad_to_channels(const u8 *sad) {
> + return 1 + (sad[0] & 0x7);
I think you missed using your defined mask here;
> +}
> +
> +static int calc_audio_bw(int channel_count, int rate) {
> + int bandwidth = channel_count * rate *
> AUDIO_SAMPLE_CONTAINER_SIZE;
> + return bandwidth;
Why introduce a variable here why not just
return channel_count * rate * AUDIO_SAMPLE_CONTAINER_SIZE;
> +}
> +
> +static void calc_and_calibrate_audio_config_params(struct intel_crtc_state
> *pipe_config,
> + int channel, bool
> calibration_required) {
I think this should have a int type function that returns 0 if max_rate and max_channel_count
are non zero else return -EINVAL
> + struct drm_display_mode *adjusted_mode = &pipe_config-
> >hw.adjusted_mode;
> + int channel_count;
> + int index, rate[] = { 192000, 176400, 96000, 88200, 48000, 44100,
> 32000 };
Where do we get these rate values from.
What if we kept them at crtc_state so these can be update if required.
> + int audio_req_bandwidth, available_blank_bandwidth, vblank, hblank;
> +
> + hblank = adjusted_mode->htotal - adjusted_mode->hdisplay;
> + vblank = adjusted_mode->vtotal - adjusted_mode->vdisplay;
> + available_blank_bandwidth = hblank * vblank *
> + drm_mode_vrefresh(adjusted_mode) * pipe_config->pipe_bpp;
> +
> + /*
> + * Expected calibration of channels and respective rates,
> + * based on MAX_CHANNEL_COUNT. First calculate channel and
> + * rate based on Maximum that source can compute, letter
> + * with respect to sink's maximum channel capacity, calibrate
> + * supportive rates.
Typo: *maximum and *later and *supported
> + */
> + if (calibration_required) {
> + channel_count = channel;
> + for (index = 0; index < ARRAY_SIZE(rate); index++) {
> + audio_req_bandwidth = calc_audio_bw(channel_count,
> + rate[index]);
> + if (audio_req_bandwidth < available_blank_bandwidth)
> {
> + pipe_config->audio.max_rate = rate[index];
> + pipe_config->audio.max_channel_count =
> channel_count;
I think the above lines can be moved to function set_max_rate_and_channel as this is duplicated even in
the else block
> + return;
> + }
> + }
> + } else {
> + for (channel_count = channel; channel_count > 0;
> channel_count--) {
> + for (index = 0; index < ARRAY_SIZE(rate); index++) {
> + audio_req_bandwidth =
> calc_audio_bw(channel_count, rate[index]);
> + if (audio_req_bandwidth <
> available_blank_bandwidth) {
> + pipe_config->audio.max_rate =
> rate[index];
> + pipe_config-
> >audio.max_channel_count = channel_count;
> + return;
> + }
> + }
> + }
> + }
> +
> + pipe_config->audio.max_rate = 0;
> + pipe_config->audio.max_channel_count = 0; }
> +
> +static int get_supported_freq_mask(struct intel_crtc_state *crtc_state)
> +{
> + int rate[] = { 32000, 44100, 48000, 88200, 96000, 176400, 192000 };
So you do use the same array of rates maybe add these in the intel_crtc_state audio
struct and which can be filled in intel_dp_compute_config ,
also mention where we get these rates from.
> + int mask = 0, index;
> +
> + for (index = 0; index < ARRAY_SIZE(rate); index++) {
> + if (rate[index] > crtc_state->audio.max_rate)
> + break;
> +
> + mask |= 1 << index;
> +
> + if (crtc_state->audio.max_rate != rate[index])
> + continue;
Why are the above two lines of code needed?
It's not like there is anything to skip below them.
> + }
> +
> + return mask;
> +}
> +
> +static void intel_audio_compute_eld(struct intel_crtc_state
> +*crtc_state) {
Lets not have this as a void function and lets return the appropriate errors
If required
> + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
> + u8 *eld, *sad;
> + int index, mask = 0;
> +
> + eld = crtc_state->eld;
> + if (!eld)
> + return;
> +
> + sad = drm_extract_sad_from_eld(eld);
> + if (!sad)
> + return;
> +
> + calc_and_calibrate_audio_config_params(crtc_state,
> MAX_CHANNEL_COUNT,
> + false);
> +
> + mask = get_supported_freq_mask(crtc_state);
> + for (index = 0; index < drm_eld_sad_count(eld); index++, sad += 3) {
> + /*
> + * Respect source restricitions. Limit capabilities to a subset
> that is
> + * supported both by the source and the sink.
> + */
> + if (sad_to_channels(sad) >= crtc_state-
> >audio.max_channel_count) {
> + sad[0] &= ~ELD_SAD_CHANNELS_MASK;
> + sad[0] |= crtc_state->audio.max_channel_count - 1;
> + drm_dbg_kms(&i915->drm, "Channel count is limited
> to %d\n",
> + crtc_state->audio.max_channel_count - 1);
> + } else {
> + /*
> + * calibrate rate when, sink supported channel
> + * count is slight less than max supported
Typo: *slightly
Regards,
Suraj Kandpal
> + * channel count.
> + */
> + calc_and_calibrate_audio_config_params(crtc_state,
> +
> sad_to_channels(sad),
> + true);
> + mask = get_supported_freq_mask(crtc_state);
> + }
> +
> + sad[1] &= mask;
> + }
> +}
> +
> bool intel_audio_compute_config(struct intel_encoder *encoder,
> struct intel_crtc_state *crtc_state,
> struct drm_connector_state *conn_state) @@
> -791,6 +916,8 @@ bool intel_audio_compute_config(struct intel_encoder
> *encoder,
>
> crtc_state->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
>
> + intel_audio_compute_eld(crtc_state);
> +
> return true;
> }
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h
> b/drivers/gpu/drm/i915/display/intel_display_types.h
> index ebd147180a6e..8815837a95a6 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -1131,6 +1131,12 @@ struct intel_crtc_state {
>
> struct {
> bool has_audio;
> +
> + /* Audio rate in Hz */
> + int max_rate;
> +
> + /* Number of audio channels */
> + int max_channel_count;
> } audio;
>
> /*
> --
> 2.25.1
More information about the Intel-gfx
mailing list