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 "hw_shared.h" 29 #include "dcn30_afmt.h" 30 #include "reg_helper.h" 31 32 #define DC_LOGGER \ 33 afmt3->base.ctx->logger 34 35 #define REG(reg)\ 36 (afmt3->regs->reg) 37 38 #undef FN 39 #define FN(reg_name, field_name) \ 40 afmt3->afmt_shift->field_name, afmt3->afmt_mask->field_name 41 42 43 #define CTX \ 44 afmt3->base.ctx 45 46 47 void afmt3_setup_hdmi_audio( 48 struct afmt *afmt) 49 { 50 struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); 51 52 if (afmt->funcs->afmt_poweron) 53 afmt->funcs->afmt_poweron(afmt); 54 55 /* AFMT_AUDIO_PACKET_CONTROL */ 56 REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL, AFMT_60958_CS_UPDATE, 1); 57 58 /* AFMT_AUDIO_PACKET_CONTROL2 */ 59 REG_UPDATE_2(AFMT_AUDIO_PACKET_CONTROL2, 60 AFMT_AUDIO_LAYOUT_OVRD, 0, 61 AFMT_60958_OSF_OVRD, 0); 62 63 /* AFMT_60958_0__AFMT_60958_CS_CHANNEL_NUMBER_L_MASK & 64 * AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK 65 */ 66 REG_UPDATE_2(AFMT_60958_0, 67 AFMT_60958_CS_CHANNEL_NUMBER_L, 1, 68 AFMT_60958_CS_CLOCK_ACCURACY, 0); 69 70 /* AFMT_60958_1 AFMT_60958_CS_CHALNNEL_NUMBER_R */ 71 REG_UPDATE(AFMT_60958_1, AFMT_60958_CS_CHANNEL_NUMBER_R, 2); 72 73 /* AFMT_60958_2 now keep this settings until 74 * Programming guide comes out 75 */ 76 REG_UPDATE_6(AFMT_60958_2, 77 AFMT_60958_CS_CHANNEL_NUMBER_2, 3, 78 AFMT_60958_CS_CHANNEL_NUMBER_3, 4, 79 AFMT_60958_CS_CHANNEL_NUMBER_4, 5, 80 AFMT_60958_CS_CHANNEL_NUMBER_5, 6, 81 AFMT_60958_CS_CHANNEL_NUMBER_6, 7, 82 AFMT_60958_CS_CHANNEL_NUMBER_7, 8); 83 } 84 85 static union audio_cea_channels speakers_to_channels( 86 struct audio_speaker_flags speaker_flags) 87 { 88 union audio_cea_channels cea_channels = {0}; 89 90 /* these are one to one */ 91 cea_channels.channels.FL = speaker_flags.FL_FR; 92 cea_channels.channels.FR = speaker_flags.FL_FR; 93 cea_channels.channels.LFE = speaker_flags.LFE; 94 cea_channels.channels.FC = speaker_flags.FC; 95 96 /* if Rear Left and Right exist move RC speaker to channel 7 97 * otherwise to channel 5 98 */ 99 if (speaker_flags.RL_RR) { 100 cea_channels.channels.RL_RC = speaker_flags.RL_RR; 101 cea_channels.channels.RR = speaker_flags.RL_RR; 102 cea_channels.channels.RC_RLC_FLC = speaker_flags.RC; 103 } else { 104 cea_channels.channels.RL_RC = speaker_flags.RC; 105 } 106 107 /* FRONT Left Right Center and REAR Left Right Center are exclusive */ 108 if (speaker_flags.FLC_FRC) { 109 cea_channels.channels.RC_RLC_FLC = speaker_flags.FLC_FRC; 110 cea_channels.channels.RRC_FRC = speaker_flags.FLC_FRC; 111 } else { 112 cea_channels.channels.RC_RLC_FLC = speaker_flags.RLC_RRC; 113 cea_channels.channels.RRC_FRC = speaker_flags.RLC_RRC; 114 } 115 116 return cea_channels; 117 } 118 119 void afmt3_se_audio_setup( 120 struct afmt *afmt, 121 unsigned int az_inst, 122 struct audio_info *audio_info) 123 { 124 struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); 125 126 uint32_t speakers = 0; 127 uint32_t channels = 0; 128 129 ASSERT(audio_info); 130 /* This should not happen.it does so we don't get BSOD*/ 131 if (audio_info == NULL) 132 return; 133 134 speakers = audio_info->flags.info.ALLSPEAKERS; 135 channels = speakers_to_channels(audio_info->flags.speaker_flags).all; 136 137 /* setup the audio stream source select (audio -> dig mapping) */ 138 REG_SET(AFMT_AUDIO_SRC_CONTROL, 0, AFMT_AUDIO_SRC_SELECT, az_inst); 139 140 /* Channel allocation */ 141 REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL2, AFMT_AUDIO_CHANNEL_ENABLE, channels); 142 143 /* Disable forced mem power off */ 144 if (afmt->funcs->afmt_poweron == NULL) 145 REG_UPDATE(AFMT_MEM_PWR, AFMT_MEM_PWR_FORCE, 0); 146 } 147 148 void afmt3_audio_mute_control( 149 struct afmt *afmt, 150 bool mute) 151 { 152 struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); 153 if (mute && afmt->funcs->afmt_powerdown) 154 afmt->funcs->afmt_powerdown(afmt); 155 if (!mute && afmt->funcs->afmt_poweron) 156 afmt->funcs->afmt_poweron(afmt); 157 /* enable/disable transmission of audio packets */ 158 REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, !mute); 159 } 160 161 void afmt3_audio_info_immediate_update( 162 struct afmt *afmt) 163 { 164 struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); 165 166 /* update double-buffered AUDIO_INFO registers immediately */ 167 REG_UPDATE(AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1); 168 } 169 170 void afmt3_setup_dp_audio( 171 struct afmt *afmt) 172 { 173 struct dcn30_afmt *afmt3 = DCN30_AFMT_FROM_AFMT(afmt); 174 175 if (afmt->funcs->afmt_poweron) 176 afmt->funcs->afmt_poweron(afmt); 177 178 /* AFMT_AUDIO_PACKET_CONTROL */ 179 REG_UPDATE(AFMT_AUDIO_PACKET_CONTROL, AFMT_60958_CS_UPDATE, 1); 180 181 /* AFMT_AUDIO_PACKET_CONTROL2 */ 182 /* Program the ATP and AIP next */ 183 REG_UPDATE_2(AFMT_AUDIO_PACKET_CONTROL2, 184 AFMT_AUDIO_LAYOUT_OVRD, 0, 185 AFMT_60958_OSF_OVRD, 0); 186 187 /* AFMT_INFOFRAME_CONTROL0 */ 188 REG_UPDATE(AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1); 189 190 /* AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK */ 191 REG_UPDATE(AFMT_60958_0, AFMT_60958_CS_CLOCK_ACCURACY, 0); 192 } 193 194 static struct afmt_funcs dcn30_afmt_funcs = { 195 .setup_hdmi_audio = afmt3_setup_hdmi_audio, 196 .se_audio_setup = afmt3_se_audio_setup, 197 .audio_mute_control = afmt3_audio_mute_control, 198 .audio_info_immediate_update = afmt3_audio_info_immediate_update, 199 .setup_dp_audio = afmt3_setup_dp_audio, 200 }; 201 202 void afmt3_construct(struct dcn30_afmt *afmt3, 203 struct dc_context *ctx, 204 uint32_t inst, 205 const struct dcn30_afmt_registers *afmt_regs, 206 const struct dcn30_afmt_shift *afmt_shift, 207 const struct dcn30_afmt_mask *afmt_mask) 208 { 209 afmt3->base.ctx = ctx; 210 211 afmt3->base.inst = inst; 212 afmt3->base.funcs = &dcn30_afmt_funcs; 213 214 afmt3->regs = afmt_regs; 215 afmt3->afmt_shift = afmt_shift; 216 afmt3->afmt_mask = afmt_mask; 217 } 218