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: 18+ 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 ` [PATCH v4 1/7] media: Add support for circular graph traversal Laurent Pinchart
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 ` [PATCH v4 3/7] v4l: Add media format codes for ARGB8888 and AYUV8888 on 32-bit busses 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 ` [PATCH v4 5/7] v4l: Renesas R-Car VSP1 driver Laurent Pinchart
2013-07-31 21:02 ` Sylwester Nawrocki [this message]
2013-07-31 22:03 ` Laurent Pinchart
2013-08-01 22:31 ` Sylwester Nawrocki
2013-08-01 23:47 ` Laurent Pinchart
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 21:29 ` Sakari Ailus
2013-07-31 22:48 ` Laurent Pinchart
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 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox