aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.14.71/0276-drm-amd-display-Add-DCE12-core-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/0276-drm-amd-display-Add-DCE12-core-support.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.14.71/0276-drm-amd-display-Add-DCE12-core-support.patch3496
1 files changed, 3496 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/0276-drm-amd-display-Add-DCE12-core-support.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/0276-drm-amd-display-Add-DCE12-core-support.patch
new file mode 100644
index 00000000..774d72e3
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/0276-drm-amd-display-Add-DCE12-core-support.patch
@@ -0,0 +1,3496 @@
+From 0babc74552e1f38dce837f82f72ecf0d189e171c Mon Sep 17 00:00:00 2001
+From: Harry Wentland <harry.wentland@amd.com>
+Date: Mon, 6 Mar 2017 14:36:02 -0500
+Subject: [PATCH 0276/4131] drm/amd/display: Add DCE12 core support
+
+Signed-off-by: Harry Wentland <harry.wentland@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@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.7.4
+