dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Steve Longerbeam <slongerbeam@gmail.com>
To: dri-devel@lists.freedesktop.org
Subject: [PATCH 51/72] imx-drm: Move page flip handling to plane driver
Date: Fri, 31 Oct 2014 15:54:34 -0700	[thread overview]
Message-ID: <1414796095-10107-52-git-send-email-steve_longerbeam@mentor.com> (raw)
In-Reply-To: <1414796095-10107-1-git-send-email-steve_longerbeam@mentor.com>

Move page flip handling and associated vblank handling to the
plane driver. This paves the way to allow page flipping in not
just the primary plane but the overlay plane as well.

To do this the primary and overlay planes are assigned a pipe value
suitable for passing to the drm core vblank methods (drm_vblank_get,
put,handle).

We modify imx-drm core slightly to make room for primary and overlay
pipe id's when assigning the crtc pipe. So crtc 0 has a primary pipe
value of 0 and overlay pipe value 1, crtc 1 has primary pipe value 2
and overlay pipe value 3, etc. imx_drm_crtc_id() returns the primary
pipe divided by 2 as an id value to form possible crtc masks.

The drm core vblank sees these planes as additional crtcs (pipes) and
does not need significant changes.

The plane driver implements page flip using idmac double-buffering.
Without double-buffering, a page flip operation changes the idmac
channel buffer base address while the buffer is still active. This
is not recommended according to the reference manual.

With double-buffering, a page-flip can set the base of the inactive
buffer before switching to it using buffer-ready control.

Note that for the synchronous display channels, the buffer ready signal can
be driven either by the ARM core writing to the buffer ready registers,
or by the DI.

When the ARM core does not drive ping-pong buffer ready selection at
every EOF, the DI will drive buffer ready, triggered by a timer located
in the DI. The IPU's FSU unit will quickly settle on a single buffer and
then remain at that buffer, the DI driving buffer ready at that buffer.

If the ARM core (the plane driver) then selects the other (inactive)
buffer, the FSU switches to it and then remains at this buffer, the DI
again taking over buffer ready signalling at the new buffer, until the
ARM core makes the next buffer selection.

So we take advantage of this behaviour and use buffer selection to
switch to the other buffer when we want to flip to another DRM
framebuffer for page-flip.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/imx-drm-core.c |   86 +++++++++--------
 drivers/staging/imx-drm/imx-drm.h      |   10 +-
 drivers/staging/imx-drm/ipuv3-crtc.c   |  111 ++++++++--------------
 drivers/staging/imx-drm/ipuv3-plane.c  |  158 ++++++++++++++++++++++++++++----
 drivers/staging/imx-drm/ipuv3-plane.h  |   21 ++++-
 5 files changed, 252 insertions(+), 134 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 59200ff..e0178d6 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -28,6 +28,7 @@
 #include "imx-drm.h"
 
 #define MAX_CRTC	4
+#define MAX_PIPES	(2 * MAX_CRTC)
 
 struct imx_drm_crtc;
 
@@ -53,12 +54,29 @@ struct imx_drm_crtc {
 static int legacyfb_depth = 16;
 module_param(legacyfb_depth, int, 0444);
 
+static inline int pipe_to_crtc_id(int pipe)
+{
+	return pipe >> 1;
+}
+
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
 {
-	return crtc->pipe;
+	return pipe_to_crtc_id(crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
 
+int imx_drm_primary_plane_pipe(struct imx_drm_crtc *crtc)
+{
+	return crtc->pipe;
+}
+EXPORT_SYMBOL_GPL(imx_drm_primary_plane_pipe);
+
+int imx_drm_overlay_plane_pipe(struct imx_drm_crtc *crtc)
+{
+	return crtc->pipe + 1;
+}
+EXPORT_SYMBOL_GPL(imx_drm_overlay_plane_pipe);
+
 static void imx_drm_driver_lastclose(struct drm_device *drm)
 {
 #if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
@@ -129,30 +147,16 @@ int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
 }
 EXPORT_SYMBOL_GPL(imx_drm_panel_format);
 
-int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
-{
-	return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
-}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
-
-void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
-{
-	drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
-}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
-
-void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
-{
-	drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
-}
-EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
-
-static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
+static int imx_drm_enable_vblank(struct drm_device *drm, int pipe)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
-	struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
+	struct imx_drm_crtc *imx_drm_crtc;
 	int ret;
 
+	if (pipe >= MAX_PIPES)
+		return -EINVAL;
+
+	imx_drm_crtc = imxdrm->crtc[pipe_to_crtc_id(pipe)];
 	if (!imx_drm_crtc)
 		return -EINVAL;
 
@@ -160,35 +164,40 @@ static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
 		return -ENOSYS;
 
 	ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
-			imx_drm_crtc->crtc);
+		imx_drm_crtc->crtc, pipe);
 
 	return ret;
 }
 
-static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
+static void imx_drm_disable_vblank(struct drm_device *drm, int pipe)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
-	struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
+	struct imx_drm_crtc *imx_drm_crtc;
 
