aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2437-drm-amd-display-Add-DCN2-OPTC.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2437-drm-amd-display-Add-DCN2-OPTC.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2437-drm-amd-display-Add-DCN2-OPTC.patch755
1 files changed, 755 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2437-drm-amd-display-Add-DCN2-OPTC.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2437-drm-amd-display-Add-DCN2-OPTC.patch
new file mode 100644
index 00000000..a448bad1
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2437-drm-amd-display-Add-DCN2-OPTC.patch
@@ -0,0 +1,755 @@
+From f1aaa19c20e9fd483c18f3e08f259a9f7b9863c8 Mon Sep 17 00:00:00 2001
+From: Harry Wentland <harry.wentland@amd.com>
+Date: Fri, 22 Feb 2019 10:19:04 -0500
+Subject: [PATCH 2437/2940] drm/amd/display: Add DCN2 OPTC
+
+Add support for programming the DCN2 OPTC (Output Timing Controller)
+
+HW Blocks:
+
+ +--------+
+ | OPTC |
+ +--------+
+ |
+ v
+ +--------+ +--------+
+ | DIO | | DCCG |
+ +--------+ +--------+
+
+Signed-off-by: Harry Wentland <harry.wentland@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+---
+ .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.h | 33 +-
+ .../gpu/drm/amd/display/dc/dcn20/dcn20_optc.c | 415 ++++++++++++++++++
+ .../gpu/drm/amd/display/dc/dcn20/dcn20_optc.h | 103 +++++
+ .../gpu/drm/amd/display/dc/inc/hw/hw_shared.h | 43 +-
+ .../amd/display/dc/inc/hw/timing_generator.h | 22 +
+ 5 files changed, 614 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
+ create mode 100644 drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
+index 444c56c8104f..cd9b662fbea9 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
+@@ -89,7 +89,6 @@
+ SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\
+ SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst)
+
+-
+ #define TG_COMMON_REG_LIST_DCN1_0(inst) \
+ TG_COMMON_REG_LIST_DCN(inst),\
+ SRI(OTG_TEST_PATTERN_PARAMETERS, OTG, inst),\
+@@ -164,6 +163,13 @@ struct dcn_optc_registers {
+ uint32_t OTG_CRC0_WINDOWB_X_CONTROL;
+ uint32_t OTG_CRC0_WINDOWB_Y_CONTROL;
+ uint32_t GSL_SOURCE_SELECT;
++#ifdef CONFIG_DRM_AMD_DC_DCN2_0
++ uint32_t DWB_SOURCE_SELECT;
++ uint32_t OTG_DSC_START_POSITION;
++ uint32_t OPTC_DATA_FORMAT_CONTROL;
++ uint32_t OPTC_BYTES_PER_PIXEL;
++ uint32_t OPTC_WIDTH_CONTROL;
++#endif
+ };
+
+ #define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\
+@@ -442,10 +448,35 @@ struct dcn_optc_registers {
+ type MANUAL_FLOW_CONTROL;\
+ type MANUAL_FLOW_CONTROL_SEL;
+
++#ifdef CONFIG_DRM_AMD_DC_DCN2_0
++
++#define TG_REG_FIELD_LIST(type) \
++ TG_REG_FIELD_LIST_DCN1_0(type)\
++ type MASTER_UPDATE_LOCK_DB_X;\
++ type MASTER_UPDATE_LOCK_DB_Y;\
++ type MASTER_UPDATE_LOCK_DB_EN;\
++ type GLOBAL_UPDATE_LOCK_EN;\
++ type DIG_UPDATE_LOCATION;\
++ type OTG_DSC_START_POSITION_X;\
++ type OTG_DSC_START_POSITION_LINE_NUM;\
++ type OPTC_NUM_OF_INPUT_SEGMENT;\
++ type OPTC_SEG0_SRC_SEL;\
++ type OPTC_SEG1_SRC_SEL;\
++ type OPTC_MEM_SEL;\
++ type OPTC_DSC_MODE;\
++ type OPTC_DSC_BYTES_PER_PIXEL;\
++ type OPTC_DSC_SLICE_WIDTH;\
++ type OPTC_SEGMENT_WIDTH;\
++ type OPTC_DWB0_SOURCE_SELECT;\
++ type OPTC_DWB1_SOURCE_SELECT;
++
++#else
+
+ #define TG_REG_FIELD_LIST(type) \
+ TG_REG_FIELD_LIST_DCN1_0(type)
+
++#endif
++
+
+ struct dcn_optc_shift {
+ TG_REG_FIELD_LIST(uint8_t)
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
+new file mode 100644
+index 000000000000..72d72c3a35ee
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
+@@ -0,0 +1,415 @@
++/*
++ * 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 "reg_helper.h"
++#include "dcn20_optc.h"
++#include "dc.h"
++
++#define REG(reg)\
++ optc1->tg_regs->reg
++
++#define CTX \
++ optc1->base.ctx
++
++#undef FN
++#define FN(reg_name, field_name) \
++ optc1->tg_shift->field_name, optc1->tg_mask->field_name
++
++/**
++ * Enable CRTC
++ * Enable CRTC - call ASIC Control Object to enable Timing generator.
++ */
++bool optc2_enable_crtc(struct timing_generator *optc)
++{
++ /* TODO FPGA wait for answer
++ * OTG_MASTER_UPDATE_MODE != CRTC_MASTER_UPDATE_MODE
++ * OTG_MASTER_UPDATE_LOCK != CRTC_MASTER_UPDATE_LOCK
++ */
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ /* opp instance for OTG. For DCN1.0, ODM is remoed.
++ * OPP and OPTC should 1:1 mapping
++ */
++ REG_UPDATE(OPTC_DATA_SOURCE_SELECT,
++ OPTC_SEG0_SRC_SEL, optc->inst);
++
++ /* VTG enable first is for HW workaround */
++ REG_UPDATE(CONTROL,
++ VTG0_ENABLE, 1);
++
++ /* Enable CRTC */
++ REG_UPDATE_2(OTG_CONTROL,
++ OTG_DISABLE_POINT_CNTL, 3,
++ OTG_MASTER_EN, 1);
++
++ return true;
++}
++
++/**
++ * DRR double buffering control to select buffer point
++ * for V_TOTAL, H_TOTAL, VTOTAL_MIN, VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers
++ * Options: anytime, start of frame, dp start of frame (range timing)
++ */
++void optc2_set_timing_db_mode(struct timing_generator *optc, bool enable)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ uint32_t blank_data_double_buffer_enable = enable ? 1 : 0;
++
++ REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL,
++ OTG_RANGE_TIMING_DBUF_UPDATE_MODE, blank_data_double_buffer_enable);
++}
++
++/**
++ *For the below, I'm not sure how your GSL parameters are stored in your env,
++ * so I will assume a gsl_params struct for now
++ */
++void optc2_set_gsl(struct timing_generator *optc,
++ const struct gsl_params *params)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++/**
++ * There are (MAX_OPTC+1)/2 gsl groups available for use.
++ * In each group (assign an OTG to a group by setting OTG_GSLX_EN = 1,
++ * set one of the OTGs to be the master (OTG_GSL_MASTER_EN = 1) and the rest are slaves.
++ */
++ REG_UPDATE_5(OTG_GSL_CONTROL,
++ OTG_GSL0_EN, params->gsl0_en,
++ OTG_GSL1_EN, params->gsl1_en,
++ OTG_GSL2_EN, params->gsl2_en,
++ OTG_GSL_MASTER_EN, params->gsl_master_en,
++ OTG_GSL_MASTER_MODE, params->gsl_master_mode);
++}
++
++
++/* Use the gsl allow flip as the master update lock */
++void optc2_use_gsl_as_master_update_lock(struct timing_generator *optc,
++ const struct gsl_params *params)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ REG_UPDATE(OTG_GSL_CONTROL,
++ OTG_MASTER_UPDATE_LOCK_GSL_EN, params->master_update_lock_gsl_en);
++}
++
++/* You can control the GSL timing by limiting GSL to a window (X,Y) */
++void optc2_set_gsl_window(struct timing_generator *optc,
++ const struct gsl_params *params)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ REG_SET_2(OTG_GSL_WINDOW_X, 0,
++ OTG_GSL_WINDOW_START_X, params->gsl_window_start_x,
++ OTG_GSL_WINDOW_END_X, params->gsl_window_end_x);
++ REG_SET_2(OTG_GSL_WINDOW_Y, 0,
++ OTG_GSL_WINDOW_START_Y, params->gsl_window_start_y,
++ OTG_GSL_WINDOW_END_Y, params->gsl_window_end_y);
++}
++
++/**
++ * Vupdate keepout can be set to a window to block the update lock for that pipe from changing.
++ * Start offset begins with vstartup and goes for x number of clocks,
++ * end offset starts from end of vupdate to x number of clocks.
++ */
++void optc2_set_vupdate_keepout(struct timing_generator *optc,
++ const struct vupdate_keepout_params *params)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ REG_SET_3(OTG_VUPDATE_KEEPOUT, 0,
++ MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, params->start_offset,
++ MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, params->end_offset,
++ OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, params->enable);
++}
++
++void optc2_set_gsl_source_select(
++ struct timing_generator *optc,
++ int group_idx,
++ uint32_t gsl_ready_signal)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ switch (group_idx) {
++ case 1:
++ REG_UPDATE(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, gsl_ready_signal);
++ break;
++ case 2:
++ REG_UPDATE(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, gsl_ready_signal);
++ break;
++ case 3:
++ REG_UPDATE(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, gsl_ready_signal);
++ break;
++ default:
++ break;
++ }
++}
++
++
++/**
++ * PTI i think is already done somewhere else for 2ka
++ * (opp?, please double check.
++ * OPTC side only has 1 register to set for PTI_ENABLE)
++ */
++
++void optc2_set_odm_bypass(struct timing_generator *optc,
++ const struct dc_crtc_timing *dc_crtc_timing)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++ uint32_t h_div_2 = 0;
++
++ optc1->comb_opp_id = 0xf;
++ REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0,
++ OPTC_NUM_OF_INPUT_SEGMENT, 0,
++ OPTC_SEG0_SRC_SEL, optc->inst,
++ OPTC_SEG1_SRC_SEL, 0xf);
++ REG_WRITE(OTG_H_TIMING_CNTL, 0);
++
++ h_div_2 = optc1_is_two_pixels_per_containter(dc_crtc_timing);
++ REG_UPDATE(OTG_H_TIMING_CNTL,
++ OTG_H_TIMING_DIV_BY2, h_div_2);
++ REG_SET(OPTC_MEMORY_CONFIG, 0,
++ OPTC_MEM_SEL, 0);
++}
++
++void optc2_set_odm_combine(struct timing_generator *optc, int combine_opp_id, int mpcc_hactive)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++ /* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192 */
++ int memory_mask = mpcc_hactive <= 2560 ? 0x3 : 0xf;
++
++ /* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic
++ * REG_SET(OTG_GLOBAL_CONTROL2, 0, GLOBAL_UPDATE_LOCK_EN, 1);
++ * Program OTG register MASTER_UPDATE_LOCK_DB_X/Y to the position before DP frame start
++ * REG_SET_2(OTG_GLOBAL_CONTROL1, 0,
++ * MASTER_UPDATE_LOCK_DB_X, 160,
++ * MASTER_UPDATE_LOCK_DB_Y, 240);
++ */
++ if (REG(OPTC_MEMORY_CONFIG))
++ REG_SET(OPTC_MEMORY_CONFIG, 0,
++ OPTC_MEM_SEL, memory_mask << (optc->inst * 4));
++
++ REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0,
++ OPTC_NUM_OF_INPUT_SEGMENT, 1,
++ OPTC_SEG0_SRC_SEL, optc->inst,
++ OPTC_SEG1_SRC_SEL, combine_opp_id);
++
++ REG_UPDATE(OPTC_WIDTH_CONTROL,
++ OPTC_SEGMENT_WIDTH, mpcc_hactive);
++
++ REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_BY2, 1);
++ optc1->comb_opp_id = combine_opp_id;
++}
++
++void optc2_get_optc_source(struct timing_generator *optc,
++ uint32_t *num_of_src_opp,
++ uint32_t *src_opp_id_0,
++ uint32_t *src_opp_id_1)
++{
++ uint32_t num_of_input_segments;
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ REG_GET_3(OPTC_DATA_SOURCE_SELECT,
++ OPTC_NUM_OF_INPUT_SEGMENT, &num_of_input_segments,
++ OPTC_SEG0_SRC_SEL, src_opp_id_0,
++ OPTC_SEG1_SRC_SEL, src_opp_id_1);
++
++ if (num_of_input_segments == 1)
++ *num_of_src_opp = 2;
++ else
++ *num_of_src_opp = 1;
++}
++
++void optc2_set_dwb_source(struct timing_generator *optc,
++ uint32_t dwb_pipe_inst)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ if (dwb_pipe_inst == 0)
++ REG_UPDATE(DWB_SOURCE_SELECT,
++ OPTC_DWB0_SOURCE_SELECT, optc->inst);
++ else if (dwb_pipe_inst == 1)
++ REG_UPDATE(DWB_SOURCE_SELECT,
++ OPTC_DWB1_SOURCE_SELECT, optc->inst);
++}
++
++void optc2_triplebuffer_lock(struct timing_generator *optc)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ REG_SET(OTG_GLOBAL_CONTROL0, 0,
++ OTG_MASTER_UPDATE_LOCK_SEL, optc->inst);
++
++ REG_SET(OTG_VUPDATE_KEEPOUT, 0,
++ OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1);
++
++ REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
++ OTG_MASTER_UPDATE_LOCK, 1);
++
++ if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS)
++ REG_WAIT(OTG_MASTER_UPDATE_LOCK,
++ UPDATE_LOCK_STATUS, 1,
++ 1, 10);
++}
++
++void optc2_triplebuffer_unlock(struct timing_generator *optc)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
++ OTG_MASTER_UPDATE_LOCK, 0);
++
++ REG_SET(OTG_VUPDATE_KEEPOUT, 0,
++ OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 0);
++
++}
++
++void optc2_setup_global_lock(struct timing_generator *optc)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++ uint32_t v_blank_start = 0;
++ uint32_t h_blank_start = 0, h_total = 0;
++
++ REG_SET(OTG_GLOBAL_CONTROL2, 0, DIG_UPDATE_LOCATION, 20);
++
++ REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START, &v_blank_start);
++
++ REG_GET(OTG_H_BLANK_START_END, OTG_H_BLANK_START, &h_blank_start);
++
++ REG_GET(OTG_H_TOTAL, OTG_H_TOTAL, &h_total);
++ REG_UPDATE_2(OTG_GLOBAL_CONTROL1,
++ MASTER_UPDATE_LOCK_DB_X,
++ 0,
++ MASTER_UPDATE_LOCK_DB_Y,
++ v_blank_start - 1);
++}
++
++void optc2_lock_global(struct timing_generator *optc)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ REG_SET(OTG_GLOBAL_CONTROL1, 0, MASTER_UPDATE_LOCK_DB_EN, 1);
++
++ REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1);
++
++ REG_SET(OTG_GLOBAL_CONTROL0, 0,
++ OTG_MASTER_UPDATE_LOCK_SEL, optc->inst);
++ REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
++ OTG_MASTER_UPDATE_LOCK, 1);
++
++ /* Should be fast, status does not update on maximus */
++ if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS)
++ REG_WAIT(OTG_MASTER_UPDATE_LOCK,
++ UPDATE_LOCK_STATUS, 1,
++ 1, 10);
++}
++
++void optc2_lock(struct timing_generator *optc)
++{
++ struct optc *optc1 = DCN10TG_FROM_TG(optc);
++
++ REG_SET(OTG_GLOBAL_CONTROL1, 0, MASTER_UPDATE_LOCK_DB_EN, 0);
++
++ REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0);
++
++ REG_SET(OTG_GLOBAL_CONTROL0, 0,
++ OTG_MASTER_UPDATE_LOCK_SEL, optc->inst);
++ REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
++ OTG_MASTER_UPDATE_LOCK, 1);
++
++ /* Should be fast, status does not update on maximus */
++ if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS)
++ REG_WAIT(OTG_MASTER_UPDATE_LOCK,
++ UPDATE_LOCK_STATUS, 1,
++ 1, 10);
++}
++
++static struct timing_generator_funcs dcn20_tg_funcs = {
++ .validate_timing = optc1_validate_timing,
++ .program_timing = optc1_program_timing,
++ .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
++ .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1,
++ .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2,
++ .program_global_sync = optc1_program_global_sync,
++ .enable_crtc = optc2_enable_crtc,
++ .disable_crtc = optc1_disable_crtc,
++ /* used by enable_timing_synchronization. Not need for FPGA */
++ .is_counter_moving = optc1_is_counter_moving,
++ .get_position = optc1_get_position,
++ .get_frame_count = optc1_get_vblank_counter,
++ .get_scanoutpos = optc1_get_crtc_scanoutpos,
++ .get_otg_active_size = optc1_get_otg_active_size,
++ .set_early_control = optc1_set_early_control,
++ /* used by enable_timing_synchronization. Not need for FPGA */
++ .wait_for_state = optc1_wait_for_state,
++ .set_blank = optc1_set_blank,
++ .is_blanked = optc1_is_blanked,
++ .set_blank_color = optc1_program_blank_color,
++ .enable_reset_trigger = optc1_enable_reset_trigger,
++ .enable_crtc_reset = optc1_enable_crtc_reset,
++ .did_triggered_reset_occur = optc1_did_triggered_reset_occur,
++ .triplebuffer_lock = optc2_triplebuffer_lock,
++ .triplebuffer_unlock = optc2_triplebuffer_unlock,
++ .disable_reset_trigger = optc1_disable_reset_trigger,
++ .lock = optc2_lock,
++ .unlock = optc1_unlock,
++ .lock_global = optc2_lock_global,
++ .setup_global_lock = optc2_setup_global_lock,
++ .enable_optc_clock = optc1_enable_optc_clock,
++ .set_drr = optc1_set_drr,
++ .set_static_screen_control = optc1_set_static_screen_control,
++ .program_stereo = optc1_program_stereo,
++ .is_stereo_left_eye = optc1_is_stereo_left_eye,
++ .set_blank_data_double_buffer = optc1_set_blank_data_double_buffer,
++ .tg_init = optc1_tg_init,
++ .is_tg_enabled = optc1_is_tg_enabled,
++ .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred,
++ .clear_optc_underflow = optc1_clear_optc_underflow,
++ .setup_global_swap_lock = NULL,
++ .get_crc = optc1_get_crc,
++ .configure_crc = optc1_configure_crc,
++ .set_dwb_source = optc2_set_dwb_source,
++ .set_odm_bypass = optc2_set_odm_bypass,
++ .set_odm_combine = optc2_set_odm_combine,
++ .get_optc_source = optc2_get_optc_source,
++ .set_gsl = optc2_set_gsl,
++ .set_gsl_source_select = optc2_set_gsl_source_select,
++};
++
++void dcn20_timing_generator_init(struct optc *optc1)
++{
++ optc1->base.funcs = &dcn20_tg_funcs;
++
++ optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1;
++ optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1;
++
++ optc1->min_h_blank = 32;
++ optc1->min_v_blank = 3;
++ optc1->min_v_blank_interlace = 5;
++ optc1->min_h_sync_width = 8;
++ optc1->min_v_sync_width = 1;
++ optc1->comb_opp_id = 0xf;
++}
++
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h
+new file mode 100644
+index 000000000000..fe851049aa9b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h
+@@ -0,0 +1,103 @@
++/*
++ * 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_OPTC_DCN20_H__
++#define __DC_OPTC_DCN20_H__
++
++#include "../dcn10/dcn10_optc.h"
++
++#define TG_COMMON_REG_LIST_DCN2_0(inst) \
++ TG_COMMON_REG_LIST_DCN(inst),\
++ SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\
++ SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\
++ SRI(OTG_GSL_WINDOW_X, OTG, inst),\
++ SRI(OTG_GSL_WINDOW_Y, OTG, inst),\
++ SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\
++ SRI(OTG_DSC_START_POSITION, OTG, inst),\
++ SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\
++ SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\
++ SRI(OPTC_WIDTH_CONTROL, ODM, inst),\
++ SRI(OPTC_MEMORY_CONFIG, ODM, inst),\
++ SR(DWB_SOURCE_SELECT)
++
++#define TG_COMMON_MASK_SH_LIST_DCN2_0(mask_sh)\
++ TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\
++ SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_X, mask_sh),\
++ SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_Y, mask_sh),\
++ SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\
++ SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\
++ SF(OTG0_OTG_GLOBAL_CONTROL2, DIG_UPDATE_LOCATION, mask_sh),\
++ SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mask_sh),\
++ SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\
++ SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \
++ SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\
++ SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\
++ SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \
++ SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \
++ SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \
++ SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \
++ SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \
++ SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \
++ SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\
++ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\
++ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\
++ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\
++ SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\
++ SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\
++ SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\
++ SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\
++ SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\
++ SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\
++ SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh)
++
++void dcn20_timing_generator_init(struct optc *optc);
++
++bool optc2_enable_crtc(struct timing_generator *optc);
++
++void optc2_set_gsl(struct timing_generator *optc,
++ const struct gsl_params *params);
++
++void optc2_set_gsl_source_select(struct timing_generator *optc,
++ int group_idx,
++ uint32_t gsl_ready_signal);
++
++
++void optc2_set_odm_bypass(struct timing_generator *optc,
++ const struct dc_crtc_timing *dc_crtc_timing);
++
++void optc2_set_odm_combine(struct timing_generator *optc, int combine_opp_id, int mpcc_hactive);
++
++void optc2_get_optc_source(struct timing_generator *optc,
++ uint32_t *num_of_src_opp,
++ uint32_t *src_opp_id_0,
++ uint32_t *src_opp_id_1);
++
++void optc2_triplebuffer_lock(struct timing_generator *optc);
++void optc2_triplebuffer_unlock(struct timing_generator *optc);
++void optc2_lock(struct timing_generator *optc);
++void optc2_lock_global(struct timing_generator *optc);
++void optc2_setup_global_lock(struct timing_generator *optc);
++
++#endif /* __DC_OPTC_DCN20_H__ */
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
+index 4c8e2c6fb6db..1ff6a841fdd2 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
+@@ -35,6 +35,9 @@
+ ******************************************************************************/
+
+ #define MAX_PIPES 6
++#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
++#define MAX_DWB_PIPES 1
++#endif
+
+ struct gamma_curve {
+ uint32_t offset;
+@@ -77,6 +80,37 @@ struct pwl_result_data {
+ uint32_t delta_blue_reg;
+ };
+
++#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
++struct dc_rgb {
++ uint32_t red;
++ uint32_t green;
++ uint32_t blue;
++};
++
++struct tetrahedral_17x17x17 {
++ struct dc_rgb lut0[1229];
++ struct dc_rgb lut1[1228];
++ struct dc_rgb lut2[1228];
++ struct dc_rgb lut3[1228];
++};
++struct tetrahedral_9x9x9 {
++ struct dc_rgb lut0[183];
++ struct dc_rgb lut1[182];
++ struct dc_rgb lut2[182];
++ struct dc_rgb lut3[182];
++};
++
++struct tetrahedral_params {
++ union {
++ struct tetrahedral_17x17x17 tetrahedral_17;
++ struct tetrahedral_9x9x9 tetrahedral_9;
++ };
++ bool use_tetrahedral_9;
++ bool use_12bits;
++
++};
++#endif
++
+ /* arr_curve_points - regamma regions/segments specification
+ * arr_points - beginning and end point specified separately (only one on DCE)
+ * corner_points - beginning and end point for all 3 colors (DCN)
+@@ -160,6 +194,7 @@ enum opp_regamma {
+ OPP_REGAMMA_USER
+ };
+
++
+ struct dc_bias_and_scale {
+ uint16_t scale_red;
+ uint16_t bias_red;
+@@ -181,7 +216,12 @@ enum test_pattern_mode {
+ TEST_PATTERN_MODE_VERTICALBARS,
+ TEST_PATTERN_MODE_HORIZONTALBARS,
+ TEST_PATTERN_MODE_SINGLERAMP_RGB,
++#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
++ TEST_PATTERN_MODE_DUALRAMP_RGB,
++ TEST_PATTERN_MODE_XR_BIAS_RGB
++#else
+ TEST_PATTERN_MODE_DUALRAMP_RGB
++#endif
+ };
+
+ enum test_pattern_color_format {
+@@ -203,7 +243,8 @@ enum controller_dp_test_pattern {
+ CONTROLLER_DP_TEST_PATTERN_RESERVED_8,
+ CONTROLLER_DP_TEST_PATTERN_RESERVED_9,
+ CONTROLLER_DP_TEST_PATTERN_RESERVED_A,
+- CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA
++ CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA,
++ CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR
+ };
+
+ enum dc_lut_mode {
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
+index a89d0cf59cca..e8e521102adb 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
+@@ -188,6 +188,10 @@ struct timing_generator_funcs {
+ void (*unlock)(struct timing_generator *tg);
+ void (*lock)(struct timing_generator *tg);
+ void (*lock_global)(struct timing_generator *tg);
++#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
++ void(*triplebuffer_unlock)(struct timing_generator *tg);
++ void(*triplebuffer_lock)(struct timing_generator *tg);
++#endif
+ void (*enable_reset_trigger)(struct timing_generator *tg,
+ int source_tg_inst);
+ void (*enable_crtc_reset)(struct timing_generator *tg,
+@@ -224,6 +228,16 @@ struct timing_generator_funcs {
+ bool (*is_optc_underflow_occurred)(struct timing_generator *tg);
+ void (*clear_optc_underflow)(struct timing_generator *tg);
+
++#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
++ void (*set_dwb_source)(struct timing_generator *optc,
++ uint32_t dwb_pipe_inst);
++
++ void (*get_optc_source)(struct timing_generator *optc,
++ uint32_t *num_of_input_segments,
++ uint32_t *seg0_src_sel,
++ uint32_t *seg1_src_sel);
++#endif
++
+ /**
+ * Configure CRCs for the given timing generator. Return false if TG is
+ * not on.
+@@ -243,6 +257,14 @@ struct timing_generator_funcs {
+
+ void (*set_vtg_params)(struct timing_generator *optc,
+ const struct dc_crtc_timing *dc_crtc_timing);
++#ifdef CONFIG_DRM_AMD_DC_DCN2_0
++ void (*set_odm_bypass)(struct timing_generator *tg, const struct dc_crtc_timing *dc_crtc_timing);
++ void (*set_odm_combine)(struct timing_generator *tg, int combine_opp_id, int mpcc_hactive);
++ void (*set_gsl)(struct timing_generator *optc, const struct gsl_params *params);
++ void (*set_gsl_source_select)(struct timing_generator *optc,
++ int group_idx,
++ uint32_t gsl_ready_signal);
++#endif
+ };
+
+ #endif
+--
+2.17.1
+