All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marek Szyprowski <m.szyprowski@samsung.com>
To: dri-devel@lists.freedesktop.org, linux-samsung-soc@vger.kernel.org
Cc: Javier Martinez Canillas <javier@osg.samsung.com>,
	Krzysztof Kozlowski <k.kozlowski@samsung.com>,
	Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>,
	Seung-Woo Kim <sw0312.kim@samsung.com>,
	Andrzej Hajda <a.hajda@samsung.com>,
	Tobias Jakobi <tjakobi@math.uni-bielefeld.de>,
	Marek Szyprowski <m.szyprowski@samsung.com>
Subject: [PATCH v2 22/22] drm/exynos: add support for plane rotation, scalling and colospace convesion
Date: Mon, 30 Nov 2015 14:53:37 +0100	[thread overview]
Message-ID: <1448891617-18830-23-git-send-email-m.szyprowski@samsung.com> (raw)
In-Reply-To: <1448891617-18830-1-git-send-email-m.szyprowski@samsung.com>

This patch adds generic plane rotation property for all supported
drivers. This has been implemented with additional help from Exynos IPP
(Exynos Image Post-Processing subsystem) with temporary framebuffers.
Besides rotation, scaling and color space conversion are also supported.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/gpu/drm/exynos/Kconfig                |   8 +
 drivers/gpu/drm/exynos/Makefile               |   1 +
 drivers/gpu/drm/exynos/exynos_drm_drv.h       |   9 +
 drivers/gpu/drm/exynos/exynos_drm_ipp.c       | 154 ++++++++++-
 drivers/gpu/drm/exynos/exynos_drm_ipp.h       |   4 +
 drivers/gpu/drm/exynos/exynos_drm_plane.c     |  28 +-
 drivers/gpu/drm/exynos/exynos_drm_plane_ipp.c | 369 ++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_plane_ipp.h |  73 +++++
 8 files changed, 641 insertions(+), 5 deletions(-)
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_plane_ipp.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_plane_ipp.h

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 83efca941388..e7d414aefbdc 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -104,6 +104,14 @@ config DRM_EXYNOS_IPP
 	help
 	  Choose this option if you want to use IPP feature for DRM.
 
+config DRM_EXYNOS_PLANE_IPP
+	depends on DRM_EXYNOS_IPP
+	bool "Use IPP framework for implementing unsupported plane properties"
+	help
+	  Choose this option if you want to let IPP framework to provide plane
+	  properties (like rotation, overlay scaling and more pixel formats),
+	  which are not supported by hardware CRTC drivers.
+
 config DRM_EXYNOS_FIMC
 	bool "FIMC"
 	depends on DRM_EXYNOS_IPP && MFD_SYSCON
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 6496532aaa91..92c3f7cac7a9 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -19,6 +19,7 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI)	+= exynos_drm_vidi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_G2D)	+= exynos_drm_g2d.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_IPP)	+= exynos_drm_ipp.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_PLANE_IPP)	+= exynos_drm_plane_ipp.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMC)	+= exynos_drm_fimc.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_ROTATOR)	+= exynos_drm_rotator.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_GSC)	+= exynos_drm_gsc.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 670f6d06a2a9..b17e419935db 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -70,6 +70,13 @@ struct exynos_drm_plane_state {
 	unsigned int h_ratio;
 	unsigned int v_ratio;
 	struct drm_framebuffer *fb;
+	unsigned int rotation;
+
+	unsigned int ipp_needed;
+	uint32_t ipp_pixel_format;
+	struct exynos_drm_rect ipp_src;
+	struct exynos_drm_rect ipp_dst;
+	struct drm_framebuffer *ipp_fb;
 };
 
 static inline struct exynos_drm_plane_state *
@@ -93,6 +100,8 @@ struct exynos_drm_plane {
 	const struct exynos_drm_plane_config *config;
 	unsigned int zpos;
 	struct drm_framebuffer *pending_fb;
+	struct drm_framebuffer *ipp_cur_fb;
+	struct drm_framebuffer *ipp_next_fb;
 };
 
 #define EXYNOS_DRM_PLANE_CAP_DOUBLE	(1 << 0)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index 44a6689e0f4c..231cfbfe036c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -20,6 +20,7 @@
 #include <drm/drmP.h>
 #include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
+#include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_ipp.h"
 #include "exynos_drm_iommu.h"
@@ -1513,7 +1514,7 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
 
 	spin_lock_irqsave(&drm_dev->event_lock, flags);
 	list_move_tail(&e->base.link, &e->base.file_priv->event_list);
-	wake_up_interruptible(&e->base.file_priv->event_wait);
+	wake_up(&e->base.file_priv->event_wait);
 	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
 	mutex_unlock(&c_node->event_lock);
 
@@ -1579,6 +1580,157 @@ err_completion:
 		complete(&c_node->start_complete);
 }
 
+static struct drm_exynos_ipp_mem_node
+		*ipp_get_internal_mem_node(struct drm_device *drm_dev,
+		struct drm_exynos_ipp_cmd_node *c_node,
+		__u32 prop_id, enum drm_exynos_ops_id ops_id,
+		struct drm_framebuffer *fb)
+{
+	struct drm_exynos_ipp_mem_node *m_node;
+	struct drm_exynos_ipp_buf_info *buf_info;
+	int i;
+
+	m_node = kzalloc(sizeof(*m_node), GFP_KERNEL);
+	if (!m_node)
+		return ERR_PTR(-ENOMEM);
+
+	buf_info = &m_node->buf_info;
+
+	m_node->ops_id = ops_id;
+	m_node->prop_id = prop_id;
+	INIT_LIST_HEAD(&m_node->list);
+
+	DRM_DEBUG_KMS("m_node[0x%x]ops_id[%d]prop_id[%d]\n", (int)m_node, ops_id, prop_id);
+
+	for_each_ipp_planar(i) {
+		buf_info->obj[i] = NULL;
+		buf_info->base[i] = exynos_drm_fb_dma_addr(fb, i);
+		buf_info->size[i] = fb->pitches[i] * fb->height;
+	}
+
+	mutex_lock(&c_node->mem_lock);
+	list_add_tail(&m_node->list, &c_node->mem_list[ops_id]);
+	mutex_unlock(&c_node->mem_lock);
+
+	return m_node;
+}
+
+
+static int exynos_drm_ipp_internal_enqueue_buf(struct drm_device *drm_dev,
+		__u32 prop_id, enum drm_exynos_ops_id ops_id,
+		struct drm_framebuffer *fb)
+{
+	struct drm_exynos_ipp_cmd_node *c_node;
+	struct drm_exynos_ipp_mem_node *m_node;
+	int ret;
+	struct drm_exynos_ipp_queue_buf qbuf = {
+		.ops_id = ops_id,
+		.buf_type = IPP_BUF_ENQUEUE,
+		.prop_id = prop_id,
+	};
+
+	DRM_DEBUG_KMS("prop_id[%d]ops_id[%s]\n",
+		prop_id, ops_id ? "dst" : "src");
+
+	c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, prop_id);
+	if (!c_node) {
+		DRM_ERROR("failed to get command node.\n");
+		return -ENODEV;
+	}
+
+	m_node = ipp_get_internal_mem_node(drm_dev, c_node, prop_id,
+					   ops_id, fb);
+	if (IS_ERR(m_node)) {
+		DRM_ERROR("failed to get m_node.\n");
+		return PTR_ERR(m_node);
+	}
+
+	if (ops_id == EXYNOS_DRM_OPS_DST) {
+		ret = ipp_get_event(drm_dev, c_node, &qbuf);
+		if (ret) {
+			DRM_ERROR("failed to get event.\n");
+			goto err_clean_node;
+		}
+
+		ret = ipp_queue_buf_with_run(c_node, m_node, &qbuf);
+		if (ret) {
+			DRM_ERROR("failed to run command.\n");
+			goto err_clean_node;
+		}
+	}
+
+	return 0;
+
+err_clean_node:
+	DRM_ERROR("clean memory nodes.\n");
+
+	ipp_clean_queue_buf(drm_dev, c_node, &qbuf);
+	return ret;
+}
+
+int exynos_ipp_process_internal(struct drm_device *drm_dev,
+	struct drm_exynos_ipp_config *src_conf, struct drm_framebuffer *src_fb,
+	struct drm_exynos_ipp_config *dst_conf, struct drm_framebuffer *dst_fb)
+{
+	int ret;
+	struct drm_exynos_ipp_property property = {
+		.config = {
+			*src_conf,
+			*dst_conf,
+		},
+		.cmd = IPP_CMD_M2M,
+	};
+	struct drm_exynos_ipp_cmd_ctrl ctrl = {
+		/* .prop_id */
+		.ctrl = IPP_CTRL_PLAY,
+	};
+	struct drm_exynos_ipp_cmd_ctrl ctrl_stop = {
+		/* .prop_id */
+		.ctrl = IPP_CTRL_STOP,
+	};
+	struct drm_file virt_file = { };
+
+	INIT_LIST_HEAD(&virt_file.lhead);
+	INIT_LIST_HEAD(&virt_file.fbs);
+	mutex_init(&virt_file.fbs_lock);
+	INIT_LIST_HEAD(&virt_file.blobs);
+	INIT_LIST_HEAD(&virt_file.event_list);
+	init_waitqueue_head(&virt_file.event_wait);
+	virt_file.event_space = 4096;
+	virt_file.uid = current_euid();
+	virt_file.pid = get_pid(task_pid(current));
+	virt_file.authenticated = capable(CAP_SYS_ADMIN);
+	virt_file.lock_count = 0;
+
+	ret = exynos_drm_ipp_set_property(drm_dev, &property, &virt_file);
+	if (ret)
+		return ret;
+
+	ctrl.prop_id = property.prop_id;
+	ctrl_stop.prop_id = property.prop_id;
+
+	ret = exynos_drm_ipp_internal_enqueue_buf(drm_dev, property.prop_id,
+						  EXYNOS_DRM_OPS_SRC, src_fb);
+	if (ret)
+		goto cleanup;
+
+	ret = exynos_drm_ipp_internal_enqueue_buf(drm_dev, property.prop_id,
+						  EXYNOS_DRM_OPS_DST, dst_fb);
+	if (ret)
+		goto cleanup;
+
+	ret = exynos_drm_ipp_cmd_ctrl(drm_dev, &ctrl, &virt_file);
+	if (ret)
+		goto cleanup;
+
+	wait_event(virt_file.event_wait, !list_empty(&virt_file.event_list));
+
+cleanup:
+	exynos_drm_ipp_cmd_ctrl(drm_dev, &ctrl_stop, &virt_file);
+
+	return ret;
+}
+
 static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
 {
 	struct exynos_drm_ippdrv *ippdrv;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.h b/drivers/gpu/drm/exynos/exynos_drm_ipp.h
index 1dc13bf57b16..7e95437edecb 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.h
@@ -24,6 +24,10 @@
 #define IPP_GET_LCD_HEIGHT	_IOR('F', 303, int)
 #define IPP_SET_WRITEBACK	_IOW('F', 304, u32)
 
+int exynos_ipp_process_internal(struct drm_device *drm_dev,
+	struct drm_exynos_ipp_config *src_conf, struct drm_framebuffer *src_fb,
+	struct drm_exynos_ipp_config *dst_conf, struct drm_framebuffer *dst_fb);
+
 /* definition of state */
 enum drm_exynos_ipp_state {
 	IPP_STATE_IDLE,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 8a1242b5a938..34ed1d6b8184 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -19,6 +19,7 @@
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_plane.h"
+#include "exynos_drm_plane_ipp.h"
 
 /*
  * This function is to get X or Y size shown via screen. This needs length and
@@ -56,7 +57,8 @@ static int exynos_plane_get_size(int start, unsigned length, unsigned last)
 	return size;
 }
 
-static void exynos_plane_mode_set(struct exynos_drm_plane_state *exynos_state)
+static void exynos_plane_mode_set(struct exynos_drm_plane_state *exynos_state,
+				  const struct exynos_drm_plane_config *config)
 
 {
 	struct drm_plane_state *state = &exynos_state->base;
@@ -85,6 +87,9 @@ static void exynos_plane_mode_set(struct exynos_drm_plane_state *exynos_state)
 	src_w = state->src_w >> 16;
 	src_h = state->src_h >> 16;
 
+	exynos_plane_ipp_setup(exynos_state, config, &src_x, &src_y, &src_w,
+			       &src_h, &crtc_w, &crtc_h);
+
 	/* set ratio */
 	exynos_state->h_ratio = (src_w << 16) / crtc_w;
 	exynos_state->v_ratio = (src_h << 16) / crtc_h;
@@ -163,6 +168,13 @@ static void exynos_drm_plane_destroy_state(struct drm_plane *plane,
 {
 	struct exynos_drm_plane_state *old_exynos_state =
 					to_exynos_plane_state(old_state);
+	struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
+	/*
+	 * This is the only place in the code, where all temporary objects
+	 * used for processing are no longer used and can be freed.
+	 */
+	exynos_plane_ipp_cleanup(exynos_plane, old_exynos_state);
+
 	__drm_atomic_helper_plane_destroy_state(plane, old_state);
 	kfree(old_exynos_state);
 }
@@ -174,6 +186,7 @@ static struct drm_plane_funcs exynos_plane_funcs = {
 	.reset		= exynos_drm_plane_reset,
 	.atomic_duplicate_state = exynos_drm_plane_duplicate_state,
 	.atomic_destroy_state = exynos_drm_plane_destroy_state,
+	.set_property = drm_atomic_helper_plane_set_property,
 };
 
 static int
@@ -218,16 +231,21 @@ static int exynos_plane_atomic_check(struct drm_plane *plane,
 		return 0;
 
 	/* translate state into exynos_state */
-	exynos_plane_mode_set(exynos_state);
+	exynos_plane_mode_set(exynos_state, exynos_plane->config);
 
 	ret = exynos_drm_plane_check_size(exynos_plane->config, exynos_state);
-	return ret;
+	if (ret)
+		return ret;
+
+	return exynos_plane_ipp_check(exynos_plane, exynos_state);
 }
 
 static void exynos_plane_atomic_update(struct drm_plane *plane,
 				       struct drm_plane_state *old_state)
 {
 	struct drm_plane_state *state = plane->state;
+	struct exynos_drm_plane_state *exynos_state =
+						to_exynos_plane_state(state);
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(state->crtc);
 	struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
 
@@ -237,6 +255,8 @@ static void exynos_plane_atomic_update(struct drm_plane *plane,
 	plane->crtc = state->crtc;
 	exynos_plane->pending_fb = state->fb;
 
+	exynos_plane_ipp_update(exynos_plane, exynos_state);
+
 	if (exynos_crtc->ops->update_plane)
 		exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane);
 }
@@ -308,5 +328,5 @@ int exynos_plane_init(struct drm_device *dev,
 		exynos_plane_attach_zpos_property(&exynos_plane->base,
 						  config->zpos);
 
-	return 0;
+	return exynos_plane_ipp_init(dev, exynos_plane);
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_plane_ipp.c
new file mode 100644
index 000000000000..3086fd29f482
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane_ipp.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2015 Samsung Electronics Co.Ltd
+ * Authors: Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <drm/drmP.h>
+
+#include <drm/exynos_drm.h>
+#include "exynos_drm_drv.h"
+#include "exynos_drm_fb.h"
+#include "exynos_drm_gem.h"
+#include "exynos_drm_ipp.h"
+#include "exynos_drm_plane.h"
+#include "exynos_drm_plane_ipp.h"
+#include "exynos_drm_iommu.h"
+
+static uint32_t preferred_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_NV12,
+};
+
+static uint32_t supported_formats[] = {
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_VYUY,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV16,
+	DRM_FORMAT_NV21,
+	DRM_FORMAT_NV61,
+	DRM_FORMAT_YUV422,
+	DRM_FORMAT_YUV420,
+	DRM_FORMAT_YVU420,
+};
+
+static bool
+exynos_plane_check_format(const struct exynos_drm_plane_config *config,
+			       uint32_t format)
+{
+	int i;
+
+	for (i = 0; i < config->num_pixel_formats; i++)
+		if (config->pixel_formats[i] == format)
+			return true;
+	return false;
+}
+
+static struct drm_framebuffer *exynos_plane_ipp_alloc_fb(struct drm_device *dev,
+					struct exynos_drm_plane_state *state)
+{
+	struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER] = { NULL };
+	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
+	struct drm_framebuffer *fb;
+	unsigned int size;
+	unsigned int flags;
+	int i, cpp;
+	int num_planes = drm_format_num_planes(state->ipp_pixel_format);
+	int ret = 0;
+
+
+	if (is_drm_iommu_supported(dev))
+		flags = EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC;
+	else
+		flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC;
+
+	mode_cmd.width = state->ipp_dst.x + state->ipp_dst.w;
+	mode_cmd.height = state->ipp_dst.y + state->ipp_dst.h;
+	mode_cmd.pixel_format = state->ipp_pixel_format;
+
+	for (i = 0; i < num_planes; i++) {
+		cpp = drm_format_plane_cpp(state->ipp_pixel_format, i);
+		mode_cmd.pitches[i] = roundup(mode_cmd.width,
+					EXYNOS_DRM_PITCH_ALIGN) * cpp;
+		mode_cmd.offsets[i] = 0;
+		size = mode_cmd.height * mode_cmd.pitches[i];
+		exynos_gem[i] = exynos_drm_gem_create(dev, flags, size);
+		if (IS_ERR(exynos_gem[i])) {
+			ret = PTR_ERR(exynos_gem[i]);
+			goto err_free;
+		}
+	}
+
+	fb = exynos_drm_framebuffer_init(dev, &mode_cmd, exynos_gem, num_planes);
+	if (IS_ERR(fb)) {
+		ret = PTR_ERR(fb);
+		goto err_free;
+	}
+
+	return fb;
+
+err_free:
+	for (;i >= 0; i--)
+		exynos_drm_gem_destroy(exynos_gem[i]);
+	return ERR_PTR(ret);
+}
+
+static bool exynos_plane_ipp_check_fb(struct drm_framebuffer *ipp_fb,
+				struct exynos_drm_plane_state *state)
+{
+	if (state->ipp_dst.x + state->ipp_dst.w <= ipp_fb->width &&
+	    state->ipp_dst.y + state->ipp_dst.h <= ipp_fb->height &&
+	    state->base.fb->pixel_format == ipp_fb->pixel_format)
+		return true;
+	return false;
+}
+
+static int exynos_plane_ipp_transform(struct exynos_drm_plane_state *state)
+{
+	struct drm_framebuffer *src_fb = state->base.fb;
+	struct drm_framebuffer *dst_fb = state->ipp_fb;
+	struct drm_exynos_ipp_config src_config = {
+		.ops_id = EXYNOS_DRM_OPS_SRC,
+		.sz = {
+			.hsize = src_fb->pitches[0] /
+				drm_format_plane_cpp(src_fb->pixel_format, 0),
+			.vsize = src_fb->height,
+		},
+		.fmt = src_fb->pixel_format,
+		.pos = {
+			.x = state->ipp_src.x,
+			.y = state->ipp_src.y,
+			.w = state->ipp_src.w,
+			.h = state->ipp_src.h,
+		},
+	};
+	struct drm_exynos_ipp_config dst_config = {
+		.sz = {
+			.hsize = dst_fb->pitches[0] /
+				drm_format_plane_cpp(dst_fb->pixel_format, 0),
+			.vsize = dst_fb->height,
+		},
+		.fmt = dst_fb->pixel_format,
+		.pos = {
+			.x = state->ipp_dst.x,
+			.y = state->ipp_dst.y,
+			.w = state->ipp_dst.w,
+			.h = state->ipp_dst.h,
+		},
+	};
+	int degree = 0, flip = 0;
+
+	if (state->rotation & BIT(DRM_ROTATE_180))
+		degree = EXYNOS_DRM_DEGREE_180;
+	else if (state->rotation & BIT(DRM_ROTATE_90))
+		degree = EXYNOS_DRM_DEGREE_90;
+	else if (state->rotation & BIT(DRM_ROTATE_270))
+		degree = EXYNOS_DRM_DEGREE_270;
+
+	if (state->rotation & BIT(DRM_REFLECT_X))
+		flip |= EXYNOS_DRM_FLIP_HORIZONTAL;
+	if (state->rotation & BIT(DRM_REFLECT_Y))
+		flip |= EXYNOS_DRM_FLIP_VERTICAL;
+
+	dst_config.flip = flip;
+	dst_config.degree = degree;
+
+	return exynos_ipp_process_internal(src_fb->dev, &src_config, src_fb,
+					   &dst_config, dst_fb);
+}
+
+void exynos_plane_ipp_setup(struct exynos_drm_plane_state *state,
+			    const struct exynos_drm_plane_config *config,
+			    unsigned int *src_x, unsigned int *src_y,
+			    unsigned int *src_w, unsigned int *src_h,
+			    unsigned int *crtc_w, unsigned int *crtc_h)
+{
+	int rotation = state->base.rotation;
+	int pre_x, pre_y, post_x, post_y;
+	int i;
+	bool supported_pixel_format =
+		exynos_plane_check_format(config, state->base.fb->pixel_format);
+
+	state->rotation = rotation;
+
+	/* check if ipp is really needed */
+	if (rotation == BIT(DRM_ROTATE_0) && supported_pixel_format &&
+	    (*src_w == *crtc_w ||
+	     ((config->capabilities & EXYNOS_DRM_PLANE_CAP_DOUBLE) &&
+	       *src_w * 2 == *crtc_w) ||
+	      config->capabilities & EXYNOS_DRM_PLANE_CAP_SCALE) &&
+	    (*src_h == *crtc_h ||
+	     ((config->capabilities & EXYNOS_DRM_PLANE_CAP_DOUBLE) &&
+	       *src_h * 2 == *crtc_h) ||
+	      config->capabilities & EXYNOS_DRM_PLANE_CAP_SCALE))
+		return;
+
+	state->ipp_needed = true;
+
+	state->ipp_pixel_format = state->base.fb->pixel_format;
+	if (!supported_pixel_format) {
+		for (i = 0; i < ARRAY_SIZE(preferred_formats); i++)
+			if (exynos_plane_check_format(config,
+						      preferred_formats[i])) {
+				state->ipp_pixel_format = preferred_formats[i];
+				break;
+			}
+	}
+
+	state->ipp_src.x = rounddown(*src_x, EXYNOS_DRM_PITCH_ALIGN);
+	state->ipp_src.y = rounddown(*src_y, EXYNOS_DRM_PITCH_ALIGN);
+	state->ipp_dst.x = 0;
+	state->ipp_dst.y = 0;
+
+	pre_x = *src_x & (EXYNOS_DRM_PITCH_ALIGN - 1);
+	pre_y = *src_y & (EXYNOS_DRM_PITCH_ALIGN - 1);
+
+	state->ipp_src.w = roundup(*src_w + pre_x, EXYNOS_DRM_PITCH_ALIGN);
+	state->ipp_src.h = roundup(*src_h + pre_y, EXYNOS_DRM_PITCH_ALIGN);
+	if (state->ipp_src.w > state->base.fb->pitches[0])
+		state->ipp_src.w = state->base.fb->pitches[0];
+	if (state->ipp_src.h > state->base.fb->height)
+		state->ipp_src.h = state->base.fb->height;
+
+	state->ipp_dst.w = state->ipp_src.w;
+	state->ipp_dst.h = state->ipp_src.h;
+
+	post_x = state->ipp_src.w - pre_x - *src_w;
+	post_y = state->ipp_src.h - pre_y - *src_h;
+
+	if (rotation & BIT(DRM_REFLECT_Y))
+		swap(pre_y, post_y);
+
+	if (rotation & BIT(DRM_REFLECT_X))
+		swap(pre_x, post_x);
+
+	switch (rotation & 0xf) {
+	case BIT(DRM_ROTATE_0):
+		*src_x = pre_x;
+		*src_y = pre_y;
+		break;
+	case BIT(DRM_ROTATE_90):
+		*src_x = post_y;
+		*src_y = pre_x;
+		swap(*src_w, *src_h);
+		swap(state->ipp_dst.w, state->ipp_dst.h);
+		break;
+	case BIT(DRM_ROTATE_180):
+		*src_x = post_x;
+		*src_y = post_y;
+		break;
+	case BIT(DRM_ROTATE_270):
+		*src_x = pre_y;
+		*src_y = post_x;
+		swap(*src_w, *src_h);
+		swap(state->ipp_dst.w, state->ipp_dst.h);
+		break;
+	}
+
+	/* apply scalling */
+	state->ipp_dst.w = state->ipp_dst.w * *crtc_w / *src_w;
+	state->ipp_dst.h = state->ipp_dst.h * *crtc_h / *src_h;
+
+	*src_x = *src_x * *crtc_w / *src_w;
+	*src_y = *src_y * *crtc_h / *src_h;
+	*src_w = *crtc_w;
+	*src_h = *crtc_h;
+}
+
+int exynos_plane_ipp_check(struct exynos_drm_plane *plane,
+			   struct exynos_drm_plane_state *state)
+{
+	if (!state->ipp_needed)
+		return 0;
+
+	/* check if currently allocated ipp fb can be reused */
+	if (plane->ipp_next_fb &&
+		!exynos_plane_ipp_check_fb(plane->ipp_next_fb, state)) {
+		drm_framebuffer_unreference(plane->ipp_next_fb);
+		plane->ipp_next_fb = NULL;
+	}
+
+	/* allocate new ipp fb */
+	if (!plane->ipp_next_fb) {
+		struct drm_framebuffer *ipp_fb;
+
+		ipp_fb = exynos_plane_ipp_alloc_fb(plane->base.dev, state);
+		if (IS_ERR(ipp_fb))
+			return PTR_ERR(ipp_fb);
+		plane->ipp_next_fb = ipp_fb;
+	}
+
+	state->fb = state->ipp_fb = plane->ipp_next_fb;
+
+	/* perform transformation */
+	return exynos_plane_ipp_transform(state);
+}
+
+void exynos_plane_ipp_update(struct exynos_drm_plane *plane,
+			     struct exynos_drm_plane_state *state)
+{
+	if (!state->ipp_needed)
+		return;
+
+	if (plane->ipp_next_fb)
+		swap(plane->ipp_next_fb, plane->ipp_cur_fb);
+}
+
+void exynos_plane_ipp_cleanup(struct exynos_drm_plane *plane,
+			      struct exynos_drm_plane_state *old_state)
+{
+	struct exynos_drm_plane_state *state;
+
+	/* get current plane state */
+	state = to_exynos_plane_state(plane->base.state);
+
+	if (!state->ipp_needed) {
+		if (plane->ipp_cur_fb) {
+			drm_framebuffer_unreference(plane->ipp_cur_fb);
+			plane->ipp_cur_fb = NULL;
+		}
+		if (plane->ipp_next_fb) {
+			drm_framebuffer_unreference(plane->ipp_next_fb);
+			plane->ipp_next_fb = NULL;
+		}
+	}
+}
+
+int exynos_plane_ipp_init(struct drm_device *dev,
+			  struct exynos_drm_plane *plane)
+{
+	int i, j, num_formats, ipp_formats = 0;
+	uint32_t *formats;
+
+	for (i = 0; i < ARRAY_SIZE(supported_formats); i++)
+		if (!exynos_plane_check_format(plane->config,
+					       supported_formats[i]))
+			ipp_formats++;
+
+	num_formats = plane->config->num_pixel_formats + ipp_formats;
+	formats = kmalloc_array(num_formats, sizeof(uint32_t), GFP_KERNEL);
+	if (!formats)
+		return -ENOMEM;
+
+	memcpy(formats, plane->config->pixel_formats,
+	       plane->config->num_pixel_formats * sizeof(uint32_t));
+	j = plane->config->num_pixel_formats;
+
+	for (i = 0; i < ARRAY_SIZE(supported_formats); i++)
+		if (!exynos_plane_check_format(plane->config,
+					       supported_formats[i]))
+			formats[j++] = supported_formats[i];
+
+	kfree(plane->base.format_types);
+	plane->base.format_types = formats;
+	plane->base.format_count = num_formats;
+
+	if (!dev->mode_config.rotation_property)
+		dev->mode_config.rotation_property =
+			drm_mode_create_rotation_property(dev,
+				BIT(DRM_ROTATE_0) | BIT(DRM_ROTATE_90) |
+				BIT(DRM_ROTATE_180) | BIT(DRM_ROTATE_270) |
+				BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y));
+
+	if (dev->mode_config.rotation_property)
+		drm_object_attach_property(&plane->base.base,
+					   dev->mode_config.rotation_property,
+					   BIT(DRM_ROTATE_0));
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane_ipp.h b/drivers/gpu/drm/exynos/exynos_drm_plane_ipp.h
new file mode 100644
index 000000000000..44b7f2c53829
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane_ipp.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 Samsung Electronics Co.Ltd
+ * Authors: Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _EXYNOS_DRM_PLANE_IPP_H_
+#define _EXYNOS_DRM_PLANE_IPP_H_
+
+#ifdef CONFIG_DRM_EXYNOS_PLANE_IPP
+
+void exynos_plane_ipp_setup(struct exynos_drm_plane_state *state,
+			    const struct exynos_drm_plane_config *config,
+			    unsigned int *src_x, unsigned int *src_y,
+			    unsigned int *src_w, unsigned int *src_h,
+			    unsigned int *crtc_w, unsigned int *crtc_h);
+
+int exynos_plane_ipp_check(struct exynos_drm_plane *plane,
+			   struct exynos_drm_plane_state *state);
+
+void exynos_plane_ipp_update(struct exynos_drm_plane *plane,
+			     struct exynos_drm_plane_state *state);
+
+void exynos_plane_ipp_cleanup(struct exynos_drm_plane *plane,
+			      struct exynos_drm_plane_state *old_state);
+
+int exynos_plane_ipp_init(struct drm_device *dev,
+			  struct exynos_drm_plane *plane);
+
+#else
+
+static inline
+void exynos_plane_ipp_setup(struct exynos_drm_plane_state *state,
+			    const struct exynos_drm_plane_config *config,
+			    unsigned int *src_x, unsigned int *src_y,
+			    unsigned int *src_w, unsigned int *src_h,
+			    unsigned int *crtc_w, unsigned int *crtc_h)
+{
+}
+
+static inline
+int exynos_plane_ipp_check(struct exynos_drm_plane *plane,
+			   struct exynos_drm_plane_state *state)
+{
+	return 0;
+}
+
+static inline
+void exynos_plane_ipp_update(struct exynos_drm_plane *plane,
+			     struct exynos_drm_plane_state *state)
+{
+}
+
+static inline
+void exynos_plane_ipp_cleanup(struct exynos_drm_plane *plane,
+			      struct exynos_drm_plane_state *old_state)
+{
+}
+
+static inline
+int exynos_plane_ipp_init(struct drm_device *dev,
+			  struct exynos_drm_plane *plane)
+{
+	return 0;
+}
+
+#endif
+#endif
-- 
1.9.2

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

  parent reply	other threads:[~2015-11-30 13:53 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-30 13:53 [PATCH v2 00/22] Exynos DRM: new life of IPP (Image Post Processing) subsystem Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 01/22] drm/exynos: gsc: prepare and unprepare gsc clock Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 02/22] drm/exynos: gsc: fix wrong pm_runtime state Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 03/22] drm/exynos: gsc: add device tree support and remove usage of static mappings Marek Szyprowski
2015-12-10  6:48   ` Inki Dae
2015-12-10  6:55     ` Krzysztof Kozlowski
2015-11-30 13:53 ` [PATCH v2 04/22] drm/exynos: rotator: convert to common clock framework Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 05/22] drm/exynos: exynos7-decon: remove excessive check Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 06/22] drm/exynos: move dma_addr attribute from exynos plane to exynos fb Marek Szyprowski
2015-12-10 13:05   ` Inki Dae
2015-12-11  9:02     ` Inki Dae
2015-12-11  9:26       ` Marek Szyprowski
2015-12-11  9:57         ` Inki Dae
2015-12-11 11:27           ` Marek Szyprowski
2015-12-11 14:52             ` Inki Dae
2015-12-14  9:15               ` Marek Szyprowski
2015-12-14  9:43                 ` Inki Dae
2015-11-30 13:53 ` [PATCH v2 07/22] drm/exynos: introduce exynos_drm_plane_state structure Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 08/22] drm/exynos: mixer: use crtc->state->adjusted_mode instead of crtc->mode Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 09/22] drm/exynos: mixer: enable video overlay plane only when VP is available Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 10/22] drm/exynos: introduce exynos_drm_plane_config structure Marek Szyprowski
2015-12-10 11:47   ` Inki Dae
2015-11-30 13:53 ` [PATCH v2 11/22] drm/exynos: add generic check for plane state Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 12/22] drm/exynos: mixer: use ratio precalculated in exynos_state Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 13/22] drm/exynos: fix clipping when scaling is enabled Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 14/22] drm/exynos: fimd: fix dma burst size setting for small plane size Marek Szyprowski
2015-11-30 15:40   ` Daniel Stone
2015-12-10 11:35   ` Inki Dae
2015-12-10 12:59     ` Marek Szyprowski
2015-12-10 15:36       ` Daniel Stone
2015-12-11  9:04       ` Inki Dae
2015-11-30 13:53 ` [PATCH v2 15/22] drm/exynos: gem: remove old unused prototypes Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 16/22] drm/exynos: add fb pointer to exynos_drm_plane_state Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 17/22] drm/exynos: gem: set default alignment for dumb GEM buffers Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 18/22] drm/exynos: fix to calculate offset of each plane for ipp fimc Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 19/22] drm/exynos: fix to calculate offset of each plane for ipp gsc Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 20/22] drm/exynos: gem: simplify access to exynos gem object Marek Szyprowski
2015-11-30 13:53 ` [PATCH v2 21/22] drm/exynos: ipp: make framework context global Marek Szyprowski
2015-11-30 13:53 ` Marek Szyprowski [this message]
2016-03-15 14:46 ` [PATCH v2 00/22] Exynos DRM: new life of IPP (Image Post Processing) subsystem Tobias Jakobi

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=1448891617-18830-23-git-send-email-m.szyprowski@samsung.com \
    --to=m.szyprowski@samsung.com \
    --cc=a.hajda@samsung.com \
    --cc=b.zolnierkie@samsung.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=javier@osg.samsung.com \
    --cc=k.kozlowski@samsung.com \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=sw0312.kim@samsung.com \
    --cc=tjakobi@math.uni-bielefeld.de \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.