+	if (pipe >= MAX_PIPES)
+		return;
+
+	imx_drm_crtc = imxdrm->crtc[pipe_to_crtc_id(pipe)];
 	if (!imx_drm_crtc)
 		return;
 
 	if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
 		return;
 
-	imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
+	imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(
+		imx_drm_crtc->crtc, pipe);
 }
 
 static void imx_drm_driver_preclose(struct drm_device *drm,
 		struct drm_file *file)
 {
-	int i;
+	int pipe;
 
 	if (!file->is_master)
 		return;
 
-	for (i = 0; i < MAX_CRTC; i++)
-		imx_drm_disable_vblank(drm, i);
+	for (pipe = 0; pipe < MAX_PIPES; pipe++)
+		imx_drm_disable_vblank(drm, pipe);
 }
 
 static const struct file_operations imx_drm_driver_fops = {
@@ -271,7 +280,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
 	drm_mode_config_init(drm);
 
-	ret = drm_vblank_init(drm, MAX_CRTC);
+	ret = drm_vblank_init(drm, MAX_PIPES);
 	if (ret)
 		goto err_kms;
 
@@ -349,13 +358,13 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 	struct imx_drm_crtc *imx_drm_crtc;
-	int ret;
+	int id, ret;
 
 	/*
-	 * The vblank arrays are dimensioned by MAX_CRTC - we can't
+	 * The vblank arrays are dimensioned by MAX_PIPES - we can't
 	 * pass IDs greater than this to those functions.
 	 */
-	if (imxdrm->pipes >= MAX_CRTC)
+	if (imxdrm->pipes >= MAX_PIPES)
 		return -EINVAL;
 
 	if (imxdrm->drm->open_count)
@@ -366,11 +375,15 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 		return -ENOMEM;
 
 	imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
-	imx_drm_crtc->pipe = imxdrm->pipes++;
+	imx_drm_crtc->pipe = imxdrm->pipes;
 	imx_drm_crtc->port = port;
 	imx_drm_crtc->crtc = crtc;
 
-	imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
+	imxdrm->pipes += 2;
+
+	id = pipe_to_crtc_id(imx_drm_crtc->pipe);
+
+	imxdrm->crtc[id] = imx_drm_crtc;
 
 	*new_crtc = imx_drm_crtc;
 
@@ -387,7 +400,7 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	return 0;
 
 err_register:
-	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
+	imxdrm->crtc[id] = NULL;
 	kfree(imx_drm_crtc);
 	return ret;
 }
@@ -399,10 +412,11 @@ EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
 int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
 {
 	struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
+	int id = pipe_to_crtc_id(imx_drm_crtc->pipe);
 
 	drm_crtc_cleanup(imx_drm_crtc->crtc);
 
-	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
+	imxdrm->crtc[id] = NULL;
 
 	kfree(imx_drm_crtc);
 
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 3a30f16..ec084fe 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -13,10 +13,12 @@ struct imx_drm_crtc;
 struct platform_device;
 
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
+int imx_drm_primary_plane_pipe(struct imx_drm_crtc *crtc);
+int imx_drm_overlay_plane_pipe(struct imx_drm_crtc *crtc);
 
 struct imx_drm_crtc_helper_funcs {
-	int (*enable_vblank)(struct drm_crtc *crtc);
-	void (*disable_vblank)(struct drm_crtc *crtc);
+	int (*enable_vblank)(struct drm_crtc *crtc, int pipe);
+	void (*disable_vblank)(struct drm_crtc *crtc, int pipe);
 	int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
 			u32 pix_fmt, int hsync_pin, int vsync_pin);
 	const struct drm_crtc_helper_funcs *crtc_helper_funcs;
@@ -33,10 +35,6 @@ int imx_drm_init_drm(struct platform_device *pdev,
 		int preferred_bpp);
 int imx_drm_exit_drm(void);
 
-int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
-void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
-void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
-
 void imx_drm_mode_config_init(struct drm_device *drm);
 
 struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 593261f..423b004 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -90,9 +90,7 @@ struct ipu_crtc {
 	struct ipu_dc		*dc;
 	struct ipu_di		*di;
 	int			enabled;
-	struct drm_pending_vblank_event *page_flip_event;
-	struct drm_framebuffer	*newfb;
-	int			irq;
+
 	u32			interface_pix_fmt;
 	unsigned long		di_clkflags;
 	int			di_hsync_pin;
@@ -101,6 +99,22 @@ struct ipu_crtc {
 
 #define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base)
 
+static struct ipu_plane *pipe_to_plane(struct ipu_crtc *ipu_crtc,
+				       int pipe)
+{
+	struct ipu_plane *plane;
+
+	plane = &ipu_crtc->plane[0];
+	if (pipe == plane->pipe)
+		return plane;
+
+	plane = &ipu_crtc->plane[1];
+	if (ipu_crtc->have_overlay && pipe == plane->pipe)
+		return plane;
+
+	return NULL;
+}
+
 static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
 {
 	if (ipu_crtc->enabled)
@@ -149,36 +163,18 @@ static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode)
 	}
 }
 
-static int ipu_page_flip(struct drm_crtc *crtc,
+static int ipu_crtc_page_flip(struct drm_crtc *crtc,
 		struct drm_framebuffer *fb,
 		struct drm_pending_vblank_event *event,
 		uint32_t page_flip_flags)
 {
-	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-	int ret;
-
-	if (ipu_crtc->newfb)
-		return -EBUSY;
-
-	ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc);
-	if (ret) {
-		dev_dbg(ipu_crtc->dev, "failed to acquire vblank counter\n");
-		list_del(&event->base.link);
-
-		return ret;
-	}
-
-	ipu_crtc->newfb = fb;
-	ipu_crtc->page_flip_event = event;
-	crtc->primary->fb = fb;
-
-	return 0;
+	return ipu_plane_page_flip(crtc->primary, fb, event, page_flip_flags);
 }
 
 static const struct drm_crtc_funcs ipu_crtc_funcs = {
 	.set_config = drm_crtc_helper_set_config,
 	.destroy = drm_crtc_cleanup,
-	.page_flip = ipu_page_flip,
+	.page_flip = ipu_crtc_page_flip,
 };
 
 static int ipu_crtc_mode_set(struct drm_crtc *crtc,
@@ -248,37 +244,6 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
 				  x, y, mode->hdisplay, mode->vdisplay);
 }
 
