drm/amd/display: log destination of vertical interrupt

[Why]
Knowing the destination of OTG's vertical interrupt 2 is useful for
debugging, but it is not currently included in the OTG state readback
logic

[How]
Read the OTG interrupt destination register to get the vertical interrupt
2 destination on ASICs that have this register when reading back the OTG
state from hardware

Reviewed-by: Sung Lee <sung.lee@amd.com>
Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Signed-off-by: Josip Pavic <Josip.Pavic@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Josip Pavic 2025-01-07 11:00:11 -05:00 committed by Alex Deucher
parent 6eb4c13a38
commit 06b0a4ad71
23 changed files with 145 additions and 42 deletions

View File

@ -429,7 +429,9 @@ static unsigned int dcn10_get_otg_states(struct dc *dc, char *pBuf, unsigned int
struct dcn_otg_state s = {0};
int pix_clk = 0;
optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
if (tg->funcs->read_otg_state)
tg->funcs->read_otg_state(tg, &s);
pix_clk = dc->current_state->res_ctx.pipe_ctx[i].stream_res.pix_clk_params.requested_pix_clk_100hz / 10;
//only print if OTG master is enabled
@ -495,7 +497,8 @@ static void dcn10_clear_otpc_underflow(struct dc *dc)
struct timing_generator *tg = pool->timing_generators[i];
struct dcn_otg_state s = {0};
optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
if (tg->funcs->read_otg_state)
tg->funcs->read_otg_state(tg, &s);
if (s.otg_enabled & 1)
tg->funcs->clear_optc_underflow(tg);

View File

@ -415,7 +415,8 @@ void dcn10_log_hw_state(struct dc *dc,
struct timing_generator *tg = pool->timing_generators[i];
struct dcn_otg_state s = {0};
/* Read shared OTG state registers for all DCNx */
optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
if (tg->funcs->read_otg_state)
tg->funcs->read_otg_state(tg, &s);
/*
* For DCN2 and greater, a register on the OPP is used to

View File

@ -70,35 +70,7 @@ struct optc {
enum signal_type signal;
};
struct dcn_otg_state {
uint32_t v_blank_start;
uint32_t v_blank_end;
uint32_t v_sync_a_pol;
uint32_t v_total;
uint32_t v_total_max;
uint32_t v_total_min;
uint32_t v_total_min_sel;
uint32_t v_total_max_sel;
uint32_t v_sync_a_start;
uint32_t v_sync_a_end;
uint32_t h_blank_start;
uint32_t h_blank_end;
uint32_t h_sync_a_start;
uint32_t h_sync_a_end;
uint32_t h_sync_a_pol;
uint32_t h_total;
uint32_t underflow_occurred_status;
uint32_t otg_enabled;
uint32_t blank_enabled;
uint32_t vertical_interrupt1_en;
uint32_t vertical_interrupt1_line;
uint32_t vertical_interrupt2_en;
uint32_t vertical_interrupt2_line;
uint32_t otg_master_update_lock;
uint32_t otg_double_buffer_control;
};
void optc1_read_otg_state(struct optc *optc1, struct dcn_otg_state *s);
void optc1_read_otg_state(struct timing_generator *optc, struct dcn_otg_state *s);
bool optc1_get_hw_timing(struct timing_generator *tg, struct dc_crtc_timing *hw_crtc_timing);

View File

@ -146,6 +146,35 @@ struct crc_params {
bool reset;
};
struct dcn_otg_state {
uint32_t v_blank_start;
uint32_t v_blank_end;
uint32_t v_sync_a_pol;
uint32_t v_total;
uint32_t v_total_max;
uint32_t v_total_min;
uint32_t v_total_min_sel;
uint32_t v_total_max_sel;
uint32_t v_sync_a_start;
uint32_t v_sync_a_end;
uint32_t h_blank_start;
uint32_t h_blank_end;
uint32_t h_sync_a_start;
uint32_t h_sync_a_end;
uint32_t h_sync_a_pol;
uint32_t h_total;
uint32_t underflow_occurred_status;
uint32_t otg_enabled;
uint32_t blank_enabled;
uint32_t vertical_interrupt1_en;
uint32_t vertical_interrupt1_line;
uint32_t vertical_interrupt2_en;
uint32_t vertical_interrupt2_line;
uint32_t vertical_interrupt2_dest;
uint32_t otg_master_update_lock;
uint32_t otg_double_buffer_control;
};
/**
* struct timing_generator - Entry point to Output Timing Generator feature.
*/
@ -350,6 +379,7 @@ struct timing_generator_funcs {
bool (*get_pipe_update_pending)(struct timing_generator *tg);
void (*set_vupdate_keepout)(struct timing_generator *tg, bool enable);
bool (*wait_update_lock_status)(struct timing_generator *tg, bool locked);
void (*read_otg_state)(struct timing_generator *tg, struct dcn_otg_state *s);
};
#endif

View File

@ -1312,7 +1312,7 @@ bool optc1_get_hw_timing(struct timing_generator *tg,
if (tg == NULL || hw_crtc_timing == NULL)
return false;
optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
optc1_read_otg_state(tg, &s);
hw_crtc_timing->h_total = s.h_total + 1;
hw_crtc_timing->h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end);
@ -1328,9 +1328,11 @@ bool optc1_get_hw_timing(struct timing_generator *tg,
}
void optc1_read_otg_state(struct optc *optc1,
void optc1_read_otg_state(struct timing_generator *optc,
struct dcn_otg_state *s)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
REG_GET(OTG_CONTROL,
OTG_MASTER_EN, &s->otg_enabled);
@ -1663,6 +1665,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
.setup_manual_trigger = optc1_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.read_otg_state = optc1_read_otg_state,
};
void dcn10_timing_generator_init(struct optc *optc1)

View File

@ -209,6 +209,7 @@ struct dcn_optc_registers {
uint32_t OPTC_WIDTH_CONTROL2;
uint32_t OTG_PSTATE_REGISTER;
uint32_t OTG_PIPE_UPDATE_STATUS;
uint32_t INTERRUPT_DEST;
};
#define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\
@ -591,6 +592,7 @@ struct dcn_optc_registers {
type OTG_DC_REG_UPDATE_PENDING;\
type OTG_CURSOR_UPDATE_PENDING;\
type OTG_VUPDATE_KEEPOUT_STATUS;\
type OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST;
#define TG_REG_FIELD_LIST_DCN3_2(type) \
type OTG_H_TIMING_DIV_MODE_MANUAL;

View File

@ -562,6 +562,7 @@ static struct timing_generator_funcs dcn20_tg_funcs = {
.get_hw_timing = optc1_get_hw_timing,
.align_vblanks = optc2_align_vblanks,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.read_otg_state = optc1_read_otg_state,
};
void dcn20_timing_generator_init(struct optc *optc1)

View File

@ -180,6 +180,7 @@ static struct timing_generator_funcs dcn201_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.read_otg_state = optc1_read_otg_state,
};
void dcn201_timing_generator_init(struct optc *optc1)

View File

@ -420,6 +420,7 @@ static struct timing_generator_funcs dcn30_tg_funcs = {
.get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending,
.get_otg_double_buffer_pending = optc3_get_otg_update_pending,
.get_pipe_update_pending = optc3_get_pipe_update_pending,
.read_otg_state = optc1_read_otg_state,
};
void dcn30_timing_generator_init(struct optc *optc1)

View File

@ -172,6 +172,7 @@ static struct timing_generator_funcs dcn30_tg_funcs = {
.get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending,
.get_otg_double_buffer_pending = optc3_get_otg_update_pending,
.get_pipe_update_pending = optc3_get_pipe_update_pending,
.read_otg_state = optc1_read_otg_state,
};
void dcn301_timing_generator_init(struct optc *optc1)

View File

@ -245,6 +245,76 @@ void optc3_init_odm(struct timing_generator *optc)
optc1->opp_count = 1;
}
void optc31_read_otg_state(struct timing_generator *optc,
struct dcn_otg_state *s)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
REG_GET(OTG_CONTROL,
OTG_MASTER_EN, &s->otg_enabled);
REG_GET_2(OTG_V_BLANK_START_END,
OTG_V_BLANK_START, &s->v_blank_start,
OTG_V_BLANK_END, &s->v_blank_end);
REG_GET(OTG_V_SYNC_A_CNTL,
OTG_V_SYNC_A_POL, &s->v_sync_a_pol);
REG_GET(OTG_V_TOTAL,
OTG_V_TOTAL, &s->v_total);
REG_GET(OTG_V_TOTAL_MAX,
OTG_V_TOTAL_MAX, &s->v_total_max);
REG_GET(OTG_V_TOTAL_MIN,
OTG_V_TOTAL_MIN, &s->v_total_min);
REG_GET(OTG_V_TOTAL_CONTROL,
OTG_V_TOTAL_MAX_SEL, &s->v_total_max_sel);
REG_GET(OTG_V_TOTAL_CONTROL,
OTG_V_TOTAL_MIN_SEL, &s->v_total_min_sel);
REG_GET_2(OTG_V_SYNC_A,
OTG_V_SYNC_A_START, &s->v_sync_a_start,
OTG_V_SYNC_A_END, &s->v_sync_a_end);
REG_GET_2(OTG_H_BLANK_START_END,
OTG_H_BLANK_START, &s->h_blank_start,
OTG_H_BLANK_END, &s->h_blank_end);
REG_GET_2(OTG_H_SYNC_A,
OTG_H_SYNC_A_START, &s->h_sync_a_start,
OTG_H_SYNC_A_END, &s->h_sync_a_end);
REG_GET(OTG_H_SYNC_A_CNTL,
OTG_H_SYNC_A_POL, &s->h_sync_a_pol);
REG_GET(OTG_H_TOTAL,
OTG_H_TOTAL, &s->h_total);
REG_GET(OPTC_INPUT_GLOBAL_CONTROL,
OPTC_UNDERFLOW_OCCURRED_STATUS, &s->underflow_occurred_status);
REG_GET(OTG_VERTICAL_INTERRUPT1_CONTROL,
OTG_VERTICAL_INTERRUPT1_INT_ENABLE, &s->vertical_interrupt1_en);
REG_GET(OTG_VERTICAL_INTERRUPT1_POSITION,
OTG_VERTICAL_INTERRUPT1_LINE_START, &s->vertical_interrupt1_line);
REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL,
OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &s->vertical_interrupt2_en);
REG_GET(OTG_VERTICAL_INTERRUPT2_POSITION,
OTG_VERTICAL_INTERRUPT2_LINE_START, &s->vertical_interrupt2_line);
REG_GET(INTERRUPT_DEST,
OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, &s->vertical_interrupt2_dest);
s->otg_master_update_lock = REG_READ(OTG_MASTER_UPDATE_LOCK);
s->otg_double_buffer_control = REG_READ(OTG_DOUBLE_BUFFER_CONTROL);
}
static struct timing_generator_funcs dcn31_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
@ -306,6 +376,7 @@ static struct timing_generator_funcs dcn31_tg_funcs = {
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.read_otg_state = optc31_read_otg_state,
};
void dcn31_timing_generator_init(struct optc *optc1)

View File

@ -100,7 +100,8 @@
SRI(OTG_CRC_CNTL2, OTG, inst),\
SR(DWB_SOURCE_SELECT),\
SRI(OTG_DRR_CONTROL, OTG, inst),\
SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst)
SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst),\
SRI(INTERRUPT_DEST, OTG, inst)
#define OPTC_COMMON_MASK_SH_LIST_DCN3_1(mask_sh)\
SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\
@ -260,6 +261,7 @@
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\
SF(OTG0_INTERRUPT_DEST, OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, mask_sh)
void dcn31_timing_generator_init(struct optc *optc1);
@ -269,4 +271,7 @@ void optc31_set_drr(struct timing_generator *optc, const struct drr_params *para
void optc3_init_odm(struct timing_generator *optc);
void optc31_read_otg_state(struct timing_generator *optc,
struct dcn_otg_state *s);
#endif /* __DC_OPTC_DCN31_H__ */

View File

@ -255,6 +255,7 @@ static struct timing_generator_funcs dcn314_tg_funcs = {
.set_odm_combine = optc314_set_odm_combine,
.set_h_timing_div_manual_mode = optc314_set_h_timing_div_manual_mode,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.read_otg_state = optc31_read_otg_state,
};
void dcn314_timing_generator_init(struct optc *optc1)

View File

@ -99,7 +99,8 @@
SRI(OPTC_WIDTH_CONTROL, ODM, inst),\
SRI(OPTC_MEMORY_CONFIG, ODM, inst),\
SRI(OTG_DRR_CONTROL, OTG, inst),\
SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst)
SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst),\
SRI(INTERRUPT_DEST, OTG, inst)
#define OPTC_COMMON_MASK_SH_LIST_DCN3_14(mask_sh)\
SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\
@ -254,6 +255,7 @@
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\
SF(OTG0_INTERRUPT_DEST, OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, mask_sh)
void dcn314_timing_generator_init(struct optc *optc1);

