Merge tag 'LA.UM.9.14.r1-23300-LAHAINA.QSSI14.0' of https://git.codelinaro.org/clo/la/platform/vendor/opensource/display-drivers into android13-5.4-lahaina

"LA.UM.9.14.r1-23300-LAHAINA.QSSI14.0"

* tag 'LA.UM.9.14.r1-23300-LAHAINA.QSSI14.0' of https://git.codelinaro.org/clo/la/platform/vendor/opensource/display-drivers:
  disp: msm: sde: skip msm_lastclose if display is stuck in splash
  disp: msm: cancel all delayed_works before triggering msm_lastclose
  disp: msm: sde: cancel delayed work items during TUI transition

Change-Id: I8dbdda8ada31d7d58a5aceaf7e72d6955cee2ec2
This commit is contained in:
Michael Bestas 2023-12-11 20:41:53 +02:00
commit 8b685a05b5
No known key found for this signature in database
GPG key ID: CC95044519BE6669
7 changed files with 159 additions and 84 deletions

View file

@ -954,6 +954,25 @@ mdss_init_fail:
return ret;
}
void msm_atomic_flush_display_threads(struct msm_drm_private *priv)
{
int i;
if (!priv) {
SDE_ERROR("invalid private data\n");
return;
}
for (i = 0; i < priv->num_crtcs; i++) {
if (priv->disp_thread[i].thread)
kthread_flush_worker(&priv->disp_thread[i].worker);
if (priv->event_thread[i].thread)
kthread_flush_worker(&priv->event_thread[i].worker);
}
kthread_flush_worker(&priv->pp_event_worker);
}
/*
* DRM operations:
*/
@ -1050,10 +1069,8 @@ static void msm_lastclose(struct drm_device *dev)
priv->pending_crtcs);
rc = kms->funcs->trigger_null_flush(kms);
if (rc) {
DRM_ERROR("null flush commit failure during lastclose\n");
if (rc)
return;
}
}
/*
@ -1077,6 +1094,8 @@ static void msm_lastclose(struct drm_device *dev)
DRM_INFO("wait for crtc mask 0x%x failed, commit anyway...\n",
priv->pending_crtcs);
msm_atomic_flush_display_threads(priv);
if (priv->fbdev) {
rc = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
if (rc)

View file

@ -973,6 +973,8 @@ struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev);
void msm_atomic_state_clear(struct drm_atomic_state *state);
void msm_atomic_state_free(struct drm_atomic_state *state);
void msm_atomic_flush_display_threads(struct msm_drm_private *priv);
int msm_gem_init_vma(struct msm_gem_address_space *aspace,
struct msm_gem_vma *vma, int npages);
void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,

View file

@ -6626,6 +6626,24 @@ static void __sde_crtc_idle_notify_work(struct kthread_work *work)
}
}
void sde_crtc_cancel_delayed_work(struct drm_crtc *crtc)
{
struct sde_crtc *sde_crtc;
struct sde_crtc_state *cstate;
bool idle_status;
bool cache_status;
if (!crtc || !crtc->state)
return;
sde_crtc = to_sde_crtc(crtc);
cstate = to_sde_crtc_state(crtc->state);
idle_status = kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work);
cache_status = kthread_cancel_delayed_work_sync(&sde_crtc->static_cache_read_work);
SDE_EVT32(DRMID(crtc), idle_status, cache_status);
}
/* initialize crtc */
struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane)
{

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
@ -966,4 +966,10 @@ void sde_crtc_reset_sw_state(struct drm_crtc *crtc);
*/
void _sde_crtc_clear_dim_layers_v1(struct drm_crtc_state *state);
/**
* sde_crtc_cancel_delayed_work - cancel any pending work items for a given crtc
* @crtc: Pointer to DRM crtc object
*/
void sde_crtc_cancel_delayed_work(struct drm_crtc *crtc);
#endif /* _SDE_CRTC_H_ */

View file

@ -1687,6 +1687,17 @@ static void _sde_encoder_rc_cancel_delayed(struct sde_encoder_virt *sde_enc,
sw_event);
}
void sde_encoder_cancel_delayed_work(struct drm_encoder *encoder)
{
struct sde_encoder_virt *sde_enc;
if (!encoder)
return;
sde_enc = to_sde_encoder_virt(encoder);
_sde_encoder_rc_cancel_delayed(sde_enc, 0);
}
static void _sde_encoder_rc_kickoff_delayed(struct sde_encoder_virt *sde_enc,
u32 sw_event)
{

View file

@ -1,4 +1,5 @@
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
@ -597,6 +598,12 @@ static inline u32 sde_encoder_get_dfps_maxfps(struct drm_encoder *drm_enc)
*/
void sde_encoder_virt_reset(struct drm_encoder *drm_enc);
/**
* sde_encoder_cancel_delayed_work - cancel delayed off work for encoder
* @drm_enc: Pointer to drm encoder structure
*/
void sde_encoder_cancel_delayed_work(struct drm_encoder *encoder);
/**
* sde_encoder_get_kms - retrieve the kms from encoder
* @drm_enc: Pointer to drm encoder structure

View file

@ -1034,6 +1034,7 @@ int sde_kms_vm_primary_prepare_commit(struct sde_kms *sde_kms,
struct drm_connector *connector;
struct sde_vm_ops *vm_ops;
struct sde_crtc_state *cstate;
struct drm_connector_list_iter iter;
enum sde_crtc_vm_req vm_req;
int rc = 0;
@ -1070,9 +1071,11 @@ int sde_kms_vm_primary_prepare_commit(struct sde_kms *sde_kms,
}
/* Schedule ESD work */
list_for_each_entry(connector, &ddev->mode_config.connector_list, head)
drm_connector_list_iter_begin(ddev, &iter);
drm_for_each_connector_iter(connector, &iter)
if (drm_connector_mask(connector) & crtc->state->connector_mask)
sde_connector_schedule_status_work(connector, true);
drm_connector_list_iter_end(&iter);
/* enable vblank events */
drm_crtc_vblank_on(crtc);
@ -1292,6 +1295,72 @@ static void _sde_kms_release_splash_resource(struct sde_kms *sde_kms,
}
}
static void sde_kms_cancel_delayed_work(struct drm_crtc *crtc)
{
struct drm_connector *connector;
struct drm_connector_list_iter iter;
struct drm_encoder *encoder;
/* Cancel CRTC work */
sde_crtc_cancel_delayed_work(crtc);
/* Cancel ESD work */
drm_connector_list_iter_begin(crtc->dev, &iter);
drm_for_each_connector_iter(connector, &iter)
if (drm_connector_mask(connector) & crtc->state->connector_mask)
sde_connector_schedule_status_work(connector, false);
drm_connector_list_iter_end(&iter);
/* Cancel Idle-PC work */
drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) {
if (sde_encoder_in_clone_mode(encoder))
continue;
sde_encoder_cancel_delayed_work(encoder);
}
}
int sde_kms_vm_pre_release(struct sde_kms *sde_kms,
struct drm_atomic_state *state, bool is_primary)
{
struct drm_crtc *crtc;
struct drm_encoder *encoder;
int rc = 0;
crtc = sde_kms_vm_get_vm_crtc(state);
if (!crtc)
return 0;
/* if vm_req is enabled, once CRTC on the commit is guaranteed */
sde_kms_wait_for_frame_transfer_complete(&sde_kms->base, crtc);
sde_kms_cancel_delayed_work(crtc);
/* disable SDE irq's */
drm_for_each_encoder_mask(encoder, crtc->dev,
crtc->state->encoder_mask) {
if (sde_encoder_in_clone_mode(encoder))
continue;
sde_encoder_irq_control(encoder, false);
}
if (is_primary) {
/* disable IRQ line */
sde_irq_update(&sde_kms->base, false);
/* disable vblank events */
drm_crtc_vblank_off(crtc);
/* reset sw state */
sde_crtc_reset_sw_state(crtc);
}
sde_dbg_set_hw_ownership_status(false);
return rc;
}
int sde_kms_vm_trusted_post_commit(struct sde_kms *sde_kms,
struct drm_atomic_state *state)
{
@ -1299,7 +1368,6 @@ int sde_kms_vm_trusted_post_commit(struct sde_kms *sde_kms,
struct drm_device *ddev;
struct drm_crtc *crtc;
struct drm_plane *plane;
struct drm_encoder *encoder;
struct sde_crtc_state *cstate;
struct drm_crtc_state *new_cstate;
enum sde_crtc_vm_req vm_req;
@ -1321,24 +1389,13 @@ int sde_kms_vm_trusted_post_commit(struct sde_kms *sde_kms,
if (vm_req != VM_REQ_RELEASE)
return 0;
/* if vm_req is enabled, once CRTC on the commit is guaranteed */
sde_kms_wait_for_frame_transfer_complete(&sde_kms->base, crtc);
drm_for_each_encoder_mask(encoder, crtc->dev,
crtc->state->encoder_mask) {
if (sde_encoder_in_clone_mode(encoder))
continue;
sde_encoder_irq_control(encoder, false);
}
sde_kms_vm_pre_release(sde_kms, state, false);
list_for_each_entry(plane, &ddev->mode_config.plane_list, head)
sde_plane_set_sid(plane, 0);
sde_hw_set_lutdma_sid(sde_kms->hw_sid, 0);
sde_dbg_set_hw_ownership_status(false);
sde_vm_lock(sde_kms);
if (vm_ops->vm_release)
@ -1349,62 +1406,6 @@ int sde_kms_vm_trusted_post_commit(struct sde_kms *sde_kms,
return rc;
}
int sde_kms_vm_pre_release(struct sde_kms *sde_kms,
struct drm_atomic_state *state)
{
struct drm_device *ddev;
struct drm_crtc *crtc;
struct drm_encoder *encoder;
struct drm_connector *connector;
int rc = 0;
struct msm_drm_private *priv;
ddev = sde_kms->dev;
crtc = sde_kms_vm_get_vm_crtc(state);
if (!crtc)
return 0;
priv = crtc->dev->dev_private;
/* if vm_req is enabled, once CRTC on the commit is guaranteed */
sde_kms_wait_for_frame_transfer_complete(&sde_kms->base, crtc);
/* disable ESD work */
list_for_each_entry(connector,
&ddev->mode_config.connector_list, head) {
if (drm_connector_mask(connector) & crtc->state->connector_mask)
sde_connector_schedule_status_work(connector, false);
}
/* disable SDE irq's */
drm_for_each_encoder_mask(encoder, crtc->dev,
crtc->state->encoder_mask) {
if (sde_encoder_in_clone_mode(encoder))
continue;
sde_encoder_irq_control(encoder, false);
}
/* disable IRQ line */
sde_irq_update(&sde_kms->base, false);
/* disable vblank events */
drm_crtc_vblank_off(crtc);
/*
* Flush event thread queue for any pending events as vblank work
* might get scheduled from drm_crtc_vblank_off
*/
kthread_flush_worker(&priv->event_thread[crtc->index].worker);
/* reset sw state */
sde_crtc_reset_sw_state(crtc);
sde_dbg_set_hw_ownership_status(false);
return rc;
}
int sde_kms_vm_primary_post_commit(struct sde_kms *sde_kms,
struct drm_atomic_state *state)
{
@ -1431,7 +1432,7 @@ int sde_kms_vm_primary_post_commit(struct sde_kms *sde_kms,
return 0;
/* handle SDE pre-release */
rc = sde_kms_vm_pre_release(sde_kms, state);
rc = sde_kms_vm_pre_release(sde_kms, state, true);
if (rc) {
SDE_ERROR("sde vm pre_release failed, rc=%d\n", rc);
goto exit;
@ -2589,6 +2590,11 @@ error:
drm_framebuffer_put(fb);
}
drm_for_each_crtc(crtc, dev) {
if (!ret && crtc_mask & drm_crtc_mask(crtc))
sde_kms_cancel_delayed_work(crtc);
}
end:
return ret;
}
@ -3794,6 +3800,7 @@ static int sde_kms_trigger_null_flush(struct msm_kms *kms)
{
struct sde_kms *sde_kms;
struct sde_splash_display *splash_display;
struct drm_crtc *crtc;
int i, rc = 0;
if (!kms) {
@ -3803,22 +3810,35 @@ static int sde_kms_trigger_null_flush(struct msm_kms *kms)
sde_kms = to_sde_kms(kms);
if (!sde_kms->splash_data.num_splash_displays ||
sde_kms->dsi_display_count == sde_kms->splash_data.num_splash_displays)
return rc;
/* If splash handoff is done, early return*/
if (!sde_kms->splash_data.num_splash_displays)
return 0;
/* If all builtin-displays are having cont splash enabled, ignore lastclose*/
if (sde_kms->dsi_display_count == sde_kms->splash_data.num_splash_displays)
return -EINVAL;
/* Trigger NULL flush if built-in secondary/primary is stuck in splash
* while the primary/secondary is running respectively before lastclose.
*/
for (i = 0; i < MAX_DSI_DISPLAYS; i++) {
splash_display = &sde_kms->splash_data.splash_display[i];
if (splash_display->cont_splash_enabled && splash_display->encoder) {
crtc = splash_display->encoder->crtc;
SDE_DEBUG("triggering null commit on enc:%d\n",
DRMID(splash_display->encoder));
SDE_EVT32(DRMID(splash_display->encoder), SDE_EVTLOG_FUNC_ENTRY);
rc = _sde_kms_null_commit(sde_kms->dev, splash_display->encoder);
if (!rc && crtc)
sde_kms_cancel_delayed_work(crtc);
if (rc)
DRM_ERROR("null flush commit failure during lastclose\n");
}
}
return rc;
return 0;
}
#ifdef CONFIG_DEEPSLEEP
@ -3875,7 +3895,7 @@ static inline int _sde_kms_pm_deepsleep_helper(struct sde_kms *sde_kms,
static void _sde_kms_pm_suspend_idle_helper(struct sde_kms *sde_kms,
struct device *dev)
{
int i, ret, crtc_id = 0;
int ret, crtc_id = 0;
struct drm_device *ddev = dev_get_drvdata(dev);
struct drm_connector *conn;
struct drm_connector_list_iter conn_iter;
@ -3912,15 +3932,7 @@ static void _sde_kms_pm_suspend_idle_helper(struct sde_kms *sde_kms,
}
drm_connector_list_iter_end(&conn_iter);
for (i = 0; i < priv->num_crtcs; i++) {
if (priv->disp_thread[i].thread)
kthread_flush_worker(
&priv->disp_thread[i].worker);
if (priv->event_thread[i].thread)
kthread_flush_worker(
&priv->event_thread[i].worker);
}
kthread_flush_worker(&priv->pp_event_worker);
msm_atomic_flush_display_threads(priv);
}
static int sde_kms_pm_suspend(struct device *dev)