-static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
-{
-	unsigned long flags;
-	struct drm_device *drm = ipu_crtc->base.dev;
-
-	spin_lock_irqsave(&drm->event_lock, flags);
-	if (ipu_crtc->page_flip_event)
-		drm_send_vblank_event(drm, -1, ipu_crtc->page_flip_event);
-	ipu_crtc->page_flip_event = NULL;
-	imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
-	spin_unlock_irqrestore(&drm->event_lock, flags);
-}
-
-static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
-{
-	struct ipu_crtc *ipu_crtc = dev_id;
-
-	imx_drm_handle_vblank(ipu_crtc->imx_crtc);
-
-	if (ipu_crtc->newfb) {
-		struct ipu_plane *plane = &ipu_crtc->plane[0];
-
-		ipu_crtc->newfb = NULL;
-		ipu_plane_set_base(plane, ipu_crtc->base.primary->fb,
-				   plane->x, plane->y);
-		ipu_crtc_handle_pageflip(ipu_crtc);
-	}
-
-	return IRQ_HANDLED;
-}
-
 static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
 				  const struct drm_display_mode *mode,
 				  struct drm_display_mode *adjusted_mode)
@@ -308,17 +273,26 @@ static struct drm_crtc_helper_funcs ipu_helper_funcs = {
 	.commit = ipu_crtc_commit,
 };
 
-static int ipu_enable_vblank(struct drm_crtc *crtc)
+static int ipu_enable_vblank(struct drm_crtc *crtc, int pipe)
 {
-	return 0;
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	struct ipu_plane *ipu_plane = pipe_to_plane(ipu_crtc, pipe);
+
+	if (!ipu_plane)
+		return -EINVAL;
+
+	return ipu_plane_enable_vblank(ipu_plane);
 }
 
-static void ipu_disable_vblank(struct drm_crtc *crtc)
+static void ipu_disable_vblank(struct drm_crtc *crtc, int pipe)
 {
 	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	struct ipu_plane *ipu_plane = pipe_to_plane(ipu_crtc, pipe);
+
+	if (!ipu_plane)
+		return;
 
-	ipu_crtc->page_flip_event = NULL;
-	ipu_crtc->newfb = NULL;
+	ipu_plane_disable_vblank(ipu_plane);
 }
 
 static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
@@ -465,8 +439,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 			 struct drm_device *drm)
 {
 	struct device_node *np = ipu_crtc->dev->of_node;
+	int id, primary_pipe, overlay_pipe;
 	int ret;
-	int id;
 
 	ret = ipu_get_resources(ipu_crtc, np);
 	if (ret) {
@@ -484,8 +458,11 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 	}
 
 	id = imx_drm_crtc_id(ipu_crtc->imx_crtc);
+	primary_pipe = imx_drm_primary_plane_pipe(ipu_crtc->imx_crtc);
+
 	ret = ipu_plane_init(&ipu_crtc->plane[0], drm,
 			     ipu_crtc->ipu,
+			     primary_pipe,
 			     ipu_crtc->ch->dma[0],
 			     ipu_crtc->ch->dp[0],
 			     BIT(id), true);
@@ -504,8 +481,10 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 
 	/* If this crtc is using the DP, add an overlay plane */
 	if (ipu_crtc->ch->dp[1] >= 0) {
+		overlay_pipe = imx_drm_overlay_plane_pipe(ipu_crtc->imx_crtc);
 		ret = ipu_plane_init(&ipu_crtc->plane[1], drm,
 				     ipu_crtc->ipu,
+				     overlay_pipe,
 				     ipu_crtc->ch->dma[1],
 				     ipu_crtc->ch->dp[1],
 				     BIT(id), false);
@@ -513,18 +492,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 		ipu_crtc->have_overlay = ret ? false : true;
 	}
 
-	ipu_crtc->irq = ipu_plane_irq(&ipu_crtc->plane[0]);
-	ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0,
-			"imx_drm", ipu_crtc);
-	if (ret < 0) {
-		dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
-		goto err_put_plane_res;
-	}
-
 	return 0;
 
