Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5518a41 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab
Browse files

[media] V4L: sh-mobile-ceu-camera: prepare to support multi-size buffers



Prepare the sh_mobile_ceu_camera friver to support the new
VIDIOC_CREATE_BUFS and VIDIOC_PREPARE_BUF ioctl()s. The .queue_setup()
vb2 operation must be able to handle buffer sizes, provided by the
caller, and the .buf_prepare() operation must not use the currently
configured frame format for its operation.

Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 91b6286f
Loading
Loading
Loading
Loading
+81 −43
Original line number Original line Diff line number Diff line
@@ -90,7 +90,6 @@
struct sh_mobile_ceu_buffer {
struct sh_mobile_ceu_buffer {
	struct vb2_buffer vb; /* v4l buffer must be first */
	struct vb2_buffer vb; /* v4l buffer must be first */
	struct list_head queue;
	struct list_head queue;
	enum v4l2_mbus_pixelcode code;
};
};


struct sh_mobile_ceu_dev {
struct sh_mobile_ceu_dev {
@@ -100,7 +99,8 @@ struct sh_mobile_ceu_dev {


	unsigned int irq;
	unsigned int irq;
	void __iomem *base;
	void __iomem *base;
	unsigned long video_limit;
	size_t video_limit;
	size_t buf_total;


	spinlock_t lock;		/* Protects video buffer lists */
	spinlock_t lock;		/* Protects video buffer lists */
	struct list_head capture;
	struct list_head capture;
@@ -192,6 +192,12 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
/*
/*
 *  Videobuf operations
 *  Videobuf operations
 */
 */

/*
 * .queue_setup() is called to check, whether the driver can accept the
 *		  requested number of buffers and to fill in plane sizes
 *		  for the current frame format if required
 */
static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
			const struct v4l2_format *fmt,
			const struct v4l2_format *fmt,
			unsigned int *count, unsigned int *num_planes,
			unsigned int *count, unsigned int *num_planes,
@@ -200,26 +206,47 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
	struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq);
	struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq);
	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
	struct sh_mobile_ceu_dev *pcdev = ici->priv;
	struct sh_mobile_ceu_dev *pcdev = ici->priv;
	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
	int bytes_per_line;
						icd->current_fmt->host_fmt);
	unsigned int height;


	if (fmt) {
		const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
								fmt->fmt.pix.pixelformat);
		if (!xlate)
			return -EINVAL;
		bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
							 xlate->host_fmt);
		height = fmt->fmt.pix.height;
	} else {
		/* Called from VIDIOC_REQBUFS or in compatibility mode */
		bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
						icd->current_fmt->host_fmt);
		height = icd->user_height;
	}
	if (bytes_per_line < 0)
	if (bytes_per_line < 0)
		return bytes_per_line;
		return bytes_per_line;


	*num_planes = 1;
	sizes[0] = bytes_per_line * height;


	pcdev->sequence = 0;
	sizes[0] = bytes_per_line * icd->user_height;
	alloc_ctxs[0] = pcdev->alloc_ctx;
	alloc_ctxs[0] = pcdev->alloc_ctx;


	if (!vq->num_buffers)
		pcdev->sequence = 0;

	if (!*count)
	if (!*count)
		*count = 2;
		*count = 2;


	if (pcdev->video_limit) {
	/* If *num_planes != 0, we have already verified *count. */
		if (PAGE_ALIGN(sizes[0]) * *count > pcdev->video_limit)
	if (pcdev->video_limit && !*num_planes) {
			*count = pcdev->video_limit / PAGE_ALIGN(sizes[0]);
		size_t size = PAGE_ALIGN(sizes[0]) * *count;

		if (size + pcdev->buf_total > pcdev->video_limit)
			*count = (pcdev->video_limit - pcdev->buf_total) /
				PAGE_ALIGN(sizes[0]);
	}
	}


	*num_planes = 1;

	dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]);
	dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]);


	return 0;
	return 0;
