AMD-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Harry Wentland <harry.wentland@amd.com>
To: <amd-gfx@lists.freedesktop.org>
Cc: <Jerry.Zuo@amd.com>, Harry Wentland <harry.wentland@amd.com>
Subject: [PATCH v5 04/13] drm/amd/display: Add DCCG DIO, HPO, OPP, and OPTC support for FRL
Date: Tue, 12 May 2026 11:52:35 -0400	[thread overview]
Message-ID: <20260512155244.403854-5-harry.wentland@amd.com> (raw)
In-Reply-To: <20260512155244.403854-1-harry.wentland@amd.com>

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>
---
 .../amd/display/dc/dccg/dcn30/dcn30_dccg.c    |  40 +
 .../amd/display/dc/dccg/dcn30/dcn30_dccg.h    |   8 +
 .../amd/display/dc/dccg/dcn31/dcn31_dccg.c    |  88 ++
 .../amd/display/dc/dccg/dcn31/dcn31_dccg.h    |  13 +
 .../amd/display/dc/dccg/dcn314/dcn314_dccg.c  |  25 +
 .../amd/display/dc/dccg/dcn32/dcn32_dccg.c    |  68 ++
 .../amd/display/dc/dccg/dcn35/dcn35_dccg.c    | 321 ++++++
 .../amd/display/dc/dccg/dcn401/dcn401_dccg.c  |  73 ++
 .../amd/display/dc/dccg/dcn401/dcn401_dccg.h  |   4 +
 .../amd/display/dc/dccg/dcn42/dcn42_dccg.c    |  33 +
 .../display/dc/dio/dcn10/dcn10_link_encoder.c |   3 +-
 .../display/dc/dio/dcn20/dcn20_link_encoder.h |   1 +
 .../dc/dio/dcn30/dcn30_dio_link_encoder.c     | 250 +++++
 .../dc/dio/dcn30/dcn30_dio_link_encoder.h     |  17 +
 .../dc/dio/dcn301/dcn301_dio_link_encoder.c   |  18 +
 .../dc/dio/dcn31/dcn31_dio_link_encoder.c     | 114 +++
 .../dc/dio/dcn31/dcn31_dio_link_encoder.h     |   8 +
 .../dc/dio/dcn32/dcn32_dio_link_encoder.c     | 214 ++++
 .../dc/dio/dcn32/dcn32_dio_link_encoder.h     |  16 +
 .../dc/dio/dcn321/dcn321_dio_link_encoder.c   |  20 +
 .../dc/dio/dcn35/dcn35_dio_link_encoder.c     |  21 +
 .../dc/dio/dcn401/dcn401_dio_link_encoder.c   | 220 ++++
 .../dc/dio/dcn401/dcn401_dio_link_encoder.h   |  16 +
 .../dc/dio/dcn42/dcn42_dio_link_encoder.c     |  21 +
 drivers/gpu/drm/amd/display/dc/hpo/Makefile   |  10 +
 .../dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.c | 286 ++++++
 .../dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.h | 146 +++
 .../hpo/dcn30/dcn30_hpo_frl_stream_encoder.c  | 938 ++++++++++++++++++
 .../hpo/dcn30/dcn30_hpo_frl_stream_encoder.h  | 436 ++++++++
 .../dcn401/dcn401_hpo_frl_stream_encoder.c    | 906 +++++++++++++++++
 .../dcn401/dcn401_hpo_frl_stream_encoder.h    | 335 +++++++
 .../hpo/dcn42/dcn42_hpo_frl_stream_encoder.c  | 206 ++++
 .../hpo/dcn42/dcn42_hpo_frl_stream_encoder.h  |  59 ++
 .../drm/amd/display/dc/opp/dcn10/dcn10_opp.c  |   1 +
 .../amd/display/dc/optc/dcn10/dcn10_optc.h    |   5 +-
 .../amd/display/dc/optc/dcn30/dcn30_optc.h    |   8 +-
 .../amd/display/dc/optc/dcn31/dcn31_optc.c    |   2 +
 .../amd/display/dc/optc/dcn401/dcn401_optc.c  |   2 +
 38 files changed, 4948 insertions(+), 4 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.h

diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c
index adec7c3c2d49..180175693e0e 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c
@@ -42,8 +42,48 @@
 #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,
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.h
index 3f1da7f3a91c..379fe94734ba 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.h
@@ -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__
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c
index 1f5a4a8bf691..a4f6faaf97fb 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c
@@ -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,
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.h
index b5e3849ef12a..2c2d682a82c2 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.h
@@ -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,
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c
index 2e9c4b13988a..410e914c720c 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c
@@ -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,
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c
index d2752dd8f81f..c81362876774 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c
@@ -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,
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
index 33418ee1fa62..83589777f1ca 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
@@ -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,
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
index d49689baa7ca..b9c88bc436e0 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
@@ -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,
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.h
index 5947a35363aa..95f0602466d3 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.h
@@ -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__
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c
index 9612f4498ef6..e57242f8bc12 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c
@@ -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,
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_link_encoder.c
index 59b68422334d..4b36c01a9e7a 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_link_encoder.c
@@ -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*/
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_link_encoder.h
index 762c579fcb44..1beba9c7d3f9 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn20/dcn20_link_encoder.h
@@ -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;
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.c
index 57b9ae5fca1d..8c4010c5b2e7 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.c
@@ -48,11 +48,240 @@
 	(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)\
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.h
index 5b6177c2ae98..4fc0915a5dc5 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn30/dcn30_dio_link_encoder.h
@@ -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__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn301/dcn301_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn301/dcn301_dio_link_encoder.c
index 47d84a2a48ce..02fb844670f9 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn301/dcn301_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn301/dcn301_dio_link_encoder.c
@@ -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;
+	}
 }
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c
index 07d362ef0daf..bcb791d74189 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c
@@ -67,6 +67,17 @@
 #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(
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.h
index ee78ba80797c..3cf587527991 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.h
@@ -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__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.c
index 65d28cb07b04..68e0dc93ae7d 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.c
@@ -62,6 +62,17 @@
 #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;
