summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorAbhijit Kulkarni <kabhijit@codeaurora.org>2016-07-05 15:27:25 -0400
committerDhaval Patel <pdhaval@codeaurora.org>2016-08-01 11:58:07 -0700
commit367202b1e7aecbfbd1e24424fb5d8ae83c7655cf (patch)
treea325c135abc9745578bffff87dfd7c1c2c6ac32c /drivers/gpu
parent5edb750561e25d4241639e735aba3b2691afcead (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.c55
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.h2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c12
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys.h3
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c14
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c5
-rw-r--r--drivers/gpu/drm/msm/sde/sde_irq.c3
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c18
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.h6
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,