diff options
| author | Lloyd Atkinson <latkinso@codeaurora.org> | 2016-08-11 10:53:37 -0400 |
|---|---|---|
| committer | Lloyd Atkinson <latkinso@codeaurora.org> | 2016-08-22 17:05:33 -0400 |
| commit | 80005ea6b3366054dafa3a314459ab4ea1cc69ae (patch) | |
| tree | 49d5ca5f37a8ce5f42a2db19a114c633d3d77bc5 /drivers/gpu | |
| parent | 284e6ac53dc95850af49169cc619f569dea47449 (diff) | |
drm/msm/sde: move crtc towards multi-encoder support
SDE CRTC currently assumes one encoder per CRTC associated at
initialization time. Need to break this assumption and move
towards tracking multiple encoders, though full dynamic
assignment is not provided by this patch.
Change-Id: I47f42f5ef57f4df2f19f66bdef737cc86906ab1d
Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org>
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_crtc.c | 200 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_crtc.h | 30 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_encoder.c | 18 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_encoder_phys.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c | 21 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_kms.c | 31 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_kms.h | 20 |
9 files changed, 200 insertions, 136 deletions
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index ee8ff92746a0..638cbe7bd89c 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -41,8 +41,7 @@ static struct sde_kms *get_kms(struct drm_crtc *crtc) return to_sde_kms(priv->kms); } -static int sde_crtc_reserve_hw_resources(struct drm_crtc *crtc, - struct drm_encoder *encoder) +static int sde_crtc_reserve_hw_resources(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); struct sde_kms *sde_kms = get_kms(crtc); @@ -70,14 +69,14 @@ static int sde_crtc_reserve_hw_resources(struct drm_crtc *crtc, } /* query encoder resources */ - sde_encoder_get_hw_resources(sde_crtc->encoder, &enc_hw_res); + sde_encoder_get_hw_resources(sde_crtc->mixers[0].encoder, &enc_hw_res); /* parse encoder hw resources, find CTL paths */ for (i = CTL_0; i <= sde_kms->catalog->ctl_count; i++) { WARN_ON(sde_crtc->num_ctls > CRTC_DUAL_MIXERS); if (enc_hw_res.ctls[i]) { struct sde_crtc_mixer *mixer = - &sde_crtc->mixer[sde_crtc->num_ctls]; + &sde_crtc->mixers[sde_crtc->num_ctls]; mixer->hw_ctl = sde_rm_get_ctl_path(sde_kms, i); if (IS_ERR_OR_NULL(mixer->hw_ctl)) { DRM_ERROR("Invalid ctl_path\n"); @@ -98,7 +97,7 @@ static int sde_crtc_reserve_hw_resources(struct drm_crtc *crtc, for (i = INTF_0; i <= sde_kms->catalog->intf_count; i++) { if (enc_hw_res.intfs[i]) { struct sde_crtc_mixer *mixer = - &sde_crtc->mixer[sde_crtc->num_mixers]; + &sde_crtc->mixers[sde_crtc->num_mixers]; plat_hw_res_map = sde_rm_get_res_map(sde_kms, i, SDE_NONE); @@ -106,15 +105,12 @@ static int sde_crtc_reserve_hw_resources(struct drm_crtc *crtc, if (!lm_idx && unused_lm_count) lm_idx = unused_lm_id[--unused_lm_count]; - DBG("Acquiring LM %d", lm_idx); + DBG("intf %d acquiring lm %d", i, lm_idx); mixer->hw_lm = sde_rm_acquire_mixer(sde_kms, lm_idx); if (IS_ERR_OR_NULL(mixer->hw_lm)) { DRM_ERROR("Invalid mixer\n"); return -EACCES; } - /* interface info */ - mixer->intf_idx = i; - mixer->mode = enc_hw_res.intfs[i]; sde_crtc->num_mixers++; } } @@ -126,7 +122,7 @@ static int sde_crtc_reserve_hw_resources(struct drm_crtc *crtc, for (i = WB_0; i < WB_MAX; i++) { if (enc_hw_res.wbs[i]) { struct sde_crtc_mixer *mixer = - &sde_crtc->mixer[sde_crtc->num_mixers]; + &sde_crtc->mixers[sde_crtc->num_mixers]; plat_hw_res_map = sde_rm_get_res_map(sde_kms, SDE_NONE, i); @@ -134,27 +130,24 @@ static int sde_crtc_reserve_hw_resources(struct drm_crtc *crtc, if (!lm_idx && unused_lm_count) lm_idx = unused_lm_id[--unused_lm_count]; - DBG("Acquiring LM %d", lm_idx); + DBG("wb %d acquiring lm %d", i, lm_idx); mixer->hw_lm = sde_rm_acquire_mixer(sde_kms, lm_idx); if (IS_ERR_OR_NULL(mixer->hw_lm)) { DRM_ERROR("Invalid mixer\n"); return -EACCES; } - /* interface info */ - mixer->wb_idx = i; - mixer->mode = enc_hw_res.wbs[i]; sde_crtc->num_mixers++; } } DBG("control paths %d, num_mixers %d, lm[0] %d, ctl[0] %d ", sde_crtc->num_ctls, sde_crtc->num_mixers, - sde_crtc->mixer[0].hw_lm->idx, - sde_crtc->mixer[0].hw_ctl->idx); + sde_crtc->mixers[0].hw_lm->idx, + sde_crtc->mixers[0].hw_ctl->idx); if (sde_crtc->num_mixers > 1) DBG("lm[1] %d, ctl[1], %d", - sde_crtc->mixer[1].hw_lm->idx, - sde_crtc->mixer[1].hw_ctl->idx); + sde_crtc->mixers[1].hw_lm->idx, + sde_crtc->mixers[1].hw_ctl->idx); return 0; } @@ -270,7 +263,7 @@ static void sde_crtc_get_blend_cfg(struct sde_hw_blend_cfg *cfg, static void blend_setup(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_crtc_mixer *mixer = sde_crtc->mixer; + struct sde_crtc_mixer *mixer = sde_crtc->mixers; struct drm_plane *plane; struct sde_plane_state *pstate; struct sde_hw_blend_cfg blend; @@ -305,7 +298,7 @@ static void blend_setup(struct drm_crtc *crtc) sde_plane_pipe(plane); DBG("crtc_id %d - mixer %d pipe %d at stage %d", i, - sde_crtc->id, + crtc->base.id, sde_plane_pipe(plane), pstate->stage); plane_cnt++; @@ -369,7 +362,7 @@ void sde_crtc_prepare_fence(struct drm_crtc *crtc) sde_crtc = to_sde_crtc(crtc); - MSM_EVT(crtc->dev, sde_crtc->id, crtc->enabled); + MSM_EVT(crtc->dev, crtc->base.id, 0); sde_fence_prepare(&sde_crtc->output_fence); } @@ -391,8 +384,9 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) */ if (!file || (event->base.file_priv == file)) { sde_crtc->event = NULL; - DBG("%s: send event: %pK", sde_crtc->name, event); - drm_send_vblank_event(dev, sde_crtc->id, event); + SDE_DEBUG("%s: send event: %pK", sde_crtc->name, event); + drm_send_vblank_event(dev, sde_crtc->drm_crtc_id, + event); } } spin_unlock_irqrestore(&dev->event_lock, flags); @@ -414,10 +408,10 @@ static void sde_crtc_vblank_cb(void *data) drm_crtc_vblank_put(crtc); } - if (sde_crtc->drm_requested_vblank) { - drm_handle_vblank(dev, sde_crtc->id); + if (atomic_read(&sde_crtc->drm_requested_vblank)) { + drm_handle_vblank(dev, sde_crtc->drm_crtc_id); DBG_IRQ(""); - MSM_EVT(crtc->dev, sde_crtc->id, 0); + MSM_EVT(crtc->dev, crtc->base.id, 0); } } @@ -433,30 +427,13 @@ static u32 _sde_crtc_update_ctl_flush_mask(struct drm_crtc *crtc) return -EINVAL; } - MSM_EVT(crtc->dev, sde_crtc->id, 0); + MSM_EVT(crtc->dev, crtc->base.id, 0); DBG(""); for (i = 0; i < sde_crtc->num_ctls; i++) { - mixer = &sde_crtc->mixer[i]; + mixer = &sde_crtc->mixers[i]; ctl = mixer->hw_ctl; - - switch (mixer->mode) { - case INTF_MODE_CMD: - case INTF_MODE_VIDEO: - ctl->ops.get_bitmask_intf(ctl, &mixer->flush_mask, - mixer->intf_idx); - break; - case INTF_MODE_WB_LINE: - ctl->ops.get_bitmask_wb(ctl, &mixer->flush_mask, - mixer->wb_idx); - break; - default: - DBG("Invalid ctl %d interface mode %d", ctl->idx, - mixer->mode); - return -EINVAL; - } - ctl->ops.update_pending_flush(ctl, mixer->flush_mask); DBG("added CTL_ID %d mask 0x%x to pending flush", ctl->idx, mixer->flush_mask); @@ -493,55 +470,37 @@ static void _sde_crtc_trigger_kickoff(void *data) { struct drm_crtc *crtc = (struct drm_crtc *)data; struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct sde_crtc_mixer *mixer; struct sde_hw_ctl *ctl; - u32 i; + int i; if (!data) { DRM_ERROR("invalid argument\n"); return; } - MSM_EVT(crtc->dev, sde_crtc->id, 0); + MSM_EVT(crtc->dev, crtc->base.id, 0); /* Commit all pending flush masks to hardware */ - for (i = 0; i < sde_crtc->num_ctls; i++) { - ctl = sde_crtc->mixer[i].hw_ctl; - ctl->ops.trigger_flush(ctl); + for (i = 0; i < ARRAY_SIZE(sde_crtc->mixers); i++) { + ctl = sde_crtc->mixers[i].hw_ctl; + if (ctl) { + ctl->ops.trigger_flush(ctl); + MSM_EVT(crtc->dev, crtc->base.id, ctl->idx); + } } /* Signal start to any interface types that require it */ - for (i = 0; i < sde_crtc->num_ctls; i++) { - ctl = sde_crtc->mixer[i].hw_ctl; - if (sde_crtc->mixer[i].mode != INTF_MODE_VIDEO) { + for (i = 0; i < ARRAY_SIZE(sde_crtc->mixers); i++) { + mixer = &sde_crtc->mixers[i]; + ctl = mixer->hw_ctl; + if (ctl && sde_encoder_needs_ctl_start(mixer->encoder)) { ctl->ops.trigger_start(ctl); - DBG("trigger start on ctl %d", ctl->idx); + MSM_EVT(crtc->dev, crtc->base.id, ctl->idx); } } } -void sde_crtc_wait_for_commit_done(struct drm_crtc *crtc) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - int ret; - - /* ref count the vblank event and interrupts while we wait for it */ - if (drm_crtc_vblank_get(crtc)) - return; - - /* - * Wait post-flush if necessary to delay before plane_cleanup - * For example, wait for vsync in case of video mode panels - * This should be a no-op for command mode panels - */ - MSM_EVT(crtc->dev, sde_crtc->id, 0); - ret = sde_encoder_wait_for_commit_done(sde_crtc->encoder); - if (ret) - DBG("sde_encoder_wait_post_flush returned %d", ret); - - /* release vblank event ref count */ - drm_crtc_vblank_put(crtc); -} - /** * _sde_crtc_set_input_fence_timeout - update ns version of in fence timeout * @cstate: Pointer to sde crtc state @@ -629,9 +588,9 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc, /* Reset flush mask from previous commit */ for (i = 0; i < sde_crtc->num_ctls; i++) { - struct sde_hw_ctl *ctl = sde_crtc->mixer[i].hw_ctl; + struct sde_hw_ctl *ctl = sde_crtc->mixers[i].hw_ctl; - sde_crtc->mixer[i].flush_mask = 0; + sde_crtc->mixers[i].flush_mask = 0; ctl->ops.clear_pending_flush(ctl); } @@ -750,19 +709,26 @@ static void sde_crtc_destroy_state(struct drm_crtc *crtc, void sde_crtc_commit_kickoff(struct drm_crtc *crtc) { - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct drm_encoder *encoder; + struct drm_device *dev; if (!crtc) { DRM_ERROR("invalid argument\n"); return; } + dev = crtc->dev; - /* - * Encoder will flush/start now, unless it has a tx pending - * in which case it may delay and flush at an irq event (e.g. ppdone) - */ - sde_encoder_schedule_kickoff(sde_crtc->encoder, - _sde_crtc_trigger_kickoff, crtc); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + + /* + * Encoder will flush/start now, unless it has a tx pending. + * If so, it may delay and flush at an irq event (e.g. ppdone) + */ + sde_encoder_schedule_kickoff(encoder, _sde_crtc_trigger_kickoff, + crtc); + } } /** @@ -875,7 +841,7 @@ static void sde_crtc_enable(struct drm_crtc *crtc) DBG(""); sde_crtc = to_sde_crtc(crtc); - mixer = sde_crtc->mixer; + mixer = sde_crtc->mixers; if (WARN_ON(!crtc->state)) return; @@ -891,7 +857,7 @@ static void sde_crtc_enable(struct drm_crtc *crtc) */ if ((sde_crtc->num_ctls == 0) || (sde_crtc->num_mixers == 0)) { - rc = sde_crtc_reserve_hw_resources(crtc, sde_crtc->encoder); + rc = sde_crtc_reserve_hw_resources(crtc); if (rc) { DRM_ERROR("error reserving HW resource for CRTC\n"); return; @@ -998,25 +964,30 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, int sde_crtc_vblank(struct drm_crtc *crtc, bool en) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct drm_encoder *encoder; + struct drm_device *dev = crtc->dev; DBG("%d", en); - MSM_EVT(crtc->dev, en, 0); - - /* - * Mark that framework requested vblank, - * as opposed to enabling vblank only for our internal purposes - * Currently this variable isn't required, but may be useful for future - * features - */ - sde_crtc->drm_requested_vblank = en; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + /* + * Mark that framework requested vblank, + * as opposed to enabling vblank only for our internal purposes + * Currently this variable isn't required, but may be useful for + * future features + */ + atomic_set(&sde_crtc->drm_requested_vblank, en); + MSM_EVT(crtc->dev, crtc->base.id, en); - if (en) - sde_encoder_register_vblank_callback(sde_crtc->encoder, - sde_crtc_vblank_cb, (void *)crtc); - else - sde_encoder_register_vblank_callback(sde_crtc->encoder, - NULL, NULL); + if (en) + sde_encoder_register_vblank_callback(encoder, + sde_crtc_vblank_cb, (void *)crtc); + else + sde_encoder_register_vblank_callback(encoder, NULL, + NULL); + } return 0; } @@ -1152,17 +1123,15 @@ static int _sde_debugfs_mixer_read(struct seq_file *s, void *data) sde_crtc = s->private; for (i = 0; i < sde_crtc->num_mixers; ++i) { - m = &sde_crtc->mixer[i]; + m = &sde_crtc->mixers[i]; if (!m->hw_lm) { seq_printf(s, "Mixer[%d] has no LM\n", i); } else if (!m->hw_ctl) { seq_printf(s, "Mixer[%d] has no CTL\n", i); } else { - seq_printf(s, "LM_%d/CTL_%d -> INTF_%d, WB_%d\n", + seq_printf(s, "LM_%d/CTL_%d\n", m->hw_lm->idx - LM_0, - m->hw_ctl->idx - CTL_0, - m->intf_idx - INTF_0, - m->wb_idx - WB_0); + m->hw_ctl->idx - CTL_0); } } seq_printf(s, "Border: %d\n", sde_crtc->stage_cfg.border_enable); @@ -1231,13 +1200,14 @@ static void _sde_crtc_init_debugfs(struct sde_crtc *sde_crtc, /* initialize crtc */ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_encoder *encoder, - struct drm_plane *plane, int id) + struct drm_plane *plane, + int drm_crtc_id) { struct drm_crtc *crtc = NULL; struct sde_crtc *sde_crtc = NULL; struct msm_drm_private *priv = NULL; struct sde_kms *kms = NULL; - int rc; + int i, rc; priv = dev->dev_private; kms = to_sde_kms(priv->kms); @@ -1248,8 +1218,9 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, crtc = &sde_crtc->base; - sde_crtc->id = id; - sde_crtc->encoder = encoder; + sde_crtc->drm_crtc_id = drm_crtc_id; + atomic_set(&sde_crtc->drm_requested_vblank, 0); + spin_lock_init(&sde_crtc->lm_lock); drm_crtc_init_with_planes(dev, crtc, plane, NULL, &sde_crtc_funcs); @@ -1257,7 +1228,10 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, drm_crtc_helper_add(crtc, &sde_crtc_helper_funcs); plane->crtc = crtc; - rc = sde_crtc_reserve_hw_resources(crtc, encoder); + for (i = 0; i < ARRAY_SIZE(sde_crtc->mixers); i++) + sde_crtc->mixers[i].encoder = encoder; + + rc = sde_crtc_reserve_hw_resources(crtc); if (rc) { DRM_ERROR(" error reserving HW resource for this CRTC\n"); return ERR_PTR(-EINVAL); diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index c34be7f40f05..e0c74f98e40c 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -26,31 +26,26 @@ #define CRTC_HW_MIXER_MAXSTAGES(c, idx) ((c)->mixer[idx].sblk->maxblendstages) /** - * struct sde_crtc_mixer - stores the map for each virtual pipeline in the CRTC - * @hw_dspp : DSPP HW Driver context - * @hw_lm : LM HW Driver context - * @hw_ctl : CTL Path HW driver context - * @intf_idx : Interface idx - * @wb_idx : Writeback idx - * @mode : Interface mode Active/CMD - * @flush_mask : Flush mask value for this commit + * struct sde_crtc_mixer: stores the map for each virtual pipeline in the CRTC + * @hw_lm: LM HW Driver context + * @hw_ctl: CTL Path HW driver context + * @flush_mask: Flush mask value for this commit + * @encoder: Encoder attached to this lm & ctl */ struct sde_crtc_mixer { - struct sde_hw_dspp *hw_dspp; struct sde_hw_mixer *hw_lm; struct sde_hw_ctl *hw_ctl; - enum sde_intf intf_idx; - enum sde_wb wb_idx; - enum sde_intf_mode mode; u32 flush_mask; + struct drm_encoder *encoder; }; /** * struct sde_crtc - virtualized CRTC data structure * @base : Base drm crtc structure * @name : ASCII description of this crtc - * @encoder : Associated drm encoder object - * @id : Unique crtc identifier + * @drm_crtc_id : Id for reporting vblank. Id is relative init order into + * mode_config.crtc_list and used by user space to identify + * specific crtc in apis such as drm_wait_vblank * @lm_lock : LM register access spinlock * @num_ctls : Number of ctl paths in use * @num_mixers : Number of mixers in use @@ -67,21 +62,20 @@ struct sde_crtc_mixer { struct sde_crtc { struct drm_crtc base; char name[SDE_CRTC_NAME_SIZE]; - struct drm_encoder *encoder; - int id; + int drm_crtc_id; spinlock_t lm_lock; /* protect registers */ /* HW Resources reserved for the crtc */ u32 num_ctls; u32 num_mixers; - struct sde_crtc_mixer mixer[CRTC_DUAL_MIXERS]; + struct sde_crtc_mixer mixers[CRTC_DUAL_MIXERS]; /*if there is a pending flip, these will be non-null */ struct drm_pending_vblank_event *event; atomic_t pending; u32 vsync_count; - bool drm_requested_vblank; + atomic_t drm_requested_vblank; struct msm_property_info property_info; struct msm_property_data property_data[CRTC_PROP_COUNT]; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 2b5fc41d42af..644cca31eec1 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -179,6 +179,24 @@ void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc, } } +bool sde_encoder_needs_ctl_start(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = NULL; + struct sde_encoder_phys *phys; + + if (!drm_enc) { + DRM_ERROR("Invalid pointer"); + return false; + } + sde_enc = to_sde_encoder_virt(drm_enc); + phys = sde_enc->cur_master; + + if (phys && phys->ops.needs_ctl_start) + return phys->ops.needs_ctl_start(phys); + + return false; +} + static void sde_encoder_destroy(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc = NULL; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index e478b6275041..f67ae38660c2 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -79,6 +79,7 @@ struct sde_encoder_virt_ops { * triggering the next kickoff * (ie for previous tx to complete) * @handle_post_kickoff: Do any work necessary post-kickoff work + * @needs_ctl_start: Whether encoder type needs ctl_start */ struct sde_encoder_phys_ops { @@ -102,6 +103,7 @@ struct sde_encoder_phys_ops { void (*prepare_for_kickoff)(struct sde_encoder_phys *phys_enc, bool *wait_until_ready); void (*handle_post_kickoff)(struct sde_encoder_phys *phys_enc); + bool (*needs_ctl_start)(struct sde_encoder_phys *phys_enc); }; /** diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index 056ea83341d5..700f780a4389 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -423,6 +423,12 @@ static void sde_encoder_phys_cmd_prepare_for_kickoff( MSM_EVT(DEV(phys_enc), cmd_enc->hw_pp->idx, new_pending_cnt); } +static bool sde_encoder_phys_cmd_needs_ctl_start( + struct sde_encoder_phys *phys_enc) +{ + return true; +} + static void sde_encoder_phys_cmd_init_ops( struct sde_encoder_phys_ops *ops) { @@ -436,6 +442,7 @@ static void sde_encoder_phys_cmd_init_ops( ops->control_vblank_irq = sde_encoder_phys_cmd_control_vblank_irq; ops->wait_for_commit_done = sde_encoder_phys_cmd_wait_for_commit_done; ops->prepare_for_kickoff = sde_encoder_phys_cmd_prepare_for_kickoff; + ops->needs_ctl_start = sde_encoder_phys_cmd_needs_ctl_start; } struct sde_encoder_phys *sde_encoder_phys_cmd_init( diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c index 6e703c92613c..3ebefc9fb057 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -586,6 +586,12 @@ static void sde_encoder_phys_vid_handle_post_kickoff( } } +static bool sde_encoder_phys_vid_needs_ctl_start( + struct sde_encoder_phys *phys_enc) +{ + return false; +} + static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops) { ops->is_master = sde_encoder_phys_vid_is_master; @@ -599,6 +605,7 @@ static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops) ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_commit_done; ops->prepare_for_kickoff = sde_encoder_phys_vid_prepare_for_kickoff; ops->handle_post_kickoff = sde_encoder_phys_vid_handle_post_kickoff; + ops->needs_ctl_start = sde_encoder_phys_vid_needs_ctl_start; } struct sde_encoder_phys *sde_encoder_phys_vid_init( diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c index 00b2e648d733..df2a7e59a7c9 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -32,6 +32,14 @@ #define DEV(phy_enc) (phy_enc->parent->dev) /** + * sde_encoder_phys_wb_is_master - report wb always as master encoder + */ +static bool sde_encoder_phys_wb_is_master(struct sde_encoder_phys *phys_enc) +{ + return true; +} + +/** * sde_encoder_phys_wb_get_intr_type - get interrupt type based on block mode * @hw_wb: Pointer to h/w writeback driver */ @@ -769,6 +777,17 @@ static void sde_encoder_phys_wb_get_hw_resources( * cached ctl_idx at init time, shouldn't we use that? */ hw_res->ctls[hw_res_map->ctl] = true; + +} +/** + * sde_encoder_phys_wb_needs_ctl_start - Whether encoder needs ctl_start + * @phys_enc: Pointer to physical encoder + * @Return: Whether encoder needs ctl_start + */ +static bool sde_encoder_phys_wb_needs_ctl_start( + struct sde_encoder_phys *phys_enc) +{ + return true; } #ifdef CONFIG_DEBUG_FS @@ -872,6 +891,7 @@ static void sde_encoder_phys_wb_destroy(struct sde_encoder_phys *phys_enc) */ static void sde_encoder_phys_wb_init_ops(struct sde_encoder_phys_ops *ops) { + ops->is_master = sde_encoder_phys_wb_is_master; ops->mode_set = sde_encoder_phys_wb_mode_set; ops->enable = sde_encoder_phys_wb_enable; ops->disable = sde_encoder_phys_wb_disable; @@ -882,6 +902,7 @@ static void sde_encoder_phys_wb_init_ops(struct sde_encoder_phys_ops *ops) ops->wait_for_commit_done = sde_encoder_phys_wb_wait_for_commit_done; ops->prepare_for_kickoff = sde_encoder_phys_wb_prepare_for_kickoff; ops->handle_post_kickoff = sde_encoder_phys_wb_handle_post_kickoff; + ops->needs_ctl_start = sde_encoder_phys_wb_needs_ctl_start; } /** diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 4a557ee0db32..f2a54f762b0b 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -208,10 +208,35 @@ static void sde_complete_commit(struct msm_kms *kms, MSM_EVT(sde_kms->dev, 0, 0); } -static void sde_wait_for_crtc_commit_done(struct msm_kms *kms, +static void sde_wait_for_commit_done(struct msm_kms *kms, struct drm_crtc *crtc) { - sde_crtc_wait_for_commit_done(crtc); + struct drm_encoder *encoder; + struct drm_device *dev = crtc->dev; + int ret; + + /* ref count the vblank event and interrupts while we wait for it */ + if (drm_crtc_vblank_get(crtc)) + return; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + /* + * Wait post-flush if necessary to delay before plane_cleanup + * For example, wait for vsync in case of video mode panels + * This should be a no-op for command mode panels + */ + MSM_EVT(crtc->dev, crtc->base.id, 0); + ret = sde_encoder_wait_for_commit_done(encoder); + if (ret && ret != -EWOULDBLOCK) { + DRM_ERROR("wait for commit done returned %d\n", ret); + break; + } + } + + /* release vblank event ref count */ + drm_crtc_vblank_put(crtc); } static void sde_kms_prepare_fence(struct msm_kms *kms, @@ -351,7 +376,7 @@ static const struct msm_kms_funcs kms_funcs = { .prepare_commit = sde_prepare_commit, .commit = sde_commit, .complete_commit = sde_complete_commit, - .wait_for_crtc_commit_done = sde_wait_for_crtc_commit_done, + .wait_for_crtc_commit_done = sde_wait_for_commit_done, .enable_vblank = sde_enable_vblank, .disable_vblank = sde_disable_vblank, .check_modified_format = sde_format_check_modified_format, diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index d04dd6053cae..e0bb7a8cfbcf 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -613,7 +613,6 @@ int sde_plane_color_fill(struct drm_plane *plane, * CRTC functions */ 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); @@ -623,9 +622,18 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc); */ void sde_crtc_prepare_fence(struct drm_crtc *crtc); +/** + * sde_crtc_init - create a new crtc object + * @dev: sde device + * @encoder: encoder attached to this crtc + * @plane: base plane + * @vblank_id: Id for reporting vblank. Id in range from 0..dev->num_crtcs. + * @Return: new crtc object or error + */ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_encoder *encoder, - struct drm_plane *plane, int id); + struct drm_plane *plane, + int vblank_id); /** * sde_crtc_complete_commit - callback signalling completion of current commit @@ -653,6 +661,14 @@ void sde_encoder_get_hw_resources(struct drm_encoder *encoder, struct sde_encoder_hw_resources *hw_res); /** + * sde_encoder_needs_ctl_start - Get whether encoder type requires ctl_start + * CMD and WB encoders need ctl_start, video encs do not. + * @encoder: encoder pointer + * @Return: true if the encoder type requires ctl_start issued + */ +bool sde_encoder_needs_ctl_start(struct drm_encoder *encoder); + +/** * sde_encoder_register_vblank_callback - provide callback to encoder that * will be called on the next vblank. * @encoder: encoder pointer |
