diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index 4bb5cd83b2..3524fcefe9 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -320,6 +320,8 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( struct sde_encoder_phys *phys_enc) { struct sde_encoder_irq *irq; + struct sde_kms *sde_kms = phys_enc->sde_kms; + int ret = 0; if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl) { SDE_ERROR("invalid args %d %d\n", !phys_enc, @@ -332,6 +334,21 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( return; } + mutex_lock(&sde_kms->vblank_ctl_global_lock); + + if (atomic_read(&phys_enc->vblank_refcount)) { + SDE_ERROR( + "vblank_refcount mismatch detected, try to reset %d\n", + atomic_read(&phys_enc->vblank_refcount)); + ret = sde_encoder_helper_unregister_irq(phys_enc, + INTR_IDX_RDPTR); + if (ret) + SDE_ERROR( + "control vblank irq registration error %d\n", + ret); + } + atomic_set(&phys_enc->vblank_refcount, 0); + irq = &phys_enc->irq[INTR_IDX_CTL_START]; irq->hw_idx = phys_enc->hw_ctl->idx; irq->irq_idx = -EINVAL; @@ -365,6 +382,8 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( else irq->hw_idx = phys_enc->hw_pp->idx; + mutex_unlock(&sde_kms->vblank_ctl_global_lock); + } static void sde_encoder_phys_cmd_cont_splash_mode_set( @@ -800,13 +819,15 @@ static int sde_encoder_phys_cmd_control_vblank_irq( to_sde_encoder_phys_cmd(phys_enc); int ret = 0; int refcount; + struct sde_kms *sde_kms; if (!phys_enc || !phys_enc->hw_pp) { SDE_ERROR("invalid encoder\n"); return -EINVAL; } + sde_kms = phys_enc->sde_kms; - mutex_lock(phys_enc->vblank_ctl_lock); + mutex_lock(&sde_kms->vblank_ctl_global_lock); refcount = atomic_read(&phys_enc->vblank_refcount); /* Slave encoders don't report vblank */ @@ -824,11 +845,17 @@ static int sde_encoder_phys_cmd_control_vblank_irq( SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, enable, refcount); - if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) + if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) { ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR); - else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0) + if (ret) + atomic_dec_return(&phys_enc->vblank_refcount); + } else if (!enable && + atomic_dec_return(&phys_enc->vblank_refcount) == 0) { ret = sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_RDPTR); + if (ret) + atomic_inc_return(&phys_enc->vblank_refcount); + } end: if (ret) { @@ -840,7 +867,7 @@ end: enable, refcount, SDE_EVTLOG_ERROR); } - mutex_unlock(phys_enc->vblank_ctl_lock); + mutex_unlock(&sde_kms->vblank_ctl_global_lock); return ret; } diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 45b7e14021..c27a3a8dc6 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -3418,6 +3418,8 @@ static int sde_kms_hw_init(struct msm_kms *kms) dev->mode_config.max_height = sde_kms->catalog->max_display_height; mutex_init(&sde_kms->secure_transition_lock); + mutex_init(&sde_kms->vblank_ctl_global_lock); + atomic_set(&sde_kms->detach_sec_cb, 0); atomic_set(&sde_kms->detach_all_cb, 0); diff --git a/msm/sde/sde_kms.h b/msm/sde/sde_kms.h index 56c0d23eae..378b57e859 100644 --- a/msm/sde/sde_kms.h +++ b/msm/sde/sde_kms.h @@ -299,6 +299,7 @@ struct sde_kms { atomic_t detach_sec_cb; atomic_t detach_all_cb; struct mutex secure_transition_lock; + struct mutex vblank_ctl_global_lock; bool first_kickoff; bool qdss_enabled;