-err_put_plane_res:
-	ipu_plane_put_resources(&ipu_crtc->plane[0]);
 err_remove_crtc:
 	imx_drm_remove_crtc(ipu_crtc->imx_crtc);
 err_put_resources:
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
index 51a257a..76ac178 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.c
+++ b/drivers/staging/imx-drm/ipuv3-plane.c
@@ -43,12 +43,6 @@ static const uint32_t ipu_plane_formats[] = {
 	DRM_FORMAT_NV16,
 };
 
-int ipu_plane_irq(struct ipu_plane *ipu_plane)
-{
-	return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
-				     IPU_IRQ_EOF);
-}
-
 static int calc_vref(struct drm_display_mode *mode)
 {
 	unsigned long htotal, vtotal;
@@ -67,8 +61,8 @@ static inline int calc_bandwidth(int width, int height, unsigned int vref)
 	return width * height * vref;
 }
 
-int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
-		       int x, int y)
+static int set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
+		    int bufnum, int x, int y)
 {
 	struct drm_gem_cma_object *cma_obj;
 	unsigned long eba;
@@ -79,15 +73,19 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
 		return -EFAULT;
 	}
 
-	dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
-		&cma_obj->paddr, x, y);
+	DRM_DEBUG_KMS("phys = %pad, x = %d, y = %d", &cma_obj->paddr, x, y);
 
 	ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
 
 	eba = cma_obj->paddr + fb->offsets[0] +
 	      fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
-	ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
-	ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
+
+	/* bufnum < 0 means set both buffer addresses */
+	if (bufnum < 0) {
+		ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
+		ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
+	} else
+		ipu_cpmem_set_buffer(ipu_plane->ipu_ch, bufnum, eba);
 
 	/* cache offsets for subsequent pageflips */
 	ipu_plane->x = x;
@@ -96,6 +94,62 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
 	return 0;
 }
 
+static int page_flip(struct ipu_plane *ipu_plane,
+		     struct drm_framebuffer *fb)
+{
+	int curbuf, ret;
+
+	curbuf = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
+	curbuf ^= 1;
+
+	DRM_DEBUG_KMS("pipe %d: page flip to %d\n", ipu_plane->pipe, curbuf);
+
+	ret = set_base(ipu_plane, fb, curbuf, ipu_plane->x, ipu_plane->y);
+	if (!ret)
+		ipu_idmac_select_buffer(ipu_plane->ipu_ch, curbuf);
+
+	return ret;
+}
+
+static void handle_page_flip_event(struct ipu_plane *ipu_plane)
+{
+	struct drm_device *drm = ipu_plane->base.dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&drm->event_lock, flags);
+	if (ipu_plane->page_flip_event)
+		drm_send_vblank_event(drm, -1, ipu_plane->page_flip_event);
+	ipu_plane->page_flip_event = NULL;
+	drm_vblank_put(drm, ipu_plane->pipe);
+	spin_unlock_irqrestore(&drm->event_lock, flags);
+}
+
+static irqreturn_t ipu_plane_irq_handler(int irq, void *dev_id)
+{
+	struct ipu_plane *ipu_plane = dev_id;
+
+	drm_handle_vblank(ipu_plane->base.dev, ipu_plane->pipe);
+
+	if (ipu_plane->newfb) {
+		page_flip(ipu_plane, ipu_plane->newfb);
+		ipu_plane->newfb = NULL;
+		handle_page_flip_event(ipu_plane);
+	}
+
+	return IRQ_HANDLED;
+}
+
+int ipu_plane_enable_vblank(struct ipu_plane *ipu_plane)
+{
+	return 0;
+}
+
+void ipu_plane_disable_vblank(struct ipu_plane *ipu_plane)
+{
+	ipu_plane->page_flip_event = NULL;
+	ipu_plane->newfb = NULL;
+}
+
 int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
 		       struct drm_display_mode *mode,
 		       struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -206,15 +260,31 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
 
 	ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
 
-	ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
+	/* enable double-buffering */
+	ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, true);
+
+	ret = set_base(ipu_plane, fb, -1, src_x, src_y);
 	if (ret < 0)
 		return ret;
 
