]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/amd/display: Add DCCG DIO, HPO, OPP, and OPTC support for FRL
authorHarry Wentland <harry.wentland@amd.com>
Fri, 24 Apr 2026 16:17:35 +0000 (12:17 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 3 Jun 2026 17:44:31 +0000 (13:44 -0400)
This adds support to HW block programming for the core blocks
for HDMI FRL:
- DIO
- HPO
- OPP
- OPTC

Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Reviewed-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
38 files changed:
drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c
drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.h
drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c
drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.h
drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c
drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c
drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.h
drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c
drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_link_encoder.c
drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_link_encoder.h
drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.c
drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.h
drivers/gpu/drm/amd/display/dc/dio/dcn301/dcn301_dio_link_encoder.c
drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c
drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.h
drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.c
drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.h
drivers/gpu/drm/amd/display/dc/dio/dcn321/dcn321_dio_link_encoder.c
drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.c
drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c
drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h
drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_link_encoder.c
drivers/gpu/drm/amd/display/dc/hpo/Makefile
drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/opp/dcn10/dcn10_opp.c
drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h
drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h
drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c

index ca947d710ad15ec9ee7ba989c92fbef953b8747b..9df06df6c7f1be3e2fd9519077203678a69ceefe 100644 (file)
 #define DC_LOGGER \
        dccg->ctx->logger
 
+void dccg3_enable_hdmicharclk(struct dccg *dccg, int hpo_inst, int phypll_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
+       REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[hpo_inst],
+                       HDMICHARCLK0_EN, 1,
+                       HDMICHARCLK0_SRC_SEL, phypll_inst);
+
+       /* Enable FORCE_EN for SYMCLK */
+       switch (phypll_inst) {
+       case 0:
+               REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
+                               PHYASYMCLK_FORCE_EN, 1,
+                               PHYASYMCLK_FORCE_SRC_SEL, 1);
+               break;
+       case 1:
+               REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
+                               PHYBSYMCLK_FORCE_EN, 1,
+                               PHYBSYMCLK_FORCE_SRC_SEL, 1);
+               break;
+       case 2:
+               REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
+                               PHYCSYMCLK_FORCE_EN, 1,
+                               PHYCSYMCLK_FORCE_SRC_SEL, 1);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
+void dccg3_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
+}
 
 static const struct dccg_funcs dccg3_funcs = {
+       .enable_hdmicharclk = dccg3_enable_hdmicharclk,
+       .disable_hdmicharclk = dccg3_disable_hdmicharclk,
        .update_dpp_dto = dccg2_update_dpp_dto,
        .get_dccg_ref_freq = dccg2_get_dccg_ref_freq,
        .set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
index 3f1da7f3a91cb145f646de3eea70b95fa99179ee..379fe94734ba8a5c9ada04041526002a45d1c899 100644 (file)
@@ -63,4 +63,12 @@ struct dccg *dccg30_create(
        const struct dccg_shift *dccg_shift,
        const struct dccg_mask *dccg_mask);
 
+void dccg3_enable_hdmicharclk(
+       struct dccg *dccg,
+       int hpo_inst,
+       int phypll_inst);
+
+void dccg3_disable_hdmicharclk(
+       struct dccg *dccg,
+       int hpo_inst);
 #endif //__DCN30_DCCG_H__
index 21dcb812fbf71b98435a0d1c96b2d326a4cd27fc..ce90cba853f787c2be3c018d51a729a73b50918b 100644 (file)
@@ -664,6 +664,87 @@ void dccg31_set_dispclk_change_mode(
                   change_mode == DISPCLK_CHANGE_MODE_RAMPING ? 2 : 0);
 }
 
+void dccg31_set_hdmistreamclk(
+               struct dccg *dccg,
+               enum streamclk_source src,
+               uint32_t otg_inst)
+{
+       (void)otg_inst;
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       if (src == REFCLK) {
+               REG_UPDATE_2(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_SRC_SEL, 0,        /* SEL_REFCLK0 */
+                               HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
+       } else {
+               REG_UPDATE_2(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_SRC_SEL, 1,        /* SEL_DTBCLK0 */
+                               HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
+       }
+}
+
+static void dccg31_disable_hdmistreamclk(struct dccg *dccg)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream)
+               REG_UPDATE_2(HDMISTREAMCLK0_DTO_PARAM,
+                       HDMISTREAMCLK0_DTO_PHASE, 0,
+                       HDMISTREAMCLK0_DTO_MODULO, 1);
+}
+
+void dccg31_enable_hdmicharclk(struct dccg *dccg, int hpo_inst, int phypll_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
+                       HDMICHARCLK0_ROOT_GATE_DISABLE, 1);
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+                       HDMICHARCLK0_GATE_DISABLE, 1);
+       }
+
+       REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[hpo_inst],
+                       HDMICHARCLK0_EN, 1,
+                       HDMICHARCLK0_SRC_SEL, phypll_inst);
+
+       /* Enable FORCE_EN for SYMCLK */
+       switch (phypll_inst) {
+       case 0:
+               REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
+                               PHYASYMCLK_FORCE_EN, 1,
+                               PHYASYMCLK_FORCE_SRC_SEL, 1);
+               break;
+       case 1:
+               REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
+                               PHYBSYMCLK_FORCE_EN, 1,
+                               PHYBSYMCLK_FORCE_SRC_SEL, 1);
+               break;
+       case 2:
+               REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
+                               PHYCSYMCLK_FORCE_EN, 1,
+                               PHYCSYMCLK_FORCE_SRC_SEL, 1);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
+void dccg31_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+                       HDMICHARCLK0_GATE_DISABLE, 0);
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
+                       HDMICHARCLK0_ROOT_GATE_DISABLE, 0);
+       }
+}
+
 void dccg31_init(struct dccg *dccg)
 {
        /* Set HPO stream encoder to use refclk to avoid case where PHY is
@@ -692,6 +773,10 @@ void dccg31_init(struct dccg *dccg)
                dccg31_set_physymclk(dccg, 3, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
                dccg31_set_physymclk(dccg, 4, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
        }
+       dccg31_disable_hdmistreamclk(dccg);
+
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar)
+               dccg31_disable_hdmicharclk(dccg, 0);
 }
 
 void dccg31_otg_add_pixel(struct dccg *dccg,
@@ -835,6 +920,9 @@ void dccg31_read_reg_state(struct dccg *dccg, struct dcn_dccg_reg_state *dccg_re
 }
 
 static const struct dccg_funcs dccg31_funcs = {
+       .enable_hdmicharclk = dccg31_enable_hdmicharclk,
+       .disable_hdmicharclk = dccg31_disable_hdmicharclk,
+       .set_hdmistreamclk = dccg31_set_hdmistreamclk,
        .update_dpp_dto = dccg31_update_dpp_dto,
        .get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
        .dccg_init = dccg31_init,
index b5e3849ef12a8fc813bb9c748300a58dfc3f86b9..2c2d682a82c21931aa7e828241edf77597bb354c 100644 (file)
@@ -202,6 +202,19 @@ void dccg31_set_physymclk(
 void dccg31_set_audio_dtbclk_dto(
                struct dccg *dccg,
                const struct dtbclk_dto_params *params);
+void dccg31_enable_hdmicharclk(
+       struct dccg *dccg,
+       int hpo_inst,
+       int phypll_inst);
+
+void dccg31_disable_hdmicharclk(
+       struct dccg *dccg,
+       int hpo_inst);
+
+void dccg31_set_hdmistreamclk(
+       struct dccg *dccg,
+       enum streamclk_source src,
+       uint32_t otg_inst);
 
 void dccg31_update_dpp_dto(
        struct dccg *dccg,
index ac6a909187c0516dd0611c77303029410b7cb95c..1a4d4cd58ad884f4e76dafb1f83d9712362e201f 100644 (file)
@@ -286,6 +286,28 @@ void dccg314_set_dpstreamclk(
        }
 }
 
+static void dccg314_set_hdmistreamclk(
+               struct dccg *dccg,
+               enum streamclk_source src,
+               uint32_t otg_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       /* set the dtbclk_p source */
+       dccg314_set_dtbclk_p_src(dccg, src, otg_inst);
+
+       if (src == REFCLK) {
+               REG_UPDATE_2(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_EN, 0,             /* SEL_REFCLK */
+                               HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
+       } else {
+               REG_UPDATE_3(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_EN, 1,             /* selects one of the dtbclk_p as per HDMISTREAMCLK0_SRC_SEL */
+                               HDMISTREAMCLK0_SRC_SEL, otg_inst, /* Selects dtbclk_p as source for hdmistreamclk */
+                               HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
+       }
+}
+
 static void dccg314_init(struct dccg *dccg)
 {
        int otg_inst;
@@ -355,6 +377,9 @@ static void dccg314_dpp_root_clock_control(
 }
 
 static const struct dccg_funcs dccg314_funcs = {
+       .enable_hdmicharclk = dccg31_enable_hdmicharclk,
+       .disable_hdmicharclk = dccg31_disable_hdmicharclk,
+       .set_hdmistreamclk = dccg314_set_hdmistreamclk,
        .update_dpp_dto = dccg31_update_dpp_dto,
        .dpp_root_clock_control = dccg314_dpp_root_clock_control,
        .get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
index 18b9c5ceed4373d19f4d2bad0b1cdb447bc1367b..f75c5aa2d23edcda1df675f6cc09e869bdb712e9 100644 (file)
@@ -329,7 +329,75 @@ static void dccg32_otg_drop_pixel(struct dccg *dccg,
                        OTG_DROP_PIXEL[otg_inst], 1);
 }
 
+static void dccg32_set_hdmistreamclk(struct dccg *dccg,
+                                    enum streamclk_source src,
+                                    uint32_t otg_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       /* set the dtbclk_p source */
+       /* always program refclk as DTBCLK. No use-case expected to require DPREFCLK as refclk */
+       dccg32_set_dtbclk_p_src(dccg, DTBCLK0, otg_inst);
+
+       if (src == REFCLK) {
+               REG_UPDATE_2(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_EN, 0,             /* SEL_REFCLK */
+                               HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
+       } else {
+               REG_UPDATE_3(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_EN, 1,             /* selects one of the dtbclk_p as per HDMISTREAMCLK0_SRC_SEL */
+                               HDMISTREAMCLK0_SRC_SEL, otg_inst, /* Selects dtbclk_p as source for hdmistreamclk */
+                               HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
+       }
+}
+
+static void dccg32_enable_hdmicharclk(struct dccg *dccg, int hpo_inst,
+                                     int phypll_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
+       REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[hpo_inst],
+                       HDMICHARCLK0_EN, 1,
+                       HDMICHARCLK0_SRC_SEL, phypll_inst);
+
+       /* Enable FORCE_EN for SYMCLK */
+       switch (phypll_inst) {
+       case 0:
+               REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
+                               PHYASYMCLK_FORCE_EN, 1,
+                               PHYASYMCLK_FORCE_SRC_SEL, 1);
+               break;
+       case 1:
+               REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
+                               PHYBSYMCLK_FORCE_EN, 1,
+                               PHYBSYMCLK_FORCE_SRC_SEL, 1);
+               break;
+       case 2:
+               REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
+                               PHYCSYMCLK_FORCE_EN, 1,
+                               PHYCSYMCLK_FORCE_SRC_SEL, 1);
+               break;
+       case 3:
+               REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
+                               PHYDSYMCLK_FORCE_EN, 1,
+                               PHYDSYMCLK_FORCE_SRC_SEL, 1);
+               break;
+       case 4:
+               REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
+                               PHYESYMCLK_FORCE_EN, 1,
+                               PHYESYMCLK_FORCE_SRC_SEL, 1);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
 static const struct dccg_funcs dccg32_funcs = {
+       .enable_hdmicharclk = dccg32_enable_hdmicharclk,
+       .disable_hdmicharclk = dccg3_disable_hdmicharclk,
+       .set_hdmistreamclk = dccg32_set_hdmistreamclk,
        .update_dpp_dto = dccg2_update_dpp_dto,
        .get_dccg_ref_freq = dccg32_get_dccg_ref_freq,
        .dccg_init = dccg31_init,
index efac64165ccd6f549e2cb410a603242a6e5fb1b7..483cd9ab7eb76874c0c6a35397e19a1f36225e60 100644 (file)
@@ -495,6 +495,92 @@ static void dccg35_set_smclk32_se_rcg(
        }
 }
 
+static void dccg35_set_hdmistreamclk_rcg(
+               struct dccg *dccg,
+               int inst,
+               bool enable)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       if (!dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream && enable)
+               return;
+
+       switch (inst) {
+       case 0:
+                       REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, HDMISTREAMCLK0_GATE_DISABLE, enable ? 0 : 1);
+                       REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, HDMISTREAMCLK0_ROOT_GATE_DISABLE, enable ? 0 : 1);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
+static void dccg35_set_hdmi_char_clk_rcg(
+               struct dccg *dccg,
+               int inst,
+               bool enable)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       /* Only 1 HPO in DCN35 */
+       if (!dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar && enable)
+               return;
+
+       switch (inst) {
+       case 0:
+                       REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, HDMICHARCLK0_GATE_DISABLE, enable ? 0 : 1);
+                       REG_UPDATE(DCCG_GATE_DISABLE_CNTL4, HDMICHARCLK0_ROOT_GATE_DISABLE, enable ? 0 : 1);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
+static void dccg35_set_hdmi_char_clk_src_new(
+       struct dccg *dccg,
+       enum hdmi_char_clk src,
+       int inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       /* If DTBCLK_P#_EN is 0 refclock is selected as functional clock
+        * If DTBCLK_P#_EN is 1 functional clock is selected as DTBCLK_P#_SRC_SEL
+        */
+
+       switch (inst) {
+       case 0:
+               REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[0],
+                                        HDMICHARCLK0_SRC_SEL, (src == HDMI_CHAR_REFCLK) ? 0 : src,
+                                        HDMICHARCLK0_EN, (src == HDMI_CHAR_REFCLK) ? 0 : 1);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
+static void dccg35_set_hdmistreamclk_src_new(
+       struct dccg *dccg,
+       enum hdmi_stream_clk_source src,
+       int inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       switch (inst) {
+       case 0:
+               REG_UPDATE_2(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_EN,
+                                        (src == HDMI_STREAM_REFCLK) ? 0 : 1,
+                                        DPSTREAMCLK0_SRC_SEL,
+                                        (src == HDMI_STREAM_REFCLK) ? 0 : src);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
 static void dccg35_set_dsc_clk_src_new(struct dccg *dccg, int inst, enum dsc_clk_source src)
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
@@ -1107,6 +1193,35 @@ static void dccg35_enable_dpstreamclk_new(struct dccg *dccg,
        dccg35_set_dpstreamclk_src_new(dccg, src, inst);
 }
 
+static void dccg35_disable_hdmistreamclk_new(
+       struct dccg *dccg,
+       int inst)
+{
+       dccg35_set_hdmistreamclk_src_new(dccg, HDMI_STREAM_REFCLK, inst);
+       dccg35_set_hdmistreamclk_rcg(dccg, inst, true);
+}
+
+static void dccg35_enable_hdmistreamclk_new(struct dccg *dccg,
+                                                               enum hdmi_stream_clk_source src,
+                                                               int inst)
+{
+       dccg35_set_hdmistreamclk_rcg(dccg, inst, false);
+       dccg35_set_hdmistreamclk_src_new(dccg, src, inst);
+}
+
+static void dccg35_enable_hdmicharclk_new(struct dccg *dccg, enum hdmi_char_clk src,
+                                                                                 int inst)
+{
+       dccg35_set_hdmi_char_clk_rcg(dccg, inst, false);
+       dccg35_set_hdmi_char_clk_src_new(dccg, src, inst);
+}
+
+static void dccg35_disable_hdmicharclk_new(struct dccg *dccg, int inst)
+{
+       dccg35_set_hdmi_char_clk_src_new(dccg, HDMI_CHAR_REFCLK, inst);
+       dccg35_set_hdmi_char_clk_rcg(dccg, inst, true);
+}
+
 void dccg35_trigger_dio_fifo_resync(struct dccg *dccg)
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
@@ -1539,6 +1654,88 @@ void dccg35_set_dpstreamclk_root_clock_gating(struct dccg *dccg, int dp_hpo_inst
 
 
 
+static void dccg35_set_hdmistreamclk(
+               struct dccg *dccg,
+               enum streamclk_source src,
+               uint32_t otg_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       /* set the dtbclk_p source */
+       dccg35_set_dtbclk_p_src(dccg, src, otg_inst);
+
+       if (src == REFCLK) {
+               REG_UPDATE(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_EN, 0);             /* SEL_REFCLK */
+       } else {
+               REG_UPDATE_2(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_EN, 1,              /* selects one of the dtbclk_p as per HDMISTREAMCLK0_SRC_SEL */
+                               HDMISTREAMCLK0_SRC_SEL, otg_inst); /* Selects dtbclk_p as source for hdmistreamclk */
+       }
+       DC_LOG_DEBUG("%s: OTG%d HDMISTREAMCLK_EN = %d, HDMISTREAMCLK_SRC_SEL = %d\n",
+                       __func__, otg_inst, (src == REFCLK) ? 0 : 1, otg_inst);
+}
+
+void dccg35_set_hdmistreamclk_root_clock_gating(struct dccg *dccg, bool enable)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream)
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, HDMISTREAMCLK0_ROOT_GATE_DISABLE, enable ? 1 : 0);
+
+       DC_LOG_DEBUG("%s: HDMISTREAMCLK0_ROOT_GATE_DISABLE = %d\n", __func__, enable ? 1 : 0);
+}
+
+static void dccg35_enable_hdmicharclk(struct dccg *dccg, int hpo_inst,
+                                     int phypll_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
+                       HDMICHARCLK0_ROOT_GATE_DISABLE, 1);
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+                       HDMICHARCLK0_GATE_DISABLE, 1);
+       }
+
+       ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
+       REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[hpo_inst],
+                       HDMICHARCLK0_EN, 1,
+                       HDMICHARCLK0_SRC_SEL, phypll_inst);
+
+       /* Enable FORCE_EN for SYMCLK */
+       switch (phypll_inst) {
+       case 0:
+               REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
+                               PHYASYMCLK_EN, 1,
+                               PHYASYMCLK_SRC_SEL, 1);
+               break;
+       case 1:
+               REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
+                               PHYBSYMCLK_EN, 1,
+                               PHYBSYMCLK_SRC_SEL, 1);
+               break;
+       case 2:
+               REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
+                               PHYCSYMCLK_EN, 1,
+                               PHYCSYMCLK_SRC_SEL, 1);
+               break;
+       case 3:
+               REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
+                               PHYDSYMCLK_EN, 1,
+                               PHYDSYMCLK_SRC_SEL, 1);
+               break;
+       case 4:
+               REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
+                               PHYESYMCLK_EN, 1,
+                               PHYESYMCLK_SRC_SEL, 1);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
 static void dccg35_set_physymclk_root_clock_gating(
                struct dccg *dccg,
                int phy_inst,
@@ -1756,6 +1953,33 @@ void dccg35_disable_symclk32_se(struct dccg *dccg, int hpo_se_inst)
 
 }
 
+static void dccg35_disable_hdmistreamclk(struct dccg *dccg)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream) {
+//             REG_UPDATE_2(HDMISTREAMCLK0_DTO_PARAM,
+//                     HDMISTREAMCLK0_DTO_PHASE, 0,
+//                     HDMISTREAMCLK0_DTO_MODULO, 1);
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, HDMISTREAMCLK0_ROOT_GATE_DISABLE, 0);
+
+       }
+}
+
+static void dccg35_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+                       HDMICHARCLK0_GATE_DISABLE, 0);
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
+                       HDMICHARCLK0_ROOT_GATE_DISABLE, 0);
+               DC_LOG_DEBUG("%s: HDMICHARCLK0_ROOT_GATE_DISABLE = 0\n", __func__);
+       }
+}
+
 static void dccg35_init_cb(struct dccg *dccg)
 {
        (void)dccg;
@@ -1793,6 +2017,9 @@ void dccg35_init(struct dccg *dccg)
                                        __func__, otg_inst);
                }
 
+       dccg35_disable_hdmistreamclk(dccg);
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar)
+               dccg35_disable_hdmicharclk(dccg, 0);
 /*
        dccg35_enable_global_fgcg_rep(
                dccg, dccg->ctx->dc->debug.enable_fine_grain_clock_gating.bits
@@ -2088,6 +2315,92 @@ void dccg35_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint3
        }
 }
 
+static void dccg35_enable_hdmicharclk_cb(struct dccg *dccg, int hpo_inst, int phypll_inst)
+{
+       ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
+
+       /* Note that this is now done in DMU as part of phy fsm enable sequence,
+        * this function does not get called on x86
+        */
+       enum hdmi_char_clk src = (enum hdmi_char_clk) phypll_inst;
+
+       dccg35_enable_hdmicharclk_new(dccg, src, hpo_inst);
+
+       /* Select PHYD18 as final SYMCLK going to the PHY from DCCG */
+       dccg35_set_physymclk_src_new(dccg, phypll_inst, PHYSYMCLK_PHYD18CLK);
+}
+
+static void dccg35_disable_hdmicharclk_cb(struct dccg *dccg, int hpo_inst)
+{
+       ASSERT(hpo_inst >= 0);
+
+       /* Note that this is now done in DMU as part of phy fsm disable sequence,
+        * this function does not get called on x86
+        */
+       dccg35_disable_hdmicharclk_new(dccg, hpo_inst);
+
+       /* TBD Optionally check if SYMCLK is active and disable it */
+}
+
+static void dccg35_set_hdmistreamclk_cb(
+               struct dccg *dccg,
+               enum streamclk_source src,
+               uint32_t otg_inst)
+{
+       enum dtbclk_source dtb_clk_src;
+       enum hdmi_stream_clk_source hdmi_stream_clk_src;
+
+       switch (src) {
+       case REFCLK:
+               dtb_clk_src = DTBCLK_REFCLK;
+               hdmi_stream_clk_src = HDMI_STREAM_REFCLK;
+               break;
+       case DPREFCLK:
+               dtb_clk_src = DTBCLK_DPREFCLK;
+               hdmi_stream_clk_src = (enum hdmi_stream_clk_source)otg_inst;
+               break;
+       case DTBCLK0:
+               dtb_clk_src = DTBCLK_DTBCLK0;
+               hdmi_stream_clk_src = (enum hdmi_stream_clk_source)otg_inst;
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+
+       if (dtb_clk_src == DTBCLK_REFCLK &&
+               hdmi_stream_clk_src == HDMI_STREAM_REFCLK) {
+               dccg35_disable_dtbclk_p_new(dccg, otg_inst);
+               dccg35_disable_hdmistreamclk_new(dccg, 0);
+       } else {
+               dccg35_enable_dtbclk_p_new(dccg, dtb_clk_src, otg_inst);
+               dccg35_enable_hdmistreamclk_new(dccg,
+                                                                               hdmi_stream_clk_src,
+                                                                               0);
+       }
+}
+
+static void dccg35_set_hdmistreamclk_root_clock_gating_cb(
+       struct dccg *dccg,
+       bool power_on)
+{
+       /* power_on set indicates we need to ungate
+        * Currently called from optimize_bandwidth and prepare_bandwidth calls
+        * Since clock source is not passed restore to refclock on ungate
+        * Instance 0 is implied here since only one streamclock resource
+        * Redundant as gating when enabled is acheived through set_hdmistreamclk
+        */
+       if (power_on) {
+               dccg35_enable_hdmicharclk_new(dccg, HDMI_CHAR_REFCLK, 0);
+               dccg35_enable_hdmistreamclk_new(dccg,
+                                                                               HDMI_STREAM_REFCLK,
+                                                                               0);
+       } else {
+               dccg35_disable_hdmistreamclk_new(dccg, 0);
+               dccg35_disable_hdmicharclk_new(dccg, 0);
+       }
+}
+
 static void dccg35_set_dpstreamclk_cb(
                struct dccg *dccg,
                enum streamclk_source src,
@@ -2386,6 +2699,10 @@ void dccg35_root_gate_disable_control(struct dccg *dccg, uint32_t pipe_idx, uint
 }
 
 static const struct dccg_funcs dccg35_funcs_new = {
+       .enable_hdmicharclk = dccg35_enable_hdmicharclk_cb,
+       .disable_hdmicharclk = dccg35_disable_hdmicharclk_cb,
+       .set_hdmistreamclk = dccg35_set_hdmistreamclk_cb,
+       .set_hdmistreamclk_root_clock_gating = dccg35_set_hdmistreamclk_root_clock_gating_cb,
        .update_dpp_dto = dccg35_update_dpp_dto_cb,
        .dpp_root_clock_control = dccg35_dpp_root_clock_control_cb,
        .get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
@@ -2421,6 +2738,10 @@ static const struct dccg_funcs dccg35_funcs_new = {
 };
 
 static const struct dccg_funcs dccg35_funcs = {
+       .enable_hdmicharclk = dccg35_enable_hdmicharclk,
+       .disable_hdmicharclk = dccg35_disable_hdmicharclk,
+       .set_hdmistreamclk = dccg35_set_hdmistreamclk,
+       .set_hdmistreamclk_root_clock_gating = dccg35_set_hdmistreamclk_root_clock_gating,
        .update_dpp_dto = dccg35_update_dpp_dto,
        .dpp_root_clock_control = dccg35_dpp_root_clock_control,
        .get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
index 417ed9d0e6bbbd9eae8a09dcdfaa976a7837d930..7bff1b9da6f91262f378f335eac53765b79aa923 100644 (file)
@@ -381,6 +381,72 @@ static void dccg401_otg_drop_pixel(struct dccg *dccg,
                        OTG_DROP_PIXEL[otg_inst], 1);
 }
 
+void dccg401_set_hdmistreamclk(
+               struct dccg *dccg,
+               enum streamclk_source src,
+               uint32_t otg_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       if (src == REFCLK) {
+               REG_UPDATE(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_EN, 0);             /* SEL_REFCLK */
+       } else {
+               REG_UPDATE_2(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_EN, 1,              /* selects one of the dtbclk_p as per HDMISTREAMCLK0_SRC_SEL */
+                               HDMISTREAMCLK0_SRC_SEL, otg_inst); /* Selects dtbclk_p as source for hdmistreamclk */
+       }
+}
+
+void dccg401_enable_hdmicharclk(struct dccg *dccg, int hpo_inst, int phypll_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
+                       HDMICHARCLK0_ROOT_GATE_DISABLE, 1);
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+                       HDMICHARCLK0_GATE_DISABLE, 1);
+       }
+
+       REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[hpo_inst],
+                       HDMICHARCLK0_EN, 1,
+                       HDMICHARCLK0_SRC_SEL, phypll_inst);
+
+       /* Enable FORCE_EN for SYMCLK */
+       dccg401_set_physymclk(dccg, phypll_inst, PHYSYMCLK_FORCE_SRC_PHYD18CLK, true);
+}
+
+void dccg401_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+       //int phypll_inst = 0;
+
+       ASSERT(hpo_inst >= 0);
+       //REG_GET(dccg, HDMICHARCLK_CLOCK_CNTL[hpo_inst], HDMICHARCLK0_SRC_SEL, &phypll_inst);
+       REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
+
+       /* TODO should we also disable physymclk? */
+       /* Disable FORCE_EN for SYMCLK */
+       //dccg401_set_physymclk(dccg, phypll_inst, PHYSYMCLK_FORCE_SRC_PHYD18CLK, true);
+
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+                       HDMICHARCLK0_GATE_DISABLE, 0);
+               REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
+                       HDMICHARCLK0_ROOT_GATE_DISABLE, 0);
+       }
+}
+
+static void dccg401_disable_hdmistreamclk(struct dccg *dccg)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       REG_UPDATE_2(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_EN, 0,
+                               HDMISTREAMCLK0_SRC_SEL, 0);
+}
 void dccg401_enable_symclk32_le(
                struct dccg *dccg,
                int hpo_le_inst,
@@ -721,6 +787,10 @@ void dccg401_init(struct dccg *dccg)
                dccg401_set_physymclk(dccg, 2, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
                dccg401_set_physymclk(dccg, 3, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
        }
+       dccg401_disable_hdmistreamclk(dccg);
+
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar)
+               dccg401_disable_hdmicharclk(dccg, 0);
 }
 
 void dccg401_set_dto_dscclk(struct dccg *dccg, uint32_t inst, uint32_t num_slices_h)
