diff options
| author | Clarence Ip <cip@codeaurora.org> | 2016-06-13 19:05:32 -0400 |
|---|---|---|
| committer | Dhaval Patel <pdhaval@codeaurora.org> | 2016-08-01 12:35:46 -0700 |
| commit | 949a4cd105ce40775af400151501cb20678487f3 (patch) | |
| tree | 2926253ba0b8b653544a39af46234e52188caf23 /drivers/gpu | |
| parent | c5a5c2a1b07404dee4c9c5b49ba830335d999096 (diff) | |
drm/msm/sde: enable output_fence property
Add an 'output_fence' property to the crtc to support both
Linux output fence semantics and Android release fences.
A 'prepare_fence' callback is added to msm_atomic_commit() after
swapping the incoming atomic state but before spawning any
worker threads to process the commit. This guarantees that the
correct sync point value may be determined by the driver at any
point after the relevant commit request.
Change-Id: I7c024709f052fbf49f1c9e438d10a3c9f9aab023
Signed-off-by: Clarence Ip <cip@codeaurora.org>
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/msm/msm_atomic.c | 11 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_drv.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_kms.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_crtc.c | 54 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_crtc.h | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_kms.c | 17 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_kms.h | 13 |
7 files changed, 98 insertions, 4 deletions
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index f3dc6b33febb..b3b72b140c6e 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -500,6 +500,7 @@ int msm_atomic_check(struct drm_device *dev, int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async) { + struct msm_drm_private *priv = dev->dev_private; int nplanes = dev->mode_config.num_total_plane; int ncrtcs = dev->mode_config.num_crtc; ktime_t timeout; @@ -559,6 +560,16 @@ int msm_atomic_commit(struct drm_device *dev, drm_atomic_helper_swap_state(dev, state); /* + * Provide the driver a chance to prepare for output fences. This is + * done after the point of no return, but before asynchronous commits + * are dispatched to work queues, so that the fence preparation is + * finished before the .atomic_commit returns. + */ + if (priv && priv->kms && priv->kms->funcs && + priv->kms->funcs->prepare_fence) + priv->kms->funcs->prepare_fence(priv->kms, state); + + /* * Everything below can be run asynchronously without the need to grab * any modeset locks at all under one conditions: It must be guaranteed * that the asynchronous work has either been cancelled (if the driver diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index da23f716fe96..d03f1764cd3b 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -101,6 +101,7 @@ enum msm_mdp_crtc_property { /* range properties */ CRTC_PROP_INPUT_FENCE_TIMEOUT = CRTC_PROP_BLOBCOUNT, + CRTC_PROP_OUTPUT_FENCE, /* total # of properties */ CRTC_PROP_COUNT diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index b2905eba2650..26e41880c670 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -50,6 +50,8 @@ struct msm_kms_funcs { int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); /* modeset, bracketing atomic_commit(): */ + void (*prepare_fence)(struct msm_kms *kms, + struct drm_atomic_state *state); void (*prepare_commit)(struct msm_kms *kms, struct drm_atomic_state *state); void (*commit)(struct msm_kms *kms, struct drm_atomic_state *state); diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index df7063d02d50..cb8c4e94d2b4 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -140,6 +140,7 @@ static void sde_crtc_destroy(struct drm_crtc *crtc) msm_property_destroy(&sde_crtc->property_info); debugfs_remove_recursive(sde_crtc->debugfs_root); + sde_fence_deinit(&sde_crtc->output_fence); drm_crtc_cleanup(crtc); kfree(sde_crtc); @@ -328,6 +329,22 @@ out: spin_unlock_irqrestore(&sde_crtc->lm_lock, flags); } +void sde_crtc_prepare_fence(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return; + } + + sde_crtc = to_sde_crtc(crtc); + + MSM_EVT(crtc->dev, sde_crtc->id, crtc->enabled); + + sde_fence_prepare(&sde_crtc->output_fence); +} + /* if file!=NULL, this is preclose potential cancel-flip path */ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) { @@ -403,6 +420,18 @@ static u32 _sde_crtc_update_ctl_flush_mask(struct drm_crtc *crtc) return 0; } + +void sde_crtc_complete_commit(struct drm_crtc *crtc) +{ + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return; + } + + /* signal out fence at end of commit */ + sde_fence_signal(&to_sde_crtc(crtc)->output_fence, 0); +} + /** * _sde_crtc_trigger_kickoff - Iterate through the control paths and trigger * the hw_ctl object to flush any pending flush mask, and trigger @@ -976,6 +1005,10 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc) "input_fence_timeout", 0, ~0, SDE_CRTC_INPUT_FENCE_TIMEOUT, CRTC_PROP_INPUT_FENCE_TIMEOUT); + msm_property_install_range(&sde_crtc->property_info, + "output_fence", + 0, ~0, ~0, + CRTC_PROP_OUTPUT_FENCE); } /** @@ -1044,16 +1077,21 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc, { struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; - int ret = -EINVAL; + int i, ret = -EINVAL; if (!crtc || !state) { DRM_ERROR("invalid argument(s)\n"); } else { sde_crtc = to_sde_crtc(crtc); cstate = to_sde_crtc_state(state); - ret = msm_property_atomic_get(&sde_crtc->property_info, - cstate->property_values, cstate->property_blobs, - property, val); + i = msm_property_index(&sde_crtc->property_info, property); + if (i == CRTC_PROP_OUTPUT_FENCE) { + ret = sde_fence_create(&sde_crtc->output_fence, val); + } else { + ret = msm_property_atomic_get(&sde_crtc->property_info, + cstate->property_values, + cstate->property_blobs, property, val); + } } return ret; @@ -1183,6 +1221,14 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, /* save user friendly CRTC name for later */ snprintf(sde_crtc->name, SDE_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); + /* + * Initialize output fence support. Set output fence offset to zero + * so that fences returned during a commit will signal at the end of + * the same commit. + */ + sde_fence_init(dev, &sde_crtc->output_fence, sde_crtc->name, 0); + + /* initialize debugfs support */ _sde_crtc_init_debugfs(sde_crtc, kms); /* create CRTC properties */ diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index 16d7bf47a3dd..417e54b3e952 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -15,6 +15,7 @@ #include "drm_crtc.h" #include "msm_prop.h" +#include "sde_fence.h" #include "sde_kms.h" #define CRTC_DUAL_MIXERS 2 @@ -83,6 +84,9 @@ struct sde_crtc { struct msm_property_info property_info; struct msm_property_data property_data[CRTC_PROP_COUNT]; + /* output fence support */ + struct sde_fence output_fence; + struct sde_hw_stage_cfg stage_cfg; struct dentry *debugfs_root; }; diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 38afae405517..76af87a7d1f0 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -190,7 +190,12 @@ static void sde_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state) { struct sde_kms *sde_kms = to_sde_kms(kms); + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i; + for_each_crtc_in_state(state, crtc, crtc_state, i) + sde_crtc_complete_commit(crtc); sde_disable(sde_kms); MSM_EVT(sde_kms->dev, 0, 0); @@ -202,6 +207,17 @@ static void sde_wait_for_crtc_commit_done(struct msm_kms *kms, sde_crtc_wait_for_commit_done(crtc); } +static void sde_kms_prepare_fence(struct msm_kms *kms, + struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i; + + for_each_crtc_in_state(state, crtc, crtc_state, i) + sde_crtc_prepare_fence(crtc); +} + static int modeset_init(struct sde_kms *sde_kms) { struct msm_drm_private *priv = sde_kms->dev->dev_private; @@ -312,6 +328,7 @@ static const struct msm_kms_funcs kms_funcs = { .irq_postinstall = sde_irq_postinstall, .irq_uninstall = sde_irq_uninstall, .irq = sde_irq, + .prepare_fence = sde_kms_prepare_fence, .prepare_commit = sde_prepare_commit, .commit = sde_commit, .complete_commit = sde_complete_commit, diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index 5c381beb9eaf..a4389716b699 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -429,11 +429,24 @@ int sde_crtc_vblank(struct drm_crtc *crtc, bool en); void sde_crtc_wait_for_commit_done(struct drm_crtc *crtc); void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); void sde_crtc_commit_kickoff(struct drm_crtc *crtc); + +/** + * sde_crtc_prepare_fence - callback to prepare for output fences + * @crtc: Pointer to drm crtc object + */ +void sde_crtc_prepare_fence(struct drm_crtc *crtc); + struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_encoder *encoder, struct drm_plane *plane, int id); /** + * sde_crtc_complete_commit - callback signalling completion of current commit + * @crtc: Pointer to drm crtc object + */ +void sde_crtc_complete_commit(struct drm_crtc *crtc); + +/** * Encoder functions and data types */ struct sde_encoder_hw_resources { |
