[PATCH 067/100] drm/amd/display: Add DCE12 core support

Alex Deucher alexdeucher at gmail.com
Mon Mar 20 20:30:02 UTC 2017


From: Harry Wentland <harry.wentland at amd.com>

Signed-off-by: Harry Wentland <harry.wentland at amd.com>
Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
---
 .../amd/display/dc/dce120/dce120_hw_sequencer.c    |  197 ++++
 .../amd/display/dc/dce120/dce120_hw_sequencer.h    |   36 +
 drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp.c |   58 +
 drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp.h |   62 ++
 .../drm/amd/display/dc/dce120/dce120_ipp_cursor.c  |  202 ++++
 .../drm/amd/display/dc/dce120/dce120_ipp_gamma.c   |  167 +++
 .../drm/amd/display/dc/dce120/dce120_mem_input.c   |  340 ++++++
 .../drm/amd/display/dc/dce120/dce120_mem_input.h   |   37 +
 .../drm/amd/display/dc/dce120/dce120_resource.c    | 1099 +++++++++++++++++++
 .../drm/amd/display/dc/dce120/dce120_resource.h    |   39 +
 .../display/dc/dce120/dce120_timing_generator.c    | 1109 ++++++++++++++++++++
 .../display/dc/dce120/dce120_timing_generator.h    |   41 +
 12 files changed, 3387 insertions(+)
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp_cursor.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp_gamma.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_mem_input.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_mem_input.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.h

diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c
new file mode 100644
index 0000000..f5ffd8f6
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c
@@ -0,0 +1,197 @@
+/*
+ * 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 "dce120_hw_sequencer.h"
+
+#include "dce110/dce110_hw_sequencer.h"
+
+/* include DCE12.0 register header files */
+#include "vega10/DC/dce_12_0_offset.h"
+#include "vega10/DC/dce_12_0_sh_mask.h"
+#include "vega10/soc15ip.h"
+#include "reg_helper.h"
+
+struct dce120_hw_seq_reg_offsets {
+	uint32_t crtc;
+};
+
+static const struct dce120_hw_seq_reg_offsets reg_offsets[] = {
+{
+	.crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
+},
+{
+	.crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
+},
+{
+	.crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
+},
+{
+	.crtc = (mmCRTC3_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
+},
+{
+	.crtc = (mmCRTC4_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
+},
+{
+	.crtc = (mmCRTC5_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
+}
+};
+
+#define HW_REG_CRTC(reg, id)\
+	(reg + reg_offsets[id].crtc)
+
+#define CNTL_ID(controller_id)\
+	controller_id
+/*******************************************************************************
+ * Private definitions
+ ******************************************************************************/
+#if 0
+static void dce120_init_pte(struct dc_context *ctx, uint8_t controller_id)
+{
+	uint32_t addr;
+	uint32_t value = 0;
+	uint32_t chunk_int = 0;
+	uint32_t chunk_mul = 0;
+/*
+	addr = mmDCP0_DVMM_PTE_CONTROL + controller_id *
+			(mmDCP1_DVMM_PTE_CONTROL- mmDCP0_DVMM_PTE_CONTROL);
+
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(
+			value, 0, DCP, controller_id,
+			DVMM_PTE_CONTROL,
+			DVMM_USE_SINGLE_PTE);
+
+	set_reg_field_value_soc15(
+			value, 1, DCP, controller_id,
+			DVMM_PTE_CONTROL,
+			DVMM_PTE_BUFFER_MODE0);
+
+	set_reg_field_value_soc15(
+			value, 1, DCP, controller_id,
+			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);
+	}
+}
+#endif
+
+static bool dce120_enable_display_power_gating(
+	struct core_dc *dc,
+	uint8_t controller_id,
+	struct dc_bios *dcb,
+	enum pipe_gating_control power_gating)
+{
+	/* disable for bringup */
+#if 0
+	enum bp_result bp_result = BP_RESULT_OK;
+	enum bp_pipe_control_action cntl;
+	struct dc_context *ctx = dc->ctx;
+
+	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);
+
+		/* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2
+		 * by default when command table is called
+		 */
+		dm_write_reg(ctx,
+			HW_REG_CRTC(mmCRTC0_CRTC_MASTER_UPDATE_MODE, controller_id),
+			0);
+	}
+
+	if (power_gating != PIPE_GATING_CONTROL_ENABLE)
+		dce120_init_pte(ctx, controller_id);
+
+	if (bp_result == BP_RESULT_OK)
+		return true;
+	else
+		return false;
+#endif
+	return false;
+}
+
+bool dce120_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.enable_display_power_gating = dce120_enable_display_power_gating;
+
+	return true;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h
new file mode 100644
index 0000000..3402413
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_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_DCE120_H__
+#define __DC_HWSS_DCE120_H__
+
+#include "core_types.h"
+
+struct core_dc;
+
+bool dce120_hw_sequencer_construct(struct core_dc *dc);
+
+#endif /* __DC_HWSS_DCE112_H__ */
+
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp.c
new file mode 100644
index 0000000..f450569
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp.c
@@ -0,0 +1,58 @@
+/*
+ * 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 "vega10/DC/dce_12_0_offset.h"
+#include "vega10/DC/dce_12_0_sh_mask.h"
+#include "vega10/soc15ip.h"
+
+#include "dce120_ipp.h"
+
+static const struct ipp_funcs funcs = {
+		.ipp_cursor_set_attributes = dce120_ipp_cursor_set_attributes,
+		.ipp_cursor_set_position = dce120_ipp_cursor_set_position,
+		.ipp_program_prescale = dce120_ipp_program_prescale,
+		.ipp_program_input_lut = dce120_ipp_program_input_lut,
+		.ipp_set_degamma = dce120_ipp_set_degamma,
+};
+
+bool dce120_ipp_construct(
+	struct dce110_ipp *ipp,
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_ipp_reg_offsets *offset)
+{
+	if (!dce110_ipp_construct(ipp, ctx, inst, offset)) {
+		ASSERT_CRITICAL(false);
+		return false;
+	}
+
+	ipp->base.funcs = &funcs;
+
+	return true;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp.h
new file mode 100644
index 0000000..4b326bc
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp.h
@@ -0,0 +1,62 @@
+/*
+ * 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_IPP_DCE120_H__
+#define __DC_IPP_DCE120_H__
+
+#include "ipp.h"
+#include "../dce110/dce110_ipp.h"
+
+
+bool dce120_ipp_construct(
+	struct dce110_ipp *ipp,
+	struct dc_context *ctx,
+	enum controller_id id,
+	const struct dce110_ipp_reg_offsets *offset);
+
+/* CURSOR RELATED */
+void dce120_ipp_cursor_set_position(
+	struct input_pixel_processor *ipp,
+	const struct dc_cursor_position *position,
+	const struct dc_cursor_mi_param *param);
+
+bool dce120_ipp_cursor_set_attributes(
+	struct input_pixel_processor *ipp,
+	const struct dc_cursor_attributes *attributes);
+
+/* DEGAMMA RELATED */
+bool dce120_ipp_set_degamma(
+	struct input_pixel_processor *ipp,
+	enum ipp_degamma_mode mode);
+
+void dce120_ipp_program_prescale(
+	struct input_pixel_processor *ipp,
+	struct ipp_prescale_params *params);
+
+void dce120_ipp_program_input_lut(
+	struct input_pixel_processor *ipp,
+	const struct dc_gamma *gamma);
+
+#endif /*__DC_IPP_DCE120_H__*/
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp_cursor.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp_cursor.c
new file mode 100644
index 0000000..d520b5d
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp_cursor.c
@@ -0,0 +1,202 @@
+/*
+ * 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 "vega10/DC/dce_12_0_offset.h"
+#include "vega10/DC/dce_12_0_sh_mask.h"
+#include "vega10/soc15ip.h"
+
+#include "../dce110/dce110_ipp.h"
+
+
+#define DCP_REG_UPDATE_N(reg_name, n, ...)	\
+		generic_reg_update_soc15(ipp110->base.ctx, ipp110->offsets.dcp_offset, reg_name, n, __VA_ARGS__)
+
+#define DCP_REG_SET_N(reg_name, n, ...)	\
+		generic_reg_set_soc15(ipp110->base.ctx, ipp110->offsets.dcp_offset, reg_name, n, __VA_ARGS__)
+
+#define DCP_REG_UPDATE(reg, field, val)	\
+		DCP_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
+
+#define DCP_REG_UPDATE_2(reg, field1, val1, field2, val2)	\
+		DCP_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define DCP_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3)	\
+		DCP_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+#define DCP_REG_SET(reg, field, val)	\
+		DCP_REG_SET_N(reg, 1, FD(reg##__##field), val)
+
+#define DCP_REG_SET_2(reg, field1, val1, field2, val2)	\
+		DCP_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define DCP_REG_SET_3(reg, field1, val1, field2, val2, field3, val3)	\
+		DCP_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+/* TODO: DAL3 does not implement cursor memory control
+ * MCIF_MEM_CONTROL, DMIF_CURSOR_MEM_CONTROL
+ */
+static void lock(
+	struct dce110_ipp *ipp110, bool lock)
+{
+	DCP_REG_UPDATE(DCP0_CUR_UPDATE, CURSOR_UPDATE_LOCK, lock);
+}
+
+static bool program_control(
+	struct dce110_ipp *ipp110,
+	enum dc_cursor_color_format color_format,
+	bool enable_magnification,
+	bool inverse_transparent_clamping)
+{
+	uint32_t mode = 0;
+
+	switch (color_format) {
+	case CURSOR_MODE_MONO:
+		mode = 0;
+		break;
+	case CURSOR_MODE_COLOR_1BIT_AND:
+		mode = 1;
+		break;
+	case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
+		mode = 2;
+		break;
+	case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
+		mode = 3;
+		break;
+	default:
+		return false;
+	}
+
+	DCP_REG_UPDATE_3(
+		DCP0_CUR_CONTROL,
+		CURSOR_MODE, mode,
+		CURSOR_2X_MAGNIFY, enable_magnification,
+		CUR_INV_TRANS_CLAMP, inverse_transparent_clamping);
+
+	if (color_format == CURSOR_MODE_MONO) {
+		DCP_REG_SET_3(
+			DCP0_CUR_COLOR1,
+			CUR_COLOR1_BLUE, 0,
+			CUR_COLOR1_GREEN, 0,
+			CUR_COLOR1_RED, 0);
+
+		DCP_REG_SET_3(
+			DCP0_CUR_COLOR2,
+			CUR_COLOR2_BLUE, 0xff,
+			CUR_COLOR2_GREEN, 0xff,
+			CUR_COLOR2_RED, 0xff);
+	}
+	return true;
+}
+
+static void program_address(
+	struct dce110_ipp *ipp110,
+	PHYSICAL_ADDRESS_LOC address)
+{
+	/* SURFACE_ADDRESS_HIGH: Higher order bits (39:32) of hardware cursor
+	 * surface base address in byte. It is 4K byte aligned.
+	 * The correct way to program cursor surface address is to first write
+	 * to CUR_SURFACE_ADDRESS_HIGH, and then write to CUR_SURFACE_ADDRESS
+	 */
+
+	DCP_REG_SET(
+		DCP0_CUR_SURFACE_ADDRESS_HIGH,
+		CURSOR_SURFACE_ADDRESS_HIGH, address.high_part);
+
+	DCP_REG_SET(
+		DCP0_CUR_SURFACE_ADDRESS,
+		CURSOR_SURFACE_ADDRESS, address.low_part);
+}
+
+void dce120_ipp_cursor_set_position(
+	struct input_pixel_processor *ipp,
+	const struct dc_cursor_position *position,
+	const struct dc_cursor_mi_param *param)
+{
+	struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+
+	/* lock cursor registers */
+	lock(ipp110, true);
+
+	/* Flag passed in structure differentiates cursor enable/disable. */
+	/* Update if it differs from cached state. */
+	DCP_REG_UPDATE(DCP0_CUR_CONTROL, CURSOR_EN, position->enable);
+
+	DCP_REG_SET_2(
+		DCP0_CUR_POSITION,
+		CURSOR_X_POSITION, position->x,
+		CURSOR_Y_POSITION, position->y);
+
+	if (position->hot_spot_enable)
+		DCP_REG_SET_2(
+			DCP0_CUR_HOT_SPOT,
+			CURSOR_HOT_SPOT_X, position->x_hotspot,
+			CURSOR_HOT_SPOT_Y, position->y_hotspot);
+
+	/* unlock cursor registers */
+	lock(ipp110, false);
+}
+
+bool dce120_ipp_cursor_set_attributes(
+	struct input_pixel_processor *ipp,
+	const struct dc_cursor_attributes *attributes)
+{
+	struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+	/* Lock cursor registers */
+	lock(ipp110, true);
+
+	/* Program cursor control */
+	program_control(
+		ipp110,
+		attributes->color_format,
+		attributes->attribute_flags.bits.ENABLE_MAGNIFICATION,
+		attributes->attribute_flags.bits.INVERSE_TRANSPARENT_CLAMPING);
+
+	/* Program hot spot coordinates */
+	DCP_REG_SET_2(
+		DCP0_CUR_HOT_SPOT,
+		CURSOR_HOT_SPOT_X, attributes->x_hot,
+		CURSOR_HOT_SPOT_Y, attributes->y_hot);
+
+	/*
+	 * Program cursor size -- NOTE: HW spec specifies that HW register
+	 * stores size as (height - 1, width - 1)
+	 */
+	DCP_REG_SET_2(
+		DCP0_CUR_SIZE,
+		CURSOR_WIDTH, attributes->width-1,
+		CURSOR_HEIGHT, attributes->height-1);
+
+	/* Program cursor surface address */
+	program_address(ipp110, attributes->address);
+
+	/* Unlock Cursor registers. */
+	lock(ipp110, false);
+
+	return true;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp_gamma.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp_gamma.c
new file mode 100644
index 0000000..7aa5a49
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_ipp_gamma.c
@@ -0,0 +1,167 @@
+/*
+ * 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 "include/fixed31_32.h"
+#include "basics/conversion.h"
+
+#include "vega10/DC/dce_12_0_offset.h"
+#include "vega10/DC/dce_12_0_sh_mask.h"
+#include "vega10/soc15ip.h"
+
+#include "../dce110/dce110_ipp.h"
+
+#define DCP_REG_UPDATE_N(reg_name, n, ...)	\
+		generic_reg_update_soc15(ipp110->base.ctx, ipp110->offsets.dcp_offset, reg_name, n, __VA_ARGS__)
+
+#define DCP_REG_SET_N(reg_name, n, ...)	\
+		generic_reg_set_soc15(ipp110->base.ctx, ipp110->offsets.dcp_offset, reg_name, n, __VA_ARGS__)
+
+#define DCP_REG_UPDATE(reg, field, val)	\
+		DCP_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
+
+#define DCP_REG_UPDATE_2(reg, field1, val1, field2, val2)	\
+		DCP_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define DCP_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3)	\
+		DCP_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+#define DCP_REG_SET(reg, field, val)	\
+		DCP_REG_SET_N(reg, 1, FD(reg##__##field), val)
+
+#define DCP_REG_SET_2(reg, field1, val1, field2, val2)	\
+		DCP_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define DCP_REG_SET_3(reg, field1, val1, field2, val2, field3, val3)	\
+		DCP_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+
+bool dce120_ipp_set_degamma(
+	struct input_pixel_processor *ipp,
+	enum ipp_degamma_mode mode)
+{
+	struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+	uint32_t degamma_type = (mode == IPP_DEGAMMA_MODE_HW_sRGB) ? 1 : 0;
+
+	ASSERT(mode == IPP_DEGAMMA_MODE_BYPASS ||
+			mode == IPP_DEGAMMA_MODE_HW_sRGB);
+
+	DCP_REG_SET_3(
+		DCP0_DEGAMMA_CONTROL,
+		GRPH_DEGAMMA_MODE, degamma_type,
+		CURSOR_DEGAMMA_MODE, degamma_type,
+		CURSOR2_DEGAMMA_MODE, degamma_type);
+
+	return true;
+}
+
+void dce120_ipp_program_prescale(
+	struct input_pixel_processor *ipp,
+	struct ipp_prescale_params *params)
+{
+	struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+
+	/* set to bypass mode first before change */
+	DCP_REG_UPDATE(
+		DCP0_PRESCALE_GRPH_CONTROL,
+		GRPH_PRESCALE_BYPASS,
+		1);
+
+	DCP_REG_SET_2(
+		DCP0_PRESCALE_VALUES_GRPH_R,
+		GRPH_PRESCALE_SCALE_R, params->scale,
+		GRPH_PRESCALE_BIAS_R, params->bias);
+
+	DCP_REG_SET_2(
+		DCP0_PRESCALE_VALUES_GRPH_G,
+		GRPH_PRESCALE_SCALE_G, params->scale,
+		GRPH_PRESCALE_BIAS_G, params->bias);
+
+	DCP_REG_SET_2(
+		DCP0_PRESCALE_VALUES_GRPH_B,
+		GRPH_PRESCALE_SCALE_B, params->scale,
+		GRPH_PRESCALE_BIAS_B, params->bias);
+
+	if (params->mode != IPP_PRESCALE_MODE_BYPASS) {
+		DCP_REG_UPDATE(DCP0_PRESCALE_GRPH_CONTROL,
+			       GRPH_PRESCALE_BYPASS, 0);
+
+		/* If prescale is in use, then legacy lut should be bypassed */
+		DCP_REG_UPDATE(DCP0_INPUT_GAMMA_CONTROL,
+			       GRPH_INPUT_GAMMA_MODE, 1);
+	}
+}
+
+static void dce120_helper_select_lut(struct dce110_ipp *ipp110)
+{
+	/* enable all */
+	DCP_REG_SET(
+		DCP0_DC_LUT_WRITE_EN_MASK,
+		DC_LUT_WRITE_EN_MASK,
+		0x7);
+
+	/* 256 entry mode */
+	DCP_REG_UPDATE(DCP0_DC_LUT_RW_MODE, DC_LUT_RW_MODE, 0);
+
+	/* LUT-256, unsigned, integer, new u0.12 format */
+	DCP_REG_SET_3(
+		DCP0_DC_LUT_CONTROL,
+		DC_LUT_DATA_R_FORMAT, 3,
+		DC_LUT_DATA_G_FORMAT, 3,
+		DC_LUT_DATA_B_FORMAT, 3);
+
+	/* start from index 0 */
+	DCP_REG_SET(
+		DCP0_DC_LUT_RW_INDEX,
+		DC_LUT_RW_INDEX,
+		0);
+}
+
+void dce120_ipp_program_input_lut(
+	struct input_pixel_processor *ipp,
+	const struct dc_gamma *gamma)
+{
+	int i;
+	struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
+
+	/* power on LUT memory */
+	DCP_REG_SET(DCFE0_DCFE_MEM_PWR_CTRL, DCP_LUT_MEM_PWR_DIS, 1);
+
+	dce120_helper_select_lut(ipp110);
+
+	for (i = 0; i < INPUT_LUT_ENTRIES; i++) {
+		DCP_REG_SET(DCP0_DC_LUT_SEQ_COLOR, DC_LUT_SEQ_COLOR, gamma->red[i]);
+		DCP_REG_SET(DCP0_DC_LUT_SEQ_COLOR, DC_LUT_SEQ_COLOR, gamma->green[i]);
+		DCP_REG_SET(DCP0_DC_LUT_SEQ_COLOR, DC_LUT_SEQ_COLOR, gamma->blue[i]);
+	}
+
+	/* power off LUT memory */
+	DCP_REG_SET(DCFE0_DCFE_MEM_PWR_CTRL, DCP_LUT_MEM_PWR_DIS, 0);
+
+	/* bypass prescale, enable legacy LUT */
+	DCP_REG_UPDATE(DCP0_PRESCALE_GRPH_CONTROL, GRPH_PRESCALE_BYPASS, 1);
+	DCP_REG_UPDATE(DCP0_INPUT_GAMMA_CONTROL, GRPH_INPUT_GAMMA_MODE, 0);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_mem_input.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_mem_input.c
new file mode 100644
index 0000000..c067721
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_mem_input.c
@@ -0,0 +1,340 @@
+/*
+ * 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 "dce120_mem_input.h"
+
+
+#include "vega10/DC/dce_12_0_offset.h"
+#include "vega10/DC/dce_12_0_sh_mask.h"
+#include "vega10/soc15ip.h"
+
+#define GENERAL_REG_UPDATE_N(reg_name, n, ...)	\
+		generic_reg_update_soc15(mem_input110->base.ctx, 0, reg_name, n, __VA_ARGS__)
+
+#define GENERAL_REG_UPDATE(reg, field, val)	\
+		GENERAL_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
+
+#define GENERAL_REG_UPDATE_2(reg, field1, val1, field2, val2)	\
+		GENERAL_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+
+
+#define DCP_REG_UPDATE_N(reg_name, n, ...)	\
+		generic_reg_update_soc15(mem_input110->base.ctx, mem_input110->offsets.dcp, reg_name, n, __VA_ARGS__)
+
+#define DCP_REG_SET_N(reg_name, n, ...)	\
+		generic_reg_set_soc15(mem_input110->base.ctx, mem_input110->offsets.dcp, reg_name, n, __VA_ARGS__)
+
+#define DCP_REG_UPDATE(reg, field, val)	\
+		DCP_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
+
+#define DCP_REG_UPDATE_2(reg, field1, val1, field2, val2)	\
+		DCP_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define DCP_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3)	\
+		DCP_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+#define DCP_REG_SET(reg, field, val)	\
+		DCP_REG_SET_N(reg, 1, FD(reg##__##field), val)
+
+#define DCP_REG_SET_2(reg, field1, val1, field2, val2)	\
+		DCP_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define DCP_REG_SET_3(reg, field1, val1, field2, val2, field3, val3)	\
+		DCP_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+
+
+#define DMIF_REG_UPDATE_N(reg_name, n, ...)	\
+		generic_reg_update_soc15(mem_input110->base.ctx, mem_input110->offsets.dmif, reg_name, n, __VA_ARGS__)
+
+#define DMIF_REG_SET_N(reg_name, n, ...)	\
+		generic_reg_set_soc15(mem_input110->base.ctx, mem_input110->offsets.dmif, reg_name, n, __VA_ARGS__)
+
+#define DMIF_REG_UPDATE(reg, field, val)	\
+		DMIF_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
+
+#define DMIF_REG_UPDATE_2(reg, field1, val1, field2, val2)	\
+		DMIF_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define DMIF_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3)	\
+		DMIF_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+#define DMIF_REG_SET(reg, field, val)	\
+		DMIF_REG_SET_N(reg, 1, FD(reg##__##field), val)
+
+#define DMIF_REG_SET_2(reg, field1, val1, field2, val2)	\
+		DMIF_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define DMIF_REG_SET_3(reg, field1, val1, field2, val2, field3, val3)	\
+		DMIF_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+
+
+#define PIPE_REG_UPDATE_N(reg_name, n, ...)	\
+		generic_reg_update_soc15(mem_input110->base.ctx, mem_input110->offsets.pipe, reg_name, n, __VA_ARGS__)
+
+#define PIPE_REG_SET_N(reg_name, n, ...)	\
+		generic_reg_set_soc15(mem_input110->base.ctx, mem_input110->offsets.pipe, reg_name, n, __VA_ARGS__)
+
+#define PIPE_REG_UPDATE(reg, field, val)	\
+		PIPE_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
+
+#define PIPE_REG_UPDATE_2(reg, field1, val1, field2, val2)	\
+		PIPE_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define PIPE_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3)	\
+		PIPE_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+#define PIPE_REG_SET(reg, field, val)	\
+		PIPE_REG_SET_N(reg, 1, FD(reg##__##field), val)
+
+#define PIPE_REG_SET_2(reg, field1, val1, field2, val2)	\
+		PIPE_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define PIPE_REG_SET_3(reg, field1, val1, field2, val2, field3, val3)	\
+		PIPE_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+
+
+static void program_sec_addr(
+	struct dce110_mem_input *mem_input110,
+	PHYSICAL_ADDRESS_LOC address)
+{
+	uint32_t temp;
+
+	/*high register MUST be programmed first*/
+	temp = address.high_part &
+		DCP0_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH__GRPH_SECONDARY_SURFACE_ADDRESS_HIGH_MASK;
+
+	DCP_REG_SET(
+		DCP0_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
+		GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
+		temp);
+
+	temp = address.low_part >>
+		DCP0_GRPH_SECONDARY_SURFACE_ADDRESS__GRPH_SECONDARY_SURFACE_ADDRESS__SHIFT;
+
+	DCP_REG_SET_2(
+		DCP0_GRPH_SECONDARY_SURFACE_ADDRESS,
+		GRPH_SECONDARY_SURFACE_ADDRESS, temp,
+		GRPH_SECONDARY_DFQ_ENABLE, 0);
+}
+
+static void program_pri_addr(
+	struct dce110_mem_input *mem_input110,
+	PHYSICAL_ADDRESS_LOC address)
+{
+	uint32_t temp;
+
+	/*high register MUST be programmed first*/
+	temp = address.high_part &
+		DCP0_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH__GRPH_PRIMARY_SURFACE_ADDRESS_HIGH_MASK;
+
+	DCP_REG_SET(
+		DCP0_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
+		GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
+		temp);
+
+	temp = address.low_part >>
+		DCP0_GRPH_PRIMARY_SURFACE_ADDRESS__GRPH_PRIMARY_SURFACE_ADDRESS__SHIFT;
+
+	DCP_REG_SET(
+		DCP0_GRPH_PRIMARY_SURFACE_ADDRESS,
+		GRPH_PRIMARY_SURFACE_ADDRESS,
+		temp);
+}
+
+
+static bool mem_input_is_flip_pending(struct mem_input *mem_input)
+{
+	struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mem_input);
+	uint32_t value;
+
+	value = dm_read_reg_soc15(mem_input110->base.ctx,
+			mmDCP0_GRPH_UPDATE, mem_input110->offsets.dcp);
+
+	if (get_reg_field_value(value, DCP0_GRPH_UPDATE,
+			GRPH_SURFACE_UPDATE_PENDING))
+		return true;
+
+	mem_input->current_address = mem_input->request_address;
+	return false;
+}
+
+static bool mem_input_program_surface_flip_and_addr(
+	struct mem_input *mem_input,
+	const struct dc_plane_address *address,
+	bool flip_immediate)
+{
+	struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mem_input);
+
+	/* TODO: Figure out if two modes are needed:
+	 * non-XDMA Mode: GRPH_SURFACE_UPDATE_IMMEDIATE_EN = 1
+	 * XDMA Mode: GRPH_SURFACE_UPDATE_H_RETRACE_EN = 1
+	 */
+	DCP_REG_UPDATE(DCP0_GRPH_UPDATE,
+			GRPH_UPDATE_LOCK, 1);
+
+	if (flip_immediate) {
+		DCP_REG_UPDATE_2(
+			DCP0_GRPH_FLIP_CONTROL,
+			GRPH_SURFACE_UPDATE_IMMEDIATE_EN, 0,
+			GRPH_SURFACE_UPDATE_H_RETRACE_EN, 1);
+	} else {
+		DCP_REG_UPDATE_2(
+			DCP0_GRPH_FLIP_CONTROL,
+			GRPH_SURFACE_UPDATE_IMMEDIATE_EN, 0,
+			GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0);
+	}
+
+	switch (address->type) {
+	case PLN_ADDR_TYPE_GRAPHICS:
+		if (address->grph.addr.quad_part == 0)
+			break;
+		program_pri_addr(mem_input110, address->grph.addr);
+		break;
+	case PLN_ADDR_TYPE_GRPH_STEREO:
+		if (address->grph_stereo.left_addr.quad_part == 0
+			|| address->grph_stereo.right_addr.quad_part == 0)
+			break;
+		program_pri_addr(mem_input110, address->grph_stereo.left_addr);
+		program_sec_addr(mem_input110, address->grph_stereo.right_addr);
+		break;
+	default:
+		/* not supported */
+		BREAK_TO_DEBUGGER();
+		break;
+	}
+
+	mem_input->request_address = *address;
+
+	if (flip_immediate)
+		mem_input->current_address = *address;
+
+	DCP_REG_UPDATE(DCP0_GRPH_UPDATE,
+			GRPH_UPDATE_LOCK, 0);
+
+	return true;
+}
+
+static void mem_input_update_dchub(struct mem_input *mi,
+		struct dchub_init_data *dh_data)
+{
+	struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mi);
+	/* TODO: port code from dal2 */
+	switch (dh_data->fb_mode) {
+	case FRAME_BUFFER_MODE_ZFB_ONLY:
+		/*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/
+		GENERAL_REG_UPDATE_2(
+				DCHUB_FB_LOCATION,
+				FB_TOP, 0,
+				FB_BASE, 0x0FFFF);
+
+		GENERAL_REG_UPDATE(
+				DCHUB_AGP_BASE,
+				AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
+
+		GENERAL_REG_UPDATE(
+				DCHUB_AGP_BOT,
+				AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
+
+		GENERAL_REG_UPDATE(
+				DCHUB_AGP_TOP,
+				AGP_TOP, (dh_data->zfb_mc_base_addr + dh_data->zfb_size_in_byte - 1) >> 22);
+		break;
+	case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL:
+		/*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
+		GENERAL_REG_UPDATE(
+				DCHUB_AGP_BASE,
+				AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
+
+		GENERAL_REG_UPDATE(
+				DCHUB_AGP_BOT,
+				AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
+
+		GENERAL_REG_UPDATE(
+				DCHUB_AGP_TOP,
+				AGP_TOP, (dh_data->zfb_mc_base_addr + dh_data->zfb_size_in_byte - 1) >> 22);
+		break;
+	case FRAME_BUFFER_MODE_LOCAL_ONLY:
+		/*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
+		GENERAL_REG_UPDATE(
+				DCHUB_AGP_BASE,
+				AGP_BASE, 0);
+
+		GENERAL_REG_UPDATE(
+				DCHUB_AGP_BOT,
+				AGP_BOT, 0x03FFFF);
+
+		GENERAL_REG_UPDATE(
+				DCHUB_AGP_TOP,
+				AGP_TOP, 0);
+		break;
+	default:
+		break;
+	}
+
+	dh_data->dchub_initialzied = true;
+	dh_data->dchub_info_valid = false;
+}
+
+static struct mem_input_funcs dce120_mem_input_funcs = {
+	.mem_input_program_display_marks = dce_mem_input_program_display_marks,
+	.allocate_mem_input = dce_mem_input_allocate_dmif,
+	.free_mem_input = dce_mem_input_free_dmif,
+	.mem_input_program_surface_flip_and_addr =
+			mem_input_program_surface_flip_and_addr,
+	.mem_input_program_pte_vm = dce_mem_input_program_pte_vm,
+	.mem_input_program_surface_config =
+			dce_mem_input_program_surface_config,
+	.mem_input_is_flip_pending = mem_input_is_flip_pending,
+	.mem_input_update_dchub = mem_input_update_dchub
+};
+
+/*****************************************/
+/* Constructor, Destructor               */
+/*****************************************/
+
+bool dce120_mem_input_construct(
+	struct dce110_mem_input *mem_input110,
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_mem_input_reg_offsets *offsets)
+{
+	/* supported stutter method
+	 * STUTTER_MODE_ENHANCED
+	 * STUTTER_MODE_QUAD_DMIF_BUFFER
+	 * STUTTER_MODE_WATERMARK_NBP_STATE
+	 */
+
+	if (!dce110_mem_input_construct(mem_input110, ctx, inst, offsets))
+		return false;
+
+	mem_input110->base.funcs = &dce120_mem_input_funcs;
+	mem_input110->offsets = *offsets;
+
+	return true;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_mem_input.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_mem_input.h
new file mode 100644
index 0000000..379fd72
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_mem_input.h
@@ -0,0 +1,37 @@
+/* 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_DCE120_H__
+#define __DC_MEM_INPUT_DCE120_H__
+
+#include "mem_input.h"
+#include "dce110/dce110_mem_input.h"
+
+bool dce120_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/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
new file mode 100644
index 0000000..9a1984b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
@@ -0,0 +1,1099 @@
+/*
+* Copyright 2012-15 Advanced Micro Devices, Inc.cls
+*
+ *
+ * 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 "stream_encoder.h"
+#include "resource.h"
+#include "include/irq_service_interface.h"
+#include "dce120_resource.h"
+#include "dce112/dce112_resource.h"
+
+#include "dce110/dce110_resource.h"
+#include "../virtual/virtual_stream_encoder.h"
+#include "dce120_timing_generator.h"
+#include "irq/dce120/irq_service_dce120.h"
+#include "dce/dce_opp.h"
+#include "dce/dce_clock_source.h"
+#include "dce/dce_clocks.h"
+#include "dce120_ipp.h"
+#include "dce110/dce110_mem_input.h"
+#include "dce120/dce120_mem_input.h"
+
+#include "dce110/dce110_hw_sequencer.h"
+#include "dce120/dce120_hw_sequencer.h"
+#include "dce/dce_transform.h"
+
+#include "dce/dce_audio.h"
+#include "dce/dce_link_encoder.h"
+#include "dce/dce_stream_encoder.h"
+#include "dce/dce_hwseq.h"
+#include "dce/dce_abm.h"
+#include "dce/dce_dmcu.h"
+
+#include "vega10/DC/dce_12_0_offset.h"
+#include "vega10/DC/dce_12_0_sh_mask.h"
+#include "vega10/soc15ip.h"
+#include "vega10/NBIO/nbio_6_1_offset.h"
+#include "reg_helper.h"
+
+#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL
+	#define mmDP0_DP_DPHY_INTERNAL_CTRL		0x210f
+	#define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX	2
+	#define mmDP1_DP_DPHY_INTERNAL_CTRL		0x220f
+	#define mmDP1_DP_DPHY_INTERNAL_CTRL_BASE_IDX	2
+	#define mmDP2_DP_DPHY_INTERNAL_CTRL		0x230f
+	#define mmDP2_DP_DPHY_INTERNAL_CTRL_BASE_IDX	2
+	#define mmDP3_DP_DPHY_INTERNAL_CTRL		0x240f
+	#define mmDP3_DP_DPHY_INTERNAL_CTRL_BASE_IDX	2
+	#define mmDP4_DP_DPHY_INTERNAL_CTRL		0x250f
+	#define mmDP4_DP_DPHY_INTERNAL_CTRL_BASE_IDX	2
+	#define mmDP5_DP_DPHY_INTERNAL_CTRL		0x260f
+	#define mmDP5_DP_DPHY_INTERNAL_CTRL_BASE_IDX	2
+	#define mmDP6_DP_DPHY_INTERNAL_CTRL		0x270f
+	#define mmDP6_DP_DPHY_INTERNAL_CTRL_BASE_IDX	2
+#endif
+
+enum dce120_clk_src_array_id {
+	DCE120_CLK_SRC_PLL0,
+	DCE120_CLK_SRC_PLL1,
+	DCE120_CLK_SRC_PLL2,
+	DCE120_CLK_SRC_PLL3,
+	DCE120_CLK_SRC_PLL4,
+	DCE120_CLK_SRC_PLL5,
+
+	DCE120_CLK_SRC_TOTAL
+};
+
+static const struct dce110_timing_generator_offsets dce120_tg_offsets[] = {
+	{
+		.crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL),
+	}
+};
+
+/* begin *********************
+ * macros to expend register list macro defined in HW object header file */
+
+#define BASE_INNER(seg) \
+	DCE_BASE__INST0_SEG ## seg
+
+#define NBIO_BASE_INNER(seg) \
+	NBIF_BASE__INST0_SEG ## seg
+
+#define NBIO_BASE(seg) \
+	NBIO_BASE_INNER(seg)
+
+/* compile time expand base address. */
+#define BASE(seg) \
+	BASE_INNER(seg)
+
+#define SR(reg_name)\
+		.reg_name = BASE(mm ## reg_name ## _BASE_IDX) +  \
+					mm ## reg_name
+
+#define SRI(reg_name, block, id)\
+	.reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+					mm ## block ## id ## _ ## reg_name
+
+/* macros to expend register list macro defined in HW object header file
+ * end *********************/
+
+
+static const struct dce_disp_clk_registers disp_clk_regs = {
+		CLK_COMMON_REG_LIST_DCE_BASE()
+};
+
+static const struct dce_disp_clk_shift disp_clk_shift = {
+		CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
+};
+
+static const struct dce_disp_clk_mask disp_clk_mask = {
+		CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
+};
+
+static const struct dce_dmcu_registers dmcu_regs = {
+		DMCU_DCE110_COMMON_REG_LIST()
+};
+
+static const struct dce_dmcu_shift dmcu_shift = {
+		DMCU_MASK_SH_LIST_DCE110(__SHIFT)
+};
+
+static const struct dce_dmcu_mask dmcu_mask = {
+		DMCU_MASK_SH_LIST_DCE110(_MASK)
+};
+
+static const struct dce_abm_registers abm_regs = {
+		ABM_DCE110_COMMON_REG_LIST()
+};
+
+static const struct dce_abm_shift abm_shift = {
+		ABM_MASK_SH_LIST_DCE110(__SHIFT)
+};
+
+static const struct dce_abm_mask abm_mask = {
+		ABM_MASK_SH_LIST_DCE110(_MASK)
+};
+
+#define transform_regs(id)\
+[id] = {\
+		XFM_COMMON_REG_LIST_DCE110(id)\
+}
+
+static const struct dce_transform_registers xfm_regs[] = {
+		transform_regs(0),
+		transform_regs(1),
+		transform_regs(2),
+		transform_regs(3),
+		transform_regs(4),
+		transform_regs(5)
+};
+
+static const struct dce_transform_shift xfm_shift = {
+		XFM_COMMON_MASK_SH_LIST_SOC_BASE(__SHIFT)
+};
+
+static const struct dce_transform_mask xfm_mask = {
+		XFM_COMMON_MASK_SH_LIST_SOC_BASE(_MASK)
+};
+
+#define aux_regs(id)\
+[id] = {\
+	AUX_REG_LIST(id)\
+}
+
+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 hpd_regs(id)\
+[id] = {\
+	HPD_REG_LIST(id)\
+}
+
+static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = {
+		hpd_regs(0),
+		hpd_regs(1),
+		hpd_regs(2),
+		hpd_regs(3),
+		hpd_regs(4),
+		hpd_regs(5)
+};
+
+#define link_regs(id)\
+[id] = {\
+	LE_DCE120_REG_LIST(id), \
+	SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \
+}
+
+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),
+	link_regs(6),
+};
+
+
+#define stream_enc_regs(id)\
+[id] = {\
+	SE_COMMON_REG_LIST(id),\
+	.TMDS_CNTL = 0,\
+}
+
+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 dce_stream_encoder_shift se_shift = {
+		SE_COMMON_MASK_SH_LIST_DCE120(__SHIFT)
+};
+
+static const struct dce_stream_encoder_mask se_mask = {
+		SE_COMMON_MASK_SH_LIST_DCE120(_MASK)
+};
+
+#define opp_regs(id)\
+[id] = {\
+	OPP_DCE_120_REG_LIST(id),\
+}
+
+static const struct dce_opp_registers opp_regs[] = {
+	opp_regs(0),
+	opp_regs(1),
+	opp_regs(2),
+	opp_regs(3),
+	opp_regs(4),
+	opp_regs(5)
+};
+
+static const struct dce_opp_shift opp_shift = {
+	OPP_COMMON_MASK_SH_LIST_DCE_120(__SHIFT)
+};
+
+static const struct dce_opp_mask opp_mask = {
+	OPP_COMMON_MASK_SH_LIST_DCE_120(_MASK)
+};
+
+#define audio_regs(id)\
+[id] = {\
+	AUD_COMMON_REG_LIST(id)\
+}
+
+static struct dce_audio_registers audio_regs[] = {
+	audio_regs(0),
+	audio_regs(1),
+	audio_regs(2),
+	audio_regs(3),
+	audio_regs(4),
+	audio_regs(5)
+};
+
+#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\
+		SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\
+		SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\
+		AUD_COMMON_MASK_SH_LIST_BASE(mask_sh)
+
+static const struct dce_audio_shift audio_shift = {
+		DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce_aduio_mask audio_mask = {
+		DCE120_AUD_COMMON_MASK_SH_LIST(_MASK)
+};
+
+#define clk_src_regs(index, id)\
+[index] = {\
+	CS_COMMON_REG_LIST_DCE_112(id),\
+}
+
+static const struct dce110_clk_src_regs clk_src_regs[] = {
+	clk_src_regs(0, A),
+	clk_src_regs(1, B),
+	clk_src_regs(2, C),
+	clk_src_regs(3, D),
+	clk_src_regs(4, E),
+	clk_src_regs(5, F)
+};
+
+static const struct dce110_clk_src_shift cs_shift = {
+		CS_COMMON_MASK_SH_LIST_DCE_112(__SHIFT)
+};
+
+static const struct dce110_clk_src_mask cs_mask = {
+		CS_COMMON_MASK_SH_LIST_DCE_112(_MASK)
+};
+
+struct output_pixel_processor *dce120_opp_create(
+	struct dc_context *ctx,
+	uint32_t inst)
+{
+	struct dce110_opp *opp =
+		dm_alloc(sizeof(struct dce110_opp));
+
+	if (!opp)
+		return NULL;
+
+	if (dce110_opp_construct(opp,
+			ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask))
+		return &opp->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(opp);
+	return NULL;
+}
+
+static const struct dce110_ipp_reg_offsets dce120_ipp_reg_offsets[] = {
+	{
+		.dcp_offset = (mmDCP0_CUR_CONTROL - mmDCP0_CUR_CONTROL),
+	},
+	{
+		.dcp_offset = (mmDCP1_CUR_CONTROL - mmDCP0_CUR_CONTROL),
+	},
+	{
+		.dcp_offset = (mmDCP2_CUR_CONTROL - mmDCP0_CUR_CONTROL),
+	},
+	{
+		.dcp_offset = (mmDCP3_CUR_CONTROL - mmDCP0_CUR_CONTROL),
+	},
+	{
+		.dcp_offset = (mmDCP4_CUR_CONTROL - mmDCP0_CUR_CONTROL),
+	},
+	{
+		.dcp_offset = (mmDCP5_CUR_CONTROL - mmDCP0_CUR_CONTROL),
+	}
+};
+
+static const struct dce110_mem_input_reg_offsets dce120_mi_reg_offsets[] = {
+	{
+		.dcp = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+		.dmif = (mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL
+				- mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE0_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+		.dmif = (mmDMIF_PG1_DPG_WATERMARK_MASK_CONTROL
+				- mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE1_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+		.dmif = (mmDMIF_PG2_DPG_WATERMARK_MASK_CONTROL
+				- mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE2_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP3_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+		.dmif = (mmDMIF_PG3_DPG_WATERMARK_MASK_CONTROL
+				- mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE3_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP4_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+		.dmif = (mmDMIF_PG4_DPG_WATERMARK_MASK_CONTROL
+				- mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE4_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP5_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+		.dmif = (mmDMIF_PG5_DPG_WATERMARK_MASK_CONTROL
+				- mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE5_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	}
+};
+
+static const struct bios_registers bios_regs = {
+	.BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 + NBIO_BASE(mmBIOS_SCRATCH_6_BASE_IDX)
+};
+
+static const struct resource_caps res_cap = {
+		.num_timing_generator = 3,
+		.num_audio = 7,
+		.num_stream_encoder = 6,
+		.num_pll = 6,
+};
+
+static const struct dc_debug debug_defaults = {
+		.disable_clock_gate = true,
+};
+
+struct clock_source *dce120_clock_source_create(
+	struct dc_context *ctx,
+	struct dc_bios *bios,
+	enum clock_source_id id,
+	const struct dce110_clk_src_regs *regs,
+	bool dp_clk_src)
+{
+	struct dce110_clk_src *clk_src =
+		dm_alloc(sizeof(struct dce110_clk_src));
+
+	if (!clk_src)
+		return NULL;
+
+	if (dce110_clk_src_construct(clk_src, ctx, bios, id,
+			regs, &cs_shift, &cs_mask)) {
+		clk_src->base.dp_clk_src = dp_clk_src;
+		return &clk_src->base;
+	}
+
+	BREAK_TO_DEBUGGER();
+	return NULL;
+}
+
+void dce120_clock_source_destroy(struct clock_source **clk_src)
+{
+	dm_free(TO_DCE110_CLK_SRC(*clk_src));
+	*clk_src = NULL;
+}
+
+
+bool dce120_hw_sequencer_create(struct core_dc *dc)
+{
+	/* All registers used by dce11.2 match those in dce11 in offset and
+	 * structure
+	 */
+	dce120_hw_sequencer_construct(dc);
+
+	/*TODO	Move to separate file and Override what is needed */
+
+	return true;
+}
+
+static struct timing_generator *dce120_timing_generator_create(
+		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 (dce120_timing_generator_construct(tg110, ctx, instance, offsets))
+		return &tg110->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(tg110);
+	return NULL;
+}
+
+static void dce120_ipp_destroy(struct input_pixel_processor **ipp)
+{
+	dm_free(TO_DCE110_IPP(*ipp));
+	*ipp = NULL;
+}
+
+static void dce120_transform_destroy(struct transform **xfm)
+{
+	dm_free(TO_DCE_TRANSFORM(*xfm));
+	*xfm = NULL;
+}
+
+static void destruct(struct dce110_resource_pool *pool)
+{
+	unsigned int i;
+
+	for (i = 0; i < pool->base.pipe_count; i++) {
+		if (pool->base.opps[i] != NULL)
+			dce110_opp_destroy(&pool->base.opps[i]);
+
+		if (pool->base.transforms[i] != NULL)
+			dce120_transform_destroy(&pool->base.transforms[i]);
+
+		if (pool->base.ipps[i] != NULL)
+			dce120_ipp_destroy(&pool->base.ipps[i]);
+
+		if (pool->base.mis[i] != NULL) {
+			dm_free(TO_DCE110_MEM_INPUT(pool->base.mis[i]));
+			pool->base.mis[i] = NULL;
+		}
+
+		if (pool->base.irqs != NULL) {
+			dal_irq_service_destroy(&pool->base.irqs);
+		}
+
+		if (pool->base.timing_generators[i] != NULL) {
+			dm_free(DCE110TG_FROM_TG(pool->base.timing_generators[i]));
+			pool->base.timing_generators[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < pool->base.audio_count; i++) {
+		if (pool->base.audios[i])
+			dce_aud_destroy(&pool->base.audios[i]);
+	}
+
+	for (i = 0; i < pool->base.stream_enc_count; i++) {
+		if (pool->base.stream_enc[i] != NULL)
+			dm_free(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i]));
+	}
+
+	for (i = 0; i < pool->base.clk_src_count; i++) {
+		if (pool->base.clock_sources[i] != NULL)
+			dce120_clock_source_destroy(
+				&pool->base.clock_sources[i]);
+	}
+
+	if (pool->base.dp_clock_source != NULL)
+		dce120_clock_source_destroy(&pool->base.dp_clock_source);
+
+	if (pool->base.abm != NULL)
+		dce_abm_destroy(&pool->base.abm);
+
+	if (pool->base.dmcu != NULL)
+		dce_dmcu_destroy(&pool->base.dmcu);
+
+	if (pool->base.display_clock != NULL)
+		dce_disp_clk_destroy(&pool->base.display_clock);
+}
+
+static void read_dce_straps(
+	struct dc_context *ctx,
+	struct resource_straps *straps)
+{
+	/* TODO: Registers are missing */
+	/*REG_GET_2(CC_DC_HDMI_STRAPS,
+			HDMI_DISABLE, &straps->hdmi_disable,
+			AUDIO_STREAM_NUMBER, &straps->audio_stream_number);
+
+	REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio);*/
+}
+
+static struct audio *create_audio(
+		struct dc_context *ctx, unsigned int inst)
+{
+	return dce_audio_create(ctx, inst,
+			&audio_regs[inst], &audio_shift, &audio_mask);
+}
+
+static const struct encoder_feature_support link_enc_feature = {
+		.max_hdmi_deep_color = COLOR_DEPTH_121212,
+		.max_hdmi_pixel_clock = 600000,
+		.ycbcr420_supported = true,
+		.flags.bits.IS_HBR2_CAPABLE = true,
+		.flags.bits.IS_HBR3_CAPABLE = true,
+		.flags.bits.IS_TPS3_CAPABLE = true,
+		.flags.bits.IS_TPS4_CAPABLE = true,
+		.flags.bits.IS_YCBCR_CAPABLE = true
+};
+
+struct link_encoder *dce120_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 (dce110_link_encoder_construct(
+			enc110,
+			enc_init_data,
+			&link_enc_feature,
+			&link_enc_regs[enc_init_data->transmitter],
+			&link_enc_aux_regs[enc_init_data->channel - 1],
+			&link_enc_hpd_regs[enc_init_data->hpd_source])) {
+
+		return &enc110->base;
+	}
+
+	BREAK_TO_DEBUGGER();
+	dm_free(enc110);
+	return NULL;
+}
+
+static struct input_pixel_processor *dce120_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 (dce120_ipp_construct(ipp, ctx, inst, offset))
+		return &ipp->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(ipp);
+	return NULL;
+}
+
+static struct stream_encoder *dce120_stream_encoder_create(
+	enum engine_id eng_id,
+	struct dc_context *ctx)
+{
+	struct dce110_stream_encoder *enc110 =
+		dm_alloc(sizeof(struct dce110_stream_encoder));
+
+	if (!enc110)
+		return NULL;
+
+	if (dce110_stream_encoder_construct(
+			enc110, ctx, ctx->dc_bios, eng_id,
+			&stream_enc_regs[eng_id], &se_shift, &se_mask))
+		return &enc110->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(enc110);
+	return NULL;
+}
+
+#define SRII(reg_name, block, id)\
+	.reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+					mm ## block ## id ## _ ## reg_name
+
+static const struct dce_hwseq_registers hwseq_reg = {
+		HWSEQ_DCE112_REG_LIST()
+};
+
+static const struct dce_hwseq_shift hwseq_shift = {
+		HWSEQ_DCE12_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce_hwseq_mask hwseq_mask = {
+		HWSEQ_DCE12_MASK_SH_LIST(_MASK)
+};
+
+static struct dce_hwseq *dce120_hwseq_create(
+	struct dc_context *ctx)
+{
+	struct dce_hwseq *hws = dm_alloc(sizeof(struct dce_hwseq));
+
+	if (hws) {
+		hws->ctx = ctx;
+		hws->regs = &hwseq_reg;
+		hws->shifts = &hwseq_shift;
+		hws->masks = &hwseq_mask;
+	}
+	return hws;
+}
+
+static const struct resource_create_funcs res_create_funcs = {
+	.read_dce_straps = read_dce_straps,
+	.create_audio = create_audio,
+	.create_stream_encoder = dce120_stream_encoder_create,
+	.create_hwseq = dce120_hwseq_create,
+};
+
+#define mi_inst_regs(id) { MI_DCE12_REG_LIST(id) }
+static const struct dce_mem_input_registers mi_regs[] = {
+		mi_inst_regs(0),
+		mi_inst_regs(1),
+		mi_inst_regs(2),
+		mi_inst_regs(3),
+		mi_inst_regs(4),
+		mi_inst_regs(5),
+};
+
+static const struct dce_mem_input_shift mi_shifts = {
+		MI_DCE12_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce_mem_input_mask mi_masks = {
+		MI_DCE12_MASK_SH_LIST(_MASK)
+};
+
+static struct mem_input *dce120_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 (dce120_mem_input_construct(mem_input110, ctx, inst, offset)) {
+		struct mem_input *mi = &mem_input110->base;
+
+		mi->regs = &mi_regs[inst];
+		mi->shifts = &mi_shifts;
+		mi->masks = &mi_masks;
+		return mi;
+	}
+
+	BREAK_TO_DEBUGGER();
+	dm_free(mem_input110);
+	return NULL;
+}
+
+static struct transform *dce120_transform_create(
+	struct dc_context *ctx,
+	uint32_t inst)
+{
+	struct dce_transform *transform =
+		dm_alloc(sizeof(struct dce_transform));
+
+	if (!transform)
+		return NULL;
+
+	if (dce_transform_construct(transform, ctx, inst,
+			&xfm_regs[inst], &xfm_shift, &xfm_mask)) {
+		transform->lb_memory_size = 0x1404; /*5124*/
+		return &transform->base;
+	}
+
+	BREAK_TO_DEBUGGER();
+	dm_free(transform);
+	return NULL;
+}
+
+static void dce120_destroy_resource_pool(struct resource_pool **pool)
+{
+	struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool);
+
+	destruct(dce110_pool);
+	dm_free(dce110_pool);
+	*pool = NULL;
+}
+
+static const struct resource_funcs dce120_res_pool_funcs = {
+	.destroy = dce120_destroy_resource_pool,
+	.link_enc_create = dce120_link_encoder_create,
+	.validate_with_context = dce112_validate_with_context,
+	.validate_guaranteed = dce112_validate_guaranteed,
+	.validate_bandwidth = dce112_validate_bandwidth
+};
+
+static void bw_calcs_data_update_from_pplib(struct core_dc *dc)
+{
+	struct dm_pp_clock_levels_with_latency eng_clks = {0};
+	struct dm_pp_clock_levels_with_latency mem_clks = {0};
+	struct dm_pp_wm_sets_with_clock_ranges clk_ranges = {0};
+	int i;
+	unsigned int clk;
+	unsigned int latency;
+
+	/*do system clock*/
+	if (!dm_pp_get_clock_levels_by_type_with_latency(
+				dc->ctx,
+				DM_PP_CLOCK_TYPE_ENGINE_CLK,
+				&eng_clks) || eng_clks.num_levels == 0) {
+
+		eng_clks.num_levels = 8;
+		clk = 300000;
+
+		for (i = 0; i < eng_clks.num_levels; i++) {
+			eng_clks.data[i].clocks_in_khz = clk;
+			clk += 100000;
+		}
+	}
+
+	/* convert all the clock fro kHz to fix point mHz  TODO: wloop data */
+	dc->bw_vbios.high_sclk = bw_frc_to_fixed(
+		eng_clks.data[eng_clks.num_levels-1].clocks_in_khz, 1000);
+	dc->bw_vbios.mid1_sclk  = bw_frc_to_fixed(
+		eng_clks.data[eng_clks.num_levels/8].clocks_in_khz, 1000);
+	dc->bw_vbios.mid2_sclk  = bw_frc_to_fixed(
+		eng_clks.data[eng_clks.num_levels*2/8].clocks_in_khz, 1000);
+	dc->bw_vbios.mid3_sclk  = bw_frc_to_fixed(
+		eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz, 1000);
+	dc->bw_vbios.mid4_sclk  = bw_frc_to_fixed(
+		eng_clks.data[eng_clks.num_levels*4/8].clocks_in_khz, 1000);
+	dc->bw_vbios.mid5_sclk  = bw_frc_to_fixed(
+		eng_clks.data[eng_clks.num_levels*5/8].clocks_in_khz, 1000);
+	dc->bw_vbios.mid6_sclk  = bw_frc_to_fixed(
+		eng_clks.data[eng_clks.num_levels*6/8].clocks_in_khz, 1000);
+	dc->bw_vbios.low_sclk  = bw_frc_to_fixed(
+			eng_clks.data[0].clocks_in_khz, 1000);
+
+	/*do memory clock*/
+	if (!dm_pp_get_clock_levels_by_type_with_latency(
+			dc->ctx,
+			DM_PP_CLOCK_TYPE_MEMORY_CLK,
+			&mem_clks) || mem_clks.num_levels == 0) {
+
+		mem_clks.num_levels = 3;
+		clk = 250000;
+		latency = 45;
+
+		for (i = 0; i < eng_clks.num_levels; i++) {
+			mem_clks.data[i].clocks_in_khz = clk;
+			mem_clks.data[i].latency_in_us = latency;
+			clk += 500000;
+			latency -= 5;
+		}
+
+	}
+
+	/* we don't need to call PPLIB for validation clock since they
+	 * also give us the highest sclk and highest mclk (UMA clock).
+	 * ALSO always convert UMA clock (from PPLIB)  to YCLK (HW formula):
+	 * YCLK = UMACLK*m_memoryTypeMultiplier
+	 */
+	dc->bw_vbios.low_yclk = bw_frc_to_fixed(
+		mem_clks.data[0].clocks_in_khz * MEMORY_TYPE_MULTIPLIER, 1000);
+	dc->bw_vbios.mid_yclk = bw_frc_to_fixed(
+		mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER,
+		1000);
+	dc->bw_vbios.high_yclk = bw_frc_to_fixed(
+		mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER,
+		1000);
+
+	/* Now notify PPLib/SMU about which Watermarks sets they should select
+	 * depending on DPM state they are in. And update BW MGR GFX Engine and
+	 * Memory clock member variables for Watermarks calculations for each
+	 * Watermark Set
+	 */
+	clk_ranges.num_wm_sets = 4;
+	clk_ranges.wm_clk_ranges[0].wm_set_id = WM_SET_A;
+	clk_ranges.wm_clk_ranges[0].wm_min_eng_clk_in_khz =
+			eng_clks.data[0].clocks_in_khz;
+	clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz =
+			eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1;
+	clk_ranges.wm_clk_ranges[0].wm_min_memg_clk_in_khz =
+			mem_clks.data[0].clocks_in_khz;
+	clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz =
+			mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1;
+
+	clk_ranges.wm_clk_ranges[1].wm_set_id = WM_SET_B;
+	clk_ranges.wm_clk_ranges[1].wm_min_eng_clk_in_khz =
+			eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz;
+	/* 5 GHz instead of data[7].clockInKHz to cover Overdrive */
+	clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000;
+	clk_ranges.wm_clk_ranges[1].wm_min_memg_clk_in_khz =
+			mem_clks.data[0].clocks_in_khz;
+	clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz =
+			mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1;
+
+	clk_ranges.wm_clk_ranges[2].wm_set_id = WM_SET_C;
+	clk_ranges.wm_clk_ranges[2].wm_min_eng_clk_in_khz =
+			eng_clks.data[0].clocks_in_khz;
+	clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz =
+			eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1;
+	clk_ranges.wm_clk_ranges[2].wm_min_memg_clk_in_khz =
+			mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz;
+	/* 5 GHz instead of data[2].clockInKHz to cover Overdrive */
+	clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000;
+
+	clk_ranges.wm_clk_ranges[3].wm_set_id = WM_SET_D;
+	clk_ranges.wm_clk_ranges[3].wm_min_eng_clk_in_khz =
+			eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz;
+	/* 5 GHz instead of data[7].clockInKHz to cover Overdrive */
+	clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000;
+	clk_ranges.wm_clk_ranges[3].wm_min_memg_clk_in_khz =
+			mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz;
+	/* 5 GHz instead of data[2].clockInKHz to cover Overdrive */
+	clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000;
+
+	/* Notify PP Lib/SMU which Watermarks to use for which clock ranges */
+	dm_pp_notify_wm_clock_changes(dc->ctx, &clk_ranges);
+}
+
+static bool construct(
+	uint8_t num_virtual_links,
+	struct core_dc *dc,
+	struct dce110_resource_pool *pool)
+{
+	unsigned int i;
+	struct dc_context *ctx = dc->ctx;
+
+	ctx->dc_bios->regs = &bios_regs;
+
+	pool->base.res_cap = &res_cap;
+	pool->base.funcs = &dce120_res_pool_funcs;
+
+	/* TODO: Fill more data from GreenlandAsicCapability.cpp */
+	pool->base.pipe_count = 6;
+	pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE;
+
+	dc->public.caps.max_downscale_ratio = 200;
+	dc->public.caps.i2c_speed_in_khz = 100;
+	dc->public.caps.max_cursor_size = 128;
+	dc->public.debug = debug_defaults;
+
+	/*************************************************
+	 *  Create resources                             *
+	 *************************************************/
+
+	pool->base.clock_sources[DCE120_CLK_SRC_PLL0] =
+			dce120_clock_source_create(ctx, ctx->dc_bios,
+				CLOCK_SOURCE_COMBO_PHY_PLL0,
+				&clk_src_regs[0], false);
+	pool->base.clock_sources[DCE120_CLK_SRC_PLL1] =
+			dce120_clock_source_create(ctx, ctx->dc_bios,
+				CLOCK_SOURCE_COMBO_PHY_PLL1,
+				&clk_src_regs[1], false);
+	pool->base.clock_sources[DCE120_CLK_SRC_PLL2] =
+			dce120_clock_source_create(ctx, ctx->dc_bios,
+				CLOCK_SOURCE_COMBO_PHY_PLL2,
+				&clk_src_regs[2], false);
+	pool->base.clock_sources[DCE120_CLK_SRC_PLL3] =
+			dce120_clock_source_create(ctx, ctx->dc_bios,
+				CLOCK_SOURCE_COMBO_PHY_PLL3,
+				&clk_src_regs[3], false);
+	pool->base.clock_sources[DCE120_CLK_SRC_PLL4] =
+			dce120_clock_source_create(ctx, ctx->dc_bios,
+				CLOCK_SOURCE_COMBO_PHY_PLL4,
+				&clk_src_regs[4], false);
+	pool->base.clock_sources[DCE120_CLK_SRC_PLL5] =
+			dce120_clock_source_create(ctx, ctx->dc_bios,
+				CLOCK_SOURCE_COMBO_PHY_PLL5,
+				&clk_src_regs[5], false);
+	pool->base.clk_src_count = DCE120_CLK_SRC_TOTAL;
+
+	pool->base.dp_clock_source =
+			dce120_clock_source_create(ctx, ctx->dc_bios,
+				CLOCK_SOURCE_ID_DP_DTO,
+				&clk_src_regs[0], true);
+
+	for (i = 0; i < pool->base.clk_src_count; i++) {
+		if (pool->base.clock_sources[i] == NULL) {
+			dm_error("DC: failed to create clock sources!\n");
+			BREAK_TO_DEBUGGER();
+			goto clk_src_create_fail;
+		}
+	}
+
+	pool->base.display_clock = dce120_disp_clk_create(ctx,
+			&disp_clk_regs,
+			&disp_clk_shift,
+			&disp_clk_mask);
+	if (pool->base.display_clock == NULL) {
+		dm_error("DC: failed to create display clock!\n");
+		BREAK_TO_DEBUGGER();
+		goto disp_clk_create_fail;
+	}
+
+	pool->base.dmcu = dce_dmcu_create(ctx,
+			&dmcu_regs,
+			&dmcu_shift,
+			&dmcu_mask);
+	if (pool->base.dmcu == NULL) {
+		dm_error("DC: failed to create dmcu!\n");
+		BREAK_TO_DEBUGGER();
+		goto res_create_fail;
+	}
+
+	pool->base.abm = dce_abm_create(ctx,
+			&abm_regs,
+			&abm_shift,
+			&abm_mask);
+	if (pool->base.abm == NULL) {
+		dm_error("DC: failed to create abm!\n");
+		BREAK_TO_DEBUGGER();
+		goto res_create_fail;
+	}
+
+	{
+	#if defined(CONFIG_DRM_AMD_DC_DCE12_0)
+		struct irq_service_init_data init_data;
+		init_data.ctx = dc->ctx;
+		pool->base.irqs = dal_irq_service_dce120_create(&init_data);
+		if (!pool->base.irqs)
+			goto irqs_create_fail;
+	#endif
+	}
+
+	for (i = 0; i < pool->base.pipe_count; i++) {
+		pool->base.timing_generators[i] =
+				dce120_timing_generator_create(
+					ctx,
+					i,
+					&dce120_tg_offsets[i]);
+		if (pool->base.timing_generators[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error("DC: failed to create tg!\n");
+			goto controller_create_fail;
+		}
+
+		pool->base.mis[i] = dce120_mem_input_create(ctx,
+				i, &dce120_mi_reg_offsets[i]);
+
+		if (pool->base.mis[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create memory input!\n");
+			goto controller_create_fail;
+		}
+
+		pool->base.ipps[i] = dce120_ipp_create(ctx, i,
+				&dce120_ipp_reg_offsets[i]);
+		if (pool->base.ipps[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create input pixel processor!\n");
+			goto controller_create_fail;
+		}
+
+		pool->base.transforms[i] = dce120_transform_create(ctx, i);
+		if (pool->base.transforms[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create transform!\n");
+			goto res_create_fail;
+		}
+
+		pool->base.opps[i] = dce120_opp_create(
+			ctx,
+			i);
+		if (pool->base.opps[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create output pixel processor!\n");
+		}
+	}
+
+	if (!resource_construct(num_virtual_links, dc, &pool->base,
+			 &res_create_funcs))
+		goto res_create_fail;
+
+	/* Create hardware sequencer */
+	if (!dce120_hw_sequencer_create(dc))
+		goto controller_create_fail;
+
+	bw_calcs_init(&dc->bw_dceip, &dc->bw_vbios, dc->ctx->asic_id);
+
+	bw_calcs_data_update_from_pplib(dc);
+
+	return true;
+
+irqs_create_fail:
+controller_create_fail:
+disp_clk_create_fail:
+clk_src_create_fail:
+res_create_fail:
+
+	destruct(pool);
+
+	return false;
+}
+
+struct resource_pool *dce120_create_resource_pool(
+	uint8_t num_virtual_links,
+	struct core_dc *dc)
+{
+	struct dce110_resource_pool *pool =
+		dm_alloc(sizeof(struct dce110_resource_pool));
+
+	if (!pool)
+		return NULL;
+
+	if (construct(num_virtual_links, dc, pool))
+		return &pool->base;
+
+	BREAK_TO_DEBUGGER();
+	return NULL;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.h
new file mode 100644
index 0000000..038c78d
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.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 __DC_RESOURCE_DCE120_H__
+#define __DC_RESOURCE_DCE120_H__
+
+#include "core_types.h"
+
+struct core_dc;
+struct resource_pool;
+
+struct resource_pool *dce120_create_resource_pool(
+	uint8_t num_virtual_links,
+	struct core_dc *dc);
+
+#endif /* __DC_RESOURCE_DCE120_H__ */
+
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c
new file mode 100644
index 0000000..d7e787b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c
@@ -0,0 +1,1109 @@
+/*
+ * 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 "vega10/DC/dce_12_0_offset.h"
+#include "vega10/DC/dce_12_0_sh_mask.h"
+#include "vega10/soc15ip.h"
+
+#include "dc_types.h"
+#include "dc_bios_types.h"
+
+#include "include/grph_object_id.h"
+#include "include/logger_interface.h"
+#include "dce120_timing_generator.h"
+
+#include "timing_generator.h"
+
+#define CRTC_REG_UPDATE_N(reg_name, n, ...)	\
+		generic_reg_update_soc15(tg110->base.ctx, tg110->offsets.crtc, reg_name, n, __VA_ARGS__)
+
+#define CRTC_REG_SET_N(reg_name, n, ...)	\
+		generic_reg_set_soc15(tg110->base.ctx, tg110->offsets.crtc, reg_name, n, __VA_ARGS__)
+
+#define CRTC_REG_UPDATE(reg, field, val)	\
+		CRTC_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
+
+#define CRTC_REG_UPDATE_2(reg, field1, val1, field2, val2)	\
+		CRTC_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define CRTC_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3)	\
+		CRTC_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+#define CRTC_REG_UPDATE_4(reg, field1, val1, field2, val2, field3, val3, field4, val4)	\
+		CRTC_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3, FD(reg##__##field4), val4)
+
+#define CRTC_REG_UPDATE_5(reg, field1, val1, field2, val2, field3, val3, field4, val4, field5, val5)	\
+		CRTC_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3, FD(reg##__##field4), val4, FD(reg##__##field5), val5)
+
+#define CRTC_REG_SET(reg, field, val)	\
+		CRTC_REG_SET_N(reg, 1, FD(reg##__##field), val)
+
+#define CRTC_REG_SET_2(reg, field1, val1, field2, val2)	\
+		CRTC_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define CRTC_REG_SET_3(reg, field1, val1, field2, val2, field3, val3)	\
+		CRTC_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+/**
+ *****************************************************************************
+ *  Function: is_in_vertical_blank
+ *
+ *  @brief
+ *     check the current status of CRTC to check if we are in Vertical Blank
+ *     regioneased" state
+ *
+ *  @return
+ *     true if currently in blank region, false otherwise
+ *
+ *****************************************************************************
+ */
+static bool dce120_timing_generator_is_in_vertical_blank(
+		struct timing_generator *tg)
+{
+	uint32_t field = 0;
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+	uint32_t value = dm_read_reg_soc15(
+					tg->ctx,
+					mmCRTC0_CRTC_STATUS,
+					tg110->offsets.crtc);
+
+	field = get_reg_field_value(value, CRTC0_CRTC_STATUS, CRTC_V_BLANK);
+	return field == 1;
+}
+
+
+/* determine if given timing can be supported by TG */
+bool dce120_timing_generator_validate_timing(
+	struct timing_generator *tg,
+	const struct dc_crtc_timing *timing,
+	enum signal_type signal)
+{
+	uint32_t interlace_factor = timing->flags.INTERLACE ? 2 : 1;
+	uint32_t v_blank =
+					(timing->v_total - timing->v_addressable -
+					timing->v_border_top - timing->v_border_bottom) *
+					interlace_factor;
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	if (!dce110_timing_generator_validate_timing(
+					tg,
+					timing,
+					signal))
+		return false;
+
+
+	if (v_blank < tg110->min_v_blank	||
+		 timing->h_sync_width  < tg110->min_h_sync_width ||
+		 timing->v_sync_width  < tg110->min_v_sync_width)
+		return false;
+
+	return true;
+}
+
+bool dce120_tg_validate_timing(struct timing_generator *tg,
+	const struct dc_crtc_timing *timing)
+{
+	return dce120_timing_generator_validate_timing(tg, timing, SIGNAL_TYPE_NONE);
+}
+
+/******** HW programming ************/
+/* Disable/Enable Timing Generator */
+bool dce120_timing_generator_enable_crtc(struct timing_generator *tg)
+{
+	enum bp_result result;
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	/* Set MASTER_UPDATE_MODE to 0
+	 * This is needed for DRR, and also suggested to be default value by Syed.*/
+
+	CRTC_REG_UPDATE(CRTC0_CRTC_MASTER_UPDATE_MODE,
+			MASTER_UPDATE_MODE, 0);
+
+	CRTC_REG_UPDATE(CRTC0_CRTC_MASTER_UPDATE_LOCK,
+			UNDERFLOW_UPDATE_LOCK, 0);
+
+	/* TODO API for AtomFirmware didn't change*/
+	result = tg->bp->funcs->enable_crtc(tg->bp, tg110->controller_id, true);
+
+	return result == BP_RESULT_OK;
+}
+
+void dce120_timing_generator_set_early_control(
+		struct timing_generator *tg,
+		uint32_t early_cntl)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	CRTC_REG_UPDATE(CRTC0_CRTC_CONTROL,
+			CRTC_HBLANK_EARLY_CONTROL, early_cntl);
+}
+
+/**************** TG current status ******************/
+
+/* return the current frame counter. Used by Linux kernel DRM */
+uint32_t dce120_timing_generator_get_vblank_counter(
+		struct timing_generator *tg)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+	uint32_t value = dm_read_reg_soc15(
+				tg->ctx,
+				mmCRTC0_CRTC_STATUS_FRAME_COUNT,
+				tg110->offsets.crtc);
+	uint32_t field = get_reg_field_value(
+				value, CRTC0_CRTC_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT);
+
+	return field;
+}
+
+/* Get current H and V position */
+void dce120_timing_generator_get_crtc_positions(
+	struct timing_generator *tg,
+	int32_t *h_position,
+	int32_t *v_position)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+	uint32_t value = dm_read_reg_soc15(
+				tg->ctx,
+				mmCRTC0_CRTC_STATUS_POSITION,
+				tg110->offsets.crtc);
+
+	*h_position = get_reg_field_value(
+					value, CRTC0_CRTC_STATUS_POSITION, CRTC_HORZ_COUNT);
+
+	*v_position = get_reg_field_value(
+						value, CRTC0_CRTC_STATUS_POSITION, CRTC_VERT_COUNT);
+}
+
+/* wait until TG is in beginning of vertical blank region */
+void dce120_timing_generator_wait_for_vblank(struct timing_generator *tg)
+{
+	/* We want to catch beginning of VBlank here, so if the first try are
+	 * in VBlank, we might be very close to Active, in this case wait for
+	 * another frame
+	 */
+	while (dce120_timing_generator_is_in_vertical_blank(tg)) {
+		if (!tg->funcs->is_counter_moving(tg)) {
+			/* error - no point to wait if counter is not moving */
+			break;
+		}
+	}
+
+	while (!dce120_timing_generator_is_in_vertical_blank(tg)) {
+		if (!tg->funcs->is_counter_moving(tg)) {
+			/* error - no point to wait if counter is not moving */
+			break;
+		}
+	}
+}
+
+/* wait until TG is in beginning of active region */
+void dce120_timing_generator_wait_for_vactive(struct timing_generator *tg)
+{
+	while (dce120_timing_generator_is_in_vertical_blank(tg)) {
+		if (!tg->funcs->is_counter_moving(tg)) {
+			/* error - no point to wait if counter is not moving */
+			break;
+		}
+	}
+}
+
+/*********** Timing Generator Synchronization routines ****/
+
+/* Setups Global Swap Lock group, TimingServer or TimingClient*/
+void dce120_timing_generator_setup_global_swap_lock(
+	struct timing_generator *tg,
+	const struct dcp_gsl_params *gsl_params)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+	uint32_t value_crtc_vtotal =
+							dm_read_reg_soc15(tg->ctx,
+							mmCRTC0_CRTC_V_TOTAL,
+							tg110->offsets.crtc);
+	/* Checkpoint relative to end of frame */
+	uint32_t check_point =
+							get_reg_field_value(value_crtc_vtotal,
+							CRTC0_CRTC_V_TOTAL,
+							CRTC_V_TOTAL);
+
+
+	dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_GSL_WINDOW, tg110->offsets.crtc, 0);
+
+	CRTC_REG_UPDATE_N(DCP0_DCP_GSL_CONTROL, 6,
+		/* This pipe will belong to GSL Group zero. */
+		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL0_EN), 1,
+		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_MASTER_EN), gsl_params->gsl_master == tg->inst,
+		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_FORCE_DELAY), HFLIP_READY_DELAY,
+		/* Keep signal low (pending high) during 6 lines.
+		 * Also defines minimum interval before re-checking signal. */
+		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_CHECK_DELAY), HFLIP_CHECK_DELAY,
+		/* DCP_GSL_PURPOSE_SURFACE_FLIP */
+		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_SYNC_SOURCE), 0,
+		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_DELAY_SURFACE_UPDATE_PENDING), 1);
+
+	CRTC_REG_SET_2(
+			CRTC0_CRTC_GSL_CONTROL,
+			CRTC_GSL_CHECK_LINE_NUM, check_point - FLIP_READY_BACK_LOOKUP,
+			CRTC_GSL_FORCE_DELAY, VFLIP_READY_DELAY);
+}
+
+/* Clear all the register writes done by setup_global_swap_lock */
+void dce120_timing_generator_tear_down_global_swap_lock(
+	struct timing_generator *tg)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	/* Settig HW default values from reg specs */
+	CRTC_REG_SET_N(DCP0_DCP_GSL_CONTROL, 6,
+			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL0_EN), 0,
+			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_MASTER_EN), 0,
+			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_FORCE_DELAY), HFLIP_READY_DELAY,
+			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_CHECK_DELAY), HFLIP_CHECK_DELAY,
+			/* DCP_GSL_PURPOSE_SURFACE_FLIP */
+			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_SYNC_SOURCE), 0,
+			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_DELAY_SURFACE_UPDATE_PENDING), 0);
+
+		CRTC_REG_SET_2(
+			CRTC0_CRTC_GSL_CONTROL,
+			CRTC_GSL_CHECK_LINE_NUM, 0,
+			CRTC_GSL_FORCE_DELAY, 0x2); /*TODO Why this value here ?*/
+}
+
+/* Reset slave controllers on master VSync */
+void dce120_timing_generator_enable_reset_trigger(
+	struct timing_generator *tg,
+	int source)
+{
+	enum trigger_source_select trig_src_select = TRIGGER_SOURCE_SELECT_LOGIC_ZERO;
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+	uint32_t rising_edge = 0;
+	uint32_t falling_edge = 0;
+	/* Setup trigger edge */
+	uint32_t pol_value = dm_read_reg_soc15(
+									tg->ctx,
+									mmCRTC0_CRTC_V_SYNC_A_CNTL,
+									tg110->offsets.crtc);
+
+	/* Register spec has reversed definition:
+	 *	0 for positive, 1 for negative */
+	if (get_reg_field_value(pol_value,
+			CRTC0_CRTC_V_SYNC_A_CNTL,
+			CRTC_V_SYNC_A_POL) == 0) {
+		rising_edge = 1;
+	} else {
+		falling_edge = 1;
+	}
+
+	/* TODO What about other sources ?*/
+	trig_src_select = TRIGGER_SOURCE_SELECT_GSL_GROUP0;
+
+	CRTC_REG_UPDATE_N(CRTC0_CRTC_TRIGB_CNTL, 7,
+		FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_SOURCE_SELECT), trig_src_select,
+		FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_POLARITY_SELECT), TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
+		FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_RISING_EDGE_DETECT_CNTL), rising_edge,
+		FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_FALLING_EDGE_DETECT_CNTL), falling_edge,
+		/* send every signal */
+		FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_FREQUENCY_SELECT), 0,
+		/* no delay */
+		FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_DELAY), 0,
+		/* clear trigger status */
+		FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_CLEAR), 1);
+
+	CRTC_REG_UPDATE_3(
+			CRTC0_CRTC_FORCE_COUNT_NOW_CNTL,
+			CRTC_FORCE_COUNT_NOW_MODE, 2,
+			CRTC_FORCE_COUNT_NOW_TRIG_SEL, 1,
+			CRTC_FORCE_COUNT_NOW_CLEAR, 1);
+}
+
+/* disabling trigger-reset */
+void dce120_timing_generator_disable_reset_trigger(
+	struct timing_generator *tg)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	CRTC_REG_UPDATE_2(
+		CRTC0_CRTC_FORCE_COUNT_NOW_CNTL,
+		CRTC_FORCE_COUNT_NOW_MODE, 0,
+		CRTC_FORCE_COUNT_NOW_CLEAR, 1);
+
+	CRTC_REG_UPDATE_3(
+		CRTC0_CRTC_TRIGB_CNTL,
+		CRTC_TRIGB_SOURCE_SELECT, TRIGGER_SOURCE_SELECT_LOGIC_ZERO,
+		CRTC_TRIGB_POLARITY_SELECT, TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
+		/* clear trigger status */
+		CRTC_TRIGB_CLEAR, 1);
+
+}
+
+/* Checks whether CRTC triggered reset occurred */
+bool dce120_timing_generator_did_triggered_reset_occur(
+	struct timing_generator *tg)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+	uint32_t value = dm_read_reg_soc15(
+			tg->ctx,
+			mmCRTC0_CRTC_FORCE_COUNT_NOW_CNTL,
+			tg110->offsets.crtc);
+
+	return get_reg_field_value(value,
+			CRTC0_CRTC_FORCE_COUNT_NOW_CNTL,
+			CRTC_FORCE_COUNT_NOW_OCCURRED) != 0;
+}
+
+
+/******** Stuff to move to other virtual HW objects *****************/
+/* Move to enable accelerated mode */
+void dce120_timing_generator_disable_vga(struct timing_generator *tg)
+{
+	uint32_t addr = 0;
+	uint32_t offset = 0;
+	uint32_t value = 0;
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	switch (tg110->controller_id) {
+	case CONTROLLER_ID_D0:
+		addr = mmD1VGA_CONTROL;
+		offset = 0;
+		break;
+	case CONTROLLER_ID_D1:
+		addr = mmD2VGA_CONTROL;
+		offset = mmD2VGA_CONTROL - mmD1VGA_CONTROL;
+		break;
+	case CONTROLLER_ID_D2:
+		addr = mmD3VGA_CONTROL;
+		offset = mmD3VGA_CONTROL - mmD1VGA_CONTROL;
+		break;
+	case CONTROLLER_ID_D3:
+		addr = mmD4VGA_CONTROL;
+		offset = mmD4VGA_CONTROL - mmD1VGA_CONTROL;
+		break;
+	case CONTROLLER_ID_D4:
+		addr = mmD1VGA_CONTROL;
+		offset = mmD1VGA_CONTROL - mmD1VGA_CONTROL;
+		break;
+	case CONTROLLER_ID_D5:
+		addr = mmD6VGA_CONTROL;
+		offset = mmD6VGA_CONTROL - mmD1VGA_CONTROL;
+		break;
+	default:
+		break;
+	}
+
+	value = dm_read_reg_soc15(tg->ctx, mmD1VGA_CONTROL, offset);
+
+	set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_MODE_ENABLE);
+	set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_TIMING_SELECT);
+	set_reg_field_value(
+			value, 0, D1VGA_CONTROL, D1VGA_SYNC_POLARITY_SELECT);
+	set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_OVERSCAN_COLOR_EN);
+
+	dm_write_reg_soc15(tg->ctx, mmD1VGA_CONTROL, offset, value);
+}
+/* TODO: Should we move it to transform */
+/* Fully program CRTC timing in timing generator */
+void dce120_timing_generator_program_blanking(
+	struct timing_generator *tg,
+	const struct dc_crtc_timing *timing)
+{
+	uint32_t tmp1 = 0;
+	uint32_t tmp2 = 0;
+	uint32_t vsync_offset = timing->v_border_bottom +
+			timing->v_front_porch;
+	uint32_t v_sync_start = timing->v_addressable + vsync_offset;
+
+	uint32_t hsync_offset = timing->h_border_right +
+			timing->h_front_porch;
+	uint32_t h_sync_start = timing->h_addressable + hsync_offset;
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	CRTC_REG_UPDATE(
+			CRTC0_CRTC_H_TOTAL,
+			CRTC_H_TOTAL,
+			timing->h_total - 1);
+
+	CRTC_REG_UPDATE(
+		CRTC0_CRTC_V_TOTAL,
+		CRTC_V_TOTAL,
+		timing->v_total - 1);
+
+	tmp1 = timing->h_total -
+			(h_sync_start + timing->h_border_left);
+	tmp2 = tmp1 + timing->h_addressable +
+			timing->h_border_left + timing->h_border_right;
+
+	CRTC_REG_UPDATE_2(
+			CRTC0_CRTC_H_BLANK_START_END,
+			CRTC_H_BLANK_END, tmp1,
+			CRTC_H_BLANK_START, tmp2);
+
+	tmp1 = timing->v_total - (v_sync_start + timing->v_border_top);
+	tmp2 = tmp1 + timing->v_addressable + timing->v_border_top +
+			timing->v_border_bottom;
+
+	CRTC_REG_UPDATE_2(
+		CRTC0_CRTC_V_BLANK_START_END,
+		CRTC_V_BLANK_END, tmp1,
+		CRTC_V_BLANK_START, tmp2);
+}
+
+/* TODO: Should we move it to opp? */
+/* Combine with below and move YUV/RGB color conversion to SW layer */
+void dce120_timing_generator_program_blank_color(
+	struct timing_generator *tg,
+	const struct tg_color *black_color)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	CRTC_REG_UPDATE_3(
+		CRTC0_CRTC_BLACK_COLOR,
+		CRTC_BLACK_COLOR_B_CB, black_color->color_b_cb,
+		CRTC_BLACK_COLOR_G_Y, black_color->color_g_y,
+		CRTC_BLACK_COLOR_R_CR, black_color->color_r_cr);
+}
+/* Combine with above and move YUV/RGB color conversion to SW layer */
+void dce120_timing_generator_set_overscan_color_black(
+	struct timing_generator *tg,
+	const struct tg_color *color)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+	uint32_t value = 0;
+	CRTC_REG_SET_3(
+		CRTC0_CRTC_OVERSCAN_COLOR,
+		CRTC_OVERSCAN_COLOR_BLUE, color->color_b_cb,
+		CRTC_OVERSCAN_COLOR_GREEN, color->color_g_y,
+		CRTC_OVERSCAN_COLOR_RED, color->color_r_cr);
+
+	value = dm_read_reg_soc15(
+			tg->ctx,
+			mmCRTC0_CRTC_OVERSCAN_COLOR,
+			tg110->offsets.crtc);
+
+	dm_write_reg_soc15(
+			tg->ctx,
+			mmCRTC0_CRTC_BLACK_COLOR,
+			tg110->offsets.crtc,
+			value);
+
+	/* This is desirable to have a constant DAC output voltage during the
+	 * blank time that is higher than the 0 volt reference level that the
+	 * DAC outputs when the NBLANK signal
+	 * is asserted low, such as for output to an analog TV. */
+	dm_write_reg_soc15(
+		tg->ctx,
+		mmCRTC0_CRTC_BLANK_DATA_COLOR,
+		tg110->offsets.crtc,
+		value);
+
+	/* TO DO we have to program EXT registers and we need to know LB DATA
+	 * format because it is used when more 10 , i.e. 12 bits per color
+	 *
+	 * m_mmDxCRTC_OVERSCAN_COLOR_EXT
+	 * m_mmDxCRTC_BLACK_COLOR_EXT
+	 * m_mmDxCRTC_BLANK_DATA_COLOR_EXT
+	 */
+}
+
+void dce120_timing_generator_set_drr(
+	struct timing_generator *tg,
+	const struct drr_params *params)
+{
+
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	if (params != NULL &&
+		params->vertical_total_max > 0 &&
+		params->vertical_total_min > 0) {
+
+		CRTC_REG_UPDATE(
+				CRTC0_CRTC_V_TOTAL_MIN,
+				CRTC_V_TOTAL_MIN, params->vertical_total_min - 1);
+		CRTC_REG_UPDATE(
+				CRTC0_CRTC_V_TOTAL_MAX,
+				CRTC_V_TOTAL_MAX, params->vertical_total_max - 1);
+		CRTC_REG_SET_N(CRTC0_CRTC_V_TOTAL_CONTROL, 6,
+				FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MIN_SEL), 1,
+				FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MAX_SEL), 1,
+				FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_ON_EVENT), 0,
+				FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_TO_MASTER_VSYNC), 0,
+				FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_SET_V_TOTAL_MIN_MASK_EN), 0,
+				FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_SET_V_TOTAL_MIN_MASK), 0);
+		CRTC_REG_UPDATE(
+				CRTC0_CRTC_STATIC_SCREEN_CONTROL,
+				CRTC_STATIC_SCREEN_EVENT_MASK,
+				0x180);
+
+	} else {
+		CRTC_REG_UPDATE(
+				CRTC0_CRTC_V_TOTAL_MIN,
+				CRTC_V_TOTAL_MIN, 0);
+		CRTC_REG_UPDATE(
+				CRTC0_CRTC_V_TOTAL_MAX,
+				CRTC_V_TOTAL_MAX, 0);
+		CRTC_REG_SET_N(CRTC0_CRTC_V_TOTAL_CONTROL, 5,
+				FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MIN_SEL), 0,
+				FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MAX_SEL), 0,
+				FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_ON_EVENT), 0,
+				FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_TO_MASTER_VSYNC), 0,
+				FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_SET_V_TOTAL_MIN_MASK), 0);
+		CRTC_REG_UPDATE(
+				CRTC0_CRTC_STATIC_SCREEN_CONTROL,
+				CRTC_STATIC_SCREEN_EVENT_MASK,
+				0);
+	}
+}
+
+uint32_t dce120_timing_generator_get_crtc_scanoutpos(
+	struct timing_generator *tg,
+	uint32_t *vbl,
+	uint32_t *position)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	*vbl = dm_read_reg_soc15(
+			tg->ctx,
+			mmCRTC0_CRTC_V_BLANK_START_END,
+			tg110->offsets.crtc);
+
+	*position = dm_read_reg_soc15(
+				tg->ctx,
+				mmCRTC0_CRTC_STATUS_POSITION,
+				tg110->offsets.crtc);
+
+	return 0;
+}
+
+void dce120_timing_generator_enable_advanced_request(
+	struct timing_generator *tg,
+	bool enable,
+	const struct dc_crtc_timing *timing)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+	uint32_t v_sync_width_and_b_porch =
+				timing->v_total - timing->v_addressable -
+				timing->v_border_bottom - timing->v_front_porch;
+	uint32_t value = dm_read_reg_soc15(
+				tg->ctx,
+				mmCRTC0_CRTC_START_LINE_CONTROL,
+				tg110->offsets.crtc);
+
+
+	if (enable) {
+		set_reg_field_value(
+			value,
+			0,
+			CRTC0_CRTC_START_LINE_CONTROL,
+			CRTC_LEGACY_REQUESTOR_EN);
+	} else {
+		set_reg_field_value(
+			value,
+			1,
+			CRTC0_CRTC_START_LINE_CONTROL,
+			CRTC_LEGACY_REQUESTOR_EN);
+	}
+
+	/* Program advanced line position acc.to the best case from fetching data perspective to hide MC latency
+	 * and prefilling Line Buffer in V Blank (to 10 lines as LB can store max 10 lines)
+	 */
+	if (v_sync_width_and_b_porch > 10)
+		set_reg_field_value(
+			value,
+			10,
+			CRTC0_CRTC_START_LINE_CONTROL,
+			CRTC_ADVANCED_START_LINE_POSITION);
+	else
+		set_reg_field_value(
+			value,
+			v_sync_width_and_b_porch,
+			CRTC0_CRTC_START_LINE_CONTROL,
+			CRTC_ADVANCED_START_LINE_POSITION);
+
+	dm_write_reg_soc15(tg->ctx,
+			mmCRTC0_CRTC_START_LINE_CONTROL,
+			tg110->offsets.crtc,
+			value);
+}
+
+void dce120_tg_program_blank_color(struct timing_generator *tg,
+	const struct tg_color *black_color)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+	uint32_t value = 0;
+
+	CRTC_REG_UPDATE_3(
+		CRTC0_CRTC_BLACK_COLOR,
+		CRTC_BLACK_COLOR_B_CB, black_color->color_b_cb,
+		CRTC_BLACK_COLOR_G_Y, black_color->color_g_y,
+		CRTC_BLACK_COLOR_R_CR, black_color->color_r_cr);
+
+	value = dm_read_reg_soc15(
+				tg->ctx,
+				mmCRTC0_CRTC_BLACK_COLOR,
+				tg110->offsets.crtc);
+	dm_write_reg_soc15(
+		tg->ctx,
+		mmCRTC0_CRTC_BLANK_DATA_COLOR,
+		tg110->offsets.crtc,
+		value);
+}
+
+void dce120_tg_set_overscan_color(struct timing_generator *tg,
+	const struct tg_color *overscan_color)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	CRTC_REG_SET_3(
+		CRTC0_CRTC_OVERSCAN_COLOR,
+		CRTC_OVERSCAN_COLOR_BLUE, overscan_color->color_b_cb,
+		CRTC_OVERSCAN_COLOR_GREEN, overscan_color->color_g_y,
+		CRTC_OVERSCAN_COLOR_RED, overscan_color->color_r_cr);
+}
+
+void dce120_tg_program_timing(struct timing_generator *tg,
+	const struct dc_crtc_timing *timing,
+	bool use_vbios)
+{
+	if (use_vbios)
+			dce110_timing_generator_program_timing_generator(tg, timing);
+		else
+			dce120_timing_generator_program_blanking(tg, timing);
+}
+
+bool dce120_tg_is_blanked(struct timing_generator *tg)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+	uint32_t value = dm_read_reg_soc15(
+			tg->ctx,
+			mmCRTC0_CRTC_BLANK_CONTROL,
+			tg110->offsets.crtc);
+
+	if (
+		get_reg_field_value(
+			value,
+			CRTC0_CRTC_BLANK_CONTROL,
+			CRTC_BLANK_DATA_EN) == 1	&&
+		get_reg_field_value(
+			value,
+			CRTC0_CRTC_BLANK_CONTROL,
+			CRTC_CURRENT_BLANK_STATE) == 1)
+			return true;
+
+	return false;
+}
+
+void dce120_tg_set_blank(struct timing_generator *tg,
+		bool enable_blanking)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	CRTC_REG_SET(
+		CRTC0_CRTC_DOUBLE_BUFFER_CONTROL,
+		CRTC_BLANK_DATA_DOUBLE_BUFFER_EN, 0);
+
+	if (enable_blanking) {
+		CRTC_REG_SET(
+			CRTC0_CRTC_BLANK_CONTROL,
+			CRTC_BLANK_DATA_EN, 1);
+
+	} else
+		dm_write_reg_soc15(
+			tg->ctx,
+			mmCRTC0_CRTC_BLANK_CONTROL,
+			tg110->offsets.crtc,
+			0);
+}
+
+bool dce120_tg_validate_timing(struct timing_generator *tg,
+	const struct dc_crtc_timing *timing);
+
+void dce120_tg_wait_for_state(struct timing_generator *tg,
+	enum crtc_state state)
+{
+	switch (state) {
+	case CRTC_STATE_VBLANK:
+		dce120_timing_generator_wait_for_vblank(tg);
+		break;
+
+	case CRTC_STATE_VACTIVE:
+		dce120_timing_generator_wait_for_vactive(tg);
+		break;
+
+	default:
+		break;
+	}
+}
+
+void dce120_tg_set_colors(struct timing_generator *tg,
+	const struct tg_color *blank_color,
+	const struct tg_color *overscan_color)
+{
+	if (blank_color != NULL)
+		dce120_tg_program_blank_color(tg, blank_color);
+
+	if (overscan_color != NULL)
+		dce120_tg_set_overscan_color(tg, overscan_color);
+}
+
+static void dce120_timing_generator_set_static_screen_control(
+	struct timing_generator *tg,
+	uint32_t value)
+{
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+
+	CRTC_REG_UPDATE_2(CRTC0_CRTC_STATIC_SCREEN_CONTROL,
+			CRTC_STATIC_SCREEN_EVENT_MASK, value,
+			CRTC_STATIC_SCREEN_FRAME_COUNT, 2);
+}
+
+void dce120_timing_generator_set_test_pattern(
+	struct timing_generator *tg,
+	/* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode'
+	 * because this is not DP-specific (which is probably somewhere in DP
+	 * encoder) */
+	enum controller_dp_test_pattern test_pattern,
+	enum dc_color_depth color_depth)
+{
+	struct dc_context *ctx = tg->ctx;
+	uint32_t value;
+	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
+	enum test_pattern_color_format bit_depth;
+	enum test_pattern_dyn_range dyn_range;
+	enum test_pattern_mode mode;
+	/* color ramp generator mixes 16-bits color */
+	uint32_t src_bpc = 16;
+	/* requested bpc */
+	uint32_t dst_bpc;
+	uint32_t index;
+	/* RGB values of the color bars.
+	 * Produce two RGB colors: RGB0 - white (all Fs)
+	 * and RGB1 - black (all 0s)
+	 * (three RGB components for two colors)
+	 */
+	uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000,
+						0x0000, 0x0000};
+	/* dest color (converted to the specified color format) */
+	uint16_t dst_color[6];
+	uint32_t inc_base;
+
+	/* translate to bit depth */
+	switch (color_depth) {
+	case COLOR_DEPTH_666:
+		bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6;
+	break;
+	case COLOR_DEPTH_888:
+		bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8;
+	break;
+	case COLOR_DEPTH_101010:
+		bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10;
+	break;
+	case COLOR_DEPTH_121212:
+		bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12;
+	break;
+	default:
+		bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8;
+	break;
+	}
+
+	switch (test_pattern) {
+	case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES:
+	case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA:
+	{
+		dyn_range = (test_pattern ==
+				CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ?
+				TEST_PATTERN_DYN_RANGE_CEA :
+				TEST_PATTERN_DYN_RANGE_VESA);
+		mode = TEST_PATTERN_MODE_COLORSQUARES_RGB;
+
+		CRTC_REG_UPDATE_2(CRTC0_CRTC_TEST_PATTERN_PARAMETERS,
+				CRTC_TEST_PATTERN_VRES, 6,
+				CRTC_TEST_PATTERN_HRES, 6);
+
+		CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL,
+				CRTC_TEST_PATTERN_EN, 1,
+				CRTC_TEST_PATTERN_MODE, mode,
+				CRTC_TEST_PATTERN_DYNAMIC_RANGE, dyn_range,
+				CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth);
+	}
+	break;
+
+	case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS:
+	case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS:
+	{
+		mode = (test_pattern ==
+			CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ?
+			TEST_PATTERN_MODE_VERTICALBARS :
+			TEST_PATTERN_MODE_HORIZONTALBARS);
+
+		switch (bit_depth) {
+		case TEST_PATTERN_COLOR_FORMAT_BPC_6:
+			dst_bpc = 6;
+		break;
+		case TEST_PATTERN_COLOR_FORMAT_BPC_8:
+			dst_bpc = 8;
+		break;
+		case TEST_PATTERN_COLOR_FORMAT_BPC_10:
+			dst_bpc = 10;
+		break;
+		default:
+			dst_bpc = 8;
+		break;
+		}
+
+		/* adjust color to the required colorFormat */
+		for (index = 0; index < 6; index++) {
+			/* dst = 2^dstBpc * src / 2^srcBpc = src >>
+			 * (srcBpc - dstBpc);
+			 */
+			dst_color[index] =
+				src_color[index] >> (src_bpc - dst_bpc);
+		/* CRTC_TEST_PATTERN_DATA has 16 bits,
+		 * lowest 6 are hardwired to ZERO
+		 * color bits should be left aligned aligned to MSB
+		 * XXXXXXXXXX000000 for 10 bit,
+		 * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6
+		 */
+			dst_color[index] <<= (16 - dst_bpc);
+		}
+
+		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_PARAMETERS, tg110->offsets.crtc, 0);
+
+		/* We have to write the mask before data, similar to pipeline.
+		 * For example, for 8 bpc, if we want RGB0 to be magenta,
+		 * and RGB1 to be cyan,
+		 * we need to make 7 writes:
+		 * MASK   DATA
+		 * 000001 00000000 00000000                     set mask to R0
+		 * 000010 11111111 00000000     R0 255, 0xFF00, set mask to G0
+		 * 000100 00000000 00000000     G0 0,   0x0000, set mask to B0
+		 * 001000 11111111 00000000     B0 255, 0xFF00, set mask to R1
+		 * 010000 00000000 00000000     R1 0,   0x0000, set mask to G1
+		 * 100000 11111111 00000000     G1 255, 0xFF00, set mask to B1
+		 * 100000 11111111 00000000     B1 255, 0xFF00
+		 *
+		 * we will make a loop of 6 in which we prepare the mask,
+		 * then write, then prepare the color for next write.
+		 * first iteration will write mask only,
+		 * but each next iteration color prepared in
+		 * previous iteration will be written within new mask,
+		 * the last component will written separately,
+		 * mask is not changing between 6th and 7th write
+		 * and color will be prepared by last iteration
+		 */
+
+		/* write color, color values mask in CRTC_TEST_PATTERN_MASK
+		 * is B1, G1, R1, B0, G0, R0
+		 */
+		value = 0;
+		for (index = 0; index < 6; index++) {
+			/* prepare color mask, first write PATTERN_DATA
+			 * will have all zeros
+			 */
+			set_reg_field_value(
+				value,
+				(1 << index),
+				CRTC0_CRTC_TEST_PATTERN_COLOR,
+				CRTC_TEST_PATTERN_MASK);
+			/* write color component */
+			dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value);
+			/* prepare next color component,
+			 * will be written in the next iteration
+			 */
+			set_reg_field_value(
+				value,
+				dst_color[index],
+				CRTC0_CRTC_TEST_PATTERN_COLOR,
+				CRTC_TEST_PATTERN_DATA);
+		}
+		/* write last color component,
+		 * it's been already prepared in the loop
+		 */
+		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value);
+
+		/* enable test pattern */
+		CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL,
+				CRTC_TEST_PATTERN_EN, 1,
+				CRTC_TEST_PATTERN_MODE, mode,
+				CRTC_TEST_PATTERN_DYNAMIC_RANGE, 0,
+				CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth);
+	}
+	break;
+
+	case CONTROLLER_DP_TEST_PATTERN_COLORRAMP:
+	{
+		mode = (bit_depth ==
+			TEST_PATTERN_COLOR_FORMAT_BPC_10 ?
+			TEST_PATTERN_MODE_DUALRAMP_RGB :
+			TEST_PATTERN_MODE_SINGLERAMP_RGB);
+
+		switch (bit_depth) {
+		case TEST_PATTERN_COLOR_FORMAT_BPC_6:
+			dst_bpc = 6;
+		break;
+		case TEST_PATTERN_COLOR_FORMAT_BPC_8:
+			dst_bpc = 8;
+		break;
+		case TEST_PATTERN_COLOR_FORMAT_BPC_10:
+			dst_bpc = 10;
+		break;
+		default:
+			dst_bpc = 8;
+		break;
+		}
+
+		/* increment for the first ramp for one color gradation
+		 * 1 gradation for 6-bit color is 2^10
+		 * gradations in 16-bit color
+		 */
+		inc_base = (src_bpc - dst_bpc);
+
+		switch (bit_depth) {
+		case TEST_PATTERN_COLOR_FORMAT_BPC_6:
+		{
+			CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS,
+					CRTC_TEST_PATTERN_INC0, inc_base,
+					CRTC_TEST_PATTERN_INC1, 0,
+					CRTC_TEST_PATTERN_HRES, 6,
+					CRTC_TEST_PATTERN_VRES, 6,
+					CRTC_TEST_PATTERN_RAMP0_OFFSET, 0);
+		}
+		break;
+		case TEST_PATTERN_COLOR_FORMAT_BPC_8:
+		{
+			CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS,
+					CRTC_TEST_PATTERN_INC0, inc_base,
+					CRTC_TEST_PATTERN_INC1, 0,
+					CRTC_TEST_PATTERN_HRES, 8,
+					CRTC_TEST_PATTERN_VRES, 6,
+					CRTC_TEST_PATTERN_RAMP0_OFFSET, 0);
+		}
+		break;
+		case TEST_PATTERN_COLOR_FORMAT_BPC_10:
+		{
+			CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS,
+					CRTC_TEST_PATTERN_INC0, inc_base,
+					CRTC_TEST_PATTERN_INC1, inc_base + 2,
+					CRTC_TEST_PATTERN_HRES, 8,
+					CRTC_TEST_PATTERN_VRES, 5,
+					CRTC_TEST_PATTERN_RAMP0_OFFSET, 384 << 6);
+		}
+		break;
+		default:
+		break;
+		}
+
+		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, 0);
+
+		/* enable test pattern */
+		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc, 0);
+
+		CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL,
+				CRTC_TEST_PATTERN_EN, 1,
+				CRTC_TEST_PATTERN_MODE, mode,
+				CRTC_TEST_PATTERN_DYNAMIC_RANGE, 0,
+				CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth);
+	}
+	break;
+	case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE:
+	{
+		value = 0;
+		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc,  value);
+		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value);
+		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_PARAMETERS, tg110->offsets.crtc, value);
+	}
+	break;
+	default:
+	break;
+	}
+}
+
+static struct timing_generator_funcs dce120_tg_funcs = {
+		.validate_timing = dce120_tg_validate_timing,
+		.program_timing = dce120_tg_program_timing,
+		.enable_crtc = dce120_timing_generator_enable_crtc,
+		.disable_crtc = dce110_timing_generator_disable_crtc,
+		/* used by enable_timing_synchronization. Not need for FPGA */
+		.is_counter_moving = dce110_timing_generator_is_counter_moving,
+		/* never be called */
+		.get_position = dce120_timing_generator_get_crtc_positions,
+		.get_frame_count = dce120_timing_generator_get_vblank_counter,
+		.get_scanoutpos = dce120_timing_generator_get_crtc_scanoutpos,
+		.set_early_control = dce120_timing_generator_set_early_control,
+		/* used by enable_timing_synchronization. Not need for FPGA */
+		.wait_for_state = dce120_tg_wait_for_state,
+		.set_blank = dce120_tg_set_blank,
+		.is_blanked = dce120_tg_is_blanked,
+		/* never be called */
+		.set_colors = dce120_tg_set_colors,
+		.set_overscan_blank_color = dce120_timing_generator_set_overscan_color_black,
+		.set_blank_color = dce120_timing_generator_program_blank_color,
+		.disable_vga = dce120_timing_generator_disable_vga,
+		.did_triggered_reset_occur = dce120_timing_generator_did_triggered_reset_occur,
+		.setup_global_swap_lock = dce120_timing_generator_setup_global_swap_lock,
+		.enable_reset_trigger = dce120_timing_generator_enable_reset_trigger,
+		.disable_reset_trigger = dce120_timing_generator_disable_reset_trigger,
+		.tear_down_global_swap_lock = dce120_timing_generator_tear_down_global_swap_lock,
+		.enable_advanced_request = dce120_timing_generator_enable_advanced_request,
+		.set_drr = dce120_timing_generator_set_drr,
+		.set_static_screen_control = dce120_timing_generator_set_static_screen_control,
+		.set_test_pattern = dce120_timing_generator_set_test_pattern
+};
+
+
+bool dce120_timing_generator_construct(
+	struct dce110_timing_generator *tg110,
+	struct dc_context *ctx,
+	uint32_t instance,
+	const struct dce110_timing_generator_offsets *offsets)
+{
+	if (!tg110)
+			return false;
+
+	tg110->controller_id = CONTROLLER_ID_D0 + instance;
+	tg110->base.inst = instance;
+
+	tg110->offsets = *offsets;
+
+	tg110->base.funcs = &dce120_tg_funcs;
+
+	tg110->base.ctx = ctx;
+	tg110->base.bp = ctx->dc_bios;
+
+	tg110->max_h_total = CRTC0_CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1;
+	tg110->max_v_total = CRTC0_CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1;
+
+	/*//CRTC requires a minimum HBLANK = 32 pixels and o
+	 * Minimum HSYNC = 8 pixels*/
+	tg110->min_h_blank = 32;
+	/*DCE12_CRTC_Block_ARch.doc*/
+	tg110->min_h_front_porch = 0;
+	tg110->min_h_back_porch = 0;
+
+	tg110->min_h_sync_width = 8;
+	tg110->min_v_sync_width = 1;
+	tg110->min_v_blank = 3;
+
+	return true;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.h
new file mode 100644
index 0000000..243c0a3
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.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_TIMING_GENERATOR_DCE120_H__
+#define __DC_TIMING_GENERATOR_DCE120_H__
+
+#include "timing_generator.h"
+#include "../include/grph_object_id.h"
+#include "../include/hw_sequencer_types.h"
+#include "dce110/dce110_timing_generator.h"
+
+
+bool dce120_timing_generator_construct(
+	struct dce110_timing_generator *tg110,
+	struct dc_context *ctx,
+	uint32_t instance,
+	const struct dce110_timing_generator_offsets *offsets);
+
+#endif /* __DC_TIMING_GENERATOR_DCE120_H__ */
-- 
2.5.5



More information about the amd-gfx mailing list