@@ -881,6 +951,9 @@ void dccg401_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint
 }
 
 static const struct dccg_funcs dccg401_funcs = {
+       .enable_hdmicharclk = dccg401_enable_hdmicharclk,
+       .disable_hdmicharclk = dccg401_disable_hdmicharclk,
+       .set_hdmistreamclk = dccg401_set_hdmistreamclk,
        .update_dpp_dto = dccg401_update_dpp_dto,
        .get_dccg_ref_freq = dccg401_get_dccg_ref_freq,
        .dccg_init = dccg401_init,
index 5947a35363aace644094b6ba7261b8445ca1558b..95f0602466d3cd72a27860590a5668f3ddfb0499 100644 (file)
@@ -246,4 +246,8 @@ void dccg401_set_physymclk(
        enum physymclk_clock_source clk_src,
        bool force_enable);
 
+void dccg401_set_hdmistreamclk(struct dccg *dccg, enum streamclk_source src, uint32_t otg_inst);
+void dccg401_enable_hdmicharclk(struct dccg *dccg, int hpo_inst, int phypll_inst);
+void dccg401_disable_hdmicharclk(struct dccg *dccg, int hpo_inst);
+
 #endif //__DCN401_DCCG_H__
index 9612f4498ef6caec8c5ee21382a95deab58b865d..e57242f8bc120f811b4a84f7f98bc1df37fa81f6 100644 (file)
@@ -181,6 +181,32 @@ void dccg42_set_physymclk(
        }
 }
 
+static void dccg42_disable_hdmistreamclk(struct dccg *dccg)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       REG_UPDATE_2(HDMISTREAMCLK_CNTL,
+                               HDMISTREAMCLK0_EN, 0,
+                               HDMISTREAMCLK0_SRC_SEL, 0);
+
+       REG_UPDATE(DCCG_GATE_DISABLE_CNTL6,
+                               HDMISTREAMCLK0_ROOT_GATE_DISABLE,
+                               dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream ? 0 : 1);
+}
+
+static void dccg42_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       ASSERT(hpo_inst >= 0);
+       REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
+
+       REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+                       HDMICHARCLK0_GATE_DISABLE, 0);
+       REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
+                       HDMICHARCLK0_ROOT_GATE_DISABLE, dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar ? 0 : 1);
+}
+
 void dccg42_set_pixel_rate_div(
                struct dccg *dccg,
                uint32_t otg_inst,
@@ -270,10 +296,17 @@ static void dccg42_init(struct dccg *dccg)
                        PHYDSYMCLK_ROOT_GATE_DISABLE, 1,
                        PHYESYMCLK_ROOT_GATE_DISABLE, 1);
        }
