From 21ca2acab9462e65bda7a24a4c21a2fc80bef2f9 Mon Sep 17 00:00:00 2001 From: Christina Oliveira Date: Wed, 18 May 2022 09:38:40 -0700 Subject: [PATCH] disp: msm: sde: add support for hwfence profiling This change adds hwfence input and output fence profiling registers and debugfs to enable them. To enable input hw fences timestamps: echo 0x1 > /d/dri/0/debug/hw_fence_status To enable output hw fences timestamps: echo 0x2 > /d/dri/0/debug/hw_fence_status To enable both, input and output hw fences timestamps: echo 0x3 > /d/dri/0/debug/hw_fence_status. Change-Id: I269a38f3843a01ec8c0816890e50bb7d847a4ed9 Signed-off-by: Christina Oliveira --- msm/sde/sde_crtc.c | 10 +++++--- msm/sde/sde_encoder.c | 59 ++++++++++++++++++++++++++++++++++++------- msm/sde/sde_fence.c | 25 +++++++++++++----- msm/sde/sde_fence.h | 11 ++++++-- msm/sde/sde_hw_ctl.c | 47 ++++++++++++++++++++++++++++++++++ msm/sde/sde_hw_ctl.h | 17 +++++++++++++ msm/sde/sde_hw_top.c | 59 ++++++++++++++++++++++++++++++++++++++++++- msm/sde/sde_hw_top.h | 15 +++++++++++ msm/sde/sde_kms.c | 2 ++ msm/sde/sde_kms.h | 1 + msm/sde/sde_trace.h | 29 +++++++++++++++++++++ 11 files changed, 252 insertions(+), 23 deletions(-) diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 68c7dd5f5f..eaf5e3dcbd 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -3801,22 +3801,23 @@ static bool _sde_crtc_wait_for_fences(struct drm_crtc *crtc) int num_hw_fences = 0; struct sde_hw_ctl *hw_ctl; bool input_hw_fences_enable; + struct sde_kms *sde_kms = _sde_crtc_get_kms(crtc); int ret; SDE_DEBUG("\n"); - if (!crtc || !crtc->state) { + if (!crtc || !crtc->state || !sde_kms) { SDE_ERROR("invalid crtc/state %pK\n", crtc); return false; } - hw_ctl = _sde_crtc_get_hw_ctl(crtc); SDE_ATRACE_BEGIN("plane_wait_input_fence"); /* update ctl hw to wait for ipcc input signal before fetch */ if (test_bit(HW_FENCE_IN_FENCES_ENABLE, sde_crtc->hwfence_features_mask) && - !sde_fence_update_input_hw_fence_signal(hw_ctl)) + !sde_fence_update_input_hw_fence_signal(hw_ctl, sde_kms->debugfs_hw_fence, + sde_kms->hw_mdp)) ipcc_input_signal_wait = true; /* avoid hw-fences in first frame after timing engine enable */ @@ -4626,7 +4627,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, * condition between txq update and the hw signal during ctl-done for partial updates */ if (test_bit(HW_FENCE_OUT_FENCES_ENABLE, sde_crtc->hwfence_features_mask) && !is_vid) - sde_fence_update_hw_fences_txq(sde_crtc->output_fence, false, 0); + sde_fence_update_hw_fences_txq(sde_crtc->output_fence, false, 0, + sde_kms->debugfs_hw_fence); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc != crtc) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 3fd651ecba..877674237e 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -3433,6 +3433,35 @@ static enum sde_wb sde_encoder_get_wb(struct sde_mdss_cfg *catalog, return WB_MAX; } +void sde_encoder_hw_fence_status(struct sde_kms *sde_kms, + struct drm_crtc *crtc, struct sde_hw_ctl *hw_ctl) +{ + u64 start_timestamp, end_timestamp; + + if (!sde_kms || !hw_ctl || !sde_kms->hw_mdp) { + SDE_ERROR("invalid inputs\n"); + return; + } + + if ((sde_kms->debugfs_hw_fence & SDE_INPUT_HW_FENCE_TIMESTAMP) + && sde_kms->hw_mdp->ops.hw_fence_input_status) { + + sde_kms->hw_mdp->ops.hw_fence_input_status(sde_kms->hw_mdp, + &start_timestamp, &end_timestamp); + trace_sde_hw_fence_status(crtc->base.id, "input", + start_timestamp, end_timestamp); + } + + if ((sde_kms->debugfs_hw_fence & SDE_OUTPUT_HW_FENCE_TIMESTAMP) + && hw_ctl->ops.hw_fence_output_status) { + + hw_ctl->ops.hw_fence_output_status(hw_ctl, + &start_timestamp, &end_timestamp); + trace_sde_hw_fence_status(crtc->base.id, "output", + start_timestamp, end_timestamp); + } +} + void sde_encoder_perf_uidle_status(struct sde_kms *sde_kms, struct drm_crtc *crtc) { @@ -3492,7 +3521,7 @@ static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc, unsigned long lock_flags; ktime_t ts = 0; - if (!drm_enc || !phy_enc) + if (!drm_enc || !phy_enc || !phy_enc->sde_kms) return; SDE_ATRACE_BEGIN("encoder_vblank_callback"); @@ -3502,8 +3531,7 @@ static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc, * calculate accurate vsync timestamp when available * set current time otherwise */ - if (phy_enc->sde_kms && test_bit(SDE_FEATURE_HW_VSYNC_TS, - phy_enc->sde_kms->catalog->features)) + if (test_bit(SDE_FEATURE_HW_VSYNC_TS, phy_enc->sde_kms->catalog->features)) ts = sde_encoder_calc_last_vsync_timestamp(drm_enc); if (!ts) ts = ktime_get(); @@ -3515,10 +3543,12 @@ static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc, sde_enc->crtc_vblank_cb(sde_enc->crtc_vblank_cb_data, ts); spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags); - if (phy_enc->sde_kms && - phy_enc->sde_kms->catalog->uidle_cfg.debugfs_perf) + if (phy_enc->sde_kms->catalog->uidle_cfg.debugfs_perf) sde_encoder_perf_uidle_status(phy_enc->sde_kms, sde_enc->crtc); + if (phy_enc->sde_kms->debugfs_hw_fence) + sde_encoder_hw_fence_status(phy_enc->sde_kms, sde_enc->crtc, phy_enc->hw_ctl); + SDE_ATRACE_END("encoder_vblank_callback"); } @@ -3706,7 +3736,8 @@ int sde_encoder_idle_request(struct drm_encoder *drm_enc) * phys: Pointer to physical encoder structure * */ -static inline void _sde_encoder_update_retire_txq(struct sde_encoder_phys *phys) +static inline void _sde_encoder_update_retire_txq(struct sde_encoder_phys *phys, + struct sde_kms *sde_kms) { struct sde_connector *c_conn; int line_count; @@ -3720,7 +3751,8 @@ static inline void _sde_encoder_update_retire_txq(struct sde_encoder_phys *phys) line_count = sde_connector_get_property(phys->connector->state, CONNECTOR_PROP_EARLY_FENCE_LINE); if (c_conn->hwfence_wb_retire_fences_enable) - sde_fence_update_hw_fences_txq(c_conn->retire_fence, false, line_count); + sde_fence_update_hw_fences_txq(c_conn->retire_fence, false, line_count, + sde_kms->debugfs_hw_fence); } /** @@ -3933,16 +3965,23 @@ void sde_encoder_helper_hw_reset(struct sde_encoder_phys *phys_enc) void sde_encoder_helper_update_out_fence_txq(struct sde_encoder_virt *sde_enc, bool is_vid) { struct sde_crtc *sde_crtc; + struct sde_kms *sde_kms = NULL; if (!sde_enc || !sde_enc->crtc) { SDE_ERROR("invalid encoder %d\n", !sde_enc); return; } + sde_kms = sde_encoder_get_kms(&sde_enc->base); + if (!sde_kms) { + SDE_ERROR("invalid kms\n"); + return; + } sde_crtc = to_sde_crtc(sde_enc->crtc); SDE_EVT32(DRMID(sde_enc->crtc), is_vid); - sde_fence_update_hw_fences_txq(sde_crtc->output_fence, is_vid, 0); + sde_fence_update_hw_fences_txq(sde_crtc->output_fence, is_vid, 0, sde_kms ? + sde_kms->debugfs_hw_fence : 0); } /** @@ -4594,6 +4633,7 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool config_changed) { struct sde_encoder_virt *sde_enc; struct sde_encoder_phys *phys; + struct sde_kms *sde_kms; unsigned int i; if (!drm_enc) { @@ -4619,8 +4659,9 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool config_changed) } /* update txq for any output retire hw-fence (wb-path) */ + sde_kms = sde_encoder_get_kms(&sde_enc->base); if (sde_enc->cur_master) - _sde_encoder_update_retire_txq(sde_enc->cur_master); + _sde_encoder_update_retire_txq(sde_enc->cur_master, sde_kms); /* All phys encs are ready to go, trigger the kickoff */ _sde_encoder_kickoff_phys(sde_enc, config_changed); diff --git a/msm/sde/sde_fence.c b/msm/sde/sde_fence.c index 51b50dbe20..f461ac6f44 100644 --- a/msm/sde/sde_fence.c +++ b/msm/sde/sde_fence.c @@ -251,7 +251,7 @@ int sde_fence_register_hw_fences_wait(struct sde_hw_ctl *hw_ctl, struct dma_fenc return ret; } -static int _arm_output_hw_fence(struct sde_hw_ctl *hw_ctl, u32 line_count) +static int _arm_output_hw_fence(struct sde_hw_ctl *hw_ctl, u32 line_count, u32 debugfs_hw_fence) { struct sde_hw_fence_data *data; u32 ipcc_out_signal; @@ -279,6 +279,10 @@ static int _arm_output_hw_fence(struct sde_hw_ctl *hw_ctl, u32 line_count) SDE_DEBUG("out-fence ctl_id:%d out_signal:%d hw_fence_client:%s\n", ctl_id, ipcc_out_signal, _get_client_id_name(data->hw_fence_client_id)); + if ((debugfs_hw_fence & SDE_OUTPUT_HW_FENCE_TIMESTAMP) && + hw_ctl->ops.hw_fence_output_timestamp_ctrl) + hw_ctl->ops.hw_fence_output_timestamp_ctrl(hw_ctl, true, false); + /* update client/signal output fence */ hw_ctl->ops.hw_fence_update_output_fence(hw_ctl, data->ipcc_out_client, ipcc_out_signal); SDE_EVT32_VERBOSE(ctl_id, ipcc_out_signal); @@ -293,7 +297,8 @@ static int _arm_output_hw_fence(struct sde_hw_ctl *hw_ctl, u32 line_count) return 0; } -static int _sde_fence_arm_output_hw_fence(struct sde_fence_context *ctx, u32 line_count) +static int _sde_fence_arm_output_hw_fence(struct sde_fence_context *ctx, u32 line_count, + u32 debugfs_hw_fence) { struct sde_hw_ctl *hw_ctl = NULL; struct sde_fence *fc, *next; @@ -330,13 +335,14 @@ static int _sde_fence_arm_output_hw_fence(struct sde_fence_context *ctx, u32 lin /* arm dpu to trigger output hw-fence ipcc signal upon completion */ if (hw_ctl) - _arm_output_hw_fence(hw_ctl, line_count); + _arm_output_hw_fence(hw_ctl, line_count, debugfs_hw_fence); return 0; } /* update output hw_fences txq */ -int sde_fence_update_hw_fences_txq(struct sde_fence_context *ctx, bool vid_mode, u32 line_count) +int sde_fence_update_hw_fences_txq(struct sde_fence_context *ctx, bool vid_mode, u32 line_count, + u32 debugfs_hw_fence) { int ret = 0; struct sde_hw_fence_data *data; @@ -409,7 +415,7 @@ exit: /* arm dpu to trigger output hw-fence ipcc signal upon completion in vid-mode */ if ((txq_updated && hw_ctl) || line_count) - _sde_fence_arm_output_hw_fence(ctx, line_count); + _sde_fence_arm_output_hw_fence(ctx, line_count, debugfs_hw_fence); return ret; } @@ -462,7 +468,8 @@ static int _reset_hw_fence_timeline(struct sde_hw_ctl *hw_ctl, u32 flags) return ret; } -int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *hw_ctl) +int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *hw_ctl, u32 debugfs_hw_fence, + struct sde_hw_mdp *hw_mdp) { struct sde_hw_fence_data *data; u32 ipcc_signal_id; @@ -470,7 +477,7 @@ int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *hw_ctl) int ctl_id; /* we must support sw_override as well, so check both functions */ - if (!hw_ctl || !hw_ctl->ops.hw_fence_update_input_fence || + if (!hw_mdp || !hw_ctl || !hw_ctl->ops.hw_fence_update_input_fence || !hw_ctl->ops.hw_fence_trigger_sw_override) { SDE_ERROR("missing ctl/override/update fence %d\n", !hw_ctl); return -EINVAL; @@ -479,6 +486,10 @@ int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *hw_ctl) ctl_id = hw_ctl->idx - CTL_0; data = &hw_ctl->hwfence_data; + if ((debugfs_hw_fence & SDE_INPUT_HW_FENCE_TIMESTAMP) + && hw_mdp->ops.hw_fence_input_timestamp_ctrl) + hw_mdp->ops.hw_fence_input_timestamp_ctrl(hw_mdp, true, false); + ipcc_signal_id = data->ipcc_in_signal; ipcc_client_id = data->ipcc_in_client; diff --git a/msm/sde/sde_fence.h b/msm/sde/sde_fence.h index 6677bc8f74..57435f4b28 100644 --- a/msm/sde/sde_fence.h +++ b/msm/sde/sde_fence.h @@ -19,6 +19,9 @@ #define HW_FENCE_TRIGGER_SEL_CTRL_DONE 0x0 #define HW_FENCE_TRIGGER_SEL_PROG_LINE_COUNT 0x1 +#define SDE_INPUT_HW_FENCE_TIMESTAMP BIT(0) +#define SDE_OUTPUT_HW_FENCE_TIMESTAMP BIT(1) + #define SDE_FENCE_NAME_SIZE 24 #define MAX_SDE_HFENCE_OUT_SIGNAL_PING_PONG 2 @@ -179,17 +182,21 @@ int sde_fence_register_hw_fences_wait(struct sde_hw_ctl *hw_ctl, struct dma_fenc * * Returns: Zero on success, otherwise returns an error code. */ -int sde_fence_update_hw_fences_txq(struct sde_fence_context *ctx, bool vid_mode, u32 line_count); +int sde_fence_update_hw_fences_txq(struct sde_fence_context *ctx, bool vid_mode, u32 line_count, + u32 debugfs_hw_fence); /** * sde_fence_update_input_hw_fence_signal - updates input-fence ipcc signal in dpu and enables * hw-fences for the ctl. * * @ctl: hw ctl to update the input-fence and enable hw-fences + * @debugfs_hw_fence: hw-fence timestamp debugfs value + * @hw_mdp: pointer to hw_mdp to get timestamp registers * * Returns: Zero on success, otherwise returns an error code. */ -int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *ctl); +int sde_fence_update_input_hw_fence_signal(struct sde_hw_ctl *ctl, u32 debugfs_hw_fence, + struct sde_hw_mdp *hw_mdp); /** * sde_fence_deinit - deinit fence container diff --git a/msm/sde/sde_hw_ctl.c b/msm/sde/sde_hw_ctl.c index 6d5da122f8..fafed8cb41 100644 --- a/msm/sde/sde_hw_ctl.c +++ b/msm/sde/sde_hw_ctl.c @@ -61,6 +61,11 @@ #define CTL_OUTPUT_FENCE_ID 0x260 #define CTL_HW_FENCE_STATUS 0x278 #define CTL_OUTPUT_FENCE_SW_OVERRIDE 0x27C +#define CTL_TIMESTAMP_CTRL 0x264 +#define CTL_OUTPUT_FENCE_START_TIMESTAMP0 0x268 +#define CTL_OUTPUT_FENCE_START_TIMESTAMP1 0x26C +#define CTL_OUTPUT_FENCE_END_TIMESTAMP0 0x270 +#define CTL_OUTPUT_FENCE_END_TIMESTAMP1 0x274 #define CTL_MIXER_BORDER_OUT BIT(24) #define CTL_FLUSH_MASK_ROT BIT(27) @@ -377,6 +382,46 @@ static inline void sde_hw_ctl_trigger_output_fence_override(struct sde_hw_ctl *c SDE_REG_WRITE(&ctx->hw, CTL_OUTPUT_FENCE_SW_OVERRIDE, 0x1); } +static inline void sde_hw_ctl_fence_timestamp_ctrl(struct sde_hw_ctl *ctx, bool enable, bool clear) +{ + u32 val; + + val = SDE_REG_READ(&ctx->hw, CTL_TIMESTAMP_CTRL); + if (enable) + val |= BIT(0); + else + val &= ~BIT(0); + if (clear) + val |= BIT(1); + else + val &= ~BIT(1); + + SDE_REG_WRITE(&ctx->hw, CTL_TIMESTAMP_CTRL, val); + wmb(); /* make sure the ctrl is written */ +} + +static inline int sde_hw_ctl_output_fence_timestamps(struct sde_hw_ctl *ctx, + u64 *val_start, u64 *val_end) +{ + u32 start_l, start_h, end_l, end_h; + + if (!ctx || IS_ERR_OR_NULL(val_start) || IS_ERR_OR_NULL(val_end)) + return -EINVAL; + + start_l = SDE_REG_READ(&ctx->hw, CTL_OUTPUT_FENCE_START_TIMESTAMP0); + start_h = SDE_REG_READ(&ctx->hw, CTL_OUTPUT_FENCE_START_TIMESTAMP1); + *val_start = (u64)start_h << 32 | start_l; + + end_l = SDE_REG_READ(&ctx->hw, CTL_OUTPUT_FENCE_END_TIMESTAMP0); + end_h = SDE_REG_READ(&ctx->hw, CTL_OUTPUT_FENCE_END_TIMESTAMP1); + *val_end = (u64)end_h << 32 | end_l; + + /* clear timestamps */ + sde_hw_ctl_fence_timestamp_ctrl(ctx, false, true); + + return 0; +} + static inline int sde_hw_ctl_trigger_start(struct sde_hw_ctl *ctx) { if (!ctx) @@ -1433,6 +1478,8 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops, ops->hw_fence_trigger_sw_override = sde_hw_ctl_trigger_sw_override; ops->get_hw_fence_status = sde_hw_ctl_get_hw_fence_status; ops->trigger_output_fence_override = sde_hw_ctl_trigger_output_fence_override; + ops->hw_fence_output_status = sde_hw_ctl_output_fence_timestamps; + ops->hw_fence_output_timestamp_ctrl = sde_hw_ctl_fence_timestamp_ctrl; } if (cap & BIT(SDE_CTL_UIDLE)) diff --git a/msm/sde/sde_hw_ctl.h b/msm/sde/sde_hw_ctl.h index e1b148357b..8ed65ad088 100644 --- a/msm/sde/sde_hw_ctl.h +++ b/msm/sde/sde_hw_ctl.h @@ -189,6 +189,23 @@ struct sde_hw_ctl_ops { */ void (*hw_fence_trigger_sw_override)(struct sde_hw_ctl *ctx); + /** + * enable or clear hw fence output fence timestamps + * @ctx : ctl path ctx pointer + * @enable : indicates if timestamps should be enabled + * @clear : indicates if timestamps should be cleared + */ + void (*hw_fence_output_timestamp_ctrl)(struct sde_hw_ctl *ctx, bool enable, bool clear); + + /** + * get hw fence output fence timestamps and clear them + * @ctx : ctl path ctx pointer + * @val_start : pointer to start timestamp value + * @val_end : pointer to end timestamp value + * @Return: error code + */ + int (*hw_fence_output_status)(struct sde_hw_ctl *ctx, u64 *val_start, u64 *val_end); + /** * configure output hw fence trigger * @ctx : ctl path ctx pointer diff --git a/msm/sde/sde_hw_top.c b/msm/sde/sde_hw_top.c index 78645ca815..72bad93fa6 100644 --- a/msm/sde/sde_hw_top.c +++ b/msm/sde/sde_hw_top.c @@ -593,6 +593,60 @@ static u32 sde_hw_get_autorefresh_status(struct sde_hw_mdp *mdp, u32 intf_idx) return autorefresh_status; } +static void sde_hw_hw_fence_timestamp_ctrl(struct sde_hw_mdp *mdp, bool enable, bool clear) +{ + struct sde_hw_blk_reg_map c; + u32 val; + + if (!mdp) { + SDE_ERROR("invalid mdp, won't enable hw-fence timestamping\n"); + return; + } + + /* start from the base-address of the mdss */ + c = mdp->hw; + c.blk_off = 0x0; + + val = SDE_REG_READ(&c, MDP_CTL_HW_FENCE_ID_TIMESTAMP_CTRL); + if (enable) + val |= BIT(0); + else + val &= ~BIT(0); + if (clear) + val |= BIT(1); + else + val &= ~BIT(1); + SDE_REG_WRITE(&c, MDP_CTL_HW_FENCE_ID_TIMESTAMP_CTRL, val); +} + +static void sde_hw_input_hw_fence_status(struct sde_hw_mdp *mdp, u64 *s_val, u64 *e_val) +{ + u32 start_h, start_l, end_h, end_l; + struct sde_hw_blk_reg_map c; + + if (!mdp || IS_ERR_OR_NULL(s_val) || IS_ERR_OR_NULL(e_val)) { + SDE_ERROR("invalid mdp\n"); + return; + } + + /* start from the base-address of the mdss */ + c = mdp->hw; + c.blk_off = 0x0; + + start_l = SDE_REG_READ(&c, MDP_CTL_HW_FENCE_INPUT_START_TIMESTAMP0); + start_h = SDE_REG_READ(&c, MDP_CTL_HW_FENCE_INPUT_START_TIMESTAMP1); + *s_val = (u64)start_h << 32 | start_l; + + end_l = SDE_REG_READ(&c, MDP_CTL_HW_FENCE_INPUT_END_TIMESTAMP0); + end_h = SDE_REG_READ(&c, MDP_CTL_HW_FENCE_INPUT_END_TIMESTAMP1); + *e_val = (u64)end_h << 32 | end_l; + + /* clear the timestamps */ + sde_hw_hw_fence_timestamp_ctrl(mdp, false, true); + + wmb(); /* make sure the timestamps are cleared */ +} + static void sde_hw_setup_hw_fences_config(struct sde_hw_mdp *mdp, u32 protocol_id, unsigned long ipcc_base_addr) { @@ -711,8 +765,11 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, unsigned long cap, u32 hw ops->set_hdr_plus_metadata = sde_hw_set_hdr_plus_metadata; ops->get_autorefresh_status = sde_hw_get_autorefresh_status; - if (hw_fence_rev) + if (hw_fence_rev) { ops->setup_hw_fences = sde_hw_setup_hw_fences_config; + ops->hw_fence_input_timestamp_ctrl = sde_hw_hw_fence_timestamp_ctrl; + ops->hw_fence_input_status = sde_hw_input_hw_fence_status; + } } static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp, diff --git a/msm/sde/sde_hw_top.h b/msm/sde/sde_hw_top.h index 45fa9f808c..eed541d40f 100644 --- a/msm/sde/sde_hw_top.h +++ b/msm/sde/sde_hw_top.h @@ -215,6 +215,21 @@ struct sde_hw_mdp_ops { void (*setup_hw_fences)(struct sde_hw_mdp *mdp, u32 protocol_id, unsigned long ipcc_base_addr); + /** + * hw_fence_input_status - get hw_fence input fence timestamps and clear them + * @mdp: mdp top context driver + * @s_val: pointer to start timestamp value to populate + * @e_val: pointer to end timestamp value to populate + */ + void (*hw_fence_input_status)(struct sde_hw_mdp *mdp, u64 *s_val, u64 *e_val); + + /** + * hw_fence_input_timestamp_ctrl - enable or clear input fence timestamps + * @mdp: mdp top context driver + * @enable: indicates if timestamps should be enabled + * @enable: indicates if timestamps should be cleared + */ + void (*hw_fence_input_timestamp_ctrl)(struct sde_hw_mdp *mdp, bool enable, bool clear); }; struct sde_hw_mdp { diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index ec239bd08d..396fe0641f 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -172,6 +172,8 @@ static int _sde_debugfs_init(struct sde_kms *sde_kms) debugfs_create_u32("pm_suspend_clk_dump", 0600, debugfs_root, (u32 *)&sde_kms->pm_suspend_clk_dump); + debugfs_create_u32("hw_fence_status", 0600, debugfs_root, + (u32 *)&sde_kms->debugfs_hw_fence); return 0; } diff --git a/msm/sde/sde_kms.h b/msm/sde/sde_kms.h index d3408ee9ec..d82c5ea6d9 100644 --- a/msm/sde/sde_kms.h +++ b/msm/sde/sde_kms.h @@ -318,6 +318,7 @@ struct sde_kms { struct sde_vm *vm; unsigned long ipcc_base_addr; + u32 debugfs_hw_fence; }; struct vsync_info { diff --git a/msm/sde/sde_trace.h b/msm/sde/sde_trace.h index 0a77a80e90..6de27a1de3 100644 --- a/msm/sde/sde_trace.h +++ b/msm/sde/sde_trace.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. */ @@ -420,6 +421,34 @@ TRACE_EVENT(sde_perf_uidle_status, ) ); +TRACE_EVENT(sde_hw_fence_status, + TP_PROTO(u32 crtc, + char *fence, + u32 hw_fence_start_timestamp, + u32 hw_fence_end_timestamp), + TP_ARGS(crtc, + fence, + hw_fence_start_timestamp, + hw_fence_end_timestamp), + TP_STRUCT__entry( + __field(u32, crtc) + __field(char *, fence) + __field(u32, hw_fence_start_timestamp) + __field(u32, hw_fence_end_timestamp)), + TP_fast_assign( + __entry->crtc = crtc; + __entry->fence = fence; + __entry->hw_fence_start_timestamp = hw_fence_start_timestamp; + __entry->hw_fence_end_timestamp = hw_fence_end_timestamp;), + TP_printk( + "crtc:%d %s hw-fence start timestamp:%llu end timestamp:%llu", + __entry->crtc, + __entry->fence, + __entry->hw_fence_start_timestamp, + __entry->hw_fence_end_timestamp + ) +); + #define sde_atrace trace_tracing_mark_write #define SDE_ATRACE_END(name) sde_atrace('E', current, name, 0)