From: Harry Wentland <harry.wentl...@amd.com>

Signed-off-by: Harry Wentland <harry.wentl...@amd.com>
Signed-off-by: Alex Deucher <alexander.deuc...@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

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to