summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorRobin Chen <robin.chen@amd.com>2023-12-20 20:31:28 +0800
committerAlex Deucher <alexander.deucher@amd.com>2024-03-20 13:37:37 -0400
commiteed4edda910fe34dfae8c6bfbcf57f4593a54295 (patch)
treee81678d481ed5777c9939b08f67f993367e57450 /drivers/gpu
parentc90835b0648edb78f4630b89a2897972c3571cbd (diff)
downloadlinux-stable-eed4edda910fe34dfae8c6bfbcf57f4593a54295.tar.gz
linux-stable-eed4edda910fe34dfae8c6bfbcf57f4593a54295.tar.bz2
linux-stable-eed4edda910fe34dfae8c6bfbcf57f4593a54295.zip
drm/amd/display: Support long vblank feature
[WHY] We want to support low hz case, but the original vtotal/vtotal_min/vtotal_max can't support more than 0x7FFF. [HOW] We use the 2 HW reg to contorl long vblank case. 1. OTG_V_COUNT_STOP_CONTROL -> vcount_stop 2. OTG_V_COUNT_STOP_CONTROL2 -> vcount_stop_timer vcount_stop define from which line we stop using vcount and start using vcount2. vcount_stop_timer define how long we use vcount2. Ex: Vtotal = 7 OTG_V_COUNT_STOP_CONTROL = 4 OTG_V_COUNT_STOP_CONTROL2 = 5 time : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 vcount : 0, 1, 2, 3, - - - - - 4, 5, 6 vcount2 : 0, 1, 2, 3, 4, Reviewed-by: Jun Lei <jun.lei@amd.com> Acked-by: Alex Hung <alex.hung@amd.com> Signed-off-by: ChunTao Tso <chuntao.tso@amd.com> Signed-off-by: Robin Chen<robin.chen@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c33
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_hw_types.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c28
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c165
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h2
-rw-r--r--drivers/gpu/drm/amd/display/modules/freesync/freesync.c2
12 files changed, 253 insertions, 4 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 5c8b0183959c..64ab99628125 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -386,6 +386,30 @@ static void dc_perf_trace_destroy(struct dc_perf_trace **perf_trace)
*perf_trace = NULL;
}
+static bool set_long_vtotal(struct dc *dc, struct dc_stream_state *stream, struct dc_crtc_timing_adjust *adjust)
+{
+ if (!dc || !stream || !adjust)
+ return false;
+
+ if (!dc->current_state)
+ return false;
+
+ int i;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+
+ if (pipe->stream == stream && pipe->stream_res.tg) {
+ if (dc->hwss.set_long_vtotal)
+ dc->hwss.set_long_vtotal(&pipe, 1, adjust->v_total_min, adjust->v_total_max);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
/**
* dc_stream_adjust_vmin_vmax - look up pipe context & update parts of DRR
* @dc: dc reference
@@ -420,6 +444,15 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
stream->adjust.v_total_mid = adjust->v_total_mid;
stream->adjust.v_total_mid_frame_num = adjust->v_total_mid_frame_num;
stream->adjust.v_total_min = adjust->v_total_min;
+ stream->adjust.allow_otg_v_count_halt = adjust->allow_otg_v_count_halt;
+
+ if (dc->caps.max_v_total != 0 &&
+ (adjust->v_total_max > dc->caps.max_v_total || adjust->v_total_min > dc->caps.max_v_total)) {
+ if (adjust->allow_otg_v_count_halt)
+ return set_long_vtotal(dc, stream, adjust);
+ else
+ return false;
+ }
for (i = 0; i < MAX_PIPES; i++) {
struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
index aae2f3a2660d..465e15f57f93 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
@@ -974,6 +974,7 @@ struct dc_crtc_timing_adjust {
uint32_t v_total_max;
uint32_t v_total_mid;
uint32_t v_total_mid_frame_num;
+ uint32_t allow_otg_v_count_halt;
};
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
index 4b92df23ff0d..2e8ec58a16eb 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
@@ -1394,3 +1394,31 @@ void dcn35_set_static_screen_control(struct pipe_ctx **pipe_ctx,
set_static_screen_control(pipe_ctx[i]->stream_res.tg,
triggers, params->num_frames);
}
+
+void dcn35_set_long_vblank(struct pipe_ctx **pipe_ctx,
+ int num_pipes, uint32_t v_total_min, uint32_t v_total_max)
+{
+ int i = 0;
+ struct long_vtotal_params params = {0};
+
+ params.vertical_total_max = v_total_max;
+ params.vertical_total_min = v_total_min;
+
+ for (i = 0; i < num_pipes; i++) {
+ if (!pipe_ctx[i])
+ continue;
+
+ if (pipe_ctx[i]->stream) {
+ struct dc_crtc_timing *timing = &pipe_ctx[i]->stream->timing;
+
+ if (timing)
+ params.vertical_blank_start = timing->v_total - timing->v_front_porch;
+ else
+ params.vertical_blank_start = 0;
+
+ if ((pipe_ctx[i]->stream_res.tg != NULL) && pipe_ctx[i]->stream_res.tg->funcs &&
+ pipe_ctx[i]->stream_res.tg->funcs->set_long_vtotal)
+ pipe_ctx[i]->stream_res.tg->funcs->set_long_vtotal(pipe_ctx[i]->stream_res.tg, &params);
+ }
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
index c354efa6c1b2..7c33bea3f4e7 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
@@ -93,4 +93,7 @@ void dcn35_set_drr(struct pipe_ctx **pipe_ctx,
void dcn35_set_static_screen_control(struct pipe_ctx **pipe_ctx,
int num_pipes, const struct dc_static_screen_params *params);
+void dcn35_set_long_vblank(struct pipe_ctx **pipe_ctx,
+ int num_pipes, uint32_t v_total_min, uint32_t v_total_max);
+
#endif /* __DC_HWSS_DCN35_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
index a93073055e7b..dce620d359a6 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
@@ -122,7 +122,8 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
.hw_block_power_down = dcn35_hw_block_power_down,
.root_clock_control = dcn35_root_clock_control,
.set_idle_state = dcn35_set_idle_state,
- .get_idle_state = dcn35_get_idle_state
+ .get_idle_state = dcn35_get_idle_state,
+ .set_long_vtotal = dcn35_set_long_vblank,
};
static const struct hwseq_private_funcs dcn35_private_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
index f89f205e42a1..26ea86316e50 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -429,6 +429,7 @@ struct hw_sequencer_funcs {
bool (*is_pipe_topology_transition_seamless)(struct dc *dc,
const struct dc_state *cur_ctx,
const struct dc_state *new_ctx);
+ void (*set_long_vtotal)(struct pipe_ctx **pipe_ctx, int num_pipes, uint32_t v_total_min, uint32_t v_total_max);
};
void color_space_to_black_color(
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 ffad8fe16c54..cd68ecc242c1 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
@@ -64,6 +64,12 @@ struct drr_params {
bool immediate_flip;
};
+struct long_vtotal_params {
+ uint32_t vertical_total_min;
+ uint32_t vertical_total_max;
+ uint32_t vertical_blank_start;
+};
+
#define LEFT_EYE_3D_PRIMARY_SURFACE 1
#define RIGHT_EYE_3D_PRIMARY_SURFACE 0
@@ -331,6 +337,7 @@ struct timing_generator_funcs {
void (*init_odm)(struct timing_generator *tg);
void (*wait_drr_doublebuffer_pending_clear)(struct timing_generator *tg);
+ void (*set_long_vtotal)(struct timing_generator *optc, const struct long_vtotal_params *params);
void (*wait_odm_doublebuffer_pending_clear)(struct timing_generator *tg);
};
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h
index 6c2e84d3967f..8a45d26b7531 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h
@@ -129,6 +129,8 @@ struct dcn_optc_registers {
uint32_t OTG_V_TOTAL_MID;
uint32_t OTG_V_TOTAL_MIN;
uint32_t OTG_V_TOTAL_CONTROL;
+ uint32_t OTG_V_COUNT_STOP_CONTROL;
+ uint32_t OTG_V_COUNT_STOP_CONTROL2;
uint32_t OTG_TRIGA_CNTL;
uint32_t OTG_TRIGA_MANUAL_TRIG;
uint32_t OTG_MANUAL_FLOW_CONTROL;
@@ -581,7 +583,9 @@ struct dcn_optc_registers {
type OTG_CRC1_WINDOWB_X_END_READBACK;\
type OTG_CRC1_WINDOWB_Y_START_READBACK;\
type OTG_CRC1_WINDOWB_Y_END_READBACK;\
- type OPTC_FGCG_REP_DIS;
+ type OPTC_FGCG_REP_DIS;\
+ type OTG_V_COUNT_STOP;\
+ type OTG_V_COUNT_STOP_TIMER;
struct dcn_optc_shift {
TG_REG_FIELD_LIST(uint8_t)
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
index 5b1547508850..d393be30dff8 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
@@ -32,6 +32,7 @@
#include "reg_helper.h"
#include "dc.h"
#include "dcn_calc_math.h"
+#include "dc_dmub_srv.h"
#define REG(reg)\
optc1->tg_regs->reg
@@ -213,6 +214,167 @@ static bool optc35_configure_crc(struct timing_generator *optc,
return true;
}
+static void optc35_setup_manual_trigger(struct timing_generator *optc)
+{
+ if (!optc || !optc->ctx)
+ return;
+
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+ struct dc *dc = optc->ctx->dc;
+
+ if (dc->caps.dmub_caps.mclk_sw && !dc->debug.disable_fams)
+ dc_dmub_srv_set_drr_manual_trigger_cmd(dc, optc->inst);
+ else {
+ /*
+ * MIN_MASK_EN is gone and MASK is now always enabled.
+ *
+ * To get it to it work with manual trigger we need to make sure
+ * we program the correct bit.
+ */
+ REG_UPDATE_4(OTG_V_TOTAL_CONTROL,
+ OTG_V_TOTAL_MIN_SEL, 1,
+ OTG_V_TOTAL_MAX_SEL, 1,
+ OTG_FORCE_LOCK_ON_EVENT, 0,
+ OTG_SET_V_TOTAL_MIN_MASK, (1 << 1)); /* TRIGA */
+
+ // Setup manual flow control for EOF via TRIG_A
+ if (optc->funcs && optc->funcs->setup_manual_trigger)
+ optc->funcs->setup_manual_trigger(optc);
+ }
+}
+
+void optc35_set_drr(
+ struct timing_generator *optc,
+ const struct drr_params *params)
+{
+ if (!optc || !params)
+ return;
+
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+ uint32_t max_otg_v_total = optc1->max_v_total - 1;
+
+ if (params != NULL &&
+ params->vertical_total_max > 0 &&
+ params->vertical_total_min > 0) {
+
+ if (params->vertical_total_mid != 0) {
+
+ REG_SET(OTG_V_TOTAL_MID, 0,
+ OTG_V_TOTAL_MID, params->vertical_total_mid - 1);
+
+ REG_UPDATE_2(OTG_V_TOTAL_CONTROL,
+ OTG_VTOTAL_MID_REPLACING_MAX_EN, 1,
+ OTG_VTOTAL_MID_FRAME_NUM,
+ (uint8_t)params->vertical_total_mid_frame_num);
+
+ }
+
+ if (optc->funcs && optc->funcs->set_vtotal_min_max)
+ optc->funcs->set_vtotal_min_max(optc,
+ params->vertical_total_min - 1, params->vertical_total_max - 1);
+ optc35_setup_manual_trigger(optc);
+ } else {
+ REG_UPDATE_4(OTG_V_TOTAL_CONTROL,
+ OTG_SET_V_TOTAL_MIN_MASK, 0,
+ OTG_V_TOTAL_MIN_SEL, 0,
+ OTG_V_TOTAL_MAX_SEL, 0,
+ OTG_FORCE_LOCK_ON_EVENT, 0);
+
+ if (optc->funcs && optc->funcs->set_vtotal_min_max)
+ optc->funcs->set_vtotal_min_max(optc, 0, 0);
+ }
+
+ REG_WRITE(OTG_V_COUNT_STOP_CONTROL, max_otg_v_total);
+ REG_WRITE(OTG_V_COUNT_STOP_CONTROL2, 0);
+}
+
+static void optc35_set_long_vtotal(
+ struct timing_generator *optc,
+ const struct long_vtotal_params *params)
+{
+ if (!optc || !params)
+ return;
+
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+ uint32_t vcount_stop_timer = 0, vcount_stop = 0;
+ uint32_t max_otg_v_total = optc1->max_v_total - 1;
+
+ if (params->vertical_total_min <= max_otg_v_total && params->vertical_total_max <= max_otg_v_total)
+ return;
+
+ if (params->vertical_total_max == 0 || params->vertical_total_min == 0) {
+ REG_UPDATE_4(OTG_V_TOTAL_CONTROL,
+ OTG_SET_V_TOTAL_MIN_MASK, 0,
+ OTG_V_TOTAL_MIN_SEL, 0,
+ OTG_V_TOTAL_MAX_SEL, 0,
+ OTG_FORCE_LOCK_ON_EVENT, 0);
+
+ if (optc->funcs && optc->funcs->set_vtotal_min_max)
+ optc->funcs->set_vtotal_min_max(optc, 0, 0);
+ } else if (params->vertical_total_max == params->vertical_total_min) {
+ vcount_stop = params->vertical_blank_start;
+ vcount_stop_timer = params->vertical_total_max - max_otg_v_total;
+
+ REG_UPDATE_4(OTG_V_TOTAL_CONTROL,
+ OTG_V_TOTAL_MIN_SEL, 1,
+ OTG_V_TOTAL_MAX_SEL, 1,
+ OTG_FORCE_LOCK_ON_EVENT, 0,
+ OTG_SET_V_TOTAL_MIN_MASK, 0);
+
+ if (optc->funcs && optc->funcs->set_vtotal_min_max)
+ optc->funcs->set_vtotal_min_max(optc, max_otg_v_total, max_otg_v_total);
+
+ REG_WRITE(OTG_V_COUNT_STOP_CONTROL, vcount_stop);
+ REG_WRITE(OTG_V_COUNT_STOP_CONTROL2, vcount_stop_timer);
+ } else {
+ // Variable rate, keep DRR trigger mask
+ if (params->vertical_total_min > max_otg_v_total) {
+ // cannot be supported
+ // If MAX_OTG_V_COUNT < DRR trigger < v_total_min < v_total_max,
+ // DRR trigger will drop the vtotal counting directly to a new frame.
+ // But it should trigger between v_total_min and v_total_max.
+ ASSERT(0);
+
+ REG_UPDATE_4(OTG_V_TOTAL_CONTROL,
+ OTG_SET_V_TOTAL_MIN_MASK, 0,
+ OTG_V_TOTAL_MIN_SEL, 0,
+ OTG_V_TOTAL_MAX_SEL, 0,
+ OTG_FORCE_LOCK_ON_EVENT, 0);
+
+ if (optc->funcs && optc->funcs->set_vtotal_min_max)
+ optc->funcs->set_vtotal_min_max(optc, 0, 0);
+
+ REG_WRITE(OTG_V_COUNT_STOP_CONTROL, max_otg_v_total);
+ REG_WRITE(OTG_V_COUNT_STOP_CONTROL2, 0);
+ } else {
+ // For total_min <= MAX_OTG_V_COUNT and total_max > MAX_OTG_V_COUNT
+ vcount_stop = params->vertical_total_min;
+ vcount_stop_timer = params->vertical_total_max - max_otg_v_total;
+
+ // Example:
+ // params->vertical_total_min 1000
+ // params->vertical_total_max 2000
+ // MAX_OTG_V_COUNT_STOP = 1500
+ //
+ // If DRR event not happened,
+ // time 0,1,2,3,4,...1000,1001,........,1500,1501,1502, ...1999
+ // vcount 0,1,2,3,4....1000...................,1001,1002,1003,...1399
+ // vcount2 0,1,2,3,4,..499,
+ // else (DRR event happened, ex : at line 1004)
+ // time 0,1,2,3,4,...1000,1001.....1004, 0
+ // vcount 0,1,2,3,4....1000,.............. 0 (new frame)
+ // vcount2 0,1,2, 3, -
+ if (optc->funcs && optc->funcs->set_vtotal_min_max)
+ optc->funcs->set_vtotal_min_max(optc,
+ params->vertical_total_min - 1, max_otg_v_total);
+ optc35_setup_manual_trigger(optc);
+
+ REG_WRITE(OTG_V_COUNT_STOP_CONTROL, vcount_stop);
+ REG_WRITE(OTG_V_COUNT_STOP_CONTROL2, vcount_stop_timer);
+ }
+ }
+}
+
static struct timing_generator_funcs dcn35_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
@@ -245,7 +407,7 @@ static struct timing_generator_funcs dcn35_tg_funcs = {
.lock_doublebuffer_enable = optc3_lock_doublebuffer_enable,
.lock_doublebuffer_disable = optc3_lock_doublebuffer_disable,
.enable_optc_clock = optc1_enable_optc_clock,
- .set_drr = optc31_set_drr,
+ .set_drr = optc35_set_drr,
.get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal,
.set_vtotal_min_max = optc1_set_vtotal_min_max,
.set_static_screen_control = optc1_set_static_screen_control,
@@ -275,6 +437,7 @@ static struct timing_generator_funcs dcn35_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
+ .set_long_vtotal = optc35_set_long_vtotal,
};
void dcn35_timing_generator_init(struct optc *optc1)
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h
index 1f422e4c468f..d077e2392379 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h
@@ -65,10 +65,14 @@
SF(OTG0_OTG_CRC1_WINDOWB_X_CONTROL_READBACK, OTG_CRC1_WINDOWB_X_END_READBACK, mask_sh),\
SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL_READBACK, OTG_CRC1_WINDOWB_Y_START_READBACK, mask_sh),\
SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL_READBACK, OTG_CRC1_WINDOWB_Y_END_READBACK, mask_sh),\
- SF(OPTC_CLOCK_CONTROL, OPTC_FGCG_REP_DIS, mask_sh)
+ SF(OPTC_CLOCK_CONTROL, OPTC_FGCG_REP_DIS, mask_sh),\
+ SF(OTG0_OTG_V_COUNT_STOP_CONTROL, OTG_V_COUNT_STOP, mask_sh),\
+ SF(OTG0_OTG_V_COUNT_STOP_CONTROL2, OTG_V_COUNT_STOP_TIMER, mask_sh)
void dcn35_timing_generator_init(struct optc *optc1);
void dcn35_timing_generator_set_fgcg(struct optc *optc1, bool enable);
+void optc35_set_drr(struct timing_generator *optc, const struct drr_params *params);
+
#endif /* __DC_OPTC_DCN35_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h
index a51c4a9eaafe..f97bb4cb3761 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h
@@ -240,6 +240,8 @@ struct resource_pool *dcn35_create_resource_pool(
SRI_ARR(OTG_V_TOTAL_MAX, OTG, inst),\
SRI_ARR(OTG_V_TOTAL_MIN, OTG, inst),\
SRI_ARR(OTG_V_TOTAL_CONTROL, OTG, inst),\
+ SRI_ARR(OTG_V_COUNT_STOP_CONTROL, OTG, inst),\
+ SRI_ARR(OTG_V_COUNT_STOP_CONTROL2, OTG, inst),\
SRI_ARR(OTG_TRIGA_CNTL, OTG, inst),\
SRI_ARR(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\
SRI_ARR(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
index 3955b7e4b2e2..fbaa6effd0e3 100644
--- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
+++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
@@ -1126,6 +1126,8 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
in_out_vrr->adjust.v_total_min = stream->timing.v_total;
in_out_vrr->adjust.v_total_max = stream->timing.v_total;
}
+
+ in_out_vrr->adjust.allow_otg_v_count_halt = (in_config->state == VRR_STATE_ACTIVE_FIXED) ? true : false;
}
void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,