Re: [PATCH v2 11/12] intel-ipu3: Add imgu v4l2 driver
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
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