+	}
 }
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.h
index 35d23d9db45e..262796819a63 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn32/dcn32_dio_link_encoder.h
@@ -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__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn321/dcn321_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn321/dcn321_dio_link_encoder.c
index 968f89295b64..4108fd0f4380 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn321/dcn321_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn321/dcn321_dio_link_encoder.c
@@ -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;
+	}
 }
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.c
index 20bf04dac609..8fa9b8c500f2 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.c
@@ -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;
+	}
 
 }
 
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c
index e1f0a1bf1075..2aaf06d48771 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c
@@ -65,6 +65,17 @@
 #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;
+	}
 }
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h
index 6baab8302b81..a40c479fada8 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h
@@ -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);
diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_link_encoder.c
index 35dfe3bb0c55..fae49b3b170e 100644
--- a/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dio/dcn42/dcn42_dio_link_encoder.c
@@ -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;
+	}
 }
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/Makefile b/drivers/gpu/drm/amd/display/dc/hpo/Makefile
index 25b196714bd8..db60564b9cfd 100644
--- a/drivers/gpu/drm/amd/display/dc/hpo/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/hpo/Makefile
@@ -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
index 000000000000..56e753d2f43d
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.c
@@ -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
index 000000000000..9626793812b8
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_link_encoder.h
@@ -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
index 000000000000..cd7d2bb661e5
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
@@ -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
index 000000000000..c00be852aa17
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.h
@@ -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
index 000000000000..27f7ffd89629
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c
@@ -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
index 000000000000..b47ba55b9a68
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.h
@@ -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
index 000000000000..0ec386347f80
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
@@ -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
index 000000000000..ff8218bed753
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.h
@@ -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__ */
diff --git a/drivers/gpu/drm/amd/display/dc/opp/dcn10/dcn10_opp.c b/drivers/gpu/drm/amd/display/dc/opp/dcn10/dcn10_opp.c
index b49bd155cad4..98335a53ca52 100644
--- a/drivers/gpu/drm/amd/display/dc/opp/dcn10/dcn10_opp.c
+++ b/drivers/gpu/drm/amd/display/dc/opp/dcn10/dcn10_opp.c
@@ -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) {
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h
index 138081e6cc97..bceefb5320eb 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h
@@ -266,6 +266,7 @@
 
 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)\
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h
index e2303f9eaf13..16c5610b49ac 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h
@@ -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),\
@@ -112,7 +114,9 @@
 	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),\
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
index 5f53f8747812..98aaa22ce81c 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
@@ -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);
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
index a8e978d1fae8..a6d76f451cf8 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
@@ -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);
 }
 
-- 
2.54.0


  parent reply	other threads:[~2026-05-12 15:52 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-12 15:52 [PATCH v5 00/13] HDMI FRL and DSC Support for amdgpu Harry Wentland
2026-05-12 15:52 ` [PATCH v5 01/13] drm/amd/display: Add HDMI FRL definitions to includes Harry Wentland
2026-05-12 15:52 ` [PATCH v5 02/13] drm/amd/display: Add DML changes to support HDMI FRL Harry Wentland
2026-05-12 15:52 ` [PATCH v5 03/13] drm/amd/display: add HDMI 2.1 FRL base support to DML 2.0 Harry Wentland
2026-05-12 15:52 ` Harry Wentland [this message]
2026-05-12 15:52 ` [PATCH v5 05/13] drm/amd/display: Add FRL support to clk_mgr, dsc, hdcp Harry Wentland
2026-05-12 15:52 ` [PATCH v5 06/13] drm/amd/display: Tie FRL programming together in HWSS Harry Wentland
2026-05-12 15:52 ` [PATCH v5 07/13] drm/amd/display: Add DC resource support for FRL Harry Wentland
2026-05-12 15:52 ` [PATCH v5 08/13] drm/amd/display Add DC link " Harry Wentland
2026-05-12 15:52 ` [PATCH v5 09/13] drm/amd/display: Add support for FRL to DC core Harry Wentland
2026-05-12 15:52 ` [PATCH v5 10/13] drm/amd/display: Update HDCP and info_packet modules for FRL Harry Wentland
2026-05-12 15:52 ` [PATCH v5 11/13] drm/amd/display: Tie FRL support into amdgpu_dm Harry Wentland
2026-05-13  0:11   ` [PATCH] drm/amd/display: fix FRL link-status polling never running dyllan
2026-05-12 15:52 ` [PATCH v5 12/13] drm/amd/display: add HDMI 2.1 Compliance Support Harry Wentland
2026-05-12 15:52 ` [PATCH v5 13/13] drm/amd/display: add HDMI 2.1 DSC over FRL support Harry Wentland
2026-05-17 18:58 ` [PATCH v5 00/13] HDMI FRL and DSC Support for amdgpu Tomasz Pakuła

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260512155244.403854-5-harry.wentland@amd.com \
    --to=harry.wentland@amd.com \
    --cc=Jerry.Zuo@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox