drm/amd/display: Add DP 2.0 Audio Package Generator
authorFangzhi Zuo <Jerry.Zuo@amd.com>
Wed, 9 Jun 2021 21:36:26 +0000 (17:36 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 1 Sep 2021 20:55:09 +0000 (16:55 -0400)
HW Blocks:

                    +-----+
                    | HDA |
                    +-----+
                       |
                       |
    HPO ===============|=============
     |                 v
     |              +-----+
     |              | APG |
     v              +-----+

Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/dcn31/Makefile
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c

index 4bab97a..bc2087f 100644 (file)
@@ -11,7 +11,8 @@
 # Makefile for dcn31.
 
 DCN31 = dcn31_resource.o dcn31_hubbub.o dcn31_hwseq.o dcn31_init.o dcn31_hubp.o \
-       dcn31_dccg.o dcn31_optc.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o
+       dcn31_dccg.o dcn31_optc.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o \
+       dcn31_apg.o
 
 ifdef CONFIG_X86
 CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o := -msse
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c
new file mode 100644 (file)
index 0000000..6bd7a06
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2019 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#include "dc_bios_types.h"
+#include "hw_shared.h"
+#include "dcn31_apg.h"
+#include "reg_helper.h"
+
+#define DC_LOGGER \
+               apg31->base.ctx->logger
+
+#define REG(reg)\
+       (apg31->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) \
+       apg31->apg_shift->field_name, apg31->apg_mask->field_name
+
+
+#define CTX \
+       apg31->base.ctx
+
+
+static void apg31_enable(
+       struct apg *apg)
+{
+       struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
+
+       /* Reset APG */
+       REG_UPDATE(APG_CONTROL, APG_RESET, 1);
+       REG_WAIT(APG_CONTROL,
+                       APG_RESET_DONE, 1,
+                       1, 10);
+       REG_UPDATE(APG_CONTROL, APG_RESET, 0);
+       REG_WAIT(APG_CONTROL,
+                       APG_RESET_DONE, 0,
+                       1, 10);
+
+       /* Enable APG */
+       REG_UPDATE(APG_CONTROL2, APG_ENABLE, 1);
+}
+
+static void apg31_disable(
+       struct apg *apg)
+{
+       struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
+
+       /* Disable APG */
+       REG_UPDATE(APG_CONTROL2, APG_ENABLE, 0);
+}
+
+static union audio_cea_channels speakers_to_channels(
+       struct audio_speaker_flags speaker_flags)
+{
+       union audio_cea_channels cea_channels = {0};
+
+       /* these are one to one */
+       cea_channels.channels.FL = speaker_flags.FL_FR;
+       cea_channels.channels.FR = speaker_flags.FL_FR;
+       cea_channels.channels.LFE = speaker_flags.LFE;
+       cea_channels.channels.FC = speaker_flags.FC;
+
+       /* if Rear Left and Right exist move RC speaker to channel 7
+        * otherwise to channel 5
+        */
+       if (speaker_flags.RL_RR) {
+               cea_channels.channels.RL_RC = speaker_flags.RL_RR;
+               cea_channels.channels.RR = speaker_flags.RL_RR;
+               cea_channels.channels.RC_RLC_FLC = speaker_flags.RC;
+       } else {
+               cea_channels.channels.RL_RC = speaker_flags.RC;
+       }
+
+       /* FRONT Left Right Center and REAR Left Right Center are exclusive */
+       if (speaker_flags.FLC_FRC) {
+               cea_channels.channels.RC_RLC_FLC = speaker_flags.FLC_FRC;
+               cea_channels.channels.RRC_FRC = speaker_flags.FLC_FRC;
+       } else {
+               cea_channels.channels.RC_RLC_FLC = speaker_flags.RLC_RRC;
+               cea_channels.channels.RRC_FRC = speaker_flags.RLC_RRC;
+       }
+
+       return cea_channels;
+}
+
+static void apg31_se_audio_setup(
+       struct apg *apg,
+       unsigned int az_inst,
+       struct audio_info *audio_info)
+{
+       struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
+
+       uint32_t speakers = 0;
+       uint32_t channels = 0;
+
+       ASSERT(audio_info);
+       /* This should not happen.it does so we don't get BSOD*/
+       if (audio_info == NULL)
+               return;
+
+       speakers = audio_info->flags.info.ALLSPEAKERS;
+       channels = speakers_to_channels(audio_info->flags.speaker_flags).all;
+
+       /* DisplayPort only allows for one audio stream with stream ID 0 */
+       REG_UPDATE(APG_CONTROL2, APG_DP_AUDIO_STREAM_ID, 0);
+
+       /* When running in "pair mode", pairs of audio channels have their own enable
+        * this is for really old audio drivers */
+       REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, 0xF);
+       // REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, channels);
+
+       /* Disable forced mem power off */
+       REG_UPDATE(APG_MEM_PWR, APG_MEM_PWR_FORCE, 0);
+
+       apg31_enable(apg);
+}
+
+static void apg31_audio_mute_control(
+       struct apg *apg,
+       bool mute)
+{
+       if (mute)
+               apg31_disable(apg);
+       else
+               apg31_enable(apg);
+}
+
+static struct apg_funcs dcn31_apg_funcs = {
+       .se_audio_setup                 = apg31_se_audio_setup,
+       .audio_mute_control             = apg31_audio_mute_control,
+       .enable_apg                     = apg31_enable,
+       .disable_apg                    = apg31_disable,
+};
+
+void apg31_construct(struct dcn31_apg *apg31,
+       struct dc_context *ctx,
+       uint32_t inst,
+       const struct dcn31_apg_registers *apg_regs,
+       const struct dcn31_apg_shift *apg_shift,
+       const struct dcn31_apg_mask *apg_mask)
+{
+       apg31->base.ctx = ctx;
+
+       apg31->base.inst = inst;
+       apg31->base.funcs = &dcn31_apg_funcs;
+
+       apg31->regs = apg_regs;
+       apg31->apg_shift = apg_shift;
+       apg31->apg_mask = apg_mask;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h
new file mode 100644 (file)
index 0000000..24f568e
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_DCN31_AGP_H__
+#define __DAL_DCN31_AGP_H__
+
+
+#define DCN31_APG_FROM_APG(apg)\
+       container_of(apg, struct dcn31_apg, base)
+
+#define APG_DCN31_REG_LIST(id) \
+       SRI(APG_CONTROL, APG, id), \
+       SRI(APG_CONTROL2, APG, id),\
+       SRI(APG_MEM_PWR, APG, id),\
+       SRI(APG_DBG_GEN_CONTROL, APG, id)
+
+struct dcn31_apg_registers {
+       uint32_t APG_CONTROL;
+       uint32_t APG_CONTROL2;
+       uint32_t APG_MEM_PWR;
+       uint32_t APG_DBG_GEN_CONTROL;
+};
+
+
+#define DCN31_APG_MASK_SH_LIST(mask_sh)\
+       SE_SF(APG0_APG_CONTROL, APG_RESET, mask_sh),\
+       SE_SF(APG0_APG_CONTROL, APG_RESET_DONE, mask_sh),\
+       SE_SF(APG0_APG_CONTROL2, APG_ENABLE, mask_sh),\
+       SE_SF(APG0_APG_CONTROL2, APG_DP_AUDIO_STREAM_ID, mask_sh),\
+       SE_SF(APG0_APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, mask_sh),\
+       SE_SF(APG0_APG_MEM_PWR, APG_MEM_PWR_FORCE, mask_sh)
+
+#define APG_DCN31_REG_FIELD_LIST(type) \
+               type APG_RESET;\
+               type APG_RESET_DONE;\
+               type APG_ENABLE;\
+               type APG_DP_AUDIO_STREAM_ID;\
+               type APG_DBG_AUDIO_CHANNEL_ENABLE;\
+               type APG_MEM_PWR_FORCE
+
+struct dcn31_apg_shift {
+       APG_DCN31_REG_FIELD_LIST(uint8_t);
+};
+
+struct dcn31_apg_mask {
+       APG_DCN31_REG_FIELD_LIST(uint32_t);
+};
+
+struct apg {
+       const struct apg_funcs *funcs;
+       struct dc_context *ctx;
+       int inst;
+};
+
+struct apg_funcs {
+
+       void (*setup_hdmi_audio)(
+               struct apg *apg);
+
+       void (*se_audio_setup)(
+               struct apg *apg,
+               unsigned int az_inst,
+               struct audio_info *audio_info);
+
+       void (*audio_mute_control)(
+               struct apg *apg,
+               bool mute);
+
+       void (*enable_apg)(
+               struct apg *apg);
+
+       void (*disable_apg)(
+               struct apg *apg);
+};
+
+
+
+struct dcn31_apg {
+       struct apg base;
+       const struct dcn31_apg_registers *regs;
+       const struct dcn31_apg_shift *apg_shift;
+       const struct dcn31_apg_mask *apg_mask;
+};
+
+void apg31_construct(struct dcn31_apg *apg3,
+       struct dc_context *ctx,
+       uint32_t inst,
+       const struct dcn31_apg_registers *apg_regs,
+       const struct dcn31_apg_shift *apg_shift,
+       const struct dcn31_apg_mask *apg_mask);
+
+
+#endif
index a7702d3..7355864 100644 (file)
@@ -52,6 +52,7 @@
 #include "dcn30/dcn30_vpg.h"
 #include "dcn30/dcn30_afmt.h"
 #include "dcn30/dcn30_dio_stream_encoder.h"
+#include "dcn31/dcn31_apg.h"
 #include "dcn31/dcn31_dio_link_encoder.h"
 #include "dce/dce_clock_source.h"
 #include "dce/dce_audio.h"
@@ -457,6 +458,26 @@ static const struct dcn30_afmt_mask afmt_mask = {
        DCN3_AFMT_MASK_SH_LIST(_MASK)
 };
 
+#define apg_regs(id)\
+[id] = {\
+       APG_DCN31_REG_LIST(id)\
+}
+
+static const struct dcn31_apg_registers apg_regs[] = {
+       apg_regs(0),
+       apg_regs(1),
+       apg_regs(2),
+       apg_regs(3)
+};
+
+static const struct dcn31_apg_shift apg_shift = {
+       DCN31_APG_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_apg_mask apg_mask = {
+               DCN31_APG_MASK_SH_LIST(_MASK)
+};
+
 #define stream_enc_regs(id)\
 [id] = {\
        SE_DCN3_REG_LIST(id)\
@@ -1260,6 +1281,23 @@ static struct afmt *dcn31_afmt_create(
        return &afmt3->base;
 }
 
+static struct apg *dcn31_apg_create(
+       struct dc_context *ctx,
+       uint32_t inst)
+{
+       struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL);
+
+       if (!apg31)
+               return NULL;
+
+       apg31_construct(apg31, ctx, inst,
+                       &apg_regs[inst],
+                       &apg_shift,
+                       &apg_mask);
+
+       return &apg31->base;
+}
+
 static struct stream_encoder *dcn31_stream_encoder_create(
        enum engine_id eng_id,
        struct dc_context *ctx)