[PATCH 49/52] drm/amd/dal: add core support for Polaris family (v2)

Alex Deucher alexdeucher at gmail.com
Wed Mar 23 17:43:05 UTC 2016


This adds core dc support for polaris 10 and 11.

v2: add missing files

Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
---
 drivers/gpu/drm/amd/dal/dc/Makefile                |    4 +
 drivers/gpu/drm/amd/dal/dc/adapter/Makefile        |    4 +
 .../gpu/drm/amd/dal/dc/adapter/adapter_service.c   |   12 +
 .../adapter/dce112/hw_ctx_adapter_service_dce112.c |  302 +++
 .../adapter/dce112/hw_ctx_adapter_service_dce112.h |   39 +
 .../gpu/drm/amd/dal/dc/asic_capability/Makefile    |    9 +
 .../amd/dal/dc/asic_capability/asic_capability.c   |   15 +-
 .../dc/asic_capability/polaris10_asic_capability.c |  146 ++
 .../dc/asic_capability/polaris10_asic_capability.h |   36 +
 drivers/gpu/drm/amd/dal/dc/audio/Makefile          |    8 +
 drivers/gpu/drm/amd/dal/dc/audio/audio_base.c      |    9 +
 .../gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.c |  451 +++++
 .../gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.h |   40 +
 .../amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.c  | 1923 ++++++++++++++++++++
 .../amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.h  |   47 +
 drivers/gpu/drm/amd/dal/dc/bios/Makefile           |    9 +
 .../gpu/drm/amd/dal/dc/bios/bios_parser_helper.c   |    6 +
 .../gpu/drm/amd/dal/dc/bios/bios_parser_helper.h   |    4 +
 drivers/gpu/drm/amd/dal/dc/bios/command_table.c    |   78 +-
 .../gpu/drm/amd/dal/dc/bios/command_table_helper.c |    6 +
 .../gpu/drm/amd/dal/dc/bios/command_table_helper.h |    3 +
 .../dal/dc/bios/dce112/bios_parser_helper_dce112.c |  480 +++++
 .../dal/dc/bios/dce112/bios_parser_helper_dce112.h |   34 +
 .../dc/bios/dce112/command_table_helper_dce112.c   |  417 +++++
 .../dc/bios/dce112/command_table_helper_dce112.h   |   34 +
 drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c |  206 +++
 drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c  |    7 +
 drivers/gpu/drm/amd/dal/dc/core/dc_resource.c      |   22 +-
 .../drm/amd/dal/dc/dce110/dce110_hw_sequencer.c    |    1 +
 .../amd/dal/dc/dce110/dce110_timing_generator.c    |    2 +-
 drivers/gpu/drm/amd/dal/dc/dce112/Makefile         |   10 +
 .../drm/amd/dal/dc/dce112/dce112_clock_source.c    |  266 +++
 .../drm/amd/dal/dc/dce112/dce112_clock_source.h    |   52 +
 .../gpu/drm/amd/dal/dc/dce112/dce112_compressor.c  |  883 +++++++++
 .../gpu/drm/amd/dal/dc/dce112/dce112_compressor.h  |   84 +
 .../drm/amd/dal/dc/dce112/dce112_hw_sequencer.c    |  178 ++
 .../drm/amd/dal/dc/dce112/dce112_hw_sequencer.h    |   36 +
 .../drm/amd/dal/dc/dce112/dce112_link_encoder.c    |  116 ++
 .../drm/amd/dal/dc/dce112/dce112_link_encoder.h    |   41 +
 .../gpu/drm/amd/dal/dc/dce112/dce112_mem_input.c   |  455 +++++
 .../gpu/drm/amd/dal/dc/dce112/dce112_mem_input.h   |   38 +
 .../gpu/drm/amd/dal/dc/dce112/dce112_resource.c    | 1404 ++++++++++++++
 .../gpu/drm/amd/dal/dc/dce112/dce112_resource.h    |   42 +
 drivers/gpu/drm/amd/dal/dc/dm_services_types.h     |    5 +
 drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c       |    3 +
 drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c     |    3 +
 drivers/gpu/drm/amd/dal/dc/gpu/Makefile            |    8 +
 .../amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.c |   89 +
 .../amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.h |   33 +
 .../amd/dal/dc/gpu/dce112/display_clock_dce112.c   |  964 ++++++++++
 .../amd/dal/dc/gpu/dce112/display_clock_dce112.h   |   54 +
 drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c         |    5 +-
 drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h   |    4 +-
 drivers/gpu/drm/amd/dal/dc/irq/irq_service.c       |    4 +
 drivers/gpu/drm/amd/dal/include/dal_asic_id.h      |   14 +
 drivers/gpu/drm/amd/dal/include/dal_types.h        |    3 +
 .../drm/amd/dal/include/display_clock_interface.h  |    6 +
 57 files changed, 9146 insertions(+), 8 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/Makefile
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.h

diff --git a/drivers/gpu/drm/amd/dal/dc/Makefile b/drivers/gpu/drm/amd/dal/dc/Makefile
index 5112ec9..a718674 100644
--- a/drivers/gpu/drm/amd/dal/dc/Makefile
+++ b/drivers/gpu/drm/amd/dal/dc/Makefile
@@ -5,6 +5,10 @@
 DC_LIBS = adapter asic_capability audio basics bios calcs \
 gpio gpu i2caux irq virtual
 
+ifdef CONFIG_DRM_AMD_DAL_DCE11_2
+DC_LIBS += dce112
+endif
+
 ifdef CONFIG_DRM_AMD_DAL_DCE11_0
 DC_LIBS += dce110
 endif
diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/Makefile b/drivers/gpu/drm/amd/dal/dc/adapter/Makefile
index db1f0e8..370323e 100644
--- a/drivers/gpu/drm/amd/dal/dc/adapter/Makefile
+++ b/drivers/gpu/drm/amd/dal/dc/adapter/Makefile
@@ -25,6 +25,10 @@ ifdef CONFIG_DRM_AMD_DAL_DCE11_0
 AMD_DAL_FILES += $(AMDDALPATH)/dc/adapter/dce110/hw_ctx_adapter_service_dce110.o
 endif
 
+ifdef CONFIG_DRM_AMD_DAL_DCE11_2
+AMD_DAL_FILES += $(AMDDALPATH)/dc/adapter/dce112/hw_ctx_adapter_service_dce112.o
+endif
+
 ###############################################################################
 # FPGA Diagnositcs
 ###############################################################################
diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c b/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c
index f7aea01..308d456 100644
--- a/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c
+++ b/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c
@@ -49,6 +49,10 @@
 #include "dce110/hw_ctx_adapter_service_dce110.h"
 #endif
 
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+#include "dce112/hw_ctx_adapter_service_dce112.h"
+#endif
+
 #include "diagnostics/hw_ctx_adapter_service_diag.h"
 
 /*
@@ -664,6 +668,10 @@ static struct hw_ctx_adapter_service *create_hw_ctx(
 	case DCE_VERSION_11_0:
 		return dal_adapter_service_create_hw_ctx_dce110(ctx);
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	case DCE_VERSION_11_2:
+		return dal_adapter_service_create_hw_ctx_dce112(ctx);
+#endif
 	default:
 		ASSERT_CRITICAL(false);
 		return NULL;
@@ -907,6 +915,10 @@ enum dce_version dal_adapter_service_get_dce_version(
 	case 0x110:
 		return DCE_VERSION_11_0;
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	case 0x112:
+		return DCE_VERSION_11_2;
+#endif
 	default:
 		ASSERT_CRITICAL(false);
 		return DCE_VERSION_UNKNOWN;
diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.c b/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.c
new file mode 100644
index 0000000..f438998
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.c
@@ -0,0 +1,302 @@
+/*
+ * 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 "../hw_ctx_adapter_service.h"
+
+#include "hw_ctx_adapter_service_dce112.h"
+
+#include "include/logger_interface.h"
+#include "include/grph_object_id.h"
+
+#include "dce/dce_11_2_d.h"
+#include "dce/dce_11_2_sh_mask.h"
+
+#ifndef mmCC_DC_HDMI_STRAPS
+#define mmCC_DC_HDMI_STRAPS 0x4819
+#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40
+#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6
+#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700
+#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8
+#endif
+
+static const struct graphics_object_id invalid_go = {
+	0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN, 0
+};
+
+/* Macro */
+#define AUDIO_STRAPS_HDMI_ENABLE 0x2
+
+#define FROM_HW_CTX(ptr) \
+	container_of((ptr), struct hw_ctx_adapter_service_dce112, base)
+
+static const uint32_t audio_index_reg_offset[] = {
+	/*CZ has 3 DIGs but 4 audio endpoints*/
+	mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX,
+	mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_INDEX,
+	mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_INDEX,
+	mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_INDEX
+};
+
+static const uint32_t audio_data_reg_offset[] = {
+	mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA,
+	mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_DATA,
+	mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_DATA,
+	mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_DATA,
+};
+
+enum {
+	MAX_NUMBER_OF_AUDIO_PINS = 4
+};
+
+static void destruct(
+	struct hw_ctx_adapter_service_dce112 *hw_ctx)
+{
+	/* There is nothing to destruct at the moment */
+	dal_adapter_service_destruct_hw_ctx(&hw_ctx->base);
+}
+
+static void destroy(
+	struct hw_ctx_adapter_service *ptr)
+{
+	struct hw_ctx_adapter_service_dce112 *hw_ctx =
+		FROM_HW_CTX(ptr);
+
+	destruct(hw_ctx);
+
+	dm_free(hw_ctx);
+}
+
+/*
+ * enum_audio_object
+ *
+ * @brief enumerate audio object
+ *
+ * @param
+ * const struct hw_ctx_adapter_service *hw_ctx - [in] provides num of endpoints
+ * uint32_t index - [in] audio index
+ *
+ * @return
+ * grphic object id
+ */
+static struct graphics_object_id enum_audio_object(
+	const struct hw_ctx_adapter_service *hw_ctx,
+	uint32_t index)
+{
+	uint32_t number_of_connected_audio_endpoints =
+		FROM_HW_CTX(hw_ctx)->number_of_connected_audio_endpoints;
+
+	if (index >= number_of_connected_audio_endpoints ||
+			number_of_connected_audio_endpoints == 0)
+		return invalid_go;
+	else
+		return dal_graphics_object_id_init(
+			AUDIO_ID_INTERNAL_AZALIA,
+			(enum object_enum_id)(index + 1),
+			OBJECT_TYPE_AUDIO);
+}
+
+static uint32_t get_number_of_connected_audio_endpoints_multistream(
+		struct dc_context *ctx)
+{
+	uint32_t num_connected_audio_endpoints = 0;
+	uint32_t i;
+	uint32_t default_config =
+	ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT;
+
+	/* find the total number of streams available via the
+	 * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
+	 * registers (one for each pin) starting from pin 1
+	 * up to the max number of audio pins.
+	 * We stop on the first pin where
+	 * PORT_CONNECTIVITY == 1 (as instructed by HW team).
+	 */
+	for (i = 0; i < MAX_NUMBER_OF_AUDIO_PINS; i++) {
+		uint32_t value = 0;
+
+		set_reg_field_value(value,
+			default_config,
+			AZALIA_F0_CODEC_ENDPOINT_INDEX,
+			AZALIA_ENDPOINT_REG_INDEX);
+
+		dm_write_reg(ctx, audio_index_reg_offset[i], value);
+
+		value = 0;
+		value = dm_read_reg(ctx, audio_data_reg_offset[i]);
+
+		/* 1 means not supported*/
+		if (get_reg_field_value(value,
+		AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT,
+		PORT_CONNECTIVITY) == 1)
+			break;
+
+		num_connected_audio_endpoints++;
+	}
+
+	return num_connected_audio_endpoints;
+
+}
+
+/*
+ * get_number_of_connected_audio_endpoints
+ */
+static uint32_t get_number_of_connected_audio_endpoints(
+	struct hw_ctx_adapter_service *hw_ctx)
+{
+	uint32_t addr = mmCC_DC_HDMI_STRAPS;
+	uint32_t value = 0;
+	uint32_t field = 0;
+
+	if (hw_ctx->cached_audio_straps == AUDIO_STRAPS_NOT_ALLOWED)
+		/* audio straps indicate no audio supported */
+		return 0;
+
+	value = dm_read_reg(hw_ctx->ctx, addr);
+
+	field = get_reg_field_value(
+			value, CC_DC_HDMI_STRAPS, AUDIO_STREAM_NUMBER);
+	if (field == 1)
+		/* multi streams not supported */
+		return 1;
+	else if (field == 0)
+		/* multi streams supported */
+		return get_number_of_connected_audio_endpoints_multistream(
+				hw_ctx->ctx);
+
+	/* unexpected value */
+	ASSERT_CRITICAL(false);
+	return field;
+}
+
+/*
+ * power_up
+ *
+ * @brief
+ * Determine and cache audio support from register.
+ *
+ * @param
+ * struct hw_ctx_adapter_service *hw_ctx - [in] adapter service hw context
+ *
+ * @return
+ * true if succeed, false otherwise
+ */
+static bool power_up(
+	struct hw_ctx_adapter_service *hw_ctx)
+{
+	struct hw_ctx_adapter_service_dce112 *hw_ctx_dce11 =
+			FROM_HW_CTX(hw_ctx);
+	/* Allow DP audio all the time
+	 * without additional pinstrap check on Fusion */
+
+	{
+		uint32_t value = 0;
+		uint32_t field = 0;
+
+		value = dm_read_reg(hw_ctx->ctx, mmCC_DC_HDMI_STRAPS);
+		field = get_reg_field_value(
+				value, CC_DC_HDMI_STRAPS, HDMI_DISABLE);
+
+		if (field == 0) {
+			hw_ctx->cached_audio_straps = AUDIO_STRAPS_DP_HDMI_AUDIO;
+		} else {
+			value = dm_read_reg(
+					hw_ctx->ctx, mmDC_PINSTRAPS);
+			field = get_reg_field_value(
+						value,
+						DC_PINSTRAPS,
+						DC_PINSTRAPS_AUDIO);
+
+			if (field & AUDIO_STRAPS_HDMI_ENABLE)
+				hw_ctx->cached_audio_straps =
+					AUDIO_STRAPS_DP_HDMI_AUDIO_ON_DONGLE;
+			else
+				hw_ctx->cached_audio_straps =
+						AUDIO_STRAPS_DP_AUDIO_ALLOWED;
+		}
+
+	}
+
+	/* get the number of connected audio endpoints */
+	hw_ctx_dce11->number_of_connected_audio_endpoints =
+		get_number_of_connected_audio_endpoints(hw_ctx);
+
+	return true;
+}
+
+static void update_audio_connectivity(
+	struct hw_ctx_adapter_service *hw_ctx,
+	uint32_t number_of_audio_capable_display_path,
+	uint32_t number_of_controllers)
+{
+	/* this one should be empty on DCE112 */
+}
+
+static const struct hw_ctx_adapter_service_funcs funcs = {
+	.destroy = destroy,
+	.power_up = power_up,
+	.enum_fake_path_resource = NULL,
+	.enum_stereo_sync_object = NULL,
+	.enum_sync_output_object = NULL,
+	.enum_audio_object = enum_audio_object,
+	.update_audio_connectivity = update_audio_connectivity
+};
+
+static bool construct(
+	struct hw_ctx_adapter_service_dce112 *hw_ctx,
+	struct dc_context *ctx)
+{
+	if (!dal_adapter_service_construct_hw_ctx(&hw_ctx->base, ctx)) {
+		ASSERT_CRITICAL(false);
+		return false;
+	}
+
+	hw_ctx->base.funcs = &funcs;
+	hw_ctx->number_of_connected_audio_endpoints = 0;
+
+	return true;
+}
+
+struct hw_ctx_adapter_service *
+	dal_adapter_service_create_hw_ctx_dce112(
+			struct dc_context *ctx)
+{
+	struct hw_ctx_adapter_service_dce112 *hw_ctx =
+			dm_alloc(sizeof(struct hw_ctx_adapter_service_dce112));
+
+	if (!hw_ctx) {
+		ASSERT_CRITICAL(false);
+		return NULL;
+	}
+
+	if (construct(hw_ctx, ctx))
+		return &hw_ctx->base;
+
+	ASSERT_CRITICAL(false);
+
+	dm_free(hw_ctx);
+
+	return NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.h b/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.h
new file mode 100644
index 0000000..bc60030
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.h
@@ -0,0 +1,39 @@
+/*
+ * 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 __DAL_HW_CTX_ADAPTER_SERVICE_DCE112_H__
+#define __DAL_HW_CTX_ADAPTER_SERVICE_DCE112_H__
+
+struct hw_ctx_adapter_service_dce112 {
+	struct hw_ctx_adapter_service base;
+	uint32_t number_of_connected_audio_endpoints;
+};
+
+struct hw_ctx_adapter_service *
+	dal_adapter_service_create_hw_ctx_dce112(
+			struct dc_context *ctx);
+
+#endif /* __DAL_HW_CTX_ADAPTER_SERVICE_DCE112_H__ */
+
diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile b/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile
index b243542..e80de2a 100644
--- a/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile
+++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile
@@ -46,3 +46,12 @@ AMD_DAL_ASIC_CAPABILITY_DCE11 = \
 
 AMD_DAL_FILES += $(AMD_DAL_ASIC_CAPABILITY_DCE11)
 endif
+
+ifdef CONFIG_DRM_AMD_DAL_DCE11_2
+ASIC_CAPABILITY_DCE112 = polaris10_asic_capability.o
+
+AMD_DAL_ASIC_CAPABILITY_DCE112 = \
+	$(addprefix $(AMDDALPATH)/dc/asic_capability/,$(ASIC_CAPABILITY_DCE112))
+
+AMD_DAL_FILES += $(AMD_DAL_ASIC_CAPABILITY_DCE112)
+endif
diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c b/drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c
index 75e0e27..aeabfc6 100644
--- a/drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c
+++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c
@@ -44,6 +44,10 @@
 #include "carrizo_asic_capability.h"
 #endif
 
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+#include "polaris10_asic_capability.h"
+#endif
+
 /*
  * Initializes asic_capability instance.
  */
@@ -108,7 +112,8 @@ static bool construct(
 		asic_supported = true;
 #endif
 		break;
- 	case FAMILY_VI:
+
+	case FAMILY_VI:
 #if defined(CONFIG_DRM_AMD_DAL_DCE10_0)
 		if (ASIC_REV_IS_TONGA_P(init->hw_internal_rev) ||
 				ASIC_REV_IS_FIJI_P(init->hw_internal_rev)) {
@@ -117,7 +122,15 @@ static bool construct(
 			break;
 		}
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+		if (ASIC_REV_IS_POLARIS10_P(init->hw_internal_rev) ||
+				ASIC_REV_IS_POLARIS11_M(init->hw_internal_rev)) {
+			polaris10_asic_capability_create(cap, init);
+			asic_supported = true;
+		}
+#endif
 		break;
+
 	default:
 		/* unsupported "chip_family" */
 		break;
diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.c b/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.c
new file mode 100644
index 0000000..9e4fdfa
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.c
@@ -0,0 +1,146 @@
+/*
+ * 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 "include/asic_capability_interface.h"
+#include "include/asic_capability_types.h"
+
+#include "polaris10_asic_capability.h"
+
+#include "atom.h"
+#include "dce/dce_11_2_d.h"
+#include "dce/dce_11_2_sh_mask.h"
+#include "dal_asic_id.h"
+
+#define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074
+
+/*
+ * carrizo_asic_capability_create
+ *
+ * Create and initiate Carrizo capability.
+ */
+void polaris10_asic_capability_create(struct asic_capability *cap,
+	struct hw_asic_id *init)
+{
+	uint32_t e_fuse_setting;
+	/* ASIC data */
+	if (ASIC_REV_IS_POLARIS11_M(init->hw_internal_rev)) {
+		cap->data[ASIC_DATA_CONTROLLERS_NUM] = 5;
+		cap->data[ASIC_DATA_FUNCTIONAL_CONTROLLERS_NUM] = 5;
+		cap->data[ASIC_DATA_LINEBUFFER_NUM] = 5;
+		cap->data[ASIC_DATA_DIGFE_NUM] = 5;
+		cap->data[ASIC_DATA_CLOCKSOURCES_NUM] = 7;
+		cap->data[ASIC_DATA_MAX_COFUNC_NONDP_DISPLAYS] = 5;
+		cap->data[ASIC_DATA_SUPPORTED_HDMI_CONNECTION_NUM] = 5;
+	} else {
+		cap->data[ASIC_DATA_CONTROLLERS_NUM] = 6;
+		cap->data[ASIC_DATA_FUNCTIONAL_CONTROLLERS_NUM] = 6;
+		cap->data[ASIC_DATA_LINEBUFFER_NUM] = 6;
+		cap->data[ASIC_DATA_DIGFE_NUM] = 6;
+		cap->data[ASIC_DATA_CLOCKSOURCES_NUM] = 8;
+		cap->data[ASIC_DATA_MAX_COFUNC_NONDP_DISPLAYS] = 6;
+		cap->data[ASIC_DATA_SUPPORTED_HDMI_CONNECTION_NUM] = 6;
+	}
+
+	cap->data[ASIC_DATA_PATH_NUM_PER_DPMST_CONNECTOR] = 4;
+	cap->data[ASIC_DATA_DCE_VERSION] = 0x112; /* DCE 11 */
+	cap->data[ASIC_DATA_LINEBUFFER_SIZE] = 5124 * 144;
+	cap->data[ASIC_DATA_DRAM_BANDWIDTH_EFFICIENCY] = 70;
+
+	cap->data[ASIC_DATA_MC_LATENCY] = 3000;
+	cap->data[ASIC_DATA_STUTTERMODE] = 0x200A;
+	cap->data[ASIC_DATA_VIEWPORT_PIXEL_GRANULARITY] = 2;
+
+	cap->data[ASIC_DATA_MEMORYTYPE_MULTIPLIER] = 4;
+	cap->data[ASIC_DATA_DEFAULT_I2C_SPEED_IN_KHZ] = 100;
+	cap->data[ASIC_DATA_NUM_OF_VIDEO_PLANES] = 0;
+
+	cap->data[ASIC_DATA_MIN_DISPCLK_FOR_UNDERSCAN] = 300000;
+
+	/* ASIC basic capability */
+	cap->caps.IS_FUSION = true;
+	cap->caps.DP_MST_SUPPORTED = true;
+	cap->caps.PANEL_SELF_REFRESH_SUPPORTED = true;
+	cap->caps.MIRABILIS_SUPPORTED = true;
+	cap->caps.NO_VCC_OFF_HPD_POLLING = true;
+	cap->caps.VCE_SUPPORTED = true;
+	cap->caps.HPD_CHECK_FOR_EDID = true;
+	cap->caps.DFSBYPASS_DYNAMIC_SUPPORT = true;
+	cap->caps.SUPPORT_8BPP = false;
+
+	/* ASIC stereo 3d capability */
+	cap->stereo_3d_caps.DISPLAY_BASED_ON_WS = true;
+	cap->stereo_3d_caps.HDMI_FRAME_PACK = true;
+	cap->stereo_3d_caps.INTERLACE_FRAME_PACK = true;
+	cap->stereo_3d_caps.DISPLAYPORT_FRAME_PACK = true;
+	cap->stereo_3d_caps.DISPLAYPORT_FRAME_ALT = true;
+	cap->stereo_3d_caps.INTERLEAVE = true;
+
+	e_fuse_setting = dm_read_index_reg(cap->ctx,CGS_IND_REG__SMC, ixVCE_HARVEST_FUSE_MACRO__ADDRESS);
+
+	/* Bits [28:27]*/
+	switch ((e_fuse_setting >> 27) & 0x3) {
+	case 0:
+		/*both VCE engine are working*/
+		cap->caps.VCE_SUPPORTED = true;
+		cap->caps.WIRELESS_TIMING_ADJUSTMENT = false;
+		/*TODO:
+		cap->caps.wirelessLowVCEPerformance = false;
+		m_AsicCaps.vceInstance0Enabled = true;
+		m_AsicCaps.vceInstance1Enabled = true;*/
+		cap->caps.NEED_MC_TUNING = true;
+		break;
+
+	case 1:
+		cap->caps.VCE_SUPPORTED = true;
+		cap->caps.WIRELESS_TIMING_ADJUSTMENT = true;
+		/*TODO:
+		m_AsicCaps.wirelessLowVCEPerformance = false;
+		m_AsicCaps.vceInstance1Enabled = true;*/
+		cap->caps.NEED_MC_TUNING = true;
+		break;
+
+	case 2:
+		cap->caps.VCE_SUPPORTED = true;
+		cap->caps.WIRELESS_TIMING_ADJUSTMENT = true;
+		/*TODO:
+		m_AsicCaps.wirelessLowVCEPerformance = false;
+		m_AsicCaps.vceInstance0Enabled = true;*/
+		cap->caps.NEED_MC_TUNING = true;
+		break;
+
+	case 3:
+		/* VCE_DISABLE = 0x3  - both VCE
+		 * instances are in harvesting,
+		 * no VCE supported any more.
+		 */
+		cap->caps.VCE_SUPPORTED = false;
+		break;
+
+	default:
+		break;
+	}
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.h b/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.h
new file mode 100644
index 0000000..c8aebe1
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.h
@@ -0,0 +1,36 @@
+/*
+ * 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 __DAL_POLARIS10_ASIC_CAPABILITY_H__
+#define __DAL_POLARIS10_ASIC_CAPABILITY_H__
+
+/* Forward declaration */
+struct asic_capability;
+
+/* Create and initialize Polaris10 data */
+void polaris10_asic_capability_create(struct asic_capability *cap,
+	struct hw_asic_id *init);
+
+#endif /* __DAL_POLARIS10_ASIC_CAPABILITY_H__ */
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/Makefile b/drivers/gpu/drm/amd/dal/dc/audio/Makefile
index 2433d90..9a9a64c 100644
--- a/drivers/gpu/drm/amd/dal/dc/audio/Makefile
+++ b/drivers/gpu/drm/amd/dal/dc/audio/Makefile
@@ -32,3 +32,11 @@ AMD_DAL_AUDIO_DCE11 = $(addprefix $(AMDDALPATH)/dc/audio/dce110/,$(AUDIO_DCE11))
 
 AMD_DAL_FILES += $(AMD_DAL_AUDIO_DCE11)
 endif
+
+ifdef CONFIG_DRM_AMD_DAL_DCE11_2
+AUDIO_DCE112 = audio_dce112.o hw_ctx_audio_dce112.o
+
+AMD_DAL_AUDIO_DCE112 = $(addprefix $(AMDDALPATH)/dc/audio/dce112/,$(AUDIO_DCE112))
+
+AMD_DAL_FILES += $(AMD_DAL_AUDIO_DCE112)
+endif
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c b/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
index c297d95..a8137e0 100644
--- a/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
+++ b/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
@@ -40,6 +40,11 @@
 #include "dce110/hw_ctx_audio_dce110.h"
 #endif
 
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+#include "dce112/audio_dce112.h"
+#include "dce112/hw_ctx_audio_dce112.h"
+#endif
+
 /***** static function : only used within audio.c *****/
 
 /* stub for hook functions */
@@ -281,6 +286,10 @@ struct audio *dal_audio_create(
 	case DCE_VERSION_11_0:
 		return dal_audio_create_dce110(init_data);
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	case DCE_VERSION_11_2:
+		return dal_audio_create_dce112(init_data);
+#endif
 	default:
 		BREAK_TO_DEBUGGER();
 		return NULL;
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.c b/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.c
new file mode 100644
index 0000000..66c32b0
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.c
@@ -0,0 +1,451 @@
+/*
+ * 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 "include/logger_interface.h"
+
+#include "audio_dce112.h"
+
+/***** static functions  *****/
+
+static void destruct(struct audio_dce112 *audio)
+{
+	/*release memory allocated for hw_ctx -- allocated is initiated
+	 *by audio_dce112 power_up
+	 *audio->base->hw_ctx = NULL is done within hw-ctx->destroy
+	 */
+	if (audio->base.hw_ctx)
+		audio->base.hw_ctx->funcs->destroy(&(audio->base.hw_ctx));
+
+	/* reset base_audio_block */
+	dal_audio_destruct_base(&audio->base);
+}
+
+static void destroy(struct audio **ptr)
+{
+	struct audio_dce112 *audio = NULL;
+
+	audio = container_of(*ptr, struct audio_dce112, base);
+
+	destruct(audio);
+
+	/* release memory allocated for audio_dce112*/
+	dm_free(audio);
+	*ptr = NULL;
+}
+
+/* The inital call of hook function comes from audio object level.
+ *The passing object handle "struct audio *audio" point to base object
+ *already.There is not need to get base object from audio_dce112.
+ */
+
+/**
+* setup
+*
+* @brief
+*  setup Audio HW block, to be called by dal_audio_setup
+*
+*/
+static enum audio_result setup(
+	struct audio *audio,
+	struct audio_output *output,
+	struct audio_info *info)
+{
+	switch (output->signal) {
+	case SIGNAL_TYPE_HDMI_TYPE_A:
+		/*setup HDMI audio engine*/
+		audio->hw_ctx->funcs->enable_afmt_clock(
+			audio->hw_ctx,
+			output->engine_id,
+			true);
+		audio->hw_ctx->funcs->setup_hdmi_audio(
+			audio->hw_ctx, output->engine_id, &output->crtc_info);
+
+		audio->hw_ctx->funcs->setup_azalia(
+			audio->hw_ctx,
+			output->engine_id,
+			output->signal,
+			&output->crtc_info,
+			&output->pll_info,
+			info);
+		break;
+
+	case SIGNAL_TYPE_WIRELESS:
+		/* setup Azalia block for Wireless Display - This
+			is different than for wired
+			displays because there is no
+			DIG to program.*/
+		/*TODO:
+		audio->hw_ctx->funcs->setup_azalia_for_vce(
+			audio->hw_ctx,
+			audio->signal,
+			audio->crtc_info,
+			info);
+		*/
+		break;
+	case SIGNAL_TYPE_DISPLAY_PORT:
+	case SIGNAL_TYPE_DISPLAY_PORT_MST:
+	case SIGNAL_TYPE_EDP:
+		/* setup DP audio engine will be done at enable output */
+
+		/* setup Azalia block*/
+		audio->hw_ctx->funcs->setup_azalia(
+			audio->hw_ctx,
+			output->engine_id,
+			output->signal,
+			&output->crtc_info,
+			&output->pll_info,
+			info);
+
+		break;
+	default:
+		return AUDIO_RESULT_ERROR;
+	}
+
+	return AUDIO_RESULT_OK;
+}
+
+/**
+* enable_output
+*
+* @brief
+*  enable Audio HW block, to be called by dal_audio_enable_output
+*/
+static enum audio_result enable_output(
+	struct audio *audio,
+	enum engine_id engine_id,
+	enum signal_type signal)
+{
+	/* enable audio output */
+	switch (signal) {
+	case SIGNAL_TYPE_HDMI_TYPE_A:
+		break;
+	case SIGNAL_TYPE_DISPLAY_PORT:
+	case SIGNAL_TYPE_DISPLAY_PORT_MST:
+	case SIGNAL_TYPE_EDP: {
+			/* enable AFMT clock before enable audio*/
+			audio->hw_ctx->funcs->enable_afmt_clock(
+				audio->hw_ctx, engine_id, true);
+			/* setup DP audio engine */
+			audio->hw_ctx->funcs->setup_dp_audio(
+				audio->hw_ctx, engine_id);
+			/* enabl DP audio packets will be done at unblank */
+			audio->hw_ctx->funcs->enable_dp_audio(
+				audio->hw_ctx, engine_id);
+		}
+		break;
+	case SIGNAL_TYPE_WIRELESS:
+		/* route audio to VCE block */
+		audio->hw_ctx->funcs->setup_vce_audio(audio->hw_ctx);
+		break;
+	default:
+		return AUDIO_RESULT_ERROR;
+	}
+	return AUDIO_RESULT_OK;
+}
+
+/**
+* disable_output
+*
+* @brief
+*  disable Audio HW block, to be called by dal_audio_disable_output
+*
+*/
+static enum audio_result disable_output(
+	struct audio *audio,
+	enum engine_id engine_id,
+	enum signal_type signal)
+{
+	switch (signal) {
+	case SIGNAL_TYPE_HDMI_TYPE_A:
+	case SIGNAL_TYPE_WIRELESS:
+		/* disable HDMI audio */
+		audio->hw_ctx->
+			funcs->disable_azalia_audio(
+					audio->hw_ctx, engine_id);
+		audio->hw_ctx->
+			funcs->enable_afmt_clock(
+					audio->hw_ctx, engine_id,
+					false);
+
+		break;
+	case SIGNAL_TYPE_DISPLAY_PORT:
+	case SIGNAL_TYPE_DISPLAY_PORT_MST:
+	case SIGNAL_TYPE_EDP: {
+			/* disable DP audio */
+			audio->hw_ctx->funcs->disable_dp_audio(
+				audio->hw_ctx, engine_id);
+			audio->hw_ctx->funcs->disable_azalia_audio(
+				audio->hw_ctx, engine_id);
+			audio->hw_ctx->funcs->enable_afmt_clock(
+				audio->hw_ctx, engine_id, false);
+		}
+		break;
+	default:
+		return AUDIO_RESULT_ERROR;
+	}
+
+	return AUDIO_RESULT_OK;
+}
+
+/**
+* unmute
+*
+* @brief
+*  unmute audio, to be called by dal_audio_unmute
+*
+*/
+static enum audio_result unmute(
+	struct audio *audio,
+	enum engine_id engine_id,
+	enum signal_type signal)
+{
+	switch (signal) {
+	case SIGNAL_TYPE_HDMI_TYPE_A:
+	case SIGNAL_TYPE_DISPLAY_PORT:
+	case SIGNAL_TYPE_DISPLAY_PORT_MST:
+	case SIGNAL_TYPE_EDP:
+		/* unmute Azalia audio */
+		audio->hw_ctx->funcs->unmute_azalia_audio(
+				audio->hw_ctx, engine_id);
+		break;
+	case SIGNAL_TYPE_WIRELESS:
+		/*Do nothing for wireless display*/
+		break;
+	default:
+		return AUDIO_RESULT_ERROR;
+	}
+	return AUDIO_RESULT_OK;
+}
+
+/**
+* mute
+*
+* @brief
+*  mute audio, to be called  by dal_audio_nmute
+*
+*/
+static enum audio_result mute(
+	struct audio *audio,
+	enum engine_id engine_id,
+	enum signal_type signal)
+{
+	switch (signal) {
+	case SIGNAL_TYPE_HDMI_TYPE_A:
+	case SIGNAL_TYPE_DISPLAY_PORT:
+	case SIGNAL_TYPE_DISPLAY_PORT_MST:
+	case SIGNAL_TYPE_EDP:
+		/* mute Azalia audio */
+		audio->hw_ctx->funcs->mute_azalia_audio(
+				audio->hw_ctx, engine_id);
+		break;
+	case SIGNAL_TYPE_WIRELESS:
+		/*Do nothing for wireless display*/
+		break;
+	default:
+		return AUDIO_RESULT_ERROR;
+	}
+	return AUDIO_RESULT_OK;
+}
+
+/**
+* initialize
+*
+* @brief
+*  Perform SW initialization - create audio hw context. Then do HW
+*  initialization. this function is called at dal_audio_power_up.
+*
+*/
+static enum audio_result initialize(
+	struct audio *audio)
+{
+	uint8_t audio_endpoint_enum_id = 0;
+
+	audio_endpoint_enum_id = audio->id.enum_id;
+
+	/* HW CTX already create*/
+	if (audio->hw_ctx != NULL)
+		return AUDIO_RESULT_OK;
+
+	audio->hw_ctx = dal_hw_ctx_audio_dce112_create(
+			audio->ctx,
+			audio_endpoint_enum_id);
+
+	if (audio->hw_ctx == NULL)
+		return AUDIO_RESULT_ERROR;
+
+	/* override HW default settings */
+	audio->hw_ctx->funcs->hw_initialize(audio->hw_ctx);
+
+	return AUDIO_RESULT_OK;
+}
+
+/* enable multi channel split */
+static void enable_channel_splitting_mapping(
+	struct audio *audio,
+	enum engine_id engine_id,
+	enum signal_type signal,
+	const struct audio_channel_associate_info *audio_mapping,
+	bool enable)
+{
+	audio->hw_ctx->funcs->setup_channel_splitting_mapping(
+		audio->hw_ctx,
+		engine_id,
+		signal,
+		audio_mapping, enable);
+}
+
+/* get current multi channel split. */
+static enum audio_result get_channel_splitting_mapping(
+	struct audio *audio,
+	enum engine_id engine_id,
+	struct audio_channel_associate_info *audio_mapping)
+{
+	if (audio->hw_ctx->funcs->get_channel_splitting_mapping(
+		audio->hw_ctx, engine_id, audio_mapping)) {
+		return AUDIO_RESULT_OK;
+	} else {
+		return AUDIO_RESULT_ERROR;
+	}
+}
+
+/**
+* set_unsolicited_response_payload
+*
+* @brief
+*  Set payload value for the unsolicited response
+*/
+static void set_unsolicited_response_payload(
+	struct audio *audio,
+	enum audio_payload payload)
+{
+	audio->hw_ctx->funcs->set_unsolicited_response_payload(
+			audio->hw_ctx, payload);
+}
+
+/**
+* setup_audio_wall_dto
+*
+* @brief
+*  Update audio source clock from hardware context.
+*
+*/
+static void setup_audio_wall_dto(
+	struct audio *audio,
+	enum signal_type signal,
+	const struct audio_crtc_info *crtc_info,
+	const struct audio_pll_info *pll_info)
+{
+	audio->hw_ctx->funcs->setup_audio_wall_dto(
+		audio->hw_ctx, signal, crtc_info, pll_info);
+}
+
+/**
+* get_supported_features
+*
+* @brief
+*  options and features supported by Audio
+*  returns supported engines, signals.
+*  features are reported for HW audio/Azalia block rather then Audio object
+*  itself the difference for DCE6.x is that MultiStream Audio is now supported
+*
+*/
+static struct audio_feature_support get_supported_features(struct audio *audio)
+{
+	struct audio_feature_support afs = {0};
+
+	afs.ENGINE_DIGA = 1;
+	afs.ENGINE_DIGB = 1;
+	afs.ENGINE_DIGC = 1;
+	afs.MULTISTREAM_AUDIO = 1;
+
+	return afs;
+}
+
+static const struct audio_funcs funcs = {
+	.destroy = destroy,
+	.setup = setup,
+	.enable_output = enable_output,
+	.disable_output = disable_output,
+	.unmute = unmute,
+	.mute = mute,
+	.initialize = initialize,
+	.enable_channel_splitting_mapping =
+		enable_channel_splitting_mapping,
+	.get_channel_splitting_mapping =
+		get_channel_splitting_mapping,
+	.set_unsolicited_response_payload =
+		set_unsolicited_response_payload,
+	.setup_audio_wall_dto = setup_audio_wall_dto,
+	.get_supported_features = get_supported_features,
+};
+
+static bool construct(
+	struct audio_dce112 *audio,
+	const struct audio_init_data *init_data)
+{
+	struct audio *base = &audio->base;
+
+	/* base audio construct*/
+	if (!dal_audio_construct_base(base, init_data))
+		return false;
+
+	/*vtable methods*/
+	base->funcs = &funcs;
+	return true;
+}
+
+/* --- audio scope functions  --- */
+
+struct audio *dal_audio_create_dce112(
+	const struct audio_init_data *init_data)
+{
+	/*allocate memory for audio_dce112 */
+	struct audio_dce112 *audio = dm_alloc(sizeof(*audio));
+
+	if (audio == NULL) {
+		ASSERT_CRITICAL(audio);
+		return NULL;
+	}
+	/*pointer to base_audio_block of audio_dce112 ==> audio base object */
+	if (construct(audio, init_data))
+		return &audio->base;
+
+	dal_logger_write(
+		init_data->ctx->logger,
+		LOG_MAJOR_ERROR,
+		LOG_MINOR_COMPONENT_AUDIO,
+		"Failed to create audio object for DCE11\n");
+
+	 /*release memory allocated if fail */
+	dm_free(audio);
+	return NULL;
+}
+
+/* Do not need expose construct_dce112 and destruct_dce112 becuase there is
+ *derived object after dce112
+ */
+
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.h b/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.h
new file mode 100644
index 0000000..7c8d71c
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.h
@@ -0,0 +1,40 @@
+/*
+ * 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 __DAL_AUDIO_DCE_112_H__
+#define __DAL_AUDIO_DCE_112_H__
+
+#include "audio/audio.h"
+#include "audio/hw_ctx_audio.h"
+#include "audio/dce112/hw_ctx_audio_dce112.h"
+
+struct audio_dce112 {
+	struct audio base;
+	/* dce-specific members are following */
+	/* none */
+};
+
+struct audio *dal_audio_create_dce112(const struct audio_init_data *init_data);
+
+#endif   /*__DAL_AUDIO_DCE_112_H__*/
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.c b/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.c
new file mode 100644
index 0000000..95cb86f
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.c
@@ -0,0 +1,1923 @@
+/*
+ * 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 "include/logger_interface.h"
+#include "../hw_ctx_audio.h"
+#include "hw_ctx_audio_dce112.h"
+
+#include "dce/dce_11_2_d.h"
+#include "dce/dce_11_2_sh_mask.h"
+
+#define FROM_BASE(ptr) \
+	container_of((ptr), struct hw_ctx_audio_dce112, base)
+
+#define DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT 0x8000
+#define DP_AUDIO_DTO_MODULE_WITHOUT_SS 360
+#define DP_AUDIO_DTO_PHASE_WITHOUT_SS 24
+
+#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUDIO_FRONT_END 0
+#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC 1
+#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__REGISTER_PROGRAMMABLE 2
+
+#define FIRST_AUDIO_STREAM_ID 1
+
+#define NOT_IMPLEMENTED() DAL_LOGGER_NOT_IMPL(LOG_MINOR_COMPONENT_AUDIO, \
+			"Audio:%s()\n", __func__)
+
+static const uint32_t engine_offset[] = {
+	0,
+	mmDIG1_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
+	mmDIG2_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
+	mmDIG3_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
+	mmDIG4_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
+	mmDIG5_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL
+};
+
+static void destruct(
+	struct hw_ctx_audio_dce112 *hw_ctx_dce112)
+{
+	dal_audio_destruct_hw_ctx_audio(&hw_ctx_dce112->base);
+}
+
+static void destroy(
+	struct hw_ctx_audio **ptr)
+{
+	struct hw_ctx_audio_dce112 *hw_ctx_dce112;
+
+	hw_ctx_dce112 = container_of(
+		*ptr, struct hw_ctx_audio_dce112, base);
+
+	destruct(hw_ctx_dce112);
+	/* release memory allocated for struct hw_ctx_audio_dce112 */
+	dm_free(hw_ctx_dce112);
+
+	*ptr = NULL;
+}
+
+/* ---  helpers --- */
+static void write_indirect_azalia_reg(
+	const struct hw_ctx_audio *hw_ctx,
+	uint32_t reg_index,
+	uint32_t reg_data)
+{
+	uint32_t addr = 0;
+	uint32_t value = 0;
+	/* AZALIA_F0_CODEC_ENDPOINT_INDEX  endpoint index  */
+	{
+		addr =
+			FROM_BASE(hw_ctx)->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_index;
+
+		set_reg_field_value(value, reg_index,
+			AZALIA_F0_CODEC_ENDPOINT_INDEX,
+			AZALIA_ENDPOINT_REG_INDEX);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* AZALIA_F0_CODEC_ENDPOINT_DATA  endpoint data  */
+	{
+		addr =
+			FROM_BASE(hw_ctx)->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_data;
+
+		value = 0;
+		set_reg_field_value(value, reg_data,
+			AZALIA_F0_CODEC_ENDPOINT_DATA,
+			AZALIA_ENDPOINT_REG_DATA);
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	dal_logger_write(
+		hw_ctx->ctx->logger,
+		LOG_MAJOR_HW_TRACE,
+		LOG_MINOR_HW_TRACE_AUDIO,
+		"AUDIO:write_indirect_azalia_reg: index: %u  data: %u\n",
+		reg_index, reg_data);
+}
+
+static uint32_t read_indirect_azalia_reg(
+	const struct hw_ctx_audio *hw_ctx,
+	uint32_t reg_index)
+{
+	uint32_t ret_val = 0;
+	uint32_t addr = 0;
+	uint32_t value = 0;
+
+	/* AZALIA_F0_CODEC_ENDPOINT_INDEX  endpoint index  */
+	{
+		addr =
+			FROM_BASE(hw_ctx)->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_index;
+
+		set_reg_field_value(value, reg_index,
+			AZALIA_F0_CODEC_ENDPOINT_INDEX,
+			AZALIA_ENDPOINT_REG_INDEX);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* AZALIA_F0_CODEC_ENDPOINT_DATA  endpoint data  */
+	{
+		addr =
+			FROM_BASE(hw_ctx)->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_data;
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+		ret_val = value;
+	}
+
+	dal_logger_write(
+		hw_ctx->ctx->logger,
+		LOG_MAJOR_HW_TRACE,
+		LOG_MINOR_HW_TRACE_AUDIO,
+		"AUDIO:read_indirect_azalia_reg: index: %u  data: %u\n",
+		reg_index, ret_val);
+
+	return ret_val;
+}
+
+/* expose/not expose HBR capability to Audio driver */
+static void set_high_bit_rate_capable(
+	const struct hw_ctx_audio *hw_ctx,
+	bool capable)
+{
+	uint32_t value = 0;
+
+	/* set high bit rate audio capable*/
+	value = read_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR);
+
+	set_reg_field_value(value, capable,
+		AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR,
+		HBR_CAPABLE);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR,
+		value);
+}
+
+/* set HBR channnel count *
+static void set_hbr_channel_count(
+	const struct hw_ctx_audio *hw_ctx,
+	uint32_t hbr_channel_count)
+{
+	uint32_t value = 0;
+
+	if (hbr_channel_count > 7)
+		return;
+
+	value = dal_read_reg(hw_ctx->ctx,
+		mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL);
+
+	set_reg_field_value(value, hbr_channel_count,
+		AZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL,
+		HBR_CHANNEL_COUNT);
+
+	dal_write_reg(hw_ctx->ctx,
+		mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL, value);
+
+}
+
+*set compressed audio channel count *
+static void set_compressed_audio_channel_count(
+	const struct hw_ctx_audio *hw_ctx,
+	uint32_t compressed_audio_ch_count)
+{
+	uint32_t value = 0;
+	if (compressed_audio_ch_count > 7)
+		return;
+
+	value = dal_read_reg(hw_ctx->ctx,
+		mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL);
+
+	set_reg_field_value(value, compressed_audio_ch_count,
+		AZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL,
+		COMPRESSED_CHANNEL_COUNT);
+
+	dal_write_reg(hw_ctx->ctx,
+		mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL,
+		value);
+
+}
+*/
+/* set video latency in in ms/2+1 */
+static void set_video_latency(
+	const struct hw_ctx_audio *hw_ctx,
+	int latency_in_ms)
+{
+	uint32_t value = 0;
+
+	if ((latency_in_ms < 0) || (latency_in_ms > 255))
+		return;
+
+	value = read_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC);
+
+	set_reg_field_value(value, latency_in_ms,
+		AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+		VIDEO_LIPSYNC);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+		value);
+
+}
+
+/* set audio latency in in ms/2+1 */
+static void set_audio_latency(
+	const struct hw_ctx_audio *hw_ctx,
+	int latency_in_ms)
+{
+	uint32_t value = 0;
+
+	if (latency_in_ms < 0)
+		latency_in_ms = 0;
+
+	if (latency_in_ms > 255)
+		latency_in_ms = 255;
+
+	value = read_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC);
+
+	set_reg_field_value(value, latency_in_ms,
+		AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+		AUDIO_LIPSYNC);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+		value);
+
+}
+
+/* enable HW/SW Sync */
+/*static void enable_hw_sw_sync(
+	const struct hw_ctx_audio *hw_ctx)
+{
+		union AZALIA_CYCLIC_BUFFER_SYNC value;
+
+	value = dal_read_reg(mmAZALIA_CYCLIC_BUFFER_SYNC);
+	value.bits.CYCLIC_BUFFER_SYNC_ENABLE = 1;
+	dal_write_reg(mmAZALIA_CYCLIC_BUFFER_SYNC, value);
+}*/
+
+/* disable HW/SW Sync */
+/*static void disable_hw_sw_sync(
+	const struct hw_ctx_audio *hw_ctx)
+{
+	union AZALIA_CYCLIC_BUFFER_SYNC value;
+
+	value = dal_read_reg(
+		mmAZALIA_CYCLIC_BUFFER_SYNC);
+	value.bits.CYCLIC_BUFFER_SYNC_ENABLE = 0;
+	dal_write_reg(
+		mmAZALIA_CYCLIC_BUFFER_SYNC, value);
+}*/
+
+/* update hardware with software's current position in cyclic buffer */
+/*static void update_sw_write_ptr(
+	const struct hw_ctx_audio *hw_ctx,
+	uint32_t offset)
+{
+		union AZALIA_APPLICATION_POSITION_IN_CYCLIC_BUFFER value;
+
+	value = dal_read_reg(
+		mmAZALIA_APPLICATION_POSITION_IN_CYCLIC_BUFFER);
+	value.bits.APPLICATION_POSITION_IN_CYCLIC_BUFFER = offset;
+	dal_write_reg(
+		mmAZALIA_APPLICATION_POSITION_IN_CYCLIC_BUFFER,
+		value);
+}*/
+
+/* update Audio/Video association */
+/*static void update_av_association(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id,
+	enum signal_type signal,
+	uint32_t displayId)
+{
+
+}*/
+
+/* ---  hook functions --- */
+static bool get_azalia_clock_info_hdmi(
+	const struct hw_ctx_audio *hw_ctx,
+	uint32_t crtc_pixel_clock_in_khz,
+	uint32_t actual_pixel_clock_in_khz,
+	struct azalia_clock_info *azalia_clock_info);
+
+static bool get_azalia_clock_info_dp(
+	const struct hw_ctx_audio *hw_ctx,
+	uint32_t requested_pixel_clock_in_khz,
+	const struct audio_pll_info *pll_info,
+	struct azalia_clock_info *azalia_clock_info);
+
+static void setup_audio_wall_dto(
+	const struct hw_ctx_audio *hw_ctx,
+	enum signal_type signal,
+	const struct audio_crtc_info *crtc_info,
+	const struct audio_pll_info *pll_info)
+{
+	struct azalia_clock_info clock_info = { 0 };
+
+	uint32_t value = dm_read_reg(hw_ctx->ctx, mmDCCG_AUDIO_DTO_SOURCE);
+
+	/* TODO: GraphicsObject\inc\GraphicsObjectDefs.hpp(131):
+	 *inline bool isHdmiSignal(SignalType signal)
+	 *if (Signals::isHdmiSignal(signal))
+	 */
+	if (dc_is_hdmi_signal(signal)) {
+		/*DTO0 Programming goal:
+		-generate 24MHz, 128*Fs from 24MHz
+		-use DTO0 when an active HDMI port is connected
+		(optionally a DP is connected) */
+
+		/* calculate DTO settings */
+		get_azalia_clock_info_hdmi(
+			hw_ctx,
+			crtc_info->requested_pixel_clock,
+			crtc_info->calculated_pixel_clock,
+			&clock_info);
+
+		/* On TN/SI, Program DTO source select and DTO select before
+		programming DTO modulo and DTO phase. These bits must be
+		programmed first, otherwise there will be no HDMI audio at boot
+		up. This is a HW sequence change (different from old ASICs).
+		Caution when changing this programming sequence.
+
+		HDMI enabled, using DTO0
+		program master CRTC for DTO0 */
+		{
+			set_reg_field_value(value,
+				pll_info->dto_source - DTO_SOURCE_ID0,
+				DCCG_AUDIO_DTO_SOURCE,
+				DCCG_AUDIO_DTO0_SOURCE_SEL);
+
+			set_reg_field_value(value,
+				0,
+				DCCG_AUDIO_DTO_SOURCE,
+				DCCG_AUDIO_DTO_SEL);
+
+			dm_write_reg(hw_ctx->ctx,
+					mmDCCG_AUDIO_DTO_SOURCE, value);
+		}
+
+		/* module */
+		{
+			value = dm_read_reg(hw_ctx->ctx,
+					mmDCCG_AUDIO_DTO0_MODULE);
+			set_reg_field_value(value,
+				clock_info.audio_dto_module,
+				DCCG_AUDIO_DTO0_MODULE,
+				DCCG_AUDIO_DTO0_MODULE);
+			dm_write_reg(hw_ctx->ctx,
+					mmDCCG_AUDIO_DTO0_MODULE, value);
+		}
+
+		/* phase */
+		{
+			value = 0;
+
+			value = dm_read_reg(hw_ctx->ctx,
+					mmDCCG_AUDIO_DTO0_PHASE);
+			set_reg_field_value(value,
+				clock_info.audio_dto_phase,
+				DCCG_AUDIO_DTO0_PHASE,
+				DCCG_AUDIO_DTO0_PHASE);
+
+			dm_write_reg(hw_ctx->ctx,
+					mmDCCG_AUDIO_DTO0_PHASE, value);
+		}
+
+	} else {
+		/*DTO1 Programming goal:
+		-generate 24MHz, 512*Fs, 128*Fs from 24MHz
+		-default is to used DTO1, and switch to DTO0 when an audio
+		master HDMI port is connected
+		-use as default for DP
+
+		calculate DTO settings */
+		get_azalia_clock_info_dp(
+			hw_ctx,
+			crtc_info->requested_pixel_clock,
+			pll_info,
+			&clock_info);
+
+		/* Program DTO select before programming DTO modulo and DTO
+		phase. default to use DTO1 */
+
+		{
+			set_reg_field_value(value, 1,
+				DCCG_AUDIO_DTO_SOURCE,
+				DCCG_AUDIO_DTO_SEL);
+			/*dal_write_reg(mmDCCG_AUDIO_DTO_SOURCE, value)*/
+
+			/* Select 512fs for DP TODO: web register definition
+			does not match register header file
+			set_reg_field_value(value, 1,
+				DCCG_AUDIO_DTO_SOURCE,
+				DCCG_AUDIO_DTO2_USE_512FBR_DTO);
+			*/
+
+			dm_write_reg(hw_ctx->ctx,
+					mmDCCG_AUDIO_DTO_SOURCE, value);
+		}
+
+		/* module */
+		{
+			value = 0;
+
+			value = dm_read_reg(hw_ctx->ctx,
+					mmDCCG_AUDIO_DTO1_MODULE);
+
+			set_reg_field_value(value,
+				clock_info.audio_dto_module,
+				DCCG_AUDIO_DTO1_MODULE,
+				DCCG_AUDIO_DTO1_MODULE);
+
+			dm_write_reg(hw_ctx->ctx,
+					mmDCCG_AUDIO_DTO1_MODULE, value);
+		}
+
+		/* phase */
+		{
+			value = 0;
+
+			value = dm_read_reg(hw_ctx->ctx,
+					mmDCCG_AUDIO_DTO1_PHASE);
+
+			set_reg_field_value(value,
+				clock_info.audio_dto_phase,
+				DCCG_AUDIO_DTO1_PHASE,
+				DCCG_AUDIO_DTO1_PHASE);
+
+			dm_write_reg(hw_ctx->ctx,
+					mmDCCG_AUDIO_DTO1_PHASE, value);
+		}
+
+		/* DAL2 code separate DCCG_AUDIO_DTO_SEL and
+		DCCG_AUDIO_DTO2_USE_512FBR_DTO programming into two different
+		location. merge together should not hurt */
+		/*value.bits.DCCG_AUDIO_DTO2_USE_512FBR_DTO = 1;
+		dal_write_reg(mmDCCG_AUDIO_DTO_SOURCE, value);*/
+	}
+}
+
+/* setup HDMI audio */
+static void setup_hdmi_audio(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id,
+	const struct audio_crtc_info *crtc_info)
+{
+	struct audio_clock_info audio_clock_info = {0};
+	uint32_t max_packets_per_line;
+	uint32_t addr = 0;
+	uint32_t value = 0;
+
+	/* For now still do calculation, although this field is ignored when
+	above HDMI_PACKET_GEN_VERSION set to 1 */
+	max_packets_per_line =
+		dal_audio_hw_ctx_calc_max_audio_packets_per_line(
+			hw_ctx,
+			crtc_info);
+
+	/* HDMI_AUDIO_PACKET_CONTROL */
+	{
+		addr =
+			mmHDMI_AUDIO_PACKET_CONTROL + engine_offset[engine_id];
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+
+		set_reg_field_value(value, max_packets_per_line,
+			HDMI_AUDIO_PACKET_CONTROL,
+			HDMI_AUDIO_PACKETS_PER_LINE);
+		/* still apply RS600's default setting which is 1. */
+		set_reg_field_value(value, 1,
+			HDMI_AUDIO_PACKET_CONTROL,
+			HDMI_AUDIO_DELAY_EN);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* AFMT_AUDIO_PACKET_CONTROL */
+	{
+		addr = mmAFMT_AUDIO_PACKET_CONTROL + engine_offset[engine_id];
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+
+		set_reg_field_value(value, 1,
+			AFMT_AUDIO_PACKET_CONTROL,
+			AFMT_60958_CS_UPDATE);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* AFMT_AUDIO_PACKET_CONTROL2 */
+	{
+		addr = mmAFMT_AUDIO_PACKET_CONTROL2 + engine_offset[engine_id];
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+
+		set_reg_field_value(value, 0,
+				AFMT_AUDIO_PACKET_CONTROL2,
+				AFMT_AUDIO_LAYOUT_OVRD);
+
+		/*Register field changed.*/
+		set_reg_field_value(value, 0,
+			AFMT_AUDIO_PACKET_CONTROL2,
+			AFMT_60958_OSF_OVRD);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* HDMI_ACR_PACKET_CONTROL */
+	{
+		addr = mmHDMI_ACR_PACKET_CONTROL + engine_offset[engine_id];
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+		set_reg_field_value(value, 1,
+			HDMI_ACR_PACKET_CONTROL,
+			HDMI_ACR_AUTO_SEND);
+
+		/* Set HDMI_ACR_SOURCE to 0, to use hardwre
+		 *  computed CTS values.*/
+		set_reg_field_value(value, 0,
+			HDMI_ACR_PACKET_CONTROL,
+			HDMI_ACR_SOURCE);
+
+		/* For now clear HDMI_ACR_AUDIO_PRIORITY =>ACR packet has
+		higher priority over Audio Sample */
+		set_reg_field_value(value, 0,
+			HDMI_ACR_PACKET_CONTROL,
+			HDMI_ACR_AUDIO_PRIORITY);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* Program audio clock sample/regeneration parameters */
+	if (dal_audio_hw_ctx_get_audio_clock_info(
+		hw_ctx,
+		crtc_info->color_depth,
+		crtc_info->requested_pixel_clock,
+		crtc_info->calculated_pixel_clock,
+		&audio_clock_info)) {
+
+		/* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
+		{
+			addr = mmHDMI_ACR_32_0 + engine_offset[engine_id];
+
+			value = dm_read_reg(hw_ctx->ctx, addr);
+
+			set_reg_field_value(value, audio_clock_info.cts_32khz,
+				HDMI_ACR_32_0,
+				HDMI_ACR_CTS_32);
+
+			dm_write_reg(hw_ctx->ctx, addr, value);
+		}
+
+		/* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
+		{
+			addr = mmHDMI_ACR_32_1 + engine_offset[engine_id];
+
+			value = dm_read_reg(hw_ctx->ctx, addr);
+			set_reg_field_value(value, audio_clock_info.n_32khz,
+				HDMI_ACR_32_1,
+				HDMI_ACR_N_32);
+
+			dm_write_reg(hw_ctx->ctx, addr, value);
+		}
+
+		/* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
+		{
+			addr = mmHDMI_ACR_44_0 + engine_offset[engine_id];
+
+			value = dm_read_reg(hw_ctx->ctx, addr);
+			set_reg_field_value(value, audio_clock_info.cts_44khz,
+				HDMI_ACR_44_0,
+				HDMI_ACR_CTS_44);
+
+			dm_write_reg(hw_ctx->ctx, addr, value);
+		}
+
+		/* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
+		{
+			addr = mmHDMI_ACR_44_1 + engine_offset[engine_id];
+
+			value = dm_read_reg(hw_ctx->ctx, addr);
+			set_reg_field_value(value, audio_clock_info.n_44khz,
+				HDMI_ACR_44_1,
+				HDMI_ACR_N_44);
+
+			dm_write_reg(hw_ctx->ctx, addr, value);
+		}
+
+		/* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
+		{
+			addr = mmHDMI_ACR_48_0 + engine_offset[engine_id];
+
+			value = dm_read_reg(hw_ctx->ctx, addr);
+			set_reg_field_value(value, audio_clock_info.cts_48khz,
+				HDMI_ACR_48_0,
+				HDMI_ACR_CTS_48);
+
+			dm_write_reg(hw_ctx->ctx, addr, value);
+		}
+
+		/* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
+		{
+			addr = mmHDMI_ACR_48_1 + engine_offset[engine_id];
+
+			value = dm_read_reg(hw_ctx->ctx, addr);
+			set_reg_field_value(value, audio_clock_info.n_48khz,
+				HDMI_ACR_48_1,
+				HDMI_ACR_N_48);
+
+			dm_write_reg(hw_ctx->ctx, addr, value);
+		}
+
+		/* Video driver cannot know in advance which sample rate will
+		be used by HD Audio driver
+		HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
+		programmed below in interruppt callback */
+	} /* if */
+
+	/* AFMT_60958_0__AFMT_60958_CS_CHANNEL_NUMBER_L_MASK &
+	AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK */
+	{
+		addr = mmAFMT_60958_0 + engine_offset[engine_id];
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+		set_reg_field_value(value, 1,
+			AFMT_60958_0,
+			AFMT_60958_CS_CHANNEL_NUMBER_L);
+
+		 /*HW default */
+		set_reg_field_value(value, 0,
+			AFMT_60958_0,
+			AFMT_60958_CS_CLOCK_ACCURACY);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* AFMT_60958_1 AFMT_60958_CS_CHALNNEL_NUMBER_R */
+	{
+		addr = mmAFMT_60958_1 + engine_offset[engine_id];
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+		set_reg_field_value(value, 2,
+			AFMT_60958_1,
+			AFMT_60958_CS_CHANNEL_NUMBER_R);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/*AFMT_60958_2 now keep this settings until
+	 *  Programming guide comes out*/
+	{
+		addr = mmAFMT_60958_2 + engine_offset[engine_id];
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+		set_reg_field_value(value, 3,
+			AFMT_60958_2,
+			AFMT_60958_CS_CHANNEL_NUMBER_2);
+
+		set_reg_field_value(value, 4,
+			AFMT_60958_2,
+			AFMT_60958_CS_CHANNEL_NUMBER_3);
+
+		set_reg_field_value(value, 5,
+			AFMT_60958_2,
+			AFMT_60958_CS_CHANNEL_NUMBER_4);
+
+		set_reg_field_value(value, 6,
+			AFMT_60958_2,
+			AFMT_60958_CS_CHANNEL_NUMBER_5);
+
+		set_reg_field_value(value, 7,
+			AFMT_60958_2,
+			AFMT_60958_CS_CHANNEL_NUMBER_6);
+
+		set_reg_field_value(value, 8,
+			AFMT_60958_2,
+			AFMT_60958_CS_CHANNEL_NUMBER_7);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+}
+
+ /* setup DP audio */
+static void setup_dp_audio(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id)
+{
+	/* --- DP Audio packet configurations --- */
+	uint32_t addr = 0;
+	uint32_t value = 0;
+
+	/* ATP Configuration */
+	{
+		addr = mmDP_SEC_AUD_N + engine_offset[engine_id];
+
+		set_reg_field_value(value,
+			DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT,
+			DP_SEC_AUD_N,
+			DP_SEC_AUD_N);
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* Async/auto-calc timestamp mode */
+	{
+		addr = mmDP_SEC_TIMESTAMP +
+			engine_offset[engine_id];
+
+		value = 0;
+
+		set_reg_field_value(value,
+			DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC,
+			DP_SEC_TIMESTAMP,
+			DP_SEC_TIMESTAMP_MODE);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* --- The following are the registers
+	 *  copied from the SetupHDMI --- */
+
+	/* AFMT_AUDIO_PACKET_CONTROL */
+	{
+		addr = mmAFMT_AUDIO_PACKET_CONTROL +
+			engine_offset[engine_id];
+
+		value = 0;
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+		set_reg_field_value(value,
+			1,
+			AFMT_AUDIO_PACKET_CONTROL,
+			AFMT_60958_CS_UPDATE);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* AFMT_AUDIO_PACKET_CONTROL2 */
+	{
+		addr =
+			mmAFMT_AUDIO_PACKET_CONTROL2 + engine_offset[engine_id];
+
+		value = 0;
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+		set_reg_field_value(value,
+			0,
+			AFMT_AUDIO_PACKET_CONTROL2,
+			AFMT_AUDIO_LAYOUT_OVRD);
+
+		set_reg_field_value(value,
+			0,
+			AFMT_AUDIO_PACKET_CONTROL2,
+			AFMT_60958_OSF_OVRD);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* AFMT_INFOFRAME_CONTROL0 */
+	{
+		addr =
+			mmAFMT_INFOFRAME_CONTROL0 + engine_offset[engine_id];
+
+		value = 0;
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+
+		set_reg_field_value(value,
+			1,
+			AFMT_INFOFRAME_CONTROL0,
+			AFMT_AUDIO_INFO_UPDATE);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK */
+	{
+		addr = mmAFMT_60958_0 + engine_offset[engine_id];
+
+		value = 0;
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+		set_reg_field_value(value,
+			0,
+			AFMT_60958_0,
+			AFMT_60958_CS_CLOCK_ACCURACY);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+}
+
+ /* setup VCE audio */
+static void setup_vce_audio(
+	const struct hw_ctx_audio *hw_ctx)
+{
+	struct dc_context *ctx = hw_ctx->ctx;
+
+	NOT_IMPLEMENTED();
+
+	/*TODO:
+	const uint32_t addr = mmDOUT_DCE_VCE_CONTROL;
+	uint32_t value = 0;
+
+	value = dal_read_reg(hw_ctx->ctx,
+			addr);
+
+	set_reg_field_value(value,
+		FROM_BASE(hw_ctx)->azalia_stream_id - 1,
+		DOUT_DCE_VCE_CONTROL,
+		DC_VCE_AUDIO_STREAM_SELECT);
+
+	dal_write_reg(hw_ctx->ctx,
+			addr, value);*/
+}
+
+static void enable_afmt_clock(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id,
+	bool enable_flag)
+{
+	uint32_t engine_offs = engine_offset[engine_id];
+	uint32_t value;
+	uint32_t count = 0;
+	uint32_t enable = enable_flag ? 1:0;
+
+	/* Enable Audio packets*/
+	value = dm_read_reg(hw_ctx->ctx, mmAFMT_CNTL + engine_offs);
+
+	/*enable AFMT clock*/
+	set_reg_field_value(value, enable,
+		AFMT_CNTL, AFMT_AUDIO_CLOCK_EN);
+	dm_write_reg(hw_ctx->ctx, mmAFMT_CNTL + engine_offs, value);
+
+	/*wait for AFMT clock to turn on,
+	 * the expectation is that this
+	 * should complete in 1-2 reads)
+	 */
+	do {
+		/* Wait for 1us between subsequent register reads.*/
+		udelay(1);
+		value = dm_read_reg(hw_ctx->ctx,
+				mmAFMT_CNTL + engine_offs);
+	} while (get_reg_field_value(value,
+				AFMT_CNTL, AFMT_AUDIO_CLOCK_ON) !=
+						enable && count++ < 10);
+}
+
+/* enable Azalia audio */
+static void enable_azalia_audio(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id)
+{
+	uint32_t value;
+
+	value = read_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
+
+	if (get_reg_field_value(value,
+			AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+			AUDIO_ENABLED) != 1)
+		set_reg_field_value(value, 1,
+			AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+			AUDIO_ENABLED);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+		value);
+}
+
+/* disable Azalia audio */
+static void disable_azalia_audio(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id)
+{
+	uint32_t value;
+
+	value = read_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
+
+	set_reg_field_value(value, 0,
+		AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+		AUDIO_ENABLED);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+		value);
+}
+
+/* enable DP audio */
+static void enable_dp_audio(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id)
+{
+	const uint32_t addr = mmDP_SEC_CNTL + engine_offset[engine_id];
+
+	uint32_t value;
+
+	/* Enable Audio packets */
+	value = dm_read_reg(hw_ctx->ctx, addr);
+	set_reg_field_value(value, 1,
+		DP_SEC_CNTL,
+		DP_SEC_ASP_ENABLE);
+
+	dm_write_reg(hw_ctx->ctx, addr, value);
+
+	/* Program the ATP and AIP next */
+	set_reg_field_value(value, 1,
+		DP_SEC_CNTL,
+		DP_SEC_ATP_ENABLE);
+
+	set_reg_field_value(value, 1,
+		DP_SEC_CNTL,
+		DP_SEC_AIP_ENABLE);
+
+	dm_write_reg(hw_ctx->ctx, addr, value);
+
+	/* Program STREAM_ENABLE after all the other enables. */
+	set_reg_field_value(value, 1,
+		DP_SEC_CNTL,
+		DP_SEC_STREAM_ENABLE);
+
+	dm_write_reg(hw_ctx->ctx, addr, value);
+}
+
+/* disable DP audio */
+static void disable_dp_audio(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id)
+{
+	const uint32_t addr = mmDP_SEC_CNTL + engine_offset[engine_id];
+
+	uint32_t value;
+
+	/* Disable Audio packets */
+	value = dm_read_reg(hw_ctx->ctx, addr);
+
+	set_reg_field_value(value, 0,
+		DP_SEC_CNTL,
+		DP_SEC_ASP_ENABLE);
+
+	set_reg_field_value(value, 0,
+		DP_SEC_CNTL,
+		DP_SEC_ATP_ENABLE);
+
+	set_reg_field_value(value, 0,
+		DP_SEC_CNTL,
+		DP_SEC_AIP_ENABLE);
+
+	set_reg_field_value(value, 0,
+		DP_SEC_CNTL,
+		DP_SEC_ACM_ENABLE);
+
+	set_reg_field_value(value, 0,
+		DP_SEC_CNTL,
+		DP_SEC_STREAM_ENABLE);
+
+	/* This register shared with encoder info frame. Therefore we need to
+	keep master enabled if at least on of the fields is not 0 */
+	if (value != 0)
+		set_reg_field_value(value, 1,
+			DP_SEC_CNTL,
+			DP_SEC_STREAM_ENABLE);
+
+	dm_write_reg(hw_ctx->ctx, addr, value);
+}
+
+static void configure_azalia(
+	const struct hw_ctx_audio *hw_ctx,
+	enum signal_type signal,
+	const struct audio_crtc_info *crtc_info,
+	const struct audio_info *audio_info)
+{
+	uint32_t speakers = audio_info->flags.info.ALLSPEAKERS;
+	uint32_t value;
+	uint32_t field = 0;
+	enum audio_format_code audio_format_code;
+	uint32_t format_index;
+	uint32_t index;
+	bool is_ac3_supported = false;
+	bool is_audio_format_supported = false;
+	union audio_sample_rates sample_rate;
+	uint32_t strlen = 0;
+
+	/* Speaker Allocation */
+	/*
+	uint32_t value;
+	uint32_t field = 0;*/
+	value = read_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
+
+	set_reg_field_value(value,
+		speakers,
+		AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+		SPEAKER_ALLOCATION);
+
+	/* LFE_PLAYBACK_LEVEL = LFEPBL
+	 * LFEPBL = 0 : Unknown or refer to other information
+	 * LFEPBL = 1 : 0dB playback
+	 * LFEPBL = 2 : +10dB playback
+	 * LFE_BL = 3 : Reserved
+	 */
+	set_reg_field_value(value,
+		0,
+		AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+		LFE_PLAYBACK_LEVEL);
+
+	set_reg_field_value(value,
+		0,
+		AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+		HDMI_CONNECTION);
+
+	set_reg_field_value(value,
+		0,
+		AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+		DP_CONNECTION);
+
+	field = get_reg_field_value(value,
+			AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+			EXTRA_CONNECTION_INFO);
+
+	field &= ~0x1;
+
+	set_reg_field_value(value,
+		field,
+		AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+		EXTRA_CONNECTION_INFO);
+
+	/* set audio for output signal */
+	switch (signal) {
+	case SIGNAL_TYPE_HDMI_TYPE_A:
+		set_reg_field_value(value,
+			1,
+			AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+			HDMI_CONNECTION);
+
+		break;
+	case SIGNAL_TYPE_WIRELESS: {
+		/*LSB used for "is wireless" flag */
+		field = 0;
+		field = get_reg_field_value(value,
+		AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+		EXTRA_CONNECTION_INFO);
+		field |= 0x1;
+		set_reg_field_value(value,
+			field,
+			AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+			EXTRA_CONNECTION_INFO);
+
+		set_reg_field_value(value,
+			1,
+			AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+			HDMI_CONNECTION);
+
+		}
+		break;
+	case SIGNAL_TYPE_EDP:
+	case SIGNAL_TYPE_DISPLAY_PORT:
+	case SIGNAL_TYPE_DISPLAY_PORT_MST:
+		set_reg_field_value(value,
+			1,
+			AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+			DP_CONNECTION);
+
+		break;
+	default:
+		break;
+	}
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+		value);
+
+	/* Wireless Display identification */
+	value = read_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION);
+
+	set_reg_field_value(value,
+		signal == SIGNAL_TYPE_WIRELESS ? 1 : 0,
+		AZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION,
+		WIRELESS_DISPLAY_IDENTIFICATION);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION,
+		value);
+
+	/*  Audio Descriptors   */
+	/* pass through all formats */
+	for (format_index = 0; format_index < AUDIO_FORMAT_CODE_COUNT;
+			format_index++) {
+		audio_format_code =
+			(AUDIO_FORMAT_CODE_FIRST + format_index);
+
+		/* those are unsupported, skip programming */
+		if (audio_format_code == AUDIO_FORMAT_CODE_1BITAUDIO ||
+			audio_format_code == AUDIO_FORMAT_CODE_DST)
+			continue;
+
+		value = 0;
+
+		/* check if supported */
+		is_audio_format_supported =
+			dal_audio_hw_ctx_is_audio_format_supported(
+				hw_ctx,
+				audio_info,
+				audio_format_code, &index);
+
+		if (is_audio_format_supported) {
+			const struct audio_mode *audio_mode =
+					&audio_info->modes[index];
+			union audio_sample_rates sample_rates =
+					audio_mode->sample_rates;
+			uint8_t byte2 = audio_mode->max_bit_rate;
+
+			/* adjust specific properties */
+			switch (audio_format_code) {
+			case AUDIO_FORMAT_CODE_LINEARPCM: {
+				dal_hw_ctx_audio_check_audio_bandwidth(
+					hw_ctx,
+					crtc_info,
+					audio_mode->channel_count,
+					signal,
+					&sample_rates);
+
+				byte2 = audio_mode->sample_size;
+
+				set_reg_field_value(value,
+				sample_rates.all,
+		AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+				SUPPORTED_FREQUENCIES_STEREO);
+
+				}
+				break;
+			case AUDIO_FORMAT_CODE_AC3:
+				is_ac3_supported = true;
+				break;
+			case AUDIO_FORMAT_CODE_DOLBYDIGITALPLUS:
+			case AUDIO_FORMAT_CODE_DTS_HD:
+			case AUDIO_FORMAT_CODE_MAT_MLP:
+			case AUDIO_FORMAT_CODE_DST:
+			case AUDIO_FORMAT_CODE_WMAPRO:
+				byte2 = audio_mode->vendor_specific;
+				break;
+			default:
+				break;
+			}
+
+			/* fill audio format data */
+			set_reg_field_value(value,
+			audio_mode->channel_count - 1,
+			AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+			MAX_CHANNELS);
+
+			set_reg_field_value(value,
+			sample_rates.all,
+			AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+			SUPPORTED_FREQUENCIES);
+
+			set_reg_field_value(value,
+			byte2,
+			AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+			DESCRIPTOR_BYTE_2);
+
+		} /* if */
+
+		write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0 +
+		format_index,
+		value);
+	} /* for */
+
+	if (is_ac3_supported)
+		dm_write_reg(hw_ctx->ctx,
+		mmAZALIA_F0_CODEC_FUNCTION_PARAMETER_STREAM_FORMATS,
+		0x05);
+
+	/* check for 192khz/8-Ch support for HBR requirements */
+	sample_rate.all = 0;
+	sample_rate.rate.RATE_192 = 1;
+	dal_hw_ctx_audio_check_audio_bandwidth(
+		hw_ctx,
+		crtc_info,
+		8,
+		signal,
+		&sample_rate);
+
+	set_high_bit_rate_capable(hw_ctx, sample_rate.rate.RATE_192);
+
+	/* Audio and Video Lipsync */
+	set_video_latency(hw_ctx, audio_info->video_latency);
+	set_audio_latency(hw_ctx, audio_info->audio_latency);
+
+	value = 0;
+	set_reg_field_value(value, audio_info->manufacture_id,
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
+		MANUFACTURER_ID);
+
+	set_reg_field_value(value, audio_info->product_id,
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
+		PRODUCT_ID);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
+		value);
+
+	value = 0;
+
+	/*get display name string length */
+	while (audio_info->display_name[strlen++] != '\0') {
+		if (strlen >=
+		MAX_HW_AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS)
+			break;
+		}
+	set_reg_field_value(value, strlen,
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1,
+		SINK_DESCRIPTION_LEN);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1,
+		value);
+
+	/*
+	*write the port ID:
+	*PORT_ID0 = display index
+	*PORT_ID1 = 16bit BDF
+	*(format MSB->LSB: 8bit Bus, 5bit Device, 3bit Function)
+	*/
+
+	value = 0;
+
+	set_reg_field_value(value, audio_info->port_id[0],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2,
+		PORT_ID0);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2,
+		value);
+
+	value = 0;
+	set_reg_field_value(value, audio_info->port_id[1],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3,
+		PORT_ID1);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3,
+		value);
+
+	/*write the 18 char monitor string */
+
+	value = 0;
+	set_reg_field_value(value, audio_info->display_name[0],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
+		DESCRIPTION0);
+
+	set_reg_field_value(value, audio_info->display_name[1],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
+		DESCRIPTION1);
+
+	set_reg_field_value(value, audio_info->display_name[2],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
+		DESCRIPTION2);
+
+	set_reg_field_value(value, audio_info->display_name[3],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
+		DESCRIPTION3);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
+		value);
+
+	value = 0;
+	set_reg_field_value(value, audio_info->display_name[4],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
+		DESCRIPTION4);
+
+	set_reg_field_value(value, audio_info->display_name[5],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
+		DESCRIPTION5);
+
+	set_reg_field_value(value, audio_info->display_name[6],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
+		DESCRIPTION6);
+
+	set_reg_field_value(value, audio_info->display_name[7],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
+		DESCRIPTION7);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
+		value);
+
+	value = 0;
+	set_reg_field_value(value, audio_info->display_name[8],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
+		DESCRIPTION8);
+
+	set_reg_field_value(value, audio_info->display_name[9],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
+		DESCRIPTION9);
+
+	set_reg_field_value(value, audio_info->display_name[10],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
+		DESCRIPTION10);
+
+	set_reg_field_value(value, audio_info->display_name[11],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
+		DESCRIPTION11);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
+		value);
+
+	value = 0;
+	set_reg_field_value(value, audio_info->display_name[12],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
+		DESCRIPTION12);
+
+	set_reg_field_value(value, audio_info->display_name[13],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
+		DESCRIPTION13);
+
+	set_reg_field_value(value, audio_info->display_name[14],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
+		DESCRIPTION14);
+
+	set_reg_field_value(value, audio_info->display_name[15],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
+		DESCRIPTION15);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
+		value);
+
+	value = 0;
+	set_reg_field_value(value, audio_info->display_name[16],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
+		DESCRIPTION16);
+
+	set_reg_field_value(value, audio_info->display_name[17],
+		AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
+		DESCRIPTION17);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
+		value);
+
+}
+
+/* setup Azalia HW block */
+static void setup_azalia(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id,
+	enum signal_type signal,
+	const struct audio_crtc_info *crtc_info,
+	const struct audio_pll_info *pll_info,
+	const struct audio_info *audio_info)
+{
+	uint32_t speakers = 0;
+	uint32_t channels = 0;
+
+	if (audio_info == NULL)
+		/* This should not happen.it does so we don't get BSOD*/
+		return;
+
+	speakers = audio_info->flags.info.ALLSPEAKERS;
+	channels = dal_audio_hw_ctx_speakers_to_channels(
+		hw_ctx,
+		audio_info->flags.speaker_flags).all;
+
+	/* setup the audio stream source select (audio -> dig mapping) */
+	{
+		const uint32_t addr =
+			mmAFMT_AUDIO_SRC_CONTROL + engine_offset[engine_id];
+
+		uint32_t value = 0;
+		/*convert one-based index to zero-based */
+		set_reg_field_value(value,
+			FROM_BASE(hw_ctx)->azalia_stream_id - 1,
+			AFMT_AUDIO_SRC_CONTROL,
+			AFMT_AUDIO_SRC_SELECT);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/* Channel allocation */
+	{
+		const uint32_t addr =
+			mmAFMT_AUDIO_PACKET_CONTROL2 + engine_offset[engine_id];
+		uint32_t value = dm_read_reg(hw_ctx->ctx, addr);
+
+		set_reg_field_value(value,
+			channels,
+			AFMT_AUDIO_PACKET_CONTROL2,
+			AFMT_AUDIO_CHANNEL_ENABLE);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	configure_azalia(hw_ctx, signal, crtc_info, audio_info);
+}
+
+/* unmute audio */
+static void unmute_azalia_audio(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id)
+{
+	const uint32_t addr = mmAFMT_AUDIO_PACKET_CONTROL +
+		engine_offset[engine_id];
+
+	uint32_t value = 0;
+
+	value = dm_read_reg(hw_ctx->ctx, addr);
+
+	set_reg_field_value(value, 1,
+		AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND);
+
+	dm_write_reg(hw_ctx->ctx, addr, value);
+}
+
+/* mute audio */
+static void mute_azalia_audio(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id)
+{
+	const uint32_t addr = mmAFMT_AUDIO_PACKET_CONTROL +
+		engine_offset[engine_id];
+
+	uint32_t value = 0;
+
+	value = dm_read_reg(hw_ctx->ctx, addr);
+
+	set_reg_field_value(value, 0,
+		AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND);
+
+	dm_write_reg(hw_ctx->ctx, addr, value);
+}
+
+/* enable channel splitting mapping */
+static void setup_channel_splitting_mapping(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id,
+	enum signal_type signal,
+	const struct audio_channel_associate_info *audio_mapping,
+	bool enable)
+{
+	uint32_t value = 0;
+
+	if ((audio_mapping == NULL || audio_mapping->u32all == 0) && enable)
+		return;
+
+	value = audio_mapping->u32all;
+
+	if (enable == false)
+		/*0xFFFFFFFF;*/
+		value = MULTI_CHANNEL_SPLIT_NO_ASSO_INFO;
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_ASSOCIATION_INFO,
+		value);
+}
+
+/* get current channel spliting */
+static bool get_channel_splitting_mapping(
+	const struct hw_ctx_audio *hw_ctx,
+	enum engine_id engine_id,
+	struct audio_channel_associate_info *audio_mapping)
+{
+	uint32_t value = 0;
+
+	if (audio_mapping == NULL)
+		return false;
+
+	value = read_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_ASSOCIATION_INFO);
+
+	/*0xFFFFFFFF*/
+	if (get_reg_field_value(value,
+			AZALIA_F0_CODEC_PIN_ASSOCIATION_INFO,
+			ASSOCIATION_INFO) !=
+			MULTI_CHANNEL_SPLIT_NO_ASSO_INFO) {
+		uint32_t multi_channel01_enable = 0;
+		uint32_t multi_channel23_enable = 0;
+		uint32_t multi_channel45_enable = 0;
+		uint32_t multi_channel67_enable = 0;
+		/* get the one we set.*/
+		audio_mapping->u32all = value;
+
+		/* check each enable status*/
+		value = read_indirect_azalia_reg(
+			hw_ctx,
+			ixAZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE);
+
+		multi_channel01_enable = get_reg_field_value(value,
+		AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
+		MULTICHANNEL01_ENABLE);
+
+		multi_channel23_enable = get_reg_field_value(value,
+		AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
+		MULTICHANNEL23_ENABLE);
+
+		multi_channel45_enable = get_reg_field_value(value,
+		AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
+		MULTICHANNEL45_ENABLE);
+
+		multi_channel67_enable = get_reg_field_value(value,
+		AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
+		MULTICHANNEL67_ENABLE);
+
+		if (multi_channel01_enable == 0 &&
+			multi_channel23_enable == 0 &&
+			multi_channel45_enable == 0 &&
+			multi_channel67_enable == 0)
+			dal_logger_write(hw_ctx->ctx->logger,
+				LOG_MAJOR_HW_TRACE,
+				LOG_MINOR_COMPONENT_AUDIO,
+				"Audio driver did not enable multi-channel\n");
+
+		return true;
+	}
+
+	return false;
+}
+
+/* set the payload value for the unsolicited response */
+static void set_unsolicited_response_payload(
+	const struct hw_ctx_audio *hw_ctx,
+	enum audio_payload payload)
+{
+	/* set the payload value for the unsolicited response
+	 Jack presence is not required to be enabled */
+	uint32_t value = 0;
+
+	value = read_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE);
+
+	set_reg_field_value(value, payload,
+		AZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE,
+		UNSOLICITED_RESPONSE_PAYLOAD);
+
+	set_reg_field_value(value, 1,
+		AZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE,
+		UNSOLICITED_RESPONSE_FORCE);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE,
+		value);
+}
+
+/* initialize HW state */
+static void hw_initialize(
+	const struct hw_ctx_audio *hw_ctx)
+{
+	uint32_t stream_id = FROM_BASE(hw_ctx)->azalia_stream_id;
+	uint32_t addr;
+
+	/* we only need to program the following registers once, so we only do
+	it for the first audio stream.*/
+	if (stream_id != FIRST_AUDIO_STREAM_ID)
+		return;
+
+	/* Suport R5 - 32khz
+	 * Suport R6 - 44.1khz
+	 * Suport R7 - 48khz
+	 */
+	addr = mmAZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES;
+	{
+		uint32_t value;
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+
+		set_reg_field_value(value, 0x70,
+		AZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES,
+		AUDIO_RATE_CAPABILITIES);
+
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+
+	/*Keep alive bit to verify HW block in BU. */
+	addr = mmAZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES;
+	{
+		uint32_t value;
+
+		value = dm_read_reg(hw_ctx->ctx, addr);
+
+		set_reg_field_value(value, 1,
+		AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES,
+		CLKSTOP);
+
+		set_reg_field_value(value, 1,
+		AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES,
+		EPSS);
+		dm_write_reg(hw_ctx->ctx, addr, value);
+	}
+}
+
+/* Assign GTC group and enable GTC value embedding */
+static void enable_gtc_embedding_with_group(
+	const struct hw_ctx_audio *hw_ctx,
+	uint32_t group_num,
+	uint32_t audio_latency)
+{
+	/*need to replace the static number with variable */
+	if (group_num <= 6) {
+		uint32_t value = read_indirect_azalia_reg(
+			hw_ctx,
+			ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING);
+
+		set_reg_field_value(
+			value,
+			group_num,
+			AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
+			PRESENTATION_TIME_EMBEDDING_GROUP);
+
+		set_reg_field_value(
+			value,
+			1,
+			AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
+			PRESENTATION_TIME_EMBEDDING_ENABLE);
+
+		write_indirect_azalia_reg(
+			hw_ctx,
+			ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
+			value);
+
+		/*update audio latency to LIPSYNC*/
+		set_audio_latency(hw_ctx, audio_latency);
+	} else {
+		dal_logger_write(
+			hw_ctx->ctx->logger,
+			LOG_MAJOR_HW_TRACE,
+			LOG_MINOR_COMPONENT_AUDIO,
+			"GTC group number %d is too big",
+			group_num);
+	}
+}
+
+ /* Disable GTC value embedding */
+static void disable_gtc_embedding(
+	const struct hw_ctx_audio *hw_ctx)
+{
+	uint32_t value = 0;
+
+	value = read_indirect_azalia_reg(
+	hw_ctx,
+	ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING);
+
+	set_reg_field_value(value, 0,
+	AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
+	PRESENTATION_TIME_EMBEDDING_ENABLE);
+
+	set_reg_field_value(value, 0,
+	AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
+	PRESENTATION_TIME_EMBEDDING_GROUP);
+
+	write_indirect_azalia_reg(
+		hw_ctx,
+		ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
+		value);
+}
+
+/* search pixel clock value for Azalia HDMI Audio */
+static bool get_azalia_clock_info_hdmi(
+	const struct hw_ctx_audio *hw_ctx,
+	uint32_t crtc_pixel_clock_in_khz,
+	uint32_t actual_pixel_clock_in_khz,
+	struct azalia_clock_info *azalia_clock_info)
+{
+	if (azalia_clock_info == NULL)
+		return false;
+
+	/* audio_dto_phase= 24 * 10,000;
+	 *   24MHz in [100Hz] units */
+	azalia_clock_info->audio_dto_phase =
+			24 * 10000;
+
+	/* audio_dto_module = PCLKFrequency * 10,000;
+	 *  [khz] -> [100Hz] */
+	azalia_clock_info->audio_dto_module =
+			actual_pixel_clock_in_khz * 10;
+
+	return true;
+}
+
+/* search pixel clock value for Azalia DP Audio */
+static bool get_azalia_clock_info_dp(
+	const struct hw_ctx_audio *hw_ctx,
+	uint32_t requested_pixel_clock_in_khz,
+	const struct audio_pll_info *pll_info,
+	struct azalia_clock_info *azalia_clock_info)
+{
+	if (pll_info == NULL || azalia_clock_info == NULL)
+		return false;
+
+	/* Reported dpDtoSourceClockInkhz value for
+	 * DCE8 already adjusted for SS, do not need any
+	 * adjustment here anymore
+	 */
+
+	/*audio_dto_phase = 24 * 10,000;
+	 * 24MHz in [100Hz] units */
+	azalia_clock_info->audio_dto_phase = 24 * 10000;
+
+	/*audio_dto_module = dpDtoSourceClockInkhz * 10,000;
+	 *  [khz] ->[100Hz] */
+	azalia_clock_info->audio_dto_module =
+		pll_info->dp_dto_source_clock_in_khz * 10;
+
+	return true;
+}
+
+static const struct hw_ctx_audio_funcs funcs = {
+	.destroy = destroy,
+	.setup_audio_wall_dto =
+		setup_audio_wall_dto,
+	.setup_hdmi_audio =
+		setup_hdmi_audio,
+	.setup_dp_audio = setup_dp_audio,
+	.setup_vce_audio = setup_vce_audio,
+	.enable_azalia_audio =
+		enable_azalia_audio,
+	.disable_azalia_audio =
+		disable_azalia_audio,
+	.enable_dp_audio =
+		enable_dp_audio,
+	.disable_dp_audio =
+		disable_dp_audio,
+	.setup_azalia =
+		setup_azalia,
+	.disable_az_clock_gating = NULL,
+	.unmute_azalia_audio =
+		unmute_azalia_audio,
+	.mute_azalia_audio =
+		mute_azalia_audio,
+	.setup_channel_splitting_mapping =
+		setup_channel_splitting_mapping,
+	.get_channel_splitting_mapping =
+		get_channel_splitting_mapping,
+	.set_unsolicited_response_payload =
+		set_unsolicited_response_payload,
+	.hw_initialize =
+		hw_initialize,
+	.enable_gtc_embedding_with_group =
+		enable_gtc_embedding_with_group,
+	.disable_gtc_embedding =
+		disable_gtc_embedding,
+	.get_azalia_clock_info_hdmi =
+		get_azalia_clock_info_hdmi,
+	.get_azalia_clock_info_dp =
+		get_azalia_clock_info_dp,
+	.enable_afmt_clock = enable_afmt_clock
+};
+
+static bool construct(
+	struct hw_ctx_audio_dce112 *hw_ctx,
+	uint8_t azalia_stream_id,
+	struct dc_context *ctx)
+{
+	struct hw_ctx_audio *base = &hw_ctx->base;
+
+	if (!dal_audio_construct_hw_ctx_audio(base))
+		return false;
+
+	base->funcs = &funcs;
+
+	/* save audio endpoint or dig front for current dce112 audio object */
+	hw_ctx->azalia_stream_id = azalia_stream_id;
+	hw_ctx->base.ctx = ctx;
+
+	/* azalia audio endpoints register offsets. azalia is associated with
+	DIG front. save AUDIO register offset */
+	switch (azalia_stream_id) {
+	case 1: {
+			hw_ctx->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_index =
+			mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX;
+			hw_ctx->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_data =
+			mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA;
+		}
+		break;
+	case 2: {
+			hw_ctx->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_index =
+			mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_INDEX;
+			hw_ctx->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_data =
+			mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_DATA;
+		}
+		break;
+	case 3: {
+			hw_ctx->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_index =
+			mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_INDEX;
+			hw_ctx->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_data =
+			mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_DATA;
+		}
+		break;
+	case 4: {
+			hw_ctx->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_index =
+			mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_INDEX;
+			hw_ctx->az_mm_reg_offsets.
+			azf0endpointx_azalia_f0_codec_endpoint_data =
+			mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_DATA;
+		}
+		break;
+	default:
+		dal_logger_write(
+			hw_ctx->base.ctx->logger,
+			LOG_MAJOR_WARNING,
+			LOG_MINOR_COMPONENT_AUDIO,
+			"Invalid Azalia stream ID!");
+		break;
+	}
+
+	return true;
+}
+
+/* audio_dce112 is derived from audio directly, not via dce80  */
+struct hw_ctx_audio *dal_hw_ctx_audio_dce112_create(
+	struct dc_context *ctx,
+	uint32_t azalia_stream_id)
+{
+	/* allocate memory for struc hw_ctx_audio_dce112 */
+	struct hw_ctx_audio_dce112 *hw_ctx_dce112 =
+			dm_alloc(sizeof(struct hw_ctx_audio_dce112));
+
+	if (!hw_ctx_dce112) {
+		ASSERT_CRITICAL(hw_ctx_dce112);
+		return NULL;
+	}
+
+	/*return pointer to hw_ctx_audio back to caller  -- audio object */
+	if (construct(
+			hw_ctx_dce112, azalia_stream_id, ctx))
+		return &hw_ctx_dce112->base;
+
+	dal_logger_write(
+		ctx->logger,
+		LOG_MAJOR_ERROR,
+		LOG_MINOR_COMPONENT_AUDIO,
+		"Failed to create hw_ctx_audio for DCE11\n");
+
+	dm_free(hw_ctx_dce112);
+
+	return NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.h b/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.h
new file mode 100644
index 0000000..af61aad
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.h
@@ -0,0 +1,47 @@
+/*
+ * 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 __DAL_HW_CTX_AUDIO_DCE112_H__
+#define __DAL_HW_CTX_AUDIO_DCE112_H__
+
+#include "audio/hw_ctx_audio.h"
+
+struct hw_ctx_audio_dce112 {
+	struct hw_ctx_audio base;
+
+	/* azalia stream id 1 based indexing, corresponding to audio GO enumId*/
+	uint32_t azalia_stream_id;
+
+	/* azalia stream endpoint register offsets */
+	struct azalia_reg_offsets az_mm_reg_offsets;
+
+	/* audio encoder block MM register offset -- associate with DIG FRONT */
+};
+
+struct hw_ctx_audio *dal_hw_ctx_audio_dce112_create(
+	struct dc_context *ctx,
+	uint32_t azalia_stream_id);
+
+#endif  /* __DAL_HW_CTX_AUDIO_DCE110_H__ */
diff --git a/drivers/gpu/drm/amd/dal/dc/bios/Makefile b/drivers/gpu/drm/amd/dal/dc/bios/Makefile
index e5c8876..9c90230 100644
--- a/drivers/gpu/drm/amd/dal/dc/bios/Makefile
+++ b/drivers/gpu/drm/amd/dal/dc/bios/Makefile
@@ -37,3 +37,12 @@ endif
 
 AMD_DAL_FILES += $(AMDDALPATH)/dc/bios/dce110/command_table_helper_dce110.o
 endif
+
+ifdef CONFIG_DRM_AMD_DAL_DCE11_2
+ccflags-y += -DLATEST_ATOM_BIOS_SUPPORT
+ifdef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT
+AMD_DAL_FILES += $(AMDDALPATH)/dc/bios/dce112/bios_parser_helper_dce112.o
+endif
+
+AMD_DAL_FILES += $(AMDDALPATH)/dc/bios/dce112/command_table_helper_dce112.o
+endif
diff --git a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c
index 4e2bc90..4204798 100644
--- a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c
+++ b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c
@@ -55,6 +55,12 @@ bool dal_bios_parser_init_bios_helper(
 		return true;
 
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	case DCE_VERSION_11_2:
+		bp->bios_helper = dal_bios_parser_helper_dce112_get_table();
+		return true;
+
+#endif
 	default:
 		BREAK_TO_DEBUGGER();
 		return false;
diff --git a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h
index c58b9bb..b93b046 100644
--- a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h
+++ b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h
@@ -34,6 +34,10 @@
 #include "dce110/bios_parser_helper_dce110.h"
 #endif
 
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+#include "dce112/bios_parser_helper_dce112.h"
+#endif
+
 struct bios_parser;
 
 struct vbios_helper_data {
diff --git a/drivers/gpu/drm/amd/dal/dc/bios/command_table.c b/drivers/gpu/drm/amd/dal/dc/bios/command_table.c
index ccd1c7e..22524b3 100644
--- a/drivers/gpu/drm/amd/dal/dc/bios/command_table.c
+++ b/drivers/gpu/drm/amd/dal/dc/bios/command_table.c
@@ -104,6 +104,13 @@ static enum bp_result encoder_control_digx_v3(
 static enum bp_result encoder_control_digx_v4(
 	struct bios_parser *bp,
 	struct bp_encoder_control *cntl);
+
+#ifdef LATEST_ATOM_BIOS_SUPPORT
+static enum bp_result encoder_control_digx_v5(
+	struct bios_parser *bp,
+	struct bp_encoder_control *cntl);
+#endif
+
 static void init_encoder_control_dig_v1(struct bios_parser *bp);
 
 static void init_dig_encoder_control(struct bios_parser *bp)
@@ -112,12 +119,19 @@ static void init_dig_encoder_control(struct bios_parser *bp)
 		BIOS_CMD_TABLE_PARA_REVISION(DIGxEncoderControl);
 
 	switch (version) {
+	case 2:
+		bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v3;
+		break;
 	case 4:
 		bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v4;
 		break;
-	case 2:
-		bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v3;
+
+#ifdef LATEST_ATOM_BIOS_SUPPORT
+	case 5:
+		bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v5;
 		break;
+#endif
+
 	default:
 		init_encoder_control_dig_v1(bp);
 		break;
@@ -302,6 +316,66 @@ static enum bp_result encoder_control_digx_v4(
 	return result;
 }
 
+#ifdef LATEST_ATOM_BIOS_SUPPORT
+static enum bp_result encoder_control_digx_v5(
+	struct bios_parser *bp,
+	struct bp_encoder_control *cntl)
+{
+	enum bp_result result = BP_RESULT_FAILURE;
+	ENCODER_STREAM_SETUP_PARAMETERS_V5 params = {0};
+
+	params.ucDigId = (uint8_t)(cntl->engine_id);
+	params.ucAction = bp->cmd_helper->encoder_action_to_atom(cntl->action);
+
+	params.ulPixelClock = cntl->pixel_clock / 10;
+	params.ucDigMode =
+			(uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom(
+					cntl->signal,
+					cntl->enable_dp_audio));
+	params.ucLaneNum = (uint8_t)(cntl->lanes_number);
+
+	switch (cntl->color_depth) {
+	case COLOR_DEPTH_888:
+		params.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+		break;
+	case COLOR_DEPTH_101010:
+		params.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+		break;
+	case COLOR_DEPTH_121212:
+		params.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+		break;
+	case COLOR_DEPTH_161616:
+		params.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+		break;
+	default:
+		break;
+	}
+
+	if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A)
+		switch (cntl->color_depth) {
+		case COLOR_DEPTH_101010:
+			params.ulPixelClock =
+				(params.ulPixelClock * 30) / 24;
+			break;
+		case COLOR_DEPTH_121212:
+			params.ulPixelClock =
+				(params.ulPixelClock * 36) / 24;
+			break;
+		case COLOR_DEPTH_161616:
+			params.ulPixelClock =
+				(params.ulPixelClock * 48) / 24;
+			break;
+		default:
+			break;
+		}
+
+	if (EXEC_BIOS_CMD_TABLE(DIGxEncoderControl, params))
+		result = BP_RESULT_OK;
+
+	return result;
+}
+#endif
+
 /*******************************************************************************
  ********************************************************************************
  **
diff --git a/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c
index 85a5924..a27db8c 100644
--- a/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c
+++ b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c
@@ -55,6 +55,12 @@ bool dal_bios_parser_init_cmd_tbl_helper(
 		return true;
 #endif
 
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	case DCE_VERSION_11_2:
+		*h = dal_cmd_tbl_helper_dce112_get_table();
+		return true;
+#endif
+
 	default:
 		/* Unsupported DCE */
 		BREAK_TO_DEBUGGER();
diff --git a/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h
index a462917..e6a0d19 100644
--- a/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h
+++ b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h
@@ -32,6 +32,9 @@
 #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) || defined(CONFIG_DRM_AMD_DAL_DCE10_0)
 #include "dce110/command_table_helper_dce110.h"
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+#include "dce112/command_table_helper_dce112.h"
+#endif
 
 struct command_table_helper {
 	bool (*controller_id_to_atom)(enum controller_id id, uint8_t *atom_id);
diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.c b/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.c
new file mode 100644
index 0000000..1b0f816
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.c
@@ -0,0 +1,480 @@
+/*
+ * 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, sub license,
+ * 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 "atom.h"
+
+#include "include/bios_parser_types.h"
+#include "include/adapter_service_types.h"
+#include "include/logger_interface.h"
+
+#include "../bios_parser_helper.h"
+
+#include "dce/dce_11_0_d.h"
+#include "bif/bif_5_1_d.h"
+
+/**
+ * set_scratch_acc_mode_change
+ *
+ * @brief
+ *  set Accelerated Mode in VBIOS scratch register, VBIOS will clean it when
+ *  VGA/non-Accelerated mode is set
+ *
+ * @param
+ *  struct dc_context *ctx - [in] DAL context
+ */
+static void set_scratch_acc_mode_change(
+	struct dc_context *ctx)
+{
+	uint32_t addr = mmBIOS_SCRATCH_6;
+	uint32_t value = 0;
+
+	value = dm_read_reg(ctx, addr);
+
+	value |= ATOM_S6_ACC_MODE;
+
+	dm_write_reg(ctx, addr, value);
+}
+
+/*
+ * set_scratch_active_and_requested
+ *
+ * @brief
+ * Set VBIOS scratch pad registers about active and requested displays
+ *
+ * @param
+ * struct dc_context *ctx - [in] DAL context for register accessing
+ * struct vbios_helper_data *d - [in] values to write
+ */
+static void set_scratch_active_and_requested(
+	struct dc_context *ctx,
+	struct vbios_helper_data *d)
+{
+	uint32_t addr = 0;
+	uint32_t value = 0;
+
+	/* mmBIOS_SCRATCH_3 = mmBIOS_SCRATCH_0 + ATOM_ACTIVE_INFO_DEF */
+	addr = mmBIOS_SCRATCH_3;
+
+	value = dm_read_reg(ctx, addr);
+
+	value &= ~ATOM_S3_DEVICE_ACTIVE_MASK;
+	value |= (d->active & ATOM_S3_DEVICE_ACTIVE_MASK);
+
+	dm_write_reg(ctx, addr, value);
+
+	/* mmBIOS_SCRATCH_6 =  mmBIOS_SCRATCH_0 + ATOM_ACC_CHANGE_INFO_DEF */
+	addr = mmBIOS_SCRATCH_6;
+
+	value = dm_read_reg(ctx, addr);
+
+	value &= ~ATOM_S6_ACC_REQ_MASK;
+	value |= (d->requested & ATOM_S6_ACC_REQ_MASK);
+
+	dm_write_reg(ctx, addr, value);
+
+	/* mmBIOS_SCRATCH_5 =  mmBIOS_SCRATCH_0 + ATOM_DOS_REQ_INFO_DEF */
+	addr = mmBIOS_SCRATCH_5;
+
+	value = dm_read_reg(ctx, addr);
+
+	value &= ~ATOM_S5_DOS_REQ_DEVICEw0;
+	value |= (d->active & ATOM_S5_DOS_REQ_DEVICEw0);
+
+	dm_write_reg(ctx, addr, value);
+
+	d->active = 0;
+	d->requested = 0;
+}
+
+/**
+ * get LCD Scale Mode from VBIOS scratch register
+ */
+static enum lcd_scale get_scratch_lcd_scale(
+	struct dc_context *ctx)
+{
+	uint32_t addr = mmBIOS_SCRATCH_6;
+	uint32_t value = 0;
+
+	value = dm_read_reg(ctx, addr);
+
+	if (value & ATOM_S6_REQ_LCD_EXPANSION_FULL)
+		return LCD_SCALE_FULLPANEL;
+	else if (value & ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO)
+		return LCD_SCALE_ASPECTRATIO;
+	else
+		return LCD_SCALE_NONE;
+}
+
+/**
+ * prepare_scratch_active_and_requested
+ *
+ * @brief
+ *  prepare and update VBIOS scratch pad registers about active and requested
+ *  displays
+ *
+ * @param
+ * data - helper's shared data
+ * enum controller_ild - controller Id
+ * enum signal_type - signal type used on display
+ * const struct connector_device_tag_info* - pointer to display type and enum id
+ */
+static void prepare_scratch_active_and_requested(
+	struct dc_context *ctx,
+	struct vbios_helper_data *data,
+	enum controller_id id,
+	enum signal_type s,
+	const struct connector_device_tag_info *dev_tag)
+{
+	switch (s) {
+	case SIGNAL_TYPE_DVI_SINGLE_LINK:
+	case SIGNAL_TYPE_DVI_DUAL_LINK:
+	case SIGNAL_TYPE_HDMI_TYPE_A:
+	case SIGNAL_TYPE_DISPLAY_PORT:
+	case SIGNAL_TYPE_DISPLAY_PORT_MST:
+		if (dev_tag->dev_id.device_type == DEVICE_TYPE_DFP)
+			switch (dev_tag->dev_id.enum_id) {
+			case 1:
+				data->requested |= ATOM_S6_ACC_REQ_DFP1;
+				data->active |= ATOM_S3_DFP1_ACTIVE;
+				break;
+			case 2:
+				data->requested |= ATOM_S6_ACC_REQ_DFP2;
+				data->active |= ATOM_S3_DFP2_ACTIVE;
+				break;
+			case 3:
+				data->requested |= ATOM_S6_ACC_REQ_DFP3;
+				data->active |= ATOM_S3_DFP3_ACTIVE;
+				break;
+			case 4:
+				data->requested |= ATOM_S6_ACC_REQ_DFP4;
+				data->active |= ATOM_S3_DFP4_ACTIVE;
+				break;
+			case 5:
+				data->requested |= ATOM_S6_ACC_REQ_DFP5;
+				data->active |= ATOM_S3_DFP5_ACTIVE;
+				break;
+			case 6:
+				data->requested |= ATOM_S6_ACC_REQ_DFP6;
+				data->active |= ATOM_S3_DFP6_ACTIVE;
+				break;
+			default:
+				break;
+			}
+		break;
+	case SIGNAL_TYPE_LVDS:
+	case SIGNAL_TYPE_EDP:
+		data->requested |= ATOM_S6_ACC_REQ_LCD1;
+		data->active |= ATOM_S3_LCD1_ACTIVE;
+		break;
+	case SIGNAL_TYPE_RGB:
+		if (dev_tag->dev_id.device_type == DEVICE_TYPE_CRT)
+			switch (dev_tag->dev_id.enum_id) {
+			case 1:
+				data->requested |= ATOM_S6_ACC_REQ_CRT1;
+				data->active |= ATOM_S3_CRT1_ACTIVE;
+				break;
+			case 2:
+				dal_logger_write(ctx->logger,
+					LOG_MAJOR_BIOS,
+					LOG_MINOR_COMPONENT_BIOS,
+					"%s: DAL does not support DAC2!\n",
+					__func__);
+				break;
+			default:
+				break;
+			}
+		break;
+	default:
+		dal_logger_write(ctx->logger,
+				LOG_MAJOR_BIOS,
+				LOG_MINOR_COMPONENT_BIOS,
+				"%s: No such signal!\n",
+				__func__);
+		break;
+	}
+}
+
+/*
+ * is_accelerated_mode
+ *
+ * @brief
+ *  set Accelerated Mode in VBIOS scratch register, VBIOS will clean it when
+ *  VGA/non-Accelerated mode is set
+ *
+ * @param
+ * struct dc_context *ctx
+ *
+ * @return
+ * true if in acceleration mode, false otherwise.
+ */
+static bool is_accelerated_mode(
+	struct dc_context *ctx)
+{
+	uint32_t addr = mmBIOS_SCRATCH_6;
+	uint32_t value = dm_read_reg(ctx, addr);
+
+	return (value & ATOM_S6_ACC_MODE) ? true : false;
+}
+
+#define BIOS_SCRATCH0_DAC_B_SHIFT 8
+
+/**
+ * detect_sink
+ *
+ * @brief
+ *  read VBIOS scratch register to determine whether display for the specified
+ *  signal is present and return the actual sink signal type
+ *  For analog signals VBIOS load detection has to be called prior reading the
+ *  register
+ *
+ * @param
+ *  encoder - encoder id (to specify DAC)
+ *  connector - connector id (to check CV on DIN)
+ *  signal - signal (as display type) to check
+ *
+ * @return
+ *  signal_type - actual (on the sink) signal type detected
+ */
+static enum signal_type detect_sink(
+	struct dc_context *ctx,
+	struct graphics_object_id encoder,
+	struct graphics_object_id connector,
+	enum signal_type signal)
+{
+	uint32_t bios_scratch0;
+	uint32_t encoder_id = encoder.id;
+	/* after DCE 10.x does not support DAC2, so assert and return SIGNAL_TYPE_NONE */
+	if (encoder_id == ENCODER_ID_INTERNAL_DAC2
+		|| encoder_id == ENCODER_ID_INTERNAL_KLDSCP_DAC2) {
+		ASSERT(false);
+		return SIGNAL_TYPE_NONE;
+	}
+
+	bios_scratch0 = dm_read_reg(ctx,
+		mmBIOS_SCRATCH_0 + ATOM_DEVICE_CONNECT_INFO_DEF);
+
+	/* In further processing we use DACB masks. If we want detect load on
+	 * DACA, we need to shift the register so DACA bits will be in place of
+	 * DACB bits
+	 */
+	if (encoder_id == ENCODER_ID_INTERNAL_DAC1
+		|| encoder_id == ENCODER_ID_INTERNAL_KLDSCP_DAC1
+		|| encoder_id == ENCODER_ID_EXTERNAL_NUTMEG
+		|| encoder_id == ENCODER_ID_EXTERNAL_TRAVIS) {
+		bios_scratch0 <<= BIOS_SCRATCH0_DAC_B_SHIFT;
+	}
+
+	switch (signal) {
+	case SIGNAL_TYPE_RGB: {
+		if (bios_scratch0 & ATOM_S0_CRT2_MASK)
+			return SIGNAL_TYPE_RGB;
+		break;
+	}
+	case SIGNAL_TYPE_LVDS: {
+		if (bios_scratch0 & ATOM_S0_LCD1)
+			return SIGNAL_TYPE_LVDS;
+		break;
+	}
+	case SIGNAL_TYPE_EDP: {
+		if (bios_scratch0 & ATOM_S0_LCD1)
+			return SIGNAL_TYPE_EDP;
+		break;
+	}
+	default:
+		break;
+	}
+
+	return SIGNAL_TYPE_NONE;
+}
+
+/**
+ * set_scratch_connected
+ *
+ * @brief
+ *    update BIOS_SCRATCH_0 register about connected displays
+ *
+ * @param
+ * bool - update scratch register or just prepare info to be updated
+ * bool - connection state
+ * const struct connector_device_tag_info * - pointer to device type and enum ID
+ */
+static void set_scratch_connected(
+	struct dc_context *ctx,
+	struct graphics_object_id id,
+	bool connected,
+	const struct connector_device_tag_info *device_tag)
+{
+	uint32_t addr = 0;
+	uint32_t value = 0;
+	uint32_t update = 0;
+
+	switch (device_tag->dev_id.device_type) {
+	case DEVICE_TYPE_LCD:
+		/* For LCD VBIOS will update LCD Panel connected bit always and
+		 * Lid state bit based on SBIOS info do not do anything here
+		 * for LCD
+		 */
+		break;
+	case DEVICE_TYPE_CRT:
+		/* CRT is not supported in DCE11 */
+		break;
+	case DEVICE_TYPE_DFP:
+		switch (device_tag->dev_id.enum_id) {
+		case 1:
+			update |= ATOM_S0_DFP1;
+			break;
+		case 2:
+			update |= ATOM_S0_DFP2;
+			break;
+		case 3:
+			update |= ATOM_S0_DFP3;
+			break;
+		case 4:
+			update |= ATOM_S0_DFP4;
+			break;
+		case 5:
+			update |= ATOM_S0_DFP5;
+			break;
+		case 6:
+			update |= ATOM_S0_DFP6;
+			break;
+		default:
+			break;
+		}
+		break;
+	case DEVICE_TYPE_CV:
+		/* DCE 8.0 does not support CV, so don't do anything */
+		break;
+
+	case DEVICE_TYPE_TV:
+		/* For TV VBIOS will update S-Video or
+		 * Composite scratch bits on DAL_LoadDetect
+		 * when called by driver, do not do anything
+		 * here for TV
+		 */
+		break;
+
+	default:
+		break;
+
+	}
+
+	/* update scratch register */
+	addr = mmBIOS_SCRATCH_0 + ATOM_DEVICE_CONNECT_INFO_DEF;
+
+	value = dm_read_reg(ctx, addr);
+
+	if (connected)
+		value |= update;
+	else
+		value &= ~update;
+
+	dm_write_reg(ctx, addr, value);
+}
+
+static void set_scratch_critical_state(
+	struct dc_context *ctx,
+	bool state)
+{
+	uint32_t addr = mmBIOS_SCRATCH_6;
+	uint32_t value = dm_read_reg(ctx, addr);
+
+	if (state)
+		value |= ATOM_S6_CRITICAL_STATE;
+	else
+		value &= ~ATOM_S6_CRITICAL_STATE;
+
+	dm_write_reg(ctx, addr, value);
+}
+
+static void set_scratch_lcd_scale(
+	struct dc_context *ctx,
+	enum lcd_scale lcd_scale_request)
+{
+	DAL_LOGGER_NOT_IMPL(
+		LOG_MINOR_COMPONENT_BIOS,
+		"Bios Parser:%s\n",
+		__func__);
+}
+
+static bool is_lid_open(struct dc_context *ctx)
+{
+	uint32_t bios_scratch6;
+
+	bios_scratch6 =
+		dm_read_reg(
+			ctx,
+			mmBIOS_SCRATCH_0 + ATOM_ACC_CHANGE_INFO_DEF);
+
+	/* lid is open if the bit is not set */
+	if (!(bios_scratch6 & ATOM_S6_LID_STATE))
+		return true;
+
+	return false;
+}
+
+/* function table */
+static const struct bios_parser_helper bios_parser_helper_funcs = {
+	.detect_sink = detect_sink,
+	.fmt_bit_depth_control = NULL,
+	.fmt_control = NULL,
+	.get_bios_event_info = NULL,
+	.get_embedded_display_controller_id = NULL,
+	.get_embedded_display_refresh_rate = NULL,
+	.get_requested_backlight_level = NULL,
+	.get_scratch_lcd_scale = get_scratch_lcd_scale,
+	.is_accelerated_mode = is_accelerated_mode,
+	.is_active_display = NULL,
+	.is_display_config_changed = NULL,
+	.is_lid_open = is_lid_open,
+	.is_lid_status_changed = NULL,
+	.prepare_scratch_active_and_requested =
+			prepare_scratch_active_and_requested,
+	.set_scratch_acc_mode_change = set_scratch_acc_mode_change,
+	.set_scratch_active_and_requested = set_scratch_active_and_requested,
+	.set_scratch_connected = set_scratch_connected,
+	.set_scratch_critical_state = set_scratch_critical_state,
+	.set_scratch_lcd_scale = set_scratch_lcd_scale,
+	.take_backlight_control = NULL,
+	.update_requested_backlight_level = NULL,
+};
+
+/*
+ * dal_bios_parser_dce112_init_bios_helper
+ *
+ * @brief
+ * Initialize BIOS helper functions
+ *
+ * @param
+ * const struct command_table_helper **h - [out] struct of functions
+ *
+ */
+
+const struct bios_parser_helper *dal_bios_parser_helper_dce112_get_table()
+{
+	return &bios_parser_helper_funcs;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.h b/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.h
new file mode 100644
index 0000000..044327e
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.h
@@ -0,0 +1,34 @@
+/*
+ * 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, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_BIOS_PARSER_HELPER_DCE112_H__
+#define __DAL_BIOS_PARSER_HELPER_DCE112_H__
+
+struct bios_parser_helper;
+
+/* Initialize BIOS helper functions */
+const struct bios_parser_helper *dal_bios_parser_helper_dce112_get_table(void);
+
+#endif /* __DAL_BIOS_PARSER_HELPER_DCE110_H__ */
diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.c b/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.c
new file mode 100644
index 0000000..32ec228
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.c
@@ -0,0 +1,417 @@
+/*
+ * 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 "atom.h"
+
+#include "include/bios_parser_types.h"
+#include "include/adapter_service_types.h"
+
+#include "../command_table_helper.h"
+
+static uint8_t phy_id_to_atom(enum transmitter t)
+{
+	uint8_t atom_phy_id;
+
+	switch (t) {
+	case TRANSMITTER_UNIPHY_A:
+		atom_phy_id = ATOM_PHY_ID_UNIPHYA;
+		break;
+	case TRANSMITTER_UNIPHY_B:
+		atom_phy_id = ATOM_PHY_ID_UNIPHYB;
+		break;
+	case TRANSMITTER_UNIPHY_C:
+		atom_phy_id = ATOM_PHY_ID_UNIPHYC;
+		break;
+	case TRANSMITTER_UNIPHY_D:
+		atom_phy_id = ATOM_PHY_ID_UNIPHYD;
+		break;
+	case TRANSMITTER_UNIPHY_E:
+		atom_phy_id = ATOM_PHY_ID_UNIPHYE;
+		break;
+	case TRANSMITTER_UNIPHY_F:
+		atom_phy_id = ATOM_PHY_ID_UNIPHYF;
+		break;
+	case TRANSMITTER_UNIPHY_G:
+		atom_phy_id = ATOM_PHY_ID_UNIPHYG;
+		break;
+	default:
+		atom_phy_id = ATOM_PHY_ID_UNIPHYA;
+		break;
+	}
+	return atom_phy_id;
+}
+
+static uint8_t signal_type_to_atom_dig_mode(enum signal_type s)
+{
+	uint8_t atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP;
+
+	switch (s) {
+	case SIGNAL_TYPE_DISPLAY_PORT:
+	case SIGNAL_TYPE_EDP:
+		atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP;
+		break;
+	case SIGNAL_TYPE_DVI_SINGLE_LINK:
+	case SIGNAL_TYPE_DVI_DUAL_LINK:
+		atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DVI;
+		break;
+	case SIGNAL_TYPE_HDMI_TYPE_A:
+		atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_HDMI;
+		break;
+	case SIGNAL_TYPE_DISPLAY_PORT_MST:
+		atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP_MST;
+		break;
+	default:
+		atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DVI;
+		break;
+	}
+
+	return atom_dig_mode;
+}
+
+static uint8_t clock_source_id_to_atom_phy_clk_src_id(
+		enum clock_source_id id)
+{
+	uint8_t atom_phy_clk_src_id = 0;
+
+	switch (id) {
+	case CLOCK_SOURCE_ID_PLL0:
+		atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P0PLL;
+		break;
+	case CLOCK_SOURCE_ID_PLL1:
+		atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P1PLL;
+		break;
+	case CLOCK_SOURCE_ID_PLL2:
+		atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P2PLL;
+		break;
+	case CLOCK_SOURCE_ID_EXTERNAL:
+		atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_REFCLK_SRC_EXT;
+		break;
+	default:
+		atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P1PLL;
+		break;
+	}
+
+	return atom_phy_clk_src_id >> 2;
+}
+
+static uint8_t hpd_sel_to_atom(enum hpd_source_id id)
+{
+	uint8_t atom_hpd_sel = 0;
+
+	switch (id) {
+	case HPD_SOURCEID1:
+		atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD1_SEL;
+		break;
+	case HPD_SOURCEID2:
+		atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD2_SEL;
+		break;
+	case HPD_SOURCEID3:
+		atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD3_SEL;
+		break;
+	case HPD_SOURCEID4:
+		atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD4_SEL;
+		break;
+	case HPD_SOURCEID5:
+		atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD5_SEL;
+		break;
+	case HPD_SOURCEID6:
+		atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD6_SEL;
+		break;
+	case HPD_SOURCEID_UNKNOWN:
+	default:
+		atom_hpd_sel = 0;
+		break;
+	}
+	return atom_hpd_sel;
+}
+
+static uint8_t dig_encoder_sel_to_atom(enum engine_id id)
+{
+	uint8_t atom_dig_encoder_sel = 0;
+
+	switch (id) {
+	case ENGINE_ID_DIGA:
+		atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGA_SEL;
+		break;
+	case ENGINE_ID_DIGB:
+		atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGB_SEL;
+		break;
+	case ENGINE_ID_DIGC:
+		atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGC_SEL;
+		break;
+	case ENGINE_ID_DIGD:
+		atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGD_SEL;
+		break;
+	case ENGINE_ID_DIGE:
+		atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGE_SEL;
+		break;
+	case ENGINE_ID_DIGF:
+		atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGF_SEL;
+		break;
+	case ENGINE_ID_DIGG:
+		atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGG_SEL;
+		break;
+	case ENGINE_ID_UNKNOWN:
+		/* No DIG_FRONT is associated to DIG_BACKEND */
+		atom_dig_encoder_sel = 0;
+		break;
+	default:
+		atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGA_SEL;
+		break;
+	}
+
+	return atom_dig_encoder_sel;
+}
+
+static bool clock_source_id_to_atom(
+	enum clock_source_id id,
+	uint32_t *atom_pll_id)
+{
+	bool result = true;
+
+	if (atom_pll_id != NULL)
+		switch (id) {
+		case CLOCK_SOURCE_COMBO_PHY_PLL0:
+			*atom_pll_id = ATOM_COMBOPHY_PLL0;
+			break;
+		case CLOCK_SOURCE_COMBO_PHY_PLL1:
+			*atom_pll_id = ATOM_COMBOPHY_PLL1;
+			break;
+		case CLOCK_SOURCE_COMBO_PHY_PLL2:
+			*atom_pll_id = ATOM_COMBOPHY_PLL2;
+			break;
+		case CLOCK_SOURCE_COMBO_PHY_PLL3:
+			*atom_pll_id = ATOM_COMBOPHY_PLL3;
+			break;
+		case CLOCK_SOURCE_COMBO_PHY_PLL4:
+			*atom_pll_id = ATOM_COMBOPHY_PLL4;
+			break;
+		case CLOCK_SOURCE_COMBO_PHY_PLL5:
+			*atom_pll_id = ATOM_COMBOPHY_PLL5;
+			break;
+		case CLOCK_SOURCE_COMBO_DISPLAY_PLL0:
+			*atom_pll_id = ATOM_PPLL0;
+			break;
+		case CLOCK_SOURCE_ID_DFS:
+			*atom_pll_id = ATOM_GCK_DFS;
+			break;
+		case CLOCK_SOURCE_ID_VCE:
+			*atom_pll_id = ATOM_DP_DTO;
+			break;
+		case CLOCK_SOURCE_ID_DP_DTO:
+			*atom_pll_id = ATOM_DP_DTO;
+			break;
+		case CLOCK_SOURCE_ID_UNDEFINED:
+			/* Should not happen */
+			*atom_pll_id = ATOM_PPLL_INVALID;
+			result = false;
+			break;
+		default:
+			result = false;
+			break;
+		}
+
+	return result;
+}
+
+static bool engine_bp_to_atom(enum engine_id id, uint32_t *atom_engine_id)
+{
+	bool result = false;
+
+	if (atom_engine_id != NULL)
+		switch (id) {
+		case ENGINE_ID_DIGA:
+			*atom_engine_id = ASIC_INT_DIG1_ENCODER_ID;
+			result = true;
+			break;
+		case ENGINE_ID_DIGB:
+			*atom_engine_id = ASIC_INT_DIG2_ENCODER_ID;
+			result = true;
+			break;
+		case ENGINE_ID_DIGC:
+			*atom_engine_id = ASIC_INT_DIG3_ENCODER_ID;
+			result = true;
+			break;
+		case ENGINE_ID_DIGD:
+			*atom_engine_id = ASIC_INT_DIG4_ENCODER_ID;
+			result = true;
+			break;
+		case ENGINE_ID_DIGE:
+			*atom_engine_id = ASIC_INT_DIG5_ENCODER_ID;
+			result = true;
+			break;
+		case ENGINE_ID_DIGF:
+			*atom_engine_id = ASIC_INT_DIG6_ENCODER_ID;
+			result = true;
+			break;
+		case ENGINE_ID_DIGG:
+			*atom_engine_id = ASIC_INT_DIG7_ENCODER_ID;
+			result = true;
+			break;
+		case ENGINE_ID_DACA:
+			*atom_engine_id = ASIC_INT_DAC1_ENCODER_ID;
+			result = true;
+			break;
+		default:
+			break;
+		}
+
+	return result;
+}
+
+static uint8_t encoder_action_to_atom(enum bp_encoder_control_action action)
+{
+	uint8_t atom_action = 0;
+
+	switch (action) {
+	case ENCODER_CONTROL_ENABLE:
+		atom_action = ATOM_ENABLE;
+		break;
+	case ENCODER_CONTROL_DISABLE:
+		atom_action = ATOM_DISABLE;
+		break;
+	case ENCODER_CONTROL_SETUP:
+		atom_action = ATOM_ENCODER_CMD_STREAM_SETUP;
+		break;
+	case ENCODER_CONTROL_INIT:
+		atom_action = ATOM_ENCODER_INIT;
+		break;
+	default:
+		BREAK_TO_DEBUGGER(); /* Unhandle action in driver.!! */
+		break;
+	}
+
+	return atom_action;
+}
+
+static uint8_t disp_power_gating_action_to_atom(
+	enum bp_pipe_control_action action)
+{
+	uint8_t atom_pipe_action = 0;
+
+	switch (action) {
+	case ASIC_PIPE_DISABLE:
+		atom_pipe_action = ATOM_DISABLE;
+		break;
+	case ASIC_PIPE_ENABLE:
+		atom_pipe_action = ATOM_ENABLE;
+		break;
+	case ASIC_PIPE_INIT:
+		atom_pipe_action = ATOM_INIT;
+		break;
+	default:
+		ASSERT_CRITICAL(false); /* Unhandle action in driver! */
+		break;
+	}
+
+	return atom_pipe_action;
+}
+
+bool dc_clock_type_to_atom(enum bp_dce_clock_type id, uint32_t *atom_clock_type)
+{
+	bool retCode = true;
+
+	if (atom_clock_type != NULL) {
+		switch (id) {
+		case DCECLOCK_TYPE_DISPLAY_CLOCK:
+			*atom_clock_type = DCE_CLOCK_TYPE_DISPCLK;
+			break;
+
+		case DCECLOCK_TYPE_DPREFCLK:
+			*atom_clock_type = DCE_CLOCK_TYPE_DPREFCLK;
+			break;
+
+		default:
+			ASSERT_CRITICAL(false); /* Unhandle action in driver! */
+			break;
+		}
+	}
+
+	return retCode;
+}
+
+uint8_t transmitter_color_depth_to_atom(enum transmitter_color_depth id)
+{
+	uint8_t atomColorDepth = 0;
+
+	switch (id) {
+	case TRANSMITTER_COLOR_DEPTH_24:
+		atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_DIS;
+		break;
+	case TRANSMITTER_COLOR_DEPTH_30:
+		atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_5_4;
+		break;
+	case TRANSMITTER_COLOR_DEPTH_36:
+		atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_3_2;
+		break;
+	case TRANSMITTER_COLOR_DEPTH_48:
+		atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_2_1;
+		break;
+	default:
+		ASSERT_CRITICAL(false); /* Unhandle action in driver! */
+		break;
+	}
+
+	return atomColorDepth;
+}
+
+/* function table */
+static const struct command_table_helper command_table_helper_funcs = {
+	.controller_id_to_atom = dal_cmd_table_helper_controller_id_to_atom,
+	.encoder_action_to_atom = encoder_action_to_atom,
+	.engine_bp_to_atom = engine_bp_to_atom,
+	.clock_source_id_to_atom = clock_source_id_to_atom,
+	.clock_source_id_to_atom_phy_clk_src_id =
+			clock_source_id_to_atom_phy_clk_src_id,
+	.signal_type_to_atom_dig_mode = signal_type_to_atom_dig_mode,
+	.hpd_sel_to_atom = hpd_sel_to_atom,
+	.dig_encoder_sel_to_atom = dig_encoder_sel_to_atom,
+	.phy_id_to_atom = phy_id_to_atom,
+	.disp_power_gating_action_to_atom = disp_power_gating_action_to_atom,
+	.assign_control_parameter = NULL,
+	.clock_source_id_to_ref_clk_src = NULL,
+	.transmitter_bp_to_atom = NULL,
+	.encoder_id_to_atom = dal_cmd_table_helper_encoder_id_to_atom,
+	.encoder_mode_bp_to_atom = dal_cmd_table_helper_encoder_mode_bp_to_atom,
+	.dc_clock_type_to_atom = dc_clock_type_to_atom,
+	.transmitter_color_depth_to_atom = transmitter_color_depth_to_atom,
+};
+
+/*
+ * dal_cmd_tbl_helper_dce110_get_table
+ *
+ * @brief
+ * Initialize command table helper functions
+ *
+ * @param
+ * const struct command_table_helper **h - [out] struct of functions
+ *
+ */
+const struct command_table_helper *dal_cmd_tbl_helper_dce112_get_table()
+{
+	return &command_table_helper_funcs;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.h b/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.h
new file mode 100644
index 0000000..dc36609
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.h
@@ -0,0 +1,34 @@
+/*
+ * 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 __DAL_COMMAND_TABLE_HELPER_DCE112_H__
+#define __DAL_COMMAND_TABLE_HELPER_DCE112_H__
+
+struct command_table_helper;
+
+/* Initialize command table helper functions */
+const struct command_table_helper *dal_cmd_tbl_helper_dce112_get_table(void);
+
+#endif /* __DAL_COMMAND_TABLE_HELPER_DCE110_H__ */
diff --git a/drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c b/drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c
index f39499a..8a19139 100644
--- a/drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c
+++ b/drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c
@@ -3726,6 +3726,212 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip,
 		dceip.scatter_gather_pte_request_rows_in_tiling_mode = 2;
 		dceip.mcifwr_all_surfaces_burst_time = bw_int_to_fixed(0); /* todo: this is a bug*/
 		break;
+	case BW_CALCS_VERSION_ELLESMERE:
+		vbios.number_of_dram_channels = 8;
+		vbios.dram_channel_width_in_bits = 32;
+		vbios.number_of_dram_banks = 8;
+		vbios.high_yclk = bw_int_to_fixed(6000);
+		vbios.mid_yclk = bw_int_to_fixed(3200);
+		vbios.low_yclk = bw_int_to_fixed(1000);
+		vbios.low_sclk = bw_int_to_fixed(300);
+		vbios.mid_sclk = bw_int_to_fixed(974);
+		vbios.high_sclk = bw_int_to_fixed(1154);
+		vbios.low_voltage_max_dispclk = bw_int_to_fixed(459);
+		vbios.mid_voltage_max_dispclk = bw_int_to_fixed(654);
+		vbios.high_voltage_max_dispclk = bw_int_to_fixed(1132);
+		vbios.data_return_bus_width = bw_int_to_fixed(32);
+		vbios.trc = bw_int_to_fixed(48);
+		vbios.dmifmc_urgent_latency = bw_int_to_fixed(3);
+		vbios.stutter_self_refresh_exit_latency = bw_int_to_fixed(5);
+		vbios.nbp_state_change_latency = bw_int_to_fixed(45);
+		vbios.mcifwrmc_urgent_latency = bw_int_to_fixed(10);
+		vbios.scatter_gather_enable = true;
+		vbios.down_spread_percentage = bw_frc_to_fixed(5, 10);
+		vbios.cursor_width = 32;
+		vbios.average_compression_rate = 4;
+		vbios.number_of_request_slots_gmc_reserves_for_dmif_per_channel =
+			256;
+		vbios.blackout_duration = bw_int_to_fixed(0); /* us */
+		vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0);
+
+		dceip.dmif_request_buffer_size = bw_int_to_fixed(768);
+		dceip.de_tiling_buffer = bw_int_to_fixed(0);
+		dceip.dcfclk_request_generation = 0;
+		dceip.lines_interleaved_into_lb = 2;
+		dceip.chunk_width = 256;
+		dceip.number_of_graphics_pipes = 6;
+		dceip.number_of_underlay_pipes = 0;
+		dceip.display_write_back_supported = false;
+		dceip.argb_compression_support = false;
+		dceip.underlay_vscaler_efficiency6_bit_per_component =
+			bw_frc_to_fixed(35556, 10000);
+		dceip.underlay_vscaler_efficiency8_bit_per_component =
+			bw_frc_to_fixed(34286, 10000);
+		dceip.underlay_vscaler_efficiency10_bit_per_component =
+			bw_frc_to_fixed(32, 10);
+		dceip.underlay_vscaler_efficiency12_bit_per_component =
+			bw_int_to_fixed(3);
+		dceip.graphics_vscaler_efficiency6_bit_per_component =
+			bw_frc_to_fixed(35, 10);
+		dceip.graphics_vscaler_efficiency8_bit_per_component =
+			bw_frc_to_fixed(34286, 10000);
+		dceip.graphics_vscaler_efficiency10_bit_per_component =
+			bw_frc_to_fixed(32, 10);
+		dceip.graphics_vscaler_efficiency12_bit_per_component =
+			bw_int_to_fixed(3);
+		dceip.alpha_vscaler_efficiency = bw_int_to_fixed(3);
+		dceip.max_dmif_buffer_allocated = 4;
+		dceip.graphics_dmif_size = 12288;
+		dceip.underlay_luma_dmif_size = 19456;
+		dceip.underlay_chroma_dmif_size = 23552;
+		dceip.pre_downscaler_enabled = true;
+		dceip.underlay_downscale_prefetch_enabled = true;
+		dceip.lb_write_pixels_per_dispclk = bw_int_to_fixed(1);
+		dceip.lb_size_per_component444 = bw_int_to_fixed(245952);
+		dceip.graphics_lb_nodownscaling_multi_line_prefetching = true;
+		dceip.stutter_and_dram_clock_state_change_gated_before_cursor =
+			bw_int_to_fixed(1);
+		dceip.underlay420_luma_lb_size_per_component = bw_int_to_fixed(
+			82176);
+		dceip.underlay420_chroma_lb_size_per_component =
+			bw_int_to_fixed(164352);
+		dceip.underlay422_lb_size_per_component = bw_int_to_fixed(
+			82176);
+		dceip.cursor_chunk_width = bw_int_to_fixed(64);
+		dceip.cursor_dcp_buffer_lines = bw_int_to_fixed(4);
+		dceip.cursor_memory_interface_buffer_pixels = bw_int_to_fixed(
+			64);
+		dceip.underlay_maximum_width_efficient_for_tiling =
+			bw_int_to_fixed(1920);
+		dceip.underlay_maximum_height_efficient_for_tiling =
+			bw_int_to_fixed(1080);
+		dceip.peak_pte_request_to_eviction_ratio_limiting_multiple_displays_or_single_rotated_display =
+			bw_frc_to_fixed(3, 10);
+		dceip.peak_pte_request_to_eviction_ratio_limiting_single_display_no_rotation =
+			bw_int_to_fixed(25);
+		dceip.minimum_outstanding_pte_request_limit = bw_int_to_fixed(
+			2);
+		dceip.maximum_total_outstanding_pte_requests_allowed_by_saw =
+			bw_int_to_fixed(128);
+		dceip.limit_excessive_outstanding_dmif_requests = true;
+		dceip.linear_mode_line_request_alternation_slice =
+			bw_int_to_fixed(64);
+		dceip.scatter_gather_lines_of_pte_prefetching_in_linear_mode =
+			32;
+		dceip.display_write_back420_luma_mcifwr_buffer_size = 12288;
+		dceip.display_write_back420_chroma_mcifwr_buffer_size = 8192;
+		dceip.request_efficiency = bw_frc_to_fixed(8, 10);
+		dceip.dispclk_per_request = bw_int_to_fixed(2);
+		dceip.dispclk_ramping_factor = bw_frc_to_fixed(11, 10);
+		dceip.display_pipe_throughput_factor = bw_frc_to_fixed(
+			105,
+			100);
+		dceip.scatter_gather_pte_request_rows_in_tiling_mode = 2;
+		dceip.mcifwr_all_surfaces_burst_time = bw_int_to_fixed(0);
+		break;
+	case BW_CALCS_VERSION_BAFFIN:
+		vbios.number_of_dram_channels = 4;
+		vbios.dram_channel_width_in_bits = 32;
+		vbios.number_of_dram_banks = 8;
+		vbios.high_yclk = bw_int_to_fixed(6000);
+		vbios.mid_yclk = bw_int_to_fixed(3200);
+		vbios.low_yclk = bw_int_to_fixed(1000);
+		vbios.low_sclk = bw_int_to_fixed(300);
+		vbios.mid_sclk = bw_int_to_fixed(974);
+		vbios.high_sclk = bw_int_to_fixed(1154);
+		vbios.low_voltage_max_dispclk = bw_int_to_fixed(459);
+		vbios.mid_voltage_max_dispclk = bw_int_to_fixed(654);
+		vbios.high_voltage_max_dispclk = bw_int_to_fixed(1132);
+		vbios.data_return_bus_width = bw_int_to_fixed(32);
+		vbios.trc = bw_int_to_fixed(48);
+		vbios.dmifmc_urgent_latency = bw_int_to_fixed(3);
+		vbios.stutter_self_refresh_exit_latency = bw_int_to_fixed(5);
+		vbios.nbp_state_change_latency = bw_int_to_fixed(45);
+		vbios.mcifwrmc_urgent_latency = bw_int_to_fixed(10);
+		vbios.scatter_gather_enable = true;
+		vbios.down_spread_percentage = bw_frc_to_fixed(5, 10);
+		vbios.cursor_width = 32;
+		vbios.average_compression_rate = 4;
+		vbios.number_of_request_slots_gmc_reserves_for_dmif_per_channel =
+			256;
+		vbios.blackout_duration = bw_int_to_fixed(0); /* us */
+		vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0);
+
+		dceip.dmif_request_buffer_size = bw_int_to_fixed(768);
+		dceip.de_tiling_buffer = bw_int_to_fixed(0);
+		dceip.dcfclk_request_generation = 0;
+		dceip.lines_interleaved_into_lb = 2;
+		dceip.chunk_width = 256;
+		dceip.number_of_graphics_pipes = 5;
+		dceip.number_of_underlay_pipes = 0;
+		dceip.display_write_back_supported = false;
+		dceip.argb_compression_support = false;
+		dceip.underlay_vscaler_efficiency6_bit_per_component =
+			bw_frc_to_fixed(35556, 10000);
+		dceip.underlay_vscaler_efficiency8_bit_per_component =
+			bw_frc_to_fixed(34286, 10000);
+		dceip.underlay_vscaler_efficiency10_bit_per_component =
+			bw_frc_to_fixed(32, 10);
+		dceip.underlay_vscaler_efficiency12_bit_per_component =
+			bw_int_to_fixed(3);
+		dceip.graphics_vscaler_efficiency6_bit_per_component =
+			bw_frc_to_fixed(35, 10);
+		dceip.graphics_vscaler_efficiency8_bit_per_component =
+			bw_frc_to_fixed(34286, 10000);
+		dceip.graphics_vscaler_efficiency10_bit_per_component =
+			bw_frc_to_fixed(32, 10);
+		dceip.graphics_vscaler_efficiency12_bit_per_component =
+			bw_int_to_fixed(3);
+		dceip.alpha_vscaler_efficiency = bw_int_to_fixed(3);
+		dceip.max_dmif_buffer_allocated = 4;
+		dceip.graphics_dmif_size = 12288;
+		dceip.underlay_luma_dmif_size = 19456;
+		dceip.underlay_chroma_dmif_size = 23552;
+		dceip.pre_downscaler_enabled = true;
+		dceip.underlay_downscale_prefetch_enabled = true;
+		dceip.lb_write_pixels_per_dispclk = bw_int_to_fixed(1);
+		dceip.lb_size_per_component444 = bw_int_to_fixed(245952);
+		dceip.graphics_lb_nodownscaling_multi_line_prefetching = true;
+		dceip.stutter_and_dram_clock_state_change_gated_before_cursor =
+			bw_int_to_fixed(1);
+		dceip.underlay420_luma_lb_size_per_component = bw_int_to_fixed(
+			82176);
+		dceip.underlay420_chroma_lb_size_per_component =
+			bw_int_to_fixed(164352);
+		dceip.underlay422_lb_size_per_component = bw_int_to_fixed(
+			82176);
+		dceip.cursor_chunk_width = bw_int_to_fixed(64);
+		dceip.cursor_dcp_buffer_lines = bw_int_to_fixed(4);
+		dceip.cursor_memory_interface_buffer_pixels = bw_int_to_fixed(
+			64);
+		dceip.underlay_maximum_width_efficient_for_tiling =
+			bw_int_to_fixed(1920);
+		dceip.underlay_maximum_height_efficient_for_tiling =
+			bw_int_to_fixed(1080);
+		dceip.peak_pte_request_to_eviction_ratio_limiting_multiple_displays_or_single_rotated_display =
+			bw_frc_to_fixed(3, 10);
+		dceip.peak_pte_request_to_eviction_ratio_limiting_single_display_no_rotation =
+			bw_int_to_fixed(25);
+		dceip.minimum_outstanding_pte_request_limit = bw_int_to_fixed(
+			2);
+		dceip.maximum_total_outstanding_pte_requests_allowed_by_saw =
+			bw_int_to_fixed(128);
+		dceip.limit_excessive_outstanding_dmif_requests = true;
+		dceip.linear_mode_line_request_alternation_slice =
+			bw_int_to_fixed(64);
+		dceip.scatter_gather_lines_of_pte_prefetching_in_linear_mode =
+			32;
+		dceip.display_write_back420_luma_mcifwr_buffer_size = 12288;
+		dceip.display_write_back420_chroma_mcifwr_buffer_size = 8192;
+		dceip.request_efficiency = bw_frc_to_fixed(8, 10);
+		dceip.dispclk_per_request = bw_int_to_fixed(2);
+		dceip.dispclk_ramping_factor = bw_frc_to_fixed(11, 10);
+		dceip.display_pipe_throughput_factor = bw_frc_to_fixed(
+			105,
+			100);
+		dceip.scatter_gather_pte_request_rows_in_tiling_mode = 2;
+		dceip.mcifwr_all_surfaces_burst_time = bw_int_to_fixed(0);
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c
index 61bb67a..f9dd0d8 100644
--- a/drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c
@@ -34,6 +34,9 @@
 #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
 #include "dce110/dce110_hw_sequencer.h"
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+#include "dce112/dce112_hw_sequencer.h"
+#endif
 
 bool dc_construct_hw_sequencer(
 				struct adapter_service *adapter_serv,
@@ -55,6 +58,10 @@ bool dc_construct_hw_sequencer(
 	case DCE_VERSION_11_0:
 		return dce110_hw_sequencer_construct(dc);
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	case DCE_VERSION_11_2:
+		return dce112_hw_sequencer_construct(dc);
+#endif
 	default:
 		break;
 	}
diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c b/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
index 5f3b702..087670d 100644
--- a/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
@@ -41,11 +41,13 @@
 #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
 #include "dce110/dce110_resource.h"
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+#include "dce112/dce112_resource.h"
+#endif
 
 enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
- {
+{
 	enum dce_version dc_version = DCE_VERSION_UNKNOWN;
-
 	switch (asic_id.chip_family) {
 
 #if defined(CONFIG_DRM_AMD_DAL_DCE8_0)
@@ -68,6 +70,12 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
 			break;
 		}
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+		if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) ||
+				ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev)) {
+			dc_version = DCE_VERSION_11_2;
+		}
+#endif
 		break;
 	default:
 		dc_version = DCE_VERSION_UNKNOWN;
@@ -83,6 +91,11 @@ bool dc_construct_resource_pool(struct adapter_service *adapter_serv,
 {
 
 	switch (dc_version) {
+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0)
+	case DCE_VERSION_8_0:
+		return dce80_construct_resource_pool(
+			adapter_serv, num_virtual_links, dc, &dc->res_pool);
+#endif
 #if defined(CONFIG_DRM_AMD_DAL_DCE10_0)
 	case DCE_VERSION_10_0:
 		return dce100_construct_resource_pool(
@@ -93,6 +106,11 @@ bool dc_construct_resource_pool(struct adapter_service *adapter_serv,
 		return dce110_construct_resource_pool(
 			adapter_serv, num_virtual_links, dc, &dc->res_pool);
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	case DCE_VERSION_11_2:
+		return dce112_construct_resource_pool(
+			adapter_serv, num_virtual_links, dc, &dc->res_pool);
+#endif
 	default:
 		break;
 	}
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
index 3d4f8b7..a21fcbd 100644
--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
@@ -416,6 +416,7 @@ static void dce110_crtc_switch_to_clk_src(
 	uint32_t pixel_rate_cntl_value;
 	uint32_t addr;
 
+	/* These addresses are the same across DCE8 - DCE11.2 */
 	addr = mmCRTC0_PIXEL_RATE_CNTL + crtc_inst *
 			(mmCRTC1_PIXEL_RATE_CNTL - mmCRTC0_PIXEL_RATE_CNTL);
 
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c
index de370ee..a9ef65d 100644
--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c
@@ -59,7 +59,7 @@ enum black_color_format {
 
 /* Flowing register offsets are same in files of
  * dce/dce_11_0_d.h
- * dce/vi_ellesmere_p/vi_ellesmere_d.h
+ * dce/vi_polaris10_p/vi_polaris10_d.h
  *
  * So we can create dce110 timing generator to use it.
  */
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/Makefile b/drivers/gpu/drm/amd/dal/dc/dce112/Makefile
new file mode 100644
index 0000000..c7d61d9
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the 'controller' sub-component of DAL.
+# It provides the control and status of HW CRTC block.
+
+DCE112 = dce112_link_encoder.o dce112_compressor.o dce112_hw_sequencer.o \
+dce112_resource.o dce112_clock_source.o dce112_mem_input.o
+
+AMD_DAL_DCE112 = $(addprefix $(AMDDALPATH)/dc/dce112/,$(DCE112))
+
+AMD_DAL_FILES += $(AMD_DAL_DCE112)
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.c
new file mode 100644
index 0000000..7ec9508
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.c
@@ -0,0 +1,266 @@
+/*
+ * 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 "dce112_clock_source.h"
+
+/* include DCE11.2 register header files */
+#include "dce/dce_11_2_d.h"
+#include "dce/dce_11_2_sh_mask.h"
+
+#include "dc_types.h"
+#include "core_types.h"
+
+#include "include/grph_object_id.h"
+#include "include/logger_interface.h"
+
+/**
+ * Calculate PLL Dividers for given Clock Value.
+ * First will call VBIOS Adjust Exec table to check if requested Pixel clock
+ * will be Adjusted based on usage.
+ * Then it will calculate PLL Dividers for this Adjusted clock using preferred
+ * method (Maximum VCO frequency).
+ *
+ * \return
+ *     Calculation error in units of 0.01%
+ */
+static uint32_t dce112_get_pix_clk_dividers(
+		struct clock_source *cs,
+		struct pixel_clk_params *pix_clk_params,
+		struct pll_settings *pll_settings)
+{
+	struct dce112_clk_src *clk_src = TO_DCE112_CLK_SRC(cs);
+	uint32_t actualPixelClockInKHz;
+
+	if (pix_clk_params == NULL || pll_settings == NULL
+			|| pix_clk_params->requested_pix_clk == 0) {
+		dal_logger_write(cs->ctx->logger,
+			LOG_MAJOR_ERROR,
+			LOG_MINOR_COMPONENT_GPU,
+			"%s: Invalid parameters!!\n", __func__);
+		return 0;
+	}
+
+	memset(pll_settings, 0, sizeof(*pll_settings));
+
+	if (clk_src->base.id == CLOCK_SOURCE_ID_DP_DTO) {
+		pll_settings->adjusted_pix_clk = clk_src->ext_clk_khz;
+		pll_settings->calculated_pix_clk = clk_src->ext_clk_khz;
+		pll_settings->actual_pix_clk =
+					pix_clk_params->requested_pix_clk;
+		return 0;
+	}
+	/* PLL only after this point */
+
+	actualPixelClockInKHz = pix_clk_params->requested_pix_clk;
+
+	/* Calculate Dividers */
+	if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
+		switch (pix_clk_params->color_depth) {
+		case COLOR_DEPTH_101010:
+			actualPixelClockInKHz = (actualPixelClockInKHz * 5) >> 2;
+			break;
+		case COLOR_DEPTH_121212:
+			actualPixelClockInKHz = (actualPixelClockInKHz * 6) >> 2;
+			break;
+		case COLOR_DEPTH_161616:
+			actualPixelClockInKHz = actualPixelClockInKHz * 2;
+			break;
+		default:
+			break;
+		}
+	}
+
+	pll_settings->actual_pix_clk = actualPixelClockInKHz;
+	pll_settings->adjusted_pix_clk = actualPixelClockInKHz;
+	pll_settings->calculated_pix_clk = pix_clk_params->requested_pix_clk;
+
+	return 0;
+}
+
+static void program_pixel_clk_resync(
+		struct dce112_clk_src *clk_src,
+		enum signal_type signal_type,
+		enum dc_color_depth colordepth)
+{
+	uint32_t value = 0;
+
+	value = dm_read_reg(clk_src->base.ctx,
+		clk_src->offsets.pixclk_resync_cntl);
+
+	set_reg_field_value(
+		value,
+		0,
+		PHYPLLA_PIXCLK_RESYNC_CNTL,
+		PHYPLLA_DCCG_DEEP_COLOR_CNTL);
+
+	/*
+	 24 bit mode: TMDS clock = 1.0 x pixel clock  (1:1)
+	 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
+	 36 bit mode: TMDS clock = 1.5 x pixel clock  (3:2)
+	 48 bit mode: TMDS clock = 2 x pixel clock    (2:1)
+	 */
+	if (signal_type != SIGNAL_TYPE_HDMI_TYPE_A)
+		return;
+
+	switch (colordepth) {
+	case COLOR_DEPTH_888:
+		set_reg_field_value(
+			value,
+			0,
+			PHYPLLA_PIXCLK_RESYNC_CNTL,
+			PHYPLLA_DCCG_DEEP_COLOR_CNTL);
+		break;
+	case COLOR_DEPTH_101010:
+		set_reg_field_value(
+			value,
+			1,
+			PHYPLLA_PIXCLK_RESYNC_CNTL,
+			PHYPLLA_DCCG_DEEP_COLOR_CNTL);
+		break;
+	case COLOR_DEPTH_121212:
+		set_reg_field_value(
+			value,
+			2,
+			PHYPLLA_PIXCLK_RESYNC_CNTL,
+			PHYPLLA_DCCG_DEEP_COLOR_CNTL);
+		break;
+	case COLOR_DEPTH_161616:
+		set_reg_field_value(
+			value,
+			3,
+			PHYPLLA_PIXCLK_RESYNC_CNTL,
+			PHYPLLA_DCCG_DEEP_COLOR_CNTL);
+		break;
+	default:
+		break;
+	}
+
+	dm_write_reg(
+		clk_src->base.ctx,
+		clk_src->offsets.pixclk_resync_cntl,
+		value);
+}
+
+static bool dce112_program_pix_clk(
+		struct clock_source *clk_src,
+		struct pixel_clk_params *pix_clk_params,
+		struct pll_settings *pll_settings)
+{
+	struct dce112_clk_src *dce112_clk_src = TO_DCE112_CLK_SRC(clk_src);
+	struct bp_pixel_clock_parameters bp_pc_params = {0};
+
+	/*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
+	bp_pc_params.controller_id = pix_clk_params->controller_id;
+	bp_pc_params.pll_id = clk_src->id;
+	bp_pc_params.target_pixel_clock = pll_settings->actual_pix_clk;
+	bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
+	bp_pc_params.signal_type = pix_clk_params->signal_type;
+
+	if (clk_src->id != CLOCK_SOURCE_ID_DP_DTO) {
+		bp_pc_params.flags.SET_GENLOCK_REF_DIV_SRC =
+						pll_settings->use_external_clk;
+		bp_pc_params.flags.SET_XTALIN_REF_SRC =
+						!pll_settings->use_external_clk;
+		bp_pc_params.flags.SUPPORT_YUV_420 = 0;
+	}
+
+	if (dce112_clk_src->bios->funcs->set_pixel_clock(
+			dce112_clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
+		return false;
+
+	/* TODO: support YCBCR420 */
+
+	/* Resync deep color DTO */
+	if (clk_src->id != CLOCK_SOURCE_ID_DP_DTO)
+		program_pixel_clk_resync(dce112_clk_src,
+					pix_clk_params->signal_type,
+					pix_clk_params->color_depth);
+
+	return true;
+}
+
+static bool dce112_clock_source_power_down(
+		struct clock_source *clk_src)
+{
+	struct dce112_clk_src *dce112_clk_src = TO_DCE112_CLK_SRC(clk_src);
+	enum bp_result bp_result;
+	struct bp_pixel_clock_parameters bp_pixel_clock_params = {0};
+
+	if (clk_src->id == CLOCK_SOURCE_ID_DP_DTO)
+		return true;
+
+	/* If Pixel Clock is 0 it means Power Down Pll*/
+	bp_pixel_clock_params.controller_id = CONTROLLER_ID_UNDEFINED;
+	bp_pixel_clock_params.pll_id = clk_src->id;
+	bp_pixel_clock_params.flags.FORCE_PROGRAMMING_OF_PLL = 1;
+
+	/*Call ASICControl to process ATOMBIOS Exec table*/
+	bp_result = dce112_clk_src->bios->funcs->set_pixel_clock(
+			dce112_clk_src->bios,
+			&bp_pixel_clock_params);
+
+	return bp_result == BP_RESULT_OK;
+}
+
+/*****************************************/
+/* Constructor                           */
+/*****************************************/
+static struct clock_source_funcs dce112_clk_src_funcs = {
+	.cs_power_down = dce112_clock_source_power_down,
+	.program_pix_clk = dce112_program_pix_clk,
+	.get_pix_clk_dividers = dce112_get_pix_clk_dividers
+};
+
+bool dce112_clk_src_construct(
+	struct dce112_clk_src *clk_src,
+	struct dc_context *ctx,
+	struct dc_bios *bios,
+	enum clock_source_id id,
+	const struct dce112_clk_src_reg_offsets *reg_offsets)
+{
+	struct firmware_info fw_info = { { 0 } };
+
+	clk_src->base.ctx = ctx;
+	clk_src->bios = bios;
+	clk_src->base.id = id;
+	clk_src->base.funcs = &dce112_clk_src_funcs;
+	clk_src->offsets = *reg_offsets;
+
+	if (clk_src->bios->funcs->get_firmware_info(
+			clk_src->bios, &fw_info) != BP_RESULT_OK) {
+		ASSERT_CRITICAL(false);
+		goto unexpected_failure;
+	}
+
+	clk_src->ext_clk_khz = fw_info.external_clock_source_frequency_for_dp;
+
+	return true;
+
+unexpected_failure:
+	return false;
+}
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.h
new file mode 100644
index 0000000..40ecc58
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.h
@@ -0,0 +1,52 @@
+/* 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_CLOCK_SOURCE_DCE110_H__
+#define __DC_CLOCK_SOURCE_DCE110_H__
+
+#include "clock_source.h"
+
+#define TO_DCE112_CLK_SRC(clk_src)\
+	container_of(clk_src, struct dce112_clk_src, base)
+
+struct dce112_clk_src_reg_offsets {
+	uint32_t pixclk_resync_cntl;
+};
+
+struct dce112_clk_src {
+	struct clock_source base;
+	struct dce112_clk_src_reg_offsets offsets;
+	struct dc_bios *bios;
+
+	uint32_t ext_clk_khz;
+};
+
+bool dce112_clk_src_construct(
+	struct dce112_clk_src *clk_src,
+	struct dc_context *ctx,
+	struct dc_bios *bios,
+	enum clock_source_id,
+	const struct dce112_clk_src_reg_offsets *reg_offsets);
+
+#endif
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.c
new file mode 100644
index 0000000..9526ffd
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.c
@@ -0,0 +1,883 @@
+/*
+ * 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 "dce/dce_11_2_d.h"
+#include "dce/dce_11_2_sh_mask.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+#include "gmc/gmc_8_1_d.h"
+
+#include "include/logger_interface.h"
+#include "include/adapter_service_interface.h"
+
+#include "dce112_compressor.h"
+
+#define DCP_REG(reg)\
+	(reg + cp110->offsets.dcp_offset)
+#define DMIF_REG(reg)\
+	(reg + cp110->offsets.dmif_offset)
+
+static const struct dce112_compressor_reg_offsets reg_offsets[] = {
+{
+	.dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+	.dmif_offset =
+		(mmDMIF_PG0_DPG_PIPE_DPM_CONTROL
+			- mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+	.dmif_offset =
+		(mmDMIF_PG1_DPG_PIPE_DPM_CONTROL
+			- mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+	.dmif_offset =
+		(mmDMIF_PG2_DPG_PIPE_DPM_CONTROL
+			- mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
+}
+};
+
+static const uint32_t dce11_one_lpt_channel_max_resolution = 2560 * 1600;
+
+enum fbc_idle_force {
+	/* Bit 0 - Display registers updated */
+	FBC_IDLE_FORCE_DISPLAY_REGISTER_UPDATE = 0x00000001,
+
+	/* Bit 2 - FBC_GRPH_COMP_EN register updated */
+	FBC_IDLE_FORCE_GRPH_COMP_EN = 0x00000002,
+	/* Bit 3 - FBC_SRC_SEL register updated */
+	FBC_IDLE_FORCE_SRC_SEL_CHANGE = 0x00000004,
+	/* Bit 4 - FBC_MIN_COMPRESSION register updated */
+	FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE = 0x00000008,
+	/* Bit 5 - FBC_ALPHA_COMP_EN register updated */
+	FBC_IDLE_FORCE_ALPHA_COMP_EN = 0x00000010,
+	/* Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated */
+	FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN = 0x00000020,
+	/* Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated */
+	FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF = 0x00000040,
+
+	/* Bit 24 - Memory write to region 0 defined by MC registers. */
+	FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION0 = 0x01000000,
+	/* Bit 25 - Memory write to region 1 defined by MC registers */
+	FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION1 = 0x02000000,
+	/* Bit 26 - Memory write to region 2 defined by MC registers */
+	FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION2 = 0x04000000,
+	/* Bit 27 - Memory write to region 3 defined by MC registers. */
+	FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION3 = 0x08000000,
+
+	/* Bit 28 - Memory write from any client other than MCIF */
+	FBC_IDLE_FORCE_MEMORY_WRITE_OTHER_THAN_MCIF = 0x10000000,
+	/* Bit 29 - CG statics screen signal is inactive */
+	FBC_IDLE_FORCE_CG_STATIC_SCREEN_IS_INACTIVE = 0x20000000,
+};
+
+static uint32_t lpt_size_alignment(struct dce112_compressor *cp110)
+{
+	/*LPT_ALIGNMENT (in bytes) = ROW_SIZE * #BANKS * # DRAM CHANNELS. */
+	return cp110->base.raw_size * cp110->base.banks_num *
+		cp110->base.dram_channels_num;
+}
+
+static uint32_t lpt_memory_control_config(struct dce112_compressor *cp110,
+	uint32_t lpt_control)
+{
+	/*LPT MC Config */
+	if (cp110->base.options.bits.LPT_MC_CONFIG == 1) {
+		/* POSSIBLE VALUES for LPT NUM_PIPES (DRAM CHANNELS):
+		 * 00 - 1 CHANNEL
+		 * 01 - 2 CHANNELS
+		 * 02 - 4 OR 6 CHANNELS
+		 * (Only for discrete GPU, N/A for CZ)
+		 * 03 - 8 OR 12 CHANNELS
+		 * (Only for discrete GPU, N/A for CZ) */
+		switch (cp110->base.dram_channels_num) {
+		case 2:
+			set_reg_field_value(
+				lpt_control,
+				1,
+				LOW_POWER_TILING_CONTROL,
+				LOW_POWER_TILING_NUM_PIPES);
+			break;
+		case 1:
+			set_reg_field_value(
+				lpt_control,
+				0,
+				LOW_POWER_TILING_CONTROL,
+				LOW_POWER_TILING_NUM_PIPES);
+			break;
+		default:
+			dal_logger_write(
+				cp110->base.ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_CONTROLLER,
+				"%s: Invalid LPT NUM_PIPES!!!",
+				__func__);
+			break;
+		}
+
+		/* The mapping for LPT NUM_BANKS is in
+		 * GRPH_CONTROL.GRPH_NUM_BANKS register field
+		 * Specifies the number of memory banks for tiling
+		 * purposes. Only applies to 2D and 3D tiling modes.
+		 * POSSIBLE VALUES:
+		 * 00 - DCP_GRPH_NUM_BANKS_2BANK: ADDR_SURF_2_BANK
+		 * 01 - DCP_GRPH_NUM_BANKS_4BANK: ADDR_SURF_4_BANK
+		 * 02 - DCP_GRPH_NUM_BANKS_8BANK: ADDR_SURF_8_BANK
+		 * 03 - DCP_GRPH_NUM_BANKS_16BANK: ADDR_SURF_16_BANK */
+		switch (cp110->base.banks_num) {
+		case 16:
+			set_reg_field_value(
+				lpt_control,
+				3,
+				LOW_POWER_TILING_CONTROL,
+				LOW_POWER_TILING_NUM_BANKS);
+			break;
+		case 8:
+			set_reg_field_value(
+				lpt_control,
+				2,
+				LOW_POWER_TILING_CONTROL,
+				LOW_POWER_TILING_NUM_BANKS);
+			break;
+		case 4:
+			set_reg_field_value(
+				lpt_control,
+				1,
+				LOW_POWER_TILING_CONTROL,
+				LOW_POWER_TILING_NUM_BANKS);
+			break;
+		case 2:
+			set_reg_field_value(
+				lpt_control,
+				0,
+				LOW_POWER_TILING_CONTROL,
+				LOW_POWER_TILING_NUM_BANKS);
+			break;
+		default:
+			dal_logger_write(
+				cp110->base.ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_CONTROLLER,
+				"%s: Invalid LPT NUM_BANKS!!!",
+				__func__);
+			break;
+		}
+
+		/* The mapping is in DMIF_ADDR_CALC.
+		 * ADDR_CONFIG_PIPE_INTERLEAVE_SIZE register field for
+		 * Carrizo specifies the memory interleave per pipe.
+		 * It effectively specifies the location of pipe bits in
+		 * the memory address.
+		 * POSSIBLE VALUES:
+		 * 00 - ADDR_CONFIG_PIPE_INTERLEAVE_256B: 256 byte
+		 * interleave
+		 * 01 - ADDR_CONFIG_PIPE_INTERLEAVE_512B: 512 byte
+		 * interleave
+		 */
+		switch (cp110->base.channel_interleave_size) {
+		case 256: /*256B */
+			set_reg_field_value(
+				lpt_control,
+				0,
+				LOW_POWER_TILING_CONTROL,
+				LOW_POWER_TILING_PIPE_INTERLEAVE_SIZE);
+			break;
+		case 512: /*512B */
+			set_reg_field_value(
+				lpt_control,
+				1,
+				LOW_POWER_TILING_CONTROL,
+				LOW_POWER_TILING_PIPE_INTERLEAVE_SIZE);
+			break;
+		default:
+			dal_logger_write(
+				cp110->base.ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_CONTROLLER,
+				"%s: Invalid LPT INTERLEAVE_SIZE!!!",
+				__func__);
+			break;
+		}
+
+		/* The mapping for LOW_POWER_TILING_ROW_SIZE is in
+		 * DMIF_ADDR_CALC.ADDR_CONFIG_ROW_SIZE register field
+		 * for Carrizo. Specifies the size of dram row in bytes.
+		 * This should match up with NOOFCOLS field in
+		 * MC_ARB_RAMCFG (ROW_SIZE = 4 * 2 ^^ columns).
+		 * This register DMIF_ADDR_CALC is not used by the
+		 * hardware as it is only used for addrlib assertions.
+		 * POSSIBLE VALUES:
+		 * 00 - ADDR_CONFIG_1KB_ROW: Treat 1KB as DRAM row
+		 * boundary
+		 * 01 - ADDR_CONFIG_2KB_ROW: Treat 2KB as DRAM row
+		 * boundary
+		 * 02 - ADDR_CONFIG_4KB_ROW: Treat 4KB as DRAM row
+		 * boundary */
+		switch (cp110->base.raw_size) {
+		case 4096: /*4 KB */
+			set_reg_field_value(
+				lpt_control,
+				2,
+				LOW_POWER_TILING_CONTROL,
+				LOW_POWER_TILING_ROW_SIZE);
+			break;
+		case 2048:
+			set_reg_field_value(
+				lpt_control,
+				1,
+				LOW_POWER_TILING_CONTROL,
+				LOW_POWER_TILING_ROW_SIZE);
+			break;
+		case 1024:
+			set_reg_field_value(
+				lpt_control,
+				0,
+				LOW_POWER_TILING_CONTROL,
+				LOW_POWER_TILING_ROW_SIZE);
+			break;
+		default:
+			dal_logger_write(
+				cp110->base.ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_CONTROLLER,
+				"%s: Invalid LPT ROW_SIZE!!!",
+				__func__);
+			break;
+		}
+	} else {
+		dal_logger_write(
+			cp110->base.ctx->logger,
+			LOG_MAJOR_WARNING,
+			LOG_MINOR_COMPONENT_CONTROLLER,
+			"%s: LPT MC Configuration is not provided",
+			__func__);
+	}
+
+	return lpt_control;
+}
+
+static bool is_source_bigger_than_epanel_size(
+	struct dce112_compressor *cp110,
+	uint32_t source_view_width,
+	uint32_t source_view_height)
+{
+	if (cp110->base.embedded_panel_h_size != 0 &&
+		cp110->base.embedded_panel_v_size != 0 &&
+		((source_view_width * source_view_height) >
+		(cp110->base.embedded_panel_h_size *
+			cp110->base.embedded_panel_v_size)))
+		return true;
+
+	return false;
+}
+
+static uint32_t align_to_chunks_number_per_line(
+	struct dce112_compressor *cp110,
+	uint32_t pixels)
+{
+	return 256 * ((pixels + 255) / 256);
+}
+
+static void wait_for_fbc_state_changed(
+	struct dce112_compressor *cp110,
+	bool enabled)
+{
+	uint8_t counter = 0;
+	uint32_t addr = mmFBC_STATUS;
+	uint32_t value;
+
+	while (counter < 10) {
+		value = dm_read_reg(cp110->base.ctx, addr);
+		if (get_reg_field_value(
+			value,
+			FBC_STATUS,
+			FBC_ENABLE_STATUS) == enabled)
+			break;
+		udelay(10);
+		counter++;
+	}
+
+	if (counter == 10) {
+		dal_logger_write(
+			cp110->base.ctx->logger,
+			LOG_MAJOR_WARNING,
+			LOG_MINOR_COMPONENT_CONTROLLER,
+			"%s: wait counter exceeded, changes to HW not applied",
+			__func__);
+	}
+}
+
+void dce112_compressor_power_up_fbc(struct compressor *compressor)
+{
+	uint32_t value;
+	uint32_t addr;
+
+	addr = mmFBC_CNTL;
+	value = dm_read_reg(compressor->ctx, addr);
+	set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
+	set_reg_field_value(value, 1, FBC_CNTL, FBC_EN);
+	set_reg_field_value(value, 2, FBC_CNTL, FBC_COHERENCY_MODE);
+	if (compressor->options.bits.CLK_GATING_DISABLED == 1) {
+		/* HW needs to do power measurement comparison. */
+		set_reg_field_value(
+			value,
+			0,
+			FBC_CNTL,
+			FBC_COMP_CLK_GATE_EN);
+	}
+	dm_write_reg(compressor->ctx, addr, value);
+
+	addr = mmFBC_COMP_MODE;
+	value = dm_read_reg(compressor->ctx, addr);
+	set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_RLE_EN);
+	set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_DPCM4_RGB_EN);
+	set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_IND_EN);
+	dm_write_reg(compressor->ctx, addr, value);
+
+	addr = mmFBC_COMP_CNTL;
+	value = dm_read_reg(compressor->ctx, addr);
+	set_reg_field_value(value, 1, FBC_COMP_CNTL, FBC_DEPTH_RGB08_EN);
+	dm_write_reg(compressor->ctx, addr, value);
+	/*FBC_MIN_COMPRESSION 0 ==> 2:1 */
+	/*                    1 ==> 4:1 */
+	/*                    2 ==> 8:1 */
+	/*                  0xF ==> 1:1 */
+	set_reg_field_value(value, 0xF, FBC_COMP_CNTL, FBC_MIN_COMPRESSION);
+	dm_write_reg(compressor->ctx, addr, value);
+	compressor->min_compress_ratio = FBC_COMPRESS_RATIO_1TO1;
+
+	value = 0;
+	dm_write_reg(compressor->ctx, mmFBC_IND_LUT0, value);
+
+	value = 0xFFFFFF;
+	dm_write_reg(compressor->ctx, mmFBC_IND_LUT1, value);
+}
+
+void dce112_compressor_enable_fbc(
+	struct compressor *compressor,
+	uint32_t paths_num,
+	struct compr_addr_and_pitch_params *params)
+{
+	struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
+
+	if (compressor->options.bits.FBC_SUPPORT &&
+		(compressor->options.bits.DUMMY_BACKEND == 0) &&
+		(!dce112_compressor_is_fbc_enabled_in_hw(compressor, NULL)) &&
+		(!is_source_bigger_than_epanel_size(
+			cp110,
+			params->source_view_width,
+			params->source_view_height))) {
+
+		uint32_t addr;
+		uint32_t value;
+
+		/* Before enabling FBC first need to enable LPT if applicable
+		 * LPT state should always be changed (enable/disable) while FBC
+		 * is disabled */
+		if (compressor->options.bits.LPT_SUPPORT && (paths_num < 2) &&
+			(params->source_view_width *
+				params->source_view_height <=
+				dce11_one_lpt_channel_max_resolution)) {
+			dce112_compressor_enable_lpt(compressor);
+		}
+
+		addr = mmFBC_CNTL;
+		value = dm_read_reg(compressor->ctx, addr);
+		set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
+		set_reg_field_value(
+			value,
+			params->inst,
+			FBC_CNTL, FBC_SRC_SEL);
+		dm_write_reg(compressor->ctx, addr, value);
+
+		/* Keep track of enum controller_id FBC is attached to */
+		compressor->is_enabled = true;
+		compressor->attached_inst = params->inst;
+		cp110->offsets = reg_offsets[params->inst - 1];
+
+		/*Toggle it as there is bug in HW */
+		set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
+		dm_write_reg(compressor->ctx, addr, value);
+		set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
+		dm_write_reg(compressor->ctx, addr, value);
+
+		wait_for_fbc_state_changed(cp110, true);
+	}
+}
+
+void dce112_compressor_disable_fbc(struct compressor *compressor)
+{
+	struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
+
+	if (compressor->options.bits.FBC_SUPPORT &&
+		dce112_compressor_is_fbc_enabled_in_hw(compressor, NULL)) {
+		uint32_t reg_data;
+		/* Turn off compression */
+		reg_data = dm_read_reg(compressor->ctx, mmFBC_CNTL);
+		set_reg_field_value(reg_data, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
+		dm_write_reg(compressor->ctx, mmFBC_CNTL, reg_data);
+
+		/* Reset enum controller_id to undefined */
+		compressor->attached_inst = 0;
+		compressor->is_enabled = false;
+
+		/* Whenever disabling FBC make sure LPT is disabled if LPT
+		 * supported */
+		if (compressor->options.bits.LPT_SUPPORT)
+			dce112_compressor_disable_lpt(compressor);
+
+		wait_for_fbc_state_changed(cp110, false);
+	}
+}
+
+bool dce112_compressor_is_fbc_enabled_in_hw(
+	struct compressor *compressor,
+	uint32_t *inst)
+{
+	/* Check the hardware register */
+	uint32_t value;
+
+	value = dm_read_reg(compressor->ctx, mmFBC_STATUS);
+	if (get_reg_field_value(value, FBC_STATUS, FBC_ENABLE_STATUS)) {
+		if (inst != NULL)
+			*inst = compressor->attached_inst;
+		return true;
+	}
+
+	value = dm_read_reg(compressor->ctx, mmFBC_MISC);
+	if (get_reg_field_value(value, FBC_MISC, FBC_STOP_ON_HFLIP_EVENT)) {
+		value = dm_read_reg(compressor->ctx, mmFBC_CNTL);
+
+		if (get_reg_field_value(value, FBC_CNTL, FBC_GRPH_COMP_EN)) {
+			if (inst != NULL)
+				*inst =
+					compressor->attached_inst;
+			return true;
+		}
+	}
+	return false;
+}
+
+bool dce112_compressor_is_lpt_enabled_in_hw(struct compressor *compressor)
+{
+	/* Check the hardware register */
+	uint32_t value = dm_read_reg(compressor->ctx,
+		mmLOW_POWER_TILING_CONTROL);
+
+	return get_reg_field_value(
+		value,
+		LOW_POWER_TILING_CONTROL,
+		LOW_POWER_TILING_ENABLE);
+}
+
+void dce112_compressor_program_compressed_surface_address_and_pitch(
+	struct compressor *compressor,
+	struct compr_addr_and_pitch_params *params)
+{
+	struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
+	uint32_t value = 0;
+	uint32_t fbc_pitch = 0;
+	uint32_t compressed_surf_address_low_part =
+		compressor->compr_surface_address.addr.low_part;
+
+	/* Clear content first. */
+	dm_write_reg(
+		compressor->ctx,
+		DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
+		0);
+	dm_write_reg(compressor->ctx,
+		DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), 0);
+
+	if (compressor->options.bits.LPT_SUPPORT) {
+		uint32_t lpt_alignment = lpt_size_alignment(cp110);
+
+		if (lpt_alignment != 0) {
+			compressed_surf_address_low_part =
+				((compressed_surf_address_low_part
+					+ (lpt_alignment - 1)) / lpt_alignment)
+					* lpt_alignment;
+		}
+	}
+
+	/* Write address, HIGH has to be first. */
+	dm_write_reg(compressor->ctx,
+		DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
+		compressor->compr_surface_address.addr.high_part);
+	dm_write_reg(compressor->ctx,
+		DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS),
+		compressed_surf_address_low_part);
+
+	fbc_pitch = align_to_chunks_number_per_line(
+		cp110,
+		params->source_view_width);
+
+	if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1)
+		fbc_pitch = fbc_pitch / 8;
+	else
+		dal_logger_write(
+			compressor->ctx->logger,
+			LOG_MAJOR_WARNING,
+			LOG_MINOR_COMPONENT_CONTROLLER,
+			"%s: Unexpected DCE11 compression ratio",
+			__func__);
+
+	/* Clear content first. */
+	dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), 0);
+
+	/* Write FBC Pitch. */
+	set_reg_field_value(
+		value,
+		fbc_pitch,
+		GRPH_COMPRESS_PITCH,
+		GRPH_COMPRESS_PITCH);
+	dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), value);
+
+}
+
+void dce112_compressor_disable_lpt(struct compressor *compressor)
+{
+	struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
+	uint32_t value;
+	uint32_t addr;
+	uint32_t inx;
+
+	/* Disable all pipes LPT Stutter */
+	for (inx = 0; inx < 3; inx++) {
+		value =
+			dm_read_reg(
+				compressor->ctx,
+				DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH));
+		set_reg_field_value(
+			value,
+			0,
+			DPG_PIPE_STUTTER_CONTROL_NONLPTCH,
+			STUTTER_ENABLE_NONLPTCH);
+		dm_write_reg(
+			compressor->ctx,
+			DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH),
+			value);
+	}
+	/* Disable Underlay pipe LPT Stutter */
+	addr = mmDPGV0_PIPE_STUTTER_CONTROL_NONLPTCH;
+	value = dm_read_reg(compressor->ctx, addr);
+	set_reg_field_value(
+		value,
+		0,
+		DPGV0_PIPE_STUTTER_CONTROL_NONLPTCH,
+		STUTTER_ENABLE_NONLPTCH);
+	dm_write_reg(compressor->ctx, addr, value);
+
+	/* Disable LPT */
+	addr = mmLOW_POWER_TILING_CONTROL;
+	value = dm_read_reg(compressor->ctx, addr);
+	set_reg_field_value(
+		value,
+		0,
+		LOW_POWER_TILING_CONTROL,
+		LOW_POWER_TILING_ENABLE);
+	dm_write_reg(compressor->ctx, addr, value);
+
+	/* Clear selection of Channel(s) containing Compressed Surface */
+	addr = mmGMCON_LPT_TARGET;
+	value = dm_read_reg(compressor->ctx, addr);
+	set_reg_field_value(
+		value,
+		0xFFFFFFFF,
+		GMCON_LPT_TARGET,
+		STCTRL_LPT_TARGET);
+	dm_write_reg(compressor->ctx, mmGMCON_LPT_TARGET, value);
+}
+
+void dce112_compressor_enable_lpt(struct compressor *compressor)
+{
+	struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
+	uint32_t value;
+	uint32_t addr;
+	uint32_t value_control;
+	uint32_t channels;
+
+	/* Enable LPT Stutter from Display pipe */
+	value = dm_read_reg(compressor->ctx,
+		DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH));
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_STUTTER_CONTROL_NONLPTCH,
+		STUTTER_ENABLE_NONLPTCH);
+	dm_write_reg(compressor->ctx,
+		DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH), value);
+
+	/* Enable Underlay pipe LPT Stutter */
+	addr = mmDPGV0_PIPE_STUTTER_CONTROL_NONLPTCH;
+	value = dm_read_reg(compressor->ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		DPGV0_PIPE_STUTTER_CONTROL_NONLPTCH,
+		STUTTER_ENABLE_NONLPTCH);
+	dm_write_reg(compressor->ctx, addr, value);
+
+	/* Selection of Channel(s) containing Compressed Surface: 0xfffffff
+	 * will disable LPT.
+	 * STCTRL_LPT_TARGETn corresponds to channel n. */
+	addr = mmLOW_POWER_TILING_CONTROL;
+	value_control = dm_read_reg(compressor->ctx, addr);
+	channels = get_reg_field_value(value_control,
+			LOW_POWER_TILING_CONTROL,
+			LOW_POWER_TILING_MODE);
+
+	addr = mmGMCON_LPT_TARGET;
+	value = dm_read_reg(compressor->ctx, addr);
+	set_reg_field_value(
+		value,
+		channels + 1, /* not mentioned in programming guide,
+				but follow DCE8.1 */
+		GMCON_LPT_TARGET,
+		STCTRL_LPT_TARGET);
+	dm_write_reg(compressor->ctx, addr, value);
+
+	/* Enable LPT */
+	addr = mmLOW_POWER_TILING_CONTROL;
+	value = dm_read_reg(compressor->ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		LOW_POWER_TILING_CONTROL,
+		LOW_POWER_TILING_ENABLE);
+	dm_write_reg(compressor->ctx, addr, value);
+}
+
+void dce112_compressor_program_lpt_control(
+	struct compressor *compressor,
+	struct compr_addr_and_pitch_params *params)
+{
+	struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
+	uint32_t rows_per_channel;
+	uint32_t lpt_alignment;
+	uint32_t source_view_width;
+	uint32_t source_view_height;
+	uint32_t lpt_control = 0;
+
+	if (!compressor->options.bits.LPT_SUPPORT)
+		return;
+
+	lpt_control = dm_read_reg(compressor->ctx,
+		mmLOW_POWER_TILING_CONTROL);
+
+	/* POSSIBLE VALUES for Low Power Tiling Mode:
+	 * 00 - Use channel 0
+	 * 01 - Use Channel 0 and 1
+	 * 02 - Use Channel 0,1,2,3
+	 * 03 - reserved */
+	switch (compressor->lpt_channels_num) {
+	/* case 2:
+	 * Use Channel 0 & 1 / Not used for DCE 11 */
+	case 1:
+		/*Use Channel 0 for LPT for DCE 11 */
+		set_reg_field_value(
+			lpt_control,
+			0,
+			LOW_POWER_TILING_CONTROL,
+			LOW_POWER_TILING_MODE);
+		break;
+	default:
+		dal_logger_write(
+			compressor->ctx->logger,
+			LOG_MAJOR_WARNING,
+			LOG_MINOR_COMPONENT_CONTROLLER,
+			"%s: Invalid selected DRAM channels for LPT!!!",
+			__func__);
+		break;
+	}
+
+	lpt_control = lpt_memory_control_config(cp110, lpt_control);
+
+	/* Program LOW_POWER_TILING_ROWS_PER_CHAN field which depends on
+	 * FBC compressed surface pitch.
+	 * LOW_POWER_TILING_ROWS_PER_CHAN = Roundup ((Surface Height *
+	 * Surface Pitch) / (Row Size * Number of Channels *
+	 * Number of Banks)). */
+	rows_per_channel = 0;
+	lpt_alignment = lpt_size_alignment(cp110);
+	source_view_width =
+		align_to_chunks_number_per_line(
+			cp110,
+			params->source_view_width);
+	source_view_height = (params->source_view_height + 1) & (~0x1);
+
+	if (lpt_alignment != 0) {
+		rows_per_channel = source_view_width * source_view_height * 4;
+		rows_per_channel =
+			(rows_per_channel % lpt_alignment) ?
+				(rows_per_channel / lpt_alignment + 1) :
+				rows_per_channel / lpt_alignment;
+	}
+
+	set_reg_field_value(
+		lpt_control,
+		rows_per_channel,
+		LOW_POWER_TILING_CONTROL,
+		LOW_POWER_TILING_ROWS_PER_CHAN);
+
+	dm_write_reg(compressor->ctx,
+		mmLOW_POWER_TILING_CONTROL, lpt_control);
+}
+
+/*
+ * DCE 11 Frame Buffer Compression Implementation
+ */
+
+void dce112_compressor_set_fbc_invalidation_triggers(
+	struct compressor *compressor,
+	uint32_t fbc_trigger)
+{
+	/* Disable region hit event, FBC_MEMORY_REGION_MASK = 0 (bits 16-19)
+	 * for DCE 11 regions cannot be used - does not work with S/G
+	 */
+	uint32_t addr = mmFBC_CLIENT_REGION_MASK;
+	uint32_t value = dm_read_reg(compressor->ctx, addr);
+
+	set_reg_field_value(
+		value,
+		0,
+		FBC_CLIENT_REGION_MASK,
+		FBC_MEMORY_REGION_MASK);
+	dm_write_reg(compressor->ctx, addr, value);
+
+	/* Setup events when to clear all CSM entries (effectively marking
+	 * current compressed data invalid)
+	 * For DCE 11 CSM metadata 11111 means - "Not Compressed"
+	 * Used as the initial value of the metadata sent to the compressor
+	 * after invalidation, to indicate that the compressor should attempt
+	 * to compress all chunks on the current pass.  Also used when the chunk
+	 * is not successfully written to memory.
+	 * When this CSM value is detected, FBC reads from the uncompressed
+	 * buffer. Set events according to passed in value, these events are
+	 * valid for DCE11:
+	 *     - bit  0 - display register updated
+	 *     - bit 28 - memory write from any client except from MCIF
+	 *     - bit 29 - CG static screen signal is inactive
+	 * In addition, DCE11.1 also needs to set new DCE11.1 specific events
+	 * that are used to trigger invalidation on certain register changes,
+	 * for example enabling of Alpha Compression may trigger invalidation of
+	 * FBC once bit is set. These events are as follows:
+	 *      - Bit 2 - FBC_GRPH_COMP_EN register updated
+	 *      - Bit 3 - FBC_SRC_SEL register updated
+	 *      - Bit 4 - FBC_MIN_COMPRESSION register updated
+	 *      - Bit 5 - FBC_ALPHA_COMP_EN register updated
+	 *      - Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated
+	 *      - Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated
+	 */
+	addr = mmFBC_IDLE_FORCE_CLEAR_MASK;
+	value = dm_read_reg(compressor->ctx, addr);
+	set_reg_field_value(
+		value,
+		fbc_trigger |
+		FBC_IDLE_FORCE_GRPH_COMP_EN |
+		FBC_IDLE_FORCE_SRC_SEL_CHANGE |
+		FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE |
+		FBC_IDLE_FORCE_ALPHA_COMP_EN |
+		FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN |
+		FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF,
+		FBC_IDLE_FORCE_CLEAR_MASK,
+		FBC_IDLE_FORCE_CLEAR_MASK);
+	dm_write_reg(compressor->ctx, addr, value);
+}
+
+bool dce112_compressor_construct(struct dce112_compressor *compressor,
+	struct dc_context *ctx, struct adapter_service *as)
+{
+	struct embedded_panel_info panel_info;
+
+	compressor->base.options.bits.FBC_SUPPORT = true;
+	if (!(dal_adapter_service_is_feature_supported(
+		FEATURE_DISABLE_LPT_SUPPORT)))
+		compressor->base.options.bits.LPT_SUPPORT = true;
+	 /* For DCE 11 always use one DRAM channel for LPT */
+	compressor->base.lpt_channels_num = 1;
+
+	if (dal_adapter_service_is_feature_supported(FEATURE_DUMMY_FBC_BACKEND))
+		compressor->base.options.bits.DUMMY_BACKEND = true;
+
+	/* Check if this system has more than 1 DRAM channel; if only 1 then LPT
+	 * should not be supported */
+	if (compressor->base.memory_bus_width == 64)
+		compressor->base.options.bits.LPT_SUPPORT = false;
+
+	if (dal_adapter_service_is_feature_supported(
+		FEATURE_DISABLE_FBC_COMP_CLK_GATE))
+		compressor->base.options.bits.CLK_GATING_DISABLED = true;
+
+	compressor->base.ctx = ctx;
+	compressor->base.embedded_panel_h_size = 0;
+	compressor->base.embedded_panel_v_size = 0;
+	compressor->base.memory_bus_width =
+		dal_adapter_service_get_asic_vram_bit_width(as);
+	compressor->base.allocated_size = 0;
+	compressor->base.preferred_requested_size = 0;
+	compressor->base.min_compress_ratio = FBC_COMPRESS_RATIO_INVALID;
+	compressor->base.options.raw = 0;
+	compressor->base.banks_num = 0;
+	compressor->base.raw_size = 0;
+	compressor->base.channel_interleave_size = 0;
+	compressor->base.dram_channels_num = 0;
+	compressor->base.lpt_channels_num = 0;
+	compressor->base.attached_inst = 0;
+	compressor->base.is_enabled = false;
+
+	if (dal_adapter_service_get_embedded_panel_info(as,
+		&panel_info)) {
+		compressor->base.embedded_panel_h_size =
+			panel_info.lcd_timing.horizontal_addressable;
+		compressor->base.embedded_panel_v_size =
+			panel_info.lcd_timing.vertical_addressable;
+	}
+	return true;
+}
+
+struct compressor *dce112_compressor_create(struct dc_context *ctx,
+	struct adapter_service *as)
+{
+	struct dce112_compressor *cp110 =
+		dm_alloc(sizeof(struct dce112_compressor));
+
+	if (!cp110)
+		return NULL;
+
+	if (dce112_compressor_construct(cp110, ctx, as))
+		return &cp110->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(cp110);
+	return NULL;
+}
+
+void dce112_compressor_destroy(struct compressor **compressor)
+{
+	dm_free(TO_DCE112_COMPRESSOR(*compressor));
+	*compressor = NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.h
new file mode 100644
index 0000000..bcf44802
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.h
@@ -0,0 +1,84 @@
+/* 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_COMPRESSOR_DCE112_H__
+#define __DC_COMPRESSOR_DCE112_H__
+
+#include "../inc/compressor.h"
+
+#define TO_DCE112_COMPRESSOR(compressor)\
+	container_of(compressor, struct dce112_compressor, base)
+
+struct dce112_compressor_reg_offsets {
+	uint32_t dcp_offset;
+	uint32_t dmif_offset;
+};
+
+struct dce112_compressor {
+	struct compressor base;
+	struct dce112_compressor_reg_offsets offsets;
+};
+
+struct compressor *dce112_compressor_create(struct dc_context *ctx,
+	struct adapter_service *as);
+
+bool dce112_compressor_construct(struct dce112_compressor *cp110,
+	struct dc_context *ctx, struct adapter_service *as);
+
+void dce112_compressor_destroy(struct compressor **cp);
+
+/* FBC RELATED */
+void dce112_compressor_power_up_fbc(struct compressor *cp);
+
+void dce112_compressor_enable_fbc(struct compressor *cp, uint32_t paths_num,
+	struct compr_addr_and_pitch_params *params);
+
+void dce112_compressor_disable_fbc(struct compressor *cp);
+
+void dce112_compressor_set_fbc_invalidation_triggers(struct compressor *cp,
+	uint32_t fbc_trigger);
+
+void dce112_compressor_program_compressed_surface_address_and_pitch(
+	struct compressor *cp,
+	struct compr_addr_and_pitch_params *params);
+
+bool dce112_compressor_get_required_compressed_surface_size(
+	struct compressor *cp,
+	struct fbc_input_info *input_info,
+	struct fbc_requested_compressed_size *size);
+
+bool dce112_compressor_is_fbc_enabled_in_hw(struct compressor *cp,
+	uint32_t *fbc_mapped_crtc_id);
+
+/* LPT RELATED */
+void dce112_compressor_enable_lpt(struct compressor *cp);
+
+void dce112_compressor_disable_lpt(struct compressor *cp);
+
+void dce112_compressor_program_lpt_control(struct compressor *cp,
+	struct compr_addr_and_pitch_params *params);
+
+bool dce112_compressor_is_lpt_enabled_in_hw(struct compressor *cp);
+
+#endif
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.c
new file mode 100644
index 0000000..b94130f
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2015 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.h"
+#include "core_dc.h"
+#include "core_types.h"
+#include "dce112_hw_sequencer.h"
+
+#include "dce110/dce110_hw_sequencer.h"
+#include "gpu/dce112/dc_clock_gating_dce112.h"
+
+/* include DCE11.2 register header files */
+#include "dce/dce_11_2_d.h"
+#include "dce/dce_11_2_sh_mask.h"
+
+static void dce112_crtc_switch_to_clk_src(
+				struct clock_source *clk_src, uint8_t crtc_inst)
+{
+	uint32_t pixel_rate_cntl_value;
+	uint32_t addr;
+
+	addr = mmCRTC0_PIXEL_RATE_CNTL + crtc_inst *
+			(mmCRTC1_PIXEL_RATE_CNTL - mmCRTC0_PIXEL_RATE_CNTL);
+
+	pixel_rate_cntl_value = dm_read_reg(clk_src->ctx, addr);
+
+	if (clk_src->id == CLOCK_SOURCE_ID_DP_DTO)
+		set_reg_field_value(pixel_rate_cntl_value, 1,
+			CRTC0_PIXEL_RATE_CNTL, DP_DTO0_ENABLE);
+	else {
+		set_reg_field_value(pixel_rate_cntl_value,
+				0,
+				CRTC0_PIXEL_RATE_CNTL,
+				DP_DTO0_ENABLE);
+
+		set_reg_field_value(pixel_rate_cntl_value,
+				clk_src->id - 1,
+				CRTC0_PIXEL_RATE_CNTL,
+				CRTC0_PIXEL_RATE_SOURCE);
+	}
+	dm_write_reg(clk_src->ctx, addr, pixel_rate_cntl_value);
+}
+
+static void dce112_init_pte(struct dc_context *ctx)
+{
+	uint32_t addr;
+	uint32_t value = 0;
+	uint32_t chunk_int = 0;
+	uint32_t chunk_mul = 0;
+
+	addr = mmUNP_DVMM_PTE_CONTROL;
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(
+		value,
+		0,
+		DVMM_PTE_CONTROL,
+		DVMM_USE_SINGLE_PTE);
+
+	set_reg_field_value(
+		value,
+		1,
+		DVMM_PTE_CONTROL,
+		DVMM_PTE_BUFFER_MODE0);
+
+	set_reg_field_value(
+		value,
+		1,
+		DVMM_PTE_CONTROL,
+		DVMM_PTE_BUFFER_MODE1);
+
+	dm_write_reg(ctx, addr, value);
+
+	addr = mmDVMM_PTE_REQ;
+	value = dm_read_reg(ctx, addr);
+
+	chunk_int = get_reg_field_value(
+		value,
+		DVMM_PTE_REQ,
+		HFLIP_PTEREQ_PER_CHUNK_INT);
+
+	chunk_mul = get_reg_field_value(
+		value,
+		DVMM_PTE_REQ,
+		HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
+
+	if (chunk_int != 0x4 || chunk_mul != 0x4) {
+
+		set_reg_field_value(
+			value,
+			255,
+			DVMM_PTE_REQ,
+			MAX_PTEREQ_TO_ISSUE);
+
+		set_reg_field_value(
+			value,
+			4,
+			DVMM_PTE_REQ,
+			HFLIP_PTEREQ_PER_CHUNK_INT);
+
+		set_reg_field_value(
+			value,
+			4,
+			DVMM_PTE_REQ,
+			HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
+
+		dm_write_reg(ctx, addr, value);
+	}
+}
+
+static bool dce112_enable_display_power_gating(
+	struct dc_context *ctx,
+	uint8_t controller_id,
+	struct dc_bios *dcb,
+	enum pipe_gating_control power_gating)
+{
+	enum bp_result bp_result = BP_RESULT_OK;
+	enum bp_pipe_control_action cntl;
+
+	if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
+		return true;
+
+	if (power_gating == PIPE_GATING_CONTROL_INIT)
+		cntl = ASIC_PIPE_INIT;
+	else if (power_gating == PIPE_GATING_CONTROL_ENABLE)
+		cntl = ASIC_PIPE_ENABLE;
+	else
+		cntl = ASIC_PIPE_DISABLE;
+
+	if (power_gating != PIPE_GATING_CONTROL_INIT || controller_id == 0)
+		bp_result = dcb->funcs->enable_disp_power_gating(
+						dcb, controller_id + 1, cntl);
+
+	if (power_gating != PIPE_GATING_CONTROL_ENABLE)
+		dce112_init_pte(ctx);
+
+	if (bp_result == BP_RESULT_OK)
+		return true;
+	else
+		return false;
+}
+
+bool dce112_hw_sequencer_construct(struct core_dc *dc)
+{
+	/* All registers used by dce11.2 match those in dce11 in offset and
+	 * structure
+	 */
+	dce110_hw_sequencer_construct(dc);
+	dc->hwss.crtc_switch_to_clk_src = dce112_crtc_switch_to_clk_src;
+	dc->hwss.enable_display_power_gating = dce112_enable_display_power_gating;
+	dc->hwss.clock_gating_power_up = dal_dc_clock_gating_dce112_power_up;
+
+	return true;
+}
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.h
new file mode 100644
index 0000000..d96c582
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.h
@@ -0,0 +1,36 @@
+/*
+* 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_HWSS_DCE112_H__
+#define __DC_HWSS_DCE112_H__
+
+#include "core_types.h"
+
+struct core_dc;
+
+bool dce112_hw_sequencer_construct(struct core_dc *dc);
+
+#endif /* __DC_HWSS_DCE112_H__ */
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.c
new file mode 100644
index 0000000..23e127c
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.c
@@ -0,0 +1,116 @@
+/*
+ * 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 "dce112_link_encoder.h"
+#include "../dce110/dce110_link_encoder.h"
+#include "i2caux_interface.h"
+#include "dce/dce_11_2_sh_mask.h"
+
+/* 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
+
+/* 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
+};
+
+static void dce112_link_encoder_dp_set_phy_pattern(
+	struct link_encoder *enc,
+	const struct encoder_set_dp_phy_pattern_param *param)
+{
+	switch (param->dp_phy_pattern) {
+	case DP_TEST_PATTERN_TRAINING_PATTERN4:
+		dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 3);
+		break;
+	default:
+		dce110_link_encoder_dp_set_phy_pattern(enc, param);
+		break;
+	}
+}
+
+static struct link_encoder_funcs dce112_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 = dce112_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,
+	.destroy = dce110_link_encoder_destroy
+};
+
+bool dce112_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)
+{
+	dce110_link_encoder_construct(
+		enc110,
+		init_data,
+		link_regs,
+		aux_regs,
+		bl_regs);
+
+	enc110->base.funcs = &dce112_lnk_enc_funcs;
+
+	enc110->base.features.flags.bits.IS_HBR3_CAPABLE = true;
+
+	enc110->base.features.flags.bits.IS_TPS4_CAPABLE = true;
+
+	return true;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.h
new file mode 100644
index 0000000..cfc9cc5
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.h
@@ -0,0 +1,41 @@
+/*
+ * 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__DCE112_H__
+#define __DC_LINK_ENCODER__DCE112_H__
+
+#include "link_encoder.h"
+#include "../dce110/dce110_link_encoder.h"
+
+bool dce112_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);
+
+/****************** HW programming ************************/
+
+#endif /* __DC_LINK_ENCODER__DCE112_H__ */
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.c
new file mode 100644
index 0000000..823849e
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.c
@@ -0,0 +1,455 @@
+/*
+ * 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 "dce112_mem_input.h"
+
+
+#include "dce/dce_11_2_d.h"
+#include "dce/dce_11_2_sh_mask.h"
+
+
+#define DCP_REG(reg) (reg + mem_input110->offsets.dcp)
+#define DMIF_REG(reg) (reg + mem_input110->offsets.dmif)
+#define PIPE_REG(reg) (reg + mem_input110->offsets.pipe)
+
+static void program_urgency_watermark(
+	const struct dc_context *ctx,
+	const uint32_t offset,
+	struct bw_watermarks marks_low,
+	uint32_t total_dest_line_time_ns)
+{
+	/* register value */
+	uint32_t urgency_cntl = 0;
+	uint32_t wm_mask_cntl = 0;
+
+	uint32_t urgency_addr = offset + mmDPG_PIPE_URGENCY_CONTROL;
+	uint32_t wm_addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+
+	/*Write mask to enable reading/writing of watermark set A*/
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+			0,
+			DPG_WATERMARK_MASK_CONTROL,
+			URGENCY_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	urgency_cntl = dm_read_reg(ctx, urgency_addr);
+
+	set_reg_field_value(
+		urgency_cntl,
+		marks_low.a_mark,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_LOW_WATERMARK);
+
+	set_reg_field_value(
+		urgency_cntl,
+		total_dest_line_time_ns,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_HIGH_WATERMARK);
+	dm_write_reg(ctx, urgency_addr, urgency_cntl);
+
+	/*Write mask to enable reading/writing of watermark set B*/
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+			1,
+			DPG_WATERMARK_MASK_CONTROL,
+			URGENCY_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	urgency_cntl = dm_read_reg(ctx, urgency_addr);
+
+	set_reg_field_value(urgency_cntl,
+		marks_low.b_mark,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_LOW_WATERMARK);
+
+	set_reg_field_value(urgency_cntl,
+		total_dest_line_time_ns,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_HIGH_WATERMARK);
+	dm_write_reg(ctx, urgency_addr, urgency_cntl);
+
+	/*Write mask to enable reading/writing of watermark set C*/
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+			2,
+			DPG_WATERMARK_MASK_CONTROL,
+			URGENCY_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	urgency_cntl = dm_read_reg(ctx, urgency_addr);
+
+	set_reg_field_value(urgency_cntl,
+		marks_low.c_mark,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_LOW_WATERMARK);
+
+	set_reg_field_value(urgency_cntl,
+		total_dest_line_time_ns,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_HIGH_WATERMARK);
+	dm_write_reg(ctx, urgency_addr, urgency_cntl);
+
+	/*Write mask to enable reading/writing of watermark set D*/
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+			3,
+			DPG_WATERMARK_MASK_CONTROL,
+			URGENCY_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	urgency_cntl = dm_read_reg(ctx, urgency_addr);
+
+	set_reg_field_value(urgency_cntl,
+		marks_low.d_mark,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_LOW_WATERMARK);
+
+	set_reg_field_value(urgency_cntl,
+		total_dest_line_time_ns,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_HIGH_WATERMARK);
+	dm_write_reg(ctx, urgency_addr, urgency_cntl);
+}
+
+static void program_stutter_watermark(
+	const struct dc_context *ctx,
+	const uint32_t offset,
+	struct bw_watermarks marks)
+{
+	/* register value */
+	uint32_t stutter_cntl = 0;
+	uint32_t wm_mask_cntl = 0;
+
+	uint32_t stutter_addr = offset + mmDPG_PIPE_STUTTER_CONTROL;
+	uint32_t wm_addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+
+	/*Write mask to enable reading/writing of watermark set A*/
+
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+		0,
+		DPG_WATERMARK_MASK_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	stutter_cntl = dm_read_reg(ctx, stutter_addr);
+
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_ENABLE);
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_IGNORE_FBC);
+
+	/*Write watermark set A*/
+	set_reg_field_value(stutter_cntl,
+		marks.a_mark,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK);
+	dm_write_reg(ctx, stutter_addr, stutter_cntl);
+
+	/*Write mask to enable reading/writing of watermark set B*/
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+		1,
+		DPG_WATERMARK_MASK_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	stutter_cntl = dm_read_reg(ctx, stutter_addr);
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_ENABLE);
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_IGNORE_FBC);
+
+	/*Write watermark set B*/
+	set_reg_field_value(stutter_cntl,
+		marks.b_mark,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK);
+	dm_write_reg(ctx, stutter_addr, stutter_cntl);
+
+	/*Write mask to enable reading/writing of watermark set C*/
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+		2,
+		DPG_WATERMARK_MASK_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	stutter_cntl = dm_read_reg(ctx, stutter_addr);
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_ENABLE);
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_IGNORE_FBC);
+
+	/*Write watermark set C*/
+	set_reg_field_value(stutter_cntl,
+		marks.c_mark,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK);
+	dm_write_reg(ctx, stutter_addr, stutter_cntl);
+
+	/*Write mask to enable reading/writing of watermark set D*/
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+		3,
+		DPG_WATERMARK_MASK_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	stutter_cntl = dm_read_reg(ctx, stutter_addr);
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_ENABLE);
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_IGNORE_FBC);
+
+	/*Write watermark set D*/
+	set_reg_field_value(stutter_cntl,
+		marks.d_mark,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK);
+	dm_write_reg(ctx, stutter_addr, stutter_cntl);
+}
+
+static void program_nbp_watermark(
+	const struct dc_context *ctx,
+	const uint32_t offset,
+	struct bw_watermarks marks)
+{
+	uint32_t value;
+	uint32_t addr;
+	/* Write mask to enable reading/writing of watermark set A */
+	addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		0,
+		DPG_WATERMARK_MASK_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK_MASK);
+	dm_write_reg(ctx, addr, value);
+
+	addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_ENABLE);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
+	dm_write_reg(ctx, addr, value);
+
+	/* Write watermark set A */
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		marks.a_mark,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK);
+	dm_write_reg(ctx, addr, value);
+
+	/* Write mask to enable reading/writing of watermark set B */
+	addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_WATERMARK_MASK_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK_MASK);
+	dm_write_reg(ctx, addr, value);
+
+	addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_ENABLE);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
+	dm_write_reg(ctx, addr, value);
+
+	/* Write watermark set B */
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		marks.b_mark,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK);
+	dm_write_reg(ctx, addr, value);
+
+	/* Write mask to enable reading/writing of watermark set C */
+	addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		2,
+		DPG_WATERMARK_MASK_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK_MASK);
+	dm_write_reg(ctx, addr, value);
+
+	addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_ENABLE);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
+	dm_write_reg(ctx, addr, value);
+
+	/* Write watermark set C */
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		marks.c_mark,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK);
+	dm_write_reg(ctx, addr, value);
+
+	/* Write mask to enable reading/writing of watermark set D */
+	addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		3,
+		DPG_WATERMARK_MASK_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK_MASK);
+	dm_write_reg(ctx, addr, value);
+
+	addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_ENABLE);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
+	dm_write_reg(ctx, addr, value);
+
+	/* Write watermark set D */
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		marks.d_mark,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK);
+	dm_write_reg(ctx, addr, value);
+}
+
+static void dce112_mem_input_program_display_marks(
+	struct mem_input *mem_input,
+	struct bw_watermarks nbp,
+	struct bw_watermarks stutter,
+	struct bw_watermarks urgent,
+	uint32_t total_dest_line_time_ns)
+{
+	struct dce110_mem_input *bm_dce110 = TO_DCE110_MEM_INPUT(mem_input);
+
+	program_urgency_watermark(
+		mem_input->ctx,
+		bm_dce110->offsets.dmif,
+		urgent,
+		total_dest_line_time_ns);
+
+	program_nbp_watermark(
+		mem_input->ctx,
+		bm_dce110->offsets.dmif,
+		nbp);
+
+	program_stutter_watermark(
+		mem_input->ctx,
+		bm_dce110->offsets.dmif,
+		stutter);
+}
+
+/*****************************************/
+/* Constructor, Destructor               */
+/*****************************************/
+
+bool dce112_mem_input_construct(
+	struct dce110_mem_input *mem_input110,
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_mem_input_reg_offsets *offsets)
+{
+	if (!dce110_mem_input_construct(mem_input110, ctx, inst, offsets))
+		return false;
+
+	mem_input110->base.funcs->mem_input_program_display_marks =
+					dce112_mem_input_program_display_marks;
+
+	return true;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.h
new file mode 100644
index 0000000..de2aaf0
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.h
@@ -0,0 +1,38 @@
+/* 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_MEM_INPUT_DCE112_H__
+#define __DC_MEM_INPUT_DCE112_H__
+
+#include "mem_input.h"
+#include "dce110/dce110_mem_input.h"
+
+bool dce112_mem_input_construct(
+	struct dce110_mem_input *mem_input110,
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_mem_input_reg_offsets *offsets);
+
+
+#endif
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.c
new file mode 100644
index 0000000..420b8ca
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.c
@@ -0,0 +1,1404 @@
+/*
+* 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 "link_encoder.h"
+#include "stream_encoder.h"
+
+#include "resource.h"
+#include "include/irq_service_interface.h"
+#include "../virtual/virtual_stream_encoder.h"
+#include "dce110/dce110_resource.h"
+#include "dce110/dce110_timing_generator.h"
+#include "dce112/dce112_mem_input.h"
+#include "dce112/dce112_link_encoder.h"
+#include "dce110/dce110_link_encoder.h"
+#include "dce110/dce110_transform.h"
+#include "dce110/dce110_stream_encoder.h"
+#include "dce110/dce110_opp.h"
+#include "dce110/dce110_ipp.h"
+#include "dce112/dce112_clock_source.h"
+
+#include "dce/dce_11_2_d.h"
+
+#ifndef mmDP_DPHY_INTERNAL_CTRL
+	#define mmDP_DPHY_INTERNAL_CTRL 0x4aa7
+	#define mmDP0_DP_DPHY_INTERNAL_CTRL 0x4aa7
+	#define mmDP1_DP_DPHY_INTERNAL_CTRL 0x4ba7
+	#define mmDP2_DP_DPHY_INTERNAL_CTRL 0x4ca7
+	#define mmDP3_DP_DPHY_INTERNAL_CTRL 0x4da7
+	#define mmDP4_DP_DPHY_INTERNAL_CTRL 0x4ea7
+	#define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4fa7
+	#define mmDP6_DP_DPHY_INTERNAL_CTRL 0x54a7
+	#define mmDP7_DP_DPHY_INTERNAL_CTRL 0x56a7
+	#define mmDP8_DP_DPHY_INTERNAL_CTRL 0x57a7
+#endif
+
+enum dce112_clk_src_array_id {
+	DCE112_CLK_SRC_PLL0,
+	DCE112_CLK_SRC_PLL1,
+	DCE112_CLK_SRC_PLL2,
+	DCE112_CLK_SRC_PLL3,
+	DCE112_CLK_SRC_PLL4,
+	DCE112_CLK_SRC_PLL5,
+
+	DCE112_CLK_SRC_TOTAL
+};
+
+static const struct dce110_transform_reg_offsets dce112_xfm_offsets[] = {
+{
+	.scl_offset = (mmSCL0_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmDCFE0_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB0_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+},
+{	.scl_offset = (mmSCL1_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmDCFE1_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB1_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+},
+{	.scl_offset = (mmSCL2_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmDCFE2_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB2_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+},
+{
+	.scl_offset = (mmSCL3_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmDCFE3_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB3_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+},
+{	.scl_offset = (mmSCL4_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmDCFE4_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB4_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+},
+{	.scl_offset = (mmSCL5_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmDCFE5_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB5_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+}
+};
+
+static const struct dce110_timing_generator_offsets dce112_tg_offsets[] = {
+	{
+		.crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp =  (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL),
+	}
+};
+
+static const struct dce110_mem_input_reg_offsets dce112_mi_reg_offsets[] = {
+	{
+		.dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE0_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG1_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE1_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG2_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE2_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG3_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE3_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG4_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE4_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG5_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE5_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	}
+};
+
+static const struct dce110_ipp_reg_offsets ipp_reg_offsets[] = {
+{
+	.dcp_offset = (mmDCP0_CUR_CONTROL - mmCUR_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP1_CUR_CONTROL - mmCUR_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP2_CUR_CONTROL - mmCUR_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP3_CUR_CONTROL - mmCUR_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP4_CUR_CONTROL - mmCUR_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP5_CUR_CONTROL - mmCUR_CONTROL),
+}
+};
+
+static const struct dce110_link_enc_bl_registers link_enc_bl_regs = {
+		.BL_PWM_CNTL = mmBL_PWM_CNTL,
+		.BL_PWM_GRP1_REG_LOCK = mmBL_PWM_GRP1_REG_LOCK,
+		.BL_PWM_PERIOD_CNTL = mmBL_PWM_PERIOD_CNTL,
+		.LVTMA_PWRSEQ_CNTL = mmLVTMA_PWRSEQ_CNTL,
+		.LVTMA_PWRSEQ_STATE = mmLVTMA_PWRSEQ_STATE
+};
+
+#define aux_regs(id)\
+[id] = {\
+	.AUX_CONTROL = mmDP_AUX ## id ## _AUX_CONTROL,\
+	.AUX_DPHY_RX_CONTROL0 = mmDP_AUX ## id ## _AUX_DPHY_RX_CONTROL0\
+}
+
+static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = {
+	aux_regs(0),
+	aux_regs(1),
+	aux_regs(2),
+	aux_regs(3),
+	aux_regs(4),
+	aux_regs(5)
+};
+
+#define link_regs(id)\
+[id] = {\
+	.DIG_BE_CNTL = mmDIG ## id ## _DIG_BE_CNTL,\
+	.DIG_BE_EN_CNTL = mmDIG ## id ## _DIG_BE_EN_CNTL,\
+	.DP_CONFIG = mmDP ## id ## _DP_CONFIG,\
+	.DP_DPHY_CNTL = mmDP ## id ## _DP_DPHY_CNTL,\
+	.DP_DPHY_INTERNAL_CTRL = mmDP ## id ## _DP_DPHY_INTERNAL_CTRL,\
+	.DP_DPHY_PRBS_CNTL = mmDP ## id ## _DP_DPHY_PRBS_CNTL,\
+	.DP_DPHY_SYM0 = mmDP ## id ## _DP_DPHY_SYM0,\
+	.DP_DPHY_SYM1 = mmDP ## id ## _DP_DPHY_SYM1,\
+	.DP_DPHY_SYM2 = mmDP ## id ## _DP_DPHY_SYM2,\
+	.DP_DPHY_TRAINING_PATTERN_SEL = mmDP ## id ## _DP_DPHY_TRAINING_PATTERN_SEL,\
+	.DP_LINK_CNTL = mmDP ## id ## _DP_LINK_CNTL,\
+	.DP_LINK_FRAMING_CNTL = mmDP ## id ## _DP_LINK_FRAMING_CNTL,\
+	.DP_MSE_SAT0 = mmDP ## id ## _DP_MSE_SAT0,\
+	.DP_MSE_SAT1 = mmDP ## id ## _DP_MSE_SAT1,\
+	.DP_MSE_SAT2 = mmDP ## id ## _DP_MSE_SAT2,\
+	.DP_MSE_SAT_UPDATE = mmDP ## id ## _DP_MSE_SAT_UPDATE,\
+	.DP_SEC_CNTL = mmDP ## id ## _DP_SEC_CNTL,\
+	.DP_VID_STREAM_CNTL = mmDP ## id ## _DP_VID_STREAM_CNTL\
+}
+
+static const struct dce110_link_enc_registers link_enc_regs[] = {
+	link_regs(0),
+	link_regs(1),
+	link_regs(2),
+	link_regs(3),
+	link_regs(4),
+	link_regs(5)
+};
+
+#define stream_enc_regs(id)\
+[id] = {\
+	.AFMT_AVI_INFO0 = mmDIG ## id ## _AFMT_AVI_INFO0,\
+	.AFMT_AVI_INFO1 = mmDIG ## id ## _AFMT_AVI_INFO1,\
+	.AFMT_AVI_INFO2 = mmDIG ## id ## _AFMT_AVI_INFO2,\
+	.AFMT_AVI_INFO3 = mmDIG ## id ## _AFMT_AVI_INFO3,\
+	.AFMT_GENERIC_0 = mmDIG ## id ## _AFMT_GENERIC_0,\
+	.AFMT_GENERIC_7 = mmDIG ## id ## _AFMT_GENERIC_7,\
+	.AFMT_GENERIC_HDR = mmDIG ## id ## _AFMT_GENERIC_HDR,\
+	.AFMT_INFOFRAME_CONTROL0 = mmDIG ## id ## _AFMT_INFOFRAME_CONTROL0,\
+	.AFMT_VBI_PACKET_CONTROL = mmDIG ## id ## _AFMT_VBI_PACKET_CONTROL,\
+	.DIG_FE_CNTL = mmDIG ## id ## _DIG_FE_CNTL,\
+	.DP_MSE_RATE_CNTL = mmDP ## id ## _DP_MSE_RATE_CNTL,\
+	.DP_MSE_RATE_UPDATE = mmDP ## id ## _DP_MSE_RATE_UPDATE,\
+	.DP_PIXEL_FORMAT = mmDP ## id ## _DP_PIXEL_FORMAT,\
+	.DP_SEC_CNTL = mmDP ## id ## _DP_SEC_CNTL,\
+	.DP_STEER_FIFO = mmDP ## id ## _DP_STEER_FIFO,\
+	.DP_VID_M = mmDP ## id ## _DP_VID_M,\
+	.DP_VID_N = mmDP ## id ## _DP_VID_N,\
+	.DP_VID_STREAM_CNTL = mmDP ## id ## _DP_VID_STREAM_CNTL,\
+	.DP_VID_TIMING = mmDP ## id ## _DP_VID_TIMING,\
+	.HDMI_CONTROL = mmDIG ## id ## _HDMI_CONTROL,\
+	.HDMI_GC = mmDIG ## id ## _HDMI_GC,\
+	.HDMI_GENERIC_PACKET_CONTROL0 = mmDIG ## id ## _HDMI_GENERIC_PACKET_CONTROL0,\
+	.HDMI_GENERIC_PACKET_CONTROL1 = mmDIG ## id ## _HDMI_GENERIC_PACKET_CONTROL1,\
+	.HDMI_INFOFRAME_CONTROL0 = mmDIG ## id ## _HDMI_INFOFRAME_CONTROL0,\
+	.HDMI_INFOFRAME_CONTROL1 = mmDIG ## id ## _HDMI_INFOFRAME_CONTROL1,\
+	.HDMI_VBI_PACKET_CONTROL = mmDIG ## id ## _HDMI_VBI_PACKET_CONTROL,\
+	.TMDS_CNTL = mmDIG ## id ## _TMDS_CNTL\
+}
+
+static const struct dce110_stream_enc_registers stream_enc_regs[] = {
+	stream_enc_regs(0),
+	stream_enc_regs(1),
+	stream_enc_regs(2),
+	stream_enc_regs(3),
+	stream_enc_regs(4),
+	stream_enc_regs(5)
+};
+
+static const struct dce110_opp_reg_offsets dce112_opp_reg_offsets[] = {
+{
+	.fmt_offset = (mmFMT0_FMT_CONTROL - mmFMT0_FMT_CONTROL),
+	.dcfe_offset = (mmDCFE0_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+},
+{	.fmt_offset = (mmFMT1_FMT_CONTROL - mmFMT0_FMT_CONTROL),
+	.dcfe_offset = (mmDCFE1_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+},
+{	.fmt_offset = (mmFMT2_FMT_CONTROL - mmFMT0_FMT_CONTROL),
+	.dcfe_offset = (mmDCFE2_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+},
+{
+	.fmt_offset = (mmFMT3_FMT_CONTROL - mmFMT0_FMT_CONTROL),
+	.dcfe_offset = (mmDCFE3_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP3_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+},
+{	.fmt_offset = (mmFMT4_FMT_CONTROL - mmFMT0_FMT_CONTROL),
+	.dcfe_offset = (mmDCFE4_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP4_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+},
+{	.fmt_offset = (mmFMT5_FMT_CONTROL - mmFMT0_FMT_CONTROL),
+	.dcfe_offset = (mmDCFE5_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP5_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+}
+};
+
+static const struct dce112_clk_src_reg_offsets dce112_clk_src_reg_offsets[] = {
+	{
+		.pixclk_resync_cntl  = mmPHYPLLA_PIXCLK_RESYNC_CNTL
+	},
+	{
+		.pixclk_resync_cntl  = mmPHYPLLB_PIXCLK_RESYNC_CNTL
+	},
+	{
+		.pixclk_resync_cntl  = mmPHYPLLC_PIXCLK_RESYNC_CNTL
+	},
+	{
+		.pixclk_resync_cntl  = mmPHYPLLD_PIXCLK_RESYNC_CNTL
+	},
+	{
+		.pixclk_resync_cntl  = mmPHYPLLE_PIXCLK_RESYNC_CNTL
+	},
+	{
+		.pixclk_resync_cntl  = mmPHYPLLF_PIXCLK_RESYNC_CNTL
+	}
+};
+
+static struct timing_generator *dce112_timing_generator_create(
+		struct adapter_service *as,
+		struct dc_context *ctx,
+		uint32_t instance,
+		const struct dce110_timing_generator_offsets *offsets)
+{
+	struct dce110_timing_generator *tg110 =
+		dm_alloc(sizeof(struct dce110_timing_generator));
+
+	if (!tg110)
+		return NULL;
+
+	if (dce110_timing_generator_construct(tg110, as, ctx, instance, offsets))
+		return &tg110->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(tg110);
+	return NULL;
+}
+
+static struct stream_encoder *dce112_stream_encoder_create(
+	enum engine_id eng_id,
+	struct dc_context *ctx,
+	struct dc_bios *bp,
+	const struct dce110_stream_enc_registers *regs)
+{
+	struct dce110_stream_encoder *enc110 =
+		dm_alloc(sizeof(struct dce110_stream_encoder));
+
+	if (!enc110)
+		return NULL;
+
+	if (dce110_stream_encoder_construct(enc110, ctx, bp, eng_id, regs))
+		return &enc110->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(enc110);
+	return NULL;
+}
+
+static struct mem_input *dce112_mem_input_create(
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_mem_input_reg_offsets *offset)
+{
+	struct dce110_mem_input *mem_input110 =
+		dm_alloc(sizeof(struct dce110_mem_input));
+
+	if (!mem_input110)
+		return NULL;
+
+	if (dce112_mem_input_construct(mem_input110,
+			ctx, inst, offset))
+		return &mem_input110->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(mem_input110);
+	return NULL;
+}
+
+static void dce112_transform_destroy(struct transform **xfm)
+{
+	dm_free(TO_DCE110_TRANSFORM(*xfm));
+	*xfm = NULL;
+}
+
+static struct transform *dce112_transform_create(
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_transform_reg_offsets *offsets)
+{
+	struct dce110_transform *transform =
+		dm_alloc(sizeof(struct dce110_transform));
+
+	if (!transform)
+		return NULL;
+
+	if (dce110_transform_construct(transform, ctx, inst, offsets))
+		return &transform->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(transform);
+	return NULL;
+}
+struct link_encoder *dce112_link_encoder_create(
+	const struct encoder_init_data *enc_init_data)
+{
+	struct dce110_link_encoder *enc110 =
+		dm_alloc(sizeof(struct dce110_link_encoder));
+
+	if (!enc110)
+		return NULL;
+
+	if (dce112_link_encoder_construct(
+			enc110,
+			enc_init_data,
+			&link_enc_regs[enc_init_data->transmitter],
+			&link_enc_aux_regs[enc_init_data->channel - 1],
+			&link_enc_bl_regs))
+		return &enc110->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(enc110);
+	return NULL;
+}
+
+struct input_pixel_processor *dce112_ipp_create(
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_ipp_reg_offsets *offset)
+{
+	struct dce110_ipp *ipp =
+		dm_alloc(sizeof(struct dce110_ipp));
+
+	if (!ipp)
+		return NULL;
+
+	if (dce110_ipp_construct(ipp, ctx, inst, offset))
+			return &ipp->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(ipp);
+	return NULL;
+}
+
+void dce112_ipp_destroy(struct input_pixel_processor **ipp)
+{
+	dm_free(TO_DCE110_IPP(*ipp));
+	*ipp = NULL;
+}
+
+struct output_pixel_processor *dce112_opp_create(
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_opp_reg_offsets *offset)
+{
+	struct dce110_opp *opp =
+		dm_alloc(sizeof(struct dce110_opp));
+
+	if (!opp)
+		return NULL;
+
+	if (dce110_opp_construct(opp,
+			ctx, inst, offset))
+		return &opp->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(opp);
+	return NULL;
+}
+
+void dce112_opp_destroy(struct output_pixel_processor **opp)
+{
+	dm_free(FROM_DCE11_OPP(*opp)->regamma.coeff128_dx);
+	dm_free(FROM_DCE11_OPP(*opp)->regamma.coeff128_oem);
+	dm_free(FROM_DCE11_OPP(*opp)->regamma.coeff128);
+	dm_free(FROM_DCE11_OPP(*opp)->regamma.axis_x_1025);
+	dm_free(FROM_DCE11_OPP(*opp)->regamma.axis_x_256);
+	dm_free(FROM_DCE11_OPP(*opp)->regamma.coordinates_x);
+	dm_free(FROM_DCE11_OPP(*opp)->regamma.rgb_regamma);
+	dm_free(FROM_DCE11_OPP(*opp)->regamma.rgb_resulted);
+	dm_free(FROM_DCE11_OPP(*opp)->regamma.rgb_oem);
+	dm_free(FROM_DCE11_OPP(*opp)->regamma.rgb_user);
+	dm_free(FROM_DCE11_OPP(*opp));
+	*opp = NULL;
+}
+
+struct clock_source *dce112_clock_source_create(
+	struct dc_context *ctx,
+	struct dc_bios *bios,
+	enum clock_source_id id,
+	const struct dce112_clk_src_reg_offsets *offsets)
+{
+	struct dce112_clk_src *clk_src =
+		dm_alloc(sizeof(struct dce112_clk_src));
+
+	if (!clk_src)
+		return NULL;
+
+	if (dce112_clk_src_construct(clk_src, ctx, bios, id, offsets))
+		return &clk_src->base;
+
+	BREAK_TO_DEBUGGER();
+	return NULL;
+}
+
+void dce112_clock_source_destroy(struct clock_source **clk_src)
+{
+	dm_free(TO_DCE112_CLK_SRC(*clk_src));
+	*clk_src = NULL;
+}
+
+void dce112_destruct_resource_pool(struct resource_pool *pool)
+{
+	unsigned int i;
+
+	for (i = 0; i < pool->pipe_count; i++) {
+		if (pool->opps[i] != NULL)
+			dce112_opp_destroy(&pool->opps[i]);
+
+		if (pool->transforms[i] != NULL)
+			dce112_transform_destroy(&pool->transforms[i]);
+
+		if (pool->ipps[i] != NULL)
+			dce112_ipp_destroy(&pool->ipps[i]);
+
+		if (pool->mis[i] != NULL) {
+			dm_free(TO_DCE110_MEM_INPUT(pool->mis[i]));
+			pool->mis[i] = NULL;
+		}
+
+		if (pool->timing_generators[i] != NULL) {
+			dm_free(DCE110TG_FROM_TG(pool->timing_generators[i]));
+			pool->timing_generators[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < pool->stream_enc_count; i++) {
+		if (pool->stream_enc[i] != NULL)
+			dm_free(DCE110STRENC_FROM_STRENC(pool->stream_enc[i]));
+	}
+
+	for (i = 0; i < pool->clk_src_count; i++) {
+		if (pool->clock_sources[i] != NULL) {
+			dce112_clock_source_destroy(&pool->clock_sources[i]);
+		}
+	}
+
+	if (pool->dp_clock_source != NULL)
+		dce112_clock_source_destroy(&pool->dp_clock_source);
+
+	for (i = 0; i < pool->audio_count; i++)	{
+		if (pool->audios[i] != NULL) {
+			dal_audio_destroy(&pool->audios[i]);
+		}
+	}
+
+	if (pool->display_clock != NULL) {
+		dal_display_clock_destroy(&pool->display_clock);
+	}
+
+	if (pool->scaler_filter != NULL) {
+		dal_scaler_filter_destroy(&pool->scaler_filter);
+	}
+	if (pool->irqs != NULL) {
+		dal_irq_service_destroy(&pool->irqs);
+	}
+
+	if (pool->adapter_srv != NULL) {
+		dal_adapter_service_destroy(&pool->adapter_srv);
+	}
+}
+
+static struct clock_source *find_matching_pll(struct resource_context *res_ctx,
+		const struct core_stream *const stream)
+{
+	switch (stream->sink->link->link_enc->transmitter) {
+	case TRANSMITTER_UNIPHY_A:
+		return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL0];
+	case TRANSMITTER_UNIPHY_B:
+		return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL1];
+	case TRANSMITTER_UNIPHY_C:
+		return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL2];
+	case TRANSMITTER_UNIPHY_D:
+		return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL3];
+	case TRANSMITTER_UNIPHY_E:
+		return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL4];
+	case TRANSMITTER_UNIPHY_F:
+		return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL5];
+	default:
+		return NULL;
+	};
+
+	return 0;
+}
+
+static enum audio_dto_source translate_to_dto_source(enum controller_id crtc_id)
+{
+	switch (crtc_id) {
+	case CONTROLLER_ID_D0:
+		return DTO_SOURCE_ID0;
+	case CONTROLLER_ID_D1:
+		return DTO_SOURCE_ID1;
+	case CONTROLLER_ID_D2:
+		return DTO_SOURCE_ID2;
+	case CONTROLLER_ID_D3:
+		return DTO_SOURCE_ID3;
+	case CONTROLLER_ID_D4:
+		return DTO_SOURCE_ID4;
+	case CONTROLLER_ID_D5:
+		return DTO_SOURCE_ID5;
+	default:
+		return DTO_SOURCE_UNKNOWN;
+	}
+}
+
+static void build_audio_output(
+	const struct pipe_ctx *pipe_ctx,
+	struct audio_output *audio_output)
+{
+	const struct core_stream *stream = pipe_ctx->stream;
+	audio_output->engine_id = pipe_ctx->stream_enc->id;
+
+	audio_output->signal = pipe_ctx->signal;
+
+	/* audio_crtc_info  */
+
+	audio_output->crtc_info.h_total =
+		stream->public.timing.h_total;
+
+	/* Audio packets are sent during actual CRTC blank physical signal, we
+	 * need to specify actual active signal portion */
+	audio_output->crtc_info.h_active =
+			stream->public.timing.h_addressable
+			+ stream->public.timing.h_border_left
+			+ stream->public.timing.h_border_right;
+
+	audio_output->crtc_info.v_active =
+			stream->public.timing.v_addressable
+			+ stream->public.timing.v_border_top
+			+ stream->public.timing.v_border_bottom;
+
+	audio_output->crtc_info.pixel_repetition = 1;
+
+	audio_output->crtc_info.interlaced =
+			stream->public.timing.flags.INTERLACE;
+
+	audio_output->crtc_info.refresh_rate =
+		(stream->public.timing.pix_clk_khz*1000)/
+		(stream->public.timing.h_total*stream->public.timing.v_total);
+
+	audio_output->crtc_info.color_depth =
+		stream->public.timing.display_color_depth;
+
+	audio_output->crtc_info.requested_pixel_clock =
+			pipe_ctx->pix_clk_params.requested_pix_clk;
+
+	/* TODO - Investigate why calculated pixel clk has to be
+	 * requested pixel clk */
+	audio_output->crtc_info.calculated_pixel_clock =
+			pipe_ctx->pix_clk_params.requested_pix_clk;
+
+	if (pipe_ctx->signal == SIGNAL_TYPE_DISPLAY_PORT ||
+			pipe_ctx->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+		audio_output->pll_info.dp_dto_source_clock_in_khz =
+			dal_display_clock_get_dp_ref_clk_frequency(
+				pipe_ctx->dis_clk);
+	}
+
+	audio_output->pll_info.feed_back_divider =
+			pipe_ctx->pll_settings.feedback_divider;
+
+	audio_output->pll_info.dto_source =
+		translate_to_dto_source(
+			pipe_ctx->pipe_idx + 1);
+
+	/* TODO hard code to enable for now. Need get from stream */
+	audio_output->pll_info.ss_enabled = true;
+
+	audio_output->pll_info.ss_percentage =
+			pipe_ctx->pll_settings.ss_percentage;
+}
+
+static void get_pixel_clock_parameters(
+	const struct pipe_ctx *pipe_ctx,
+	struct pixel_clk_params *pixel_clk_params)
+{
+	const struct core_stream *stream = pipe_ctx->stream;
+	pixel_clk_params->requested_pix_clk = stream->public.timing.pix_clk_khz;
+	pixel_clk_params->encoder_object_id = stream->sink->link->link_enc->id;
+	pixel_clk_params->signal_type = stream->sink->public.sink_signal;
+	pixel_clk_params->controller_id = pipe_ctx->pipe_idx + 1;
+	/* TODO: un-hardcode*/
+	pixel_clk_params->requested_sym_clk = LINK_RATE_LOW *
+		LINK_RATE_REF_FREQ_IN_KHZ;
+	pixel_clk_params->flags.ENABLE_SS = 0;
+	pixel_clk_params->color_depth =
+		stream->public.timing.display_color_depth;
+	pixel_clk_params->flags.DISPLAY_BLANKED = 1;
+}
+
+static enum dc_status build_pipe_hw_param(struct pipe_ctx *pipe_ctx)
+{
+	/*TODO: unhardcode*/
+	pipe_ctx->max_tmds_clk_from_edid_in_mhz = 0;
+	pipe_ctx->max_hdmi_deep_color = COLOR_DEPTH_121212;
+	pipe_ctx->max_hdmi_pixel_clock = 600000;
+
+	get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->pix_clk_params);
+	pipe_ctx->clock_source->funcs->get_pix_clk_dividers(
+		pipe_ctx->clock_source,
+		&pipe_ctx->pix_clk_params,
+		&pipe_ctx->pll_settings);
+
+	build_audio_output(pipe_ctx, &pipe_ctx->audio_output);
+
+	return DC_OK;
+}
+
+static enum dc_status validate_mapped_resource(
+		const struct core_dc *dc,
+		struct validate_context *context)
+{
+	enum dc_status status = DC_OK;
+	uint8_t i, j, k;
+
+	for (i = 0; i < context->target_count; i++) {
+		struct core_target *target = context->targets[i];
+		if (context->target_flags[i].unchanged)
+			continue;
+		for (j = 0; j < target->public.stream_count; j++) {
+			struct core_stream *stream =
+				DC_STREAM_TO_CORE(target->public.streams[j]);
+			struct core_link *link = stream->sink->link;
+
+			for (k = 0; k < MAX_PIPES; k++) {
+				struct pipe_ctx *pipe_ctx =
+					&context->res_ctx.pipe_ctx[k];
+
+				if (context->res_ctx.pipe_ctx[k].stream != stream)
+					continue;
+
+				if (!pipe_ctx->tg->funcs->validate_timing(
+						pipe_ctx->tg, &stream->public.timing))
+					return DC_FAIL_CONTROLLER_VALIDATE;
+
+				status = build_pipe_hw_param(pipe_ctx);
+
+				if (status != DC_OK)
+					return status;
+
+				if (!link->link_enc->funcs->validate_output_with_stream(
+						link->link_enc,
+						pipe_ctx))
+					return DC_FAIL_ENC_VALIDATE;
+
+				/* TODO: validate audio ASIC caps, encoder */
+
+				status = dc_link_validate_mode_timing(stream->sink,
+						link,
+						&stream->public.timing);
+
+				if (status != DC_OK)
+					return status;
+
+				resource_build_info_frame(pipe_ctx);
+
+				/* do not need to validate non root pipes */
+				break;
+			}
+		}
+	}
+
+	return DC_OK;
+}
+
+enum dc_status dce112_validate_bandwidth(
+	const struct core_dc *dc,
+	struct validate_context *context)
+{
+	uint8_t i;
+	enum dc_status result = DC_ERROR_UNEXPECTED;
+	uint8_t number_of_displays = 0;
+	uint8_t max_htaps = 1;
+	uint8_t max_vtaps = 1;
+	bool all_displays_in_sync = true;
+	struct dc_crtc_timing prev_timing;
+
+	memset(&context->bw_mode_data, 0, sizeof(context->bw_mode_data));
+
+	for (i = 0; i < MAX_PIPES; i++) {
+		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+		struct bw_calcs_input_single_display *disp = &context->
+			bw_mode_data.displays_data[number_of_displays];
+
+		if (pipe_ctx->stream == NULL)
+			continue;
+
+		if (pipe_ctx->scl_data.ratios.vert.value == 0) {
+			disp->graphics_scale_ratio = bw_int_to_fixed(1);
+			disp->graphics_h_taps = 2;
+			disp->graphics_v_taps = 2;
+
+			/* TODO: remove when bw formula accepts taps per
+			 * display
+			 */
+			if (max_vtaps < 2)
+				max_vtaps = 2;
+			if (max_htaps < 2)
+				max_htaps = 2;
+
+		} else {
+			disp->graphics_scale_ratio =
+				fixed31_32_to_bw_fixed(
+					pipe_ctx->scl_data.ratios.vert.value);
+			disp->graphics_h_taps = pipe_ctx->scl_data.taps.h_taps;
+			disp->graphics_v_taps = pipe_ctx->scl_data.taps.v_taps;
+
+			/* TODO: remove when bw formula accepts taps per
+			 * display
+			 */
+			if (max_vtaps < pipe_ctx->scl_data.taps.v_taps)
+				max_vtaps = pipe_ctx->scl_data.taps.v_taps;
+			if (max_htaps < pipe_ctx->scl_data.taps.h_taps)
+				max_htaps = pipe_ctx->scl_data.taps.h_taps;
+		}
+
+		disp->graphics_src_width =
+			pipe_ctx->stream->public.timing.h_addressable;
+		disp->graphics_src_height =
+			pipe_ctx->stream->public.timing.v_addressable;
+		disp->h_total = pipe_ctx->stream->public.timing.h_total;
+		disp->pixel_rate = bw_frc_to_fixed(
+			pipe_ctx->stream->public.timing.pix_clk_khz, 1000);
+
+		/*TODO: get from surface*/
+		disp->graphics_bytes_per_pixel = 4;
+		disp->graphics_tiling_mode = bw_def_tiled;
+
+		/* DCE11 defaults*/
+		disp->graphics_lb_bpc = 10;
+		disp->graphics_interlace_mode = false;
+		disp->fbc_enable = false;
+		disp->lpt_enable = false;
+		disp->graphics_stereo_mode = bw_def_mono;
+		disp->underlay_mode = bw_def_none;
+
+		/*All displays will be synchronized if timings are all
+		 * the same
+		 */
+		if (number_of_displays != 0 && all_displays_in_sync)
+			if (memcmp(&prev_timing,
+				&pipe_ctx->stream->public.timing,
+				sizeof(struct dc_crtc_timing)) != 0)
+				all_displays_in_sync = false;
+		if (number_of_displays == 0)
+			prev_timing = pipe_ctx->stream->public.timing;
+
+		number_of_displays++;
+	}
+
+	/* TODO: remove when bw formula accepts taps per
+	 * display
+	 */
+	context->bw_mode_data.displays_data[0].graphics_v_taps = max_vtaps;
+	context->bw_mode_data.displays_data[0].graphics_h_taps = max_htaps;
+
+	context->bw_mode_data.number_of_displays = number_of_displays;
+	context->bw_mode_data.display_synchronization_enabled =
+							all_displays_in_sync;
+
+	dal_logger_write(
+		dc->ctx->logger,
+		LOG_MAJOR_BWM,
+		LOG_MINOR_BWM_REQUIRED_BANDWIDTH_CALCS,
+		"%s: start",
+		__func__);
+
+	if (!bw_calcs(
+			dc->ctx,
+			&dc->bw_dceip,
+			&dc->bw_vbios,
+			&context->bw_mode_data,
+			&context->bw_results))
+		result =  DC_FAIL_BANDWIDTH_VALIDATE;
+	else
+		result =  DC_OK;
+
+	if (result == DC_FAIL_BANDWIDTH_VALIDATE)
+		dal_logger_write(dc->ctx->logger,
+			LOG_MAJOR_BWM,
+			LOG_MINOR_BWM_MODE_VALIDATION,
+			"%s: Bandwidth validation failed!",
+			__func__);
+
+	if (memcmp(&dc->current_context.bw_results,
+			&context->bw_results, sizeof(context->bw_results))) {
+		struct log_entry log_entry;
+		dal_logger_open(
+			dc->ctx->logger,
+			&log_entry,
+			LOG_MAJOR_BWM,
+			LOG_MINOR_BWM_REQUIRED_BANDWIDTH_CALCS);
+		dal_logger_append(&log_entry, "%s: finish, numDisplays: %d\n"
+			"nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n"
+			"stutMark_b: %d stutMark_a: %d\n",
+			__func__, number_of_displays,
+			context->bw_results.nbp_state_change_wm_ns[0].b_mark,
+			context->bw_results.nbp_state_change_wm_ns[0].a_mark,
+			context->bw_results.urgent_wm_ns[0].b_mark,
+			context->bw_results.urgent_wm_ns[0].a_mark,
+			context->bw_results.stutter_exit_wm_ns[0].b_mark,
+			context->bw_results.stutter_exit_wm_ns[0].a_mark);
+		dal_logger_append(&log_entry,
+			"nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n"
+			"stutMark_b: %d stutMark_a: %d\n",
+			context->bw_results.nbp_state_change_wm_ns[1].b_mark,
+			context->bw_results.nbp_state_change_wm_ns[1].a_mark,
+			context->bw_results.urgent_wm_ns[1].b_mark,
+			context->bw_results.urgent_wm_ns[1].a_mark,
+			context->bw_results.stutter_exit_wm_ns[1].b_mark,
+			context->bw_results.stutter_exit_wm_ns[1].a_mark);
+		dal_logger_append(&log_entry,
+			"nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n"
+			"stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n",
+			context->bw_results.nbp_state_change_wm_ns[2].b_mark,
+			context->bw_results.nbp_state_change_wm_ns[2].a_mark,
+			context->bw_results.urgent_wm_ns[2].b_mark,
+			context->bw_results.urgent_wm_ns[2].a_mark,
+			context->bw_results.stutter_exit_wm_ns[2].b_mark,
+			context->bw_results.stutter_exit_wm_ns[2].a_mark,
+			context->bw_results.stutter_mode_enable);
+		dal_logger_append(&log_entry,
+			"cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n"
+			"sclk: %d sclk_sleep: %d yclk: %d blackout_duration: %d\n",
+			context->bw_results.cpuc_state_change_enable,
+			context->bw_results.cpup_state_change_enable,
+			context->bw_results.nbp_state_change_enable,
+			context->bw_results.all_displays_in_sync,
+			context->bw_results.dispclk_khz,
+			context->bw_results.required_sclk,
+			context->bw_results.required_sclk_deep_sleep,
+			context->bw_results.required_yclk,
+			context->bw_results.required_blackout_duration_us);
+		dal_logger_close(&log_entry);
+	}
+	return result;
+}
+
+static void set_target_unchanged(
+		struct validate_context *context,
+		uint8_t target_idx)
+{
+	uint8_t i, j;
+	struct core_target *target = context->targets[target_idx];
+	context->target_flags[target_idx].unchanged = true;
+	for (i = 0; i < target->public.stream_count; i++) {
+		struct core_stream *stream =
+			DC_STREAM_TO_CORE(target->public.streams[i]);
+		for (j = 0; j < MAX_PIPES; j++) {
+			if (context->res_ctx.pipe_ctx[j].stream == stream)
+				context->res_ctx.pipe_ctx[j].flags.unchanged =
+									true;
+		}
+	}
+}
+
+static enum dc_status map_clock_resources(
+		const struct core_dc *dc,
+		struct validate_context *context)
+{
+	uint8_t i, j, k;
+
+	/* acquire new resources */
+	for (i = 0; i < context->target_count; i++) {
+		struct core_target *target = context->targets[i];
+
+		if (context->target_flags[i].unchanged)
+			continue;
+
+		for (j = 0; j < target->public.stream_count; j++) {
+			struct core_stream *stream =
+				DC_STREAM_TO_CORE(target->public.streams[j]);
+
+			for (k = 0; k < MAX_PIPES; k++) {
+				struct pipe_ctx *pipe_ctx =
+					&context->res_ctx.pipe_ctx[k];
+
+				if (context->res_ctx.pipe_ctx[k].stream != stream)
+					continue;
+
+				if (dc_is_dp_signal(pipe_ctx->signal)
+					|| pipe_ctx->signal == SIGNAL_TYPE_VIRTUAL)
+					pipe_ctx->clock_source =
+						context->res_ctx.pool.dp_clock_source;
+				else
+					pipe_ctx->clock_source =
+							find_matching_pll(&context->res_ctx,
+									stream);
+
+				if (pipe_ctx->clock_source == NULL)
+					return DC_NO_CLOCK_SOURCE_RESOURCE;
+
+				resource_reference_clock_source(
+						&context->res_ctx,
+						pipe_ctx->clock_source);
+
+				/* only one cs per stream regardless of mpo */
+				break;
+			}
+		}
+	}
+
+	return DC_OK;
+}
+
+enum dc_status dce112_validate_with_context(
+		const struct core_dc *dc,
+		const struct dc_validation_set set[],
+		uint8_t set_count,
+		struct validate_context *context)
+{
+	enum dc_status result = DC_ERROR_UNEXPECTED;
+	uint8_t i, j;
+	struct dc_context *dc_ctx = dc->ctx;
+
+	for (i = 0; i < set_count; i++) {
+		bool unchanged = false;
+
+		context->targets[i] = DC_TARGET_TO_CORE(set[i].target);
+		dc_target_retain(&context->targets[i]->public);
+		context->target_count++;
+
+		for (j = 0; j < dc->current_context.target_count; j++)
+			if (dc->current_context.targets[j]
+						== context->targets[i]) {
+				unchanged = true;
+				set_target_unchanged(context, i);
+				resource_attach_surfaces_to_context(
+					(struct dc_surface **)dc->current_context.
+						target_status[j].surfaces,
+					dc->current_context.target_status[j].surface_count,
+					&context->targets[i]->public,
+					context);
+				context->target_status[i] =
+					dc->current_context.target_status[j];
+			}
+		if (!unchanged || set[i].surface_count != 0)
+			if (!resource_attach_surfaces_to_context(
+					(struct dc_surface **)set[i].surfaces,
+					set[i].surface_count,
+					&context->targets[i]->public,
+					context)) {
+				DC_ERROR("Failed to attach surface to target!\n");
+				return DC_FAIL_ATTACH_SURFACES;
+			}
+	}
+
+	context->res_ctx.pool = dc->res_pool;
+
+	result = resource_map_pool_resources(dc, context);
+
+	if (result == DC_OK)
+		result = map_clock_resources(dc, context);
+
+	if (result == DC_OK)
+		result = validate_mapped_resource(dc, context);
+
+	if (result == DC_OK)
+		resource_build_scaling_params_for_context(dc, context);
+
+	if (result == DC_OK)
+		result = dce112_validate_bandwidth(dc, context);
+
+	return result;
+}
+
+static struct resource_funcs dce112_res_pool_funcs = {
+	.destruct = dce112_destruct_resource_pool,
+	.link_enc_create = dce112_link_encoder_create,
+	.validate_with_context = dce112_validate_with_context,
+	.validate_bandwidth = dce112_validate_bandwidth
+};
+
+static void bw_calcs_data_update_from_pplib(struct core_dc *dc)
+{
+	struct dm_pp_clock_levels clks = {0};
+
+	/*do system clock*/
+	dm_pp_get_clock_levels_by_type(
+			dc->ctx,
+			DM_PP_CLOCK_TYPE_ENGINE_CLK,
+			&clks);
+	/* convert all the clock fro kHz to fix point mHz */
+	dc->bw_vbios.high_sclk = bw_frc_to_fixed(
+			clks.clocks_in_khz[clks.num_levels-1], 1000);
+	dc->bw_vbios.mid_sclk  = bw_frc_to_fixed(
+			clks.clocks_in_khz[clks.num_levels>>1], 1000);
+	dc->bw_vbios.low_sclk  = bw_frc_to_fixed(
+			clks.clocks_in_khz[0], 1000);
+
+	/*do display clock*/
+	dm_pp_get_clock_levels_by_type(
+			dc->ctx,
+			DM_PP_CLOCK_TYPE_DISPLAY_CLK,
+			&clks);
+
+	dc->bw_vbios.high_voltage_max_dispclk = bw_frc_to_fixed(
+			clks.clocks_in_khz[clks.num_levels-1], 1000);
+	dc->bw_vbios.mid_voltage_max_dispclk  = bw_frc_to_fixed(
+			clks.clocks_in_khz[clks.num_levels>>1], 1000);
+	dc->bw_vbios.low_voltage_max_dispclk  = bw_frc_to_fixed(
+			clks.clocks_in_khz[0], 1000);
+
+	/*do memory clock*/
+	dm_pp_get_clock_levels_by_type(
+			dc->ctx,
+			DM_PP_CLOCK_TYPE_MEMORY_CLK,
+			&clks);
+
+	dc->bw_vbios.low_yclk = bw_frc_to_fixed(
+		clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER, 1000);
+	dc->bw_vbios.mid_yclk = bw_frc_to_fixed(
+		clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER,
+		1000);
+	dc->bw_vbios.high_yclk = bw_frc_to_fixed(
+		clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER,
+		1000);
+}
+
+
+bool dce112_construct_resource_pool(
+	struct adapter_service *adapter_serv,
+	uint8_t num_virtual_links,
+	struct core_dc *dc,
+	struct resource_pool *pool)
+{
+	unsigned int i;
+	struct audio_init_data audio_init_data = { 0 };
+	struct dc_context *ctx = dc->ctx;
+
+	pool->adapter_srv = adapter_serv;
+	pool->funcs = &dce112_res_pool_funcs;
+
+	pool->stream_engines.engine.ENGINE_ID_DIGA = 1;
+	pool->stream_engines.engine.ENGINE_ID_DIGB = 1;
+	pool->stream_engines.engine.ENGINE_ID_DIGC = 1;
+	pool->stream_engines.engine.ENGINE_ID_DIGD = 1;
+	pool->stream_engines.engine.ENGINE_ID_DIGE = 1;
+	pool->stream_engines.engine.ENGINE_ID_DIGF = 1;
+
+	pool->clock_sources[DCE112_CLK_SRC_PLL0] = dce112_clock_source_create(
+		ctx, dal_adapter_service_get_bios_parser(adapter_serv),
+		CLOCK_SOURCE_COMBO_PHY_PLL0, &dce112_clk_src_reg_offsets[0]);
+	pool->clock_sources[DCE112_CLK_SRC_PLL1] = dce112_clock_source_create(
+		ctx, dal_adapter_service_get_bios_parser(adapter_serv),
+		CLOCK_SOURCE_COMBO_PHY_PLL1, &dce112_clk_src_reg_offsets[1]);
+	pool->clock_sources[DCE112_CLK_SRC_PLL2] = dce112_clock_source_create(
+		ctx, dal_adapter_service_get_bios_parser(adapter_serv),
+		CLOCK_SOURCE_COMBO_PHY_PLL2, &dce112_clk_src_reg_offsets[2]);
+	pool->clock_sources[DCE112_CLK_SRC_PLL3] = dce112_clock_source_create(
+		ctx, dal_adapter_service_get_bios_parser(adapter_serv),
+		CLOCK_SOURCE_COMBO_PHY_PLL3, &dce112_clk_src_reg_offsets[3]);
+	pool->clock_sources[DCE112_CLK_SRC_PLL4] = dce112_clock_source_create(
+		ctx, dal_adapter_service_get_bios_parser(adapter_serv),
+		CLOCK_SOURCE_COMBO_PHY_PLL4, &dce112_clk_src_reg_offsets[4]);
+	pool->clock_sources[DCE112_CLK_SRC_PLL5] = dce112_clock_source_create(
+		ctx, dal_adapter_service_get_bios_parser(adapter_serv),
+		CLOCK_SOURCE_COMBO_PHY_PLL5, &dce112_clk_src_reg_offsets[5]);
+	pool->clk_src_count = DCE112_CLK_SRC_TOTAL;
+
+	pool->dp_clock_source =  dce112_clock_source_create(
+		ctx, dal_adapter_service_get_bios_parser(adapter_serv),
+		CLOCK_SOURCE_ID_DP_DTO, &dce112_clk_src_reg_offsets[0]);
+
+	for (i = 0; i < pool->clk_src_count; i++) {
+		if (pool->clock_sources[i] == NULL) {
+			dm_error("DC: failed to create clock sources!\n");
+			BREAK_TO_DEBUGGER();
+			goto clk_src_create_fail;
+		}
+	}
+
+	pool->display_clock = dal_display_clock_dce112_create(ctx, adapter_serv);
+	if (pool->display_clock == NULL) {
+		dm_error("DC: failed to create display clock!\n");
+		BREAK_TO_DEBUGGER();
+		goto disp_clk_create_fail;
+	}
+
+	{
+		struct irq_service_init_data init_data;
+		init_data.ctx = dc->ctx;
+		pool->irqs = dal_irq_service_create(
+				dal_adapter_service_get_dce_version(
+					dc->res_pool.adapter_srv),
+				&init_data);
+		if (!pool->irqs)
+			goto irqs_create_fail;
+
+	}
+
+	pool->pipe_count =
+		dal_adapter_service_get_func_controllers_num(adapter_serv);
+	pool->stream_enc_count = 6;
+	pool->scaler_filter = dal_scaler_filter_create(ctx);
+	if (pool->scaler_filter == NULL) {
+		BREAK_TO_DEBUGGER();
+		dm_error("DC: failed to create filter!\n");
+		goto filter_create_fail;
+	}
+
+	for (i = 0; i < pool->pipe_count; i++) {
+		pool->timing_generators[i] = dce112_timing_generator_create(
+				adapter_serv,
+				ctx,
+				i,
+				&dce112_tg_offsets[i]);
+		if (pool->timing_generators[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error("DC: failed to create tg!\n");
+			goto controller_create_fail;
+		}
+
+		pool->mis[i] = dce112_mem_input_create(
+			ctx,
+			i,
+			&dce112_mi_reg_offsets[i]);
+		if (pool->mis[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create memory input!\n");
+			goto controller_create_fail;
+		}
+
+		pool->ipps[i] = dce112_ipp_create(
+			ctx,
+			i,
+			&ipp_reg_offsets[i]);
+		if (pool->ipps[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create input pixel processor!\n");
+			goto controller_create_fail;
+		}
+
+		pool->transforms[i] = dce112_transform_create(
+				ctx,
+				i,
+				&dce112_xfm_offsets[i]);
+		if (pool->transforms[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create transform!\n");
+			goto controller_create_fail;
+		}
+		pool->transforms[i]->funcs->transform_set_scaler_filter(
+				pool->transforms[i],
+				pool->scaler_filter);
+
+		pool->opps[i] = dce112_opp_create(
+			ctx,
+			i,
+			&dce112_opp_reg_offsets[i]);
+		if (pool->opps[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create output pixel processor!\n");
+			goto controller_create_fail;
+		}
+	}
+
+	audio_init_data.as = adapter_serv;
+	audio_init_data.ctx = ctx;
+	pool->audio_count = 0;
+	for (i = 0; i < pool->pipe_count; i++) {
+		struct graphics_object_id obj_id;
+
+		obj_id = dal_adapter_service_enum_audio_object(adapter_serv, i);
+		if (false == dal_graphics_object_id_is_valid(obj_id)) {
+			/* no more valid audio objects */
+			break;
+		}
+
+		audio_init_data.audio_stream_id = obj_id;
+		pool->audios[i] = dal_audio_create(&audio_init_data);
+		if (pool->audios[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error("DC: failed to create DPPs!\n");
+			goto audio_create_fail;
+		}
+		pool->audio_count++;
+	}
+
+	for (i = 0; i < pool->stream_enc_count; i++) {
+		/* TODO: rework fragile code*/
+		if (pool->stream_engines.u_all & 1 << i) {
+			pool->stream_enc[i] = dce112_stream_encoder_create(
+				i, dc->ctx,
+				dal_adapter_service_get_bios_parser(
+					adapter_serv),
+				&stream_enc_regs[i]);
+			if (pool->stream_enc[i] == NULL) {
+				BREAK_TO_DEBUGGER();
+				dm_error("DC: failed to create stream_encoder!\n");
+				goto stream_enc_create_fail;
+			}
+		}
+	}
+
+	for (i = 0; i < num_virtual_links; i++) {
+		pool->stream_enc[pool->stream_enc_count] =
+			virtual_stream_encoder_create(
+				dc->ctx, dal_adapter_service_get_bios_parser(
+								adapter_serv));
+		if (pool->stream_enc[pool->stream_enc_count] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error("DC: failed to create stream_encoder!\n");
+			goto stream_enc_create_fail;
+		}
+		pool->stream_enc_count++;
+	}
+
+	/* Create hardware sequencer */
+	if (!dc_construct_hw_sequencer(adapter_serv, dc))
+		goto stream_enc_create_fail;
+
+	bw_calcs_init(&dc->bw_dceip, &dc->bw_vbios, BW_CALCS_VERSION_BAFFIN);
+
+	bw_calcs_data_update_from_pplib(dc);
+
+	return true;
+
+stream_enc_create_fail:
+	for (i = 0; i < pool->stream_enc_count; i++) {
+		if (pool->stream_enc[i] != NULL)
+			dm_free(DCE110STRENC_FROM_STRENC(pool->stream_enc[i]));
+	}
+
+audio_create_fail:
+	for (i = 0; i < pool->pipe_count; i++) {
+		if (pool->audios[i] != NULL)
+			dal_audio_destroy(&pool->audios[i]);
+	}
+
+controller_create_fail:
+	for (i = 0; i < pool->pipe_count; i++) {
+		if (pool->opps[i] != NULL)
+			dce112_opp_destroy(&pool->opps[i]);
+
+		if (pool->transforms[i] != NULL)
+			dce112_transform_destroy(&pool->transforms[i]);
+
+		if (pool->ipps[i] != NULL)
+			dce112_ipp_destroy(&pool->ipps[i]);
+
+		if (pool->mis[i] != NULL) {
+			dm_free(TO_DCE110_MEM_INPUT(pool->mis[i]));
+			pool->mis[i] = NULL;
+		}
+
+		if (pool->timing_generators[i] != NULL) {
+			dm_free(DCE110TG_FROM_TG(pool->timing_generators[i]));
+			pool->timing_generators[i] = NULL;
+		}
+	}
+
+filter_create_fail:
+	dal_irq_service_destroy(&pool->irqs);
+
+irqs_create_fail:
+	dal_display_clock_destroy(&pool->display_clock);
+
+disp_clk_create_fail:
+clk_src_create_fail:
+	for (i = 0; i < pool->clk_src_count; i++) {
+		if (pool->clock_sources[i] != NULL)
+			dce112_clock_source_destroy(&pool->clock_sources[i]);
+	}
+
+	return false;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.h
new file mode 100644
index 0000000..eed1faf
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.h
@@ -0,0 +1,42 @@
+/*
+* 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_RESOURCE_DCE112_H__
+#define __DC_RESOURCE_DCE112_H__
+
+#include "core_types.h"
+
+struct adapter_service;
+struct core_dc;
+struct resource_pool;
+
+bool dce112_construct_resource_pool(
+	struct adapter_service *adapter_serv,
+	uint8_t num_virtual_links,
+	struct core_dc *dc,
+	struct resource_pool *pool);
+
+#endif /* __DC_RESOURCE_DCE112_H__ */
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dm_services_types.h b/drivers/gpu/drm/amd/dal/dc/dm_services_types.h
index 1e87624..982e968 100644
--- a/drivers/gpu/drm/amd/dal/dc/dm_services_types.h
+++ b/drivers/gpu/drm/amd/dal/dc/dm_services_types.h
@@ -212,6 +212,11 @@ enum dm_pp_clock_type {
 struct dm_pp_clock_levels {
 	uint32_t num_levels;
 	uint32_t clocks_in_khz[DM_PP_MAX_CLOCK_LEVELS];
+
+	/* TODO: add latency for polaris11
+	 * do we need to know invalid (unsustainable boost) level for watermark
+	 * programming? if not we can just report less elements in array
+	 */
 };
 
 struct dm_pp_single_disp_config {
diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c
index 63d6b54..5037a2d 100644
--- a/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c
+++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c
@@ -78,6 +78,9 @@ bool dal_hw_factory_init(
 #endif
 #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
 	case DCE_VERSION_11_0:
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	case DCE_VERSION_11_2:
+#endif
 		dal_hw_factory_dce110_init(factory);
 		return true;
 #endif
diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c
index d3c6bc8..da56db7 100644
--- a/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c
+++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c
@@ -75,6 +75,9 @@ bool dal_hw_translate_init(
 	case DCE_VERSION_10_0:
 #endif
 	case DCE_VERSION_11_0:
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	case DCE_VERSION_11_2:
+#endif
 		dal_hw_translate_dce110_init(translate);
 		return true;
 #endif
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/Makefile b/drivers/gpu/drm/amd/dal/dc/gpu/Makefile
index cb23508..3095006 100644
--- a/drivers/gpu/drm/amd/dal/dc/gpu/Makefile
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/Makefile
@@ -32,3 +32,11 @@ AMD_DAL_GPU_DCE110 = $(addprefix $(AMDDALPATH)/dc/gpu/dce110/,$(GPU_DCE110))
 
 AMD_DAL_FILES += $(AMD_DAL_GPU_DCE110)
 endif
+
+ifdef CONFIG_DRM_AMD_DAL_DCE11_2
+GPU_DCE112 = display_clock_dce112.o dc_clock_gating_dce112.o
+
+AMD_DAL_GPU_DCE112 = $(addprefix $(AMDDALPATH)/dc/gpu/dce112/,$(GPU_DCE112))
+
+AMD_DAL_FILES += $(AMD_DAL_GPU_DCE110) $(AMD_DAL_GPU_DCE112)
+endif
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.c
new file mode 100644
index 0000000..bf24457
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.c
@@ -0,0 +1,89 @@
+/*
+ * 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 "include/logger_interface.h"
+
+#include "dce/dce_11_2_d.h"
+#include "dce/dce_11_2_sh_mask.h"
+#include "dc_clock_gating_dce112.h"
+
+/******************************************************************************
+ * Macro definitions
+ *****************************************************************************/
+
+#define NOT_IMPLEMENTED() DAL_LOGGER_NOT_IMPL(LOG_MINOR_COMPONENT_GPU, \
+		"%s:%s()\n", __FILE__, __func__)
+
+/******************************************************************************
+ * static functions
+ *****************************************************************************/
+static void force_hw_base_light_sleep(struct dc_context *ctx)
+{
+	uint32_t addr = 0;
+	uint32_t value = 0;
+
+	addr = mmDC_MEM_GLOBAL_PWR_REQ_CNTL;
+	/* Read the mmDC_MEM_GLOBAL_PWR_REQ_CNTL to get the currently
+	 * programmed DC_MEM_GLOBAL_PWR_REQ_DIS*/
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(
+			value,
+			1,
+			DC_MEM_GLOBAL_PWR_REQ_CNTL,
+			DC_MEM_GLOBAL_PWR_REQ_DIS);
+
+	dm_write_reg(ctx, addr, value);
+
+}
+
+static void enable_hw_base_light_sleep(struct dc_context *ctx)
+{
+	NOT_IMPLEMENTED();
+}
+
+static void disable_sw_manual_control_light_sleep(
+		struct dc_context *ctx)
+{
+	NOT_IMPLEMENTED();
+}
+
+/******************************************************************************
+ * public functions
+ *****************************************************************************/
+
+void dal_dc_clock_gating_dce112_power_up(
+		struct dc_context *ctx,
+		bool enable)
+{
+	if (enable) {
+		enable_hw_base_light_sleep(ctx);
+		disable_sw_manual_control_light_sleep(ctx);
+	} else {
+		force_hw_base_light_sleep(ctx);
+	}
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.h
new file mode 100644
index 0000000..118da64
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.h
@@ -0,0 +1,33 @@
+/*
+ * 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 __DAL_DC_CLOCK_GATING_DCE112_H__
+#define __DAL_DC_CLOCK_GATING_DCE112_H__
+
+void dal_dc_clock_gating_dce112_power_up(
+		struct dc_context *ctx,
+		bool enable);
+
+#endif /* __DAL_DC_CLOCK_GATING_DCE110_H__ */
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.c
new file mode 100644
index 0000000..e559f95
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.c
@@ -0,0 +1,964 @@
+/*
+ * 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 "dce/dce_11_2_d.h"
+#include "dce/dce_11_2_sh_mask.h"
+
+#include "include/adapter_service_interface.h"
+#include "include/bios_parser_interface.h"
+#include "include/fixed32_32.h"
+#include "include/logger_interface.h"
+
+#include "../divider_range.h"
+
+#include "display_clock_dce112.h"
+
+#define FROM_DISPLAY_CLOCK(base) \
+	container_of(base, struct display_clock_dce112, disp_clk_base)
+
+static struct state_dependent_clocks max_clks_by_state[] = {
+/*ClocksStateInvalid - should not be used*/
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
+{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
+/*ClocksStateLow*/
+{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
+/*ClocksStateNominal*/
+{ .display_clk_khz = 467000, .pixel_clk_khz = 400000 },
+/*ClocksStatePerformance*/
+{ .display_clk_khz = 643000, .pixel_clk_khz = 4000000 } };
+
+/* Starting point for each divider range.*/
+enum divider_range_start {
+	DIVIDER_RANGE_01_START = 200, /* 2.00*/
+	DIVIDER_RANGE_02_START = 1600, /* 16.00*/
+	DIVIDER_RANGE_03_START = 3200, /* 32.00*/
+	DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/
+};
+
+/* Array identifiers and count for the divider ranges.*/
+enum divider_range_count {
+	DIVIDER_RANGE_01 = 0,
+	DIVIDER_RANGE_02,
+	DIVIDER_RANGE_03,
+	DIVIDER_RANGE_MAX /* == 3*/
+};
+
+/* Ranges for divider identifiers (Divider ID or DID)
+ mmDENTIST_DISPCLK_CNTL.DENTIST_DISPCLK_WDIVIDER*/
+enum divider_id_register_setting {
+	DIVIDER_RANGE_01_BASE_DIVIDER_ID = 0X08,
+	DIVIDER_RANGE_02_BASE_DIVIDER_ID = 0X40,
+	DIVIDER_RANGE_03_BASE_DIVIDER_ID = 0X60,
+	DIVIDER_RANGE_MAX_DIVIDER_ID = 0X80
+};
+
+/* Step size between each divider within a range.
+ Incrementing the DENTIST_DISPCLK_WDIVIDER by one
+ will increment the divider by this much.*/
+enum divider_range_step_size {
+	DIVIDER_RANGE_01_STEP_SIZE = 25, /* 0.25*/
+	DIVIDER_RANGE_02_STEP_SIZE = 50, /* 0.50*/
+	DIVIDER_RANGE_03_STEP_SIZE = 100 /* 1.00 */
+};
+
+static struct divider_range divider_ranges[DIVIDER_RANGE_MAX];
+
+#define dce112_DFS_BYPASS_THRESHOLD_KHZ 400000
+/*****************************************************************************
+ * static functions
+ *****************************************************************************/
+
+/*
+ * store_max_clocks_state
+ *
+ * @brief
+ * Cache the clock state
+ *
+ * @param
+ * struct display_clock *base - [out] cach the state in this structure
+ * enum clocks_state max_clocks_state - [in] state to be stored
+ */
+static void store_max_clocks_state(
+	struct display_clock *base,
+	enum clocks_state max_clocks_state)
+{
+	struct display_clock_dce112 *dc = DCLCK112_FROM_BASE(base);
+
+	switch (max_clocks_state) {
+	case CLOCKS_STATE_LOW:
+	case CLOCKS_STATE_NOMINAL:
+	case CLOCKS_STATE_PERFORMANCE:
+	case CLOCKS_STATE_ULTRA_LOW:
+		dc->max_clks_state = max_clocks_state;
+		break;
+
+	case CLOCKS_STATE_INVALID:
+	default:
+		/*Invalid Clocks State!*/
+		ASSERT_CRITICAL(false);
+		break;
+	}
+}
+
+static enum clocks_state get_min_clocks_state(struct display_clock *base)
+{
+	return base->cur_min_clks_state;
+}
+
+static bool set_min_clocks_state(
+	struct display_clock *base,
+	enum clocks_state clocks_state)
+{
+	struct display_clock_dce112 *dc = DCLCK112_FROM_BASE(base);
+
+	if (clocks_state > dc->max_clks_state) {
+		/*Requested state exceeds max supported state.*/
+		dal_logger_write(base->ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_GPU,
+				"Requested state exceeds max supported state");
+		return false;
+	} else if (clocks_state == base->cur_min_clks_state) {
+		/*if we're trying to set the same state, we can just return
+		 * since nothing needs to be done*/
+		return true;
+	}
+
+	base->cur_min_clks_state = clocks_state;
+
+	return true;
+}
+
+static uint32_t get_dp_ref_clk_frequency(struct display_clock *dc)
+{
+	uint32_t dispclk_cntl_value;
+	uint32_t dp_ref_clk_cntl_value;
+	uint32_t dp_ref_clk_cntl_src_sel_value;
+	uint32_t dp_ref_clk_khz = 600000;
+	uint32_t target_div = INVALID_DIVIDER;
+	struct display_clock_dce112 *disp_clk = FROM_DISPLAY_CLOCK(dc);
+
+	/* ASSERT DP Reference Clock source is from DFS*/
+	dp_ref_clk_cntl_value = dm_read_reg(dc->ctx,
+			mmDPREFCLK_CNTL);
+
+	dp_ref_clk_cntl_src_sel_value =
+			get_reg_field_value(
+				dp_ref_clk_cntl_value,
+				DPREFCLK_CNTL, DPREFCLK_SRC_SEL);
+
+	ASSERT(dp_ref_clk_cntl_src_sel_value == 0);
+
+	/* Read the mmDENTIST_DISPCLK_CNTL to get the currently
+	 * programmed DID DENTIST_DPREFCLK_WDIVIDER*/
+	dispclk_cntl_value = dm_read_reg(dc->ctx,
+			mmDENTIST_DISPCLK_CNTL);
+
+	/* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
+	target_div = dal_divider_range_get_divider(
+		divider_ranges,
+		DIVIDER_RANGE_MAX,
+		get_reg_field_value(dispclk_cntl_value,
+			DENTIST_DISPCLK_CNTL,
+			DENTIST_DPREFCLK_WDIVIDER));
+
+	if (target_div != INVALID_DIVIDER) {
+		/* Calculate the current DFS clock, in kHz.*/
+		dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR
+			* disp_clk->dentist_vco_freq_khz) / target_div;
+	}
+
+	/* SW will adjust DP REF Clock average value for all purposes
+	 * (DP DTO / DP Audio DTO and DP GTC)
+	 if clock is spread for all cases:
+	 -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
+	 calculations for DS_INCR/DS_MODULO (this is planned to be default case)
+	 -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
+	 calculations (not planned to be used, but average clock should still
+	 be valid)
+	 -if SS enabled on DP Ref clock and HW de-spreading disabled
+	 (should not be case with CIK) then SW should program all rates
+	 generated according to average value (case as with previous ASICs)
+	  */
+	if ((disp_clk->ss_on_gpu_pll) && (disp_clk->gpu_pll_ss_divider != 0)) {
+		struct fixed32_32 ss_percentage = dal_fixed32_32_div_int(
+				dal_fixed32_32_from_fraction(
+					disp_clk->gpu_pll_ss_percentage,
+					disp_clk->gpu_pll_ss_divider), 200);
+		struct fixed32_32 adj_dp_ref_clk_khz;
+
+		ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one,
+								ss_percentage);
+		adj_dp_ref_clk_khz =
+			dal_fixed32_32_mul_int(
+				ss_percentage,
+				dp_ref_clk_khz);
+		dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz);
+	}
+
+	return dp_ref_clk_khz;
+}
+
+static void destroy(struct display_clock **base)
+{
+	struct display_clock_dce112 *dc112;
+
+	dc112 = DCLCK112_FROM_BASE(*base);
+
+	dm_free(dc112);
+
+	*base = NULL;
+}
+
+static uint32_t get_validation_clock(struct display_clock *dc)
+{
+	uint32_t clk = 0;
+	struct display_clock_dce112 *disp_clk = DCLCK112_FROM_BASE(dc);
+
+	switch (disp_clk->max_clks_state) {
+	case CLOCKS_STATE_ULTRA_LOW:
+		/*Currently not supported, it has 0 in table entry*/
+	case CLOCKS_STATE_LOW:
+		clk = max_clks_by_state[CLOCKS_STATE_LOW].
+						display_clk_khz;
+		break;
+
+	case CLOCKS_STATE_NOMINAL:
+		clk = max_clks_by_state[CLOCKS_STATE_NOMINAL].
+						display_clk_khz;
+		break;
+
+	case CLOCKS_STATE_PERFORMANCE:
+		clk = max_clks_by_state[CLOCKS_STATE_PERFORMANCE].
+						display_clk_khz;
+		break;
+
+	case CLOCKS_STATE_INVALID:
+	default:
+		/*Invalid Clocks State*/
+		dal_logger_write(dc->ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_GPU,
+				"Invalid clock state");
+		/* just return the display engine clock for
+		 * lowest supported state*/
+		clk = max_clks_by_state[CLOCKS_STATE_LOW].
+						display_clk_khz;
+		break;
+	}
+	return clk;
+}
+
+static struct fixed32_32 get_deep_color_factor(struct min_clock_params *params)
+{
+	/* DeepColorFactor = IF (HDMI = True, bpp / 24, 1)*/
+	struct fixed32_32 deep_color_factor = dal_fixed32_32_from_int(1);
+
+	if (params->signal_type != SIGNAL_TYPE_HDMI_TYPE_A)
+		return deep_color_factor;
+
+	switch (params->deep_color_depth) {
+	case COLOR_DEPTH_101010:
+		/*deep color ratio for 30bpp is 30/24 = 1.25*/
+		deep_color_factor = dal_fixed32_32_from_fraction(30, 24);
+		break;
+
+	case COLOR_DEPTH_121212:
+		/* deep color ratio for 36bpp is 36/24 = 1.5*/
+		deep_color_factor = dal_fixed32_32_from_fraction(36, 24);
+		break;
+
+	case COLOR_DEPTH_161616:
+		/* deep color ratio for 48bpp is 48/24 = 2.0 */
+		deep_color_factor = dal_fixed32_32_from_fraction(48, 24);
+		break;
+	default:
+		break;
+	}
+	return deep_color_factor;
+}
+
+static struct fixed32_32 get_scaler_efficiency(
+	struct dc_context *ctx,
+	struct min_clock_params *params)
+{
+	struct fixed32_32 scaler_efficiency = dal_fixed32_32_from_int(3);
+
+	if (params->scaler_efficiency == V_SCALER_EFFICIENCY_LB18BPP) {
+		scaler_efficiency =
+			dal_fixed32_32_add(
+				dal_fixed32_32_from_fraction(35555, 10000),
+				dal_fixed32_32_from_fraction(
+					55556,
+					100000 * 10000));
+	} else if (params->scaler_efficiency == V_SCALER_EFFICIENCY_LB24BPP) {
+		scaler_efficiency =
+			dal_fixed32_32_add(
+				dal_fixed32_32_from_fraction(34285, 10000),
+				dal_fixed32_32_from_fraction(
+					71429,
+					100000 * 10000));
+	} else if (params->scaler_efficiency == V_SCALER_EFFICIENCY_LB30BPP)
+		scaler_efficiency = dal_fixed32_32_from_fraction(32, 10);
+
+	return scaler_efficiency;
+}
+
+static struct fixed32_32 get_lb_lines_in_per_line_out(
+		struct min_clock_params *params,
+		struct fixed32_32 v_scale_ratio)
+{
+	struct fixed32_32 two = dal_fixed32_32_from_int(2);
+	struct fixed32_32 four = dal_fixed32_32_from_int(4);
+	struct fixed32_32 f4_to_3 = dal_fixed32_32_from_fraction(4, 3);
+	struct fixed32_32 f6_to_4 = dal_fixed32_32_from_fraction(6, 4);
+
+	if (params->line_buffer_prefetch_enabled)
+		return dal_fixed32_32_max(v_scale_ratio, dal_fixed32_32_one);
+	else if (dal_fixed32_32_le(v_scale_ratio, dal_fixed32_32_one))
+		return dal_fixed32_32_one;
+	else if (dal_fixed32_32_le(v_scale_ratio, f4_to_3))
+		return f4_to_3;
+	else if (dal_fixed32_32_le(v_scale_ratio, f6_to_4))
+		return f6_to_4;
+	else if (dal_fixed32_32_le(v_scale_ratio, two))
+		return two;
+	else if (dal_fixed32_32_le(v_scale_ratio, dal_fixed32_32_from_int(3)))
+		return four;
+	else
+		return dal_fixed32_32_zero;
+}
+
+static uint32_t get_actual_required_display_clk(
+	struct display_clock_dce112 *disp_clk,
+	uint32_t target_clk_khz)
+{
+	uint32_t disp_clk_khz = target_clk_khz;
+	uint32_t div = INVALID_DIVIDER;
+	uint32_t did = INVALID_DID;
+	uint32_t scaled_vco =
+		disp_clk->dentist_vco_freq_khz * DIVIDER_RANGE_SCALE_FACTOR;
+
+	ASSERT_CRITICAL(!!disp_clk_khz);
+
+	if (disp_clk_khz)
+		div = scaled_vco / disp_clk_khz;
+
+	did = dal_divider_range_get_did(divider_ranges, DIVIDER_RANGE_MAX, div);
+
+	if (did != INVALID_DID) {
+		div = dal_divider_range_get_divider(
+			divider_ranges, DIVIDER_RANGE_MAX, did);
+
+		if ((div != INVALID_DIVIDER) &&
+			(did > DIVIDER_RANGE_01_BASE_DIVIDER_ID))
+			if (disp_clk_khz > (scaled_vco / div))
+				div = dal_divider_range_get_divider(
+					divider_ranges, DIVIDER_RANGE_MAX,
+					did - 1);
+
+		if (div != INVALID_DIVIDER)
+			disp_clk_khz = scaled_vco / div;
+
+	}
+	/* We need to add 10KHz to this value because the accuracy in VBIOS is
+	 in 10KHz units. So we need to always round the last digit up in order
+	 to reach the next div level.*/
+	return disp_clk_khz + 10;
+}
+
+static uint32_t calc_single_display_min_clks(
+	struct display_clock *base,
+	struct min_clock_params *params,
+	bool set_clk)
+{
+	struct fixed32_32 h_scale_ratio = dal_fixed32_32_one;
+	struct fixed32_32 v_scale_ratio = dal_fixed32_32_one;
+	uint32_t pix_clk_khz = 0;
+	uint32_t lb_source_width = 0;
+	struct fixed32_32 deep_color_factor;
+	struct fixed32_32 scaler_efficiency;
+	struct fixed32_32 v_filter_init;
+	uint32_t v_filter_init_trunc;
+	uint32_t num_lines_at_frame_start = 3;
+	struct fixed32_32 v_filter_init_ceil;
+	struct fixed32_32 lines_per_lines_out_at_frame_start;
+	struct fixed32_32 lb_lines_in_per_line_out; /* in middle of the frame*/
+	uint32_t src_wdth_rnd_to_chunks;
+	struct fixed32_32 scaling_coeff;
+	struct fixed32_32 h_blank_granularity_factor =
+			dal_fixed32_32_one;
+	struct fixed32_32 fx_disp_clk_mhz;
+	struct fixed32_32 line_time;
+	struct fixed32_32 disp_pipe_pix_throughput;
+	struct fixed32_32 fx_alt_disp_clk_mhz;
+	uint32_t disp_clk_khz;
+	uint32_t alt_disp_clk_khz;
+	struct display_clock_dce112 *disp_clk_110 = DCLCK112_FROM_BASE(base);
+	uint32_t max_clk_khz = get_validation_clock(base);
+	bool panning_allowed = false; /* TODO: receive this value from AS */
+
+	if (params == NULL) {
+		dal_logger_write(base->ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_GPU,
+				"Invalid input parameter in %s",
+				__func__);
+		return 0;
+	}
+
+	deep_color_factor = get_deep_color_factor(params);
+	scaler_efficiency = get_scaler_efficiency(base->ctx, params);
+	pix_clk_khz = params->requested_pixel_clock;
+	lb_source_width = params->source_view.width;
+
+	if (0 != params->dest_view.height && 0 != params->dest_view.width) {
+
+		h_scale_ratio = dal_fixed32_32_from_fraction(
+			params->source_view.width,
+			params->dest_view.width);
+		v_scale_ratio = dal_fixed32_32_from_fraction(
+			params->source_view.height,
+			params->dest_view.height);
+	} else {
+		dal_logger_write(base->ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_GPU,
+				"Destination height or width is 0!\n");
+	}
+
+	v_filter_init =
+		dal_fixed32_32_add(
+			v_scale_ratio,
+			dal_fixed32_32_add_int(
+				dal_fixed32_32_div_int(
+					dal_fixed32_32_mul_int(
+						v_scale_ratio,
+						params->timing_info.INTERLACED),
+					2),
+				params->scaling_info.v_taps + 1));
+	v_filter_init = dal_fixed32_32_div_int(v_filter_init, 2);
+
+	v_filter_init_trunc = dal_fixed32_32_floor(v_filter_init);
+
+	v_filter_init_ceil = dal_fixed32_32_from_fraction(
+						v_filter_init_trunc, 2);
+	v_filter_init_ceil = dal_fixed32_32_from_int(
+		dal_fixed32_32_ceil(v_filter_init_ceil));
+	v_filter_init_ceil = dal_fixed32_32_mul_int(v_filter_init_ceil, 2);
+
+	lines_per_lines_out_at_frame_start =
+			dal_fixed32_32_div_int(v_filter_init_ceil,
+					num_lines_at_frame_start);
+	lb_lines_in_per_line_out =
+			get_lb_lines_in_per_line_out(params, v_scale_ratio);
+
+	if (panning_allowed)
+		src_wdth_rnd_to_chunks =
+			((lb_source_width - 1) / 128) * 128 + 256;
+	else
+		src_wdth_rnd_to_chunks =
+			((lb_source_width + 127) / 128) * 128;
+
+	scaling_coeff =
+		dal_fixed32_32_div(
+			dal_fixed32_32_from_int(params->scaling_info.v_taps),
+			scaler_efficiency);
+
+	if (dal_fixed32_32_le(h_scale_ratio, dal_fixed32_32_one))
+		scaling_coeff = dal_fixed32_32_max(
+			dal_fixed32_32_from_int(
+				dal_fixed32_32_ceil(
+					dal_fixed32_32_from_fraction(
+						params->scaling_info.h_taps,
+						4))),
+			dal_fixed32_32_max(
+				dal_fixed32_32_mul(
+					scaling_coeff,
+					h_scale_ratio),
+				dal_fixed32_32_one));
+
+	if (!params->line_buffer_prefetch_enabled &&
+		dal_fixed32_32_floor(lb_lines_in_per_line_out) != 2 &&
+		dal_fixed32_32_floor(lb_lines_in_per_line_out) != 4) {
+		uint32_t line_total_pixel =
+			params->timing_info.h_total + lb_source_width - 256;
+		h_blank_granularity_factor = dal_fixed32_32_div(
+			dal_fixed32_32_from_int(params->timing_info.h_total),
+			dal_fixed32_32_div(
+			dal_fixed32_32_from_fraction(
+				line_total_pixel, 2),
+				h_scale_ratio));
+	}
+
+	/* Calculate display clock with ramping. Ramping factor is 1.1*/
+	fx_disp_clk_mhz =
+		dal_fixed32_32_div_int(
+			dal_fixed32_32_mul_int(scaling_coeff, 11),
+			10);
+	line_time = dal_fixed32_32_from_fraction(
+			params->timing_info.h_total * 1000, pix_clk_khz);
+
+	disp_pipe_pix_throughput = dal_fixed32_32_mul(
+			lb_lines_in_per_line_out, h_blank_granularity_factor);
+	disp_pipe_pix_throughput = dal_fixed32_32_max(
+			disp_pipe_pix_throughput,
+			lines_per_lines_out_at_frame_start);
+	disp_pipe_pix_throughput = dal_fixed32_32_div(dal_fixed32_32_mul_int(
+			disp_pipe_pix_throughput, src_wdth_rnd_to_chunks),
+			line_time);
+
+	if (0 != params->timing_info.h_total) {
+		fx_disp_clk_mhz =
+			dal_fixed32_32_max(
+				dal_fixed32_32_div_int(
+					dal_fixed32_32_mul_int(
+						scaling_coeff, pix_clk_khz),
+						1000),
+				disp_pipe_pix_throughput);
+		fx_disp_clk_mhz =
+			dal_fixed32_32_mul(
+				fx_disp_clk_mhz,
+				dal_fixed32_32_from_fraction(11, 10));
+	}
+
+	fx_disp_clk_mhz = dal_fixed32_32_max(fx_disp_clk_mhz,
+		dal_fixed32_32_mul(deep_color_factor,
+		dal_fixed32_32_from_fraction(11, 10)));
+
+	/* Calculate display clock without ramping */
+	fx_alt_disp_clk_mhz = scaling_coeff;
+
+	if (0 != params->timing_info.h_total) {
+		fx_alt_disp_clk_mhz = dal_fixed32_32_max(
+				dal_fixed32_32_div_int(dal_fixed32_32_mul_int(
+						scaling_coeff, pix_clk_khz),
+						1000),
+				dal_fixed32_32_div_int(dal_fixed32_32_mul_int(
+						disp_pipe_pix_throughput, 105),
+						100));
+	}
+
+	if (set_clk && disp_clk_110->ss_on_gpu_pll &&
+			disp_clk_110->gpu_pll_ss_divider)
+		fx_alt_disp_clk_mhz = dal_fixed32_32_mul(fx_alt_disp_clk_mhz,
+				dal_fixed32_32_add_int(
+				dal_fixed32_32_div_int(
+				dal_fixed32_32_div_int(
+				dal_fixed32_32_from_fraction(
+				disp_clk_110->gpu_pll_ss_percentage,
+				disp_clk_110->gpu_pll_ss_divider), 100),
+				2),
+				1));
+
+	/* convert to integer */
+	disp_clk_khz = dal_fixed32_32_round(
+			dal_fixed32_32_mul_int(fx_disp_clk_mhz, 1000));
+	alt_disp_clk_khz = dal_fixed32_32_round(
+			dal_fixed32_32_mul_int(fx_alt_disp_clk_mhz, 1000));
+
+	if ((disp_clk_khz > max_clk_khz) && (alt_disp_clk_khz <= max_clk_khz))
+		disp_clk_khz = alt_disp_clk_khz;
+
+	if (set_clk) { /* only compensate clock if we are going to set it.*/
+		disp_clk_khz = get_actual_required_display_clk(
+			disp_clk_110, disp_clk_khz);
+	}
+
+	disp_clk_khz = disp_clk_khz > max_clk_khz ? max_clk_khz : disp_clk_khz;
+
+	return disp_clk_khz;
+}
+
+static uint32_t calculate_min_clock(
+	struct display_clock *base,
+	uint32_t path_num,
+	struct min_clock_params *params)
+{
+	uint32_t i;
+	uint32_t validation_clk_khz =
+			get_validation_clock(base);
+	uint32_t min_clk_khz = validation_clk_khz;
+	uint32_t max_clk_khz = 0;
+	struct display_clock_dce112 *dc = DCLCK112_FROM_BASE(base);
+
+	if (dc->use_max_disp_clk)
+		return min_clk_khz;
+
+	if (params != NULL) {
+		uint32_t disp_clk_khz = 0;
+
+		for (i = 0; i < path_num; ++i) {
+
+			disp_clk_khz = calc_single_display_min_clks(
+							base, params, true);
+
+			/* update the max required clock found*/
+			if (disp_clk_khz > max_clk_khz)
+				max_clk_khz = disp_clk_khz;
+
+			params++;
+		}
+	}
+
+	min_clk_khz = max_clk_khz;
+
+	if (min_clk_khz > validation_clk_khz)
+		min_clk_khz = validation_clk_khz;
+	else if (min_clk_khz < base->min_display_clk_threshold_khz)
+		min_clk_khz = base->min_display_clk_threshold_khz;
+
+	if (dc->use_max_disp_clk)
+		min_clk_khz = get_validation_clock(base);
+
+	return min_clk_khz;
+}
+
+static bool display_clock_integrated_info_construct(
+	struct display_clock_dce112 *disp_clk,
+	struct adapter_service *as)
+{
+	struct integrated_info info;
+	uint32_t i;
+	struct display_clock *base = &disp_clk->disp_clk_base;
+
+	memset(&info, 0, sizeof(struct integrated_info));
+
+	disp_clk->dentist_vco_freq_khz = info.dentist_vco_freq;
+	if (disp_clk->dentist_vco_freq_khz == 0)
+		disp_clk->dentist_vco_freq_khz = 3600000;
+
+	disp_clk->crystal_freq_khz = 100000;
+
+	base->min_display_clk_threshold_khz =
+		disp_clk->dentist_vco_freq_khz / 64;
+
+	/*update the maximum display clock for each power state*/
+	for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
+		enum clocks_state clk_state = CLOCKS_STATE_INVALID;
+
+		switch (i) {
+		case 0:
+			clk_state = CLOCKS_STATE_ULTRA_LOW;
+			break;
+
+		case 1:
+			clk_state = CLOCKS_STATE_LOW;
+			break;
+
+		case 2:
+			clk_state = CLOCKS_STATE_NOMINAL;
+			break;
+
+		case 3:
+			clk_state = CLOCKS_STATE_PERFORMANCE;
+			break;
+
+		default:
+			clk_state = CLOCKS_STATE_INVALID;
+			break;
+		}
+
+		/*Do not allow bad VBIOS/SBIOS to override with invalid values,
+		 * check for > 100MHz*/
+		if (info.disp_clk_voltage[i].max_supported_clk >= 100000) {
+			max_clks_by_state[clk_state].display_clk_khz =
+				info.disp_clk_voltage[i].max_supported_clk;
+		}
+	}
+	disp_clk->dfs_bypass_enabled =
+		dal_adapter_service_is_dfs_bypass_enabled(as);
+	disp_clk->use_max_disp_clk =
+		dal_adapter_service_is_feature_supported(
+			FEATURE_USE_MAX_DISPLAY_CLK);
+
+	return true;
+}
+
+static uint32_t get_clock(struct display_clock *dc)
+{
+	uint32_t disp_clock = get_validation_clock(dc);
+	uint32_t target_div = INVALID_DIVIDER;
+	uint32_t addr = mmDENTIST_DISPCLK_CNTL;
+	uint32_t value = 0;
+	uint32_t field = 0;
+	struct display_clock_dce112 *disp_clk = DCLCK112_FROM_BASE(dc);
+
+	/* Read the mmDENTIST_DISPCLK_CNTL to get the currently programmed
+	 DID DENTIST_DISPCLK_WDIVIDER.*/
+	value = dm_read_reg(dc->ctx, addr);
+	field = get_reg_field_value(
+			value, DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER);
+
+	/* Convert DENTIST_DISPCLK_WDIVIDER to actual divider*/
+	target_div = dal_divider_range_get_divider(
+		divider_ranges,
+		DIVIDER_RANGE_MAX,
+		field);
+
+	if (target_div != INVALID_DIVIDER)
+		/* Calculate the current DFS clock in KHz.
+		 Should be okay up to 42.9 THz before overflowing.*/
+		disp_clock = (DIVIDER_RANGE_SCALE_FACTOR
+			* disp_clk->dentist_vco_freq_khz) / target_div;
+	return disp_clock;
+}
+
+static enum clocks_state get_required_clocks_state(
+		struct display_clock *dc,
+		struct state_dependent_clocks *req_clocks)
+{
+	int32_t i;
+	struct display_clock_dce112 *disp_clk = DCLCK112_FROM_BASE(dc);
+	enum clocks_state low_req_clk = disp_clk->max_clks_state;
+
+	if (!req_clocks) {
+		/* NULL pointer*/
+		dal_logger_write(dc->ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_GPU,
+				"%s: Invalid parameter",
+				__func__);
+		return CLOCKS_STATE_INVALID;
+	}
+
+	/* Iterate from highest supported to lowest valid state, and update
+	 * lowest RequiredState with the lowest state that satisfies
+	 * all required clocks
+	 */
+	for (i = disp_clk->max_clks_state; i >= CLOCKS_STATE_ULTRA_LOW; --i) {
+		if ((req_clocks->display_clk_khz <=
+			max_clks_by_state[i].display_clk_khz) &&
+			(req_clocks->pixel_clk_khz <=
+				max_clks_by_state[i].pixel_clk_khz))
+			low_req_clk = i;
+	}
+	return low_req_clk;
+}
+
+static void set_clock(
+	struct display_clock *base,
+	uint32_t requested_clk_khz)
+{
+	struct bp_set_dce_clock_parameters dce_clk_params;
+	struct display_clock_dce112 *dc = DCLCK112_FROM_BASE(base);
+	struct dc_bios *bp = dal_adapter_service_get_bios_parser(base->as);
+
+	/* Prepare to program display clock*/
+	memset(&dce_clk_params, 0, sizeof(dce_clk_params));
+
+	dce_clk_params.target_clock_frequency = requested_clk_khz;
+	dce_clk_params.pll_id = dc->disp_clk_base.id;
+	dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
+
+	bp->funcs->set_dce_clock(bp, &dce_clk_params);
+
+	/* from power down, we need mark the clock state as ClocksStateNominal
+	 * from HWReset, so when resume we will call pplib voltage regulator.*/
+	if (requested_clk_khz == 0)
+		base->cur_min_clks_state = CLOCKS_STATE_NOMINAL;
+
+	/*Program DP ref Clock*/
+	/*VBIOS will determine DPREFCLK frequency, so we don't set it*/
+	dce_clk_params.target_clock_frequency = 0;
+	dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
+	dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
+			(dce_clk_params.pll_id == CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
+
+	bp->funcs->set_dce_clock(bp, &dce_clk_params);
+}
+
+static void set_clock_state(
+	struct display_clock *dc,
+	struct display_clock_state clk_state)
+{
+	struct display_clock_dce112 *disp_clk = DCLCK112_FROM_BASE(dc);
+
+	disp_clk->clock_state = clk_state;
+}
+
+static struct display_clock_state get_clock_state(
+	struct display_clock *dc)
+{
+	struct display_clock_dce112 *disp_clk = DCLCK112_FROM_BASE(dc);
+
+	return disp_clk->clock_state;
+}
+
+static uint32_t get_dfs_bypass_threshold(struct display_clock *dc)
+{
+	return dce112_DFS_BYPASS_THRESHOLD_KHZ;
+}
+
+static const struct display_clock_funcs funcs = {
+	.destroy = destroy,
+	.calculate_min_clock = calculate_min_clock,
+	.get_clock = get_clock,
+	.get_clock_state = get_clock_state,
+	.get_dfs_bypass_threshold = get_dfs_bypass_threshold,
+	.get_dp_ref_clk_frequency = get_dp_ref_clk_frequency,
+	.get_min_clocks_state = get_min_clocks_state,
+	.get_required_clocks_state = get_required_clocks_state,
+	.get_validation_clock = get_validation_clock,
+	.set_clock = set_clock,
+	.set_clock_state = set_clock_state,
+	.set_dp_ref_clock_source = NULL,
+	.set_min_clocks_state = set_min_clocks_state,
+	.store_max_clocks_state = store_max_clocks_state,
+	.validate = NULL,
+};
+
+static bool dal_display_clock_dce112_construct(
+	struct display_clock_dce112 *dc112,
+	struct dc_context *ctx,
+	struct adapter_service *as)
+{
+	struct display_clock *dc_base = &dc112->disp_clk_base;
+
+	if (NULL == as)
+		return false;
+
+	if (!dal_display_clock_construct_base(dc_base, ctx, as))
+		return false;
+
+	dc_base->funcs = &funcs;
+
+	dc112->dfs_bypass_disp_clk = 0;
+
+	if (!display_clock_integrated_info_construct(dc112, as))
+		dal_logger_write(dc_base->ctx->logger,
+			LOG_MAJOR_WARNING,
+			LOG_MINOR_COMPONENT_GPU,
+			"Cannot obtain VBIOS integrated info\n");
+
+	dc112->gpu_pll_ss_percentage = 0;
+	dc112->gpu_pll_ss_divider = 1000;
+	dc112->ss_on_gpu_pll = false;
+
+	dc_base->id = CLOCK_SOURCE_ID_DFS;
+/* Initially set max clocks state to nominal.  This should be updated by
+ * via a pplib call to DAL IRI eventually calling a
+ * DisplayEngineClock_dce112::StoreMaxClocksState().  This call will come in
+ * on PPLIB init. This is from DCE5x. in case HW wants to use mixed method.*/
+	dc112->max_clks_state = CLOCKS_STATE_NOMINAL;
+
+	dc112->disp_clk_base.min_display_clk_threshold_khz =
+			dc112->crystal_freq_khz;
+
+	if (dc112->disp_clk_base.min_display_clk_threshold_khz <
+			(dc112->dentist_vco_freq_khz / 62))
+		dc112->disp_clk_base.min_display_clk_threshold_khz =
+				(dc112->dentist_vco_freq_khz / 62);
+
+	dal_divider_range_construct(
+		&divider_ranges[DIVIDER_RANGE_01],
+		DIVIDER_RANGE_01_START,
+		DIVIDER_RANGE_01_STEP_SIZE,
+		DIVIDER_RANGE_01_BASE_DIVIDER_ID,
+		DIVIDER_RANGE_02_BASE_DIVIDER_ID);
+	dal_divider_range_construct(
+		&divider_ranges[DIVIDER_RANGE_02],
+		DIVIDER_RANGE_02_START,
+		DIVIDER_RANGE_02_STEP_SIZE,
+		DIVIDER_RANGE_02_BASE_DIVIDER_ID,
+		DIVIDER_RANGE_03_BASE_DIVIDER_ID);
+	dal_divider_range_construct(
+		&divider_ranges[DIVIDER_RANGE_03],
+		DIVIDER_RANGE_03_START,
+		DIVIDER_RANGE_03_STEP_SIZE,
+		DIVIDER_RANGE_03_BASE_DIVIDER_ID,
+		DIVIDER_RANGE_MAX_DIVIDER_ID);
+
+	{
+		uint32_t ss_info_num =
+			dal_adapter_service_get_ss_info_num(
+				as,
+				AS_SIGNAL_TYPE_GPU_PLL);
+
+		if (ss_info_num) {
+			struct spread_spectrum_info info;
+			bool result;
+
+			memset(&info, 0, sizeof(info));
+
+			result =
+				dal_adapter_service_get_ss_info(
+					as,
+					AS_SIGNAL_TYPE_GPU_PLL,
+					0,
+					&info);
+
+			/* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
+			 * even if SS not enabled and in that case
+			 * SSInfo.spreadSpectrumPercentage !=0 would be sign
+			 * that SS is enabled
+			 */
+			if (result && info.spread_spectrum_percentage != 0) {
+				dc112->ss_on_gpu_pll = true;
+				dc112->gpu_pll_ss_divider =
+					info.spread_percentage_divider;
+
+				if (info.type.CENTER_MODE == 0) {
+					/* Currently for DP Reference clock we
+					 * need only SS percentage for
+					 * downspread */
+					dc112->gpu_pll_ss_percentage =
+						info.spread_spectrum_percentage;
+				}
+			}
+
+		}
+	}
+
+	dc112->use_max_disp_clk = true;
+
+	return true;
+}
+
+/*****************************************************************************
+ * public functions
+ *****************************************************************************/
+
+struct display_clock *dal_display_clock_dce112_create(
+	struct dc_context *ctx,
+	struct adapter_service *as)
+{
+	struct display_clock_dce112 *dc112;
+
+	dc112 = dm_alloc(sizeof(struct display_clock_dce112));
+
+	if (dc112 == NULL)
+		return NULL;
+
+	if (dal_display_clock_dce112_construct(dc112, ctx, as))
+		return &dc112->disp_clk_base;
+
+	dm_free(dc112);
+
+	return NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.h
new file mode 100644
index 0000000..02fc67a
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.h
@@ -0,0 +1,54 @@
+/*
+ * 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 __DAL_DISPLAY_CLOCK_DCE112_H__
+#define __DAL_DISPLAY_CLOCK_DCE112_H__
+
+#include "gpu/display_clock.h"
+
+struct display_clock_dce112 {
+	struct display_clock disp_clk_base;
+	/* Max display block clocks state*/
+	enum clocks_state max_clks_state;
+	bool use_max_disp_clk;
+	uint32_t crystal_freq_khz;
+	uint32_t dentist_vco_freq_khz;
+	/* Cache the status of DFS-bypass feature*/
+	bool dfs_bypass_enabled;
+	/* GPU PLL SS percentage (if down-spread enabled) */
+	uint32_t gpu_pll_ss_percentage;
+	/* GPU PLL SS percentage Divider (100 or 1000) */
+	uint32_t gpu_pll_ss_divider;
+	/* Flag for Enabled SS on GPU PLL */
+	bool ss_on_gpu_pll;
+	/* Cache the display clock returned by VBIOS if DFS-bypass is enabled.
+	 * This is basically "Crystal Frequency In KHz" (XTALIN) frequency */
+	uint32_t dfs_bypass_disp_clk;
+	struct display_clock_state clock_state;
+};
+
+#define DCLCK112_FROM_BASE(dc_base) \
+	container_of(dc_base, struct display_clock_dce112, disp_clk_base)
+
+#endif /* __DAL_DISPLAY_CLOCK_DCE112_H__ */
diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c
index 47e7922..2d394cf 100644
--- a/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c
+++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c
@@ -88,10 +88,13 @@ struct i2caux *dal_i2caux_create(
 		return dal_i2caux_dce80_create(as, ctx);
 #endif
 #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
+	case DCE_VERSION_11_0:
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	case DCE_VERSION_11_2:
+#endif
 #if defined(CONFIG_DRM_AMD_DAL_DCE10_0)
 	case DCE_VERSION_10_0:
 #endif
-	case DCE_VERSION_11_0:
 		return dal_i2caux_dce110_create(as, ctx);
 #endif
 	default:
diff --git a/drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h b/drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h
index d6a599c..da00b2e 100644
--- a/drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h
+++ b/drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h
@@ -505,7 +505,9 @@ struct bw_calcs_output {
 
 enum bw_calcs_version {
 	BW_CALCS_VERSION_INVALID,
-	BW_CALCS_VERSION_CARRIZO
+	BW_CALCS_VERSION_CARRIZO,
+	BW_CALCS_VERSION_ELLESMERE,
+	BW_CALCS_VERSION_BAFFIN
 };
 
 /**
diff --git a/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c b/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c
index cde34ce..bfffa8e 100644
--- a/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c
+++ b/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c
@@ -65,6 +65,10 @@ struct irq_service *dal_irq_service_create(
 	case DCE_VERSION_10_0:
 		return dal_irq_service_dce110_create(init_data);
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	case DCE_VERSION_11_2:
+		return dal_irq_service_dce110_create(init_data);
+#endif
 #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
 	case DCE_VERSION_11_0:
 		return dal_irq_service_dce110_create(init_data);
diff --git a/drivers/gpu/drm/amd/dal/include/dal_asic_id.h b/drivers/gpu/drm/amd/dal/include/dal_asic_id.h
index d8c4cd1..4cb6a9f 100644
--- a/drivers/gpu/drm/amd/dal/include/dal_asic_id.h
+++ b/drivers/gpu/drm/amd/dal/include/dal_asic_id.h
@@ -83,11 +83,25 @@
 #define VI_TONGA_P_A1 21
 #define VI_FIJI_P_A0 60
 
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+/* DCE112 */
+#define VI_POLARIS10_P_A0 80
+#define VI_POLARIS11_M_A0 90
+#endif
+
+#define VI_UNKNOWN 0xFF
+
 #define ASIC_REV_IS_TONGA_P(eChipRev) ((eChipRev >= VI_TONGA_P_A0) && \
 		(eChipRev < 40))
 #define ASIC_REV_IS_FIJI_P(eChipRev) ((eChipRev >= VI_FIJI_P_A0) && \
 		(eChipRev < 80))
 
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+#define ASIC_REV_IS_POLARIS10_P(eChipRev) ((eChipRev >= VI_POLARIS10_P_A0) && \
+		(eChipRev < VI_POLARIS11_M_A0))
+#define ASIC_REV_IS_POLARIS11_M(eChipRev) (eChipRev >= VI_POLARIS11_M_A0)
+#endif
+
 /* DCE11 */
 #define CZ_CARRIZO_A0 0x01
 
diff --git a/drivers/gpu/drm/amd/dal/include/dal_types.h b/drivers/gpu/drm/amd/dal/include/dal_types.h
index bcf83e9..21ee669 100644
--- a/drivers/gpu/drm/amd/dal/include/dal_types.h
+++ b/drivers/gpu/drm/amd/dal/include/dal_types.h
@@ -43,6 +43,9 @@ enum dce_version {
 #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
 	DCE_VERSION_11_0,
 #endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+	DCE_VERSION_11_2,
+#endif
 	DCE_VERSION_MAX,
 };
 
diff --git a/drivers/gpu/drm/amd/dal/include/display_clock_interface.h b/drivers/gpu/drm/amd/dal/include/display_clock_interface.h
index a625e24..317ce3b 100644
--- a/drivers/gpu/drm/amd/dal/include/display_clock_interface.h
+++ b/drivers/gpu/drm/amd/dal/include/display_clock_interface.h
@@ -131,6 +131,12 @@ struct display_clock_state {
 
 struct display_clock;
 
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
+struct display_clock *dal_display_clock_dce112_create(
+	struct dc_context *ctx,
+	struct adapter_service *as);
+#endif
+
 #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
 struct display_clock *dal_display_clock_dce110_create(
 	struct dc_context *ctx,
-- 
2.5.0



More information about the dri-devel mailing list