linux/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_afmt.c
<<
>>
Prefs
   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
  47static 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
  82static 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
 116static 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
 144static 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
 154static 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
 163static 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
 184static 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
 192void 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