Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2019 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  *  and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 
0027 #include "dc_bios_types.h"
0028 #include "hw_shared.h"
0029 #include "dcn31_apg.h"
0030 #include "reg_helper.h"
0031 
0032 #define DC_LOGGER \
0033         apg31->base.ctx->logger
0034 
0035 #define REG(reg)\
0036     (apg31->regs->reg)
0037 
0038 #undef FN
0039 #define FN(reg_name, field_name) \
0040     apg31->apg_shift->field_name, apg31->apg_mask->field_name
0041 
0042 
0043 #define CTX \
0044     apg31->base.ctx
0045 
0046 
0047 static void apg31_enable(
0048     struct apg *apg)
0049 {
0050     struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
0051 
0052     /* Reset APG */
0053     REG_UPDATE(APG_CONTROL, APG_RESET, 1);
0054     REG_WAIT(APG_CONTROL,
0055             APG_RESET_DONE, 1,
0056             1, 10);
0057     REG_UPDATE(APG_CONTROL, APG_RESET, 0);
0058     REG_WAIT(APG_CONTROL,
0059             APG_RESET_DONE, 0,
0060             1, 10);
0061 
0062     /* Enable APG */
0063     REG_UPDATE(APG_CONTROL2, APG_ENABLE, 1);
0064 }
0065 
0066 static void apg31_disable(
0067     struct apg *apg)
0068 {
0069     struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
0070 
0071     /* Disable APG */
0072     REG_UPDATE(APG_CONTROL2, APG_ENABLE, 0);
0073 }
0074 
0075 static union audio_cea_channels speakers_to_channels(
0076     struct audio_speaker_flags speaker_flags)
0077 {
0078     union audio_cea_channels cea_channels = {0};
0079 
0080     /* these are one to one */
0081     cea_channels.channels.FL = speaker_flags.FL_FR;
0082     cea_channels.channels.FR = speaker_flags.FL_FR;
0083     cea_channels.channels.LFE = speaker_flags.LFE;
0084     cea_channels.channels.FC = speaker_flags.FC;
0085 
0086     /* if Rear Left and Right exist move RC speaker to channel 7
0087      * otherwise to channel 5
0088      */
0089     if (speaker_flags.RL_RR) {
0090         cea_channels.channels.RL_RC = speaker_flags.RL_RR;
0091         cea_channels.channels.RR = speaker_flags.RL_RR;
0092         cea_channels.channels.RC_RLC_FLC = speaker_flags.RC;
0093     } else {
0094         cea_channels.channels.RL_RC = speaker_flags.RC;
0095     }
0096 
0097     /* FRONT Left Right Center and REAR Left Right Center are exclusive */
0098     if (speaker_flags.FLC_FRC) {
0099         cea_channels.channels.RC_RLC_FLC = speaker_flags.FLC_FRC;
0100         cea_channels.channels.RRC_FRC = speaker_flags.FLC_FRC;
0101     } else {
0102         cea_channels.channels.RC_RLC_FLC = speaker_flags.RLC_RRC;
0103         cea_channels.channels.RRC_FRC = speaker_flags.RLC_RRC;
0104     }
0105 
0106     return cea_channels;
0107 }
0108 
0109 static void apg31_se_audio_setup(
0110     struct apg *apg,
0111     unsigned int az_inst,
0112     struct audio_info *audio_info)
0113 {
0114     struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
0115 
0116     uint32_t speakers = 0;
0117     uint32_t channels = 0;
0118 
0119     ASSERT(audio_info);
0120     /* This should not happen.it does so we don't get BSOD*/
0121     if (audio_info == NULL)
0122         return;
0123 
0124     speakers = audio_info->flags.info.ALLSPEAKERS;
0125     channels = speakers_to_channels(audio_info->flags.speaker_flags).all;
0126 
0127     /* DisplayPort only allows for one audio stream with stream ID 0 */
0128     REG_UPDATE(APG_CONTROL2, APG_DP_AUDIO_STREAM_ID, 0);
0129 
0130     /* When running in "pair mode", pairs of audio channels have their own enable
0131      * this is for really old audio drivers */
0132     REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, 0xFF);
0133     // REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, channels);
0134 
0135     /* Disable forced mem power off */
0136     REG_UPDATE(APG_MEM_PWR, APG_MEM_PWR_FORCE, 0);
0137 
0138     apg31_enable(apg);
0139 }
0140 
0141 static void apg31_audio_mute_control(
0142     struct apg *apg,
0143     bool mute)
0144 {
0145     if (mute)
0146         apg31_disable(apg);
0147     else
0148         apg31_enable(apg);
0149 }
0150 
0151 static struct apg_funcs dcn31_apg_funcs = {
0152     .se_audio_setup         = apg31_se_audio_setup,
0153     .audio_mute_control     = apg31_audio_mute_control,
0154     .enable_apg         = apg31_enable,
0155     .disable_apg            = apg31_disable,
0156 };
0157 
0158 void apg31_construct(struct dcn31_apg *apg31,
0159     struct dc_context *ctx,
0160     uint32_t inst,
0161     const struct dcn31_apg_registers *apg_regs,
0162     const struct dcn31_apg_shift *apg_shift,
0163     const struct dcn31_apg_mask *apg_mask)
0164 {
0165     apg31->base.ctx = ctx;
0166 
0167     apg31->base.inst = inst;
0168     apg31->base.funcs = &dcn31_apg_funcs;
0169 
0170     apg31->regs = apg_regs;
0171     apg31->apg_shift = apg_shift;
0172     apg31->apg_mask = apg_mask;
0173 }