Commit 6476a7c8 authored by Joshua Aberback's avatar Joshua Aberback Committed by Alex Deucher

drm/amd/display: Program VTG params after programming Global Sync

[Why]
VTG has a parameter FP2, which is defined as:
    if VSTARTUP is before VSYNC:
        FP2 = number of lines in between VSTARTUP and VSYNC
    else
        FP2 = 0
Currently, FP2 is only programmed during "program_timing". However, the
position of VSTARTUP is affected by the prefetching requirements on all pipes,
so the position might change when we do memory request control on another pipe, so we need
to make sure that FP2 stays up-to-date whenever we adjust VSTARTUP.

[How]
 - refactor VTG_CONTROL programming into a new function "set_vtg_params"
 - call it after calling "program_global_sync"
   - make sure it's called after because it relies on the cached dlg params
Signed-off-by: default avatarJoshua Aberback <joshua.aberback@amd.com>
Reviewed-by: default avatarTony Cheng <Tony.Cheng@amd.com>
Acked-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Acked-by: default avatarJun Lei <Jun.Lei@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 24c18794
......@@ -2285,6 +2285,9 @@ static void program_all_pipe_in_tree(
pipe_ctx->pipe_dlg_param.vupdate_offset,
pipe_ctx->pipe_dlg_param.vupdate_width);
pipe_ctx->stream_res.tg->funcs->set_vtg_params(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
dc->hwss.blank_pixel_data(dc, pipe_ctx, blank);
}
......
......@@ -46,9 +46,7 @@
* This is a workaround for a bug that has existed since R5xx and has not been
* fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive.
*/
static void optc1_apply_front_porch_workaround(
struct timing_generator *optc,
struct dc_crtc_timing *timing)
static void apply_front_porch_workaround(struct dc_crtc_timing *timing)
{
if (timing->flags.INTERLACE == 1) {
if (timing->v_front_porch < 2)
......@@ -149,17 +147,14 @@ void optc1_program_timing(
bool use_vbios)
{
struct dc_crtc_timing patched_crtc_timing;
uint32_t vesa_sync_start;
uint32_t asic_blank_end;
uint32_t asic_blank_start;
uint32_t v_total;
uint32_t v_sync_end;
uint32_t v_init, v_fp2;
uint32_t h_sync_polarity, v_sync_polarity;
uint32_t start_point = 0;
uint32_t field_num = 0;
uint32_t h_div_2;
int32_t vertical_line_start;
struct optc *optc1 = DCN10TG_FROM_TG(optc);
......@@ -169,7 +164,7 @@ void optc1_program_timing(
optc1->vupdate_offset = vupdate_offset;
optc1->vupdate_width = vupdate_width;
patched_crtc_timing = *dc_crtc_timing;
optc1_apply_front_porch_workaround(optc, &patched_crtc_timing);
apply_front_porch_workaround(&patched_crtc_timing);
/* Load horizontal timing */
......@@ -182,24 +177,16 @@ void optc1_program_timing(
OTG_H_SYNC_A_START, 0,
OTG_H_SYNC_A_END, patched_crtc_timing.h_sync_width);
/* asic_h_blank_end = HsyncWidth + HbackPorch =
* vesa. usHorizontalTotal - vesa. usHorizontalSyncStart -
* vesa.h_left_border
*/
vesa_sync_start = patched_crtc_timing.h_addressable +
patched_crtc_timing.h_border_right +
/* blank_start = line end - front porch */
asic_blank_start = patched_crtc_timing.h_total -
patched_crtc_timing.h_front_porch;
asic_blank_end = patched_crtc_timing.h_total -
vesa_sync_start -
/* blank_end = blank_start - active */
asic_blank_end = asic_blank_start -
patched_crtc_timing.h_border_right -
patched_crtc_timing.h_addressable -
patched_crtc_timing.h_border_left;
/* h_blank_start = v_blank_end + v_active */
asic_blank_start = asic_blank_end +
patched_crtc_timing.h_border_left +
patched_crtc_timing.h_addressable +
patched_crtc_timing.h_border_right;
REG_UPDATE_2(OTG_H_BLANK_START_END,
OTG_H_BLANK_START, asic_blank_start,
OTG_H_BLANK_END, asic_blank_end);
......@@ -231,24 +218,15 @@ void optc1_program_timing(
OTG_V_SYNC_A_START, 0,
OTG_V_SYNC_A_END, v_sync_end);
vesa_sync_start = patched_crtc_timing.v_addressable +
patched_crtc_timing.v_border_bottom +
/* blank_start = frame end - front porch */
asic_blank_start = patched_crtc_timing.v_total -
patched_crtc_timing.v_front_porch;
asic_blank_end = (patched_crtc_timing.v_total -
vesa_sync_start -
patched_crtc_timing.v_border_top);
/* v_blank_start = v_blank_end + v_active */
asic_blank_start = asic_blank_end +
(patched_crtc_timing.v_border_top +
patched_crtc_timing.v_addressable +
patched_crtc_timing.v_border_bottom);
vertical_line_start = asic_blank_end - optc1->vstartup_start + 1;
v_fp2 = 0;
if (vertical_line_start < 0)
v_fp2 = -vertical_line_start;
/* blank_end = blank_start - active */
asic_blank_end = asic_blank_start -
patched_crtc_timing.v_border_bottom -
patched_crtc_timing.v_addressable -
patched_crtc_timing.v_border_top;
REG_UPDATE_2(OTG_V_BLANK_START_END,
OTG_V_BLANK_START, asic_blank_start,
......@@ -261,10 +239,9 @@ void optc1_program_timing(
REG_UPDATE(OTG_V_SYNC_A_CNTL,
OTG_V_SYNC_A_POL, v_sync_polarity);
v_init = asic_blank_start;
if (optc1->signal == SIGNAL_TYPE_DISPLAY_PORT ||
optc1->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
optc1->signal == SIGNAL_TYPE_EDP) {
optc1->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
optc1->signal == SIGNAL_TYPE_EDP) {
start_point = 1;
if (patched_crtc_timing.flags.INTERLACE == 1)
field_num = 1;
......@@ -272,13 +249,10 @@ void optc1_program_timing(
/* Interlace */
if (REG(OTG_INTERLACE_CONTROL)) {
if (patched_crtc_timing.flags.INTERLACE == 1) {
if (patched_crtc_timing.flags.INTERLACE == 1)
REG_UPDATE(OTG_INTERLACE_CONTROL,
OTG_INTERLACE_ENABLE, 1);
v_init = v_init / 2;
if ((optc1->vstartup_start/2)*2 > asic_blank_end)
v_fp2 = v_fp2 / 2;
} else
else
REG_UPDATE(OTG_INTERLACE_CONTROL,
OTG_INTERLACE_ENABLE, 0);
}
......@@ -287,21 +261,19 @@ void optc1_program_timing(
REG_UPDATE(CONTROL,
VTG0_ENABLE, 0);
REG_UPDATE_2(CONTROL,
VTG0_FP2, v_fp2,
VTG0_VCOUNT_INIT, v_init);
/* original code is using VTG offset to address OTG reg, seems wrong */
REG_UPDATE_2(OTG_CONTROL,
OTG_START_POINT_CNTL, start_point,
OTG_FIELD_NUMBER_CNTL, field_num);
optc1_program_global_sync(optc,
optc->funcs->program_global_sync(optc,
vready_offset,
vstartup_start,
vupdate_offset,
vupdate_width);
optc->funcs->set_vtg_params(optc, dc_crtc_timing);
/* TODO
* patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1
* program_horz_count_by_2
......@@ -319,6 +291,48 @@ void optc1_program_timing(
}
void optc1_set_vtg_params(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing)
{
struct dc_crtc_timing patched_crtc_timing;
uint32_t asic_blank_end;
uint32_t v_init;
uint32_t v_fp2 = 0;
int32_t vertical_line_start;
struct optc *optc1 = DCN10TG_FROM_TG(optc);
patched_crtc_timing = *dc_crtc_timing;
apply_front_porch_workaround(&patched_crtc_timing);
/* VCOUNT_INIT is the start of blank */
v_init = patched_crtc_timing.v_total - patched_crtc_timing.v_front_porch;
/* end of blank = v_init - active */
asic_blank_end = v_init -
patched_crtc_timing.v_border_bottom -
patched_crtc_timing.v_addressable -
patched_crtc_timing.v_border_top;
/* if VSTARTUP is before VSYNC, FP2 is the offset, otherwise 0 */
vertical_line_start = asic_blank_end - optc1->vstartup_start + 1;
if (vertical_line_start < 0)
v_fp2 = -vertical_line_start;
/* Interlace */
if (REG(OTG_INTERLACE_CONTROL)) {
if (patched_crtc_timing.flags.INTERLACE == 1) {
v_init = v_init / 2;
if ((optc1->vstartup_start/2)*2 > asic_blank_end)
v_fp2 = v_fp2 / 2;
}
}
REG_UPDATE_2(CONTROL,
VTG0_FP2, v_fp2,
VTG0_VCOUNT_INIT, v_init);
}
void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
......@@ -1443,6 +1457,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
.clear_optc_underflow = optc1_clear_optc_underflow,
.get_crc = optc1_get_crc,
.configure_crc = optc1_configure_crc,
.set_vtg_params = optc1_set_vtg_params,
};
void dcn10_timing_generator_init(struct optc *optc1)
......
......@@ -597,4 +597,7 @@ bool optc1_get_crc(struct timing_generator *optc,
bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing);
void optc1_set_vtg_params(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing);
#endif /* __DC_TIMING_GENERATOR_DCN10_H__ */
......@@ -238,6 +238,8 @@ struct timing_generator_funcs {
bool (*get_crc)(struct timing_generator *tg,
uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb);
void (*set_vtg_params)(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing);
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment