diff options
| author | Abhijit Kulkarni <kabhijit@codeaurora.org> | 2016-07-05 15:27:25 -0400 |
|---|---|---|
| committer | Dhaval Patel <pdhaval@codeaurora.org> | 2016-08-01 11:58:07 -0700 |
| commit | 367202b1e7aecbfbd1e24424fb5d8ae83c7655cf (patch) | |
| tree | a325c135abc9745578bffff87dfd7c1c2c6ac32c /drivers/gpu | |
| parent | 5edb750561e25d4241639e735aba3b2691afcead (diff) | |
drm/msm/sde: add support for vblank callback
Add ability for CRTC to control whether encoder generates
vblank callbacks depending on whether upper layer DRM requests
vblank events.
Change-Id: I5a63afa2765c43d220bfbbedd81d19c3a64de7d7
Signed-off-by: Abhijit Kulkarni <kabhijit@codeaurora.org>
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_crtc.c | 55 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_crtc.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_encoder.c | 12 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_encoder_phys.h | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c | 14 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_irq.c | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_kms.c | 18 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_kms.h | 6 |
9 files changed, 70 insertions, 48 deletions
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 69d445987049..49534f798bb9 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -355,56 +355,52 @@ static void sde_crtc_vblank_cb(void *data) { struct drm_crtc *crtc = (struct drm_crtc *)data; struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct sde_kms *sde_kms = get_kms(crtc); + struct drm_device *dev = sde_kms->dev; unsigned pending; - /* unregister callback */ - sde_encoder_register_vblank_callback(sde_crtc->encoder, NULL, NULL); - pending = atomic_xchg(&sde_crtc->pending, 0); if (pending & PENDING_FLIP) complete_flip(crtc, NULL); + + if (sde_crtc->vblank_enable) { + drm_handle_vblank(dev, sde_crtc->id); + DBG(""); + } } -static int frame_flushed(struct sde_crtc *sde_crtc) +static bool frame_flushed(struct sde_crtc *sde_crtc) { struct vsync_info vsync; /* encoder get vsync_info */ /* if frame_count does not match frame is flushed */ sde_encoder_get_vsync_info(sde_crtc->encoder, &vsync); - - return (vsync.frame_count & sde_crtc->vsync_count); - + return (vsync.frame_count != sde_crtc->vsync_count) ? true : false; } void sde_crtc_wait_for_commit_done(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - u32 pending; + struct drm_device *dev = crtc->dev; int i, ret; + if (!sde_crtc->num_ctls) + return; + /* ref count the vblank event */ ret = drm_crtc_vblank_get(crtc); if (ret) return; - /* register callback */ - sde_encoder_register_vblank_callback(sde_crtc->encoder, - sde_crtc_vblank_cb, - (void *)crtc); - /* wait */ - pending = atomic_read(&sde_crtc->pending); - if (pending & PENDING_FLIP) { - wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue, - (frame_flushed(sde_crtc) != 0), - msecs_to_jiffies(CRTC_MAX_WAIT_ONE_FRAME)); - if (ret <= 0) - dev_warn(dev->dev, "vblank time out, crtc=%d\n", - sde_crtc->id); - } + wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue, + frame_flushed(sde_crtc), + msecs_to_jiffies(50)); + if (ret <= 0) + dev_warn(dev->dev, "vblank time out, crtc=%d, ret %u\n", + sde_crtc->id, ret); for (i = 0; i < sde_crtc->num_ctls; i++) sde_crtc->mixer[i].flush_mask = 0; @@ -625,8 +621,19 @@ static const struct drm_crtc_helper_funcs sde_crtc_helper_funcs = { .atomic_flush = sde_crtc_atomic_flush, }; -uint32_t sde_crtc_vblank(struct drm_crtc *crtc) +int sde_crtc_vblank(struct drm_crtc *crtc, bool en) { + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + + DBG("%d", 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); + + sde_crtc->vblank_enable = en; return 0; } diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index 9f14f999913d..d8dfe2319e5c 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -54,6 +54,7 @@ struct sde_crtc_mixer { * @event : Pointer to last received drm vblank event * @pending : Whether or not an update is pending * @vsync_count : Running count of received vsync events + * @vblank_enable : Whether vblanks have been enabled in the encoder */ struct sde_crtc { struct drm_crtc base; @@ -72,6 +73,7 @@ struct sde_crtc { struct drm_pending_vblank_event *event; atomic_t pending; u32 vsync_count; + bool vblank_enable; }; #define to_sde_crtc(x) container_of(x, struct sde_crtc, base) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 63bd58e90b6c..b1d00662f7e9 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -255,14 +255,16 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) for (i = 0; i < sde_enc->num_phys_encs; i++) { struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - - if (phys && phys->phys_ops.enable) - + if (phys && phys->phys_ops.enable) { /* enable/disable dual interface top config */ if (phys->phys_ops.enable_split_config) phys->phys_ops.enable_split_config(phys, splitmode); - phys->phys_ops.enable(phys); + /* + * enable interrupts on master only + */ + phys->phys_ops.enable(phys, (i == 0) ? true : false); + } } } @@ -323,8 +325,6 @@ static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc) struct sde_encoder_virt *sde_enc = NULL; unsigned long lock_flags; - DBG(""); - if (!drm_enc) { DRM_ERROR("Invalid pointer"); return; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index d35e084f9bef..45935bb858bd 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -35,7 +35,7 @@ struct sde_encoder_phys_ops { bool (*mode_fixup)(struct sde_encoder_phys *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); - void (*enable)(struct sde_encoder_phys *encoder); + void (*enable)(struct sde_encoder_phys *encoder, bool intr_en); void (*disable)(struct sde_encoder_phys *encoder); void (*destroy)(struct sde_encoder_phys *encoder); void (*get_hw_resources)(struct sde_encoder_phys *encoder, @@ -69,6 +69,7 @@ struct sde_encoder_phys_vid { struct sde_encoder_phys base; int irq_idx; struct completion vblank_complete; + bool intr_en; }; struct sde_encoder_virt { 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 aefa11d5cdde..ab91a8dcc61f 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -365,8 +365,11 @@ static int sde_encoder_phys_vid_unregister_irq( return 0; } -static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc) +static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc, + bool intr_en) { + struct sde_encoder_phys_vid *vid_enc = + to_sde_encoder_phys_vid(phys_enc); int ret = 0; DBG(""); @@ -379,8 +382,11 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc) sde_encoder_phys_vid_flush_intf(phys_enc); /* Register for interrupt unless we're the slave encoder */ - if (sde_encoder_phys_vid_is_master(phys_enc)) + if (sde_encoder_phys_vid_is_master(phys_enc) && intr_en) { ret = sde_encoder_phys_vid_register_irq(phys_enc); + if (!ret) + vid_enc->intr_en = true; + } if (!ret && !phys_enc->enabled) { unsigned long lock_flags = 0; @@ -422,7 +428,8 @@ static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc) * scanout buffer) don't latch properly.. */ sde_encoder_phys_vid_wait_for_vblank(vid_enc); - sde_encoder_phys_vid_unregister_irq(phys_enc); + if (vid_enc->intr_en) + sde_encoder_phys_vid_unregister_irq(phys_enc); phys_enc->enabled = false; } @@ -485,7 +492,6 @@ static void sde_encoder_intf_split_config(struct sde_encoder_phys *phys_enc, sde_kms->catalog); struct split_pipe_cfg cfg; - DBG("%p", mdp); cfg.en = true; cfg.mode = INTF_MODE_VIDEO; if (!IS_ERR_OR_NULL(mdp)) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c b/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c index 66a0e612c8fe..71c7dd559872 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c @@ -75,13 +75,10 @@ struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx, const struct sde_mdp_cfg *cfg; /* mdp top is singleton */ - if (c) { - pr_err(" %s returning %p", __func__, c); + if (c) return c; - } c = kzalloc(sizeof(*c), GFP_KERNEL); - pr_err(" %s returning %p", __func__, c); if (!c) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c index 305f51c8b2f3..41e5d67141b9 100644 --- a/drivers/gpu/drm/msm/sde/sde_irq.c +++ b/drivers/gpu/drm/msm/sde/sde_irq.c @@ -268,11 +268,12 @@ irqreturn_t sde_irq(struct msm_kms *kms) int sde_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { - return sde_crtc_vblank(crtc); + return sde_crtc_vblank(crtc, true); } void sde_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { + sde_crtc_vblank(crtc, false); } static void sde_hw_irq_mask(struct irq_data *irqd) diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 9ca4e325e13b..08aa9142f3a9 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -22,20 +22,26 @@ static const char * const iommu_ports[] = { }; static const struct sde_hw_res_map res_table[INTF_MAX] = { - { SDE_NONE, SDE_NONE, SDE_NONE, SDE_NONE}, - { INTF_0, SDE_NONE, SDE_NONE, SDE_NONE}, - { INTF_1, LM_0, PINGPONG_0, CTL_0}, - { INTF_2, LM_1, PINGPONG_1, CTL_1}, - { INTF_3, SDE_NONE, SDE_NONE, CTL_2}, + { SDE_NONE, SDE_NONE, SDE_NONE, SDE_NONE }, + { INTF_0, SDE_NONE, SDE_NONE, SDE_NONE }, + { INTF_1, LM_0, PINGPONG_0, CTL_0 }, + { INTF_2, LM_1, PINGPONG_1, CTL_1 }, + { INTF_3, SDE_NONE, SDE_NONE, CTL_2 }, }; -#define DEFAULT_MDP_SRC_CLK 200000000 +#define DEFAULT_MDP_SRC_CLK 300000000 int sde_disable(struct sde_kms *sde_kms) { DBG(""); + clk_disable_unprepare(sde_kms->ahb_clk); + clk_disable_unprepare(sde_kms->axi_clk); + clk_disable_unprepare(sde_kms->core_clk); + if (sde_kms->lut_clk) + clk_disable_unprepare(sde_kms->lut_clk); + return 0; } diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index 7ae00110633d..172149312672 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -57,7 +57,7 @@ struct sde_hw_res_map { }; /* struct sde_hw_resource_manager : Resource mananger maintains the current - * platform configuration and manages shared + * default platform config and manages shared * hw resources ex:ctl_path hw driver context * is needed by CRTCs/PLANEs/ENCODERs * @ctl : table of control path hw driver contexts allocated @@ -152,6 +152,8 @@ int sde_enable(struct sde_kms *sde_kms); * @sde_rm_get_mixer : returns mixer context for already * acquired mixer * @sde_rm_release_mixer : Frees mixer hw driver context + * @sde_rm_acquire_intr : Allocate hw intr context + * @sde_rm_get_intr : Returns already acquired intr context * @sde_rm_get_hw_res_map : Returns map for the passed INTF */ struct sde_hw_ctl *sde_rm_acquire_ctl_path(struct sde_kms *sde_kms, @@ -274,7 +276,7 @@ struct drm_plane *sde_plane_init(struct drm_device *dev, uint32_t pipe, /** * CRTC functions */ -uint32_t sde_crtc_vblank(struct drm_crtc *crtc); +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); struct drm_crtc *sde_crtc_init(struct drm_device *dev, |
