Thread (12 messages) 12 messages, 3 authors, 2020-12-08

Re: [PATCH v3 2/4] media: meson: Add M2M driver for the Amlogic GE2D Accelerator Unit

From: Neil Armstrong <hidden>
Date: 2020-12-02 14:57:07
Also in: linux-amlogic, linux-media, lkml

Hi Hans,

On 02/12/2020 13:40, Hans Verkuil wrote:
On 17/11/2020 09:44, Neil Armstrong wrote:
quoted
The GE2D is a 2D accelerator with various features like configurable blitter
with alpha blending, frame rotation, scaling, format conversion and colorspace
conversion.

The driver implements a Memory2Memory VB2 V4L2 streaming device permitting:
- 0, 90, 180, 270deg rotation
- horizontal/vertical flipping
- source cropping
- destination compositing
- 32bit/24bit/16bit format conversion

This adds the support for the GE2D version found in the AXG SoCs Family.

The missing features are:
- Source scaling
- Colorspace conversion
- Advanced alpha blending & blitting options

Is passes v4l2-compliance SHA: ea16a7ef13a902793a5c2626b0cefc4d956147f3, 64 bits, 64-bit time_t

Signed-off-by: Neil Armstrong <redacted>
---
 drivers/media/platform/Kconfig                |   13 +
 drivers/media/platform/Makefile               |    2 +
 drivers/media/platform/meson/ge2d/Makefile    |    3 +
 drivers/media/platform/meson/ge2d/ge2d-regs.h |  360 ++++++
 drivers/media/platform/meson/ge2d/ge2d.c      | 1091 +++++++++++++++++
 5 files changed, 1469 insertions(+)
 create mode 100644 drivers/media/platform/meson/ge2d/Makefile
 create mode 100644 drivers/media/platform/meson/ge2d/ge2d-regs.h
 create mode 100644 drivers/media/platform/meson/ge2d/ge2d.c
[...]
quoted
+
+#define DEFAULT_WIDTH	100
+#define DEFAULT_HEIGHT	100
That's a weird default value. I would expect to see some multiple of 8 here.
Sure, whatever the HW is quite flexible, I took 100x100 from the other 2D accelerator drivers actually.

[...]
quoted
+
+static void ge2d_stop_streaming(struct vb2_queue *vq)
+{
+	struct ge2d_ctx *ctx = vb2_get_drv_priv(vq);
+	struct vb2_v4l2_buffer *vbuf;
+
+	if (V4L2_TYPE_IS_OUTPUT(vq->type))
+		ctx->streamon_out = false;
+	else
+		ctx->streamon_cap = false;
Do you need streamon_out/cap? Can't you use vb2_start_streaming_called() instead?
Indeed, I'll switch to vb2_start_streaming_called & co.

[...]
quoted
+
+static int vidioc_try_fmt_out(struct file *file, void *priv, struct v4l2_format *f)
+{
+	const struct ge2d_fmt *fmt = find_fmt(f);
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.pixelformat = fmt->fourcc;
+
+	if (f->fmt.pix.width > MAX_WIDTH)
+		f->fmt.pix.width = MAX_WIDTH;
+	if (f->fmt.pix.height > MAX_HEIGHT)
+		f->fmt.pix.height = MAX_HEIGHT;
+
+	if (f->fmt.pix.width < 0)
+		f->fmt.pix.width = 0;
+	if (f->fmt.pix.height < 0)
+		f->fmt.pix.height = 0;
width and height are unsigned, so this check is not needed.
Ok

[...]
quoted
+
+static int ge2d_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ge2d_ctx *ctx = container_of(ctrl->handler, struct ge2d_ctx,
+					   ctrl_handler);
+	struct v4l2_pix_format fmt;
+	struct vb2_queue *vq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->ge2d->ctrl_lock, flags);
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		ctx->hflip = ctrl->val;
+		break;
+	case V4L2_CID_VFLIP:
+		ctx->vflip = ctrl->val;
+		break;
+	case V4L2_CID_ROTATE:
+		vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+		if (vb2_is_busy(vq))
+			return -EBUSY;
This doesn't call spin_unlock_irqrestore()!

Do you need the spinlock at all? This function is already called with a mutex
for ctrl->handler held. It's unusual to see a spinlock here.
Is device_run also called with ctrl->handler held ?

The spinlock is used to protect against concurrent re-config & run.

[...]
quoted
+
+	platform_set_drvdata(pdev, ge2d);
+	ge2d->m2m_dev = v4l2_m2m_init(&ge2d_m2m_ops);
+	if (IS_ERR(ge2d->m2m_dev)) {
+		v4l2_err(&ge2d->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(ge2d->m2m_dev);
+		goto unreg_video_dev;
This should be goto rel_vdev.
quoted
+	}
+
+	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
+	if (ret) {
+		v4l2_err(&ge2d->v4l2_dev, "Failed to register video device\n");
+		goto rel_vdev;
+	}
+
+	v4l2_info(&ge2d->v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+
+	return 0;
+
+rel_vdev:
+	video_device_release(vfd);
+unreg_video_dev:
+	video_unregister_device(ge2d->vfd);
This makes no sense. If video_register_device() fails, then you
call video_device_release(vfd), not video_unregister_device().

Just drop these two lines.
ok
quoted
+unreg_v4l2_dev:
+	v4l2_device_unregister(&ge2d->v4l2_dev);
+disable_clks:
+	clk_disable_unprepare(ge2d->clk);
+
+	return ret;
+}
+
+static int ge2d_remove(struct platform_device *pdev)
+{
+	struct meson_ge2d *ge2d = platform_get_drvdata(pdev);
+
+	v4l2_m2m_release(ge2d->m2m_dev);
+	video_unregister_device(ge2d->vfd);
+	v4l2_device_unregister(&ge2d->v4l2_dev);
+
+	clk_disable_unprepare(ge2d->clk);
+
+	return 0;
+}
+
+static const struct of_device_id meson_ge2d_match[] = {
+	{
+		.compatible = "amlogic,axg-ge2d",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, meson_ge2d_match);
+
+static struct platform_driver ge2d_drv = {
+	.probe = ge2d_probe,
+	.remove = ge2d_remove,
+	.driver = {
+		.name = "meson-ge2d",
+		.of_match_table = meson_ge2d_match,
+	},
+};
+
+module_platform_driver(ge2d_drv);
+
+MODULE_AUTHOR("Neil Armstrong [off-list ref]");
+MODULE_DESCRIPTION("Amlogic 2D Graphic Acceleration Unit");
+MODULE_LICENSE("GPL");
Regards,

	Hans
Thanks,
Neil

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help