aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2018-01-04 18:29:20 -0500
committerDave Airlie <airlied@redhat.com>2018-01-04 18:29:20 -0500
commit4ef0bef2ec56a63bd5f51dd07d5f6bedf1123fa3 (patch)
treeea3e3ab6fdbfce772bc16d40ef7e26e59b922f61 /drivers
parenta9742b794aeea2abfbc12d1384de05b29f169cb9 (diff)
parent8ded59413ccc58fe138ab4bf337d0d0b3131d46b (diff)
Merge tag 'exynos-drm-next-for-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
Remove lagacy IPP driver - This driver isn't used anymore so remove it. Marek is preparing new one which includes completely rewritten API so this driver will be replaced with the new version[1] later. And cleanups. [1] https://patches.linaro.org/cover/118386/ * tag 'exynos-drm-next-for-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: drm/exynos: ipp: Remove Exynos DRM IPP subsystem drm/exynos/decon: Add include guard to the Exynos7 header drm/exynos/decon: Move headers from global to local place drm/exynos: decon5433: Remove unnecessary platform_get_resource() error check
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/exynos/Kconfig11
-rw-r--r--drivers/gpu/drm/exynos/Makefile1
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos7_drm_decon.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.c1806
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.h252
-rw-r--r--drivers/gpu/drm/exynos/regs-decon5433.h209
-rw-r--r--drivers/gpu/drm/exynos/regs-decon7.h353
10 files changed, 567 insertions, 2089 deletions
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 5a7c9d8abd6b..735ce47688f9 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -95,26 +95,21 @@ config DRM_EXYNOS_G2D
95 help 95 help
96 Choose this option if you want to use Exynos G2D for DRM. 96 Choose this option if you want to use Exynos G2D for DRM.
97 97
98config DRM_EXYNOS_IPP
99 bool "Image Post Processor"
100 help
101 Choose this option if you want to use IPP feature for DRM.
102
103config DRM_EXYNOS_FIMC 98config DRM_EXYNOS_FIMC
104 bool "FIMC" 99 bool "FIMC"
105 depends on DRM_EXYNOS_IPP && MFD_SYSCON 100 depends on BROKEN && MFD_SYSCON
106 help 101 help
107 Choose this option if you want to use Exynos FIMC for DRM. 102 Choose this option if you want to use Exynos FIMC for DRM.
108 103
109config DRM_EXYNOS_ROTATOR 104config DRM_EXYNOS_ROTATOR
110 bool "Rotator" 105 bool "Rotator"
111 depends on DRM_EXYNOS_IPP 106 depends on BROKEN
112 help 107 help
113 Choose this option if you want to use Exynos Rotator for DRM. 108 Choose this option if you want to use Exynos Rotator for DRM.
114 109
115config DRM_EXYNOS_GSC 110config DRM_EXYNOS_GSC
116 bool "GScaler" 111 bool "GScaler"
117 depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && VIDEO_SAMSUNG_EXYNOS_GSC=n 112 depends on BROKEN && ARCH_EXYNOS5 && VIDEO_SAMSUNG_EXYNOS_GSC=n
118 help 113 help
119 Choose this option if you want to use Exynos GSC for DRM. 114 Choose this option if you want to use Exynos GSC for DRM.
120 115
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
18exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o 18exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o
19exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o 19exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o
20exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o 20exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o
21exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o
22exynosdrm-$(CONFIG_DRM_EXYNOS_FIMC) += exynos_drm_fimc.o 21exynosdrm-$(CONFIG_DRM_EXYNOS_FIMC) += exynos_drm_fimc.o
23exynosdrm-$(CONFIG_DRM_EXYNOS_ROTATOR) += exynos_drm_rotator.o 22exynosdrm-$(CONFIG_DRM_EXYNOS_ROTATOR) += exynos_drm_rotator.o
24exynosdrm-$(CONFIG_DRM_EXYNOS_GSC) += exynos_drm_gsc.o 23exynosdrm-$(CONFIG_DRM_EXYNOS_GSC) += exynos_drm_gsc.o
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
index 6be5b53c3b27..1c330f2a7a5d 100644
--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -21,13 +21,12 @@
21#include <linux/pm_runtime.h> 21#include <linux/pm_runtime.h>
22#include <linux/regmap.h> 22#include <linux/regmap.h>
23 23
24#include <video/exynos5433_decon.h>
25
26#include "exynos_drm_drv.h" 24#include "exynos_drm_drv.h"
27#include "exynos_drm_crtc.h" 25#include "exynos_drm_crtc.h"
28#include "exynos_drm_fb.h" 26#include "exynos_drm_fb.h"
29#include "exynos_drm_plane.h" 27#include "exynos_drm_plane.h"
30#include "exynos_drm_iommu.h" 28#include "exynos_drm_iommu.h"
29#include "regs-decon5433.h"
31 30
32#define DSD_CFG_MUX 0x1004 31#define DSD_CFG_MUX 0x1004
33#define DSD_CFG_MUX_TE_UNMASK_GLOBAL BIT(13) 32#define DSD_CFG_MUX_TE_UNMASK_GLOBAL BIT(13)
@@ -744,11 +743,6 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
744 } 743 }
745 744
746 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 745 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
747 if (!res) {
748 dev_err(dev, "cannot find IO resource\n");
749 return -ENXIO;
750 }
751
752 ctx->addr = devm_ioremap_resource(dev, res); 746 ctx->addr = devm_ioremap_resource(dev, res);
753 if (IS_ERR(ctx->addr)) { 747 if (IS_ERR(ctx->addr)) {
754 dev_err(dev, "ioremap failed\n"); 748 dev_err(dev, "ioremap failed\n");
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
index 615efcf7782a..3931d5e33fe0 100644
--- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -25,13 +25,13 @@
25 25
26#include <video/of_display_timing.h> 26#include <video/of_display_timing.h>
27#include <video/of_videomode.h> 27#include <video/of_videomode.h>
28#include <video/exynos7_decon.h>
29 28
30#include "exynos_drm_crtc.h" 29#include "exynos_drm_crtc.h"
31#include "exynos_drm_plane.h" 30#include "exynos_drm_plane.h"
32#include "exynos_drm_drv.h" 31#include "exynos_drm_drv.h"
33#include "exynos_drm_fb.h" 32#include "exynos_drm_fb.h"
34#include "exynos_drm_iommu.h" 33#include "exynos_drm_iommu.h"
34#include "regs-decon7.h"
35 35
36/* 36/*
37 * DECON stands for Display and Enhancement controller. 37 * DECON stands for Display and Enhancement controller.
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index b96bd5a781b2..a518e9c6d6cc 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -29,7 +29,6 @@
29#include "exynos_drm_plane.h" 29#include "exynos_drm_plane.h"
30#include "exynos_drm_vidi.h" 30#include "exynos_drm_vidi.h"
31#include "exynos_drm_g2d.h" 31#include "exynos_drm_g2d.h"
32#include "exynos_drm_ipp.h"
33#include "exynos_drm_iommu.h" 32#include "exynos_drm_iommu.h"
34 33
35#define DRIVER_NAME "exynos" 34#define DRIVER_NAME "exynos"
@@ -109,14 +108,6 @@ static const struct drm_ioctl_desc exynos_ioctls[] = {
109 DRM_AUTH | DRM_RENDER_ALLOW), 108 DRM_AUTH | DRM_RENDER_ALLOW),
110 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl, 109 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl,
111 DRM_AUTH | DRM_RENDER_ALLOW), 110 DRM_AUTH | DRM_RENDER_ALLOW),
112 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY, exynos_drm_ipp_get_property,
113 DRM_AUTH | DRM_RENDER_ALLOW),
114 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY, exynos_drm_ipp_set_property,
115 DRM_AUTH | DRM_RENDER_ALLOW),
116 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF, exynos_drm_ipp_queue_buf,
117 DRM_AUTH | DRM_RENDER_ALLOW),
118 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL, exynos_drm_ipp_cmd_ctrl,
119 DRM_AUTH | DRM_RENDER_ALLOW),
120}; 111};
121 112
122static const struct file_operations exynos_drm_driver_fops = { 113static const struct file_operations exynos_drm_driver_fops = {
@@ -257,9 +248,6 @@ static struct exynos_drm_driver_info exynos_drm_drivers[] = {
257 }, { 248 }, {
258 DRV_PTR(gsc_driver, CONFIG_DRM_EXYNOS_GSC), 249 DRV_PTR(gsc_driver, CONFIG_DRM_EXYNOS_GSC),
259 }, { 250 }, {
260 DRV_PTR(ipp_driver, CONFIG_DRM_EXYNOS_IPP),
261 DRM_VIRTUAL_DEVICE
262 }, {
263 &exynos_drm_platform_driver, 251 &exynos_drm_platform_driver,
264 DRM_VIRTUAL_DEVICE 252 DRM_VIRTUAL_DEVICE
265 } 253 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 589d465a7f88..df2262f70d91 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -188,7 +188,6 @@ struct exynos_drm_g2d_private {
188 188
189struct drm_exynos_file_private { 189struct drm_exynos_file_private {
190 struct exynos_drm_g2d_private *g2d_priv; 190 struct exynos_drm_g2d_private *g2d_priv;
191 struct device *ipp_dev;
192}; 191};
193 192
194/* 193/*
@@ -291,6 +290,5 @@ extern struct platform_driver g2d_driver;
291extern struct platform_driver fimc_driver; 290extern struct platform_driver fimc_driver;
292extern struct platform_driver rotator_driver; 291extern struct platform_driver rotator_driver;
293extern struct platform_driver gsc_driver; 292extern struct platform_driver gsc_driver;
294extern struct platform_driver ipp_driver;
295extern struct platform_driver mic_driver; 293extern struct platform_driver mic_driver;
296#endif 294#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 @@
1/*
2 * Copyright (C) 2012 Samsung Electronics Co.Ltd
3 * Authors:
4 * Eunchul Kim <chulspro.kim@samsung.com>
5 * Jinyoung Jeon <jy0.jeon@samsung.com>
6 * Sangmin Lee <lsmin.lee@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14#include <linux/kernel.h>
15#include <linux/platform_device.h>
16#include <linux/types.h>
17#include <linux/clk.h>
18#include <linux/pm_runtime.h>
19
20#include <drm/drmP.h>
21#include <drm/exynos_drm.h>
22#include "exynos_drm_drv.h"
23#include "exynos_drm_gem.h"
24#include "exynos_drm_ipp.h"
25#include "exynos_drm_iommu.h"
26
27/*
28 * IPP stands for Image Post Processing and
29 * supports image scaler/rotator and input/output DMA operations.
30 * using FIMC, GSC, Rotator, so on.
31 * IPP is integration device driver of same attribute h/w
32 */
33
34/*
35 * TODO
36 * 1. expand command control id.
37 * 2. integrate property and config.
38 * 3. removed send_event id check routine.
39 * 4. compare send_event id if needed.
40 * 5. free subdrv_remove notifier callback list if needed.
41 * 6. need to check subdrv_open about multi-open.
42 * 7. need to power_on implement power and sysmmu ctrl.
43 */
44
45#define get_ipp_context(dev) platform_get_drvdata(to_platform_device(dev))
46#define ipp_is_m2m_cmd(c) (c == IPP_CMD_M2M)
47
48/*
49 * A structure of event.
50 *
51 * @base: base of event.
52 * @event: ipp event.
53 */
54struct drm_exynos_ipp_send_event {
55 struct drm_pending_event base;
56 struct drm_exynos_ipp_event event;
57};
58
59/*
60 * A structure of memory node.
61 *
62 * @list: list head to memory queue information.
63 * @ops_id: id of operations.
64 * @prop_id: id of property.
65 * @buf_id: id of buffer.
66 * @buf_info: gem objects and dma address, size.
67 * @filp: a pointer to drm_file.
68 */
69struct drm_exynos_ipp_mem_node {
70 struct list_head list;
71 enum drm_exynos_ops_id ops_id;
72 u32 prop_id;
73 u32 buf_id;
74 struct drm_exynos_ipp_buf_info buf_info;
75};
76
77/*
78 * A structure of ipp context.
79 *
80 * @subdrv: prepare initialization using subdrv.
81 * @ipp_lock: lock for synchronization of access to ipp_idr.
82 * @prop_lock: lock for synchronization of access to prop_idr.
83 * @ipp_idr: ipp driver idr.
84 * @prop_idr: property idr.
85 * @event_workq: event work queue.
86 * @cmd_workq: command work queue.
87 */
88struct ipp_context {
89 struct exynos_drm_subdrv subdrv;
90 struct mutex ipp_lock;
91 struct mutex prop_lock;
92 struct idr ipp_idr;
93 struct idr prop_idr;
94 struct workqueue_struct *event_workq;
95 struct workqueue_struct *cmd_workq;
96};
97
98static LIST_HEAD(exynos_drm_ippdrv_list);
99static DEFINE_MUTEX(exynos_drm_ippdrv_lock);
100static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list);
101
102int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv)
103{
104 mutex_lock(&exynos_drm_ippdrv_lock);
105 list_add_tail(&ippdrv->drv_list, &exynos_drm_ippdrv_list);
106 mutex_unlock(&exynos_drm_ippdrv_lock);
107
108 return 0;
109}
110
111int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv)
112{
113 mutex_lock(&exynos_drm_ippdrv_lock);
114 list_del(&ippdrv->drv_list);
115 mutex_unlock(&exynos_drm_ippdrv_lock);
116
117 return 0;
118}
119
120static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj)
121{
122 int ret;
123
124 mutex_lock(lock);
125 ret = idr_alloc(id_idr, obj, 1, 0, GFP_KERNEL);
126 mutex_unlock(lock);
127
128 return ret;
129}
130
131static void ipp_remove_id(struct idr *id_idr, struct mutex *lock, u32 id)
132{
133 mutex_lock(lock);
134 idr_remove(id_idr, id);
135 mutex_unlock(lock);
136}
137
138static void *ipp_find_obj(struct idr *id_idr, struct mutex *lock, u32 id)
139{
140 void *obj;
141
142 mutex_lock(lock);
143 obj = idr_find(id_idr, id);
144 mutex_unlock(lock);
145
146 return obj;
147}
148
149static int ipp_check_driver(struct exynos_drm_ippdrv *ippdrv,
150 struct drm_exynos_ipp_property *property)
151{
152 if (ippdrv->dedicated || (!ipp_is_m2m_cmd(property->cmd) &&
153 !pm_runtime_suspended(ippdrv->dev)))
154 return -EBUSY;
155
156 if (ippdrv->check_property &&
157 ippdrv->check_property(ippdrv->dev, property))
158 return -EINVAL;
159
160 return 0;
161}
162
163static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx,
164 struct drm_exynos_ipp_property *property)
165{
166 struct exynos_drm_ippdrv *ippdrv;
167 u32 ipp_id = property->ipp_id;
168 int ret;
169
170 if (ipp_id) {
171 ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, ipp_id);
172 if (!ippdrv) {
173 DRM_DEBUG("ipp%d driver not found\n", ipp_id);
174 return ERR_PTR(-ENODEV);
175 }
176
177 ret = ipp_check_driver(ippdrv, property);
178 if (ret < 0) {
179 DRM_DEBUG("ipp%d driver check error %d\n", ipp_id, ret);
180 return ERR_PTR(ret);
181 }
182
183 return ippdrv;
184 } else {
185 list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
186 ret = ipp_check_driver(ippdrv, property);
187 if (ret == 0)
188 return ippdrv;
189 }
190
191 DRM_DEBUG("cannot find driver suitable for given property.\n");
192 }
193
194 return ERR_PTR(-ENODEV);
195}
196
197static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id)
198{
199 struct exynos_drm_ippdrv *ippdrv;
200 struct drm_exynos_ipp_cmd_node *c_node;
201 int count = 0;
202
203 DRM_DEBUG_KMS("prop_id[%d]\n", prop_id);
204
205 /*
206 * This case is search ipp driver by prop_id handle.
207 * sometimes, ipp subsystem find driver by prop_id.
208 * e.g PAUSE state, queue buf, command control.
209 */
210 list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
211 DRM_DEBUG_KMS("count[%d]ippdrv[%pK]\n", count++, ippdrv);
212
213 mutex_lock(&ippdrv->cmd_lock);
214 list_for_each_entry(c_node, &ippdrv->cmd_list, list) {
215 if (c_node->property.prop_id == prop_id) {
216 mutex_unlock(&ippdrv->cmd_lock);
217 return ippdrv;
218 }
219 }
220 mutex_unlock(&ippdrv->cmd_lock);
221 }
222
223 return ERR_PTR(-ENODEV);
224}
225
226int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,
227 struct drm_file *file)
228{
229 struct drm_exynos_file_private *file_priv = file->driver_priv;
230 struct device *dev = file_priv->ipp_dev;
231 struct ipp_context *ctx = get_ipp_context(dev);
232 struct drm_exynos_ipp_prop_list *prop_list = data;
233 struct exynos_drm_ippdrv *ippdrv;
234 int count = 0;
235
236 if (!ctx) {
237 DRM_ERROR("invalid context.\n");
238 return -EINVAL;
239 }
240
241 if (!prop_list) {
242 DRM_ERROR("invalid property parameter.\n");
243 return -EINVAL;
244 }
245
246 DRM_DEBUG_KMS("ipp_id[%d]\n", prop_list->ipp_id);
247
248 if (!prop_list->ipp_id) {
249 list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list)
250 count++;
251
252 /*
253 * Supports ippdrv list count for user application.
254 * First step user application getting ippdrv count.
255 * and second step getting ippdrv capability using ipp_id.
256 */
257 prop_list->count = count;
258 } else {
259 /*
260 * Getting ippdrv capability by ipp_id.
261 * some device not supported wb, output interface.
262 * so, user application detect correct ipp driver
263 * using this ioctl.
264 */
265 ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock,
266 prop_list->ipp_id);
267 if (!ippdrv) {
268 DRM_ERROR("not found ipp%d driver.\n",
269 prop_list->ipp_id);
270 return -ENODEV;
271 }
272
273 *prop_list = ippdrv->prop_list;
274 }
275
276 return 0;
277}
278
279static void ipp_print_property(struct drm_exynos_ipp_property *property,
280 int idx)
281{
282 struct drm_exynos_ipp_config *config = &property->config[idx];
283 struct drm_exynos_pos *pos = &config->pos;
284 struct drm_exynos_sz *sz = &config->sz;
285
286 DRM_DEBUG_KMS("prop_id[%d]ops[%s]fmt[0x%x]\n",
287 property->prop_id, idx ? "dst" : "src", config->fmt);
288
289 DRM_DEBUG_KMS("pos[%d %d %d %d]sz[%d %d]f[%d]r[%d]\n",
290 pos->x, pos->y, pos->w, pos->h,
291 sz->hsize, sz->vsize, config->flip, config->degree);
292}
293
294static struct drm_exynos_ipp_cmd_work *ipp_create_cmd_work(void)
295{
296 struct drm_exynos_ipp_cmd_work *cmd_work;
297
298 cmd_work = kzalloc(sizeof(*cmd_work), GFP_KERNEL);
299 if (!cmd_work)
300 return ERR_PTR(-ENOMEM);
301
302 INIT_WORK((struct work_struct *)cmd_work, ipp_sched_cmd);
303
304 return cmd_work;
305}
306
307static struct drm_exynos_ipp_event_work *ipp_create_event_work(void)
308{
309 struct drm_exynos_ipp_event_work *event_work;
310
311 event_work = kzalloc(sizeof(*event_work), GFP_KERNEL);
312 if (!event_work)
313 return ERR_PTR(-ENOMEM);
314
315 INIT_WORK(&event_work->work, ipp_sched_event);
316
317 return event_work;
318}
319
320int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
321 struct drm_file *file)
322{
323 struct drm_exynos_file_private *file_priv = file->driver_priv;
324 struct device *dev = file_priv->ipp_dev;
325 struct ipp_context *ctx = get_ipp_context(dev);
326 struct drm_exynos_ipp_property *property = data;
327 struct exynos_drm_ippdrv *ippdrv;
328 struct drm_exynos_ipp_cmd_node *c_node;
329 u32 prop_id;
330 int ret, i;
331
332 if (!ctx) {
333 DRM_ERROR("invalid context.\n");
334 return -EINVAL;
335 }
336
337 if (!property) {
338 DRM_ERROR("invalid property parameter.\n");
339 return -EINVAL;
340 }
341
342 prop_id = property->prop_id;
343
344 /*
345 * This is log print for user application property.
346 * user application set various property.
347 */
348 for_each_ipp_ops(i)
349 ipp_print_property(property, i);
350
351 /*
352 * In case prop_id is not zero try to set existing property.
353 */
354 if (prop_id) {
355 c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, prop_id);
356
357 if (!c_node || c_node->filp != file) {
358 DRM_DEBUG_KMS("prop_id[%d] not found\n", prop_id);
359 return -EINVAL;
360 }
361
362 if (c_node->state != IPP_STATE_STOP) {
363 DRM_DEBUG_KMS("prop_id[%d] not stopped\n", prop_id);
364 return -EINVAL;
365 }
366
367 c_node->property = *property;
368
369 return 0;
370 }
371
372 /* find ipp driver using ipp id */
373 ippdrv = ipp_find_driver(ctx, property);
374 if (IS_ERR(ippdrv)) {
375 DRM_ERROR("failed to get ipp driver.\n");
376 return -EINVAL;
377 }
378
379 /* allocate command node */
380 c_node = kzalloc(sizeof(*c_node), GFP_KERNEL);
381 if (!c_node)
382 return -ENOMEM;
383
384 ret = ipp_create_id(&ctx->prop_idr, &ctx->prop_lock, c_node);
385 if (ret < 0) {
386 DRM_ERROR("failed to create id.\n");
387 goto err_clear;
388 }
389 property->prop_id = ret;
390
391 DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[%pK]\n",
392 property->prop_id, property->cmd, ippdrv);
393
394 /* stored property information and ippdrv in private data */
395 c_node->property = *property;
396 c_node->state = IPP_STATE_IDLE;
397 c_node->filp = file;
398
399 c_node->start_work = ipp_create_cmd_work();
400 if (IS_ERR(c_node->start_work)) {
401 DRM_ERROR("failed to create start work.\n");
402 ret = PTR_ERR(c_node->start_work);
403 goto err_remove_id;
404 }
405
406 c_node->stop_work = ipp_create_cmd_work();
407 if (IS_ERR(c_node->stop_work)) {
408 DRM_ERROR("failed to create stop work.\n");
409 ret = PTR_ERR(c_node->stop_work);
410 goto err_free_start;
411 }
412
413 c_node->event_work = ipp_create_event_work();
414 if (IS_ERR(c_node->event_work)) {
415 DRM_ERROR("failed to create event work.\n");
416 ret = PTR_ERR(c_node->event_work);
417 goto err_free_stop;
418 }
419
420 mutex_init(&c_node->lock);
421 mutex_init(&c_node->mem_lock);
422 mutex_init(&c_node->event_lock);
423
424 init_completion(&c_node->start_complete);
425 init_completion(&c_node->stop_complete);
426
427 for_each_ipp_ops(i)
428 INIT_LIST_HEAD(&c_node->mem_list[i]);
429
430 INIT_LIST_HEAD(&c_node->event_list);
431 mutex_lock(&ippdrv->cmd_lock);
432 list_add_tail(&c_node->list, &ippdrv->cmd_list);
433 mutex_unlock(&ippdrv->cmd_lock);
434
435 /* make dedicated state without m2m */
436 if (!ipp_is_m2m_cmd(property->cmd))
437 ippdrv->dedicated = true;
438
439 return 0;
440
441err_free_stop:
442 kfree(c_node->stop_work);
443err_free_start:
444 kfree(c_node->start_work);
445err_remove_id:
446 ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, property->prop_id);
447err_clear:
448 kfree(c_node);
449 return ret;
450}
451
452static int ipp_validate_mem_node(struct drm_device *drm_dev,
453 struct drm_exynos_ipp_mem_node *m_node,
454 struct drm_exynos_ipp_cmd_node *c_node)
455{
456 struct drm_exynos_ipp_config *ipp_cfg;
457 unsigned int num_plane;
458 unsigned long size, buf_size = 0, plane_size, img_size = 0;
459 unsigned int bpp, width, height;
460 int i;
461
462 ipp_cfg = &c_node->property.config[m_node->ops_id];
463 num_plane = drm_format_num_planes(ipp_cfg->fmt);
464
465 /**
466 * This is a rather simplified validation of a memory node.
467 * It basically verifies provided gem object handles
468 * and the buffer sizes with respect to current configuration.
469 * This is not the best that can be done
470 * but it seems more than enough
471 */
472 for (i = 0; i < num_plane; ++i) {
473 width = ipp_cfg->sz.hsize;
474 height = ipp_cfg->sz.vsize;
475 bpp = drm_format_plane_cpp(ipp_cfg->fmt, i);
476
477 /*
478 * The result of drm_format_plane_cpp() for chroma planes must
479 * be used with drm_format_xxxx_chroma_subsampling() for
480 * correct result.
481 */
482 if (i > 0) {
483 width /= drm_format_horz_chroma_subsampling(
484 ipp_cfg->fmt);
485 height /= drm_format_vert_chroma_subsampling(
486 ipp_cfg->fmt);
487 }
488 plane_size = width * height * bpp;
489 img_size += plane_size;
490
491 if (m_node->buf_info.handles[i]) {
492 size = exynos_drm_gem_get_size(drm_dev,
493 m_node->buf_info.handles[i],
494 c_node->filp);
495 if (plane_size > size) {
496 DRM_ERROR(
497 "buffer %d is smaller than required\n",
498 i);
499 return -EINVAL;
500 }
501
502 buf_size += size;
503 }
504 }
505
506 if (buf_size < img_size) {
507 DRM_ERROR("size of buffers(%lu) is smaller than image(%lu)\n",
508 buf_size, img_size);
509 return -EINVAL;
510 }
511
512 return 0;
513}
514
515static int ipp_put_mem_node(struct drm_device *drm_dev,
516 struct drm_exynos_ipp_cmd_node *c_node,
517 struct drm_exynos_ipp_mem_node *m_node)
518{
519 int i;
520
521 DRM_DEBUG_KMS("node[%pK]\n", m_node);
522
523 if (!m_node) {
524 DRM_ERROR("invalid dequeue node.\n");
525 return -EFAULT;
526 }
527
528 DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);
529
530 /* put gem buffer */
531 for_each_ipp_planar(i) {
532 unsigned long handle = m_node->buf_info.handles[i];
533 if (handle)
534 exynos_drm_gem_put_dma_addr(drm_dev, handle,
535 c_node->filp);
536 }
537
538 list_del(&m_node->list);
539 kfree(m_node);
540
541 return 0;
542}
543
544static struct drm_exynos_ipp_mem_node
545 *ipp_get_mem_node(struct drm_device *drm_dev,
546 struct drm_exynos_ipp_cmd_node *c_node,
547 struct drm_exynos_ipp_queue_buf *qbuf)
548{
549 struct drm_exynos_ipp_mem_node *m_node;
550 struct drm_exynos_ipp_buf_info *buf_info;
551 int i;
552
553 m_node = kzalloc(sizeof(*m_node), GFP_KERNEL);
554 if (!m_node)
555 return ERR_PTR(-ENOMEM);
556
557 buf_info = &m_node->buf_info;
558
559 /* operations, buffer id */
560 m_node->ops_id = qbuf->ops_id;
561 m_node->prop_id = qbuf->prop_id;
562 m_node->buf_id = qbuf->buf_id;
563 INIT_LIST_HEAD(&m_node->list);
564
565 DRM_DEBUG_KMS("m_node[%pK]ops_id[%d]\n", m_node, qbuf->ops_id);
566 DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]\n", qbuf->prop_id, m_node->buf_id);
567
568 for_each_ipp_planar(i) {
569 DRM_DEBUG_KMS("i[%d]handle[0x%x]\n", i, qbuf->handle[i]);
570
571 /* get dma address by handle */
572 if (qbuf->handle[i]) {
573 dma_addr_t *addr;
574
575 addr = exynos_drm_gem_get_dma_addr(drm_dev,
576 qbuf->handle[i], c_node->filp);
577 if (IS_ERR(addr)) {
578 DRM_ERROR("failed to get addr.\n");
579 ipp_put_mem_node(drm_dev, c_node, m_node);
580 return ERR_PTR(-EFAULT);
581 }
582
583 buf_info->handles[i] = qbuf->handle[i];
584 buf_info->base[i] = *addr;
585 DRM_DEBUG_KMS("i[%d]base[%pad]hd[0x%lx]\n", i,
586 &buf_info->base[i], buf_info->handles[i]);
587 }
588 }
589
590 mutex_lock(&c_node->mem_lock);
591 if (ipp_validate_mem_node(drm_dev, m_node, c_node)) {
592 ipp_put_mem_node(drm_dev, c_node, m_node);
593 mutex_unlock(&c_node->mem_lock);
594 return ERR_PTR(-EFAULT);
595 }
596 list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]);
597 mutex_unlock(&c_node->mem_lock);
598
599 return m_node;
600}
601
602static void ipp_clean_mem_nodes(struct drm_device *drm_dev,
603 struct drm_exynos_ipp_cmd_node *c_node, int ops)
604{
605 struct drm_exynos_ipp_mem_node *m_node, *tm_node;
606 struct list_head *head = &c_node->mem_list[ops];
607
608 mutex_lock(&c_node->mem_lock);
609
610 list_for_each_entry_safe(m_node, tm_node, head, list) {
611 int ret;
612
613 ret = ipp_put_mem_node(drm_dev, c_node, m_node);
614 if (ret)
615 DRM_ERROR("failed to put m_node.\n");
616 }
617
618 mutex_unlock(&c_node->mem_lock);
619}
620
621static int ipp_get_event(struct drm_device *drm_dev,
622 struct drm_exynos_ipp_cmd_node *c_node,
623 struct drm_exynos_ipp_queue_buf *qbuf)
624{
625 struct drm_exynos_ipp_send_event *e;
626 int ret;
627
628 DRM_DEBUG_KMS("ops_id[%d]buf_id[%d]\n", qbuf->ops_id, qbuf->buf_id);
629
630 e = kzalloc(sizeof(*e), GFP_KERNEL);
631 if (!e)
632 return -ENOMEM;
633
634 /* make event */
635 e->event.base.type = DRM_EXYNOS_IPP_EVENT;
636 e->event.base.length = sizeof(e->event);
637 e->event.user_data = qbuf->user_data;
638 e->event.prop_id = qbuf->prop_id;
639 e->event.buf_id[EXYNOS_DRM_OPS_DST] = qbuf->buf_id;
640
641 ret = drm_event_reserve_init(drm_dev, c_node->filp, &e->base, &e->event.base);
642 if (ret) {
643 kfree(e);
644 return ret;
645 }
646
647 mutex_lock(&c_node->event_lock);
648 list_add_tail(&e->base.link, &c_node->event_list);
649 mutex_unlock(&c_node->event_lock);
650
651 return 0;
652}
653
654static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node,
655 struct drm_exynos_ipp_queue_buf *qbuf)
656{
657 struct drm_exynos_ipp_send_event *e, *te;
658 int count = 0;
659
660 mutex_lock(&c_node->event_lock);
661 list_for_each_entry_safe(e, te, &c_node->event_list, base.link) {
662 DRM_DEBUG_KMS("count[%d]e[%pK]\n", count++, e);
663
664 /*
665 * qbuf == NULL condition means all event deletion.
666 * stop operations want to delete all event list.
667 * another case delete only same buf id.
668 */
669 if (!qbuf) {
670 /* delete list */
671 list_del(&e->base.link);
672 kfree(e);
673 }
674
675 /* compare buffer id */
676 if (qbuf && (qbuf->buf_id ==
677 e->event.buf_id[EXYNOS_DRM_OPS_DST])) {
678 /* delete list */
679 list_del(&e->base.link);
680 kfree(e);
681 goto out_unlock;
682 }
683 }
684
685out_unlock:
686 mutex_unlock(&c_node->event_lock);
687 return;
688}
689
690static void ipp_clean_cmd_node(struct ipp_context *ctx,
691 struct drm_exynos_ipp_cmd_node *c_node)
692{
693 int i;
694
695 /* cancel works */
696 cancel_work_sync(&c_node->start_work->work);
697 cancel_work_sync(&c_node->stop_work->work);
698 cancel_work_sync(&c_node->event_work->work);
699
700 /* put event */
701 ipp_put_event(c_node, NULL);
702
703 for_each_ipp_ops(i)
704 ipp_clean_mem_nodes(ctx->subdrv.drm_dev, c_node, i);
705
706 /* delete list */
707 list_del(&c_node->list);
708
709 ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock,
710 c_node->property.prop_id);
711
712 /* destroy mutex */
713 mutex_destroy(&c_node->lock);
714 mutex_destroy(&c_node->mem_lock);
715 mutex_destroy(&c_node->event_lock);
716
717 /* free command node */
718 kfree(c_node->start_work);
719 kfree(c_node->stop_work);
720 kfree(c_node->event_work);
721 kfree(c_node);
722}
723
724static bool ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node)
725{
726 switch (c_node->property.cmd) {
727 case IPP_CMD_WB:
728 return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]);
729 case IPP_CMD_OUTPUT:
730 return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]);
731 case IPP_CMD_M2M:
732 default:
733 return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]) &&
734 !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]);
735 }
736}
737
738static struct drm_exynos_ipp_mem_node
739 *ipp_find_mem_node(struct drm_exynos_ipp_cmd_node *c_node,
740 struct drm_exynos_ipp_queue_buf *qbuf)
741{
742 struct drm_exynos_ipp_mem_node *m_node;
743 struct list_head *head;
744 int count = 0;
745
746 DRM_DEBUG_KMS("buf_id[%d]\n", qbuf->buf_id);
747
748 /* source/destination memory list */
749 head = &c_node->mem_list[qbuf->ops_id];
750
751 /* find memory node from memory list */
752 list_for_each_entry(m_node, head, list) {
753 DRM_DEBUG_KMS("count[%d]m_node[%pK]\n", count++, m_node);
754
755 /* compare buffer id */
756 if (m_node->buf_id == qbuf->buf_id)
757 return m_node;
758 }
759
760 return NULL;
761}
762
763static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,
764 struct drm_exynos_ipp_cmd_node *c_node,
765 struct drm_exynos_ipp_mem_node *m_node)
766{
767 struct exynos_drm_ipp_ops *ops = NULL;
768 int ret = 0;
769
770 DRM_DEBUG_KMS("node[%pK]\n", m_node);
771
772 if (!m_node) {
773 DRM_ERROR("invalid queue node.\n");
774 return -EFAULT;
775 }
776
777 DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);
778
779 /* get operations callback */
780 ops = ippdrv->ops[m_node->ops_id];
781 if (!ops) {
782 DRM_ERROR("not support ops.\n");
783 return -EFAULT;
784 }
785
786 /* set address and enable irq */
787 if (ops->set_addr) {
788 ret = ops->set_addr(ippdrv->dev, &m_node->buf_info,
789 m_node->buf_id, IPP_BUF_ENQUEUE);
790 if (ret) {
791 DRM_ERROR("failed to set addr.\n");
792 return ret;
793 }
794 }
795
796 return ret;
797}
798
799static void ipp_handle_cmd_work(struct device *dev,
800 struct exynos_drm_ippdrv *ippdrv,
801 struct drm_exynos_ipp_cmd_work *cmd_work,
802 struct drm_exynos_ipp_cmd_node *c_node)
803{
804 struct ipp_context *ctx = get_ipp_context(dev);
805
806 cmd_work->ippdrv = ippdrv;
807 cmd_work->c_node = c_node;
808 queue_work(ctx->cmd_workq, &cmd_work->work);
809}
810
811static int ipp_queue_buf_with_run(struct device *dev,
812 struct drm_exynos_ipp_cmd_node *c_node,
813 struct drm_exynos_ipp_mem_node *m_node,
814 struct drm_exynos_ipp_queue_buf *qbuf)
815{
816 struct exynos_drm_ippdrv *ippdrv;
817 struct drm_exynos_ipp_property *property;
818 struct exynos_drm_ipp_ops *ops;
819 int ret;
820
821 ippdrv = ipp_find_drv_by_handle(qbuf->prop_id);
822 if (IS_ERR(ippdrv)) {
823 DRM_ERROR("failed to get ipp driver.\n");
824 return -EFAULT;
825 }
826
827 ops = ippdrv->ops[qbuf->ops_id];
828 if (!ops) {
829 DRM_ERROR("failed to get ops.\n");
830 return -EFAULT;
831 }
832
833 property = &c_node->property;
834
835 if (c_node->state != IPP_STATE_START) {
836 DRM_DEBUG_KMS("bypass for invalid state.\n");
837 return 0;
838 }
839
840 mutex_lock(&c_node->mem_lock);
841 if (!ipp_check_mem_list(c_node)) {
842 mutex_unlock(&c_node->mem_lock);
843 DRM_DEBUG_KMS("empty memory.\n");
844 return 0;
845 }
846
847 /*
848 * If set destination buffer and enabled clock,
849 * then m2m operations need start operations at queue_buf
850 */
851 if (ipp_is_m2m_cmd(property->cmd)) {
852 struct drm_exynos_ipp_cmd_work *cmd_work = c_node->start_work;
853
854 cmd_work->ctrl = IPP_CTRL_PLAY;
855 ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node);
856 } else {
857 ret = ipp_set_mem_node(ippdrv, c_node, m_node);
858 if (ret) {
859 mutex_unlock(&c_node->mem_lock);
860 DRM_ERROR("failed to set m node.\n");
861 return ret;
862 }
863 }
864 mutex_unlock(&c_node->mem_lock);
865
866 return 0;
867}
868
869static void ipp_clean_queue_buf(struct drm_device *drm_dev,
870 struct drm_exynos_ipp_cmd_node *c_node,
871 struct drm_exynos_ipp_queue_buf *qbuf)
872{
873 struct drm_exynos_ipp_mem_node *m_node, *tm_node;
874
875 /* delete list */
876 mutex_lock(&c_node->mem_lock);
877 list_for_each_entry_safe(m_node, tm_node,
878 &c_node->mem_list[qbuf->ops_id], list) {
879 if (m_node->buf_id == qbuf->buf_id &&
880 m_node->ops_id == qbuf->ops_id)
881 ipp_put_mem_node(drm_dev, c_node, m_node);
882 }
883 mutex_unlock(&c_node->mem_lock);
884}
885
886int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
887 struct drm_file *file)
888{
889 struct drm_exynos_file_private *file_priv = file->driver_priv;
890 struct device *dev = file_priv->ipp_dev;
891 struct ipp_context *ctx = get_ipp_context(dev);
892 struct drm_exynos_ipp_queue_buf *qbuf = data;
893 struct drm_exynos_ipp_cmd_node *c_node;
894 struct drm_exynos_ipp_mem_node *m_node;
895 int ret;
896
897 if (!qbuf) {
898 DRM_ERROR("invalid buf parameter.\n");
899 return -EINVAL;
900 }
901
902 if (qbuf->ops_id >= EXYNOS_DRM_OPS_MAX) {
903 DRM_ERROR("invalid ops parameter.\n");
904 return -EINVAL;
905 }
906
907 DRM_DEBUG_KMS("prop_id[%d]ops_id[%s]buf_id[%d]buf_type[%d]\n",
908 qbuf->prop_id, qbuf->ops_id ? "dst" : "src",
909 qbuf->buf_id, qbuf->buf_type);
910
911 /* find command node */
912 c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
913 qbuf->prop_id);
914 if (!c_node || c_node->filp != file) {
915 DRM_ERROR("failed to get command node.\n");
916 return -ENODEV;
917 }
918
919 /* buffer control */
920 switch (qbuf->buf_type) {
921 case IPP_BUF_ENQUEUE:
922 /* get memory node */
923 m_node = ipp_get_mem_node(drm_dev, c_node, qbuf);
924 if (IS_ERR(m_node)) {
925 DRM_ERROR("failed to get m_node.\n");
926 return PTR_ERR(m_node);
927 }
928
929 /*
930 * first step get event for destination buffer.
931 * and second step when M2M case run with destination buffer
932 * if needed.
933 */
934 if (qbuf->ops_id == EXYNOS_DRM_OPS_DST) {
935 /* get event for destination buffer */
936 ret = ipp_get_event(drm_dev, c_node, qbuf);
937 if (ret) {
938 DRM_ERROR("failed to get event.\n");
939 goto err_clean_node;
940 }
941
942 /*
943 * M2M case run play control for streaming feature.
944 * other case set address and waiting.
945 */
946 ret = ipp_queue_buf_with_run(dev, c_node, m_node, qbuf);
947 if (ret) {
948 DRM_ERROR("failed to run command.\n");
949 goto err_clean_node;
950 }
951 }
952 break;
953 case IPP_BUF_DEQUEUE:
954 mutex_lock(&c_node->lock);
955
956 /* put event for destination buffer */
957 if (qbuf->ops_id == EXYNOS_DRM_OPS_DST)
958 ipp_put_event(c_node, qbuf);
959
960 ipp_clean_queue_buf(drm_dev, c_node, qbuf);
961
962 mutex_unlock(&c_node->lock);
963 break;
964 default:
965 DRM_ERROR("invalid buffer control.\n");
966 return -EINVAL;
967 }
968
969 return 0;
970
971err_clean_node:
972 DRM_ERROR("clean memory nodes.\n");
973
974 ipp_clean_queue_buf(drm_dev, c_node, qbuf);
975 return ret;
976}
977
978static bool exynos_drm_ipp_check_valid(struct device *dev,
979 enum drm_exynos_ipp_ctrl ctrl, enum drm_exynos_ipp_state state)
980{
981 if (ctrl != IPP_CTRL_PLAY) {
982 if (pm_runtime_suspended(dev)) {
983 DRM_ERROR("pm:runtime_suspended.\n");
984 goto err_status;
985 }
986 }
987
988 switch (ctrl) {
989 case IPP_CTRL_PLAY:
990 if (state != IPP_STATE_IDLE)
991 goto err_status;
992 break;
993 case IPP_CTRL_STOP:
994 if (state == IPP_STATE_STOP)
995 goto err_status;
996 break;
997 case IPP_CTRL_PAUSE:
998 if (state != IPP_STATE_START)
999 goto err_status;
1000 break;
1001 case IPP_CTRL_RESUME:
1002 if (state != IPP_STATE_STOP)
1003 goto err_status;
1004 break;
1005 default:
1006 DRM_ERROR("invalid state.\n");
1007 goto err_status;
1008 }
1009
1010 return true;
1011
1012err_status:
1013 DRM_ERROR("invalid status:ctrl[%d]state[%d]\n", ctrl, state);
1014 return false;
1015}
1016
1017int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
1018 struct drm_file *file)
1019{
1020 struct drm_exynos_file_private *file_priv = file->driver_priv;
1021 struct exynos_drm_ippdrv *ippdrv = NULL;
1022 struct device *dev = file_priv->ipp_dev;
1023 struct ipp_context *ctx = get_ipp_context(dev);
1024 struct drm_exynos_ipp_cmd_ctrl *cmd_ctrl = data;
1025 struct drm_exynos_ipp_cmd_work *cmd_work;
1026 struct drm_exynos_ipp_cmd_node *c_node;
1027
1028 if (!ctx) {
1029 DRM_ERROR("invalid context.\n");
1030 return -EINVAL;
1031 }
1032
1033 if (!cmd_ctrl) {
1034 DRM_ERROR("invalid control parameter.\n");
1035 return -EINVAL;
1036 }
1037
1038 DRM_DEBUG_KMS("ctrl[%d]prop_id[%d]\n",
1039 cmd_ctrl->ctrl, cmd_ctrl->prop_id);
1040
1041 ippdrv = ipp_find_drv_by_handle(cmd_ctrl->prop_id);
1042 if (IS_ERR(ippdrv)) {
1043 DRM_ERROR("failed to get ipp driver.\n");
1044 return PTR_ERR(ippdrv);
1045 }
1046
1047 c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
1048 cmd_ctrl->prop_id);
1049 if (!c_node || c_node->filp != file) {
1050 DRM_ERROR("invalid command node list.\n");
1051 return -ENODEV;
1052 }
1053
1054 if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl,
1055 c_node->state)) {
1056 DRM_ERROR("invalid state.\n");
1057 return -EINVAL;
1058 }
1059
1060 switch (cmd_ctrl->ctrl) {
1061 case IPP_CTRL_PLAY:
1062 if (pm_runtime_suspended(ippdrv->dev))
1063 pm_runtime_get_sync(ippdrv->dev);
1064
1065 c_node->state = IPP_STATE_START;
1066
1067 cmd_work = c_node->start_work;
1068 cmd_work->ctrl = cmd_ctrl->ctrl;
1069 ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node);
1070 break;
1071 case IPP_CTRL_STOP:
1072 cmd_work = c_node->stop_work;
1073 cmd_work->ctrl = cmd_ctrl->ctrl;
1074 ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node);
1075
1076 if (!wait_for_completion_timeout(&c_node->stop_complete,
1077 msecs_to_jiffies(300))) {
1078 DRM_ERROR("timeout stop:prop_id[%d]\n",
1079 c_node->property.prop_id);
1080 }
1081
1082 c_node->state = IPP_STATE_STOP;
1083 ippdrv->dedicated = false;
1084 mutex_lock(&ippdrv->cmd_lock);
1085 ipp_clean_cmd_node(ctx, c_node);
1086
1087 if (list_empty(&ippdrv->cmd_list))
1088 pm_runtime_put_sync(ippdrv->dev);
1089 mutex_unlock(&ippdrv->cmd_lock);
1090 break;
1091 case IPP_CTRL_PAUSE:
1092 cmd_work = c_node->stop_work;
1093 cmd_work->ctrl = cmd_ctrl->ctrl;
1094 ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node);
1095
1096 if (!wait_for_completion_timeout(&c_node->stop_complete,
1097 msecs_to_jiffies(200))) {
1098 DRM_ERROR("timeout stop:prop_id[%d]\n",
1099 c_node->property.prop_id);
1100 }
1101
1102 c_node->state = IPP_STATE_STOP;
1103 break;
1104 case IPP_CTRL_RESUME:
1105 c_node->state = IPP_STATE_START;
1106 cmd_work = c_node->start_work;
1107 cmd_work->ctrl = cmd_ctrl->ctrl;
1108 ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node);
1109 break;
1110 default:
1111 DRM_ERROR("could not support this state currently.\n");
1112 return -EINVAL;
1113 }
1114
1115 DRM_DEBUG_KMS("done ctrl[%d]prop_id[%d]\n",
1116 cmd_ctrl->ctrl, cmd_ctrl->prop_id);
1117
1118 return 0;
1119}
1120
1121int exynos_drm_ippnb_register(struct notifier_block *nb)
1122{
1123 return blocking_notifier_chain_register(
1124 &exynos_drm_ippnb_list, nb);
1125}
1126
1127int exynos_drm_ippnb_unregister(struct notifier_block *nb)
1128{
1129 return blocking_notifier_chain_unregister(
1130 &exynos_drm_ippnb_list, nb);
1131}
1132
1133int exynos_drm_ippnb_send_event(unsigned long val, void *v)
1134{
1135 return blocking_notifier_call_chain(
1136 &exynos_drm_ippnb_list, val, v);
1137}
1138
1139static int ipp_set_property(struct exynos_drm_ippdrv *ippdrv,
1140 struct drm_exynos_ipp_property *property)
1141{
1142 struct exynos_drm_ipp_ops *ops = NULL;
1143 bool swap = false;
1144 int ret, i;
1145
1146 if (!property) {
1147 DRM_ERROR("invalid property parameter.\n");
1148 return -EINVAL;
1149 }
1150
1151 DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
1152
1153 /* reset h/w block */
1154 if (ippdrv->reset &&
1155 ippdrv->reset(ippdrv->dev)) {
1156 return -EINVAL;
1157 }
1158
1159 /* set source,destination operations */
1160 for_each_ipp_ops(i) {
1161 struct drm_exynos_ipp_config *config =
1162 &property->config[i];
1163
1164 ops = ippdrv->ops[i];
1165 if (!ops || !config) {
1166 DRM_ERROR("not support ops and config.\n");
1167 return -EINVAL;
1168 }
1169
1170 /* set format */
1171 if (ops->set_fmt) {
1172 ret = ops->set_fmt(ippdrv->dev, config->fmt);
1173 if (ret)
1174 return ret;
1175 }
1176
1177 /* set transform for rotation, flip */
1178 if (ops->set_transf) {
1179 ret = ops->set_transf(ippdrv->dev, config->degree,
1180 config->flip, &swap);
1181 if (ret)
1182 return ret;
1183 }
1184
1185 /* set size */
1186 if (ops->set_size) {
1187 ret = ops->set_size(ippdrv->dev, swap, &config->pos,
1188 &config->sz);
1189 if (ret)
1190 return ret;
1191 }
1192 }
1193
1194 return 0;
1195}
1196
1197static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
1198 struct drm_exynos_ipp_cmd_node *c_node)
1199{
1200 struct drm_exynos_ipp_mem_node *m_node;
1201 struct drm_exynos_ipp_property *property = &c_node->property;
1202 struct list_head *head;
1203 int ret, i;
1204
1205 DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
1206
1207 /* store command info in ippdrv */
1208 ippdrv->c_node = c_node;
1209
1210 mutex_lock(&c_node->mem_lock);
1211 if (!ipp_check_mem_list(c_node)) {
1212 DRM_DEBUG_KMS("empty memory.\n");
1213 ret = -ENOMEM;
1214 goto err_unlock;
1215 }
1216
1217 /* set current property in ippdrv */
1218 ret = ipp_set_property(ippdrv, property);
1219 if (ret) {
1220 DRM_ERROR("failed to set property.\n");
1221 ippdrv->c_node = NULL;
1222 goto err_unlock;
1223 }
1224
1225 /* check command */
1226 switch (property->cmd) {
1227 case IPP_CMD_M2M:
1228 for_each_ipp_ops(i) {
1229 /* source/destination memory list */
1230 head = &c_node->mem_list[i];
1231
1232 m_node = list_first_entry(head,
1233 struct drm_exynos_ipp_mem_node, list);
1234
1235 DRM_DEBUG_KMS("m_node[%pK]\n", m_node);
1236
1237 ret = ipp_set_mem_node(ippdrv, c_node, m_node);
1238 if (ret) {
1239 DRM_ERROR("failed to set m node.\n");
1240 goto err_unlock;
1241 }
1242 }
1243 break;
1244 case IPP_CMD_WB:
1245 /* destination memory list */
1246 head = &c_node->mem_list[EXYNOS_DRM_OPS_DST];
1247
1248 list_for_each_entry(m_node, head, list) {
1249 ret = ipp_set_mem_node(ippdrv, c_node, m_node);
1250 if (ret) {
1251 DRM_ERROR("failed to set m node.\n");
1252 goto err_unlock;
1253 }
1254 }
1255 break;
1256 case IPP_CMD_OUTPUT:
1257 /* source memory list */
1258 head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC];
1259
1260 list_for_each_entry(m_node, head, list) {
1261 ret = ipp_set_mem_node(ippdrv, c_node, m_node);
1262 if (ret) {
1263 DRM_ERROR("failed to set m node.\n");
1264 goto err_unlock;
1265 }
1266 }
1267 break;
1268 default:
1269 DRM_ERROR("invalid operations.\n");
1270 ret = -EINVAL;
1271 goto err_unlock;
1272 }
1273 mutex_unlock(&c_node->mem_lock);
1274
1275 DRM_DEBUG_KMS("cmd[%d]\n", property->cmd);
1276
1277 /* start operations */
1278 if (ippdrv->start) {
1279 ret = ippdrv->start(ippdrv->dev, property->cmd);
1280 if (ret) {
1281 DRM_ERROR("failed to start ops.\n");
1282 ippdrv->c_node = NULL;
1283 return ret;
1284 }
1285 }
1286
1287 return 0;
1288
1289err_unlock:
1290 mutex_unlock(&c_node->mem_lock);
1291 ippdrv->c_node = NULL;
1292 return ret;
1293}
1294
1295static int ipp_stop_property(struct drm_device *drm_dev,
1296 struct exynos_drm_ippdrv *ippdrv,
1297 struct drm_exynos_ipp_cmd_node *c_node)
1298{
1299 struct drm_exynos_ipp_property *property = &c_node->property;
1300 int i;
1301
1302 DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
1303
1304 /* stop operations */
1305 if (ippdrv->stop)
1306 ippdrv->stop(ippdrv->dev, property->cmd);
1307
1308 /* check command */
1309 switch (property->cmd) {
1310 case IPP_CMD_M2M:
1311 for_each_ipp_ops(i)
1312 ipp_clean_mem_nodes(drm_dev, c_node, i);
1313 break;
1314 case IPP_CMD_WB:
1315 ipp_clean_mem_nodes(drm_dev, c_node, EXYNOS_DRM_OPS_DST);
1316 break;
1317 case IPP_CMD_OUTPUT:
1318 ipp_clean_mem_nodes(drm_dev, c_node, EXYNOS_DRM_OPS_SRC);
1319 break;
1320 default:
1321 DRM_ERROR("invalid operations.\n");
1322 return -EINVAL;
1323 }
1324
1325 return 0;
1326}
1327
1328void ipp_sched_cmd(struct work_struct *work)
1329{
1330 struct drm_exynos_ipp_cmd_work *cmd_work =
1331 container_of(work, struct drm_exynos_ipp_cmd_work, work);
1332 struct exynos_drm_ippdrv *ippdrv;
1333 struct drm_exynos_ipp_cmd_node *c_node;
1334 struct drm_exynos_ipp_property *property;
1335 int ret;
1336
1337 ippdrv = cmd_work->ippdrv;
1338 if (!ippdrv) {
1339 DRM_ERROR("invalid ippdrv list.\n");
1340 return;
1341 }
1342
1343 c_node = cmd_work->c_node;
1344 if (!c_node) {
1345 DRM_ERROR("invalid command node list.\n");
1346 return;
1347 }
1348
1349 mutex_lock(&c_node->lock);
1350
1351 property = &c_node->property;
1352
1353 switch (cmd_work->ctrl) {
1354 case IPP_CTRL_PLAY:
1355 case IPP_CTRL_RESUME:
1356 ret = ipp_start_property(ippdrv, c_node);
1357 if (ret) {
1358 DRM_ERROR("failed to start property:prop_id[%d]\n",
1359 c_node->property.prop_id);
1360 goto err_unlock;
1361 }
1362
1363 /*
1364 * M2M case supports wait_completion of transfer.
1365 * because M2M case supports single unit operation
1366 * with multiple queue.
1367 * M2M need to wait completion of data transfer.
1368 */
1369 if (ipp_is_m2m_cmd(property->cmd)) {
1370 if (!wait_for_completion_timeout
1371 (&c_node->start_complete, msecs_to_jiffies(200))) {
1372 DRM_ERROR("timeout event:prop_id[%d]\n",
1373 c_node->property.prop_id);
1374 goto err_unlock;
1375 }
1376 }
1377 break;
1378 case IPP_CTRL_STOP:
1379 case IPP_CTRL_PAUSE:
1380 ret = ipp_stop_property(ippdrv->drm_dev, ippdrv,
1381 c_node);
1382 if (ret) {
1383 DRM_ERROR("failed to stop property.\n");
1384 goto err_unlock;
1385 }
1386
1387 complete(&c_node->stop_complete);
1388 break;
1389 default:
1390 DRM_ERROR("unknown control type\n");
1391 break;
1392 }
1393
1394 DRM_DEBUG_KMS("ctrl[%d] done.\n", cmd_work->ctrl);
1395
1396err_unlock:
1397 mutex_unlock(&c_node->lock);
1398}
1399
1400static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
1401 struct drm_exynos_ipp_cmd_node *c_node, int *buf_id)
1402{
1403 struct drm_device *drm_dev = ippdrv->drm_dev;
1404 struct drm_exynos_ipp_property *property = &c_node->property;
1405 struct drm_exynos_ipp_mem_node *m_node;
1406 struct drm_exynos_ipp_queue_buf qbuf;
1407 struct drm_exynos_ipp_send_event *e;
1408 struct list_head *head;
1409 struct timeval now;
1410 u32 tbuf_id[EXYNOS_DRM_OPS_MAX] = {0, };
1411 int ret, i;
1412
1413 for_each_ipp_ops(i)
1414 DRM_DEBUG_KMS("%s buf_id[%d]\n", i ? "dst" : "src", buf_id[i]);
1415
1416 if (!drm_dev) {
1417 DRM_ERROR("failed to get drm_dev.\n");
1418 return -EINVAL;
1419 }
1420
1421 if (!property) {
1422 DRM_ERROR("failed to get property.\n");
1423 return -EINVAL;
1424 }
1425
1426 mutex_lock(&c_node->event_lock);
1427 if (list_empty(&c_node->event_list)) {
1428 DRM_DEBUG_KMS("event list is empty.\n");
1429 ret = 0;
1430 goto err_event_unlock;
1431 }
1432
1433 mutex_lock(&c_node->mem_lock);
1434 if (!ipp_check_mem_list(c_node)) {
1435 DRM_DEBUG_KMS("empty memory.\n");
1436 ret = 0;
1437 goto err_mem_unlock;
1438 }
1439
1440 /* check command */
1441 switch (property->cmd) {
1442 case IPP_CMD_M2M:
1443 for_each_ipp_ops(i) {
1444 /* source/destination memory list */
1445 head = &c_node->mem_list[i];
1446
1447 m_node = list_first_entry(head,
1448 struct drm_exynos_ipp_mem_node, list);
1449
1450 tbuf_id[i] = m_node->buf_id;
1451 DRM_DEBUG_KMS("%s buf_id[%d]\n",
1452 i ? "dst" : "src", tbuf_id[i]);
1453
1454 ret = ipp_put_mem_node(drm_dev, c_node, m_node);
1455 if (ret)
1456 DRM_ERROR("failed to put m_node.\n");
1457 }
1458 break;
1459 case IPP_CMD_WB:
1460 /* clear buf for finding */
1461 memset(&qbuf, 0x0, sizeof(qbuf));
1462 qbuf.ops_id = EXYNOS_DRM_OPS_DST;
1463 qbuf.buf_id = buf_id[EXYNOS_DRM_OPS_DST];
1464
1465 /* get memory node entry */
1466 m_node = ipp_find_mem_node(c_node, &qbuf);
1467 if (!m_node) {
1468 DRM_ERROR("empty memory node.\n");
1469 ret = -ENOMEM;
1470 goto err_mem_unlock;
1471 }
1472
1473 tbuf_id[EXYNOS_DRM_OPS_DST] = m_node->buf_id;
1474
1475 ret = ipp_put_mem_node(drm_dev, c_node, m_node);
1476 if (ret)
1477 DRM_ERROR("failed to put m_node.\n");
1478 break;
1479 case IPP_CMD_OUTPUT:
1480 /* source memory list */
1481 head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC];
1482
1483 m_node = list_first_entry(head,
1484 struct drm_exynos_ipp_mem_node, list);
1485
1486 tbuf_id[EXYNOS_DRM_OPS_SRC] = m_node->buf_id;
1487
1488 ret = ipp_put_mem_node(drm_dev, c_node, m_node);
1489 if (ret)
1490 DRM_ERROR("failed to put m_node.\n");
1491 break;
1492 default:
1493 DRM_ERROR("invalid operations.\n");
1494 ret = -EINVAL;
1495 goto err_mem_unlock;
1496 }
1497 mutex_unlock(&c_node->mem_lock);
1498
1499 if (tbuf_id[EXYNOS_DRM_OPS_DST] != buf_id[EXYNOS_DRM_OPS_DST])
1500 DRM_ERROR("failed to match buf_id[%d %d]prop_id[%d]\n",
1501 tbuf_id[1], buf_id[1], property->prop_id);
1502
1503 /*
1504 * command node have event list of destination buffer
1505 * If destination buffer enqueue to mem list,
1506 * then we make event and link to event list tail.
1507 * so, we get first event for first enqueued buffer.
1508 */
1509 e = list_first_entry(&c_node->event_list,
1510 struct drm_exynos_ipp_send_event, base.link);
1511
1512 do_gettimeofday(&now);
1513 DRM_DEBUG_KMS("tv_sec[%ld]tv_usec[%ld]\n", now.tv_sec, now.tv_usec);
1514 e->event.tv_sec = now.tv_sec;
1515 e->event.tv_usec = now.tv_usec;
1516 e->event.prop_id = property->prop_id;
1517
1518 /* set buffer id about source destination */
1519 for_each_ipp_ops(i)
1520 e->event.buf_id[i] = tbuf_id[i];
1521
1522 drm_send_event(drm_dev, &e->base);
1523 mutex_unlock(&c_node->event_lock);
1524
1525 DRM_DEBUG_KMS("done cmd[%d]prop_id[%d]buf_id[%d]\n",
1526 property->cmd, property->prop_id, tbuf_id[EXYNOS_DRM_OPS_DST]);
1527
1528 return 0;
1529
1530err_mem_unlock:
1531 mutex_unlock(&c_node->mem_lock);
1532err_event_unlock:
1533 mutex_unlock(&c_node->event_lock);
1534 return ret;
1535}
1536
1537void ipp_sched_event(struct work_struct *work)
1538{
1539 struct drm_exynos_ipp_event_work *event_work =
1540 container_of(work, struct drm_exynos_ipp_event_work, work);
1541 struct exynos_drm_ippdrv *ippdrv;
1542 struct drm_exynos_ipp_cmd_node *c_node;
1543 int ret;
1544
1545 if (!event_work) {
1546 DRM_ERROR("failed to get event_work.\n");
1547 return;
1548 }
1549
1550 DRM_DEBUG_KMS("buf_id[%d]\n", event_work->buf_id[EXYNOS_DRM_OPS_DST]);
1551
1552 ippdrv = event_work->ippdrv;
1553 if (!ippdrv) {
1554 DRM_ERROR("failed to get ipp driver.\n");
1555 return;
1556 }
1557
1558 c_node = ippdrv->c_node;
1559 if (!c_node) {
1560 DRM_ERROR("failed to get command node.\n");
1561 return;
1562 }
1563
1564 /*
1565 * IPP supports command thread, event thread synchronization.
1566 * If IPP close immediately from user land, then IPP make
1567 * synchronization with command thread, so make complete event.
1568 * or going out operations.
1569 */
1570 if (c_node->state != IPP_STATE_START) {
1571 DRM_DEBUG_KMS("bypass state[%d]prop_id[%d]\n",
1572 c_node->state, c_node->property.prop_id);
1573 goto err_completion;
1574 }
1575
1576 ret = ipp_send_event(ippdrv, c_node, event_work->buf_id);
1577 if (ret) {
1578 DRM_ERROR("failed to send event.\n");
1579 goto err_completion;
1580 }
1581
1582err_completion:
1583 if (ipp_is_m2m_cmd(c_node->property.cmd))
1584 complete(&c_node->start_complete);
1585}
1586
1587static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
1588{
1589 struct ipp_context *ctx = get_ipp_context(dev);
1590 struct exynos_drm_ippdrv *ippdrv;
1591 int ret, count = 0;
1592
1593 /* get ipp driver entry */
1594 list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
1595 ippdrv->drm_dev = drm_dev;
1596
1597 ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv);
1598 if (ret < 0) {
1599 DRM_ERROR("failed to create id.\n");
1600 goto err;
1601 }
1602 ippdrv->prop_list.ipp_id = ret;
1603
1604 DRM_DEBUG_KMS("count[%d]ippdrv[%pK]ipp_id[%d]\n",
1605 count++, ippdrv, ret);
1606
1607 /* store parent device for node */
1608 ippdrv->parent_dev = dev;
1609
1610 /* store event work queue and handler */
1611 ippdrv->event_workq = ctx->event_workq;
1612 ippdrv->sched_event = ipp_sched_event;
1613 INIT_LIST_HEAD(&ippdrv->cmd_list);
1614 mutex_init(&ippdrv->cmd_lock);
1615
1616 ret = drm_iommu_attach_device(drm_dev, ippdrv->dev);
1617 if (ret) {
1618 DRM_ERROR("failed to activate iommu\n");
1619 goto err;
1620 }
1621 }
1622
1623 return 0;
1624
1625err:
1626 /* get ipp driver entry */
1627 list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list,
1628 drv_list) {
1629 drm_iommu_detach_device(drm_dev, ippdrv->dev);
1630
1631 ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock,
1632 ippdrv->prop_list.ipp_id);
1633 }
1634
1635 return ret;
1636}
1637
1638static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
1639{
1640 struct exynos_drm_ippdrv *ippdrv, *t;
1641 struct ipp_context *ctx = get_ipp_context(dev);
1642
1643 /* get ipp driver entry */
1644 list_for_each_entry_safe(ippdrv, t, &exynos_drm_ippdrv_list, drv_list) {
1645 drm_iommu_detach_device(drm_dev, ippdrv->dev);
1646
1647 ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock,
1648 ippdrv->prop_list.ipp_id);
1649
1650 ippdrv->drm_dev = NULL;
1651 exynos_drm_ippdrv_unregister(ippdrv);
1652 }
1653}
1654
1655static int ipp_subdrv_open(struct drm_device *drm_dev, struct device *dev,
1656 struct drm_file *file)
1657{
1658 struct drm_exynos_file_private *file_priv = file->driver_priv;
1659
1660 file_priv->ipp_dev = dev;
1661
1662 DRM_DEBUG_KMS("done priv[%pK]\n", dev);
1663
1664 return 0;
1665}
1666
1667static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev,
1668 struct drm_file *file)
1669{
1670 struct exynos_drm_ippdrv *ippdrv = NULL;
1671 struct ipp_context *ctx = get_ipp_context(dev);
1672 struct drm_exynos_ipp_cmd_node *c_node, *tc_node;
1673 int count = 0;
1674
1675 list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
1676 mutex_lock(&ippdrv->cmd_lock);
1677 list_for_each_entry_safe(c_node, tc_node,
1678 &ippdrv->cmd_list, list) {
1679 DRM_DEBUG_KMS("count[%d]ippdrv[%pK]\n",
1680 count++, ippdrv);
1681
1682 if (c_node->filp == file) {
1683 /*
1684 * userland goto unnormal state. process killed.
1685 * and close the file.
1686 * so, IPP didn't called stop cmd ctrl.
1687 * so, we are make stop operation in this state.
1688 */
1689 if (c_node->state == IPP_STATE_START) {
1690 ipp_stop_property(drm_dev, ippdrv,
1691 c_node);
1692 c_node->state = IPP_STATE_STOP;
1693 }
1694
1695 ippdrv->dedicated = false;
1696 ipp_clean_cmd_node(ctx, c_node);
1697 if (list_empty(&ippdrv->cmd_list))
1698 pm_runtime_put_sync(ippdrv->dev);
1699 }
1700 }
1701 mutex_unlock(&ippdrv->cmd_lock);
1702 }
1703
1704 return;
1705}
1706
1707static int ipp_probe(struct platform_device *pdev)
1708{
1709 struct device *dev = &pdev->dev;
1710 struct ipp_context *ctx;
1711 struct exynos_drm_subdrv *subdrv;
1712 int ret;
1713
1714 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
1715 if (!ctx)
1716 return -ENOMEM;
1717
1718 mutex_init(&ctx->ipp_lock);
1719 mutex_init(&ctx->prop_lock);
1720
1721 idr_init(&ctx->ipp_idr);
1722 idr_init(&ctx->prop_idr);
1723
1724 /*
1725 * create single thread for ipp event
1726 * IPP supports event thread for IPP drivers.
1727 * IPP driver send event_work to this thread.
1728 * and IPP event thread send event to user process.
1729 */
1730 ctx->event_workq = create_singlethread_workqueue("ipp_event");
1731 if (!ctx->event_workq) {
1732 dev_err(dev, "failed to create event workqueue\n");
1733 return -EINVAL;
1734 }
1735
1736 /*
1737 * create single thread for ipp command
1738 * IPP supports command thread for user process.
1739 * user process make command node using set property ioctl.
1740 * and make start_work and send this work to command thread.
1741 * and then this command thread start property.
1742 */
1743 ctx->cmd_workq = create_singlethread_workqueue("ipp_cmd");
1744 if (!ctx->cmd_workq) {
1745 dev_err(dev, "failed to create cmd workqueue\n");
1746 ret = -EINVAL;
1747 goto err_event_workq;
1748 }
1749
1750 /* set sub driver informations */
1751 subdrv = &ctx->subdrv;
1752 subdrv->dev = dev;
1753 subdrv->probe = ipp_subdrv_probe;
1754 subdrv->remove = ipp_subdrv_remove;
1755 subdrv->open = ipp_subdrv_open;
1756 subdrv->close = ipp_subdrv_close;
1757
1758 platform_set_drvdata(pdev, ctx);
1759
1760 ret = exynos_drm_subdrv_register(subdrv);
1761 if (ret < 0) {
1762 DRM_ERROR("failed to register drm ipp device.\n");
1763 goto err_cmd_workq;
1764 }
1765
1766 dev_info(dev, "drm ipp registered successfully.\n");
1767
1768 return 0;
1769
1770err_cmd_workq:
1771 destroy_workqueue(ctx->cmd_workq);
1772err_event_workq:
1773 destroy_workqueue(ctx->event_workq);
1774 return ret;
1775}
1776
1777static int ipp_remove(struct platform_device *pdev)
1778{
1779 struct ipp_context *ctx = platform_get_drvdata(pdev);
1780
1781 /* unregister sub driver */
1782 exynos_drm_subdrv_unregister(&ctx->subdrv);
1783
1784 /* remove,destroy ipp idr */
1785 idr_destroy(&ctx->ipp_idr);
1786 idr_destroy(&ctx->prop_idr);
1787
1788 mutex_destroy(&ctx->ipp_lock);
1789 mutex_destroy(&ctx->prop_lock);
1790
1791 /* destroy command, event work queue */
1792 destroy_workqueue(ctx->cmd_workq);
1793 destroy_workqueue(ctx->event_workq);
1794
1795 return 0;
1796}
1797
1798struct platform_driver ipp_driver = {
1799 .probe = ipp_probe,
1800 .remove = ipp_remove,
1801 .driver = {
1802 .name = "exynos-drm-ipp",
1803 .owner = THIS_MODULE,
1804 },
1805};
1806
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 @@
1/*
2 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
3 *
4 * Authors:
5 * Eunchul Kim <chulspro.kim@samsung.com>
6 * Jinyoung Jeon <jy0.jeon@samsung.com>
7 * Sangmin Lee <lsmin.lee@samsung.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */
14
15#ifndef _EXYNOS_DRM_IPP_H_
16#define _EXYNOS_DRM_IPP_H_
17
18#define for_each_ipp_ops(pos) \
19 for (pos = 0; pos < EXYNOS_DRM_OPS_MAX; pos++)
20#define for_each_ipp_planar(pos) \
21 for (pos = 0; pos < EXYNOS_DRM_PLANAR_MAX; pos++)
22
23#define IPP_GET_LCD_WIDTH _IOR('F', 302, int)
24#define IPP_GET_LCD_HEIGHT _IOR('F', 303, int)
25#define IPP_SET_WRITEBACK _IOW('F', 304, u32)
26
27/* definition of state */
28enum drm_exynos_ipp_state {
29 IPP_STATE_IDLE,
30 IPP_STATE_START,
31 IPP_STATE_STOP,
32};
33
34/*
35 * A structure of command work information.
36 * @work: work structure.
37 * @ippdrv: current work ippdrv.
38 * @c_node: command node information.
39 * @ctrl: command control.
40 */
41struct drm_exynos_ipp_cmd_work {
42 struct work_struct work;
43 struct exynos_drm_ippdrv *ippdrv;
44 struct drm_exynos_ipp_cmd_node *c_node;
45 enum drm_exynos_ipp_ctrl ctrl;
46};
47
48/*
49 * A structure of command node.
50 *
51 * @list: list head to command queue information.
52 * @event_list: list head of event.
53 * @mem_list: list head to source,destination memory queue information.
54 * @lock: lock for synchronization of access to ioctl.
55 * @mem_lock: lock for synchronization of access to memory nodes.
56 * @event_lock: lock for synchronization of access to scheduled event.
57 * @start_complete: completion of start of command.
58 * @stop_complete: completion of stop of command.
59 * @property: property information.
60 * @start_work: start command work structure.
61 * @stop_work: stop command work structure.
62 * @event_work: event work structure.
63 * @state: state of command node.
64 * @filp: associated file pointer.
65 */
66struct drm_exynos_ipp_cmd_node {
67 struct list_head list;
68 struct list_head event_list;
69 struct list_head mem_list[EXYNOS_DRM_OPS_MAX];
70 struct mutex lock;
71 struct mutex mem_lock;
72 struct mutex event_lock;
73 struct completion start_complete;
74 struct completion stop_complete;
75 struct drm_exynos_ipp_property property;
76 struct drm_exynos_ipp_cmd_work *start_work;
77 struct drm_exynos_ipp_cmd_work *stop_work;
78 struct drm_exynos_ipp_event_work *event_work;
79 enum drm_exynos_ipp_state state;
80 struct drm_file *filp;
81};
82
83/*
84 * A structure of buffer information.
85 *
86 * @handles: Y, Cb, Cr each gem object handle.
87 * @base: Y, Cb, Cr each planar address.
88 */
89struct drm_exynos_ipp_buf_info {
90 unsigned long handles[EXYNOS_DRM_PLANAR_MAX];
91 dma_addr_t base[EXYNOS_DRM_PLANAR_MAX];
92};
93
94/*
95 * A structure of wb setting information.
96 *
97 * @enable: enable flag for wb.
98 * @refresh: HZ of the refresh rate.
99 */
100struct drm_exynos_ipp_set_wb {
101 __u32 enable;
102 __u32 refresh;
103};
104
105/*
106 * A structure of event work information.
107 *
108 * @work: work structure.
109 * @ippdrv: current work ippdrv.
110 * @buf_id: id of src, dst buffer.
111 */
112struct drm_exynos_ipp_event_work {
113 struct work_struct work;
114 struct exynos_drm_ippdrv *ippdrv;
115 u32 buf_id[EXYNOS_DRM_OPS_MAX];
116};
117
118/*
119 * A structure of source,destination operations.
120 *
121 * @set_fmt: set format of image.
122 * @set_transf: set transform(rotations, flip).
123 * @set_size: set size of region.
124 * @set_addr: set address for dma.
125 */
126struct exynos_drm_ipp_ops {
127 int (*set_fmt)(struct device *dev, u32 fmt);
128 int (*set_transf)(struct device *dev,
129 enum drm_exynos_degree degree,
130 enum drm_exynos_flip flip, bool *swap);
131 int (*set_size)(struct device *dev, int swap,
132 struct drm_exynos_pos *pos, struct drm_exynos_sz *sz);
133 int (*set_addr)(struct device *dev,
134 struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id,
135 enum drm_exynos_ipp_buf_type buf_type);
136};
137
138/*
139 * A structure of ipp driver.
140 *
141 * @drv_list: list head for registed sub driver information.
142 * @parent_dev: parent device information.
143 * @dev: platform device.
144 * @drm_dev: drm device.
145 * @dedicated: dedicated ipp device.
146 * @ops: source, destination operations.
147 * @event_workq: event work queue.
148 * @c_node: current command information.
149 * @cmd_list: list head for command information.
150 * @cmd_lock: lock for synchronization of access to cmd_list.
151 * @prop_list: property informations of current ipp driver.
152 * @check_property: check property about format, size, buffer.
153 * @reset: reset ipp block.
154 * @start: ipp each device start.
155 * @stop: ipp each device stop.
156 * @sched_event: work schedule handler.
157 */
158struct exynos_drm_ippdrv {
159 struct list_head drv_list;
160 struct device *parent_dev;
161 struct device *dev;
162 struct drm_device *drm_dev;
163 bool dedicated;
164 struct exynos_drm_ipp_ops *ops[EXYNOS_DRM_OPS_MAX];
165 struct workqueue_struct *event_workq;
166 struct drm_exynos_ipp_cmd_node *c_node;
167 struct list_head cmd_list;
168 struct mutex cmd_lock;
169 struct drm_exynos_ipp_prop_list prop_list;
170
171 int (*check_property)(struct device *dev,
172 struct drm_exynos_ipp_property *property);
173 int (*reset)(struct device *dev);
174 int (*start)(struct device *dev, enum drm_exynos_ipp_cmd cmd);
175 void (*stop)(struct device *dev, enum drm_exynos_ipp_cmd cmd);
176 void (*sched_event)(struct work_struct *work);
177};
178
179#ifdef CONFIG_DRM_EXYNOS_IPP
180extern int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv);
181extern int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv);
182extern int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,
183 struct drm_file *file);
184extern int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
185 struct drm_file *file);
186extern int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
187 struct drm_file *file);
188extern int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
189 struct drm_file *file);
190extern int exynos_drm_ippnb_register(struct notifier_block *nb);
191extern int exynos_drm_ippnb_unregister(struct notifier_block *nb);
192extern int exynos_drm_ippnb_send_event(unsigned long val, void *v);
193extern void ipp_sched_cmd(struct work_struct *work);
194extern void ipp_sched_event(struct work_struct *work);
195
196#else
197static inline int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv)
198{
199 return -ENODEV;
200}
201
202static inline int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv)
203{
204 return -ENODEV;
205}
206
207static inline int exynos_drm_ipp_get_property(struct drm_device *drm_dev,
208 void *data,
209 struct drm_file *file_priv)
210{
211 return -ENOTTY;
212}
213
214static inline int exynos_drm_ipp_set_property(struct drm_device *drm_dev,
215 void *data,
216 struct drm_file *file_priv)
217{
218 return -ENOTTY;
219}
220
221static inline int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev,
222 void *data,
223 struct drm_file *file)
224{
225 return -ENOTTY;
226}
227
228static inline int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev,
229 void *data,
230 struct drm_file *file)
231{
232 return -ENOTTY;
233}
234
235static inline int exynos_drm_ippnb_register(struct notifier_block *nb)
236{
237 return -ENODEV;
238}
239
240static inline int exynos_drm_ippnb_unregister(struct notifier_block *nb)
241{
242 return -ENODEV;
243}
244
245static inline int exynos_drm_ippnb_send_event(unsigned long val, void *v)
246{
247 return -ENOTTY;
248}
249#endif
250
251#endif /* _EXYNOS_DRM_IPP_H_ */
252
diff --git a/drivers/gpu/drm/exynos/regs-decon5433.h b/drivers/gpu/drm/exynos/regs-decon5433.h
new file mode 100644
index 000000000000..19ad9e47945e
--- /dev/null
+++ b/drivers/gpu/drm/exynos/regs-decon5433.h
@@ -0,0 +1,209 @@
1/*
2 * Copyright (C) 2014 Samsung Electronics Co.Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundationr
7 */
8
9#ifndef EXYNOS_REGS_DECON5433_H
10#define EXYNOS_REGS_DECON5433_H
11
12/* Exynos543X DECON */
13#define DECON_VIDCON0 0x0000
14#define DECON_VIDOUTCON0 0x0010
15#define DECON_WINCONx(n) (0x0020 + ((n) * 4))
16#define DECON_VIDOSDxH(n) (0x0080 + ((n) * 4))
17#define DECON_SHADOWCON 0x00A0
18#define DECON_VIDOSDxA(n) (0x00B0 + ((n) * 0x20))
19#define DECON_VIDOSDxB(n) (0x00B4 + ((n) * 0x20))
20#define DECON_VIDOSDxC(n) (0x00B8 + ((n) * 0x20))
21#define DECON_VIDOSDxD(n) (0x00BC + ((n) * 0x20))
22#define DECON_VIDOSDxE(n) (0x00C0 + ((n) * 0x20))
23#define DECON_VIDW0xADD0B0(n) (0x0150 + ((n) * 0x10))
24#define DECON_VIDW0xADD0B1(n) (0x0154 + ((n) * 0x10))
25#define DECON_VIDW0xADD0B2(n) (0x0158 + ((n) * 0x10))
26#define DECON_VIDW0xADD1B0(n) (0x01A0 + ((n) * 0x10))
27#define DECON_VIDW0xADD1B1(n) (0x01A4 + ((n) * 0x10))
28#define DECON_VIDW0xADD1B2(n) (0x01A8 + ((n) * 0x10))
29#define DECON_VIDW0xADD2(n) (0x0200 + ((n) * 4))
30#define DECON_LOCALxSIZE(n) (0x0214 + ((n) * 4))
31#define DECON_VIDINTCON0 0x0220
32#define DECON_VIDINTCON1 0x0224
33#define DECON_WxKEYCON0(n) (0x0230 + ((n - 1) * 8))
34#define DECON_WxKEYCON1(n) (0x0234 + ((n - 1) * 8))
35#define DECON_WxKEYALPHA(n) (0x0250 + ((n - 1) * 4))
36#define DECON_WINxMAP(n) (0x0270 + ((n) * 4))
37#define DECON_QOSLUT07_00 0x02C0
38#define DECON_QOSLUT15_08 0x02C4
39#define DECON_QOSCTRL 0x02C8
40#define DECON_BLENDERQx(n) (0x0300 + ((n - 1) * 4))
41#define DECON_BLENDCON 0x0310
42#define DECON_OPE_VIDW0xADD0(n) (0x0400 + ((n) * 4))
43#define DECON_OPE_VIDW0xADD1(n) (0x0414 + ((n) * 4))
44#define DECON_FRAMEFIFO_REG7 0x051C
45#define DECON_FRAMEFIFO_REG8 0x0520
46#define DECON_FRAMEFIFO_STATUS 0x0524
47#define DECON_CMU 0x1404
48#define DECON_UPDATE 0x1410
49#define DECON_CRFMID 0x1414
50#define DECON_UPDATE_SCHEME 0x1438
51#define DECON_VIDCON1 0x2000
52#define DECON_VIDCON2 0x2004
53#define DECON_VIDCON3 0x2008
54#define DECON_VIDCON4 0x200C
55#define DECON_VIDTCON2 0x2028
56#define DECON_FRAME_SIZE 0x2038
57#define DECON_LINECNT_OP_THRESHOLD 0x203C
58#define DECON_TRIGCON 0x2040
59#define DECON_TRIGSKIP 0x2050
60#define DECON_CRCRDATA 0x20B0
61#define DECON_CRCCTRL 0x20B4
62
63/* Exynos5430 DECON */
64#define DECON_VIDTCON0 0x2020
65#define DECON_VIDTCON1 0x2024
66
67/* Exynos5433 DECON */
68#define DECON_VIDTCON00 0x2010
69#define DECON_VIDTCON01 0x2014
70#define DECON_VIDTCON10 0x2018
71#define DECON_VIDTCON11 0x201C
72
73/* Exynos543X DECON Internal */
74#define DECON_W013DSTREOCON 0x0320
75#define DECON_W233DSTREOCON 0x0324
76#define DECON_FRAMEFIFO_REG0 0x0500
77#define DECON_ENHANCER_CTRL 0x2100
78
79/* Exynos543X DECON TV */
80#define DECON_VCLKCON0 0x0014
81#define DECON_VIDINTCON2 0x0228
82#define DECON_VIDINTCON3 0x022C
83
84/* VIDCON0 */
85#define VIDCON0_SWRESET (1 << 28)
86#define VIDCON0_CLKVALUP (1 << 14)
87#define VIDCON0_VLCKFREE (1 << 5)
88#define VIDCON0_STOP_STATUS (1 << 2)
89#define VIDCON0_ENVID (1 << 1)
90#define VIDCON0_ENVID_F (1 << 0)
91
92/* VIDOUTCON0 */
93#define VIDOUT_INTERLACE_FIELD_F (1 << 29)
94#define VIDOUT_INTERLACE_EN_F (1 << 28)
95#define VIDOUT_LCD_ON (1 << 24)
96#define VIDOUT_IF_F_MASK (0x3 << 20)
97#define VIDOUT_RGB_IF (0x0 << 20)
98#define VIDOUT_COMMAND_IF (0x2 << 20)
99
100/* WINCONx */
101#define WINCONx_HAWSWP_F (1 << 16)
102#define WINCONx_WSWP_F (1 << 15)
103#define WINCONx_BURSTLEN_MASK (0x3 << 10)
104#define WINCONx_BURSTLEN_16WORD (0x0 << 10)
105#define WINCONx_BURSTLEN_8WORD (0x1 << 10)
106#define WINCONx_BURSTLEN_4WORD (0x2 << 10)
107#define WINCONx_BLD_PIX_F (1 << 6)
108#define WINCONx_BPPMODE_MASK (0xf << 2)
109#define WINCONx_BPPMODE_16BPP_565 (0x5 << 2)
110#define WINCONx_BPPMODE_16BPP_A1555 (0x6 << 2)
111#define WINCONx_BPPMODE_16BPP_I1555 (0x7 << 2)
112#define WINCONx_BPPMODE_24BPP_888 (0xb << 2)
113#define WINCONx_BPPMODE_24BPP_A1887 (0xc << 2)
114#define WINCONx_BPPMODE_25BPP_A1888 (0xd << 2)
115#define WINCONx_BPPMODE_32BPP_A8888 (0xd << 2)
116#define WINCONx_BPPMODE_16BPP_A4444 (0xe << 2)
117#define WINCONx_ALPHA_SEL_F (1 << 1)
118#define WINCONx_ENWIN_F (1 << 0)
119
120/* SHADOWCON */
121#define SHADOWCON_PROTECT_MASK GENMASK(14, 10)
122#define SHADOWCON_Wx_PROTECT(n) (1 << (10 + (n)))
123
124/* VIDOSDxD */
125#define VIDOSD_Wx_ALPHA_R_F(n) (((n) & 0xff) << 16)
126#define VIDOSD_Wx_ALPHA_G_F(n) (((n) & 0xff) << 8)
127#define VIDOSD_Wx_ALPHA_B_F(n) (((n) & 0xff) << 0)
128
129/* VIDINTCON0 */
130#define VIDINTCON0_FRAMEDONE (1 << 17)
131#define VIDINTCON0_FRAMESEL_BP (0 << 15)
132#define VIDINTCON0_FRAMESEL_VS (1 << 15)
133#define VIDINTCON0_FRAMESEL_AC (2 << 15)
134#define VIDINTCON0_FRAMESEL_FP (3 << 15)
135#define VIDINTCON0_INTFRMEN (1 << 12)
136#define VIDINTCON0_INTEN (1 << 0)
137
138/* VIDINTCON1 */
139#define VIDINTCON1_INTFRMDONEPEND (1 << 2)
140#define VIDINTCON1_INTFRMPEND (1 << 1)
141#define VIDINTCON1_INTFIFOPEND (1 << 0)
142
143/* DECON_CMU */
144#define CMU_CLKGAGE_MODE_SFR_F (1 << 1)
145#define CMU_CLKGAGE_MODE_MEM_F (1 << 0)
146
147/* DECON_UPDATE */
148#define STANDALONE_UPDATE_F (1 << 0)
149
150/* DECON_VIDCON1 */
151#define VIDCON1_LINECNT_MASK (0x0fff << 16)
152#define VIDCON1_I80_ACTIVE (1 << 15)
153#define VIDCON1_VSTATUS_MASK (0x3 << 13)
154#define VIDCON1_VSTATUS_VS (0 << 13)
155#define VIDCON1_VSTATUS_BP (1 << 13)
156#define VIDCON1_VSTATUS_AC (2 << 13)
157#define VIDCON1_VSTATUS_FP (3 << 13)
158#define VIDCON1_VCLK_MASK (0x3 << 9)
159#define VIDCON1_VCLK_RUN_VDEN_DISABLE (0x3 << 9)
160#define VIDCON1_VCLK_HOLD (0x0 << 9)
161#define VIDCON1_VCLK_RUN (0x1 << 9)
162
163
164/* DECON_VIDTCON00 */
165#define VIDTCON00_VBPD_F(x) (((x) & 0xfff) << 16)
166#define VIDTCON00_VFPD_F(x) ((x) & 0xfff)
167
168/* DECON_VIDTCON01 */
169#define VIDTCON01_VSPW_F(x) (((x) & 0xfff) << 16)
170
171/* DECON_VIDTCON10 */
172#define VIDTCON10_HBPD_F(x) (((x) & 0xfff) << 16)
173#define VIDTCON10_HFPD_F(x) ((x) & 0xfff)
174
175/* DECON_VIDTCON11 */
176#define VIDTCON11_HSPW_F(x) (((x) & 0xfff) << 16)
177
178/* DECON_VIDTCON2 */
179#define VIDTCON2_LINEVAL(x) (((x) & 0xfff) << 16)
180#define VIDTCON2_HOZVAL(x) ((x) & 0xfff)
181
182/* TRIGCON */
183#define TRIGCON_TRIGEN_PER_F (1 << 31)
184#define TRIGCON_TRIGEN_F (1 << 30)
185#define TRIGCON_TE_AUTO_MASK (1 << 29)
186#define TRIGCON_WB_SWTRIGCMD (1 << 28)
187#define TRIGCON_SWTRIGCMD_W4BUF (1 << 26)
188#define TRIGCON_TRIGMODE_W4BUF (1 << 25)
189#define TRIGCON_SWTRIGCMD_W3BUF (1 << 21)
190#define TRIGCON_TRIGMODE_W3BUF (1 << 20)
191#define TRIGCON_SWTRIGCMD_W2BUF (1 << 16)
192#define TRIGCON_TRIGMODE_W2BUF (1 << 15)
193#define TRIGCON_SWTRIGCMD_W1BUF (1 << 11)
194#define TRIGCON_TRIGMODE_W1BUF (1 << 10)
195#define TRIGCON_SWTRIGCMD_W0BUF (1 << 6)
196#define TRIGCON_TRIGMODE_W0BUF (1 << 5)
197#define TRIGCON_HWTRIGMASK (1 << 4)
198#define TRIGCON_HWTRIGEN (1 << 3)
199#define TRIGCON_HWTRIG_INV (1 << 2)
200#define TRIGCON_SWTRIGCMD (1 << 1)
201#define TRIGCON_SWTRIGEN (1 << 0)
202
203/* DECON_CRCCTRL */
204#define CRCCTRL_CRCCLKEN (0x1 << 2)
205#define CRCCTRL_CRCSTART_F (0x1 << 1)
206#define CRCCTRL_CRCEN (0x1 << 0)
207#define CRCCTRL_MASK (0x7)
208
209#endif /* EXYNOS_REGS_DECON5433_H */
diff --git a/drivers/gpu/drm/exynos/regs-decon7.h b/drivers/gpu/drm/exynos/regs-decon7.h
new file mode 100644
index 000000000000..5df7765d2397
--- /dev/null
+++ b/drivers/gpu/drm/exynos/regs-decon7.h
@@ -0,0 +1,353 @@
1/*
2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 * Author: Ajay Kumar <ajaykumar.rs@samsung.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 */
10
11#ifndef EXYNOS_REGS_DECON7_H
12#define EXYNOS_REGS_DECON7_H
13
14/* VIDCON0 */
15#define VIDCON0 0x00
16
17#define VIDCON0_SWRESET (1 << 28)
18#define VIDCON0_DECON_STOP_STATUS (1 << 2)
19#define VIDCON0_ENVID (1 << 1)
20#define VIDCON0_ENVID_F (1 << 0)
21
22/* VIDOUTCON0 */
23#define VIDOUTCON0 0x4
24
25#define VIDOUTCON0_DUAL_MASK (0x3 << 24)
26#define VIDOUTCON0_DUAL_ON (0x3 << 24)
27#define VIDOUTCON0_DISP_IF_1_ON (0x2 << 24)
28#define VIDOUTCON0_DISP_IF_0_ON (0x1 << 24)
29#define VIDOUTCON0_DUAL_OFF (0x0 << 24)
30#define VIDOUTCON0_IF_SHIFT 23
31#define VIDOUTCON0_IF_MASK (0x1 << 23)
32#define VIDOUTCON0_RGBIF (0x0 << 23)
33#define VIDOUTCON0_I80IF (0x1 << 23)
34
35/* VIDCON3 */
36#define VIDCON3 0x8
37
38/* VIDCON4 */
39#define VIDCON4 0xC
40#define VIDCON4_FIFOCNT_START_EN (1 << 0)
41
42/* VCLKCON0 */
43#define VCLKCON0 0x10
44#define VCLKCON0_CLKVALUP (1 << 8)
45#define VCLKCON0_VCLKFREE (1 << 0)
46
47/* VCLKCON */
48#define VCLKCON1 0x14
49#define VCLKCON1_CLKVAL_NUM_VCLK(val) (((val) & 0xff) << 0)
50#define VCLKCON2 0x18
51
52/* SHADOWCON */
53#define SHADOWCON 0x30
54
55#define SHADOWCON_WINx_PROTECT(_win) (1 << (10 + (_win)))
56
57/* WINCONx */
58#define WINCON(_win) (0x50 + ((_win) * 4))
59
60#define WINCONx_BUFSTATUS (0x3 << 30)
61#define WINCONx_BUFSEL_MASK (0x3 << 28)
62#define WINCONx_BUFSEL_SHIFT 28
63#define WINCONx_TRIPLE_BUF_MODE (0x1 << 18)
64#define WINCONx_DOUBLE_BUF_MODE (0x0 << 18)
65#define WINCONx_BURSTLEN_16WORD (0x0 << 11)
66#define WINCONx_BURSTLEN_8WORD (0x1 << 11)
67#define WINCONx_BURSTLEN_MASK (0x1 << 11)
68#define WINCONx_BURSTLEN_SHIFT 11
69#define WINCONx_BLD_PLANE (0 << 8)
70#define WINCONx_BLD_PIX (1 << 8)
71#define WINCONx_ALPHA_MUL (1 << 7)
72
73#define WINCONx_BPPMODE_MASK (0xf << 2)
74#define WINCONx_BPPMODE_SHIFT 2
75#define WINCONx_BPPMODE_16BPP_565 (0x8 << 2)
76#define WINCONx_BPPMODE_24BPP_BGRx (0x7 << 2)
77#define WINCONx_BPPMODE_24BPP_RGBx (0x6 << 2)
78#define WINCONx_BPPMODE_24BPP_xBGR (0x5 << 2)
79#define WINCONx_BPPMODE_24BPP_xRGB (0x4 << 2)
80#define WINCONx_BPPMODE_32BPP_BGRA (0x3 << 2)
81#define WINCONx_BPPMODE_32BPP_RGBA (0x2 << 2)
82#define WINCONx_BPPMODE_32BPP_ABGR (0x1 << 2)
83#define WINCONx_BPPMODE_32BPP_ARGB (0x0 << 2)
84#define WINCONx_ALPHA_SEL (1 << 1)
85#define WINCONx_ENWIN (1 << 0)
86
87#define WINCON1_ALPHA_MUL_F (1 << 7)
88#define WINCON2_ALPHA_MUL_F (1 << 7)
89#define WINCON3_ALPHA_MUL_F (1 << 7)
90#define WINCON4_ALPHA_MUL_F (1 << 7)
91
92/* VIDOSDxH: The height for the OSD image(READ ONLY)*/
93#define VIDOSD_H(_x) (0x80 + ((_x) * 4))
94
95/* Frame buffer start addresses: VIDWxxADD0n */
96#define VIDW_BUF_START(_win) (0x80 + ((_win) * 0x10))
97#define VIDW_BUF_START1(_win) (0x84 + ((_win) * 0x10))
98#define VIDW_BUF_START2(_win) (0x88 + ((_win) * 0x10))
99
100#define VIDW_WHOLE_X(_win) (0x0130 + ((_win) * 8))
101#define VIDW_WHOLE_Y(_win) (0x0134 + ((_win) * 8))
102#define VIDW_OFFSET_X(_win) (0x0170 + ((_win) * 8))
103#define VIDW_OFFSET_Y(_win) (0x0174 + ((_win) * 8))
104#define VIDW_BLKOFFSET(_win) (0x01B0 + ((_win) * 4))
105#define VIDW_BLKSIZE(win) (0x0200 + ((_win) * 4))
106
107/* Interrupt controls register */
108#define VIDINTCON2 0x228
109
110#define VIDINTCON1_INTEXTRA1_EN (1 << 1)
111#define VIDINTCON1_INTEXTRA0_EN (1 << 0)
112
113/* Interrupt controls and status register */
114#define VIDINTCON3 0x22C
115
116#define VIDINTCON1_INTEXTRA1_PEND (1 << 1)
117#define VIDINTCON1_INTEXTRA0_PEND (1 << 0)
118
119/* VIDOSDxA ~ VIDOSDxE */
120#define VIDOSD_BASE 0x230
121
122#define OSD_STRIDE 0x20
123
124#define VIDOSD_A(_win) (VIDOSD_BASE + \
125 ((_win) * OSD_STRIDE) + 0x00)
126#define VIDOSD_B(_win) (VIDOSD_BASE + \
127 ((_win) * OSD_STRIDE) + 0x04)
128#define VIDOSD_C(_win) (VIDOSD_BASE + \
129 ((_win) * OSD_STRIDE) + 0x08)
130#define VIDOSD_D(_win) (VIDOSD_BASE + \
131 ((_win) * OSD_STRIDE) + 0x0C)
132#define VIDOSD_E(_win) (VIDOSD_BASE + \
133 ((_win) * OSD_STRIDE) + 0x10)
134
135#define VIDOSDxA_TOPLEFT_X_MASK (0x1fff << 13)
136#define VIDOSDxA_TOPLEFT_X_SHIFT 13
137#define VIDOSDxA_TOPLEFT_X_LIMIT 0x1fff
138#define VIDOSDxA_TOPLEFT_X(_x) (((_x) & 0x1fff) << 13)
139
140#define VIDOSDxA_TOPLEFT_Y_MASK (0x1fff << 0)
141#define VIDOSDxA_TOPLEFT_Y_SHIFT 0
142#define VIDOSDxA_TOPLEFT_Y_LIMIT 0x1fff
143#define VIDOSDxA_TOPLEFT_Y(_x) (((_x) & 0x1fff) << 0)
144
145#define VIDOSDxB_BOTRIGHT_X_MASK (0x1fff << 13)
146#define VIDOSDxB_BOTRIGHT_X_SHIFT 13
147#define VIDOSDxB_BOTRIGHT_X_LIMIT 0x1fff
148#define VIDOSDxB_BOTRIGHT_X(_x) (((_x) & 0x1fff) << 13)
149
150#define VIDOSDxB_BOTRIGHT_Y_MASK (0x1fff << 0)
151#define VIDOSDxB_BOTRIGHT_Y_SHIFT 0
152#define VIDOSDxB_BOTRIGHT_Y_LIMIT 0x1fff
153#define VIDOSDxB_BOTRIGHT_Y(_x) (((_x) & 0x1fff) << 0)
154
155#define VIDOSDxC_ALPHA0_R_F(_x) (((_x) & 0xFF) << 16)
156#define VIDOSDxC_ALPHA0_G_F(_x) (((_x) & 0xFF) << 8)
157#define VIDOSDxC_ALPHA0_B_F(_x) (((_x) & 0xFF) << 0)
158
159#define VIDOSDxD_ALPHA1_R_F(_x) (((_x) & 0xFF) << 16)
160#define VIDOSDxD_ALPHA1_G_F(_x) (((_x) & 0xFF) << 8)
161#define VIDOSDxD_ALPHA1_B_F(_x) (((_x) & 0xFF) >> 0)
162
163/* Window MAP (Color map) */
164#define WINxMAP(_win) (0x340 + ((_win) * 4))
165
166#define WINxMAP_MAP (1 << 24)
167#define WINxMAP_MAP_COLOUR_MASK (0xffffff << 0)
168#define WINxMAP_MAP_COLOUR_SHIFT 0
169#define WINxMAP_MAP_COLOUR_LIMIT 0xffffff
170#define WINxMAP_MAP_COLOUR(_x) ((_x) << 0)
171
172/* Window colour-key control registers */
173#define WKEYCON 0x370
174
175#define WKEYCON0 0x00
176#define WKEYCON1 0x04
177#define WxKEYCON0_KEYBL_EN (1 << 26)
178#define WxKEYCON0_KEYEN_F (1 << 25)
179#define WxKEYCON0_DIRCON (1 << 24)
180#define WxKEYCON0_COMPKEY_MASK (0xffffff << 0)
181#define WxKEYCON0_COMPKEY_SHIFT 0
182#define WxKEYCON0_COMPKEY_LIMIT 0xffffff
183#define WxKEYCON0_COMPKEY(_x) ((_x) << 0)
184#define WxKEYCON1_COLVAL_MASK (0xffffff << 0)
185#define WxKEYCON1_COLVAL_SHIFT 0
186#define WxKEYCON1_COLVAL_LIMIT 0xffffff
187#define WxKEYCON1_COLVAL(_x) ((_x) << 0)
188
189/* color key control register for hardware window 1 ~ 4. */
190#define WKEYCON0_BASE(x) ((WKEYCON + WKEYCON0) + ((x - 1) * 8))
191/* color key value register for hardware window 1 ~ 4. */
192#define WKEYCON1_BASE(x) ((WKEYCON + WKEYCON1) + ((x - 1) * 8))
193
194/* Window KEY Alpha value */
195#define WxKEYALPHA(_win) (0x3A0 + (((_win) - 1) * 0x4))
196
197#define Wx_KEYALPHA_R_F_SHIFT 16
198#define Wx_KEYALPHA_G_F_SHIFT 8
199#define Wx_KEYALPHA_B_F_SHIFT 0
200
201/* Blending equation */
202#define BLENDE(_win) (0x03C0 + ((_win) * 4))
203#define BLENDE_COEF_ZERO 0x0
204#define BLENDE_COEF_ONE 0x1
205#define BLENDE_COEF_ALPHA_A 0x2
206#define BLENDE_COEF_ONE_MINUS_ALPHA_A 0x3
207#define BLENDE_COEF_ALPHA_B 0x4
208#define BLENDE_COEF_ONE_MINUS_ALPHA_B 0x5
209#define BLENDE_COEF_ALPHA0 0x6
210#define BLENDE_COEF_A 0xA
211#define BLENDE_COEF_ONE_MINUS_A 0xB
212#define BLENDE_COEF_B 0xC
213#define BLENDE_COEF_ONE_MINUS_B 0xD
214#define BLENDE_Q_FUNC(_v) ((_v) << 18)
215#define BLENDE_P_FUNC(_v) ((_v) << 12)
216#define BLENDE_B_FUNC(_v) ((_v) << 6)
217#define BLENDE_A_FUNC(_v) ((_v) << 0)
218
219/* Blending equation control */
220#define BLENDCON 0x3D8
221#define BLENDCON_NEW_MASK (1 << 0)
222#define BLENDCON_NEW_8BIT_ALPHA_VALUE (1 << 0)
223#define BLENDCON_NEW_4BIT_ALPHA_VALUE (0 << 0)
224
225/* Interrupt control register */
226#define VIDINTCON0 0x500
227
228#define VIDINTCON0_WAKEUP_MASK (0x3f << 26)
229#define VIDINTCON0_INTEXTRAEN (1 << 21)
230
231#define VIDINTCON0_FRAMESEL0_SHIFT 15
232#define VIDINTCON0_FRAMESEL0_MASK (0x3 << 15)
233#define VIDINTCON0_FRAMESEL0_BACKPORCH (0x0 << 15)
234#define VIDINTCON0_FRAMESEL0_VSYNC (0x1 << 15)
235#define VIDINTCON0_FRAMESEL0_ACTIVE (0x2 << 15)
236#define VIDINTCON0_FRAMESEL0_FRONTPORCH (0x3 << 15)
237
238#define VIDINTCON0_INT_FRAME (1 << 11)
239
240#define VIDINTCON0_FIFOLEVEL_MASK (0x7 << 3)
241#define VIDINTCON0_FIFOLEVEL_SHIFT 3
242#define VIDINTCON0_FIFOLEVEL_EMPTY (0x0 << 3)
243#define VIDINTCON0_FIFOLEVEL_TO25PC (0x1 << 3)
244#define VIDINTCON0_FIFOLEVEL_TO50PC (0x2 << 3)
245#define VIDINTCON0_FIFOLEVEL_FULL (0x4 << 3)
246
247#define VIDINTCON0_FIFOSEL_MAIN_EN (1 << 1)
248#define VIDINTCON0_INT_FIFO (1 << 1)
249
250#define VIDINTCON0_INT_ENABLE (1 << 0)
251
252/* Interrupt controls and status register */
253#define VIDINTCON1 0x504
254
255#define VIDINTCON1_INT_EXTRA (1 << 3)
256#define VIDINTCON1_INT_I80 (1 << 2)
257#define VIDINTCON1_INT_FRAME (1 << 1)
258#define VIDINTCON1_INT_FIFO (1 << 0)
259
260/* VIDCON1 */
261#define VIDCON1(_x) (0x0600 + ((_x) * 0x50))
262#define VIDCON1_LINECNT_GET(_v) (((_v) >> 17) & 0x1fff)
263#define VIDCON1_VCLK_MASK (0x3 << 9)
264#define VIDCON1_VCLK_HOLD (0x0 << 9)
265#define VIDCON1_VCLK_RUN (0x1 << 9)
266#define VIDCON1_VCLK_RUN_VDEN_DISABLE (0x3 << 9)
267#define VIDCON1_RGB_ORDER_O_MASK (0x7 << 4)
268#define VIDCON1_RGB_ORDER_O_RGB (0x0 << 4)
269#define VIDCON1_RGB_ORDER_O_GBR (0x1 << 4)
270#define VIDCON1_RGB_ORDER_O_BRG (0x2 << 4)
271#define VIDCON1_RGB_ORDER_O_BGR (0x4 << 4)
272#define VIDCON1_RGB_ORDER_O_RBG (0x5 << 4)
273#define VIDCON1_RGB_ORDER_O_GRB (0x6 << 4)
274
275/* VIDTCON0 */
276#define VIDTCON0 0x610
277
278#define VIDTCON0_VBPD_MASK (0xffff << 16)
279#define VIDTCON0_VBPD_SHIFT 16
280#define VIDTCON0_VBPD_LIMIT 0xffff
281#define VIDTCON0_VBPD(_x) ((_x) << 16)
282
283#define VIDTCON0_VFPD_MASK (0xffff << 0)
284#define VIDTCON0_VFPD_SHIFT 0
285#define VIDTCON0_VFPD_LIMIT 0xffff
286#define VIDTCON0_VFPD(_x) ((_x) << 0)
287
288/* VIDTCON1 */
289#define VIDTCON1 0x614
290
291#define VIDTCON1_VSPW_MASK (0xffff << 16)
292#define VIDTCON1_VSPW_SHIFT 16
293#define VIDTCON1_VSPW_LIMIT 0xffff
294#define VIDTCON1_VSPW(_x) ((_x) << 16)
295
296/* VIDTCON2 */
297#define VIDTCON2 0x618
298
299#define VIDTCON2_HBPD_MASK (0xffff << 16)
300#define VIDTCON2_HBPD_SHIFT 16
301#define VIDTCON2_HBPD_LIMIT 0xffff
302#define VIDTCON2_HBPD(_x) ((_x) << 16)
303
304#define VIDTCON2_HFPD_MASK (0xffff << 0)
305#define VIDTCON2_HFPD_SHIFT 0
306#define VIDTCON2_HFPD_LIMIT 0xffff
307#define VIDTCON2_HFPD(_x) ((_x) << 0)
308
309/* VIDTCON3 */
310#define VIDTCON3 0x61C
311
312#define VIDTCON3_HSPW_MASK (0xffff << 16)
313#define VIDTCON3_HSPW_SHIFT 16
314#define VIDTCON3_HSPW_LIMIT 0xffff
315#define VIDTCON3_HSPW(_x) ((_x) << 16)
316
317/* VIDTCON4 */
318#define VIDTCON4 0x620
319
320#define VIDTCON4_LINEVAL_MASK (0xfff << 16)
321#define VIDTCON4_LINEVAL_SHIFT 16
322#define VIDTCON4_LINEVAL_LIMIT 0xfff
323#define VIDTCON4_LINEVAL(_x) (((_x) & 0xfff) << 16)
324
325#define VIDTCON4_HOZVAL_MASK (0xfff << 0)
326#define VIDTCON4_HOZVAL_SHIFT 0
327#define VIDTCON4_HOZVAL_LIMIT 0xfff
328#define VIDTCON4_HOZVAL(_x) (((_x) & 0xfff) << 0)
329
330/* LINECNT OP THRSHOLD*/
331#define LINECNT_OP_THRESHOLD 0x630
332
333/* CRCCTRL */
334#define CRCCTRL 0x6C8
335#define CRCCTRL_CRCCLKEN (0x1 << 2)
336#define CRCCTRL_CRCSTART_F (0x1 << 1)
337#define CRCCTRL_CRCEN (0x1 << 0)
338
339/* DECON_CMU */
340#define DECON_CMU 0x704
341
342#define DECON_CMU_ALL_CLKGATE_ENABLE 0x3
343#define DECON_CMU_SE_CLKGATE_ENABLE (0x1 << 2)
344#define DECON_CMU_SFR_CLKGATE_ENABLE (0x1 << 1)
345#define DECON_CMU_MEM_CLKGATE_ENABLE (0x1 << 0)
346
347/* DECON_UPDATE */
348#define DECON_UPDATE 0x710
349
350#define DECON_UPDATE_SLAVE_SYNC (1 << 4)
351#define DECON_UPDATE_STANDALONE_F (1 << 0)
352
353#endif /* EXYNOS_REGS_DECON7_H */