aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kocialkowski <paul.kocialkowski@bootlin.com>2018-09-13 10:51:55 -0400
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>2018-09-24 10:47:10 -0400
commit50e761516f2b8c0cdeb31a8c6ca1b4ef98cd13f1 (patch)
tree28ad6401e53e50245d2161481d9f9f52c3787918
parenta20625fb03df9d84378b63540c2ad6b34703af33 (diff)
media: platform: Add Cedrus VPU decoder driver
This introduces the Cedrus VPU driver that supports the VPU found in Allwinner SoCs, also known as Video Engine. It is implemented through a V4L2 M2M decoder device and a media device (used for media requests). So far, it only supports MPEG-2 decoding. Since this VPU is stateless, synchronization with media requests is required in order to ensure consistency between frame headers that contain metadata about the frame to process and the raw slice data that is used to generate the frame. This driver was made possible thanks to the long-standing effort carried out by the linux-sunxi community in the interest of reverse engineering, documenting and implementing support for the Allwinner VPU. Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com> Acked-by: Maxime Ripard <maxime.ripard@bootlin.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> [hans.verkuil@cisco.com: dropped obsolete MEDIA_REQUEST_API from Kconfig] Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
-rw-r--r--MAINTAINERS7
-rw-r--r--drivers/staging/media/Kconfig2
-rw-r--r--drivers/staging/media/Makefile1
-rw-r--r--drivers/staging/media/sunxi/Kconfig15
-rw-r--r--drivers/staging/media/sunxi/Makefile1
-rw-r--r--drivers/staging/media/sunxi/cedrus/Kconfig14
-rw-r--r--drivers/staging/media/sunxi/cedrus/Makefile3
-rw-r--r--drivers/staging/media/sunxi/cedrus/TODO7
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.c431
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.h167
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_dec.c70
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_dec.h27
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_hw.c327
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_hw.h30
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c246
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_regs.h235
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_video.c542
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_video.h30
18 files changed, 2155 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index a5b256b25905..6d69f3ad1aa9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -663,6 +663,13 @@ L: linux-crypto@vger.kernel.org
663S: Maintained 663S: Maintained
664F: drivers/crypto/sunxi-ss/ 664F: drivers/crypto/sunxi-ss/
665 665
666ALLWINNER VPU DRIVER
667M: Maxime Ripard <maxime.ripard@bootlin.com>
668M: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
669L: linux-media@vger.kernel.org
670S: Maintained
671F: drivers/staging/media/sunxi/cedrus/
672
666ALPHA PORT 673ALPHA PORT
667M: Richard Henderson <rth@twiddle.net> 674M: Richard Henderson <rth@twiddle.net>
668M: Ivan Kokshaysky <ink@jurassic.park.msu.ru> 675M: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index db5cf67047ad..b3620a8f2d9f 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -31,6 +31,8 @@ source "drivers/staging/media/mt9t031/Kconfig"
31 31
32source "drivers/staging/media/omap4iss/Kconfig" 32source "drivers/staging/media/omap4iss/Kconfig"
33 33
34source "drivers/staging/media/sunxi/Kconfig"
35
34source "drivers/staging/media/tegra-vde/Kconfig" 36source "drivers/staging/media/tegra-vde/Kconfig"
35 37
36source "drivers/staging/media/zoran/Kconfig" 38source "drivers/staging/media/zoran/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 503fbe47fa58..42948f805548 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -5,5 +5,6 @@ obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074/
5obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031/ 5obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031/
6obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ 6obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
7obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ 7obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
8obj-$(CONFIG_VIDEO_SUNXI) += sunxi/
8obj-$(CONFIG_TEGRA_VDE) += tegra-vde/ 9obj-$(CONFIG_TEGRA_VDE) += tegra-vde/
9obj-$(CONFIG_VIDEO_ZORAN) += zoran/ 10obj-$(CONFIG_VIDEO_ZORAN) += zoran/
diff --git a/drivers/staging/media/sunxi/Kconfig b/drivers/staging/media/sunxi/Kconfig
new file mode 100644
index 000000000000..c78d92240ceb
--- /dev/null
+++ b/drivers/staging/media/sunxi/Kconfig
@@ -0,0 +1,15 @@
1config VIDEO_SUNXI
2 bool "Allwinner sunXi family Video Devices"
3 depends on ARCH_SUNXI || COMPILE_TEST
4 help
5 If you have an Allwinner SoC based on the sunXi family, say Y.
6
7 Note that this option doesn't include new drivers in the
8 kernel: saying N will just cause Kconfig to skip all the
9 questions about Allwinner media devices.
10
11if VIDEO_SUNXI
12
13source "drivers/staging/media/sunxi/cedrus/Kconfig"
14
15endif
diff --git a/drivers/staging/media/sunxi/Makefile b/drivers/staging/media/sunxi/Makefile
new file mode 100644
index 000000000000..cee2846c3ecf
--- /dev/null
+++ b/drivers/staging/media/sunxi/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += cedrus/
diff --git a/drivers/staging/media/sunxi/cedrus/Kconfig b/drivers/staging/media/sunxi/cedrus/Kconfig
new file mode 100644
index 000000000000..a7a34e89c42d
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/Kconfig
@@ -0,0 +1,14 @@
1config VIDEO_SUNXI_CEDRUS
2 tristate "Allwinner Cedrus VPU driver"
3 depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER
4 depends on HAS_DMA
5 depends on OF
6 select SUNXI_SRAM
7 select VIDEOBUF2_DMA_CONTIG
8 select V4L2_MEM2MEM_DEV
9 help
10 Support for the VPU found in Allwinner SoCs, also known as the Cedar
11 video engine.
12
13 To compile this driver as a module, choose M here: the module
14 will be called sunxi-cedrus.
diff --git a/drivers/staging/media/sunxi/cedrus/Makefile b/drivers/staging/media/sunxi/cedrus/Makefile
new file mode 100644
index 000000000000..e9dc68b7bcb6
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/Makefile
@@ -0,0 +1,3 @@
1obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o
2
3sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o cedrus_mpeg2.o
diff --git a/drivers/staging/media/sunxi/cedrus/TODO b/drivers/staging/media/sunxi/cedrus/TODO
new file mode 100644
index 000000000000..ec277ece47af
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/TODO
@@ -0,0 +1,7 @@
1Before this stateless decoder driver can leave the staging area:
2* The Request API needs to be stabilized;
3* The codec-specific controls need to be thoroughly reviewed to ensure they
4 cover all intended uses cases;
5* Userspace support for the Request API needs to be reviewed;
6* Another stateless decoder driver should be submitted;
7* At least one stateless encoder driver should be submitted.
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
new file mode 100644
index 000000000000..82558455384a
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -0,0 +1,431 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Cedrus VPU driver
4 *
5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7 * Copyright (C) 2018 Bootlin
8 *
9 * Based on the vim2m driver, that is:
10 *
11 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
12 * Pawel Osciak, <pawel@osciak.com>
13 * Marek Szyprowski, <m.szyprowski@samsung.com>
14 */
15
16#include <linux/platform_device.h>
17#include <linux/module.h>
18#include <linux/of.h>
19
20#include <media/v4l2-device.h>
21#include <media/v4l2-ioctl.h>
22#include <media/v4l2-ctrls.h>
23#include <media/v4l2-mem2mem.h>
24
25#include "cedrus.h"
26#include "cedrus_video.h"
27#include "cedrus_dec.h"
28#include "cedrus_hw.h"
29
30static const struct cedrus_control cedrus_controls[] = {
31 {
32 .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
33 .elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params),
34 .codec = CEDRUS_CODEC_MPEG2,
35 .required = true,
36 },
37 {
38 .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
39 .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization),
40 .codec = CEDRUS_CODEC_MPEG2,
41 .required = false,
42 },
43};
44
45#define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls)
46
47void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id)
48{
49 unsigned int i;
50
51 for (i = 0; ctx->ctrls[i]; i++)
52 if (ctx->ctrls[i]->id == id)
53 return ctx->ctrls[i]->p_cur.p;
54
55 return NULL;
56}
57
58static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
59{
60 struct v4l2_ctrl_handler *hdl = &ctx->hdl;
61 struct v4l2_ctrl *ctrl;
62 unsigned int ctrl_size;
63 unsigned int i;
64
65 v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT);
66 if (hdl->error) {
67 v4l2_err(&dev->v4l2_dev,
68 "Failed to initialize control handler\n");
69 return hdl->error;
70 }
71
72 ctrl_size = sizeof(ctrl) * CEDRUS_CONTROLS_COUNT + 1;
73
74 ctx->ctrls = kzalloc(ctrl_size, GFP_KERNEL);
75 memset(ctx->ctrls, 0, ctrl_size);
76
77 for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
78 struct v4l2_ctrl_config cfg = { 0 };
79
80 cfg.elem_size = cedrus_controls[i].elem_size;
81 cfg.id = cedrus_controls[i].id;
82
83 ctrl = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
84 if (hdl->error) {
85 v4l2_err(&dev->v4l2_dev,
86 "Failed to create new custom control\n");
87
88 v4l2_ctrl_handler_free(hdl);
89 kfree(ctx->ctrls);
90 return hdl->error;
91 }
92
93 ctx->ctrls[i] = ctrl;
94 }
95
96 ctx->fh.ctrl_handler = hdl;
97 v4l2_ctrl_handler_setup(hdl);
98
99 return 0;
100}
101
102static int cedrus_request_validate(struct media_request *req)
103{
104 struct media_request_object *obj;
105 struct v4l2_ctrl_handler *parent_hdl, *hdl;
106 struct cedrus_ctx *ctx = NULL;
107 struct v4l2_ctrl *ctrl_test;
108 unsigned int count;
109 unsigned int i;
110
111 count = vb2_request_buffer_cnt(req);
112 if (!count) {
113 v4l2_info(&ctx->dev->v4l2_dev,
114 "No buffer was provided with the request\n");
115 return -ENOENT;
116 } else if (count > 1) {
117 v4l2_info(&ctx->dev->v4l2_dev,
118 "More than one buffer was provided with the request\n");
119 return -EINVAL;
120 }
121
122 list_for_each_entry(obj, &req->objects, list) {
123 struct vb2_buffer *vb;
124
125 if (vb2_request_object_is_buffer(obj)) {
126 vb = container_of(obj, struct vb2_buffer, req_obj);
127 ctx = vb2_get_drv_priv(vb->vb2_queue);
128
129 break;
130 }
131 }
132
133 if (!ctx)
134 return -ENOENT;
135
136 parent_hdl = &ctx->hdl;
137
138 hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl);
139 if (!hdl) {
140 v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control(s)\n");
141 return -ENOENT;
142 }
143
144 for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
145 if (cedrus_controls[i].codec != ctx->current_codec ||
146 !cedrus_controls[i].required)
147 continue;
148
149 ctrl_test = v4l2_ctrl_request_hdl_ctrl_find(hdl,
150 cedrus_controls[i].id);
151 if (!ctrl_test) {
152 v4l2_info(&ctx->dev->v4l2_dev,
153 "Missing required codec control\n");
154 return -ENOENT;
155 }
156 }
157
158 v4l2_ctrl_request_hdl_put(hdl);
159
160 return vb2_request_validate(req);
161}
162
163static int cedrus_open(struct file *file)
164{
165 struct cedrus_dev *dev = video_drvdata(file);
166 struct cedrus_ctx *ctx = NULL;
167 int ret;
168
169 if (mutex_lock_interruptible(&dev->dev_mutex))
170 return -ERESTARTSYS;
171
172 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
173 if (!ctx) {
174 mutex_unlock(&dev->dev_mutex);
175 return -ENOMEM;
176 }
177
178 v4l2_fh_init(&ctx->fh, video_devdata(file));
179 file->private_data = &ctx->fh;
180 ctx->dev = dev;
181
182 ret = cedrus_init_ctrls(dev, ctx);
183 if (ret)
184 goto err_free;
185
186 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
187 &cedrus_queue_init);
188 if (IS_ERR(ctx->fh.m2m_ctx)) {
189 ret = PTR_ERR(ctx->fh.m2m_ctx);
190 goto err_ctrls;
191 }
192
193 v4l2_fh_add(&ctx->fh);
194
195 mutex_unlock(&dev->dev_mutex);
196
197 return 0;
198
199err_ctrls:
200 v4l2_ctrl_handler_free(&ctx->hdl);
201err_free:
202 kfree(ctx);
203 mutex_unlock(&dev->dev_mutex);
204
205 return ret;
206}
207
208static int cedrus_release(struct file *file)
209{
210 struct cedrus_dev *dev = video_drvdata(file);
211 struct cedrus_ctx *ctx = container_of(file->private_data,
212 struct cedrus_ctx, fh);
213
214 mutex_lock(&dev->dev_mutex);
215
216 v4l2_fh_del(&ctx->fh);
217 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
218
219 v4l2_ctrl_handler_free(&ctx->hdl);
220 kfree(ctx->ctrls);
221
222 v4l2_fh_exit(&ctx->fh);
223
224 kfree(ctx);
225
226 mutex_unlock(&dev->dev_mutex);
227
228 return 0;
229}
230
231static const struct v4l2_file_operations cedrus_fops = {
232 .owner = THIS_MODULE,
233 .open = cedrus_open,
234 .release = cedrus_release,
235 .poll = v4l2_m2m_fop_poll,
236 .unlocked_ioctl = video_ioctl2,
237 .mmap = v4l2_m2m_fop_mmap,
238};
239
240static const struct video_device cedrus_video_device = {
241 .name = CEDRUS_NAME,
242 .vfl_dir = VFL_DIR_M2M,
243 .fops = &cedrus_fops,
244 .ioctl_ops = &cedrus_ioctl_ops,
245 .minor = -1,
246 .release = video_device_release_empty,
247 .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
248};
249
250static const struct v4l2_m2m_ops cedrus_m2m_ops = {
251 .device_run = cedrus_device_run,
252};
253
254static const struct media_device_ops cedrus_m2m_media_ops = {
255 .req_validate = cedrus_request_validate,
256 .req_queue = vb2_m2m_request_queue,
257};
258
259static int cedrus_probe(struct platform_device *pdev)
260{
261 struct cedrus_dev *dev;
262 struct video_device *vfd;
263 int ret;
264
265 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
266 if (!dev)
267 return -ENOMEM;
268
269 dev->vfd = cedrus_video_device;
270 dev->dev = &pdev->dev;
271 dev->pdev = pdev;
272
273 ret = cedrus_hw_probe(dev);
274 if (ret) {
275 dev_err(&pdev->dev, "Failed to probe hardware\n");
276 return ret;
277 }
278
279 dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
280
281 mutex_init(&dev->dev_mutex);
282 spin_lock_init(&dev->irq_lock);
283
284 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
285 if (ret) {
286 dev_err(&pdev->dev, "Failed to register V4L2 device\n");
287 return ret;
288 }
289
290 vfd = &dev->vfd;
291 vfd->lock = &dev->dev_mutex;
292 vfd->v4l2_dev = &dev->v4l2_dev;
293
294 snprintf(vfd->name, sizeof(vfd->name), "%s", cedrus_video_device.name);
295 video_set_drvdata(vfd, dev);
296
297 dev->m2m_dev = v4l2_m2m_init(&cedrus_m2m_ops);
298 if (IS_ERR(dev->m2m_dev)) {
299 v4l2_err(&dev->v4l2_dev,
300 "Failed to initialize V4L2 M2M device\n");
301 ret = PTR_ERR(dev->m2m_dev);
302
303 goto err_video;
304 }
305
306 dev->mdev.dev = &pdev->dev;
307 strscpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model));
308
309 media_device_init(&dev->mdev);
310 dev->mdev.ops = &cedrus_m2m_media_ops;
311 dev->v4l2_dev.mdev = &dev->mdev;
312
313 ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
314 MEDIA_ENT_F_PROC_VIDEO_DECODER);
315 if (ret) {
316 v4l2_err(&dev->v4l2_dev,
317 "Failed to initialize V4L2 M2M media controller\n");
318 goto err_m2m;
319 }
320
321 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
322 if (ret) {
323 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
324 goto err_v4l2;
325 }
326
327 v4l2_info(&dev->v4l2_dev,
328 "Device registered as /dev/video%d\n", vfd->num);
329
330 ret = media_device_register(&dev->mdev);
331 if (ret) {
332 v4l2_err(&dev->v4l2_dev, "Failed to register media device\n");
333 goto err_m2m_mc;
334 }
335
336 platform_set_drvdata(pdev, dev);
337
338 return 0;
339
340err_m2m_mc:
341 v4l2_m2m_unregister_media_controller(dev->m2m_dev);
342err_m2m:
343 v4l2_m2m_release(dev->m2m_dev);
344err_video:
345 video_unregister_device(&dev->vfd);
346err_v4l2:
347 v4l2_device_unregister(&dev->v4l2_dev);
348
349 return ret;
350}
351
352static int cedrus_remove(struct platform_device *pdev)
353{
354 struct cedrus_dev *dev = platform_get_drvdata(pdev);
355
356 if (media_devnode_is_registered(dev->mdev.devnode)) {
357 media_device_unregister(&dev->mdev);
358 v4l2_m2m_unregister_media_controller(dev->m2m_dev);
359 media_device_cleanup(&dev->mdev);
360 }
361
362 v4l2_m2m_release(dev->m2m_dev);
363 video_unregister_device(&dev->vfd);
364 v4l2_device_unregister(&dev->v4l2_dev);
365
366 cedrus_hw_remove(dev);
367
368 return 0;
369}
370
371static const struct cedrus_variant sun4i_a10_cedrus_variant = {
372 /* No particular capability. */
373};
374
375static const struct cedrus_variant sun5i_a13_cedrus_variant = {
376 /* No particular capability. */
377};
378
379static const struct cedrus_variant sun7i_a20_cedrus_variant = {
380 /* No particular capability. */
381};
382
383static const struct cedrus_variant sun8i_a33_cedrus_variant = {
384 .capabilities = CEDRUS_CAPABILITY_UNTILED,
385};
386
387static const struct cedrus_variant sun8i_h3_cedrus_variant = {
388 .capabilities = CEDRUS_CAPABILITY_UNTILED,
389};
390
391static const struct of_device_id cedrus_dt_match[] = {
392 {
393 .compatible = "allwinner,sun4i-a10-video-engine",
394 .data = &sun4i_a10_cedrus_variant,
395 },
396 {
397 .compatible = "allwinner,sun5i-a13-video-engine",
398 .data = &sun5i_a13_cedrus_variant,
399 },
400 {
401 .compatible = "allwinner,sun7i-a20-video-engine",
402 .data = &sun7i_a20_cedrus_variant,
403 },
404 {
405 .compatible = "allwinner,sun8i-a33-video-engine",
406 .data = &sun8i_a33_cedrus_variant,
407 },
408 {
409 .compatible = "allwinner,sun8i-h3-video-engine",
410 .data = &sun8i_h3_cedrus_variant,
411 },
412 { /* sentinel */ }
413};
414MODULE_DEVICE_TABLE(of, cedrus_dt_match);
415
416static struct platform_driver cedrus_driver = {
417 .probe = cedrus_probe,
418 .remove = cedrus_remove,
419 .driver = {
420 .name = CEDRUS_NAME,
421 .owner = THIS_MODULE,
422 .of_match_table = of_match_ptr(cedrus_dt_match),
423 },
424};
425module_platform_driver(cedrus_driver);
426
427MODULE_LICENSE("GPL v2");
428MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>");
429MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
430MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
431MODULE_DESCRIPTION("Cedrus VPU driver");
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
new file mode 100644
index 000000000000..3f61248c57ac
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -0,0 +1,167 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Cedrus VPU driver
4 *
5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7 * Copyright (C) 2018 Bootlin
8 *
9 * Based on the vim2m driver, that is:
10 *
11 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
12 * Pawel Osciak, <pawel@osciak.com>
13 * Marek Szyprowski, <m.szyprowski@samsung.com>
14 */
15
16#ifndef _CEDRUS_H_
17#define _CEDRUS_H_
18
19#include <media/v4l2-ctrls.h>
20#include <media/v4l2-device.h>
21#include <media/v4l2-mem2mem.h>
22#include <media/videobuf2-v4l2.h>
23#include <media/videobuf2-dma-contig.h>
24
25#include <linux/platform_device.h>
26
27#define CEDRUS_NAME "cedrus"
28
29#define CEDRUS_CAPABILITY_UNTILED BIT(0)
30
31enum cedrus_codec {
32 CEDRUS_CODEC_MPEG2,
33
34 CEDRUS_CODEC_LAST,
35};
36
37enum cedrus_irq_status {
38 CEDRUS_IRQ_NONE,
39 CEDRUS_IRQ_ERROR,
40 CEDRUS_IRQ_OK,
41};
42
43struct cedrus_control {
44 u32 id;
45 u32 elem_size;
46 enum cedrus_codec codec;
47 unsigned char required:1;
48};
49
50struct cedrus_mpeg2_run {
51 const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
52 const struct v4l2_ctrl_mpeg2_quantization *quantization;
53};
54
55struct cedrus_run {
56 struct vb2_v4l2_buffer *src;
57 struct vb2_v4l2_buffer *dst;
58
59 union {
60 struct cedrus_mpeg2_run mpeg2;
61 };
62};
63
64struct cedrus_buffer {
65 struct v4l2_m2m_buffer m2m_buf;
66};
67
68struct cedrus_ctx {
69 struct v4l2_fh fh;
70 struct cedrus_dev *dev;
71
72 struct v4l2_pix_format src_fmt;
73 struct v4l2_pix_format dst_fmt;
74 enum cedrus_codec current_codec;
75
76 struct v4l2_ctrl_handler hdl;
77 struct v4l2_ctrl **ctrls;
78
79 struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME];
80};
81
82struct cedrus_dec_ops {
83 void (*irq_clear)(struct cedrus_ctx *ctx);
84 void (*irq_disable)(struct cedrus_ctx *ctx);
85 enum cedrus_irq_status (*irq_status)(struct cedrus_ctx *ctx);
86 void (*setup)(struct cedrus_ctx *ctx, struct cedrus_run *run);
87 int (*start)(struct cedrus_ctx *ctx);
88 void (*stop)(struct cedrus_ctx *ctx);
89 void (*trigger)(struct cedrus_ctx *ctx);
90};
91
92struct cedrus_variant {
93 unsigned int capabilities;
94};
95
96struct cedrus_dev {
97 struct v4l2_device v4l2_dev;
98 struct video_device vfd;
99 struct media_device mdev;
100 struct media_pad pad[2];
101 struct platform_device *pdev;
102 struct device *dev;
103 struct v4l2_m2m_dev *m2m_dev;
104 struct cedrus_dec_ops *dec_ops[CEDRUS_CODEC_LAST];
105
106 /* Device file mutex */
107 struct mutex dev_mutex;
108 /* Interrupt spinlock */
109 spinlock_t irq_lock;
110
111 void __iomem *base;
112
113 struct clk *mod_clk;
114 struct clk *ahb_clk;
115 struct clk *ram_clk;
116
117 struct reset_control *rstc;
118
119 unsigned int capabilities;
120};
121
122extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2;
123
124static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val)
125{
126 writel(val, dev->base + reg);
127}
128
129static inline u32 cedrus_read(struct cedrus_dev *dev, u32 reg)
130{
131 return readl(dev->base + reg);
132}
133
134static inline dma_addr_t cedrus_buf_addr(struct vb2_buffer *buf,
135 struct v4l2_pix_format *pix_fmt,
136 unsigned int plane)
137{
138 dma_addr_t addr = vb2_dma_contig_plane_dma_addr(buf, 0);
139
140 return addr + (pix_fmt ? (dma_addr_t)pix_fmt->bytesperline *
141 pix_fmt->height * plane : 0);
142}
143
144static inline dma_addr_t cedrus_dst_buf_addr(struct cedrus_ctx *ctx,
145 unsigned int index,
146 unsigned int plane)
147{
148 struct vb2_buffer *buf = ctx->dst_bufs[index];
149
150 return buf ? cedrus_buf_addr(buf, &ctx->dst_fmt, plane) : 0;
151}
152
153static inline struct cedrus_buffer *
154vb2_v4l2_to_cedrus_buffer(const struct vb2_v4l2_buffer *p)
155{
156 return container_of(p, struct cedrus_buffer, m2m_buf.vb);
157}
158
159static inline struct cedrus_buffer *
160vb2_to_cedrus_buffer(const struct vb2_buffer *p)
161{
162 return vb2_v4l2_to_cedrus_buffer(to_vb2_v4l2_buffer(p));
163}
164
165void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id);
166
167#endif
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
new file mode 100644
index 000000000000..e40180a33951
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -0,0 +1,70 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Cedrus VPU driver
4 *
5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7 * Copyright (C) 2018 Bootlin
8 *
9 * Based on the vim2m driver, that is:
10 *
11 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
12 * Pawel Osciak, <pawel@osciak.com>
13 * Marek Szyprowski, <m.szyprowski@samsung.com>
14 */
15
16#include <media/v4l2-device.h>
17#include <media/v4l2-ioctl.h>
18#include <media/v4l2-event.h>
19#include <media/v4l2-mem2mem.h>
20
21#include "cedrus.h"
22#include "cedrus_dec.h"
23#include "cedrus_hw.h"
24
25void cedrus_device_run(void *priv)
26{
27 struct cedrus_ctx *ctx = priv;
28 struct cedrus_dev *dev = ctx->dev;
29 struct cedrus_run run = { 0 };
30 struct media_request *src_req;
31 unsigned long flags;
32
33 run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
34 run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
35
36 /* Apply request(s) controls if needed. */
37 src_req = run.src->vb2_buf.req_obj.req;
38
39 if (src_req)
40 v4l2_ctrl_request_setup(src_req, &ctx->hdl);
41
42 spin_lock_irqsave(&ctx->dev->irq_lock, flags);
43
44 switch (ctx->src_fmt.pixelformat) {
45 case V4L2_PIX_FMT_MPEG2_SLICE:
46 run.mpeg2.slice_params = cedrus_find_control_data(ctx,
47 V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS);
48 run.mpeg2.quantization = cedrus_find_control_data(ctx,
49 V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION);
50 break;
51
52 default:
53 break;
54 }
55
56 dev->dec_ops[ctx->current_codec]->setup(ctx, &run);
57
58 spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
59
60 /* Complete request(s) controls if needed. */
61
62 if (src_req)
63 v4l2_ctrl_request_complete(src_req, &ctx->hdl);
64
65 spin_lock_irqsave(&ctx->dev->irq_lock, flags);
66
67 dev->dec_ops[ctx->current_codec]->trigger(ctx);
68
69 spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
70}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.h b/drivers/staging/media/sunxi/cedrus/cedrus_dec.h
new file mode 100644
index 000000000000..4f423d3a1cad
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.h
@@ -0,0 +1,27 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Cedrus VPU driver
4 *
5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7 * Copyright (C) 2018 Bootlin
8 *
9 * Based on the vim2m driver, that is:
10 *
11 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
12 * Pawel Osciak, <pawel@osciak.com>
13 * Marek Szyprowski, <m.szyprowski@samsung.com>
14 */
15
16#ifndef _CEDRUS_DEC_H_
17#define _CEDRUS_DEC_H_
18
19extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
20
21void cedrus_device_work(struct work_struct *work);
22void cedrus_device_run(void *priv);
23
24int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
25 struct vb2_queue *dst_vq);
26
27#endif
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
new file mode 100644
index 000000000000..32adbcbe6175
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
@@ -0,0 +1,327 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Cedrus VPU driver
4 *
5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7 * Copyright (C) 2018 Bootlin
8 *
9 * Based on the vim2m driver, that is:
10 *
11 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
12 * Pawel Osciak, <pawel@osciak.com>
13 * Marek Szyprowski, <m.szyprowski@samsung.com>
14 */
15
16#include <linux/platform_device.h>
17#include <linux/of_reserved_mem.h>
18#include <linux/of_device.h>
19#include <linux/dma-mapping.h>
20#include <linux/interrupt.h>
21#include <linux/clk.h>
22#include <linux/regmap.h>
23#include <linux/reset.h>
24#include <linux/soc/sunxi/sunxi_sram.h>
25
26#include <media/videobuf2-core.h>
27#include <media/v4l2-mem2mem.h>
28
29#include "cedrus.h"
30#include "cedrus_hw.h"
31#include "cedrus_regs.h"
32
33int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec)
34{
35 u32 reg = 0;
36
37 /*
38 * FIXME: This is only valid on 32-bits DDR's, we should test
39 * it on the A13/A33.
40 */
41 reg |= VE_MODE_REC_WR_MODE_2MB;
42 reg |= VE_MODE_DDR_MODE_BW_128;
43
44 switch (codec) {
45 case CEDRUS_CODEC_MPEG2:
46 reg |= VE_MODE_DEC_MPEG;
47 break;
48
49 default:
50 return -EINVAL;
51 }
52
53 cedrus_write(dev, VE_MODE, reg);
54
55 return 0;
56}
57
58void cedrus_engine_disable(struct cedrus_dev *dev)
59{
60 cedrus_write(dev, VE_MODE, VE_MODE_DISABLED);
61}
62
63void cedrus_dst_format_set(struct cedrus_dev *dev,
64 struct v4l2_pix_format *fmt)
65{
66 unsigned int width = fmt->width;
67 unsigned int height = fmt->height;
68 u32 chroma_size;
69 u32 reg;
70
71 switch (fmt->pixelformat) {
72 case V4L2_PIX_FMT_NV12:
73 chroma_size = ALIGN(width, 16) * ALIGN(height, 16) / 2;
74
75 reg = VE_PRIMARY_OUT_FMT_NV12;
76 cedrus_write(dev, VE_PRIMARY_OUT_FMT, reg);
77
78 reg = VE_CHROMA_BUF_LEN_SDRT(chroma_size / 2);
79 cedrus_write(dev, VE_CHROMA_BUF_LEN, reg);
80
81 reg = chroma_size / 2;
82 cedrus_write(dev, VE_PRIMARY_CHROMA_BUF_LEN, reg);
83
84 reg = VE_PRIMARY_FB_LINE_STRIDE_LUMA(ALIGN(width, 16)) |
85 VE_PRIMARY_FB_LINE_STRIDE_CHROMA(ALIGN(width, 16) / 2);
86 cedrus_write(dev, VE_PRIMARY_FB_LINE_STRIDE, reg);
87
88 break;
89 case V4L2_PIX_FMT_SUNXI_TILED_NV12:
90 default:
91 reg = VE_PRIMARY_OUT_FMT_TILED_32_NV12;
92 cedrus_write(dev, VE_PRIMARY_OUT_FMT, reg);
93
94 reg = VE_SECONDARY_OUT_FMT_TILED_32_NV12;
95 cedrus_write(dev, VE_CHROMA_BUF_LEN, reg);
96
97 break;
98 }
99}
100
101static irqreturn_t cedrus_bh(int irq, void *data)
102{
103 struct cedrus_dev *dev = data;
104 struct cedrus_ctx *ctx;
105
106 ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
107 if (!ctx) {
108 v4l2_err(&dev->v4l2_dev,
109 "Instance released before the end of transaction\n");
110 return IRQ_HANDLED;
111 }
112
113 v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
114
115 return IRQ_HANDLED;
116}
117
118static irqreturn_t cedrus_irq(int irq, void *data)
119{
120 struct cedrus_dev *dev = data;
121 struct cedrus_ctx *ctx;
122 struct vb2_v4l2_buffer *src_buf, *dst_buf;
123 enum vb2_buffer_state state;
124 enum cedrus_irq_status status;
125 unsigned long flags;
126
127 spin_lock_irqsave(&dev->irq_lock, flags);
128
129 ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
130 if (!ctx) {
131 v4l2_err(&dev->v4l2_dev,
132 "Instance released before the end of transaction\n");
133 spin_unlock_irqrestore(&dev->irq_lock, flags);
134
135 return IRQ_NONE;
136 }
137
138 status = dev->dec_ops[ctx->current_codec]->irq_status(ctx);
139 if (status == CEDRUS_IRQ_NONE) {
140 spin_unlock_irqrestore(&dev->irq_lock, flags);
141 return IRQ_NONE;
142 }
143
144 dev->dec_ops[ctx->current_codec]->irq_disable(ctx);
145 dev->dec_ops[ctx->current_codec]->irq_clear(ctx);
146
147 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
148 dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
149
150 if (!src_buf || !dst_buf) {
151 v4l2_err(&dev->v4l2_dev,
152 "Missing source and/or destination buffers\n");
153 spin_unlock_irqrestore(&dev->irq_lock, flags);
154
155 return IRQ_HANDLED;
156 }
157
158 if (status == CEDRUS_IRQ_ERROR)
159 state = VB2_BUF_STATE_ERROR;
160 else
161 state = VB2_BUF_STATE_DONE;
162
163 v4l2_m2m_buf_done(src_buf, state);
164 v4l2_m2m_buf_done(dst_buf, state);
165
166 spin_unlock_irqrestore(&dev->irq_lock, flags);
167
168 return IRQ_WAKE_THREAD;
169}
170
171int cedrus_hw_probe(struct cedrus_dev *dev)
172{
173 const struct cedrus_variant *variant;
174 struct resource *res;
175 int irq_dec;
176 int ret;
177
178 variant = of_device_get_match_data(dev->dev);
179 if (!variant)
180 return -EINVAL;
181
182 dev->capabilities = variant->capabilities;
183
184 irq_dec = platform_get_irq(dev->pdev, 0);
185 if (irq_dec <= 0) {
186 v4l2_err(&dev->v4l2_dev, "Failed to get IRQ\n");
187
188 return irq_dec;
189 }
190 ret = devm_request_threaded_irq(dev->dev, irq_dec, cedrus_irq,
191 cedrus_bh, 0, dev_name(dev->dev),
192 dev);
193 if (ret) {
194 v4l2_err(&dev->v4l2_dev, "Failed to request IRQ\n");
195
196 return ret;
197 }
198
199 /*
200 * The VPU is only able to handle bus addresses so we have to subtract
201 * the RAM offset to the physcal addresses.
202 *
203 * This information will eventually be obtained from device-tree.
204 */
205
206#ifdef PHYS_PFN_OFFSET
207 dev->dev->dma_pfn_offset = PHYS_PFN_OFFSET;
208#endif
209
210 ret = of_reserved_mem_device_init(dev->dev);
211 if (ret && ret != -ENODEV) {
212 v4l2_err(&dev->v4l2_dev, "Failed to reserve memory\n");
213
214 return ret;
215 }
216
217 ret = sunxi_sram_claim(dev->dev);
218 if (ret) {
219 v4l2_err(&dev->v4l2_dev, "Failed to claim SRAM\n");
220
221 goto err_mem;
222 }
223
224 dev->ahb_clk = devm_clk_get(dev->dev, "ahb");
225 if (IS_ERR(dev->ahb_clk)) {
226 v4l2_err(&dev->v4l2_dev, "Failed to get AHB clock\n");
227
228 ret = PTR_ERR(dev->ahb_clk);
229 goto err_sram;
230 }
231
232 dev->mod_clk = devm_clk_get(dev->dev, "mod");
233 if (IS_ERR(dev->mod_clk)) {
234 v4l2_err(&dev->v4l2_dev, "Failed to get MOD clock\n");
235
236 ret = PTR_ERR(dev->mod_clk);
237 goto err_sram;
238 }
239
240 dev->ram_clk = devm_clk_get(dev->dev, "ram");
241 if (IS_ERR(dev->ram_clk)) {
242 v4l2_err(&dev->v4l2_dev, "Failed to get RAM clock\n");
243
244 ret = PTR_ERR(dev->ram_clk);
245 goto err_sram;
246 }
247
248 dev->rstc = devm_reset_control_get(dev->dev, NULL);
249 if (IS_ERR(dev->rstc)) {
250 v4l2_err(&dev->v4l2_dev, "Failed to get reset control\n");
251
252 ret = PTR_ERR(dev->rstc);
253 goto err_sram;
254 }
255
256 res = platform_get_resource(dev->pdev, IORESOURCE_MEM, 0);
257 dev->base = devm_ioremap_resource(dev->dev, res);
258 if (!dev->base) {
259 v4l2_err(&dev->v4l2_dev, "Failed to map registers\n");
260
261 ret = -ENOMEM;
262 goto err_sram;
263 }
264
265 ret = clk_set_rate(dev->mod_clk, CEDRUS_CLOCK_RATE_DEFAULT);
266 if (ret) {
267 v4l2_err(&dev->v4l2_dev, "Failed to set clock rate\n");
268
269 goto err_sram;
270 }
271
272 ret = clk_prepare_enable(dev->ahb_clk);
273 if (ret) {
274 v4l2_err(&dev->v4l2_dev, "Failed to enable AHB clock\n");
275
276 goto err_sram;
277 }
278
279 ret = clk_prepare_enable(dev->mod_clk);
280 if (ret) {
281 v4l2_err(&dev->v4l2_dev, "Failed to enable MOD clock\n");
282
283 goto err_ahb_clk;
284 }
285
286 ret = clk_prepare_enable(dev->ram_clk);
287 if (ret) {
288 v4l2_err(&dev->v4l2_dev, "Failed to enable RAM clock\n");
289
290 goto err_mod_clk;
291 }
292
293 ret = reset_control_reset(dev->rstc);
294 if (ret) {
295 v4l2_err(&dev->v4l2_dev, "Failed to apply reset\n");
296
297 goto err_ram_clk;
298 }
299
300 return 0;
301
302err_ram_clk:
303 clk_disable_unprepare(dev->ram_clk);
304err_mod_clk:
305 clk_disable_unprepare(dev->mod_clk);
306err_ahb_clk:
307 clk_disable_unprepare(dev->ahb_clk);
308err_sram:
309 sunxi_sram_release(dev->dev);
310err_mem:
311 of_reserved_mem_device_release(dev->dev);
312
313 return ret;
314}
315
316void cedrus_hw_remove(struct cedrus_dev *dev)
317{
318 reset_control_assert(dev->rstc);
319
320 clk_disable_unprepare(dev->ram_clk);
321 clk_disable_unprepare(dev->mod_clk);
322 clk_disable_unprepare(dev->ahb_clk);
323
324 sunxi_sram_release(dev->dev);
325
326 of_reserved_mem_device_release(dev->dev);
327}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
new file mode 100644
index 000000000000..b43c77d54b95
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
@@ -0,0 +1,30 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Cedrus VPU driver
4 *
5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7 * Copyright (C) 2018 Bootlin
8 *
9 * Based on the vim2m driver, that is:
10 *
11 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
12 * Pawel Osciak, <pawel@osciak.com>
13 * Marek Szyprowski, <m.szyprowski@samsung.com>
14 */
15
16#ifndef _CEDRUS_HW_H_
17#define _CEDRUS_HW_H_
18
19#define CEDRUS_CLOCK_RATE_DEFAULT 320000000
20
21int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec);
22void cedrus_engine_disable(struct cedrus_dev *dev);
23
24void cedrus_dst_format_set(struct cedrus_dev *dev,
25 struct v4l2_pix_format *fmt);
26
27int cedrus_hw_probe(struct cedrus_dev *dev);
28void cedrus_hw_remove(struct cedrus_dev *dev);
29
30#endif
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
new file mode 100644
index 000000000000..9abd39cae38c
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
@@ -0,0 +1,246 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Cedrus VPU driver
4 *
5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7 * Copyright (C) 2018 Bootlin
8 */
9
10#include <media/videobuf2-dma-contig.h>
11
12#include "cedrus.h"
13#include "cedrus_hw.h"
14#include "cedrus_regs.h"
15
16/* Default MPEG-2 quantization coefficients, from the specification. */
17
18static const u8 intra_quantization_matrix_default[64] = {
19 8, 16, 16, 19, 16, 19, 22, 22,
20 22, 22, 22, 22, 26, 24, 26, 27,
21 27, 27, 26, 26, 26, 26, 27, 27,
22 27, 29, 29, 29, 34, 34, 34, 29,
23 29, 29, 27, 27, 29, 29, 32, 32,
24 34, 34, 37, 38, 37, 35, 35, 34,
25 35, 38, 38, 40, 40, 40, 48, 48,
26 46, 46, 56, 56, 58, 69, 69, 83
27};
28
29static const u8 non_intra_quantization_matrix_default[64] = {
30 16, 16, 16, 16, 16, 16, 16, 16,
31 16, 16, 16, 16, 16, 16, 16, 16,
32 16, 16, 16, 16, 16, 16, 16, 16,
33 16, 16, 16, 16, 16, 16, 16, 16,
34 16, 16, 16, 16, 16, 16, 16, 16,
35 16, 16, 16, 16, 16, 16, 16, 16,
36 16, 16, 16, 16, 16, 16, 16, 16,
37 16, 16, 16, 16, 16, 16, 16, 16
38};
39
40static enum cedrus_irq_status cedrus_mpeg2_irq_status(struct cedrus_ctx *ctx)
41{
42 struct cedrus_dev *dev = ctx->dev;
43 u32 reg;
44
45 reg = cedrus_read(dev, VE_DEC_MPEG_STATUS);
46 reg &= VE_DEC_MPEG_STATUS_CHECK_MASK;
47
48 if (!reg)
49 return CEDRUS_IRQ_NONE;
50
51 if (reg & VE_DEC_MPEG_STATUS_CHECK_ERROR ||
52 !(reg & VE_DEC_MPEG_STATUS_SUCCESS))
53 return CEDRUS_IRQ_ERROR;
54
55 return CEDRUS_IRQ_OK;
56}
57
58static void cedrus_mpeg2_irq_clear(struct cedrus_ctx *ctx)
59{
60 struct cedrus_dev *dev = ctx->dev;
61
62 cedrus_write(dev, VE_DEC_MPEG_STATUS, VE_DEC_MPEG_STATUS_CHECK_MASK);
63}
64
65static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx)
66{
67 struct cedrus_dev *dev = ctx->dev;
68 u32 reg = cedrus_read(dev, VE_DEC_MPEG_CTRL);
69
70 reg &= ~VE_DEC_MPEG_CTRL_IRQ_MASK;
71
72 cedrus_write(dev, VE_DEC_MPEG_CTRL, reg);
73}
74
75static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
76{
77 const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
78 const struct v4l2_mpeg2_sequence *sequence;
79 const struct v4l2_mpeg2_picture *picture;
80 const struct v4l2_ctrl_mpeg2_quantization *quantization;
81 dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr;
82 dma_addr_t fwd_luma_addr, fwd_chroma_addr;
83 dma_addr_t bwd_luma_addr, bwd_chroma_addr;
84 struct cedrus_dev *dev = ctx->dev;
85 const u8 *matrix;
86 unsigned int i;
87 u32 reg;
88
89 slice_params = run->mpeg2.slice_params;
90 sequence = &slice_params->sequence;
91 picture = &slice_params->picture;
92
93 quantization = run->mpeg2.quantization;
94
95 /* Activate MPEG engine. */
96 cedrus_engine_enable(dev, CEDRUS_CODEC_MPEG2);
97
98 /* Set intra quantization matrix. */
99
100 if (quantization && quantization->load_intra_quantiser_matrix)
101 matrix = quantization->intra_quantiser_matrix;
102 else
103 matrix = intra_quantization_matrix_default;
104
105 for (i = 0; i < 64; i++) {
106 reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
107 reg |= VE_DEC_MPEG_IQMINPUT_FLAG_INTRA;
108
109 cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg);
110 }
111
112 /* Set non-intra quantization matrix. */
113
114 if (quantization && quantization->load_non_intra_quantiser_matrix)
115 matrix = quantization->non_intra_quantiser_matrix;
116 else
117 matrix = non_intra_quantization_matrix_default;
118
119 for (i = 0; i < 64; i++) {
120 reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
121 reg |= VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA;
122
123 cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg);
124 }
125
126 /* Set MPEG picture header. */
127
128 reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(picture->picture_coding_type);
129 reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, picture->f_code[0][0]);
130 reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, picture->f_code[0][1]);
131 reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, picture->f_code[1][0]);
132 reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, picture->f_code[1][1]);
133 reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(picture->intra_dc_precision);
134 reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(picture->picture_structure);
135 reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(picture->top_field_first);
136 reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(picture->frame_pred_frame_dct);
137 reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(picture->concealment_motion_vectors);
138 reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(picture->q_scale_type);
139 reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(picture->intra_vlc_format);
140 reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(picture->alternate_scan);
141 reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_FORWARD_VECTOR(0);
142 reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_BACKWARD_VECTOR(0);
143
144 cedrus_write(dev, VE_DEC_MPEG_MP12HDR, reg);
145
146 /* Set frame dimensions. */
147
148 reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(sequence->horizontal_size);
149 reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(sequence->vertical_size);
150
151 cedrus_write(dev, VE_DEC_MPEG_PICCODEDSIZE, reg);
152
153 reg = VE_DEC_MPEG_PICBOUNDSIZE_WIDTH(ctx->src_fmt.width);
154 reg |= VE_DEC_MPEG_PICBOUNDSIZE_HEIGHT(ctx->src_fmt.height);
155
156 cedrus_write(dev, VE_DEC_MPEG_PICBOUNDSIZE, reg);
157
158 /* Forward and backward prediction reference buffers. */
159
160 fwd_luma_addr = cedrus_dst_buf_addr(ctx,
161 slice_params->forward_ref_index,
162 0);
163 fwd_chroma_addr = cedrus_dst_buf_addr(ctx,
164 slice_params->forward_ref_index,
165 1);
166
167 cedrus_write(dev, VE_DEC_MPEG_FWD_REF_LUMA_ADDR, fwd_luma_addr);
168 cedrus_write(dev, VE_DEC_MPEG_FWD_REF_CHROMA_ADDR, fwd_chroma_addr);
169
170 bwd_luma_addr = cedrus_dst_buf_addr(ctx,
171 slice_params->backward_ref_index,
172 0);
173 bwd_chroma_addr = cedrus_dst_buf_addr(ctx,
174 slice_params->backward_ref_index,
175 1);
176
177 cedrus_write(dev, VE_DEC_MPEG_BWD_REF_LUMA_ADDR, bwd_luma_addr);
178 cedrus_write(dev, VE_DEC_MPEG_BWD_REF_CHROMA_ADDR, bwd_chroma_addr);
179
180 /* Destination luma and chroma buffers. */
181
182 dst_luma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 0);
183 dst_chroma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 1);
184
185 cedrus_write(dev, VE_DEC_MPEG_REC_LUMA, dst_luma_addr);
186 cedrus_write(dev, VE_DEC_MPEG_REC_CHROMA, dst_chroma_addr);
187
188 /* Source offset and length in bits. */
189
190 cedrus_write(dev, VE_DEC_MPEG_VLD_OFFSET,
191 slice_params->data_bit_offset);
192
193 reg = slice_params->bit_size - slice_params->data_bit_offset;
194 cedrus_write(dev, VE_DEC_MPEG_VLD_LEN, reg);
195
196 /* Source beginning and end addresses. */
197
198 src_buf_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0);
199
200 reg = VE_DEC_MPEG_VLD_ADDR_BASE(src_buf_addr);
201 reg |= VE_DEC_MPEG_VLD_ADDR_VALID_PIC_DATA;
202 reg |= VE_DEC_MPEG_VLD_ADDR_LAST_PIC_DATA;
203 reg |= VE_DEC_MPEG_VLD_ADDR_FIRST_PIC_DATA;
204
205 cedrus_write(dev, VE_DEC_MPEG_VLD_ADDR, reg);
206
207 reg = src_buf_addr + DIV_ROUND_UP(slice_params->bit_size, 8);
208 cedrus_write(dev, VE_DEC_MPEG_VLD_END_ADDR, reg);
209
210 /* Macroblock address: start at the beginning. */
211 reg = VE_DEC_MPEG_MBADDR_Y(0) | VE_DEC_MPEG_MBADDR_X(0);
212 cedrus_write(dev, VE_DEC_MPEG_MBADDR, reg);
213
214 /* Clear previous errors. */
215 cedrus_write(dev, VE_DEC_MPEG_ERROR, 0);
216
217 /* Clear correct macroblocks register. */
218 cedrus_write(dev, VE_DEC_MPEG_CRTMBADDR, 0);
219
220 /* Enable appropriate interruptions and components. */
221
222 reg = VE_DEC_MPEG_CTRL_IRQ_MASK | VE_DEC_MPEG_CTRL_MC_NO_WRITEBACK |
223 VE_DEC_MPEG_CTRL_MC_CACHE_EN;
224
225 cedrus_write(dev, VE_DEC_MPEG_CTRL, reg);
226}
227
228static void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx)
229{
230 struct cedrus_dev *dev = ctx->dev;
231 u32 reg;
232
233 /* Trigger MPEG engine. */
234 reg = VE_DEC_MPEG_TRIGGER_HW_MPEG_VLD | VE_DEC_MPEG_TRIGGER_MPEG2 |
235 VE_DEC_MPEG_TRIGGER_MB_BOUNDARY;
236
237 cedrus_write(dev, VE_DEC_MPEG_TRIGGER, reg);
238}
239
240struct cedrus_dec_ops cedrus_dec_ops_mpeg2 = {
241 .irq_clear = cedrus_mpeg2_irq_clear,
242 .irq_disable = cedrus_mpeg2_irq_disable,
243 .irq_status = cedrus_mpeg2_irq_status,
244 .setup = cedrus_mpeg2_setup,
245 .trigger = cedrus_mpeg2_trigger,
246};
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
new file mode 100644
index 000000000000..de2d6b6f64bf
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -0,0 +1,235 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Cedrus VPU driver
4 *
5 * Copyright (c) 2013-2016 Jens Kuske <jenskuske@gmail.com>
6 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
7 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
8 */
9
10#ifndef _CEDRUS_REGS_H_
11#define _CEDRUS_REGS_H_
12
13/*
14 * Common acronyms and contractions used in register descriptions:
15 * * VLD : Variable-Length Decoder
16 * * IQ: Inverse Quantization
17 * * IDCT: Inverse Discrete Cosine Transform
18 * * MC: Motion Compensation
19 * * STCD: Start Code Detect
20 * * SDRT: Scale Down and Rotate
21 */
22
23#define VE_ENGINE_DEC_MPEG 0x100
24#define VE_ENGINE_DEC_H264 0x200
25
26#define VE_MODE 0x00
27
28#define VE_MODE_REC_WR_MODE_2MB (0x01 << 20)
29#define VE_MODE_REC_WR_MODE_1MB (0x00 << 20)
30#define VE_MODE_DDR_MODE_BW_128 (0x03 << 16)
31#define VE_MODE_DDR_MODE_BW_256 (0x02 << 16)
32#define VE_MODE_DISABLED (0x07 << 0)
33#define VE_MODE_DEC_H265 (0x04 << 0)
34#define VE_MODE_DEC_H264 (0x01 << 0)
35#define VE_MODE_DEC_MPEG (0x00 << 0)
36
37#define VE_PRIMARY_CHROMA_BUF_LEN 0xc4
38#define VE_PRIMARY_FB_LINE_STRIDE 0xc8
39
40#define VE_PRIMARY_FB_LINE_STRIDE_CHROMA(s) (((s) << 16) & GENMASK(31, 16))
41#define VE_PRIMARY_FB_LINE_STRIDE_LUMA(s) (((s) << 0) & GENMASK(15, 0))
42
43#define VE_CHROMA_BUF_LEN 0xe8
44
45#define VE_SECONDARY_OUT_FMT_TILED_32_NV12 (0x00 << 30)
46#define VE_SECONDARY_OUT_FMT_EXT (0x01 << 30)
47#define VE_SECONDARY_OUT_FMT_YU12 (0x02 << 30)
48#define VE_SECONDARY_OUT_FMT_YV12 (0x03 << 30)
49#define VE_CHROMA_BUF_LEN_SDRT(l) ((l) & GENMASK(27, 0))
50
51#define VE_PRIMARY_OUT_FMT 0xec
52
53#define VE_PRIMARY_OUT_FMT_TILED_32_NV12 (0x00 << 4)
54#define VE_PRIMARY_OUT_FMT_TILED_128_NV12 (0x01 << 4)
55#define VE_PRIMARY_OUT_FMT_YU12 (0x02 << 4)
56#define VE_PRIMARY_OUT_FMT_YV12 (0x03 << 4)
57#define VE_PRIMARY_OUT_FMT_NV12 (0x04 << 4)
58#define VE_PRIMARY_OUT_FMT_NV21 (0x05 << 4)
59#define VE_SECONDARY_OUT_FMT_EXT_TILED_32_NV12 (0x00 << 0)
60#define VE_SECONDARY_OUT_FMT_EXT_TILED_128_NV12 (0x01 << 0)
61#define VE_SECONDARY_OUT_FMT_EXT_YU12 (0x02 << 0)
62#define VE_SECONDARY_OUT_FMT_EXT_YV12 (0x03 << 0)
63#define VE_SECONDARY_OUT_FMT_EXT_NV12 (0x04 << 0)
64#define VE_SECONDARY_OUT_FMT_EXT_NV21 (0x05 << 0)
65
66#define VE_VERSION 0xf0
67
68#define VE_VERSION_SHIFT 16
69
70#define VE_DEC_MPEG_MP12HDR (VE_ENGINE_DEC_MPEG + 0x00)
71
72#define VE_DEC_MPEG_MP12HDR_SLICE_TYPE(t) (((t) << 28) & GENMASK(30, 28))
73#define VE_DEC_MPEG_MP12HDR_F_CODE_SHIFT(x, y) (24 - 4 * (y) - 8 * (x))
74#define VE_DEC_MPEG_MP12HDR_F_CODE(__x, __y, __v) \
75 (((__v) & GENMASK(3, 0)) << VE_DEC_MPEG_MP12HDR_F_CODE_SHIFT(__x, __y))
76
77#define VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(p) \
78 (((p) << 10) & GENMASK(11, 10))
79#define VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(s) \
80 (((s) << 8) & GENMASK(9, 8))
81#define VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(v) \
82 ((v) ? BIT(7) : 0)
83#define VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(v) \
84 ((v) ? BIT(6) : 0)
85#define VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(v) \
86 ((v) ? BIT(5) : 0)
87#define VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(v) \
88 ((v) ? BIT(4) : 0)
89#define VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(v) \
90 ((v) ? BIT(3) : 0)
91#define VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(v) \
92 ((v) ? BIT(2) : 0)
93#define VE_DEC_MPEG_MP12HDR_FULL_PEL_FORWARD_VECTOR(v) \
94 ((v) ? BIT(1) : 0)
95#define VE_DEC_MPEG_MP12HDR_FULL_PEL_BACKWARD_VECTOR(v) \
96 ((v) ? BIT(0) : 0)
97
98#define VE_DEC_MPEG_PICCODEDSIZE (VE_ENGINE_DEC_MPEG + 0x08)
99
100#define VE_DEC_MPEG_PICCODEDSIZE_WIDTH(w) \
101 ((DIV_ROUND_UP((w), 16) << 8) & GENMASK(15, 8))
102#define VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(h) \
103 ((DIV_ROUND_UP((h), 16) << 0) & GENMASK(7, 0))
104
105#define VE_DEC_MPEG_PICBOUNDSIZE (VE_ENGINE_DEC_MPEG + 0x0c)
106
107#define VE_DEC_MPEG_PICBOUNDSIZE_WIDTH(w) (((w) << 16) & GENMASK(27, 16))
108#define VE_DEC_MPEG_PICBOUNDSIZE_HEIGHT(h) (((h) << 0) & GENMASK(11, 0))
109
110#define VE_DEC_MPEG_MBADDR (VE_ENGINE_DEC_MPEG + 0x10)
111
112#define VE_DEC_MPEG_MBADDR_X(w) (((w) << 8) & GENMASK(15, 8))
113#define VE_DEC_MPEG_MBADDR_Y(h) (((h) << 0) & GENMASK(0, 7))
114
115#define VE_DEC_MPEG_CTRL (VE_ENGINE_DEC_MPEG + 0x14)
116
117#define VE_DEC_MPEG_CTRL_MC_CACHE_EN BIT(31)
118#define VE_DEC_MPEG_CTRL_SW_VLD BIT(27)
119#define VE_DEC_MPEG_CTRL_SW_IQ_IS BIT(17)
120#define VE_DEC_MPEG_CTRL_QP_AC_DC_OUT_EN BIT(14)
121#define VE_DEC_MPEG_CTRL_ROTATE_SCALE_OUT_EN BIT(8)
122#define VE_DEC_MPEG_CTRL_MC_NO_WRITEBACK BIT(7)
123#define VE_DEC_MPEG_CTRL_ROTATE_IRQ_EN BIT(6)
124#define VE_DEC_MPEG_CTRL_VLD_DATA_REQ_IRQ_EN BIT(5)
125#define VE_DEC_MPEG_CTRL_ERROR_IRQ_EN BIT(4)
126#define VE_DEC_MPEG_CTRL_FINISH_IRQ_EN BIT(3)
127#define VE_DEC_MPEG_CTRL_IRQ_MASK \
128 (VE_DEC_MPEG_CTRL_FINISH_IRQ_EN | VE_DEC_MPEG_CTRL_ERROR_IRQ_EN | \
129 VE_DEC_MPEG_CTRL_VLD_DATA_REQ_IRQ_EN)
130
131#define VE_DEC_MPEG_TRIGGER (VE_ENGINE_DEC_MPEG + 0x18)
132
133#define VE_DEC_MPEG_TRIGGER_MB_BOUNDARY BIT(31)
134
135#define VE_DEC_MPEG_TRIGGER_CHROMA_FMT_420 (0x00 << 27)
136#define VE_DEC_MPEG_TRIGGER_CHROMA_FMT_411 (0x01 << 27)
137#define VE_DEC_MPEG_TRIGGER_CHROMA_FMT_422 (0x02 << 27)
138#define VE_DEC_MPEG_TRIGGER_CHROMA_FMT_444 (0x03 << 27)
139#define VE_DEC_MPEG_TRIGGER_CHROMA_FMT_422T (0x04 << 27)
140
141#define VE_DEC_MPEG_TRIGGER_MPEG1 (0x01 << 24)
142#define VE_DEC_MPEG_TRIGGER_MPEG2 (0x02 << 24)
143#define VE_DEC_MPEG_TRIGGER_JPEG (0x03 << 24)
144#define VE_DEC_MPEG_TRIGGER_MPEG4 (0x04 << 24)
145#define VE_DEC_MPEG_TRIGGER_VP62 (0x05 << 24)
146
147#define VE_DEC_MPEG_TRIGGER_VP62_AC_GET_BITS BIT(7)
148
149#define VE_DEC_MPEG_TRIGGER_STCD_VC1 (0x02 << 4)
150#define VE_DEC_MPEG_TRIGGER_STCD_MPEG2 (0x01 << 4)
151#define VE_DEC_MPEG_TRIGGER_STCD_AVC (0x00 << 4)
152
153#define VE_DEC_MPEG_TRIGGER_HW_MPEG_VLD (0x0f << 0)
154#define VE_DEC_MPEG_TRIGGER_HW_JPEG_VLD (0x0e << 0)
155#define VE_DEC_MPEG_TRIGGER_HW_MB (0x0d << 0)
156#define VE_DEC_MPEG_TRIGGER_HW_ROTATE (0x0c << 0)
157#define VE_DEC_MPEG_TRIGGER_HW_VP6_VLD (0x0b << 0)
158#define VE_DEC_MPEG_TRIGGER_HW_MAF (0x0a << 0)
159#define VE_DEC_MPEG_TRIGGER_HW_STCD_END (0x09 << 0)
160#define VE_DEC_MPEG_TRIGGER_HW_STCD_BEGIN (0x08 << 0)
161#define VE_DEC_MPEG_TRIGGER_SW_MC (0x07 << 0)
162#define VE_DEC_MPEG_TRIGGER_SW_IQ (0x06 << 0)
163#define VE_DEC_MPEG_TRIGGER_SW_IDCT (0x05 << 0)
164#define VE_DEC_MPEG_TRIGGER_SW_SCALE (0x04 << 0)
165#define VE_DEC_MPEG_TRIGGER_SW_VP6 (0x03 << 0)
166#define VE_DEC_MPEG_TRIGGER_SW_VP62_AC_GET_BITS (0x02 << 0)
167
168#define VE_DEC_MPEG_STATUS (VE_ENGINE_DEC_MPEG + 0x1c)
169
170#define VE_DEC_MPEG_STATUS_START_DETECT_BUSY BIT(27)
171#define VE_DEC_MPEG_STATUS_VP6_BIT BIT(26)
172#define VE_DEC_MPEG_STATUS_VP6_BIT_BUSY BIT(25)
173#define VE_DEC_MPEG_STATUS_MAF_BUSY BIT(23)
174#define VE_DEC_MPEG_STATUS_VP6_MVP_BUSY BIT(22)
175#define VE_DEC_MPEG_STATUS_JPEG_BIT_END BIT(21)
176#define VE_DEC_MPEG_STATUS_JPEG_RESTART_ERROR BIT(20)
177#define VE_DEC_MPEG_STATUS_JPEG_MARKER BIT(19)
178#define VE_DEC_MPEG_STATUS_ROTATE_BUSY BIT(18)
179#define VE_DEC_MPEG_STATUS_DEBLOCKING_BUSY BIT(17)
180#define VE_DEC_MPEG_STATUS_SCALE_DOWN_BUSY BIT(16)
181#define VE_DEC_MPEG_STATUS_IQIS_BUF_EMPTY BIT(15)
182#define VE_DEC_MPEG_STATUS_IDCT_BUF_EMPTY BIT(14)
183#define VE_DEC_MPEG_STATUS_VE_BUSY BIT(13)
184#define VE_DEC_MPEG_STATUS_MC_BUSY BIT(12)
185#define VE_DEC_MPEG_STATUS_IDCT_BUSY BIT(11)
186#define VE_DEC_MPEG_STATUS_IQIS_BUSY BIT(10)
187#define VE_DEC_MPEG_STATUS_DCAC_BUSY BIT(9)
188#define VE_DEC_MPEG_STATUS_VLD_BUSY BIT(8)
189#define VE_DEC_MPEG_STATUS_ROTATE_SUCCESS BIT(3)
190#define VE_DEC_MPEG_STATUS_VLD_DATA_REQ BIT(2)
191#define VE_DEC_MPEG_STATUS_ERROR BIT(1)
192#define VE_DEC_MPEG_STATUS_SUCCESS BIT(0)
193#define VE_DEC_MPEG_STATUS_CHECK_MASK \
194 (VE_DEC_MPEG_STATUS_SUCCESS | VE_DEC_MPEG_STATUS_ERROR | \
195 VE_DEC_MPEG_STATUS_VLD_DATA_REQ)
196#define VE_DEC_MPEG_STATUS_CHECK_ERROR \
197 (VE_DEC_MPEG_STATUS_ERROR | VE_DEC_MPEG_STATUS_VLD_DATA_REQ)
198
199#define VE_DEC_MPEG_VLD_ADDR (VE_ENGINE_DEC_MPEG + 0x28)
200
201#define VE_DEC_MPEG_VLD_ADDR_FIRST_PIC_DATA BIT(30)
202#define VE_DEC_MPEG_VLD_ADDR_LAST_PIC_DATA BIT(29)
203#define VE_DEC_MPEG_VLD_ADDR_VALID_PIC_DATA BIT(28)
204#define VE_DEC_MPEG_VLD_ADDR_BASE(a) \
205 ({ \
206 u32 _tmp = (a); \
207 u32 _lo = _tmp & GENMASK(27, 4); \
208 u32 _hi = (_tmp >> 28) & GENMASK(3, 0); \
209 (_lo | _hi); \
210 })
211
212#define VE_DEC_MPEG_VLD_OFFSET (VE_ENGINE_DEC_MPEG + 0x2c)
213#define VE_DEC_MPEG_VLD_LEN (VE_ENGINE_DEC_MPEG + 0x30)
214#define VE_DEC_MPEG_VLD_END_ADDR (VE_ENGINE_DEC_MPEG + 0x34)
215
216#define VE_DEC_MPEG_REC_LUMA (VE_ENGINE_DEC_MPEG + 0x48)
217#define VE_DEC_MPEG_REC_CHROMA (VE_ENGINE_DEC_MPEG + 0x4c)
218#define VE_DEC_MPEG_FWD_REF_LUMA_ADDR (VE_ENGINE_DEC_MPEG + 0x50)
219#define VE_DEC_MPEG_FWD_REF_CHROMA_ADDR (VE_ENGINE_DEC_MPEG + 0x54)
220#define VE_DEC_MPEG_BWD_REF_LUMA_ADDR (VE_ENGINE_DEC_MPEG + 0x58)
221#define VE_DEC_MPEG_BWD_REF_CHROMA_ADDR (VE_ENGINE_DEC_MPEG + 0x5c)
222
223#define VE_DEC_MPEG_IQMINPUT (VE_ENGINE_DEC_MPEG + 0x80)
224
225#define VE_DEC_MPEG_IQMINPUT_FLAG_INTRA (0x01 << 14)
226#define VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA (0x00 << 14)
227#define VE_DEC_MPEG_IQMINPUT_WEIGHT(i, v) \
228 (((v) & GENMASK(7, 0)) | (((i) << 8) & GENMASK(13, 8)))
229
230#define VE_DEC_MPEG_ERROR (VE_ENGINE_DEC_MPEG + 0xc4)
231#define VE_DEC_MPEG_CRTMBADDR (VE_ENGINE_DEC_MPEG + 0xc8)
232#define VE_DEC_MPEG_ROT_LUMA (VE_ENGINE_DEC_MPEG + 0xcc)
233#define VE_DEC_MPEG_ROT_CHROMA (VE_ENGINE_DEC_MPEG + 0xd0)
234
235#endif
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
new file mode 100644
index 000000000000..5c5fce678b93
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -0,0 +1,542 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Cedrus VPU driver
4 *
5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7 * Copyright (C) 2018 Bootlin
8 *
9 * Based on the vim2m driver, that is:
10 *
11 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
12 * Pawel Osciak, <pawel@osciak.com>
13 * Marek Szyprowski, <m.szyprowski@samsung.com>
14 */
15
16#include <media/videobuf2-dma-contig.h>
17#include <media/v4l2-device.h>
18#include <media/v4l2-ioctl.h>
19#include <media/v4l2-event.h>
20#include <media/v4l2-mem2mem.h>
21
22#include "cedrus.h"
23#include "cedrus_video.h"
24#include "cedrus_dec.h"
25#include "cedrus_hw.h"
26
27#define CEDRUS_DECODE_SRC BIT(0)
28#define CEDRUS_DECODE_DST BIT(1)
29
30#define CEDRUS_MIN_WIDTH 16U
31#define CEDRUS_MIN_HEIGHT 16U
32#define CEDRUS_MAX_WIDTH 3840U
33#define CEDRUS_MAX_HEIGHT 2160U
34
35static struct cedrus_format cedrus_formats[] = {
36 {
37 .pixelformat = V4L2_PIX_FMT_MPEG2_SLICE,
38 .directions = CEDRUS_DECODE_SRC,
39 },
40 {
41 .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12,
42 .directions = CEDRUS_DECODE_DST,
43 },
44 {
45 .pixelformat = V4L2_PIX_FMT_NV12,
46 .directions = CEDRUS_DECODE_DST,
47 .capabilities = CEDRUS_CAPABILITY_UNTILED,
48 },
49};
50
51#define CEDRUS_FORMATS_COUNT ARRAY_SIZE(cedrus_formats)
52
53static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file)
54{
55 return container_of(file->private_data, struct cedrus_ctx, fh);
56}
57
58static struct cedrus_format *cedrus_find_format(u32 pixelformat, u32 directions,
59 unsigned int capabilities)
60{
61 struct cedrus_format *fmt;
62 unsigned int i;
63
64 for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
65 fmt = &cedrus_formats[i];
66
67 if (fmt->capabilities && (fmt->capabilities & capabilities) !=
68 fmt->capabilities)
69 continue;
70
71 if (fmt->pixelformat == pixelformat &&
72 (fmt->directions & directions) != 0)
73 break;
74 }
75
76 if (i == CEDRUS_FORMATS_COUNT)
77 return NULL;
78
79 return &cedrus_formats[i];
80}
81
82static bool cedrus_check_format(u32 pixelformat, u32 directions,
83 unsigned int capabilities)
84{
85 return cedrus_find_format(pixelformat, directions, capabilities);
86}
87
88static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt)
89{
90 unsigned int width = pix_fmt->width;
91 unsigned int height = pix_fmt->height;
92 unsigned int sizeimage = pix_fmt->sizeimage;
93 unsigned int bytesperline = pix_fmt->bytesperline;
94
95 pix_fmt->field = V4L2_FIELD_NONE;
96
97 /* Limit to hardware min/max. */
98 width = clamp(width, CEDRUS_MIN_WIDTH, CEDRUS_MAX_WIDTH);
99 height = clamp(height, CEDRUS_MIN_HEIGHT, CEDRUS_MAX_HEIGHT);
100
101 switch (pix_fmt->pixelformat) {
102 case V4L2_PIX_FMT_MPEG2_SLICE:
103 /* Zero bytes per line for encoded source. */
104 bytesperline = 0;
105
106 break;
107
108 case V4L2_PIX_FMT_SUNXI_TILED_NV12:
109 /* 32-aligned stride. */
110 bytesperline = ALIGN(width, 32);
111
112 /* 32-aligned height. */
113 height = ALIGN(height, 32);
114
115 /* Luma plane size. */
116 sizeimage = bytesperline * height;
117
118 /* Chroma plane size. */
119 sizeimage += bytesperline * height / 2;
120
121 break;
122
123 case V4L2_PIX_FMT_NV12:
124 /* 16-aligned stride. */
125 bytesperline = ALIGN(width, 16);
126
127 /* 16-aligned height. */
128 height = ALIGN(height, 16);
129
130 /* Luma plane size. */
131 sizeimage = bytesperline * height;
132
133 /* Chroma plane size. */
134 sizeimage += bytesperline * height / 2;
135
136 break;
137 }
138
139 pix_fmt->width = width;
140 pix_fmt->height = height;
141
142 pix_fmt->bytesperline = bytesperline;
143 pix_fmt->sizeimage = sizeimage;
144}
145
146static int cedrus_querycap(struct file *file, void *priv,
147 struct v4l2_capability *cap)
148{
149 strscpy(cap->driver, CEDRUS_NAME, sizeof(cap->driver));
150 strscpy(cap->card, CEDRUS_NAME, sizeof(cap->card));
151 snprintf(cap->bus_info, sizeof(cap->bus_info),
152 "platform:%s", CEDRUS_NAME);
153
154 return 0;
155}
156
157static int cedrus_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
158 u32 direction)
159{
160 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
161 struct cedrus_dev *dev = ctx->dev;
162 unsigned int capabilities = dev->capabilities;
163 struct cedrus_format *fmt;
164 unsigned int i, index;
165
166 /* Index among formats that match the requested direction. */
167 index = 0;
168
169 for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
170 fmt = &cedrus_formats[i];
171
172 if (fmt->capabilities && (fmt->capabilities & capabilities) !=
173 fmt->capabilities)
174 continue;
175
176 if (!(cedrus_formats[i].directions & direction))
177 continue;
178
179 if (index == f->index)
180 break;
181
182 index++;
183 }
184
185 /* Matched format. */
186 if (i < CEDRUS_FORMATS_COUNT) {
187 f->pixelformat = cedrus_formats[i].pixelformat;
188
189 return 0;
190 }
191
192 return -EINVAL;
193}
194
195static int cedrus_enum_fmt_vid_cap(struct file *file, void *priv,
196 struct v4l2_fmtdesc *f)
197{
198 return cedrus_enum_fmt(file, f, CEDRUS_DECODE_DST);
199}
200
201static int cedrus_enum_fmt_vid_out(struct file *file, void *priv,
202 struct v4l2_fmtdesc *f)
203{
204 return cedrus_enum_fmt(file, f, CEDRUS_DECODE_SRC);
205}
206
207static int cedrus_g_fmt_vid_cap(struct file *file, void *priv,
208 struct v4l2_format *f)
209{
210 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
211
212 /* Fall back to dummy default by lack of hardware configuration. */
213 if (!ctx->dst_fmt.width || !ctx->dst_fmt.height) {
214 f->fmt.pix.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12;
215 cedrus_prepare_format(&f->fmt.pix);
216
217 return 0;
218 }
219
220 f->fmt.pix = ctx->dst_fmt;
221
222 return 0;
223}
224
225static int cedrus_g_fmt_vid_out(struct file *file, void *priv,
226 struct v4l2_format *f)
227{
228 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
229
230 /* Fall back to dummy default by lack of hardware configuration. */
231 if (!ctx->dst_fmt.width || !ctx->dst_fmt.height) {
232 f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE;
233 f->fmt.pix.sizeimage = SZ_1K;
234 cedrus_prepare_format(&f->fmt.pix);
235
236 return 0;
237 }
238
239 f->fmt.pix = ctx->src_fmt;
240
241 return 0;
242}
243
244static int cedrus_try_fmt_vid_cap(struct file *file, void *priv,
245 struct v4l2_format *f)
246{
247 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
248 struct cedrus_dev *dev = ctx->dev;
249 struct v4l2_pix_format *pix_fmt = &f->fmt.pix;
250
251 if (!cedrus_check_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST,
252 dev->capabilities))
253 return -EINVAL;
254
255 cedrus_prepare_format(pix_fmt);
256
257 return 0;
258}
259
260static int cedrus_try_fmt_vid_out(struct file *file, void *priv,
261 struct v4l2_format *f)
262{
263 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
264 struct cedrus_dev *dev = ctx->dev;
265 struct v4l2_pix_format *pix_fmt = &f->fmt.pix;
266
267 if (!cedrus_check_format(pix_fmt->pixelformat, CEDRUS_DECODE_SRC,
268 dev->capabilities))
269 return -EINVAL;
270
271 /* Source image size has to be provided by userspace. */
272 if (pix_fmt->sizeimage == 0)
273 return -EINVAL;
274
275 cedrus_prepare_format(pix_fmt);
276
277 return 0;
278}
279
280static int cedrus_s_fmt_vid_cap(struct file *file, void *priv,
281 struct v4l2_format *f)
282{
283 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
284 struct cedrus_dev *dev = ctx->dev;
285 int ret;
286
287 ret = cedrus_try_fmt_vid_cap(file, priv, f);
288 if (ret)
289 return ret;
290
291 ctx->dst_fmt = f->fmt.pix;
292
293 cedrus_dst_format_set(dev, &ctx->dst_fmt);
294
295 return 0;
296}
297
298static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
299 struct v4l2_format *f)
300{
301 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
302 int ret;
303
304 ret = cedrus_try_fmt_vid_out(file, priv, f);
305 if (ret)
306 return ret;
307
308 ctx->src_fmt = f->fmt.pix;
309
310 /* Propagate colorspace information to capture. */
311 ctx->dst_fmt.colorspace = f->fmt.pix.colorspace;
312 ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func;
313 ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc;
314 ctx->dst_fmt.quantization = f->fmt.pix.quantization;
315
316 return 0;
317}
318
319const struct v4l2_ioctl_ops cedrus_ioctl_ops = {
320 .vidioc_querycap = cedrus_querycap,
321
322 .vidioc_enum_fmt_vid_cap = cedrus_enum_fmt_vid_cap,
323 .vidioc_g_fmt_vid_cap = cedrus_g_fmt_vid_cap,
324 .vidioc_try_fmt_vid_cap = cedrus_try_fmt_vid_cap,
325 .vidioc_s_fmt_vid_cap = cedrus_s_fmt_vid_cap,
326
327 .vidioc_enum_fmt_vid_out = cedrus_enum_fmt_vid_out,
328 .vidioc_g_fmt_vid_out = cedrus_g_fmt_vid_out,
329 .vidioc_try_fmt_vid_out = cedrus_try_fmt_vid_out,
330 .vidioc_s_fmt_vid_out = cedrus_s_fmt_vid_out,
331
332 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
333 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
334 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
335 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
336 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
337 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
338 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
339
340 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
341 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
342
343 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
344 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
345};
346
347static int cedrus_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
348 unsigned int *nplanes, unsigned int sizes[],
349 struct device *alloc_devs[])
350{
351 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
352 struct cedrus_dev *dev = ctx->dev;
353 struct v4l2_pix_format *pix_fmt;
354 u32 directions;
355
356 if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
357 directions = CEDRUS_DECODE_SRC;
358 pix_fmt = &ctx->src_fmt;
359 } else {
360 directions = CEDRUS_DECODE_DST;
361 pix_fmt = &ctx->dst_fmt;
362 }
363
364 if (!cedrus_check_format(pix_fmt->pixelformat, directions,
365 dev->capabilities))
366 return -EINVAL;
367
368 if (*nplanes) {
369 if (sizes[0] < pix_fmt->sizeimage)
370 return -EINVAL;
371 } else {
372 sizes[0] = pix_fmt->sizeimage;
373 *nplanes = 1;
374 }
375
376 return 0;
377}
378
379static void cedrus_queue_cleanup(struct vb2_queue *vq, u32 state)
380{
381 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
382 struct vb2_v4l2_buffer *vbuf;
383 unsigned long flags;
384
385 for (;;) {
386 spin_lock_irqsave(&ctx->dev->irq_lock, flags);
387
388 if (V4L2_TYPE_IS_OUTPUT(vq->type))
389 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
390 else
391 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
392
393 spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
394
395 if (!vbuf)
396 return;
397
398 v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
399 &ctx->hdl);
400 v4l2_m2m_buf_done(vbuf, state);
401 }
402}
403
404static int cedrus_buf_init(struct vb2_buffer *vb)
405{
406 struct vb2_queue *vq = vb->vb2_queue;
407 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
408
409 if (!V4L2_TYPE_IS_OUTPUT(vq->type))
410 ctx->dst_bufs[vb->index] = vb;
411
412 return 0;
413}
414
415static void cedrus_buf_cleanup(struct vb2_buffer *vb)
416{
417 struct vb2_queue *vq = vb->vb2_queue;
418 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
419
420 if (!V4L2_TYPE_IS_OUTPUT(vq->type))
421 ctx->dst_bufs[vb->index] = NULL;
422}
423
424static int cedrus_buf_prepare(struct vb2_buffer *vb)
425{
426 struct vb2_queue *vq = vb->vb2_queue;
427 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
428 struct v4l2_pix_format *pix_fmt;
429
430 if (V4L2_TYPE_IS_OUTPUT(vq->type))
431 pix_fmt = &ctx->src_fmt;
432 else
433 pix_fmt = &ctx->dst_fmt;
434
435 if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage)
436 return -EINVAL;
437
438 vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
439
440 return 0;
441}
442
443static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
444{
445 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
446 struct cedrus_dev *dev = ctx->dev;
447 int ret = 0;
448
449 switch (ctx->src_fmt.pixelformat) {
450 case V4L2_PIX_FMT_MPEG2_SLICE:
451 ctx->current_codec = CEDRUS_CODEC_MPEG2;
452 break;
453
454 default:
455 return -EINVAL;
456 }
457
458 if (V4L2_TYPE_IS_OUTPUT(vq->type) &&
459 dev->dec_ops[ctx->current_codec]->start)
460 ret = dev->dec_ops[ctx->current_codec]->start(ctx);
461
462 if (ret)
463 cedrus_queue_cleanup(vq, VB2_BUF_STATE_QUEUED);
464
465 return ret;
466}
467
468static void cedrus_stop_streaming(struct vb2_queue *vq)
469{
470 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
471 struct cedrus_dev *dev = ctx->dev;
472
473 if (V4L2_TYPE_IS_OUTPUT(vq->type) &&
474 dev->dec_ops[ctx->current_codec]->stop)
475 dev->dec_ops[ctx->current_codec]->stop(ctx);
476
477 cedrus_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
478}
479
480static void cedrus_buf_queue(struct vb2_buffer *vb)
481{
482 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
483 struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
484
485 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
486}
487
488static void cedrus_buf_request_complete(struct vb2_buffer *vb)
489{
490 struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
491
492 v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
493}
494
495static struct vb2_ops cedrus_qops = {
496 .queue_setup = cedrus_queue_setup,
497 .buf_prepare = cedrus_buf_prepare,
498 .buf_init = cedrus_buf_init,
499 .buf_cleanup = cedrus_buf_cleanup,
500 .buf_queue = cedrus_buf_queue,
501 .buf_request_complete = cedrus_buf_request_complete,
502 .start_streaming = cedrus_start_streaming,
503 .stop_streaming = cedrus_stop_streaming,
504 .wait_prepare = vb2_ops_wait_prepare,
505 .wait_finish = vb2_ops_wait_finish,
506};
507
508int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
509 struct vb2_queue *dst_vq)
510{
511 struct cedrus_ctx *ctx = priv;
512 int ret;
513
514 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
515 src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
516 src_vq->drv_priv = ctx;
517 src_vq->buf_struct_size = sizeof(struct cedrus_buffer);
518 src_vq->min_buffers_needed = 1;
519 src_vq->ops = &cedrus_qops;
520 src_vq->mem_ops = &vb2_dma_contig_memops;
521 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
522 src_vq->lock = &ctx->dev->dev_mutex;
523 src_vq->dev = ctx->dev->dev;
524 src_vq->supports_requests = true;
525
526 ret = vb2_queue_init(src_vq);
527 if (ret)
528 return ret;
529
530 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
531 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
532 dst_vq->drv_priv = ctx;
533 dst_vq->buf_struct_size = sizeof(struct cedrus_buffer);
534 dst_vq->min_buffers_needed = 1;
535 dst_vq->ops = &cedrus_qops;
536 dst_vq->mem_ops = &vb2_dma_contig_memops;
537 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
538 dst_vq->lock = &ctx->dev->dev_mutex;
539 dst_vq->dev = ctx->dev->dev;
540
541 return vb2_queue_init(dst_vq);
542}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.h b/drivers/staging/media/sunxi/cedrus/cedrus_video.h
new file mode 100644
index 000000000000..0e4f7a8cccf2
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.h
@@ -0,0 +1,30 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Cedrus VPU driver
4 *
5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7 * Copyright (C) 2018 Bootlin
8 *
9 * Based on the vim2m driver, that is:
10 *
11 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
12 * Pawel Osciak, <pawel@osciak.com>
13 * Marek Szyprowski, <m.szyprowski@samsung.com>
14 */
15
16#ifndef _CEDRUS_VIDEO_H_
17#define _CEDRUS_VIDEO_H_
18
19struct cedrus_format {
20 u32 pixelformat;
21 u32 directions;
22 unsigned int capabilities;
23};
24
25extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
26
27int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
28 struct vb2_queue *dst_vq);
29
30#endif