View File

@ -364,6 +364,7 @@ static struct timing_generator_funcs dcn32_tg_funcs = {
.get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending,
.get_otg_double_buffer_pending = optc3_get_otg_update_pending,
.get_pipe_update_pending = optc3_get_pipe_update_pending,
.read_otg_state = optc31_read_otg_state,
};
void dcn32_timing_generator_init(struct optc *optc1)

View File

@ -181,7 +181,8 @@
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh)
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\
SF(OTG0_INTERRUPT_DEST, OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, mask_sh)
void dcn32_timing_generator_init(struct optc *optc1);
void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode);

View File

@ -492,6 +492,7 @@ static struct timing_generator_funcs dcn35_tg_funcs = {
.init_odm = optc3_init_odm,
.set_long_vtotal = optc35_set_long_vtotal,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.read_otg_state = optc31_read_otg_state,
};
void dcn35_timing_generator_init(struct optc *optc1)

View File

@ -71,7 +71,8 @@
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh)
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\
SF(OTG0_INTERRUPT_DEST, OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, mask_sh)
void dcn35_timing_generator_init(struct optc *optc1);

View File

@ -527,6 +527,7 @@ static struct timing_generator_funcs dcn401_tg_funcs = {
.get_pipe_update_pending = optc3_get_pipe_update_pending,
.set_vupdate_keepout = optc401_set_vupdate_keepout,
.wait_update_lock_status = optc401_wait_update_lock_status,
.read_otg_state = optc31_read_otg_state,
};
void dcn401_timing_generator_init(struct optc *optc1)

