From: Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
To: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Cc: linux-media@vger.kernel.org, linux-sh@vger.kernel.org,
Hans Verkuil <hverkuil@xs4all.nl>,
Sakari Ailus <sakari.ailus@iki.fi>,
Katsuya MATSUBARA <matsu@igel.co.jp>
Subject: Re: [PATCH v4 5/7] v4l: Renesas R-Car VSP1 driver
Date: Wed, 31 Jul 2013 21:02:05 +0000 [thread overview]
Message-ID: <51F97B4D.70305@gmail.com> (raw)
In-Reply-To: <1375285954-32153-6-git-send-email-laurent.pinchart+renesas@ideasonboard.com>
Hi Laurent,
just a few small remarks...
On 07/31/2013 05:52 PM, Laurent Pinchart wrote:
> The VSP1 is a video processing engine that includes a blender, scalers,
> filters and statistics computation. Configurable data path routing logic
> allows ordering the internal blocks in a flexible way.
>
> Due to the configurable nature of the pipeline the driver implements the
> media controller API and doesn't use the V4L2 mem-to-mem framework, even
> though the device usually operates in memory to memory mode.
>
> Only the read pixel formatters, up/down scalers, write pixel formatters
> and LCDC interface are supported at this stage.
>
> Signed-off-by: Laurent Pinchart<laurent.pinchart+renesas@ideasonboard.com>
>
> Changes since v1:
>
> - Updated to the v3.11 media controller API changes
> - Only add the LIF entity to the entities list when the LIF is present
> - Added a MODULE_ALIAS()
> - Fixed file descriptions in comment blocks
> - Removed function prototypes for the unimplemented destroy functions
> - Fixed a typo in the HST register name
> - Fixed format propagation for the UDS entities
> - Added v4l2_capability::device_caps support
> - Prefix the device name with "platform:" in bus_info
> - Zero the v4l2_pix_format priv field in the internal try format handler
> - Use vb2_is_busy() instead of vb2_is_streaming() when setting the
> format
> - Use the vb2_ioctl_* handlers where possible
> - Fix register macros that were missing a n argument
> - Mask unused bits when clearing the interrupt status register
> - Explain why stride alignment to 128 bytes is needed
> - Use the aligned stride value when computing the image size
> - Assorted cosmetic changes
> ---
> drivers/media/platform/Kconfig | 10 +
> drivers/media/platform/Makefile | 2 +
> drivers/media/platform/vsp1/Makefile | 5 +
> drivers/media/platform/vsp1/vsp1.h | 73 ++
> drivers/media/platform/vsp1/vsp1_drv.c | 497 +++++++++++++
> drivers/media/platform/vsp1/vsp1_entity.c | 181 +++++
> drivers/media/platform/vsp1/vsp1_entity.h | 68 ++
> drivers/media/platform/vsp1/vsp1_lif.c | 238 ++++++
> drivers/media/platform/vsp1/vsp1_lif.h | 37 +
> drivers/media/platform/vsp1/vsp1_regs.h | 581 +++++++++++++++
> drivers/media/platform/vsp1/vsp1_rpf.c | 209 ++++++
> drivers/media/platform/vsp1/vsp1_rwpf.c | 124 ++++
> drivers/media/platform/vsp1/vsp1_rwpf.h | 53 ++
> drivers/media/platform/vsp1/vsp1_uds.c | 346 +++++++++
> drivers/media/platform/vsp1/vsp1_uds.h | 40 +
> drivers/media/platform/vsp1/vsp1_video.c | 1135 +++++++++++++++++++++++++++++
> drivers/media/platform/vsp1/vsp1_video.h | 144 ++++
> drivers/media/platform/vsp1/vsp1_wpf.c | 233 ++++++
> include/linux/platform_data/vsp1.h | 25 +
> 19 files changed, 4001 insertions(+)
> create mode 100644 drivers/media/platform/vsp1/Makefile
> create mode 100644 drivers/media/platform/vsp1/vsp1.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_drv.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_entity.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_entity.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_lif.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_lif.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_regs.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_rpf.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_rwpf.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_rwpf.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_uds.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_uds.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_video.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_video.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_wpf.c
> create mode 100644 include/linux/platform_data/vsp1.h
>
[...]
> +/* -----------------------------------------------------------------------------
> + * Platform Driver
> + */
[...]
> +static int vsp1_probe(struct platform_device *pdev)
> +{
> + struct vsp1_device *vsp1;
> + struct resource *irq;
> + struct resource *io;
> + int ret;
> +
> + vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL);
> + if (vsp1 = NULL) {
> + dev_err(&pdev->dev, "failed to allocate private data\n");
k*alloc already log any errors, hence this line could be dropped. I've
seen patches removing such logging.
> + return -ENOMEM;
> + }
> +
> + vsp1->dev =&pdev->dev;
> + mutex_init(&vsp1->lock);
> + INIT_LIST_HEAD(&vsp1->entities);
> +
> + vsp1->pdata = vsp1_get_platform_data(pdev);
> + if (vsp1->pdata = NULL)
> + return -ENODEV;
> +
> + /* I/O, IRQ and clock resources */
> + io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +
> + if (!io || !irq) {
> + dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
> + return -EINVAL;
> + }
> +
> + vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
> + if (IS_ERR((void *)vsp1->mmio)) {
> + dev_err(&pdev->dev, "failed to remap memory resource\n");
Similarly devm_ioremap_resource() already logs any errors, including
checking
if the second argument is valid.
> + return PTR_ERR((void *)vsp1->mmio);
> + }
> +
> + vsp1->clock = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(vsp1->clock)) {
> + dev_err(&pdev->dev, "failed to get clock\n");
> + return PTR_ERR(vsp1->clock);
> + }
> +
> + ret = devm_request_irq(&pdev->dev, irq->start, vsp1_irq_handler,
> + IRQF_SHARED, dev_name(&pdev->dev), vsp1);
> + if (ret< 0) {
> + dev_err(&pdev->dev, "failed to request IRQ\n");
> + return ret;
> + }
> +
> + /* Instanciate entities */
> + ret = vsp1_create_entities(vsp1);
> + if (ret< 0) {
> + dev_err(&pdev->dev, "failed to create entities\n");
> + return ret;
> + }
> +
> + platform_set_drvdata(pdev, vsp1);
> +
> + return 0;
> +}
> +
[...]
> +/* -----------------------------------------------------------------------------
> + * Initialization and Cleanup
> + */
> +
> +struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
> +{
> + struct v4l2_subdev *subdev;
> + struct vsp1_lif *lif;
> + int ret;
> +
> + lif = devm_kzalloc(vsp1->dev, sizeof(*lif), GFP_KERNEL);
> + if (lif = NULL)
> + return ERR_PTR(-ENOMEM);
> +
> + lif->entity.type = VSP1_ENTITY_LIF;
> + lif->entity.id = VI6_DPR_NODE_LIF;
> +
> + ret = vsp1_entity_init(vsp1,&lif->entity, 2);
> + if (ret< 0)
> + return ERR_PTR(ret);
> +
> + /* Initialize the V4L2 subdev. */
> + subdev =&lif->entity.subdev;
> + v4l2_subdev_init(subdev,&lif_ops);
> +
> + subdev->entity.ops =&vsp1_media_ops;
> + subdev->internal_ops =&vsp1_subdev_internal_ops;
> + snprintf(subdev->name, sizeof(subdev->name), "%s lif",
> + dev_name(vsp1->dev));
Using dev_name() looks reasonable since it guarantees the subdev names
are unique. But for dt and non-dt boot you will get different device
names. Not sure if it would have been really an issue though.
> + v4l2_set_subdevdata(subdev, lif);
> + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +
> + vsp1_entity_init_formats(subdev, NULL);
> +
> + return lif;
> +}
[...]
> +static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
> +{
> + struct vsp1_entity *entity;
> + unsigned long flags;
> + int ret;
> +
> + spin_lock_irqsave(&pipe->irqlock, flags);
> + pipe->state = VSP1_PIPELINE_STOPPING;
> + spin_unlock_irqrestore(&pipe->irqlock, flags);
> +
> + ret = wait_event_timeout(pipe->wq, pipe->state = VSP1_PIPELINE_STOPPED,
> + msecs_to_jiffies(500));
> + ret = ret = 0 ? -ETIMEDOUT : 0;
Wouldn't be -ETIME more appropriate ?
#define ETIME 62 /* Timer expired */
...
#define ETIMEDOUT 110 /* Connection timed out */
> + list_for_each_entry(entity,&pipe->entities, list_pipe) {
> + if (entity->route)
> + vsp1_write(entity->vsp1, entity->route,
> + VI6_DPR_NODE_UNUSED);
> +
> + v4l2_subdev_call(&entity->subdev, video, s_stream, 0);
> + }
> +
> + return ret;
> +}
[...]
> +/* -----------------------------------------------------------------------------
> + * videobuf2 Queue Operations
> + */
> +
> +static int
> +vsp1_video_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
> + unsigned int *nbuffers, unsigned int *nplanes,
> + unsigned int sizes[], void *alloc_ctxs[])
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vq);
> + struct v4l2_pix_format_mplane *format =&video->format;
> + unsigned int i;
If you don't support VIDIOC_CREATE_BUFS ioctl then there should probably
be at least something like:
if (fmt)
return -EINVAL;
But it's likely better to add proper handling of 'fmt' right away.
> + *nplanes = format->num_planes;
> +
> + for (i = 0; i< format->num_planes; ++i) {
> + sizes[i] = format->plane_fmt[i].sizeimage;
> + alloc_ctxs[i] = video->alloc_ctx;
> + }
> +
> + return 0;
> +}
> +
> +static int vsp1_video_buffer_prepare(struct vb2_buffer *vb)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue);
> + struct vsp1_video_buffer *buf = to_vsp1_video_buffer(vb);
> + unsigned int i;
> +
> + buf->video = video;
> +
> + for (i = 0; i< vb->num_planes; ++i) {
> + buf->addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
> + buf->length[i] = vb2_plane_size(vb, i);
> + }
> +
> + return 0;
> +}
> +
> +static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue);
> + struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
> + struct vsp1_video_buffer *buf = to_vsp1_video_buffer(vb);
> + unsigned long flags;
> + bool empty;
> +
> + spin_lock_irqsave(&video->irqlock, flags);
> + empty = list_empty(&video->irqqueue);
> + list_add_tail(&buf->queue,&video->irqqueue);
> + spin_unlock_irqrestore(&video->irqlock, flags);
> +
> + if (!empty)
> + return;
> +
> + spin_lock_irqsave(&pipe->irqlock, flags);
> +
> + video->ops->queue(video, buf);
> + pipe->buffers_ready |= 1<< video->pipe_index;
> +
> + if (vb2_is_streaming(&video->queue)&&
> + vsp1_pipeline_ready(pipe))
> + vsp1_pipeline_run(pipe);
> +
> + spin_unlock_irqrestore(&pipe->irqlock, flags);
> +}
> +
> +static void vsp1_video_wait_prepare(struct vb2_queue *vq)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vq);
> +
> + mutex_unlock(&video->lock);
> +}
> +
> +static void vsp1_video_wait_finish(struct vb2_queue *vq)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vq);
> +
> + mutex_lock(&video->lock);
> +}
> +
> +static void vsp1_entity_route_setup(struct vsp1_entity *source)
> +{
> + struct vsp1_entity *sink;
> +
> + if (source->route = 0)
> + return;
> +
> + sink = container_of(source->sink, struct vsp1_entity, subdev.entity);
> + vsp1_write(source->vsp1, source->route, sink->id);
> +}
> +
> +static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vq);
> + struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
> + struct vsp1_entity *entity;
> + unsigned long flags;
> + int ret;
> +
> + mutex_lock(&pipe->lock);
> + if (pipe->stream_count = pipe->num_video - 1) {
> + list_for_each_entry(entity,&pipe->entities, list_pipe) {
> + vsp1_entity_route_setup(entity);
> +
> + ret = v4l2_subdev_call(&entity->subdev, video,
> + s_stream, 1);
> + if (ret< 0) {
> + mutex_unlock(&pipe->lock);
> + return ret;
> + }
> + }
> + }
> +
> + pipe->stream_count++;
> + mutex_unlock(&pipe->lock);
> +
> + spin_lock_irqsave(&pipe->irqlock, flags);
> + if (vsp1_pipeline_ready(pipe))
> + vsp1_pipeline_run(pipe);
> + spin_unlock_irqrestore(&pipe->irqlock, flags);
> +
> + return 0;
> +}
> +
> +static int vsp1_video_stop_streaming(struct vb2_queue *vq)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vq);
> + struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
> + unsigned long flags;
> + int ret;
> +
> + mutex_lock(&pipe->lock);
> + if (--pipe->stream_count = 0) {
> + /* Stop the pipeline. */
> + ret = vsp1_pipeline_stop(pipe);
> + if (ret = -ETIMEDOUT)
ETIME ?
> + dev_err(video->vsp1->dev, "pipeline stop timeout\n");
> + }
> + mutex_unlock(&pipe->lock);
> +
> + vsp1_pipeline_cleanup(pipe);
> + media_entity_pipeline_stop(&video->video.entity);
> +
> + /* Remove all buffers from the IRQ queue. */
> + spin_lock_irqsave(&video->irqlock, flags);
> + INIT_LIST_HEAD(&video->irqqueue);
> + spin_unlock_irqrestore(&video->irqlock, flags);
> +
> + return 0;
> +}
> +
> +static struct vb2_ops vsp1_video_queue_qops = {
> + .queue_setup = vsp1_video_queue_setup,
> + .buf_prepare = vsp1_video_buffer_prepare,
> + .buf_queue = vsp1_video_buffer_queue,
> + .wait_prepare = vsp1_video_wait_prepare,
> + .wait_finish = vsp1_video_wait_finish,
> + .start_streaming = vsp1_video_start_streaming,
> + .stop_streaming = vsp1_video_stop_streaming,
> +};
> +
> +/* -----------------------------------------------------------------------------
> + * V4L2 ioctls
> + */
[...]
> +static int __vsp1_video_try_format(struct vsp1_video *video,
> + struct v4l2_pix_format_mplane *pix,
> + const struct vsp1_format_info **fmtinfo)
> +{
> + const struct vsp1_format_info *info;
> + unsigned int width = pix->width;
> + unsigned int height = pix->height;
> + unsigned int i;
> +
> + /* Retrieve format information and select the default format if the
> + * requested format isn't supported.
> + */
Nitpicking: Isn't proper multi-line comment style
/*
* Retrieve format information and select the default format if the
* requested format isn't supported.
*/
? In fact the media subsystem code is pretty messy WRT that detail.
> + info = vsp1_get_format_info(pix->pixelformat);
> + if (info = NULL)
> + info = vsp1_get_format_info(VSP1_VIDEO_DEF_FORMAT);
> +
> + pix->pixelformat = info->fourcc;
> + pix->colorspace = V4L2_COLORSPACE_SRGB;
> + pix->field = V4L2_FIELD_NONE;
> + memset(pix->reserved, 0, sizeof(pix->reserved));
> +
> + /* Align the width and height for YUV 4:2:2 and 4:2:0 formats. */
> + width = round_down(width, info->hsub);
> + height = round_down(height, info->vsub);
> +
> + /* Clamp the width and height. */
> + pix->width = clamp(width, VSP1_VIDEO_MIN_WIDTH, VSP1_VIDEO_MAX_WIDTH);
> + pix->height = clamp(height, VSP1_VIDEO_MIN_HEIGHT,
> + VSP1_VIDEO_MAX_HEIGHT);
> +
> + /* Compute and clamp the stride and image size. While not documented in
> + * the datasheet, strides not aligned to a multiple of 128 bytes result
> + * in image corruption.
> + */
> + for (i = 0; i< max(info->planes, 2U); ++i) {
> + unsigned int hsub = i> 0 ? info->hsub : 1;
> + unsigned int vsub = i> 0 ? info->vsub : 1;
> + unsigned int align = 128;
> + unsigned int bpl;
> +
> + bpl = clamp_t(unsigned int, pix->plane_fmt[i].bytesperline,
> + pix->width / hsub * info->bpp[i] / 8,
> + round_down(65535U, align));
> +
> + pix->plane_fmt[i].bytesperline = round_up(bpl, align);
> + pix->plane_fmt[i].sizeimage = pix->plane_fmt[i].bytesperline
> + * pix->height / vsub;
> + }
> +
> + if (info->planes = 3) {
> + /* The second and third planes must have the same stride. */
> + pix->plane_fmt[2].bytesperline = pix->plane_fmt[1].bytesperline;
> + pix->plane_fmt[2].sizeimage = pix->plane_fmt[1].sizeimage;
> + }
> +
> + pix->num_planes = info->planes;
> +
> + if (fmtinfo)
> + *fmtinfo = info;
> +
> + return 0;
> +}
> +
Regards,
Sylwester
WARNING: multiple messages have this Message-ID (diff)
From: Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
To: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Cc: linux-media@vger.kernel.org, linux-sh@vger.kernel.org,
Hans Verkuil <hverkuil@xs4all.nl>,
Sakari Ailus <sakari.ailus@iki.fi>,
Katsuya MATSUBARA <matsu@igel.co.jp>
Subject: Re: [PATCH v4 5/7] v4l: Renesas R-Car VSP1 driver
Date: Wed, 31 Jul 2013 23:02:05 +0200 [thread overview]
Message-ID: <51F97B4D.70305@gmail.com> (raw)
In-Reply-To: <1375285954-32153-6-git-send-email-laurent.pinchart+renesas@ideasonboard.com>
Hi Laurent,
just a few small remarks...
On 07/31/2013 05:52 PM, Laurent Pinchart wrote:
> The VSP1 is a video processing engine that includes a blender, scalers,
> filters and statistics computation. Configurable data path routing logic
> allows ordering the internal blocks in a flexible way.
>
> Due to the configurable nature of the pipeline the driver implements the
> media controller API and doesn't use the V4L2 mem-to-mem framework, even
> though the device usually operates in memory to memory mode.
>
> Only the read pixel formatters, up/down scalers, write pixel formatters
> and LCDC interface are supported at this stage.
>
> Signed-off-by: Laurent Pinchart<laurent.pinchart+renesas@ideasonboard.com>
>
> Changes since v1:
>
> - Updated to the v3.11 media controller API changes
> - Only add the LIF entity to the entities list when the LIF is present
> - Added a MODULE_ALIAS()
> - Fixed file descriptions in comment blocks
> - Removed function prototypes for the unimplemented destroy functions
> - Fixed a typo in the HST register name
> - Fixed format propagation for the UDS entities
> - Added v4l2_capability::device_caps support
> - Prefix the device name with "platform:" in bus_info
> - Zero the v4l2_pix_format priv field in the internal try format handler
> - Use vb2_is_busy() instead of vb2_is_streaming() when setting the
> format
> - Use the vb2_ioctl_* handlers where possible
> - Fix register macros that were missing a n argument
> - Mask unused bits when clearing the interrupt status register
> - Explain why stride alignment to 128 bytes is needed
> - Use the aligned stride value when computing the image size
> - Assorted cosmetic changes
> ---
> drivers/media/platform/Kconfig | 10 +
> drivers/media/platform/Makefile | 2 +
> drivers/media/platform/vsp1/Makefile | 5 +
> drivers/media/platform/vsp1/vsp1.h | 73 ++
> drivers/media/platform/vsp1/vsp1_drv.c | 497 +++++++++++++
> drivers/media/platform/vsp1/vsp1_entity.c | 181 +++++
> drivers/media/platform/vsp1/vsp1_entity.h | 68 ++
> drivers/media/platform/vsp1/vsp1_lif.c | 238 ++++++
> drivers/media/platform/vsp1/vsp1_lif.h | 37 +
> drivers/media/platform/vsp1/vsp1_regs.h | 581 +++++++++++++++
> drivers/media/platform/vsp1/vsp1_rpf.c | 209 ++++++
> drivers/media/platform/vsp1/vsp1_rwpf.c | 124 ++++
> drivers/media/platform/vsp1/vsp1_rwpf.h | 53 ++
> drivers/media/platform/vsp1/vsp1_uds.c | 346 +++++++++
> drivers/media/platform/vsp1/vsp1_uds.h | 40 +
> drivers/media/platform/vsp1/vsp1_video.c | 1135 +++++++++++++++++++++++++++++
> drivers/media/platform/vsp1/vsp1_video.h | 144 ++++
> drivers/media/platform/vsp1/vsp1_wpf.c | 233 ++++++
> include/linux/platform_data/vsp1.h | 25 +
> 19 files changed, 4001 insertions(+)
> create mode 100644 drivers/media/platform/vsp1/Makefile
> create mode 100644 drivers/media/platform/vsp1/vsp1.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_drv.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_entity.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_entity.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_lif.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_lif.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_regs.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_rpf.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_rwpf.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_rwpf.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_uds.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_uds.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_video.c
> create mode 100644 drivers/media/platform/vsp1/vsp1_video.h
> create mode 100644 drivers/media/platform/vsp1/vsp1_wpf.c
> create mode 100644 include/linux/platform_data/vsp1.h
>
[...]
> +/* -----------------------------------------------------------------------------
> + * Platform Driver
> + */
[...]
> +static int vsp1_probe(struct platform_device *pdev)
> +{
> + struct vsp1_device *vsp1;
> + struct resource *irq;
> + struct resource *io;
> + int ret;
> +
> + vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL);
> + if (vsp1 == NULL) {
> + dev_err(&pdev->dev, "failed to allocate private data\n");
k*alloc already log any errors, hence this line could be dropped. I've
seen patches removing such logging.
> + return -ENOMEM;
> + }
> +
> + vsp1->dev =&pdev->dev;
> + mutex_init(&vsp1->lock);
> + INIT_LIST_HEAD(&vsp1->entities);
> +
> + vsp1->pdata = vsp1_get_platform_data(pdev);
> + if (vsp1->pdata == NULL)
> + return -ENODEV;
> +
> + /* I/O, IRQ and clock resources */
> + io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +
> + if (!io || !irq) {
> + dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
> + return -EINVAL;
> + }
> +
> + vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
> + if (IS_ERR((void *)vsp1->mmio)) {
> + dev_err(&pdev->dev, "failed to remap memory resource\n");
Similarly devm_ioremap_resource() already logs any errors, including
checking
if the second argument is valid.
> + return PTR_ERR((void *)vsp1->mmio);
> + }
> +
> + vsp1->clock = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(vsp1->clock)) {
> + dev_err(&pdev->dev, "failed to get clock\n");
> + return PTR_ERR(vsp1->clock);
> + }
> +
> + ret = devm_request_irq(&pdev->dev, irq->start, vsp1_irq_handler,
> + IRQF_SHARED, dev_name(&pdev->dev), vsp1);
> + if (ret< 0) {
> + dev_err(&pdev->dev, "failed to request IRQ\n");
> + return ret;
> + }
> +
> + /* Instanciate entities */
> + ret = vsp1_create_entities(vsp1);
> + if (ret< 0) {
> + dev_err(&pdev->dev, "failed to create entities\n");
> + return ret;
> + }
> +
> + platform_set_drvdata(pdev, vsp1);
> +
> + return 0;
> +}
> +
[...]
> +/* -----------------------------------------------------------------------------
> + * Initialization and Cleanup
> + */
> +
> +struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
> +{
> + struct v4l2_subdev *subdev;
> + struct vsp1_lif *lif;
> + int ret;
> +
> + lif = devm_kzalloc(vsp1->dev, sizeof(*lif), GFP_KERNEL);
> + if (lif == NULL)
> + return ERR_PTR(-ENOMEM);
> +
> + lif->entity.type = VSP1_ENTITY_LIF;
> + lif->entity.id = VI6_DPR_NODE_LIF;
> +
> + ret = vsp1_entity_init(vsp1,&lif->entity, 2);
> + if (ret< 0)
> + return ERR_PTR(ret);
> +
> + /* Initialize the V4L2 subdev. */
> + subdev =&lif->entity.subdev;
> + v4l2_subdev_init(subdev,&lif_ops);
> +
> + subdev->entity.ops =&vsp1_media_ops;
> + subdev->internal_ops =&vsp1_subdev_internal_ops;
> + snprintf(subdev->name, sizeof(subdev->name), "%s lif",
> + dev_name(vsp1->dev));
Using dev_name() looks reasonable since it guarantees the subdev names
are unique. But for dt and non-dt boot you will get different device
names. Not sure if it would have been really an issue though.
> + v4l2_set_subdevdata(subdev, lif);
> + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +
> + vsp1_entity_init_formats(subdev, NULL);
> +
> + return lif;
> +}
[...]
> +static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
> +{
> + struct vsp1_entity *entity;
> + unsigned long flags;
> + int ret;
> +
> + spin_lock_irqsave(&pipe->irqlock, flags);
> + pipe->state = VSP1_PIPELINE_STOPPING;
> + spin_unlock_irqrestore(&pipe->irqlock, flags);
> +
> + ret = wait_event_timeout(pipe->wq, pipe->state == VSP1_PIPELINE_STOPPED,
> + msecs_to_jiffies(500));
> + ret = ret == 0 ? -ETIMEDOUT : 0;
Wouldn't be -ETIME more appropriate ?
#define ETIME 62 /* Timer expired */
...
#define ETIMEDOUT 110 /* Connection timed out */
> + list_for_each_entry(entity,&pipe->entities, list_pipe) {
> + if (entity->route)
> + vsp1_write(entity->vsp1, entity->route,
> + VI6_DPR_NODE_UNUSED);
> +
> + v4l2_subdev_call(&entity->subdev, video, s_stream, 0);
> + }
> +
> + return ret;
> +}
[...]
> +/* -----------------------------------------------------------------------------
> + * videobuf2 Queue Operations
> + */
> +
> +static int
> +vsp1_video_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
> + unsigned int *nbuffers, unsigned int *nplanes,
> + unsigned int sizes[], void *alloc_ctxs[])
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vq);
> + struct v4l2_pix_format_mplane *format =&video->format;
> + unsigned int i;
If you don't support VIDIOC_CREATE_BUFS ioctl then there should probably
be at least something like:
if (fmt)
return -EINVAL;
But it's likely better to add proper handling of 'fmt' right away.
> + *nplanes = format->num_planes;
> +
> + for (i = 0; i< format->num_planes; ++i) {
> + sizes[i] = format->plane_fmt[i].sizeimage;
> + alloc_ctxs[i] = video->alloc_ctx;
> + }
> +
> + return 0;
> +}
> +
> +static int vsp1_video_buffer_prepare(struct vb2_buffer *vb)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue);
> + struct vsp1_video_buffer *buf = to_vsp1_video_buffer(vb);
> + unsigned int i;
> +
> + buf->video = video;
> +
> + for (i = 0; i< vb->num_planes; ++i) {
> + buf->addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
> + buf->length[i] = vb2_plane_size(vb, i);
> + }
> +
> + return 0;
> +}
> +
> +static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vb->vb2_queue);
> + struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
> + struct vsp1_video_buffer *buf = to_vsp1_video_buffer(vb);
> + unsigned long flags;
> + bool empty;
> +
> + spin_lock_irqsave(&video->irqlock, flags);
> + empty = list_empty(&video->irqqueue);
> + list_add_tail(&buf->queue,&video->irqqueue);
> + spin_unlock_irqrestore(&video->irqlock, flags);
> +
> + if (!empty)
> + return;
> +
> + spin_lock_irqsave(&pipe->irqlock, flags);
> +
> + video->ops->queue(video, buf);
> + pipe->buffers_ready |= 1<< video->pipe_index;
> +
> + if (vb2_is_streaming(&video->queue)&&
> + vsp1_pipeline_ready(pipe))
> + vsp1_pipeline_run(pipe);
> +
> + spin_unlock_irqrestore(&pipe->irqlock, flags);
> +}
> +
> +static void vsp1_video_wait_prepare(struct vb2_queue *vq)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vq);
> +
> + mutex_unlock(&video->lock);
> +}
> +
> +static void vsp1_video_wait_finish(struct vb2_queue *vq)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vq);
> +
> + mutex_lock(&video->lock);
> +}
> +
> +static void vsp1_entity_route_setup(struct vsp1_entity *source)
> +{
> + struct vsp1_entity *sink;
> +
> + if (source->route == 0)
> + return;
> +
> + sink = container_of(source->sink, struct vsp1_entity, subdev.entity);
> + vsp1_write(source->vsp1, source->route, sink->id);
> +}
> +
> +static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vq);
> + struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
> + struct vsp1_entity *entity;
> + unsigned long flags;
> + int ret;
> +
> + mutex_lock(&pipe->lock);
> + if (pipe->stream_count == pipe->num_video - 1) {
> + list_for_each_entry(entity,&pipe->entities, list_pipe) {
> + vsp1_entity_route_setup(entity);
> +
> + ret = v4l2_subdev_call(&entity->subdev, video,
> + s_stream, 1);
> + if (ret< 0) {
> + mutex_unlock(&pipe->lock);
> + return ret;
> + }
> + }
> + }
> +
> + pipe->stream_count++;
> + mutex_unlock(&pipe->lock);
> +
> + spin_lock_irqsave(&pipe->irqlock, flags);
> + if (vsp1_pipeline_ready(pipe))
> + vsp1_pipeline_run(pipe);
> + spin_unlock_irqrestore(&pipe->irqlock, flags);
> +
> + return 0;
> +}
> +
> +static int vsp1_video_stop_streaming(struct vb2_queue *vq)
> +{
> + struct vsp1_video *video = vb2_get_drv_priv(vq);
> + struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
> + unsigned long flags;
> + int ret;
> +
> + mutex_lock(&pipe->lock);
> + if (--pipe->stream_count == 0) {
> + /* Stop the pipeline. */
> + ret = vsp1_pipeline_stop(pipe);
> + if (ret == -ETIMEDOUT)
ETIME ?
> + dev_err(video->vsp1->dev, "pipeline stop timeout\n");
> + }
> + mutex_unlock(&pipe->lock);
> +
> + vsp1_pipeline_cleanup(pipe);
> + media_entity_pipeline_stop(&video->video.entity);
> +
> + /* Remove all buffers from the IRQ queue. */
> + spin_lock_irqsave(&video->irqlock, flags);
> + INIT_LIST_HEAD(&video->irqqueue);
> + spin_unlock_irqrestore(&video->irqlock, flags);
> +
> + return 0;
> +}
> +
> +static struct vb2_ops vsp1_video_queue_qops = {
> + .queue_setup = vsp1_video_queue_setup,
> + .buf_prepare = vsp1_video_buffer_prepare,
> + .buf_queue = vsp1_video_buffer_queue,
> + .wait_prepare = vsp1_video_wait_prepare,
> + .wait_finish = vsp1_video_wait_finish,
> + .start_streaming = vsp1_video_start_streaming,
> + .stop_streaming = vsp1_video_stop_streaming,
> +};
> +
> +/* -----------------------------------------------------------------------------
> + * V4L2 ioctls
> + */
[...]
> +static int __vsp1_video_try_format(struct vsp1_video *video,
> + struct v4l2_pix_format_mplane *pix,
> + const struct vsp1_format_info **fmtinfo)
> +{
> + const struct vsp1_format_info *info;
> + unsigned int width = pix->width;
> + unsigned int height = pix->height;
> + unsigned int i;
> +
> + /* Retrieve format information and select the default format if the
> + * requested format isn't supported.
> + */
Nitpicking: Isn't proper multi-line comment style
/*
* Retrieve format information and select the default format if the
* requested format isn't supported.
*/
? In fact the media subsystem code is pretty messy WRT that detail.
> + info = vsp1_get_format_info(pix->pixelformat);
> + if (info == NULL)
> + info = vsp1_get_format_info(VSP1_VIDEO_DEF_FORMAT);
> +
> + pix->pixelformat = info->fourcc;
> + pix->colorspace = V4L2_COLORSPACE_SRGB;
> + pix->field = V4L2_FIELD_NONE;
> + memset(pix->reserved, 0, sizeof(pix->reserved));
> +
> + /* Align the width and height for YUV 4:2:2 and 4:2:0 formats. */
> + width = round_down(width, info->hsub);
> + height = round_down(height, info->vsub);
> +
> + /* Clamp the width and height. */
> + pix->width = clamp(width, VSP1_VIDEO_MIN_WIDTH, VSP1_VIDEO_MAX_WIDTH);
> + pix->height = clamp(height, VSP1_VIDEO_MIN_HEIGHT,
> + VSP1_VIDEO_MAX_HEIGHT);
> +
> + /* Compute and clamp the stride and image size. While not documented in
> + * the datasheet, strides not aligned to a multiple of 128 bytes result
> + * in image corruption.
> + */
> + for (i = 0; i< max(info->planes, 2U); ++i) {
> + unsigned int hsub = i> 0 ? info->hsub : 1;
> + unsigned int vsub = i> 0 ? info->vsub : 1;
> + unsigned int align = 128;
> + unsigned int bpl;
> +
> + bpl = clamp_t(unsigned int, pix->plane_fmt[i].bytesperline,
> + pix->width / hsub * info->bpp[i] / 8,
> + round_down(65535U, align));
> +
> + pix->plane_fmt[i].bytesperline = round_up(bpl, align);
> + pix->plane_fmt[i].sizeimage = pix->plane_fmt[i].bytesperline
> + * pix->height / vsub;
> + }
> +
> + if (info->planes == 3) {
> + /* The second and third planes must have the same stride. */
> + pix->plane_fmt[2].bytesperline = pix->plane_fmt[1].bytesperline;
> + pix->plane_fmt[2].sizeimage = pix->plane_fmt[1].sizeimage;
> + }
> +
> + pix->num_planes = info->planes;
> +
> + if (fmtinfo)
> + *fmtinfo = info;
> +
> + return 0;
> +}
> +
Regards,
Sylwester
next prev parent reply other threads:[~2013-07-31 21:02 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-31 15:52 [PATCH v4 0/7] Renesas VSP1 driver Laurent Pinchart
2013-07-31 15:52 ` Laurent Pinchart
2013-07-31 15:52 ` [PATCH v4 1/7] media: Add support for circular graph traversal Laurent Pinchart
2013-07-31 15:52 ` Laurent Pinchart
2013-07-31 20:40 ` Sakari Ailus
2013-07-31 20:40 ` Sakari Ailus
2013-07-31 15:52 ` [PATCH v4 2/7] v4l: Fix V4L2_MBUS_FMT_YUV10_1X30 media bus pixel code value Laurent Pinchart
2013-07-31 15:52 ` Laurent Pinchart
2013-07-31 15:52 ` [PATCH v4 3/7] v4l: Add media format codes for ARGB8888 and AYUV8888 on 32-bit busses Laurent Pinchart
2013-07-31 15:52 ` Laurent Pinchart
2013-07-31 15:52 ` [PATCH v4 4/7] v4l: Add V4L2_PIX_FMT_NV16M and V4L2_PIX_FMT_NV61M formats Laurent Pinchart
2013-07-31 15:52 ` Laurent Pinchart
2013-07-31 15:52 ` [PATCH v4 5/7] v4l: Renesas R-Car VSP1 driver Laurent Pinchart
2013-07-31 21:02 ` Sylwester Nawrocki [this message]
2013-07-31 21:02 ` Sylwester Nawrocki
2013-07-31 22:03 ` Laurent Pinchart
2013-07-31 22:03 ` Laurent Pinchart
2013-08-01 22:31 ` Sylwester Nawrocki
2013-08-01 22:31 ` Sylwester Nawrocki
2013-08-01 23:47 ` Laurent Pinchart
2013-08-01 23:47 ` Laurent Pinchart
2013-07-31 21:04 ` Sakari Ailus
2013-07-31 21:04 ` Sakari Ailus
2013-07-31 15:52 ` [PATCH v4 6/7] vsp1: Fix lack of the sink entity registration for enabled links Laurent Pinchart
2013-07-31 15:52 ` Laurent Pinchart
2013-07-31 21:29 ` Sakari Ailus
2013-07-31 21:29 ` Sakari Ailus
2013-07-31 22:48 ` Laurent Pinchart
2013-07-31 22:48 ` Laurent Pinchart
2013-08-01 13:04 ` Sakari Ailus
2013-08-01 13:04 ` Sakari Ailus
2013-07-31 15:52 ` [PATCH v4 7/7] vsp1: Use the maximum number of entities defined in platform data Laurent Pinchart
2013-07-31 15:52 ` Laurent Pinchart
2013-07-31 21:08 ` Sakari Ailus
2013-07-31 21:08 ` Sakari Ailus
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=51F97B4D.70305@gmail.com \
--to=sylvester.nawrocki@gmail.com \
--cc=hverkuil@xs4all.nl \
--cc=laurent.pinchart+renesas@ideasonboard.com \
--cc=linux-media@vger.kernel.org \
--cc=linux-sh@vger.kernel.org \
--cc=matsu@igel.co.jp \
--cc=sakari.ailus@iki.fi \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.