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