summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2015-06-29 18:49:26 -0700
committerEric Anholt <eric@anholt.net>2015-06-29 18:59:07 -0700
commit3c84e9023b144abfb2626fe5fe37a6e42dc3205a (patch)
tree85d1423482197a3642f1daaf785634ae6ec02d07
parentf51aff90487c13d99c213f5ce47fbf55fa55658e (diff)
downloadlinux-3c84e9023b144abfb2626fe5fe37a6e42dc3205a.tar.gz
drm/vc4: When asked for a page flip event, send it at vblank time.
Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c49
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c10
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h3
3 files changed, 62 insertions, 0 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 9ddaffe49832..f9960ac34fd7 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -265,6 +265,19 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc)
DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc));
vc4_hvs_dump_state(dev);
}
+
+ if (crtc->state->event) {
+ unsigned long flags;
+
+ crtc->state->event->pipe = drm_crtc_index(crtc);
+
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ vc4_crtc->event = crtc->state->event;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ crtc->state->event = NULL;
+ }
}
int vc4_enable_vblank(struct drm_device *dev, int crtc_id)
@@ -285,6 +298,21 @@ void vc4_disable_vblank(struct drm_device *dev, int crtc_id)
CRTC_WRITE(PV_INTEN, 0);
}
+static void
+vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
+{
+ struct drm_crtc *crtc = &vc4_crtc->base;
+ struct drm_device *dev = crtc->dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ if (vc4_crtc->event) {
+ drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
+ vc4_crtc->event = NULL;
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
{
struct vc4_crtc *vc4_crtc = data;
@@ -294,6 +322,7 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
if (stat & PV_INT_VFP_START) {
CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START);
drm_crtc_handle_vblank(&vc4_crtc->base);
+ vc4_crtc_handle_page_flip(vc4_crtc);
ret = IRQ_HANDLED;
}
@@ -322,6 +351,26 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
.atomic_flush = vc4_crtc_atomic_flush,
};
+/* Frees the page flip event when the DRM device is closed with the
+ * event still outstanding.
+ */
+void vc4_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
+{
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+
+ if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) {
+ vc4_crtc->event->base.destroy(&vc4_crtc->event->base);
+ drm_crtc_vblank_put(crtc);
+ vc4_crtc->event = NULL;
+ }
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 2ea207562310..64fea2618084 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -85,6 +85,15 @@ static int vc4_drm_unload(struct drm_device *dev)
return 0;
}
+static void vc4_drm_preclose(struct drm_device *dev, struct drm_file *file)
+{
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct drm_crtc *crtc;
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+ vc4_cancel_page_flip(crtc, file);
+}
+
static const struct file_operations vc4_drm_fops = {
.owner = THIS_MODULE,
.open = drm_open,
@@ -116,6 +125,7 @@ static struct drm_driver vc4_drm_driver = {
.load = vc4_drm_load,
.unload = vc4_drm_unload,
.set_busid = drm_platform_set_busid,
+ .preclose = vc4_drm_preclose,
.irq_handler = vc4_irq,
.irq_preinstall = vc4_irq_preinstall,
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 5b4227f41015..ed3f48212e00 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -138,6 +138,8 @@ struct vc4_crtc {
u32 __iomem *dlist;
u32 dlist_size; /* in dwords */
+
+ struct drm_pending_vblank_event *event;
};
static inline struct vc4_crtc *
@@ -315,6 +317,7 @@ void vc4_crtc_register(void);
void vc4_crtc_unregister(void);
int vc4_enable_vblank(struct drm_device *dev, int crtc_id);
void vc4_disable_vblank(struct drm_device *dev, int crtc_id);
+void vc4_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
/**
* _wait_for - magic (register) wait macro