From: Andrey Grodzovsky <Andrey.Grodzovsky@xxxxxxx> VBLANK interrupt is driven bu line buffer vcounter which is ahead of CRTC vcounter. Use an interrupt that fires at the actual CRTC vblank start boundry. Change-Id: I2d397447e105137451c966ddfc73f533f0d8bc4b Signed-off-by: Andrey Grodzovsky <Andrey.Grodzovsky at amd.com> Acked-by: Harry Wentland <Harry.Wentland at amd.com> Reviewed-by: Andrey Grodzovsky <Andrey.Grodzovsky at amd.com> --- .../display/dc/dce110/dce110_timing_generator.c | 46 ++++++++++++++- .../display/dc/dce110/dce110_timing_generator.h | 3 + .../display/dc/dce120/dce120_timing_generator.c | 32 +++++++++- .../amd/display/dc/dce80/dce80_timing_generator.c | 1 + .../drm/amd/display/dc/inc/hw/timing_generator.h | 2 + .../amd/display/dc/irq/dce110/irq_service_dce110.c | 68 +++++++++++++++------- .../amd/display/dc/irq/dce110/irq_service_dce110.h | 5 ++ .../amd/display/dc/irq/dce120/irq_service_dce120.c | 11 ++-- .../amd/display/dc/irq/dce80/irq_service_dce80.c | 22 ++++--- 9 files changed, 152 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c index f4b8576a0546..006412be7a02 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c @@ -1869,6 +1869,48 @@ void dce110_tg_set_colors(struct timing_generator *tg, dce110_tg_set_overscan_color(tg, overscan_color); } +/* Gets first line of blank region of the display timing for CRTC + * and programms is as a trigger to fire vertical interrupt + */ +bool dce110_arm_vert_intr(struct timing_generator *tg, uint8_t width) +{ + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t vbl = 0; + uint32_t val = 0; + uint32_t position, vbl_start; + + tg->funcs->get_scanoutpos( + tg, + &vbl, + &position); + + if (vbl == 0) + return false; + + vbl_start = + get_reg_field_value( + vbl, + CRTC_V_BLANK_START_END, + CRTC_V_BLANK_START); + + set_reg_field_value( + val, + vbl_start, + CRTC_VERTICAL_INTERRUPT0_POSITION, + CRTC_VERTICAL_INTERRUPT0_LINE_START); + + /* Set interaval width for interrupt to fire to 1 scanline */ + set_reg_field_value( + val, + vbl_start + width, + CRTC_VERTICAL_INTERRUPT0_POSITION, + CRTC_VERTICAL_INTERRUPT0_LINE_END); + + dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_VERTICAL_INTERRUPT0_POSITION), val); + + return true; +} + static const struct timing_generator_funcs dce110_tg_funcs = { .validate_timing = dce110_tg_validate_timing, .program_timing = dce110_tg_program_timing, @@ -1901,8 +1943,8 @@ static const struct timing_generator_funcs dce110_tg_funcs = { dce110_timing_generator_set_drr, .set_static_screen_control = dce110_timing_generator_set_static_screen_control, - .set_test_pattern = dce110_timing_generator_set_test_pattern - + .set_test_pattern = dce110_timing_generator_set_test_pattern, + .arm_vert_intr = dce110_arm_vert_intr, }; bool dce110_timing_generator_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h index 378509b8e56c..ca387b40fc67 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h @@ -271,4 +271,7 @@ void dce110_tg_set_colors(struct timing_generator *tg, const struct tg_color *blank_color, const struct tg_color *overscan_color); +bool dce110_arm_vert_intr( + struct timing_generator *tg, uint8_t width); + #endif /* __DC_TIMING_GENERATOR_DCE110_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 index d7e787b591a0..95cb1768aeb5 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c @@ -1039,6 +1039,35 @@ void dce120_timing_generator_set_test_pattern( } } +static bool dce120_arm_vert_intr( + struct timing_generator *tg, + uint8_t width) +{ + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t vbl, position, vbl_start; + + tg->funcs->get_scanoutpos( + tg, + &vbl, + &position); + + if (vbl == 0) + return false; + + vbl_start = + get_reg_field_value( + vbl, + CRTC0_CRTC_V_BLANK_START_END, + CRTC_V_BLANK_START); + + CRTC_REG_SET_2( + CRTC0_CRTC_VERTICAL_INTERRUPT0_POSITION, + CRTC_VERTICAL_INTERRUPT0_LINE_START, vbl_start, + CRTC_VERTICAL_INTERRUPT0_LINE_END, vbl_start + width); + + return true; +} + static struct timing_generator_funcs dce120_tg_funcs = { .validate_timing = dce120_tg_validate_timing, .program_timing = dce120_tg_program_timing, @@ -1068,7 +1097,8 @@ static struct timing_generator_funcs dce120_tg_funcs = { .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 + .set_test_pattern = dce120_timing_generator_set_test_pattern, + .arm_vert_intr = dce120_arm_vert_intr, }; diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c index eeccabd65a7a..1198f2fbf9c7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c @@ -145,6 +145,7 @@ static const struct timing_generator_funcs dce80_tg_funcs = { .set_static_screen_control = dce110_timing_generator_set_static_screen_control, .set_test_pattern = dce110_timing_generator_set_test_pattern, + .arm_vert_intr = dce110_arm_vert_intr, /* DCE8.0 overrides */ .enable_advanced_request = 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 62c19358254b..51902a4f8798 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 @@ -156,6 +156,8 @@ struct timing_generator_funcs { enum controller_dp_test_pattern test_pattern, enum dc_color_depth color_depth); + bool (*arm_vert_intr)(struct timing_generator *tg, uint8_t width); + }; #endif diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c index 4c7c85d45518..52361d1472fa 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c @@ -31,14 +31,10 @@ #include "dce/dce_11_0_d.h" #include "dce/dce_11_0_sh_mask.h" + #include "ivsrcid/ivsrcid_vislands30.h" -#define VISLANDS30_IV_SRCID_D1_VBLANK 1 -#define VISLANDS30_IV_SRCID_D2_VBLANK 2 -#define VISLANDS30_IV_SRCID_D3_VBLANK 3 -#define VISLANDS30_IV_SRCID_D4_VBLANK 4 -#define VISLANDS30_IV_SRCID_D5_VBLANK 5 -#define VISLANDS30_IV_SRCID_D6_VBLANK 6 +#include "core_dc.h" static bool hpd_ack( struct irq_service *irq_service, @@ -83,7 +79,7 @@ static const struct irq_source_info_funcs pflip_irq_info_funcs = { }; static const struct irq_source_info_funcs vblank_irq_info_funcs = { - .set = NULL, + .set = dce110_vblank_set, .ack = NULL }; @@ -148,18 +144,19 @@ static const struct irq_source_info_funcs vblank_irq_info_funcs = { #define vblank_int_entry(reg_num)\ [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ - .enable_reg = mmLB ## reg_num ## _LB_INTERRUPT_MASK,\ + .enable_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\ .enable_mask =\ - LB_INTERRUPT_MASK__VBLANK_INTERRUPT_MASK_MASK,\ + CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ .enable_value = {\ - LB_INTERRUPT_MASK__VBLANK_INTERRUPT_MASK_MASK,\ - ~LB_INTERRUPT_MASK__VBLANK_INTERRUPT_MASK_MASK},\ - .ack_reg = mmLB ## reg_num ## _LB_VBLANK_STATUS,\ + CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ + ~CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK},\ + .ack_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\ .ack_mask =\ - LB_VBLANK_STATUS__VBLANK_ACK_MASK,\ + CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\ .ack_value =\ - LB_VBLANK_STATUS__VBLANK_ACK_MASK,\ - .funcs = &vblank_irq_info_funcs\ + CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\ + .funcs = &vblank_irq_info_funcs,\ + .src_id = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 + reg_num\ } #define dummy_irq_entry() \ @@ -202,6 +199,35 @@ bool dal_irq_service_dummy_ack( return false; } + +bool dce110_vblank_set( + struct irq_service *irq_service, + const struct irq_source_info *info, + bool enable) +{ + struct dc_context *dc_ctx = irq_service->ctx; + struct core_dc *core_dc = DC_TO_CORE(irq_service->ctx->dc); + enum dc_irq_source dal_irq_src = dc_interrupt_to_irq_source( + irq_service->ctx->dc, + info->src_id, + info->ext_id); + uint8_t pipe_offset = dal_irq_src - IRQ_TYPE_VBLANK; + + struct timing_generator *tg = + core_dc->current_context->res_ctx.pipe_ctx[pipe_offset].tg; + + if (enable) { + if (!tg->funcs->arm_vert_intr(tg, 2)) { + DC_ERROR("Failed to get VBLANK!\n"); + return false; + } + } + + dal_irq_service_set_generic(irq_service, info, enable); + return true; + +} + static const struct irq_source_info_funcs dummy_irq_info_funcs = { .set = dal_irq_service_dummy_set, .ack = dal_irq_service_dummy_ack @@ -302,17 +328,17 @@ enum dc_irq_source to_dal_irq_source_dce110( uint32_t ext_id) { switch (src_id) { - case VISLANDS30_IV_SRCID_D1_VBLANK: + case VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0: return DC_IRQ_SOURCE_VBLANK1; - case VISLANDS30_IV_SRCID_D2_VBLANK: + case VISLANDS30_IV_SRCID_D2_VERTICAL_INTERRUPT0: return DC_IRQ_SOURCE_VBLANK2; - case VISLANDS30_IV_SRCID_D3_VBLANK: + case VISLANDS30_IV_SRCID_D3_VERTICAL_INTERRUPT0: return DC_IRQ_SOURCE_VBLANK3; - case VISLANDS30_IV_SRCID_D4_VBLANK: + case VISLANDS30_IV_SRCID_D4_VERTICAL_INTERRUPT0: return DC_IRQ_SOURCE_VBLANK4; - case VISLANDS30_IV_SRCID_D5_VBLANK: + case VISLANDS30_IV_SRCID_D5_VERTICAL_INTERRUPT0: return DC_IRQ_SOURCE_VBLANK5; - case VISLANDS30_IV_SRCID_D6_VBLANK: + case VISLANDS30_IV_SRCID_D6_VERTICAL_INTERRUPT0: return DC_IRQ_SOURCE_VBLANK6; case VISLANDS30_IV_SRCID_D1_V_UPDATE_INT: return DC_IRQ_SOURCE_VUPDATE1; diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.h b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.h index a84f360c6515..9237646c0959 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.h +++ b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.h @@ -45,4 +45,9 @@ bool dal_irq_service_dummy_ack( struct irq_service *irq_service, const struct irq_source_info *info); +bool dce110_vblank_set( + struct irq_service *irq_service, + const struct irq_source_info *info, + bool enable); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c b/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c index 5a263b2efa51..3871633ac635 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c @@ -79,7 +79,7 @@ static const struct irq_source_info_funcs pflip_irq_info_funcs = { }; static const struct irq_source_info_funcs vblank_irq_info_funcs = { - .set = NULL, + .set = dce110_vblank_set, .ack = NULL }; @@ -144,10 +144,11 @@ static const struct irq_source_info_funcs vblank_irq_info_funcs = { #define vblank_int_entry(reg_num)\ [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ - IRQ_REG_ENTRY(LB, reg_num,\ - LB_INTERRUPT_MASK, VBLANK_INTERRUPT_MASK,\ - LB_VBLANK_STATUS, VBLANK_ACK),\ - .funcs = &vblank_irq_info_funcs\ + IRQ_REG_ENTRY(CRTC, reg_num,\ + CRTC_VERTICAL_INTERRUPT0_CONTROL, CRTC_VERTICAL_INTERRUPT0_INT_ENABLE,\ + CRTC_VERTICAL_INTERRUPT0_CONTROL, CRTC_VERTICAL_INTERRUPT0_CLEAR),\ + .funcs = &vblank_irq_info_funcs,\ + .src_id = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 + reg_num\ } #define dummy_irq_entry() \ diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c b/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c index dd09d2b6d4a7..7e8cb22f280f 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c @@ -35,6 +35,9 @@ #include "ivsrcid/ivsrcid_vislands30.h" +#include "dc_types.h" +#include "inc/core_dc.h" + static bool hpd_ack( struct irq_service *irq_service, const struct irq_source_info *info) @@ -78,7 +81,7 @@ static const struct irq_source_info_funcs pflip_irq_info_funcs = { }; static const struct irq_source_info_funcs vblank_irq_info_funcs = { - .set = NULL, + .set = dce110_vblank_set, .ack = NULL }; @@ -145,18 +148,19 @@ static const struct irq_source_info_funcs vblank_irq_info_funcs = { #define vblank_int_entry(reg_num)\ [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ - .enable_reg = mmLB ## reg_num ## _LB_INTERRUPT_MASK,\ + .enable_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\ .enable_mask =\ - LB_INTERRUPT_MASK__VBLANK_INTERRUPT_MASK_MASK,\ + CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ .enable_value = {\ - LB_INTERRUPT_MASK__VBLANK_INTERRUPT_MASK_MASK,\ - ~LB_INTERRUPT_MASK__VBLANK_INTERRUPT_MASK_MASK},\ - .ack_reg = mmLB ## reg_num ## _LB_VBLANK_STATUS,\ + CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ + ~CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK},\ + .ack_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\ .ack_mask =\ - LB_VBLANK_STATUS__VBLANK_ACK_MASK,\ + CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\ .ack_value =\ - LB_VBLANK_STATUS__VBLANK_ACK_MASK,\ - .funcs = &vblank_irq_info_funcs\ + CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\ + .funcs = &vblank_irq_info_funcs,\ + .src_id = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 + reg_num\ } #define dummy_irq_entry() \ -- 2.11.0