View File

@ -163,7 +163,8 @@
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh)
SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\
SF(OTG0_INTERRUPT_DEST, OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, mask_sh)
void dcn401_timing_generator_init(struct optc *optc1);

View File

@ -1055,7 +1055,8 @@ unsigned int dcn32_calculate_mall_ways_from_bytes(const struct dc *dc, unsigned
SRI_ARR(OPTC_WIDTH_CONTROL, ODM, inst), \
SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst), \
SRI_ARR(OTG_DRR_CONTROL, OTG, inst), \
SRI_ARR(OTG_PIPE_UPDATE_STATUS, OTG, inst)
SRI_ARR(OTG_PIPE_UPDATE_STATUS, OTG, inst), \
SRI_ARR(INTERRUPT_DEST, OTG, inst)
/* HUBP */

View File

@ -305,7 +305,8 @@ struct resource_pool *dcn35_create_resource_pool(
SRI_ARR(OPTC_WIDTH_CONTROL, ODM, inst),\
SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst),\
SRI_ARR(OTG_DRR_CONTROL, OTG, inst),\
SRI2_ARR(OPTC_CLOCK_CONTROL, OPTC, inst)
SRI2_ARR(OPTC_CLOCK_CONTROL, OPTC, inst),\
SRI_ARR(INTERRUPT_DEST, OTG, inst)
/* DPP */
#define DPP_REG_LIST_DCN35_RI(id)\

View File

@ -538,7 +538,8 @@ void dcn401_prepare_mcache_programming(struct dc *dc, struct dc_state *context);
SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst), \
SRI_ARR(OTG_DRR_CONTROL, OTG, inst), \
SRI_ARR(OTG_PSTATE_REGISTER, OTG, inst), \
SRI_ARR(OTG_PIPE_UPDATE_STATUS, OTG, inst)
SRI_ARR(OTG_PIPE_UPDATE_STATUS, OTG, inst), \
SRI_ARR(INTERRUPT_DEST, OTG, inst)
/* HUBBUB */
#define HUBBUB_REG_LIST_DCN4_01_RI(id) \