|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
|
|
|
+ * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
|
|
|
* Copyright (C) 2013 Red Hat
|
|
|
* Author: Rob Clark <robdclark@gmail.com>
|
|
|
*
|
|
@@ -60,6 +60,11 @@ struct mdp5_crtc {
|
|
|
|
|
|
struct mdp_irq vblank;
|
|
|
struct mdp_irq err;
|
|
|
+ struct mdp_irq pp_done;
|
|
|
+
|
|
|
+ struct completion pp_completion;
|
|
|
+
|
|
|
+ bool cmd_mode;
|
|
|
|
|
|
struct {
|
|
|
/* protect REG_MDP5_LM_CURSOR* registers and cursor scanout_bo*/
|
|
@@ -87,6 +92,12 @@ static void request_pending(struct drm_crtc *crtc, uint32_t pending)
|
|
|
mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank);
|
|
|
}
|
|
|
|
|
|
+static void request_pp_done_pending(struct drm_crtc *crtc)
|
|
|
+{
|
|
|
+ struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
|
|
|
+ reinit_completion(&mdp5_crtc->pp_completion);
|
|
|
+}
|
|
|
+
|
|
|
static u32 crtc_flush(struct drm_crtc *crtc, u32 flush_mask)
|
|
|
{
|
|
|
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
|
|
@@ -281,6 +292,9 @@ static void mdp5_crtc_disable(struct drm_crtc *crtc)
|
|
|
if (WARN_ON(!mdp5_crtc->enabled))
|
|
|
return;
|
|
|
|
|
|
+ if (mdp5_crtc->cmd_mode)
|
|
|
+ mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->pp_done);
|
|
|
+
|
|
|
mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
|
|
|
mdp5_disable(mdp5_kms);
|
|
|
|
|
@@ -300,6 +314,9 @@ static void mdp5_crtc_enable(struct drm_crtc *crtc)
|
|
|
mdp5_enable(mdp5_kms);
|
|
|
mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
|
|
|
|
|
|
+ if (mdp5_crtc->cmd_mode)
|
|
|
+ mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->pp_done);
|
|
|
+
|
|
|
mdp5_crtc->enabled = true;
|
|
|
}
|
|
|
|
|
@@ -401,6 +418,15 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc)
|
|
|
|
|
|
blend_setup(crtc);
|
|
|
|
|
|
+ /* PP_DONE irq is only used by command mode for now.
|
|
|
+ * It is better to request pending before FLUSH and START trigger
|
|
|
+ * to make sure no pp_done irq missed.
|
|
|
+ * This is safe because no pp_done will happen before SW trigger
|
|
|
+ * in command mode.
|
|
|
+ */
|
|
|
+ if (mdp5_crtc->cmd_mode)
|
|
|
+ request_pp_done_pending(crtc);
|
|
|
+
|
|
|
mdp5_crtc->flushed_mask = crtc_flush_all(crtc);
|
|
|
|
|
|
request_pending(crtc, PENDING_FLIP);
|
|
@@ -607,6 +633,26 @@ static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
|
|
|
DBG("%s: error: %08x", mdp5_crtc->name, irqstatus);
|
|
|
}
|
|
|
|
|
|
+static void mdp5_crtc_pp_done_irq(struct mdp_irq *irq, uint32_t irqstatus)
|
|
|
+{
|
|
|
+ struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc,
|
|
|
+ pp_done);
|
|
|
+
|
|
|
+ complete(&mdp5_crtc->pp_completion);
|
|
|
+}
|
|
|
+
|
|
|
+static void mdp5_crtc_wait_for_pp_done(struct drm_crtc *crtc)
|
|
|
+{
|
|
|
+ struct drm_device *dev = crtc->dev;
|
|
|
+ struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = wait_for_completion_timeout(&mdp5_crtc->pp_completion,
|
|
|
+ msecs_to_jiffies(50));
|
|
|
+ if (ret == 0)
|
|
|
+ dev_warn(dev->dev, "pp done time out, lm=%d\n", mdp5_crtc->lm);
|
|
|
+}
|
|
|
+
|
|
|
static void mdp5_crtc_wait_for_flush_done(struct drm_crtc *crtc)
|
|
|
{
|
|
|
struct drm_device *dev = crtc->dev;
|
|
@@ -654,16 +700,18 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf)
|
|
|
|
|
|
/* now that we know what irq's we want: */
|
|
|
mdp5_crtc->err.irqmask = intf2err(intf->num);
|
|
|
-
|
|
|
- /* Register command mode Pingpong done as vblank for now,
|
|
|
- * so that atomic commit should wait for it to finish.
|
|
|
- * Ideally, in the future, we should take rd_ptr done as vblank,
|
|
|
- * and let atomic commit wait for pingpong done for commond mode.
|
|
|
- */
|
|
|
- if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
|
|
|
- mdp5_crtc->vblank.irqmask = lm2ppdone(lm);
|
|
|
- else
|
|
|
- mdp5_crtc->vblank.irqmask = intf2vblank(lm, intf);
|
|
|
+ mdp5_crtc->vblank.irqmask = intf2vblank(lm, intf);
|
|
|
+
|
|
|
+ if ((intf->type == INTF_DSI) &&
|
|
|
+ (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)) {
|
|
|
+ mdp5_crtc->pp_done.irqmask = lm2ppdone(lm);
|
|
|
+ mdp5_crtc->pp_done.irq = mdp5_crtc_pp_done_irq;
|
|
|
+ mdp5_crtc->cmd_mode = true;
|
|
|
+ } else {
|
|
|
+ mdp5_crtc->pp_done.irqmask = 0;
|
|
|
+ mdp5_crtc->pp_done.irq = NULL;
|
|
|
+ mdp5_crtc->cmd_mode = false;
|
|
|
+ }
|
|
|
|
|
|
mdp_irq_update(&mdp5_kms->base);
|
|
|
|
|
@@ -684,11 +732,12 @@ struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc)
|
|
|
|
|
|
void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc)
|
|
|
{
|
|
|
- /* wait_for_flush_done is the only case for now.
|
|
|
- * Later we will have command mode CRTC to wait for
|
|
|
- * other event.
|
|
|
- */
|
|
|
- mdp5_crtc_wait_for_flush_done(crtc);
|
|
|
+ struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
|
|
|
+
|
|
|
+ if (mdp5_crtc->cmd_mode)
|
|
|
+ mdp5_crtc_wait_for_pp_done(crtc);
|
|
|
+ else
|
|
|
+ mdp5_crtc_wait_for_flush_done(crtc);
|
|
|
}
|
|
|
|
|
|
/* initialize crtc */
|
|
@@ -709,6 +758,7 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
|
|
|
|
|
|
spin_lock_init(&mdp5_crtc->lm_lock);
|
|
|
spin_lock_init(&mdp5_crtc->cursor.lock);
|
|
|
+ init_completion(&mdp5_crtc->pp_completion);
|
|
|
|
|
|
mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq;
|
|
|
mdp5_crtc->err.irq = mdp5_crtc_err_irq;
|