diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index f2359ccfa3fe..b72fa2f08ddf 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -2887,12 +2887,16 @@ static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc, static void sde_encoder_underrun_callback(struct drm_encoder *drm_enc, struct sde_encoder_phys *phy_enc) { + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); if (!phy_enc) return; SDE_ATRACE_BEGIN("encoder_underrun_callback"); atomic_inc(&phy_enc->underrun_cnt); SDE_EVT32(DRMID(drm_enc), atomic_read(&phy_enc->underrun_cnt)); + if (sde_enc->cur_master->ops.get_underrun_line_count) + sde_enc->cur_master->ops.get_underrun_line_count( + sde_enc->cur_master); trace_sde_encoder_underrun(DRMID(drm_enc), atomic_read(&phy_enc->underrun_cnt)); diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 6cea9324f8e2..698aab7b1d66 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -133,6 +133,8 @@ struct sde_encoder_virt_ops { * unitl transaction is complete. * @wait_for_active: Wait for display scan line to be in active area * @setup_vsync_source: Configure vsync source selection for cmd mode. + * @get_underrun_line_count: Obtain and log current internal vertical line + * count and underrun line count */ struct sde_encoder_phys_ops { @@ -185,6 +187,7 @@ struct sde_encoder_phys_ops { int (*wait_for_active)(struct sde_encoder_phys *phys); void (*setup_vsync_source)(struct sde_encoder_phys *phys, u32 vsync_source, bool is_dummy); + u32 (*get_underrun_line_count)(struct sde_encoder_phys *phys); }; /** diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index 303f70ef5ea7..fb3ee711eb25 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -1174,6 +1174,33 @@ static int sde_encoder_phys_vid_get_line_count( return phys_enc->hw_intf->ops.get_line_count(phys_enc->hw_intf); } +static u32 sde_encoder_phys_vid_get_underrun_line_count( + struct sde_encoder_phys *phys_enc) +{ + u32 underrun_linecount = 0xebadebad; + struct intf_status intf_status = {0}; + + if (!phys_enc) + return -EINVAL; + + if (!sde_encoder_phys_vid_is_master(phys_enc) || !phys_enc->hw_intf) + return -EINVAL; + + if (phys_enc->hw_intf->ops.get_status) + phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, + &intf_status); + + if (phys_enc->hw_intf->ops.get_underrun_line_count) + underrun_linecount = + phys_enc->hw_intf->ops.get_underrun_line_count( + phys_enc->hw_intf); + + SDE_EVT32(DRMID(phys_enc->parent), underrun_linecount, + intf_status.frame_count, intf_status.line_count); + + return underrun_linecount; +} + static int sde_encoder_phys_vid_wait_for_active( struct sde_encoder_phys *phys_enc) { @@ -1268,6 +1295,8 @@ static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops) ops->wait_dma_trigger = sde_encoder_phys_vid_wait_dma_trigger; ops->wait_for_active = sde_encoder_phys_vid_wait_for_active; ops->prepare_commit = sde_encoder_phys_vid_prepare_for_commit; + ops->get_underrun_line_count = + sde_encoder_phys_vid_get_underrun_line_count; } struct sde_encoder_phys *sde_encoder_phys_vid_init( diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index 91c69d2ad7ee..8024aadc0b48 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -62,6 +62,7 @@ #define INTF_MISR_SIGNATURE 0x184 #define INTF_MUX 0x25C +#define INTF_UNDERRUN_COUNT 0x268 #define INTF_STATUS 0x26C #define INTF_AVR_CONTROL 0x270 #define INTF_AVR_MODE 0x274 @@ -484,6 +485,23 @@ static u32 sde_hw_intf_get_line_count(struct sde_hw_intf *intf) return SDE_REG_READ(c, INTF_LINE_COUNT); } +static u32 sde_hw_intf_get_underrun_line_count(struct sde_hw_intf *intf) +{ + struct sde_hw_blk_reg_map *c; + u32 hsync_period; + + if (!intf) + return 0; + + c = &intf->hw; + hsync_period = SDE_REG_READ(c, INTF_HSYNC_CTL); + hsync_period = ((hsync_period & 0xffff0000) >> 16); + + return hsync_period ? + SDE_REG_READ(c, INTF_UNDERRUN_COUNT) / hsync_period : + 0xebadebad; +} + static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf, struct sde_hw_tear_check *te) { @@ -695,6 +713,7 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops, ops->setup_misr = sde_hw_intf_setup_misr; ops->collect_misr = sde_hw_intf_collect_misr; ops->get_line_count = sde_hw_intf_get_line_count; + ops->get_underrun_line_count = sde_hw_intf_get_underrun_line_count; ops->avr_setup = sde_hw_intf_avr_setup; ops->avr_trigger = sde_hw_intf_avr_trigger; ops->avr_ctrl = sde_hw_intf_avr_ctrl; diff --git a/msm/sde/sde_hw_intf.h b/msm/sde/sde_hw_intf.h index 3312397e51fe..790147103f9d 100644 --- a/msm/sde/sde_hw_intf.h +++ b/msm/sde/sde_hw_intf.h @@ -68,6 +68,8 @@ struct intf_avr_params { * @ setup_misr: enables/disables MISR in HW register * @ collect_misr: reads and stores MISR data from HW register * @ get_line_count: reads current vertical line counter + * @ get_underrun_line_count: reads current underrun pixel clock count and + * converts it into line count * @bind_pingpong_blk: enable/disable the connection with pingpong which will * feed pixels to this interface */ @@ -100,6 +102,7 @@ struct sde_hw_intf_ops { * is used for command mode panels */ u32 (*get_line_count)(struct sde_hw_intf *intf); + u32 (*get_underrun_line_count)(struct sde_hw_intf *intf); void (*bind_pingpong_blk)(struct sde_hw_intf *intf, bool enable,