+       dccg42_disable_hdmistreamclk(dccg);
+       if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar)
+               dccg42_disable_hdmicharclk(dccg, 0);
 }
 
 
 static const struct dccg_funcs dccg42_funcs = {
+       .enable_hdmicharclk = dccg401_enable_hdmicharclk,
+       .disable_hdmicharclk = dccg42_disable_hdmicharclk,
+       .set_hdmistreamclk = dccg401_set_hdmistreamclk,
+       .set_hdmistreamclk_root_clock_gating = dccg35_set_hdmistreamclk_root_clock_gating,
        .update_dpp_dto = dccg35_update_dpp_dto,
        .dpp_root_clock_control = dccg35_dpp_root_clock_control,
        .get_dccg_ref_freq = dccg401_get_dccg_ref_freq,
index 59b68422334dd2b22a4e62ca4a7a20e6318e4dfb..4b36c01a9e7abad965b59b82c0a92ec3c8f42e75 100644 (file)
@@ -1066,7 +1066,8 @@ void dcn10_link_encoder_disable_output(
        struct bp_transmitter_control cntl = { 0 };
        enum bp_result result;
 
-       if (enc->funcs->is_dig_enabled && !enc->funcs->is_dig_enabled(enc)) {
+       if (!dc_is_hdmi_frl_signal(signal) &&
+           (enc->funcs->is_dig_enabled && !enc->funcs->is_dig_enabled(enc))) {
                /* OF_SKIP_POWER_DOWN_INACTIVE_ENCODER */
        /*in DP_Alt_No_Connect case, we turn off the dig already,
        after excuation the PHY w/a sequence, not allow touch PHY any more*/
index 762c579fcb44dd6423eb1071f625c81566303396..1beba9c7d3f9984a204aa5bd2865ecdba18285d6 100644 (file)
@@ -291,6 +291,7 @@ struct dpcssys_phy_seq_cfg {
        bool use_calibration_setting;
        struct mpll_cfg mpll_cfg;
        bool load_sram_fw;
+       bool tx_hdmi_frl_mode;
 #if 0
 
        bool hdmimode_enable;
index 57b9ae5fca1dc778b9e397e16bdf346a737ac4bf..8c4010c5b2e7c07b05df094518b796a4c52539df 100644 (file)
        (enc10->link_regs->index)
 
 
+static bool dcn30_link_encoder_validate_hdmi_frl_output(
+       const struct dcn10_link_encoder *enc10,
+       const struct dc_crtc_timing *crtc_timing)
+{
+       enum dc_color_depth max_deep_color =
+                       enc10->base.features.max_hdmi_deep_color;
+
+       if (!enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE)
+               return false;
+
+       if (max_deep_color < crtc_timing->display_color_depth)
+               return false;
+
+       if (crtc_timing->display_color_depth < COLOR_DEPTH_888)
+               return false;
+
+       /* TODO: check if hdmi_charclk is above ASIC cap (10 GBS for DCN3AG) */
+
+       return true;
+}
+
 bool dcn30_link_encoder_validate_output_with_stream(
        struct link_encoder *enc,
        const struct dc_stream_state *stream)
 {
+       if (dc_is_hdmi_frl_signal(stream->signal)) {
+               struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+
+               return dcn30_link_encoder_validate_hdmi_frl_output(enc10, &stream->timing);
+       } else {
                return dcn10_link_encoder_validate_output_with_stream(enc, stream);
+       }
+}
+
+//---------------------------------------------------
+// Task: Program EQ setting
+// Note:
+//      EQ setting can be dont during P2 state or P0 state
+//      If set in P0 state, The values are latched in a single
+//      cycle of txX_clk but will take maximum of 40 txX_clk symbols
+//      to be reflected on the output. During this period the
+//      analog serial lines might have a transitional behavior.
+//---------------------------------------------------
+void dpcs30_program_eq_setting(
+               struct link_encoder *enc,
+               uint8_t FFE_Level,
+               bool de_emphasis_only,
+               bool pre_shoot_only,
+               bool no_ffe,
+               const struct dc_hdmi_frl_link_settings *link_settings)
+{
+       (void)link_settings;
+       struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+       /* EQ setting for DP lane0 */
+       uint32_t eq_main;
+       uint32_t eq_pre;
+       uint32_t eq_post;
+
+       if (enc10->base.ctx->dc->debug.ignore_ffe)
+               return;
+
+       if (FFE_Level < 0x5)
+               enc10->base.txffe_state = FFE_Level;
+
+       if (FFE_Level == 0xEE) {
+               enc10->base.txffe_state++;
+               if (enc10->base.txffe_state > 3)
+                       enc10->base.txffe_state = 0;
+       }
+
+       switch (enc10->base.txffe_state) {
+       case 0:
+               eq_main = 0x31;
+               if (de_emphasis_only)
+                       eq_main = 0x36;
+               if (pre_shoot_only)
+                       eq_main = 0x39;
+               eq_pre = 0x5;
+               eq_post = 0x8;
+               break;
+       case 1:
+               eq_main = 0x2F;
+               if (de_emphasis_only)
+                       eq_main = 0x34;
+               if (pre_shoot_only)
+                       eq_main = 0x39;
+               eq_pre = 0x5;
+               eq_post = 0xA;
+               break;
+       case 2:
+               eq_main = 0x2C;
+               if (de_emphasis_only)
+                       eq_main = 0x31;
+               if (pre_shoot_only)
+                       eq_main = 0x39;
+               eq_pre = 0x5;
+               eq_post = 0xD;
+               break;
+       case 3:
+               eq_main = 0x29;
+               if (de_emphasis_only)
+                       eq_main = 0x2E;
+               if (pre_shoot_only)
+                       eq_main = 0x39;
+               eq_pre = 0x5;
+               eq_post = 0x10;
+               break;
+       default:
+               return;
+       }
+
+       eq_pre = de_emphasis_only ? 0 : eq_pre;
+       eq_post = pre_shoot_only ? 0 : eq_post;
+
+       if (no_ffe) {
+               eq_pre = 0;
+               eq_post = 0;
+               eq_main = 0x3E;
+       }
+
+       REG_UPDATE_3(RDPCSTX_PHY_FUSE0,
+                       RDPCS_PHY_DP_TX0_EQ_MAIN, eq_main,
+                       RDPCS_PHY_DP_TX0_EQ_PRE, eq_pre,
+                       RDPCS_PHY_DP_TX0_EQ_POST, eq_post);
+
+       REG_UPDATE_3(RDPCSTX_PHY_FUSE1,
+                       RDPCS_PHY_DP_TX1_EQ_MAIN, eq_main,
+                       RDPCS_PHY_DP_TX1_EQ_PRE, eq_pre,
+                       RDPCS_PHY_DP_TX1_EQ_POST, eq_post);
+
+       REG_UPDATE_3(RDPCSTX_PHY_FUSE2,
+                       RDPCS_PHY_DP_TX2_EQ_MAIN, eq_main,
+                       RDPCS_PHY_DP_TX2_EQ_PRE, eq_pre,
+                       RDPCS_PHY_DP_TX2_EQ_POST, eq_post);
+
+       REG_UPDATE_3(RDPCSTX_PHY_FUSE3,
+                       RDPCS_PHY_DP_TX3_EQ_MAIN, eq_main,
+                       RDPCS_PHY_DP_TX3_EQ_PRE, eq_pre,
+                       RDPCS_PHY_DP_TX3_EQ_POST, eq_post);
+}
+
+void dpcs30_get_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings)
+{
+       struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+       /* EQ setting for DP lane0 */
+       uint32_t eq_main;
+       uint32_t eq_pre;
+       uint32_t eq_post;
+
+       REG_GET_3(RDPCSTX_PHY_FUSE0,
+                       RDPCS_PHY_DP_TX0_EQ_MAIN, &eq_main,
+                       RDPCS_PHY_DP_TX0_EQ_PRE, &eq_pre,
+                       RDPCS_PHY_DP_TX0_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[0] = eq_main;
+       lane_settings->pre_emphasis[0] = eq_pre;
+       lane_settings->post_emphasis[0] = eq_post;
+
+       REG_GET_3(RDPCSTX_PHY_FUSE1,
+                       RDPCS_PHY_DP_TX1_EQ_MAIN, &eq_main,
+                       RDPCS_PHY_DP_TX1_EQ_PRE, &eq_pre,
+                       RDPCS_PHY_DP_TX1_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[1] = eq_main;
+       lane_settings->pre_emphasis[1] = eq_pre;
+       lane_settings->post_emphasis[1] = eq_post;
+
+       REG_GET_3(RDPCSTX_PHY_FUSE2,
+                       RDPCS_PHY_DP_TX2_EQ_MAIN, &eq_main,
+                       RDPCS_PHY_DP_TX2_EQ_PRE, &eq_pre,
+                       RDPCS_PHY_DP_TX2_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[2] = eq_main;
+       lane_settings->pre_emphasis[2] = eq_pre;
+       lane_settings->post_emphasis[2] = eq_post;
+
+       REG_GET_3(RDPCSTX_PHY_FUSE3,
+                       RDPCS_PHY_DP_TX3_EQ_MAIN, &eq_main,
+                       RDPCS_PHY_DP_TX3_EQ_PRE, &eq_pre,
+                       RDPCS_PHY_DP_TX3_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[3] = eq_main;
+       lane_settings->pre_emphasis[3] = eq_pre;
+       lane_settings->post_emphasis[3] = eq_post;
+
+}
+
+void dpcs30_set_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings)
+{
+       struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+       /* EQ setting for DP lane0 */
+       uint32_t eq_main;
+       uint32_t eq_pre;
+       uint32_t eq_post;
+
+       eq_main = lane_settings->amplitude[0];
+       eq_pre = lane_settings->pre_emphasis[0];
+       eq_post = lane_settings->post_emphasis[0];
+
+       REG_UPDATE_3(RDPCSTX_PHY_FUSE0,
+                       RDPCS_PHY_DP_TX0_EQ_MAIN, eq_main,
+                       RDPCS_PHY_DP_TX0_EQ_PRE, eq_pre,
+                       RDPCS_PHY_DP_TX0_EQ_POST, eq_post);
+
+       eq_main = lane_settings->amplitude[1];
+       eq_pre = lane_settings->pre_emphasis[1];
+       eq_post = lane_settings->post_emphasis[1];
+
+       REG_UPDATE_3(RDPCSTX_PHY_FUSE1,
+                       RDPCS_PHY_DP_TX1_EQ_MAIN, eq_main,
+                       RDPCS_PHY_DP_TX1_EQ_PRE, eq_pre,
+                       RDPCS_PHY_DP_TX1_EQ_POST, eq_post);
+
+       eq_main = lane_settings->amplitude[2];
+       eq_pre = lane_settings->pre_emphasis[2];
+       eq_post = lane_settings->post_emphasis[2];
+
+       REG_UPDATE_3(RDPCSTX_PHY_FUSE2,
+                       RDPCS_PHY_DP_TX2_EQ_MAIN, eq_main,
+                       RDPCS_PHY_DP_TX2_EQ_PRE, eq_pre,
+                       RDPCS_PHY_DP_TX2_EQ_POST, eq_post);
+
+       eq_main = lane_settings->amplitude[3];
+       eq_pre = lane_settings->pre_emphasis[3];
+       eq_post = lane_settings->post_emphasis[3];
+
+       REG_UPDATE_3(RDPCSTX_PHY_FUSE3,
+                       RDPCS_PHY_DP_TX3_EQ_MAIN, eq_main,
+                       RDPCS_PHY_DP_TX3_EQ_PRE, eq_pre,
+                       RDPCS_PHY_DP_TX3_EQ_POST, eq_post);
 }
 
 static const struct link_encoder_funcs dcn30_link_enc_funcs = {
@@ -84,6 +313,15 @@ static const struct link_encoder_funcs dcn30_link_enc_funcs = {
        .get_dig_mode = dcn10_get_dig_mode,
        .is_in_alt_mode = dcn20_link_encoder_is_in_alt_mode,
        .get_max_link_cap = dcn20_link_encoder_get_max_link_cap,
+       .dpcstx_set_order_invert_18_bit = NULL,
+       .set_phy_source = NULL,
+       .dpcs_initialize_phy = NULL,
+       .dpcs_configure_phypll = NULL,
+       .dpcs_configure_dpcs = NULL,
+       .dpcs_enable_dpcs = NULL,
+       .prog_eq_setting = dpcs30_program_eq_setting,
+       .get_txffe = dpcs30_get_txffe,
+       .set_txffe = dpcs30_set_txffe,
        .get_hpd_state = dcn10_get_hpd_state,
        .program_hpd_filter = dcn10_program_hpd_filter,
 };
@@ -198,6 +436,12 @@ void dcn30_link_encoder_construct(
                enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
                enc10->base.features.flags.bits.DP_IS_USB_C =
                                bp_cap_info.DP_IS_USB_C;
+
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = bp_cap_info.IS_HDMI_FRL_CAPABLE;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
+               enc10->base.txffe_state = 0;
        } else {
                DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
                                __func__,
@@ -206,6 +450,12 @@ void dcn30_link_encoder_construct(
        if (enc10->base.ctx->dc->debug.hdmi20_disable) {
                enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
        }
+       if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
+       }
 }
 
 #define AUX_REG(reg)\
index 5b6177c2ae981115059993afdfd1c5a181785e01..4fc0915a5dc518a82ba43e38ba75523a05716e07 100644 (file)
@@ -60,6 +60,8 @@
 
 #define DPCS_DCN3_MASK_SH_LIST(mask_sh)\
        DPCS_DCN2_MASK_SH_LIST(mask_sh),\
+       LE_SF(DPCSTX0_DPCSTX_TX_CNTL, DPCS_TX_HDMI_FRL_MODE, mask_sh),\
+       LE_SF(DPCSTX0_DPCSTX_TX_CNTL, DPCS_TX_DATA_SWAP_10_BIT, mask_sh),\
        LE_SF(DPCSTX0_DPCSTX_TX_CNTL, DPCS_TX_DATA_ORDER_INVERT_18_BIT, mask_sh),\
        LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_PHY_TX_VBOOST_LVL, mask_sh),\
        LE_SF(RDPCSTX0_RDPCSTX_CLOCK_CNTL, RDPCS_TX_CLK_EN, mask_sh),\
@@ -83,4 +85,19 @@ bool dcn30_link_encoder_validate_output_with_stream(
        struct link_encoder *enc,
        const struct dc_stream_state *stream);
 
+void dpcs30_program_eq_setting(
+               struct link_encoder *enc,
+               uint8_t FFE_Level,
+               bool de_emphasis_only,
+               bool pre_shoot_only,
+               bool no_ffe,
+               const struct dc_hdmi_frl_link_settings *link_settings);
+
+void dpcs30_get_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings);
+
+void dpcs30_set_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings);
 #endif /* __DC_LINK_ENCODER__DCN30_H__ */
index 47d84a2a48ce8fd7caa6291d852d4dfc60ec34bf..02fb844670f9d1f664168eba7b17a44fce52d84a 100644 (file)
@@ -73,6 +73,13 @@ static const struct link_encoder_funcs dcn301_link_enc_funcs = {
        .get_dig_mode = dcn10_get_dig_mode,
        .is_in_alt_mode = dcn20_link_encoder_is_in_alt_mode,
        .get_max_link_cap = dcn20_link_encoder_get_max_link_cap,
+       .dpcstx_set_order_invert_18_bit = NULL,
+       .set_phy_source = NULL,
+       .dpcs_initialize_phy = NULL,
+       .dpcs_configure_phypll = NULL,
+       .dpcs_configure_dpcs = NULL,
+       .dpcs_enable_dpcs = NULL,
+       .prog_eq_setting = NULL,
        .get_hpd_state = dcn10_get_hpd_state,
        .program_hpd_filter = dcn10_program_hpd_filter,
 };
@@ -183,6 +190,11 @@ void dcn301_link_encoder_construct(
                enc10->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
                enc10->base.features.flags.bits.DP_IS_USB_C =
                                bp_cap_info.DP_IS_USB_C;
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = bp_cap_info.IS_HDMI_FRL_CAPABLE;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
+               enc10->base.txffe_state = 0;
        } else {
                DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
                                __func__,
@@ -191,4 +203,10 @@ void dcn301_link_encoder_construct(
        if (enc10->base.ctx->dc->debug.hdmi20_disable) {
                enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
        }
+       if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
+       }
 }
index 07d362ef0daf3cd32e5cc3a28e9129c816a3a59d..bcb791d741894e0cebbcca78b824976680c965ed 100644 (file)
 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
 #endif
 
+// HDMI FRL EQ Setting masks/shifts
+// EQ level 0-32 bits[0:1]
+#define HDMI_FRL_EQ__LEVEL__SHIFT 0x0
+#define HDMI_FRL_EQ__LEVEL__MASK 0x3
+// Enable no preshoot bit[5]
+#define HDMI_FRL_EQ__NO_PRE__SHIFT 0x5
+// Enable no demphasis bit[6]
+#define HDMI_FRL_EQ__NO_DEMPH__SHIFT 0x6
+// Enable no FFE bit[4]
+#define HDMI_FRL_EQ__NO_FFE__SHIFT 0x4
+
 static uint8_t phy_id_from_transmitter(enum transmitter t)
 {
        uint8_t phy_id;
@@ -246,6 +257,89 @@ void enc31_hw_init(struct link_encoder *enc)
        dcn10_aux_initialize(enc10);
 }
 
+static enum bp_result link_transmitter_control(
+       struct dcn10_link_encoder *enc10,
+       struct bp_transmitter_control *cntl)
+{
+       enum bp_result result;
+       struct dc_bios *bp = enc10->base.ctx->dc_bios;
+
+       result = bp->funcs->transmitter_control(bp, cntl);
+
+       return result;
+}
+//---------------------------------------------------
+// Task: Program EQ setting in HDMI FRL mode
+// Note:
+//      EQ setting can be dont during P2 state or P0 state
+//      If set in P0 state, The values are latched in a single
+//      cycle of txX_clk but will take maximum of 40 txX_clk symbols
+//      to be reflected on the output. During this period the
+//      analog serial lines might have a transitional behavior.
+//---------------------------------------------------
+void dpcs31_program_eq_setting(
+               struct link_encoder *enc,
+               uint8_t FFE_Level,
+               bool de_emphasis_only,
+               bool pre_shoot_only,
+               bool no_ffe,
+               const struct dc_hdmi_frl_link_settings *link_settings)
+{
+       struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+       struct bp_transmitter_control cntl = { 0 };
+       /* EQ setting for DP lane0 */
+
+       if (enc10->base.ctx->dc->debug.ignore_ffe)
+               return;
+
+       if (FFE_Level < 0x5)
+               enc10->base.txffe_state = FFE_Level;
+
+       if (FFE_Level == 0xEE) {
+               enc10->base.txffe_state++;
+               if (enc10->base.txffe_state > 3)
+                       enc10->base.txffe_state = 0;
+       }
+
+       if (no_ffe) {
+               de_emphasis_only = true;
+               pre_shoot_only = true;
+       }
+       /* Pass on the input params to DMCUB for proper calc of eq settings */
+       cntl.lane_settings = ((de_emphasis_only ? 1 : 0) << HDMI_FRL_EQ__NO_PRE__SHIFT) |
+                                                ((pre_shoot_only ? 1 : 0) << HDMI_FRL_EQ__NO_DEMPH__SHIFT) |
+                                                ((enc10->base.txffe_state & HDMI_FRL_EQ__LEVEL__MASK)
+                                                 << HDMI_FRL_EQ__LEVEL__SHIFT);
+       cntl.lane_select = 0;
+       cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
+       cntl.transmitter = enc10->base.transmitter;
+       cntl.connector_obj_id = enc10->base.connector;
+       cntl.lanes_number = link_settings->frl_num_lanes;
+       cntl.hpd_sel = enc10->base.hpd_source;
+       /* Use below or dc_link_frl_bandwidth_kbps()? */
+       switch (link_settings->frl_link_rate) {
+       case HDMI_FRL_LINK_RATE_3GBPS:
+               cntl.pixel_clock = 166667 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_6GBPS:
+       case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
+               cntl.pixel_clock = 333333 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_8GBPS:
+               cntl.pixel_clock = 444444 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_10GBPS:
+               cntl.pixel_clock = 555555 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_12GBPS:
+       default:
+               cntl.pixel_clock = 666667 / 10;
+               break;
+       }
+       /* call VBIOS table to set eq settings - voltage swing and pre-emphasis */
+       link_transmitter_control(enc10, &cntl);
+}
+
 static const struct link_encoder_funcs dcn31_link_enc_funcs = {
        .read_state = link_enc2_read_state,
        .validate_output_with_stream =
@@ -275,6 +369,15 @@ static const struct link_encoder_funcs dcn31_link_enc_funcs = {
        .get_dig_mode = dcn10_get_dig_mode,
        .is_in_alt_mode = dcn31_link_encoder_is_in_alt_mode,
        .get_max_link_cap = dcn31_link_encoder_get_max_link_cap,
+       .dpcstx_set_order_invert_18_bit = NULL,
+       .set_phy_source = NULL,
+       .dpcs_initialize_phy = NULL,
+       .dpcs_configure_phypll = NULL,
+       .dpcs_configure_dpcs = NULL,
+       .dpcs_enable_dpcs = NULL,
+       .prog_eq_setting = dpcs31_program_eq_setting,
+       .get_txffe = dpcs30_get_txffe,
+       .set_txffe = dpcs30_set_txffe,
        .set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
        .get_hpd_state = dcn10_get_hpd_state,
        .program_hpd_filter = dcn10_program_hpd_filter,
@@ -387,6 +490,11 @@ void dcn31_link_encoder_construct(
                enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
                enc10->base.features.flags.bits.DP_IS_USB_C =
                                bp_cap_info.DP_IS_USB_C;
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = bp_cap_info.IS_HDMI_FRL_CAPABLE;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
+               enc10->base.txffe_state = 0;
        } else {
                DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
                                __func__,
@@ -395,6 +503,12 @@ void dcn31_link_encoder_construct(
        if (enc10->base.ctx->dc->debug.hdmi20_disable) {
                enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
        }
+       if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
+       }
 }
 
 void dcn31_link_encoder_construct_minimal(
index ee78ba80797c86f945d6714fa6551dd6116d1c0b..3cf587527991641b94cfa5a7941bf08b331bd241 100644 (file)
@@ -285,6 +285,14 @@ bool dcn31_link_encoder_is_in_alt_mode(
 void dcn31_link_encoder_get_max_link_cap(struct link_encoder *enc,
        struct dc_link_settings *link_settings);
 
+void dpcs31_program_eq_setting(
+               struct link_encoder *enc,
+               uint8_t FFE_Level,
+               bool de_emphasis_only,
+               bool pre_shoot_only,
+               bool no_ffe,
+               const struct dc_hdmi_frl_link_settings *link_settings);
+
 void enc31_hw_init(struct link_encoder *enc);
 
 #endif /* __DC_LINK_ENCODER__DCN31_H__ */
index 65d28cb07b0465e78601a453ea4b1cebceffa3bf..68e0dc93ae7d6cd0fa0397fb501b3cb53476a485 100644 (file)
 #define AUX_REG_WRITE(reg_name, val) \
                        dm_write_reg(CTX, AUX_REG(reg_name), val)
 
+// HDMI FRL EQ Setting masks/shifts
+// EQ level 0-32 bits[0:1]
+#define HDMI_FRL_EQ__LEVEL__SHIFT 0x0
+#define HDMI_FRL_EQ__LEVEL__MASK 0x3
+// Enable no preshoot bit[5]
+#define HDMI_FRL_EQ__NO_PRE__SHIFT 0x5
+// Enable no demphasis bit[6]
+#define HDMI_FRL_EQ__NO_DEMPH__SHIFT 0x6
+// Enable no FFE bit[4]
+#define HDMI_FRL_EQ__NO_FFE__SHIFT 0x4
+
 static uint8_t phy_id_from_transmitter(enum transmitter t)
 {
        uint8_t phy_id;
@@ -203,6 +214,188 @@ void dcn32_link_encoder_get_max_link_cap(struct link_encoder *enc,
 }
 
 
+static enum bp_result link_transmitter_control(
+       struct dcn10_link_encoder *enc10,
+       struct bp_transmitter_control *cntl)
+{
+       enum bp_result result;
+       struct dc_bios *bp = enc10->base.ctx->dc_bios;
+
+       result = bp->funcs->transmitter_control(bp, cntl);
+
+       return result;
+}
+//---------------------------------------------------
+// Task: Program EQ setting
+// Note:
+//      EQ setting can be dont during P2 state or P0 state
+//      If set in P0 state, The values are latched in a single
+//      cycle of txX_clk but will take maximum of 40 txX_clk symbols
+//      to be reflected on the output. During this period the
+//      analog serial lines might have a transitional behavior.
+//---------------------------------------------------
+void dpcs32_program_eq_setting(
+               struct link_encoder *enc,
+               uint8_t FFE_Level,
+               bool de_emphasis_only,
+               bool pre_shoot_only,
+               bool no_ffe,
+               const struct dc_hdmi_frl_link_settings *link_settings)
+{
+       struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+       struct bp_transmitter_control cntl = { 0 };
+       /* EQ setting for DP lane0 */
+
+       if (enc10->base.ctx->dc->debug.ignore_ffe)
+               return;
+
+       if (FFE_Level < 0x5)
+               enc10->base.txffe_state = FFE_Level;
+
+       if (FFE_Level == 0xEE) {
+               enc10->base.txffe_state++;
+               if (enc10->base.txffe_state > 3)
+                       enc10->base.txffe_state = 0;
+       }
+
+       if (no_ffe) {
+               de_emphasis_only = true;
+               pre_shoot_only = true;
+       }
+       /* Pass on the input params to DMCUB for proper calc of eq settings */
+       cntl.lane_settings = ((de_emphasis_only ? 1 : 0) << HDMI_FRL_EQ__NO_PRE__SHIFT) |
+                                                ((pre_shoot_only ? 1 : 0) << HDMI_FRL_EQ__NO_DEMPH__SHIFT) |
+                                                ((enc10->base.txffe_state & HDMI_FRL_EQ__LEVEL__MASK)
+                                                 << HDMI_FRL_EQ__LEVEL__SHIFT);
+       cntl.lane_select = 0;
+       cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
+       cntl.transmitter = enc10->base.transmitter;
+       cntl.connector_obj_id = enc10->base.connector;
+       cntl.lanes_number = link_settings->frl_num_lanes;
+       cntl.hpd_sel = enc10->base.hpd_source;
+       /* Use below or dc_link_frl_bandwidth_kbps()? */
+       switch (link_settings->frl_link_rate) {
+       case HDMI_FRL_LINK_RATE_3GBPS:
+               cntl.pixel_clock = 166667 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_6GBPS:
+       case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
+               cntl.pixel_clock = 333333 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_8GBPS:
+               cntl.pixel_clock = 444444 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_10GBPS:
+               cntl.pixel_clock = 555555 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_12GBPS:
+       default:
+               cntl.pixel_clock = 666667 / 10;
+               break;
+       }
+       /* call VBIOS table to set eq settings - voltage swing and pre-emphasis */
+       link_transmitter_control(enc10, &cntl);
+}
+
+void dpcs32_get_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings)
+{
+       (void)enc;
+       /* EQ setting for DP lane0 */
+       uint32_t eq_main = 0;
+       uint32_t eq_pre = 0;
+       uint32_t eq_post = 0;
+
+       /* TODO */
+       //REG_GET_3(RDPCSTX_PHY_FUSE0,
+       //              RDPCS_PHY_DP_TX0_EQ_MAIN, &eq_main,
+       //              RDPCS_PHY_DP_TX0_EQ_PRE, &eq_pre,
+       //              RDPCS_PHY_DP_TX0_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[0] = eq_main;
+       lane_settings->pre_emphasis[0] = eq_pre;
+       lane_settings->post_emphasis[0] = eq_post;
+
+       //REG_GET_3(RDPCSTX_PHY_FUSE1,
+       //              RDPCS_PHY_DP_TX1_EQ_MAIN, &eq_main,
+       //              RDPCS_PHY_DP_TX1_EQ_PRE, &eq_pre,
+       //              RDPCS_PHY_DP_TX1_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[1] = eq_main;
+       lane_settings->pre_emphasis[1] = eq_pre;
+       lane_settings->post_emphasis[1] = eq_post;
+
+       //REG_GET_3(RDPCSTX_PHY_FUSE2,
+       //              RDPCS_PHY_DP_TX2_EQ_MAIN, &eq_main,
+       //              RDPCS_PHY_DP_TX2_EQ_PRE, &eq_pre,
+       //              RDPCS_PHY_DP_TX2_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[2] = eq_main;
+       lane_settings->pre_emphasis[2] = eq_pre;
+       lane_settings->post_emphasis[2] = eq_post;
+
+       //REG_GET_3(RDPCSTX_PHY_FUSE3,
+       //              RDPCS_PHY_DP_TX3_EQ_MAIN, &eq_main,
+       //              RDPCS_PHY_DP_TX3_EQ_PRE, &eq_pre,
+       //              RDPCS_PHY_DP_TX3_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[3] = eq_main;
+       lane_settings->pre_emphasis[3] = eq_pre;
+       lane_settings->post_emphasis[3] = eq_post;
+
+}
+
+void dpcs32_set_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings)
+{
+       (void)enc;
+       (void)lane_settings;
+       /* EQ setting for DP lane0 */
+       //uint32_t eq_main;
+       //uint32_t eq_pre;
+       //uint32_t eq_post;
+
+       //eq_main = lane_settings->amplitude[0];
+       //eq_pre = lane_settings->pre_emphasis[0];
+       //eq_post = lane_settings->post_emphasis[0];
+
+       /* TODO */
+       //REG_UPDATE_3(RDPCSTX_PHY_FUSE0,
+       //              RDPCS_PHY_DP_TX0_EQ_MAIN, eq_main,
+       //              RDPCS_PHY_DP_TX0_EQ_PRE, eq_pre,
+       //              RDPCS_PHY_DP_TX0_EQ_POST, eq_post);
+
+       //eq_main = lane_settings->amplitude[1];
+       //eq_pre = lane_settings->pre_emphasis[1];
+       //eq_post = lane_settings->post_emphasis[1];
+
+       //REG_UPDATE_3(RDPCSTX_PHY_FUSE1,
+       //              RDPCS_PHY_DP_TX1_EQ_MAIN, eq_main,
+       //              RDPCS_PHY_DP_TX1_EQ_PRE, eq_pre,
+       //              RDPCS_PHY_DP_TX1_EQ_POST, eq_post);
+
+       //eq_main = lane_settings->amplitude[2];
+       //eq_pre = lane_settings->pre_emphasis[2];
+       //eq_post = lane_settings->post_emphasis[2];
+
+       //REG_UPDATE_3(RDPCSTX_PHY_FUSE2,
+       //              RDPCS_PHY_DP_TX2_EQ_MAIN, eq_main,
+       //              RDPCS_PHY_DP_TX2_EQ_PRE, eq_pre,
+       //              RDPCS_PHY_DP_TX2_EQ_POST, eq_post);
+
+       //1eq_main = lane_settings->amplitude[3];
+       //eq_pre = lane_settings->pre_emphasis[3];
+       //eq_post = lane_settings->post_emphasis[3];
+
+       //REG_UPDATE_3(RDPCSTX_PHY_FUSE3,
+       //              RDPCS_PHY_DP_TX3_EQ_MAIN, eq_main,
+       //              RDPCS_PHY_DP_TX3_EQ_PRE, eq_pre,
+       //              RDPCS_PHY_DP_TX3_EQ_POST, eq_post);
+}
+
+
 static const struct link_encoder_funcs dcn32_link_enc_funcs = {
        .read_state = link_enc2_read_state,
        .validate_output_with_stream =
@@ -232,6 +425,15 @@ static const struct link_encoder_funcs dcn32_link_enc_funcs = {
        .get_dig_mode = dcn10_get_dig_mode,
        .is_in_alt_mode = dcn32_link_encoder_is_in_alt_mode,
        .get_max_link_cap = dcn32_link_encoder_get_max_link_cap,
+       .dpcstx_set_order_invert_18_bit = NULL,
+       .set_phy_source = NULL,
+       .dpcs_initialize_phy = NULL,
+       .dpcs_configure_phypll = NULL,
+       .dpcs_configure_dpcs = NULL,
+       .dpcs_enable_dpcs = NULL,
+       .prog_eq_setting = dpcs32_program_eq_setting,
+       .get_txffe = dpcs32_get_txffe,
+       .set_txffe = dpcs32_set_txffe,
        .set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
        .get_hpd_state = dcn10_get_hpd_state,
        .program_hpd_filter = dcn10_program_hpd_filter,
@@ -329,6 +531,12 @@ void dcn32_link_encoder_construct(
                enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
                enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
                enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
+
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
+               enc10->base.txffe_state = 0;
        } else {
                DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
                                __func__,
@@ -337,4 +545,10 @@ void dcn32_link_encoder_construct(
        if (enc10->base.ctx->dc->debug.hdmi20_disable) {
                enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
        }
+       if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
+       }
 }
index 35d23d9db45e1dbfedfe6b5a73f18a008d669d37..262796819a63410078aa5eb4c8df4f7f6fc4c5ac 100644 (file)
@@ -50,4 +50,20 @@ bool dcn32_link_encoder_is_in_alt_mode(struct link_encoder *enc);
 void dcn32_link_encoder_get_max_link_cap(struct link_encoder *enc,
        struct dc_link_settings *link_settings);
 
+void dpcs32_program_eq_setting(
+               struct link_encoder *enc,
+               uint8_t FFE_Level,
+               bool de_emphasis_only,
+               bool pre_shoot_only,
+               bool no_ffe,
+               const struct dc_hdmi_frl_link_settings *link_settings);
+
+void dpcs32_get_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings);
+
+void dpcs32_set_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings);
+
 #endif /* __DC_LINK_ENCODER__DCN32_H__ */
index 968f89295b64c30dfd53b24125c2e2dea8b4ca1b..4108fd0f43802fa99abf9ffaae1caa7802d09bb6 100644 (file)
@@ -88,6 +88,15 @@ static const struct link_encoder_funcs dcn321_link_enc_funcs = {
        .get_dig_mode = dcn10_get_dig_mode,
        .is_in_alt_mode = dcn20_link_encoder_is_in_alt_mode,
        .get_max_link_cap = dcn20_link_encoder_get_max_link_cap,
+       .dpcstx_set_order_invert_18_bit = NULL,
+       .set_phy_source = NULL,
+       .dpcs_initialize_phy = NULL,
+       .dpcs_configure_phypll = NULL,
+       .dpcs_configure_dpcs = NULL,
+       .dpcs_enable_dpcs = NULL,
+       .prog_eq_setting = dpcs32_program_eq_setting,
+       .get_txffe = dpcs32_get_txffe,
+       .set_txffe = dpcs32_set_txffe,
        .set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
        .get_hpd_state = dcn10_get_hpd_state,
        .program_hpd_filter = dcn10_program_hpd_filter,
@@ -183,6 +192,11 @@ void dcn321_link_encoder_construct(
                enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
                enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
                enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
+               enc10->base.txffe_state = 0;
        } else {
                DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
                                __func__,
@@ -190,4 +204,10 @@ void dcn321_link_encoder_construct(
        }
        if (enc10->base.ctx->dc->debug.hdmi20_disable)
                enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
+       if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
+       }
 }
index 20bf04dac609ac9745d19bc0550780bbab76cb99..8fa9b8c500f203a1597ba74698da8e1ddd943d5e 100644 (file)
@@ -158,6 +158,15 @@ static const struct link_encoder_funcs dcn35_link_enc_funcs = {
        .get_dig_mode = dcn35_get_dig_mode,
        .is_in_alt_mode = dcn31_link_encoder_is_in_alt_mode,
        .get_max_link_cap = dcn31_link_encoder_get_max_link_cap,
+       .dpcstx_set_order_invert_18_bit = NULL,
+       .set_phy_source = NULL,
+       .dpcs_initialize_phy = NULL,
+       .dpcs_configure_phypll = NULL,
+       .dpcs_configure_dpcs = NULL,
+       .dpcs_enable_dpcs = NULL,
+       .prog_eq_setting = dpcs32_program_eq_setting,
+       .get_txffe = dpcs32_get_txffe,
+       .set_txffe = dpcs32_set_txffe,
        .set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
        .enable_dpia_output = dcn35_link_encoder_enable_dpia_output,
        .disable_dpia_output = dcn35_link_encoder_disable_dpia_output,
@@ -261,6 +270,12 @@ void dcn35_link_encoder_construct(
                enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
                enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
 
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE =
+                               bp_cap_info.FRL_8G_EN || bp_cap_info.FRL_10G_EN || bp_cap_info.FRL_12G_EN;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
+               enc10->base.txffe_state = 0;
        } else {
                DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
                                __func__,
@@ -268,6 +283,12 @@ void dcn35_link_encoder_construct(
        }
        if (enc10->base.ctx->dc->debug.hdmi20_disable)
                enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
+       if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
+       }
 
 }
 
index e1f0a1bf10756b4da58eafeaaee4fb0de33bbb39..2aaf06d487719d1615ddb8bb6426aca498774841 100644 (file)
 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
 #endif
 
+// HDMI FRL EQ Setting masks/shifts
+// EQ level 0-32 bits[0:1]
+#define HDMI_FRL_EQ__LEVEL__SHIFT 0x0
+#define HDMI_FRL_EQ__LEVEL__MASK 0x3
+// Enable no preshoot bit[5]
+#define HDMI_FRL_EQ__NO_PRE__SHIFT 0x5
+// Enable no demphasis bit[6]
+#define HDMI_FRL_EQ__NO_DEMPH__SHIFT 0x6
+// Enable no FFE bit[4]
+#define HDMI_FRL_EQ__NO_FFE__SHIFT 0x4
+
 void enc401_hw_init(struct link_encoder *enc)
 {
        struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
@@ -120,6 +131,194 @@ void dcn401_link_encoder_enable_dp_output(
        }
 }
 
+static enum bp_result link_transmitter_control(
+       struct dcn10_link_encoder *enc10,
+       struct bp_transmitter_control *cntl)
+{
+       enum bp_result result;
+       struct dc_bios *bp = enc10->base.ctx->dc_bios;
+
+       result = bp->funcs->transmitter_control(bp, cntl);
+
+       return result;
+}
+//---------------------------------------------------
+// Task: Program EQ setting
+// Note:
+//      EQ setting can be dont during P2 state or P0 state
+//      If set in P0 state, The values are latched in a single
+//      cycle of txX_clk but will take maximum of 40 txX_clk symbols
+//      to be reflected on the output. During this period the
+//      analog serial lines might have a transitional behavior.
+//---------------------------------------------------
+
+void dpcs401_program_eq_setting(
+               struct link_encoder *enc,
+               uint8_t FFE_Level,
+               bool de_emphasis_only,
+               bool pre_shoot_only,
+               bool no_ffe,
+               const struct dc_hdmi_frl_link_settings *link_settings)
+{
+       struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+       struct bp_transmitter_control cntl = { 0 };
+
+       if (enc10->base.ctx->dc->debug.ignore_ffe)
+               return;
+
+       if (FFE_Level < 0x5)
+               enc10->base.txffe_state = FFE_Level;
+
+       if (enc10->base.ctx->dc->debug.select_ffe)
+               enc10->base.txffe_state =
+                               (uint8_t)enc10->base.ctx->dc->debug.select_ffe;
+
+       if (FFE_Level == 0xEE) {
+               enc10->base.txffe_state++;
+               if (enc10->base.txffe_state > 3)
+                       enc10->base.txffe_state = 0;
+       }
+
+       if (no_ffe) {
+               de_emphasis_only = true;
+               pre_shoot_only = true;
+       }
+       /* Pass on the input params to DMCUB for proper calc of eq settings */
+       cntl.lane_settings = ((de_emphasis_only ? 1 : 0) << HDMI_FRL_EQ__NO_PRE__SHIFT) |
+                                                ((pre_shoot_only ? 1 : 0) << HDMI_FRL_EQ__NO_DEMPH__SHIFT) |
+                                                ((enc10->base.txffe_state & HDMI_FRL_EQ__LEVEL__MASK)
+                                                 << HDMI_FRL_EQ__LEVEL__SHIFT);
+       cntl.lane_select = 0;
+       cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
+       cntl.transmitter = enc10->base.transmitter;
+       cntl.connector_obj_id = enc10->base.connector;
+       cntl.lanes_number = link_settings->frl_num_lanes;
+       cntl.hpd_sel = enc10->base.hpd_source;
+       /* Use below or dc_link_frl_bandwidth_kbps()? */
+       switch (link_settings->frl_link_rate) {
+       case HDMI_FRL_LINK_RATE_3GBPS:
+               cntl.pixel_clock = 166667 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_6GBPS:
+       case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
+               cntl.pixel_clock = 333333 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_8GBPS:
+               cntl.pixel_clock = 444444 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_10GBPS:
+               cntl.pixel_clock = 555555 / 10;
+               break;
+       case HDMI_FRL_LINK_RATE_12GBPS:
+       default:
+               cntl.pixel_clock = 666667 / 10;
+               break;
+       }
+       /* call VBIOS table to set eq settings - voltage swing and pre-emphasis */
+       link_transmitter_control(enc10, &cntl);
+}
+
+void dpcs401_get_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings)
+{
+       (void)enc;
+       /* EQ setting for DP lane0 */
+       uint32_t eq_main = 0;
+       uint32_t eq_pre = 0;
+       uint32_t eq_post = 0;
+
+       /* TODO */
+       //REG_GET_3(RDPCSTX_PHY_FUSE0,
+       //              RDPCS_PHY_DP_TX0_EQ_MAIN, &eq_main,
+       //              RDPCS_PHY_DP_TX0_EQ_PRE, &eq_pre,
+       //              RDPCS_PHY_DP_TX0_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[0] = eq_main;
+       lane_settings->pre_emphasis[0] = eq_pre;
+       lane_settings->post_emphasis[0] = eq_post;
+
+       //REG_GET_3(RDPCSTX_PHY_FUSE1,
+       //              RDPCS_PHY_DP_TX1_EQ_MAIN, &eq_main,
+       //              RDPCS_PHY_DP_TX1_EQ_PRE, &eq_pre,
+       //              RDPCS_PHY_DP_TX1_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[1] = eq_main;
+       lane_settings->pre_emphasis[1] = eq_pre;
+       lane_settings->post_emphasis[1] = eq_post;
+
+       //REG_GET_3(RDPCSTX_PHY_FUSE2,
+       //              RDPCS_PHY_DP_TX2_EQ_MAIN, &eq_main,
+       //              RDPCS_PHY_DP_TX2_EQ_PRE, &eq_pre,
+       //              RDPCS_PHY_DP_TX2_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[2] = eq_main;
+       lane_settings->pre_emphasis[2] = eq_pre;
+       lane_settings->post_emphasis[2] = eq_post;
+
+       //REG_GET_3(RDPCSTX_PHY_FUSE3,
+       //              RDPCS_PHY_DP_TX3_EQ_MAIN, &eq_main,
+       //              RDPCS_PHY_DP_TX3_EQ_PRE, &eq_pre,
+       //              RDPCS_PHY_DP_TX3_EQ_POST, &eq_post);
+
+       lane_settings->amplitude[3] = eq_main;
+       lane_settings->pre_emphasis[3] = eq_pre;
+       lane_settings->post_emphasis[3] = eq_post;
+
+}
+
+void dpcs401_set_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings)
+{
+       (void)enc;
+       (void)lane_settings;
+       //struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+       /* EQ setting for DP lane0 */
+       //TODO: Unused
+       //uint32_t eq_main;
+       //uint32_t eq_pre;
+       //uint32_t eq_post;
+
+       //eq_main = lane_settings->amplitude[0];
+       //eq_pre = lane_settings->pre_emphasis[0];
+       //eq_post = lane_settings->post_emphasis[0];
+
+       /* TODO */
+       //REG_UPDATE_3(RDPCSTX_PHY_FUSE0,
+       //              RDPCS_PHY_DP_TX0_EQ_MAIN, eq_main,
+       //              RDPCS_PHY_DP_TX0_EQ_PRE, eq_pre,
+       //              RDPCS_PHY_DP_TX0_EQ_POST, eq_post);
+
+       //eq_main = lane_settings->amplitude[1];
+       //eq_pre = lane_settings->pre_emphasis[1];
+       //eq_post = lane_settings->post_emphasis[1];
+
+       //REG_UPDATE_3(RDPCSTX_PHY_FUSE1,
+       //              RDPCS_PHY_DP_TX1_EQ_MAIN, eq_main,
+       //              RDPCS_PHY_DP_TX1_EQ_PRE, eq_pre,
+       //              RDPCS_PHY_DP_TX1_EQ_POST, eq_post);
+
+       //eq_main = lane_settings->amplitude[2];
+       //eq_pre = lane_settings->pre_emphasis[2];
+       //eq_post = lane_settings->post_emphasis[2];
+
+       //REG_UPDATE_3(RDPCSTX_PHY_FUSE2,
+       //              RDPCS_PHY_DP_TX2_EQ_MAIN, eq_main,
+       //              RDPCS_PHY_DP_TX2_EQ_PRE, eq_pre,
+       //              RDPCS_PHY_DP_TX2_EQ_POST, eq_post);
+
+       //eq_main = lane_settings->amplitude[3];
+       //eq_pre = lane_settings->pre_emphasis[3];
+       //eq_post = lane_settings->post_emphasis[3];
+
+       //REG_UPDATE_3(RDPCSTX_PHY_FUSE3,
+       //              RDPCS_PHY_DP_TX3_EQ_MAIN, eq_main,
+       //              RDPCS_PHY_DP_TX3_EQ_PRE, eq_pre,
+       //              RDPCS_PHY_DP_TX3_EQ_POST, eq_post);
+}
+
+
 void dcn401_link_encoder_setup(
        struct link_encoder *enc,
        enum signal_type signal)
@@ -214,6 +413,15 @@ static const struct link_encoder_funcs dcn401_link_enc_funcs = {
        .get_dig_mode = dcn401_get_dig_mode,
        .is_in_alt_mode = dcn32_link_encoder_is_in_alt_mode,
        .get_max_link_cap = dcn32_link_encoder_get_max_link_cap,
+       .dpcstx_set_order_invert_18_bit = NULL,
+       .set_phy_source = NULL,
+       .dpcs_initialize_phy = NULL,
+       .dpcs_configure_phypll = NULL,
+       .dpcs_configure_dpcs = NULL,
+       .dpcs_enable_dpcs = NULL,
+       .prog_eq_setting = dpcs401_program_eq_setting,
+       .get_txffe = dpcs401_get_txffe,
+       .set_txffe = dpcs401_set_txffe,
        .set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
        .get_hpd_state = dcn10_get_hpd_state,
        .program_hpd_filter = dcn10_program_hpd_filter,
@@ -314,6 +522,12 @@ void dcn401_link_encoder_construct(
                enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
                enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
                enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE =
+                               bp_cap_info.FRL_8G_EN || bp_cap_info.FRL_10G_EN || bp_cap_info.FRL_12G_EN;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
+               enc10->base.txffe_state = 0;
        } else {
                DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
                                __func__,
@@ -322,4 +536,10 @@ void dcn401_link_encoder_construct(
        if (enc10->base.ctx->dc->debug.hdmi20_disable) {
                enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
        }
+       if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
+       }
 }
index 6baab8302b8139e9450601a9d9e144e188a8a53f..a40c479fada8873cd1e741dad1655199a1a7debc 100644 (file)
@@ -121,6 +121,22 @@ void dcn401_link_encoder_enable_dp_output(
        const struct dc_link_settings *link_settings,
        enum clock_source_id clock_source);
 
+void dpcs401_program_eq_setting(
+               struct link_encoder *enc,
+               uint8_t FFE_Level,
+               bool de_emphasis_only,
+               bool pre_shoot_only,
+               bool no_ffe,
+               const struct dc_hdmi_frl_link_settings *link_settings);
+
+void dpcs401_get_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings);
+
+void dpcs401_set_txffe(
+               struct link_encoder *enc,
+               struct frl_txffe *lane_settings);
+
 void dcn401_link_encoder_setup(
        struct link_encoder *enc,
        enum signal_type signal);
index 35dfe3bb0c5555b6e6538b3ec5468a8f74f0cdf8..fae49b3b170e79fa6861168c0802911e99797859 100644 (file)
@@ -93,6 +93,15 @@ static const struct link_encoder_funcs dcn42_link_enc_funcs = {
        .get_dig_mode = dcn401_get_dig_mode,
        .is_in_alt_mode = dcn32_link_encoder_is_in_alt_mode,
        .get_max_link_cap = dcn32_link_encoder_get_max_link_cap,
+       .dpcstx_set_order_invert_18_bit = NULL,
+       .set_phy_source = NULL,
+       .dpcs_initialize_phy = NULL,
+       .dpcs_configure_phypll = NULL,
+       .dpcs_configure_dpcs = NULL,
+       .dpcs_enable_dpcs = NULL,
+       .prog_eq_setting = dpcs401_program_eq_setting,
+       .get_txffe = dpcs401_get_txffe,
+       .set_txffe = dpcs401_set_txffe,
        .set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
        .enable_dpia_output = dcn35_link_encoder_enable_dpia_output,
        .disable_dpia_output = dcn35_link_encoder_disable_dpia_output,
@@ -194,6 +203,12 @@ void dcn42_link_encoder_construct(
                enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
                enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
                enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE =
+                               bp_cap_info.FRL_8G_EN || bp_cap_info.FRL_10G_EN || bp_cap_info.FRL_12G_EN;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
+               enc10->base.txffe_state = 0;
        } else {
                DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
                                __func__,
@@ -202,4 +217,10 @@ void dcn42_link_encoder_construct(
        if (enc10->base.ctx->dc->debug.hdmi20_disable) {
                enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
        }
+       if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
+               enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
+               enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
+       }
 }
index 25b196714bd8c65c62afd853921d3dfeac2418a2..db60564b9cfd6b1697920596bfc8a3e1bdc66c7c 100644 (file)
@@ -27,6 +27,7 @@ ifdef CONFIG_DRM_AMD_DC_FP
 ###############################################################################
 # DCN30
 ###############################################################################
+HPO_DCN30 = dcn30_hpo_frl_link_encoder.o dcn30_hpo_frl_stream_encoder.o
 
 AMD_DAL_HPO_DCN30 = $(addprefix $(AMDDALPATH)/dc/hpo/dcn30/,$(HPO_DCN30))
 
@@ -48,10 +49,19 @@ AMD_DAL_HPO_DCN32 = $(addprefix $(AMDDALPATH)/dc/hpo/dcn32/,$(HPO_DCN32))
 
 AMD_DISPLAY_FILES += $(AMD_DAL_HPO_DCN32)
 
+###############################################################################
+# DCN401
+###############################################################################
+HPO_DCN401 = dcn401_hpo_frl_stream_encoder.o
+
+AMD_DAL_HPO_DCN401 = $(addprefix $(AMDDALPATH)/dc/hpo/dcn401/,$(HPO_DCN401))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_HPO_DCN401)
 ###############################################################################
 # DCN42
 ###############################################################################
 HPO_DCN42 = dcn42_hpo_dp_link_encoder.o
+HPO_DCN42 += dcn42_hpo_frl_stream_encoder.o
 
 AMD_DAL_HPO_DCN42 = $(addprefix $(AMDDALPATH)/dc/hpo/dcn42/,$(HPO_DCN42))
 
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.c
new file mode 100644 (file)
index 0000000..56e753d
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * 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 "core_types.h"
+#include "dc_bios_types.h"
+#include "dcn30_hpo_frl_link_encoder.h"
+#include "reg_helper.h"
+#include "dcn10/dcn10_link_encoder.h"
+
+#define DC_LOGGER enc3->base.ctx->logger
+
+#define REG(reg) (enc3->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) enc3->hpo_le_shift->field_name, enc3->hpo_le_mask->field_name
+
+#define CTX enc3->base.ctx
+
+void hpo_frl_link_enc3_setup_link_encoder(struct hpo_frl_link_encoder *enc,
+                                                int lane_count)
+{
+       struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
+
+       DC_LOG_DEBUG("Entering [%s]\n", __func__);
+
+       if (enc->ctx->dc->caps.ips_v2_support) {
+               REG_UPDATE(HDMI_FRL_ENC_MEM_CTRL,
+                       METERBUFFER_MEM_PWR_DIS, 1);
+               REG_WAIT(HDMI_FRL_ENC_MEM_CTRL, METERBUFFER_MEM_PWR_STATE, 0, 1, 100);
+       }
+       /* Enable Link encoder clock */
+       REG_UPDATE(HDMI_LINK_ENC_CLK_CTRL,
+                  HDMI_LINK_ENC_CLOCK_EN, 1);
+
+       /* Configure lane count of FRL encoder */
+       REG_UPDATE(HDMI_FRL_ENC_CONFIG,
+                  HDMI_LINK_LANE_COUNT, lane_count == 3 ? 0 : 1);
+
+       /* Reset link encoder */
+       REG_UPDATE_2(HDMI_LINK_ENC_CONTROL,
+                    HDMI_LINK_ENC_ENABLE, 0,
+                    HDMI_LINK_ENC_SOFT_RESET, 1);
+
+       REG_UPDATE(HDMI_LINK_ENC_CONTROL,
+                  HDMI_LINK_ENC_SOFT_RESET, 0);
+
+       /* Enable link encoder */
+       REG_UPDATE(HDMI_LINK_ENC_CONTROL,
+                  HDMI_LINK_ENC_ENABLE, 1);
+
+       DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
+}
+
+void hpo_frl_link_enc3_set_training_pattern(struct hpo_frl_link_encoder *enc,
+                                                  uint32_t lane0_pattern,
+                                                  uint32_t lane1_pattern,
+                                                  uint32_t lane2_pattern,
+                                                  uint32_t lane3_pattern)
+{
+       struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
+
+       /* Configure lane count of FRL encoder */
+       REG_UPDATE(HDMI_FRL_ENC_CONFIG,
+                  HDMI_LINK_TRAINING_ENABLE, 1);
+
+       if (lane0_pattern < 8)
+               REG_UPDATE(HDMI_FRL_ENC_CONFIG,
+                          HDMI_LINK_LANE0_TRAINING_PATTERN, lane0_pattern);
+
+       if (lane1_pattern < 8)
+               REG_UPDATE(HDMI_FRL_ENC_CONFIG,
+                          HDMI_LINK_LANE1_TRAINING_PATTERN, lane1_pattern);
+
+       if (lane2_pattern < 8)
+               REG_UPDATE(HDMI_FRL_ENC_CONFIG,
+                          HDMI_LINK_LANE2_TRAINING_PATTERN, lane2_pattern);
+
+       if (lane3_pattern < 8)
+               REG_UPDATE(HDMI_FRL_ENC_CONFIG,
+                          HDMI_LINK_LANE3_TRAINING_PATTERN, lane3_pattern);
+}
+
+void hpo_frl_link_enc3_get_training_pattern(struct hpo_frl_link_encoder *enc,
+                                                  uint32_t *lane0_pattern,
+                                                  uint32_t *lane1_pattern,
+                                                  uint32_t *lane2_pattern,
+                                                  uint32_t *lane3_pattern)
+{
+       struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
+
+       /* Configure lane count of FRL encoder */
+       REG_GET_4(HDMI_FRL_ENC_CONFIG,
+                 HDMI_LINK_LANE0_TRAINING_PATTERN, lane0_pattern,
+                 HDMI_LINK_LANE1_TRAINING_PATTERN, lane1_pattern,
+                 HDMI_LINK_LANE2_TRAINING_PATTERN, lane2_pattern,
+                 HDMI_LINK_LANE3_TRAINING_PATTERN, lane3_pattern);
+}
+
+static enum bp_result link_transmitter_control(struct dcn10_link_encoder *enc10,
+                                              struct bp_transmitter_control *cntl)
+{
+       struct dc_bios *bp = enc10->base.ctx->dc_bios;
+
+       return bp->funcs->transmitter_control(bp, cntl);
+}
+
+static void hpo_frl_link_enc3_enable_phy_output(struct hpo_frl_link_encoder *hpo_enc,
+                                               struct link_encoder *enc,
+                                               enum clock_source_id clock_source,
+                                               enum hdmi_frl_link_rate frl_link_rate)
+{
+       struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(hpo_enc);
+       struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+       struct bp_transmitter_control cntl = { 0 };
+       enum bp_result result;
+
+       /* Enable the PHY */
+       cntl.action = TRANSMITTER_CONTROL_ENABLE;
+       cntl.engine_id = enc->preferred_engine;
+       cntl.transmitter = enc10->base.transmitter;
+       cntl.pll_id = clock_source;
+       cntl.signal = SIGNAL_TYPE_HDMI_FRL;
+       cntl.hpd_sel = enc10->base.hpd_source;
+
+       switch (frl_link_rate) {
+       case HDMI_FRL_LINK_RATE_3GBPS:
+               cntl.pixel_clock = 166667;
+               break;
+       case HDMI_FRL_LINK_RATE_6GBPS:
+       case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
+               cntl.pixel_clock = 333333;
+               break;
+       case HDMI_FRL_LINK_RATE_8GBPS:
+               cntl.pixel_clock = 444444;
+               break;
+       case HDMI_FRL_LINK_RATE_10GBPS:
+               cntl.pixel_clock = 555555;
+               break;
+       case HDMI_FRL_LINK_RATE_12GBPS:
+       default:
+               cntl.pixel_clock = 666667;
+               break;
+       }
+
+       cntl.hpo_engine_id = enc3->base.inst + ENGINE_ID_HPO_0;
+
+       if (frl_link_rate <= HDMI_FRL_LINK_RATE_6GBPS)
+               cntl.lanes_number = 3;
+       else
+               cntl.lanes_number = 4;
+
+       result = link_transmitter_control(enc10, &cntl);
+
+       if (result != BP_RESULT_OK) {
+               DC_LOG_HDMI_FRL("%s: Failed to execute VBIOS command table!\n", __func__);
+               BREAK_TO_DEBUGGER();
+       }
+}
+
+void hpo_frl_link_enc3_enable_output(struct hpo_frl_link_encoder *enc)
+{
+       struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
+
+       DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
+
+       /* Enable FRL packet transmission */
+       REG_UPDATE(HDMI_FRL_ENC_CONFIG,
+                  HDMI_LINK_TRAINING_ENABLE, 0);
+       DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
+}
+
+void hpo_frl_link_enc3_disable(struct hpo_frl_link_encoder *enc)
+{
+       struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
+
+       DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
+
+       REG_UPDATE_5(HDMI_FRL_ENC_CONFIG,
+                    HDMI_LINK_TRAINING_ENABLE, 1,
+                    HDMI_LINK_LANE0_TRAINING_PATTERN, 0,
+                    HDMI_LINK_LANE1_TRAINING_PATTERN, 0,
+                    HDMI_LINK_LANE2_TRAINING_PATTERN, 0,
+                    HDMI_LINK_LANE3_TRAINING_PATTERN, 0);
+
+       /* Disable link encoder */
+       REG_UPDATE(HDMI_LINK_ENC_CONTROL,
+                  HDMI_LINK_ENC_ENABLE, 0);
+
+       /* Disable Link encoder clock */
+       REG_UPDATE(HDMI_LINK_ENC_CLK_CTRL,
+                  HDMI_LINK_ENC_CLOCK_EN, 0);
+       REG_UPDATE(HDMI_FRL_ENC_CONFIG2,
+                  HDMI_LINK_RC_COMPRESS_DISABLE, 0);
+
+       DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
+}
+
+void hpo_frl_link_enc3_read_state(struct hpo_frl_link_encoder *enc,
+                                        struct hpo_frl_link_enc_state *state)
+{
+       struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
+       unsigned int link_training_enabled;
+       unsigned int lane_count_field;
+
+       ASSERT(state);
+       REG_GET(HDMI_LINK_ENC_CONTROL,
+               HDMI_LINK_ENC_ENABLE, &state->link_enc_enabled);
+
+       REG_GET_2(HDMI_FRL_ENC_CONFIG,
+                 HDMI_LINK_TRAINING_ENABLE, &link_training_enabled,
+                         HDMI_LINK_LANE_COUNT, &lane_count_field);
+
+       state->link_active = link_training_enabled == 1;
+
+       if (lane_count_field == 1)
+               state->lane_count = 4;
+       else
+               state->lane_count = 3;
+}
+
+void hpo_frl_link_enc3_destroy(struct hpo_frl_link_encoder **enc)
+{
+       kfree(DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(*enc));
+       *enc = NULL;
+}
+
+void hpo_frl_link_enc3_apply_vsdb_rcc_wa(struct hpo_frl_link_encoder *enc)
+{
+       struct dcn30_hpo_frl_link_encoder *enc3 =
+                       DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
+
+       REG_UPDATE(HDMI_FRL_ENC_CONFIG2,
+                       HDMI_LINK_RC_COMPRESS_DISABLE, 1);
+}
+
+static struct hpo_frl_link_encoder_funcs dcn30_hpo_frl_link_encoder_funcs = {
+       .setup_link_encoder = hpo_frl_link_enc3_setup_link_encoder,
+       .set_hdmi_training_pattern = hpo_frl_link_enc3_set_training_pattern,
+       .get_hdmi_training_pattern = hpo_frl_link_enc3_get_training_pattern,
+       .enable_frl_phy_output = hpo_frl_link_enc3_enable_phy_output,
+       .enable_output = hpo_frl_link_enc3_enable_output,
+       .disable_link_encoder = hpo_frl_link_enc3_disable,
+       .read_state = hpo_frl_link_enc3_read_state,
+       .destroy = hpo_frl_link_enc3_destroy,
+       .apply_vsdb_rcc_wa = hpo_frl_link_enc3_apply_vsdb_rcc_wa
+};
+
+void hpo_frl_link_encoder3_construct(struct dcn30_hpo_frl_link_encoder *enc3,
+                                    struct dc_context *ctx,
+                                    uint32_t inst,
+                                    const struct dcn30_hpo_frl_link_encoder_registers *hpo_le_regs,
+                                    const struct dcn30_hpo_frl_link_encoder_shift *hpo_le_shift,
+                                    const struct dcn30_hpo_frl_link_encoder_mask *hpo_le_mask)
+{
+       enc3->base.ctx = ctx;
+
+       enc3->base.inst = inst;
+       enc3->base.funcs = &dcn30_hpo_frl_link_encoder_funcs;
+
+       enc3->regs = hpo_le_regs;
+       enc3->hpo_le_shift = hpo_le_shift;
+       enc3->hpo_le_mask = hpo_le_mask;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.h b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.h
new file mode 100644 (file)
index 0000000..9626793
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __DAL_DCN30_HPO_FRL_LINK_ENCODER_H__
+#define __DAL_DCN30_HPO_FRL_LINK_ENCODER_H__
+
+#include "link_encoder.h"
+
+
+#define DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(hpo_frl_link_encoder)\
+       container_of(hpo_frl_link_encoder, struct dcn30_hpo_frl_link_encoder, base)
+
+
+#define DCN3_0_HPO_FRL_LINK_ENC_REG_LIST(id) \
+       SR(HDMI_LINK_ENC_CLK_CTRL), \
+       SR(HDMI_LINK_ENC_CONTROL), \
+       SR(HDMI_FRL_ENC_CONFIG), \
+       SR(HDMI_FRL_ENC_CONFIG2),\
+       SR(HDMI_FRL_ENC_MEM_CTRL)
+
+struct dcn30_hpo_frl_link_encoder_registers {
+       uint32_t HDMI_LINK_ENC_CLK_CTRL;
+       uint32_t HDMI_LINK_ENC_CONTROL;
+       uint32_t HDMI_FRL_ENC_CONFIG;
+       uint32_t HDMI_FRL_ENC_CONFIG2;
+       uint32_t HDMI_FRL_ENC_MEM_CTRL;
+};
+
+#define DCN3_0_HPO_FRL_LINK_ENC_MASK_SH_LIST(mask_sh)\
+       SE_SF(HDMI_LINK_ENC_CLK_CTRL, HDMI_LINK_ENC_CLOCK_EN, mask_sh),\
+       SE_SF(HDMI_LINK_ENC_CONTROL, HDMI_LINK_ENC_ENABLE, mask_sh),\
+       SE_SF(HDMI_LINK_ENC_CONTROL, HDMI_LINK_ENC_SOFT_RESET, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_MEM_CTRL, METERBUFFER_MEM_PWR_DIS, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_MEM_CTRL, METERBUFFER_MEM_PWR_FORCE, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_MEM_CTRL, METERBUFFER_MEM_PWR_STATE, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_MEM_CTRL, METERBUFFER_MEM_DEFAULT_MEM_LOW_POWER_STATE, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_LANE_COUNT, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_TRAINING_ENABLE, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_LANE0_TRAINING_PATTERN, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_LANE1_TRAINING_PATTERN, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_LANE2_TRAINING_PATTERN, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_LANE3_TRAINING_PATTERN, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_MAX_JITTER_VALUE, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_JITTER_THRESHOLD, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_JITTER_CAL_EN, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_RC_COMPRESS_DISABLE, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_FRL_HDMISTREAMCLK_DB_SEL, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_MAX_JITTER_VALUE_RESET, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_JITTER_EXCEED_STATUS, mask_sh),\
+       SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_METER_BUFFER_OVERFLOW_STATUS, mask_sh)
+
+#define HPO_FRL_LINK_ENC_DCN3_REG_FIELD_LIST(type) \
+       type HDMI_LINK_ENC_CLOCK_EN;\
+       type HDMI_LINK_ENC_ENABLE;\
+       type HDMI_LINK_ENC_SOFT_RESET;\
+       type HDMI_LINK_LANE_COUNT;\
+       type HDMI_LINK_TRAINING_ENABLE;\
+       type HDMI_LINK_LANE0_TRAINING_PATTERN;\
+       type HDMI_LINK_LANE1_TRAINING_PATTERN;\
+       type HDMI_LINK_LANE2_TRAINING_PATTERN;\
+       type HDMI_LINK_LANE3_TRAINING_PATTERN;\
+       type HDMI_LINK_MAX_JITTER_VALUE;\
+       type HDMI_LINK_JITTER_THRESHOLD;\
+       type HDMI_LINK_JITTER_CAL_EN;\
+       type HDMI_LINK_RC_COMPRESS_DISABLE;\
+       type METERBUFFER_MEM_PWR_DIS;\
+       type METERBUFFER_MEM_PWR_STATE;\
+       type METERBUFFER_MEM_PWR_FORCE;\
+       type METERBUFFER_MEM_DEFAULT_MEM_LOW_POWER_STATE;\
+       type HDMI_FRL_HDMISTREAMCLK_DB_SEL;\
+       type HDMI_LINK_MAX_JITTER_VALUE_RESET;\
+       type HDMI_LINK_JITTER_EXCEED_STATUS;\
+       type HDMI_LINK_METER_BUFFER_OVERFLOW_STATUS
+
+
+struct dcn30_hpo_frl_link_encoder_shift {
+       HPO_FRL_LINK_ENC_DCN3_REG_FIELD_LIST(uint8_t);
+};
+
+struct dcn30_hpo_frl_link_encoder_mask {
+       HPO_FRL_LINK_ENC_DCN3_REG_FIELD_LIST(uint32_t);
+};
+
+struct dcn30_hpo_frl_link_encoder {
+       struct hpo_frl_link_encoder base;
+       const struct dcn30_hpo_frl_link_encoder_registers *regs;
+       const struct dcn30_hpo_frl_link_encoder_shift *hpo_le_shift;
+       const struct dcn30_hpo_frl_link_encoder_mask *hpo_le_mask;
+};
+
+void hpo_frl_link_enc3_setup_link_encoder(struct hpo_frl_link_encoder *enc,
+                                                int lane_count);
+
+void hpo_frl_link_enc3_set_training_pattern(struct hpo_frl_link_encoder *enc,
+                                               uint32_t lane0_pattern,
+                                               uint32_t lane1_pattern,
+                                               uint32_t lane2_pattern,
+                                               uint32_t lane3_pattern);
+
+void hpo_frl_link_enc3_get_training_pattern(struct hpo_frl_link_encoder *enc,
+                                               uint32_t *lane0_pattern,
+                                               uint32_t *lane1_pattern,
+                                               uint32_t *lane2_pattern,
+                                               uint32_t *lane3_pattern);
+
+void hpo_frl_link_enc3_enable_output(struct hpo_frl_link_encoder *enc);
+
+void hpo_frl_link_enc3_disable(struct hpo_frl_link_encoder *enc);
+
+void hpo_frl_link_enc3_read_state(struct hpo_frl_link_encoder *enc,
+                                        struct hpo_frl_link_enc_state *state);
+
+void hpo_frl_link_enc3_destroy(struct hpo_frl_link_encoder **enc);
+
+void hpo_frl_link_enc3_apply_vsdb_rcc_wa(struct hpo_frl_link_encoder *enc);
+
+void hpo_frl_link_encoder3_construct(struct dcn30_hpo_frl_link_encoder *enc3,
+                                    struct dc_context *ctx,
+                                    uint32_t inst,
+                                    const struct dcn30_hpo_frl_link_encoder_registers *hpo_le_regs,
+                                    const struct dcn30_hpo_frl_link_encoder_shift *hpo_le_shift,
+                                    const struct dcn30_hpo_frl_link_encoder_mask *hpo_le_mask);
+
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
new file mode 100644 (file)
index 0000000..cd7d2bb
--- /dev/null
@@ -0,0 +1,938 @@
+/*
+ * 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 "core_types.h"
+#include "dcn30_hpo_frl_stream_encoder.h"
+#include "reg_helper.h"
+#include "hw_shared.h"
+#include "dcn_calc_math.h"
+#include "dml/dcn30/dcn30_fpu.h"
+
+#undef DC_LOGGER
+#define DC_LOGGER enc3->base.ctx->logger
+
+#define DTRACE(str, ...) {DC_LOG_HDMI_FRL(str, ##__VA_ARGS__); }
+
+#define DEBUG_FRL_CAP_CHK 1
+
+#define REG(reg) (enc3->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) enc3->hpo_se_shift->field_name, enc3->hpo_se_mask->field_name
+
+#define CTX enc3->base.ctx
+
+#define VBI_LINE_0 0
+
+void hpo_enc3_enable(struct hpo_frl_stream_encoder *enc, int otg_inst)
+{
+       struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
+
+       /* Enable DISPCLK, SOCCLK, and HDMISTREAMCLK */
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_CONTROL,
+                  HDMI_STREAM_ENC_CLOCK_EN, 1);
+
+       /* Reset */
+       REG_UPDATE_2(HDMI_TB_ENC_CONTROL,
+                    HDMI_RESET, 1,
+                    HDMI_TB_ENC_EN, 0);
+       REG_WAIT(HDMI_TB_ENC_CONTROL, HDMI_RESET_DONE,
+                1, 10, 100);
+       REG_UPDATE(HDMI_TB_ENC_CONTROL,
+                  HDMI_RESET, 0);
+
+       /* FOR DEBUG:  enable CRC */
+       REG_UPDATE_2(HDMI_TB_ENC_CRC_CNTL,
+                    HDMI_CRC_EN, 1,
+                    HDMI_CRC_CONT_EN, 1);
+
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2,
+                  FIFO_DB_DISABLE, 1);
+
+       /* TODO: confirm if need to set HDMI_DB_DISABLE -- HW team only setting FIFO_DB_DISABLE */
+       REG_UPDATE(HDMI_TB_ENC_DB_CONTROL,
+                  HDMI_DB_DISABLE, 1);
+
+       /* Set the input mux to select OTG source */
+       REG_UPDATE(HDMI_STREAM_ENC_INPUT_MUX_CONTROL,
+                  HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, otg_inst);
+
+       DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
+}
+
+void hpo_enc3_unblank(struct hpo_frl_stream_encoder *enc, int otg_inst)
+{
+       (void)otg_inst;
+       struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
+
+       /*make sure FIFO_VIDEO_STREAM_ACTIVE =1*/
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_ENABLE, 0);
+
+       /* Reset */
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_RESET, 1);
+       REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
+                1, 10, 1000);
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_RESET, 0);
+       REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
+                0, 10, 1000);
+
+       /* Enable HDMI Tribyte Encoder */
+       REG_UPDATE(HDMI_TB_ENC_CONTROL,
+                  HDMI_TB_ENC_EN, 1);
+
+       /* Enable Clock Ramp Adjuster FIFO */
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_ENABLE, 1);
+
+       DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
+}
+
+bool hpo_enc3_fifo_odm_enabled(struct hpo_frl_stream_encoder *enc)
+{
+       struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+       uint32_t fifo_odm_combine_mode;
+
+       REG_GET(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                       FIFO_ODM_COMBINE_MODE, &fifo_odm_combine_mode);
+
+       return (fifo_odm_combine_mode != 0);
+}
+
+void hpo_enc3_blank(struct hpo_frl_stream_encoder *enc)
+{
+       struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       /* Disable Clock Ramp Adjuster FIFO */
+       REG_UPDATE_2(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_ENABLE, 0,
+                  FIFO_ODM_COMBINE_MODE, 0);
+
+       /* Disable HDMI Tribyte Encoder */
+       REG_UPDATE(HDMI_TB_ENC_CONTROL,
+                  HDMI_TB_ENC_EN, 0);
+
+       /* Disable DISPCLK, SOCCLK, and HDMISTREAMCLK */
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_CONTROL,
+                  HDMI_STREAM_ENC_CLOCK_EN, 0);
+}
+
+/* Setup stream encoder in hdmi mode
+ * - Precondition: link is trained
+ */
+void hpo_enc3_set_hdmi_stream_attribute(struct hpo_frl_stream_encoder *enc,
+                                       struct dc_crtc_timing *crtc_timing,
+                                       struct frl_borrow_params *borrow_params,
+                                       int odm_combine_num_segments)
+{
+       struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+       uint32_t h_active;
+       uint32_t h_blank;
+
+       DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
+
+       /* Configure pixel encoding */
+       switch (crtc_timing->pixel_encoding) {
+       case PIXEL_ENCODING_YCBCR422:
+               REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
+                          HDMI_PIXEL_ENCODING, 1);
+               REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                          FIFO_PIXEL_ENCODING, 1);
+               break;
+       case PIXEL_ENCODING_YCBCR420:
+               REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
+                          HDMI_PIXEL_ENCODING, 2);
+               REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                          FIFO_PIXEL_ENCODING, 2);
+               break;
+       default:
+               REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
+                          HDMI_PIXEL_ENCODING, 0);
+               REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                          FIFO_PIXEL_ENCODING, 0);
+               break;
+       }
+
+       /* Configure color depth */
+       switch (crtc_timing->display_color_depth) {
+       case COLOR_DEPTH_888:
+               REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                            HDMI_DEEP_COLOR_DEPTH, 0,
+                            HDMI_DEEP_COLOR_ENABLE, 0);
+               break;
+       case COLOR_DEPTH_101010:
+               if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+                       REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                                    HDMI_DEEP_COLOR_DEPTH, 1,
+                                    HDMI_DEEP_COLOR_ENABLE, 0);
+               } else {
+                       REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                                    HDMI_DEEP_COLOR_DEPTH, 1,
+                                    HDMI_DEEP_COLOR_ENABLE, 1);
+               }
+               break;
+       case COLOR_DEPTH_121212:
+               if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+                       REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                                    HDMI_DEEP_COLOR_DEPTH, 2,
+                                    HDMI_DEEP_COLOR_ENABLE, 0);
+               } else {
+                       REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                                    HDMI_DEEP_COLOR_DEPTH, 2,
+                                    HDMI_DEEP_COLOR_ENABLE, 1);
+               }
+               break;
+       default:
+               break;
+       }
+
+       /* Configure ODM combine mode */
+       switch (odm_combine_num_segments) {
+       case 1:
+               REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                          FIFO_ODM_COMBINE_MODE, 0);
+
+               if (enc3->hpo_se_mask->HDMI_ODM_COMBINE_MODE)
+                       REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
+                                  HDMI_ODM_COMBINE_MODE, 0);
+               break;
+       case 2:
+               REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                          FIFO_ODM_COMBINE_MODE, 1);
+
+               if (enc3->hpo_se_mask->HDMI_ODM_COMBINE_MODE)
+                       REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
+                                  HDMI_ODM_COMBINE_MODE, 1);
+               break;
+       case 4:
+               REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                          FIFO_ODM_COMBINE_MODE, 3);
+               break;
+       default:
+               break;
+       }
+
+       /* Configure horizontal active and blank size */
+       h_active = crtc_timing->h_addressable + crtc_timing->h_border_left + crtc_timing->h_border_right;
+       h_blank = crtc_timing->h_total - h_active;
+
+       if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 ||
+           crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+               h_active /= 2;
+               h_blank /= 2;
+       }
+
+
+       REG_SET_2(HDMI_TB_ENC_H_ACTIVE_BLANK, 0,
+                 HDMI_H_ACTIVE, h_active,
+                 HDMI_H_BLANK, h_blank);
+
+       /* Configure borrow parameters */
+       REG_UPDATE(HDMI_TB_ENC_MODE,
+                  HDMI_BORROW_MODE, borrow_params->borrow_mode);
+
+       REG_UPDATE(HDMI_TB_ENC_PACKET_CONTROL,
+                  HDMI_MAX_PACKETS_PER_LINE, borrow_params->audio_packets_line);
+
+       REG_SET_2(HDMI_TB_ENC_HC_ACTIVE_BLANK, 0,
+                 HDMI_HC_ACTIVE, borrow_params->hc_active_target,
+                 HDMI_HC_BLANK, borrow_params->hc_blank_target);
+
+       /* Enable transmission of General Control packet on every frame */
+       REG_UPDATE_2(HDMI_TB_ENC_VBI_PACKET_CONTROL1,
+                    HDMI_GC_CONT, 1,
+                    HDMI_GC_SEND, 1);
+
+       /* Disable Audio Content Protection packet transmission */
+       /* TODO: review if this needs to be here */
+       REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1,
+                  HDMI_ACP_SEND, 0);
+
+       /* Enable Audio InfoFrame packet transmission. */
+       REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1,
+                  HDMI_AUDIO_INFO_SEND, 1);
+
+       /* update double-buffered AUDIO_INFO registers immediately */
+       ASSERT(enc->afmt);
+       enc->afmt->funcs->audio_info_immediate_update(enc->afmt);
+
+       /* Select line number on which to send Audio InfoFrame packets */
+       REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_LINE,
+                  VBI_LINE_0 + 2);
+
+       /* set HDMI GC AVMUTE */
+       REG_UPDATE(HDMI_TB_ENC_GC_CONTROL,
+                  HDMI_GC_AVMUTE, 0);
+
+       DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
+}
+
+void hpo_enc3_update_hdmi_info_packets(struct hpo_frl_stream_encoder *enc,
+                                      const struct encoder_info_frame *info_frame)
+{
+       struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       hpo_enc3_update_hdmi_info_packet(enc3, 0, &info_frame->avi);
+       hpo_enc3_update_hdmi_info_packet(enc3, 1, &info_frame->vendor);
+       hpo_enc3_update_hdmi_info_packet(enc3, 2, &info_frame->gamut);
+       hpo_enc3_update_hdmi_info_packet(enc3, 3, &info_frame->spd);
+       hpo_enc3_update_hdmi_info_packet(enc3, 4, &info_frame->hdrsmd);
+
+       /* 5-10 used by dsc */
+       hpo_enc3_update_hdmi_info_packet(enc3, 11, &info_frame->hfvsif);
+       hpo_enc3_update_hdmi_info_packet(enc3, 12, &info_frame->vtem);
+}
+
+void hpo_enc3_update_hdmi_info_packet(struct dcn30_hpo_frl_stream_encoder *enc3,
+                                     uint32_t packet_index,
+                                     const struct dc_info_packet *info_packet)
+{
+       uint32_t cont, send, line;
+
+       if (info_packet->valid) {
+               enc3->base.vpg->funcs->update_generic_info_packet(
+                               enc3->base.vpg,
+                               packet_index,
+                               info_packet,
+                               true);
+
+               /* enable transmission of packet(s) -
+                * packet transmission begins on the next frame */
+               cont = 1;
+               /* send packet(s) every frame */
+               send = 1;
+               /* select line number to send packets on */
+               /* TODO: check if line 2 is correct */
+               line = 2;
+       } else {
+               cont = 0;
+               send = 0;
+               line = 0;
+       }
+
+       /* TODO: set bit to indicate if packet is Extended Metadata Packet. */
+       /* TODO: In DCN3, there are 0-14 generic packets */
+
+       /* choose which generic packet control to use */
+       switch (packet_index) {
+       case 0:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                            HDMI_GENERIC0_CONT, cont,
+                            HDMI_GENERIC0_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE,
+                          HDMI_GENERIC0_LINE, line);
+               break;
+       case 1:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                            HDMI_GENERIC1_CONT, cont,
+                            HDMI_GENERIC1_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE,
+                          HDMI_GENERIC1_LINE, line);
+               break;
+       case 2:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                            HDMI_GENERIC2_CONT, cont,
+                            HDMI_GENERIC2_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE,
+                          HDMI_GENERIC2_LINE, line);
+               break;
+       case 3:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                            HDMI_GENERIC3_CONT, cont,
+                            HDMI_GENERIC3_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE,
+                          HDMI_GENERIC3_LINE, line);
+               break;
+       case 4:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                            HDMI_GENERIC4_CONT, cont,
+                            HDMI_GENERIC4_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE,
+                          HDMI_GENERIC4_LINE, line);
+               break;
+       case 5:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                            HDMI_GENERIC5_CONT, cont,
+                            HDMI_GENERIC5_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE,
+                          HDMI_GENERIC5_LINE, line);
+               break;
+       case 6:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                            HDMI_GENERIC6_CONT, cont,
+                            HDMI_GENERIC6_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE,
+                          HDMI_GENERIC6_LINE, line);
+               break;
+       case 7:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                            HDMI_GENERIC7_CONT, cont,
+                            HDMI_GENERIC7_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE,
+                          HDMI_GENERIC7_LINE, line);
+               break;
+       case 8:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                            HDMI_GENERIC8_CONT, cont,
+                            HDMI_GENERIC8_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE,
+                          HDMI_GENERIC8_LINE, line);
+               break;
+       case 9:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                            HDMI_GENERIC9_CONT, cont,
+                            HDMI_GENERIC9_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE,
+                          HDMI_GENERIC9_LINE, line);
+               break;
+       case 10:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                            HDMI_GENERIC10_CONT, cont,
+                            HDMI_GENERIC10_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE,
+                          HDMI_GENERIC10_LINE, line);
+               break;
+       case 11:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                            HDMI_GENERIC11_CONT, cont,
+                            HDMI_GENERIC11_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE,
+                          HDMI_GENERIC11_LINE, line);
+               break;
+       case 12:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                            HDMI_GENERIC12_CONT, cont,
+                            HDMI_GENERIC12_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE,
+                          HDMI_GENERIC12_LINE, line);
+               break;
+       case 13:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                            HDMI_GENERIC13_CONT, cont,
+                            HDMI_GENERIC13_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE,
+                          HDMI_GENERIC13_LINE, line);
+               break;
+       case 14:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                            HDMI_GENERIC14_CONT, cont,
+                            HDMI_GENERIC14_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET14_LINE,
+                          HDMI_GENERIC14_LINE, line);
+               break;
+       default:
+               /* invalid HW packet index */
+               DC_LOG_WARNING("Invalid HW packet index: %s()\n", __func__);
+               return;
+       }
+}
+
+void hpo_enc3_stop_hdmi_info_packets(
+       struct hpo_frl_stream_encoder *enc)
+{
+       struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       /* TODO: should also set extended metadata packet bit back to 0? */
+
+       /* stop generic packets 0,1 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
+               HDMI_GENERIC0_CONT, 0,
+               HDMI_GENERIC0_SEND, 0,
+               HDMI_GENERIC1_CONT, 0,
+               HDMI_GENERIC1_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, 0,
+               HDMI_GENERIC0_LINE, 0,
+               HDMI_GENERIC1_LINE, 0);
+
+       /* stop generic packets 2,3 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
+               HDMI_GENERIC2_CONT, 0,
+               HDMI_GENERIC2_SEND, 0,
+               HDMI_GENERIC3_CONT, 0,
+               HDMI_GENERIC3_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, 0,
+               HDMI_GENERIC2_LINE, 0,
+               HDMI_GENERIC3_LINE, 0);
+
+       /* stop generic packets 4,5 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
+               HDMI_GENERIC4_CONT, 0,
+               HDMI_GENERIC4_SEND, 0,
+               HDMI_GENERIC5_CONT, 0,
+               HDMI_GENERIC5_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, 0,
+               HDMI_GENERIC4_LINE, 0,
+               HDMI_GENERIC5_LINE, 0);
+
+       /* stop generic packets 6,7 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
+               HDMI_GENERIC6_CONT, 0,
+               HDMI_GENERIC6_SEND, 0,
+               HDMI_GENERIC7_CONT, 0,
+               HDMI_GENERIC7_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, 0,
+               HDMI_GENERIC6_LINE, 0,
+               HDMI_GENERIC7_LINE, 0);
+
+       /* stop generic packets 8,9 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
+               HDMI_GENERIC8_CONT, 0,
+               HDMI_GENERIC8_SEND, 0,
+               HDMI_GENERIC9_CONT, 0,
+               HDMI_GENERIC9_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, 0,
+               HDMI_GENERIC8_LINE, 0,
+               HDMI_GENERIC9_LINE, 0);
+
+       /* stop generic packets 10,11 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
+               HDMI_GENERIC10_CONT, 0,
+               HDMI_GENERIC10_SEND, 0,
+               HDMI_GENERIC11_CONT, 0,
+               HDMI_GENERIC11_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, 0,
+               HDMI_GENERIC10_LINE, 0,
+               HDMI_GENERIC11_LINE, 0);
+
+       /* stop generic packets 12,13 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
+               HDMI_GENERIC12_CONT, 0,
+               HDMI_GENERIC12_SEND, 0,
+               HDMI_GENERIC13_CONT, 0,
+               HDMI_GENERIC13_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, 0,
+               HDMI_GENERIC12_LINE, 0,
+               HDMI_GENERIC13_LINE, 0);
+
+       /* stop generic packets 14 on HDMI */
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
+               HDMI_GENERIC14_CONT, 0,
+               HDMI_GENERIC14_SEND, 0);
+       REG_SET(HDMI_TB_ENC_GENERIC_PACKET14_LINE, 0,
+               HDMI_GENERIC14_LINE, 0);
+
+}
+
+//Covered both, rounding up or rounding down from FRL Link Rate /18.
+static const struct frl_audio_clock_info frl_audio_clock_info_table[10] = {
+       {166666, 4224, 171875, 5292, 156250, 5760, 156250},
+       {166667, 4224, 171875, 5292, 156250, 5760, 156250},
+       {333333, 4032, 328125, 5292, 312500, 6048, 328125},
+       {333334, 4032, 328125, 5292, 312500, 6048, 328125},
+       {444444, 4032, 437500, 3969, 312500, 6048, 437500},
+       {444445, 4032, 437500, 3969, 312500, 6048, 437500},
+       {555555, 3456, 468750, 3969, 390625, 5184, 468750},
+       {555556, 3456, 468750, 3969, 390625, 5184, 468750},
+       {666666, 3072, 500000, 3969, 468750, 4752, 515625},
+       {666667, 3072, 500000, 3969, 468750, 4752, 515625}
+};
+
+static void get_audio_clock_info(
+       enum dc_color_depth color_depth,
+       uint32_t frl_character_clock_kHz,
+       struct frl_audio_clock_info *audio_clock_info)
+{
+       (void)color_depth;
+       const struct frl_audio_clock_info *clock_info;
+       uint32_t index;
+       uint32_t audio_array_size;
+
+       clock_info = frl_audio_clock_info_table;
+       audio_array_size = ARRAY_SIZE(
+                       frl_audio_clock_info_table);
+
+       if (clock_info != NULL) {
+               /* search for exact frl character clock in table */
+               for (index = 0; index < audio_array_size; index++) {
+                       if (clock_info[index].frl_character_clock_kHz >
+                               frl_character_clock_kHz)
+                               break;  /* not match */
+                       else if (clock_info[index].frl_character_clock_kHz ==
+                                       frl_character_clock_kHz) {
+                               /* match found */
+                               *audio_clock_info = clock_info[index];
+                               return;
+                       }
+               }
+       }
+       /*Only 3, 6, 8, 10 and 12 Gbps are used for FRL Link rates with character
+        *clocks of 166.667, 333.333, 444.444, 555.555 and 666.667 MHz are used
+        *so entry should be found in above table if no bugs */
+       BREAK_TO_DEBUGGER();
+}
+
+void hpo_enc3_setup_hdmi_audio(
+       struct hpo_frl_stream_encoder *enc,
+       const struct audio_crtc_info *crtc_info)
+{
+       struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+       struct frl_audio_clock_info audio_clock_info = {0};
+
+       DC_LOG_DEBUG("Entering [%s]\n", __func__);
+
+       /* TODO:  HDMI_AUDIO_DELAY_EN bit only in DIG -- not in HPO? */
+       /* HDMI_AUDIO_PACKET_CONTROL */
+       //REG_UPDATE(HDMI_AUDIO_PACKET_CONTROL,
+       //              HDMI_AUDIO_DELAY_EN, 1);
+
+       /* Setup audio in AFMT - program AFMT block associated with HPO */
+       ASSERT (enc->afmt);
+       enc->afmt->funcs->setup_hdmi_audio(enc->afmt);
+
+       /* TODO: Same programming, but using HDMI_TB_ENC register */
+       /* HDMI_ACR_PACKET_CONTROL */
+       REG_UPDATE_3(HDMI_TB_ENC_ACR_PACKET_CONTROL,
+                       HDMI_ACR_AUTO_SEND, 1,
+                       HDMI_ACR_SOURCE, 0,
+                       HDMI_ACR_AUDIO_PRIORITY, 0);
+
+       /* N/CTS computed relative to FRL rate instead of video rate (TMDS character clock). */
+       /* Program audio clock sample/regeneration parameters */
+       get_audio_clock_info(crtc_info->color_depth,
+                            crtc_info->frl_character_clock_kHz,
+                            &audio_clock_info);
+       DC_LOG_HW_AUDIO(
+                       "\n%s:Input::requested_pixel_clock_100Hz = %d"  \
+                       "calculated_pixel_clock_100Hz = %d \n", __func__,       \
+                       crtc_info->requested_pixel_clock_100Hz,         \
+                       crtc_info->calculated_pixel_clock_100Hz);
+
+       /* Same register definition, but using HDMI_TB_ENC register */
+       /* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz);
+
+       /* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_32_1, HDMI_ACR_N_32, audio_clock_info.n_32khz);
+
+       /* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_44_0, HDMI_ACR_CTS_44, audio_clock_info.cts_44khz);
+
+       /* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_44_1, HDMI_ACR_N_44, audio_clock_info.n_44khz);
+
+       /* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_48_0, HDMI_ACR_CTS_48, audio_clock_info.cts_48khz);
+
+       /* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_48_1, HDMI_ACR_N_48, audio_clock_info.n_48khz);
+
+
+       /* TODO: HDMI_TB_ENC_ACR_PACKET_CONTROL::ACR_N_MULTIPLE
+        *       Same register definition, but using HDMI_TB_ENC register*/
+
+       /* Video driver cannot know in advance which sample rate will
+        * be used by HD Audio driver
+        * HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
+        * programmed below in interrupt callback
+        */
+       DC_LOG_DEBUG("Exiting [%s]\n", __func__);
+}
+
+void hpo_enc3_hdmi_audio_setup(
+       struct hpo_frl_stream_encoder *enc,
+       unsigned int az_inst,
+       struct audio_info *info,
+       struct audio_crtc_info *audio_crtc_info)
+{
+       hpo_enc3_setup_hdmi_audio(enc, audio_crtc_info);
+       ASSERT (enc->afmt);
+       enc->afmt->funcs->se_audio_setup(enc->afmt, az_inst, info);
+}
+
+void hpo_enc3_hdmi_audio_disable(
+       struct hpo_frl_stream_encoder *enc)
+{
+       ASSERT(enc->afmt);
+       if (enc->afmt->funcs->afmt_powerdown)
+               enc->afmt->funcs->afmt_powerdown(enc->afmt);
+}
+
+void hpo_enc3_audio_mute_control(
+       struct hpo_frl_stream_encoder *enc,
+       bool mute)
+{
+       ASSERT (enc->afmt);
+       enc->afmt->funcs->audio_mute_control(enc->afmt, mute);
+}
+
+void enc3_stream_encoder_set_avmute(
+       struct hpo_frl_stream_encoder *enc,
+       bool enable)
+{
+       struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+       unsigned int value = enable ? 1 : 0;
+
+       REG_UPDATE(HDMI_TB_ENC_GC_CONTROL, HDMI_GC_AVMUTE, value);
+}
+
+static enum frl_cap_chk_result frl_cap_chk_uncompressed(
+               struct hpo_frl_stream_encoder *enc,
+               struct frl_cap_chk_params *params,
+               struct frl_cap_chk_intermediates *inter)
+{
+       int res;
+       DC_FP_START();
+       res = frl_fpu_cap_chk_uncompressed(enc, params, inter);
+       DC_FP_END();
+       return res;
+}
+
+static enum frl_cap_chk_result frl_cap_chk_compressed(
+               struct hpo_frl_stream_encoder *enc,
+               struct frl_cap_chk_params *params,
+               struct frl_cap_chk_intermediates *inter)
+{
+       int res;
+       DC_FP_START();
+       res = frl_fpu_cap_chk_compressed(enc, params, inter);
+       DC_FP_END();
+       return res;
+}
+
+static bool hpo_enc3_frl_cap_chk(
+               struct hpo_frl_stream_encoder *enc,
+               struct frl_cap_chk_params *params)
+{
+       struct frl_cap_chk_intermediates   inter;
+       enum frl_cap_chk_result res;
+
+       if (params->compressed)
+               res = frl_cap_chk_compressed(enc, params, &inter);
+       else
+               res = frl_cap_chk_uncompressed(enc, params, &inter);
+
+       return (res == FRL_CAP_CHK_OK);
+}
+
+bool hpo_enc3_validate_hdmi_frl_output(
+       struct hpo_frl_stream_encoder *enc,
+       const struct dc_crtc_timing *timing,
+       const struct audio_check *audio,
+       struct dc_hdmi_frl_link_settings *frl_link_settings,
+       unsigned int dsc_max_rate)
+{
+       struct frl_cap_chk_params frl_params = {0};
+       bool frl_check_res = false;
+
+       /* Set inputs for FRL check */
+       frl_params.lanes = frl_link_settings->frl_num_lanes;
+       DC_FP_START();
+       hpo_fpu_enc3_validate_hdmi_frl_output_link(enc,
+                                                  frl_link_settings,
+                                                  &frl_params,
+                                                  timing,
+                                                  dsc_max_rate);
+       DC_FP_END();
+
+       if (timing->display_color_depth == COLOR_DEPTH_888)
+               frl_params.bpc = 8;
+       else if (timing->display_color_depth == COLOR_DEPTH_101010)
+               frl_params.bpc = 10;
+       else
+               frl_params.bpc = 12;
+
+       switch (timing->hdmi_vic) {
+       case 1:
+               frl_params.vic = 95;
+               break;
+       case 2:
+               frl_params.vic = 94;
+               break;
+       case 3:
+               frl_params.vic = 93;
+               break;
+       case 4:
+               frl_params.vic = 98;
+               break;
+       default:
+               break;
+       }
+       if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
+               frl_params.pixel_encoding = HDMI_FRL_PIXEL_ENCODING_420;
+       else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
+               frl_params.pixel_encoding = HDMI_FRL_PIXEL_ENCODING_422;
+       else
+               frl_params.pixel_encoding = HDMI_FRL_PIXEL_ENCODING_444;
+       /* Audio parameters */
+       /* TODO: set Audio parameters */
+
+       if (audio->audio_packet_type == 2) {
+               if (audio->max_channel_count <= 2
+                         || (timing->v_addressable + timing->v_border_top + timing->v_border_bottom) <= 576)
+                       frl_params.layout = 0;
+               else
+                       frl_params.layout = 1;
+
+       }
+
+       /* Check HDMI FRL Capacity and compute borrow parameters */
+       frl_check_res = hpo_enc3_frl_cap_chk(enc, &frl_params);
+       /* Save borrow parameters and average tribyte rate (for capture sideband) */
+       if (frl_check_res) {
+               frl_link_settings->borrow_params.audio_packets_line =
+                               frl_params.borrow_params.audio_packets_line;
+               frl_link_settings->borrow_params.hc_active_target =
+                               frl_params.borrow_params.hc_active_target;
+               frl_link_settings->borrow_params.hc_blank_target =
+                               frl_params.borrow_params.hc_blank_target;
+               frl_link_settings->borrow_params.borrow_mode =
+                               (unsigned int) frl_params.borrow_params.borrow_mode;
+               frl_link_settings->average_tribyte_rate = frl_params.average_tribyte_rate;
+       }
+
+       return frl_check_res;
+}
+
+void hpo_enc3_read_state(
+       struct hpo_frl_stream_encoder *enc,
+       struct hpo_frl_stream_encoder_state *state)
+{
+       int pixel_encoding;
+       int color_depth;
+       int odm_combine;
+       struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       ASSERT(state);
+
+       REG_GET(HDMI_TB_ENC_CONTROL,
+                       HDMI_TB_ENC_EN, &state->stream_enc_enabled);
+
+       REG_GET(HDMI_STREAM_ENC_INPUT_MUX_CONTROL,
+                       HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, &state->otg_inst);
+
+       REG_GET_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                       HDMI_PIXEL_ENCODING, &pixel_encoding,
+                       HDMI_DEEP_COLOR_DEPTH, &color_depth);
+
+       REG_GET(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                       FIFO_ODM_COMBINE_MODE, &odm_combine);
+
+       REG_GET_2(HDMI_TB_ENC_H_ACTIVE_BLANK,
+                       HDMI_H_ACTIVE, &state->h_active,
+                       HDMI_H_BLANK, &state->h_blank);
+
+       REG_GET(HDMI_TB_ENC_MODE,
+                       HDMI_BORROW_MODE, &state->borrow_mode);
+
+       if (pixel_encoding == 0)
+               state->pixel_format = PIXEL_ENCODING_YCBCR444;
+       else if (pixel_encoding == 1)
+               state->pixel_format = PIXEL_ENCODING_YCBCR422;
+       else
+               state->pixel_format = PIXEL_ENCODING_YCBCR420;
+
+       if (color_depth == 0)
+               state->color_depth = 8;
+       else if (color_depth == 1)
+               state->color_depth = 10;
+       else
+               state->color_depth = 12;
+
+       state->num_odm_segments = odm_combine + 1;
+}
+
+/* Set Dynamic Metadata-configuration.
+ *   enable_dme:         TRUE: enables Dynamic Metadata Enfine, FALSE: disables DME
+ *   hubp_requestor_id:  HUBP physical instance that is the source of dynamic metadata
+ *                       only needs to be set when enable_dme is TRUE
+ *   dmdata_mode:        dynamic metadata packet type: DP, HDMI, or Dolby Vision
+ *
+ *   Ensure the OTG master update lock is set when changing DME configuration.
+ */
+void hpo_enc3_set_dynamic_metadata(struct hpo_frl_stream_encoder *enc,
+       bool enable_dme,
+       uint32_t hubp_requestor_id,
+       enum dynamic_metadata_mode dmdata_mode)
+{
+       struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       if (enable_dme) {
+               REG_UPDATE_2(DME_CONTROL,
+                       METADATA_HUBP_REQUESTOR_ID, hubp_requestor_id,
+                       METADATA_STREAM_TYPE, (dmdata_mode == dmdata_dolby_vision) ? 1 : 0);
+
+               REG_UPDATE_3(HDMI_TB_ENC_METADATA_PACKET_CONTROL,
+                       HDMI_METADATA_PACKET_ENABLE, 1,
+                       HDMI_METADATA_PACKET_LINE_REFERENCE, 0,
+                       HDMI_METADATA_PACKET_LINE, 2);
+
+               REG_UPDATE(DME_CONTROL,
+                       METADATA_ENGINE_EN, 1);
+       } else {
+               REG_UPDATE(DME_CONTROL,
+                       METADATA_ENGINE_EN, 0);
+
+               REG_UPDATE(HDMI_TB_ENC_METADATA_PACKET_CONTROL,
+                       HDMI_METADATA_PACKET_ENABLE, 0);
+       }
+}
+
+static const struct hpo_frl_stream_encoder_funcs dcn30_str_enc_funcs = {
+       .hdmi_frl_enable                = hpo_enc3_enable,
+       .hdmi_frl_unblank               = hpo_enc3_unblank,
+       .hdmi_frl_blank                 = hpo_enc3_blank,
+       .hdmi_frl_set_stream_attribute  = hpo_enc3_set_hdmi_stream_attribute,
+       .update_hdmi_info_packets       = hpo_enc3_update_hdmi_info_packets,
+       .stop_hdmi_info_packets         = hpo_enc3_stop_hdmi_info_packets,
+       .audio_mute_control             = hpo_enc3_audio_mute_control,
+       .hdmi_audio_setup               = hpo_enc3_hdmi_audio_setup,
+       .hdmi_audio_disable             = hpo_enc3_hdmi_audio_disable,
+       .set_avmute                     = enc3_stream_encoder_set_avmute,
+       .validate_hdmi_frl_output       = hpo_enc3_validate_hdmi_frl_output,
+       .read_state                     = hpo_enc3_read_state,
+       .set_dynamic_metadata           = hpo_enc3_set_dynamic_metadata,
+       .hdmi_frl_fifo_odm_enabled = hpo_enc3_fifo_odm_enabled,
+};
+
+void dcn30_hpo_frl_stream_encoder_construct(
+       struct dcn30_hpo_frl_stream_encoder *enc3,
+       struct dc_context *ctx,
+       struct dc_bios *bp,
+       enum engine_id eng_id,
+       struct vpg *vpg,
+       struct afmt *afmt,
+       const struct dcn30_hpo_frl_stream_enc_registers *regs,
+       const struct dcn30_hpo_frl_stream_encoder_shift *hpo_se_shift,
+       const struct dcn30_hpo_frl_stream_encoder_mask *hpo_se_mask)
+{
+       enc3->base.funcs = &dcn30_str_enc_funcs;
+       enc3->base.ctx = ctx;
+       enc3->base.id = eng_id;
+       enc3->base.bp = bp;
+       enc3->base.vpg = vpg;
+       enc3->base.afmt = afmt;
+       enc3->regs = regs;
+       enc3->hpo_se_shift = hpo_se_shift;
+       enc3->hpo_se_mask = hpo_se_mask;
+       enc3->base.stream_enc_inst = vpg->inst;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.h
new file mode 100644 (file)
index 0000000..c00be85
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __DC_HPO_FRL_STREAM_ENCODER_DCN30_H__
+#define __DC_HPO_FRL_STREAM_ENCODER_DCN30_H__
+
+#include "dcn30/dcn30_vpg.h"
+#include "dcn30/dcn30_afmt.h"
+#include "stream_encoder.h"
+#include "dml/dml1_frl_cap_chk.h"
+
+#define DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(hpo_frl_stream_encoder)\
+       container_of(hpo_frl_stream_encoder, struct dcn30_hpo_frl_stream_encoder, base)
+
+#define SE_SF(reg_name, field_name, post_fix)\
+       .field_name = reg_name ## __ ## field_name ## post_fix
+
+#define DCN3_0_HDMI_STREAM_ENC_REG_LIST \
+       SR(HDMI_STREAM_ENC_CLOCK_CONTROL), \
+       SR(HDMI_STREAM_ENC_INPUT_MUX_CONTROL), \
+       SR(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0), \
+       SR(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2)
+
+#define DCN3_0_HDMI_TB_ENC_REG_LIST \
+       SR(HDMI_TB_ENC_CONTROL), \
+       SR(HDMI_TB_ENC_H_ACTIVE_BLANK), \
+       SR(HDMI_TB_ENC_HC_ACTIVE_BLANK), \
+       SR(HDMI_TB_ENC_MODE), \
+       SR(HDMI_TB_ENC_PACKET_CONTROL), \
+       SR(HDMI_TB_ENC_DB_CONTROL), \
+       SR(HDMI_TB_ENC_PIXEL_FORMAT), \
+       SR(HDMI_TB_ENC_VBI_PACKET_CONTROL1), \
+       SR(HDMI_TB_ENC_GC_CONTROL), \
+       SR(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0), \
+       SR(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1), \
+       SR(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE), \
+       SR(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE), \
+       SR(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE), \
+       SR(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE), \
+       SR(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE), \
+       SR(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE), \
+       SR(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE), \
+       SR(HDMI_TB_ENC_GENERIC_PACKET14_LINE), \
+       SR(HDMI_TB_ENC_ACR_PACKET_CONTROL), \
+       SR(HDMI_TB_ENC_ACR_32_0), \
+       SR(HDMI_TB_ENC_ACR_32_1), \
+       SR(HDMI_TB_ENC_ACR_44_0), \
+       SR(HDMI_TB_ENC_ACR_44_1), \
+       SR(HDMI_TB_ENC_ACR_48_0), \
+       SR(HDMI_TB_ENC_ACR_48_1), \
+       SR(HDMI_TB_ENC_CRC_CNTL),\
+       SR(HDMI_TB_ENC_METADATA_PACKET_CONTROL)
+
+#define DCN3_0_HPO_FRL_STREAM_ENC_REG_LIST(id) \
+       DCN3_0_HDMI_STREAM_ENC_REG_LIST, \
+       DCN3_0_HDMI_TB_ENC_REG_LIST
+
+#define DCN3_0_HPO_STREAM_ENC_DME_REG_LIST(id, offset) \
+       [id - offset]SRI(DME_CONTROL, DME, id)
+
+
+struct dcn30_hpo_frl_stream_enc_registers {
+       uint32_t HDMI_STREAM_ENC_CLOCK_CONTROL;
+       uint32_t HDMI_STREAM_ENC_INPUT_MUX_CONTROL;
+       uint32_t HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0;
+       uint32_t HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2;
+       uint32_t HDMI_STREAM_ENC_AUDIO_CONTROL;
+       uint32_t HDMI_TB_ENC_CONTROL;
+       uint32_t HDMI_TB_ENC_MODE;
+       uint32_t HDMI_TB_ENC_H_ACTIVE_BLANK;
+       uint32_t HDMI_TB_ENC_HC_ACTIVE_BLANK;
+       uint32_t HDMI_TB_ENC_PACKET_CONTROL;
+       uint32_t HDMI_TB_ENC_DB_CONTROL;
+       uint32_t HDMI_TB_ENC_PIXEL_FORMAT;
+       uint32_t HDMI_TB_ENC_VBI_PACKET_CONTROL1;
+       uint32_t HDMI_TB_ENC_GC_CONTROL;
+       uint32_t HDMI_TB_ENC_GENERIC_PACKET_CONTROL0;
+       uint32_t HDMI_TB_ENC_GENERIC_PACKET_CONTROL1;
+       uint32_t HDMI_TB_ENC_GENERIC_PACKET0_1_LINE;
+       uint32_t HDMI_TB_ENC_GENERIC_PACKET2_3_LINE;
+       uint32_t HDMI_TB_ENC_GENERIC_PACKET4_5_LINE;
+       uint32_t HDMI_TB_ENC_GENERIC_PACKET6_7_LINE;
+       uint32_t HDMI_TB_ENC_GENERIC_PACKET8_9_LINE;
+       uint32_t HDMI_TB_ENC_GENERIC_PACKET10_11_LINE;
+       uint32_t HDMI_TB_ENC_GENERIC_PACKET12_13_LINE;
+       uint32_t HDMI_TB_ENC_GENERIC_PACKET14_LINE;
+       uint32_t HDMI_TB_ENC_ACR_PACKET_CONTROL;
+       uint32_t HDMI_TB_ENC_ACR_32_0;
+       uint32_t HDMI_TB_ENC_ACR_32_1;
+       uint32_t HDMI_TB_ENC_ACR_44_0;
+       uint32_t HDMI_TB_ENC_ACR_44_1;
+       uint32_t HDMI_TB_ENC_ACR_48_0;
+       uint32_t HDMI_TB_ENC_ACR_48_1;
+       uint32_t HDMI_TB_ENC_CRC_CNTL;
+       uint32_t DME_CONTROL;
+       uint32_t HDMI_TB_ENC_METADATA_PACKET_CONTROL;
+       uint32_t HDMI_TB_ENC_MEM_CTRL;
+       uint32_t HDMI_FRL_ENC_MEM_CTRL;
+};
+
+#define DCN3_0_HDMI_STREAM_ENC_MASK_SH_LIST(mask_sh)\
+       SE_SF(HDMI_STREAM_ENC_INPUT_MUX_CONTROL, HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_ENABLE, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_PIXEL_ENCODING, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_CONTROL, HDMI_STREAM_ENC_CLOCK_EN, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_ODM_COMBINE_MODE, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_DSC_MODE, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2, FIFO_DB_DISABLE, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2, FIFO_DB_DISABLE, mask_sh),\
+       SE_SF(DME0_DME_CONTROL, METADATA_HUBP_REQUESTOR_ID, mask_sh),\
+       SE_SF(DME0_DME_CONTROL, METADATA_ENGINE_EN, mask_sh),\
+       SE_SF(DME0_DME_CONTROL, METADATA_STREAM_TYPE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_MEM_CTRL, BORROWBUFFER_MEM_PWR_DIS, mask_sh),\
+       SE_SF(HDMI_TB_ENC_MEM_CTRL, BORROWBUFFER_MEM_PWR_FORCE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_MEM_CTRL, BORROWBUFFER_MEM_PWR_STATE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_MEM_CTRL, BORROWBUFFER_MEM_DEFAULT_MEM_LOW_POWER_STATE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_ENABLE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE_REFERENCE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_MISSED, mask_sh),\
+       SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE, mask_sh)
+
+#define DCN3_0_HDMI_TB_ENC_MASK_SH_LIST(mask_sh)\
+       SE_SF(HDMI_TB_ENC_CONTROL, HDMI_TB_ENC_EN, mask_sh),\
+       SE_SF(HDMI_TB_ENC_CONTROL, HDMI_RESET, mask_sh),\
+       SE_SF(HDMI_TB_ENC_CONTROL, HDMI_RESET_DONE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_MODE, HDMI_BORROW_MODE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_H_ACTIVE_BLANK, HDMI_H_ACTIVE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_H_ACTIVE_BLANK, HDMI_H_BLANK, mask_sh),\
+       SE_SF(HDMI_TB_ENC_HC_ACTIVE_BLANK, HDMI_HC_ACTIVE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_HC_ACTIVE_BLANK, HDMI_HC_BLANK, mask_sh),\
+       SE_SF(HDMI_TB_ENC_PACKET_CONTROL, HDMI_MAX_PACKETS_PER_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_DB_CONTROL, HDMI_DB_DISABLE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_PIXEL_ENCODING, mask_sh),\
+       SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DEEP_COLOR_DEPTH, mask_sh),\
+       SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DEEP_COLOR_ENABLE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DSC_MODE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_GC_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_GC_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_ACP_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GC_CONTROL, HDMI_GC_AVMUTE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC8_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC9_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC10_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC11_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC12_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC13_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC14_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC8_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC9_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC10_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC11_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC12_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC13_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC14_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, HDMI_GENERIC0_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, HDMI_GENERIC1_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, HDMI_GENERIC2_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, HDMI_GENERIC3_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, HDMI_GENERIC4_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, HDMI_GENERIC5_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, HDMI_GENERIC6_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, HDMI_GENERIC7_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, HDMI_GENERIC8_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, HDMI_GENERIC9_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, HDMI_GENERIC10_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, HDMI_GENERIC11_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, HDMI_GENERIC12_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, HDMI_GENERIC13_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET14_LINE, HDMI_GENERIC14_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_AUTO_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_SOURCE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_AUDIO_PRIORITY, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_32_0, HDMI_ACR_CTS_32, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_32_1, HDMI_ACR_N_32, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_44_0, HDMI_ACR_CTS_44, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_44_1, HDMI_ACR_N_44, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_48_0, HDMI_ACR_CTS_48, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_48_1, HDMI_ACR_N_48, mask_sh),\
+       SE_SF(HDMI_TB_ENC_CRC_CNTL, HDMI_CRC_EN, mask_sh),\
+       SE_SF(HDMI_TB_ENC_CRC_CNTL, HDMI_CRC_CONT_EN, mask_sh)
+
+#define DCN3_0_HPO_STREAM_ENC_MASK_SH_LIST(mask_sh)\
+       DCN3_0_HDMI_STREAM_ENC_MASK_SH_LIST(mask_sh),\
+       DCN3_0_HDMI_TB_ENC_MASK_SH_LIST(mask_sh)
+
+
+
+
+#define DCN3_HDMI_TB_ENC_REG_FIELD_LIST(type) \
+       type HDMI_TB_ENC_EN;\
+       type HDMI_RESET;\
+       type HDMI_RESET_DONE;\
+       type HDMI_STREAM_ENC_CLOCK_EN;\
+       type HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL;\
+       type HDMI_MAX_PACKETS_PER_LINE;\
+       type FIFO_ENABLE;\
+       type FIFO_RESET;\
+       type FIFO_RESET_DONE;\
+       type FIFO_PIXEL_ENCODING;\
+       type FIFO_ODM_COMBINE_MODE;\
+       type FIFO_DSC_MODE;\
+       type FIFO_DB_DISABLE;\
+       type HDMI_BORROW_MODE;\
+       type HDMI_H_ACTIVE;\
+       type HDMI_H_BLANK;\
+       type HDMI_HC_ACTIVE;\
+       type HDMI_HC_BLANK;\
+       type HDMI_DB_DISABLE;\
+       type HDMI_PIXEL_ENCODING;\
+       type HDMI_DEEP_COLOR_DEPTH;\
+       type HDMI_DEEP_COLOR_ENABLE;\
+       type HDMI_ODM_COMBINE_MODE;\
+       type HDMI_DSC_MODE;\
+       type HDMI_GC_CONT;\
+       type HDMI_GC_SEND;\
+       type HDMI_ACP_SEND;\
+       type HDMI_AUDIO_INFO_SEND;\
+       type HDMI_AUDIO_INFO_LINE;\
+       type HDMI_GC_AVMUTE;\
+       type HDMI_GENERIC0_CONT;\
+       type HDMI_GENERIC0_SEND;\
+       type HDMI_GENERIC0_LINE;\
+       type HDMI_GENERIC1_CONT;\
+       type HDMI_GENERIC1_SEND;\
+       type HDMI_GENERIC1_LINE;\
+       type HDMI_GENERIC2_CONT;\
+       type HDMI_GENERIC2_SEND;\
+       type HDMI_GENERIC2_LINE;\
+       type HDMI_GENERIC3_CONT;\
+       type HDMI_GENERIC3_SEND;\
+       type HDMI_GENERIC3_LINE;\
+       type HDMI_GENERIC4_CONT;\
+       type HDMI_GENERIC4_SEND;\
+       type HDMI_GENERIC4_LINE;\
+       type HDMI_GENERIC5_CONT;\
+       type HDMI_GENERIC5_SEND;\
+       type HDMI_GENERIC5_LINE;\
+       type HDMI_GENERIC6_CONT;\
+       type HDMI_GENERIC6_SEND;\
+       type HDMI_GENERIC6_LINE;\
+       type HDMI_GENERIC7_CONT;\
+       type HDMI_GENERIC7_SEND;\
+       type HDMI_GENERIC7_LINE;\
+       type HDMI_GENERIC8_CONT;\
+       type HDMI_GENERIC8_SEND;\
+       type HDMI_GENERIC8_LINE;\
+       type HDMI_GENERIC9_CONT;\
+       type HDMI_GENERIC9_SEND;\
+       type HDMI_GENERIC9_LINE;\
+       type HDMI_GENERIC10_CONT;\
+       type HDMI_GENERIC10_SEND;\
+       type HDMI_GENERIC10_LINE;\
+       type HDMI_GENERIC11_CONT;\
+       type HDMI_GENERIC11_SEND;\
+       type HDMI_GENERIC11_LINE;\
+       type HDMI_GENERIC12_CONT;\
+       type HDMI_GENERIC12_SEND;\
+       type HDMI_GENERIC12_LINE;\
+       type HDMI_GENERIC13_CONT;\
+       type HDMI_GENERIC13_SEND;\
+       type HDMI_GENERIC13_LINE;\
+       type HDMI_GENERIC14_CONT;\
+       type HDMI_GENERIC14_SEND;\
+       type HDMI_GENERIC14_LINE;\
+       type HDMI_ACR_AUTO_SEND;\
+       type HDMI_ACR_SOURCE;\
+       type HDMI_ACR_AUDIO_PRIORITY;\
+       type HDMI_ACR_CTS_32;\
+       type HDMI_ACR_N_32;\
+       type HDMI_ACR_CTS_44;\
+       type HDMI_ACR_N_44;\
+       type HDMI_ACR_CTS_48;\
+       type HDMI_ACR_N_48;\
+       type HDMI_CRC_EN;\
+       type HDMI_CRC_CONT_EN;\
+       type METADATA_HUBP_REQUESTOR_ID;\
+       type METADATA_ENGINE_EN;\
+       type METADATA_STREAM_TYPE;\
+       type HDMI_METADATA_PACKET_ENABLE;\
+       type HDMI_METADATA_PACKET_LINE_REFERENCE;\
+       type HDMI_METADATA_PACKET_MISSED;\
+       type HDMI_METADATA_PACKET_LINE;\
+       type BORROWBUFFER_MEM_PWR_DIS;\
+       type BORROWBUFFER_MEM_PWR_FORCE;\
+       type BORROWBUFFER_MEM_PWR_STATE;\
+       type BORROWBUFFER_MEM_DEFAULT_MEM_LOW_POWER_STATE
+
+
+struct dcn30_hpo_frl_stream_encoder_shift {
+       DCN3_HDMI_TB_ENC_REG_FIELD_LIST(uint8_t);
+};
+
+struct dcn30_hpo_frl_stream_encoder_mask {
+       DCN3_HDMI_TB_ENC_REG_FIELD_LIST(uint32_t);
+};
+
+struct dcn30_hpo_frl_stream_encoder {
+       struct hpo_frl_stream_encoder base;
+       const struct dcn30_hpo_frl_stream_enc_registers *regs;
+       const struct dcn30_hpo_frl_stream_encoder_shift *hpo_se_shift;
+       const struct dcn30_hpo_frl_stream_encoder_mask *hpo_se_mask;
+};
+
+void hpo_enc3_enable(
+       struct hpo_frl_stream_encoder *enc,
+       int otg_inst);
+
+void hpo_enc3_unblank(
+       struct hpo_frl_stream_encoder *enc,
+       int otg_inst);
+
+void hpo_enc3_read_state(
+       struct hpo_frl_stream_encoder *enc,
+       struct hpo_frl_stream_encoder_state *state);
+
+bool hpo_enc3_fifo_odm_enabled(
+       struct hpo_frl_stream_encoder *enc);
+
+void hpo_enc3_blank(
+       struct hpo_frl_stream_encoder *enc);
+
+void hpo_enc3_set_hdmi_stream_attribute(
+       struct hpo_frl_stream_encoder *enc,
+       struct dc_crtc_timing *crtc_timing,
+       struct frl_borrow_params *borrow_params,
+       int odm_combine_num_segments);
+
+void hpo_enc3_update_hdmi_info_packet(
+       struct dcn30_hpo_frl_stream_encoder *enc3,
+       uint32_t packet_index,
+       const struct dc_info_packet *info_packet);
+
+void hpo_enc3_update_hdmi_info_packets(
+       struct hpo_frl_stream_encoder *enc,
+       const struct encoder_info_frame *info_frame);
+
+void hpo_enc3_hdmi_set_dsc_config(
+       struct hpo_frl_stream_encoder *enc,
+       struct dc_crtc_timing *timing,
+       uint8_t *dsc_packed_pps);
+
+void hpo_enc3_stop_hdmi_info_packets(
+       struct hpo_frl_stream_encoder *enc);
+
+void hpo_enc3_setup_hdmi_audio(
+       struct hpo_frl_stream_encoder *enc,
+       const struct audio_crtc_info *crtc_info);
+
+void hpo_enc3_hdmi_audio_setup(
+       struct hpo_frl_stream_encoder *enc,
+       unsigned int az_inst,
+       struct audio_info *info,
+       struct audio_crtc_info *audio_crtc_info);
+
+void hpo_enc3_hdmi_audio_disable(
+       struct hpo_frl_stream_encoder *enc);
+
+void hpo_enc3_audio_mute_control(
+       struct hpo_frl_stream_encoder *enc,
+       bool mute);
+
+void enc3_stream_encoder_set_avmute(
+       struct hpo_frl_stream_encoder *enc,
+       bool enable);
+
+bool hpo_enc3_validate_hdmi_frl_output(
+       struct hpo_frl_stream_encoder *enc,
+       const struct dc_crtc_timing *timing,
+       const struct audio_check *audio,
+       struct dc_hdmi_frl_link_settings *frl_link_settings,
+       unsigned int dsc_max_rate);
+
+void hpo_enc3_set_dynamic_metadata(
+       struct hpo_frl_stream_encoder *enc,
+       bool enable_dme,
+       uint32_t hubp_requestor_id,
+       enum dynamic_metadata_mode dmdata_mode);
+
+void dcn30_hpo_frl_stream_encoder_construct(
+       struct dcn30_hpo_frl_stream_encoder *enc3,
+       struct dc_context *ctx,
+       struct dc_bios *bp,
+       enum engine_id eng_id,
+       struct vpg *vpg,
+       struct afmt *afmt,
+       const struct dcn30_hpo_frl_stream_enc_registers *regs,
+       const struct dcn30_hpo_frl_stream_encoder_shift *hpo_se_shift,
+       const struct dcn30_hpo_frl_stream_encoder_mask *hpo_se_mask);
+
+void convert_dc_info_packet_to_128(
+       const struct dc_info_packet *info_packet,
+       struct dc_info_packet_128 *info_packet_128);
+
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c
new file mode 100644 (file)
index 0000000..27f7ffd
--- /dev/null
@@ -0,0 +1,906 @@
+/*
+ * 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 "core_types.h"
+#include "dcn401_hpo_frl_stream_encoder.h"
+#include "dcn30/dcn30_hpo_frl_stream_encoder.h"
+#include "reg_helper.h"
+#include "hw_shared.h"
+#include "dcn_calc_math.h"
+#include "dml/dcn30/dcn30_fpu.h"
+
+#undef DC_LOGGER
+#define DC_LOGGER \
+               enc401->base.ctx->logger
+
+#define DTRACE(str, ...) {DC_LOG_HDMI_FRL(str, ##__VA_ARGS__); }
+
+#define DEBUG_FRL_CAP_CHK 1
+
+#define REG(reg)\
+       (enc401->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) \
+       enc401->hpo_se_shift->field_name, enc401->hpo_se_mask->field_name
+
+
+#define CTX \
+       enc401->base.ctx
+
+
+#define VBI_LINE_0 0
+
+void hpo_enc401_enable(
+       struct hpo_frl_stream_encoder *enc,
+       int otg_inst)
+{
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       DC_LOG_DEBUG("Entering [%s]\n", __func__);
+
+       /* Enable DISPCLK, SOCCLK, and HDMISTREAMCLK */
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_CONTROL, HDMI_STREAM_ENC_CLOCK_EN, 1);
+
+       /* Reset */
+       REG_UPDATE_2(HDMI_TB_ENC_CONTROL,
+                       HDMI_RESET, 1,
+                       HDMI_TB_ENC_EN, 0);
+       REG_WAIT(HDMI_TB_ENC_CONTROL, HDMI_RESET_DONE,
+                       1, 10, 100);
+       REG_UPDATE(HDMI_TB_ENC_CONTROL,
+                       HDMI_RESET, 0);
+
+       /* FOR DEBUG:  enable CRC */
+       REG_UPDATE_2(HDMI_TB_ENC_CRC_CNTL,
+                       HDMI_CRC_EN, 1,
+                       HDMI_CRC_CONT_EN, 1);
+
+//     REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2, FIFO_DB_DISABLE, 1);
+       /* TODO: confirm if need to set HDMI_DB_DISABLE -- HW team only setting FIFO_DB_DISABLE */
+       REG_UPDATE(HDMI_TB_ENC_DB_CONTROL, HDMI_DB_DISABLE, 1);
+
+       /* Set the input mux to select OTG source */
+       REG_UPDATE(HDMI_STREAM_ENC_INPUT_MUX_CONTROL, HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, otg_inst);
+
+       DC_LOG_DEBUG("Exiting [%s]\n", __func__);
+}
+
+void hpo_enc401_unblank(struct hpo_frl_stream_encoder *enc, int otg_inst)
+{
+       (void)otg_inst;
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
+
+       /*make sure FIFO_VIDEO_STREAM_ACTIVE =1*/
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_ENABLE, 0);
+
+       /* Reset */
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_RESET, 1);
+       REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
+                1, 10, 1000);
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_RESET, 0);
+       REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
+                0, 10, 1000);
+
+       /* Enable HDMI Tribyte Encoder */
+       REG_UPDATE(HDMI_TB_ENC_CONTROL,
+                  HDMI_TB_ENC_EN, 1);
+
+       /* Enable Clock Ramp Adjuster FIFO */
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_ENABLE, 1);
+
+       DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
+}
+
+void hpo_enc401_blank(struct hpo_frl_stream_encoder *enc)
+{
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       /* Disable Clock Ramp Adjuster FIFO */
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_ENABLE, 0);
+
+       /* Disable HDMI Tribyte Encoder */
+       REG_UPDATE(HDMI_TB_ENC_CONTROL,
+                  HDMI_TB_ENC_EN, 0);
+
+       /* Disable DISPCLK, SOCCLK, and HDMISTREAMCLK */
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_CONTROL,
+                  HDMI_STREAM_ENC_CLOCK_EN, 0);
+}
+
+void hpo_enc401_read_state(
+       struct hpo_frl_stream_encoder *enc,
+       struct hpo_frl_stream_encoder_state *state)
+{
+       int pixel_encoding;
+       int color_depth;
+//     int odm_combine;
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       ASSERT(state);
+
+       REG_GET(HDMI_TB_ENC_CONTROL,
+                       HDMI_TB_ENC_EN, &state->stream_enc_enabled);
+
+       REG_GET(HDMI_STREAM_ENC_INPUT_MUX_CONTROL,
+                       HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, &state->otg_inst);
+
+       REG_GET_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                       HDMI_PIXEL_ENCODING, &pixel_encoding,
+                       HDMI_DEEP_COLOR_DEPTH, &color_depth);
+
+//     REG_GET(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+       //              FIFO_ODM_COMBINE_MODE, &odm_combine);
+
+       REG_GET_2(HDMI_TB_ENC_H_ACTIVE_BLANK,
+                       HDMI_H_ACTIVE, &state->h_active,
+                       HDMI_H_BLANK, &state->h_blank);
+
+       REG_GET(HDMI_TB_ENC_MODE,
+                       HDMI_BORROW_MODE, &state->borrow_mode);
+
+       if (pixel_encoding == 0)
+               state->pixel_format = PIXEL_ENCODING_YCBCR444;
+       else if (pixel_encoding == 1)
+               state->pixel_format = PIXEL_ENCODING_YCBCR422;
+       else
+               state->pixel_format = PIXEL_ENCODING_YCBCR420;
+
+       if (color_depth == 0)
+               state->color_depth = 8;
+       else if (color_depth == 1)
+               state->color_depth = 10;
+       else
+               state->color_depth = 12;
+
+//     state->num_odm_segments = odm_combine + 1;
+}
+
+/* setup stream encoder in hdmi mode */
+/* Precondition: link is trained */
+void hpo_enc401_set_hdmi_stream_attribute(
+       struct hpo_frl_stream_encoder *enc,
+       struct dc_crtc_timing *crtc_timing,
+       struct frl_borrow_params *borrow_params,
+       int odm_combine_num_segments)
+{
+       (void)odm_combine_num_segments;
+       uint32_t h_active;
+       uint32_t h_blank;
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       DC_LOG_DEBUG("Entering [%s]\n", __func__);
+
+       /* Configure pixel encoding */
+       switch (crtc_timing->pixel_encoding) {
+       case PIXEL_ENCODING_YCBCR422:
+               REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
+                               HDMI_PIXEL_ENCODING, 1);
+               REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                               FIFO_UNCOMPRESSED_PIXEL_FORMAT, 0);
+               break;
+       case PIXEL_ENCODING_YCBCR420:
+               REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
+                               HDMI_PIXEL_ENCODING, 2);
+               REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                               FIFO_UNCOMPRESSED_PIXEL_FORMAT, 1);
+               break;
+       default:
+               REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
+                               HDMI_PIXEL_ENCODING, 0);
+               REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                               FIFO_UNCOMPRESSED_PIXEL_FORMAT, 0);
+               break;
+       }
+
+       /* Configure color depth */
+       switch (crtc_timing->display_color_depth) {
+       case COLOR_DEPTH_888:
+               REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                               HDMI_DEEP_COLOR_DEPTH, 0,
+                               HDMI_DEEP_COLOR_ENABLE, 0);
+               break;
+       case COLOR_DEPTH_101010:
+               if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+                       REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                                       HDMI_DEEP_COLOR_DEPTH, 1,
+                                       HDMI_DEEP_COLOR_ENABLE, 0);
+               } else {
+                       REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                                       HDMI_DEEP_COLOR_DEPTH, 1,
+                                       HDMI_DEEP_COLOR_ENABLE, 1);
+               }
+               break;
+       case COLOR_DEPTH_121212:
+               if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+                       REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                                       HDMI_DEEP_COLOR_DEPTH, 2,
+                                       HDMI_DEEP_COLOR_ENABLE, 0);
+               } else {
+                       REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                                       HDMI_DEEP_COLOR_DEPTH, 2,
+                                       HDMI_DEEP_COLOR_ENABLE, 1);
+               }
+               break;
+       default:
+               break;
+       }
+
+       /* When compression active, CD/PP/Phase field shall be zero in GCP */
+       if (crtc_timing->flags.DSC) {
+               REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+                               HDMI_DEEP_COLOR_DEPTH, 0,
+                               HDMI_DEEP_COLOR_ENABLE, 0);
+       }
+
+       /* Configure horizontal active and blank size */
+       h_active = crtc_timing->h_addressable + crtc_timing->h_border_left + crtc_timing->h_border_right;
+       h_blank = crtc_timing->h_total - h_active;
+
+       if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 ||
+                       crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+               h_active /= 2;
+               h_blank /= 2;
+       }
+
+
+       REG_SET_2(HDMI_TB_ENC_H_ACTIVE_BLANK, 0,
+                       HDMI_H_ACTIVE, h_active,
+                       HDMI_H_BLANK, h_blank);
+
+       /* Configure borrow parameters */
+       REG_UPDATE(HDMI_TB_ENC_MODE,
+                       HDMI_BORROW_MODE, borrow_params->borrow_mode);
+       REG_UPDATE(HDMI_TB_ENC_PACKET_CONTROL,
+                       HDMI_MAX_PACKETS_PER_LINE, borrow_params->audio_packets_line);
+       REG_SET_2(HDMI_TB_ENC_HC_ACTIVE_BLANK, 0,
+                       HDMI_HC_ACTIVE, borrow_params->hc_active_target,
+                       HDMI_HC_BLANK, borrow_params->hc_blank_target);
+
+       /* Enable transmission of General Control packet on every frame */
+       REG_UPDATE_2(HDMI_TB_ENC_VBI_PACKET_CONTROL1,
+               HDMI_GC_CONT, 1,
+               HDMI_GC_SEND, 1);
+
+       /* Disable Audio Content Protection packet transmission */
+       /* TODO: review if this needs to be here */
+       REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_ACP_SEND, 0);
+
+
+       /* Enable Audio InfoFrame packet transmission. */
+       REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_SEND, 1);
+
+       /* update double-buffered AUDIO_INFO registers immediately */
+       if (enc->afmt && enc->afmt->funcs->audio_info_immediate_update)
+               enc->afmt->funcs->audio_info_immediate_update(enc->afmt);
+
+       /* Select line number on which to send Audio InfoFrame packets */
+       REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_LINE,
+                               VBI_LINE_0 + 2);
+
+       /* set HDMI GC AVMUTE */
+       REG_UPDATE(HDMI_TB_ENC_GC_CONTROL, HDMI_GC_AVMUTE, 0);
+
+       DC_LOG_DEBUG("Exiting [%s]\n", __func__);
+}
+
+void hpo_enc401_update_hdmi_info_packet(
+       struct dcn401_hpo_frl_stream_encoder *enc401,
+       uint32_t packet_index,
+       const struct dc_info_packet *info_packet)
+{
+       uint32_t cont, send, line;
+
+       if (info_packet->valid) {
+               enc401->base.vpg->funcs->update_generic_info_packet(
+                               enc401->base.vpg,
+                               packet_index,
+                               info_packet,
+                               true);
+
+               /* enable transmission of packet(s) -
+                * packet transmission begins on the next frame
+                */
+               cont = 1;
+               /* send packet(s) every frame */
+               send = 1;
+               /* select line number to send packets on */
+               /* TODO: check if line 2 is correct */
+               line = 2;
+       } else {
+               cont = 0;
+               send = 0;
+               line = 0;
+       }
+
+       /* TODO: set bit to indicate if packet is Extended Metadata Packet. */
+       /* TODO: In DCN3, there are 0-14 generic packets */
+
+       /* choose which generic packet control to use */
+       switch (packet_index) {
+       case 0:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                               HDMI_GENERIC0_CONT, cont,
+                               HDMI_GENERIC0_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE,
+                               HDMI_GENERIC0_LINE, line);
+               break;
+       case 1:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                               HDMI_GENERIC1_CONT, cont,
+                               HDMI_GENERIC1_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE,
+                               HDMI_GENERIC1_LINE, line);
+               break;
+       case 2:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                               HDMI_GENERIC2_CONT, cont,
+                               HDMI_GENERIC2_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE,
+                               HDMI_GENERIC2_LINE, line);
+               break;
+       case 3:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                               HDMI_GENERIC3_CONT, cont,
+                               HDMI_GENERIC3_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE,
+                               HDMI_GENERIC3_LINE, line);
+               break;
+       case 4:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                               HDMI_GENERIC4_CONT, cont,
+                               HDMI_GENERIC4_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE,
+                               HDMI_GENERIC4_LINE, line);
+               break;
+       case 5:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                               HDMI_GENERIC5_CONT, cont,
+                               HDMI_GENERIC5_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE,
+                               HDMI_GENERIC5_LINE, line);
+               break;
+       case 6:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                               HDMI_GENERIC6_CONT, cont,
+                               HDMI_GENERIC6_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE,
+                               HDMI_GENERIC6_LINE, line);
+               break;
+       case 7:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
+                               HDMI_GENERIC7_CONT, cont,
+                               HDMI_GENERIC7_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE,
+                               HDMI_GENERIC7_LINE, line);
+               break;
+       case 8:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                               HDMI_GENERIC8_CONT, cont,
+                               HDMI_GENERIC8_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE,
+                               HDMI_GENERIC8_LINE, line);
+               break;
+       case 9:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                               HDMI_GENERIC9_CONT, cont,
+                               HDMI_GENERIC9_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE,
+                               HDMI_GENERIC9_LINE, line);
+               break;
+       case 10:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                               HDMI_GENERIC10_CONT, cont,
+                               HDMI_GENERIC10_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE,
+                               HDMI_GENERIC10_LINE, line);
+               break;
+       case 11:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                               HDMI_GENERIC11_CONT, cont,
+                               HDMI_GENERIC11_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE,
+                               HDMI_GENERIC11_LINE, line);
+               break;
+       case 12:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                               HDMI_GENERIC12_CONT, cont,
+                               HDMI_GENERIC12_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE,
+                               HDMI_GENERIC12_LINE, line);
+               break;
+       case 13:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                               HDMI_GENERIC13_CONT, cont,
+                               HDMI_GENERIC13_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE,
+                               HDMI_GENERIC13_LINE, line);
+               break;
+       case 14:
+               REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
+                               HDMI_GENERIC14_CONT, cont,
+                               HDMI_GENERIC14_SEND, send);
+               REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET14_LINE,
+                               HDMI_GENERIC14_LINE, line);
+               break;
+       default:
+               /* invalid HW packet index */
+               DC_LOG_WARNING(
+                       "Invalid HW packet index: %s()\n",
+                       __func__);
+               return;
+       }
+}
+
+void hpo_enc401_update_hdmi_info_packets(struct hpo_frl_stream_encoder *enc,
+                                      const struct encoder_info_frame *info_frame)
+{
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       hpo_enc401_update_hdmi_info_packet(enc401, 0, &info_frame->avi);
+       hpo_enc401_update_hdmi_info_packet(enc401, 1, &info_frame->vendor);
+       hpo_enc401_update_hdmi_info_packet(enc401, 2, &info_frame->gamut);
+       hpo_enc401_update_hdmi_info_packet(enc401, 3, &info_frame->spd);
+       hpo_enc401_update_hdmi_info_packet(enc401, 4, &info_frame->hdrsmd);
+
+       /* 5-10 used by dsc */
+       hpo_enc401_update_hdmi_info_packet(enc401, 11, &info_frame->hfvsif);
+       hpo_enc401_update_hdmi_info_packet(enc401, 12, &info_frame->vtem);
+}
+
+void hpo_enc401_hdmi_set_dsc_config(
+       struct hpo_frl_stream_encoder *enc,
+       struct dc_crtc_timing *timing,
+       uint8_t *dsc_packed_pps)
+{
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+       enum optc_dsc_mode dsc_mode = OPTC_DSC_DISABLED;
+       uint8_t i;
+
+       if (dsc_packed_pps) {
+               if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 ||
+                               (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
+                                       && !timing->dsc_cfg.ycbcr422_simple))
+                       dsc_mode = OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
+               else
+                       dsc_mode = OPTC_DSC_ENABLED_444;
+       }
+
+       switch (dsc_mode) {
+       case OPTC_DSC_DISABLED:
+               REG_UPDATE_2(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                               FIFO_PIXEL_ENCODING_TYPE, 0,
+                               FIFO_COMPRESSED_PIXEL_FORMAT, 0);
+               break;
+       case OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED:
+               REG_UPDATE_2(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                               FIFO_PIXEL_ENCODING_TYPE, 1,
+                               FIFO_COMPRESSED_PIXEL_FORMAT, 1);
+               break;
+       case OPTC_DSC_ENABLED_444:
+               REG_UPDATE_2(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                               FIFO_PIXEL_ENCODING_TYPE, 1,
+                               FIFO_COMPRESSED_PIXEL_FORMAT, 0);
+               break;
+       }
+
+       REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
+                       HDMI_DSC_MODE, dsc_mode);
+
+       /* 5 packets for hdmi 2.1, use generic packets 5-10 to transmit*/
+       /* TODO: do we change new bit to 0 after first transmission? Do we set End bit when exiting dsc? */
+       if (dsc_mode != OPTC_DSC_DISABLED) {
+               struct dc_info_packet emp_packet = {0};
+               /* Need to find the padded h_total to recover the expected h_back*/
+               uint32_t h_active_padding = timing->h_addressable % timing->dsc_cfg.num_slices_h;
+               if (h_active_padding != 0)
+                       h_active_padding = timing->dsc_cfg.num_slices_h - h_active_padding;
+               /* if YCBCR420, ensure slice width is even */
+               uint32_t slice_width = (timing->h_addressable + h_active_padding) / timing->dsc_cfg.num_slices_h;
+               if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 &&
+                       slice_width % 2 != 0)
+                       h_active_padding += timing->dsc_cfg.num_slices_h;
+               uint32_t dsc_pic_width = timing->h_addressable + timing->h_border_left + timing->h_border_right + h_active_padding;
+               uint32_t h_back = timing->h_total - dsc_pic_width - timing->h_sync_width - timing->h_front_porch + h_active_padding;
+               /* HCactivebytes = Slices * ceil(SliceWidth * bpp/8)
+                * Since bpp is stored as 16x actual value do (sliceWidth * bpp + 127) / 128 to ceil
+                */
+               uint32_t h_cactive_bytes = timing->dsc_cfg.num_slices_h * (
+                               (dsc_pic_width /
+                                               timing->dsc_cfg.num_slices_h * timing->dsc_cfg.bits_per_pixel + 127) / 128);
+
+               /* Packet 0 */
+               emp_packet.valid = true;
+               emp_packet.hb0 = 0x7F; /* Default */
+               emp_packet.hb1 = (1 << 7); /* First */
+               emp_packet.hb2 = 0; /* Sequence index */
+               emp_packet.sb[0] = (1 << 1) | (1 << 2) | (1 << 7); /* Sync[1] = 1, VFR[2] = 1, New[7] = 1*/
+               emp_packet.sb[2] = 1; /* Organization_ID = 1 (Vesa spec)*/
+               emp_packet.sb[4] = 2; /* Data_Set_Tag(LSB) = 2*/
+               emp_packet.sb[6] = 136; /* Data_Set_Length(LSB) = 136*/
+               memcpy(&emp_packet.sb[7], dsc_packed_pps, 21);
+               hpo_enc401_update_hdmi_info_packet(enc401, 5, &emp_packet);
+
+               /* Packets 1-3 */
+               emp_packet.hb1 = 0; /* Not first or last*/
+               for (i = 1; i < 4; i++) {
+                       emp_packet.hb2 = i; /* Sequence index */
+                       memcpy(&emp_packet.sb[0], &dsc_packed_pps[21 + 28 * (i - 1)], 28);
+                       hpo_enc401_update_hdmi_info_packet(enc401, 5 + i, &emp_packet);
+               }
+
+               /* Packet 4 */
+               emp_packet.hb2 = 4; /* Sequence index */
+               memcpy(&emp_packet.sb[0], &dsc_packed_pps[105], 23);
+               emp_packet.sb[23] = (uint8_t)timing->h_front_porch; /* Hfront[7:0] */
+               emp_packet.sb[24] = (uint8_t)(timing->h_front_porch >> 8); /* Hfront[15:8] */
+               emp_packet.sb[25] = (uint8_t)timing->h_sync_width; /* Hsync[7:0] */
+               emp_packet.sb[26] = (uint8_t)(timing->h_sync_width >> 8); /* Hsync[15:8] */
+               emp_packet.sb[27] = (uint8_t)h_back; /* Hback[7:0] */
+               hpo_enc401_update_hdmi_info_packet(enc401, 9, &emp_packet);
+
+               /* Packet 5 */
+               emp_packet.hb1 = (1 << 6); /* Last */
+               emp_packet.hb2 = 5;
+               emp_packet.sb[0] = (uint8_t)(h_back >> 8); /* Hback[15:8] */
+               emp_packet.sb[1] = (uint8_t)h_cactive_bytes; /* HCactive_bytes[7:0] */
+               emp_packet.sb[2] = (uint8_t)(h_cactive_bytes >> 8); /* HCactive_bytes[15:8] */
+               hpo_enc401_update_hdmi_info_packet(enc401, 10, &emp_packet);
+
+               /* Packet 0 - Clear New[7] */
+               emp_packet.valid = true;
+               emp_packet.hb0 = 0x7F; /* Default */
+               emp_packet.hb1 = (1 << 7); /* First */
+               emp_packet.hb2 = 0; /* Sequence index */
+               emp_packet.sb[0] = (1 << 1) | (1 << 2); /* Sync[1] = 1, VFR[2] = 1*/
+               emp_packet.sb[2] = 1; /* Organization_ID = 1 (Vesa spec)*/
+               emp_packet.sb[4] = 2; /* Data_Set_Tag(LSB) = 2*/
+               emp_packet.sb[6] = 136; /* Data_Set_Length(LSB) = 136*/
+               memcpy(&emp_packet.sb[7], dsc_packed_pps, 21);
+               hpo_enc401_update_hdmi_info_packet(enc401, 5, &emp_packet);
+       }
+}
+
+void hpo_enc401_stop_hdmi_info_packets(
+       struct hpo_frl_stream_encoder *enc)
+{
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       /* TODO: should also set extended metadata packet bit back to 0? */
+
+       /* stop generic packets 0,1 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
+               HDMI_GENERIC0_CONT, 0,
+               HDMI_GENERIC0_SEND, 0,
+               HDMI_GENERIC1_CONT, 0,
+               HDMI_GENERIC1_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, 0,
+               HDMI_GENERIC0_LINE, 0,
+               HDMI_GENERIC1_LINE, 0);
+
+       /* stop generic packets 2,3 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
+               HDMI_GENERIC2_CONT, 0,
+               HDMI_GENERIC2_SEND, 0,
+               HDMI_GENERIC3_CONT, 0,
+               HDMI_GENERIC3_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, 0,
+               HDMI_GENERIC2_LINE, 0,
+               HDMI_GENERIC3_LINE, 0);
+
+       /* stop generic packets 4,5 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
+               HDMI_GENERIC4_CONT, 0,
+               HDMI_GENERIC4_SEND, 0,
+               HDMI_GENERIC5_CONT, 0,
+               HDMI_GENERIC5_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, 0,
+               HDMI_GENERIC4_LINE, 0,
+               HDMI_GENERIC5_LINE, 0);
+
+       /* stop generic packets 6,7 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
+               HDMI_GENERIC6_CONT, 0,
+               HDMI_GENERIC6_SEND, 0,
+               HDMI_GENERIC7_CONT, 0,
+               HDMI_GENERIC7_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, 0,
+               HDMI_GENERIC6_LINE, 0,
+               HDMI_GENERIC7_LINE, 0);
+
+       /* stop generic packets 8,9 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
+               HDMI_GENERIC8_CONT, 0,
+               HDMI_GENERIC8_SEND, 0,
+               HDMI_GENERIC9_CONT, 0,
+               HDMI_GENERIC9_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, 0,
+               HDMI_GENERIC8_LINE, 0,
+               HDMI_GENERIC9_LINE, 0);
+
+       /* stop generic packets 10,11 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
+               HDMI_GENERIC10_CONT, 0,
+               HDMI_GENERIC10_SEND, 0,
+               HDMI_GENERIC11_CONT, 0,
+               HDMI_GENERIC11_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, 0,
+               HDMI_GENERIC10_LINE, 0,
+               HDMI_GENERIC11_LINE, 0);
+
+       /* stop generic packets 12,13 on HDMI */
+       REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
+               HDMI_GENERIC12_CONT, 0,
+               HDMI_GENERIC12_SEND, 0,
+               HDMI_GENERIC13_CONT, 0,
+               HDMI_GENERIC13_SEND, 0);
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, 0,
+               HDMI_GENERIC12_LINE, 0,
+               HDMI_GENERIC13_LINE, 0);
+
+       /* stop generic packets 14 on HDMI */
+       REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
+               HDMI_GENERIC14_CONT, 0,
+               HDMI_GENERIC14_SEND, 0);
+       REG_SET(HDMI_TB_ENC_GENERIC_PACKET14_LINE, 0,
+               HDMI_GENERIC14_LINE, 0);
+
+}
+
+//Covered both, rounding up or rounding down from FRL Link Rate /18.
+static const struct frl_audio_clock_info frl_audio_clock_info_table[10] = {
+       {166666, 4224, 171875, 5292, 156250, 5760, 156250},
+       {166667, 4224, 171875, 5292, 156250, 5760, 156250},
+       {333333, 4032, 328125, 5292, 312500, 6048, 328125},
+       {333334, 4032, 328125, 5292, 312500, 6048, 328125},
+       {444444, 4032, 437500, 3969, 312500, 6048, 437500},
+       {444445, 4032, 437500, 3969, 312500, 6048, 437500},
+       {555555, 3456, 468750, 3969, 390625, 5184, 468750},
+       {555556, 3456, 468750, 3969, 390625, 5184, 468750},
+       {666666, 3072, 500000, 3969, 468750, 4752, 515625},
+       {666667, 3072, 500000, 3969, 468750, 4752, 515625}
+};
+
+void frl_get_audio_clock_info(
+       enum dc_color_depth color_depth,
+       uint32_t frl_character_clock_kHz,
+       struct frl_audio_clock_info *audio_clock_info)
+{
+       (void)color_depth;
+       const struct frl_audio_clock_info *clock_info;
+       uint32_t index;
+       uint32_t audio_array_size;
+
+       clock_info = frl_audio_clock_info_table;
+       audio_array_size = ARRAY_SIZE(
+                       frl_audio_clock_info_table);
+
+       if (clock_info != NULL) {
+               /* search for exact frl character clock in table */
+               for (index = 0; index < audio_array_size; index++) {
+                       if (clock_info[index].frl_character_clock_kHz >
+                               frl_character_clock_kHz)
+                               break;  /* not match */
+                       else if (clock_info[index].frl_character_clock_kHz ==
+                                       frl_character_clock_kHz) {
+                               /* match found */
+                               *audio_clock_info = clock_info[index];
+                               return;
+                       }
+               }
+       }
+       /*Only 3, 6, 8, 10 and 12 Gbps are used for FRL Link rates with character
+        *clocks of 166.667, 333.333, 444.444, 555.555 and 666.667 MHz are used
+        *so entry should be found in above table if no bugs */
+       BREAK_TO_DEBUGGER();
+}
+
+void hpo_enc401_setup_hdmi_audio(
+       struct hpo_frl_stream_encoder *enc,
+       const struct audio_crtc_info *crtc_info)
+{
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+       struct frl_audio_clock_info audio_clock_info = {0};
+
+       DC_LOG_DEBUG("Entering [%s]\n", __func__);
+
+       /* TODO:  HDMI_AUDIO_DELAY_EN bit only in DIG -- not in HPO? */
+       /* HDMI_AUDIO_PACKET_CONTROL */
+       //REG_UPDATE(HDMI_AUDIO_PACKET_CONTROL,
+       //              HDMI_AUDIO_DELAY_EN, 1);
+
+       /* Setup audio in AFMT - program AFMT block associated with HPO */
+       ASSERT (enc->afmt);
+       enc->afmt->funcs->setup_hdmi_audio(enc->afmt);
+
+       /* TODO: Same programming, but using HDMI_TB_ENC register */
+       /* HDMI_ACR_PACKET_CONTROL */
+       REG_UPDATE_3(HDMI_TB_ENC_ACR_PACKET_CONTROL,
+                       HDMI_ACR_AUTO_SEND, 1,
+                       HDMI_ACR_SOURCE, 0,
+                       HDMI_ACR_AUDIO_PRIORITY, 0);
+
+       /* N/CTS computed relative to FRL rate instead of video rate (TMDS character clock). */
+       /* Program audio clock sample/regeneration parameters */
+       frl_get_audio_clock_info(crtc_info->color_depth,
+                            crtc_info->frl_character_clock_kHz,
+                            &audio_clock_info);
+       DC_LOG_HW_AUDIO(
+                       "\n%s:Input::requested_pixel_clock_100Hz = %d"  \
+                       "calculated_pixel_clock_100Hz = %d \n", __func__,       \
+                       crtc_info->requested_pixel_clock_100Hz,         \
+                       crtc_info->calculated_pixel_clock_100Hz);
+
+       /* Same register definition, but using HDMI_TB_ENC register */
+       /* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz);
+
+       /* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_32_1, HDMI_ACR_N_32, audio_clock_info.n_32khz);
+
+       /* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_44_0, HDMI_ACR_CTS_44, audio_clock_info.cts_44khz);
+
+       /* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_44_1, HDMI_ACR_N_44, audio_clock_info.n_44khz);
+
+       /* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_48_0, HDMI_ACR_CTS_48, audio_clock_info.cts_48khz);
+
+       /* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_48_1, HDMI_ACR_N_48, audio_clock_info.n_48khz);
+
+
+       /* TODO: HDMI_TB_ENC_ACR_PACKET_CONTROL::ACR_N_MULTIPLE
+        *       Same register definition, but using HDMI_TB_ENC register*/
+
+       /* Video driver cannot know in advance which sample rate will
+        * be used by HD Audio driver
+        * HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
+        * programmed below in interrupt callback
+        */
+       DC_LOG_DEBUG("Exiting [%s]\n", __func__);
+}
+
+void hpo_enc401_hdmi_audio_setup(
+       struct hpo_frl_stream_encoder *enc,
+       unsigned int az_inst,
+       struct audio_info *info,
+       struct audio_crtc_info *audio_crtc_info)
+{
+       hpo_enc401_setup_hdmi_audio(enc, audio_crtc_info);
+       ASSERT (enc->afmt);
+       enc->afmt->funcs->se_audio_setup(enc->afmt, az_inst, info);
+}
+
+void hpo_enc401_hdmi_audio_disable(
+       struct hpo_frl_stream_encoder *enc)
+{
+       ASSERT(enc->afmt);
+       if (enc->afmt->funcs->afmt_powerdown)
+               enc->afmt->funcs->afmt_powerdown(enc->afmt);
+}
+
+void hpo_enc401_audio_mute_control(
+       struct hpo_frl_stream_encoder *enc,
+       bool mute)
+{
+       ASSERT (enc->afmt);
+       enc->afmt->funcs->audio_mute_control(enc->afmt, mute);
+}
+
+void enc401_stream_encoder_set_avmute(
+       struct hpo_frl_stream_encoder *enc,
+       bool enable)
+{
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+       unsigned int value = enable ? 1 : 0;
+
+       REG_UPDATE(HDMI_TB_ENC_GC_CONTROL, HDMI_GC_AVMUTE, value);
+}
+
+/* Set Dynamic Metadata-configuration.
+ *   enable_dme:         TRUE: enables Dynamic Metadata Enfine, FALSE: disables DME
+ *   hubp_requestor_id:  HUBP physical instance that is the source of dynamic metadata
+ *                       only needs to be set when enable_dme is TRUE
+ *   dmdata_mode:        dynamic metadata packet type: DP, HDMI, or Dolby Vision
+ *
+ *   Ensure the OTG master update lock is set when changing DME configuration.
+ */
+void hpo_enc401_set_dynamic_metadata(struct hpo_frl_stream_encoder *enc,
+       bool enable_dme,
+       uint32_t hubp_requestor_id,
+       enum dynamic_metadata_mode dmdata_mode)
+{
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       if (enable_dme) {
+               REG_UPDATE_2(DME_CONTROL,
+                       METADATA_HUBP_REQUESTOR_ID, hubp_requestor_id,
+                       METADATA_STREAM_TYPE, (dmdata_mode == dmdata_dolby_vision) ? 1 : 0);
+
+               REG_UPDATE_3(HDMI_TB_ENC_METADATA_PACKET_CONTROL,
+                       HDMI_METADATA_PACKET_ENABLE, 1,
+                       HDMI_METADATA_PACKET_LINE_REFERENCE, 0,
+                       HDMI_METADATA_PACKET_LINE, 2);
+
+               REG_UPDATE(DME_CONTROL,
+                       METADATA_ENGINE_EN, 1);
+       } else {
+               REG_UPDATE(DME_CONTROL,
+                       METADATA_ENGINE_EN, 0);
+
+               REG_UPDATE(HDMI_TB_ENC_METADATA_PACKET_CONTROL,
+                       HDMI_METADATA_PACKET_ENABLE, 0);
+       }
+}
+
+static const struct hpo_frl_stream_encoder_funcs dcn401_str_enc_funcs = {
+       .hdmi_frl_enable                = hpo_enc401_enable,
+       .hdmi_frl_unblank               = hpo_enc401_unblank,
+       .hdmi_frl_blank                 = hpo_enc401_blank,
+       .hdmi_frl_set_stream_attribute  = hpo_enc401_set_hdmi_stream_attribute,
+       .validate_hdmi_frl_output       = hpo_enc3_validate_hdmi_frl_output,
+       .update_hdmi_info_packets       = hpo_enc401_update_hdmi_info_packets,
+       .stop_hdmi_info_packets         = hpo_enc401_stop_hdmi_info_packets,
+       .audio_mute_control             = hpo_enc401_audio_mute_control,
+       .hdmi_audio_setup               = hpo_enc401_hdmi_audio_setup,
+       .hdmi_audio_disable             = hpo_enc401_hdmi_audio_disable,
+       .set_avmute                     = enc401_stream_encoder_set_avmute,
+       .read_state                     = hpo_enc401_read_state,
+       .set_dynamic_metadata           = hpo_enc401_set_dynamic_metadata,
+};
+
+void dcn401_hpo_frl_stream_encoder_construct(
+       struct dcn401_hpo_frl_stream_encoder *enc401,
+       struct dc_context *ctx,
+       struct dc_bios *bp,
+       enum engine_id eng_id,
+       struct vpg *vpg,
+       struct afmt *afmt,
+       const struct dcn30_hpo_frl_stream_enc_registers *regs,
+       const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift,
+       const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask)
+{
+       enc401->base.funcs = &dcn401_str_enc_funcs;
+       enc401->base.ctx = ctx;
+       enc401->base.id = eng_id;
+       enc401->base.bp = bp;
+       enc401->base.vpg = vpg;
+       enc401->base.afmt = afmt;
+       enc401->regs = regs;
+       enc401->hpo_se_shift = hpo_se_shift;
+       enc401->hpo_se_mask = hpo_se_mask;
+       enc401->base.stream_enc_inst = vpg->inst;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.h
new file mode 100644 (file)
index 0000000..b47ba55
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2023 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 __DC_HPO_FRL_STREAM_ENCODER_DCN401_H__
+#define __DC_HPO_FRL_STREAM_ENCODER_DCN401_H__
+
+#include "dcn30/dcn30_vpg.h"
+#include "dcn30/dcn30_afmt.h"
+#include "dcn30/dcn30_hpo_frl_stream_encoder.h"
+#include "stream_encoder.h"
+#include "dml/dml1_frl_cap_chk.h"
+
+#define DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(hpo_frl_stream_encoder)\
+       container_of(hpo_frl_stream_encoder, struct dcn401_hpo_frl_stream_encoder, base)
+
+#define SE_SF(reg_name, field_name, post_fix)\
+       .field_name = reg_name ## __ ## field_name ## post_fix
+
+#define DCN401_HDMI_STREAM_ENC_MASK_SH_LIST(mask_sh)\
+       SE_SF(HDMI_STREAM_ENC_INPUT_MUX_CONTROL, HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_ENABLE, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_PIXEL_ENCODING_TYPE, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_UNCOMPRESSED_PIXEL_FORMAT, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_COMPRESSED_PIXEL_FORMAT, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_CLOCK_CONTROL, HDMI_STREAM_ENC_CLOCK_EN, mask_sh),\
+       SE_SF(DME0_DME_CONTROL, METADATA_HUBP_REQUESTOR_ID, mask_sh),\
+       SE_SF(DME0_DME_CONTROL, METADATA_ENGINE_EN, mask_sh),\
+       SE_SF(DME0_DME_CONTROL, METADATA_STREAM_TYPE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_ENABLE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE_REFERENCE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_MISSED, mask_sh),\
+       SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE, mask_sh)
+
+#define DCN401_HDMI_TB_ENC_MASK_SH_LIST(mask_sh)\
+       SE_SF(HDMI_TB_ENC_CONTROL, HDMI_TB_ENC_EN, mask_sh),\
+       SE_SF(HDMI_TB_ENC_CONTROL, HDMI_RESET, mask_sh),\
+       SE_SF(HDMI_TB_ENC_CONTROL, HDMI_RESET_DONE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_MODE, HDMI_BORROW_MODE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_H_ACTIVE_BLANK, HDMI_H_ACTIVE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_H_ACTIVE_BLANK, HDMI_H_BLANK, mask_sh),\
+       SE_SF(HDMI_TB_ENC_HC_ACTIVE_BLANK, HDMI_HC_ACTIVE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_HC_ACTIVE_BLANK, HDMI_HC_BLANK, mask_sh),\
+       SE_SF(HDMI_TB_ENC_PACKET_CONTROL, HDMI_MAX_PACKETS_PER_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_DB_CONTROL, HDMI_DB_DISABLE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_PIXEL_ENCODING, mask_sh),\
+       SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DEEP_COLOR_DEPTH, mask_sh),\
+       SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DEEP_COLOR_ENABLE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DSC_MODE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_GC_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_GC_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_ACP_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GC_CONTROL, HDMI_GC_AVMUTE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC8_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC9_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC10_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC11_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC12_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC13_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC14_CONT, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC8_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC9_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC10_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC11_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC12_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC13_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC14_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, HDMI_GENERIC0_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, HDMI_GENERIC1_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, HDMI_GENERIC2_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, HDMI_GENERIC3_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, HDMI_GENERIC4_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, HDMI_GENERIC5_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, HDMI_GENERIC6_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, HDMI_GENERIC7_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, HDMI_GENERIC8_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, HDMI_GENERIC9_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, HDMI_GENERIC10_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, HDMI_GENERIC11_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, HDMI_GENERIC12_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, HDMI_GENERIC13_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_GENERIC_PACKET14_LINE, HDMI_GENERIC14_LINE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_AUTO_SEND, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_SOURCE, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_AUDIO_PRIORITY, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_32_0, HDMI_ACR_CTS_32, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_32_1, HDMI_ACR_N_32, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_44_0, HDMI_ACR_CTS_44, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_44_1, HDMI_ACR_N_44, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_48_0, HDMI_ACR_CTS_48, mask_sh),\
+       SE_SF(HDMI_TB_ENC_ACR_48_1, HDMI_ACR_N_48, mask_sh),\
+       SE_SF(HDMI_TB_ENC_CRC_CNTL, HDMI_CRC_EN, mask_sh),\
+       SE_SF(HDMI_TB_ENC_CRC_CNTL, HDMI_CRC_CONT_EN, mask_sh)
+
+#define DCN401_HDMI_TB_ENC_REG_FIELD_LIST(type) \
+       type HDMI_TB_ENC_EN;\
+       type HDMI_RESET;\
+       type HDMI_RESET_DONE;\
+       type HDMI_STREAM_ENC_CLOCK_EN;\
+       type HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL;\
+       type HDMI_MAX_PACKETS_PER_LINE;\
+       type FIFO_ENABLE;\
+       type FIFO_RESET;\
+       type FIFO_PIXEL_ENCODING_TYPE;\
+       type FIFO_UNCOMPRESSED_PIXEL_FORMAT;\
+       type FIFO_COMPRESSED_PIXEL_FORMAT;\
+       type FIFO_RESET_DONE;\
+       type HDMI_BORROW_MODE;\
+       type HDMI_H_ACTIVE;\
+       type HDMI_H_BLANK;\
+       type HDMI_HC_ACTIVE;\
+       type HDMI_HC_BLANK;\
+       type HDMI_DB_DISABLE;\
+       type HDMI_PIXEL_ENCODING;\
+       type HDMI_DEEP_COLOR_DEPTH;\
+       type HDMI_DEEP_COLOR_ENABLE;\
+       type HDMI_ODM_COMBINE_MODE;\
+       type HDMI_DSC_MODE;\
+       type HDMI_GC_CONT;\
+       type HDMI_GC_SEND;\
+       type HDMI_ACP_SEND;\
+       type HDMI_AUDIO_INFO_SEND;\
+       type HDMI_AUDIO_INFO_LINE;\
+       type HDMI_GC_AVMUTE;\
+       type HDMI_GENERIC0_CONT;\
+       type HDMI_GENERIC0_SEND;\
+       type HDMI_GENERIC0_LINE;\
+       type HDMI_GENERIC1_CONT;\
+       type HDMI_GENERIC1_SEND;\
+       type HDMI_GENERIC1_LINE;\
+       type HDMI_GENERIC2_CONT;\
+       type HDMI_GENERIC2_SEND;\
+       type HDMI_GENERIC2_LINE;\
+       type HDMI_GENERIC3_CONT;\
+       type HDMI_GENERIC3_SEND;\
+       type HDMI_GENERIC3_LINE;\
+       type HDMI_GENERIC4_CONT;\
+       type HDMI_GENERIC4_SEND;\
+       type HDMI_GENERIC4_LINE;\
+       type HDMI_GENERIC5_CONT;\
+       type HDMI_GENERIC5_SEND;\
+       type HDMI_GENERIC5_LINE;\
+       type HDMI_GENERIC6_CONT;\
+       type HDMI_GENERIC6_SEND;\
+       type HDMI_GENERIC6_LINE;\
+       type HDMI_GENERIC7_CONT;\
+       type HDMI_GENERIC7_SEND;\
+       type HDMI_GENERIC7_LINE;\
+       type HDMI_GENERIC8_CONT;\
+       type HDMI_GENERIC8_SEND;\
+       type HDMI_GENERIC8_LINE;\
+       type HDMI_GENERIC9_CONT;\
+       type HDMI_GENERIC9_SEND;\
+       type HDMI_GENERIC9_LINE;\
+       type HDMI_GENERIC10_CONT;\
+       type HDMI_GENERIC10_SEND;\
+       type HDMI_GENERIC10_LINE;\
+       type HDMI_GENERIC11_CONT;\
+       type HDMI_GENERIC11_SEND;\
+       type HDMI_GENERIC11_LINE;\
+       type HDMI_GENERIC12_CONT;\
+       type HDMI_GENERIC12_SEND;\
+       type HDMI_GENERIC12_LINE;\
+       type HDMI_GENERIC13_CONT;\
+       type HDMI_GENERIC13_SEND;\
+       type HDMI_GENERIC13_LINE;\
+       type HDMI_GENERIC14_CONT;\
+       type HDMI_GENERIC14_SEND;\
+       type HDMI_GENERIC14_LINE;\
+       type HDMI_ACR_AUTO_SEND;\
+       type HDMI_ACR_SOURCE;\
+       type HDMI_ACR_AUDIO_PRIORITY;\
+       type HDMI_ACR_CTS_32;\
+       type HDMI_ACR_N_32;\
+       type HDMI_ACR_CTS_44;\
+       type HDMI_ACR_N_44;\
+       type HDMI_ACR_CTS_48;\
+       type HDMI_ACR_N_48;\
+       type HDMI_CRC_EN;\
+       type HDMI_CRC_CONT_EN;\
+       type METADATA_HUBP_REQUESTOR_ID;\
+       type METADATA_ENGINE_EN;\
+       type METADATA_STREAM_TYPE;\
+       type HDMI_METADATA_PACKET_ENABLE;\
+       type HDMI_METADATA_PACKET_LINE_REFERENCE;\
+       type HDMI_METADATA_PACKET_MISSED;\
+       type HDMI_METADATA_PACKET_LINE
+
+#define DCN401_HPO_STREAM_ENC_MASK_SH_LIST(mask_sh)\
+       DCN401_HDMI_STREAM_ENC_MASK_SH_LIST(mask_sh),\
+       DCN401_HDMI_TB_ENC_MASK_SH_LIST(mask_sh)
+
+#define DCN42_HDMI_TB_ENC_REG_FIELD_LIST(type) \
+       type HDMI_STREAM_ENC_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL;\
+       type HDMI_STREAM_ENC_APG_CLOCK_EN
+
+struct dcn401_hpo_frl_stream_encoder_shift {
+       DCN401_HDMI_TB_ENC_REG_FIELD_LIST(uint8_t);
+       DCN42_HDMI_TB_ENC_REG_FIELD_LIST(uint8_t);
+};
+
+struct dcn401_hpo_frl_stream_encoder_mask {
+       DCN401_HDMI_TB_ENC_REG_FIELD_LIST(uint32_t);
+       DCN42_HDMI_TB_ENC_REG_FIELD_LIST(uint32_t);
+};
+
+struct dcn401_hpo_frl_stream_encoder {
+       struct hpo_frl_stream_encoder base;
+       const struct dcn30_hpo_frl_stream_enc_registers *regs;
+       const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift;
+       const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask;
+};
+
+void hpo_enc401_enable(
+               struct hpo_frl_stream_encoder *enc,
+               int otg_inst);
+
+void hpo_enc401_unblank(
+       struct hpo_frl_stream_encoder *enc,
+       int otg_inst);
+
+void hpo_enc401_read_state(
+               struct hpo_frl_stream_encoder *enc,
+               struct hpo_frl_stream_encoder_state *state);
+
+void hpo_enc401_blank(
+       struct hpo_frl_stream_encoder *enc);
+
+void hpo_enc401_set_hdmi_stream_attribute(
+       struct hpo_frl_stream_encoder *enc,
+       struct dc_crtc_timing *crtc_timing,
+       struct frl_borrow_params *borrow_params,
+       int odm_combine_num_segments);
+
+void hpo_enc401_update_hdmi_info_packet(
+       struct dcn401_hpo_frl_stream_encoder *enc401,
+       uint32_t packet_index,
+       const struct dc_info_packet *info_packet);
+
+void hpo_enc401_update_hdmi_info_packets(
+       struct hpo_frl_stream_encoder *enc,
+       const struct encoder_info_frame *info_frame);
+
+void hpo_enc401_hdmi_set_dsc_config(
+  struct hpo_frl_stream_encoder *enc,
+  struct dc_crtc_timing *timing,
+  uint8_t *dsc_packed_pps);
+
+void hpo_enc401_stop_hdmi_info_packets(
+       struct hpo_frl_stream_encoder *enc);
+
+void hpo_enc401_setup_hdmi_audio(
+       struct hpo_frl_stream_encoder *enc,
+       const struct audio_crtc_info *crtc_info);
+
+void hpo_enc401_hdmi_audio_setup(
+       struct hpo_frl_stream_encoder *enc,
+       unsigned int az_inst,
+       struct audio_info *info,
+       struct audio_crtc_info *audio_crtc_info);
+
+void hpo_enc401_hdmi_audio_disable(
+       struct hpo_frl_stream_encoder *enc);
+
+void hpo_enc401_audio_mute_control(
+       struct hpo_frl_stream_encoder *enc,
+       bool mute);
+
+void enc401_stream_encoder_set_avmute(
+       struct hpo_frl_stream_encoder *enc,
+       bool enable);
+
+void hpo_enc401_set_dynamic_metadata(
+       struct hpo_frl_stream_encoder *enc,
+       bool enable_dme,
+       uint32_t hubp_requestor_id,
+       enum dynamic_metadata_mode dmdata_mode);
+void frl_get_audio_clock_info(
+       enum dc_color_depth color_depth,
+       uint32_t frl_character_clock_kHz,
+       struct frl_audio_clock_info *audio_clock_info);
+
+void dcn401_hpo_frl_stream_encoder_construct(
+       struct dcn401_hpo_frl_stream_encoder *enc401,
+       struct dc_context *ctx,
+       struct dc_bios *bp,
+       enum engine_id eng_id,
+       struct vpg *vpg,
+       struct afmt *afmt,
+       const struct dcn30_hpo_frl_stream_enc_registers *regs,
+       const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift,
+       const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask);
+
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
new file mode 100644 (file)
index 0000000..0ec3863
--- /dev/null
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#include "dc_bios_types.h"
+#include "core_types.h"
+#include "dcn42_hpo_frl_stream_encoder.h"
+#include "dcn31/dcn31_apg.h"
+#include "dcn401/dcn401_hpo_frl_stream_encoder.h"
+#include "dcn30/dcn30_hpo_frl_stream_encoder.h"
+#include "reg_helper.h"
+#include "hw_shared.h"
+#include "dcn_calc_math.h"
+#include "dml/dcn30/dcn30_fpu.h"
+
+#undef DC_LOGGER
+#define DC_LOGGER \
+               enc401->base.ctx->logger
+
+#define DTRACE(str, ...) {DC_LOG_HDMI_FRL(str, ##__VA_ARGS__); }
+
+#define DEBUG_FRL_CAP_CHK 1
+
+#define REG(reg)\
+       (enc401->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) \
+       enc401->hpo_se_shift->field_name, enc401->hpo_se_mask->field_name
+
+#define CTX \
+       enc401->base.ctx
+
+#define VBI_LINE_0 0
+
+void hpo_enc42_unblank(struct hpo_frl_stream_encoder *enc, int otg_inst)
+{
+       (void)otg_inst;
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
+
+       /*make sure FIFO_VIDEO_STREAM_ACTIVE =1*/
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_ENABLE, 0);
+
+       /* Reset */
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_RESET, 1);
+       REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
+                1, 10, 1000);
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_RESET, 0);
+       REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
+                0, 10, 1000);
+
+       /* Enable HDMI Tribyte Encoder */
+       REG_UPDATE(HDMI_TB_ENC_CONTROL,
+                  HDMI_TB_ENC_EN, 1);
+
+       /* Enable Clock Ramp Adjuster FIFO */
+       REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+                  FIFO_ENABLE, 1);
+
+       DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
+}
+
+void hpo_enc42_setup_hdmi_audio(
+       struct hpo_frl_stream_encoder *enc,
+       const struct audio_crtc_info *crtc_info)
+{
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+       struct frl_audio_clock_info audio_clock_info = {0};
+
+       DC_LOG_DEBUG("Entering [%s]\n", __func__);
+
+       /* TODO:  HDMI_AUDIO_DELAY_EN bit only in DIG -- not in HPO? */
+       /* HDMI_AUDIO_PACKET_CONTROL */
+       //REG_UPDATE(HDMI_AUDIO_PACKET_CONTROL,
+       //              HDMI_AUDIO_DELAY_EN, 1);
+
+       /* Setup audio in APG - program APG block associated with HPO */
+       ASSERT(enc->apg);
+
+       /* HDMI_ACR_PACKET_CONTROL */
+       REG_UPDATE_3(HDMI_TB_ENC_ACR_PACKET_CONTROL,
+                       HDMI_ACR_AUTO_SEND, 1,
+                       HDMI_ACR_SOURCE, 0,
+                       HDMI_ACR_AUDIO_PRIORITY, 0);
+
+       /* N/CTS computed relative to FRL rate instead of video rate (TMDS character clock). */
+       /* Program audio clock sample/regeneration parameters */
+       frl_get_audio_clock_info(crtc_info->color_depth,
+                            crtc_info->frl_character_clock_kHz,
+                            &audio_clock_info);
+       DC_LOG_HW_AUDIO(
+                       "\n%s:Input::requested_pixel_clock_100Hz = %d"  \
+                       "calculated_pixel_clock_100Hz = %d \n", __func__,       \
+                       crtc_info->requested_pixel_clock_100Hz,         \
+                       crtc_info->calculated_pixel_clock_100Hz);
+
+       /* Same register definition, but using HDMI_TB_ENC register */
+       /* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz);
+
+       /* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_32_1, HDMI_ACR_N_32, audio_clock_info.n_32khz);
+
+       /* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_44_0, HDMI_ACR_CTS_44, audio_clock_info.cts_44khz);
+
+       /* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_44_1, HDMI_ACR_N_44, audio_clock_info.n_44khz);
+
+       /* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_48_0, HDMI_ACR_CTS_48, audio_clock_info.cts_48khz);
+
+       /* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
+       REG_UPDATE(HDMI_TB_ENC_ACR_48_1, HDMI_ACR_N_48, audio_clock_info.n_48khz);
+
+
+       /* TODO: HDMI_TB_ENC_ACR_PACKET_CONTROL::ACR_N_MULTIPLE
+        *       Same register definition, but using HDMI_TB_ENC register*/
+
+       /* Video driver cannot know in advance which sample rate will
+        * be used by HD Audio driver
+        * HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
+        * programmed below in interrupt callback
+        */
+       DC_LOG_DEBUG("Exiting [%s]\n", __func__);
+}
+
+void hpo_enc42_hdmi_audio_setup(
+       struct hpo_frl_stream_encoder *enc,
+       unsigned int az_inst,
+       struct audio_info *info,
+       struct audio_crtc_info *audio_crtc_info)
+{
+       struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+
+       REG_UPDATE_2(HDMI_STREAM_ENC_AUDIO_CONTROL,
+                       HDMI_STREAM_ENC_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, az_inst,
+                       HDMI_STREAM_ENC_APG_CLOCK_EN, 1);
+
+       hpo_enc42_setup_hdmi_audio(enc, audio_crtc_info);
+       ASSERT (enc->apg);
+       enc->apg->funcs->se_audio_setup(enc->apg, az_inst, info);
+}
+
+void hpo_enc42_hdmi_audio_disable(
+       struct hpo_frl_stream_encoder *enc)
+{
+       ASSERT(enc->apg);
+       if (enc->apg->funcs->disable_apg)
+               enc->apg->funcs->disable_apg(enc->apg);
+}
+
+void hpo_enc42_audio_mute_control(
+       struct hpo_frl_stream_encoder *enc,
+       bool mute)
+{
+       ASSERT (enc->apg);
+       if (mute)
+               enc->apg->funcs->disable_apg(enc->apg);
+       else
+               enc->apg->funcs->enable_apg(enc->apg);
+}
+
+static const struct hpo_frl_stream_encoder_funcs dcn42_str_enc_funcs = {
+       .hdmi_frl_enable                = hpo_enc401_enable,
+       .hdmi_frl_unblank               = hpo_enc42_unblank,
+       .hdmi_frl_blank                 = hpo_enc401_blank,
+       .hdmi_frl_set_stream_attribute  = hpo_enc401_set_hdmi_stream_attribute,
+       .validate_hdmi_frl_output       = hpo_enc3_validate_hdmi_frl_output,
+       .update_hdmi_info_packets       = hpo_enc401_update_hdmi_info_packets,
+       .stop_hdmi_info_packets         = hpo_enc401_stop_hdmi_info_packets,
+       .audio_mute_control             = hpo_enc42_audio_mute_control,
+       .hdmi_audio_setup               = hpo_enc42_hdmi_audio_setup,
+       .hdmi_audio_disable             = hpo_enc42_hdmi_audio_disable,
+       .set_avmute                     = enc401_stream_encoder_set_avmute,
+       .read_state                     = hpo_enc401_read_state,
+       .set_dynamic_metadata           = hpo_enc401_set_dynamic_metadata,
+};
+
+void dcn42_hpo_frl_stream_encoder_construct(
+       struct dcn42_hpo_frl_stream_encoder *enc42,
+       struct dc_context *ctx,
+       struct dc_bios *bp,
+       enum engine_id eng_id,
+       struct vpg *vpg,
+       struct apg *apg,
+       const struct dcn30_hpo_frl_stream_enc_registers *regs,
+       const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift,
+       const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask)
+{
+       enc42->base.funcs = &dcn42_str_enc_funcs;
+       enc42->base.ctx = ctx;
+       enc42->base.id = eng_id;
+       enc42->base.bp = bp;
+       enc42->base.vpg = vpg;
+       enc42->base.apg = apg;
+       enc42->regs = regs;
+       enc42->hpo_se_shift = hpo_se_shift;
+       enc42->hpo_se_mask = hpo_se_mask;
+       enc42->base.stream_enc_inst = vpg->inst;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.h
new file mode 100644 (file)
index 0000000..ff8218b
--- /dev/null
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#ifndef __DC_HPO_FRL_STREAM_ENCODER_DCN42_H__
+#define __DC_HPO_FRL_STREAM_ENCODER_DCN42_H__
+
+#include "dcn30/dcn30_vpg.h"
+#include "dcn31/dcn31_apg.h"
+#include "dcn30/dcn30_hpo_frl_stream_encoder.h"
+#include "dcn401/dcn401_hpo_frl_stream_encoder.h"
+
+#include "stream_encoder.h"
+#include "dml/dml1_frl_cap_chk.h"
+
+#define DCN42_HDMI_STREAM_ENC_MASK_SH_LIST(mask_sh)\
+       DCN401_HPO_STREAM_ENC_MASK_SH_LIST(mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, mask_sh),\
+       SE_SF(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, mask_sh)
+struct dcn42_hpo_frl_stream_encoder {
+       struct hpo_frl_stream_encoder base;
+       const struct dcn30_hpo_frl_stream_enc_registers *regs;
+       const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift;
+       const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask;
+};
+
+void hpo_enc42_unblank(
+       struct hpo_frl_stream_encoder *enc,
+       int otg_inst);
+
+void hpo_enc42_setup_hdmi_audio(
+       struct hpo_frl_stream_encoder *enc,
+       const struct audio_crtc_info *crtc_info);
+
+void hpo_enc42_hdmi_audio_setup(
+       struct hpo_frl_stream_encoder *enc,
+       unsigned int az_inst,
+       struct audio_info *info,
+       struct audio_crtc_info *audio_crtc_info);
+
+void hpo_enc42_hdmi_audio_disable(
+       struct hpo_frl_stream_encoder *enc);
+
+void hpo_enc42_audio_mute_control(
+       struct hpo_frl_stream_encoder *enc,
+       bool mute);
+
+void dcn42_hpo_frl_stream_encoder_construct(
+       struct dcn42_hpo_frl_stream_encoder *enc42,
+       struct dc_context *ctx,
+       struct dc_bios *bp,
+       enum engine_id eng_id,
+       struct vpg *vpg,
+       struct apg *apg,
+       const struct dcn30_hpo_frl_stream_enc_registers *regs,
+       const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift,
+       const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask);
+
+#endif /* __DC_HPO_STREAM_ENCODER_DCN42_H__ */
index b49bd155cad4c8e96c12ec2f23a3953e2f6d592a..98335a53ca52118a470a8829c2b34bb50fb7f02b 100644 (file)
@@ -263,6 +263,7 @@ void opp1_set_dyn_expansion(
        /*00 - 10-bit -> 12-bit dynamic expansion*/
        /*01 - 8-bit  -> 12-bit dynamic expansion*/
        if (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
+               signal == SIGNAL_TYPE_HDMI_FRL ||
                signal == SIGNAL_TYPE_DISPLAY_PORT ||
                signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
                signal == SIGNAL_TYPE_VIRTUAL) {
index 138081e6cc977b9d0de33bc417173c213d01e219..bceefb5320ebd96e419326af66b1840aa61c6f39 100644 (file)
 
 struct dcn_optc_registers {
        OPTC_REG_VARIABLE_LIST_DCN;
+       uint32_t OTG_DRR_V_TOTAL_REACH_RANGE;
        OPTC_REG_VARIABLE_LIST_DCN42;
 };
 
@@ -595,7 +596,9 @@ struct dcn_optc_registers {
        type MANUAL_FLOW_CONTROL;\
        type MANUAL_FLOW_CONTROL_SEL;
 
-#define V_TOTAL_REGS(type)
+#define V_TOTAL_REGS(type) \
+       type OTG_DRR_V_TOTAL_REACH_LOWER_RANGE;\
+       type OTG_DRR_V_TOTAL_REACH_UPPER_RANGE;
 
 #define TG_REG_FIELD_LIST(type) \
        TG_REG_FIELD_LIST_DCN1_0(type)\
index e2303f9eaf13b699c8a6d2c83e37ef05994136a6..16c5610b49acc39ca0a9a7a854466864f231567e 100644 (file)
@@ -28,7 +28,9 @@
 
 #include "dcn20/dcn20_optc.h"
 
-#define V_TOTAL_REGS_DCN30_SRI(inst)
+#define V_TOTAL_REGS_DCN30_SRI(inst) \
+       SRI(OTG_V_TOTAL_MID, OTG, inst),\
+       SRI(OTG_DRR_V_TOTAL_REACH_RANGE, OTG, inst),
 
 #define OPTC_COMMON_REG_LIST_DCN3_BASE(inst) \
        SRI(OTG_VSTARTUP_PARAM, OTG, inst),\
        SR(DWB_SOURCE_SELECT),\
        SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst)
 
-#define DCN30_VTOTAL_REGS_SF(mask_sh)
+#define DCN30_VTOTAL_REGS_SF(mask_sh)\
+       SF(OTG0_OTG_DRR_V_TOTAL_REACH_RANGE, OTG_DRR_V_TOTAL_REACH_LOWER_RANGE, mask_sh),\
+       SF(OTG0_OTG_DRR_V_TOTAL_REACH_RANGE, OTG_DRR_V_TOTAL_REACH_UPPER_RANGE, mask_sh),
 
 #define OPTC_COMMON_MASK_SH_LIST_DCN3_BASE(mask_sh)\
        SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\
index 5f53f8747812a659cab8627045490216ddaedc5d..98aaa22ce81cf7f93a17b46fe1f0d6dc2becdf2f 100644 (file)
@@ -320,6 +320,8 @@ void optc31_read_reg_state(struct timing_generator *optc, struct dcn_optc_reg_st
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
 
+       optc_reg_state->otg_drr_v_total_reach_range = REG_READ(OTG_DRR_V_TOTAL_REACH_RANGE);
+
        optc_reg_state->optc_bytes_per_pixel = REG_READ(OPTC_BYTES_PER_PIXEL);
        optc_reg_state->optc_data_format_control = REG_READ(OPTC_DATA_FORMAT_CONTROL);
        optc_reg_state->optc_data_source_select = REG_READ(OPTC_DATA_SOURCE_SELECT);
index a8e978d1fae87a84044127ff5ce3d108f46318ed..a6d76f451cf8c0d5d36d13a1e46118cbf760bbc2 100644 (file)
@@ -378,6 +378,8 @@ void optc401_set_out_mux(struct timing_generator *optc, enum otg_out_mux_dest de
           01 - OTG_CONTROL_OTG_OUT_MUX_1 : Reserved.
           02 - OTG_CONTROL_OTG_OUT_MUX_2 : Connects to HPO.
        */
+       if (dest  == OUT_MUX_HPO_FRL)
+               dest = OUT_MUX_HPO_DP;
        REG_UPDATE(OTG_CONTROL, OTG_OUT_MUX, dest);
 }