Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Laurent Pinchart and committed by
Mauro Carvalho Chehab
df330515 c9bca8b3

+2308
+35
Documentation/devicetree/bindings/media/xilinx/video.txt
··· 1 + DT bindings for Xilinx video IP cores 2 + ------------------------------------- 3 + 4 + Xilinx video IP cores process video streams by acting as video sinks and/or 5 + sources. They are connected by links through their input and output ports, 6 + creating a video pipeline. 7 + 8 + Each video IP core is represented by an AMBA bus child node in the device 9 + tree using bindings documented in this directory. Connections between the IP 10 + cores are represented as defined in ../video-interfaces.txt. 11 + 12 + The whole pipeline is represented by an AMBA bus child node in the device 13 + tree using bindings documented in ./xlnx,video.txt. 14 + 15 + Common properties 16 + ----------------- 17 + 18 + The following properties are common to all Xilinx video IP cores. 19 + 20 + - xlnx,video-format: This property represents a video format transmitted on an 21 + AXI bus between video IP cores, using its VF code as defined in "AXI4-Stream 22 + Video IP and System Design Guide" [UG934]. How the format relates to the IP 23 + core is decribed in the IP core bindings documentation. 24 + 25 + - xlnx,video-width: This property qualifies the video format with the sample 26 + width expressed as a number of bits per pixel component. All components must 27 + use the same width. 28 + 29 + - xlnx,cfa-pattern: When the video format is set to Mono/Sensor, this property 30 + describes the sensor's color filter array pattern. Supported values are 31 + "bggr", "gbrg", "grbg", "rggb" and "mono". If not specified, the pattern 32 + defaults to "mono". 33 + 34 + 35 + [UG934] http://www.xilinx.com/support/documentation/ip_documentation/axi_videoip/v1_0/ug934_axi_videoIP.pdf
+55
Documentation/devicetree/bindings/media/xilinx/xlnx,video.txt
··· 1 + Xilinx Video IP Pipeline (VIPP) 2 + ------------------------------- 3 + 4 + General concept 5 + --------------- 6 + 7 + Xilinx video IP pipeline processes video streams through one or more Xilinx 8 + video IP cores. Each video IP core is represented as documented in video.txt 9 + and IP core specific documentation, xlnx,v-*.txt, in this directory. The DT 10 + node of the VIPP represents as a top level node of the pipeline and defines 11 + mappings between DMAs and the video IP cores. 12 + 13 + Required properties: 14 + 15 + - compatible: Must be "xlnx,video". 16 + 17 + - dmas, dma-names: List of one DMA specifier and identifier string (as defined 18 + in Documentation/devicetree/bindings/dma/dma.txt) per port. Each port 19 + requires a DMA channel with the identifier string set to "port" followed by 20 + the port index. 21 + 22 + - ports: Video port, using the DT bindings defined in ../video-interfaces.txt. 23 + 24 + Required port properties: 25 + 26 + - direction: should be either "input" or "output" depending on the direction 27 + of stream. 28 + 29 + Example: 30 + 31 + video_cap { 32 + compatible = "xlnx,video"; 33 + dmas = <&vdma_1 1>, <&vdma_3 1>; 34 + dma-names = "port0", "port1"; 35 + 36 + ports { 37 + #address-cells = <1>; 38 + #size-cells = <0>; 39 + 40 + port@0 { 41 + reg = <0>; 42 + direction = "input"; 43 + vcap0_in0: endpoint { 44 + remote-endpoint = <&scaler0_out>; 45 + }; 46 + }; 47 + port@1 { 48 + reg = <1>; 49 + direction = "input"; 50 + vcap0_in1: endpoint { 51 + remote-endpoint = <&switch_out1>; 52 + }; 53 + }; 54 + }; 55 + };
+9
MAINTAINERS
··· 10818 10818 S: Maintained 10819 10819 F: drivers/tty/serial/uartlite.c 10820 10820 10821 + XILINX VIDEO IP CORES 10822 + M: Hyun Kwon <hyun.kwon@xilinx.com> 10823 + M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 10824 + L: linux-media@vger.kernel.org 10825 + T: git git://linuxtv.org/media_tree.git 10826 + S: Supported 10827 + F: Documentation/devicetree/bindings/media/xilinx/ 10828 + F: drivers/media/platform/xilinx/ 10829 + 10821 10830 XILLYBUS DRIVER 10822 10831 M: Eli Billauer <eli.billauer@gmail.com> 10823 10832 L: linux-kernel@vger.kernel.org
+1
drivers/media/platform/Kconfig
··· 118 118 source "drivers/media/platform/exynos4-is/Kconfig" 119 119 source "drivers/media/platform/s5p-tv/Kconfig" 120 120 source "drivers/media/platform/am437x/Kconfig" 121 + source "drivers/media/platform/xilinx/Kconfig" 121 122 122 123 endif # V4L_PLATFORM_DRIVERS 123 124
+2
drivers/media/platform/Makefile
··· 48 48 49 49 obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ 50 50 51 + obj-$(CONFIG_VIDEO_XILINX) += xilinx/ 52 + 51 53 ccflags-y += -I$(srctree)/drivers/media/i2c
+10
drivers/media/platform/xilinx/Kconfig
··· 1 + config 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 + 8 + if VIDEO_XILINX 9 + 10 + endif #VIDEO_XILINX
+3
drivers/media/platform/xilinx/Makefile
··· 1 + xilinx-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o 2 + 3 + obj-$(CONFIG_VIDEO_XILINX) += xilinx-video.o
+766
drivers/media/platform/xilinx/xilinx-dma.c
··· 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 + 46 + static struct v4l2_subdev * 47 + xvip_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 + 62 + static 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 + */ 101 + static 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 + */ 156 + static 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 + 174 + done: 175 + mutex_unlock(&pipe->lock); 176 + return ret; 177 + } 178 + 179 + static 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 + 220 + static 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 + */ 232 + static 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 + */ 253 + static 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 + 272 + done: 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 + */ 287 + struct 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 + 295 + static 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 + 311 + static int 312 + xvip_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 + 330 + static 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 + 340 + static 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 + 386 + static 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 + 430 + error_stop: 431 + media_entity_pipeline_stop(&dma->video.entity); 432 + 433 + error: 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 + 445 + static 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 + 470 + static 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 + 484 + static int 485 + xvip_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 + */ 511 + static int 512 + xvip_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 + 527 + static int 528 + xvip_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 + 538 + static 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 + 589 + static int 590 + xvip_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 + 599 + static int 600 + xvip_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 + 617 + static 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 + 640 + static 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 + 653 + int 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 + 746 + error: 747 + xvip_dma_cleanup(dma); 748 + return ret; 749 + } 750 + 751 + void 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 + }
+109
drivers/media/platform/xilinx/xilinx-dma.h
··· 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 + 27 + struct dma_chan; 28 + struct xvip_composite_device; 29 + struct 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 + */ 40 + struct 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 + 51 + static 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 + */ 77 + struct 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 + 105 + int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, 106 + enum v4l2_buf_type type, unsigned int port); 107 + void xvip_dma_cleanup(struct xvip_dma *dma); 108 + 109 + #endif /* __XILINX_VIP_DMA_H__ */
+323
drivers/media/platform/xilinx/xilinx-vip.c
··· 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 + 29 + static 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 + */ 56 + const 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 + } 69 + EXPORT_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 + */ 79 + const 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 + } 92 + EXPORT_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 + */ 105 + const 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 + } 139 + EXPORT_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 + */ 150 + void 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 + } 158 + EXPORT_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 + */ 177 + void 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 + } 185 + EXPORT_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 + */ 197 + void 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 + } 206 + EXPORT_SYMBOL_GPL(xvip_clr_and_set); 207 + 208 + int 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 + } 225 + EXPORT_SYMBOL_GPL(xvip_init_resources); 226 + 227 + void xvip_cleanup_resources(struct xvip_device *xvip) 228 + { 229 + clk_disable_unprepare(xvip->clk); 230 + } 231 + EXPORT_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 + */ 251 + int 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 + } 272 + EXPORT_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 + */ 289 + int 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 + } 323 + EXPORT_SYMBOL_GPL(xvip_enum_frame_size);
+238
drivers/media/platform/xilinx/xilinx-vip.h
··· 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 + 21 + struct 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 + */ 98 + struct 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 + */ 116 + struct 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 + 126 + const struct xvip_video_format *xvip_get_format_by_code(unsigned int code); 127 + const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc); 128 + const struct xvip_video_format *xvip_of_get_format(struct device_node *node); 129 + void xvip_set_format_size(struct v4l2_mbus_framefmt *format, 130 + const struct v4l2_subdev_format *fmt); 131 + int xvip_enum_mbus_code(struct v4l2_subdev *subdev, 132 + struct v4l2_subdev_pad_config *cfg, 133 + struct v4l2_subdev_mbus_code_enum *code); 134 + int xvip_enum_frame_size(struct v4l2_subdev *subdev, 135 + struct v4l2_subdev_pad_config *cfg, 136 + struct v4l2_subdev_frame_size_enum *fse); 137 + 138 + static inline u32 xvip_read(struct xvip_device *xvip, u32 addr) 139 + { 140 + return ioread32(xvip->iomem + addr); 141 + } 142 + 143 + static inline void xvip_write(struct xvip_device *xvip, u32 addr, u32 value) 144 + { 145 + iowrite32(value, xvip->iomem + addr); 146 + } 147 + 148 + static 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 + 153 + static 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 + 158 + void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set); 159 + void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set); 160 + 161 + int xvip_init_resources(struct xvip_device *xvip); 162 + void xvip_cleanup_resources(struct xvip_device *xvip); 163 + 164 + static inline void xvip_reset(struct xvip_device *xvip) 165 + { 166 + xvip_write(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_RESET); 167 + } 168 + 169 + static 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 + 175 + static inline void xvip_stop(struct xvip_device *xvip) 176 + { 177 + xvip_clr(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_ENABLE); 178 + } 179 + 180 + static 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 + 186 + static 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 + 193 + static 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 + 201 + static 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 + 213 + static 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 + 218 + static 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 + 223 + static 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__ */
+669
drivers/media/platform/xilinx/xilinx-vipp.c
··· 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 + */ 41 + struct 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 + 54 + static struct xvip_graph_entity * 55 + xvip_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 + 68 + static 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 + 175 + static struct xvip_dma * 176 + xvip_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 + 188 + static 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 + 289 + static 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 + 317 + static 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 + 348 + static 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 + 400 + static 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 + 424 + static 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 + 465 + static 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 + 486 + static 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 + 506 + static 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 + 559 + done: 560 + if (ret < 0) 561 + xvip_graph_cleanup(xdev); 562 + 563 + return ret; 564 + } 565 + 566 + /* ----------------------------------------------------------------------------- 567 + * Media Controller and V4L2 568 + */ 569 + 570 + static 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 + 576 + static 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 + 608 + static 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 + 635 + error: 636 + xvip_composite_v4l2_cleanup(xdev); 637 + return ret; 638 + } 639 + 640 + static 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 + 650 + static const struct of_device_id xvip_composite_of_id_table[] = { 651 + { .compatible = "xlnx,video" }, 652 + { } 653 + }; 654 + MODULE_DEVICE_TABLE(of, xvip_composite_of_id_table); 655 + 656 + static 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 + 665 + module_platform_driver(xvip_composite_driver); 666 + 667 + MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); 668 + MODULE_DESCRIPTION("Xilinx Video IP Composite Driver"); 669 + MODULE_LICENSE("GPL v2");
+49
drivers/media/platform/xilinx/xilinx-vipp.h
··· 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 + */ 36 + struct 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__ */
+39
include/dt-bindings/media/xilinx-vip.h
··· 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 __DT_BINDINGS_MEDIA_XILINX_VIP_H__ 16 + #define __DT_BINDINGS_MEDIA_XILINX_VIP_H__ 17 + 18 + /* 19 + * Video format codes as defined in "AXI4-Stream Video IP and System Design 20 + * Guide". 21 + */ 22 + #define XVIP_VF_YUV_422 0 23 + #define XVIP_VF_YUV_444 1 24 + #define XVIP_VF_RBG 2 25 + #define XVIP_VF_YUV_420 3 26 + #define XVIP_VF_YUVA_422 4 27 + #define XVIP_VF_YUVA_444 5 28 + #define XVIP_VF_RGBA 6 29 + #define XVIP_VF_YUVA_420 7 30 + #define XVIP_VF_YUVD_422 8 31 + #define XVIP_VF_YUVD_444 9 32 + #define XVIP_VF_RGBD 10 33 + #define XVIP_VF_YUVD_420 11 34 + #define XVIP_VF_MONO_SENSOR 12 35 + #define XVIP_VF_CUSTOM2 13 36 + #define XVIP_VF_CUSTOM3 14 37 + #define XVIP_VF_CUSTOM4 15 38 + 39 + #endif /* __DT_BINDINGS_MEDIA_XILINX_VIP_H__ */