1 /* 2 * Copyright 2020 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 27 #include "dc_bios_types.h" 28 #include "dcn30_afmt.h" 29 #include "reg_helper.h" 30 31 #define DC_LOGGER \ 32 afmt3->base.ctx->logger 33 34 #define REG(reg)\ 35 (afmt3->regs->reg) 36 37 #undef FN 38 #define FN(reg_name, field_name) \ 39 afmt3->afmt_shift->field_name, afmt3->afmt_mask->field_name 40 41 42 #define CTX \ 43 afmt3->base.ctx 44 45 46 static void afmt3_setup_hdmi_audio( 47 struct afmt *afmt) 48 { 49 struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); 50 51 /* AFMT_AUDIO_PACKET_CONTROL */ 52 REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL, AFMT_60958_CS_UPDATE, 1); 53 54 /* AFMT_AUDIO_PACKET_CONTROL2 */ 55 REG_UPDATE_2(AFMT_AUDIO_PACKET_CONTROL2, 56 AFMT_AUDIO_LAYOUT_OVRD, 0, 57 AFMT_60958_OSF_OVRD, 0); 58 59 /* AFMT_60958_0__AFMT_60958_CS_CHANNEL_NUMBER_L_MASK & 60 * AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK 61 */ 62 REG_UPDATE_2(AFMT_60958_0, 63 AFMT_60958_CS_CHANNEL_NUMBER_L, 1, 64 AFMT_60958_CS_CLOCK_ACCURACY, 0); 65 66 /* AFMT_60958_1 AFMT_60958_CS_CHALNNEL_NUMBER_R */ 67 REG_UPDATE(AFMT_60958_1, AFMT_60958_CS_CHANNEL_NUMBER_R, 2); 68 69 /* AFMT_60958_2 now keep this settings until 70 * Programming guide comes out 71 */ 72 REG_UPDATE_6(AFMT_60958_2, 73 AFMT_60958_CS_CHANNEL_NUMBER_2, 3, 74 AFMT_60958_CS_CHANNEL_NUMBER_3, 4, 75 AFMT_60958_CS_CHANNEL_NUMBER_4, 5, 76 AFMT_60958_CS_CHANNEL_NUMBER_5, 6, 77 AFMT_60958_CS_CHANNEL_NUMBER_6, 7, 78 AFMT_60958_CS_CHANNEL_NUMBER_7, 8); 79 } 80 81 static union audio_cea_channels speakers_to_channels( 82 struct audio_speaker_flags speaker_flags) 83 { 84 union audio_cea_channels cea_channels = {0}; 85 86 /* these are one to one */ 87 cea_channels.channels.FL = speaker_flags.FL_FR; 88 cea_channels.channels.FR = speaker_flags.FL_FR; 89 cea_channels.channels.LFE = speaker_flags.LFE; 90 cea_channels.channels.FC = speaker_flags.FC; 91 92 /* if Rear Left and Right exist move RC speaker to channel 7 93 * otherwise to channel 5 94 */ 95 if (speaker_flags.RL_RR) { 96 cea_channels.channels.RL_RC = speaker_flags.RL_RR; 97 cea_channels.channels.RR = speaker_flags.RL_RR; 98 cea_channels.channels.RC_RLC_FLC = speaker_flags.RC; 99 } else { 100 cea_channels.channels.RL_RC = speaker_flags.RC; 101 } 102 103 /* FRONT Left Right Center and REAR Left Right Center are exclusive */ 104 if (speaker_flags.FLC_FRC) { 105 cea_channels.channels.RC_RLC_FLC = speaker_flags.FLC_FRC; 106 cea_channels.channels.RRC_FRC = speaker_flags.FLC_FRC; 107 } else { 108 cea_channels.channels.RC_RLC_FLC = speaker_flags.RLC_RRC; 109 cea_channels.channels.RRC_FRC = speaker_flags.RLC_RRC; 110 } 111 112 return cea_channels; 113 } 114 115 static void afmt3_se_audio_setup( 116 struct afmt *afmt, 117 unsigned int az_inst, 118 struct audio_info *audio_info) 119 { 120 struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); 121 122 uint32_t speakers = 0; 123 uint32_t channels = 0; 124 125 ASSERT(audio_info); 126 /* This should not happen.it does so we don't get BSOD*/ 127 if (audio_info == NULL) 128 return; 129 130 speakers = audio_info->flags.info.ALLSPEAKERS; 131 channels = speakers_to_channels(audio_info->flags.speaker_flags).all; 132 133 /* setup the audio stream source select (audio -> dig mapping) */ 134 REG_SET(AFMT_AUDIO_SRC_CONTROL, 0, AFMT_AUDIO_SRC_SELECT, az_inst); 135 136 /* Channel allocation */ 137 REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL2, AFMT_AUDIO_CHANNEL_ENABLE, channels); 138 139 /* Disable forced mem power off */ 140 REG_UPDATE(AFMT_MEM_PWR, AFMT_MEM_PWR_FORCE, 0); 141 } 142 143 static void afmt3_audio_mute_control( 144 struct afmt *afmt, 145 bool mute) 146 { 147 struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); 148 149 /* enable/disable transmission of audio packets */ 150 REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, !mute); 151 } 152 153 static void afmt3_audio_info_immediate_update( 154 struct afmt *afmt) 155 { 156 struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); 157 158 /* update double-buffered AUDIO_INFO registers immediately */ 159 REG_UPDATE(AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1); 160 } 161 162 static void afmt3_setup_dp_audio( 163 struct afmt *afmt) 164 { 165 struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); 166 167 /* AFMT_AUDIO_PACKET_CONTROL */ 168 REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL, AFMT_60958_CS_UPDATE, 1); 169 170 /* AFMT_AUDIO_PACKET_CONTROL2 */ 171 /* Program the ATP and AIP next */ 172 REG_UPDATE_2(AFMT_AUDIO_PACKET_CONTROL2, 173 AFMT_AUDIO_LAYOUT_OVRD, 0, 174 AFMT_60958_OSF_OVRD, 0); 175 176 /* AFMT_INFOFRAME_CONTROL0 */ 177 REG_UPDATE(AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1); 178 179 /* AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK */ 180 REG_UPDATE(AFMT_60958_0, AFMT_60958_CS_CLOCK_ACCURACY, 0); 181 } 182 183 static struct afmt_funcs dcn30_afmt_funcs = { 184 .setup_hdmi_audio = afmt3_setup_hdmi_audio, 185 .se_audio_setup = afmt3_se_audio_setup, 186 .audio_mute_control = afmt3_audio_mute_control, 187 .audio_info_immediate_update = afmt3_audio_info_immediate_update, 188 .setup_dp_audio = afmt3_setup_dp_audio, 189 }; 190 191 void afmt3_construct(struct dcn30_afmt *afmt3, 192 struct dc_context *ctx, 193 uint32_t inst, 194 const struct dcn30_afmt_registers *afmt_regs, 195 const struct dcn30_afmt_shift *afmt_shift, 196 const struct dcn30_afmt_mask *afmt_mask) 197 { 198 afmt3->base.ctx = ctx; 199 200 afmt3->base.inst = inst; 201 afmt3->base.funcs = &dcn30_afmt_funcs; 202 203 afmt3->regs = afmt_regs; 204 afmt3->afmt_shift = afmt_shift; 205 afmt3->afmt_mask = afmt_mask; 206 } 207