+	/* cache width/height for subsequent pageflips */
+	ipu_plane->width = src_w;
+	ipu_plane->height = src_h;
+
+	/* set buffers ready */
+	ipu_idmac_select_buffer(ipu_plane->ipu_ch, 0);
+	ipu_idmac_select_buffer(ipu_plane->ipu_ch, 1);
+
 	return 0;
 }
 
 void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
 {
+	if (ipu_plane->irq) {
+		devm_free_irq(ipu_plane->base.dev->dev,
+			      ipu_plane->irq, ipu_plane);
+		ipu_plane->irq = 0;
+	}
 	if (!IS_ERR_OR_NULL(ipu_plane->dp))
 		ipu_dp_put(ipu_plane->dp);
 	if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
@@ -250,6 +320,18 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
 		}
 	}
 
+	ipu_plane->irq = ipu_idmac_channel_irq(ipu_plane->ipu,
+					       ipu_plane->ipu_ch,
+					       IPU_IRQ_EOF);
+	ret = devm_request_irq(ipu_plane->base.dev->dev,
+			       ipu_plane->irq, ipu_plane_irq_handler, 0,
+			       "imx_drm", ipu_plane);
+	if (ret < 0) {
+		DRM_ERROR("irq request failed with %d\n", ret);
+		ipu_plane->irq = 0;
+		goto err_out;
+	}
+
 	return 0;
 err_out:
 	ipu_plane_put_resources(ipu_plane);
@@ -267,6 +349,12 @@ void ipu_plane_enable(struct ipu_plane *ipu_plane)
 		ipu_dp_enable_channel(ipu_plane->dp);
 
 	ipu_plane->enabled = true;
+
+	/*
+	 * we need to wait up to one frame time after enabling
+	 * to allow the IPU's FSU to settle on an IDMAC buffer.
+	 */
+	usleep_range(50000, 50001);
 }
 
 void ipu_plane_disable(struct ipu_plane *ipu_plane)
@@ -416,6 +504,43 @@ static int ipu_plane_set_property(struct drm_plane *plane,
 	return ret;
 }
 
