Re: [PATCH v2 11/12] intel-ipu3: Add imgu v4l2 driver

2017-06-16 Thread Sakari Ailus
Hi Yong,

On Wed, Jun 14, 2017 at 05:19:26PM -0500, Yong Zhi wrote:
> +int ipu3_v4l2_register(struct imgu_device *dev)
> +{
> + struct ipu3_mem2mem2_device *m2m2 = >mem2mem2;
> + int i, r;
> +
> + /* Initialize miscellaneous variables */
> + m2m2->streaming = false;
> + m2m2->v4l2_file_ops = ipu3_v4l2_fops;
> +
> + /* Set up media device */
> + m2m2->media_dev.dev = m2m2->dev;
> + strlcpy(m2m2->media_dev.model, m2m2->model,
> + sizeof(m2m2->media_dev.model));
> + snprintf(m2m2->media_dev.bus_info, sizeof(m2m2->media_dev.bus_info),
> +  "%s", dev_name(m2m2->dev));
> + m2m2->media_dev.driver_version = KERNEL_VERSION(4, 12, 0);
> + m2m2->media_dev.hw_revision = 0;
> + media_device_init(>media_dev);
> + r = media_device_register(>media_dev);
> + if (r) {
> + dev_err(m2m2->dev, "failed to register media device (%d)\n", r);
> + goto fail_media_dev;
> + }
> +
> + /* Set up v4l2 device */
> + m2m2->v4l2_dev.mdev = >media_dev;
> + m2m2->v4l2_dev.ctrl_handler = m2m2->ctrl_handler;
> + r = v4l2_device_register(m2m2->dev, >v4l2_dev);
> + if (r) {
> + dev_err(m2m2->dev, "failed to register V4L2 device (%d)\n", r);
> + goto fail_v4l2_dev;
> + }
> +
> + /* Initialize subdev media entity */
> + m2m2->subdev_pads = kzalloc(sizeof(*m2m2->subdev_pads) *
> + m2m2->num_nodes, GFP_KERNEL);
> + if (!m2m2->subdev_pads) {
> + r = -ENOMEM;
> + goto fail_subdev_pads;
> + }
> + r = media_entity_pads_init(>subdev.entity, m2m2->num_nodes,
> +m2m2->subdev_pads);
> + if (r) {
> + dev_err(m2m2->dev,
> + "failed initialize subdev media entity (%d)\n", r);
> + goto fail_media_entity;
> + }
> + m2m2->subdev.entity.ops = _media_ops;
> + for (i = 0; i < m2m2->num_nodes; i++) {
> + m2m2->subdev_pads[i].flags = m2m2->nodes[i].output ?
> + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
> + }
> +
> + /* Initialize subdev */
> + v4l2_subdev_init(>subdev, _subdev_ops);
> + m2m2->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
> + snprintf(m2m2->subdev.name, sizeof(m2m2->subdev.name),
> +  "%s", m2m2->name);
> + v4l2_set_subdevdata(>subdev, m2m2);
> + m2m2->subdev.ctrl_handler = m2m2->ctrl_handler;
> + r = v4l2_device_register_subdev(>v4l2_dev, >subdev);
> + if (r) {
> + dev_err(m2m2->dev, "failed initialize subdev (%d)\n", r);
> + goto fail_subdev;
> + }
> + r = v4l2_device_register_subdev_nodes(>v4l2_dev);
> + if (r) {
> + dev_err(m2m2->dev, "failed to register subdevs (%d)\n", r);
> + goto fail_subdevs;
> + }
> +
> + /* Create video nodes and links */
> + for (i = 0; i < m2m2->num_nodes; i++) {
> + struct imgu_video_device *node = >nodes[i];
> + struct video_device *vdev = >vdev;
> + struct vb2_queue *vbq = >vbq;
> + struct v4l2_mbus_framefmt *fmt;
> + u32 flags;
> +
> + /* Initialize miscellaneous variables */
> + mutex_init(>lock);
> + INIT_LIST_HEAD(>buffers);
> +
> + /* Initialize formats to default values */
> + fmt = >pad_fmt;
> + fmt->width = 352;
> + fmt->height = 288;
> + fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
> + fmt->field = V4L2_FIELD_NONE;
> + fmt->colorspace = V4L2_COLORSPACE_RAW;
> + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> + fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
> + fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
> + fmt = >pad_fmt;
> + node->vdev_fmt.type = node->output ?
> + V4L2_BUF_TYPE_VIDEO_OUTPUT :
> + V4L2_BUF_TYPE_VIDEO_CAPTURE;
> + node->vdev_fmt.fmt.pix.width = fmt->width;
> + node->vdev_fmt.fmt.pix.height = fmt->height;
> + node->vdev_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
> + node->vdev_fmt.fmt.pix.field = fmt->field;
> + node->vdev_fmt.fmt.pix.bytesperline = fmt->width * 2;
> + node->vdev_fmt.fmt.pix.sizeimage =
> + node->vdev_fmt.fmt.pix.bytesperline * fmt->height;
> + node->vdev_fmt.fmt.pix.colorspace = fmt->colorspace;
> + node->vdev_fmt.fmt.pix.priv = 0;
> + node->vdev_fmt.fmt.pix.flags = 0;
> + node->vdev_fmt.fmt.pix.ycbcr_enc = fmt->ycbcr_enc;
> + node->vdev_fmt.fmt.pix.quantization = fmt->quantization;
> + node->vdev_fmt.fmt.pix.xfer_func = fmt->xfer_func;
> +
> + /* Initialize media entities */
> + r = media_entity_pads_init(>entity, 1, >vdev_pad);
> + if (r) {
> +   

[PATCH v2 11/12] intel-ipu3: Add imgu v4l2 driver

2017-06-14 Thread Yong Zhi
ipu3 imgu video device based on v4l2, vb2 and
media controller framework.

Signed-off-by: Yong Zhi 
---
 drivers/media/pci/intel/ipu3/ipu3-v4l2.c | 727 +++
 1 file changed, 727 insertions(+)
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-v4l2.c

diff --git a/drivers/media/pci/intel/ipu3/ipu3-v4l2.c 
b/drivers/media/pci/intel/ipu3/ipu3-v4l2.c
new file mode 100644
index 000..c9493dc
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-v4l2.c
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+#include "ipu3.h"
+
+/ v4l2_subdev_ops /
+
+static int ipu3_subdev_s_stream(struct v4l2_subdev *sd, int enable)
+{
+   struct ipu3_mem2mem2_device *m2m2 =
+   container_of(sd, struct ipu3_mem2mem2_device, subdev);
+   int r = 0;
+
+   if (m2m2->ops && m2m2->ops->s_stream)
+   r = m2m2->ops->s_stream(m2m2, enable);
+
+   if (!r)
+   m2m2->streaming = enable;
+
+   return r;
+}
+
+static int ipu3_subdev_get_fmt(struct v4l2_subdev *sd,
+  struct v4l2_subdev_pad_config *cfg,
+  struct v4l2_subdev_format *fmt)
+{
+   struct ipu3_mem2mem2_device *m2m2 =
+   container_of(sd, struct ipu3_mem2mem2_device, subdev);
+   struct v4l2_mbus_framefmt *mf;
+   u32 pad = fmt->pad;
+
+   if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+   fmt->format = m2m2->nodes[pad].pad_fmt;
+   } else {
+   mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+   fmt->format = *mf;
+   }
+
+   return 0;
+}
+
+static int ipu3_subdev_set_fmt(struct v4l2_subdev *sd,
+  struct v4l2_subdev_pad_config *cfg,
+  struct v4l2_subdev_format *fmt)
+{
+   struct ipu3_mem2mem2_device *m2m2 =
+   container_of(sd, struct ipu3_mem2mem2_device, subdev);
+   struct v4l2_mbus_framefmt *mf;
+   u32 pad = fmt->pad;
+
+   if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+   mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+   else
+   mf = >nodes[pad].pad_fmt;
+
+   /* Clamp the w and h based on the hardware capabilities */
+   if (m2m2->subdev_pads[pad].flags & MEDIA_PAD_FL_SOURCE) {
+
+   fmt->format.width = clamp(fmt->format.width,
+   IPU3_OUTPUT_MIN_WIDTH,
+   IPU3_OUTPUT_MAX_WIDTH);
+   fmt->format.height = clamp(fmt->format.height,
+   IPU3_OUTPUT_MIN_HEIGHT,
+   IPU3_OUTPUT_MAX_HEIGHT);
+   } else {
+   fmt->format.width = clamp(fmt->format.width,
+   IPU3_INPUT_MIN_WIDTH,
+   IPU3_INPUT_MAX_WIDTH);
+   fmt->format.height = clamp(fmt->format.height,
+   IPU3_INPUT_MIN_HEIGHT,
+   IPU3_INPUT_MAX_HEIGHT);
+   }
+
+   *mf = fmt->format;
+
+   return 0;
+}
+
+/ media_entity_operations /
+
+static int ipu3_link_setup(struct media_entity *entity,
+const struct media_pad *local,
+const struct media_pad *remote, u32 flags)
+{
+   struct ipu3_mem2mem2_device *m2m2 =
+   container_of(entity, struct ipu3_mem2mem2_device, subdev.entity);
+   u32 pad = local->index;
+
+   WARN_ON(pad >= m2m2->num_nodes);
+
+   m2m2->nodes[pad].enabled = !!(flags & MEDIA_LNK_FL_ENABLED);
+
+   return 0;
+}
+
+/ vb2_ops /
+
+/* Transfer buffer ownership to me */
+static void ipu3_vb2_buf_queue(struct vb2_buffer *vb)
+{
+   struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vb->vb2_queue);
+   struct imgu_device *imgu =
+   container_of(m2m2, struct imgu_device, mem2mem2);
+   struct imgu_video_device *node =
+   container_of(vb->vb2_queue, struct imgu_video_device, vbq);
+   int queue;
+
+   queue = imgu_node_to_queue(node - m2m2->nodes);
+
+   if (queue < 0) {
+   dev_err(>pci_dev->dev, "Invalid imgu node.\n");
+   return;
+   }
+
+   if (queue == IPU3_CSS_QUEUE_PARAMS) {
+   unsigned int