[RFC PATCH 6/7] drm/msm/dpu: Implement tearcheck support on INTF block
Dmitry Baryshkov
dmitry.baryshkov at linaro.org
Mon Jan 2 15:48:05 UTC 2023
On 02/01/2023 13:06, Marijn Suijten wrote:
> On 2023-01-01 15:32:11, Dmitry Baryshkov wrote:
>> On 31/12/2022 23:50, Marijn Suijten wrote:
>>> Since DPU 5.0.0 the TEARCHECK registers and interrupts moved out of the
>>> PINGPONG block and into the INTF. Implement the necessary callbacks in
>>> the INTF block, and use these callbacks together with the INTF_TEAR
>>> interrupts
>>>
>>> Signed-off-by: Marijn Suijten <marijn.suijten at somainline.org>
>>
>> Generally I have the same question as for the patch 2. Can we have some
>> higher level functions in the hw_pp and hw_intf files?
>
> That is mostly because patch 2 only cleaned up non-optional handling of
> hw_pp callbacks in dpu_encoder_phys_cmd_prepare_commit, which utilizes
> hw_intf's autorefresh callbacks since this patch. I don't think there's
> any logic in the encoder currently that is unique to either PP or INTF?
I think it would be better to duplicate the logic rather than having a
spaghetti of hw_pp and hw_intf calls.
> There are quite a few functions that check for NULL hw_pp only, while -
> especially after this patch - should also check hw_intf to raise
> "invalid encoder". Should I extend those checks as well?
I think so. However in most of cases these checks should be void, since
cmd encoder can not be instantiated without intf.
>> Moreover, as I
>> review your patch I have the feeling that it would make sense to have to
>> two sets of encoder callbacks, one for the hw_pp tearing handling and
>> another set for hw_intf-based one.
>
> Do you mean to duplicate most phy_cmd functions and switch them based on
> has_intf_te in dpu_encoder_phys_cmd_init_ops? Or introduce an entirely
> new set of callbacks that simply hide / abstract away the check on
> has_intf_te? The former would duplicate a bunch of code unless that is
> abstracted away into other functions, mainly in
> dpu_encoder_phys_cmd_tearcheck_config and
> dpu_encoder_phys_cmd_prepare_commit.
For the dpu_encoder_phys_cmd_tearcheck_config() it seems logical to fill
in the tc_cfg and then to call either the single hw_pp callback or a
single hw_intf callback.
I'd move most of the code from prepare_commit to dpu_hw_pp and then
duplicate it to dpu_hw_intf. This seems like the lesser evil.
This function really stands out, since if you inline
_dpu_encoder_phys_cmd_connect_te() and
dpu_encoder_phys_cmd_is_ongoing_pptx() it becomes obvious that the whole
function is a mixture of linked calls to hw_pp ops. And judging from
your patch it doesn't make sense to check them one by one. Either we
have all of them, or none.
>
> Alternatively, could we find a way where these PP and INTF ops share the
> same struct and function signature? That might be tricky for passing in
> the hw_pp or hw_intf struct without leaking those details to the
> callback and/or have the switching logic in there.
>
>>> ---
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 11 +
>>> .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 10 +-
>>> .../drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 113 +++++++---
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 206 ++++++++++++++++++
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h | 29 +++
>>> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 2 +
>>> 6 files changed, 340 insertions(+), 31 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>>> index 9c6817b5a194..8b9070220ab2 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>>> @@ -673,6 +673,7 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc,
>>> struct dpu_kms *dpu_kms;
>>> struct dpu_hw_mdp *hw_mdptop;
>>> struct drm_encoder *drm_enc;
>>> + struct dpu_encoder_phys *phys_enc;
>>> int i;
>>>
>>> if (!dpu_enc || !disp_info) {
>>> @@ -703,12 +704,22 @@ static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc,
>>> vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx;
>>>
>>> vsync_cfg.pp_count = dpu_enc->num_phys_encs;
>>> + vsync_cfg.frame_rate = drm_mode_vrefresh(&dpu_enc->base.crtc->state->adjusted_mode);
>>> +
>>> if (disp_info->is_te_using_watchdog_timer)
>>> vsync_cfg.vsync_source = DPU_VSYNC_SOURCE_WD_TIMER_0;
>>> else
>>> vsync_cfg.vsync_source = DPU_VSYNC0_SOURCE_GPIO;
>>>
>>> hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg);
>>> +
>>> + for (i = 0; i < dpu_enc->num_phys_encs; i++) {
>>> + phys_enc = dpu_enc->phys_encs[i];
>>> +
>>> + if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel)
>>> + phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf,
>>> + vsync_cfg.vsync_source);
>>> + }
>>> }
>>> }
>>>
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
>>> index f2af07d87f56..47e79401032c 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
>>> @@ -148,10 +148,10 @@ struct dpu_encoder_phys_ops {
>>> /**
>>> * enum dpu_intr_idx - dpu encoder interrupt index
>>> * @INTR_IDX_VSYNC: Vsync interrupt for video mode panel
>>> - * @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel
>>> - * @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel
>>> - * @INTR_IDX_RDPTR: Readpointer done unterrupt for cmd mode panel
>>> - * @INTR_IDX_WB_DONE: Writeback fone interrupt for virtual connector
>>> + * @INTR_IDX_PINGPONG: Pingpong done interrupt for cmd mode panel
>>> + * @INTR_IDX_UNDERRUN: Underrun interrupt for video and cmd mode panel
>>> + * @INTR_IDX_RDPTR: Readpointer done interrupt for cmd mode panel
>>> + * @INTR_IDX_WB_DONE: Writeback done interrupt for virtual connector
>>> */
>>> enum dpu_intr_idx {
>>> INTR_IDX_VSYNC,
>>> @@ -195,6 +195,7 @@ enum dpu_intr_idx {
>>> * pending.
>>> * @pending_kickoff_wq: Wait queue for blocking until kickoff completes
>>> * @irq: IRQ indices
>>> + * @has_intf_te: Interface TE configuration support
>>> */
>>> struct dpu_encoder_phys {
>>> struct drm_encoder *parent;
>>> @@ -220,6 +221,7 @@ struct dpu_encoder_phys {
>>> atomic_t pending_kickoff_cnt;
>>> wait_queue_head_t pending_kickoff_wq;
>>> int irq[INTR_IDX_MAX];
>>> + bool has_intf_te;
>>> };
>>>
>>> static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
>>> index 7e5ba52197cd..ca44a8087f01 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
>>> @@ -100,12 +100,12 @@ static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
>>> DPU_ATRACE_END("pp_done_irq");
>>> }
>>>
>>> -static void dpu_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx)
>>> +static void dpu_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx)
>>> {
>>> struct dpu_encoder_phys *phys_enc = arg;
>>> struct dpu_encoder_phys_cmd *cmd_enc;
>>>
>>> - if (!phys_enc->hw_pp)
>>> + if (!phys_enc->hw_pp || !phys_enc->hw_intf)
>>> return;
>>>
>>> DPU_ATRACE_BEGIN("rd_ptr_irq");
>>> @@ -147,11 +147,19 @@ static void dpu_encoder_phys_cmd_atomic_mode_set(
>>> struct drm_crtc_state *crtc_state,
>>> struct drm_connector_state *conn_state)
>>> {
>>> + if (phys_enc->has_intf_te && !phys_enc->hw_intf) {
>>> + DPU_ERROR("invalid intf configuration\n");
>>> + return;
>>> + }
>>> +
>>> phys_enc->irq[INTR_IDX_CTL_START] = phys_enc->hw_ctl->caps->intr_start;
>>>
>>> phys_enc->irq[INTR_IDX_PINGPONG] = phys_enc->hw_pp->caps->intr_done;
>>>
>>> - phys_enc->irq[INTR_IDX_RDPTR] = phys_enc->hw_pp->caps->intr_rdptr;
>>> + if (phys_enc->has_intf_te)
>>> + phys_enc->irq[INTR_IDX_RDPTR] = phys_enc->hw_intf->cap->intr_tear_rd_ptr;
>>> + else
>>> + phys_enc->irq[INTR_IDX_RDPTR] = phys_enc->hw_pp->caps->intr_rdptr;
>>>
>>> phys_enc->irq[INTR_IDX_UNDERRUN] = phys_enc->hw_intf->cap->intr_underrun;
>>> }
>>> @@ -264,7 +272,7 @@ static int dpu_encoder_phys_cmd_control_vblank_irq(
>>> if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
>>> ret = dpu_core_irq_register_callback(phys_enc->dpu_kms,
>>> phys_enc->irq[INTR_IDX_RDPTR],
>>> - dpu_encoder_phys_cmd_pp_rd_ptr_irq,
>>> + dpu_encoder_phys_cmd_te_rd_ptr_irq,
>>> phys_enc);
>>> else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0)
>>> ret = dpu_core_irq_unregister_callback(phys_enc->dpu_kms,
>
> Fwiw looks like this function is a prime candidate to get updated with
> hw_intf information (in error checking and logging), as this callback is
> now shared between PP and INTF.
>
>>> @@ -336,10 +344,18 @@ static void dpu_encoder_phys_cmd_tearcheck_config(
>>>
>>> DPU_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
>>>
>>> - if (!phys_enc->hw_pp->ops.setup_tearcheck ||
>>> - !phys_enc->hw_pp->ops.enable_tearcheck) {
>>> - DPU_DEBUG_CMDENC(cmd_enc, "tearcheck not supported\n");
>>> - return;
>>> + if (phys_enc->has_intf_te) {
>>> + if (!phys_enc->hw_intf->ops.setup_tearcheck ||
>>> + !phys_enc->hw_intf->ops.enable_tearcheck) {
>>> + DPU_DEBUG_CMDENC(cmd_enc, "tearcheck not supported\n");
>>> + return;
>>> + }
>>> + } else {
>>> + if (!phys_enc->hw_pp->ops.setup_tearcheck ||
>>> + !phys_enc->hw_pp->ops.enable_tearcheck) {
>>> + DPU_DEBUG_CMDENC(cmd_enc, "tearcheck not supported\n");
>>> + return;
>>> + }
>>> }
>>>
>>> dpu_kms = phys_enc->dpu_kms;
>>> @@ -392,8 +408,13 @@ static void dpu_encoder_phys_cmd_tearcheck_config(
>>> phys_enc->hw_pp->idx - PINGPONG_0, tc_cfg.sync_cfg_height,
>>> tc_cfg.sync_threshold_start, tc_cfg.sync_threshold_continue);
>>>
>>> - phys_enc->hw_pp->ops.setup_tearcheck(phys_enc->hw_pp, &tc_cfg);
>>> - phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, tc_enable);
>>
>> A simple random example: setup_tearcheck is always followed with the
>> enable_tearcheck. If we merge them, the code would be simpler.
>
> setup_tearcheck could include this functionality, but note that
> dpu_encoder_phys_cmd_disable currently calls enable_tearcheck(false)
> without setup_tearcheck.
Yes, so enable_tearcheck() and disable_tearcheck() sound more useful.
>
> - Marijn
>
>>> <snip>
--
With best wishes
Dmitry
More information about the dri-devel
mailing list