+int ipu_plane_page_flip(struct drm_plane *plane,
+			struct drm_framebuffer *fb,
+			struct drm_pending_vblank_event *event,
+			uint32_t flags)
+{
+	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+	int ret;
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	if (ipu_plane->newfb)
+		return -EBUSY;
+
+	if (ipu_plane->width > fb->width ||
+	    ipu_plane->height > fb->height ||
+	    ipu_plane->x > fb->width - ipu_plane->width ||
+	    ipu_plane->y > fb->height - ipu_plane->height) {
+		DRM_DEBUG_KMS("Invalid fb size %ux%u for plane %ux%u+%d+%d.\n",
+			      fb->width, fb->height,
+			      ipu_plane->width, ipu_plane->height,
+			      ipu_plane->x, ipu_plane->y);
+		return -ENOSPC;
+	}
+
+	ret = drm_vblank_get(ipu_plane->base.dev, ipu_plane->pipe);
+	if (ret) {
+		DRM_DEBUG_KMS("failed to acquire vblank counter\n");
+		return ret;
+	}
+
+	ipu_plane->newfb = fb;
+	ipu_plane->page_flip_event = event;
+	plane->fb = fb;
+
+	return 0;
+}
+
 static struct drm_plane_funcs ipu_plane_funcs = {
 	.update_plane	= ipu_update_plane,
 	.disable_plane	= ipu_disable_plane,
@@ -424,15 +549,16 @@ static struct drm_plane_funcs ipu_plane_funcs = {
 };
 
 int ipu_plane_init(struct ipu_plane *ipu_plane, struct drm_device *drm,
-		   struct ipu_soc *ipu, int dma, int dp,
+		   struct ipu_soc *ipu, int pipe, int dma, int dp,
 		   unsigned int possible_crtcs, bool priv)
 {
 	int ret;
 
-	DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
-		      dma, dp, possible_crtcs);
+	DRM_DEBUG_KMS("channel %d, dp flow %d, pipe %d, possible_crtcs=0x%x\n",
+		      dma, dp, pipe, possible_crtcs);
 
 	ipu_plane->ipu = ipu;
+	ipu_plane->pipe = pipe;
 	ipu_plane->dma = dma;
 	ipu_plane->dp_flow = dp;
 
diff --git a/drivers/staging/imx-drm/ipuv3-plane.h b/drivers/staging/imx-drm/ipuv3-plane.h
index 1487a08..4d856e9 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.h
+++ b/drivers/staging/imx-drm/ipuv3-plane.h
@@ -15,6 +15,7 @@ struct ipu_dp;
 
 struct ipu_plane {
 	struct drm_plane	base;
+	int			pipe;
 
 	struct ipu_soc		*ipu;
 	struct ipuv3_channel	*ipu_ch;
@@ -24,6 +25,8 @@ struct ipu_plane {
 	int			dma;
 	int			dp_flow;
 
+	int			width;
+	int			height;
 	int			x;
 	int			y;
 
@@ -34,11 +37,15 @@ struct ipu_plane {
 	bool			colorkey_en;
 	u32			colorkey;
 
+	struct drm_pending_vblank_event *page_flip_event;
+	struct drm_framebuffer	*newfb;
+	int			irq;
+
 	bool			enabled;
 };
 
 int ipu_plane_init(struct ipu_plane *ipu_plane, struct drm_device *drm,
-		   struct ipu_soc *ipu, int dma, int dp,
+		   struct ipu_soc *ipu, int pipe, int dma, int dp,
 		   unsigned int possible_crtcs, bool priv);
 
 /* Init IDMAC, DMFC, DP */
@@ -49,14 +56,18 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,
 		       uint32_t src_x, uint32_t src_y, uint32_t src_w,
 		       uint32_t src_h);
 
+int ipu_plane_page_flip(struct drm_plane *plane,
+			struct drm_framebuffer *fb,
+			struct drm_pending_vblank_event *event,
+			uint32_t flags);
+
+int ipu_plane_enable_vblank(struct ipu_plane *ipu_plane);
+void ipu_plane_disable_vblank(struct ipu_plane *ipu_plane);
+
 void ipu_plane_enable(struct ipu_plane *plane);
 void ipu_plane_disable(struct ipu_plane *plane);
-int ipu_plane_set_base(struct ipu_plane *plane, struct drm_framebuffer *fb,
-		       int x, int y);
 
 int ipu_plane_get_resources(struct ipu_plane *plane);
 void ipu_plane_put_resources(struct ipu_plane *plane);
 
-int ipu_plane_irq(struct ipu_plane *plane);
-
 #endif
-- 
1.7.9.5

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

  parent reply	other threads:[~2014-10-31 22:57 UTC|newest]

Thread overview: 115+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-31 22:53 [PATCH 00/72] staging imx-drm new features and fixes Steve Longerbeam
2014-10-31 22:53 ` [PATCH 01/72] ARM: dts: imx6qdl-sabrelite: Add HDMI device Steve Longerbeam
2014-10-31 22:53 ` [PATCH 02/72] ARM: dts: imx6qdl-sabreauto: " Steve Longerbeam
2014-10-31 22:53 ` [PATCH 03/72] ARM: dts: imx6qdl: Create imx-drm crtc nodes Steve Longerbeam
2014-11-03 12:31   ` Philipp Zabel
2014-11-03 17:09     ` Steve Longerbeam
2014-10-31 22:53 ` [PATCH 04/72] ARM: i.MX6: use pll2_pfd0_352m as clock root of ipu_di Steve Longerbeam
2014-11-03 12:30   ` Philipp Zabel
2014-11-03 19:10     ` Steve Longerbeam
2014-10-31 22:53 ` [PATCH 05/72] ARM: i.MX6: select pll3_usb_otg for ldb_di for rev 1.0 chip Steve Longerbeam
2014-11-03 12:30   ` Philipp Zabel
2014-11-03 19:17     ` Steve Longerbeam
2014-11-03 20:06       ` Fabio Estevam
2014-11-04  2:38         ` Steve Longerbeam
2014-10-31 22:53 ` [PATCH 06/72] gpu: ipu-cpmem: Add ipu_cpmem_set_uv_offset() Steve Longerbeam
2014-11-03 12:30   ` Philipp Zabel
2014-11-03 22:52     ` Steve Longerbeam
2014-10-31 22:53 ` [PATCH 07/72] gpu: ipu-v3: Add ipu_dp_set_chroma_key() Steve Longerbeam
2014-11-03 12:31   ` Philipp Zabel
2014-11-04  1:55     ` Steve Longerbeam
2014-10-31 22:53 ` [PATCH 08/72] gpu: ipu-v3: Add ipu_dp_set_gamma_correction() Steve Longerbeam
2014-10-31 22:53 ` [PATCH 09/72] gpu: ipu-v3: Add support for dynamic DC interface pixel maps Steve Longerbeam
2014-10-31 22:53 ` [PATCH 10/72] gpu: ipu-v3: Add ipu_dc_uninit_sync() Steve Longerbeam
2014-10-31 22:53 ` [PATCH 11/72] gpu: ipu-v3: Pass struct ipu_dc to enable/disable Steve Longerbeam
2014-10-31 22:53 ` [PATCH 12/72] gpu: ipu-v3: Add ipu_dp_uninit_channel() Steve Longerbeam
2014-10-31 22:53 ` [PATCH 13/72] gpu: ipu-v3: Pass struct ipu_dp to enable/disable Steve Longerbeam
2014-10-31 22:53 ` [PATCH 14/72] gpu: ipu-v3: Implement use counter for ipu_dc_enable(), ipu_dc_disable() Steve Longerbeam
2014-10-31 22:53 ` [PATCH 15/72] gpu: ipu-v3: fix HDMI timing issues Steve Longerbeam
2014-10-31 22:53 ` [PATCH 16/72] gpu: ipu-v3: Add DMFC/DP/DC/DI module enable/disable debug Steve Longerbeam
2014-10-31 22:54 ` [PATCH 17/72] gpu: ipu-v3: Add ipu_di_uninit_sync_panel() Steve Longerbeam
2014-10-31 22:54 ` [PATCH 18/72] gpu: ipu-v3: Split out DI clock enable/disable Steve Longerbeam
2014-10-31 22:54 ` [PATCH 19/72] gpu: ipu-v3: Protect more CM reg access with IPU lock Steve Longerbeam
2014-11-04 17:51   ` Philipp Zabel
2014-11-05  1:54     ` Steve Longerbeam
2014-11-05  1:55     ` Steve Longerbeam
2014-10-31 22:54 ` [PATCH 20/72] gpu: ipu-v3: Move DI waveform counter enable/disable to ipu-di Steve Longerbeam
2014-10-31 22:54 ` [PATCH 21/72] gpu: ipu-v3: Update DP sync SRM always in ipu_dp_enable_channel() Steve Longerbeam
2014-10-31 22:54 ` [PATCH 22/72] gpu: ipu-v3: Fix indent/ws in ipu-dmfc Steve Longerbeam
2014-10-31 22:54 ` [PATCH 23/72] gpu: ipu-v3: Allow burstsize of 20 in ipu_dmfc_setup_channel() Steve Longerbeam
2014-10-31 22:54 ` [PATCH 24/72] gpu: ipu-v3: Remove ipu_dmfc_init_channel() Steve Longerbeam
2014-10-31 22:54 ` [PATCH 25/72] gpu: ipu-v3: Consolidate mutex lock in ipu_dmfc_alloc_bandwidth() Steve Longerbeam
2014-10-31 22:54 ` [PATCH 26/72] gpu: ipu-v3: Enumerate the DC channel names Steve Longerbeam
2014-10-31 22:54 ` [PATCH 27/72] gpu: ipu-di: Move ipu pointer init Steve Longerbeam
2014-10-31 22:54 ` [PATCH 28/72] gpu: ipu-di: Add and improve debug/error messages Steve Longerbeam
2014-10-31 22:54 ` [PATCH 29/72] gpu: ipu-v3: Change signal names in struct ipu_di_signal_cfg Steve Longerbeam
2014-10-31 22:54 ` [PATCH 30/72] gpu: ipu-v3: Remove IPU client registration Steve Longerbeam
2014-10-31 22:54 ` [PATCH 31/72] gpu: ipu-di: Set rate of DI pre clock Steve Longerbeam
2014-10-31 22:54 ` [PATCH 32/72] gpu: ipu-v3: Add RGB666 interface pixel map Steve Longerbeam
2014-10-31 22:54 ` [PATCH 33/72] gpu: ipu-cpmem: Pass drm fourcc to ipu_cpmem_set_yuv_* Steve Longerbeam
2014-10-31 22:54 ` [PATCH 34/72] gpu: ipu-v3: Add ipu_drm_fourcc_is_planar() Steve Longerbeam
2014-10-31 22:54 ` [PATCH 35/72] gpu: ipu-v3: Add IDMA channel linking support Steve Longerbeam
2014-10-31 22:54 ` [PATCH 36/72] gpu: ipu-cpmem: Support YVU422 Steve Longerbeam
2014-10-31 22:54 ` [PATCH 37/72] gpu: ipu-cpmem: Add ipu_cpmem_get_burstsize() Steve Longerbeam
2014-10-31 22:54 ` [PATCH 38/72] imx-drm: Crtcs moved to device tree Steve Longerbeam
2014-10-31 22:54 ` [PATCH 39/72] imx-drm: hdmi: optimize i2c write wait Steve Longerbeam
2014-10-31 22:54 ` [PATCH 40/72] imx-drm: parallel-display: Support RGB666 pixel fmt Steve Longerbeam
2014-10-31 22:54 ` [PATCH 41/72] imx-drm: imx-ldb: Add debug to connector/encoder entry points Steve Longerbeam
2014-10-31 22:54 ` [PATCH 42/72] imx-drm: imx-ldb: Implement imx_ldb_encoder_dpms() Steve Longerbeam
2014-10-31 22:54 ` [PATCH 43/72] imx-drm: parallel-display: Fix typo when setting mode type Steve Longerbeam
2014-10-31 22:54 ` [PATCH 44/72] imx-drm: ipuv3-plane: Fix planar formats Steve Longerbeam
2014-10-31 22:54 ` [PATCH 45/72] imx-drm: ipuv3-plane: Allow YUV space for background plane Steve Longerbeam
2014-10-31 22:54 ` [PATCH 46/72] imx-drm: ipuv3-plane: Add more supported pixel formats Steve Longerbeam
2014-10-31 22:54 ` [PATCH 47/72] imx-drm: ipuv3-plane: Implement global alpha and colorkey properties Steve Longerbeam
2014-10-31 22:54 ` [PATCH 48/72] imx-drm: hdmi: rework irq request/free Steve Longerbeam
2014-10-31 22:54 ` [PATCH 49/72] imx-drm: imx-ldb: Add DDC support Steve Longerbeam
2014-11-04 17:52   ` Philipp Zabel
2014-10-31 22:54 ` [PATCH 50/72] imx-drm: Fix separate primary plane objects Steve Longerbeam
2014-10-31 22:54 ` Steve Longerbeam [this message]
2014-10-31 22:54 ` [PATCH 52/72] imx-drm: Reset ipu unit pointers to NULL on errors Steve Longerbeam
2014-10-31 22:54 ` [PATCH 53/72] drm: implement page flipping support for planes Steve Longerbeam
2014-11-01 13:25   ` Rob Clark
2014-10-31 22:54 ` [PATCH 54/72] imx-drm: ipuv3-plane: Assign page_flip method to drm_plane_funcs Steve Longerbeam
2014-10-31 22:54 ` [PATCH 55/72] imx-drm: Implement DRM gamma set Steve Longerbeam
2014-10-31 22:54 ` [PATCH 56/72] imx-drm: Implement custom ioctl to set gamma Steve Longerbeam
2014-10-31 22:54 ` [PATCH 57/72] imx-drm: Add support for interface pixel maps Steve Longerbeam
2014-10-31 22:54 ` [PATCH 58/72] imx-drm: parallel-display: Add interface-pix-map DT property Steve Longerbeam
2014-10-31 22:54 ` [PATCH 59/72] imx-drm: hdmi: set DI clock source to DI pre clock Steve Longerbeam
2014-10-31 22:54 ` [PATCH 60/72] imx-drm: ipuv3-crtc: Set the crtc device name Steve Longerbeam
2014-10-31 22:54 ` [PATCH 61/72] imx-drm: hdmi: Save ipu/di mux for later iomux setup Steve Longerbeam
2014-10-31 22:54 ` [PATCH 62/72] imx-drm: ipuv3-plane: Assign correct dmfc burst size Steve Longerbeam
2014-10-31 22:54 ` [PATCH 63/72] drm_modes: videomode: add pos/neg pixel clock polarity flag Steve Longerbeam
2014-10-31 22:54 ` [PATCH 64/72] imx-drm: ipuv3-crtc: Use DRM mode flags to configure pixel clock polarity Steve Longerbeam
2014-10-31 22:54 ` [PATCH 65/72] imx-drm: imx-ldb: Add all defined of video modes Steve Longerbeam
2014-10-31 22:54 ` [PATCH 66/72] imx-drm: parallel-display: " Steve Longerbeam
2014-10-31 22:54 ` [PATCH 67/72] imx-drm: ipuv3-crtc: Disable fb on crtc unbind Steve Longerbeam
2014-10-31 22:54 ` [PATCH 68/72] imx-drm: imx-ldb: Use DDC probe as connection detect Steve Longerbeam
2014-11-04 17:57   ` Philipp Zabel
2014-10-31 22:54 ` [PATCH 69/72] imx-drm: ipuv3-crtc: Implement mode_set_base Steve Longerbeam
2014-10-31 22:54 ` [PATCH 70/72] imx-drm: Cancel pending page flip events at preclose Steve Longerbeam
2014-10-31 22:54 ` [PATCH 71/72] imx-drm: ipuv3-crtc: Disable overlay plane during crtc disable Steve Longerbeam
2014-10-31 22:54 ` [PATCH 72/72] imx-drm: ipuv3-plane: Enable 8 burst locking Steve Longerbeam
2014-11-01  0:09 ` [PATCH 00/72] staging imx-drm new features and fixes Fabio Estevam
2014-11-01  0:19   ` Steve Longerbeam
2014-11-03 13:12     ` Fabio Estevam
2014-11-03 13:17       ` Fabio Estevam
2014-11-03 13:20       ` Fabio Estevam
2014-11-03 14:13         ` Fabio Estevam
2014-11-03 22:41           ` Steve Longerbeam
2014-11-04 15:15             ` Fabio Estevam
2014-11-02  3:03   ` Steve Longerbeam
2014-11-03 11:17 ` Zubair Lutfullah Kakakhel
2014-11-03 16:04   ` Rob Clark
2014-11-03 16:12 ` Daniel Vetter
2014-11-03 16:14   ` Greg KH
2014-11-03 17:17     ` Daniel Vetter
2014-11-03 17:48       ` Greg KH
2014-11-03 18:58         ` Steve Longerbeam
2014-11-04  2:32           ` Alex Deucher
2014-11-03 18:59         ` Steve Longerbeam
2014-11-03 20:00           ` Fabio Estevam
2014-11-03 22:11             ` Steve Longerbeam
2014-11-04  9:35           ` Philipp Zabel
2014-11-05  1:20             ` Steve Longerbeam
2015-01-17 19:45               ` Fabio Estevam
2015-01-21 17:22 ` Rob Clark

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1414796095-10107-52-git-send-email-steve_longerbeam@mentor.com \
    --to=slongerbeam@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox