From patchwork Thu Apr 20 09:13:39 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 9689937 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 2FD4C600C8 for ; Thu, 20 Apr 2017 09:14:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 10890282E2 for ; Thu, 20 Apr 2017 09:14:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 048B62845B; Thu, 20 Apr 2017 09:14:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 253F6282E2 for ; Thu, 20 Apr 2017 09:14:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S943111AbdDTJO2 (ORCPT ); Thu, 20 Apr 2017 05:14:28 -0400 Received: from mailout4.w1.samsung.com ([210.118.77.14]:53524 "EHLO mailout4.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S937838AbdDTJOU (ORCPT ); Thu, 20 Apr 2017 05:14:20 -0400 Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout4.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0OOP00LNWAZKQE20@mailout4.w1.samsung.com> for linux-samsung-soc@vger.kernel.org; Thu, 20 Apr 2017 10:14:09 +0100 (BST) Received: from eusmges4.samsung.com (unknown [203.254.199.244]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20170420091408eucas1p2a8cf72e0bd6e3cabdaacf76db84f58d9~3EDtinWdy1334513345eucas1p2W; Thu, 20 Apr 2017 09:14:08 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges4.samsung.com (EUCPMTA) with SMTP id 98.90.04729.0EB78F85; Thu, 20 Apr 2017 10:14:08 +0100 (BST) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20170420091407eucas1p281bd7bb7f7b45855cf593ec8aed6136a~3EDswmJ4I0348403484eucas1p2P; Thu, 20 Apr 2017 09:14:07 +0000 (GMT) X-AuditID: cbfec7f4-f79806d000001279-01-58f87be08263 Received: from eusync2.samsung.com ( [203.254.199.212]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id 1F.69.17452.16C78F85; Thu, 20 Apr 2017 10:16:17 +0100 (BST) Received: from AMDC2765.digital.local ([106.116.147.25]) by eusync2.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OOP00DTXAZACLB0@eusync2.samsung.com>; Thu, 20 Apr 2017 10:14:07 +0100 (BST) From: Marek Szyprowski To: dri-devel@lists.freedesktop.org, linux-samsung-soc@vger.kernel.org Cc: Marek Szyprowski , Inki Dae , Seung-Woo Kim , Andrzej Hajda , Bartlomiej Zolnierkiewicz , Tobias Jakobi , Rob Clark , Daniel Vetter Subject: [RFC 3/4] drm/exynos: Add Picture Processor framework Date: Thu, 20 Apr 2017 11:13:39 +0200 Message-id: <1492679620-12792-4-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.9.1 In-reply-to: <1492679620-12792-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrNIsWRmVeSWpSXmKPExsWy7djPc7oPqn9EGPy8I21xa905VouNM9az WvzfNpHZ4srX92wWk+5PYLGYcX4fk8XaI3fZLZ4v/MFsMWPySzaLttUfWB24PPZ+W8DisXPW XXaP+93HmTz+HWP36NuyitHj8ya5ALYoLpuU1JzMstQifbsEroy2qekFE6cwVVy5eoSxgfHH Q8YuRg4OCQETiQV3rLoYOYFMMYkL99azdTFycQgJLGWU2PD+KxOE85lR4kX3YSaYhvNTTSDi yxglPrz4xArhNDBJrLyxmhVkFJuAoUTX2y42EFtEwE2i6fBMsCJmgTNMEnt+dzOBJIQF7CR+ LGphBrFZBFQl3n08wA5i8wp4SJy89pMF4iY5iZPHJoMN5RTwlDh8djHYSRICk9klFn37xAZx kqzEpgPMEPUuEkvOvILqFZZ4dXwLO4QtI9HZcZAJwu5nlGhq1YawZzBKnHvLC2FbSxw+fhFs F7MAn8SkbdOZIcbzSnS0CUGUeEgseX4bGhCOEpff20H8PodRYt+S9cwTGGUWMDKsYhRJLS3O TU8tNtErTswtLs1L10vOz93ECIzy0/+Of9nBuPiY1SFGAQ5GJR7eDRnfI4RYE8uKK3MPMUpw MCuJ8CqW/4gQ4k1JrKxKLcqPLyrNSS0+xCjNwaIkzst16lqEkEB6YklqdmpqQWoRTJaJg1Oq gTEse6Kc/+3pvJJsZf8U1/FtuCXqGWVs9931dPGlJ1mZoTffiRwTeqoXuraqTjPbw/Dwg8en M00/vyztXNk/ST89TPFLzsMXP9kW9QQ+eDjB4vrvV8/1b1YtD1fhurGrUdz5fIze+7QJgcv3 XJv0cPfFFc9Yu18e4pjd3yxqYJJzcheT4CRVhktKLMUZiYZazEXFiQBT3l9j7gIAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrNLMWRmVeSWpSXmKPExsVy+t/xK7qJNT8iDPrOW1vcWneO1WLjjPWs Fv+3TWS2uPL1PZvFpPsTWCxmnN/HZLH2yF12i+cLfzBbzJj8ks2ibfUHVgcuj73fFrB47Jx1 l93jfvdxJo9/x9g9+rasYvT4vEkugC3KzSYjNTEltUghNS85PyUzL91WKTTETddCSSEvMTfV VilC1zckSEmhLDGnFMgzMkADDs4B7sFK+nYJbhltU9MLJk5hqrhy9QhjA+OPh4xdjBwcEgIm EuenmnQxcgKZYhIX7q1n62Lk4hASWMIoceHwUlaQhJBAE5PE8kXZIDabgKFE19suNhBbRMBN ounwTLAaZoFzTBL3FvuC2MICdhI/FrUwg9gsAqoS7z4eYAexeQU8JE5e+8kCsUxO4uSxyWC9 nAKeEofPLmaC2OUh0X3zFNMERt4FjAyrGEVSS4tz03OLDfWKE3OLS/PS9ZLzczcxAgN+27Gf m3cwXtoYfIhRgINRiYc3Iu17hBBrYllxZe4hRgkOZiURXsXyHxFCvCmJlVWpRfnxRaU5qcWH GE2BjprILCWanA+MxrySeEMTQ3NLQyNjCwtzIyMlcd6SD1fChQTSE0tSs1NTC1KLYPqYODil GhitjERWv8mYePUty9X/syqrQnZUmp5lWh4karCsTz387WFhtseRs1ZtPJx2hs356/Xyp2bO R9g+xgoZtv7ab//nU7TJxUgB4Yyitm7nv+dU4mP3feWw/fPp1nxl+bQHe+uqio9NWdV3Ip93 0d+mUg/xX1aT2GZO/tBemCO5bfpCp741vf1Xb09VYinOSDTUYi4qTgQAygce/I4CAAA= X-MTR: 20000000000000000@CPGS X-CMS-MailID: 20170420091407eucas1p281bd7bb7f7b45855cf593ec8aed6136a X-Msg-Generator: CA X-Sender-IP: 182.198.249.179 X-Local-Sender: =?UTF-8?B?TWFyZWsgU3p5cHJvd3NraRtTUlBPTC1LZXJuZWwgKFRQKRs=?= =?UTF-8?B?7IK87ISx7KCE7J6QG1NlbmlvciBTb2Z0d2FyZSBFbmdpbmVlcg==?= X-Global-Sender: =?UTF-8?B?TWFyZWsgU3p5cHJvd3NraRtTUlBPTC1LZXJuZWwgKFRQKRtT?= =?UTF-8?B?YW1zdW5nIEVsZWN0cm9uaWNzG1NlbmlvciBTb2Z0d2FyZSBFbmdpbmVlcg==?= X-Sender-Code: =?UTF-8?B?QzEwG0VIURtDMTBDRDAyQ0QwMjczOTI=?= CMS-TYPE: 201P X-HopCount: 7 X-CMS-RootMailID: 20170420091407eucas1p281bd7bb7f7b45855cf593ec8aed6136a X-RootMTR: 20170420091407eucas1p281bd7bb7f7b45855cf593ec8aed6136a References: <1492679620-12792-1-git-send-email-m.szyprowski@samsung.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch extends Exynos DRM API with picture processor hardware modules. Such modules can be used for processing image data from the one memory buffer to another. Typical memory-to-memory operations are: rotation, scaling, colour space conversion or mix of them. The proposed API is heavily inspired by atomic KMS approach - it is also based on DRM objects and their properties. A new DRM object is introduced: picture processor (called pp for convenience). Such objects have a set of standard DRM properties, which describes the operation to be performed by respective hardware module. In typical case those properties are a source fb id and rectangle (x, y, width, height) and destination fb id and rectangle. Optionally a rotation property can be also specified if supported by the given hardware. To perform an operation on image data, userspace provides a set of properties and their values for given fbproc object in a similar way as object and properties are provided for performing atomic page flip / mode setting. The proposed API consists of the 3 new ioctls: - DRM_IOCTL_EXYNOS_PP_GET_RESOURCES: to enumerate all available picture processors, - DRM_IOCTL_EXYNOS_PP_GET: to query capabilities of given picture processor, - DRM_IOCTL_EXYNOS_PP_COMMIT: to perform operation described by given property set. The proposed API is extensible. Drivers can attach their own, custom properties to add support for more advanced picture processing (for example blending). Signed-off-by: Marek Szyprowski --- drivers/gpu/drm/exynos/Makefile | 3 +- drivers/gpu/drm/exynos/exynos_drm_drv.c | 8 + drivers/gpu/drm/exynos/exynos_drm_drv.h | 15 + drivers/gpu/drm/exynos/exynos_drm_pp.c | 775 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_pp.h | 155 +++++++ include/uapi/drm/exynos_drm.h | 62 +++ 6 files changed, 1017 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/exynos/exynos_drm_pp.c create mode 100644 drivers/gpu/drm/exynos/exynos_drm_pp.h diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index f663490e949d..2632b0ee5d2d 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile @@ -3,7 +3,8 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fb.o \ - exynos_drm_gem.o exynos_drm_core.o exynos_drm_plane.o + exynos_drm_gem.o exynos_drm_core.o exynos_drm_plane.o \ + exynos_drm_pp.o exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 09d3c4c3c858..41942b111285 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -26,6 +26,7 @@ #include "exynos_drm_fb.h" #include "exynos_drm_gem.h" #include "exynos_drm_plane.h" +#include "exynos_drm_pp.h" #include "exynos_drm_vidi.h" #include "exynos_drm_g2d.h" #include "exynos_drm_ipp.h" @@ -128,6 +129,12 @@ static void exynos_drm_lastclose(struct drm_device *dev) DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL, exynos_drm_ipp_cmd_ctrl, DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(EXYNOS_PP_GET_RESOURCES, exynos_drm_pp_get_res, + DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(EXYNOS_PP_GET, exynos_drm_pp_get, + DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(EXYNOS_PP_COMMIT, exynos_drm_pp_commit, + DRM_AUTH | DRM_RENDER_ALLOW), }; static const struct file_operations exynos_drm_driver_fops = { @@ -360,6 +367,7 @@ static int exynos_drm_bind(struct device *dev) drm_mode_config_init(drm); exynos_drm_mode_config_init(drm); + exynos_drm_pp_init(drm); /* setup possible_clones. */ cnt = 0; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index cb3176930596..7915200f2f7c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -220,6 +220,21 @@ struct exynos_drm_private { u32 pending; spinlock_t lock; wait_queue_head_t wait; + + /* for pp api */ + int num_pp; + struct list_head pp_list; + + struct drm_property *pp_src_fb; + struct drm_property *pp_src_x; + struct drm_property *pp_src_y; + struct drm_property *pp_src_w; + struct drm_property *pp_src_h; + struct drm_property *pp_dst_fb; + struct drm_property *pp_dst_x; + struct drm_property *pp_dst_y; + struct drm_property *pp_dst_w; + struct drm_property *pp_dst_h; }; static inline struct device *to_dma_dev(struct drm_device *dev) diff --git a/drivers/gpu/drm/exynos/exynos_drm_pp.c b/drivers/gpu/drm/exynos/exynos_drm_pp.c new file mode 100644 index 000000000000..18c4738b7679 --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos_drm_pp.c @@ -0,0 +1,775 @@ +/* + * Copyright (C) 2017 Samsung Electronics Co.Ltd + * Authors: + * Marek Szyprowski + * + * Exynos DRM Picture Processor (PP) related functions + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include +#include +#include + +#include "exynos_drm_drv.h" +#include "exynos_drm_pp.h" + +struct drm_pending_exynos_pp_event { + struct drm_pending_event base; + struct drm_exynos_pp_event event; +}; + +/** + * exynos_drm_pp_create_properties - Initialize Picture Processor extension + * @dev: DRM device + */ +int exynos_drm_pp_init(struct drm_device *dev) +{ + struct exynos_drm_private *priv = dev->dev_private; + struct drm_property *prop; + + INIT_LIST_HEAD(&priv->pp_list); + + prop = drm_property_create_object(dev, DRM_MODE_PROP_VENDOR, + "SRC_FB_ID", DRM_MODE_OBJECT_FB); + if (!prop) + return -ENOMEM; + priv->pp_src_fb = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_VENDOR, + "SRC_X", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + priv->pp_src_x = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_VENDOR, + "SRC_Y", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + priv->pp_src_y = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_VENDOR, + "SRC_W", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + priv->pp_src_w = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_VENDOR, + "SRC_H", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + priv->pp_src_h = prop; + + prop = drm_property_create_object(dev, DRM_MODE_PROP_VENDOR, + "DST_FB_ID", DRM_MODE_OBJECT_FB); + if (!prop) + return -ENOMEM; + priv->pp_dst_fb = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_VENDOR, + "DST_X", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + priv->pp_dst_x = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_VENDOR, + "DST_Y", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + priv->pp_dst_y = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_VENDOR, + "DST_W", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + priv->pp_dst_w = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_VENDOR, + "DST_H", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + priv->pp_dst_h = prop; + + return 0; +} + +/** + * exynos_drm_pp_register - Register a new picture processor hardware module + * @dev: DRM device + * @pp: pp module to init + * @funcs: callbacks for the new pp object + * @caps: bitmask of pp capabilities (%DRM_EXYNOS_PP_CAP_*) + * @src_fmts: array of supported source fb formats (%DRM_FORMAT_*) + * @src_fmt_count: number of elements in @src_fmts + * @dst_fmts: array of supported destination fb formats (%DRM_FORMAT_*) + * @dst_fmt_count: number of elements in @dst_fmts + * @rotation: a set of supported rotation transformations + * @name: printf style format string, or NULL for the default name + * + * Initializes a pp module. + * + * Returns: + * Zero on success, error code on failure. + */ +int exynos_drm_pp_register(struct drm_device *dev, struct exynos_drm_pp *pp, + const struct exynos_drm_pp_funcs *funcs, unsigned int caps, + const uint32_t *src_fmts, unsigned int src_fmt_count, + const uint32_t *dst_fmts, unsigned int dst_fmt_count, + unsigned int rotation, const char *name, ...) +{ + static const struct drm_prop_enum_list props[] = { + { __builtin_ffs(DRM_ROTATE_0) - 1, "rotate-0" }, + { __builtin_ffs(DRM_ROTATE_90) - 1, "rotate-90" }, + { __builtin_ffs(DRM_ROTATE_180) - 1, "rotate-180" }, + { __builtin_ffs(DRM_ROTATE_270) - 1, "rotate-270" }, + { __builtin_ffs(DRM_REFLECT_X) - 1, "reflect-x" }, + { __builtin_ffs(DRM_REFLECT_Y) - 1, "reflect-y" }, + }; + struct exynos_drm_private *priv = dev->dev_private; + struct drm_property *prop; + int ret; + + ret = drm_mode_object_add(dev, &pp->base, DRM_EXYNOS_OBJECT_PP); + if (ret) + return ret; + + spin_lock_init(&pp->lock); + INIT_LIST_HEAD(&pp->todo_list); + init_waitqueue_head(&pp->done_wq); + pp->base.properties = &pp->properties; + pp->dev = dev; + pp->funcs = funcs; + pp->capabilities = caps; + pp->src_format_count = src_fmt_count; + pp->dst_format_count = dst_fmt_count; + + if (name) { + va_list ap; + + va_start(ap, name); + pp->name = kvasprintf(GFP_KERNEL, name, ap); + va_end(ap); + } else { + pp->name = kasprintf(GFP_KERNEL, "pp-%d", + priv->num_pp); + } + if (!pp->name) + goto free; + + pp->src_format_types = kmemdup(src_fmts, + sizeof(uint32_t) * src_fmt_count, GFP_KERNEL); + if (!pp->src_format_types) + goto free; + + pp->dst_format_types = kmemdup(dst_fmts, + sizeof(uint32_t) * dst_fmt_count, GFP_KERNEL); + if (!pp->dst_format_types) + goto free; + + prop = drm_property_create_bitmask(dev, DRM_MODE_PROP_VENDOR, + "rotation", props, ARRAY_SIZE(props), + rotation); + if (!prop) + goto free; + + pp->rotation_property = prop; + + list_add_tail(&pp->head, &priv->pp_list); + + drm_object_attach_property(&pp->base, priv->pp_src_fb, 0); + drm_object_attach_property(&pp->base, priv->pp_src_x, 0); + drm_object_attach_property(&pp->base, priv->pp_src_y, 0); + drm_object_attach_property(&pp->base, priv->pp_src_w, 0); + drm_object_attach_property(&pp->base, priv->pp_src_h, 0); + drm_object_attach_property(&pp->base, priv->pp_dst_fb, 0); + drm_object_attach_property(&pp->base, priv->pp_dst_x, 0); + drm_object_attach_property(&pp->base, priv->pp_dst_y, 0); + drm_object_attach_property(&pp->base, priv->pp_dst_w, 0); + drm_object_attach_property(&pp->base, priv->pp_dst_h, 0); + drm_object_attach_property(&pp->base, prop, DRM_ROTATE_0); + + priv->num_pp++; + DRM_DEBUG_DRIVER("Registered pp %d\n", pp->base.id); + + return 0; + +free: + kfree(pp->dst_format_types); + kfree(pp->src_format_types); + kfree(pp->name); + drm_mode_object_unregister(dev, &pp->base); + return -ENOMEM; +} + +/** + * exynos_drm_pp_unregister - Unregister the picture processor module + * @dev: DRM device + * @pp: pp module + */ +void exynos_drm_pp_unregister(struct drm_device *dev, struct exynos_drm_pp *pp) +{ + BUG_ON(pp->task); + BUG_ON(!list_empty(&pp->todo_list)); + + kfree(pp->dst_format_types); + kfree(pp->src_format_types); + kfree(pp->name); + drm_mode_object_unregister(dev, &pp->base); +} + +/** + * exynos_drm_pp_get_res - enumerate all pp modules + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Construct a list of pp ids to return to the user. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int exynos_drm_pp_get_res(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct exynos_drm_private *priv = dev->dev_private; + struct drm_exynos_pp_get_res *resp = data; + struct exynos_drm_pp *pp; + uint32_t __user *pp_ptr; + unsigned int count = priv->num_pp, copied = 0; + + /* + * This ioctl is called twice, once to determine how much space is + * needed, and the 2nd time to fill it. + */ + if (count && resp->count_pps >= count) { + pp_ptr = (uint32_t __user *) + (unsigned long)resp->pp_id_ptr; + + list_for_each_entry(pp, &priv->pp_list, head) { + if (put_user(pp->base.id, pp_ptr + copied)) + return -EFAULT; + copied++; + } + } + resp->count_pps = count; + + return 0; +} + +static inline struct exynos_drm_pp *exynos_drm_pp_find(struct drm_device *dev, + uint32_t id) +{ + struct exynos_drm_private *priv = dev->dev_private; + struct exynos_drm_pp *pp; + + list_for_each_entry(pp, &priv->pp_list, head) { + if (pp->base.id == id) + return pp; + } + return NULL; +} + +/** + * exynos_drm_pp_get - get picture processor module parameters + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Construct a pp configuration structure to return to the user. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int exynos_drm_pp_get(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_exynos_pp_get *resp = data; + struct exynos_drm_pp *pp; + uint32_t __user *format_ptr; + + pp = exynos_drm_pp_find(dev, resp->pp_id); + if (!pp) + return -ENOENT; + + resp->pp_id = pp->base.id; + resp->capabilities = pp->capabilities; + + /* + * This ioctl is called twice, once to determine how much space is + * needed, and the 2nd time to fill it. + */ + if (pp->src_format_count && + (resp->src_format_count >= pp->src_format_count)) { + format_ptr = (uint32_t __user *) + (unsigned long)resp->src_format_type_ptr; + if (copy_to_user(format_ptr, pp->src_format_types, + sizeof(uint32_t) * pp->src_format_count)) + return -EFAULT; + } + if (pp->dst_format_count && + (resp->dst_format_count >= pp->dst_format_count)) { + format_ptr = (uint32_t __user *) + (unsigned long)resp->dst_format_type_ptr; + if (copy_to_user(format_ptr, pp->dst_format_types, + sizeof(uint32_t) * pp->dst_format_count)) + return -EFAULT; + } + resp->src_format_count = pp->src_format_count; + resp->dst_format_count = pp->dst_format_count; + + return 0; +} + +static inline struct exynos_drm_pp_task * + exynos_drm_pp_task_alloc(struct exynos_drm_pp *pp) +{ + struct exynos_drm_pp_task *task; + + task = kzalloc(sizeof(*task), GFP_KERNEL); + if (!task) + return NULL; + + task->dev = pp->dev; + task->pp = pp; + task->src_w = task->dst_w = UINT_MAX; + task->src_h = task->dst_h = UINT_MAX; + task->rotation = DRM_ROTATE_0; + + DRM_DEBUG_DRIVER("Allocated task %pK\n", task); + + return task; +} + +static void exynos_drm_pp_task_free(struct exynos_drm_pp *pp, + struct exynos_drm_pp_task *task) +{ + DRM_DEBUG_DRIVER("Freeing task %pK\n", task); + + task->pp = NULL; + + if (task->src_fb) { + drm_framebuffer_unreference(task->src_fb); + task->src_fb = NULL; + } + if (task->dst_fb) { + drm_framebuffer_unreference(task->dst_fb); + task->dst_fb = NULL; + } + if (task->event) { + drm_event_cancel_free(pp->dev, &task->event->base); + task->event = NULL; + } + kfree(task); +} + +static int exynos_drm_pp_task_set_property(struct exynos_drm_pp_task *task, + struct drm_property *prop, uint64_t prop_value) +{ + struct drm_device *dev = task->dev; + struct exynos_drm_private *priv = dev->dev_private; + struct exynos_drm_pp *pp = task->pp; + struct drm_framebuffer *fb; + int ret = 0; + + if (prop == priv->pp_src_fb) { + fb = drm_framebuffer_lookup(dev, prop_value); + if (task->src_fb) + drm_framebuffer_unreference(task->src_fb); + task->src_fb = fb; + } else if (prop == priv->pp_src_x) { + task->src_x = prop_value; + } else if (prop == priv->pp_src_y) { + task->src_y = prop_value; + } else if (prop == priv->pp_src_w) { + task->src_w = prop_value; + } else if (prop == priv->pp_src_h) { + task->src_h = prop_value; + } else if (prop == priv->pp_dst_fb) { + fb = drm_framebuffer_lookup(dev, prop_value); + if (task->dst_fb) + drm_framebuffer_unreference(task->dst_fb); + task->dst_fb = fb; + } else if (prop == priv->pp_dst_x) { + task->dst_x = prop_value; + } else if (prop == priv->pp_dst_y) { + task->dst_y = prop_value; + } else if (prop == priv->pp_dst_w) { + task->dst_w = prop_value; + } else if (prop == priv->pp_dst_h) { + task->dst_h = prop_value; + } else if (prop == pp->rotation_property) { + task->rotation = prop_value; + } else { + ret = -EINVAL; + } + + return ret; +} + +static struct drm_pending_exynos_pp_event *exynos_drm_pp_event_create( + struct drm_device *dev, struct drm_file *file_priv, + uint64_t user_data) +{ + struct drm_pending_exynos_pp_event *e = NULL; + int ret; + + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) + return NULL; + + e->event.base.type = DRM_EXYNOS_PP_EVENT; + e->event.base.length = sizeof(e->event); + e->event.user_data = user_data; + + if (file_priv) { + ret = drm_event_reserve_init(dev, file_priv, &e->base, + &e->event.base); + if (ret) { + kfree(e); + return NULL; + } + } + + return e; +} + +static void exynos_drm_pp_event_send(struct drm_device *dev, + struct exynos_drm_pp *pp, + struct drm_pending_exynos_pp_event *e) +{ + struct timeval now = ktime_to_timeval(ktime_get()); + + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + e->event.sequence = atomic_inc_return(&pp->sequence); + + drm_send_event(dev, &e->base); +} + +static inline bool drm_fb_check_format(struct drm_framebuffer *fb, + const uint32_t *formats, int format_counts) +{ + while (format_counts--) + if (*formats++ == fb->format->format) + return true; + return false; +} + +static int exynos_drm_pp_task_check(struct exynos_drm_pp_task *task) +{ + struct exynos_drm_pp *pp = task->pp; + int ret = 0; + + DRM_DEBUG_DRIVER("checking %pK\n", task); + + if (!task->src_fb || !task->dst_fb) + return -EINVAL; + + if (!drm_fb_check_format(task->src_fb, pp->src_format_types, + pp->src_format_count)) + return -EINVAL; + + if (!drm_fb_check_format(task->dst_fb, pp->dst_format_types, + pp->dst_format_count)) + return -EINVAL; + + if (task->src_w == UINT_MAX) + task->src_w = task->src_fb->width << 16; + if (task->src_h == UINT_MAX) + task->src_h = task->src_fb->height << 16; + if (task->dst_w == UINT_MAX) + task->dst_w = task->dst_fb->width << 16; + if (task->dst_h == UINT_MAX) + task->dst_h = task->dst_fb->height << 16; + + if (task->src_x + task->src_w > (task->src_fb->width << 16) || + task->src_y + task->src_h > (task->src_fb->height << 16) || + task->dst_x + task->dst_w > (task->dst_fb->width << 16) || + task->dst_y + task->dst_h > (task->dst_fb->height << 16)) + return -EINVAL; + + if (!(pp->capabilities & DRM_EXYNOS_PP_CAP_CROP) && + (task->src_x || task->src_y || task->dst_x || task->dst_y)) + return -EINVAL; + + if (!(pp->capabilities & DRM_EXYNOS_PP_CAP_ROTATE) && + task->rotation != DRM_ROTATE_0) + return -EINVAL; + + if (!(pp->capabilities & DRM_EXYNOS_PP_CAP_SCALE) && + (!drm_rotation_90_or_270(task->rotation) && + (task->src_w != task->dst_w || task->src_h != task->dst_h)) && + (drm_rotation_90_or_270(task->rotation) && + (task->src_w != task->dst_h || task->src_h != task->dst_w))) + return -EINVAL; + + if (!(pp->capabilities & DRM_EXYNOS_PP_CAP_CONVERT) && + task->src_fb->format->format != task->dst_fb->format->format) + return -EINVAL; + + if (!(pp->capabilities & DRM_EXYNOS_PP_CAP_FB_MODIFIERS) && + ((task->src_fb->flags & DRM_MODE_FB_MODIFIERS) || + (task->dst_fb->flags & DRM_MODE_FB_MODIFIERS))) + return -EINVAL; + + if (pp->funcs->check) + ret = pp->funcs->check(pp, task); + + return ret; +} + +static int exynos_drm_pp_task_cleanup(struct exynos_drm_pp_task *task) +{ + int ret = task->ret; + + if (ret == 0 && task->event) { + exynos_drm_pp_event_send(task->dev, task->pp, task->event); + /* ensure event won't be canceled on task free */ + task->event = NULL; + } + + exynos_drm_pp_task_free(task->pp, task); + return ret; +} + +static void exynos_drm_pp_cleanup_work(struct work_struct *work) +{ + struct exynos_drm_pp_task *task = container_of(work, + struct exynos_drm_pp_task, cleanup_work); + + exynos_drm_pp_task_cleanup(task); +} + +static void exynos_drm_pp_next_task(struct exynos_drm_pp *pp); + +void exynos_drm_pp_task_done(struct exynos_drm_pp_task *task, int ret) +{ + struct exynos_drm_pp *pp = task->pp; + unsigned long flags; + + DRM_DEBUG_DRIVER("pp: %d, task %pK done\n", pp->base.id, + task); + + spin_lock_irqsave(&pp->lock, flags); + if (pp->task == task) + pp->task = NULL; + task->flags |= DRM_EXYNOS_PP_TASK_DONE; + task->ret = ret; + spin_unlock_irqrestore(&pp->lock, flags); + + exynos_drm_pp_next_task(pp); + wake_up(&pp->done_wq); + + if (task->flags & DRM_EXYNOS_PP_TASK_ASYNC) { + INIT_WORK(&task->cleanup_work, exynos_drm_pp_cleanup_work); + schedule_work(&task->cleanup_work); + } +} + +static void exynos_drm_pp_next_task(struct exynos_drm_pp *pp) +{ + struct exynos_drm_pp_task *task; + unsigned long flags; + int ret; + + DRM_DEBUG_DRIVER("pp: %d, try to run new task\n", pp->base.id); + + spin_lock_irqsave(&pp->lock, flags); + + if (pp->task || list_empty(&pp->todo_list)) { + spin_unlock_irqrestore(&pp->lock, flags); + return; + } + + task = list_first_entry(&pp->todo_list, struct exynos_drm_pp_task, + head); + list_del_init(&task->head); + pp->task = task; + + spin_unlock_irqrestore(&pp->lock, flags); + + DRM_DEBUG_DRIVER("pp: %d, selected task %pK to run\n", + pp->base.id, task); + + ret = pp->funcs->commit(pp, task); + if (ret) + exynos_drm_pp_task_done(task, ret); +} + +static void exynos_drm_pp_schedule_task(struct exynos_drm_pp *pp, + struct exynos_drm_pp_task *task) +{ + unsigned long flags; + + spin_lock_irqsave(&pp->lock, flags); + list_add(&task->head, &pp->todo_list); + spin_unlock_irqrestore(&pp->lock, flags); + + exynos_drm_pp_next_task(pp); +} + +static void exynos_drm_pp_task_abort(struct exynos_drm_pp *pp, + struct exynos_drm_pp_task *task) +{ + unsigned long flags; + + spin_lock_irqsave(&pp->lock, flags); + if (task->flags & DRM_EXYNOS_PP_TASK_DONE) { + /* already completed task */ + exynos_drm_pp_task_cleanup(task); + } else if (pp->task != task) { + /* task has not been scheduled for execution yet */ + list_del_init(&task->head); + exynos_drm_pp_task_cleanup(task); + } else { + /* + * currently processed task, call abort() and perform + * cleanup with async worker + */ + task->flags |= DRM_EXYNOS_PP_TASK_ASYNC; + if (pp->funcs->abort) + pp->funcs->abort(pp, task); + } + spin_unlock_irqrestore(&pp->lock, flags); +} + +/** + * exynos_drm_pp_ioctl - perform operation on framebuffer processor object + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Construct a pp task from the set of properties provided from the user + * and try to schedule it to framebuffer processor hardware. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int exynos_drm_pp_commit(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_exynos_pp_commit *arg = data; + uint32_t __user *props_ptr = + (uint32_t __user *)(unsigned long)(arg->props_ptr); + uint64_t __user *prop_values_ptr = + (uint64_t __user *)(unsigned long)(arg->prop_values_ptr); + struct exynos_drm_pp *pp; + struct exynos_drm_pp_task *task; + int ret = 0; + unsigned int i; + + if (arg->flags & ~DRM_EXYNOS_PP_FLAGS) + return -EINVAL; + + if (arg->reserved) + return -EINVAL; + + /* can't test and expect an event at the same time */ + if ((arg->flags & DRM_EXYNOS_PP_FLAG_TEST_ONLY) && + (arg->flags & DRM_EXYNOS_PP_FLAG_EVENT)) + return -EINVAL; + + pp = exynos_drm_pp_find(dev, arg->pp_id); + if (!pp) + return -ENOENT; + + task = exynos_drm_pp_task_alloc(pp); + if (!task) { + ret = -ENOMEM; + goto free; + } + + for (i = 0; i < arg->count_props; i++) { + uint32_t prop_id; + uint64_t prop_value; + struct drm_property *prop; + + if (get_user(prop_id, props_ptr + i)) { + ret = -EFAULT; + goto free; + } + + prop = drm_property_find(dev, prop_id); + if (!prop) { + ret = -ENOENT; + goto free; + } + + if (copy_from_user(&prop_value, prop_values_ptr + i, + sizeof(prop_value))) { + ret = -EFAULT; + goto free; + } + + ret = exynos_drm_pp_task_set_property(task, prop, prop_value); + if (ret) + goto free; + } + + if (arg->flags & DRM_EXYNOS_PP_FLAG_EVENT) { + struct drm_pending_exynos_pp_event *e; + + e = exynos_drm_pp_event_create(dev, file_priv, arg->user_data); + if (!e) { + ret = -ENOMEM; + goto free; + } + task->event = e; + } + + ret = exynos_drm_pp_task_check(task); + if (ret || arg->flags & DRM_EXYNOS_PP_FLAG_TEST_ONLY) + goto free; + + /* + * Queue task for processing on the hardware. task object will be + * then freed after exynos_drm_pp_task_done() + */ + if (arg->flags & DRM_EXYNOS_PP_FLAG_NONBLOCK) { + DRM_DEBUG_DRIVER("pp: %d, nonblocking processing task %pK\n", + task->pp->base.id, task); + + task->flags |= DRM_EXYNOS_PP_TASK_ASYNC; + exynos_drm_pp_schedule_task(task->pp, task); + ret = 0; + } else { + DRM_DEBUG_DRIVER("pp: %d, processing task %pK\n", pp->base.id, + task); + exynos_drm_pp_schedule_task(pp, task); + ret = wait_event_interruptible(pp->done_wq, + task->flags & DRM_EXYNOS_PP_TASK_DONE); + if (ret) + exynos_drm_pp_task_abort(pp, task); + else + ret = exynos_drm_pp_task_cleanup(task); + } + return ret; +free: + exynos_drm_pp_task_free(pp, task); + + return ret; +} diff --git a/drivers/gpu/drm/exynos/exynos_drm_pp.h b/drivers/gpu/drm/exynos/exynos_drm_pp.h new file mode 100644 index 000000000000..d892097f7e89 --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos_drm_pp.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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_FBPROC_H_ +#define _EXYNOS_DRM_FBPORC_H_ + +#include + +struct exynos_drm_pp; +struct exynos_drm_pp_task; + +/** + * struct exynos_drm_pp_funcs - exynos_drm_pp control functions + */ +struct exynos_drm_pp_funcs { + /** + * @check: + * + * This is the optional hook to validate an pp task. This function + * must reject any task which the hardware or driver doesn't support. + * This includes but is of course not limited to: + * + * - Checking that the framebuffers, scaling and placement + * requirements and so on are within the limits of the hardware. + * + * - The driver does not need to repeat basic input validation like + * done in the exynos_drm_pp_check_only() function. The core does + * that before calling this hook. + * + * RETURNS: + * + * 0 on success or one of the below negative error codes: + * + * - -EINVAL, if any of the above constraints are violated. + */ + int (*check)(struct exynos_drm_pp *pp, + struct exynos_drm_pp_task *task); + + /** + * @commit: + * + * This is the main entry point to start framebuffer processing + * in the hardware. The exynos_drm_pp_task has been already validated. + * This function must not wait until the device finishes processing. + * When the driver finishes processing, it has to call + * exynos_exynos_drm_pp_task_done() function. + * + * RETURNS: + * + * 0 on success or negative error codes in case of failure. + */ + int (*commit)(struct exynos_drm_pp *pp, + struct exynos_drm_pp_task *task); + + /** + * @abort: + * + * Informs the driver that it has to abort the currently running + * task as soon as possible (i.e. as soon as it can stop the device + * safely), even if the task would not have been finished by then. + * After the driver performs the necessary steps, it has to call + * exynos_drm_pp_task_done() (as if the task ended normally). + * This function does not have to (and will usually not) wait + * until the device enters a state when it can be stopped. + */ + void (*abort)(struct exynos_drm_pp *pp, + struct exynos_drm_pp_task *task); +}; + +/** + * struct exynos_drm_pp - central picture processor module structure + */ +struct exynos_drm_pp { + struct drm_device *dev; + struct list_head head; + + char *name; + struct drm_mode_object base; + const struct exynos_drm_pp_funcs *funcs; + unsigned int capabilities; + atomic_t sequence; + + spinlock_t lock; + struct exynos_drm_pp_task *task; + struct list_head todo_list; + wait_queue_head_t done_wq; + + uint32_t *src_format_types; + unsigned int src_format_count; + uint32_t *dst_format_types; + unsigned int dst_format_count; + + struct drm_object_properties properties; + + struct drm_property *rotation_property; +}; + +/** + * struct exynos_drm_pp_task - a structure describing transformation that + * has to be performed by the picture processor hardware module + */ +struct exynos_drm_pp_task { + struct drm_device *dev; + struct exynos_drm_pp *pp; + struct list_head head; + + struct drm_framebuffer *src_fb; + + /* Source values are 16.16 fixed point */ + uint32_t src_x, src_y; + uint32_t src_h, src_w; + + struct drm_framebuffer *dst_fb; + + /* Destination values are 16.16 fixed point */ + uint32_t dst_x, dst_y; + uint32_t dst_h, dst_w; + + unsigned int rotation; + + struct work_struct cleanup_work; + unsigned int flags; + int ret; + + struct drm_pending_exynos_pp_event *event; +}; + +#define DRM_EXYNOS_PP_TASK_DONE (1 << 0) +#define DRM_EXYNOS_PP_TASK_ASYNC (1 << 1) + +int exynos_drm_pp_init(struct drm_device *dev); + +int exynos_drm_pp_register(struct drm_device *dev, struct exynos_drm_pp *pp, + const struct exynos_drm_pp_funcs *funcs, unsigned int caps, + const uint32_t *src_fmts, unsigned int src_fmt_count, + const uint32_t *dst_fmts, unsigned int dst_fmt_count, + unsigned int rotation, const char *name, ...); +void exynos_drm_pp_unregister(struct drm_device *dev, struct exynos_drm_pp *pp); + +void exynos_drm_pp_task_done(struct exynos_drm_pp_task *task, int ret); + +int exynos_drm_pp_get_res(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int exynos_drm_pp_get(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int exynos_drm_pp_commit(struct drm_device *dev, + void *data, struct drm_file *file_priv); + +#endif diff --git a/include/uapi/drm/exynos_drm.h b/include/uapi/drm/exynos_drm.h index cb3e9f9d029f..5a13287856f3 100644 --- a/include/uapi/drm/exynos_drm.h +++ b/include/uapi/drm/exynos_drm.h @@ -300,6 +300,46 @@ struct drm_exynos_ipp_cmd_ctrl { __u32 ctrl; }; +struct drm_exynos_pp_get_res { + __u64 pp_id_ptr; + __u32 count_pps; +}; + +struct drm_exynos_pp_get { + __u32 pp_id; + __u32 capabilities; + + __u32 src_format_count; + __u32 dst_format_count; + __u64 src_format_type_ptr; + __u64 dst_format_type_ptr; +}; + +#define DRM_EXYNOS_OBJECT_PP 0x88888888 + +#define DRM_EXYNOS_PP_CAP_CROP 0x01 +#define DRM_EXYNOS_PP_CAP_ROTATE 0x02 +#define DRM_EXYNOS_PP_CAP_SCALE 0x04 +#define DRM_EXYNOS_PP_CAP_CONVERT 0x08 +#define DRM_EXYNOS_PP_CAP_FB_MODIFIERS 0x1000 + +#define DRM_EXYNOS_PP_FLAG_EVENT 0x01 +#define DRM_EXYNOS_PP_FLAG_TEST_ONLY 0x02 +#define DRM_EXYNOS_PP_FLAG_NONBLOCK 0x04 + +#define DRM_EXYNOS_PP_FLAGS (DRM_EXYNOS_PP_FLAG_EVENT |\ + DRM_EXYNOS_PP_FLAG_TEST_ONLY | DRM_EXYNOS_PP_FLAG_NONBLOCK) + +struct drm_exynos_pp_commit { + __u32 pp_id; + __u32 flags; + __u32 count_props; + __u64 props_ptr; + __u64 prop_values_ptr; + __u64 reserved; + __u64 user_data; +}; + #define DRM_EXYNOS_GEM_CREATE 0x00 #define DRM_EXYNOS_GEM_MAP 0x01 /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */ @@ -317,6 +357,10 @@ struct drm_exynos_ipp_cmd_ctrl { #define DRM_EXYNOS_IPP_QUEUE_BUF 0x32 #define DRM_EXYNOS_IPP_CMD_CTRL 0x33 +#define DRM_EXYNOS_PP_GET_RESOURCES 0x40 +#define DRM_EXYNOS_PP_GET 0x41 +#define DRM_EXYNOS_PP_COMMIT 0x42 + #define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) #define DRM_IOCTL_EXYNOS_GEM_MAP DRM_IOWR(DRM_COMMAND_BASE + \ @@ -343,9 +387,17 @@ struct drm_exynos_ipp_cmd_ctrl { #define DRM_IOCTL_EXYNOS_IPP_CMD_CTRL DRM_IOWR(DRM_COMMAND_BASE + \ DRM_EXYNOS_IPP_CMD_CTRL, struct drm_exynos_ipp_cmd_ctrl) +#define DRM_IOCTL_EXYNOS_PP_GET_RESOURCES DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_PP_GET_RESOURCES, struct drm_exynos_pp_get_res) +#define DRM_IOCTL_EXYNOS_PP_GET DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_PP_GET, struct drm_exynos_pp_get) +#define DRM_IOCTL_EXYNOS_PP_COMMIT DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_PP_COMMIT, struct drm_exynos_pp_commit) + /* EXYNOS specific events */ #define DRM_EXYNOS_G2D_EVENT 0x80000000 #define DRM_EXYNOS_IPP_EVENT 0x80000001 +#define DRM_EXYNOS_PP_EVENT 0x80000002 struct drm_exynos_g2d_event { struct drm_event base; @@ -366,6 +418,16 @@ struct drm_exynos_ipp_event { __u32 buf_id[EXYNOS_DRM_OPS_MAX]; }; +struct drm_exynos_pp_event { + struct drm_event base; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; + __u32 pp_id; + __u32 sequence; + __u64 reserved; +}; + #if defined(__cplusplus) } #endif