@@ -330,24 +357,41 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
}
}


static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
{
	struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);

	/* Added list head initialization on alloc */
	WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb);

	return 0;
}

static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
{
{
	struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
	struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
	struct sh_mobile_ceu_buffer *buf;
	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
	struct sh_mobile_ceu_dev *pcdev = ici->priv;
	struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
	unsigned long size;
	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
						icd->current_fmt->host_fmt);
						icd->current_fmt->host_fmt);
	unsigned long size;


	if (bytes_per_line < 0)
	if (bytes_per_line < 0)
		return bytes_per_line;
		goto error;


	buf = to_ceu_vb(vb);
	size = icd->user_height * bytes_per_line;

	if (vb2_plane_size(vb, 0) < size) {
		dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n",
			vb->v4l2_buf.index, vb2_plane_size(vb, 0), size);
		goto error;
	}

	vb2_set_plane_payload(vb, 0, size);


	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));


	/* Added list head initialization on alloc */
	WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb);

#ifdef DEBUG
#ifdef DEBUG
	/*
	/*
	 * This can be useful if you want to see if we actually fill
	 * This can be useful if you want to see if we actually fill
@@ -357,31 +401,6 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
		memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
		memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
#endif
#endif


	BUG_ON(NULL == icd->current_fmt);

	size = icd->user_height * bytes_per_line;

	if (vb2_plane_size(vb, 0) < size) {
		dev_err(icd->parent, "Buffer too small (%lu < %lu)\n",
			vb2_plane_size(vb, 0), size);
		return -ENOBUFS;
	}

	vb2_set_plane_payload(vb, 0, size);

	return 0;
}

static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
{
	struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
	struct sh_mobile_ceu_dev *pcdev = ici->priv;
	struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);

	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
		vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));

	spin_lock_irq(&pcdev->lock);
	spin_lock_irq(&pcdev->lock);
	list_add_tail(&buf->queue, &pcdev->capture);
	list_add_tail(&buf->queue, &pcdev->capture);


@@ -395,6 +414,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
		sh_mobile_ceu_capture(pcdev);
		sh_mobile_ceu_capture(pcdev);
	}
	}
	spin_unlock_irq(&pcdev->lock);
	spin_unlock_irq(&pcdev->lock);

	return;

error:
	vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
}
}


static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
@@ -419,11 +443,23 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
	if (buf->queue.next)
	if (buf->queue.next)
		list_del_init(&buf->queue);
		list_del_init(&buf->queue);


	pcdev->buf_total -= PAGE_ALIGN(vb2_plane_size(vb, 0));
	dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__,
		pcdev->buf_total);

	spin_unlock_irq(&pcdev->lock);
	spin_unlock_irq(&pcdev->lock);
}
}


static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
{
{
	struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
	struct sh_mobile_ceu_dev *pcdev = ici->priv;

	pcdev->buf_total += PAGE_ALIGN(vb2_plane_size(vb, 0));
	dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__,
		pcdev->buf_total);

	/* This is for locking debugging only */
	/* This is for locking debugging only */
	INIT_LIST_HEAD(&to_ceu_vb(vb)->queue);
	INIT_LIST_HEAD(&to_ceu_vb(vb)->queue);
	return 0;
	return 0;
@@ -525,6 +561,8 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)


	pm_runtime_get_sync(ici->v4l2_dev.dev);
	pm_runtime_get_sync(ici->v4l2_dev.dev);


	pcdev->buf_total = 0;

	ret = sh_mobile_ceu_soft_reset(pcdev);
	ret = sh_mobile_ceu_soft_reset(pcdev);


	csi2_sd = find_csi2(pcdev);
	csi2_sd = find_csi2(pcdev);
@@ -1712,7 +1750,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
		image_mode = false;
		image_mode = false;
	}
	}


	dev_info(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code,
	dev_geo(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code,
		pix->width, pix->height);
		pix->width, pix->height);


	dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height);
	dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height);