aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier Martin <javier.martin@vista-silicon.com>2012-01-13 04:31:02 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-02-28 05:19:24 -0500
commit8091cb7d9ce671628bb094d5e6bd5395bc3db4f4 (patch)
tree0f42a1e6c4608c471de5e684700de3bb08789779
parent9a56ec5b0327e292a725bec7f6db069ecc72b2db (diff)
[media] MEM2MEM: Add support for eMMa-PrP mem2mem operations
i.MX2x SoCs have a PrP which is capable of resizing and format conversion of video frames. This driver provides support for resizing and format conversion from YUYV to YUV420. This operation is of the utmost importance since some of these SoCs like i.MX27 include an H.264 video codec which only accepts YUV420 as input. Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Javier Martin <javier.martin@vista-silicon.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/Kconfig10
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/mx2_emmaprp.c1008
3 files changed, 1020 insertions, 0 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 9adada0d7447..9495b6a7f865 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1176,4 +1176,14 @@ config VIDEO_SAMSUNG_S5P_MFC
1176 help 1176 help
1177 MFC 5.1 driver for V4L2. 1177 MFC 5.1 driver for V4L2.
1178 1178
1179config VIDEO_MX2_EMMAPRP
1180 tristate "MX2 eMMa-PrP support"
1181 depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27
1182 select VIDEOBUF2_DMA_CONTIG
1183 select V4L2_MEM2MEM_DEV
1184 help
1185 MX2X chips have a PrP that can be used to process buffers from
1186 memory to memory. Operations include resizing and format
1187 conversion.
1188
1179endif # V4L_MEM2MEM_DRIVERS 1189endif # V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 354138804cda..563443c6b635 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -177,6 +177,8 @@ obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
177obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o 177obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
178obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o 178obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
179 179
180obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
181
180obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ 182obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/
181obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ 183obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/
182obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ 184obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/
diff --git a/drivers/media/video/mx2_emmaprp.c b/drivers/media/video/mx2_emmaprp.c
new file mode 100644
index 000000000000..ba89a7401c8c
--- /dev/null
+++ b/drivers/media/video/mx2_emmaprp.c
@@ -0,0 +1,1008 @@
1/*
2 * Support eMMa-PrP through mem2mem framework.
3 *
4 * eMMa-PrP is a piece of HW that allows fetching buffers
5 * from one memory location and do several operations on
6 * them such as scaling or format conversion giving, as a result
7 * a new processed buffer in another memory location.
8 *
9 * Based on mem2mem_testdev.c by Pawel Osciak.
10 *
11 * Copyright (c) 2011 Vista Silicon S.L.
12 * Javier Martin <javier.martin@vista-silicon.com>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version
18 */
19#include <linux/module.h>
20#include <linux/clk.h>
21#include <linux/slab.h>
22#include <linux/interrupt.h>
23#include <linux/io.h>
24
25#include <linux/platform_device.h>
26#include <media/v4l2-mem2mem.h>
27#include <media/v4l2-device.h>
28#include <media/v4l2-ioctl.h>
29#include <media/videobuf2-dma-contig.h>
30#include <asm/sizes.h>
31
32#define EMMAPRP_MODULE_NAME "mem2mem-emmaprp"
33
34MODULE_DESCRIPTION("Mem-to-mem device which supports eMMa-PrP present in mx2 SoCs");
35MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com");
36MODULE_LICENSE("GPL");
37MODULE_VERSION("0.0.1");
38
39static bool debug;
40module_param(debug, bool, 0644);
41
42#define MIN_W 32
43#define MIN_H 32
44#define MAX_W 2040
45#define MAX_H 2046
46
47#define S_ALIGN 1 /* multiple of 2 */
48#define W_ALIGN_YUV420 3 /* multiple of 8 */
49#define W_ALIGN_OTHERS 2 /* multiple of 4 */
50#define H_ALIGN 1 /* multiple of 2 */
51
52/* Flags that indicate a format can be used for capture/output */
53#define MEM2MEM_CAPTURE (1 << 0)
54#define MEM2MEM_OUTPUT (1 << 1)
55
56#define MEM2MEM_NAME "m2m-emmaprp"
57
58/* In bytes, per queue */
59#define MEM2MEM_VID_MEM_LIMIT SZ_16M
60
61#define dprintk(dev, fmt, arg...) \
62 v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
63
64/* EMMA PrP */
65#define PRP_CNTL 0x00
66#define PRP_INTR_CNTL 0x04
67#define PRP_INTRSTATUS 0x08
68#define PRP_SOURCE_Y_PTR 0x0c
69#define PRP_SOURCE_CB_PTR 0x10
70#define PRP_SOURCE_CR_PTR 0x14
71#define PRP_DEST_RGB1_PTR 0x18
72#define PRP_DEST_RGB2_PTR 0x1c
73#define PRP_DEST_Y_PTR 0x20
74#define PRP_DEST_CB_PTR 0x24
75#define PRP_DEST_CR_PTR 0x28
76#define PRP_SRC_FRAME_SIZE 0x2c
77#define PRP_DEST_CH1_LINE_STRIDE 0x30
78#define PRP_SRC_PIXEL_FORMAT_CNTL 0x34
79#define PRP_CH1_PIXEL_FORMAT_CNTL 0x38
80#define PRP_CH1_OUT_IMAGE_SIZE 0x3c
81#define PRP_CH2_OUT_IMAGE_SIZE 0x40
82#define PRP_SRC_LINE_STRIDE 0x44
83#define PRP_CSC_COEF_012 0x48
84#define PRP_CSC_COEF_345 0x4c
85#define PRP_CSC_COEF_678 0x50
86#define PRP_CH1_RZ_HORI_COEF1 0x54
87#define PRP_CH1_RZ_HORI_COEF2 0x58
88#define PRP_CH1_RZ_HORI_VALID 0x5c
89#define PRP_CH1_RZ_VERT_COEF1 0x60
90#define PRP_CH1_RZ_VERT_COEF2 0x64
91#define PRP_CH1_RZ_VERT_VALID 0x68
92#define PRP_CH2_RZ_HORI_COEF1 0x6c
93#define PRP_CH2_RZ_HORI_COEF2 0x70
94#define PRP_CH2_RZ_HORI_VALID 0x74
95#define PRP_CH2_RZ_VERT_COEF1 0x78
96#define PRP_CH2_RZ_VERT_COEF2 0x7c
97#define PRP_CH2_RZ_VERT_VALID 0x80
98
99#define PRP_CNTL_CH1EN (1 << 0)
100#define PRP_CNTL_CH2EN (1 << 1)
101#define PRP_CNTL_CSIEN (1 << 2)
102#define PRP_CNTL_DATA_IN_YUV420 (0 << 3)
103#define PRP_CNTL_DATA_IN_YUV422 (1 << 3)
104#define PRP_CNTL_DATA_IN_RGB16 (2 << 3)
105#define PRP_CNTL_DATA_IN_RGB32 (3 << 3)
106#define PRP_CNTL_CH1_OUT_RGB8 (0 << 5)
107#define PRP_CNTL_CH1_OUT_RGB16 (1 << 5)
108#define PRP_CNTL_CH1_OUT_RGB32 (2 << 5)
109#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5)
110#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7)
111#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7)
112#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7)
113#define PRP_CNTL_CH1_LEN (1 << 9)
114#define PRP_CNTL_CH2_LEN (1 << 10)
115#define PRP_CNTL_SKIP_FRAME (1 << 11)
116#define PRP_CNTL_SWRST (1 << 12)
117#define PRP_CNTL_CLKEN (1 << 13)
118#define PRP_CNTL_WEN (1 << 14)
119#define PRP_CNTL_CH1BYP (1 << 15)
120#define PRP_CNTL_IN_TSKIP(x) ((x) << 16)
121#define PRP_CNTL_CH1_TSKIP(x) ((x) << 19)
122#define PRP_CNTL_CH2_TSKIP(x) ((x) << 22)
123#define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25)
124#define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27)
125#define PRP_CNTL_CH2B1EN (1 << 29)
126#define PRP_CNTL_CH2B2EN (1 << 30)
127#define PRP_CNTL_CH2FEN (1 << 31)
128
129#define PRP_SIZE_HEIGHT(x) (x)
130#define PRP_SIZE_WIDTH(x) ((x) << 16)
131
132/* IRQ Enable and status register */
133#define PRP_INTR_RDERR (1 << 0)
134#define PRP_INTR_CH1WERR (1 << 1)
135#define PRP_INTR_CH2WERR (1 << 2)
136#define PRP_INTR_CH1FC (1 << 3)
137#define PRP_INTR_CH2FC (1 << 5)
138#define PRP_INTR_LBOVF (1 << 7)
139#define PRP_INTR_CH2OVF (1 << 8)
140
141#define PRP_INTR_ST_RDERR (1 << 0)
142#define PRP_INTR_ST_CH1WERR (1 << 1)
143#define PRP_INTR_ST_CH2WERR (1 << 2)
144#define PRP_INTR_ST_CH2B2CI (1 << 3)
145#define PRP_INTR_ST_CH2B1CI (1 << 4)
146#define PRP_INTR_ST_CH1B2CI (1 << 5)
147#define PRP_INTR_ST_CH1B1CI (1 << 6)
148#define PRP_INTR_ST_LBOVF (1 << 7)
149#define PRP_INTR_ST_CH2OVF (1 << 8)
150
151struct emmaprp_fmt {
152 char *name;
153 u32 fourcc;
154 /* Types the format can be used for */
155 u32 types;
156};
157
158static struct emmaprp_fmt formats[] = {
159 {
160 .name = "YUV 4:2:0 Planar",
161 .fourcc = V4L2_PIX_FMT_YUV420,
162 .types = MEM2MEM_CAPTURE,
163 },
164 {
165 .name = "4:2:2, packed, YUYV",
166 .fourcc = V4L2_PIX_FMT_YUYV,
167 .types = MEM2MEM_OUTPUT,
168 },
169};
170
171/* Per-queue, driver-specific private data */
172struct emmaprp_q_data {
173 unsigned int width;
174 unsigned int height;
175 unsigned int sizeimage;
176 struct emmaprp_fmt *fmt;
177};
178
179enum {
180 V4L2_M2M_SRC = 0,
181 V4L2_M2M_DST = 1,
182};
183
184#define NUM_FORMATS ARRAY_SIZE(formats)
185
186static struct emmaprp_fmt *find_format(struct v4l2_format *f)
187{
188 struct emmaprp_fmt *fmt;
189 unsigned int k;
190
191 for (k = 0; k < NUM_FORMATS; k++) {
192 fmt = &formats[k];
193 if (fmt->fourcc == f->fmt.pix.pixelformat)
194 break;
195 }
196
197 if (k == NUM_FORMATS)
198 return NULL;
199
200 return &formats[k];
201}
202
203struct emmaprp_dev {
204 struct v4l2_device v4l2_dev;
205 struct video_device *vfd;
206
207 struct mutex dev_mutex;
208 spinlock_t irqlock;
209
210 int irq_emma;
211 void __iomem *base_emma;
212 struct clk *clk_emma;
213 struct resource *res_emma;
214
215 struct v4l2_m2m_dev *m2m_dev;
216 struct vb2_alloc_ctx *alloc_ctx;
217};
218
219struct emmaprp_ctx {
220 struct emmaprp_dev *dev;
221 /* Abort requested by m2m */
222 int aborting;
223 struct emmaprp_q_data q_data[2];
224 struct v4l2_m2m_ctx *m2m_ctx;
225};
226
227static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx,
228 enum v4l2_buf_type type)
229{
230 switch (type) {
231 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
232 return &(ctx->q_data[V4L2_M2M_SRC]);
233 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
234 return &(ctx->q_data[V4L2_M2M_DST]);
235 default:
236 BUG();
237 }
238 return NULL;
239}
240
241/*
242 * mem2mem callbacks
243 */
244static void emmaprp_job_abort(void *priv)
245{
246 struct emmaprp_ctx *ctx = priv;
247 struct emmaprp_dev *pcdev = ctx->dev;
248
249 ctx->aborting = 1;
250
251 dprintk(pcdev, "Aborting task\n");
252
253 v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx);
254}
255
256static void emmaprp_lock(void *priv)
257{
258 struct emmaprp_ctx *ctx = priv;
259 struct emmaprp_dev *pcdev = ctx->dev;
260 mutex_lock(&pcdev->dev_mutex);
261}
262
263static void emmaprp_unlock(void *priv)
264{
265 struct emmaprp_ctx *ctx = priv;
266 struct emmaprp_dev *pcdev = ctx->dev;
267 mutex_unlock(&pcdev->dev_mutex);
268}
269
270static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev)
271{
272 dprintk(pcdev,
273 "eMMa-PrP Registers:\n"
274 " SOURCE_Y_PTR = 0x%08X\n"
275 " SRC_FRAME_SIZE = 0x%08X\n"
276 " DEST_Y_PTR = 0x%08X\n"
277 " DEST_CR_PTR = 0x%08X\n"
278 " DEST_CB_PTR = 0x%08X\n"
279 " CH2_OUT_IMAGE_SIZE = 0x%08X\n"
280 " CNTL = 0x%08X\n",
281 readl(pcdev->base_emma + PRP_SOURCE_Y_PTR),
282 readl(pcdev->base_emma + PRP_SRC_FRAME_SIZE),
283 readl(pcdev->base_emma + PRP_DEST_Y_PTR),
284 readl(pcdev->base_emma + PRP_DEST_CR_PTR),
285 readl(pcdev->base_emma + PRP_DEST_CB_PTR),
286 readl(pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE),
287 readl(pcdev->base_emma + PRP_CNTL));
288}
289
290static void emmaprp_device_run(void *priv)
291{
292 struct emmaprp_ctx *ctx = priv;
293 struct emmaprp_q_data *s_q_data, *d_q_data;
294 struct vb2_buffer *src_buf, *dst_buf;
295 struct emmaprp_dev *pcdev = ctx->dev;
296 unsigned int s_width, s_height;
297 unsigned int d_width, d_height;
298 unsigned int d_size;
299 dma_addr_t p_in, p_out;
300 u32 tmp;
301
302 src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
303 dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
304
305 s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
306 s_width = s_q_data->width;
307 s_height = s_q_data->height;
308
309 d_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
310 d_width = d_q_data->width;
311 d_height = d_q_data->height;
312 d_size = d_width * d_height;
313
314 p_in = vb2_dma_contig_plane_dma_addr(src_buf, 0);
315 p_out = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
316 if (!p_in || !p_out) {
317 v4l2_err(&pcdev->v4l2_dev,
318 "Acquiring kernel pointers to buffers failed\n");
319 return;
320 }
321
322 /* Input frame parameters */
323 writel(p_in, pcdev->base_emma + PRP_SOURCE_Y_PTR);
324 writel(PRP_SIZE_WIDTH(s_width) | PRP_SIZE_HEIGHT(s_height),
325 pcdev->base_emma + PRP_SRC_FRAME_SIZE);
326
327 /* Output frame parameters */
328 writel(p_out, pcdev->base_emma + PRP_DEST_Y_PTR);
329 writel(p_out + d_size, pcdev->base_emma + PRP_DEST_CB_PTR);
330 writel(p_out + d_size + (d_size >> 2),
331 pcdev->base_emma + PRP_DEST_CR_PTR);
332 writel(PRP_SIZE_WIDTH(d_width) | PRP_SIZE_HEIGHT(d_height),
333 pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
334
335 /* IRQ configuration */
336 tmp = readl(pcdev->base_emma + PRP_INTR_CNTL);
337 writel(tmp | PRP_INTR_RDERR |
338 PRP_INTR_CH2WERR |
339 PRP_INTR_CH2FC,
340 pcdev->base_emma + PRP_INTR_CNTL);
341
342 emmaprp_dump_regs(pcdev);
343
344 /* Enable transfer */
345 tmp = readl(pcdev->base_emma + PRP_CNTL);
346 writel(tmp | PRP_CNTL_CH2_OUT_YUV420 |
347 PRP_CNTL_DATA_IN_YUV422 |
348 PRP_CNTL_CH2EN,
349 pcdev->base_emma + PRP_CNTL);
350}
351
352static irqreturn_t emmaprp_irq(int irq_emma, void *data)
353{
354 struct emmaprp_dev *pcdev = data;
355 struct emmaprp_ctx *curr_ctx;
356 struct vb2_buffer *src_vb, *dst_vb;
357 unsigned long flags;
358 u32 irqst;
359
360 /* Check irq flags and clear irq */
361 irqst = readl(pcdev->base_emma + PRP_INTRSTATUS);
362 writel(irqst, pcdev->base_emma + PRP_INTRSTATUS);
363 dprintk(pcdev, "irqst = 0x%08x\n", irqst);
364
365 curr_ctx = v4l2_m2m_get_curr_priv(pcdev->m2m_dev);
366 if (curr_ctx == NULL) {
367 pr_err("Instance released before the end of transaction\n");
368 return IRQ_HANDLED;
369 }
370
371 if (!curr_ctx->aborting) {
372 if ((irqst & PRP_INTR_ST_RDERR) ||
373 (irqst & PRP_INTR_ST_CH2WERR)) {
374 pr_err("PrP bus error ocurred, this transfer is probably corrupted\n");
375 writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
376 } else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */
377 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
378 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
379
380 spin_lock_irqsave(&pcdev->irqlock, flags);
381 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
382 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
383 spin_unlock_irqrestore(&pcdev->irqlock, flags);
384 }
385 }
386
387 v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx);
388 return IRQ_HANDLED;
389}
390
391/*
392 * video ioctls
393 */
394static int vidioc_querycap(struct file *file, void *priv,
395 struct v4l2_capability *cap)
396{
397 strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
398 strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
399 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
400 | V4L2_CAP_STREAMING;
401
402 return 0;
403}
404
405static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
406{
407 int i, num;
408 struct emmaprp_fmt *fmt;
409
410 num = 0;
411
412 for (i = 0; i < NUM_FORMATS; ++i) {
413 if (formats[i].types & type) {
414 /* index-th format of type type found ? */
415 if (num == f->index)
416 break;
417 /* Correct type but haven't reached our index yet,
418 * just increment per-type index */
419 ++num;
420 }
421 }
422
423 if (i < NUM_FORMATS) {
424 /* Format found */
425 fmt = &formats[i];
426 strlcpy(f->description, fmt->name, sizeof(f->description) - 1);
427 f->pixelformat = fmt->fourcc;
428 return 0;
429 }
430
431 /* Format not found */
432 return -EINVAL;
433}
434
435static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
436 struct v4l2_fmtdesc *f)
437{
438 return enum_fmt(f, MEM2MEM_CAPTURE);
439}
440
441static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
442 struct v4l2_fmtdesc *f)
443{
444 return enum_fmt(f, MEM2MEM_OUTPUT);
445}
446
447static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
448{
449 struct vb2_queue *vq;
450 struct emmaprp_q_data *q_data;
451
452 vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
453 if (!vq)
454 return -EINVAL;
455
456 q_data = get_q_data(ctx, f->type);
457
458 f->fmt.pix.width = q_data->width;
459 f->fmt.pix.height = q_data->height;
460 f->fmt.pix.field = V4L2_FIELD_NONE;
461 f->fmt.pix.pixelformat = q_data->fmt->fourcc;
462 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
463 f->fmt.pix.bytesperline = q_data->width * 3 / 2;
464 else /* YUYV */
465 f->fmt.pix.bytesperline = q_data->width * 2;
466 f->fmt.pix.sizeimage = q_data->sizeimage;
467
468 return 0;
469}
470
471static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
472 struct v4l2_format *f)
473{
474 return vidioc_g_fmt(priv, f);
475}
476
477static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
478 struct v4l2_format *f)
479{
480 return vidioc_g_fmt(priv, f);
481}
482
483static int vidioc_try_fmt(struct v4l2_format *f)
484{
485 enum v4l2_field field;
486
487
488 if (!find_format(f))
489 return -EINVAL;
490
491 field = f->fmt.pix.field;
492 if (field == V4L2_FIELD_ANY)
493 field = V4L2_FIELD_NONE;
494 else if (V4L2_FIELD_NONE != field)
495 return -EINVAL;
496
497 /* V4L2 specification suggests the driver corrects the format struct
498 * if any of the dimensions is unsupported */
499 f->fmt.pix.field = field;
500
501 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
502 v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
503 W_ALIGN_YUV420, &f->fmt.pix.height,
504 MIN_H, MAX_H, H_ALIGN, S_ALIGN);
505 f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
506 } else {
507 v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
508 W_ALIGN_OTHERS, &f->fmt.pix.height,
509 MIN_H, MAX_H, H_ALIGN, S_ALIGN);
510 f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
511 }
512 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
513
514 return 0;
515}
516
517static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
518 struct v4l2_format *f)
519{
520 struct emmaprp_fmt *fmt;
521 struct emmaprp_ctx *ctx = priv;
522
523 fmt = find_format(f);
524 if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
525 v4l2_err(&ctx->dev->v4l2_dev,
526 "Fourcc format (0x%08x) invalid.\n",
527 f->fmt.pix.pixelformat);
528 return -EINVAL;
529 }
530
531 return vidioc_try_fmt(f);
532}
533
534static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
535 struct v4l2_format *f)
536{
537 struct emmaprp_fmt *fmt;
538 struct emmaprp_ctx *ctx = priv;
539
540 fmt = find_format(f);
541 if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
542 v4l2_err(&ctx->dev->v4l2_dev,
543 "Fourcc format (0x%08x) invalid.\n",
544 f->fmt.pix.pixelformat);
545 return -EINVAL;
546 }
547
548 return vidioc_try_fmt(f);
549}
550
551static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
552{
553 struct emmaprp_q_data *q_data;
554 struct vb2_queue *vq;
555 int ret;
556
557 vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
558 if (!vq)
559 return -EINVAL;
560
561 q_data = get_q_data(ctx, f->type);
562 if (!q_data)
563 return -EINVAL;
564
565 if (vb2_is_busy(vq)) {
566 v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
567 return -EBUSY;
568 }
569
570 ret = vidioc_try_fmt(f);
571 if (ret)
572 return ret;
573
574 q_data->fmt = find_format(f);
575 q_data->width = f->fmt.pix.width;
576 q_data->height = f->fmt.pix.height;
577 if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
578 q_data->sizeimage = q_data->width * q_data->height * 3 / 2;
579 else /* YUYV */
580 q_data->sizeimage = q_data->width * q_data->height * 2;
581
582 dprintk(ctx->dev,
583 "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
584 f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
585
586 return 0;
587}
588
589static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
590 struct v4l2_format *f)
591{
592 int ret;
593
594 ret = vidioc_try_fmt_vid_cap(file, priv, f);
595 if (ret)
596 return ret;
597
598 return vidioc_s_fmt(priv, f);
599}
600
601static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
602 struct v4l2_format *f)
603{
604 int ret;
605
606 ret = vidioc_try_fmt_vid_out(file, priv, f);
607 if (ret)
608 return ret;
609
610 return vidioc_s_fmt(priv, f);
611}
612
613static int vidioc_reqbufs(struct file *file, void *priv,
614 struct v4l2_requestbuffers *reqbufs)
615{
616 struct emmaprp_ctx *ctx = priv;
617
618 return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
619}
620
621static int vidioc_querybuf(struct file *file, void *priv,
622 struct v4l2_buffer *buf)
623{
624 struct emmaprp_ctx *ctx = priv;
625
626 return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
627}
628
629static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
630{
631 struct emmaprp_ctx *ctx = priv;
632
633 return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
634}
635
636static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
637{
638 struct emmaprp_ctx *ctx = priv;
639
640 return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
641}
642
643static int vidioc_streamon(struct file *file, void *priv,
644 enum v4l2_buf_type type)
645{
646 struct emmaprp_ctx *ctx = priv;
647
648 return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
649}
650
651static int vidioc_streamoff(struct file *file, void *priv,
652 enum v4l2_buf_type type)
653{
654 struct emmaprp_ctx *ctx = priv;
655
656 return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
657}
658
659static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = {
660 .vidioc_querycap = vidioc_querycap,
661
662 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
663 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
664 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
665 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
666
667 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
668 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
669 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
670 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
671
672 .vidioc_reqbufs = vidioc_reqbufs,
673 .vidioc_querybuf = vidioc_querybuf,
674
675 .vidioc_qbuf = vidioc_qbuf,
676 .vidioc_dqbuf = vidioc_dqbuf,
677
678 .vidioc_streamon = vidioc_streamon,
679 .vidioc_streamoff = vidioc_streamoff,
680};
681
682
683/*
684 * Queue operations
685 */
686static int emmaprp_queue_setup(struct vb2_queue *vq,
687 const struct v4l2_format *fmt,
688 unsigned int *nbuffers, unsigned int *nplanes,
689 unsigned int sizes[], void *alloc_ctxs[])
690{
691 struct emmaprp_ctx *ctx = vb2_get_drv_priv(vq);
692 struct emmaprp_q_data *q_data;
693 unsigned int size, count = *nbuffers;
694
695 q_data = get_q_data(ctx, vq->type);
696
697 if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
698 size = q_data->width * q_data->height * 3 / 2;
699 else
700 size = q_data->width * q_data->height * 2;
701
702 while (size * count > MEM2MEM_VID_MEM_LIMIT)
703 (count)--;
704
705 *nplanes = 1;
706 *nbuffers = count;
707 sizes[0] = size;
708
709 alloc_ctxs[0] = ctx->dev->alloc_ctx;
710
711 dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
712
713 return 0;
714}
715
716static int emmaprp_buf_prepare(struct vb2_buffer *vb)
717{
718 struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
719 struct emmaprp_q_data *q_data;
720
721 dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
722
723 q_data = get_q_data(ctx, vb->vb2_queue->type);
724
725 if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
726 dprintk(ctx->dev, "%s data will not fit into plane"
727 "(%lu < %lu)\n", __func__,
728 vb2_plane_size(vb, 0),
729 (long)q_data->sizeimage);
730 return -EINVAL;
731 }
732
733 vb2_set_plane_payload(vb, 0, q_data->sizeimage);
734
735 return 0;
736}
737
738static void emmaprp_buf_queue(struct vb2_buffer *vb)
739{
740 struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
741 v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
742}
743
744static struct vb2_ops emmaprp_qops = {
745 .queue_setup = emmaprp_queue_setup,
746 .buf_prepare = emmaprp_buf_prepare,
747 .buf_queue = emmaprp_buf_queue,
748};
749
750static int queue_init(void *priv, struct vb2_queue *src_vq,
751 struct vb2_queue *dst_vq)
752{
753 struct emmaprp_ctx *ctx = priv;
754 int ret;
755
756 memset(src_vq, 0, sizeof(*src_vq));
757 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
758 src_vq->io_modes = VB2_MMAP;
759 src_vq->drv_priv = ctx;
760 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
761 src_vq->ops = &emmaprp_qops;
762 src_vq->mem_ops = &vb2_dma_contig_memops;
763
764 ret = vb2_queue_init(src_vq);
765 if (ret)
766 return ret;
767
768 memset(dst_vq, 0, sizeof(*dst_vq));
769 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
770 dst_vq->io_modes = VB2_MMAP;
771 dst_vq->drv_priv = ctx;
772 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
773 dst_vq->ops = &emmaprp_qops;
774 dst_vq->mem_ops = &vb2_dma_contig_memops;
775
776 return vb2_queue_init(dst_vq);
777}
778
779/*
780 * File operations
781 */
782static int emmaprp_open(struct file *file)
783{
784 struct emmaprp_dev *pcdev = video_drvdata(file);
785 struct emmaprp_ctx *ctx;
786
787 ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
788 if (!ctx)
789 return -ENOMEM;
790
791 file->private_data = ctx;
792 ctx->dev = pcdev;
793
794 ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
795
796 if (IS_ERR(ctx->m2m_ctx)) {
797 int ret = PTR_ERR(ctx->m2m_ctx);
798
799 kfree(ctx);
800 return ret;
801 }
802
803 clk_enable(pcdev->clk_emma);
804 ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1];
805 ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
806
807 dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
808
809 return 0;
810}
811
812static int emmaprp_release(struct file *file)
813{
814 struct emmaprp_dev *pcdev = video_drvdata(file);
815 struct emmaprp_ctx *ctx = file->private_data;
816
817 dprintk(pcdev, "Releasing instance %p\n", ctx);
818
819 clk_disable(pcdev->clk_emma);
820 v4l2_m2m_ctx_release(ctx->m2m_ctx);
821 kfree(ctx);
822
823 return 0;
824}
825
826static unsigned int emmaprp_poll(struct file *file,
827 struct poll_table_struct *wait)
828{
829 struct emmaprp_ctx *ctx = file->private_data;
830
831 return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
832}
833
834static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma)
835{
836 struct emmaprp_ctx *ctx = file->private_data;
837
838 return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
839}
840
841static const struct v4l2_file_operations emmaprp_fops = {
842 .owner = THIS_MODULE,
843 .open = emmaprp_open,
844 .release = emmaprp_release,
845 .poll = emmaprp_poll,
846 .unlocked_ioctl = video_ioctl2,
847 .mmap = emmaprp_mmap,
848};
849
850static struct video_device emmaprp_videodev = {
851 .name = MEM2MEM_NAME,
852 .fops = &emmaprp_fops,
853 .ioctl_ops = &emmaprp_ioctl_ops,
854 .minor = -1,
855 .release = video_device_release,
856};
857
858static struct v4l2_m2m_ops m2m_ops = {
859 .device_run = emmaprp_device_run,
860 .job_abort = emmaprp_job_abort,
861 .lock = emmaprp_lock,
862 .unlock = emmaprp_unlock,
863};
864
865static int emmaprp_probe(struct platform_device *pdev)
866{
867 struct emmaprp_dev *pcdev;
868 struct video_device *vfd;
869 struct resource *res_emma;
870 int irq_emma;
871 int ret;
872
873 pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL);
874 if (!pcdev)
875 return -ENOMEM;
876
877 spin_lock_init(&pcdev->irqlock);
878
879 pcdev->clk_emma = clk_get(&pdev->dev, NULL);
880 if (IS_ERR(pcdev->clk_emma)) {
881 ret = PTR_ERR(pcdev->clk_emma);
882 goto free_dev;
883 }
884
885 irq_emma = platform_get_irq(pdev, 0);
886 res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 0);
887 if (irq_emma < 0 || res_emma == NULL) {
888 dev_err(&pdev->dev, "Missing platform resources data\n");
889 ret = -ENODEV;
890 goto free_clk;
891 }
892
893 ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
894 if (ret)
895 goto free_clk;
896
897 mutex_init(&pcdev->dev_mutex);
898
899 vfd = video_device_alloc();
900 if (!vfd) {
901 v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n");
902 ret = -ENOMEM;
903 goto unreg_dev;
904 }
905
906 *vfd = emmaprp_videodev;
907 vfd->lock = &pcdev->dev_mutex;
908
909 video_set_drvdata(vfd, pcdev);
910 snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name);
911 pcdev->vfd = vfd;
912 v4l2_info(&pcdev->v4l2_dev, EMMAPRP_MODULE_NAME
913 " Device registered as /dev/video%d\n", vfd->num);
914
915 platform_set_drvdata(pdev, pcdev);
916
917 if (devm_request_mem_region(&pdev->dev, res_emma->start,
918 resource_size(res_emma), MEM2MEM_NAME) == NULL)
919 goto rel_vdev;
920
921 pcdev->base_emma = devm_ioremap(&pdev->dev, res_emma->start,
922 resource_size(res_emma));
923 if (!pcdev->base_emma)
924 goto rel_vdev;
925
926 pcdev->irq_emma = irq_emma;
927 pcdev->res_emma = res_emma;
928
929 if (devm_request_irq(&pdev->dev, pcdev->irq_emma, emmaprp_irq,
930 0, MEM2MEM_NAME, pcdev) < 0)
931 goto rel_vdev;
932
933 pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
934 if (IS_ERR(pcdev->alloc_ctx)) {
935 v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n");
936 ret = PTR_ERR(pcdev->alloc_ctx);
937 goto rel_vdev;
938 }
939
940 pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops);
941 if (IS_ERR(pcdev->m2m_dev)) {
942 v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n");
943 ret = PTR_ERR(pcdev->m2m_dev);
944 goto rel_ctx;
945 }
946
947 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
948 if (ret) {
949 v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
950 goto rel_m2m;
951 }
952
953 return 0;
954
955
956rel_m2m:
957 v4l2_m2m_release(pcdev->m2m_dev);
958rel_ctx:
959 vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
960rel_vdev:
961 video_device_release(vfd);
962unreg_dev:
963 v4l2_device_unregister(&pcdev->v4l2_dev);
964free_clk:
965 clk_put(pcdev->clk_emma);
966free_dev:
967 kfree(pcdev);
968
969 return ret;
970}
971
972static int emmaprp_remove(struct platform_device *pdev)
973{
974 struct emmaprp_dev *pcdev = platform_get_drvdata(pdev);
975
976 v4l2_info(&pcdev->v4l2_dev, "Removing " EMMAPRP_MODULE_NAME);
977
978 video_unregister_device(pcdev->vfd);
979 v4l2_m2m_release(pcdev->m2m_dev);
980 vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
981 v4l2_device_unregister(&pcdev->v4l2_dev);
982 clk_put(pcdev->clk_emma);
983 kfree(pcdev);
984
985 return 0;
986}
987
988static struct platform_driver emmaprp_pdrv = {
989 .probe = emmaprp_probe,
990 .remove = emmaprp_remove,
991 .driver = {
992 .name = MEM2MEM_NAME,
993 .owner = THIS_MODULE,
994 },
995};
996
997static void __exit emmaprp_exit(void)
998{
999 platform_driver_unregister(&emmaprp_pdrv);
1000}
1001
1002static int __init emmaprp_init(void)
1003{
1004 return platform_driver_register(&emmaprp_pdrv);
1005}
1006
1007module_init(emmaprp_init);
1008module_exit(emmaprp_exit);