From patchwork Wed Nov 8 09:41:40 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 118222 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5063125qgn; Wed, 8 Nov 2017 01:42:01 -0800 (PST) X-Google-Smtp-Source: ABhQp+TZhzIQA6VfMRB1+xYpffsShJHIIUpmi5ZqUQBGgFLGs3p7M6cC82CcUUQ4jQ5DzO1/dRPt X-Received: by 10.84.171.195 with SMTP id l61mr1650129plb.27.1510134121551; Wed, 08 Nov 2017 01:42:01 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1510134121; cv=none; d=google.com; s=arc-20160816; b=sgTJeFKkG/t/2VJIVdyQ9gfO8gLrvpE1iAbG1qg8w6W+7O3uk4TBreixKZPWGtHXpk NzR+09VAL3a5d+nxxkfsYknwBjNYuKh9SC8/+ozAAOVHih8HaRm/r/TCgc888HbDwzF2 Y2RWYa4Yioyu4saffyfNo9ORxo0Mv8tAmMKalKYhbwB4MGUxk3ap5h/Wkb7KUEYnjzmv fmm8+y4P41C8SrO+dbktwmrwzJCfzjN45XgKBDEwjftEj9GbTuyG3YkjsdVLxC9xSbHP N4KdUXR2VqjW8Rqllsb09LmB1xpLlBRfhce/Vffy8dEd35RtmQqktfkIn7qU0Od5Xv6b P/dQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:cc:references:cms-type:in-reply-to:message-id :date:subject:to:from:dkim-signature:dkim-filter:delivered-to :arc-authentication-results; bh=CPU2UdZKPTyDRFS1gB6EUoX88pbrsc0Eef4wKvlittw=; b=YmevKFPMFOzpHrf/tYKmfTs7bAmyv7HqztCkX06D3JyEV1qAUBrRNEbftQQ89W8wT5 7PYoppRhC425UbuV2SbQDFI0yzQlWoIgOydktGZsFMd6fw1L12kMJxLJHRdmKX96D/f8 yEzqxrQp0C1vltUcJrwjLM+X/DSRO8z8MlDuiGdGm6mR9pQVxeWimqh2ZYElG55Rv8qH ach5FvcnNFOc4imobXnYQB2TL1NFp7Kez7v95Vq/FE7N5RWAe3oOp3mapo1w4aEiQQTJ CNvrr7OBw/DEDlTLTdpKSuCI6JMlVb7cy0ZdT/DZBi1rP7vVX/AI8rz114rLgBz1z1qJ O0GA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@samsung.com header.s=mail20170921 header.b=ICdHTWNL; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=samsung.com Return-Path: Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTPS id l62si3260630pgd.402.2017.11.08.01.42.00 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 08 Nov 2017 01:42:01 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) client-ip=131.252.210.177; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@samsung.com header.s=mail20170921 header.b=ICdHTWNL; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=samsung.com Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 374536E620; Wed, 8 Nov 2017 09:41:59 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mailout2.w1.samsung.com (mailout2.w1.samsung.com [210.118.77.12]) by gabe.freedesktop.org (Postfix) with ESMTPS id DC9FF6E622 for ; Wed, 8 Nov 2017 09:41:57 +0000 (UTC) Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout2.w1.samsung.com (KnoxPortal) with ESMTP id 20171108094155euoutp02d4fd2ce1d711f74d804d1fdb076e60f5~1Evoul7nS1873818738euoutp02i; Wed, 8 Nov 2017 09:41:55 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.w1.samsung.com 20171108094155euoutp02d4fd2ce1d711f74d804d1fdb076e60f5~1Evoul7nS1873818738euoutp02i DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1510134115; bh=9C7j5ncgfFao3AQ94QPOQ0JslvyoWg34Lm49ZOZJCio=; h=From:To:Cc:Subject:Date:In-reply-to:References:From; b=ICdHTWNLz48ABsMlS1/fhWqzzvvHK+xaAilYu+hWWYtbYr0412/TGXiEfyv2P21RM 0/Jlp0yr+uDjpDvgVnVh9oabyJIOVTwEdUb8LYjKtRc/nifB7oNyEZX5+fikSfLt/c d8lFc380i+QdQJtXhZvqgrkAIR4jUCD7HytnZqFE= Received: from eusmges4.samsung.com (unknown [203.254.199.244]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20171108094155eucas1p275032153b9b08861777247b1b9153780~1EvoBctcM2464124641eucas1p2I; Wed, 8 Nov 2017 09:41:55 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges4.samsung.com (EUCPMTA) with SMTP id A1.FE.12944.261D20A5; Wed, 8 Nov 2017 09:41:54 +0000 (GMT) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20171108094154eucas1p274a3e58912af703a45340d373d05326e~1EvnXeTZC2463624636eucas1p2_; Wed, 8 Nov 2017 09:41:54 +0000 (GMT) X-AuditID: cbfec7f4-f79ab6d000003290-7a-5a02d16229cf Received: from eusync4.samsung.com ( [203.254.199.214]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id CA.91.18832.261D20A5; Wed, 8 Nov 2017 09:41:54 +0000 (GMT) Received: from AMDC2765.digital.local ([106.116.147.25]) by eusync4.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OZ300D3HEXPW8A0@eusync4.samsung.com>; Wed, 08 Nov 2017 09:41:53 +0000 (GMT) From: Marek Szyprowski To: dri-devel@lists.freedesktop.org, linux-samsung-soc@vger.kernel.org Subject: [PATCH v5 1/8] drm/exynos: ipp: Remove Exynos DRM IPP subsystem Date: Wed, 08 Nov 2017 10:41:40 +0100 Message-id: <20171108094147.25854-2-m.szyprowski@samsung.com> X-Mailer: git-send-email 2.14.2 In-reply-to: <20171108094147.25854-1-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrBIsWRmVeSWpSXmKPExsWy7djPc7pJF5miDObP17W4te4cq8Wsl+0s FhtnrGe1uPL1PZvF++VdbBaT7k9gsTh/fgO7xYzz+5gs1h65y25x+E07q8WMyS/ZLNpWf2B1 4PHYtKqTzeN+93Emj3/H2D36tqxi9Pi8SS6ANYrLJiU1J7MstUjfLoErY0ZDXsGZVpaKLTNe sjUwnljO3MXIySEhYCJxaPFMFghbTOLCvfVsXYxcHEICSxkl1nx/BeV8ZpRY8H8yXMfxOw+Y IRLLGCUWHv3JAuE0MEls/b6LHaSKTcBQouttFxuILSLgJtF0eCYrSBGzwC5miReTX4MVCQt4 SBw7exFsLIuAqkT/wb2sIDavgK3ExRdbGCHWyUu8X3AfzOYUsJOYs6IRbJCEwAY2iQs7TzFB FLlIrF94mR3CFpZ4dXwLlC0j0dlxEKqmn1GiqVUbwp7BKHHuLS+EbS1x+PhFsMXMAnwSk7ZN BzqIAyjOK9HRJgRR4iFxZ+1KNgjbUaLv6gaojycCw2XFJdYJjNILGBlWMYqklhbnpqcWm+gV J+YWl+al6yXn525iBMb36X/Hv+xgXHzM6hCjAAejEg+vhiJTlBBrYllxZe4hRgkOZiUR3nNn gUK8KYmVValF+fFFpTmpxYcYpTlYlMR5baPaIoUE0hNLUrNTUwtSi2CyTBycUg2MrWaGZY2F u2ZE3TxreEz/5+TGenu9WVci938TWjxP/9+hV50NPxatEa68+bQw6NeV8ms1/hbLO/3eLLnY bPvfI+xv3VT2Fu+3t3Z6ZrJum17zh1212iW7xDts+bSGbtuSoNPe7x+9XLOG5Y+koMXq1fvt JpxK+nfdalKHrk7MsdcxB1wF8kTeK7EUZyQaajEXFScCANhfaOnrAgAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrDLMWRmVeSWpSXmKPExsVy+t/xa7pJF5miDJ4+YLK4te4cq8Wsl+0s FhtnrGe1uPL1PZvF++VdbBaT7k9gsTh/fgO7xYzz+5gs1h65y25x+E07q8WMyS/ZLNpWf2B1 4PHYtKqTzeN+93Emj3/H2D36tqxi9Pi8SS6ANYrLJiU1J7MstUjfLoErY0ZDXsGZVpaKLTNe sjUwnljO3MXIySEhYCJx/M4DKFtM4sK99WxdjFwcQgJLGCXWHDkF5TQxSRx41gdWxSZgKNH1 tosNxBYRcJNoOjyTFcRmFtjHLLGxzRvEFhbwkDh29iJYPYuAqkT/wb1gNbwCthIXX2xhhNgm L/F+wX0wm1PATmLOikawGiGgmgVXdjNPYORdwMiwilEktbQ4Nz232FCvODG3uDQvXS85P3cT IzAMtx37uXkH46WNwYcYBTgYlXh4NRSZooRYE8uKK3MPMUpwMCuJ8J47CxTiTUmsrEotyo8v Ks1JLT7EKM3BoiTO27tndaSQQHpiSWp2ampBahFMlomDU6qB0eq17429MRc7l+zwWuxWrson xhV698Ca1y/EJoQt150ncO8xL1+OK8NdCd+FmtfF4mumhx65G+npcHfWJJ4vjft7Dy7ZpJu9 8cFuz/7FQjWmN2Q9t14U1GA3K1p93Xjfsd2V3FkPmRYdC2qYZs8uFrlk25UVj0IP8Hz5d9Ba Z8f3gwmJ9xyvHVZiKc5INNRiLipOBADstQDrPwIAAA== X-CMS-MailID: 20171108094154eucas1p274a3e58912af703a45340d373d05326e X-Msg-Generator: CA CMS-TYPE: 201P X-CMS-RootMailID: 20171108094154eucas1p274a3e58912af703a45340d373d05326e X-RootMTR: 20171108094154eucas1p274a3e58912af703a45340d373d05326e References: <20171108094147.25854-1-m.szyprowski@samsung.com> Cc: Bartlomiej Zolnierkiewicz , Seung-Woo Kim , Krzysztof Kozlowski , Tobias Jakobi , Sylwester Nawrocki , Andrzej Pietrasiewicz , Hoegeun Kwon , Marek Szyprowski X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Exynos IPP will be rewritten, so remove current IPP core code and mark existing drivers as BROKEN. Signed-off-by: Marek Szyprowski --- drivers/gpu/drm/exynos/Kconfig | 11 +- drivers/gpu/drm/exynos/Makefile | 1 - drivers/gpu/drm/exynos/exynos_drm_drv.c | 12 - drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 - drivers/gpu/drm/exynos/exynos_drm_ipp.c | 1806 ------------------------------- drivers/gpu/drm/exynos/exynos_drm_ipp.h | 252 ----- include/uapi/drm/exynos_drm.h | 192 +--- 7 files changed, 4 insertions(+), 2272 deletions(-) delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_ipp.c delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_ipp.h diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 305dc3d4ff77..88cff0e039b6 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -94,26 +94,21 @@ config DRM_EXYNOS_G2D help Choose this option if you want to use Exynos G2D for DRM. -config DRM_EXYNOS_IPP - bool "Image Post Processor" - help - Choose this option if you want to use IPP feature for DRM. - config DRM_EXYNOS_FIMC bool "FIMC" - depends on DRM_EXYNOS_IPP && MFD_SYSCON + depends on BROKEN && MFD_SYSCON help Choose this option if you want to use Exynos FIMC for DRM. config DRM_EXYNOS_ROTATOR bool "Rotator" - depends on DRM_EXYNOS_IPP + depends on BROKEN help Choose this option if you want to use Exynos Rotator for DRM. config DRM_EXYNOS_GSC bool "GScaler" - depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && VIDEO_SAMSUNG_EXYNOS_GSC=n + depends on BROKEN && ARCH_EXYNOS5 && VIDEO_SAMSUNG_EXYNOS_GSC=n help Choose this option if you want to use Exynos GSC for DRM. diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index bdf4212dde7b..a51c5459bb13 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile @@ -18,7 +18,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_MIXER) += exynos_mixer.o 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_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.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index a6ff3a538c8a..04f286d450a4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -28,7 +28,6 @@ #include "exynos_drm_plane.h" #include "exynos_drm_vidi.h" #include "exynos_drm_g2d.h" -#include "exynos_drm_ipp.h" #include "exynos_drm_iommu.h" #define DRIVER_NAME "exynos" @@ -115,14 +114,6 @@ static const struct drm_ioctl_desc exynos_ioctls[] = { DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY, exynos_drm_ipp_get_property, - DRM_AUTH | DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY, exynos_drm_ipp_set_property, - DRM_AUTH | DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF, exynos_drm_ipp_queue_buf, - DRM_AUTH | DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL, exynos_drm_ipp_cmd_ctrl, - DRM_AUTH | DRM_RENDER_ALLOW), }; static const struct file_operations exynos_drm_driver_fops = { @@ -262,9 +253,6 @@ static struct exynos_drm_driver_info exynos_drm_drivers[] = { DRV_PTR(rotator_driver, CONFIG_DRM_EXYNOS_ROTATOR), }, { DRV_PTR(gsc_driver, CONFIG_DRM_EXYNOS_GSC), - }, { - DRV_PTR(ipp_driver, CONFIG_DRM_EXYNOS_IPP), - DRM_VIRTUAL_DEVICE }, { &exynos_drm_platform_driver, DRM_VIRTUAL_DEVICE diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index f8bae4cb4823..b47f810d64d2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -185,7 +185,6 @@ struct exynos_drm_g2d_private { struct drm_exynos_file_private { struct exynos_drm_g2d_private *g2d_priv; - struct device *ipp_dev; }; /* @@ -293,6 +292,5 @@ extern struct platform_driver g2d_driver; extern struct platform_driver fimc_driver; extern struct platform_driver rotator_driver; extern struct platform_driver gsc_driver; -extern struct platform_driver ipp_driver; extern struct platform_driver mic_driver; #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c deleted file mode 100644 index 3edda18cc2d2..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ /dev/null @@ -1,1806 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics Co.Ltd - * Authors: - * Eunchul Kim - * Jinyoung Jeon - * Sangmin Lee - * - * 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 -#include -#include -#include -#include - -#include -#include -#include "exynos_drm_drv.h" -#include "exynos_drm_gem.h" -#include "exynos_drm_ipp.h" -#include "exynos_drm_iommu.h" - -/* - * IPP stands for Image Post Processing and - * supports image scaler/rotator and input/output DMA operations. - * using FIMC, GSC, Rotator, so on. - * IPP is integration device driver of same attribute h/w - */ - -/* - * TODO - * 1. expand command control id. - * 2. integrate property and config. - * 3. removed send_event id check routine. - * 4. compare send_event id if needed. - * 5. free subdrv_remove notifier callback list if needed. - * 6. need to check subdrv_open about multi-open. - * 7. need to power_on implement power and sysmmu ctrl. - */ - -#define get_ipp_context(dev) platform_get_drvdata(to_platform_device(dev)) -#define ipp_is_m2m_cmd(c) (c == IPP_CMD_M2M) - -/* - * A structure of event. - * - * @base: base of event. - * @event: ipp event. - */ -struct drm_exynos_ipp_send_event { - struct drm_pending_event base; - struct drm_exynos_ipp_event event; -}; - -/* - * A structure of memory node. - * - * @list: list head to memory queue information. - * @ops_id: id of operations. - * @prop_id: id of property. - * @buf_id: id of buffer. - * @buf_info: gem objects and dma address, size. - * @filp: a pointer to drm_file. - */ -struct drm_exynos_ipp_mem_node { - struct list_head list; - enum drm_exynos_ops_id ops_id; - u32 prop_id; - u32 buf_id; - struct drm_exynos_ipp_buf_info buf_info; -}; - -/* - * A structure of ipp context. - * - * @subdrv: prepare initialization using subdrv. - * @ipp_lock: lock for synchronization of access to ipp_idr. - * @prop_lock: lock for synchronization of access to prop_idr. - * @ipp_idr: ipp driver idr. - * @prop_idr: property idr. - * @event_workq: event work queue. - * @cmd_workq: command work queue. - */ -struct ipp_context { - struct exynos_drm_subdrv subdrv; - struct mutex ipp_lock; - struct mutex prop_lock; - struct idr ipp_idr; - struct idr prop_idr; - struct workqueue_struct *event_workq; - struct workqueue_struct *cmd_workq; -}; - -static LIST_HEAD(exynos_drm_ippdrv_list); -static DEFINE_MUTEX(exynos_drm_ippdrv_lock); -static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list); - -int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) -{ - mutex_lock(&exynos_drm_ippdrv_lock); - list_add_tail(&ippdrv->drv_list, &exynos_drm_ippdrv_list); - mutex_unlock(&exynos_drm_ippdrv_lock); - - return 0; -} - -int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv) -{ - mutex_lock(&exynos_drm_ippdrv_lock); - list_del(&ippdrv->drv_list); - mutex_unlock(&exynos_drm_ippdrv_lock); - - return 0; -} - -static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj) -{ - int ret; - - mutex_lock(lock); - ret = idr_alloc(id_idr, obj, 1, 0, GFP_KERNEL); - mutex_unlock(lock); - - return ret; -} - -static void ipp_remove_id(struct idr *id_idr, struct mutex *lock, u32 id) -{ - mutex_lock(lock); - idr_remove(id_idr, id); - mutex_unlock(lock); -} - -static void *ipp_find_obj(struct idr *id_idr, struct mutex *lock, u32 id) -{ - void *obj; - - mutex_lock(lock); - obj = idr_find(id_idr, id); - mutex_unlock(lock); - - return obj; -} - -static int ipp_check_driver(struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_property *property) -{ - if (ippdrv->dedicated || (!ipp_is_m2m_cmd(property->cmd) && - !pm_runtime_suspended(ippdrv->dev))) - return -EBUSY; - - if (ippdrv->check_property && - ippdrv->check_property(ippdrv->dev, property)) - return -EINVAL; - - return 0; -} - -static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx, - struct drm_exynos_ipp_property *property) -{ - struct exynos_drm_ippdrv *ippdrv; - u32 ipp_id = property->ipp_id; - int ret; - - if (ipp_id) { - ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, ipp_id); - if (!ippdrv) { - DRM_DEBUG("ipp%d driver not found\n", ipp_id); - return ERR_PTR(-ENODEV); - } - - ret = ipp_check_driver(ippdrv, property); - if (ret < 0) { - DRM_DEBUG("ipp%d driver check error %d\n", ipp_id, ret); - return ERR_PTR(ret); - } - - return ippdrv; - } else { - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { - ret = ipp_check_driver(ippdrv, property); - if (ret == 0) - return ippdrv; - } - - DRM_DEBUG("cannot find driver suitable for given property.\n"); - } - - return ERR_PTR(-ENODEV); -} - -static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id) -{ - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_cmd_node *c_node; - int count = 0; - - DRM_DEBUG_KMS("prop_id[%d]\n", prop_id); - - /* - * This case is search ipp driver by prop_id handle. - * sometimes, ipp subsystem find driver by prop_id. - * e.g PAUSE state, queue buf, command control. - */ - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { - DRM_DEBUG_KMS("count[%d]ippdrv[%pK]\n", count++, ippdrv); - - mutex_lock(&ippdrv->cmd_lock); - list_for_each_entry(c_node, &ippdrv->cmd_list, list) { - if (c_node->property.prop_id == prop_id) { - mutex_unlock(&ippdrv->cmd_lock); - return ippdrv; - } - } - mutex_unlock(&ippdrv->cmd_lock); - } - - return ERR_PTR(-ENODEV); -} - -int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, - struct drm_file *file) -{ - struct drm_exynos_file_private *file_priv = file->driver_priv; - struct device *dev = file_priv->ipp_dev; - struct ipp_context *ctx = get_ipp_context(dev); - struct drm_exynos_ipp_prop_list *prop_list = data; - struct exynos_drm_ippdrv *ippdrv; - int count = 0; - - if (!ctx) { - DRM_ERROR("invalid context.\n"); - return -EINVAL; - } - - if (!prop_list) { - DRM_ERROR("invalid property parameter.\n"); - return -EINVAL; - } - - DRM_DEBUG_KMS("ipp_id[%d]\n", prop_list->ipp_id); - - if (!prop_list->ipp_id) { - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) - count++; - - /* - * Supports ippdrv list count for user application. - * First step user application getting ippdrv count. - * and second step getting ippdrv capability using ipp_id. - */ - prop_list->count = count; - } else { - /* - * Getting ippdrv capability by ipp_id. - * some device not supported wb, output interface. - * so, user application detect correct ipp driver - * using this ioctl. - */ - ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, - prop_list->ipp_id); - if (!ippdrv) { - DRM_ERROR("not found ipp%d driver.\n", - prop_list->ipp_id); - return -ENODEV; - } - - *prop_list = ippdrv->prop_list; - } - - return 0; -} - -static void ipp_print_property(struct drm_exynos_ipp_property *property, - int idx) -{ - struct drm_exynos_ipp_config *config = &property->config[idx]; - struct drm_exynos_pos *pos = &config->pos; - struct drm_exynos_sz *sz = &config->sz; - - DRM_DEBUG_KMS("prop_id[%d]ops[%s]fmt[0x%x]\n", - property->prop_id, idx ? "dst" : "src", config->fmt); - - DRM_DEBUG_KMS("pos[%d %d %d %d]sz[%d %d]f[%d]r[%d]\n", - pos->x, pos->y, pos->w, pos->h, - sz->hsize, sz->vsize, config->flip, config->degree); -} - -static struct drm_exynos_ipp_cmd_work *ipp_create_cmd_work(void) -{ - struct drm_exynos_ipp_cmd_work *cmd_work; - - cmd_work = kzalloc(sizeof(*cmd_work), GFP_KERNEL); - if (!cmd_work) - return ERR_PTR(-ENOMEM); - - INIT_WORK((struct work_struct *)cmd_work, ipp_sched_cmd); - - return cmd_work; -} - -static struct drm_exynos_ipp_event_work *ipp_create_event_work(void) -{ - struct drm_exynos_ipp_event_work *event_work; - - event_work = kzalloc(sizeof(*event_work), GFP_KERNEL); - if (!event_work) - return ERR_PTR(-ENOMEM); - - INIT_WORK(&event_work->work, ipp_sched_event); - - return event_work; -} - -int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, - struct drm_file *file) -{ - struct drm_exynos_file_private *file_priv = file->driver_priv; - struct device *dev = file_priv->ipp_dev; - struct ipp_context *ctx = get_ipp_context(dev); - struct drm_exynos_ipp_property *property = data; - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_cmd_node *c_node; - u32 prop_id; - int ret, i; - - if (!ctx) { - DRM_ERROR("invalid context.\n"); - return -EINVAL; - } - - if (!property) { - DRM_ERROR("invalid property parameter.\n"); - return -EINVAL; - } - - prop_id = property->prop_id; - - /* - * This is log print for user application property. - * user application set various property. - */ - for_each_ipp_ops(i) - ipp_print_property(property, i); - - /* - * In case prop_id is not zero try to set existing property. - */ - if (prop_id) { - c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, prop_id); - - if (!c_node || c_node->filp != file) { - DRM_DEBUG_KMS("prop_id[%d] not found\n", prop_id); - return -EINVAL; - } - - if (c_node->state != IPP_STATE_STOP) { - DRM_DEBUG_KMS("prop_id[%d] not stopped\n", prop_id); - return -EINVAL; - } - - c_node->property = *property; - - return 0; - } - - /* find ipp driver using ipp id */ - ippdrv = ipp_find_driver(ctx, property); - if (IS_ERR(ippdrv)) { - DRM_ERROR("failed to get ipp driver.\n"); - return -EINVAL; - } - - /* allocate command node */ - c_node = kzalloc(sizeof(*c_node), GFP_KERNEL); - if (!c_node) - return -ENOMEM; - - ret = ipp_create_id(&ctx->prop_idr, &ctx->prop_lock, c_node); - if (ret < 0) { - DRM_ERROR("failed to create id.\n"); - goto err_clear; - } - property->prop_id = ret; - - DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[%pK]\n", - property->prop_id, property->cmd, ippdrv); - - /* stored property information and ippdrv in private data */ - c_node->property = *property; - c_node->state = IPP_STATE_IDLE; - c_node->filp = file; - - c_node->start_work = ipp_create_cmd_work(); - if (IS_ERR(c_node->start_work)) { - DRM_ERROR("failed to create start work.\n"); - ret = PTR_ERR(c_node->start_work); - goto err_remove_id; - } - - c_node->stop_work = ipp_create_cmd_work(); - if (IS_ERR(c_node->stop_work)) { - DRM_ERROR("failed to create stop work.\n"); - ret = PTR_ERR(c_node->stop_work); - goto err_free_start; - } - - c_node->event_work = ipp_create_event_work(); - if (IS_ERR(c_node->event_work)) { - DRM_ERROR("failed to create event work.\n"); - ret = PTR_ERR(c_node->event_work); - goto err_free_stop; - } - - mutex_init(&c_node->lock); - mutex_init(&c_node->mem_lock); - mutex_init(&c_node->event_lock); - - init_completion(&c_node->start_complete); - init_completion(&c_node->stop_complete); - - for_each_ipp_ops(i) - INIT_LIST_HEAD(&c_node->mem_list[i]); - - INIT_LIST_HEAD(&c_node->event_list); - mutex_lock(&ippdrv->cmd_lock); - list_add_tail(&c_node->list, &ippdrv->cmd_list); - mutex_unlock(&ippdrv->cmd_lock); - - /* make dedicated state without m2m */ - if (!ipp_is_m2m_cmd(property->cmd)) - ippdrv->dedicated = true; - - return 0; - -err_free_stop: - kfree(c_node->stop_work); -err_free_start: - kfree(c_node->start_work); -err_remove_id: - ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, property->prop_id); -err_clear: - kfree(c_node); - return ret; -} - -static int ipp_validate_mem_node(struct drm_device *drm_dev, - struct drm_exynos_ipp_mem_node *m_node, - struct drm_exynos_ipp_cmd_node *c_node) -{ - struct drm_exynos_ipp_config *ipp_cfg; - unsigned int num_plane; - unsigned long size, buf_size = 0, plane_size, img_size = 0; - unsigned int bpp, width, height; - int i; - - ipp_cfg = &c_node->property.config[m_node->ops_id]; - num_plane = drm_format_num_planes(ipp_cfg->fmt); - - /** - * This is a rather simplified validation of a memory node. - * It basically verifies provided gem object handles - * and the buffer sizes with respect to current configuration. - * This is not the best that can be done - * but it seems more than enough - */ - for (i = 0; i < num_plane; ++i) { - width = ipp_cfg->sz.hsize; - height = ipp_cfg->sz.vsize; - bpp = drm_format_plane_cpp(ipp_cfg->fmt, i); - - /* - * The result of drm_format_plane_cpp() for chroma planes must - * be used with drm_format_xxxx_chroma_subsampling() for - * correct result. - */ - if (i > 0) { - width /= drm_format_horz_chroma_subsampling( - ipp_cfg->fmt); - height /= drm_format_vert_chroma_subsampling( - ipp_cfg->fmt); - } - plane_size = width * height * bpp; - img_size += plane_size; - - if (m_node->buf_info.handles[i]) { - size = exynos_drm_gem_get_size(drm_dev, - m_node->buf_info.handles[i], - c_node->filp); - if (plane_size > size) { - DRM_ERROR( - "buffer %d is smaller than required\n", - i); - return -EINVAL; - } - - buf_size += size; - } - } - - if (buf_size < img_size) { - DRM_ERROR("size of buffers(%lu) is smaller than image(%lu)\n", - buf_size, img_size); - return -EINVAL; - } - - return 0; -} - -static int ipp_put_mem_node(struct drm_device *drm_dev, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_mem_node *m_node) -{ - int i; - - DRM_DEBUG_KMS("node[%pK]\n", m_node); - - if (!m_node) { - DRM_ERROR("invalid dequeue node.\n"); - return -EFAULT; - } - - DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id); - - /* put gem buffer */ - for_each_ipp_planar(i) { - unsigned long handle = m_node->buf_info.handles[i]; - if (handle) - exynos_drm_gem_put_dma_addr(drm_dev, handle, - c_node->filp); - } - - list_del(&m_node->list); - kfree(m_node); - - return 0; -} - -static struct drm_exynos_ipp_mem_node - *ipp_get_mem_node(struct drm_device *drm_dev, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - 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; - - /* operations, buffer id */ - m_node->ops_id = qbuf->ops_id; - m_node->prop_id = qbuf->prop_id; - m_node->buf_id = qbuf->buf_id; - INIT_LIST_HEAD(&m_node->list); - - DRM_DEBUG_KMS("m_node[%pK]ops_id[%d]\n", m_node, qbuf->ops_id); - DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]\n", qbuf->prop_id, m_node->buf_id); - - for_each_ipp_planar(i) { - DRM_DEBUG_KMS("i[%d]handle[0x%x]\n", i, qbuf->handle[i]); - - /* get dma address by handle */ - if (qbuf->handle[i]) { - dma_addr_t *addr; - - addr = exynos_drm_gem_get_dma_addr(drm_dev, - qbuf->handle[i], c_node->filp); - if (IS_ERR(addr)) { - DRM_ERROR("failed to get addr.\n"); - ipp_put_mem_node(drm_dev, c_node, m_node); - return ERR_PTR(-EFAULT); - } - - buf_info->handles[i] = qbuf->handle[i]; - buf_info->base[i] = *addr; - DRM_DEBUG_KMS("i[%d]base[%pad]hd[0x%lx]\n", i, - &buf_info->base[i], buf_info->handles[i]); - } - } - - mutex_lock(&c_node->mem_lock); - if (ipp_validate_mem_node(drm_dev, m_node, c_node)) { - ipp_put_mem_node(drm_dev, c_node, m_node); - mutex_unlock(&c_node->mem_lock); - return ERR_PTR(-EFAULT); - } - list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]); - mutex_unlock(&c_node->mem_lock); - - return m_node; -} - -static void ipp_clean_mem_nodes(struct drm_device *drm_dev, - struct drm_exynos_ipp_cmd_node *c_node, int ops) -{ - struct drm_exynos_ipp_mem_node *m_node, *tm_node; - struct list_head *head = &c_node->mem_list[ops]; - - mutex_lock(&c_node->mem_lock); - - list_for_each_entry_safe(m_node, tm_node, head, list) { - int ret; - - ret = ipp_put_mem_node(drm_dev, c_node, m_node); - if (ret) - DRM_ERROR("failed to put m_node.\n"); - } - - mutex_unlock(&c_node->mem_lock); -} - -static int ipp_get_event(struct drm_device *drm_dev, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct drm_exynos_ipp_send_event *e; - int ret; - - DRM_DEBUG_KMS("ops_id[%d]buf_id[%d]\n", qbuf->ops_id, qbuf->buf_id); - - e = kzalloc(sizeof(*e), GFP_KERNEL); - if (!e) - return -ENOMEM; - - /* make event */ - e->event.base.type = DRM_EXYNOS_IPP_EVENT; - e->event.base.length = sizeof(e->event); - e->event.user_data = qbuf->user_data; - e->event.prop_id = qbuf->prop_id; - e->event.buf_id[EXYNOS_DRM_OPS_DST] = qbuf->buf_id; - - ret = drm_event_reserve_init(drm_dev, c_node->filp, &e->base, &e->event.base); - if (ret) { - kfree(e); - return ret; - } - - mutex_lock(&c_node->event_lock); - list_add_tail(&e->base.link, &c_node->event_list); - mutex_unlock(&c_node->event_lock); - - return 0; -} - -static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct drm_exynos_ipp_send_event *e, *te; - int count = 0; - - mutex_lock(&c_node->event_lock); - list_for_each_entry_safe(e, te, &c_node->event_list, base.link) { - DRM_DEBUG_KMS("count[%d]e[%pK]\n", count++, e); - - /* - * qbuf == NULL condition means all event deletion. - * stop operations want to delete all event list. - * another case delete only same buf id. - */ - if (!qbuf) { - /* delete list */ - list_del(&e->base.link); - kfree(e); - } - - /* compare buffer id */ - if (qbuf && (qbuf->buf_id == - e->event.buf_id[EXYNOS_DRM_OPS_DST])) { - /* delete list */ - list_del(&e->base.link); - kfree(e); - goto out_unlock; - } - } - -out_unlock: - mutex_unlock(&c_node->event_lock); - return; -} - -static void ipp_clean_cmd_node(struct ipp_context *ctx, - struct drm_exynos_ipp_cmd_node *c_node) -{ - int i; - - /* cancel works */ - cancel_work_sync(&c_node->start_work->work); - cancel_work_sync(&c_node->stop_work->work); - cancel_work_sync(&c_node->event_work->work); - - /* put event */ - ipp_put_event(c_node, NULL); - - for_each_ipp_ops(i) - ipp_clean_mem_nodes(ctx->subdrv.drm_dev, c_node, i); - - /* delete list */ - list_del(&c_node->list); - - ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, - c_node->property.prop_id); - - /* destroy mutex */ - mutex_destroy(&c_node->lock); - mutex_destroy(&c_node->mem_lock); - mutex_destroy(&c_node->event_lock); - - /* free command node */ - kfree(c_node->start_work); - kfree(c_node->stop_work); - kfree(c_node->event_work); - kfree(c_node); -} - -static bool ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node) -{ - switch (c_node->property.cmd) { - case IPP_CMD_WB: - return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]); - case IPP_CMD_OUTPUT: - return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]); - case IPP_CMD_M2M: - default: - return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]) && - !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]); - } -} - -static struct drm_exynos_ipp_mem_node - *ipp_find_mem_node(struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct drm_exynos_ipp_mem_node *m_node; - struct list_head *head; - int count = 0; - - DRM_DEBUG_KMS("buf_id[%d]\n", qbuf->buf_id); - - /* source/destination memory list */ - head = &c_node->mem_list[qbuf->ops_id]; - - /* find memory node from memory list */ - list_for_each_entry(m_node, head, list) { - DRM_DEBUG_KMS("count[%d]m_node[%pK]\n", count++, m_node); - - /* compare buffer id */ - if (m_node->buf_id == qbuf->buf_id) - return m_node; - } - - return NULL; -} - -static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_mem_node *m_node) -{ - struct exynos_drm_ipp_ops *ops = NULL; - int ret = 0; - - DRM_DEBUG_KMS("node[%pK]\n", m_node); - - if (!m_node) { - DRM_ERROR("invalid queue node.\n"); - return -EFAULT; - } - - DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id); - - /* get operations callback */ - ops = ippdrv->ops[m_node->ops_id]; - if (!ops) { - DRM_ERROR("not support ops.\n"); - return -EFAULT; - } - - /* set address and enable irq */ - if (ops->set_addr) { - ret = ops->set_addr(ippdrv->dev, &m_node->buf_info, - m_node->buf_id, IPP_BUF_ENQUEUE); - if (ret) { - DRM_ERROR("failed to set addr.\n"); - return ret; - } - } - - return ret; -} - -static void ipp_handle_cmd_work(struct device *dev, - struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_cmd_work *cmd_work, - struct drm_exynos_ipp_cmd_node *c_node) -{ - struct ipp_context *ctx = get_ipp_context(dev); - - cmd_work->ippdrv = ippdrv; - cmd_work->c_node = c_node; - queue_work(ctx->cmd_workq, &cmd_work->work); -} - -static int ipp_queue_buf_with_run(struct device *dev, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_mem_node *m_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_property *property; - struct exynos_drm_ipp_ops *ops; - int ret; - - ippdrv = ipp_find_drv_by_handle(qbuf->prop_id); - if (IS_ERR(ippdrv)) { - DRM_ERROR("failed to get ipp driver.\n"); - return -EFAULT; - } - - ops = ippdrv->ops[qbuf->ops_id]; - if (!ops) { - DRM_ERROR("failed to get ops.\n"); - return -EFAULT; - } - - property = &c_node->property; - - if (c_node->state != IPP_STATE_START) { - DRM_DEBUG_KMS("bypass for invalid state.\n"); - return 0; - } - - mutex_lock(&c_node->mem_lock); - if (!ipp_check_mem_list(c_node)) { - mutex_unlock(&c_node->mem_lock); - DRM_DEBUG_KMS("empty memory.\n"); - return 0; - } - - /* - * If set destination buffer and enabled clock, - * then m2m operations need start operations at queue_buf - */ - if (ipp_is_m2m_cmd(property->cmd)) { - struct drm_exynos_ipp_cmd_work *cmd_work = c_node->start_work; - - cmd_work->ctrl = IPP_CTRL_PLAY; - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); - } else { - ret = ipp_set_mem_node(ippdrv, c_node, m_node); - if (ret) { - mutex_unlock(&c_node->mem_lock); - DRM_ERROR("failed to set m node.\n"); - return ret; - } - } - mutex_unlock(&c_node->mem_lock); - - return 0; -} - -static void ipp_clean_queue_buf(struct drm_device *drm_dev, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct drm_exynos_ipp_mem_node *m_node, *tm_node; - - /* delete list */ - mutex_lock(&c_node->mem_lock); - list_for_each_entry_safe(m_node, tm_node, - &c_node->mem_list[qbuf->ops_id], list) { - if (m_node->buf_id == qbuf->buf_id && - m_node->ops_id == qbuf->ops_id) - ipp_put_mem_node(drm_dev, c_node, m_node); - } - mutex_unlock(&c_node->mem_lock); -} - -int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, - struct drm_file *file) -{ - struct drm_exynos_file_private *file_priv = file->driver_priv; - struct device *dev = file_priv->ipp_dev; - struct ipp_context *ctx = get_ipp_context(dev); - struct drm_exynos_ipp_queue_buf *qbuf = data; - struct drm_exynos_ipp_cmd_node *c_node; - struct drm_exynos_ipp_mem_node *m_node; - int ret; - - if (!qbuf) { - DRM_ERROR("invalid buf parameter.\n"); - return -EINVAL; - } - - if (qbuf->ops_id >= EXYNOS_DRM_OPS_MAX) { - DRM_ERROR("invalid ops parameter.\n"); - return -EINVAL; - } - - DRM_DEBUG_KMS("prop_id[%d]ops_id[%s]buf_id[%d]buf_type[%d]\n", - qbuf->prop_id, qbuf->ops_id ? "dst" : "src", - qbuf->buf_id, qbuf->buf_type); - - /* find command node */ - c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, - qbuf->prop_id); - if (!c_node || c_node->filp != file) { - DRM_ERROR("failed to get command node.\n"); - return -ENODEV; - } - - /* buffer control */ - switch (qbuf->buf_type) { - case IPP_BUF_ENQUEUE: - /* get memory node */ - m_node = ipp_get_mem_node(drm_dev, c_node, qbuf); - if (IS_ERR(m_node)) { - DRM_ERROR("failed to get m_node.\n"); - return PTR_ERR(m_node); - } - - /* - * first step get event for destination buffer. - * and second step when M2M case run with destination buffer - * if needed. - */ - if (qbuf->ops_id == EXYNOS_DRM_OPS_DST) { - /* get event for destination buffer */ - ret = ipp_get_event(drm_dev, c_node, qbuf); - if (ret) { - DRM_ERROR("failed to get event.\n"); - goto err_clean_node; - } - - /* - * M2M case run play control for streaming feature. - * other case set address and waiting. - */ - ret = ipp_queue_buf_with_run(dev, c_node, m_node, qbuf); - if (ret) { - DRM_ERROR("failed to run command.\n"); - goto err_clean_node; - } - } - break; - case IPP_BUF_DEQUEUE: - mutex_lock(&c_node->lock); - - /* put event for destination buffer */ - if (qbuf->ops_id == EXYNOS_DRM_OPS_DST) - ipp_put_event(c_node, qbuf); - - ipp_clean_queue_buf(drm_dev, c_node, qbuf); - - mutex_unlock(&c_node->lock); - break; - default: - DRM_ERROR("invalid buffer control.\n"); - return -EINVAL; - } - - return 0; - -err_clean_node: - DRM_ERROR("clean memory nodes.\n"); - - ipp_clean_queue_buf(drm_dev, c_node, qbuf); - return ret; -} - -static bool exynos_drm_ipp_check_valid(struct device *dev, - enum drm_exynos_ipp_ctrl ctrl, enum drm_exynos_ipp_state state) -{ - if (ctrl != IPP_CTRL_PLAY) { - if (pm_runtime_suspended(dev)) { - DRM_ERROR("pm:runtime_suspended.\n"); - goto err_status; - } - } - - switch (ctrl) { - case IPP_CTRL_PLAY: - if (state != IPP_STATE_IDLE) - goto err_status; - break; - case IPP_CTRL_STOP: - if (state == IPP_STATE_STOP) - goto err_status; - break; - case IPP_CTRL_PAUSE: - if (state != IPP_STATE_START) - goto err_status; - break; - case IPP_CTRL_RESUME: - if (state != IPP_STATE_STOP) - goto err_status; - break; - default: - DRM_ERROR("invalid state.\n"); - goto err_status; - } - - return true; - -err_status: - DRM_ERROR("invalid status:ctrl[%d]state[%d]\n", ctrl, state); - return false; -} - -int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, - struct drm_file *file) -{ - struct drm_exynos_file_private *file_priv = file->driver_priv; - struct exynos_drm_ippdrv *ippdrv = NULL; - struct device *dev = file_priv->ipp_dev; - struct ipp_context *ctx = get_ipp_context(dev); - struct drm_exynos_ipp_cmd_ctrl *cmd_ctrl = data; - struct drm_exynos_ipp_cmd_work *cmd_work; - struct drm_exynos_ipp_cmd_node *c_node; - - if (!ctx) { - DRM_ERROR("invalid context.\n"); - return -EINVAL; - } - - if (!cmd_ctrl) { - DRM_ERROR("invalid control parameter.\n"); - return -EINVAL; - } - - DRM_DEBUG_KMS("ctrl[%d]prop_id[%d]\n", - cmd_ctrl->ctrl, cmd_ctrl->prop_id); - - ippdrv = ipp_find_drv_by_handle(cmd_ctrl->prop_id); - if (IS_ERR(ippdrv)) { - DRM_ERROR("failed to get ipp driver.\n"); - return PTR_ERR(ippdrv); - } - - c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, - cmd_ctrl->prop_id); - if (!c_node || c_node->filp != file) { - DRM_ERROR("invalid command node list.\n"); - return -ENODEV; - } - - if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl, - c_node->state)) { - DRM_ERROR("invalid state.\n"); - return -EINVAL; - } - - switch (cmd_ctrl->ctrl) { - case IPP_CTRL_PLAY: - if (pm_runtime_suspended(ippdrv->dev)) - pm_runtime_get_sync(ippdrv->dev); - - c_node->state = IPP_STATE_START; - - cmd_work = c_node->start_work; - cmd_work->ctrl = cmd_ctrl->ctrl; - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); - break; - case IPP_CTRL_STOP: - cmd_work = c_node->stop_work; - cmd_work->ctrl = cmd_ctrl->ctrl; - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); - - if (!wait_for_completion_timeout(&c_node->stop_complete, - msecs_to_jiffies(300))) { - DRM_ERROR("timeout stop:prop_id[%d]\n", - c_node->property.prop_id); - } - - c_node->state = IPP_STATE_STOP; - ippdrv->dedicated = false; - mutex_lock(&ippdrv->cmd_lock); - ipp_clean_cmd_node(ctx, c_node); - - if (list_empty(&ippdrv->cmd_list)) - pm_runtime_put_sync(ippdrv->dev); - mutex_unlock(&ippdrv->cmd_lock); - break; - case IPP_CTRL_PAUSE: - cmd_work = c_node->stop_work; - cmd_work->ctrl = cmd_ctrl->ctrl; - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); - - if (!wait_for_completion_timeout(&c_node->stop_complete, - msecs_to_jiffies(200))) { - DRM_ERROR("timeout stop:prop_id[%d]\n", - c_node->property.prop_id); - } - - c_node->state = IPP_STATE_STOP; - break; - case IPP_CTRL_RESUME: - c_node->state = IPP_STATE_START; - cmd_work = c_node->start_work; - cmd_work->ctrl = cmd_ctrl->ctrl; - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); - break; - default: - DRM_ERROR("could not support this state currently.\n"); - return -EINVAL; - } - - DRM_DEBUG_KMS("done ctrl[%d]prop_id[%d]\n", - cmd_ctrl->ctrl, cmd_ctrl->prop_id); - - return 0; -} - -int exynos_drm_ippnb_register(struct notifier_block *nb) -{ - return blocking_notifier_chain_register( - &exynos_drm_ippnb_list, nb); -} - -int exynos_drm_ippnb_unregister(struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister( - &exynos_drm_ippnb_list, nb); -} - -int exynos_drm_ippnb_send_event(unsigned long val, void *v) -{ - return blocking_notifier_call_chain( - &exynos_drm_ippnb_list, val, v); -} - -static int ipp_set_property(struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_property *property) -{ - struct exynos_drm_ipp_ops *ops = NULL; - bool swap = false; - int ret, i; - - if (!property) { - DRM_ERROR("invalid property parameter.\n"); - return -EINVAL; - } - - DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id); - - /* reset h/w block */ - if (ippdrv->reset && - ippdrv->reset(ippdrv->dev)) { - return -EINVAL; - } - - /* set source,destination operations */ - for_each_ipp_ops(i) { - struct drm_exynos_ipp_config *config = - &property->config[i]; - - ops = ippdrv->ops[i]; - if (!ops || !config) { - DRM_ERROR("not support ops and config.\n"); - return -EINVAL; - } - - /* set format */ - if (ops->set_fmt) { - ret = ops->set_fmt(ippdrv->dev, config->fmt); - if (ret) - return ret; - } - - /* set transform for rotation, flip */ - if (ops->set_transf) { - ret = ops->set_transf(ippdrv->dev, config->degree, - config->flip, &swap); - if (ret) - return ret; - } - - /* set size */ - if (ops->set_size) { - ret = ops->set_size(ippdrv->dev, swap, &config->pos, - &config->sz); - if (ret) - return ret; - } - } - - return 0; -} - -static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_cmd_node *c_node) -{ - struct drm_exynos_ipp_mem_node *m_node; - struct drm_exynos_ipp_property *property = &c_node->property; - struct list_head *head; - int ret, i; - - DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id); - - /* store command info in ippdrv */ - ippdrv->c_node = c_node; - - mutex_lock(&c_node->mem_lock); - if (!ipp_check_mem_list(c_node)) { - DRM_DEBUG_KMS("empty memory.\n"); - ret = -ENOMEM; - goto err_unlock; - } - - /* set current property in ippdrv */ - ret = ipp_set_property(ippdrv, property); - if (ret) { - DRM_ERROR("failed to set property.\n"); - ippdrv->c_node = NULL; - goto err_unlock; - } - - /* check command */ - switch (property->cmd) { - case IPP_CMD_M2M: - for_each_ipp_ops(i) { - /* source/destination memory list */ - head = &c_node->mem_list[i]; - - m_node = list_first_entry(head, - struct drm_exynos_ipp_mem_node, list); - - DRM_DEBUG_KMS("m_node[%pK]\n", m_node); - - ret = ipp_set_mem_node(ippdrv, c_node, m_node); - if (ret) { - DRM_ERROR("failed to set m node.\n"); - goto err_unlock; - } - } - break; - case IPP_CMD_WB: - /* destination memory list */ - head = &c_node->mem_list[EXYNOS_DRM_OPS_DST]; - - list_for_each_entry(m_node, head, list) { - ret = ipp_set_mem_node(ippdrv, c_node, m_node); - if (ret) { - DRM_ERROR("failed to set m node.\n"); - goto err_unlock; - } - } - break; - case IPP_CMD_OUTPUT: - /* source memory list */ - head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC]; - - list_for_each_entry(m_node, head, list) { - ret = ipp_set_mem_node(ippdrv, c_node, m_node); - if (ret) { - DRM_ERROR("failed to set m node.\n"); - goto err_unlock; - } - } - break; - default: - DRM_ERROR("invalid operations.\n"); - ret = -EINVAL; - goto err_unlock; - } - mutex_unlock(&c_node->mem_lock); - - DRM_DEBUG_KMS("cmd[%d]\n", property->cmd); - - /* start operations */ - if (ippdrv->start) { - ret = ippdrv->start(ippdrv->dev, property->cmd); - if (ret) { - DRM_ERROR("failed to start ops.\n"); - ippdrv->c_node = NULL; - return ret; - } - } - - return 0; - -err_unlock: - mutex_unlock(&c_node->mem_lock); - ippdrv->c_node = NULL; - return ret; -} - -static int ipp_stop_property(struct drm_device *drm_dev, - struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_cmd_node *c_node) -{ - struct drm_exynos_ipp_property *property = &c_node->property; - int i; - - DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id); - - /* stop operations */ - if (ippdrv->stop) - ippdrv->stop(ippdrv->dev, property->cmd); - - /* check command */ - switch (property->cmd) { - case IPP_CMD_M2M: - for_each_ipp_ops(i) - ipp_clean_mem_nodes(drm_dev, c_node, i); - break; - case IPP_CMD_WB: - ipp_clean_mem_nodes(drm_dev, c_node, EXYNOS_DRM_OPS_DST); - break; - case IPP_CMD_OUTPUT: - ipp_clean_mem_nodes(drm_dev, c_node, EXYNOS_DRM_OPS_SRC); - break; - default: - DRM_ERROR("invalid operations.\n"); - return -EINVAL; - } - - return 0; -} - -void ipp_sched_cmd(struct work_struct *work) -{ - struct drm_exynos_ipp_cmd_work *cmd_work = - container_of(work, struct drm_exynos_ipp_cmd_work, work); - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_cmd_node *c_node; - struct drm_exynos_ipp_property *property; - int ret; - - ippdrv = cmd_work->ippdrv; - if (!ippdrv) { - DRM_ERROR("invalid ippdrv list.\n"); - return; - } - - c_node = cmd_work->c_node; - if (!c_node) { - DRM_ERROR("invalid command node list.\n"); - return; - } - - mutex_lock(&c_node->lock); - - property = &c_node->property; - - switch (cmd_work->ctrl) { - case IPP_CTRL_PLAY: - case IPP_CTRL_RESUME: - ret = ipp_start_property(ippdrv, c_node); - if (ret) { - DRM_ERROR("failed to start property:prop_id[%d]\n", - c_node->property.prop_id); - goto err_unlock; - } - - /* - * M2M case supports wait_completion of transfer. - * because M2M case supports single unit operation - * with multiple queue. - * M2M need to wait completion of data transfer. - */ - if (ipp_is_m2m_cmd(property->cmd)) { - if (!wait_for_completion_timeout - (&c_node->start_complete, msecs_to_jiffies(200))) { - DRM_ERROR("timeout event:prop_id[%d]\n", - c_node->property.prop_id); - goto err_unlock; - } - } - break; - case IPP_CTRL_STOP: - case IPP_CTRL_PAUSE: - ret = ipp_stop_property(ippdrv->drm_dev, ippdrv, - c_node); - if (ret) { - DRM_ERROR("failed to stop property.\n"); - goto err_unlock; - } - - complete(&c_node->stop_complete); - break; - default: - DRM_ERROR("unknown control type\n"); - break; - } - - DRM_DEBUG_KMS("ctrl[%d] done.\n", cmd_work->ctrl); - -err_unlock: - mutex_unlock(&c_node->lock); -} - -static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_cmd_node *c_node, int *buf_id) -{ - struct drm_device *drm_dev = ippdrv->drm_dev; - struct drm_exynos_ipp_property *property = &c_node->property; - struct drm_exynos_ipp_mem_node *m_node; - struct drm_exynos_ipp_queue_buf qbuf; - struct drm_exynos_ipp_send_event *e; - struct list_head *head; - struct timeval now; - u32 tbuf_id[EXYNOS_DRM_OPS_MAX] = {0, }; - int ret, i; - - for_each_ipp_ops(i) - DRM_DEBUG_KMS("%s buf_id[%d]\n", i ? "dst" : "src", buf_id[i]); - - if (!drm_dev) { - DRM_ERROR("failed to get drm_dev.\n"); - return -EINVAL; - } - - if (!property) { - DRM_ERROR("failed to get property.\n"); - return -EINVAL; - } - - mutex_lock(&c_node->event_lock); - if (list_empty(&c_node->event_list)) { - DRM_DEBUG_KMS("event list is empty.\n"); - ret = 0; - goto err_event_unlock; - } - - mutex_lock(&c_node->mem_lock); - if (!ipp_check_mem_list(c_node)) { - DRM_DEBUG_KMS("empty memory.\n"); - ret = 0; - goto err_mem_unlock; - } - - /* check command */ - switch (property->cmd) { - case IPP_CMD_M2M: - for_each_ipp_ops(i) { - /* source/destination memory list */ - head = &c_node->mem_list[i]; - - m_node = list_first_entry(head, - struct drm_exynos_ipp_mem_node, list); - - tbuf_id[i] = m_node->buf_id; - DRM_DEBUG_KMS("%s buf_id[%d]\n", - i ? "dst" : "src", tbuf_id[i]); - - ret = ipp_put_mem_node(drm_dev, c_node, m_node); - if (ret) - DRM_ERROR("failed to put m_node.\n"); - } - break; - case IPP_CMD_WB: - /* clear buf for finding */ - memset(&qbuf, 0x0, sizeof(qbuf)); - qbuf.ops_id = EXYNOS_DRM_OPS_DST; - qbuf.buf_id = buf_id[EXYNOS_DRM_OPS_DST]; - - /* get memory node entry */ - m_node = ipp_find_mem_node(c_node, &qbuf); - if (!m_node) { - DRM_ERROR("empty memory node.\n"); - ret = -ENOMEM; - goto err_mem_unlock; - } - - tbuf_id[EXYNOS_DRM_OPS_DST] = m_node->buf_id; - - ret = ipp_put_mem_node(drm_dev, c_node, m_node); - if (ret) - DRM_ERROR("failed to put m_node.\n"); - break; - case IPP_CMD_OUTPUT: - /* source memory list */ - head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC]; - - m_node = list_first_entry(head, - struct drm_exynos_ipp_mem_node, list); - - tbuf_id[EXYNOS_DRM_OPS_SRC] = m_node->buf_id; - - ret = ipp_put_mem_node(drm_dev, c_node, m_node); - if (ret) - DRM_ERROR("failed to put m_node.\n"); - break; - default: - DRM_ERROR("invalid operations.\n"); - ret = -EINVAL; - goto err_mem_unlock; - } - mutex_unlock(&c_node->mem_lock); - - if (tbuf_id[EXYNOS_DRM_OPS_DST] != buf_id[EXYNOS_DRM_OPS_DST]) - DRM_ERROR("failed to match buf_id[%d %d]prop_id[%d]\n", - tbuf_id[1], buf_id[1], property->prop_id); - - /* - * command node have event list of destination buffer - * If destination buffer enqueue to mem list, - * then we make event and link to event list tail. - * so, we get first event for first enqueued buffer. - */ - e = list_first_entry(&c_node->event_list, - struct drm_exynos_ipp_send_event, base.link); - - do_gettimeofday(&now); - DRM_DEBUG_KMS("tv_sec[%ld]tv_usec[%ld]\n", now.tv_sec, now.tv_usec); - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; - e->event.prop_id = property->prop_id; - - /* set buffer id about source destination */ - for_each_ipp_ops(i) - e->event.buf_id[i] = tbuf_id[i]; - - drm_send_event(drm_dev, &e->base); - mutex_unlock(&c_node->event_lock); - - DRM_DEBUG_KMS("done cmd[%d]prop_id[%d]buf_id[%d]\n", - property->cmd, property->prop_id, tbuf_id[EXYNOS_DRM_OPS_DST]); - - return 0; - -err_mem_unlock: - mutex_unlock(&c_node->mem_lock); -err_event_unlock: - mutex_unlock(&c_node->event_lock); - return ret; -} - -void ipp_sched_event(struct work_struct *work) -{ - struct drm_exynos_ipp_event_work *event_work = - container_of(work, struct drm_exynos_ipp_event_work, work); - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_cmd_node *c_node; - int ret; - - if (!event_work) { - DRM_ERROR("failed to get event_work.\n"); - return; - } - - DRM_DEBUG_KMS("buf_id[%d]\n", event_work->buf_id[EXYNOS_DRM_OPS_DST]); - - ippdrv = event_work->ippdrv; - if (!ippdrv) { - DRM_ERROR("failed to get ipp driver.\n"); - return; - } - - c_node = ippdrv->c_node; - if (!c_node) { - DRM_ERROR("failed to get command node.\n"); - return; - } - - /* - * IPP supports command thread, event thread synchronization. - * If IPP close immediately from user land, then IPP make - * synchronization with command thread, so make complete event. - * or going out operations. - */ - if (c_node->state != IPP_STATE_START) { - DRM_DEBUG_KMS("bypass state[%d]prop_id[%d]\n", - c_node->state, c_node->property.prop_id); - goto err_completion; - } - - ret = ipp_send_event(ippdrv, c_node, event_work->buf_id); - if (ret) { - DRM_ERROR("failed to send event.\n"); - goto err_completion; - } - -err_completion: - if (ipp_is_m2m_cmd(c_node->property.cmd)) - complete(&c_node->start_complete); -} - -static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) -{ - struct ipp_context *ctx = get_ipp_context(dev); - struct exynos_drm_ippdrv *ippdrv; - int ret, count = 0; - - /* get ipp driver entry */ - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { - ippdrv->drm_dev = drm_dev; - - ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv); - if (ret < 0) { - DRM_ERROR("failed to create id.\n"); - goto err; - } - ippdrv->prop_list.ipp_id = ret; - - DRM_DEBUG_KMS("count[%d]ippdrv[%pK]ipp_id[%d]\n", - count++, ippdrv, ret); - - /* store parent device for node */ - ippdrv->parent_dev = dev; - - /* store event work queue and handler */ - ippdrv->event_workq = ctx->event_workq; - ippdrv->sched_event = ipp_sched_event; - INIT_LIST_HEAD(&ippdrv->cmd_list); - mutex_init(&ippdrv->cmd_lock); - - ret = drm_iommu_attach_device(drm_dev, ippdrv->dev); - if (ret) { - DRM_ERROR("failed to activate iommu\n"); - goto err; - } - } - - return 0; - -err: - /* get ipp driver entry */ - list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list, - drv_list) { - drm_iommu_detach_device(drm_dev, ippdrv->dev); - - ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, - ippdrv->prop_list.ipp_id); - } - - return ret; -} - -static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev) -{ - struct exynos_drm_ippdrv *ippdrv, *t; - struct ipp_context *ctx = get_ipp_context(dev); - - /* get ipp driver entry */ - list_for_each_entry_safe(ippdrv, t, &exynos_drm_ippdrv_list, drv_list) { - drm_iommu_detach_device(drm_dev, ippdrv->dev); - - ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, - ippdrv->prop_list.ipp_id); - - ippdrv->drm_dev = NULL; - exynos_drm_ippdrv_unregister(ippdrv); - } -} - -static int ipp_subdrv_open(struct drm_device *drm_dev, struct device *dev, - struct drm_file *file) -{ - struct drm_exynos_file_private *file_priv = file->driver_priv; - - file_priv->ipp_dev = dev; - - DRM_DEBUG_KMS("done priv[%pK]\n", dev); - - return 0; -} - -static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev, - struct drm_file *file) -{ - struct exynos_drm_ippdrv *ippdrv = NULL; - struct ipp_context *ctx = get_ipp_context(dev); - struct drm_exynos_ipp_cmd_node *c_node, *tc_node; - int count = 0; - - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { - mutex_lock(&ippdrv->cmd_lock); - list_for_each_entry_safe(c_node, tc_node, - &ippdrv->cmd_list, list) { - DRM_DEBUG_KMS("count[%d]ippdrv[%pK]\n", - count++, ippdrv); - - if (c_node->filp == file) { - /* - * userland goto unnormal state. process killed. - * and close the file. - * so, IPP didn't called stop cmd ctrl. - * so, we are make stop operation in this state. - */ - if (c_node->state == IPP_STATE_START) { - ipp_stop_property(drm_dev, ippdrv, - c_node); - c_node->state = IPP_STATE_STOP; - } - - ippdrv->dedicated = false; - ipp_clean_cmd_node(ctx, c_node); - if (list_empty(&ippdrv->cmd_list)) - pm_runtime_put_sync(ippdrv->dev); - } - } - mutex_unlock(&ippdrv->cmd_lock); - } - - return; -} - -static int ipp_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct ipp_context *ctx; - struct exynos_drm_subdrv *subdrv; - int ret; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - mutex_init(&ctx->ipp_lock); - mutex_init(&ctx->prop_lock); - - idr_init(&ctx->ipp_idr); - idr_init(&ctx->prop_idr); - - /* - * create single thread for ipp event - * IPP supports event thread for IPP drivers. - * IPP driver send event_work to this thread. - * and IPP event thread send event to user process. - */ - ctx->event_workq = create_singlethread_workqueue("ipp_event"); - if (!ctx->event_workq) { - dev_err(dev, "failed to create event workqueue\n"); - return -EINVAL; - } - - /* - * create single thread for ipp command - * IPP supports command thread for user process. - * user process make command node using set property ioctl. - * and make start_work and send this work to command thread. - * and then this command thread start property. - */ - ctx->cmd_workq = create_singlethread_workqueue("ipp_cmd"); - if (!ctx->cmd_workq) { - dev_err(dev, "failed to create cmd workqueue\n"); - ret = -EINVAL; - goto err_event_workq; - } - - /* set sub driver informations */ - subdrv = &ctx->subdrv; - subdrv->dev = dev; - subdrv->probe = ipp_subdrv_probe; - subdrv->remove = ipp_subdrv_remove; - subdrv->open = ipp_subdrv_open; - subdrv->close = ipp_subdrv_close; - - platform_set_drvdata(pdev, ctx); - - ret = exynos_drm_subdrv_register(subdrv); - if (ret < 0) { - DRM_ERROR("failed to register drm ipp device.\n"); - goto err_cmd_workq; - } - - dev_info(dev, "drm ipp registered successfully.\n"); - - return 0; - -err_cmd_workq: - destroy_workqueue(ctx->cmd_workq); -err_event_workq: - destroy_workqueue(ctx->event_workq); - return ret; -} - -static int ipp_remove(struct platform_device *pdev) -{ - struct ipp_context *ctx = platform_get_drvdata(pdev); - - /* unregister sub driver */ - exynos_drm_subdrv_unregister(&ctx->subdrv); - - /* remove,destroy ipp idr */ - idr_destroy(&ctx->ipp_idr); - idr_destroy(&ctx->prop_idr); - - mutex_destroy(&ctx->ipp_lock); - mutex_destroy(&ctx->prop_lock); - - /* destroy command, event work queue */ - destroy_workqueue(ctx->cmd_workq); - destroy_workqueue(ctx->event_workq); - - return 0; -} - -struct platform_driver ipp_driver = { - .probe = ipp_probe, - .remove = ipp_remove, - .driver = { - .name = "exynos-drm-ipp", - .owner = THIS_MODULE, - }, -}; - diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.h b/drivers/gpu/drm/exynos/exynos_drm_ipp.h deleted file mode 100644 index 2a61547a39d0..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * - * Authors: - * Eunchul Kim - * Jinyoung Jeon - * Sangmin Lee - * - * 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_IPP_H_ -#define _EXYNOS_DRM_IPP_H_ - -#define for_each_ipp_ops(pos) \ - for (pos = 0; pos < EXYNOS_DRM_OPS_MAX; pos++) -#define for_each_ipp_planar(pos) \ - for (pos = 0; pos < EXYNOS_DRM_PLANAR_MAX; pos++) - -#define IPP_GET_LCD_WIDTH _IOR('F', 302, int) -#define IPP_GET_LCD_HEIGHT _IOR('F', 303, int) -#define IPP_SET_WRITEBACK _IOW('F', 304, u32) - -/* definition of state */ -enum drm_exynos_ipp_state { - IPP_STATE_IDLE, - IPP_STATE_START, - IPP_STATE_STOP, -}; - -/* - * A structure of command work information. - * @work: work structure. - * @ippdrv: current work ippdrv. - * @c_node: command node information. - * @ctrl: command control. - */ -struct drm_exynos_ipp_cmd_work { - struct work_struct work; - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_cmd_node *c_node; - enum drm_exynos_ipp_ctrl ctrl; -}; - -/* - * A structure of command node. - * - * @list: list head to command queue information. - * @event_list: list head of event. - * @mem_list: list head to source,destination memory queue information. - * @lock: lock for synchronization of access to ioctl. - * @mem_lock: lock for synchronization of access to memory nodes. - * @event_lock: lock for synchronization of access to scheduled event. - * @start_complete: completion of start of command. - * @stop_complete: completion of stop of command. - * @property: property information. - * @start_work: start command work structure. - * @stop_work: stop command work structure. - * @event_work: event work structure. - * @state: state of command node. - * @filp: associated file pointer. - */ -struct drm_exynos_ipp_cmd_node { - struct list_head list; - struct list_head event_list; - struct list_head mem_list[EXYNOS_DRM_OPS_MAX]; - struct mutex lock; - struct mutex mem_lock; - struct mutex event_lock; - struct completion start_complete; - struct completion stop_complete; - struct drm_exynos_ipp_property property; - struct drm_exynos_ipp_cmd_work *start_work; - struct drm_exynos_ipp_cmd_work *stop_work; - struct drm_exynos_ipp_event_work *event_work; - enum drm_exynos_ipp_state state; - struct drm_file *filp; -}; - -/* - * A structure of buffer information. - * - * @handles: Y, Cb, Cr each gem object handle. - * @base: Y, Cb, Cr each planar address. - */ -struct drm_exynos_ipp_buf_info { - unsigned long handles[EXYNOS_DRM_PLANAR_MAX]; - dma_addr_t base[EXYNOS_DRM_PLANAR_MAX]; -}; - -/* - * A structure of wb setting information. - * - * @enable: enable flag for wb. - * @refresh: HZ of the refresh rate. - */ -struct drm_exynos_ipp_set_wb { - __u32 enable; - __u32 refresh; -}; - -/* - * A structure of event work information. - * - * @work: work structure. - * @ippdrv: current work ippdrv. - * @buf_id: id of src, dst buffer. - */ -struct drm_exynos_ipp_event_work { - struct work_struct work; - struct exynos_drm_ippdrv *ippdrv; - u32 buf_id[EXYNOS_DRM_OPS_MAX]; -}; - -/* - * A structure of source,destination operations. - * - * @set_fmt: set format of image. - * @set_transf: set transform(rotations, flip). - * @set_size: set size of region. - * @set_addr: set address for dma. - */ -struct exynos_drm_ipp_ops { - int (*set_fmt)(struct device *dev, u32 fmt); - int (*set_transf)(struct device *dev, - enum drm_exynos_degree degree, - enum drm_exynos_flip flip, bool *swap); - int (*set_size)(struct device *dev, int swap, - struct drm_exynos_pos *pos, struct drm_exynos_sz *sz); - int (*set_addr)(struct device *dev, - struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id, - enum drm_exynos_ipp_buf_type buf_type); -}; - -/* - * A structure of ipp driver. - * - * @drv_list: list head for registed sub driver information. - * @parent_dev: parent device information. - * @dev: platform device. - * @drm_dev: drm device. - * @dedicated: dedicated ipp device. - * @ops: source, destination operations. - * @event_workq: event work queue. - * @c_node: current command information. - * @cmd_list: list head for command information. - * @cmd_lock: lock for synchronization of access to cmd_list. - * @prop_list: property informations of current ipp driver. - * @check_property: check property about format, size, buffer. - * @reset: reset ipp block. - * @start: ipp each device start. - * @stop: ipp each device stop. - * @sched_event: work schedule handler. - */ -struct exynos_drm_ippdrv { - struct list_head drv_list; - struct device *parent_dev; - struct device *dev; - struct drm_device *drm_dev; - bool dedicated; - struct exynos_drm_ipp_ops *ops[EXYNOS_DRM_OPS_MAX]; - struct workqueue_struct *event_workq; - struct drm_exynos_ipp_cmd_node *c_node; - struct list_head cmd_list; - struct mutex cmd_lock; - struct drm_exynos_ipp_prop_list prop_list; - - int (*check_property)(struct device *dev, - struct drm_exynos_ipp_property *property); - int (*reset)(struct device *dev); - int (*start)(struct device *dev, enum drm_exynos_ipp_cmd cmd); - void (*stop)(struct device *dev, enum drm_exynos_ipp_cmd cmd); - void (*sched_event)(struct work_struct *work); -}; - -#ifdef CONFIG_DRM_EXYNOS_IPP -extern int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv); -extern int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv); -extern int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, - struct drm_file *file); -extern int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, - struct drm_file *file); -extern int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, - struct drm_file *file); -extern int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, - struct drm_file *file); -extern int exynos_drm_ippnb_register(struct notifier_block *nb); -extern int exynos_drm_ippnb_unregister(struct notifier_block *nb); -extern int exynos_drm_ippnb_send_event(unsigned long val, void *v); -extern void ipp_sched_cmd(struct work_struct *work); -extern void ipp_sched_event(struct work_struct *work); - -#else -static inline int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) -{ - return -ENODEV; -} - -static inline int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv) -{ - return -ENODEV; -} - -static inline int exynos_drm_ipp_get_property(struct drm_device *drm_dev, - void *data, - struct drm_file *file_priv) -{ - return -ENOTTY; -} - -static inline int exynos_drm_ipp_set_property(struct drm_device *drm_dev, - void *data, - struct drm_file *file_priv) -{ - return -ENOTTY; -} - -static inline int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, - void *data, - struct drm_file *file) -{ - return -ENOTTY; -} - -static inline int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, - void *data, - struct drm_file *file) -{ - return -ENOTTY; -} - -static inline int exynos_drm_ippnb_register(struct notifier_block *nb) -{ - return -ENODEV; -} - -static inline int exynos_drm_ippnb_unregister(struct notifier_block *nb) -{ - return -ENODEV; -} - -static inline int exynos_drm_ippnb_send_event(unsigned long val, void *v) -{ - return -ENOTTY; -} -#endif - -#endif /* _EXYNOS_DRM_IPP_H_ */ - diff --git a/include/uapi/drm/exynos_drm.h b/include/uapi/drm/exynos_drm.h index d01087b2a651..4a54305120e0 100644 --- a/include/uapi/drm/exynos_drm.h +++ b/include/uapi/drm/exynos_drm.h @@ -135,172 +135,6 @@ struct drm_exynos_g2d_exec { __u64 async; }; -enum drm_exynos_ops_id { - EXYNOS_DRM_OPS_SRC, - EXYNOS_DRM_OPS_DST, - EXYNOS_DRM_OPS_MAX, -}; - -struct drm_exynos_sz { - __u32 hsize; - __u32 vsize; -}; - -struct drm_exynos_pos { - __u32 x; - __u32 y; - __u32 w; - __u32 h; -}; - -enum drm_exynos_flip { - EXYNOS_DRM_FLIP_NONE = (0 << 0), - EXYNOS_DRM_FLIP_VERTICAL = (1 << 0), - EXYNOS_DRM_FLIP_HORIZONTAL = (1 << 1), - EXYNOS_DRM_FLIP_BOTH = EXYNOS_DRM_FLIP_VERTICAL | - EXYNOS_DRM_FLIP_HORIZONTAL, -}; - -enum drm_exynos_degree { - EXYNOS_DRM_DEGREE_0, - EXYNOS_DRM_DEGREE_90, - EXYNOS_DRM_DEGREE_180, - EXYNOS_DRM_DEGREE_270, -}; - -enum drm_exynos_planer { - EXYNOS_DRM_PLANAR_Y, - EXYNOS_DRM_PLANAR_CB, - EXYNOS_DRM_PLANAR_CR, - EXYNOS_DRM_PLANAR_MAX, -}; - -/** - * A structure for ipp supported property list. - * - * @version: version of this structure. - * @ipp_id: id of ipp driver. - * @count: count of ipp driver. - * @writeback: flag of writeback supporting. - * @flip: flag of flip supporting. - * @degree: flag of degree information. - * @csc: flag of csc supporting. - * @crop: flag of crop supporting. - * @scale: flag of scale supporting. - * @refresh_min: min hz of refresh. - * @refresh_max: max hz of refresh. - * @crop_min: crop min resolution. - * @crop_max: crop max resolution. - * @scale_min: scale min resolution. - * @scale_max: scale max resolution. - */ -struct drm_exynos_ipp_prop_list { - __u32 version; - __u32 ipp_id; - __u32 count; - __u32 writeback; - __u32 flip; - __u32 degree; - __u32 csc; - __u32 crop; - __u32 scale; - __u32 refresh_min; - __u32 refresh_max; - __u32 reserved; - struct drm_exynos_sz crop_min; - struct drm_exynos_sz crop_max; - struct drm_exynos_sz scale_min; - struct drm_exynos_sz scale_max; -}; - -/** - * A structure for ipp config. - * - * @ops_id: property of operation directions. - * @flip: property of mirror, flip. - * @degree: property of rotation degree. - * @fmt: property of image format. - * @sz: property of image size. - * @pos: property of image position(src-cropped,dst-scaler). - */ -struct drm_exynos_ipp_config { - __u32 ops_id; - __u32 flip; - __u32 degree; - __u32 fmt; - struct drm_exynos_sz sz; - struct drm_exynos_pos pos; -}; - -enum drm_exynos_ipp_cmd { - IPP_CMD_NONE, - IPP_CMD_M2M, - IPP_CMD_WB, - IPP_CMD_OUTPUT, - IPP_CMD_MAX, -}; - -/** - * A structure for ipp property. - * - * @config: source, destination config. - * @cmd: definition of command. - * @ipp_id: id of ipp driver. - * @prop_id: id of property. - * @refresh_rate: refresh rate. - */ -struct drm_exynos_ipp_property { - struct drm_exynos_ipp_config config[EXYNOS_DRM_OPS_MAX]; - __u32 cmd; - __u32 ipp_id; - __u32 prop_id; - __u32 refresh_rate; -}; - -enum drm_exynos_ipp_buf_type { - IPP_BUF_ENQUEUE, - IPP_BUF_DEQUEUE, -}; - -/** - * A structure for ipp buffer operations. - * - * @ops_id: operation directions. - * @buf_type: definition of buffer. - * @prop_id: id of property. - * @buf_id: id of buffer. - * @handle: Y, Cb, Cr each planar handle. - * @user_data: user data. - */ -struct drm_exynos_ipp_queue_buf { - __u32 ops_id; - __u32 buf_type; - __u32 prop_id; - __u32 buf_id; - __u32 handle[EXYNOS_DRM_PLANAR_MAX]; - __u32 reserved; - __u64 user_data; -}; - -enum drm_exynos_ipp_ctrl { - IPP_CTRL_PLAY, - IPP_CTRL_STOP, - IPP_CTRL_PAUSE, - IPP_CTRL_RESUME, - IPP_CTRL_MAX, -}; - -/** - * A structure for ipp start/stop operations. - * - * @prop_id: id of property. - * @ctrl: definition of control. - */ -struct drm_exynos_ipp_cmd_ctrl { - __u32 prop_id; - __u32 ctrl; -}; - #define DRM_EXYNOS_GEM_CREATE 0x00 #define DRM_EXYNOS_GEM_MAP 0x01 /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */ @@ -312,11 +146,7 @@ struct drm_exynos_ipp_cmd_ctrl { #define DRM_EXYNOS_G2D_SET_CMDLIST 0x21 #define DRM_EXYNOS_G2D_EXEC 0x22 -/* IPP - Image Post Processing */ -#define DRM_EXYNOS_IPP_GET_PROPERTY 0x30 -#define DRM_EXYNOS_IPP_SET_PROPERTY 0x31 -#define DRM_EXYNOS_IPP_QUEUE_BUF 0x32 -#define DRM_EXYNOS_IPP_CMD_CTRL 0x33 +/* Reserved 0x30 ~ 0x33 for obsolete Exynos IPP ioctls */ #define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) @@ -335,18 +165,8 @@ struct drm_exynos_ipp_cmd_ctrl { #define DRM_IOCTL_EXYNOS_G2D_EXEC DRM_IOWR(DRM_COMMAND_BASE + \ DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec) -#define DRM_IOCTL_EXYNOS_IPP_GET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_IPP_GET_PROPERTY, struct drm_exynos_ipp_prop_list) -#define DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_IPP_SET_PROPERTY, struct drm_exynos_ipp_property) -#define DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_IPP_QUEUE_BUF, struct drm_exynos_ipp_queue_buf) -#define DRM_IOCTL_EXYNOS_IPP_CMD_CTRL DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_IPP_CMD_CTRL, struct drm_exynos_ipp_cmd_ctrl) - /* EXYNOS specific events */ #define DRM_EXYNOS_G2D_EVENT 0x80000000 -#define DRM_EXYNOS_IPP_EVENT 0x80000001 struct drm_exynos_g2d_event { struct drm_event base; @@ -357,16 +177,6 @@ struct drm_exynos_g2d_event { __u32 reserved; }; -struct drm_exynos_ipp_event { - struct drm_event base; - __u64 user_data; - __u32 tv_sec; - __u32 tv_usec; - __u32 prop_id; - __u32 reserved; - __u32 buf_id[EXYNOS_DRM_OPS_MAX]; -}; - #if defined(__cplusplus) } #endif