diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dcn30/dcn30_afmt.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dcn30/dcn30_afmt.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_afmt.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_afmt.c new file mode 100644 index 000000000000..2b08b1d72177 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_afmt.c @@ -0,0 +1,206 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + +#include "dc_bios_types.h" +#include "dcn30_afmt.h" +#include "reg_helper.h" + +#define DC_LOGGER \ + afmt3->base.ctx->logger + +#define REG(reg)\ + (afmt3->regs->reg) + +#undef FN +#define FN(reg_name, field_name) \ + afmt3->afmt_shift->field_name, afmt3->afmt_mask->field_name + + +#define CTX \ + afmt3->base.ctx + + +static void afmt3_setup_hdmi_audio( + struct afmt *afmt) +{ + struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); + + /* AFMT_AUDIO_PACKET_CONTROL */ + REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL, AFMT_60958_CS_UPDATE, 1); + + /* AFMT_AUDIO_PACKET_CONTROL2 */ + REG_UPDATE_2(AFMT_AUDIO_PACKET_CONTROL2, + AFMT_AUDIO_LAYOUT_OVRD, 0, + AFMT_60958_OSF_OVRD, 0); + + /* AFMT_60958_0__AFMT_60958_CS_CHANNEL_NUMBER_L_MASK & + * AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK + */ + REG_UPDATE_2(AFMT_60958_0, + AFMT_60958_CS_CHANNEL_NUMBER_L, 1, + AFMT_60958_CS_CLOCK_ACCURACY, 0); + + /* AFMT_60958_1 AFMT_60958_CS_CHALNNEL_NUMBER_R */ + REG_UPDATE(AFMT_60958_1, AFMT_60958_CS_CHANNEL_NUMBER_R, 2); + + /* AFMT_60958_2 now keep this settings until + * Programming guide comes out + */ + REG_UPDATE_6(AFMT_60958_2, + AFMT_60958_CS_CHANNEL_NUMBER_2, 3, + AFMT_60958_CS_CHANNEL_NUMBER_3, 4, + AFMT_60958_CS_CHANNEL_NUMBER_4, 5, + AFMT_60958_CS_CHANNEL_NUMBER_5, 6, + AFMT_60958_CS_CHANNEL_NUMBER_6, 7, + AFMT_60958_CS_CHANNEL_NUMBER_7, 8); +} + +static union audio_cea_channels speakers_to_channels( + struct audio_speaker_flags speaker_flags) +{ + union audio_cea_channels cea_channels = {0}; + + /* these are one to one */ + cea_channels.channels.FL = speaker_flags.FL_FR; + cea_channels.channels.FR = speaker_flags.FL_FR; + cea_channels.channels.LFE = speaker_flags.LFE; + cea_channels.channels.FC = speaker_flags.FC; + + /* if Rear Left and Right exist move RC speaker to channel 7 + * otherwise to channel 5 + */ + if (speaker_flags.RL_RR) { + cea_channels.channels.RL_RC = speaker_flags.RL_RR; + cea_channels.channels.RR = speaker_flags.RL_RR; + cea_channels.channels.RC_RLC_FLC = speaker_flags.RC; + } else { + cea_channels.channels.RL_RC = speaker_flags.RC; + } + + /* FRONT Left Right Center and REAR Left Right Center are exclusive */ + if (speaker_flags.FLC_FRC) { + cea_channels.channels.RC_RLC_FLC = speaker_flags.FLC_FRC; + cea_channels.channels.RRC_FRC = speaker_flags.FLC_FRC; + } else { + cea_channels.channels.RC_RLC_FLC = speaker_flags.RLC_RRC; + cea_channels.channels.RRC_FRC = speaker_flags.RLC_RRC; + } + + return cea_channels; +} + +static void afmt3_se_audio_setup( + struct afmt *afmt, + unsigned int az_inst, + struct audio_info *audio_info) +{ + struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); + + uint32_t speakers = 0; + uint32_t channels = 0; + + ASSERT(audio_info); + /* This should not happen.it does so we don't get BSOD*/ + if (audio_info == NULL) + return; + + speakers = audio_info->flags.info.ALLSPEAKERS; + channels = speakers_to_channels(audio_info->flags.speaker_flags).all; + + /* setup the audio stream source select (audio -> dig mapping) */ + REG_SET(AFMT_AUDIO_SRC_CONTROL, 0, AFMT_AUDIO_SRC_SELECT, az_inst); + + /* Channel allocation */ + REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL2, AFMT_AUDIO_CHANNEL_ENABLE, channels); + + /* Disable forced mem power off */ + REG_UPDATE(AFMT_MEM_PWR, AFMT_MEM_PWR_FORCE, 0); +} + +static void afmt3_audio_mute_control( + struct afmt *afmt, + bool mute) +{ + struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); + + /* enable/disable transmission of audio packets */ + REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, !mute); +} + +static void afmt3_audio_info_immediate_update( + struct afmt *afmt) +{ + struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); + + /* update double-buffered AUDIO_INFO registers immediately */ + REG_UPDATE(AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1); +} + +static void afmt3_setup_dp_audio( + struct afmt *afmt) +{ + struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); + + /* AFMT_AUDIO_PACKET_CONTROL */ + REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL, AFMT_60958_CS_UPDATE, 1); + + /* AFMT_AUDIO_PACKET_CONTROL2 */ + /* Program the ATP and AIP next */ + REG_UPDATE_2(AFMT_AUDIO_PACKET_CONTROL2, + AFMT_AUDIO_LAYOUT_OVRD, 0, + AFMT_60958_OSF_OVRD, 0); + + /* AFMT_INFOFRAME_CONTROL0 */ + REG_UPDATE(AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1); + + /* AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK */ + REG_UPDATE(AFMT_60958_0, AFMT_60958_CS_CLOCK_ACCURACY, 0); +} + +static struct afmt_funcs dcn30_afmt_funcs = { + .setup_hdmi_audio = afmt3_setup_hdmi_audio, + .se_audio_setup = afmt3_se_audio_setup, + .audio_mute_control = afmt3_audio_mute_control, + .audio_info_immediate_update = afmt3_audio_info_immediate_update, + .setup_dp_audio = afmt3_setup_dp_audio, +}; + +void afmt3_construct(struct dcn30_afmt *afmt3, + struct dc_context *ctx, + uint32_t inst, + const struct dcn30_afmt_registers *afmt_regs, + const struct dcn30_afmt_shift *afmt_shift, + const struct dcn30_afmt_mask *afmt_mask) +{ + afmt3->base.ctx = ctx; + + afmt3->base.inst = inst; + afmt3->base.funcs = &dcn30_afmt_funcs; + + afmt3->regs = afmt_regs; + afmt3->afmt_shift = afmt_shift; + afmt3->afmt_mask = afmt_mask; +} |