aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2013-05-15 10:36:19 -0400
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-04-02 23:59:49 -0400
commitdf3305156f989339529b3d6744b898d498fb1f7b (patch)
tree4f55b5f60cc68ff11a75c8e7574ddaff92a21034 /drivers/media/platform
parentc9bca8b33118573da9b7ac2ea21947a8e4d287dd (diff)
[media] v4l: xilinx: Add Xilinx Video IP core
Xilinx platforms have no hardwired video capture or video processing interface. Users create capture and memory to memory processing pipelines in the FPGA fabric to suit their particular needs, by instantiating video IP cores from a large library. The Xilinx Video IP core is a framework that models a video pipeline described in the device tree and expose the pipeline to userspace through the media controller and V4L2 APIs. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Hyun Kwon <hyun.kwon@xilinx.com> Signed-off-by: Radhey Shyam Pandey <radheys@xilinx.com> Signed-off-by: Michal Simek <michal.simek@xilinx.com> Acked-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media/platform')
-rw-r--r--drivers/media/platform/Kconfig1
-rw-r--r--drivers/media/platform/Makefile2
-rw-r--r--drivers/media/platform/xilinx/Kconfig10
-rw-r--r--drivers/media/platform/xilinx/Makefile3
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c766
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.h109
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.c323
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.h238
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.c669
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.h49
10 files changed, 2170 insertions, 0 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 272dc8c40f57..421f53188c6c 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -118,6 +118,7 @@ source "drivers/media/platform/soc_camera/Kconfig"
118source "drivers/media/platform/exynos4-is/Kconfig" 118source "drivers/media/platform/exynos4-is/Kconfig"
119source "drivers/media/platform/s5p-tv/Kconfig" 119source "drivers/media/platform/s5p-tv/Kconfig"
120source "drivers/media/platform/am437x/Kconfig" 120source "drivers/media/platform/am437x/Kconfig"
121source "drivers/media/platform/xilinx/Kconfig"
121 122
122endif # V4L_PLATFORM_DRIVERS 123endif # V4L_PLATFORM_DRIVERS
123 124
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 3ec154742083..8f855616c237 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -48,4 +48,6 @@ obj-y += omap/
48 48
49obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ 49obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/
50 50
51obj-$(CONFIG_VIDEO_XILINX) += xilinx/
52
51ccflags-y += -I$(srctree)/drivers/media/i2c 53ccflags-y += -I$(srctree)/drivers/media/i2c
diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig
new file mode 100644
index 000000000000..f4347e9af252
--- /dev/null
+++ b/drivers/media/platform/xilinx/Kconfig
@@ -0,0 +1,10 @@
1config VIDEO_XILINX
2 tristate "Xilinx Video IP (EXPERIMENTAL)"
3 depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF
4 select VIDEOBUF2_DMA_CONTIG
5 ---help---
6 Driver for Xilinx Video IP Pipelines
7
8if VIDEO_XILINX
9
10endif #VIDEO_XILINX
diff --git a/drivers/media/platform/xilinx/Makefile b/drivers/media/platform/xilinx/Makefile
new file mode 100644
index 000000000000..3ef9c8e3cc8d
--- /dev/null
+++ b/drivers/media/platform/xilinx/Makefile
@@ -0,0 +1,3 @@
1xilinx-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o
2
3obj-$(CONFIG_VIDEO_XILINX) += xilinx-video.o
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
new file mode 100644
index 000000000000..10209c294168
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -0,0 +1,766 @@
1/*
2 * Xilinx Video DMA
3 *
4 * Copyright (C) 2013-2015 Ideas on Board
5 * Copyright (C) 2013-2015 Xilinx, Inc.
6 *
7 * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
8 * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/amba/xilinx_dma.h>
16#include <linux/lcm.h>
17#include <linux/list.h>
18#include <linux/module.h>
19#include <linux/of.h>
20#include <linux/slab.h>
21
22#include <media/v4l2-dev.h>
23#include <media/v4l2-fh.h>
24#include <media/v4l2-ioctl.h>
25#include <media/videobuf2-core.h>
26#include <media/videobuf2-dma-contig.h>
27
28#include "xilinx-dma.h"
29#include "xilinx-vip.h"
30#include "xilinx-vipp.h"
31
32#define XVIP_DMA_DEF_FORMAT V4L2_PIX_FMT_YUYV
33#define XVIP_DMA_DEF_WIDTH 1920
34#define XVIP_DMA_DEF_HEIGHT 1080
35
36/* Minimum and maximum widths are expressed in bytes */
37#define XVIP_DMA_MIN_WIDTH 1U
38#define XVIP_DMA_MAX_WIDTH 65535U
39#define XVIP_DMA_MIN_HEIGHT 1U
40#define XVIP_DMA_MAX_HEIGHT 8191U
41
42/* -----------------------------------------------------------------------------
43 * Helper functions
44 */
45
46static struct v4l2_subdev *
47xvip_dma_remote_subdev(struct media_pad *local, u32 *pad)
48{
49 struct media_pad *remote;
50
51 remote = media_entity_remote_pad(local);
52 if (remote == NULL ||
53 media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
54 return NULL;
55
56 if (pad)
57 *pad = remote->index;
58
59 return media_entity_to_v4l2_subdev(remote->entity);
60}
61
62static int xvip_dma_verify_format(struct xvip_dma *dma)
63{
64 struct v4l2_subdev_format fmt;
65 struct v4l2_subdev *subdev;
66 int ret;
67
68 subdev = xvip_dma_remote_subdev(&dma->pad, &fmt.pad);
69 if (subdev == NULL)
70 return -EPIPE;
71
72 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
73 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
74 if (ret < 0)
75 return ret == -ENOIOCTLCMD ? -EINVAL : ret;
76
77 if (dma->fmtinfo->code != fmt.format.code ||
78 dma->format.height != fmt.format.height ||
79 dma->format.width != fmt.format.width ||
80 dma->format.colorspace != fmt.format.colorspace)
81 return -EINVAL;
82
83 return 0;
84}
85
86/* -----------------------------------------------------------------------------
87 * Pipeline Stream Management
88 */
89
90/**
91 * xvip_pipeline_start_stop - Start ot stop streaming on a pipeline
92 * @pipe: The pipeline
93 * @start: Start (when true) or stop (when false) the pipeline
94 *
95 * Walk the entities chain starting at the pipeline output video node and start
96 * or stop all of them.
97 *
98 * Return: 0 if successful, or the return value of the failed video::s_stream
99 * operation otherwise.
100 */
101static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
102{
103 struct xvip_dma *dma = pipe->output;
104 struct media_entity *entity;
105 struct media_pad *pad;
106 struct v4l2_subdev *subdev;
107 int ret;
108
109 entity = &dma->video.entity;
110 while (1) {
111 pad = &entity->pads[0];
112 if (!(pad->flags & MEDIA_PAD_FL_SINK))
113 break;
114
115 pad = media_entity_remote_pad(pad);
116 if (pad == NULL ||
117 media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
118 break;
119
120 entity = pad->entity;
121 subdev = media_entity_to_v4l2_subdev(entity);
122
123 ret = v4l2_subdev_call(subdev, video, s_stream, start);
124 if (start && ret < 0 && ret != -ENOIOCTLCMD)
125 return ret;
126 }
127
128 return 0;
129}
130
131/**
132 * xvip_pipeline_set_stream - Enable/disable streaming on a pipeline
133 * @pipe: The pipeline
134 * @on: Turn the stream on when true or off when false
135 *
136 * The pipeline is shared between all DMA engines connect at its input and
137 * output. While the stream state of DMA engines can be controlled
138 * independently, pipelines have a shared stream state that enable or disable
139 * all entities in the pipeline. For this reason the pipeline uses a streaming
140 * counter that tracks the number of DMA engines that have requested the stream
141 * to be enabled.
142 *
143 * When called with the @on argument set to true, this function will increment
144 * the pipeline streaming count. If the streaming count reaches the number of
145 * DMA engines in the pipeline it will enable all entities that belong to the
146 * pipeline.
147 *
148 * Similarly, when called with the @on argument set to false, this function will
149 * decrement the pipeline streaming count and disable all entities in the
150 * pipeline when the streaming count reaches zero.
151 *
152 * Return: 0 if successful, or the return value of the failed video::s_stream
153 * operation otherwise. Stopping the pipeline never fails. The pipeline state is
154 * not updated when the operation fails.
155 */
156static int xvip_pipeline_set_stream(struct xvip_pipeline *pipe, bool on)
157{
158 int ret = 0;
159
160 mutex_lock(&pipe->lock);
161
162 if (on) {
163 if (pipe->stream_count == pipe->num_dmas - 1) {
164 ret = xvip_pipeline_start_stop(pipe, true);
165 if (ret < 0)
166 goto done;
167 }
168 pipe->stream_count++;
169 } else {
170 if (--pipe->stream_count == 0)
171 xvip_pipeline_start_stop(pipe, false);
172 }
173
174done:
175 mutex_unlock(&pipe->lock);
176 return ret;
177}
178
179static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
180 struct xvip_dma *start)
181{
182 struct media_entity_graph graph;
183 struct media_entity *entity = &start->video.entity;
184 struct media_device *mdev = entity->parent;
185 unsigned int num_inputs = 0;
186 unsigned int num_outputs = 0;
187
188 mutex_lock(&mdev->graph_mutex);
189
190 /* Walk the graph to locate the video nodes. */
191 media_entity_graph_walk_start(&graph, entity);
192
193 while ((entity = media_entity_graph_walk_next(&graph))) {
194 struct xvip_dma *dma;
195
196 if (entity->type != MEDIA_ENT_T_DEVNODE_V4L)
197 continue;
198
199 dma = to_xvip_dma(media_entity_to_video_device(entity));
200
201 if (dma->pad.flags & MEDIA_PAD_FL_SINK) {
202 pipe->output = dma;
203 num_outputs++;
204 } else {
205 num_inputs++;
206 }
207 }
208
209 mutex_unlock(&mdev->graph_mutex);
210
211 /* We need exactly one output and zero or one input. */
212 if (num_outputs != 1 || num_inputs > 1)
213 return -EPIPE;
214
215 pipe->num_dmas = num_inputs + num_outputs;
216
217 return 0;
218}
219
220static void __xvip_pipeline_cleanup(struct xvip_pipeline *pipe)
221{
222 pipe->num_dmas = 0;
223 pipe->output = NULL;
224}
225
226/**
227 * xvip_pipeline_cleanup - Cleanup the pipeline after streaming
228 * @pipe: the pipeline
229 *
230 * Decrease the pipeline use count and clean it up if we were the last user.
231 */
232static void xvip_pipeline_cleanup(struct xvip_pipeline *pipe)
233{
234 mutex_lock(&pipe->lock);
235
236 /* If we're the last user clean up the pipeline. */
237 if (--pipe->use_count == 0)
238 __xvip_pipeline_cleanup(pipe);
239
240 mutex_unlock(&pipe->lock);
241}
242
243/**
244 * xvip_pipeline_prepare - Prepare the pipeline for streaming
245 * @pipe: the pipeline
246 * @dma: DMA engine at one end of the pipeline
247 *
248 * Validate the pipeline if no user exists yet, otherwise just increase the use
249 * count.
250 *
251 * Return: 0 if successful or -EPIPE if the pipeline is not valid.
252 */
253static int xvip_pipeline_prepare(struct xvip_pipeline *pipe,
254 struct xvip_dma *dma)
255{
256 int ret;
257
258 mutex_lock(&pipe->lock);
259
260 /* If we're the first user validate and initialize the pipeline. */
261 if (pipe->use_count == 0) {
262 ret = xvip_pipeline_validate(pipe, dma);
263 if (ret < 0) {
264 __xvip_pipeline_cleanup(pipe);
265 goto done;
266 }
267 }
268
269 pipe->use_count++;
270 ret = 0;
271
272done:
273 mutex_unlock(&pipe->lock);
274 return ret;
275}
276
277/* -----------------------------------------------------------------------------
278 * videobuf2 queue operations
279 */
280
281/**
282 * struct xvip_dma_buffer - Video DMA buffer
283 * @buf: vb2 buffer base object
284 * @queue: buffer list entry in the DMA engine queued buffers list
285 * @dma: DMA channel that uses the buffer
286 */
287struct xvip_dma_buffer {
288 struct vb2_buffer buf;
289 struct list_head queue;
290 struct xvip_dma *dma;
291};
292
293#define to_xvip_dma_buffer(vb) container_of(vb, struct xvip_dma_buffer, buf)
294
295static void xvip_dma_complete(void *param)
296{
297 struct xvip_dma_buffer *buf = param;
298 struct xvip_dma *dma = buf->dma;
299
300 spin_lock(&dma->queued_lock);
301 list_del(&buf->queue);
302 spin_unlock(&dma->queued_lock);
303
304 buf->buf.v4l2_buf.field = V4L2_FIELD_NONE;
305 buf->buf.v4l2_buf.sequence = dma->sequence++;
306 v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp);
307 vb2_set_plane_payload(&buf->buf, 0, dma->format.sizeimage);
308 vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
309}
310
311static int
312xvip_dma_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
313 unsigned int *nbuffers, unsigned int *nplanes,
314 unsigned int sizes[], void *alloc_ctxs[])
315{
316 struct xvip_dma *dma = vb2_get_drv_priv(vq);
317
318 /* Make sure the image size is large enough. */
319 if (fmt && fmt->fmt.pix.sizeimage < dma->format.sizeimage)
320 return -EINVAL;
321
322 *nplanes = 1;
323
324 sizes[0] = fmt ? fmt->fmt.pix.sizeimage : dma->format.sizeimage;
325 alloc_ctxs[0] = dma->alloc_ctx;
326
327 return 0;
328}
329
330static int xvip_dma_buffer_prepare(struct vb2_buffer *vb)
331{
332 struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue);
333 struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb);
334
335 buf->dma = dma;
336
337 return 0;
338}
339
340static void xvip_dma_buffer_queue(struct vb2_buffer *vb)
341{
342 struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue);
343 struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb);
344 struct dma_async_tx_descriptor *desc;
345 dma_addr_t addr = vb2_dma_contig_plane_dma_addr(vb, 0);
346 u32 flags;
347
348 if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
349 flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
350 dma->xt.dir = DMA_DEV_TO_MEM;
351 dma->xt.src_sgl = false;
352 dma->xt.dst_sgl = true;
353 dma->xt.dst_start = addr;
354 } else {
355 flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
356 dma->xt.dir = DMA_MEM_TO_DEV;
357 dma->xt.src_sgl = true;
358 dma->xt.dst_sgl = false;
359 dma->xt.src_start = addr;
360 }
361
362 dma->xt.frame_size = 1;
363 dma->sgl[0].size = dma->format.width * dma->fmtinfo->bpp;
364 dma->sgl[0].icg = dma->format.bytesperline - dma->sgl[0].size;
365 dma->xt.numf = dma->format.height;
366
367 desc = dmaengine_prep_interleaved_dma(dma->dma, &dma->xt, flags);
368 if (!desc) {
369 dev_err(dma->xdev->dev, "Failed to prepare DMA transfer\n");
370 vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
371 return;
372 }
373 desc->callback = xvip_dma_complete;
374 desc->callback_param = buf;
375
376 spin_lock_irq(&dma->queued_lock);
377 list_add_tail(&buf->queue, &dma->queued_bufs);
378 spin_unlock_irq(&dma->queued_lock);
379
380 dmaengine_submit(desc);
381
382 if (vb2_is_streaming(&dma->queue))
383 dma_async_issue_pending(dma->dma);
384}
385
386static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
387{
388 struct xvip_dma *dma = vb2_get_drv_priv(vq);
389 struct xvip_dma_buffer *buf, *nbuf;
390 struct xvip_pipeline *pipe;
391 int ret;
392
393 dma->sequence = 0;
394
395 /*
396 * Start streaming on the pipeline. No link touching an entity in the
397 * pipeline can be activated or deactivated once streaming is started.
398 *
399 * Use the pipeline object embedded in the first DMA object that starts
400 * streaming.
401 */
402 pipe = dma->video.entity.pipe
403 ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe;
404
405 ret = media_entity_pipeline_start(&dma->video.entity, &pipe->pipe);
406 if (ret < 0)
407 goto error;
408
409 /* Verify that the configured format matches the output of the
410 * connected subdev.
411 */
412 ret = xvip_dma_verify_format(dma);
413 if (ret < 0)
414 goto error_stop;
415
416 ret = xvip_pipeline_prepare(pipe, dma);
417 if (ret < 0)
418 goto error_stop;
419
420 /* Start the DMA engine. This must be done before starting the blocks
421 * in the pipeline to avoid DMA synchronization issues.
422 */
423 dma_async_issue_pending(dma->dma);
424
425 /* Start the pipeline. */
426 xvip_pipeline_set_stream(pipe, true);
427
428 return 0;
429
430error_stop:
431 media_entity_pipeline_stop(&dma->video.entity);
432
433error:
434 /* Give back all queued buffers to videobuf2. */
435 spin_lock_irq(&dma->queued_lock);
436 list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) {
437 vb2_buffer_done(&buf->buf, VB2_BUF_STATE_QUEUED);
438 list_del(&buf->queue);
439 }
440 spin_unlock_irq(&dma->queued_lock);
441
442 return ret;
443}
444
445static void xvip_dma_stop_streaming(struct vb2_queue *vq)
446{
447 struct xvip_dma *dma = vb2_get_drv_priv(vq);
448 struct xvip_pipeline *pipe = to_xvip_pipeline(&dma->video.entity);
449 struct xvip_dma_buffer *buf, *nbuf;
450
451 /* Stop the pipeline. */
452 xvip_pipeline_set_stream(pipe, false);
453
454 /* Stop and reset the DMA engine. */
455 dmaengine_terminate_all(dma->dma);
456
457 /* Cleanup the pipeline and mark it as being stopped. */
458 xvip_pipeline_cleanup(pipe);
459 media_entity_pipeline_stop(&dma->video.entity);
460
461 /* Give back all queued buffers to videobuf2. */
462 spin_lock_irq(&dma->queued_lock);
463 list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) {
464 vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
465 list_del(&buf->queue);
466 }
467 spin_unlock_irq(&dma->queued_lock);
468}
469
470static struct vb2_ops xvip_dma_queue_qops = {
471 .queue_setup = xvip_dma_queue_setup,
472 .buf_prepare = xvip_dma_buffer_prepare,
473 .buf_queue = xvip_dma_buffer_queue,
474 .wait_prepare = vb2_ops_wait_prepare,
475 .wait_finish = vb2_ops_wait_finish,
476 .start_streaming = xvip_dma_start_streaming,
477 .stop_streaming = xvip_dma_stop_streaming,
478};
479
480/* -----------------------------------------------------------------------------
481 * V4L2 ioctls
482 */
483
484static int
485xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
486{
487 struct v4l2_fh *vfh = file->private_data;
488 struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
489
490 cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
491 | dma->xdev->v4l2_caps;
492
493 if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
494 cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
495 else
496 cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
497
498 strlcpy(cap->driver, "xilinx-vipp", sizeof(cap->driver));
499 strlcpy(cap->card, dma->video.name, sizeof(cap->card));
500 snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s:%u",
501 dma->xdev->dev->of_node->name, dma->port);
502
503 return 0;
504}
505
506/* FIXME: without this callback function, some applications are not configured
507 * with correct formats, and it results in frames in wrong format. Whether this
508 * callback needs to be required is not clearly defined, so it should be
509 * clarified through the mailing list.
510 */
511static int
512xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
513{
514 struct v4l2_fh *vfh = file->private_data;
515 struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
516
517 if (f->index > 0)
518 return -EINVAL;
519
520 f->pixelformat = dma->format.pixelformat;
521 strlcpy(f->description, dma->fmtinfo->description,
522 sizeof(f->description));
523
524 return 0;
525}
526
527static int
528xvip_dma_get_format(struct file *file, void *fh, struct v4l2_format *format)
529{
530 struct v4l2_fh *vfh = file->private_data;
531 struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
532
533 format->fmt.pix = dma->format;
534
535 return 0;
536}
537
538static void
539__xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix,
540 const struct xvip_video_format **fmtinfo)
541{
542 const struct xvip_video_format *info;
543 unsigned int min_width;
544 unsigned int max_width;
545 unsigned int min_bpl;
546 unsigned int max_bpl;
547 unsigned int width;
548 unsigned int align;
549 unsigned int bpl;
550
551 /* Retrieve format information and select the default format if the
552 * requested format isn't supported.
553 */
554 info = xvip_get_format_by_fourcc(pix->pixelformat);
555 if (IS_ERR(info))
556 info = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
557
558 pix->pixelformat = info->fourcc;
559 pix->field = V4L2_FIELD_NONE;
560
561 /* The transfer alignment requirements are expressed in bytes. Compute
562 * the minimum and maximum values, clamp the requested width and convert
563 * it back to pixels.
564 */
565 align = lcm(dma->align, info->bpp);
566 min_width = roundup(XVIP_DMA_MIN_WIDTH, align);
567 max_width = rounddown(XVIP_DMA_MAX_WIDTH, align);
568 width = rounddown(pix->width * info->bpp, align);
569
570 pix->width = clamp(width, min_width, max_width) / info->bpp;
571 pix->height = clamp(pix->height, XVIP_DMA_MIN_HEIGHT,
572 XVIP_DMA_MAX_HEIGHT);
573
574 /* Clamp the requested bytes per line value. If the maximum bytes per
575 * line value is zero, the module doesn't support user configurable line
576 * sizes. Override the requested value with the minimum in that case.
577 */
578 min_bpl = pix->width * info->bpp;
579 max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, dma->align);
580 bpl = rounddown(pix->bytesperline, dma->align);
581
582 pix->bytesperline = clamp(bpl, min_bpl, max_bpl);
583 pix->sizeimage = pix->bytesperline * pix->height;
584
585 if (fmtinfo)
586 *fmtinfo = info;
587}
588
589static int
590xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format)
591{
592 struct v4l2_fh *vfh = file->private_data;
593 struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
594
595 __xvip_dma_try_format(dma, &format->fmt.pix, NULL);
596 return 0;
597}
598
599static int
600xvip_dma_set_format(struct file *file, void *fh, struct v4l2_format *format)
601{
602 struct v4l2_fh *vfh = file->private_data;
603 struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
604 const struct xvip_video_format *info;
605
606 __xvip_dma_try_format(dma, &format->fmt.pix, &info);
607
608 if (vb2_is_busy(&dma->queue))
609 return -EBUSY;
610
611 dma->format = format->fmt.pix;
612 dma->fmtinfo = info;
613
614 return 0;
615}
616
617static const struct v4l2_ioctl_ops xvip_dma_ioctl_ops = {
618 .vidioc_querycap = xvip_dma_querycap,
619 .vidioc_enum_fmt_vid_cap = xvip_dma_enum_format,
620 .vidioc_g_fmt_vid_cap = xvip_dma_get_format,
621 .vidioc_g_fmt_vid_out = xvip_dma_get_format,
622 .vidioc_s_fmt_vid_cap = xvip_dma_set_format,
623 .vidioc_s_fmt_vid_out = xvip_dma_set_format,
624 .vidioc_try_fmt_vid_cap = xvip_dma_try_format,
625 .vidioc_try_fmt_vid_out = xvip_dma_try_format,
626 .vidioc_reqbufs = vb2_ioctl_reqbufs,
627 .vidioc_querybuf = vb2_ioctl_querybuf,
628 .vidioc_qbuf = vb2_ioctl_qbuf,
629 .vidioc_dqbuf = vb2_ioctl_dqbuf,
630 .vidioc_create_bufs = vb2_ioctl_create_bufs,
631 .vidioc_expbuf = vb2_ioctl_expbuf,
632 .vidioc_streamon = vb2_ioctl_streamon,
633 .vidioc_streamoff = vb2_ioctl_streamoff,
634};
635
636/* -----------------------------------------------------------------------------
637 * V4L2 file operations
638 */
639
640static const struct v4l2_file_operations xvip_dma_fops = {
641 .owner = THIS_MODULE,
642 .unlocked_ioctl = video_ioctl2,
643 .open = v4l2_fh_open,
644 .release = vb2_fop_release,
645 .poll = vb2_fop_poll,
646 .mmap = vb2_fop_mmap,
647};
648
649/* -----------------------------------------------------------------------------
650 * Xilinx Video DMA Core
651 */
652
653int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
654 enum v4l2_buf_type type, unsigned int port)
655{
656 char name[14];
657 int ret;
658
659 dma->xdev = xdev;
660 dma->port = port;
661 mutex_init(&dma->lock);
662 mutex_init(&dma->pipe.lock);
663 INIT_LIST_HEAD(&dma->queued_bufs);
664 spin_lock_init(&dma->queued_lock);
665
666 dma->fmtinfo = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
667 dma->format.pixelformat = dma->fmtinfo->fourcc;
668 dma->format.colorspace = V4L2_COLORSPACE_SRGB;
669 dma->format.field = V4L2_FIELD_NONE;
670 dma->format.width = XVIP_DMA_DEF_WIDTH;
671 dma->format.height = XVIP_DMA_DEF_HEIGHT;
672 dma->format.bytesperline = dma->format.width * dma->fmtinfo->bpp;
673 dma->format.sizeimage = dma->format.bytesperline * dma->format.height;
674
675 /* Initialize the media entity... */
676 dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE
677 ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
678
679 ret = media_entity_init(&dma->video.entity, 1, &dma->pad, 0);
680 if (ret < 0)
681 goto error;
682
683 /* ... and the video node... */
684 dma->video.fops = &xvip_dma_fops;
685 dma->video.v4l2_dev = &xdev->v4l2_dev;
686 dma->video.queue = &dma->queue;
687 snprintf(dma->video.name, sizeof(dma->video.name), "%s %s %u",
688 xdev->dev->of_node->name,
689 type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input",
690 port);
691 dma->video.vfl_type = VFL_TYPE_GRABBER;
692 dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE
693 ? VFL_DIR_RX : VFL_DIR_TX;
694 dma->video.release = video_device_release_empty;
695 dma->video.ioctl_ops = &xvip_dma_ioctl_ops;
696 dma->video.lock = &dma->lock;
697
698 video_set_drvdata(&dma->video, dma);
699
700 /* ... and the buffers queue... */
701 dma->alloc_ctx = vb2_dma_contig_init_ctx(dma->xdev->dev);
702 if (IS_ERR(dma->alloc_ctx))
703 goto error;
704
705 /* Don't enable VB2_READ and VB2_WRITE, as using the read() and write()
706 * V4L2 APIs would be inefficient. Testing on the command line with a
707 * 'cat /dev/video?' thus won't be possible, but given that the driver
708 * anyway requires a test tool to setup the pipeline before any video
709 * stream can be started, requiring a specific V4L2 test tool as well
710 * instead of 'cat' isn't really a drawback.
711 */
712 dma->queue.type = type;
713 dma->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
714 dma->queue.lock = &dma->lock;
715 dma->queue.drv_priv = dma;
716 dma->queue.buf_struct_size = sizeof(struct xvip_dma_buffer);
717 dma->queue.ops = &xvip_dma_queue_qops;
718 dma->queue.mem_ops = &vb2_dma_contig_memops;
719 dma->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
720 | V4L2_BUF_FLAG_TSTAMP_SRC_EOF;
721 ret = vb2_queue_init(&dma->queue);
722 if (ret < 0) {
723 dev_err(dma->xdev->dev, "failed to initialize VB2 queue\n");
724 goto error;
725 }
726
727 /* ... and the DMA channel. */
728 sprintf(name, "port%u", port);
729 dma->dma = dma_request_slave_channel(dma->xdev->dev, name);
730 if (dma->dma == NULL) {
731 dev_err(dma->xdev->dev, "no VDMA channel found\n");
732 ret = -ENODEV;
733 goto error;
734 }
735
736 dma->align = 1 << dma->dma->device->copy_align;
737
738 ret = video_register_device(&dma->video, VFL_TYPE_GRABBER, -1);
739 if (ret < 0) {
740 dev_err(dma->xdev->dev, "failed to register video device\n");
741 goto error;
742 }
743
744 return 0;
745
746error:
747 xvip_dma_cleanup(dma);
748 return ret;
749}
750
751void xvip_dma_cleanup(struct xvip_dma *dma)
752{
753 if (video_is_registered(&dma->video))
754 video_unregister_device(&dma->video);
755
756 if (dma->dma)
757 dma_release_channel(dma->dma);
758
759 if (!IS_ERR_OR_NULL(dma->alloc_ctx))
760 vb2_dma_contig_cleanup_ctx(dma->alloc_ctx);
761
762 media_entity_cleanup(&dma->video.entity);
763
764 mutex_destroy(&dma->lock);
765 mutex_destroy(&dma->pipe.lock);
766}
diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h
new file mode 100644
index 000000000000..a540111f8d3d
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-dma.h
@@ -0,0 +1,109 @@
1/*
2 * Xilinx Video DMA
3 *
4 * Copyright (C) 2013-2015 Ideas on Board
5 * Copyright (C) 2013-2015 Xilinx, Inc.
6 *
7 * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
8 * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef __XILINX_VIP_DMA_H__
16#define __XILINX_VIP_DMA_H__
17
18#include <linux/dmaengine.h>
19#include <linux/mutex.h>
20#include <linux/spinlock.h>
21#include <linux/videodev2.h>
22
23#include <media/media-entity.h>
24#include <media/v4l2-dev.h>
25#include <media/videobuf2-core.h>
26
27struct dma_chan;
28struct xvip_composite_device;
29struct xvip_video_format;
30
31/**
32 * struct xvip_pipeline - Xilinx Video IP pipeline structure
33 * @pipe: media pipeline
34 * @lock: protects the pipeline @stream_count
35 * @use_count: number of DMA engines using the pipeline
36 * @stream_count: number of DMA engines currently streaming
37 * @num_dmas: number of DMA engines in the pipeline
38 * @output: DMA engine at the output of the pipeline
39 */
40struct xvip_pipeline {
41 struct media_pipeline pipe;
42
43 struct mutex lock;
44 unsigned int use_count;
45 unsigned int stream_count;
46
47 unsigned int num_dmas;
48 struct xvip_dma *output;
49};
50
51static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
52{
53 return container_of(e->pipe, struct xvip_pipeline, pipe);
54}
55
56/**
57 * struct xvip_dma - Video DMA channel
58 * @list: list entry in a composite device dmas list
59 * @video: V4L2 video device associated with the DMA channel
60 * @pad: media pad for the video device entity
61 * @xdev: composite device the DMA channel belongs to
62 * @pipe: pipeline belonging to the DMA channel
63 * @port: composite device DT node port number for the DMA channel
64 * @lock: protects the @format, @fmtinfo and @queue fields
65 * @format: active V4L2 pixel format
66 * @fmtinfo: format information corresponding to the active @format
67 * @queue: vb2 buffers queue
68 * @alloc_ctx: allocation context for the vb2 @queue
69 * @sequence: V4L2 buffers sequence number
70 * @queued_bufs: list of queued buffers
71 * @queued_lock: protects the buf_queued list
72 * @dma: DMA engine channel
73 * @align: transfer alignment required by the DMA channel (in bytes)
74 * @xt: dma interleaved template for dma configuration
75 * @sgl: data chunk structure for dma_interleaved_template
76 */
77struct xvip_dma {
78 struct list_head list;
79 struct video_device video;
80 struct media_pad pad;
81
82 struct xvip_composite_device *xdev;
83 struct xvip_pipeline pipe;
84 unsigned int port;
85
86 struct mutex lock;
87 struct v4l2_pix_format format;
88 const struct xvip_video_format *fmtinfo;
89
90 struct vb2_queue queue;
91 void *alloc_ctx;
92 unsigned int sequence;
93
94 struct list_head queued_bufs;
95 spinlock_t queued_lock;
96
97 struct dma_chan *dma;
98 unsigned int align;
99 struct dma_interleaved_template xt;
100 struct data_chunk sgl[1];
101};
102
103#define to_xvip_dma(vdev) container_of(vdev, struct xvip_dma, video)
104
105int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
106 enum v4l2_buf_type type, unsigned int port);
107void xvip_dma_cleanup(struct xvip_dma *dma);
108
109#endif /* __XILINX_VIP_DMA_H__ */
diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c
new file mode 100644
index 000000000000..311259129504
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vip.c
@@ -0,0 +1,323 @@
1/*
2 * Xilinx Video IP Core
3 *
4 * Copyright (C) 2013-2015 Ideas on Board
5 * Copyright (C) 2013-2015 Xilinx, Inc.
6 *
7 * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
8 * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/clk.h>
16#include <linux/export.h>
17#include <linux/kernel.h>
18#include <linux/of.h>
19#include <linux/platform_device.h>
20
21#include <dt-bindings/media/xilinx-vip.h>
22
23#include "xilinx-vip.h"
24
25/* -----------------------------------------------------------------------------
26 * Helper functions
27 */
28
29static const struct xvip_video_format xvip_video_formats[] = {
30 { XVIP_VF_YUV_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16,
31 2, V4L2_PIX_FMT_YUYV, "4:2:2, packed, YUYV" },
32 { XVIP_VF_YUV_444, 8, NULL, MEDIA_BUS_FMT_VUY8_1X24,
33 3, V4L2_PIX_FMT_YUV444, "4:4:4, packed, YUYV" },
34 { XVIP_VF_RBG, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24,
35 3, 0, NULL },
36 { XVIP_VF_MONO_SENSOR, 8, "mono", MEDIA_BUS_FMT_Y8_1X8,
37 1, V4L2_PIX_FMT_GREY, "Greyscale 8-bit" },
38 { XVIP_VF_MONO_SENSOR, 8, "rggb", MEDIA_BUS_FMT_SRGGB8_1X8,
39 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit RGGB" },
40 { XVIP_VF_MONO_SENSOR, 8, "grbg", MEDIA_BUS_FMT_SGRBG8_1X8,
41 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit GRBG" },
42 { XVIP_VF_MONO_SENSOR, 8, "gbrg", MEDIA_BUS_FMT_SGBRG8_1X8,
43 1, V4L2_PIX_FMT_SGBRG8, "Bayer 8-bit GBRG" },
44 { XVIP_VF_MONO_SENSOR, 8, "bggr", MEDIA_BUS_FMT_SBGGR8_1X8,
45 1, V4L2_PIX_FMT_SBGGR8, "Bayer 8-bit BGGR" },
46};
47
48/**
49 * xvip_get_format_by_code - Retrieve format information for a media bus code
50 * @code: the format media bus code
51 *
52 * Return: a pointer to the format information structure corresponding to the
53 * given V4L2 media bus format @code, or ERR_PTR if no corresponding format can
54 * be found.
55 */
56const struct xvip_video_format *xvip_get_format_by_code(unsigned int code)
57{
58 unsigned int i;
59
60 for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) {
61 const struct xvip_video_format *format = &xvip_video_formats[i];
62
63 if (format->code == code)
64 return format;
65 }
66
67 return ERR_PTR(-EINVAL);
68}
69EXPORT_SYMBOL_GPL(xvip_get_format_by_code);
70
71/**
72 * xvip_get_format_by_fourcc - Retrieve format information for a 4CC
73 * @fourcc: the format 4CC
74 *
75 * Return: a pointer to the format information structure corresponding to the
76 * given V4L2 format @fourcc, or ERR_PTR if no corresponding format can be
77 * found.
78 */
79const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc)
80{
81 unsigned int i;
82
83 for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) {
84 const struct xvip_video_format *format = &xvip_video_formats[i];
85
86 if (format->fourcc == fourcc)
87 return format;
88 }
89
90 return ERR_PTR(-EINVAL);
91}
92EXPORT_SYMBOL_GPL(xvip_get_format_by_fourcc);
93
94/**
95 * xvip_of_get_format - Parse a device tree node and return format information
96 * @node: the device tree node
97 *
98 * Read the xlnx,video-format, xlnx,video-width and xlnx,cfa-pattern properties
99 * from the device tree @node passed as an argument and return the corresponding
100 * format information.
101 *
102 * Return: a pointer to the format information structure corresponding to the
103 * format name and width, or ERR_PTR if no corresponding format can be found.
104 */
105const struct xvip_video_format *xvip_of_get_format(struct device_node *node)
106{
107 const char *pattern = "mono";
108 unsigned int vf_code;
109 unsigned int i;
110 u32 width;
111 int ret;
112
113 ret = of_property_read_u32(node, "xlnx,video-format", &vf_code);
114 if (ret < 0)
115 return ERR_PTR(ret);
116
117 ret = of_property_read_u32(node, "xlnx,video-width", &width);
118 if (ret < 0)
119 return ERR_PTR(ret);
120
121 if (vf_code == XVIP_VF_MONO_SENSOR)
122 of_property_read_string(node, "xlnx,cfa-pattern", &pattern);
123
124 for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) {
125 const struct xvip_video_format *format = &xvip_video_formats[i];
126
127 if (format->vf_code != vf_code || format->width != width)
128 continue;
129
130 if (vf_code == XVIP_VF_MONO_SENSOR &&
131 strcmp(pattern, format->pattern))
132 continue;
133
134 return format;
135 }
136
137 return ERR_PTR(-EINVAL);
138}
139EXPORT_SYMBOL_GPL(xvip_of_get_format);
140
141/**
142 * xvip_set_format_size - Set the media bus frame format size
143 * @format: V4L2 frame format on media bus
144 * @fmt: media bus format
145 *
146 * Set the media bus frame format size. The width / height from the subdevice
147 * format are set to the given media bus format. The new format size is stored
148 * in @format. The width and height are clamped using default min / max values.
149 */
150void xvip_set_format_size(struct v4l2_mbus_framefmt *format,
151 const struct v4l2_subdev_format *fmt)
152{
153 format->width = clamp_t(unsigned int, fmt->format.width,
154 XVIP_MIN_WIDTH, XVIP_MAX_WIDTH);
155 format->height = clamp_t(unsigned int, fmt->format.height,
156 XVIP_MIN_HEIGHT, XVIP_MAX_HEIGHT);
157}
158EXPORT_SYMBOL_GPL(xvip_set_format_size);
159
160/**
161 * xvip_clr_or_set - Clear or set the register with a bitmask
162 * @xvip: Xilinx Video IP device
163 * @addr: address of register
164 * @mask: bitmask to be set or cleared
165 * @set: boolean flag indicating whether to set or clear
166 *
167 * Clear or set the register at address @addr with a bitmask @mask depending on
168 * the boolean flag @set. When the flag @set is true, the bitmask is set in
169 * the register, otherwise the bitmask is cleared from the register
170 * when the flag @set is false.
171 *
172 * Fox eample, this function can be used to set a control with a boolean value
173 * requested by users. If the caller knows whether to set or clear in the first
174 * place, the caller should call xvip_clr() or xvip_set() directly instead of
175 * using this function.
176 */
177void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set)
178{
179 u32 reg;
180
181 reg = xvip_read(xvip, addr);
182 reg = set ? reg | mask : reg & ~mask;
183 xvip_write(xvip, addr, reg);
184}
185EXPORT_SYMBOL_GPL(xvip_clr_or_set);
186
187/**
188 * xvip_clr_and_set - Clear and set the register with a bitmask
189 * @xvip: Xilinx Video IP device
190 * @addr: address of register
191 * @clr: bitmask to be cleared
192 * @set: bitmask to be set
193 *
194 * Clear a bit(s) of mask @clr in the register at address @addr, then set
195 * a bit(s) of mask @set in the register after.
196 */
197void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set)
198{
199 u32 reg;
200
201 reg = xvip_read(xvip, addr);
202 reg &= ~clr;
203 reg |= set;
204 xvip_write(xvip, addr, reg);
205}
206EXPORT_SYMBOL_GPL(xvip_clr_and_set);
207
208int xvip_init_resources(struct xvip_device *xvip)
209{
210 struct platform_device *pdev = to_platform_device(xvip->dev);
211 struct resource *res;
212
213 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
214 xvip->iomem = devm_ioremap_resource(xvip->dev, res);
215 if (IS_ERR(xvip->iomem))
216 return PTR_ERR(xvip->iomem);
217
218 xvip->clk = devm_clk_get(xvip->dev, NULL);
219 if (IS_ERR(xvip->clk))
220 return PTR_ERR(xvip->clk);
221
222 clk_prepare_enable(xvip->clk);
223 return 0;
224}
225EXPORT_SYMBOL_GPL(xvip_init_resources);
226
227void xvip_cleanup_resources(struct xvip_device *xvip)
228{
229 clk_disable_unprepare(xvip->clk);
230}
231EXPORT_SYMBOL_GPL(xvip_cleanup_resources);
232
233/* -----------------------------------------------------------------------------
234 * Subdev operations handlers
235 */
236
237/**
238 * xvip_enum_mbus_code - Enumerate the media format code
239 * @subdev: V4L2 subdevice
240 * @cfg: V4L2 subdev pad configuration
241 * @code: returning media bus code
242 *
243 * Enumerate the media bus code of the subdevice. Return the corresponding
244 * pad format code. This function only works for subdevices with fixed format
245 * on all pads. Subdevices with multiple format should have their own
246 * function to enumerate mbus codes.
247 *
248 * Return: 0 if the media bus code is found, or -EINVAL if the format index
249 * is not valid.
250 */
251int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
252 struct v4l2_subdev_pad_config *cfg,
253 struct v4l2_subdev_mbus_code_enum *code)
254{
255 struct v4l2_mbus_framefmt *format;
256
257 /* Enumerating frame sizes based on the active configuration isn't
258 * supported yet.
259 */
260 if (code->which == V4L2_SUBDEV_FORMAT_ACTIVE)
261 return -EINVAL;
262
263 if (code->index)
264 return -EINVAL;
265
266 format = v4l2_subdev_get_try_format(subdev, cfg, code->pad);
267
268 code->code = format->code;
269
270 return 0;
271}
272EXPORT_SYMBOL_GPL(xvip_enum_mbus_code);
273
274/**
275 * xvip_enum_frame_size - Enumerate the media bus frame size
276 * @subdev: V4L2 subdevice
277 * @cfg: V4L2 subdev pad configuration
278 * @fse: returning media bus frame size
279 *
280 * This function is a drop-in implementation of the subdev enum_frame_size pad
281 * operation. It assumes that the subdevice has one sink pad and one source
282 * pad, and that the format on the source pad is always identical to the
283 * format on the sink pad. Entities with different requirements need to
284 * implement their own enum_frame_size handlers.
285 *
286 * Return: 0 if the media bus frame size is found, or -EINVAL
287 * if the index or the code is not valid.
288 */
289int xvip_enum_frame_size(struct v4l2_subdev *subdev,
290 struct v4l2_subdev_pad_config *cfg,
291 struct v4l2_subdev_frame_size_enum *fse)
292{
293 struct v4l2_mbus_framefmt *format;
294
295 /* Enumerating frame sizes based on the active configuration isn't
296 * supported yet.
297 */
298 if (fse->which == V4L2_SUBDEV_FORMAT_ACTIVE)
299 return -EINVAL;
300
301 format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
302
303 if (fse->index || fse->code != format->code)
304 return -EINVAL;
305
306 if (fse->pad == XVIP_PAD_SINK) {
307 fse->min_width = XVIP_MIN_WIDTH;
308 fse->max_width = XVIP_MAX_WIDTH;
309 fse->min_height = XVIP_MIN_HEIGHT;
310 fse->max_height = XVIP_MAX_HEIGHT;
311 } else {
312 /* The size on the source pad is fixed and always identical to
313 * the size on the sink pad.
314 */
315 fse->min_width = format->width;
316 fse->max_width = format->width;
317 fse->min_height = format->height;
318 fse->max_height = format->height;
319 }
320
321 return 0;
322}
323EXPORT_SYMBOL_GPL(xvip_enum_frame_size);
diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h
new file mode 100644
index 000000000000..42fee2026815
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vip.h
@@ -0,0 +1,238 @@
1/*
2 * Xilinx Video IP Core
3 *
4 * Copyright (C) 2013-2015 Ideas on Board
5 * Copyright (C) 2013-2015 Xilinx, Inc.
6 *
7 * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
8 * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef __XILINX_VIP_H__
16#define __XILINX_VIP_H__
17
18#include <linux/io.h>
19#include <media/v4l2-subdev.h>
20
21struct clk;
22
23/*
24 * Minimum and maximum width and height common to most video IP cores. IP
25 * cores with different requirements must define their own values.
26 */
27#define XVIP_MIN_WIDTH 32
28#define XVIP_MAX_WIDTH 7680
29#define XVIP_MIN_HEIGHT 32
30#define XVIP_MAX_HEIGHT 7680
31
32/*
33 * Pad IDs. IP cores with with multiple inputs or outputs should define
34 * their own values.
35 */
36#define XVIP_PAD_SINK 0
37#define XVIP_PAD_SOURCE 1
38
39/* Xilinx Video IP Control Registers */
40#define XVIP_CTRL_CONTROL 0x0000
41#define XVIP_CTRL_CONTROL_SW_ENABLE (1 << 0)
42#define XVIP_CTRL_CONTROL_REG_UPDATE (1 << 1)
43#define XVIP_CTRL_CONTROL_BYPASS (1 << 4)
44#define XVIP_CTRL_CONTROL_TEST_PATTERN (1 << 5)
45#define XVIP_CTRL_CONTROL_FRAME_SYNC_RESET (1 << 30)
46#define XVIP_CTRL_CONTROL_SW_RESET (1 << 31)
47#define XVIP_CTRL_STATUS 0x0004
48#define XVIP_CTRL_STATUS_PROC_STARTED (1 << 0)
49#define XVIP_CTRL_STATUS_EOF (1 << 1)
50#define XVIP_CTRL_ERROR 0x0008
51#define XVIP_CTRL_ERROR_SLAVE_EOL_EARLY (1 << 0)
52#define XVIP_CTRL_ERROR_SLAVE_EOL_LATE (1 << 1)
53#define XVIP_CTRL_ERROR_SLAVE_SOF_EARLY (1 << 2)
54#define XVIP_CTRL_ERROR_SLAVE_SOF_LATE (1 << 3)
55#define XVIP_CTRL_IRQ_ENABLE 0x000c
56#define XVIP_CTRL_IRQ_ENABLE_PROC_STARTED (1 << 0)
57#define XVIP_CTRL_IRQ_EOF (1 << 1)
58#define XVIP_CTRL_VERSION 0x0010
59#define XVIP_CTRL_VERSION_MAJOR_MASK (0xff << 24)
60#define XVIP_CTRL_VERSION_MAJOR_SHIFT 24
61#define XVIP_CTRL_VERSION_MINOR_MASK (0xff << 16)
62#define XVIP_CTRL_VERSION_MINOR_SHIFT 16
63#define XVIP_CTRL_VERSION_REVISION_MASK (0xf << 12)
64#define XVIP_CTRL_VERSION_REVISION_SHIFT 12
65#define XVIP_CTRL_VERSION_PATCH_MASK (0xf << 8)
66#define XVIP_CTRL_VERSION_PATCH_SHIFT 8
67#define XVIP_CTRL_VERSION_INTERNAL_MASK (0xff << 0)
68#define XVIP_CTRL_VERSION_INTERNAL_SHIFT 0
69
70/* Xilinx Video IP Timing Registers */
71#define XVIP_ACTIVE_SIZE 0x0020
72#define XVIP_ACTIVE_VSIZE_MASK (0x7ff << 16)
73#define XVIP_ACTIVE_VSIZE_SHIFT 16
74#define XVIP_ACTIVE_HSIZE_MASK (0x7ff << 0)
75#define XVIP_ACTIVE_HSIZE_SHIFT 0
76#define XVIP_ENCODING 0x0028
77#define XVIP_ENCODING_NBITS_8 (0 << 4)
78#define XVIP_ENCODING_NBITS_10 (1 << 4)
79#define XVIP_ENCODING_NBITS_12 (2 << 4)
80#define XVIP_ENCODING_NBITS_16 (3 << 4)
81#define XVIP_ENCODING_NBITS_MASK (3 << 4)
82#define XVIP_ENCODING_NBITS_SHIFT 4
83#define XVIP_ENCODING_VIDEO_FORMAT_YUV422 (0 << 0)
84#define XVIP_ENCODING_VIDEO_FORMAT_YUV444 (1 << 0)
85#define XVIP_ENCODING_VIDEO_FORMAT_RGB (2 << 0)
86#define XVIP_ENCODING_VIDEO_FORMAT_YUV420 (3 << 0)
87#define XVIP_ENCODING_VIDEO_FORMAT_MASK (3 << 0)
88#define XVIP_ENCODING_VIDEO_FORMAT_SHIFT 0
89
90/**
91 * struct xvip_device - Xilinx Video IP device structure
92 * @subdev: V4L2 subdevice
93 * @dev: (OF) device
94 * @iomem: device I/O register space remapped to kernel virtual memory
95 * @clk: video core clock
96 * @saved_ctrl: saved control register for resume / suspend
97 */
98struct xvip_device {
99 struct v4l2_subdev subdev;
100 struct device *dev;
101 void __iomem *iomem;
102 struct clk *clk;
103 u32 saved_ctrl;
104};
105
106/**
107 * struct xvip_video_format - Xilinx Video IP video format description
108 * @vf_code: AXI4 video format code
109 * @width: AXI4 format width in bits per component
110 * @pattern: CFA pattern for Mono/Sensor formats
111 * @code: media bus format code
112 * @bpp: bytes per pixel (when stored in memory)
113 * @fourcc: V4L2 pixel format FCC identifier
114 * @description: format description, suitable for userspace
115 */
116struct xvip_video_format {
117 unsigned int vf_code;
118 unsigned int width;
119 const char *pattern;
120 unsigned int code;
121 unsigned int bpp;
122 u32 fourcc;
123 const char *description;
124};
125
126const struct xvip_video_format *xvip_get_format_by_code(unsigned int code);
127const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc);
128const struct xvip_video_format *xvip_of_get_format(struct device_node *node);
129void xvip_set_format_size(struct v4l2_mbus_framefmt *format,
130 const struct v4l2_subdev_format *fmt);
131int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
132 struct v4l2_subdev_pad_config *cfg,
133 struct v4l2_subdev_mbus_code_enum *code);
134int xvip_enum_frame_size(struct v4l2_subdev *subdev,
135 struct v4l2_subdev_pad_config *cfg,
136 struct v4l2_subdev_frame_size_enum *fse);
137
138static inline u32 xvip_read(struct xvip_device *xvip, u32 addr)
139{
140 return ioread32(xvip->iomem + addr);
141}
142
143static inline void xvip_write(struct xvip_device *xvip, u32 addr, u32 value)
144{
145 iowrite32(value, xvip->iomem + addr);
146}
147
148static inline void xvip_clr(struct xvip_device *xvip, u32 addr, u32 clr)
149{
150 xvip_write(xvip, addr, xvip_read(xvip, addr) & ~clr);
151}
152
153static inline void xvip_set(struct xvip_device *xvip, u32 addr, u32 set)
154{
155 xvip_write(xvip, addr, xvip_read(xvip, addr) | set);
156}
157
158void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set);
159void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set);
160
161int xvip_init_resources(struct xvip_device *xvip);
162void xvip_cleanup_resources(struct xvip_device *xvip);
163
164static inline void xvip_reset(struct xvip_device *xvip)
165{
166 xvip_write(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_RESET);
167}
168
169static inline void xvip_start(struct xvip_device *xvip)
170{
171 xvip_set(xvip, XVIP_CTRL_CONTROL,
172 XVIP_CTRL_CONTROL_SW_ENABLE | XVIP_CTRL_CONTROL_REG_UPDATE);
173}
174
175static inline void xvip_stop(struct xvip_device *xvip)
176{
177 xvip_clr(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_ENABLE);
178}
179
180static inline void xvip_resume(struct xvip_device *xvip)
181{
182 xvip_write(xvip, XVIP_CTRL_CONTROL,
183 xvip->saved_ctrl | XVIP_CTRL_CONTROL_SW_ENABLE);
184}
185
186static inline void xvip_suspend(struct xvip_device *xvip)
187{
188 xvip->saved_ctrl = xvip_read(xvip, XVIP_CTRL_CONTROL);
189 xvip_write(xvip, XVIP_CTRL_CONTROL,
190 xvip->saved_ctrl & ~XVIP_CTRL_CONTROL_SW_ENABLE);
191}
192
193static inline void xvip_set_frame_size(struct xvip_device *xvip,
194 const struct v4l2_mbus_framefmt *format)
195{
196 xvip_write(xvip, XVIP_ACTIVE_SIZE,
197 (format->height << XVIP_ACTIVE_VSIZE_SHIFT) |
198 (format->width << XVIP_ACTIVE_HSIZE_SHIFT));
199}
200
201static inline void xvip_get_frame_size(struct xvip_device *xvip,
202 struct v4l2_mbus_framefmt *format)
203{
204 u32 reg;
205
206 reg = xvip_read(xvip, XVIP_ACTIVE_SIZE);
207 format->width = (reg & XVIP_ACTIVE_HSIZE_MASK) >>
208 XVIP_ACTIVE_HSIZE_SHIFT;
209 format->height = (reg & XVIP_ACTIVE_VSIZE_MASK) >>
210 XVIP_ACTIVE_VSIZE_SHIFT;
211}
212
213static inline void xvip_enable_reg_update(struct xvip_device *xvip)
214{
215 xvip_set(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_REG_UPDATE);
216}
217
218static inline void xvip_disable_reg_update(struct xvip_device *xvip)
219{
220 xvip_clr(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_REG_UPDATE);
221}
222
223static inline void xvip_print_version(struct xvip_device *xvip)
224{
225 u32 version;
226
227 version = xvip_read(xvip, XVIP_CTRL_VERSION);
228
229 dev_info(xvip->dev, "device found, version %u.%02x%x\n",
230 ((version & XVIP_CTRL_VERSION_MAJOR_MASK) >>
231 XVIP_CTRL_VERSION_MAJOR_SHIFT),
232 ((version & XVIP_CTRL_VERSION_MINOR_MASK) >>
233 XVIP_CTRL_VERSION_MINOR_SHIFT),
234 ((version & XVIP_CTRL_VERSION_REVISION_MASK) >>
235 XVIP_CTRL_VERSION_REVISION_SHIFT));
236}
237
238#endif /* __XILINX_VIP_H__ */
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
new file mode 100644
index 000000000000..7b7cb9c28d2c
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -0,0 +1,669 @@
1/*
2 * Xilinx Video IP Composite Device
3 *
4 * Copyright (C) 2013-2015 Ideas on Board
5 * Copyright (C) 2013-2015 Xilinx, Inc.
6 *
7 * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
8 * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/list.h>
16#include <linux/module.h>
17#include <linux/of.h>
18#include <linux/of_graph.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21
22#include <media/v4l2-async.h>
23#include <media/v4l2-common.h>
24#include <media/v4l2-device.h>
25#include <media/v4l2-of.h>
26
27#include "xilinx-dma.h"
28#include "xilinx-vipp.h"
29
30#define XVIPP_DMA_S2MM 0
31#define XVIPP_DMA_MM2S 1
32
33/**
34 * struct xvip_graph_entity - Entity in the video graph
35 * @list: list entry in a graph entities list
36 * @node: the entity's DT node
37 * @entity: media entity, from the corresponding V4L2 subdev
38 * @asd: subdev asynchronous registration information
39 * @subdev: V4L2 subdev
40 */
41struct xvip_graph_entity {
42 struct list_head list;
43 struct device_node *node;
44 struct media_entity *entity;
45
46 struct v4l2_async_subdev asd;
47 struct v4l2_subdev *subdev;
48};
49
50/* -----------------------------------------------------------------------------
51 * Graph Management
52 */
53
54static struct xvip_graph_entity *
55xvip_graph_find_entity(struct xvip_composite_device *xdev,
56 const struct device_node *node)
57{
58 struct xvip_graph_entity *entity;
59
60 list_for_each_entry(entity, &xdev->entities, list) {
61 if (entity->node == node)
62 return entity;
63 }
64
65 return NULL;
66}
67
68static int xvip_graph_build_one(struct xvip_composite_device *xdev,
69 struct xvip_graph_entity *entity)
70{
71 u32 link_flags = MEDIA_LNK_FL_ENABLED;
72 struct media_entity *local = entity->entity;
73 struct media_entity *remote;
74 struct media_pad *local_pad;
75 struct media_pad *remote_pad;
76 struct xvip_graph_entity *ent;
77 struct v4l2_of_link link;
78 struct device_node *ep = NULL;
79 struct device_node *next;
80 int ret = 0;
81
82 dev_dbg(xdev->dev, "creating links for entity %s\n", local->name);
83
84 while (1) {
85 /* Get the next endpoint and parse its link. */
86 next = of_graph_get_next_endpoint(entity->node, ep);
87 if (next == NULL)
88 break;
89
90 of_node_put(ep);
91 ep = next;
92
93 dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name);
94
95 ret = v4l2_of_parse_link(ep, &link);
96 if (ret < 0) {
97 dev_err(xdev->dev, "failed to parse link for %s\n",
98 ep->full_name);
99 continue;
100 }
101
102 /* Skip sink ports, they will be processed from the other end of
103 * the link.
104 */
105 if (link.local_port >= local->num_pads) {
106 dev_err(xdev->dev, "invalid port number %u on %s\n",
107 link.local_port, link.local_node->full_name);
108 v4l2_of_put_link(&link);
109 ret = -EINVAL;
110 break;
111 }
112
113 local_pad = &local->pads[link.local_port];
114
115 if (local_pad->flags & MEDIA_PAD_FL_SINK) {
116 dev_dbg(xdev->dev, "skipping sink port %s:%u\n",
117 link.local_node->full_name, link.local_port);
118 v4l2_of_put_link(&link);
119 continue;
120 }
121
122 /* Skip DMA engines, they will be processed separately. */
123 if (link.remote_node == xdev->dev->of_node) {
124 dev_dbg(xdev->dev, "skipping DMA port %s:%u\n",
125 link.local_node->full_name, link.local_port);
126 v4l2_of_put_link(&link);
127 continue;
128 }
129
130 /* Find the remote entity. */
131 ent = xvip_graph_find_entity(xdev, link.remote_node);
132 if (ent == NULL) {
133 dev_err(xdev->dev, "no entity found for %s\n",
134 link.remote_node->full_name);
135 v4l2_of_put_link(&link);
136 ret = -ENODEV;
137 break;
138 }
139
140 remote = ent->entity;
141
142 if (link.remote_port >= remote->num_pads) {
143 dev_err(xdev->dev, "invalid port number %u on %s\n",
144 link.remote_port, link.remote_node->full_name);
145 v4l2_of_put_link(&link);
146 ret = -EINVAL;
147 break;
148 }
149
150 remote_pad = &remote->pads[link.remote_port];
151
152 v4l2_of_put_link(&link);
153
154 /* Create the media link. */
155 dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n",
156 local->name, local_pad->index,
157 remote->name, remote_pad->index);
158
159 ret = media_entity_create_link(local, local_pad->index,
160 remote, remote_pad->index,
161 link_flags);
162 if (ret < 0) {
163 dev_err(xdev->dev,
164 "failed to create %s:%u -> %s:%u link\n",
165 local->name, local_pad->index,
166 remote->name, remote_pad->index);
167 break;
168 }
169 }
170
171 of_node_put(ep);
172 return ret;
173}
174
175static struct xvip_dma *
176xvip_graph_find_dma(struct xvip_composite_device *xdev, unsigned int port)
177{
178 struct xvip_dma *dma;
179
180 list_for_each_entry(dma, &xdev->dmas, list) {
181 if (dma->port == port)
182 return dma;
183 }
184
185 return NULL;
186}
187
188static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
189{
190 u32 link_flags = MEDIA_LNK_FL_ENABLED;
191 struct device_node *node = xdev->dev->of_node;
192 struct media_entity *source;
193 struct media_entity *sink;
194 struct media_pad *source_pad;
195 struct media_pad *sink_pad;
196 struct xvip_graph_entity *ent;
197 struct v4l2_of_link link;
198 struct device_node *ep = NULL;
199 struct device_node *next;
200 struct xvip_dma *dma;
201 int ret = 0;
202
203 dev_dbg(xdev->dev, "creating links for DMA engines\n");
204
205 while (1) {
206 /* Get the next endpoint and parse its link. */
207 next = of_graph_get_next_endpoint(node, ep);
208 if (next == NULL)
209 break;
210
211 of_node_put(ep);
212 ep = next;
213
214 dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name);
215
216 ret = v4l2_of_parse_link(ep, &link);
217 if (ret < 0) {
218 dev_err(xdev->dev, "failed to parse link for %s\n",
219 ep->full_name);
220 continue;
221 }
222
223 /* Find the DMA engine. */
224 dma = xvip_graph_find_dma(xdev, link.local_port);
225 if (dma == NULL) {
226 dev_err(xdev->dev, "no DMA engine found for port %u\n",
227 link.local_port);
228 v4l2_of_put_link(&link);
229 ret = -EINVAL;
230 break;
231 }
232
233 dev_dbg(xdev->dev, "creating link for DMA engine %s\n",
234 dma->video.name);
235
236 /* Find the remote entity. */
237 ent = xvip_graph_find_entity(xdev, link.remote_node);
238 if (ent == NULL) {
239 dev_err(xdev->dev, "no entity found for %s\n",
240 link.remote_node->full_name);
241 v4l2_of_put_link(&link);
242 ret = -ENODEV;
243 break;
244 }
245
246 if (link.remote_port >= ent->entity->num_pads) {
247 dev_err(xdev->dev, "invalid port number %u on %s\n",
248 link.remote_port, link.remote_node->full_name);
249 v4l2_of_put_link(&link);
250 ret = -EINVAL;
251 break;
252 }
253
254 if (dma->pad.flags & MEDIA_PAD_FL_SOURCE) {
255 source = &dma->video.entity;
256 source_pad = &dma->pad;
257 sink = ent->entity;
258 sink_pad = &sink->pads[link.remote_port];
259 } else {
260 source = ent->entity;
261 source_pad = &source->pads[link.remote_port];
262 sink = &dma->video.entity;
263 sink_pad = &dma->pad;
264 }
265
266 v4l2_of_put_link(&link);
267
268 /* Create the media link. */
269 dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n",
270 source->name, source_pad->index,
271 sink->name, sink_pad->index);
272
273 ret = media_entity_create_link(source, source_pad->index,
274 sink, sink_pad->index,
275 link_flags);
276 if (ret < 0) {
277 dev_err(xdev->dev,
278 "failed to create %s:%u -> %s:%u link\n",
279 source->name, source_pad->index,
280 sink->name, sink_pad->index);
281 break;
282 }
283 }
284
285 of_node_put(ep);
286 return ret;
287}
288
289static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier)
290{
291 struct xvip_composite_device *xdev =
292 container_of(notifier, struct xvip_composite_device, notifier);
293 struct xvip_graph_entity *entity;
294 int ret;
295
296 dev_dbg(xdev->dev, "notify complete, all subdevs registered\n");
297
298 /* Create links for every entity. */
299 list_for_each_entry(entity, &xdev->entities, list) {
300 ret = xvip_graph_build_one(xdev, entity);
301 if (ret < 0)
302 return ret;
303 }
304
305 /* Create links for DMA channels. */
306 ret = xvip_graph_build_dma(xdev);
307 if (ret < 0)
308 return ret;
309
310 ret = v4l2_device_register_subdev_nodes(&xdev->v4l2_dev);
311 if (ret < 0)
312 dev_err(xdev->dev, "failed to register subdev nodes\n");
313
314 return ret;
315}
316
317static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,
318 struct v4l2_subdev *subdev,
319 struct v4l2_async_subdev *asd)
320{
321 struct xvip_composite_device *xdev =
322 container_of(notifier, struct xvip_composite_device, notifier);
323 struct xvip_graph_entity *entity;
324
325 /* Locate the entity corresponding to the bound subdev and store the
326 * subdev pointer.
327 */
328 list_for_each_entry(entity, &xdev->entities, list) {
329 if (entity->node != subdev->dev->of_node)
330 continue;
331
332 if (entity->subdev) {
333 dev_err(xdev->dev, "duplicate subdev for node %s\n",
334 entity->node->full_name);
335 return -EINVAL;
336 }
337
338 dev_dbg(xdev->dev, "subdev %s bound\n", subdev->name);
339 entity->entity = &subdev->entity;
340 entity->subdev = subdev;
341 return 0;
342 }
343
344 dev_err(xdev->dev, "no entity for subdev %s\n", subdev->name);
345 return -EINVAL;
346}
347
348static int xvip_graph_parse_one(struct xvip_composite_device *xdev,
349 struct device_node *node)
350{
351 struct xvip_graph_entity *entity;
352 struct device_node *remote;
353 struct device_node *ep = NULL;
354 struct device_node *next;
355 int ret = 0;
356
357 dev_dbg(xdev->dev, "parsing node %s\n", node->full_name);
358
359 while (1) {
360 next = of_graph_get_next_endpoint(node, ep);
361 if (next == NULL)
362 break;
363
364 of_node_put(ep);
365 ep = next;
366
367 dev_dbg(xdev->dev, "handling endpoint %s\n", ep->full_name);
368
369 remote = of_graph_get_remote_port_parent(ep);
370 if (remote == NULL) {
371 ret = -EINVAL;
372 break;
373 }
374
375 /* Skip entities that we have already processed. */
376 if (remote == xdev->dev->of_node ||
377 xvip_graph_find_entity(xdev, remote)) {
378 of_node_put(remote);
379 continue;
380 }
381
382 entity = devm_kzalloc(xdev->dev, sizeof(*entity), GFP_KERNEL);
383 if (entity == NULL) {
384 of_node_put(remote);
385 ret = -ENOMEM;
386 break;
387 }
388
389 entity->node = remote;
390 entity->asd.match_type = V4L2_ASYNC_MATCH_OF;
391 entity->asd.match.of.node = remote;
392 list_add_tail(&entity->list, &xdev->entities);
393 xdev->num_subdevs++;
394 }
395
396 of_node_put(ep);
397 return ret;
398}
399
400static int xvip_graph_parse(struct xvip_composite_device *xdev)
401{
402 struct xvip_graph_entity *entity;
403 int ret;
404
405 /*
406 * Walk the links to parse the full graph. Start by parsing the
407 * composite node and then parse entities in turn. The list_for_each
408 * loop will handle entities added at the end of the list while walking
409 * the links.
410 */
411 ret = xvip_graph_parse_one(xdev, xdev->dev->of_node);
412 if (ret < 0)
413 return 0;
414
415 list_for_each_entry(entity, &xdev->entities, list) {
416 ret = xvip_graph_parse_one(xdev, entity->node);
417 if (ret < 0)
418 break;
419 }
420
421 return ret;
422}
423
424static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev,
425 struct device_node *node)
426{
427 struct xvip_dma *dma;
428 enum v4l2_buf_type type;
429 const char *direction;
430 unsigned int index;
431 int ret;
432
433 ret = of_property_read_string(node, "direction", &direction);
434 if (ret < 0)
435 return ret;
436
437 if (strcmp(direction, "input") == 0)
438 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
439 else if (strcmp(direction, "output") == 0)
440 type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
441 else
442 return -EINVAL;
443
444 of_property_read_u32(node, "reg", &index);
445
446 dma = devm_kzalloc(xdev->dev, sizeof(*dma), GFP_KERNEL);
447 if (dma == NULL)
448 return -ENOMEM;
449
450 ret = xvip_dma_init(xdev, dma, type, index);
451 if (ret < 0) {
452 dev_err(xdev->dev, "%s initialization failed\n",
453 node->full_name);
454 return ret;
455 }
456
457 list_add_tail(&dma->list, &xdev->dmas);
458
459 xdev->v4l2_caps |= type == V4L2_BUF_TYPE_VIDEO_CAPTURE
460 ? V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_VIDEO_OUTPUT;
461
462 return 0;
463}
464
465static int xvip_graph_dma_init(struct xvip_composite_device *xdev)
466{
467 struct device_node *ports;
468 struct device_node *port;
469 int ret;
470
471 ports = of_get_child_by_name(xdev->dev->of_node, "ports");
472 if (ports == NULL) {
473 dev_err(xdev->dev, "ports node not present\n");
474 return -EINVAL;
475 }
476
477 for_each_child_of_node(ports, port) {
478 ret = xvip_graph_dma_init_one(xdev, port);
479 if (ret < 0)
480 return ret;
481 }
482
483 return 0;
484}
485
486static void xvip_graph_cleanup(struct xvip_composite_device *xdev)
487{
488 struct xvip_graph_entity *entityp;
489 struct xvip_graph_entity *entity;
490 struct xvip_dma *dmap;
491 struct xvip_dma *dma;
492
493 v4l2_async_notifier_unregister(&xdev->notifier);
494
495 list_for_each_entry_safe(entity, entityp, &xdev->entities, list) {
496 of_node_put(entity->node);
497 list_del(&entity->list);
498 }
499
500 list_for_each_entry_safe(dma, dmap, &xdev->dmas, list) {
501 xvip_dma_cleanup(dma);
502 list_del(&dma->list);
503 }
504}
505
506static int xvip_graph_init(struct xvip_composite_device *xdev)
507{
508 struct xvip_graph_entity *entity;
509 struct v4l2_async_subdev **subdevs = NULL;
510 unsigned int num_subdevs;
511 unsigned int i;
512 int ret;
513
514 /* Init the DMA channels. */
515 ret = xvip_graph_dma_init(xdev);
516 if (ret < 0) {
517 dev_err(xdev->dev, "DMA initialization failed\n");
518 goto done;
519 }
520
521 /* Parse the graph to extract a list of subdevice DT nodes. */
522 ret = xvip_graph_parse(xdev);
523 if (ret < 0) {
524 dev_err(xdev->dev, "graph parsing failed\n");
525 goto done;
526 }
527
528 if (!xdev->num_subdevs) {
529 dev_err(xdev->dev, "no subdev found in graph\n");
530 goto done;
531 }
532
533 /* Register the subdevices notifier. */
534 num_subdevs = xdev->num_subdevs;
535 subdevs = devm_kzalloc(xdev->dev, sizeof(*subdevs) * num_subdevs,
536 GFP_KERNEL);
537 if (subdevs == NULL) {
538 ret = -ENOMEM;
539 goto done;
540 }
541
542 i = 0;
543 list_for_each_entry(entity, &xdev->entities, list)
544 subdevs[i++] = &entity->asd;
545
546 xdev->notifier.subdevs = subdevs;
547 xdev->notifier.num_subdevs = num_subdevs;
548 xdev->notifier.bound = xvip_graph_notify_bound;
549 xdev->notifier.complete = xvip_graph_notify_complete;
550
551 ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier);
552 if (ret < 0) {
553 dev_err(xdev->dev, "notifier registration failed\n");
554 goto done;
555 }
556
557 ret = 0;
558
559done:
560 if (ret < 0)
561 xvip_graph_cleanup(xdev);
562
563 return ret;
564}
565
566/* -----------------------------------------------------------------------------
567 * Media Controller and V4L2
568 */
569
570static void xvip_composite_v4l2_cleanup(struct xvip_composite_device *xdev)
571{
572 v4l2_device_unregister(&xdev->v4l2_dev);
573 media_device_unregister(&xdev->media_dev);
574}
575
576static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev)
577{
578 int ret;
579
580 xdev->media_dev.dev = xdev->dev;
581 strlcpy(xdev->media_dev.model, "Xilinx Video Composite Device",
582 sizeof(xdev->media_dev.model));
583 xdev->media_dev.hw_revision = 0;
584
585 ret = media_device_register(&xdev->media_dev);
586 if (ret < 0) {
587 dev_err(xdev->dev, "media device registration failed (%d)\n",
588 ret);
589 return ret;
590 }
591
592 xdev->v4l2_dev.mdev = &xdev->media_dev;
593 ret = v4l2_device_register(xdev->dev, &xdev->v4l2_dev);
594 if (ret < 0) {
595 dev_err(xdev->dev, "V4L2 device registration failed (%d)\n",
596 ret);
597 media_device_unregister(&xdev->media_dev);
598 return ret;
599 }
600
601 return 0;
602}
603
604/* -----------------------------------------------------------------------------
605 * Platform Device Driver
606 */
607
608static int xvip_composite_probe(struct platform_device *pdev)
609{
610 struct xvip_composite_device *xdev;
611 int ret;
612
613 xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
614 if (!xdev)
615 return -ENOMEM;
616
617 xdev->dev = &pdev->dev;
618 INIT_LIST_HEAD(&xdev->entities);
619 INIT_LIST_HEAD(&xdev->dmas);
620
621 ret = xvip_composite_v4l2_init(xdev);
622 if (ret < 0)
623 return ret;
624
625 ret = xvip_graph_init(xdev);
626 if (ret < 0)
627 goto error;
628
629 platform_set_drvdata(pdev, xdev);
630
631 dev_info(xdev->dev, "device registered\n");
632
633 return 0;
634
635error:
636 xvip_composite_v4l2_cleanup(xdev);
637 return ret;
638}
639
640static int xvip_composite_remove(struct platform_device *pdev)
641{
642 struct xvip_composite_device *xdev = platform_get_drvdata(pdev);
643
644 xvip_graph_cleanup(xdev);
645 xvip_composite_v4l2_cleanup(xdev);
646
647 return 0;
648}
649
650static const struct of_device_id xvip_composite_of_id_table[] = {
651 { .compatible = "xlnx,video" },
652 { }
653};
654MODULE_DEVICE_TABLE(of, xvip_composite_of_id_table);
655
656static struct platform_driver xvip_composite_driver = {
657 .driver = {
658 .name = "xilinx-video",
659 .of_match_table = xvip_composite_of_id_table,
660 },
661 .probe = xvip_composite_probe,
662 .remove = xvip_composite_remove,
663};
664
665module_platform_driver(xvip_composite_driver);
666
667MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
668MODULE_DESCRIPTION("Xilinx Video IP Composite Driver");
669MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.h b/drivers/media/platform/xilinx/xilinx-vipp.h
new file mode 100644
index 000000000000..faf6b6e80b3b
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vipp.h
@@ -0,0 +1,49 @@
1/*
2 * Xilinx Video IP Composite Device
3 *
4 * Copyright (C) 2013-2015 Ideas on Board
5 * Copyright (C) 2013-2015 Xilinx, Inc.
6 *
7 * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
8 * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef __XILINX_VIPP_H__
16#define __XILINX_VIPP_H__
17
18#include <linux/list.h>
19#include <linux/mutex.h>
20#include <media/media-device.h>
21#include <media/v4l2-async.h>
22#include <media/v4l2-ctrls.h>
23#include <media/v4l2-device.h>
24
25/**
26 * struct xvip_composite_device - Xilinx Video IP device structure
27 * @v4l2_dev: V4L2 device
28 * @media_dev: media device
29 * @dev: (OF) device
30 * @notifier: V4L2 asynchronous subdevs notifier
31 * @entities: entities in the graph as a list of xvip_graph_entity
32 * @num_subdevs: number of subdevs in the pipeline
33 * @dmas: list of DMA channels at the pipeline output and input
34 * @v4l2_caps: V4L2 capabilities of the whole device (see VIDIOC_QUERYCAP)
35 */
36struct xvip_composite_device {
37 struct v4l2_device v4l2_dev;
38 struct media_device media_dev;
39 struct device *dev;
40
41 struct v4l2_async_notifier notifier;
42 struct list_head entities;
43 unsigned int num_subdevs;
44
45 struct list_head dmas;
46 u32 v4l2_caps;
47};
48
49#endif /* __XILINX_VIPP_H__ */