linux/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c
<<
>>
Prefs
   1/*
   2 * Copyright 2019 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 "dcn31_apg.h"
  30#include "reg_helper.h"
  31
  32#define DC_LOGGER \
  33                apg31->base.ctx->logger
  34
  35#define REG(reg)\
  36        (apg31->regs->reg)
  37
  38#undef FN
  39#define FN(reg_name, field_name) \
  40        apg31->apg_shift->field_name, apg31->apg_mask->field_name
  41
  42
  43#define CTX \
  44        apg31->base.ctx
  45
  46
  47static void apg31_enable(
  48        struct apg *apg)
  49{
  50        struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
  51
  52        /* Reset APG */
  53        REG_UPDATE(APG_CONTROL, APG_RESET, 1);
  54        REG_WAIT(APG_CONTROL,
  55                        APG_RESET_DONE, 1,
  56                        1, 10);
  57        REG_UPDATE(APG_CONTROL, APG_RESET, 0);
  58        REG_WAIT(APG_CONTROL,
  59                        APG_RESET_DONE, 0,
  60                        1, 10);
  61
  62        /* Enable APG */
  63        REG_UPDATE(APG_CONTROL2, APG_ENABLE, 1);
  64}
  65
  66static void apg31_disable(
  67        struct apg *apg)
  68{
  69        struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
  70
  71        /* Disable APG */
  72        REG_UPDATE(APG_CONTROL2, APG_ENABLE, 0);
  73}
  74
  75static union audio_cea_channels speakers_to_channels(
  76        struct audio_speaker_flags speaker_flags)
  77{
  78        union audio_cea_channels cea_channels = {0};
  79
  80        /* these are one to one */
  81        cea_channels.channels.FL = speaker_flags.FL_FR;
  82        cea_channels.channels.FR = speaker_flags.FL_FR;
  83        cea_channels.channels.LFE = speaker_flags.LFE;
  84        cea_channels.channels.FC = speaker_flags.FC;
  85
  86        /* if Rear Left and Right exist move RC speaker to channel 7
  87         * otherwise to channel 5
  88         */
  89        if (speaker_flags.RL_RR) {
  90                cea_channels.channels.RL_RC = speaker_flags.RL_RR;
  91                cea_channels.channels.RR = speaker_flags.RL_RR;
  92                cea_channels.channels.RC_RLC_FLC = speaker_flags.RC;
  93        } else {
  94                cea_channels.channels.RL_RC = speaker_flags.RC;
  95        }
  96
  97        /* FRONT Left Right Center and REAR Left Right Center are exclusive */
  98        if (speaker_flags.FLC_FRC) {
  99                cea_channels.channels.RC_RLC_FLC = speaker_flags.FLC_FRC;
 100                cea_channels.channels.RRC_FRC = speaker_flags.FLC_FRC;
 101        } else {
 102                cea_channels.channels.RC_RLC_FLC = speaker_flags.RLC_RRC;
 103                cea_channels.channels.RRC_FRC = speaker_flags.RLC_RRC;
 104        }
 105
 106        return cea_channels;
 107}
 108
 109static void apg31_se_audio_setup(
 110        struct apg *apg,
 111        unsigned int az_inst,
 112        struct audio_info *audio_info)
 113{
 114        struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
 115
 116        uint32_t speakers = 0;
 117        uint32_t channels = 0;
 118
 119        ASSERT(audio_info);
 120        /* This should not happen.it does so we don't get BSOD*/
 121        if (audio_info == NULL)
 122                return;
 123
 124        speakers = audio_info->flags.info.ALLSPEAKERS;
 125        channels = speakers_to_channels(audio_info->flags.speaker_flags).all;
 126
 127        /* DisplayPort only allows for one audio stream with stream ID 0 */
 128        REG_UPDATE(APG_CONTROL2, APG_DP_AUDIO_STREAM_ID, 0);
 129
 130        /* When running in "pair mode", pairs of audio channels have their own enable
 131         * this is for really old audio drivers */
 132        REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, 0xFF);
 133        // REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, channels);
 134
 135        /* Disable forced mem power off */
 136        REG_UPDATE(APG_MEM_PWR, APG_MEM_PWR_FORCE, 0);
 137
 138        apg31_enable(apg);
 139}
 140
 141static void apg31_audio_mute_control(
 142        struct apg *apg,
 143        bool mute)
 144{
 145        if (mute)
 146                apg31_disable(apg);
 147        else
 148                apg31_enable(apg);
 149}
 150
 151static struct apg_funcs dcn31_apg_funcs = {
 152        .se_audio_setup                 = apg31_se_audio_setup,
 153        .audio_mute_control             = apg31_audio_mute_control,
 154        .enable_apg                     = apg31_enable,
 155        .disable_apg                    = apg31_disable,
 156};
 157
 158void apg31_construct(struct dcn31_apg *apg31,
 159        struct dc_context *ctx,
 160        uint32_t inst,
 161        const struct dcn31_apg_registers *apg_regs,
 162        const struct dcn31_apg_shift *apg_shift,
 163        const struct dcn31_apg_mask *apg_mask)
 164{
 165        apg31->base.ctx = ctx;
 166
 167        apg31->base.inst = inst;
 168        apg31->base.funcs = &dcn31_apg_funcs;
 169
 170        apg31->regs = apg_regs;
 171        apg31->apg_shift = apg_shift;
 172        apg31->apg_mask = apg_mask;
 173}
 174