All of lore.kernel.org
 help / color / mirror / Atom feed
From: Harry Wentland <harry.wentland@amd.com>
To: dri-devel@lists.freedesktop.org
Subject: [PATCH v2 13/26] drm/amd/dal: Add encoder HW programming
Date: Tue, 16 Feb 2016 17:27:53 -0500	[thread overview]
Message-ID: <e151463d2b53a5a0db7e4db574362696538310d3.1455660367.git.harry.wentland@amd.com> (raw)
In-Reply-To: <cover.1455660366.git.harry.wentland@amd.com>

Responsible for programming back-end of display path, such as DIG,
UNIPHY, DP, DAC, and DVO.
Supports:
- DisplayPort (single stream)
- HDMI
- DVI
- eDP

Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
---
 .../drm/amd/dal/dc/dce110/dce110_link_encoder.c    | 1927 ++++++++++++++++++++
 .../drm/amd/dal/dc/dce110/dce110_link_encoder.h    |  156 ++
 .../drm/amd/dal/dc/dce110/dce110_stream_encoder.c  | 1123 ++++++++++++
 .../drm/amd/dal/dc/dce110/dce110_stream_encoder.h  |  122 ++
 4 files changed, 3328 insertions(+)
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.h

diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c
new file mode 100644
index 000000000000..f714215c0dd5
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c
@@ -0,0 +1,1927 @@
+/*
+ * Copyright 2012-15 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 "dm_services.h"
+#include "core_types.h"
+#include "link_encoder.h"
+#include "stream_encoder.h"
+#include "dce110_link_encoder.h"
+
+#include "i2caux_interface.h"
+#include "dc_bios_types.h"
+
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+#include "dce/dce_11_0_enum.h"
+
+#define LINK_REG(reg)\
+	(enc110->link_regs->reg)
+
+#define AUX_REG(reg)\
+	(enc110->aux_regs->reg)
+
+#define BL_REG(reg)\
+	(enc110->bl_regs->reg)
+
+/* For current ASICs pixel clock - 600MHz */
+#define MAX_ENCODER_CLK 600000
+
+#define DCE11_UNIPHY_MAX_PIXEL_CLK_IN_KHZ 600000
+
+#define DEFAULT_AUX_MAX_DATA_SIZE 16
+#define AUX_MAX_DEFER_WRITE_RETRY 20
+/*
+ * @brief
+ * Trigger Source Select
+ * ASIC-dependent, actual values for register programming
+ */
+#define DCE110_DIG_FE_SOURCE_SELECT_INVALID 0x0
+#define DCE110_DIG_FE_SOURCE_SELECT_DIGA 0x1
+#define DCE110_DIG_FE_SOURCE_SELECT_DIGB 0x2
+#define DCE110_DIG_FE_SOURCE_SELECT_DIGC 0x4
+#define DCE110_DIG_FE_SOURCE_SELECT_DIGD 0x08
+#define DCE110_DIG_FE_SOURCE_SELECT_DIGE 0x10
+#define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20
+
+/* all values are in milliseconds */
+/* For eDP, after power-up/power/down,
+ * 300/500 msec max. delay from LCDVCC to black video generation */
+#define PANEL_POWER_UP_TIMEOUT 300
+#define PANEL_POWER_DOWN_TIMEOUT 500
+#define HPD_CHECK_INTERVAL 10
+
+/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */
+#define TMDS_MIN_PIXEL_CLOCK 25000
+/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */
+#define TMDS_MAX_PIXEL_CLOCK 165000
+/* For current ASICs pixel clock - 600MHz */
+#define MAX_ENCODER_CLOCK 600000
+
+enum {
+	DP_MST_UPDATE_MAX_RETRY = 50
+};
+
+#define DIG_REG(reg)\
+	(reg + enc110->offsets.dig)
+
+#define DP_REG(reg)\
+	(reg + enc110->offsets.dp)
+
+static struct link_encoder_funcs dce110_lnk_enc_funcs = {
+	.validate_output_with_stream =
+		dce110_link_encoder_validate_output_with_stream,
+	.hw_init = dce110_link_encoder_hw_init,
+	.setup = dce110_link_encoder_setup,
+	.enable_tmds_output = dce110_link_encoder_enable_tmds_output,
+	.enable_dp_output = dce110_link_encoder_enable_dp_output,
+	.enable_dp_mst_output = dce110_link_encoder_enable_dp_mst_output,
+	.disable_output = dce110_link_encoder_disable_output,
+	.dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings,
+	.dp_set_phy_pattern = dce110_link_encoder_dp_set_phy_pattern,
+	.update_mst_stream_allocation_table =
+		dce110_link_encoder_update_mst_stream_allocation_table,
+	.set_lcd_backlight_level = dce110_link_encoder_set_lcd_backlight_level,
+	.backlight_control = dce110_link_encoder_edp_backlight_control,
+	.power_control = dce110_link_encoder_edp_power_control,
+	.connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe
+};
+
+static enum bp_result link_transmitter_control(
+	struct dce110_link_encoder *enc110,
+	struct bp_transmitter_control *cntl)
+{
+	enum bp_result result;
+	struct dc_bios *bp = dal_adapter_service_get_bios_parser(
+					enc110->base.adapter_service);
+
+	result = bp->funcs->transmitter_control(bp, cntl);
+
+	return result;
+}
+
+static void enable_phy_bypass_mode(
+	struct dce110_link_encoder *enc110,
+	bool enable)
+{
+	/* This register resides in DP back end block;
+	 * transmitter is used for the offset */
+	struct dc_context *ctx = enc110->base.ctx;
+
+	const uint32_t addr = LINK_REG(DP_DPHY_CNTL);
+
+	uint32_t value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(value, enable, DP_DPHY_CNTL, DPHY_BYPASS);
+
+	dm_write_reg(ctx, addr, value);
+}
+
+static void disable_prbs_symbols(
+	struct dce110_link_encoder *enc110,
+	bool disable)
+{
+	/* This register resides in DP back end block;
+	 * transmitter is used for the offset */
+	struct dc_context *ctx = enc110->base.ctx;
+
+	const uint32_t addr = LINK_REG(DP_DPHY_CNTL);
+
+	uint32_t value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(value, disable,
+			DP_DPHY_CNTL, DPHY_ATEST_SEL_LANE0);
+
+	set_reg_field_value(value, disable,
+			DP_DPHY_CNTL, DPHY_ATEST_SEL_LANE1);
+
+	set_reg_field_value(value, disable,
+			DP_DPHY_CNTL, DPHY_ATEST_SEL_LANE2);
+
+	set_reg_field_value(value, disable,
+			DP_DPHY_CNTL, DPHY_ATEST_SEL_LANE3);
+
+	dm_write_reg(ctx, addr, value);
+}
+
+static void disable_prbs_mode(
+	struct dce110_link_encoder *enc110)
+{
+	/* This register resides in DP back end block;
+	 * transmitter is used for the offset */
+	struct dc_context *ctx = enc110->base.ctx;
+
+	const uint32_t addr = LINK_REG(DP_DPHY_PRBS_CNTL);
+	uint32_t value;
+
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(value, 0, DP_DPHY_PRBS_CNTL, DPHY_PRBS_EN);
+
+	dm_write_reg(ctx, addr, value);
+}
+
+static void program_pattern_symbols(
+	struct dce110_link_encoder *enc110,
+	uint16_t pattern_symbols[8])
+{
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr;
+	uint32_t value;
+
+	/* This register resides in DP back end block;
+	 * transmitter is used for the offset */
+
+	addr = LINK_REG(DP_DPHY_SYM0);
+
+	value = 0;
+	set_reg_field_value(value, pattern_symbols[0],
+			DP_DPHY_SYM0, DPHY_SYM1);
+	set_reg_field_value(value, pattern_symbols[1],
+			DP_DPHY_SYM0, DPHY_SYM2);
+	set_reg_field_value(value, pattern_symbols[2],
+			DP_DPHY_SYM0, DPHY_SYM3);
+	dm_write_reg(ctx, addr, value);
+
+	/* This register resides in DP back end block;
+	 * transmitter is used for the offset */
+
+	addr = LINK_REG(DP_DPHY_SYM1);
+
+	value = 0;
+	set_reg_field_value(value, pattern_symbols[3],
+			DP_DPHY_SYM1, DPHY_SYM4);
+	set_reg_field_value(value, pattern_symbols[4],
+			DP_DPHY_SYM1, DPHY_SYM5);
+	set_reg_field_value(value, pattern_symbols[5],
+			DP_DPHY_SYM1, DPHY_SYM6);
+	dm_write_reg(ctx, addr, value);
+
+	/* This register resides in DP back end block;
+	 * transmitter is used for the offset */
+	addr = LINK_REG(DP_DPHY_SYM2);
+	value = 0;
+	set_reg_field_value(value, pattern_symbols[6],
+			DP_DPHY_SYM2, DPHY_SYM7);
+	set_reg_field_value(value, pattern_symbols[6],
+			DP_DPHY_SYM2, DPHY_SYM8);
+
+	dm_write_reg(ctx, addr, value);
+}
+
+static void set_dp_phy_pattern_d102(
+	struct dce110_link_encoder *enc110)
+{
+	/* Disable PHY Bypass mode to setup the test pattern */
+	enable_phy_bypass_mode(enc110, false);
+
+	/* For 10-bit PRBS or debug symbols
+	 * please use the following sequence: */
+
+	/* Enable debug symbols on the lanes */
+
+	disable_prbs_symbols(enc110, true);
+
+	/* Disable PRBS mode,
+	 * make sure DPHY_PRBS_CNTL.DPHY_PRBS_EN=0 */
+
+	disable_prbs_mode(enc110);
+
+	/* Program debug symbols to be output */
+	{
+		uint16_t pattern_symbols[8] = {
+			0x2AA, 0x2AA, 0x2AA, 0x2AA,
+			0x2AA, 0x2AA, 0x2AA, 0x2AA
+		};
+
+		program_pattern_symbols(enc110, pattern_symbols);
+	}
+
+	/* Enable phy bypass mode to enable the test pattern */
+
+	enable_phy_bypass_mode(enc110, true);
+}
+
+static void set_link_training_complete(
+	struct dce110_link_encoder *enc110,
+	bool complete)
+{
+	/* This register resides in DP back end block;
+	 * transmitter is used for the offset */
+	struct dc_context *ctx = enc110->base.ctx;
+	const uint32_t addr = LINK_REG(DP_LINK_CNTL);
+	uint32_t value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(value, complete,
+			DP_LINK_CNTL, DP_LINK_TRAINING_COMPLETE);
+
+	dm_write_reg(ctx, addr, value);
+}
+
+static void set_dp_phy_pattern_training_pattern(
+	struct dce110_link_encoder *enc110,
+	uint32_t index)
+{
+	/* Write Training Pattern */
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr = LINK_REG(DP_DPHY_TRAINING_PATTERN_SEL);
+
+	dm_write_reg(ctx, addr, index);
+
+	/* Set HW Register Training Complete to false */
+
+	set_link_training_complete(enc110, false);
+
+	/* Disable PHY Bypass mode to output Training Pattern */
+
+	enable_phy_bypass_mode(enc110, false);
+
+	/* Disable PRBS mode,
+	 * make sure DPHY_PRBS_CNTL.DPHY_PRBS_EN=0 */
+
+	disable_prbs_mode(enc110);
+}
+
+static void set_dp_phy_pattern_symbol_error(
+	struct dce110_link_encoder *enc110)
+{
+	/* Disable PHY Bypass mode to setup the test pattern */
+	struct dc_context *ctx = enc110->base.ctx;
+
+	enable_phy_bypass_mode(enc110, false);
+
+	/* program correct panel mode*/
+	{
+		const uint32_t addr = LINK_REG(DP_DPHY_INTERNAL_CTRL);
+		uint32_t value = 0x0;
+		dm_write_reg(ctx, addr, value);
+	}
+
+	/* A PRBS23 pattern is used for most DP electrical measurements. */
+
+	/* Enable PRBS symbols on the lanes */
+
+	disable_prbs_symbols(enc110, false);
+
+	/* For PRBS23 Set bit DPHY_PRBS_SEL=1 and Set bit DPHY_PRBS_EN=1 */
+	{
+		const uint32_t addr = LINK_REG(DP_DPHY_PRBS_CNTL);
+		uint32_t value = dm_read_reg(ctx, addr);
+
+		set_reg_field_value(value, 1,
+				DP_DPHY_PRBS_CNTL, DPHY_PRBS_SEL);
+		set_reg_field_value(value, 1,
+				DP_DPHY_PRBS_CNTL, DPHY_PRBS_EN);
+		dm_write_reg(ctx, addr, value);
+	}
+
+	/* Enable phy bypass mode to enable the test pattern */
+
+	enable_phy_bypass_mode(enc110, true);
+}
+
+static void set_dp_phy_pattern_prbs7(
+	struct dce110_link_encoder *enc110)
+{
+	/* Disable PHY Bypass mode to setup the test pattern */
+	struct dc_context *ctx = enc110->base.ctx;
+
+	enable_phy_bypass_mode(enc110, false);
+
+	/* A PRBS7 pattern is used for most DP electrical measurements. */
+
+	/* Enable PRBS symbols on the lanes */
+
+	disable_prbs_symbols(enc110, false);
+
+	/* For PRBS7 Set bit DPHY_PRBS_SEL=0 and Set bit DPHY_PRBS_EN=1 */
+	{
+		const uint32_t addr = LINK_REG(DP_DPHY_PRBS_CNTL);
+
+		uint32_t value = dm_read_reg(ctx, addr);
+
+		set_reg_field_value(value, 0,
+				DP_DPHY_PRBS_CNTL, DPHY_PRBS_SEL);
+
+		set_reg_field_value(value, 1,
+				DP_DPHY_PRBS_CNTL, DPHY_PRBS_EN);
+
+		dm_write_reg(ctx, addr, value);
+	}
+
+	/* Enable phy bypass mode to enable the test pattern */
+
+	enable_phy_bypass_mode(enc110, true);
+}
+
+static void set_dp_phy_pattern_80bit_custom(
+	struct dce110_link_encoder *enc110,
+	const uint8_t *pattern)
+{
+	/* Disable PHY Bypass mode to setup the test pattern */
+	enable_phy_bypass_mode(enc110, false);
+
+	/* Enable debug symbols on the lanes */
+
+	disable_prbs_symbols(enc110, true);
+
+	/* Enable PHY bypass mode to enable the test pattern */
+	/* TODO is it really needed ? */
+
+	enable_phy_bypass_mode(enc110, true);
+
+	/* Program 80 bit custom pattern */
+	{
+		uint16_t pattern_symbols[8];
+
+		pattern_symbols[0] =
+			((pattern[1] & 0x03) << 8) | pattern[0];
+		pattern_symbols[1] =
+			((pattern[2] & 0x0f) << 6) | ((pattern[1] >> 2) & 0x3f);
+		pattern_symbols[2] =
+			((pattern[3] & 0x3f) << 4) | ((pattern[2] >> 4) & 0x0f);
+		pattern_symbols[3] =
+			(pattern[4] << 2) | ((pattern[3] >> 6) & 0x03);
+		pattern_symbols[4] =
+			((pattern[6] & 0x03) << 8) | pattern[5];
+		pattern_symbols[5] =
+			((pattern[7] & 0x0f) << 6) | ((pattern[6] >> 2) & 0x3f);
+		pattern_symbols[6] =
+			((pattern[8] & 0x3f) << 4) | ((pattern[7] >> 4) & 0x0f);
+		pattern_symbols[7] =
+			(pattern[9] << 2) | ((pattern[8] >> 6) & 0x03);
+
+		program_pattern_symbols(enc110, pattern_symbols);
+	}
+
+	/* Enable phy bypass mode to enable the test pattern */
+
+	enable_phy_bypass_mode(enc110, true);
+}
+
+static void set_dp_phy_pattern_hbr2_compliance(
+	struct dce110_link_encoder *enc110)
+{
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr;
+	uint32_t value;
+
+	/* previously there is a register DP_HBR2_EYE_PATTERN
+	 * that is enabled to get the pattern.
+	 * But it does not work with the latest spec change,
+	 * so we are programming the following registers manually.
+	 *
+	 * The following settings have been confirmed
+	 * by Nick Chorney and Sandra Liu */
+
+	/* Disable PHY Bypass mode to setup the test pattern */
+
+	enable_phy_bypass_mode(enc110, false);
+
+	/* Setup DIG encoder in DP SST mode */
+
+	enc110->base.funcs->setup(&enc110->base, SIGNAL_TYPE_DISPLAY_PORT);
+
+	/* program correct panel mode*/
+	{
+		const uint32_t addr = LINK_REG(DP_DPHY_INTERNAL_CTRL);
+		uint32_t value = 0x0;
+		dm_write_reg(ctx, addr, value);
+	}
+
+	/* no vbid after BS (SR)
+	 * DP_LINK_FRAMING_CNTL changed history Sandra Liu
+	 * 11000260 / 11000104 / 110000FC */
+
+	/* TODO DP_LINK_FRAMING_CNTL should always use hardware default value
+	 * output  except output hbr2_compliance pattern for physical PHY
+	 * measurement. This is not normal usage case. SW should reset this
+	 * register to hardware default value after end use of HBR2 eye
+	 */
+	BREAK_TO_DEBUGGER();
+	/* TODO: do we still need this, find out at compliance test
+	addr = mmDP_LINK_FRAMING_CNTL + fe_addr_offset;
+
+	value = (ctx, addr);
+
+	set_reg_field_value(value, 0xFC,
+			DP_LINK_FRAMING_CNTL, DP_IDLE_BS_INTERVAL);
+	set_reg_field_value(value, 1,
+			DP_LINK_FRAMING_CNTL, DP_VBID_DISABLE);
+	set_reg_field_value(value, 1,
+			DP_LINK_FRAMING_CNTL, DP_VID_ENHANCED_FRAME_MODE);
+
+	dal_write_reg(ctx, addr, value);
+	 */
+
+	/*TODO add support for this test pattern
+	 * support_dp_hbr2_eye_pattern
+	 */
+
+	/* set link training complete */
+	set_link_training_complete(enc110, true);
+	/* do not enable video stream */
+	addr = LINK_REG(DP_VID_STREAM_CNTL);
+
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(value, 0, DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE);
+
+	dm_write_reg(ctx, addr, value);
+
+	/* Disable PHY Bypass mode to setup the test pattern */
+
+	enable_phy_bypass_mode(enc110, false);
+}
+
+static void set_dp_phy_pattern_passthrough_mode(
+	struct dce110_link_encoder *enc110,
+	enum dp_panel_mode panel_mode)
+{
+	struct dc_context *ctx = enc110->base.ctx;
+
+	/* program correct panel mode */
+	{
+		const uint32_t addr = LINK_REG(DP_DPHY_INTERNAL_CTRL);
+
+		uint32_t value;
+
+		value = dm_read_reg(ctx, addr);
+
+		switch (panel_mode) {
+		case DP_PANEL_MODE_EDP:
+			value = 0x1;
+		break;
+		case DP_PANEL_MODE_SPECIAL:
+			value = 0x11;
+		break;
+		default:
+			value = 0x0;
+			break;
+		}
+
+		dm_write_reg(ctx, addr, value);
+	}
+
+	/* set link training complete */
+
+	set_link_training_complete(enc110, true);
+
+	/* Disable PHY Bypass mode to setup the test pattern */
+
+	enable_phy_bypass_mode(enc110, false);
+
+	/* Disable PRBS mode,
+	 * make sure DPHY_PRBS_CNTL.DPHY_PRBS_EN=0 */
+
+	disable_prbs_mode(enc110);
+}
+
+/* return value is bit-vector */
+static uint8_t get_frontend_source(
+	enum engine_id engine)
+{
+	switch (engine) {
+	case ENGINE_ID_DIGA:
+		return DCE110_DIG_FE_SOURCE_SELECT_DIGA;
+	case ENGINE_ID_DIGB:
+		return DCE110_DIG_FE_SOURCE_SELECT_DIGB;
+	case ENGINE_ID_DIGC:
+		return DCE110_DIG_FE_SOURCE_SELECT_DIGC;
+	case ENGINE_ID_DIGD:
+		return DCE110_DIG_FE_SOURCE_SELECT_DIGD;
+	case ENGINE_ID_DIGE:
+		return DCE110_DIG_FE_SOURCE_SELECT_DIGE;
+	case ENGINE_ID_DIGF:
+		return DCE110_DIG_FE_SOURCE_SELECT_DIGF;
+	default:
+		ASSERT_CRITICAL(false);
+		return DCE110_DIG_FE_SOURCE_SELECT_INVALID;
+	}
+}
+
+static void configure_encoder(
+	struct dce110_link_encoder *enc110,
+	const struct link_settings *link_settings)
+{
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr;
+	uint32_t value;
+
+	/* set number of lanes */
+	addr = LINK_REG(DP_CONFIG);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(value, link_settings->lane_count - LANE_COUNT_ONE,
+			DP_CONFIG, DP_UDI_LANES);
+	dm_write_reg(ctx, addr, value);
+
+}
+
+static bool is_panel_powered_on(struct dce110_link_encoder *enc110)
+{
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t value;
+	bool ret;
+
+	value = dm_read_reg(ctx,
+			BL_REG(LVTMA_PWRSEQ_STATE));
+
+	ret = get_reg_field_value(value,
+			LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R);
+
+	return ret == 1;
+}
+
+/*
+ * @brief
+ * eDP only.
+ */
+static void link_encoder_edp_wait_for_hpd_ready(
+	struct dce110_link_encoder *enc110,
+	bool power_up)
+{
+	struct dc_context *ctx = enc110->base.ctx;
+	struct adapter_service *as = enc110->base.adapter_service;
+	struct graphics_object_id connector = enc110->base.connector;
+	struct irq *hpd;
+	bool edp_hpd_high = false;
+	uint32_t time_elapsed = 0;
+	uint32_t timeout = power_up ?
+		PANEL_POWER_UP_TIMEOUT : PANEL_POWER_DOWN_TIMEOUT;
+
+	if (dal_graphics_object_id_get_connector_id(connector) !=
+		CONNECTOR_ID_EDP) {
+		BREAK_TO_DEBUGGER();
+		return;
+	}
+
+	if (!power_up && dal_adapter_service_is_feature_supported(
+		FEATURE_NO_HPD_LOW_POLLING_VCC_OFF))
+		/* from KV, we will not HPD low after turning off VCC -
+		 * instead, we will check the SW timer in power_up(). */
+		return;
+
+	/* when we power on/off the eDP panel,
+	 * we need to wait until SENSE bit is high/low */
+
+	/* obtain HPD */
+
+	hpd = dal_adapter_service_obtain_hpd_irq(as, connector);
+
+	if (!hpd) {
+		BREAK_TO_DEBUGGER();
+		return;
+	}
+
+	dal_irq_open(hpd);
+
+	/* wait until timeout or panel detected */
+
+	do {
+		uint32_t detected = 0;
+
+		dal_irq_get_value(hpd, &detected);
+
+		if (!(detected ^ power_up)) {
+			edp_hpd_high = true;
+			break;
+		}
+
+		dm_sleep_in_milliseconds(ctx, HPD_CHECK_INTERVAL);
+
+		time_elapsed += HPD_CHECK_INTERVAL;
+	} while (time_elapsed < timeout);
+
+	dal_irq_close(hpd);
+
+	dal_adapter_service_release_irq(as, hpd);
+
+	if (false == edp_hpd_high) {
+		dal_logger_write(ctx->logger,
+				LOG_MAJOR_ERROR,
+				LOG_MINOR_HW_TRACE_RESUME_S3,
+				"%s: wait timed out!\n", __func__);
+	}
+}
+
+/*
+ * @brief
+ * eDP only. Control the power of the eDP panel.
+ */
+void dce110_link_encoder_edp_power_control(
+	struct link_encoder *enc,
+	bool power_up)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	struct bp_transmitter_control cntl = { 0 };
+	enum bp_result bp_result;
+
+	if (dal_graphics_object_id_get_connector_id(enc110->base.connector) !=
+		CONNECTOR_ID_EDP) {
+		BREAK_TO_DEBUGGER();
+		return;
+	}
+
+	if ((power_up && !is_panel_powered_on(enc110)) ||
+		(!power_up && is_panel_powered_on(enc110))) {
+
+		/* Send VBIOS command to prompt eDP panel power */
+
+		dal_logger_write(ctx->logger,
+				LOG_MAJOR_HW_TRACE,
+				LOG_MINOR_HW_TRACE_RESUME_S3,
+				"%s: Panel Power action: %s\n",
+				__func__, (power_up ? "On":"Off"));
+
+		cntl.action = power_up ?
+			TRANSMITTER_CONTROL_POWER_ON :
+			TRANSMITTER_CONTROL_POWER_OFF;
+		cntl.transmitter = enc110->base.transmitter;
+		cntl.connector_obj_id = enc110->base.connector;
+		cntl.coherent = false;
+		cntl.lanes_number = LANE_COUNT_FOUR;
+		cntl.hpd_sel = enc110->base.hpd_source;
+
+		bp_result = link_transmitter_control(enc110, &cntl);
+
+		if (BP_RESULT_OK != bp_result) {
+
+			dal_logger_write(ctx->logger,
+					LOG_MAJOR_ERROR,
+					LOG_MINOR_HW_TRACE_RESUME_S3,
+					"%s: Panel Power bp_result: %d\n",
+					__func__, bp_result);
+		}
+	} else {
+		dal_logger_write(ctx->logger,
+				LOG_MAJOR_HW_TRACE,
+				LOG_MINOR_HW_TRACE_RESUME_S3,
+				"%s: Skipping Panel Power action: %s\n",
+				__func__, (power_up ? "On":"Off"));
+	}
+
+	link_encoder_edp_wait_for_hpd_ready(enc110, true);
+}
+
+static void aux_initialize(
+	struct dce110_link_encoder *enc110)
+{
+	struct dc_context *ctx = enc110->base.ctx;
+	enum hpd_source_id hpd_source = enc110->base.hpd_source;
+	uint32_t addr = AUX_REG(AUX_CONTROL);
+	uint32_t value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(value, hpd_source, AUX_CONTROL, AUX_HPD_SEL);
+	set_reg_field_value(value, 0, AUX_CONTROL, AUX_LS_READ_EN);
+	dm_write_reg(ctx, addr, value);
+
+	addr = AUX_REG(AUX_DPHY_RX_CONTROL0);
+	value = dm_read_reg(ctx, addr);
+
+	/* 1/4 window (the maximum allowed) */
+	set_reg_field_value(value, 1,
+			AUX_DPHY_RX_CONTROL0, AUX_RX_RECEIVE_WINDOW);
+	dm_write_reg(ctx, addr, value);
+
+}
+
+/*todo: cloned in stream enc, fix*/
+static bool is_panel_backlight_on(struct dce110_link_encoder *enc110)
+{
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t value;
+
+	value = dm_read_reg(ctx, BL_REG(LVTMA_PWRSEQ_CNTL));
+
+	return get_reg_field_value(value, LVTMA_PWRSEQ_CNTL, LVTMA_BLON);
+}
+
+/*todo: cloned in stream enc, fix*/
+/*
+ * @brief
+ * eDP only. Control the backlight of the eDP panel
+ */
+void dce110_link_encoder_edp_backlight_control(
+	struct link_encoder *enc,
+	bool enable)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	struct bp_transmitter_control cntl = { 0 };
+
+	if (dal_graphics_object_id_get_connector_id(enc110->base.connector)
+		!= CONNECTOR_ID_EDP) {
+		BREAK_TO_DEBUGGER();
+		return;
+	}
+
+	if (enable && is_panel_backlight_on(enc110)) {
+		dal_logger_write(ctx->logger,
+				LOG_MAJOR_HW_TRACE,
+				LOG_MINOR_HW_TRACE_RESUME_S3,
+				"%s: panel already powered up. Do nothing.\n",
+				__func__);
+		return;
+	}
+
+	if (!enable && !is_panel_powered_on(enc110)) {
+		dal_logger_write(ctx->logger,
+				LOG_MAJOR_HW_TRACE,
+				LOG_MINOR_HW_TRACE_RESUME_S3,
+				"%s: panel already powered down. Do nothing.\n",
+				__func__);
+		return;
+	}
+
+	/* Send VBIOS command to control eDP panel backlight */
+
+	dal_logger_write(ctx->logger,
+			LOG_MAJOR_HW_TRACE,
+			LOG_MINOR_HW_TRACE_RESUME_S3,
+			"%s: backlight action: %s\n",
+			__func__, (enable ? "On":"Off"));
+
+	cntl.action = enable ?
+		TRANSMITTER_CONTROL_BACKLIGHT_ON :
+		TRANSMITTER_CONTROL_BACKLIGHT_OFF;
+	/*cntl.engine_id = ctx->engine;*/
+	cntl.transmitter = enc110->base.transmitter;
+	cntl.connector_obj_id = enc110->base.connector;
+	/*todo: unhardcode*/
+	cntl.lanes_number = LANE_COUNT_FOUR;
+	cntl.hpd_sel = enc110->base.hpd_source;
+
+	/* For eDP, the following delays might need to be considered
+	 * after link training completed:
+	 * idle period - min. accounts for required BS-Idle pattern,
+	 * max. allows for source frame synchronization);
+	 * 50 msec max. delay from valid video data from source
+	 * to video on dislpay or backlight enable.
+	 *
+	 * Disable the delay for now.
+	 * Enable it in the future if necessary.
+	 */
+	/* dc_service_sleep_in_milliseconds(50); */
+	link_transmitter_control(enc110, &cntl);
+}
+
+static bool is_dig_enabled(const struct dce110_link_encoder *enc110)
+{
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t value;
+
+	value = dm_read_reg(ctx, LINK_REG(DIG_BE_EN_CNTL));
+
+	return get_reg_field_value(value, DIG_BE_EN_CNTL, DIG_ENABLE);
+}
+
+static void link_encoder_disable(struct dce110_link_encoder *enc110)
+{
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr;
+	uint32_t value;
+
+	/* reset training pattern */
+	addr = LINK_REG(DP_DPHY_TRAINING_PATTERN_SEL);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(value, 0,
+			DP_DPHY_TRAINING_PATTERN_SEL,
+			DPHY_TRAINING_PATTERN_SEL);
+	dm_write_reg(ctx, addr, value);
+
+	/* reset training complete */
+	addr = LINK_REG(DP_LINK_CNTL);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(value, 0, DP_LINK_CNTL, DP_LINK_TRAINING_COMPLETE);
+	dm_write_reg(ctx, addr, value);
+
+	/* reset panel mode */
+	addr = LINK_REG(DP_DPHY_INTERNAL_CTRL);
+	value = 0;
+	dm_write_reg(ctx, addr, value);
+}
+
+static void hpd_initialize(
+	struct dce110_link_encoder *enc110)
+{
+	/* Associate HPD with DIG_BE */
+	struct dc_context *ctx = enc110->base.ctx;
+	enum hpd_source_id hpd_source = enc110->base.hpd_source;
+	const uint32_t addr = LINK_REG(DIG_BE_CNTL);
+	uint32_t value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(value, hpd_source, DIG_BE_CNTL, DIG_HPD_SELECT);
+	dm_write_reg(ctx, addr, value);
+}
+
+static bool validate_dvi_output(
+	const struct dce110_link_encoder *enc110,
+	enum signal_type connector_signal,
+	enum signal_type signal,
+	const struct dc_crtc_timing *crtc_timing)
+{
+	uint32_t max_pixel_clock = TMDS_MAX_PIXEL_CLOCK;
+
+	if (enc110->base.features.max_pixel_clock < TMDS_MAX_PIXEL_CLOCK)
+		max_pixel_clock = enc110->base.features.max_pixel_clock;
+
+	if (signal == SIGNAL_TYPE_DVI_DUAL_LINK)
+		max_pixel_clock <<= 1;
+
+	/* This handles the case of HDMI downgrade to DVI we don't want to
+	 * we don't want to cap the pixel clock if the DDI is not DVI.
+	 */
+	if (connector_signal != SIGNAL_TYPE_DVI_DUAL_LINK &&
+			connector_signal != SIGNAL_TYPE_DVI_SINGLE_LINK)
+		max_pixel_clock = enc110->base.features.max_pixel_clock;
+
+	/* DVI only support RGB pixel encoding */
+	if (crtc_timing->pixel_encoding != PIXEL_ENCODING_RGB)
+		return false;
+
+	if (crtc_timing->pix_clk_khz < TMDS_MIN_PIXEL_CLOCK)
+		return false;
+
+	if (crtc_timing->pix_clk_khz > max_pixel_clock)
+		return false;
+
+	/* DVI supports 6/8bpp single-link and 10/16bpp dual-link */
+	switch (crtc_timing->display_color_depth) {
+	case COLOR_DEPTH_666:
+	case COLOR_DEPTH_888:
+	break;
+	case COLOR_DEPTH_101010:
+	case COLOR_DEPTH_161616:
+		if (signal != SIGNAL_TYPE_DVI_DUAL_LINK)
+			return false;
+	break;
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+static bool validate_hdmi_output(
+	const struct dce110_link_encoder *enc110,
+	const struct dc_crtc_timing *crtc_timing,
+	uint32_t max_tmds_clk_from_edid_in_mhz,
+	enum dc_color_depth max_hdmi_deep_color,
+	uint32_t max_hdmi_pixel_clock)
+{
+	enum dc_color_depth max_deep_color = max_hdmi_deep_color;
+	/* expressed in KHz */
+	uint32_t pixel_clock = 0;
+
+	/*TODO: unhardcode*/
+	max_tmds_clk_from_edid_in_mhz = 0;
+	max_hdmi_deep_color = COLOR_DEPTH_121212;
+	max_hdmi_pixel_clock = 600000;
+
+	if (max_deep_color > enc110->base.features.max_deep_color)
+		max_deep_color = enc110->base.features.max_deep_color;
+
+	if (max_deep_color < crtc_timing->display_color_depth)
+		return false;
+
+	if (crtc_timing->pix_clk_khz < TMDS_MIN_PIXEL_CLOCK)
+		return false;
+
+	switch (crtc_timing->display_color_depth) {
+	case COLOR_DEPTH_666:
+		pixel_clock = (crtc_timing->pix_clk_khz * 3) >> 2;
+	break;
+	case COLOR_DEPTH_888:
+		pixel_clock = crtc_timing->pix_clk_khz;
+	break;
+	case COLOR_DEPTH_101010:
+		pixel_clock = (crtc_timing->pix_clk_khz * 10) >> 3;
+	break;
+	case COLOR_DEPTH_121212:
+		pixel_clock = (crtc_timing->pix_clk_khz * 3) >> 1;
+	break;
+	case COLOR_DEPTH_161616:
+		pixel_clock = crtc_timing->pix_clk_khz << 1;
+	break;
+	default:
+	break;
+	}
+
+	if (max_tmds_clk_from_edid_in_mhz > 0)
+		if (pixel_clock > max_tmds_clk_from_edid_in_mhz * 1000)
+			return false;
+
+	if ((pixel_clock == 0) ||
+		(pixel_clock > max_hdmi_pixel_clock) ||
+		(pixel_clock > enc110->base.features.max_pixel_clock))
+		return false;
+
+	/*
+	 * Restriction: allow non-CE mode (IT mode) to support RGB only.
+	 * When it is IT mode, the format mode will be 0,
+	 * but currently the code is broken,
+	 * VIDEO FORMAT is always 0 in validatepathMode().
+	 * Due to overscan change - need fix there and test the impact - to do.
+	 */
+	if (crtc_timing->timing_standard != TIMING_STANDARD_CEA861 &&
+		crtc_timing->timing_standard != TIMING_STANDARD_HDMI)
+		if (crtc_timing->pixel_encoding !=
+			PIXEL_ENCODING_RGB)
+			return false;
+
+	/* DCE11 HW does not support 420 */
+	if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
+		return false;
+
+	return true;
+}
+
+static bool validate_rgb_output(
+	const struct dce110_link_encoder *enc110,
+	const struct dc_crtc_timing *crtc_timing)
+{
+	if (crtc_timing->pix_clk_khz > enc110->base.features.max_pixel_clock)
+		return false;
+
+	if (crtc_timing->pixel_encoding != PIXEL_ENCODING_RGB)
+		return false;
+
+	return true;
+}
+
+static bool validate_dp_output(
+	const struct dce110_link_encoder *enc110,
+	const struct dc_crtc_timing *crtc_timing)
+{
+	if (crtc_timing->pix_clk_khz > enc110->base.features.max_pixel_clock)
+		return false;
+
+	/* default RGB only */
+	if (crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB)
+		return true;
+
+	if (enc110->base.features.flags.bits.IS_YCBCR_CAPABLE)
+		return true;
+
+	/* for DCE 8.x or later DP Y-only feature,
+	 * we need ASIC cap + FeatureSupportDPYonly, not support 666 */
+	if (crtc_timing->flags.Y_ONLY &&
+		enc110->base.features.flags.bits.IS_YCBCR_CAPABLE &&
+		crtc_timing->display_color_depth != COLOR_DEPTH_666)
+		return true;
+
+	return false;
+}
+
+static bool validate_wireless_output(
+	const struct dce110_link_encoder *enc110,
+	const struct dc_crtc_timing *crtc_timing)
+{
+	if (crtc_timing->pix_clk_khz > enc110->base.features.max_pixel_clock)
+		return false;
+
+	/* Wireless only supports YCbCr444 */
+	if (crtc_timing->pixel_encoding ==
+			PIXEL_ENCODING_YCBCR444)
+		return true;
+
+	return false;
+}
+
+bool dce110_link_encoder_construct(
+	struct dce110_link_encoder *enc110,
+	const struct encoder_init_data *init_data,
+	const struct dce110_link_enc_registers *link_regs,
+	const struct dce110_link_enc_aux_registers *aux_regs,
+	const struct dce110_link_enc_bl_registers *bl_regs)
+{
+	struct graphics_object_encoder_cap_info enc_cap_info = {0};
+
+	enc110->base.funcs = &dce110_lnk_enc_funcs;
+	enc110->base.ctx = init_data->ctx;
+	enc110->base.id = init_data->encoder;
+
+	enc110->base.hpd_source = init_data->hpd_source;
+	enc110->base.connector = init_data->connector;
+	enc110->base.input_signals = SIGNAL_TYPE_ALL;
+
+	enc110->base.adapter_service = init_data->adapter_service;
+
+	enc110->base.preferred_engine = ENGINE_ID_UNKNOWN;
+
+	enc110->base.features.flags.raw = 0;
+
+	enc110->base.transmitter = init_data->transmitter;
+
+	enc110->base.features.flags.bits.IS_AUDIO_CAPABLE = true;
+
+	enc110->base.features.max_pixel_clock =
+		DCE11_UNIPHY_MAX_PIXEL_CLK_IN_KHZ;
+
+	/* set the flag to indicate whether driver poll the I2C data pin
+	 * while doing the DP sink detect
+	 */
+
+	if (dal_adapter_service_is_feature_supported(
+		FEATURE_DP_SINK_DETECT_POLL_DATA_PIN))
+		enc110->base.features.flags.bits.
+			DP_SINK_DETECT_POLL_DATA_PIN = true;
+
+	enc110->base.output_signals =
+		SIGNAL_TYPE_DVI_SINGLE_LINK |
+		SIGNAL_TYPE_DVI_DUAL_LINK |
+		SIGNAL_TYPE_LVDS |
+		SIGNAL_TYPE_DISPLAY_PORT |
+		SIGNAL_TYPE_DISPLAY_PORT_MST |
+		SIGNAL_TYPE_EDP |
+		SIGNAL_TYPE_HDMI_TYPE_A;
+
+	/* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE.
+	 * SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY.
+	 * SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer
+	 * DIG is per UNIPHY and used by SST DP, eDP, HDMI, DVI and LVDS.
+	 * Prefer DIG assignment is decided by board design.
+	 * For DCE 8.0, there are only max 6 UNIPHYs, we assume board design
+	 * and VBIOS will filter out 7 UNIPHY for DCE 8.0.
+	 * By this, adding DIGG should not hurt DCE 8.0.
+	 * This will let DCE 8.1 share DCE 8.0 as much as possible
+	 */
+
+	enc110->link_regs = link_regs;
+	enc110->aux_regs = aux_regs;
+	enc110->bl_regs = bl_regs;
+
+	switch (enc110->base.transmitter) {
+	case TRANSMITTER_UNIPHY_A:
+		enc110->base.preferred_engine = ENGINE_ID_DIGA;
+	break;
+	case TRANSMITTER_UNIPHY_B:
+		enc110->base.preferred_engine = ENGINE_ID_DIGB;
+	break;
+	case TRANSMITTER_UNIPHY_C:
+		enc110->base.preferred_engine = ENGINE_ID_DIGC;
+	break;
+	case TRANSMITTER_UNIPHY_D:
+		enc110->base.preferred_engine = ENGINE_ID_DIGD;
+	break;
+	case TRANSMITTER_UNIPHY_E:
+		enc110->base.preferred_engine = ENGINE_ID_DIGE;
+	break;
+	case TRANSMITTER_UNIPHY_F:
+		enc110->base.preferred_engine = ENGINE_ID_DIGF;
+	break;
+	default:
+		ASSERT_CRITICAL(false);
+		enc110->base.preferred_engine = ENGINE_ID_UNKNOWN;
+	}
+
+	dal_logger_write(init_data->ctx->logger,
+			LOG_MAJOR_I2C_AUX,
+			LOG_MINOR_I2C_AUX_CFG,
+			"Using channel: %s [%d]\n",
+			DECODE_CHANNEL_ID(init_data->channel),
+			init_data->channel);
+
+	/* Override features with DCE-specific values */
+	if (dal_adapter_service_get_encoder_cap_info(
+			enc110->base.adapter_service,
+			enc110->base.id, &enc_cap_info))
+		enc110->base.features.flags.bits.IS_HBR2_CAPABLE =
+				enc_cap_info.dp_hbr2_cap;
+
+	/* test pattern 3 support */
+	enc110->base.features.flags.bits.IS_TPS3_CAPABLE = true;
+	enc110->base.features.max_deep_color = COLOR_DEPTH_121212;
+
+	enc110->base.features.flags.bits.IS_Y_ONLY_CAPABLE =
+		dal_adapter_service_is_feature_supported(
+			FEATURE_SUPPORT_DP_Y_ONLY);
+
+	enc110->base.features.flags.bits.IS_YCBCR_CAPABLE =
+		dal_adapter_service_is_feature_supported(
+			FEATURE_SUPPORT_DP_YUV);
+	return true;
+}
+
+bool dce110_link_encoder_validate_output_with_stream(
+	struct link_encoder *enc,
+	struct core_stream *stream)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	bool is_valid;
+
+	switch (stream->signal) {
+	case SIGNAL_TYPE_DVI_SINGLE_LINK:
+	case SIGNAL_TYPE_DVI_DUAL_LINK:
+		is_valid = validate_dvi_output(
+			enc110,
+			stream->sink->link->public.connector_signal,
+			stream->signal,
+			&stream->public.timing);
+	break;
+	case SIGNAL_TYPE_HDMI_TYPE_A:
+		is_valid = validate_hdmi_output(
+				enc110,
+				&stream->public.timing,
+				stream->max_tmds_clk_from_edid_in_mhz,
+				stream->max_hdmi_deep_color,
+				stream->max_hdmi_pixel_clock);
+	break;
+	case SIGNAL_TYPE_RGB:
+		is_valid = validate_rgb_output(
+			enc110, &stream->public.timing);
+	break;
+	case SIGNAL_TYPE_DISPLAY_PORT:
+	case SIGNAL_TYPE_DISPLAY_PORT_MST:
+	case SIGNAL_TYPE_EDP:
+		is_valid = validate_dp_output(
+			enc110, &stream->public.timing);
+	break;
+	case SIGNAL_TYPE_WIRELESS:
+		is_valid = validate_wireless_output(
+			enc110, &stream->public.timing);
+	break;
+	default:
+		is_valid = true;
+	break;
+	}
+
+	return is_valid;
+}
+
+void dce110_link_encoder_hw_init(
+	struct link_encoder *enc)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	struct bp_transmitter_control cntl = { 0 };
+	enum bp_result result;
+
+	cntl.action = TRANSMITTER_CONTROL_INIT;
+	cntl.engine_id = ENGINE_ID_UNKNOWN;
+	cntl.transmitter = enc110->base.transmitter;
+	cntl.connector_obj_id = enc110->base.connector;
+	cntl.lanes_number = LANE_COUNT_FOUR;
+	cntl.coherent = false;
+	cntl.hpd_sel = enc110->base.hpd_source;
+
+	result = link_transmitter_control(enc110, &cntl);
+
+	if (result != BP_RESULT_OK) {
+		dal_logger_write(ctx->logger,
+			LOG_MAJOR_ERROR,
+			LOG_MINOR_COMPONENT_ENCODER,
+			"%s: Failed to execute VBIOS command table!\n",
+			__func__);
+		BREAK_TO_DEBUGGER();
+		return;
+	}
+
+	if (enc110->base.connector.id == CONNECTOR_ID_LVDS) {
+		cntl.action = TRANSMITTER_CONTROL_BACKLIGHT_BRIGHTNESS;
+
+		result = link_transmitter_control(enc110, &cntl);
+
+		ASSERT(result == BP_RESULT_OK);
+
+	} else if (enc110->base.connector.id == CONNECTOR_ID_EDP) {
+		enc->funcs->power_control(&enc110->base, true);
+	}
+	aux_initialize(enc110);
+
+	/* reinitialize HPD.
+	 * hpd_initialize() will pass DIG_FE id to HW context.
+	 * All other routine within HW context will use fe_engine_offset
+	 * as DIG_FE id even caller pass DIG_FE id.
+	 * So this routine must be called first. */
+	hpd_initialize(enc110);
+}
+
+void dce110_link_encoder_setup(
+	struct link_encoder *enc,
+	enum signal_type signal)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	const uint32_t addr = LINK_REG(DIG_BE_CNTL);
+	uint32_t value = dm_read_reg(ctx, addr);
+
+	switch (signal) {
+	case SIGNAL_TYPE_EDP:
+	case SIGNAL_TYPE_DISPLAY_PORT:
+		/* DP SST */
+		set_reg_field_value(value, 0, DIG_BE_CNTL, DIG_MODE);
+		break;
+	case SIGNAL_TYPE_LVDS:
+		/* LVDS */
+		set_reg_field_value(value, 1, DIG_BE_CNTL, DIG_MODE);
+		break;
+	case SIGNAL_TYPE_DVI_SINGLE_LINK:
+	case SIGNAL_TYPE_DVI_DUAL_LINK:
+		/* TMDS-DVI */
+		set_reg_field_value(value, 2, DIG_BE_CNTL, DIG_MODE);
+		break;
+	case SIGNAL_TYPE_HDMI_TYPE_A:
+		/* TMDS-HDMI */
+		set_reg_field_value(value, 3, DIG_BE_CNTL, DIG_MODE);
+		break;
+	case SIGNAL_TYPE_DISPLAY_PORT_MST:
+		/* DP MST */
+		set_reg_field_value(value, 5, DIG_BE_CNTL, DIG_MODE);
+		break;
+	default:
+		ASSERT_CRITICAL(false);
+		/* invalid mode ! */
+		break;
+	}
+
+	dm_write_reg(ctx, addr, value);
+}
+
+/* TODO: still need depth or just pass in adjusted pixel clock? */
+void dce110_link_encoder_enable_tmds_output(
+	struct link_encoder *enc,
+	enum clock_source_id clock_source,
+	enum dc_color_depth color_depth,
+	bool hdmi,
+	bool dual_link,
+	uint32_t pixel_clock)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	struct bp_transmitter_control cntl = { 0 };
+	enum bp_result result;
+
+	/* Enable the PHY */
+
+	cntl.action = TRANSMITTER_CONTROL_ENABLE;
+	cntl.engine_id = ENGINE_ID_UNKNOWN;
+	cntl.transmitter = enc110->base.transmitter;
+	cntl.pll_id = clock_source;
+	if (hdmi) {
+		cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A;
+		cntl.lanes_number = 4;
+	} else if (dual_link) {
+		cntl.signal = SIGNAL_TYPE_DVI_DUAL_LINK;
+		cntl.lanes_number = 8;
+	} else {
+		cntl.signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
+		cntl.lanes_number = 4;
+	}
+	cntl.hpd_sel = enc110->base.hpd_source;
+
+	cntl.pixel_clock = pixel_clock;
+	cntl.color_depth = color_depth;
+
+	result = link_transmitter_control(enc110, &cntl);
+
+	if (result != BP_RESULT_OK) {
+		dal_logger_write(ctx->logger,
+			LOG_MAJOR_ERROR,
+			LOG_MINOR_COMPONENT_ENCODER,
+			"%s: Failed to execute VBIOS command table!\n",
+			__func__);
+		BREAK_TO_DEBUGGER();
+	}
+}
+
+/* enables DP PHY output */
+void dce110_link_encoder_enable_dp_output(
+	struct link_encoder *enc,
+	const struct link_settings *link_settings,
+	enum clock_source_id clock_source)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	struct bp_transmitter_control cntl = { 0 };
+	enum bp_result result;
+
+	/* Enable the PHY */
+
+	/* number_of_lanes is used for pixel clock adjust,
+	 * but it's not passed to asic_control.
+	 * We need to set number of lanes manually.
+	 */
+	configure_encoder(enc110, link_settings);
+
+	cntl.action = TRANSMITTER_CONTROL_ENABLE;
+	cntl.engine_id = enc->preferred_engine;
+	cntl.transmitter = enc110->base.transmitter;
+	cntl.pll_id = clock_source;
+	cntl.signal = SIGNAL_TYPE_DISPLAY_PORT;
+	cntl.lanes_number = link_settings->lane_count;
+	cntl.hpd_sel = enc110->base.hpd_source;
+	cntl.pixel_clock = link_settings->link_rate
+						* LINK_RATE_REF_FREQ_IN_KHZ;
+	/* TODO: check if undefined works */
+	cntl.color_depth = COLOR_DEPTH_UNDEFINED;
+
+	result = link_transmitter_control(enc110, &cntl);
+
+	if (result != BP_RESULT_OK) {
+		dal_logger_write(ctx->logger,
+			LOG_MAJOR_ERROR,
+			LOG_MINOR_COMPONENT_ENCODER,
+			"%s: Failed to execute VBIOS command table!\n",
+			__func__);
+		BREAK_TO_DEBUGGER();
+	}
+}
+
+/* enables DP PHY output in MST mode */
+void dce110_link_encoder_enable_dp_mst_output(
+	struct link_encoder *enc,
+	const struct link_settings *link_settings,
+	enum clock_source_id clock_source)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	struct bp_transmitter_control cntl = { 0 };
+	enum bp_result result;
+
+	/* Enable the PHY */
+
+	/* number_of_lanes is used for pixel clock adjust,
+	 * but it's not passed to asic_control.
+	 * We need to set number of lanes manually.
+	 */
+	configure_encoder(enc110, link_settings);
+
+	cntl.action = TRANSMITTER_CONTROL_ENABLE;
+	cntl.engine_id = enc->preferred_engine;
+	cntl.transmitter = enc110->base.transmitter;
+	cntl.pll_id = clock_source;
+	cntl.signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+	cntl.lanes_number = link_settings->lane_count;
+	cntl.hpd_sel = enc110->base.hpd_source;
+	cntl.pixel_clock = link_settings->link_rate
+						* LINK_RATE_REF_FREQ_IN_KHZ;
+	/* TODO: check if undefined works */
+	cntl.color_depth = COLOR_DEPTH_UNDEFINED;
+
+	result = link_transmitter_control(enc110, &cntl);
+
+	if (result != BP_RESULT_OK) {
+		dal_logger_write(ctx->logger,
+			LOG_MAJOR_ERROR,
+			LOG_MINOR_COMPONENT_ENCODER,
+			"%s: Failed to execute VBIOS command table!\n",
+			__func__);
+		BREAK_TO_DEBUGGER();
+	}
+}
+/*
+ * @brief
+ * Disable transmitter and its encoder
+ */
+void dce110_link_encoder_disable_output(
+	struct link_encoder *enc,
+	enum signal_type signal)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	struct bp_transmitter_control cntl = { 0 };
+	enum bp_result result;
+
+	if (!is_dig_enabled(enc110) &&
+		dal_adapter_service_should_optimize(
+			enc110->base.adapter_service,
+			OF_SKIP_POWER_DOWN_INACTIVE_ENCODER)) {
+		return;
+	}
+	/* Power-down RX and disable GPU PHY should be paired.
+	 * Disabling PHY without powering down RX may cause
+	 * symbol lock loss, on which we will get DP Sink interrupt. */
+
+	/* There is a case for the DP active dongles
+	 * where we want to disable the PHY but keep RX powered,
+	 * for those we need to ignore DP Sink interrupt
+	 * by checking lane count that has been set
+	 * on the last do_enable_output(). */
+
+	/* disable transmitter */
+	cntl.action = TRANSMITTER_CONTROL_DISABLE;
+	cntl.transmitter = enc110->base.transmitter;
+	cntl.hpd_sel = enc110->base.hpd_source;
+	cntl.signal = signal;
+	cntl.connector_obj_id = enc110->base.connector;
+
+	result = link_transmitter_control(enc110, &cntl);
+
+	if (result != BP_RESULT_OK) {
+		dal_logger_write(ctx->logger,
+			LOG_MAJOR_ERROR,
+			LOG_MINOR_COMPONENT_ENCODER,
+			"%s: Failed to execute VBIOS command table!\n",
+			__func__);
+		BREAK_TO_DEBUGGER();
+		return;
+	}
+
+	/* disable encoder */
+	if (dc_is_dp_signal(signal))
+		link_encoder_disable(enc110);
+
+	if (enc110->base.connector.id == CONNECTOR_ID_EDP) {
+		/* power down eDP panel */
+		/* TODO: Power control cause regression, we should implement
+		 * it properly, for now just comment it.
+		 *
+		 * link_encoder_edp_wait_for_hpd_ready(
+			link_enc,
+			link_enc->connector,
+			false);
+
+		 * link_encoder_edp_power_control(
+				link_enc, false); */
+	}
+}
+
+void dce110_link_encoder_dp_set_lane_settings(
+	struct link_encoder *enc,
+	const struct link_training_settings *link_settings)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	union dpcd_training_lane_set training_lane_set = { { 0 } };
+	int32_t lane = 0;
+	struct bp_transmitter_control cntl = { 0 };
+
+	if (!link_settings) {
+		BREAK_TO_DEBUGGER();
+		return;
+	}
+
+	cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
+	cntl.transmitter = enc110->base.transmitter;
+	cntl.connector_obj_id = enc110->base.connector;
+	cntl.lanes_number = link_settings->link_settings.lane_count;
+	cntl.hpd_sel = enc110->base.hpd_source;
+	cntl.pixel_clock = link_settings->link_settings.link_rate *
+						LINK_RATE_REF_FREQ_IN_KHZ;
+
+	for (lane = 0; lane < link_settings->link_settings.lane_count; ++lane) {
+		/* translate lane settings */
+
+		training_lane_set.bits.VOLTAGE_SWING_SET =
+			link_settings->lane_settings[lane].VOLTAGE_SWING;
+		training_lane_set.bits.PRE_EMPHASIS_SET =
+			link_settings->lane_settings[lane].PRE_EMPHASIS;
+
+		/* post cursor 2 setting only applies to HBR2 link rate */
+		if (link_settings->link_settings.link_rate == LINK_RATE_HIGH2) {
+			/* this is passed to VBIOS
+			 * to program post cursor 2 level */
+
+			training_lane_set.bits.POST_CURSOR2_SET =
+				link_settings->lane_settings[lane].POST_CURSOR2;
+		}
+
+		cntl.lane_select = lane;
+		cntl.lane_settings = training_lane_set.raw;
+
+		/* call VBIOS table to set voltage swing and pre-emphasis */
+		link_transmitter_control(enc110, &cntl);
+	}
+}
+
+/* set DP PHY test and training patterns */
+void dce110_link_encoder_dp_set_phy_pattern(
+	struct link_encoder *enc,
+	const struct encoder_set_dp_phy_pattern_param *param)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+
+	switch (param->dp_phy_pattern) {
+	case DP_TEST_PATTERN_TRAINING_PATTERN1:
+		set_dp_phy_pattern_training_pattern(enc110, 0);
+		break;
+	case DP_TEST_PATTERN_TRAINING_PATTERN2:
+		set_dp_phy_pattern_training_pattern(enc110, 1);
+		break;
+	case DP_TEST_PATTERN_TRAINING_PATTERN3:
+		set_dp_phy_pattern_training_pattern(enc110, 2);
+		break;
+	case DP_TEST_PATTERN_D102:
+		set_dp_phy_pattern_d102(enc110);
+		break;
+	case DP_TEST_PATTERN_SYMBOL_ERROR:
+		set_dp_phy_pattern_symbol_error(enc110);
+		break;
+	case DP_TEST_PATTERN_PRBS7:
+		set_dp_phy_pattern_prbs7(enc110);
+		break;
+	case DP_TEST_PATTERN_80BIT_CUSTOM:
+		set_dp_phy_pattern_80bit_custom(
+			enc110, param->custom_pattern);
+		break;
+	case DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE:
+		set_dp_phy_pattern_hbr2_compliance(enc110);
+		break;
+	case DP_TEST_PATTERN_VIDEO_MODE: {
+		set_dp_phy_pattern_passthrough_mode(
+			enc110, param->dp_panel_mode);
+		break;
+	}
+
+	default:
+		/* invalid phy pattern */
+		ASSERT_CRITICAL(false);
+		break;
+	}
+}
+
+static void fill_stream_allocation_row_info(
+	const struct link_mst_stream_allocation *stream_allocation,
+	uint32_t *src,
+	uint32_t *slots)
+{
+	const struct stream_encoder *stream_enc = stream_allocation->stream_enc;
+
+	if (stream_enc) {
+		*src = stream_enc->id;
+		*slots = stream_allocation->slot_count;
+	} else {
+		*src = 0;
+		*slots = 0;
+	}
+}
+
+/* programs DP MST VC payload allocation */
+void dce110_link_encoder_update_mst_stream_allocation_table(
+	struct link_encoder *enc,
+	const struct link_mst_stream_allocation_table *table)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t value0 = 0;
+	uint32_t value1 = 0;
+	uint32_t value2 = 0;
+	uint32_t slots = 0;
+	uint32_t src = 0;
+	uint32_t retries = 0;
+
+	/* For CZ, there are only 3 pipes. So Virtual channel is up 3.*/
+
+	/* --- Set MSE Stream Attribute -
+	 * Setup VC Payload Table on Tx Side,
+	 * Issue allocation change trigger
+	 * to commit payload on both tx and rx side */
+
+	/* we should clean-up table each time */
+	value0 = dm_read_reg(ctx, LINK_REG(DP_MSE_SAT0));
+	value1 = dm_read_reg(ctx, LINK_REG(DP_MSE_SAT1));
+
+	if (table->stream_count >= 1) {
+		fill_stream_allocation_row_info(
+			&table->stream_allocations[0],
+			&src,
+			&slots);
+	} else {
+		src = 0;
+		slots = 0;
+	}
+
+	set_reg_field_value(
+		value0,
+		src,
+		DP_MSE_SAT0,
+		DP_MSE_SAT_SRC0);
+
+	set_reg_field_value(
+		value0,
+		slots,
+		DP_MSE_SAT0,
+		DP_MSE_SAT_SLOT_COUNT0);
+
+	if (table->stream_count >= 2) {
+		fill_stream_allocation_row_info(
+			&table->stream_allocations[1],
+			&src,
+			&slots);
+	} else {
+		src = 0;
+		slots = 0;
+	}
+
+	set_reg_field_value(
+		value0,
+		src,
+		DP_MSE_SAT0,
+		DP_MSE_SAT_SRC1);
+
+	set_reg_field_value(
+		value0,
+		slots,
+		DP_MSE_SAT0,
+		DP_MSE_SAT_SLOT_COUNT1);
+
+	if (table->stream_count >= 3) {
+		fill_stream_allocation_row_info(
+			&table->stream_allocations[2],
+			&src,
+			&slots);
+	} else {
+		src = 0;
+		slots = 0;
+	}
+
+	set_reg_field_value(
+		value1,
+		src,
+		DP_MSE_SAT1,
+		DP_MSE_SAT_SRC2);
+
+	set_reg_field_value(
+		value1,
+		slots,
+		DP_MSE_SAT1,
+		DP_MSE_SAT_SLOT_COUNT2);
+
+	/* update ASIC MSE stream allocation table */
+	dm_write_reg(ctx, LINK_REG(DP_MSE_SAT0), value0);
+	dm_write_reg(ctx, LINK_REG(DP_MSE_SAT1), value1);
+
+	/* --- wait for transaction finish */
+
+	/* send allocation change trigger (ACT) ?
+	 * this step first sends the ACT,
+	 * then double buffers the SAT into the hardware
+	 * making the new allocation active on the DP MST mode link */
+
+	value0 = dm_read_reg(ctx, LINK_REG(DP_MSE_SAT_UPDATE));
+
+	/* DP_MSE_SAT_UPDATE:
+	 * 0 - No Action
+	 * 1 - Update SAT with trigger
+	 * 2 - Update SAT without trigger */
+
+	set_reg_field_value(
+		value0,
+		1,
+		DP_MSE_SAT_UPDATE,
+		DP_MSE_SAT_UPDATE);
+
+	dm_write_reg(ctx, LINK_REG(DP_MSE_SAT_UPDATE), value0);
+
+	/* wait for update to complete
+	 * (i.e. DP_MSE_SAT_UPDATE field is reset to 0)
+	 * then wait for the transmission
+	 * of at least 16 MTP headers on immediate local link.
+	 * i.e. DP_MSE_16_MTP_KEEPOUT field (read only) is reset to 0
+	 * a value of 1 indicates that DP MST mode
+	 * is in the 16 MTP keepout region after a VC has been added.
+	 * MST stream bandwidth (VC rate) can be configured
+	 * after this bit is cleared */
+
+	do {
+		dm_delay_in_microseconds(ctx, 10);
+
+		value0 = dm_read_reg(ctx,
+				LINK_REG(DP_MSE_SAT_UPDATE));
+
+		value1 = get_reg_field_value(
+				value0,
+				DP_MSE_SAT_UPDATE,
+				DP_MSE_SAT_UPDATE);
+		value2 = get_reg_field_value(
+				value0,
+				DP_MSE_SAT_UPDATE,
+				DP_MSE_16_MTP_KEEPOUT);
+
+		/* bit field DP_MSE_SAT_UPDATE is set to 1 already */
+		if (!value1 && !value2)
+			break;
+		++retries;
+	} while (retries < DP_MST_UPDATE_MAX_RETRY);
+}
+
+/* black light programming */
+void dce110_link_encoder_set_lcd_backlight_level(
+	struct link_encoder *enc,
+	uint32_t level)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+
+	const uint32_t backlight_update_pending_max_retry = 1000;
+
+	uint32_t backlight;
+	uint32_t backlight_period;
+	uint32_t backlight_lock;
+
+	uint32_t i;
+	uint32_t backlight_24bit;
+	uint32_t backlight_17bit;
+	uint32_t backlight_16bit;
+	uint32_t masked_pwm_period;
+	uint8_t rounding_bit;
+	uint8_t bit_count;
+	uint64_t active_duty_cycle;
+
+	backlight = dm_read_reg(ctx, BL_REG(BL_PWM_CNTL));
+	backlight_period = dm_read_reg(ctx, BL_REG(BL_PWM_PERIOD_CNTL));
+	backlight_lock = dm_read_reg(ctx, BL_REG(BL_PWM_GRP1_REG_LOCK));
+
+	/*
+	 * 1. Convert 8-bit value to 17 bit U1.16 format
+	 * (1 integer, 16 fractional bits)
+	 */
+
+	/* 1.1 multiply 8 bit value by 0x10101 to get a 24 bit value,
+	 * effectively multiplying value by 256/255
+	 * eg. for a level of 0xEF, backlight_24bit = 0xEF * 0x10101 = 0xEFEFEF
+	 */
+	backlight_24bit = level * 0x10101;
+
+	/* 1.2 The upper 16 bits of the 24 bit value is the fraction, lower 8
+	 * used for rounding, take most significant bit of fraction for
+	 * rounding, e.g. for 0xEFEFEF, rounding bit is 1
+	 */
+	rounding_bit = (backlight_24bit >> 7) & 1;
+
+	/* 1.3 Add the upper 16 bits of the 24 bit value with the rounding bit
+	 * resulting in a 17 bit value e.g. 0xEFF0 = (0xEFEFEF >> 8) + 1
+	 */
+	backlight_17bit = (backlight_24bit >> 8) + rounding_bit;
+
+	/*
+	 * 2. Find  16 bit backlight active duty cycle, where 0 <= backlight
+	 * active duty cycle <= backlight period
+	 */
+
+	/* 2.1 Apply bitmask for backlight period value based on value of BITCNT
+	 */
+	{
+		uint32_t pwm_period_bitcnt = get_reg_field_value(
+			backlight_period,
+			BL_PWM_PERIOD_CNTL,
+			BL_PWM_PERIOD_BITCNT);
+		if (pwm_period_bitcnt == 0)
+			bit_count = 16;
+		else
+			bit_count = pwm_period_bitcnt;
+	}
+
+	/* e.g. maskedPwmPeriod = 0x24 when bitCount is 6 */
+	masked_pwm_period =
+	get_reg_field_value(
+		backlight_period,
+		BL_PWM_PERIOD_CNTL,
+		BL_PWM_PERIOD) & ((1 << bit_count) - 1);
+
+	/* 2.2 Calculate integer active duty cycle required upper 16 bits
+	 * contain integer component, lower 16 bits contain fractional component
+	 * of active duty cycle e.g. 0x21BDC0 = 0xEFF0 * 0x24
+	 */
+	active_duty_cycle = backlight_17bit * masked_pwm_period;
+
+	/* 2.3 Calculate 16 bit active duty cycle from integer and fractional
+	 * components shift by bitCount then mask 16 bits and add rounding bit
+	 * from MSB of fraction e.g. 0x86F7 = ((0x21BDC0 >> 6) & 0xFFF) + 0
+	 */
+	backlight_16bit = active_duty_cycle >> bit_count;
+	backlight_16bit &= 0xFFFF;
+	backlight_16bit += (active_duty_cycle >> (bit_count - 1)) & 0x1;
+	set_reg_field_value(
+		backlight,
+		backlight_16bit,
+		BL_PWM_CNTL,
+		BL_ACTIVE_INT_FRAC_CNT);
+
+	/*
+	 * 3. Program register with updated value
+	 */
+
+	/* 3.1 Lock group 2 backlight registers */
+	set_reg_field_value(
+		backlight_lock,
+		1,
+		BL_PWM_GRP1_REG_LOCK,
+		BL_PWM_GRP1_IGNORE_MASTER_LOCK_EN);
+	set_reg_field_value(
+		backlight_lock,
+		1,
+		BL_PWM_GRP1_REG_LOCK,
+		BL_PWM_GRP1_REG_LOCK);
+	dm_write_reg(ctx, BL_REG(BL_PWM_GRP1_REG_LOCK), backlight_lock);
+
+	/* 3.2 Write new active duty cycle */
+	dm_write_reg(ctx, BL_REG(BL_PWM_CNTL), backlight);
+
+	/* 3.3 Unlock group 2 backlight registers */
+	set_reg_field_value(
+		backlight_lock,
+		0,
+		BL_PWM_GRP1_REG_LOCK,
+		BL_PWM_GRP1_REG_LOCK);
+	dm_write_reg(ctx, BL_REG(BL_PWM_GRP1_REG_LOCK), backlight_lock);
+
+	/* 5.4.4 Wait for pending bit to be cleared */
+	for (i = 0; i < backlight_update_pending_max_retry; ++i) {
+		backlight_lock = dm_read_reg(ctx, BL_REG(BL_PWM_GRP1_REG_LOCK));
+		if (!get_reg_field_value(
+			backlight_lock,
+			BL_PWM_GRP1_REG_LOCK,
+			BL_PWM_GRP1_REG_UPDATE_PENDING))
+			break;
+
+		dm_delay_in_microseconds(ctx, 10);
+	}
+}
+
+void dce110_link_encoder_connect_dig_be_to_fe(
+	struct link_encoder *enc,
+	enum engine_id engine,
+	bool connect)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr;
+	uint32_t value;
+	uint32_t field;
+
+	if (engine != ENGINE_ID_UNKNOWN) {
+		addr = LINK_REG(DIG_BE_CNTL);
+		value = dm_read_reg(ctx, addr);
+
+		field = get_reg_field_value(
+				value,
+				DIG_BE_CNTL,
+				DIG_FE_SOURCE_SELECT);
+
+		if (connect)
+			field |= get_frontend_source(engine);
+		else
+			field &= ~get_frontend_source(engine);
+
+		set_reg_field_value(
+			value,
+			field,
+			DIG_BE_CNTL,
+			DIG_FE_SOURCE_SELECT);
+		dm_write_reg(ctx, addr, value);
+	}
+}
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h
new file mode 100644
index 000000000000..46e297137b19
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2012-15 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_LINK_ENCODER__DCE110_H__
+#define __DC_LINK_ENCODER__DCE110_H__
+
+#include "inc/link_encoder.h"
+
+#define TO_DCE110_LINK_ENC(link_encoder)\
+	container_of(link_encoder, struct dce110_link_encoder, base)
+
+struct dce110_link_enc_bl_registers {
+	uint32_t BL_PWM_CNTL;
+	uint32_t BL_PWM_GRP1_REG_LOCK;
+	uint32_t BL_PWM_PERIOD_CNTL;
+	uint32_t LVTMA_PWRSEQ_CNTL;
+	uint32_t LVTMA_PWRSEQ_STATE;
+};
+
+struct dce110_link_enc_aux_registers {
+	uint32_t AUX_CONTROL;
+	uint32_t AUX_DPHY_RX_CONTROL0;
+};
+
+struct dce110_link_enc_registers {
+	uint32_t DIG_BE_CNTL;
+	uint32_t DIG_BE_EN_CNTL;
+	uint32_t DP_CONFIG;
+	uint32_t DP_DPHY_CNTL;
+	uint32_t DP_DPHY_INTERNAL_CTRL;
+	uint32_t DP_DPHY_PRBS_CNTL;
+	uint32_t DP_DPHY_SYM0;
+	uint32_t DP_DPHY_SYM1;
+	uint32_t DP_DPHY_SYM2;
+	uint32_t DP_DPHY_TRAINING_PATTERN_SEL;
+	uint32_t DP_LINK_CNTL;
+	uint32_t DP_LINK_FRAMING_CNTL;
+	uint32_t DP_MSE_SAT0;
+	uint32_t DP_MSE_SAT1;
+	uint32_t DP_MSE_SAT2;
+	uint32_t DP_MSE_SAT_UPDATE;
+	uint32_t DP_SEC_CNTL;
+	uint32_t DP_VID_STREAM_CNTL;
+};
+
+struct dce110_link_encoder {
+	struct link_encoder base;
+	const struct dce110_link_enc_registers *link_regs;
+	const struct dce110_link_enc_aux_registers *aux_regs;
+	const struct dce110_link_enc_bl_registers *bl_regs;
+};
+
+bool dce110_link_encoder_construct(
+	struct dce110_link_encoder *enc110,
+	const struct encoder_init_data *init_data,
+	const struct dce110_link_enc_registers *link_regs,
+	const struct dce110_link_enc_aux_registers *aux_regs,
+	const struct dce110_link_enc_bl_registers *bl_regs);
+
+bool dce110_link_encoder_validate_output_with_stream(
+	struct link_encoder *enc,
+	struct core_stream *stream);
+
+/****************** HW programming ************************/
+
+/* initialize HW */  /* why do we initialze aux in here? */
+void dce110_link_encoder_hw_init(struct link_encoder *enc);
+
+/* program DIG_MODE in DIG_BE */
+/* TODO can this be combined with enable_output? */
+void dce110_link_encoder_setup(
+	struct link_encoder *enc,
+	enum signal_type signal);
+
+/* enables TMDS PHY output */
+/* TODO: still need depth or just pass in adjusted pixel clock? */
+void dce110_link_encoder_enable_tmds_output(
+	struct link_encoder *enc,
+	enum clock_source_id clock_source,
+	enum dc_color_depth color_depth,
+	bool hdmi,
+	bool dual_link,
+	uint32_t pixel_clock);
+
+/* enables DP PHY output */
+void dce110_link_encoder_enable_dp_output(
+	struct link_encoder *enc,
+	const struct link_settings *link_settings,
+	enum clock_source_id clock_source);
+
+/* enables DP PHY output in MST mode */
+void dce110_link_encoder_enable_dp_mst_output(
+	struct link_encoder *enc,
+	const struct link_settings *link_settings,
+	enum clock_source_id clock_source);
+
+/* disable PHY output */
+void dce110_link_encoder_disable_output(
+	struct link_encoder *link_enc,
+	enum signal_type signal);
+
+/* set DP lane settings */
+void dce110_link_encoder_dp_set_lane_settings(
+	struct link_encoder *enc,
+	const struct link_training_settings *link_settings);
+
+void dce110_link_encoder_dp_set_phy_pattern(
+	struct link_encoder *enc,
+	const struct encoder_set_dp_phy_pattern_param *param);
+
+/* programs DP MST VC payload allocation */
+void dce110_link_encoder_update_mst_stream_allocation_table(
+	struct link_encoder *enc,
+	const struct link_mst_stream_allocation_table *table);
+
+void dce110_link_encoder_set_lcd_backlight_level(
+	struct link_encoder *enc,
+	uint32_t level);
+
+void dce110_link_encoder_edp_backlight_control(
+	struct link_encoder *enc,
+	bool enable);
+
+void dce110_link_encoder_edp_power_control(
+	struct link_encoder *enc,
+	bool power_up);
+
+void dce110_link_encoder_connect_dig_be_to_fe(
+	struct link_encoder *enc,
+	enum engine_id engine,
+	bool connect);
+
+
+#endif /* __DC_LINK_ENCODER__DCE110_H__ */
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c
new file mode 100644
index 000000000000..210730972c08
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c
@@ -0,0 +1,1123 @@
+/*
+ * Copyright 2012-15 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 "dm_services.h"
+#include "dc_bios_types.h"
+#include "dce110_stream_encoder.h"
+
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+#include "dce/dce_11_0_enum.h"
+
+#define LINK_REG(reg)\
+	(enc110->regs->reg)
+
+#define VBI_LINE_0 0
+#define DP_BLANK_MAX_RETRY 20
+#define HDMI_CLOCK_CHANNEL_RATE_MORE_340M 340000
+
+#ifndef HDMI_CONTROL__HDMI_DATA_SCRAMBLE_EN_MASK
+	#define HDMI_CONTROL__HDMI_DATA_SCRAMBLE_EN_MASK 0x2
+	#define HDMI_CONTROL__HDMI_DATA_SCRAMBLE_EN__SHIFT 0x1
+#endif
+
+enum {
+	DP_MST_UPDATE_MAX_RETRY = 50
+};
+
+static struct stream_encoder_funcs dce110_str_enc_funcs = {
+	.dp_set_stream_attribute =
+		dce110_stream_encoder_dp_set_stream_attribute,
+	.hdmi_set_stream_attribute =
+		dce110_stream_encoder_hdmi_set_stream_attribute,
+	.dvi_set_stream_attribute =
+		dce110_stream_encoder_dvi_set_stream_attribute,
+	.set_mst_bandwidth =
+		dce110_stream_encoder_set_mst_bandwidth,
+	.update_hdmi_info_packets =
+		dce110_stream_encoder_update_hdmi_info_packets,
+	.stop_hdmi_info_packets =
+		dce110_stream_encoder_stop_hdmi_info_packets,
+	.update_dp_info_packets =
+		dce110_stream_encoder_update_dp_info_packets,
+	.stop_dp_info_packets =
+		dce110_stream_encoder_stop_dp_info_packets,
+	.dp_blank =
+		dce110_stream_encoder_dp_blank,
+	.dp_unblank =
+		dce110_stream_encoder_dp_unblank,
+};
+
+static void dce110_update_generic_info_packet(
+	struct dce110_stream_encoder *enc110,
+	uint32_t packet_index,
+	const struct encoder_info_packet *info_packet)
+{
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr;
+	uint32_t regval;
+	/* choose which generic packet to use */
+	{
+		addr = LINK_REG(AFMT_VBI_PACKET_CONTROL);
+
+		regval = dm_read_reg(ctx, addr);
+
+		set_reg_field_value(
+			regval,
+			packet_index,
+			AFMT_VBI_PACKET_CONTROL,
+			AFMT_GENERIC_INDEX);
+
+		dm_write_reg(ctx, addr, regval);
+	}
+
+	/* write generic packet header
+	 * (4th byte is for GENERIC0 only) */
+	{
+		addr = LINK_REG(AFMT_GENERIC_HDR);
+
+		regval = 0;
+
+		set_reg_field_value(
+			regval,
+			info_packet->hb0,
+			AFMT_GENERIC_HDR,
+			AFMT_GENERIC_HB0);
+
+		set_reg_field_value(
+			regval,
+			info_packet->hb1,
+			AFMT_GENERIC_HDR,
+			AFMT_GENERIC_HB1);
+
+		set_reg_field_value(
+			regval,
+			info_packet->hb2,
+			AFMT_GENERIC_HDR,
+			AFMT_GENERIC_HB2);
+
+		set_reg_field_value(
+			regval,
+			info_packet->hb3,
+			AFMT_GENERIC_HDR,
+			AFMT_GENERIC_HB3);
+
+		dm_write_reg(ctx, addr, regval);
+	}
+
+	/* write generic packet contents
+	 * (we never use last 4 bytes)
+	 * there are 8 (0-7) mmDIG0_AFMT_GENERIC0_x registers */
+	{
+		const uint32_t *content =
+			(const uint32_t *) &info_packet->sb[0];
+
+		uint32_t counter = 0;
+
+		addr = LINK_REG(AFMT_GENERIC_0);
+
+		do {
+			dm_write_reg(ctx, addr++, *content++);
+
+			++counter;
+		} while (counter < 7);
+	}
+
+	addr = LINK_REG(AFMT_GENERIC_7);
+
+	dm_write_reg(
+		ctx,
+		addr,
+		0);
+
+	/* force double-buffered packet update */
+	{
+		addr = LINK_REG(AFMT_VBI_PACKET_CONTROL);
+
+		regval = dm_read_reg(ctx, addr);
+
+		set_reg_field_value(
+			regval,
+			(packet_index == 0),
+			AFMT_VBI_PACKET_CONTROL,
+			AFMT_GENERIC0_UPDATE);
+
+		set_reg_field_value(
+			regval,
+			(packet_index == 2),
+			AFMT_VBI_PACKET_CONTROL,
+			AFMT_GENERIC2_UPDATE);
+
+		dm_write_reg(ctx, addr, regval);
+	}
+}
+
+static void dce110_update_hdmi_info_packet(
+	struct dce110_stream_encoder *enc110,
+	uint32_t packet_index,
+	const struct encoder_info_packet *info_packet)
+{
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t cont, send, line;
+	uint32_t addr;
+	uint32_t regval;
+
+	if (info_packet->valid) {
+		dce110_update_generic_info_packet(
+			enc110,
+			packet_index,
+			info_packet);
+
+		/* 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 */
+		line = 2;
+	} else {
+		cont = 0;
+		send = 0;
+		line = 0;
+	}
+
+	/* choose which generic packet control to use */
+
+	switch (packet_index) {
+	case 0:
+	case 1:
+		addr = LINK_REG(HDMI_GENERIC_PACKET_CONTROL0);
+		break;
+	case 2:
+	case 3:
+		addr = LINK_REG(HDMI_GENERIC_PACKET_CONTROL1);
+		break;
+	default:
+		/* invalid HW packet index */
+		dal_logger_write(
+			ctx->logger,
+			LOG_MAJOR_WARNING,
+			LOG_MINOR_COMPONENT_ENCODER,
+			"Invalid HW packet index: %s()\n",
+			__func__);
+		return;
+	}
+
+	regval = dm_read_reg(ctx, addr);
+
+	switch (packet_index) {
+	case 0:
+	case 2:
+		set_reg_field_value(
+			regval,
+			cont,
+			HDMI_GENERIC_PACKET_CONTROL0,
+			HDMI_GENERIC0_CONT);
+		set_reg_field_value(
+			regval,
+			send,
+			HDMI_GENERIC_PACKET_CONTROL0,
+			HDMI_GENERIC0_SEND);
+		set_reg_field_value(
+			regval,
+			line,
+			HDMI_GENERIC_PACKET_CONTROL0,
+			HDMI_GENERIC0_LINE);
+		break;
+	case 1:
+	case 3:
+		set_reg_field_value(
+			regval,
+			cont,
+			HDMI_GENERIC_PACKET_CONTROL0,
+			HDMI_GENERIC1_CONT);
+		set_reg_field_value(
+			regval,
+			send,
+			HDMI_GENERIC_PACKET_CONTROL0,
+			HDMI_GENERIC1_SEND);
+		set_reg_field_value(
+			regval,
+			line,
+			HDMI_GENERIC_PACKET_CONTROL0,
+			HDMI_GENERIC1_LINE);
+		break;
+	default:
+		/* invalid HW packet index */
+		dal_logger_write(
+			ctx->logger,
+			LOG_MAJOR_WARNING,
+			LOG_MINOR_COMPONENT_ENCODER,
+			"Invalid HW packet index: %s()\n",
+			__func__);
+		return;
+	}
+
+	dm_write_reg(ctx, addr, regval);
+}
+
+bool dce110_stream_encoder_construct(
+	struct dce110_stream_encoder *enc110,
+	struct dc_context *ctx,
+	struct dc_bios *bp,
+	enum engine_id eng_id,
+	const struct dce110_stream_enc_registers *regs)
+{
+	if (!enc110)
+		return false;
+	if (!bp)
+		return false;
+
+	enc110->base.funcs = &dce110_str_enc_funcs;
+	enc110->base.ctx = ctx;
+	enc110->base.id = eng_id;
+	enc110->base.bp = bp;
+	enc110->regs = regs;
+
+	return true;
+}
+
+/* setup stream encoder in dp mode */
+void dce110_stream_encoder_dp_set_stream_attribute(
+	struct stream_encoder *enc,
+	struct dc_crtc_timing *crtc_timing)
+{
+	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	const uint32_t addr = LINK_REG(DP_PIXEL_FORMAT);
+	uint32_t value = dm_read_reg(ctx, addr);
+
+	/* set pixel encoding */
+	switch (crtc_timing->pixel_encoding) {
+	case PIXEL_ENCODING_YCBCR422:
+		set_reg_field_value(
+			value,
+			DP_PIXEL_ENCODING_YCBCR422,
+			DP_PIXEL_FORMAT,
+			DP_PIXEL_ENCODING);
+		break;
+	case PIXEL_ENCODING_YCBCR444:
+		set_reg_field_value(
+			value,
+			DP_PIXEL_ENCODING_YCBCR444,
+			DP_PIXEL_FORMAT,
+			DP_PIXEL_ENCODING);
+
+		if (crtc_timing->flags.Y_ONLY)
+			if (crtc_timing->display_color_depth != COLOR_DEPTH_666)
+				/* HW testing only, no use case yet.
+				 * Color depth of Y-only could be
+				 * 8, 10, 12, 16 bits */
+				set_reg_field_value(
+					value,
+					DP_PIXEL_ENCODING_Y_ONLY,
+					DP_PIXEL_FORMAT,
+					DP_PIXEL_ENCODING);
+		/* Note: DP_MSA_MISC1 bit 7 is the indicator
+		 * of Y-only mode.
+		 * This bit is set in HW if register
+		 * DP_PIXEL_ENCODING is programmed to 0x4 */
+		break;
+	default:
+		set_reg_field_value(
+			value,
+			DP_PIXEL_ENCODING_RGB444,
+			DP_PIXEL_FORMAT,
+			DP_PIXEL_ENCODING);
+		break;
+	}
+
+	/* set color depth */
+
+	switch (crtc_timing->display_color_depth) {
+	case COLOR_DEPTH_888:
+		set_reg_field_value(
+			value,
+			DP_COMPONENT_DEPTH_8BPC,
+			DP_PIXEL_FORMAT,
+			DP_COMPONENT_DEPTH);
+		break;
+	case COLOR_DEPTH_101010:
+		set_reg_field_value(
+			value,
+			DP_COMPONENT_DEPTH_10BPC,
+			DP_PIXEL_FORMAT,
+			DP_COMPONENT_DEPTH);
+		break;
+	case COLOR_DEPTH_121212:
+		set_reg_field_value(
+			value,
+			DP_COMPONENT_DEPTH_12BPC,
+			DP_PIXEL_FORMAT,
+			DP_COMPONENT_DEPTH);
+		break;
+	default:
+		set_reg_field_value(
+			value,
+			DP_COMPONENT_DEPTH_6BPC,
+			DP_PIXEL_FORMAT,
+			DP_COMPONENT_DEPTH);
+		break;
+	}
+
+	/* set dynamic range and YCbCr range */
+	set_reg_field_value(value, 0, DP_PIXEL_FORMAT, DP_DYN_RANGE);
+	set_reg_field_value(value, 0, DP_PIXEL_FORMAT, DP_YCBCR_RANGE);
+
+	dm_write_reg(ctx, addr, value);
+}
+
+/* setup stream encoder in hdmi mode */
+void dce110_stream_encoder_hdmi_set_stream_attribute(
+	struct stream_encoder *enc,
+	struct dc_crtc_timing *crtc_timing,
+	bool enable_audio)
+{
+	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t output_pixel_clock = crtc_timing->pix_clk_khz;
+	uint32_t value;
+	uint32_t addr;
+	struct bp_encoder_control cntl = {0};
+
+	cntl.action = ENCODER_CONTROL_SETUP;
+	cntl.engine_id = enc110->base.id;
+	cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A;
+	cntl.enable_dp_audio = enable_audio;
+	cntl.pixel_clock = crtc_timing->pix_clk_khz;
+	cntl.lanes_number = LANE_COUNT_FOUR;
+	cntl.color_depth = crtc_timing->display_color_depth;
+
+	if (enc110->base.bp->funcs->encoder_control(
+			enc110->base.bp, &cntl) != BP_RESULT_OK)
+		return;
+
+	addr = LINK_REG(DIG_FE_CNTL);
+	value = dm_read_reg(ctx, addr);
+
+	switch (crtc_timing->pixel_encoding) {
+	case PIXEL_ENCODING_YCBCR422:
+		set_reg_field_value(value, 1, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
+		break;
+	default:
+		set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
+		break;
+	}
+	set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_COLOR_FORMAT);
+	dm_write_reg(ctx, addr, value);
+
+	/* setup HDMI engine */
+	addr = LINK_REG(HDMI_CONTROL);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(value, 1, HDMI_CONTROL, HDMI_PACKET_GEN_VERSION);
+	set_reg_field_value(value, 1, HDMI_CONTROL, HDMI_KEEPOUT_MODE);
+	set_reg_field_value(value, 0, HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE);
+	set_reg_field_value(value, 0, HDMI_CONTROL, HDMI_DATA_SCRAMBLE_EN);
+	set_reg_field_value(value, 0, HDMI_CONTROL, HDMI_CLOCK_CHANNEL_RATE);
+
+	switch (crtc_timing->display_color_depth) {
+	case COLOR_DEPTH_888:
+		set_reg_field_value(
+			value,
+			0,
+			HDMI_CONTROL,
+			HDMI_DEEP_COLOR_DEPTH);
+		break;
+	case COLOR_DEPTH_101010:
+		set_reg_field_value(
+			value,
+			1,
+			HDMI_CONTROL,
+			HDMI_DEEP_COLOR_DEPTH);
+		set_reg_field_value(
+			value,
+			1,
+			HDMI_CONTROL,
+			HDMI_DEEP_COLOR_ENABLE);
+		output_pixel_clock = (crtc_timing->pix_clk_khz * 30) / 24;
+		break;
+	case COLOR_DEPTH_121212:
+		set_reg_field_value(
+			value,
+			2,
+			HDMI_CONTROL,
+			HDMI_DEEP_COLOR_DEPTH);
+		set_reg_field_value(
+			value,
+			1,
+			HDMI_CONTROL,
+			HDMI_DEEP_COLOR_ENABLE);
+		output_pixel_clock = (crtc_timing->pix_clk_khz * 36) / 24;
+		break;
+	case COLOR_DEPTH_161616:
+		set_reg_field_value(
+			value,
+			3,
+			HDMI_CONTROL,
+			HDMI_DEEP_COLOR_DEPTH);
+		set_reg_field_value(
+			value,
+			1,
+			HDMI_CONTROL,
+			HDMI_DEEP_COLOR_ENABLE);
+		output_pixel_clock = (crtc_timing->pix_clk_khz * 48) / 24;
+		break;
+	default:
+		break;
+	}
+
+	if (output_pixel_clock >= HDMI_CLOCK_CHANNEL_RATE_MORE_340M) {
+		/* enable HDMI data scrambler */
+		set_reg_field_value(
+			value,
+			1,
+			HDMI_CONTROL,
+			HDMI_DATA_SCRAMBLE_EN);
+
+		/* HDMI_CLOCK_CHANNEL_RATE_MORE_340M
+		 * Clock channel frequency is 1/4 of character rate.*/
+		set_reg_field_value(
+			value,
+			1,
+			HDMI_CONTROL,
+			HDMI_CLOCK_CHANNEL_RATE);
+	} else if (crtc_timing->flags.LTE_340MCSC_SCRAMBLE) {
+
+		/* TODO: New feature for DCE11, still need to implement */
+
+		/* enable HDMI data scrambler */
+		set_reg_field_value(
+			value,
+			1,
+			HDMI_CONTROL,
+			HDMI_DATA_SCRAMBLE_EN);
+
+		/* HDMI_CLOCK_CHANNEL_FREQ_EQUAL_TO_CHAR_RATE
+		 * Clock channel frequency is the same
+		 * as character rate */
+		set_reg_field_value(
+			value,
+			0,
+			HDMI_CONTROL,
+			HDMI_CLOCK_CHANNEL_RATE);
+	}
+
+	dm_write_reg(ctx, addr, value);
+
+	addr = LINK_REG(HDMI_VBI_PACKET_CONTROL);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(value, 1, HDMI_VBI_PACKET_CONTROL, HDMI_GC_CONT);
+	set_reg_field_value(value, 1, HDMI_VBI_PACKET_CONTROL, HDMI_GC_SEND);
+	set_reg_field_value(value, 1, HDMI_VBI_PACKET_CONTROL, HDMI_NULL_SEND);
+
+	dm_write_reg(ctx, addr, value);
+
+	/* following belongs to audio */
+	addr = LINK_REG(HDMI_INFOFRAME_CONTROL0);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		HDMI_INFOFRAME_CONTROL0,
+		HDMI_AUDIO_INFO_SEND);
+	dm_write_reg(ctx, addr, value);
+
+	addr = LINK_REG(AFMT_INFOFRAME_CONTROL0);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		AFMT_INFOFRAME_CONTROL0,
+		AFMT_AUDIO_INFO_UPDATE);
+	dm_write_reg(ctx, addr, value);
+
+	addr = LINK_REG(HDMI_INFOFRAME_CONTROL1);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		VBI_LINE_0 + 2,
+		HDMI_INFOFRAME_CONTROL1,
+		HDMI_AUDIO_INFO_LINE);
+	dm_write_reg(ctx, addr, value);
+
+	addr = LINK_REG(HDMI_GC);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(value, 0, HDMI_GC, HDMI_GC_AVMUTE);
+	dm_write_reg(ctx, addr, value);
+}
+
+/* setup stream encoder in dvi mode */
+void dce110_stream_encoder_dvi_set_stream_attribute(
+	struct stream_encoder *enc,
+	struct dc_crtc_timing *crtc_timing,
+	bool is_dual_link)
+{
+	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr = LINK_REG(DIG_FE_CNTL);
+	uint32_t value = dm_read_reg(ctx, addr);
+	struct bp_encoder_control cntl = {0};
+
+	cntl.action = ENCODER_CONTROL_SETUP;
+	cntl.engine_id = enc110->base.id;
+	cntl.signal = is_dual_link ?
+		SIGNAL_TYPE_DVI_DUAL_LINK :
+		SIGNAL_TYPE_DVI_SINGLE_LINK;
+	cntl.enable_dp_audio = false;
+	cntl.pixel_clock = crtc_timing->pix_clk_khz;
+	cntl.lanes_number = (is_dual_link) ?
+				LANE_COUNT_EIGHT : LANE_COUNT_FOUR;
+	cntl.color_depth = crtc_timing->display_color_depth;
+
+	if (enc110->base.bp->funcs->encoder_control(
+			enc110->base.bp, &cntl) != BP_RESULT_OK)
+		return;
+
+	switch (crtc_timing->pixel_encoding) {
+	case PIXEL_ENCODING_YCBCR422:
+		set_reg_field_value(value, 1, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
+		break;
+	default:
+		set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
+		break;
+	}
+
+	switch (crtc_timing->display_color_depth) {
+	case COLOR_DEPTH_101010:
+		if (crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB)
+			set_reg_field_value(
+				value,
+				2,
+				DIG_FE_CNTL,
+				TMDS_COLOR_FORMAT);
+		else
+			set_reg_field_value(
+				value,
+				0,
+				DIG_FE_CNTL,
+				TMDS_COLOR_FORMAT);
+		break;
+	default:
+		set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_COLOR_FORMAT);
+		break;
+	}
+	dm_write_reg(ctx, addr, value);
+}
+
+void dce110_stream_encoder_set_mst_bandwidth(
+	struct stream_encoder *enc,
+	struct fixed31_32 avg_time_slots_per_mtp)
+{
+	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr;
+	uint32_t field;
+	uint32_t value;
+	uint32_t retries = 0;
+	uint32_t x = dal_fixed31_32_floor(
+		avg_time_slots_per_mtp);
+	uint32_t y = dal_fixed31_32_ceil(
+		dal_fixed31_32_shl(
+			dal_fixed31_32_sub_int(
+				avg_time_slots_per_mtp,
+				x),
+			26));
+
+	{
+		addr = LINK_REG(DP_MSE_RATE_CNTL);
+		value = dm_read_reg(ctx, addr);
+
+		set_reg_field_value(
+			value,
+			x,
+			DP_MSE_RATE_CNTL,
+			DP_MSE_RATE_X);
+
+		set_reg_field_value(
+			value,
+			y,
+			DP_MSE_RATE_CNTL,
+			DP_MSE_RATE_Y);
+
+		dm_write_reg(ctx, addr, value);
+	}
+
+	/* wait for update to be completed on the link */
+	/* i.e. DP_MSE_RATE_UPDATE_PENDING field (read only) */
+	/* is reset to 0 (not pending) */
+	{
+		addr = LINK_REG(DP_MSE_RATE_UPDATE);
+
+		do {
+			value = dm_read_reg(ctx, addr);
+
+			field = get_reg_field_value(
+					value,
+					DP_MSE_RATE_UPDATE,
+					DP_MSE_RATE_UPDATE_PENDING);
+
+			if (!(field &
+			DP_MSE_RATE_UPDATE__DP_MSE_RATE_UPDATE_PENDING_MASK))
+				break;
+
+			dm_delay_in_microseconds(ctx, 10);
+
+			++retries;
+		} while (retries < DP_MST_UPDATE_MAX_RETRY);
+	}
+}
+
+void dce110_stream_encoder_update_hdmi_info_packets(
+	struct stream_encoder *enc,
+	const struct encoder_info_frame *info_frame)
+{
+	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t regval;
+	uint32_t addr;
+	uint32_t control0val;
+	uint32_t control1val;
+
+	if (info_frame->avi.valid) {
+		const uint32_t *content =
+			(const uint32_t *) &info_frame->avi.sb[0];
+
+		addr = LINK_REG(AFMT_AVI_INFO0);
+		regval = content[0];
+		dm_write_reg(
+			ctx,
+			addr,
+			regval);
+		regval = content[1];
+
+		addr = LINK_REG(AFMT_AVI_INFO1);
+		dm_write_reg(
+			ctx,
+			addr,
+			regval);
+		regval = content[2];
+
+		addr = LINK_REG(AFMT_AVI_INFO2);
+		dm_write_reg(
+			ctx,
+			addr,
+			regval);
+		regval = content[3];
+
+		/* move version to AVI_INFO3 */
+		addr = LINK_REG(AFMT_AVI_INFO3);
+		set_reg_field_value(
+			regval,
+			info_frame->avi.hb1,
+			AFMT_AVI_INFO3,
+			AFMT_AVI_INFO_VERSION);
+
+		dm_write_reg(
+			ctx,
+			addr,
+			regval);
+
+		addr = LINK_REG(HDMI_INFOFRAME_CONTROL0);
+
+		control0val = dm_read_reg(ctx, addr);
+
+		set_reg_field_value(
+			control0val,
+			1,
+			HDMI_INFOFRAME_CONTROL0,
+			HDMI_AVI_INFO_SEND);
+
+		set_reg_field_value(
+			control0val,
+			1,
+			HDMI_INFOFRAME_CONTROL0,
+			HDMI_AVI_INFO_CONT);
+
+		dm_write_reg(ctx, addr, control0val);
+
+		addr = LINK_REG(HDMI_INFOFRAME_CONTROL1);
+
+		control1val = dm_read_reg(ctx, addr);
+
+		set_reg_field_value(
+			control1val,
+			VBI_LINE_0 + 2,
+			HDMI_INFOFRAME_CONTROL1,
+			HDMI_AVI_INFO_LINE);
+
+		dm_write_reg(ctx, addr, control1val);
+	} else {
+		addr = LINK_REG(HDMI_INFOFRAME_CONTROL0);
+
+		regval = dm_read_reg(ctx, addr);
+
+		set_reg_field_value(
+			regval,
+			0,
+			HDMI_INFOFRAME_CONTROL0,
+			HDMI_AVI_INFO_SEND);
+
+		set_reg_field_value(
+			regval,
+			0,
+			HDMI_INFOFRAME_CONTROL0,
+			HDMI_AVI_INFO_CONT);
+
+		dm_write_reg(ctx, addr, regval);
+	}
+
+	dce110_update_hdmi_info_packet(enc110, 0, &info_frame->vendor);
+	dce110_update_hdmi_info_packet(enc110, 1, &info_frame->gamut);
+	dce110_update_hdmi_info_packet(enc110, 2, &info_frame->spd);
+}
+
+void dce110_stream_encoder_stop_hdmi_info_packets(
+	struct stream_encoder *enc)
+{
+	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr = 0;
+	uint32_t value = 0;
+
+	/* stop generic packets 0 & 1 on HDMI */
+	addr = LINK_REG(HDMI_GENERIC_PACKET_CONTROL0);
+
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL0,
+		HDMI_GENERIC1_CONT);
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL0,
+		HDMI_GENERIC1_LINE);
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL0,
+		HDMI_GENERIC1_SEND);
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL0,
+		HDMI_GENERIC0_CONT);
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL0,
+		HDMI_GENERIC0_LINE);
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL0,
+		HDMI_GENERIC0_SEND);
+
+	dm_write_reg(ctx, addr, value);
+
+	/* stop generic packets 2 & 3 on HDMI */
+	addr = LINK_REG(HDMI_GENERIC_PACKET_CONTROL1);
+
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL1,
+		HDMI_GENERIC2_CONT);
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL1,
+		HDMI_GENERIC2_LINE);
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL1,
+		HDMI_GENERIC2_SEND);
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL1,
+		HDMI_GENERIC3_CONT);
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL1,
+		HDMI_GENERIC3_LINE);
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_GENERIC_PACKET_CONTROL1,
+		HDMI_GENERIC3_SEND);
+
+	dm_write_reg(ctx, addr, value);
+
+	/* stop AVI packet on HDMI */
+	addr = LINK_REG(HDMI_INFOFRAME_CONTROL0);
+
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_INFOFRAME_CONTROL0,
+		HDMI_AVI_INFO_SEND);
+	set_reg_field_value(
+		value,
+		0,
+		HDMI_INFOFRAME_CONTROL0,
+		HDMI_AVI_INFO_CONT);
+
+	dm_write_reg(ctx, addr, value);
+}
+void dce110_stream_encoder_update_dp_info_packets(
+	struct stream_encoder *enc,
+	const struct encoder_info_frame *info_frame)
+{
+	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr = LINK_REG(DP_SEC_CNTL);
+	uint32_t value;
+
+	if (info_frame->vsc.valid)
+		dce110_update_generic_info_packet(
+			enc110,
+			0,
+			&info_frame->vsc);
+
+	/* enable/disable transmission of packet(s).
+	*  If enabled, packet transmission begins on the next frame
+	*/
+
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(
+		value,
+		info_frame->vsc.valid,
+		DP_SEC_CNTL,
+		DP_SEC_GSP0_ENABLE);
+	/* This bit is the master enable bit.
+	* When enabling secondary stream engine,
+	* this master bit must also be set.
+	* This register shared with audio info frame.
+	* Therefore we need to enable master bit
+	* if at least on of the fields is not 0
+	*/
+	if (value)
+		set_reg_field_value(
+			value,
+			1,
+			DP_SEC_CNTL,
+			DP_SEC_STREAM_ENABLE);
+
+	dm_write_reg(ctx, addr, value);
+}
+
+void dce110_stream_encoder_stop_dp_info_packets(
+	struct stream_encoder *enc)
+{
+	/* stop generic packets on DP */
+	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr = LINK_REG(DP_SEC_CNTL);
+	uint32_t value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP0_ENABLE);
+	set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP1_ENABLE);
+	set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP2_ENABLE);
+	set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP3_ENABLE);
+	set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_AVI_ENABLE);
+	set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_MPG_ENABLE);
+	set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_STREAM_ENABLE);
+
+	/* this register shared with audio info frame.
+	 * therefore we need to keep master enabled
+	 * if at least one of the fields is not 0 */
+
+	if (value)
+		set_reg_field_value(
+			value,
+			1,
+			DP_SEC_CNTL,
+			DP_SEC_STREAM_ENABLE);
+
+	dm_write_reg(ctx, addr, value);
+}
+
+void dce110_stream_encoder_dp_blank(
+	struct stream_encoder *enc)
+{
+	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr = LINK_REG(DP_VID_STREAM_CNTL);
+	uint32_t value = dm_read_reg(ctx, addr);
+	uint32_t retries = 0;
+	uint32_t max_retries = DP_BLANK_MAX_RETRY * 10;
+
+	/* Note: For CZ, we are changing driver default to disable
+	 * stream deferred to next VBLANK. If results are positive, we
+	 * will make the same change to all DCE versions. There are a
+	 * handful of panels that cannot handle disable stream at
+	 * HBLANK and will result in a white line flash across the
+	 * screen on stream disable. */
+
+	/* Specify the video stream disable point
+	 * (2 = start of the next vertical blank) */
+	set_reg_field_value(
+		value,
+		2,
+		DP_VID_STREAM_CNTL,
+		DP_VID_STREAM_DIS_DEFER);
+	/* Larger delay to wait until VBLANK - use max retry of
+	* 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode +
+	* a little more because we may not trust delay accuracy.
+	*/
+	max_retries = DP_BLANK_MAX_RETRY * 150;
+
+	/* disable DP stream */
+	set_reg_field_value(value, 0, DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE);
+	dm_write_reg(ctx, addr, value);
+
+	/* the encoder stops sending the video stream
+	* at the start of the vertical blanking.
+	* Poll for DP_VID_STREAM_STATUS == 0
+	*/
+
+	do {
+		value = dm_read_reg(ctx, addr);
+
+		if (!get_reg_field_value(
+			value,
+			DP_VID_STREAM_CNTL,
+			DP_VID_STREAM_STATUS))
+			break;
+
+		dm_delay_in_microseconds(ctx, 10);
+
+		++retries;
+	} while (retries < max_retries);
+
+	ASSERT(retries <= max_retries);
+
+	/* Tell the DP encoder to ignore timing from CRTC, must be done after
+	* the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is
+	* complete, stream status will be stuck in video stream enabled state,
+	* i.e. DP_VID_STREAM_STATUS stuck at 1.
+	*/
+	addr = LINK_REG(DP_STEER_FIFO);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(value, true, DP_STEER_FIFO, DP_STEER_FIFO_RESET);
+	dm_write_reg(ctx, addr, value);
+}
+
+/* output video stream to link encoder */
+void dce110_stream_encoder_dp_unblank(
+	struct stream_encoder *enc,
+	const struct encoder_unblank_param *param)
+{
+	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+	struct dc_context *ctx = enc110->base.ctx;
+	uint32_t addr;
+	uint32_t value;
+
+	if (param->link_settings.link_rate != LINK_RATE_UNKNOWN) {
+		uint32_t n_vid = 0x8000;
+		uint32_t m_vid;
+
+		/* M / N = Fstream / Flink
+		* m_vid / n_vid = pixel rate / link rate
+		*/
+
+		uint64_t m_vid_l = n_vid;
+
+		m_vid_l *= param->crtc_timing.pixel_clock;
+		m_vid_l = div_u64(m_vid_l,
+			param->link_settings.link_rate
+				* LINK_RATE_REF_FREQ_IN_KHZ);
+
+		m_vid = (uint32_t) m_vid_l;
+
+		/* enable auto measurement */
+		addr = LINK_REG(DP_VID_TIMING);
+		value = dm_read_reg(ctx, addr);
+		set_reg_field_value(value, 0, DP_VID_TIMING, DP_VID_M_N_GEN_EN);
+		dm_write_reg(ctx, addr, value);
+
+		/* auto measurement need 1 full 0x8000 symbol cycle to kick in,
+		* therefore program initial value for Mvid and Nvid
+		*/
+		addr = LINK_REG(DP_VID_N);
+		value = dm_read_reg(ctx, addr);
+		set_reg_field_value(value, n_vid, DP_VID_N, DP_VID_N);
+		dm_write_reg(ctx, addr, value);
+
+		addr = LINK_REG(DP_VID_M);
+		value = dm_read_reg(ctx, addr);
+		set_reg_field_value(value, m_vid, DP_VID_M, DP_VID_M);
+		dm_write_reg(ctx, addr, value);
+
+		addr = LINK_REG(DP_VID_TIMING);
+		value = dm_read_reg(ctx, addr);
+		set_reg_field_value(value, 1, DP_VID_TIMING, DP_VID_M_N_GEN_EN);
+		dm_write_reg(ctx, addr, value);
+	}
+
+	/* set DIG_START to 0x1 to resync FIFO */
+	addr = LINK_REG(DIG_FE_CNTL);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(value, 1, DIG_FE_CNTL, DIG_START);
+	dm_write_reg(ctx, addr, value);
+
+	/* switch DP encoder to CRTC data */
+	addr = LINK_REG(DP_STEER_FIFO);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(value, 0, DP_STEER_FIFO, DP_STEER_FIFO_RESET);
+	dm_write_reg(ctx, addr, value);
+
+	/* wait 100us for DIG/DP logic to prime
+	* (i.e. a few video lines)
+	*/
+	dm_delay_in_microseconds(ctx, 100);
+
+	/* the hardware would start sending video at the start of the next DP
+	* frame (i.e. rising edge of the vblank).
+	* NOTE: We used to program DP_VID_STREAM_DIS_DEFER = 2 here, but this
+	* register has no effect on enable transition! HW always guarantees
+	* VID_STREAM enable at start of next frame, and this is not
+	* programmable
+	*/
+	addr = LINK_REG(DP_VID_STREAM_CNTL);
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		true,
+		DP_VID_STREAM_CNTL,
+		DP_VID_STREAM_ENABLE);
+	dm_write_reg(ctx, addr, value);
+}
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.h
new file mode 100644
index 000000000000..5753a1b7614e
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012-15 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_STREAM_ENCODER_DCE110_H__
+#define __DC_STREAM_ENCODER_DCE110_H__
+
+#include "inc/stream_encoder.h"
+
+#define DCE110STRENC_FROM_STRENC(stream_encoder)\
+	container_of(stream_encoder, struct dce110_stream_encoder, base)
+
+struct dce110_stream_enc_registers {
+	uint32_t AFMT_AVI_INFO0;
+	uint32_t AFMT_AVI_INFO1;
+	uint32_t AFMT_AVI_INFO2;
+	uint32_t AFMT_AVI_INFO3;
+	uint32_t AFMT_GENERIC_0;
+	uint32_t AFMT_GENERIC_7;
+	uint32_t AFMT_GENERIC_HDR;
+	uint32_t AFMT_INFOFRAME_CONTROL0;
+	uint32_t AFMT_VBI_PACKET_CONTROL;
+	uint32_t DIG_FE_CNTL;
+	uint32_t DP_MSE_RATE_CNTL;
+	uint32_t DP_MSE_RATE_UPDATE;
+	uint32_t DP_PIXEL_FORMAT;
+	uint32_t DP_SEC_CNTL;
+	uint32_t DP_STEER_FIFO;
+	uint32_t DP_VID_M;
+	uint32_t DP_VID_N;
+	uint32_t DP_VID_STREAM_CNTL;
+	uint32_t DP_VID_TIMING;
+	uint32_t HDMI_CONTROL;
+	uint32_t HDMI_GC;
+	uint32_t HDMI_GENERIC_PACKET_CONTROL0;
+	uint32_t HDMI_GENERIC_PACKET_CONTROL1;
+	uint32_t HDMI_INFOFRAME_CONTROL0;
+	uint32_t HDMI_INFOFRAME_CONTROL1;
+	uint32_t HDMI_VBI_PACKET_CONTROL;
+	uint32_t TMDS_CNTL;
+};
+
+struct dce110_stream_encoder {
+	struct stream_encoder base;
+	const struct dce110_stream_enc_registers *regs;
+};
+
+bool dce110_stream_encoder_construct(
+	struct dce110_stream_encoder *enc110,
+	struct dc_context *ctx,
+	struct dc_bios *bp,
+	enum engine_id eng_id,
+	const struct dce110_stream_enc_registers *regs);
+
+/***** HW programming ***********/
+/* setup stream encoder in dp mode */
+void dce110_stream_encoder_dp_set_stream_attribute(
+	struct stream_encoder *enc,
+	struct dc_crtc_timing *crtc_timing);
+
+/* setup stream encoder in hdmi mode */
+void dce110_stream_encoder_hdmi_set_stream_attribute(
+	struct stream_encoder *enc,
+	struct dc_crtc_timing *crtc_timing,
+	bool enable_audio);
+
+/* setup stream encoder in dvi mode */
+void dce110_stream_encoder_dvi_set_stream_attribute(
+	struct stream_encoder *enc,
+	struct dc_crtc_timing *crtc_timing,
+	bool is_dual_link);
+
+/* set throttling for DP MST */
+void dce110_stream_encoder_set_mst_bandwidth(
+	struct stream_encoder *enc,
+	struct fixed31_32 avg_time_slots_per_mtp);
+
+void dce110_stream_encoder_update_hdmi_info_packets(
+	struct stream_encoder *enc,
+	const struct encoder_info_frame *info_frame);
+
+void dce110_stream_encoder_stop_hdmi_info_packets(
+	struct stream_encoder *enc);
+
+void dce110_stream_encoder_update_dp_info_packets(
+	struct stream_encoder *enc,
+	const struct encoder_info_frame *info_frame);
+
+void dce110_stream_encoder_stop_dp_info_packets(
+	struct stream_encoder *enc);
+
+/* output blank/idle stream to link encoder */
+void dce110_stream_encoder_dp_blank(
+	struct stream_encoder *enc);
+
+/* output video stream to link encoder */
+void dce110_stream_encoder_dp_unblank(
+	struct stream_encoder *enc,
+	const struct encoder_unblank_param *param);
+
+#endif /* __DC_STREAM_ENCODER_DCE110_H__ */
-- 
2.1.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  parent reply	other threads:[~2016-02-16 22:28 UTC|newest]

Thread overview: 87+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-11 17:19 [PATCH 00/29] Enabling new DAL display driver for amdgpu on Carrizo and Tonga Harry Wentland
2016-02-11 17:19 ` [PATCH 01/29] drm/amd/dal: Add dal headers Harry Wentland
2016-02-11 17:19 ` [PATCH 02/29] drm/amd/dal: Add DAL Basic Types and Logger Harry Wentland
2016-02-11 17:19 ` [PATCH 03/29] drm/amd/dal: Fixed point arithmetic Harry Wentland
2016-02-11 17:19 ` [PATCH 04/29] drm/amd/dal: Asic Capabilities Harry Wentland
2016-02-11 17:19 ` [PATCH 05/29] drm/amd/dal: GPIO (General Purpose IO) Harry Wentland
2016-02-11 17:19 ` [PATCH 06/29] drm/amd/dal: Adapter Service Harry Wentland
2016-02-12  0:26   ` Dave Airlie
2016-02-12 14:30     ` Wentland, Harry
2016-02-11 17:19 ` [PATCH 07/29] drm/amd/dal: BIOS Parser Harry Wentland
2016-02-11 17:19 ` [PATCH 08/29] drm/amd/dal: I2C Aux Manager Harry Wentland
2016-02-11 20:19   ` Rob Clark
2016-02-11 20:52     ` Daniel Vetter
2016-02-17  3:23     ` Harry Wentland
2016-02-11 17:19 ` [PATCH 09/29] drm/amd/dal: IRQ Service Harry Wentland
2016-02-11 17:19 ` [PATCH 10/29] drm/amd/dal: GPU Harry Wentland
2016-02-11 17:19 ` [PATCH 11/29] drm/amd/dal: Audio Harry Wentland
2016-02-11 17:19 ` [PATCH 12/29] drm/amd/dal: Bandwidth calculations Harry Wentland
2016-02-11 17:19 ` [PATCH 13/29] drm/amd/dal: Add encoder HW programming Harry Wentland
2016-02-11 17:19 ` [PATCH 14/29] drm/amd/dal: Add clock source " Harry Wentland
2016-02-11 17:19 ` [PATCH 15/29] drm/amd/dal: Add timing generator " Harry Wentland
2016-02-11 17:19 ` [PATCH 16/29] drm/amd/dal: Add surface " Harry Wentland
2016-02-11 17:19 ` [PATCH 17/29] drm/amd/dal: Add framebuffer compression " Harry Wentland
2016-02-11 17:19 ` [PATCH 18/29] drm/amd/dal: Add input pixel processing " Harry Wentland
2016-02-11 17:19 ` [PATCH 19/29] drm/amd/dal: Add output " Harry Wentland
2016-02-11 17:20 ` [PATCH 20/29] drm/amd/dal: Add transform & scaler " Harry Wentland
2016-02-11 17:20 ` [PATCH 21/29] drm/amd/dal: Add Carrizo HW sequencer and resource Harry Wentland
2016-02-11 17:20 ` [PATCH 22/29] drm/amd/dal: Add Tonga/Fiji " Harry Wentland
2016-02-11 17:20 ` [PATCH 23/29] drm/amd/dal: Add empty encoder programming for virtual HW Harry Wentland
2016-02-11 17:20 ` [PATCH 24/29] drm/amd/dal: Add display core Harry Wentland
2016-02-11 17:20 ` [PATCH 25/29] drm/amd/dal: Adding amdgpu_dm for dal Harry Wentland
2016-02-11 17:20 ` [PATCH 26/29] drm/amdgpu: Use dal driver for Carrizo, Tonga, and Fiji Harry Wentland
2016-02-11 17:20 ` [PATCH 27/29] drm/amd/dal: Correctly interpret rotation as bit set Harry Wentland
2016-02-11 21:00   ` Oded Gabbay
2016-02-16 16:46     ` Harry Wentland
2016-02-11 17:20 ` [PATCH 28/29] drm/amd/dal: fix flip clean-up state Harry Wentland
2016-02-11 17:20 ` [PATCH 29/29] drm/amd/dal: Force bw programming for DCE 10 until we start calculate BW Harry Wentland
2016-02-11 20:02 ` [PATCH 00/29] Enabling new DAL display driver for amdgpu on Carrizo and Tonga Mike Lothian
2016-02-11 20:05   ` Wentland, Harry
2016-02-11 20:52 ` Dave Airlie
2016-02-11 21:06   ` Daniel Vetter
2016-02-12  0:57     ` Dave Airlie
2016-02-12  5:34     ` Daniel Vetter
2016-02-13  0:05       ` Wentland, Harry
2016-02-14 11:22         ` Jerome Glisse
2016-02-14 13:23           ` Daniel Vetter
2016-02-17  3:28           ` Harry Wentland
2016-02-14 13:32         ` Rob Clark
2016-02-14 13:51           ` Daniel Vetter
2016-02-17  3:26           ` Harry Wentland
2016-02-14 14:01         ` Daniel Vetter
2016-02-17  3:32           ` Harry Wentland
2016-02-14 21:44         ` Daniel Stone
2016-02-16 22:27 ` [PATCH v2 00/26] " Harry Wentland
2016-02-16 22:27   ` [PATCH v2 01/26] drm/amd/dal: Add dal headers Harry Wentland
2016-02-16 22:27   ` [PATCH v2 02/26] drm/amd/dal: Add DAL Basic Types and Logger Harry Wentland
2016-02-16 22:27   ` [PATCH v2 03/26] drm/amd/dal: Fixed point arithmetic Harry Wentland
2016-02-16 22:27   ` [PATCH v2 04/26] drm/amd/dal: Asic Capabilities Harry Wentland
2016-02-16 22:27   ` [PATCH v2 05/26] drm/amd/dal: GPIO (General Purpose IO) Harry Wentland
2016-02-16 22:27   ` [PATCH v2 06/26] drm/amd/dal: Adapter Service Harry Wentland
2016-02-16 22:27   ` [PATCH v2 07/26] drm/amd/dal: BIOS Parser Harry Wentland
2016-02-16 22:27   ` [PATCH v2 08/26] drm/amd/dal: I2C Aux Manager Harry Wentland
2016-02-16 22:27   ` [PATCH v2 09/26] drm/amd/dal: IRQ Service Harry Wentland
2016-02-16 22:27   ` [PATCH v2 10/26] drm/amd/dal: GPU Harry Wentland
2016-02-16 22:27   ` [PATCH v2 11/26] drm/amd/dal: Audio Harry Wentland
2016-02-16 22:27   ` [PATCH v2 12/26] drm/amd/dal: Bandwidth calculations Harry Wentland
2016-02-16 22:27   ` Harry Wentland [this message]
2016-02-16 22:27   ` [PATCH v2 14/26] drm/amd/dal: Add clock source HW programming Harry Wentland
2016-02-16 22:27   ` [PATCH v2 15/26] drm/amd/dal: Add timing generator " Harry Wentland
2016-02-16 22:27   ` [PATCH v2 16/26] drm/amd/dal: Add surface " Harry Wentland
2016-02-16 22:27   ` [PATCH v2 17/26] drm/amd/dal: Add framebuffer compression " Harry Wentland
2016-02-16 22:27   ` [PATCH v2 18/26] drm/amd/dal: Add input pixel processing " Harry Wentland
2016-02-16 22:27   ` [PATCH v2 19/26] drm/amd/dal: Add output " Harry Wentland
2016-02-16 22:28   ` [PATCH v2 20/26] drm/amd/dal: Add transform & scaler " Harry Wentland
2016-02-16 22:28   ` [PATCH v2 21/26] drm/amd/dal: Add Carrizo HW sequencer and resource Harry Wentland
2016-02-16 22:28   ` [PATCH v2 22/26] drm/amd/dal: Add Tonga/Fiji " Harry Wentland
2016-02-16 22:28   ` [PATCH v2 23/26] drm/amd/dal: Add empty encoder programming for virtual HW Harry Wentland
2016-02-16 22:28   ` [PATCH v2 24/26] drm/amd/dal: Add display core Harry Wentland
2016-02-16 22:28   ` [PATCH v2 25/26] drm/amd/dal: Adding amdgpu_dm for dal Harry Wentland
2016-02-16 22:28   ` [PATCH v2 26/26] drm/amdgpu: Use dal driver for Carrizo, Tonga, and Fiji Harry Wentland
2016-02-29 21:56 ` [PATCH v3 00/26] Enabling new DAL display driver for amdgpu on Carrizo and Tonga Harry Wentland
2016-02-29 21:56   ` [PATCH v3 01/26] drm/amd/dal: Add dal headers Harry Wentland
2016-02-29 21:56   ` [PATCH v3 05/26] drm/amd/dal: GPIO (General Purpose IO) Harry Wentland
2016-02-29 21:56   ` [PATCH v3 07/26] drm/amd/dal: BIOS Parser Harry Wentland
2016-02-29 21:56   ` [PATCH v3 24/26] drm/amd/dal: Add display core Harry Wentland
2016-02-29 21:56   ` [PATCH v3 25/26] drm/amd/dal: Adding amdgpu_dm for dal Harry Wentland
2016-02-29 21:56   ` [PATCH v3 26/26] drm/amdgpu: Use dal driver for Carrizo, Tonga, and Fiji Harry Wentland

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=e151463d2b53a5a0db7e4db574362696538310d3.1455660367.git.harry.wentland@amd.com \
    --to=harry.wentland@amd.com \
    --cc=dri-devel@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.