All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-21  6:43 ` Tomohito Esaki
  0 siblings, 0 replies; 61+ messages in thread
From: Tomohito Esaki @ 2021-06-21  6:43 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: dri-devel, linux-renesas-soc, linux-kernel, devicetree,
	linux-doc, Tomohito Esaki

Hello
Sorry, there was a typo in the dri-devel mail address, so I've resend it.
---

Virtual DRM splits the overlay planes of a display controller into multiple
virtual devices to allow each plane to be accessed by each process.

This makes it possible to overlay images output from multiple processes on a
display. For example, one process displays the camera image without compositor
while another process overlays the UI.

Virtual DRM driver doesn’t directly control the display hardware and has no
access to the physical bus. Instead, the virtual DRM driver issues requests to
the standard DRM device driver (parent) when the hardware needs to be
controlled. The parent is modified to notify the virtual DRM driver of
interruptevents from the display hardware. Therefore, in order to use virtual
DRM, each DRM device driver needs to add code to support virutal DRM.

The only driver supported in this patch series is rcar-du. This patch series
is divided into multiple. The first patch adds vDRM feature to DRM, and the
second patch support vDRM for the rcar-du driver. The other patches add
documentation.

In particular, I would appreciate your advice on the following points:
* virtual DRM generalization
  I've only tested with rcar-du, is there anything I should consider to make
  virtual DRM work with other drivers?

* Integration to upstream
  I think it is a good idea to add virtual DRM to the DRM core functionality,
  but I would appreciate any suggestions on what needs to be improved for
  integration to upstream.

* dumb_create and fb_create callback
  I think that the dumb_create and fb_create callbacks need to be done by the
  parent, and it is preferable to use the parent's callbacks as they are.
  However, since the dumb buffer needs to be registered in the parent and
  the fb handle needs to be registered in the drm_file of the vDRM, the
  dumb_create callbacks from the parent driver cannot be used as is.
  Therefore, the current implementation of the dumb_create callback is
  workarround.
  What do you think is the best way to deal with this issue?


Tomohito Esaki (4):
  Add Virtual DRM device driver
  rcar-du: Add support virtual DRM device
  dt-bindings: display: Add virtual DRM
  doc-rst: Add virtual DRM documentation

 .../devicetree/bindings/display/vdrm.yaml     |  67 ++
 Documentation/gpu/drivers.rst                 |   1 +
 Documentation/gpu/vdrm.rst                    |  51 ++
 drivers/gpu/drm/Kconfig                       |   7 +
 drivers/gpu/drm/Makefile                      |   1 +
 drivers/gpu/drm/rcar-du/Kconfig               |   4 +
 drivers/gpu/drm/rcar-du/Makefile              |   1 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c        |  42 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h        |  13 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.c         |  13 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.h         |   3 +
 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c        | 191 ++++
 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h        |  67 ++
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c         |  22 +
 drivers/gpu/drm/rcar-du/rcar_du_vsp.h         |   1 +
 drivers/gpu/drm/vdrm/vdrm_api.h               |  68 ++
 drivers/gpu/drm/vdrm/vdrm_drv.c               | 859 ++++++++++++++++++
 drivers/gpu/drm/vdrm/vdrm_drv.h               |  80 ++
 18 files changed, 1491 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml
 create mode 100644 Documentation/gpu/vdrm.rst
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_api.h
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.c
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 61+ messages in thread

* [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-21  6:43 ` Tomohito Esaki
  0 siblings, 0 replies; 61+ messages in thread
From: Tomohito Esaki @ 2021-06-21  6:43 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: devicetree, linux-doc, linux-kernel, dri-devel,
	linux-renesas-soc, Tomohito Esaki

Hello
Sorry, there was a typo in the dri-devel mail address, so I've resend it.
---

Virtual DRM splits the overlay planes of a display controller into multiple
virtual devices to allow each plane to be accessed by each process.

This makes it possible to overlay images output from multiple processes on a
display. For example, one process displays the camera image without compositor
while another process overlays the UI.

Virtual DRM driver doesn’t directly control the display hardware and has no
access to the physical bus. Instead, the virtual DRM driver issues requests to
the standard DRM device driver (parent) when the hardware needs to be
controlled. The parent is modified to notify the virtual DRM driver of
interruptevents from the display hardware. Therefore, in order to use virtual
DRM, each DRM device driver needs to add code to support virutal DRM.

The only driver supported in this patch series is rcar-du. This patch series
is divided into multiple. The first patch adds vDRM feature to DRM, and the
second patch support vDRM for the rcar-du driver. The other patches add
documentation.

In particular, I would appreciate your advice on the following points:
* virtual DRM generalization
  I've only tested with rcar-du, is there anything I should consider to make
  virtual DRM work with other drivers?

* Integration to upstream
  I think it is a good idea to add virtual DRM to the DRM core functionality,
  but I would appreciate any suggestions on what needs to be improved for
  integration to upstream.

* dumb_create and fb_create callback
  I think that the dumb_create and fb_create callbacks need to be done by the
  parent, and it is preferable to use the parent's callbacks as they are.
  However, since the dumb buffer needs to be registered in the parent and
  the fb handle needs to be registered in the drm_file of the vDRM, the
  dumb_create callbacks from the parent driver cannot be used as is.
  Therefore, the current implementation of the dumb_create callback is
  workarround.
  What do you think is the best way to deal with this issue?


Tomohito Esaki (4):
  Add Virtual DRM device driver
  rcar-du: Add support virtual DRM device
  dt-bindings: display: Add virtual DRM
  doc-rst: Add virtual DRM documentation

 .../devicetree/bindings/display/vdrm.yaml     |  67 ++
 Documentation/gpu/drivers.rst                 |   1 +
 Documentation/gpu/vdrm.rst                    |  51 ++
 drivers/gpu/drm/Kconfig                       |   7 +
 drivers/gpu/drm/Makefile                      |   1 +
 drivers/gpu/drm/rcar-du/Kconfig               |   4 +
 drivers/gpu/drm/rcar-du/Makefile              |   1 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c        |  42 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h        |  13 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.c         |  13 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.h         |   3 +
 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c        | 191 ++++
 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h        |  67 ++
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c         |  22 +
 drivers/gpu/drm/rcar-du/rcar_du_vsp.h         |   1 +
 drivers/gpu/drm/vdrm/vdrm_api.h               |  68 ++
 drivers/gpu/drm/vdrm/vdrm_drv.c               | 859 ++++++++++++++++++
 drivers/gpu/drm/vdrm/vdrm_drv.h               |  80 ++
 18 files changed, 1491 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml
 create mode 100644 Documentation/gpu/vdrm.rst
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_api.h
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.c
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 61+ messages in thread

* [PATH 1/4] drm: Add Virtual DRM device driver
  2021-06-21  6:43 ` Tomohito Esaki
@ 2021-06-21  6:44   ` Tomohito Esaki
  -1 siblings, 0 replies; 61+ messages in thread
From: Tomohito Esaki @ 2021-06-21  6:44 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: dri-devel, linux-renesas-soc, linux-kernel, devicetree,
	linux-doc, Tomohito Esaki

Virtual DRM splits the resources of an overlay plane into multiple
virtual devices to allow each plane to be accessed by each process.

This makes it possible to overlay images output from multiple processes
on a display. For example, one process displays the camera image without
compositor while another process overlays the compositor's drawing of
the UI.

The virtual DRM creates standalone virtual device and make DRM planes
from a master device (e.g. card0) accessible via one or more virtual
devices. However, these plane are no longer accessible from the original
device.
Each virtual device (and plane) can be accessed via a separate
device file.

Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
---
 drivers/gpu/drm/Kconfig         |   7 +
 drivers/gpu/drm/Makefile        |   1 +
 drivers/gpu/drm/vdrm/vdrm_api.h |  68 +++
 drivers/gpu/drm/vdrm/vdrm_drv.c | 859 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/vdrm/vdrm_drv.h |  80 +++
 5 files changed, 1015 insertions(+)
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_api.h
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.c
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 3c16bd1afd87..ba7f4eeab385 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -294,6 +294,13 @@ config DRM_VKMS
 
 	  If M is selected the module will be called vkms.
 
+config DRM_VDRM
+	tristate "Virtual DRM"
+	depends on DRM
+	help
+	  Virtual DRM splits the resources of an overlay plane into multiple
+	  virtual devices to allow each plane to be accessed by each process.
+
 source "drivers/gpu/drm/exynos/Kconfig"
 
 source "drivers/gpu/drm/rockchip/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 5279db4392df..55dbf85e2579 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
 obj-$(CONFIG_DRM_VIA)	+=via/
 obj-$(CONFIG_DRM_VGEM)	+= vgem/
 obj-$(CONFIG_DRM_VKMS)	+= vkms/
+obj-$(CONFIG_DRM_VDRM)	+= vdrm/
 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
 obj-$(CONFIG_DRM_EXYNOS) +=exynos/
 obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
diff --git a/drivers/gpu/drm/vdrm/vdrm_api.h b/drivers/gpu/drm/vdrm/vdrm_api.h
new file mode 100644
index 000000000000..dd4d7e774800
--- /dev/null
+++ b/drivers/gpu/drm/vdrm/vdrm_api.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * vdrm_api.h -- Virtual DRM API
+ *
+ * Copyright (C) 2021 Renesas Electronics Corporation
+ */
+
+#ifndef __VDRM_API__
+#define __VDRM_API__
+
+#include <linux/of_device.h>
+#include <drm/drm_crtc.h>
+
+/**
+ * struct vdrm_property_info - Information about the properties passed from
+ *			       the DRM driver to vDRM
+ * @prop: Parent property to pass to vDRM
+ * @default_val: Default value for the property passed to vDRM
+ */
+struct vdrm_property_info {
+	struct drm_property *prop;
+	uint64_t default_val;
+};
+
+/**
+ * struct vdrm_funcs - Callbacks to parent DRM driver
+ */
+struct vdrm_funcs {
+	/**
+	 * @dumb_create:
+	 *
+	 * Called by &drm_driver.dumb_create. Please read the documentation
+	 * for the &drm_driver.dumb_create hook for more details.
+	 */
+	int (*dumb_create)(struct drm_file *file, struct drm_device *dev,
+			   struct drm_mode_create_dumb *args);
+
+	/**
+	 * @crtc_flush:
+	 *
+	 * Called by &drm_crtc_helper_funcs.atomic_flush. Please read the
+	 * documentation for the &drm_crtc_helper_funcs.atomic_flush hook for
+	 * more details.
+	 */
+	void (*crtc_flush)(struct drm_crtc *crtc);
+};
+
+struct vdrm_device;
+struct vdrm_display;
+
+void vdrm_drv_handle_vblank(struct vdrm_display *vdisplay);
+void vdrm_drv_finish_page_flip(struct vdrm_display *vdisplay);
+struct vdrm_device *vdrm_drv_init(struct drm_device *dev,
+				  struct device_node *np, int num_props,
+				  struct vdrm_property_info *props,
+				  const struct vdrm_funcs *funcs);
+int vdrm_drv_plane_init(struct vdrm_device *vdrm, struct drm_plane *plane,
+			const struct drm_plane_funcs *funcs,
+			const struct drm_plane_helper_funcs *helper_funcs,
+			const u32 *formats, unsigned int num_formats,
+			int max_zpos);
+struct vdrm_display *vdrm_drv_display_init(struct vdrm_device *vdrm,
+					   struct drm_crtc *crtc,
+					   struct drm_plane *plane);
+int vdrm_drv_register(struct vdrm_device *vdrm);
+void vdrm_drv_fini(struct vdrm_device *vdrm);
+
+#endif /* __VDRM_API__ */
diff --git a/drivers/gpu/drm/vdrm/vdrm_drv.c b/drivers/gpu/drm/vdrm/vdrm_drv.c
new file mode 100644
index 000000000000..835bdecfc8e6
--- /dev/null
+++ b/drivers/gpu/drm/vdrm/vdrm_drv.c
@@ -0,0 +1,859 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * vdrm_drv.c -- Virtual DRM driver
+ *
+ * Copyright (C) 2021 Renesas Electronics Corporation
+ *
+ * This driver is based on drivers/gpu/drm/drm_simple_kms_helper.c.
+ */
+
+#include <linux/of_device.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <video/videomode.h>
+
+#include "vdrm_drv.h"
+
+static inline struct vdrm_display *
+to_vdrm_display(struct drm_connector *connector)
+{
+	return container_of(connector, struct vdrm_display, connector);
+}
+
+static inline struct vdrm_display *
+crtc_to_vdrm_display(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct vdrm_display, crtc);
+}
+
+static int vdrm_dumb_create(struct drm_file *file, struct drm_device *dev,
+			    struct drm_mode_create_dumb *args)
+{
+	struct vdrm_device *vdrm = to_vdrm_device(dev);
+
+	return vdrm->funcs->dumb_create(file, dev, args);
+}
+
+struct vdrm_framebuffer {
+	struct drm_framebuffer fb;
+	struct drm_framebuffer *parent_fb;
+};
+
+static inline struct vdrm_framebuffer *
+to_vdrm_framebuffer(struct drm_framebuffer *fb)
+{
+	return container_of(fb, struct vdrm_framebuffer, fb);
+}
+
+static void vdrm_fb_destroy(struct drm_framebuffer *fb)
+{
+	struct vdrm_framebuffer *vfb = to_vdrm_framebuffer(fb);
+
+	vfb->parent_fb->funcs->destroy(vfb->parent_fb);
+	drm_framebuffer_cleanup(fb);
+	kfree(vfb);
+}
+
+static const struct drm_framebuffer_funcs vdrm_fb_funcs = {
+	.destroy = vdrm_fb_destroy,
+};
+
+static int vdrm_fb_init(struct drm_device *dev, struct vdrm_framebuffer *vfb)
+{
+	vfb->fb = *vfb->parent_fb;
+	vfb->fb.dev = dev;
+
+	return drm_framebuffer_init(dev, &vfb->fb, &vdrm_fb_funcs);
+}
+
+static struct drm_framebuffer *
+vdrm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
+	       const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	struct vdrm_device *vdrm = to_vdrm_device(dev);
+	const struct drm_mode_config_funcs *mode_config_funcs =
+		vdrm->parent->mode_config.funcs;
+	struct vdrm_framebuffer *vfb;
+	struct drm_framebuffer *fb;
+	int ret;
+
+	vfb = kzalloc(sizeof(*vfb), GFP_KERNEL);
+	if (!vfb)
+		return ERR_PTR(-ENOMEM);
+
+	fb = mode_config_funcs->fb_create(vdrm->parent, file_priv, mode_cmd);
+	if (IS_ERR(fb)) {
+		kfree(vfb);
+		return fb;
+	}
+
+	vfb->parent_fb = fb;
+	ret = vdrm_fb_init(dev, vfb);
+	if (ret) {
+		fb->funcs->destroy(fb);
+		kfree(vfb);
+		return ERR_PTR(ret);
+	}
+
+	return &vfb->fb;
+}
+
+static const struct drm_mode_config_funcs vdrm_mode_config_funcs = {
+	.fb_create = vdrm_fb_create,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static struct drm_display_mode *vdrm_create_mode(struct vdrm_display *disp)
+{
+	struct drm_display_mode *mode;
+	struct videomode videomode;
+
+	mode = drm_mode_create(&disp->dev->ddev);
+	if (!mode)
+		return NULL;
+
+	memset(&videomode, 0, sizeof(videomode));
+	videomode.hactive = disp->plane_info.width;
+	videomode.vactive = disp->plane_info.height;
+	videomode.pixelclock =
+		disp->parent_crtc->state->adjusted_mode.crtc_clock * 1000;
+	mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
+	drm_display_mode_from_videomode(&videomode, mode);
+
+	return mode;
+}
+
+static int vdrm_connector_get_mode(struct drm_connector *connector)
+{
+	struct vdrm_display *disp = to_vdrm_display(connector);
+	struct drm_display_mode *mode = vdrm_create_mode(disp);
+
+	if (!mode)
+		return 0;
+
+	drm_mode_probed_add(connector, mode);
+	return 1;
+}
+
+static const struct drm_connector_helper_funcs vdrm_conn_helper_funcs = {
+	.get_modes = vdrm_connector_get_mode,
+};
+
+/*
+ * TODO:
+ *  At the time this callback is called, the parent CRTC must be connected.
+ *  Since this callback will not be called when detect() callback of the
+ *  parent connector is called, vDRM driver desn't support hotplug.
+ *  In the future, it is necessary that hotplug is supported.
+ */
+static enum drm_connector_status
+vdrm_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct vdrm_display *disp = to_vdrm_display(connector);
+	struct vdrm_device *vdrm = to_vdrm_device(connector->dev);
+	struct drm_connector *conn;
+	struct drm_connector_list_iter conn_iter;
+
+	drm_connector_list_iter_begin(vdrm->parent, &conn_iter);
+	drm_for_each_connector_iter(conn, &conn_iter) {
+		if (!conn->state)
+			continue;
+
+		if (conn->state->crtc == disp->parent_crtc) {
+			drm_connector_list_iter_end(&conn_iter);
+			return connector_status_connected;
+		}
+	}
+	drm_connector_list_iter_end(&conn_iter);
+	return connector_status_disconnected;
+}
+
+static const struct drm_connector_funcs vdrm_conn_funcs = {
+	.reset = drm_atomic_helper_connector_reset,
+	.detect = vdrm_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static void vdrm_drv_finish_page_flip_internal(struct vdrm_display *disp)
+{
+	struct drm_device *dev = &disp->dev->ddev;
+	struct drm_pending_vblank_event *event;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	event = disp->event;
+	disp->event = NULL;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	if (event == NULL)
+		return;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	drm_crtc_send_vblank_event(&disp->crtc, event);
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	if (disp->vblank_count) {
+		drm_crtc_vblank_put(&disp->crtc);
+		disp->vblank_count--;
+	}
+}
+
+static void vdrm_plane_update(struct drm_plane *plane,
+			      struct drm_atomic_state *state)
+{
+	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
+	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
+	struct drm_crtc *vcrtc_old_state = old_state->crtc;
+	struct drm_crtc *vcrtc_plane_state = new_state->crtc;
+	struct drm_crtc *crtc;
+	struct vdrm_display *vdisplay;
+
+	crtc = (old_state->crtc ? old_state->crtc : new_state->crtc);
+	if (WARN_ON(!crtc))
+		return;
+
+	vdisplay = crtc_to_vdrm_display(crtc);
+
+	old_state->crtc = vdisplay->parent_crtc;
+	new_state->crtc = vdisplay->parent_crtc;
+
+	new_state->dst.x1 += vdisplay->plane_info.x;
+	new_state->dst.y1 += vdisplay->plane_info.y;
+	vdisplay->parent_plane_helper_funcs->atomic_update(plane, state);
+
+	old_state->crtc = vcrtc_old_state;
+	new_state->crtc = vcrtc_plane_state;
+}
+
+static struct vdrm_display *
+vdrm_plane_find_display(struct vdrm_device *vdrm, struct drm_plane *plane)
+{
+	struct vdrm_display *disp;
+
+	list_for_each_entry(disp, &vdrm->disps, head) {
+		if (disp->plane == plane)
+			return disp;
+	}
+
+	return NULL;
+}
+
+static void vdrm_plane_reset(struct drm_plane *plane)
+{
+	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
+	struct vdrm_display *disp;
+
+	disp = vdrm_plane_find_display(vdrm, plane);
+	if (WARN_ON(!disp))
+		return;
+
+	disp->parent_plane_funcs->reset(plane);
+	plane->state->zpos = disp->plane_info.z;
+}
+
+static struct drm_property *
+vdrm_find_parent_property(struct vdrm_device *vdrm, struct drm_property *prop)
+{
+	int i;
+
+	for (i = 0; i < vdrm->num_props; i++) {
+		if (vdrm->props[i].prop == prop)
+			return vdrm->props[i].parent_prop;
+	}
+
+	return NULL;
+}
+
+static int vdrm_plane_set_property(struct drm_plane *plane,
+				   struct drm_plane_state *state,
+				   struct drm_property *property,
+				   uint64_t val)
+{
+	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
+	struct vdrm_display *disp;
+	struct drm_property *parent_prop;
+
+	disp = vdrm_plane_find_display(vdrm, plane);
+	if (WARN_ON(!disp))
+		return -EINVAL;
+
+	parent_prop = vdrm_find_parent_property(vdrm, property);
+	if (parent_prop && disp->parent_plane_funcs->atomic_set_property)
+		return disp->parent_plane_funcs->atomic_set_property(plane,
+								state,
+								parent_prop,
+								val);
+
+	if (vdrm->plane_props.offset_x == property) {
+		if (val > disp->parent_crtc->mode.hdisplay)
+			return -EINVAL;
+		disp->plane_info.x = val;
+	} else if (vdrm->plane_props.offset_y == property) {
+		if (val > disp->parent_crtc->mode.vdisplay)
+			return -EINVAL;
+		disp->plane_info.y = val;
+	} else if (vdrm->plane_props.width == property) {
+		if (val > disp->parent_crtc->mode.hdisplay)
+			return -EINVAL;
+		disp->plane_info.width = val;
+	} else if (vdrm->plane_props.height == property) {
+		if (val > disp->parent_crtc->mode.vdisplay)
+			return -EINVAL;
+		disp->plane_info.height = val;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vdrm_plane_get_property(struct drm_plane *plane,
+				   const struct drm_plane_state *state,
+				   struct drm_property *property,
+				   uint64_t *val)
+{
+	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
+	struct vdrm_display *disp;
+	struct drm_property *parent_prop;
+
+	disp = vdrm_plane_find_display(vdrm, plane);
+	if (WARN_ON(!disp))
+		return -EINVAL;
+
+	parent_prop = vdrm_find_parent_property(vdrm, property);
+	if (parent_prop && disp->parent_plane_funcs->atomic_get_property)
+		return disp->parent_plane_funcs->atomic_get_property(plane,
+								state,
+								parent_prop,
+								val);
+
+	if (vdrm->plane_props.offset_x == property)
+		*val = disp->plane_info.x;
+	else if (vdrm->plane_props.offset_y == property)
+		*val = disp->plane_info.y;
+	else if (vdrm->plane_props.width == property)
+		*val = disp->plane_info.width;
+	else if (vdrm->plane_props.height == property)
+		*val = disp->plane_info.height;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vdrm_crtc_check(struct drm_crtc *crtc,
+			   struct drm_atomic_state *state)
+{
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
+	bool has_primary = crtc_state->plane_mask &
+				drm_plane_mask(crtc->primary);
+
+	/* We always want to have an active plane with an active CRTC */
+	if (has_primary != crtc_state->enable)
+		return -EINVAL;
+
+	return drm_atomic_add_affected_planes(state, crtc);
+}
+
+static void vdrm_crtc_flush(struct drm_crtc *crtc,
+			    struct drm_atomic_state *state)
+{
+	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
+	struct vdrm_device *vdrm = disp->dev;
+
+	if (crtc->state->event) {
+		struct drm_device *dev = crtc->dev;
+		unsigned long flags;
+
+		if (disp->crtc_enabled) {
+			WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+			disp->vblank_count++;
+		}
+
+		spin_lock_irqsave(&dev->event_lock, flags);
+		disp->event = crtc->state->event;
+		crtc->state->event = NULL;
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+	}
+
+	if (vdrm->funcs->crtc_flush)
+		vdrm->funcs->crtc_flush(disp->parent_crtc);
+}
+
+static void vdrm_crtc_enable(struct drm_crtc *crtc,
+			     struct drm_atomic_state *state)
+{
+	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
+
+	drm_crtc_vblank_on(crtc);
+	disp->crtc_enabled = true;
+}
+
+static void vdrm_crtc_disable(struct drm_crtc *crtc,
+			      struct drm_atomic_state *state)
+{
+	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
+	unsigned long flags;
+	bool pending;
+
+	disp->crtc_enabled = false;
+	drm_crtc_vblank_off(crtc);
+
+	spin_lock_irqsave(&crtc->dev->event_lock, flags);
+	pending = disp->event != NULL;
+	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
+	if (!wait_event_timeout(disp->flip_wait, !pending,
+				msecs_to_jiffies(50))) {
+		DRM_WARN("VDRM: page flip timeout\n");
+		vdrm_drv_finish_page_flip_internal(disp);
+	}
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event) {
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static const struct drm_crtc_helper_funcs vdrm_crtc_helper_funcs = {
+	.atomic_check = vdrm_crtc_check,
+	.atomic_flush = vdrm_crtc_flush,
+	.atomic_enable = vdrm_crtc_enable,
+	.atomic_disable = vdrm_crtc_disable,
+};
+
+static int vdrm_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+	struct vdrm_display *disp;
+
+	disp = crtc_to_vdrm_display(crtc);
+	disp->vblank_enabled = true;
+
+	return 0;
+}
+
+static void vdrm_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+	struct vdrm_display *disp;
+
+	disp = crtc_to_vdrm_display(crtc);
+	disp->vblank_enabled = false;
+}
+
+static const struct drm_crtc_funcs vdrm_crtc_funcs = {
+	.reset = drm_atomic_helper_crtc_reset,
+	.destroy = drm_crtc_cleanup,
+	.set_config = drm_atomic_helper_set_config,
+	.page_flip = drm_atomic_helper_page_flip,
+	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+	.enable_vblank = vdrm_crtc_enable_vblank,
+	.disable_vblank = vdrm_crtc_disable_vblank,
+};
+static const struct drm_encoder_funcs vdrm_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static int vdrm_properties_init(struct vdrm_device *vdrm, int num_props,
+				struct vdrm_property_info *props)
+{
+	int i;
+	unsigned int w = vdrm->ddev.mode_config.max_width;
+	unsigned int h = vdrm->ddev.mode_config.max_height;
+
+	vdrm->plane_props.offset_x =
+		drm_property_create_range(&vdrm->ddev, 0, "vdrm_offset_x", 0, w);
+	if (!vdrm->plane_props.offset_x)
+		return -1;
+	vdrm->plane_props.offset_y =
+		drm_property_create_range(&vdrm->ddev, 0, "vdrm_offset_y", 0, h);
+	if (!vdrm->plane_props.offset_y)
+		return -1;
+	vdrm->plane_props.width =
+		drm_property_create_range(&vdrm->ddev, 0, "vdrm_width", 1, w);
+	if (!vdrm->plane_props.width)
+		return -1;
+	vdrm->plane_props.height =
+		drm_property_create_range(&vdrm->ddev, 0, "vdrm_height", 1, h);
+	if (!vdrm->plane_props.height)
+		return -1;
+
+	if (num_props == 0)
+		return 0;
+
+	vdrm->props = devm_kzalloc(vdrm->parent->dev,
+				    sizeof(*vdrm->props) * num_props,
+				    GFP_KERNEL);
+	if (!vdrm->props)
+		return -ENOMEM;
+
+	for (i = 0; i < num_props; i++) {
+		struct drm_property *p = props[i].prop;
+
+		vdrm->props[i].prop =
+			drm_property_create_range(&vdrm->ddev, p->flags,
+						  p->name, p->values[0],
+						  p->values[1]);
+		if (!vdrm->props[i].prop)
+			goto err;
+
+		vdrm->props[i].parent_prop = p;
+		vdrm->props[i].default_val = props[i].default_val;
+	}
+	vdrm->num_props = num_props;
+
+	return 0;
+
+err:
+	for (i--; i >= 0; i--)
+		drm_property_destroy(&vdrm->ddev, vdrm->props[i].prop);
+	devm_kfree(vdrm->parent->dev, vdrm->props);
+	return -1;
+}
+
+static int vdrm_of_get_plane(struct device_node *np,
+			     int *x, int *y, int *width, int *height, int *z)
+{
+	struct device_node *child;
+	int ret;
+
+	child = of_get_next_child(np, NULL);
+	if (!child)
+		return -ENODEV;
+
+	ret = of_property_read_u32(child, "x", x);
+	ret |= of_property_read_u32(child, "y", y);
+	ret |= of_property_read_u32(child, "width", width);
+	ret |= of_property_read_u32(child, "height", height);
+	ret |= of_property_read_u32(child, "zpos", z);
+
+	of_node_put(child);
+	return ret;
+}
+
+static void vdrm_dump(struct vdrm_device *vdrm)
+{
+	struct vdrm_display *disp;
+
+	DRM_INFO("Virtual DRM Info:\n");
+	list_for_each_entry(disp, &vdrm->disps, head) {
+		DRM_INFO("\tCONNECTOR: %d\n",
+			 disp->connector.base.id);
+		DRM_INFO("\tCRTC: %d\n",
+			 disp->crtc.base.id);
+		DRM_INFO("\tENCODER: %d\n",
+			 disp->encoder.base.id);
+		DRM_INFO("\tPLANE: %d\n",
+			 disp->plane->base.id);
+		DRM_INFO("\tParent CRTC: %d\n",
+			 disp->parent_crtc->base.id);
+	}
+}
+
+/**
+ * vdrm_drv_handle_vblank - handle a vblank event for vDRM
+ * @vdisplay: vDRM display object
+ */
+void vdrm_drv_handle_vblank(struct vdrm_display *vdisplay)
+{
+	if (vdisplay->vblank_enabled)
+		drm_crtc_handle_vblank(&vdisplay->crtc);
+}
+
+/**
+ * vdrm_drv_finish_page_flip - handle a page flip event for vDRM
+ * @vdisplay: vDRM display object
+ */
+void vdrm_drv_finish_page_flip(struct vdrm_display *vdisplay)
+{
+	vdrm_drv_finish_page_flip_internal(vdisplay);
+}
+
+DEFINE_DRM_GEM_CMA_FOPS(vdrm_fops);
+
+static struct drm_driver vdrm_driver = {
+	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+	.dumb_create = vdrm_dumb_create,
+	.fops = &vdrm_fops,
+	.name = "virt-drm",
+	.desc = "Virtual DRM driver",
+	.date = "20201104",
+	.major = 1,
+	.minor = 0,
+};
+
+/**
+ * vdrm_drv_init - Initialize vDRM device
+ * @dev: parent DRM device
+ * @np: vDRM device node in DTB
+ * @num_props: number of parent property objects
+ * @props: parent plane properties used in vDRM
+ * @funcs: callbacks for vDRM
+ *
+ * Allocates a new vDRM device, initializes mode_config of the vDRM device
+ * and allocates property objects. Not initialize plane, crtc, encoder and
+ * connector. Initialization of plane must be done in vdrm_drv_plane_init()
+ * and initialization of crtc, encoder and connector must be done by
+ * vdrm_drv_display_init(). Also, after initializing the plane, crtc,
+ * connector, and encoder, register vDRM device must be done by
+ * vdrm_drv_register().
+ *
+ * Returns:
+ * vDRM object (&vdrm_device) on success, error code encoded into the pointer
+ * on failure.
+ */
+struct vdrm_device *vdrm_drv_init(struct drm_device *dev,
+				  struct device_node *np, int num_props,
+				  struct vdrm_property_info *props,
+				  const struct vdrm_funcs *funcs)
+{
+	struct vdrm_device *vdrm;
+	struct vdrm_plane_info plane_info;
+	int ret;
+
+	if (!of_device_is_compatible(np, "virt-drm"))
+		return ERR_PTR(-ENODEV);
+
+	/* get plane information from device tree */
+	ret = vdrm_of_get_plane(np, &plane_info.x, &plane_info.y,
+				&plane_info.width, &plane_info.height,
+				&plane_info.z);
+	if (ret < 0) {
+		DRM_WARN("VDRM: failed get plane node of %s\n",
+			 of_node_full_name(np));
+		return ERR_PTR(ret);
+	}
+
+	vdrm_driver.prime_handle_to_fd = dev->driver->prime_handle_to_fd;
+	vdrm_driver.prime_fd_to_handle = dev->driver->prime_fd_to_handle;
+	vdrm_driver.gem_prime_import_sg_table =
+		dev->driver->gem_prime_import_sg_table;
+	vdrm_driver.gem_prime_mmap = dev->driver->gem_prime_mmap;
+
+	vdrm = devm_drm_dev_alloc(dev->dev, &vdrm_driver, struct vdrm_device,
+				  ddev);
+	if (IS_ERR(vdrm))
+		return vdrm;
+
+	vdrm->parent = dev;
+	vdrm->funcs = funcs;
+	vdrm->of_plane_info = plane_info;
+
+	INIT_LIST_HEAD(&vdrm->disps);
+
+	ret = drmm_mode_config_init(&vdrm->ddev);
+	if (ret)
+		goto failed;
+
+	vdrm->ddev.mode_config.min_width = 0;
+	vdrm->ddev.mode_config.min_height = 0;
+	vdrm->ddev.mode_config.max_width = 8190;
+	vdrm->ddev.mode_config.max_height = 8190;
+	vdrm->ddev.mode_config.normalize_zpos = true;
+	vdrm->ddev.mode_config.funcs = &vdrm_mode_config_funcs;
+
+	ret = vdrm_properties_init(vdrm, num_props, props);
+	if (ret < 0)
+		goto failed;
+
+	drm_dev_set_unique(&vdrm->ddev, of_node_full_name(np));
+	return vdrm;
+
+failed:
+	kfree(vdrm);
+	return ERR_PTR(ret);
+}
+
+/**
+ * vdrm_drv_plane_init - Initialize the plane used by vDRM
+ * @vdrm: vDRM object
+ * @plane: plane to assign to vDRM
+ * @funcs: callbacks for the plane
+ * @helper_funcs: helper vtable to set for plane
+ * @formats: color formats
+ * @num_formats: number of color formats
+ * @max_zpos: max value for zpos property of plane
+ *
+ * Initializes a plane object of PRIMARY type by drm_universal_plane_init()
+ * and initializes @plane's properties. The property passed by vdrm_drv_init()
+ * is set to @plane.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int vdrm_drv_plane_init(struct vdrm_device *vdrm, struct drm_plane *plane,
+			const struct drm_plane_funcs *funcs,
+			const struct drm_plane_helper_funcs *helper_funcs,
+			const u32 *formats, unsigned int num_formats,
+			int max_zpos)
+{
+	struct vdrm_display *disp;
+	int i, ret;
+
+	disp = kzalloc(sizeof(*disp), GFP_KERNEL);
+	if (!disp)
+		return -ENOMEM;
+
+	disp->dev = vdrm;
+	disp->plane = plane;
+	disp->plane_info = vdrm->of_plane_info;
+
+	disp->parent_plane_funcs = funcs;
+	disp->parent_plane_helper_funcs = helper_funcs;
+	disp->plane_funcs = *funcs;
+	disp->plane_helper_funcs = *helper_funcs;
+
+	disp->plane_funcs.reset = vdrm_plane_reset;
+	disp->plane_funcs.atomic_set_property = vdrm_plane_set_property;
+	disp->plane_funcs.atomic_get_property = vdrm_plane_get_property;
+	disp->plane_helper_funcs.atomic_update = vdrm_plane_update;
+
+	drm_plane_helper_add(disp->plane, &disp->plane_helper_funcs);
+	ret = drm_universal_plane_init(&vdrm->ddev, plane, 0,
+				       &disp->plane_funcs, formats,
+				       num_formats, NULL,
+				       DRM_PLANE_TYPE_PRIMARY, NULL);
+	if (ret) {
+		kfree(disp);
+		return ret;
+	}
+
+	drm_plane_create_alpha_property(plane);
+	drm_plane_create_zpos_property(plane, disp->plane_info.z, 0, max_zpos);
+	drm_object_attach_property(&plane->base,
+				   vdrm->plane_props.offset_x,
+				   disp->plane_info.x);
+	drm_object_attach_property(&plane->base,
+				   vdrm->plane_props.offset_y,
+				   disp->plane_info.y);
+	drm_object_attach_property(&plane->base,
+				   vdrm->plane_props.width,
+				   disp->plane_info.width);
+	drm_object_attach_property(&plane->base,
+				   vdrm->plane_props.height,
+				   disp->plane_info.height);
+	for (i = 0; i < vdrm->num_props; i++) {
+		drm_object_attach_property(&plane->base,
+					   vdrm->props[i].prop,
+					   vdrm->props[i].default_val);
+	}
+
+	INIT_LIST_HEAD(&disp->head);
+	list_add_tail(&disp->head, &vdrm->disps);
+	vdrm->num_crtcs++;
+	return 0;
+}
+
+/**
+ * vdrm_drv_display_init - Initialize the vDRM display object
+ * @vdrm: vDRM object
+ * @crtc: parent crtc to be linked with the vDRM crtc
+ * @plane: plane assigned to vDRM
+ *
+ * Initializes crtc, connector and encorder, and links @crtc to crtc of vDRM.
+ *
+ * Returns:
+ * vDRM display object on success, error code encoded into the pointer on
+ * failure.
+ */
+struct vdrm_display *vdrm_drv_display_init(struct vdrm_device *vdrm,
+					   struct drm_crtc *crtc,
+					   struct drm_plane *plane)
+{
+	struct vdrm_display *disp;
+	int ret;
+
+	disp = vdrm_plane_find_display(vdrm, plane);
+	if (!disp)
+		return ERR_PTR(-EINVAL);
+
+	drm_crtc_helper_add(&disp->crtc, &vdrm_crtc_helper_funcs);
+	ret = drm_crtc_init_with_planes(&vdrm->ddev, &disp->crtc, plane, NULL,
+					&vdrm_crtc_funcs, NULL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	drm_connector_helper_add(&disp->connector, &vdrm_conn_helper_funcs);
+	ret = drm_connector_init(&vdrm->ddev, &disp->connector,
+				 &vdrm_conn_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	disp->encoder.possible_crtcs = drm_crtc_mask(&disp->crtc);
+	ret = drm_encoder_init(&vdrm->ddev, &disp->encoder, &vdrm_encoder_funcs,
+			       DRM_MODE_ENCODER_NONE, NULL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = drm_connector_attach_encoder(&disp->connector, &disp->encoder);
+	if (ret)
+		return ERR_PTR(ret);
+
+	init_waitqueue_head(&disp->flip_wait);
+	disp->parent_crtc = crtc;
+
+	return disp;
+}
+
+/**
+ * vdrm_drv_register - Register vDRM device
+ * @vdrm: vDRM object
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int vdrm_drv_register(struct vdrm_device *vdrm)
+{
+	int ret;
+	struct drm_device *dev = &vdrm->ddev;
+
+	ret = drm_vblank_init(dev, vdrm->num_crtcs);
+	if (ret)
+		return ret;
+
+	drm_mode_config_reset(dev);
+
+	ret = drm_dev_register(dev, 0);
+	if (ret)
+		return ret;
+
+	dev->irq_enabled = true;
+
+	DRM_INFO("Virtual Device is initialized.\n");
+
+	vdrm_dump(vdrm);
+
+	return 0;
+}
+
+/**
+ * vdrm_drv_fini - release vDRM resources
+ * @vdrm: vDRM object
+ */
+void vdrm_drv_fini(struct vdrm_device *vdrm)
+{
+	struct vdrm_display *disp;
+
+	if (vdrm->ddev.registered)
+		drm_dev_unregister(&vdrm->ddev);
+	drm_mode_config_cleanup(&vdrm->ddev);
+
+	list_for_each_entry(disp, &vdrm->disps, head)
+		kfree(disp);
+}
diff --git a/drivers/gpu/drm/vdrm/vdrm_drv.h b/drivers/gpu/drm/vdrm/vdrm_drv.h
new file mode 100644
index 000000000000..67b8e02efddf
--- /dev/null
+++ b/drivers/gpu/drm/vdrm/vdrm_drv.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * vdrm_drv.h -- Virtual DRM driver
+ *
+ * Copyright (C) 2021 Renesas Electronics Corporation
+ */
+
+#ifndef __VDRM_DRV_H__
+#define __VDRM_DRV_H__
+
+#include <drm/drm_device.h>
+
+#include "vdrm_api.h"
+
+struct vdrm_property {
+	struct drm_property *prop;
+	struct drm_property *parent_prop;
+	uint64_t default_val;
+};
+
+struct vdrm_plane_info {
+	int x;
+	int y;
+	unsigned int width;
+	unsigned int height;
+	unsigned int z;
+};
+
+struct vdrm_device;
+
+struct vdrm_display {
+	struct drm_connector connector;
+	struct drm_crtc crtc;
+	struct drm_crtc *parent_crtc;
+	struct drm_plane *plane;
+	struct drm_encoder encoder;
+	struct drm_pending_vblank_event *event;
+	struct vdrm_device *dev;
+	bool vblank_enabled;
+	wait_queue_head_t flip_wait;
+	bool crtc_enabled;
+	int vblank_count;
+
+	struct list_head head;
+
+	struct vdrm_plane_info plane_info;
+
+	const struct drm_plane_funcs *parent_plane_funcs;
+	const struct drm_plane_helper_funcs *parent_plane_helper_funcs;
+	struct drm_plane_funcs plane_funcs;
+	struct drm_plane_helper_funcs plane_helper_funcs;
+};
+
+struct vdrm_device {
+	struct drm_device ddev;
+	struct drm_device *parent;
+
+	int num_crtcs;
+	struct list_head disps;
+
+	const struct vdrm_funcs *funcs;
+	struct vdrm_property *props;
+	int num_props;
+
+	struct {
+		struct drm_property *offset_x;
+		struct drm_property *offset_y;
+		struct drm_property *width;
+		struct drm_property *height;
+	} plane_props;
+
+	struct vdrm_plane_info of_plane_info;
+};
+
+static inline struct vdrm_device *to_vdrm_device(struct drm_device *dev)
+{
+	return container_of(dev, struct vdrm_device, ddev);
+}
+
+#endif /* __VDRM_DRV_H__ */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATH 1/4] drm: Add Virtual DRM device driver
@ 2021-06-21  6:44   ` Tomohito Esaki
  0 siblings, 0 replies; 61+ messages in thread
From: Tomohito Esaki @ 2021-06-21  6:44 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: devicetree, linux-doc, linux-kernel, dri-devel,
	linux-renesas-soc, Tomohito Esaki

Virtual DRM splits the resources of an overlay plane into multiple
virtual devices to allow each plane to be accessed by each process.

This makes it possible to overlay images output from multiple processes
on a display. For example, one process displays the camera image without
compositor while another process overlays the compositor's drawing of
the UI.

The virtual DRM creates standalone virtual device and make DRM planes
from a master device (e.g. card0) accessible via one or more virtual
devices. However, these plane are no longer accessible from the original
device.
Each virtual device (and plane) can be accessed via a separate
device file.

Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
---
 drivers/gpu/drm/Kconfig         |   7 +
 drivers/gpu/drm/Makefile        |   1 +
 drivers/gpu/drm/vdrm/vdrm_api.h |  68 +++
 drivers/gpu/drm/vdrm/vdrm_drv.c | 859 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/vdrm/vdrm_drv.h |  80 +++
 5 files changed, 1015 insertions(+)
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_api.h
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.c
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 3c16bd1afd87..ba7f4eeab385 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -294,6 +294,13 @@ config DRM_VKMS
 
 	  If M is selected the module will be called vkms.
 
+config DRM_VDRM
+	tristate "Virtual DRM"
+	depends on DRM
+	help
+	  Virtual DRM splits the resources of an overlay plane into multiple
+	  virtual devices to allow each plane to be accessed by each process.
+
 source "drivers/gpu/drm/exynos/Kconfig"
 
 source "drivers/gpu/drm/rockchip/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 5279db4392df..55dbf85e2579 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
 obj-$(CONFIG_DRM_VIA)	+=via/
 obj-$(CONFIG_DRM_VGEM)	+= vgem/
 obj-$(CONFIG_DRM_VKMS)	+= vkms/
+obj-$(CONFIG_DRM_VDRM)	+= vdrm/
 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
 obj-$(CONFIG_DRM_EXYNOS) +=exynos/
 obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
diff --git a/drivers/gpu/drm/vdrm/vdrm_api.h b/drivers/gpu/drm/vdrm/vdrm_api.h
new file mode 100644
index 000000000000..dd4d7e774800
--- /dev/null
+++ b/drivers/gpu/drm/vdrm/vdrm_api.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * vdrm_api.h -- Virtual DRM API
+ *
+ * Copyright (C) 2021 Renesas Electronics Corporation
+ */
+
+#ifndef __VDRM_API__
+#define __VDRM_API__
+
+#include <linux/of_device.h>
+#include <drm/drm_crtc.h>
+
+/**
+ * struct vdrm_property_info - Information about the properties passed from
+ *			       the DRM driver to vDRM
+ * @prop: Parent property to pass to vDRM
+ * @default_val: Default value for the property passed to vDRM
+ */
+struct vdrm_property_info {
+	struct drm_property *prop;
+	uint64_t default_val;
+};
+
+/**
+ * struct vdrm_funcs - Callbacks to parent DRM driver
+ */
+struct vdrm_funcs {
+	/**
+	 * @dumb_create:
+	 *
+	 * Called by &drm_driver.dumb_create. Please read the documentation
+	 * for the &drm_driver.dumb_create hook for more details.
+	 */
+	int (*dumb_create)(struct drm_file *file, struct drm_device *dev,
+			   struct drm_mode_create_dumb *args);
+
+	/**
+	 * @crtc_flush:
+	 *
+	 * Called by &drm_crtc_helper_funcs.atomic_flush. Please read the
+	 * documentation for the &drm_crtc_helper_funcs.atomic_flush hook for
+	 * more details.
+	 */
+	void (*crtc_flush)(struct drm_crtc *crtc);
+};
+
+struct vdrm_device;
+struct vdrm_display;
+
+void vdrm_drv_handle_vblank(struct vdrm_display *vdisplay);
+void vdrm_drv_finish_page_flip(struct vdrm_display *vdisplay);
+struct vdrm_device *vdrm_drv_init(struct drm_device *dev,
+				  struct device_node *np, int num_props,
+				  struct vdrm_property_info *props,
+				  const struct vdrm_funcs *funcs);
+int vdrm_drv_plane_init(struct vdrm_device *vdrm, struct drm_plane *plane,
+			const struct drm_plane_funcs *funcs,
+			const struct drm_plane_helper_funcs *helper_funcs,
+			const u32 *formats, unsigned int num_formats,
+			int max_zpos);
+struct vdrm_display *vdrm_drv_display_init(struct vdrm_device *vdrm,
+					   struct drm_crtc *crtc,
+					   struct drm_plane *plane);
+int vdrm_drv_register(struct vdrm_device *vdrm);
+void vdrm_drv_fini(struct vdrm_device *vdrm);
+
+#endif /* __VDRM_API__ */
diff --git a/drivers/gpu/drm/vdrm/vdrm_drv.c b/drivers/gpu/drm/vdrm/vdrm_drv.c
new file mode 100644
index 000000000000..835bdecfc8e6
--- /dev/null
+++ b/drivers/gpu/drm/vdrm/vdrm_drv.c
@@ -0,0 +1,859 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * vdrm_drv.c -- Virtual DRM driver
+ *
+ * Copyright (C) 2021 Renesas Electronics Corporation
+ *
+ * This driver is based on drivers/gpu/drm/drm_simple_kms_helper.c.
+ */
+
+#include <linux/of_device.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <video/videomode.h>
+
+#include "vdrm_drv.h"
+
+static inline struct vdrm_display *
+to_vdrm_display(struct drm_connector *connector)
+{
+	return container_of(connector, struct vdrm_display, connector);
+}
+
+static inline struct vdrm_display *
+crtc_to_vdrm_display(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct vdrm_display, crtc);
+}
+
+static int vdrm_dumb_create(struct drm_file *file, struct drm_device *dev,
+			    struct drm_mode_create_dumb *args)
+{
+	struct vdrm_device *vdrm = to_vdrm_device(dev);
+
+	return vdrm->funcs->dumb_create(file, dev, args);
+}
+
+struct vdrm_framebuffer {
+	struct drm_framebuffer fb;
+	struct drm_framebuffer *parent_fb;
+};
+
+static inline struct vdrm_framebuffer *
+to_vdrm_framebuffer(struct drm_framebuffer *fb)
+{
+	return container_of(fb, struct vdrm_framebuffer, fb);
+}
+
+static void vdrm_fb_destroy(struct drm_framebuffer *fb)
+{
+	struct vdrm_framebuffer *vfb = to_vdrm_framebuffer(fb);
+
+	vfb->parent_fb->funcs->destroy(vfb->parent_fb);
+	drm_framebuffer_cleanup(fb);
+	kfree(vfb);
+}
+
+static const struct drm_framebuffer_funcs vdrm_fb_funcs = {
+	.destroy = vdrm_fb_destroy,
+};
+
+static int vdrm_fb_init(struct drm_device *dev, struct vdrm_framebuffer *vfb)
+{
+	vfb->fb = *vfb->parent_fb;
+	vfb->fb.dev = dev;
+
+	return drm_framebuffer_init(dev, &vfb->fb, &vdrm_fb_funcs);
+}
+
+static struct drm_framebuffer *
+vdrm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
+	       const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	struct vdrm_device *vdrm = to_vdrm_device(dev);
+	const struct drm_mode_config_funcs *mode_config_funcs =
+		vdrm->parent->mode_config.funcs;
+	struct vdrm_framebuffer *vfb;
+	struct drm_framebuffer *fb;
+	int ret;
+
+	vfb = kzalloc(sizeof(*vfb), GFP_KERNEL);
+	if (!vfb)
+		return ERR_PTR(-ENOMEM);
+
+	fb = mode_config_funcs->fb_create(vdrm->parent, file_priv, mode_cmd);
+	if (IS_ERR(fb)) {
+		kfree(vfb);
+		return fb;
+	}
+
+	vfb->parent_fb = fb;
+	ret = vdrm_fb_init(dev, vfb);
+	if (ret) {
+		fb->funcs->destroy(fb);
+		kfree(vfb);
+		return ERR_PTR(ret);
+	}
+
+	return &vfb->fb;
+}
+
+static const struct drm_mode_config_funcs vdrm_mode_config_funcs = {
+	.fb_create = vdrm_fb_create,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static struct drm_display_mode *vdrm_create_mode(struct vdrm_display *disp)
+{
+	struct drm_display_mode *mode;
+	struct videomode videomode;
+
+	mode = drm_mode_create(&disp->dev->ddev);
+	if (!mode)
+		return NULL;
+
+	memset(&videomode, 0, sizeof(videomode));
+	videomode.hactive = disp->plane_info.width;
+	videomode.vactive = disp->plane_info.height;
+	videomode.pixelclock =
+		disp->parent_crtc->state->adjusted_mode.crtc_clock * 1000;
+	mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
+	drm_display_mode_from_videomode(&videomode, mode);
+
+	return mode;
+}
+
+static int vdrm_connector_get_mode(struct drm_connector *connector)
+{
+	struct vdrm_display *disp = to_vdrm_display(connector);
+	struct drm_display_mode *mode = vdrm_create_mode(disp);
+
+	if (!mode)
+		return 0;
+
+	drm_mode_probed_add(connector, mode);
+	return 1;
+}
+
+static const struct drm_connector_helper_funcs vdrm_conn_helper_funcs = {
+	.get_modes = vdrm_connector_get_mode,
+};
+
+/*
+ * TODO:
+ *  At the time this callback is called, the parent CRTC must be connected.
+ *  Since this callback will not be called when detect() callback of the
+ *  parent connector is called, vDRM driver desn't support hotplug.
+ *  In the future, it is necessary that hotplug is supported.
+ */
+static enum drm_connector_status
+vdrm_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct vdrm_display *disp = to_vdrm_display(connector);
+	struct vdrm_device *vdrm = to_vdrm_device(connector->dev);
+	struct drm_connector *conn;
+	struct drm_connector_list_iter conn_iter;
+
+	drm_connector_list_iter_begin(vdrm->parent, &conn_iter);
+	drm_for_each_connector_iter(conn, &conn_iter) {
+		if (!conn->state)
+			continue;
+
+		if (conn->state->crtc == disp->parent_crtc) {
+			drm_connector_list_iter_end(&conn_iter);
+			return connector_status_connected;
+		}
+	}
+	drm_connector_list_iter_end(&conn_iter);
+	return connector_status_disconnected;
+}
+
+static const struct drm_connector_funcs vdrm_conn_funcs = {
+	.reset = drm_atomic_helper_connector_reset,
+	.detect = vdrm_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static void vdrm_drv_finish_page_flip_internal(struct vdrm_display *disp)
+{
+	struct drm_device *dev = &disp->dev->ddev;
+	struct drm_pending_vblank_event *event;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	event = disp->event;
+	disp->event = NULL;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	if (event == NULL)
+		return;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	drm_crtc_send_vblank_event(&disp->crtc, event);
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	if (disp->vblank_count) {
+		drm_crtc_vblank_put(&disp->crtc);
+		disp->vblank_count--;
+	}
+}
+
+static void vdrm_plane_update(struct drm_plane *plane,
+			      struct drm_atomic_state *state)
+{
+	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
+	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
+	struct drm_crtc *vcrtc_old_state = old_state->crtc;
+	struct drm_crtc *vcrtc_plane_state = new_state->crtc;
+	struct drm_crtc *crtc;
+	struct vdrm_display *vdisplay;
+
+	crtc = (old_state->crtc ? old_state->crtc : new_state->crtc);
+	if (WARN_ON(!crtc))
+		return;
+
+	vdisplay = crtc_to_vdrm_display(crtc);
+
+	old_state->crtc = vdisplay->parent_crtc;
+	new_state->crtc = vdisplay->parent_crtc;
+
+	new_state->dst.x1 += vdisplay->plane_info.x;
+	new_state->dst.y1 += vdisplay->plane_info.y;
+	vdisplay->parent_plane_helper_funcs->atomic_update(plane, state);
+
+	old_state->crtc = vcrtc_old_state;
+	new_state->crtc = vcrtc_plane_state;
+}
+
+static struct vdrm_display *
+vdrm_plane_find_display(struct vdrm_device *vdrm, struct drm_plane *plane)
+{
+	struct vdrm_display *disp;
+
+	list_for_each_entry(disp, &vdrm->disps, head) {
+		if (disp->plane == plane)
+			return disp;
+	}
+
+	return NULL;
+}
+
+static void vdrm_plane_reset(struct drm_plane *plane)
+{
+	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
+	struct vdrm_display *disp;
+
+	disp = vdrm_plane_find_display(vdrm, plane);
+	if (WARN_ON(!disp))
+		return;
+
+	disp->parent_plane_funcs->reset(plane);
+	plane->state->zpos = disp->plane_info.z;
+}
+
+static struct drm_property *
+vdrm_find_parent_property(struct vdrm_device *vdrm, struct drm_property *prop)
+{
+	int i;
+
+	for (i = 0; i < vdrm->num_props; i++) {
+		if (vdrm->props[i].prop == prop)
+			return vdrm->props[i].parent_prop;
+	}
+
+	return NULL;
+}
+
+static int vdrm_plane_set_property(struct drm_plane *plane,
+				   struct drm_plane_state *state,
+				   struct drm_property *property,
+				   uint64_t val)
+{
+	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
+	struct vdrm_display *disp;
+	struct drm_property *parent_prop;
+
+	disp = vdrm_plane_find_display(vdrm, plane);
+	if (WARN_ON(!disp))
+		return -EINVAL;
+
+	parent_prop = vdrm_find_parent_property(vdrm, property);
+	if (parent_prop && disp->parent_plane_funcs->atomic_set_property)
+		return disp->parent_plane_funcs->atomic_set_property(plane,
+								state,
+								parent_prop,
+								val);
+
+	if (vdrm->plane_props.offset_x == property) {
+		if (val > disp->parent_crtc->mode.hdisplay)
+			return -EINVAL;
+		disp->plane_info.x = val;
+	} else if (vdrm->plane_props.offset_y == property) {
+		if (val > disp->parent_crtc->mode.vdisplay)
+			return -EINVAL;
+		disp->plane_info.y = val;
+	} else if (vdrm->plane_props.width == property) {
+		if (val > disp->parent_crtc->mode.hdisplay)
+			return -EINVAL;
+		disp->plane_info.width = val;
+	} else if (vdrm->plane_props.height == property) {
+		if (val > disp->parent_crtc->mode.vdisplay)
+			return -EINVAL;
+		disp->plane_info.height = val;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vdrm_plane_get_property(struct drm_plane *plane,
+				   const struct drm_plane_state *state,
+				   struct drm_property *property,
+				   uint64_t *val)
+{
+	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
+	struct vdrm_display *disp;
+	struct drm_property *parent_prop;
+
+	disp = vdrm_plane_find_display(vdrm, plane);
+	if (WARN_ON(!disp))
+		return -EINVAL;
+
+	parent_prop = vdrm_find_parent_property(vdrm, property);
+	if (parent_prop && disp->parent_plane_funcs->atomic_get_property)
+		return disp->parent_plane_funcs->atomic_get_property(plane,
+								state,
+								parent_prop,
+								val);
+
+	if (vdrm->plane_props.offset_x == property)
+		*val = disp->plane_info.x;
+	else if (vdrm->plane_props.offset_y == property)
+		*val = disp->plane_info.y;
+	else if (vdrm->plane_props.width == property)
+		*val = disp->plane_info.width;
+	else if (vdrm->plane_props.height == property)
+		*val = disp->plane_info.height;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vdrm_crtc_check(struct drm_crtc *crtc,
+			   struct drm_atomic_state *state)
+{
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
+	bool has_primary = crtc_state->plane_mask &
+				drm_plane_mask(crtc->primary);
+
+	/* We always want to have an active plane with an active CRTC */
+	if (has_primary != crtc_state->enable)
+		return -EINVAL;
+
+	return drm_atomic_add_affected_planes(state, crtc);
+}
+
+static void vdrm_crtc_flush(struct drm_crtc *crtc,
+			    struct drm_atomic_state *state)
+{
+	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
+	struct vdrm_device *vdrm = disp->dev;
+
+	if (crtc->state->event) {
+		struct drm_device *dev = crtc->dev;
+		unsigned long flags;
+
+		if (disp->crtc_enabled) {
+			WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+			disp->vblank_count++;
+		}
+
+		spin_lock_irqsave(&dev->event_lock, flags);
+		disp->event = crtc->state->event;
+		crtc->state->event = NULL;
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+	}
+
+	if (vdrm->funcs->crtc_flush)
+		vdrm->funcs->crtc_flush(disp->parent_crtc);
+}
+
+static void vdrm_crtc_enable(struct drm_crtc *crtc,
+			     struct drm_atomic_state *state)
+{
+	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
+
+	drm_crtc_vblank_on(crtc);
+	disp->crtc_enabled = true;
+}
+
+static void vdrm_crtc_disable(struct drm_crtc *crtc,
+			      struct drm_atomic_state *state)
+{
+	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
+	unsigned long flags;
+	bool pending;
+
+	disp->crtc_enabled = false;
+	drm_crtc_vblank_off(crtc);
+
+	spin_lock_irqsave(&crtc->dev->event_lock, flags);
+	pending = disp->event != NULL;
+	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
+	if (!wait_event_timeout(disp->flip_wait, !pending,
+				msecs_to_jiffies(50))) {
+		DRM_WARN("VDRM: page flip timeout\n");
+		vdrm_drv_finish_page_flip_internal(disp);
+	}
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	if (crtc->state->event) {
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static const struct drm_crtc_helper_funcs vdrm_crtc_helper_funcs = {
+	.atomic_check = vdrm_crtc_check,
+	.atomic_flush = vdrm_crtc_flush,
+	.atomic_enable = vdrm_crtc_enable,
+	.atomic_disable = vdrm_crtc_disable,
+};
+
+static int vdrm_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+	struct vdrm_display *disp;
+
+	disp = crtc_to_vdrm_display(crtc);
+	disp->vblank_enabled = true;
+
+	return 0;
+}
+
+static void vdrm_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+	struct vdrm_display *disp;
+
+	disp = crtc_to_vdrm_display(crtc);
+	disp->vblank_enabled = false;
+}
+
+static const struct drm_crtc_funcs vdrm_crtc_funcs = {
+	.reset = drm_atomic_helper_crtc_reset,
+	.destroy = drm_crtc_cleanup,
+	.set_config = drm_atomic_helper_set_config,
+	.page_flip = drm_atomic_helper_page_flip,
+	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+	.enable_vblank = vdrm_crtc_enable_vblank,
+	.disable_vblank = vdrm_crtc_disable_vblank,
+};
+static const struct drm_encoder_funcs vdrm_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static int vdrm_properties_init(struct vdrm_device *vdrm, int num_props,
+				struct vdrm_property_info *props)
+{
+	int i;
+	unsigned int w = vdrm->ddev.mode_config.max_width;
+	unsigned int h = vdrm->ddev.mode_config.max_height;
+
+	vdrm->plane_props.offset_x =
+		drm_property_create_range(&vdrm->ddev, 0, "vdrm_offset_x", 0, w);
+	if (!vdrm->plane_props.offset_x)
+		return -1;
+	vdrm->plane_props.offset_y =
+		drm_property_create_range(&vdrm->ddev, 0, "vdrm_offset_y", 0, h);
+	if (!vdrm->plane_props.offset_y)
+		return -1;
+	vdrm->plane_props.width =
+		drm_property_create_range(&vdrm->ddev, 0, "vdrm_width", 1, w);
+	if (!vdrm->plane_props.width)
+		return -1;
+	vdrm->plane_props.height =
+		drm_property_create_range(&vdrm->ddev, 0, "vdrm_height", 1, h);
+	if (!vdrm->plane_props.height)
+		return -1;
+
+	if (num_props == 0)
+		return 0;
+
+	vdrm->props = devm_kzalloc(vdrm->parent->dev,
+				    sizeof(*vdrm->props) * num_props,
+				    GFP_KERNEL);
+	if (!vdrm->props)
+		return -ENOMEM;
+
+	for (i = 0; i < num_props; i++) {
+		struct drm_property *p = props[i].prop;
+
+		vdrm->props[i].prop =
+			drm_property_create_range(&vdrm->ddev, p->flags,
+						  p->name, p->values[0],
+						  p->values[1]);
+		if (!vdrm->props[i].prop)
+			goto err;
+
+		vdrm->props[i].parent_prop = p;
+		vdrm->props[i].default_val = props[i].default_val;
+	}
+	vdrm->num_props = num_props;
+
+	return 0;
+
+err:
+	for (i--; i >= 0; i--)
+		drm_property_destroy(&vdrm->ddev, vdrm->props[i].prop);
+	devm_kfree(vdrm->parent->dev, vdrm->props);
+	return -1;
+}
+
+static int vdrm_of_get_plane(struct device_node *np,
+			     int *x, int *y, int *width, int *height, int *z)
+{
+	struct device_node *child;
+	int ret;
+
+	child = of_get_next_child(np, NULL);
+	if (!child)
+		return -ENODEV;
+
+	ret = of_property_read_u32(child, "x", x);
+	ret |= of_property_read_u32(child, "y", y);
+	ret |= of_property_read_u32(child, "width", width);
+	ret |= of_property_read_u32(child, "height", height);
+	ret |= of_property_read_u32(child, "zpos", z);
+
+	of_node_put(child);
+	return ret;
+}
+
+static void vdrm_dump(struct vdrm_device *vdrm)
+{
+	struct vdrm_display *disp;
+
+	DRM_INFO("Virtual DRM Info:\n");
+	list_for_each_entry(disp, &vdrm->disps, head) {
+		DRM_INFO("\tCONNECTOR: %d\n",
+			 disp->connector.base.id);
+		DRM_INFO("\tCRTC: %d\n",
+			 disp->crtc.base.id);
+		DRM_INFO("\tENCODER: %d\n",
+			 disp->encoder.base.id);
+		DRM_INFO("\tPLANE: %d\n",
+			 disp->plane->base.id);
+		DRM_INFO("\tParent CRTC: %d\n",
+			 disp->parent_crtc->base.id);
+	}
+}
+
+/**
+ * vdrm_drv_handle_vblank - handle a vblank event for vDRM
+ * @vdisplay: vDRM display object
+ */
+void vdrm_drv_handle_vblank(struct vdrm_display *vdisplay)
+{
+	if (vdisplay->vblank_enabled)
+		drm_crtc_handle_vblank(&vdisplay->crtc);
+}
+
+/**
+ * vdrm_drv_finish_page_flip - handle a page flip event for vDRM
+ * @vdisplay: vDRM display object
+ */
+void vdrm_drv_finish_page_flip(struct vdrm_display *vdisplay)
+{
+	vdrm_drv_finish_page_flip_internal(vdisplay);
+}
+
+DEFINE_DRM_GEM_CMA_FOPS(vdrm_fops);
+
+static struct drm_driver vdrm_driver = {
+	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+	.dumb_create = vdrm_dumb_create,
+	.fops = &vdrm_fops,
+	.name = "virt-drm",
+	.desc = "Virtual DRM driver",
+	.date = "20201104",
+	.major = 1,
+	.minor = 0,
+};
+
+/**
+ * vdrm_drv_init - Initialize vDRM device
+ * @dev: parent DRM device
+ * @np: vDRM device node in DTB
+ * @num_props: number of parent property objects
+ * @props: parent plane properties used in vDRM
+ * @funcs: callbacks for vDRM
+ *
+ * Allocates a new vDRM device, initializes mode_config of the vDRM device
+ * and allocates property objects. Not initialize plane, crtc, encoder and
+ * connector. Initialization of plane must be done in vdrm_drv_plane_init()
+ * and initialization of crtc, encoder and connector must be done by
+ * vdrm_drv_display_init(). Also, after initializing the plane, crtc,
+ * connector, and encoder, register vDRM device must be done by
+ * vdrm_drv_register().
+ *
+ * Returns:
+ * vDRM object (&vdrm_device) on success, error code encoded into the pointer
+ * on failure.
+ */
+struct vdrm_device *vdrm_drv_init(struct drm_device *dev,
+				  struct device_node *np, int num_props,
+				  struct vdrm_property_info *props,
+				  const struct vdrm_funcs *funcs)
+{
+	struct vdrm_device *vdrm;
+	struct vdrm_plane_info plane_info;
+	int ret;
+
+	if (!of_device_is_compatible(np, "virt-drm"))
+		return ERR_PTR(-ENODEV);
+
+	/* get plane information from device tree */
+	ret = vdrm_of_get_plane(np, &plane_info.x, &plane_info.y,
+				&plane_info.width, &plane_info.height,
+				&plane_info.z);
+	if (ret < 0) {
+		DRM_WARN("VDRM: failed get plane node of %s\n",
+			 of_node_full_name(np));
+		return ERR_PTR(ret);
+	}
+
+	vdrm_driver.prime_handle_to_fd = dev->driver->prime_handle_to_fd;
+	vdrm_driver.prime_fd_to_handle = dev->driver->prime_fd_to_handle;
+	vdrm_driver.gem_prime_import_sg_table =
+		dev->driver->gem_prime_import_sg_table;
+	vdrm_driver.gem_prime_mmap = dev->driver->gem_prime_mmap;
+
+	vdrm = devm_drm_dev_alloc(dev->dev, &vdrm_driver, struct vdrm_device,
+				  ddev);
+	if (IS_ERR(vdrm))
+		return vdrm;
+
+	vdrm->parent = dev;
+	vdrm->funcs = funcs;
+	vdrm->of_plane_info = plane_info;
+
+	INIT_LIST_HEAD(&vdrm->disps);
+
+	ret = drmm_mode_config_init(&vdrm->ddev);
+	if (ret)
+		goto failed;
+
+	vdrm->ddev.mode_config.min_width = 0;
+	vdrm->ddev.mode_config.min_height = 0;
+	vdrm->ddev.mode_config.max_width = 8190;
+	vdrm->ddev.mode_config.max_height = 8190;
+	vdrm->ddev.mode_config.normalize_zpos = true;
+	vdrm->ddev.mode_config.funcs = &vdrm_mode_config_funcs;
+
+	ret = vdrm_properties_init(vdrm, num_props, props);
+	if (ret < 0)
+		goto failed;
+
+	drm_dev_set_unique(&vdrm->ddev, of_node_full_name(np));
+	return vdrm;
+
+failed:
+	kfree(vdrm);
+	return ERR_PTR(ret);
+}
+
+/**
+ * vdrm_drv_plane_init - Initialize the plane used by vDRM
+ * @vdrm: vDRM object
+ * @plane: plane to assign to vDRM
+ * @funcs: callbacks for the plane
+ * @helper_funcs: helper vtable to set for plane
+ * @formats: color formats
+ * @num_formats: number of color formats
+ * @max_zpos: max value for zpos property of plane
+ *
+ * Initializes a plane object of PRIMARY type by drm_universal_plane_init()
+ * and initializes @plane's properties. The property passed by vdrm_drv_init()
+ * is set to @plane.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int vdrm_drv_plane_init(struct vdrm_device *vdrm, struct drm_plane *plane,
+			const struct drm_plane_funcs *funcs,
+			const struct drm_plane_helper_funcs *helper_funcs,
+			const u32 *formats, unsigned int num_formats,
+			int max_zpos)
+{
+	struct vdrm_display *disp;
+	int i, ret;
+
+	disp = kzalloc(sizeof(*disp), GFP_KERNEL);
+	if (!disp)
+		return -ENOMEM;
+
+	disp->dev = vdrm;
+	disp->plane = plane;
+	disp->plane_info = vdrm->of_plane_info;
+
+	disp->parent_plane_funcs = funcs;
+	disp->parent_plane_helper_funcs = helper_funcs;
+	disp->plane_funcs = *funcs;
+	disp->plane_helper_funcs = *helper_funcs;
+
+	disp->plane_funcs.reset = vdrm_plane_reset;
+	disp->plane_funcs.atomic_set_property = vdrm_plane_set_property;
+	disp->plane_funcs.atomic_get_property = vdrm_plane_get_property;
+	disp->plane_helper_funcs.atomic_update = vdrm_plane_update;
+
+	drm_plane_helper_add(disp->plane, &disp->plane_helper_funcs);
+	ret = drm_universal_plane_init(&vdrm->ddev, plane, 0,
+				       &disp->plane_funcs, formats,
+				       num_formats, NULL,
+				       DRM_PLANE_TYPE_PRIMARY, NULL);
+	if (ret) {
+		kfree(disp);
+		return ret;
+	}
+
+	drm_plane_create_alpha_property(plane);
+	drm_plane_create_zpos_property(plane, disp->plane_info.z, 0, max_zpos);
+	drm_object_attach_property(&plane->base,
+				   vdrm->plane_props.offset_x,
+				   disp->plane_info.x);
+	drm_object_attach_property(&plane->base,
+				   vdrm->plane_props.offset_y,
+				   disp->plane_info.y);
+	drm_object_attach_property(&plane->base,
+				   vdrm->plane_props.width,
+				   disp->plane_info.width);
+	drm_object_attach_property(&plane->base,
+				   vdrm->plane_props.height,
+				   disp->plane_info.height);
+	for (i = 0; i < vdrm->num_props; i++) {
+		drm_object_attach_property(&plane->base,
+					   vdrm->props[i].prop,
+					   vdrm->props[i].default_val);
+	}
+
+	INIT_LIST_HEAD(&disp->head);
+	list_add_tail(&disp->head, &vdrm->disps);
+	vdrm->num_crtcs++;
+	return 0;
+}
+
+/**
+ * vdrm_drv_display_init - Initialize the vDRM display object
+ * @vdrm: vDRM object
+ * @crtc: parent crtc to be linked with the vDRM crtc
+ * @plane: plane assigned to vDRM
+ *
+ * Initializes crtc, connector and encorder, and links @crtc to crtc of vDRM.
+ *
+ * Returns:
+ * vDRM display object on success, error code encoded into the pointer on
+ * failure.
+ */
+struct vdrm_display *vdrm_drv_display_init(struct vdrm_device *vdrm,
+					   struct drm_crtc *crtc,
+					   struct drm_plane *plane)
+{
+	struct vdrm_display *disp;
+	int ret;
+
+	disp = vdrm_plane_find_display(vdrm, plane);
+	if (!disp)
+		return ERR_PTR(-EINVAL);
+
+	drm_crtc_helper_add(&disp->crtc, &vdrm_crtc_helper_funcs);
+	ret = drm_crtc_init_with_planes(&vdrm->ddev, &disp->crtc, plane, NULL,
+					&vdrm_crtc_funcs, NULL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	drm_connector_helper_add(&disp->connector, &vdrm_conn_helper_funcs);
+	ret = drm_connector_init(&vdrm->ddev, &disp->connector,
+				 &vdrm_conn_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	disp->encoder.possible_crtcs = drm_crtc_mask(&disp->crtc);
+	ret = drm_encoder_init(&vdrm->ddev, &disp->encoder, &vdrm_encoder_funcs,
+			       DRM_MODE_ENCODER_NONE, NULL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = drm_connector_attach_encoder(&disp->connector, &disp->encoder);
+	if (ret)
+		return ERR_PTR(ret);
+
+	init_waitqueue_head(&disp->flip_wait);
+	disp->parent_crtc = crtc;
+
+	return disp;
+}
+
+/**
+ * vdrm_drv_register - Register vDRM device
+ * @vdrm: vDRM object
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int vdrm_drv_register(struct vdrm_device *vdrm)
+{
+	int ret;
+	struct drm_device *dev = &vdrm->ddev;
+
+	ret = drm_vblank_init(dev, vdrm->num_crtcs);
+	if (ret)
+		return ret;
+
+	drm_mode_config_reset(dev);
+
+	ret = drm_dev_register(dev, 0);
+	if (ret)
+		return ret;
+
+	dev->irq_enabled = true;
+
+	DRM_INFO("Virtual Device is initialized.\n");
+
+	vdrm_dump(vdrm);
+
+	return 0;
+}
+
+/**
+ * vdrm_drv_fini - release vDRM resources
+ * @vdrm: vDRM object
+ */
+void vdrm_drv_fini(struct vdrm_device *vdrm)
+{
+	struct vdrm_display *disp;
+
+	if (vdrm->ddev.registered)
+		drm_dev_unregister(&vdrm->ddev);
+	drm_mode_config_cleanup(&vdrm->ddev);
+
+	list_for_each_entry(disp, &vdrm->disps, head)
+		kfree(disp);
+}
diff --git a/drivers/gpu/drm/vdrm/vdrm_drv.h b/drivers/gpu/drm/vdrm/vdrm_drv.h
new file mode 100644
index 000000000000..67b8e02efddf
--- /dev/null
+++ b/drivers/gpu/drm/vdrm/vdrm_drv.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * vdrm_drv.h -- Virtual DRM driver
+ *
+ * Copyright (C) 2021 Renesas Electronics Corporation
+ */
+
+#ifndef __VDRM_DRV_H__
+#define __VDRM_DRV_H__
+
+#include <drm/drm_device.h>
+
+#include "vdrm_api.h"
+
+struct vdrm_property {
+	struct drm_property *prop;
+	struct drm_property *parent_prop;
+	uint64_t default_val;
+};
+
+struct vdrm_plane_info {
+	int x;
+	int y;
+	unsigned int width;
+	unsigned int height;
+	unsigned int z;
+};
+
+struct vdrm_device;
+
+struct vdrm_display {
+	struct drm_connector connector;
+	struct drm_crtc crtc;
+	struct drm_crtc *parent_crtc;
+	struct drm_plane *plane;
+	struct drm_encoder encoder;
+	struct drm_pending_vblank_event *event;
+	struct vdrm_device *dev;
+	bool vblank_enabled;
+	wait_queue_head_t flip_wait;
+	bool crtc_enabled;
+	int vblank_count;
+
+	struct list_head head;
+
+	struct vdrm_plane_info plane_info;
+
+	const struct drm_plane_funcs *parent_plane_funcs;
+	const struct drm_plane_helper_funcs *parent_plane_helper_funcs;
+	struct drm_plane_funcs plane_funcs;
+	struct drm_plane_helper_funcs plane_helper_funcs;
+};
+
+struct vdrm_device {
+	struct drm_device ddev;
+	struct drm_device *parent;
+
+	int num_crtcs;
+	struct list_head disps;
+
+	const struct vdrm_funcs *funcs;
+	struct vdrm_property *props;
+	int num_props;
+
+	struct {
+		struct drm_property *offset_x;
+		struct drm_property *offset_y;
+		struct drm_property *width;
+		struct drm_property *height;
+	} plane_props;
+
+	struct vdrm_plane_info of_plane_info;
+};
+
+static inline struct vdrm_device *to_vdrm_device(struct drm_device *dev)
+{
+	return container_of(dev, struct vdrm_device, ddev);
+}
+
+#endif /* __VDRM_DRV_H__ */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATH 2/4] rcar-du: Add support virtual DRM device
  2021-06-21  6:43 ` Tomohito Esaki
@ 2021-06-21  6:44   ` Tomohito Esaki
  -1 siblings, 0 replies; 61+ messages in thread
From: Tomohito Esaki @ 2021-06-21  6:44 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: dri-devel, linux-renesas-soc, linux-kernel, devicetree,
	linux-doc, Tomohito Esaki

In order to use vDRM, it is necessary that the vDRM device is registered
to du decice in the device tree.
The "vdrms" key is added in du node and the vDRM device node is specified.
For example:
----------
& du {
    ...
    vdrms = <&vdrm0>;
};
----------

Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
---
 drivers/gpu/drm/rcar-du/Kconfig        |   4 +
 drivers/gpu/drm/rcar-du/Makefile       |   1 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c |  42 ++++++
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  13 ++
 drivers/gpu/drm/rcar-du/rcar_du_drv.c  |  13 ++
 drivers/gpu/drm/rcar-du/rcar_du_drv.h  |   3 +
 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c | 191 +++++++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h |  67 +++++++++
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c  |  22 +++
 drivers/gpu/drm/rcar-du/rcar_du_vsp.h  |   1 +
 10 files changed, 357 insertions(+)
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h

diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index b47e74421e34..6747f69c8593 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -50,3 +50,7 @@ config DRM_RCAR_WRITEBACK
 	bool
 	default y if ARM64
 	depends on DRM_RCAR_DU
+
+config DRM_RCAR_DU_VDRM
+	tristate "Virtual DRM for R-Car DU"
+	depends on DRM_RCAR_DU && DRM_VDRM
diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
index 4d1187ccc3e5..b589b974a9f3 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -14,6 +14,7 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_of.o \
 					   rcar_du_of_lvds_r8a7796.dtb.o
 rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
 rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o
+rcar-du-drm-$(CONFIG_DRM_RCAR_DU_VDRM)	+= rcar_du_vdrm.o
 
 obj-$(CONFIG_DRM_RCAR_CMM)		+= rcar_cmm.o
 obj-$(CONFIG_DRM_RCAR_DU)		+= rcar-du-drm.o
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index ea7e39d03545..7d48db24090b 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -32,6 +32,11 @@
 #include "rcar_du_vsp.h"
 #include "rcar_lvds.h"
 
+#include "rcar_du_vdrm.h"
+#ifdef CONFIG_DRM_RCAR_DU_VDRM
+#include "../vdrm/vdrm_api.h"
+#endif
+
 static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg)
 {
 	struct rcar_du_device *rcdu = rcrtc->dev;
@@ -1293,5 +1298,42 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
 
 	rcar_du_crtc_crc_init(rcrtc);
 
+	INIT_LIST_HEAD(&rcrtc->vdrm_displays);
+	ret = rcar_du_vdrm_crtc_init(rcrtc, swindex);
+	if (ret < 0) {
+		dev_err(rcdu->dev,
+			"failed to initialize crtc %u for vDRM\n", swindex);
+		return ret;
+	}
+
+	return 0;
+}
+
+int rcar_du_crtc_add_vdrm_display(struct rcar_du_crtc *rcrtc,
+				  struct vdrm_display *vdisplay)
+{
+	struct rcar_du_vdrm_display *disp;
+
+	disp = kzalloc(sizeof(*disp), GFP_KERNEL);
+	if (!disp)
+		return -ENOMEM;
+
+	disp->display = vdisplay;
+	INIT_LIST_HEAD(&disp->head);
+	list_add_tail(&disp->head, &rcrtc->vdrm_displays);
+
 	return 0;
 }
+
+void rcar_du_crtc_remove_vdrm_displays(struct rcar_du_crtc *rcrtc)
+{
+	struct rcar_du_vdrm_display *disp, *tmp;
+
+	if (!rcrtc->dev)
+		return;
+
+	list_for_each_entry_safe(disp, tmp, &rcrtc->vdrm_displays, head) {
+		list_del(&disp->head);
+		kfree(disp);
+	}
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 5f2940c42225..1f749f0061e5 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -21,6 +21,12 @@
 
 struct rcar_du_group;
 struct rcar_du_vsp;
+struct vdrm_display;
+
+struct rcar_du_vdrm_display {
+	struct vdrm_display *display;
+	struct list_head head;
+};
 
 /**
  * struct rcar_du_crtc - the CRTC, representing a DU superposition processor
@@ -43,6 +49,7 @@ struct rcar_du_vsp;
  * @vsp: VSP feeding video to this CRTC
  * @vsp_pipe: index of the VSP pipeline feeding video to this CRTC
  * @writeback: the writeback connector
+ * @vdrm_displays: display list for virtual DRM
  */
 struct rcar_du_crtc {
 	struct drm_crtc crtc;
@@ -73,6 +80,8 @@ struct rcar_du_crtc {
 	unsigned int sources_count;
 
 	struct drm_writeback_connector writeback;
+
+	struct list_head vdrm_displays;
 };
 
 #define to_rcar_crtc(c)		container_of(c, struct rcar_du_crtc, crtc)
@@ -111,4 +120,8 @@ void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc);
 
 void rcar_du_crtc_dsysr_clr_set(struct rcar_du_crtc *rcrtc, u32 clr, u32 set);
 
+int rcar_du_crtc_add_vdrm_display(struct rcar_du_crtc *rcrtc,
+				  struct vdrm_display *vdisplay);
+void rcar_du_crtc_remove_vdrm_displays(struct rcar_du_crtc *rcrtc);
+
 #endif /* __RCAR_DU_CRTC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index bfbff90588cb..42f0f5e0144f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -29,6 +29,7 @@
 #include "rcar_du_kms.h"
 #include "rcar_du_of.h"
 #include "rcar_du_regs.h"
+#include "rcar_du_vdrm.h"
 
 /* -----------------------------------------------------------------------------
  * Device Information
@@ -552,6 +553,8 @@ static int rcar_du_remove(struct platform_device *pdev)
 	struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
 	struct drm_device *ddev = &rcdu->ddev;
 
+	rcar_du_vdrms_fini(rcdu);
+
 	drm_dev_unregister(ddev);
 
 	drm_kms_helper_poll_fini(ddev);
@@ -584,6 +587,11 @@ static int rcar_du_probe(struct platform_device *pdev)
 	if (IS_ERR(rcdu->mmio))
 		return PTR_ERR(rcdu->mmio);
 
+	/* Initialize the vDRM device */
+	ret = rcar_du_vdrms_init(rcdu);
+	if (ret < 0)
+		return ret;
+
 	/* DRM/KMS objects */
 	ret = rcar_du_modeset_init(rcdu);
 	if (ret < 0) {
@@ -607,6 +615,11 @@ static int rcar_du_probe(struct platform_device *pdev)
 
 	drm_fbdev_generic_setup(&rcdu->ddev, 32);
 
+	/* Register the vDRM device */
+	ret = rcar_du_vdrms_register(rcdu);
+	if (ret)
+		DRM_WARN("Setup virtual device failed.\n");
+
 	return 0;
 
 error:
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 02ca2d0e1b55..327f3a250cbe 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -97,6 +97,9 @@ struct rcar_du_device {
 	unsigned int dpad0_source;
 	unsigned int dpad1_source;
 	unsigned int vspd1_sink;
+
+	struct vdrm_device **vdrms;
+	int num_vdrms;
 };
 
 static inline struct rcar_du_device *to_rcar_du_device(struct drm_device *dev)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vdrm.c b/drivers/gpu/drm/rcar-du/rcar_du_vdrm.c
new file mode 100644
index 000000000000..1f09ead92418
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vdrm.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * rcar_du_vdrm.c -- R-Car Display Unit Virtual DRMs
+ *
+ * Copyright (C) 2021 Renesas Electronics Corporation
+ */
+
+#include <linux/of_device.h>
+
+#include <drm/drm_print.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <media/vsp1.h>
+
+#include "rcar_du_vdrm.h"
+#include "rcar_du_kms.h"
+#include "rcar_du_crtc.h"
+#include "rcar_du_vsp.h"
+
+static int rcar_du_vdrm_dumb_create(struct drm_file *file,
+				    struct drm_device *dev,
+				    struct drm_mode_create_dumb *args)
+{
+	/*
+	 * TODO:
+	 *   This is Warkarround.
+	 *   In the future, this function will be removed.
+	 *   The vdrm will be modified to directly call the dumb_create
+	 *   callback of the du driver.
+	 */
+	unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+	unsigned int align;
+
+	/*
+	 * The R8A7779 DU requires a 16 pixels pitch alignment as documented.
+	 */
+	align = 16 * args->bpp / 8;
+
+	args->pitch = roundup(min_pitch, align);
+
+	return drm_gem_cma_dumb_create_internal(file, dev, args);
+}
+
+static void rcar_du_vdrm_crtc_flush(struct drm_crtc *crtc)
+{
+	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+	rcar_du_vsp_atomic_flush(rcrtc);
+}
+
+static struct vdrm_funcs vdrm_funcs = {
+	.dumb_create = rcar_du_vdrm_dumb_create,
+	.crtc_flush = rcar_du_vdrm_crtc_flush,
+};
+
+void rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status)
+{
+	struct rcar_du_vdrm_display *disp;
+
+	list_for_each_entry(disp, &crtc->vdrm_displays, head) {
+		vdrm_drv_handle_vblank(disp->display);
+		if (status & VSP1_DU_STATUS_COMPLETE)
+			vdrm_drv_finish_page_flip(disp->display);
+	}
+}
+
+int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
+{
+	const struct device_node *np = rcdu->dev->of_node;
+	int num;
+
+	num = of_property_count_u32_elems(np, "vdrms");
+	if (num < 0)
+		return 0;
+
+	return num;
+}
+
+int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
+{
+	struct vdrm_device *vdrm;
+	int num_vdrms;
+	int i, ret;
+
+	num_vdrms = rcar_du_vdrm_count(rcdu);
+	if (num_vdrms == 0)
+		return 0;
+
+	rcdu->vdrms = kcalloc(num_vdrms, sizeof(vdrm), GFP_KERNEL);
+	if (!rcdu->vdrms)
+		return -1;
+
+	DRM_INFO("VDRM: num vdrm = %d\n", num_vdrms);
+
+	for (i = 0; i < num_vdrms; i++) {
+		struct of_phandle_args args;
+		const struct device_node *np = rcdu->dev->of_node;
+
+		ret = of_parse_phandle_with_fixed_args(np, "vdrms", 0, i,
+						       &args);
+		if (ret < 0) {
+			DRM_WARN("VDRM: failed get vdrm%d.\n", i);
+			goto err;
+		}
+
+		vdrm = vdrm_drv_init(&rcdu->ddev, args.np, 0, NULL,
+				     &vdrm_funcs);
+		of_node_put(args.np);
+		if (IS_ERR(vdrm)) {
+			ret = PTR_ERR(vdrm);
+			goto err;
+		}
+
+		rcdu->vdrms[i] = vdrm;
+		rcdu->num_vdrms++;
+	}
+
+	return 0;
+
+err:
+	rcar_du_vdrms_fini(rcdu);
+	rcdu->num_vdrms = 0;
+	return ret;
+}
+
+int rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
+			    struct rcar_du_vsp_plane *plane,
+			    const struct drm_plane_funcs *funcs,
+			    const struct drm_plane_helper_funcs *helper_funcs,
+			    const u32 *formats, unsigned int num_formats,
+			    int max_zpos)
+{
+	return vdrm_drv_plane_init(vdrm, &plane->plane, funcs,
+				   helper_funcs, formats, num_formats,
+				   max_zpos);
+}
+
+int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
+{
+	struct rcar_du_device *rcdu;
+	int i;
+
+	rcdu = crtc->dev;
+	for (i = 0; i < rcdu->num_vdrms; i++) {
+		struct vdrm_display *vdisplay;
+		int plane_index = crtc->vsp->num_planes + i;
+		struct drm_plane *plane =
+			&crtc->vsp->planes[plane_index].plane;
+
+		vdisplay = vdrm_drv_display_init(rcdu->vdrms[i], &crtc->crtc,
+						 plane);
+		if (IS_ERR(vdisplay))
+			return PTR_ERR(vdisplay);
+
+		rcar_du_crtc_add_vdrm_display(crtc, vdisplay);
+	}
+
+	return 0;
+}
+
+int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
+{
+	int i, ret;
+
+	for (i = 0; i < rcdu->num_vdrms; i++) {
+		ret = vdrm_drv_register(rcdu->vdrms[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+void rcar_du_vdrms_fini(struct rcar_du_device *rcdu)
+{
+	int i;
+
+	for (i = 0; i < rcdu->num_vdrms; i++) {
+		if (rcdu->vdrms[i])
+			vdrm_drv_fini(rcdu->vdrms[i]);
+	}
+
+	for (i = 0; i < RCAR_DU_MAX_CRTCS; i++)
+		rcar_du_crtc_remove_vdrm_displays(&rcdu->crtcs[i]);
+
+	kfree(rcdu->vdrms);
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vdrm.h b/drivers/gpu/drm/rcar-du/rcar_du_vdrm.h
new file mode 100644
index 000000000000..b12706ceee54
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vdrm.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * rcar_du_vdrm.h -- R-Car Display Unit Virtual DRMs
+ *
+ * Copyright (C) 2021 Renesas Electronics Corporation
+ */
+
+#ifndef __RCAR_DU_VDRM_H__
+#define __RCAR_DU_VDRM_H__
+
+#include <drm/drm_atomic.h>
+
+#include "rcar_du_drv.h"
+#include "../vdrm/vdrm_api.h"
+
+#ifdef CONFIG_DRM_RCAR_DU_VDRM
+
+void rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status);
+void rcar_du_vdrm_vblank_event(struct rcar_du_crtc *crtc);
+int rcar_du_vdrm_count(struct rcar_du_device *rcdu);
+int rcar_du_vdrms_init(struct rcar_du_device *rcdu);
+int rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
+			    struct rcar_du_vsp_plane *plane,
+			    const struct drm_plane_funcs *funcs,
+			    const struct drm_plane_helper_funcs *helper_funcs,
+			    const u32 *formats, unsigned int num_formats,
+			    int max_zpos);
+int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index);
+int rcar_du_vdrms_register(struct rcar_du_device *rcdu);
+void rcar_du_vdrms_fini(struct rcar_du_device *rcdu);
+
+#else
+
+static inline void
+rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status) { }
+static inline void rcar_du_vdrm_vblank_event(struct rcar_du_crtc *crtc) { }
+static inline int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
+{
+	return 0;
+}
+static inline int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
+{
+	return 0;
+}
+static inline int
+rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
+			struct rcar_du_vsp_plane *plane,
+			const struct drm_plane_funcs *funcs,
+			const struct drm_plane_helper_funcs *helper_funcs,
+			const u32 *formats, unsigned int num_formats,
+			int max_zpos)
+{
+	return 0;
+}
+static inline int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
+{
+	return 0;
+}
+static inline int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
+{
+	return 0;
+}
+static inline void rcar_du_vdrms_fini(struct rcar_du_device *rcdu) { }
+
+#endif
+
+#endif /* __RCAR_DU_VDRM_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index 23e41c83c875..7666441f0005 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -31,6 +31,7 @@
 #include "rcar_du_kms.h"
 #include "rcar_du_vsp.h"
 #include "rcar_du_writeback.h"
+#include "rcar_du_vdrm.h"
 
 static void rcar_du_vsp_complete(void *private, unsigned int status, u32 crc)
 {
@@ -45,6 +46,8 @@ static void rcar_du_vsp_complete(void *private, unsigned int status, u32 crc)
 		rcar_du_writeback_complete(crtc);
 
 	drm_crtc_add_crc_entry(&crtc->crtc, false, 0, &crc);
+
+	rcar_du_vdrm_crtc_complete(crtc, status);
 }
 
 void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
@@ -373,6 +376,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
 	unsigned int num_planes;
 	unsigned int i;
 	int ret;
+	int num_vdrms;
+	int vdrm_index = 0;
 
 	/* Find the VSP device and initialize it. */
 	pdev = of_find_device_by_node(np);
@@ -395,6 +400,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
 	  */
 	num_planes = rcdu->info->gen >= 3 ? 5 : 4;
 
+	num_vdrms = rcar_du_vdrm_count(rcdu);
+
 	vsp->planes = kcalloc(num_planes, sizeof(*vsp->planes), GFP_KERNEL);
 	if (!vsp->planes)
 		return -ENOMEM;
@@ -408,6 +415,21 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
 		plane->vsp = vsp;
 		plane->index = i;
 
+		if (i >= num_planes - num_vdrms) {
+			ret = rcar_du_vdrm_plane_init(rcdu->vdrms[vdrm_index],
+						plane,
+						&rcar_du_vsp_plane_funcs,
+						&rcar_du_vsp_plane_helper_funcs,
+						rcar_du_vsp_formats,
+						ARRAY_SIZE(rcar_du_vsp_formats),
+						num_planes - 1);
+			if (ret < 0)
+				return ret;
+
+			vdrm_index++;
+			continue;
+		}
+
 		ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane,
 					       crtcs, &rcar_du_vsp_plane_funcs,
 					       rcar_du_vsp_formats,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h
index 9b4724159378..0209def9fa6f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h
@@ -16,6 +16,7 @@ struct drm_framebuffer;
 struct rcar_du_format_info;
 struct rcar_du_vsp;
 struct sg_table;
+struct vdrm_display;
 
 struct rcar_du_vsp_plane {
 	struct drm_plane plane;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATH 2/4] rcar-du: Add support virtual DRM device
@ 2021-06-21  6:44   ` Tomohito Esaki
  0 siblings, 0 replies; 61+ messages in thread
From: Tomohito Esaki @ 2021-06-21  6:44 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: devicetree, linux-doc, linux-kernel, dri-devel,
	linux-renesas-soc, Tomohito Esaki

In order to use vDRM, it is necessary that the vDRM device is registered
to du decice in the device tree.
The "vdrms" key is added in du node and the vDRM device node is specified.
For example:
----------
& du {
    ...
    vdrms = <&vdrm0>;
};
----------

Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
---
 drivers/gpu/drm/rcar-du/Kconfig        |   4 +
 drivers/gpu/drm/rcar-du/Makefile       |   1 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c |  42 ++++++
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  13 ++
 drivers/gpu/drm/rcar-du/rcar_du_drv.c  |  13 ++
 drivers/gpu/drm/rcar-du/rcar_du_drv.h  |   3 +
 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c | 191 +++++++++++++++++++++++++
 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h |  67 +++++++++
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c  |  22 +++
 drivers/gpu/drm/rcar-du/rcar_du_vsp.h  |   1 +
 10 files changed, 357 insertions(+)
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h

diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index b47e74421e34..6747f69c8593 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -50,3 +50,7 @@ config DRM_RCAR_WRITEBACK
 	bool
 	default y if ARM64
 	depends on DRM_RCAR_DU
+
+config DRM_RCAR_DU_VDRM
+	tristate "Virtual DRM for R-Car DU"
+	depends on DRM_RCAR_DU && DRM_VDRM
diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
index 4d1187ccc3e5..b589b974a9f3 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -14,6 +14,7 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_of.o \
 					   rcar_du_of_lvds_r8a7796.dtb.o
 rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
 rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o
+rcar-du-drm-$(CONFIG_DRM_RCAR_DU_VDRM)	+= rcar_du_vdrm.o
 
 obj-$(CONFIG_DRM_RCAR_CMM)		+= rcar_cmm.o
 obj-$(CONFIG_DRM_RCAR_DU)		+= rcar-du-drm.o
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index ea7e39d03545..7d48db24090b 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -32,6 +32,11 @@
 #include "rcar_du_vsp.h"
 #include "rcar_lvds.h"
 
+#include "rcar_du_vdrm.h"
+#ifdef CONFIG_DRM_RCAR_DU_VDRM
+#include "../vdrm/vdrm_api.h"
+#endif
+
 static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg)
 {
 	struct rcar_du_device *rcdu = rcrtc->dev;
@@ -1293,5 +1298,42 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
 
 	rcar_du_crtc_crc_init(rcrtc);
 
+	INIT_LIST_HEAD(&rcrtc->vdrm_displays);
+	ret = rcar_du_vdrm_crtc_init(rcrtc, swindex);
+	if (ret < 0) {
+		dev_err(rcdu->dev,
+			"failed to initialize crtc %u for vDRM\n", swindex);
+		return ret;
+	}
+
+	return 0;
+}
+
+int rcar_du_crtc_add_vdrm_display(struct rcar_du_crtc *rcrtc,
+				  struct vdrm_display *vdisplay)
+{
+	struct rcar_du_vdrm_display *disp;
+
+	disp = kzalloc(sizeof(*disp), GFP_KERNEL);
+	if (!disp)
+		return -ENOMEM;
+
+	disp->display = vdisplay;
+	INIT_LIST_HEAD(&disp->head);
+	list_add_tail(&disp->head, &rcrtc->vdrm_displays);
+
 	return 0;
 }
+
+void rcar_du_crtc_remove_vdrm_displays(struct rcar_du_crtc *rcrtc)
+{
+	struct rcar_du_vdrm_display *disp, *tmp;
+
+	if (!rcrtc->dev)
+		return;
+
+	list_for_each_entry_safe(disp, tmp, &rcrtc->vdrm_displays, head) {
+		list_del(&disp->head);
+		kfree(disp);
+	}
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 5f2940c42225..1f749f0061e5 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -21,6 +21,12 @@
 
 struct rcar_du_group;
 struct rcar_du_vsp;
+struct vdrm_display;
+
+struct rcar_du_vdrm_display {
+	struct vdrm_display *display;
+	struct list_head head;
+};
 
 /**
  * struct rcar_du_crtc - the CRTC, representing a DU superposition processor
@@ -43,6 +49,7 @@ struct rcar_du_vsp;
  * @vsp: VSP feeding video to this CRTC
  * @vsp_pipe: index of the VSP pipeline feeding video to this CRTC
  * @writeback: the writeback connector
+ * @vdrm_displays: display list for virtual DRM
  */
 struct rcar_du_crtc {
 	struct drm_crtc crtc;
@@ -73,6 +80,8 @@ struct rcar_du_crtc {
 	unsigned int sources_count;
 
 	struct drm_writeback_connector writeback;
+
+	struct list_head vdrm_displays;
 };
 
 #define to_rcar_crtc(c)		container_of(c, struct rcar_du_crtc, crtc)
@@ -111,4 +120,8 @@ void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc);
 
 void rcar_du_crtc_dsysr_clr_set(struct rcar_du_crtc *rcrtc, u32 clr, u32 set);
 
+int rcar_du_crtc_add_vdrm_display(struct rcar_du_crtc *rcrtc,
+				  struct vdrm_display *vdisplay);
+void rcar_du_crtc_remove_vdrm_displays(struct rcar_du_crtc *rcrtc);
+
 #endif /* __RCAR_DU_CRTC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index bfbff90588cb..42f0f5e0144f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -29,6 +29,7 @@
 #include "rcar_du_kms.h"
 #include "rcar_du_of.h"
 #include "rcar_du_regs.h"
+#include "rcar_du_vdrm.h"
 
 /* -----------------------------------------------------------------------------
  * Device Information
@@ -552,6 +553,8 @@ static int rcar_du_remove(struct platform_device *pdev)
 	struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
 	struct drm_device *ddev = &rcdu->ddev;
 
+	rcar_du_vdrms_fini(rcdu);
+
 	drm_dev_unregister(ddev);
 
 	drm_kms_helper_poll_fini(ddev);
@@ -584,6 +587,11 @@ static int rcar_du_probe(struct platform_device *pdev)
 	if (IS_ERR(rcdu->mmio))
 		return PTR_ERR(rcdu->mmio);
 
+	/* Initialize the vDRM device */
+	ret = rcar_du_vdrms_init(rcdu);
+	if (ret < 0)
+		return ret;
+
 	/* DRM/KMS objects */
 	ret = rcar_du_modeset_init(rcdu);
 	if (ret < 0) {
@@ -607,6 +615,11 @@ static int rcar_du_probe(struct platform_device *pdev)
 
 	drm_fbdev_generic_setup(&rcdu->ddev, 32);
 
+	/* Register the vDRM device */
+	ret = rcar_du_vdrms_register(rcdu);
+	if (ret)
+		DRM_WARN("Setup virtual device failed.\n");
+
 	return 0;
 
 error:
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 02ca2d0e1b55..327f3a250cbe 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -97,6 +97,9 @@ struct rcar_du_device {
 	unsigned int dpad0_source;
 	unsigned int dpad1_source;
 	unsigned int vspd1_sink;
+
+	struct vdrm_device **vdrms;
+	int num_vdrms;
 };
 
 static inline struct rcar_du_device *to_rcar_du_device(struct drm_device *dev)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vdrm.c b/drivers/gpu/drm/rcar-du/rcar_du_vdrm.c
new file mode 100644
index 000000000000..1f09ead92418
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vdrm.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * rcar_du_vdrm.c -- R-Car Display Unit Virtual DRMs
+ *
+ * Copyright (C) 2021 Renesas Electronics Corporation
+ */
+
+#include <linux/of_device.h>
+
+#include <drm/drm_print.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <media/vsp1.h>
+
+#include "rcar_du_vdrm.h"
+#include "rcar_du_kms.h"
+#include "rcar_du_crtc.h"
+#include "rcar_du_vsp.h"
+
+static int rcar_du_vdrm_dumb_create(struct drm_file *file,
+				    struct drm_device *dev,
+				    struct drm_mode_create_dumb *args)
+{
+	/*
+	 * TODO:
+	 *   This is Warkarround.
+	 *   In the future, this function will be removed.
+	 *   The vdrm will be modified to directly call the dumb_create
+	 *   callback of the du driver.
+	 */
+	unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+	unsigned int align;
+
+	/*
+	 * The R8A7779 DU requires a 16 pixels pitch alignment as documented.
+	 */
+	align = 16 * args->bpp / 8;
+
+	args->pitch = roundup(min_pitch, align);
+
+	return drm_gem_cma_dumb_create_internal(file, dev, args);
+}
+
+static void rcar_du_vdrm_crtc_flush(struct drm_crtc *crtc)
+{
+	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+	rcar_du_vsp_atomic_flush(rcrtc);
+}
+
+static struct vdrm_funcs vdrm_funcs = {
+	.dumb_create = rcar_du_vdrm_dumb_create,
+	.crtc_flush = rcar_du_vdrm_crtc_flush,
+};
+
+void rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status)
+{
+	struct rcar_du_vdrm_display *disp;
+
+	list_for_each_entry(disp, &crtc->vdrm_displays, head) {
+		vdrm_drv_handle_vblank(disp->display);
+		if (status & VSP1_DU_STATUS_COMPLETE)
+			vdrm_drv_finish_page_flip(disp->display);
+	}
+}
+
+int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
+{
+	const struct device_node *np = rcdu->dev->of_node;
+	int num;
+
+	num = of_property_count_u32_elems(np, "vdrms");
+	if (num < 0)
+		return 0;
+
+	return num;
+}
+
+int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
+{
+	struct vdrm_device *vdrm;
+	int num_vdrms;
+	int i, ret;
+
+	num_vdrms = rcar_du_vdrm_count(rcdu);
+	if (num_vdrms == 0)
+		return 0;
+
+	rcdu->vdrms = kcalloc(num_vdrms, sizeof(vdrm), GFP_KERNEL);
+	if (!rcdu->vdrms)
+		return -1;
+
+	DRM_INFO("VDRM: num vdrm = %d\n", num_vdrms);
+
+	for (i = 0; i < num_vdrms; i++) {
+		struct of_phandle_args args;
+		const struct device_node *np = rcdu->dev->of_node;
+
+		ret = of_parse_phandle_with_fixed_args(np, "vdrms", 0, i,
+						       &args);
+		if (ret < 0) {
+			DRM_WARN("VDRM: failed get vdrm%d.\n", i);
+			goto err;
+		}
+
+		vdrm = vdrm_drv_init(&rcdu->ddev, args.np, 0, NULL,
+				     &vdrm_funcs);
+		of_node_put(args.np);
+		if (IS_ERR(vdrm)) {
+			ret = PTR_ERR(vdrm);
+			goto err;
+		}
+
+		rcdu->vdrms[i] = vdrm;
+		rcdu->num_vdrms++;
+	}
+
+	return 0;
+
+err:
+	rcar_du_vdrms_fini(rcdu);
+	rcdu->num_vdrms = 0;
+	return ret;
+}
+
+int rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
+			    struct rcar_du_vsp_plane *plane,
+			    const struct drm_plane_funcs *funcs,
+			    const struct drm_plane_helper_funcs *helper_funcs,
+			    const u32 *formats, unsigned int num_formats,
+			    int max_zpos)
+{
+	return vdrm_drv_plane_init(vdrm, &plane->plane, funcs,
+				   helper_funcs, formats, num_formats,
+				   max_zpos);
+}
+
+int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
+{
+	struct rcar_du_device *rcdu;
+	int i;
+
+	rcdu = crtc->dev;
+	for (i = 0; i < rcdu->num_vdrms; i++) {
+		struct vdrm_display *vdisplay;
+		int plane_index = crtc->vsp->num_planes + i;
+		struct drm_plane *plane =
+			&crtc->vsp->planes[plane_index].plane;
+
+		vdisplay = vdrm_drv_display_init(rcdu->vdrms[i], &crtc->crtc,
+						 plane);
+		if (IS_ERR(vdisplay))
+			return PTR_ERR(vdisplay);
+
+		rcar_du_crtc_add_vdrm_display(crtc, vdisplay);
+	}
+
+	return 0;
+}
+
+int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
+{
+	int i, ret;
+
+	for (i = 0; i < rcdu->num_vdrms; i++) {
+		ret = vdrm_drv_register(rcdu->vdrms[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+void rcar_du_vdrms_fini(struct rcar_du_device *rcdu)
+{
+	int i;
+
+	for (i = 0; i < rcdu->num_vdrms; i++) {
+		if (rcdu->vdrms[i])
+			vdrm_drv_fini(rcdu->vdrms[i]);
+	}
+
+	for (i = 0; i < RCAR_DU_MAX_CRTCS; i++)
+		rcar_du_crtc_remove_vdrm_displays(&rcdu->crtcs[i]);
+
+	kfree(rcdu->vdrms);
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vdrm.h b/drivers/gpu/drm/rcar-du/rcar_du_vdrm.h
new file mode 100644
index 000000000000..b12706ceee54
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vdrm.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * rcar_du_vdrm.h -- R-Car Display Unit Virtual DRMs
+ *
+ * Copyright (C) 2021 Renesas Electronics Corporation
+ */
+
+#ifndef __RCAR_DU_VDRM_H__
+#define __RCAR_DU_VDRM_H__
+
+#include <drm/drm_atomic.h>
+
+#include "rcar_du_drv.h"
+#include "../vdrm/vdrm_api.h"
+
+#ifdef CONFIG_DRM_RCAR_DU_VDRM
+
+void rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status);
+void rcar_du_vdrm_vblank_event(struct rcar_du_crtc *crtc);
+int rcar_du_vdrm_count(struct rcar_du_device *rcdu);
+int rcar_du_vdrms_init(struct rcar_du_device *rcdu);
+int rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
+			    struct rcar_du_vsp_plane *plane,
+			    const struct drm_plane_funcs *funcs,
+			    const struct drm_plane_helper_funcs *helper_funcs,
+			    const u32 *formats, unsigned int num_formats,
+			    int max_zpos);
+int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index);
+int rcar_du_vdrms_register(struct rcar_du_device *rcdu);
+void rcar_du_vdrms_fini(struct rcar_du_device *rcdu);
+
+#else
+
+static inline void
+rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status) { }
+static inline void rcar_du_vdrm_vblank_event(struct rcar_du_crtc *crtc) { }
+static inline int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
+{
+	return 0;
+}
+static inline int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
+{
+	return 0;
+}
+static inline int
+rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
+			struct rcar_du_vsp_plane *plane,
+			const struct drm_plane_funcs *funcs,
+			const struct drm_plane_helper_funcs *helper_funcs,
+			const u32 *formats, unsigned int num_formats,
+			int max_zpos)
+{
+	return 0;
+}
+static inline int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
+{
+	return 0;
+}
+static inline int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
+{
+	return 0;
+}
+static inline void rcar_du_vdrms_fini(struct rcar_du_device *rcdu) { }
+
+#endif
+
+#endif /* __RCAR_DU_VDRM_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index 23e41c83c875..7666441f0005 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -31,6 +31,7 @@
 #include "rcar_du_kms.h"
 #include "rcar_du_vsp.h"
 #include "rcar_du_writeback.h"
+#include "rcar_du_vdrm.h"
 
 static void rcar_du_vsp_complete(void *private, unsigned int status, u32 crc)
 {
@@ -45,6 +46,8 @@ static void rcar_du_vsp_complete(void *private, unsigned int status, u32 crc)
 		rcar_du_writeback_complete(crtc);
 
 	drm_crtc_add_crc_entry(&crtc->crtc, false, 0, &crc);
+
+	rcar_du_vdrm_crtc_complete(crtc, status);
 }
 
 void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
@@ -373,6 +376,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
 	unsigned int num_planes;
 	unsigned int i;
 	int ret;
+	int num_vdrms;
+	int vdrm_index = 0;
 
 	/* Find the VSP device and initialize it. */
 	pdev = of_find_device_by_node(np);
@@ -395,6 +400,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
 	  */
 	num_planes = rcdu->info->gen >= 3 ? 5 : 4;
 
+	num_vdrms = rcar_du_vdrm_count(rcdu);
+
 	vsp->planes = kcalloc(num_planes, sizeof(*vsp->planes), GFP_KERNEL);
 	if (!vsp->planes)
 		return -ENOMEM;
@@ -408,6 +415,21 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
 		plane->vsp = vsp;
 		plane->index = i;
 
+		if (i >= num_planes - num_vdrms) {
+			ret = rcar_du_vdrm_plane_init(rcdu->vdrms[vdrm_index],
+						plane,
+						&rcar_du_vsp_plane_funcs,
+						&rcar_du_vsp_plane_helper_funcs,
+						rcar_du_vsp_formats,
+						ARRAY_SIZE(rcar_du_vsp_formats),
+						num_planes - 1);
+			if (ret < 0)
+				return ret;
+
+			vdrm_index++;
+			continue;
+		}
+
 		ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane,
 					       crtcs, &rcar_du_vsp_plane_funcs,
 					       rcar_du_vsp_formats,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h
index 9b4724159378..0209def9fa6f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h
@@ -16,6 +16,7 @@ struct drm_framebuffer;
 struct rcar_du_format_info;
 struct rcar_du_vsp;
 struct sg_table;
+struct vdrm_display;
 
 struct rcar_du_vsp_plane {
 	struct drm_plane plane;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATH 3/4] dt-bindings: display: Add virtual DRM
  2021-06-21  6:43 ` Tomohito Esaki
@ 2021-06-21  6:44   ` Tomohito Esaki
  -1 siblings, 0 replies; 61+ messages in thread
From: Tomohito Esaki @ 2021-06-21  6:44 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: dri-devel, linux-renesas-soc, linux-kernel, devicetree,
	linux-doc, Tomohito Esaki

Add device tree bindings documentation for virtual DRM.

Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
---
 .../devicetree/bindings/display/vdrm.yaml     | 67 +++++++++++++++++++
 1 file changed, 67 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml

diff --git a/Documentation/devicetree/bindings/display/vdrm.yaml b/Documentation/devicetree/bindings/display/vdrm.yaml
new file mode 100644
index 000000000000..6493bb0fc09f
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/vdrm.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/vdrm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Virtual DRM Device Tree Bindings
+
+description:
+  This document defines device tree properties virtual DRM. The initial
+  position, size and z-position of the plane used in the virtual DRM is
+  specified.
+  The current limitation is that these settings are applied to all crtc.
+
+properties:
+  compatible:
+    const: virt-drm
+
+patternProperties:
+  "^plane(@.*)?$":
+    description: Information of the planes used in virtual DRM
+    type: object
+
+    properties:
+      x:
+        type: int
+        description: x-coordinate of the left-top of the plane in pixels
+
+      y:
+        type: int
+        description: y-coordinate of the left-top of the plane in pixels
+
+      width:
+        type: int
+        description: width of the plane in pixels
+
+      height:
+        type: int
+	description: height of the plane in pixels
+
+      zpos:
+        type: int
+        description: z-position of the plane
+
+    required:
+      - x
+      - y
+      - width
+      - height
+      - zpos
+
+required:
+  - compatible
+  - "^plane(@.*)?$"
+
+examples:
+ - |
+   vdrm@0 {
+       compatible = "virt-drm";
+       plane@0 {
+           x = <200>;
+	   y = <100>;
+	   width = <800>;
+	   height = <600>;
+	   zpos = <1>;
+       };
+   };
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATH 3/4] dt-bindings: display: Add virtual DRM
@ 2021-06-21  6:44   ` Tomohito Esaki
  0 siblings, 0 replies; 61+ messages in thread
From: Tomohito Esaki @ 2021-06-21  6:44 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: devicetree, linux-doc, linux-kernel, dri-devel,
	linux-renesas-soc, Tomohito Esaki

Add device tree bindings documentation for virtual DRM.

Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
---
 .../devicetree/bindings/display/vdrm.yaml     | 67 +++++++++++++++++++
 1 file changed, 67 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml

diff --git a/Documentation/devicetree/bindings/display/vdrm.yaml b/Documentation/devicetree/bindings/display/vdrm.yaml
new file mode 100644
index 000000000000..6493bb0fc09f
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/vdrm.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/vdrm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Virtual DRM Device Tree Bindings
+
+description:
+  This document defines device tree properties virtual DRM. The initial
+  position, size and z-position of the plane used in the virtual DRM is
+  specified.
+  The current limitation is that these settings are applied to all crtc.
+
+properties:
+  compatible:
+    const: virt-drm
+
+patternProperties:
+  "^plane(@.*)?$":
+    description: Information of the planes used in virtual DRM
+    type: object
+
+    properties:
+      x:
+        type: int
+        description: x-coordinate of the left-top of the plane in pixels
+
+      y:
+        type: int
+        description: y-coordinate of the left-top of the plane in pixels
+
+      width:
+        type: int
+        description: width of the plane in pixels
+
+      height:
+        type: int
+	description: height of the plane in pixels
+
+      zpos:
+        type: int
+        description: z-position of the plane
+
+    required:
+      - x
+      - y
+      - width
+      - height
+      - zpos
+
+required:
+  - compatible
+  - "^plane(@.*)?$"
+
+examples:
+ - |
+   vdrm@0 {
+       compatible = "virt-drm";
+       plane@0 {
+           x = <200>;
+	   y = <100>;
+	   width = <800>;
+	   height = <600>;
+	   zpos = <1>;
+       };
+   };
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATH 4/4] doc-rst: Add virtual DRM documentation
  2021-06-21  6:43 ` Tomohito Esaki
@ 2021-06-21  6:44   ` Tomohito Esaki
  -1 siblings, 0 replies; 61+ messages in thread
From: Tomohito Esaki @ 2021-06-21  6:44 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: dri-devel, linux-renesas-soc, linux-kernel, devicetree,
	linux-doc, Tomohito Esaki

Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
---
 Documentation/gpu/drivers.rst |  1 +
 Documentation/gpu/vdrm.rst    | 51 +++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+)
 create mode 100644 Documentation/gpu/vdrm.rst

diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst
index b4a0ed3ca961..bad0226de972 100644
--- a/Documentation/gpu/drivers.rst
+++ b/Documentation/gpu/drivers.rst
@@ -19,6 +19,7 @@ GPU Driver Documentation
    xen-front
    afbc
    komeda-kms
+   vdrm
 
 .. only::  subproject and html
 
diff --git a/Documentation/gpu/vdrm.rst b/Documentation/gpu/vdrm.rst
new file mode 100644
index 000000000000..2ab1699c2f42
--- /dev/null
+++ b/Documentation/gpu/vdrm.rst
@@ -0,0 +1,51 @@
+=============================
+ drm/vdrm virtual DRM driver
+=============================
+
+Virtual DRM splits the overlay planes of a display controller into multiple
+virtual devices to allow each plane to be accessed by each process.
+
+This makes it possible to overlay images output from multiple processes on a
+display. For example, one process displays the camera image without compositor
+while another process overlays the UI.
+
+The virtual DRM creates standalone virtual device and make DRM planes from a
+master device (e.g. card0) accessible via one or more virtual device. However,
+these plane are no longer accessible from the original device.
+Each virtual device (and plane) can be accessed via a separate device file.
+
+The virtual DRM driver doesn't directly control the display hardware and has
+no access to the physical bus. Instead, the virtual DRM driver issues requests
+to the standard DRM device driver ("master" driver) when the hardware needs to
+be controlled. The master driver is modified to notify the virtual DRM driver
+of interrupt events from the display hardware.
+
+Plane position and size
+=======================
+The initial position, size and z-position of the plane used in virtual DRM is
+specified in the device tree. The position and size of the planes are set as
+properties and can be updated. The name of each property is as
+follows:
+* vdrm_offset_x: x-coordinate of the left-top of the plane on the screen
+* vdrm_offset_y: y-coordinate of the left-top of the plane on the screen
+* vdrm_width: width of the plane
+* vdrm_height: height of the plane
+
+Virtual DRM Functions Reference
+===============================
+
+.. kernel-doc:: drivers/gpu/drm/vdrm/vdrm_api.h
+    :internal:
+
+.. kernel-doc:: drivers/gpu/drm/vdrm/vdrm_drv.c
+    :export:
+
+Driver limitations
+==================
+1. Each virtual DRM device only supports one plane per CRTC.
+
+2. Virtual DRM doesn't support hot plug connector.
+
+3. If virtual DRM has multiple CRTCs, the initial position and size of the
+   virtual DRM planes is the same for all planes, since they cannot be set
+   for each plane in the device tree.
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATH 4/4] doc-rst: Add virtual DRM documentation
@ 2021-06-21  6:44   ` Tomohito Esaki
  0 siblings, 0 replies; 61+ messages in thread
From: Tomohito Esaki @ 2021-06-21  6:44 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: devicetree, linux-doc, linux-kernel, dri-devel,
	linux-renesas-soc, Tomohito Esaki

Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
---
 Documentation/gpu/drivers.rst |  1 +
 Documentation/gpu/vdrm.rst    | 51 +++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+)
 create mode 100644 Documentation/gpu/vdrm.rst

diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst
index b4a0ed3ca961..bad0226de972 100644
--- a/Documentation/gpu/drivers.rst
+++ b/Documentation/gpu/drivers.rst
@@ -19,6 +19,7 @@ GPU Driver Documentation
    xen-front
    afbc
    komeda-kms
+   vdrm
 
 .. only::  subproject and html
 
diff --git a/Documentation/gpu/vdrm.rst b/Documentation/gpu/vdrm.rst
new file mode 100644
index 000000000000..2ab1699c2f42
--- /dev/null
+++ b/Documentation/gpu/vdrm.rst
@@ -0,0 +1,51 @@
+=============================
+ drm/vdrm virtual DRM driver
+=============================
+
+Virtual DRM splits the overlay planes of a display controller into multiple
+virtual devices to allow each plane to be accessed by each process.
+
+This makes it possible to overlay images output from multiple processes on a
+display. For example, one process displays the camera image without compositor
+while another process overlays the UI.
+
+The virtual DRM creates standalone virtual device and make DRM planes from a
+master device (e.g. card0) accessible via one or more virtual device. However,
+these plane are no longer accessible from the original device.
+Each virtual device (and plane) can be accessed via a separate device file.
+
+The virtual DRM driver doesn't directly control the display hardware and has
+no access to the physical bus. Instead, the virtual DRM driver issues requests
+to the standard DRM device driver ("master" driver) when the hardware needs to
+be controlled. The master driver is modified to notify the virtual DRM driver
+of interrupt events from the display hardware.
+
+Plane position and size
+=======================
+The initial position, size and z-position of the plane used in virtual DRM is
+specified in the device tree. The position and size of the planes are set as
+properties and can be updated. The name of each property is as
+follows:
+* vdrm_offset_x: x-coordinate of the left-top of the plane on the screen
+* vdrm_offset_y: y-coordinate of the left-top of the plane on the screen
+* vdrm_width: width of the plane
+* vdrm_height: height of the plane
+
+Virtual DRM Functions Reference
+===============================
+
+.. kernel-doc:: drivers/gpu/drm/vdrm/vdrm_api.h
+    :internal:
+
+.. kernel-doc:: drivers/gpu/drm/vdrm/vdrm_drv.c
+    :export:
+
+Driver limitations
+==================
+1. Each virtual DRM device only supports one plane per CRTC.
+
+2. Virtual DRM doesn't support hot plug connector.
+
+3. If virtual DRM has multiple CRTCs, the initial position and size of the
+   virtual DRM planes is the same for all planes, since they cannot be set
+   for each plane in the device tree.
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* Re: [PATH 2/4] rcar-du: Add support virtual DRM device
  2021-06-21  6:44   ` Tomohito Esaki
  (?)
@ 2021-06-21 11:25     ` kernel test robot
  -1 siblings, 0 replies; 61+ messages in thread
From: kernel test robot @ 2021-06-21 11:25 UTC (permalink / raw)
  To: Tomohito Esaki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Daniel Vetter, Laurent Pinchart,
	Kieran Bingham
  Cc: kbuild-all, dri-devel, linux-renesas-soc, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 8658 bytes --]

Hi Tomohito,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on drm-intel/for-linux-next drm-tip/drm-tip linus/master v5.13-rc7 next-20210618]
[cannot apply to pinchartl-media/drm/du/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Tomohito-Esaki/Support-virtual-DRM/20210621-144611
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/cc44235a16ab2596f4eae5c4e9011e884ce89691
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Tomohito-Esaki/Support-virtual-DRM/20210621-144611
        git checkout cc44235a16ab2596f4eae5c4e9011e884ce89691
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:60:6: error: redefinition of 'rcar_du_vdrm_crtc_complete'
      60 | void rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status)
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:35:1: note: previous definition of 'rcar_du_vdrm_crtc_complete' was here
      35 | rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status) { }
         | ^~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:71:5: error: redefinition of 'rcar_du_vdrm_count'
      71 | int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
         |     ^~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:37:19: note: previous definition of 'rcar_du_vdrm_count' was here
      37 | static inline int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
         |                   ^~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:83:5: error: redefinition of 'rcar_du_vdrms_init'
      83 | int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
         |     ^~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:41:19: note: previous definition of 'rcar_du_vdrms_init' was here
      41 | static inline int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
         |                   ^~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:130:5: error: redefinition of 'rcar_du_vdrm_plane_init'
     130 | int rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
         |     ^~~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:46:1: note: previous definition of 'rcar_du_vdrm_plane_init' was here
      46 | rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
         | ^~~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:142:5: error: redefinition of 'rcar_du_vdrm_crtc_init'
     142 | int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
         |     ^~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:55:19: note: previous definition of 'rcar_du_vdrm_crtc_init' was here
      55 | static inline int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
         |                   ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:165:5: error: redefinition of 'rcar_du_vdrms_register'
     165 | int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
         |     ^~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:59:19: note: previous definition of 'rcar_du_vdrms_register' was here
      59 | static inline int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
         |                   ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:178:6: error: redefinition of 'rcar_du_vdrms_fini'
     178 | void rcar_du_vdrms_fini(struct rcar_du_device *rcdu)
         |      ^~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:63:20: note: previous definition of 'rcar_du_vdrms_fini' was here
      63 | static inline void rcar_du_vdrms_fini(struct rcar_du_device *rcdu) { }
         |                    ^~~~~~~~~~~~~~~~~~


vim +/rcar_du_vdrm_crtc_complete +60 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c

    59	
  > 60	void rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status)
    61	{
    62		struct rcar_du_vdrm_display *disp;
    63	
    64		list_for_each_entry(disp, &crtc->vdrm_displays, head) {
    65			vdrm_drv_handle_vblank(disp->display);
    66			if (status & VSP1_DU_STATUS_COMPLETE)
    67				vdrm_drv_finish_page_flip(disp->display);
    68		}
    69	}
    70	
  > 71	int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
    72	{
    73		const struct device_node *np = rcdu->dev->of_node;
    74		int num;
    75	
    76		num = of_property_count_u32_elems(np, "vdrms");
    77		if (num < 0)
    78			return 0;
    79	
    80		return num;
    81	}
    82	
  > 83	int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
    84	{
    85		struct vdrm_device *vdrm;
    86		int num_vdrms;
    87		int i, ret;
    88	
    89		num_vdrms = rcar_du_vdrm_count(rcdu);
    90		if (num_vdrms == 0)
    91			return 0;
    92	
    93		rcdu->vdrms = kcalloc(num_vdrms, sizeof(vdrm), GFP_KERNEL);
    94		if (!rcdu->vdrms)
    95			return -1;
    96	
    97		DRM_INFO("VDRM: num vdrm = %d\n", num_vdrms);
    98	
    99		for (i = 0; i < num_vdrms; i++) {
   100			struct of_phandle_args args;
   101			const struct device_node *np = rcdu->dev->of_node;
   102	
   103			ret = of_parse_phandle_with_fixed_args(np, "vdrms", 0, i,
   104							       &args);
   105			if (ret < 0) {
   106				DRM_WARN("VDRM: failed get vdrm%d.\n", i);
   107				goto err;
   108			}
   109	
   110			vdrm = vdrm_drv_init(&rcdu->ddev, args.np, 0, NULL,
   111					     &vdrm_funcs);
   112			of_node_put(args.np);
   113			if (IS_ERR(vdrm)) {
   114				ret = PTR_ERR(vdrm);
   115				goto err;
   116			}
   117	
   118			rcdu->vdrms[i] = vdrm;
   119			rcdu->num_vdrms++;
   120		}
   121	
   122		return 0;
   123	
   124	err:
   125		rcar_du_vdrms_fini(rcdu);
   126		rcdu->num_vdrms = 0;
   127		return ret;
   128	}
   129	
 > 130	int rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
   131				    struct rcar_du_vsp_plane *plane,
   132				    const struct drm_plane_funcs *funcs,
   133				    const struct drm_plane_helper_funcs *helper_funcs,
   134				    const u32 *formats, unsigned int num_formats,
   135				    int max_zpos)
   136	{
   137		return vdrm_drv_plane_init(vdrm, &plane->plane, funcs,
   138					   helper_funcs, formats, num_formats,
   139					   max_zpos);
   140	}
   141	
 > 142	int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
   143	{
   144		struct rcar_du_device *rcdu;
   145		int i;
   146	
   147		rcdu = crtc->dev;
   148		for (i = 0; i < rcdu->num_vdrms; i++) {
   149			struct vdrm_display *vdisplay;
   150			int plane_index = crtc->vsp->num_planes + i;
   151			struct drm_plane *plane =
   152				&crtc->vsp->planes[plane_index].plane;
   153	
   154			vdisplay = vdrm_drv_display_init(rcdu->vdrms[i], &crtc->crtc,
   155							 plane);
   156			if (IS_ERR(vdisplay))
   157				return PTR_ERR(vdisplay);
   158	
   159			rcar_du_crtc_add_vdrm_display(crtc, vdisplay);
   160		}
   161	
   162		return 0;
   163	}
   164	
 > 165	int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
   166	{
   167		int i, ret;
   168	
   169		for (i = 0; i < rcdu->num_vdrms; i++) {
   170			ret = vdrm_drv_register(rcdu->vdrms[i]);
   171			if (ret)
   172				return ret;
   173		}
   174	
   175		return 0;
   176	}
   177	
 > 178	void rcar_du_vdrms_fini(struct rcar_du_device *rcdu)

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 79102 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 2/4] rcar-du: Add support virtual DRM device
@ 2021-06-21 11:25     ` kernel test robot
  0 siblings, 0 replies; 61+ messages in thread
From: kernel test robot @ 2021-06-21 11:25 UTC (permalink / raw)
  To: Tomohito Esaki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Daniel Vetter, Laurent Pinchart,
	Kieran Bingham
  Cc: linux-renesas-soc, kbuild-all, linux-kernel, dri-devel

[-- Attachment #1: Type: text/plain, Size: 8658 bytes --]

Hi Tomohito,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on drm-intel/for-linux-next drm-tip/drm-tip linus/master v5.13-rc7 next-20210618]
[cannot apply to pinchartl-media/drm/du/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Tomohito-Esaki/Support-virtual-DRM/20210621-144611
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/cc44235a16ab2596f4eae5c4e9011e884ce89691
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Tomohito-Esaki/Support-virtual-DRM/20210621-144611
        git checkout cc44235a16ab2596f4eae5c4e9011e884ce89691
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:60:6: error: redefinition of 'rcar_du_vdrm_crtc_complete'
      60 | void rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status)
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:35:1: note: previous definition of 'rcar_du_vdrm_crtc_complete' was here
      35 | rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status) { }
         | ^~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:71:5: error: redefinition of 'rcar_du_vdrm_count'
      71 | int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
         |     ^~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:37:19: note: previous definition of 'rcar_du_vdrm_count' was here
      37 | static inline int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
         |                   ^~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:83:5: error: redefinition of 'rcar_du_vdrms_init'
      83 | int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
         |     ^~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:41:19: note: previous definition of 'rcar_du_vdrms_init' was here
      41 | static inline int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
         |                   ^~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:130:5: error: redefinition of 'rcar_du_vdrm_plane_init'
     130 | int rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
         |     ^~~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:46:1: note: previous definition of 'rcar_du_vdrm_plane_init' was here
      46 | rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
         | ^~~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:142:5: error: redefinition of 'rcar_du_vdrm_crtc_init'
     142 | int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
         |     ^~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:55:19: note: previous definition of 'rcar_du_vdrm_crtc_init' was here
      55 | static inline int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
         |                   ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:165:5: error: redefinition of 'rcar_du_vdrms_register'
     165 | int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
         |     ^~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:59:19: note: previous definition of 'rcar_du_vdrms_register' was here
      59 | static inline int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
         |                   ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:178:6: error: redefinition of 'rcar_du_vdrms_fini'
     178 | void rcar_du_vdrms_fini(struct rcar_du_device *rcdu)
         |      ^~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:63:20: note: previous definition of 'rcar_du_vdrms_fini' was here
      63 | static inline void rcar_du_vdrms_fini(struct rcar_du_device *rcdu) { }
         |                    ^~~~~~~~~~~~~~~~~~


vim +/rcar_du_vdrm_crtc_complete +60 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c

    59	
  > 60	void rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status)
    61	{
    62		struct rcar_du_vdrm_display *disp;
    63	
    64		list_for_each_entry(disp, &crtc->vdrm_displays, head) {
    65			vdrm_drv_handle_vblank(disp->display);
    66			if (status & VSP1_DU_STATUS_COMPLETE)
    67				vdrm_drv_finish_page_flip(disp->display);
    68		}
    69	}
    70	
  > 71	int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
    72	{
    73		const struct device_node *np = rcdu->dev->of_node;
    74		int num;
    75	
    76		num = of_property_count_u32_elems(np, "vdrms");
    77		if (num < 0)
    78			return 0;
    79	
    80		return num;
    81	}
    82	
  > 83	int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
    84	{
    85		struct vdrm_device *vdrm;
    86		int num_vdrms;
    87		int i, ret;
    88	
    89		num_vdrms = rcar_du_vdrm_count(rcdu);
    90		if (num_vdrms == 0)
    91			return 0;
    92	
    93		rcdu->vdrms = kcalloc(num_vdrms, sizeof(vdrm), GFP_KERNEL);
    94		if (!rcdu->vdrms)
    95			return -1;
    96	
    97		DRM_INFO("VDRM: num vdrm = %d\n", num_vdrms);
    98	
    99		for (i = 0; i < num_vdrms; i++) {
   100			struct of_phandle_args args;
   101			const struct device_node *np = rcdu->dev->of_node;
   102	
   103			ret = of_parse_phandle_with_fixed_args(np, "vdrms", 0, i,
   104							       &args);
   105			if (ret < 0) {
   106				DRM_WARN("VDRM: failed get vdrm%d.\n", i);
   107				goto err;
   108			}
   109	
   110			vdrm = vdrm_drv_init(&rcdu->ddev, args.np, 0, NULL,
   111					     &vdrm_funcs);
   112			of_node_put(args.np);
   113			if (IS_ERR(vdrm)) {
   114				ret = PTR_ERR(vdrm);
   115				goto err;
   116			}
   117	
   118			rcdu->vdrms[i] = vdrm;
   119			rcdu->num_vdrms++;
   120		}
   121	
   122		return 0;
   123	
   124	err:
   125		rcar_du_vdrms_fini(rcdu);
   126		rcdu->num_vdrms = 0;
   127		return ret;
   128	}
   129	
 > 130	int rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
   131				    struct rcar_du_vsp_plane *plane,
   132				    const struct drm_plane_funcs *funcs,
   133				    const struct drm_plane_helper_funcs *helper_funcs,
   134				    const u32 *formats, unsigned int num_formats,
   135				    int max_zpos)
   136	{
   137		return vdrm_drv_plane_init(vdrm, &plane->plane, funcs,
   138					   helper_funcs, formats, num_formats,
   139					   max_zpos);
   140	}
   141	
 > 142	int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
   143	{
   144		struct rcar_du_device *rcdu;
   145		int i;
   146	
   147		rcdu = crtc->dev;
   148		for (i = 0; i < rcdu->num_vdrms; i++) {
   149			struct vdrm_display *vdisplay;
   150			int plane_index = crtc->vsp->num_planes + i;
   151			struct drm_plane *plane =
   152				&crtc->vsp->planes[plane_index].plane;
   153	
   154			vdisplay = vdrm_drv_display_init(rcdu->vdrms[i], &crtc->crtc,
   155							 plane);
   156			if (IS_ERR(vdisplay))
   157				return PTR_ERR(vdisplay);
   158	
   159			rcar_du_crtc_add_vdrm_display(crtc, vdisplay);
   160		}
   161	
   162		return 0;
   163	}
   164	
 > 165	int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
   166	{
   167		int i, ret;
   168	
   169		for (i = 0; i < rcdu->num_vdrms; i++) {
   170			ret = vdrm_drv_register(rcdu->vdrms[i]);
   171			if (ret)
   172				return ret;
   173		}
   174	
   175		return 0;
   176	}
   177	
 > 178	void rcar_du_vdrms_fini(struct rcar_du_device *rcdu)

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 79102 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 2/4] rcar-du: Add support virtual DRM device
@ 2021-06-21 11:25     ` kernel test robot
  0 siblings, 0 replies; 61+ messages in thread
From: kernel test robot @ 2021-06-21 11:25 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 8867 bytes --]

Hi Tomohito,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on drm-intel/for-linux-next drm-tip/drm-tip linus/master v5.13-rc7 next-20210618]
[cannot apply to pinchartl-media/drm/du/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Tomohito-Esaki/Support-virtual-DRM/20210621-144611
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/cc44235a16ab2596f4eae5c4e9011e884ce89691
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Tomohito-Esaki/Support-virtual-DRM/20210621-144611
        git checkout cc44235a16ab2596f4eae5c4e9011e884ce89691
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:60:6: error: redefinition of 'rcar_du_vdrm_crtc_complete'
      60 | void rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status)
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:35:1: note: previous definition of 'rcar_du_vdrm_crtc_complete' was here
      35 | rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status) { }
         | ^~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:71:5: error: redefinition of 'rcar_du_vdrm_count'
      71 | int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
         |     ^~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:37:19: note: previous definition of 'rcar_du_vdrm_count' was here
      37 | static inline int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
         |                   ^~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:83:5: error: redefinition of 'rcar_du_vdrms_init'
      83 | int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
         |     ^~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:41:19: note: previous definition of 'rcar_du_vdrms_init' was here
      41 | static inline int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
         |                   ^~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:130:5: error: redefinition of 'rcar_du_vdrm_plane_init'
     130 | int rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
         |     ^~~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:46:1: note: previous definition of 'rcar_du_vdrm_plane_init' was here
      46 | rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
         | ^~~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:142:5: error: redefinition of 'rcar_du_vdrm_crtc_init'
     142 | int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
         |     ^~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:55:19: note: previous definition of 'rcar_du_vdrm_crtc_init' was here
      55 | static inline int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
         |                   ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:165:5: error: redefinition of 'rcar_du_vdrms_register'
     165 | int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
         |     ^~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:59:19: note: previous definition of 'rcar_du_vdrms_register' was here
      59 | static inline int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
         |                   ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:178:6: error: redefinition of 'rcar_du_vdrms_fini'
     178 | void rcar_du_vdrms_fini(struct rcar_du_device *rcdu)
         |      ^~~~~~~~~~~~~~~~~~
   In file included from drivers/gpu/drm/rcar-du/rcar_du_vdrm.c:19:
   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h:63:20: note: previous definition of 'rcar_du_vdrms_fini' was here
      63 | static inline void rcar_du_vdrms_fini(struct rcar_du_device *rcdu) { }
         |                    ^~~~~~~~~~~~~~~~~~


vim +/rcar_du_vdrm_crtc_complete +60 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c

    59	
  > 60	void rcar_du_vdrm_crtc_complete(struct rcar_du_crtc *crtc, unsigned int status)
    61	{
    62		struct rcar_du_vdrm_display *disp;
    63	
    64		list_for_each_entry(disp, &crtc->vdrm_displays, head) {
    65			vdrm_drv_handle_vblank(disp->display);
    66			if (status & VSP1_DU_STATUS_COMPLETE)
    67				vdrm_drv_finish_page_flip(disp->display);
    68		}
    69	}
    70	
  > 71	int rcar_du_vdrm_count(struct rcar_du_device *rcdu)
    72	{
    73		const struct device_node *np = rcdu->dev->of_node;
    74		int num;
    75	
    76		num = of_property_count_u32_elems(np, "vdrms");
    77		if (num < 0)
    78			return 0;
    79	
    80		return num;
    81	}
    82	
  > 83	int rcar_du_vdrms_init(struct rcar_du_device *rcdu)
    84	{
    85		struct vdrm_device *vdrm;
    86		int num_vdrms;
    87		int i, ret;
    88	
    89		num_vdrms = rcar_du_vdrm_count(rcdu);
    90		if (num_vdrms == 0)
    91			return 0;
    92	
    93		rcdu->vdrms = kcalloc(num_vdrms, sizeof(vdrm), GFP_KERNEL);
    94		if (!rcdu->vdrms)
    95			return -1;
    96	
    97		DRM_INFO("VDRM: num vdrm = %d\n", num_vdrms);
    98	
    99		for (i = 0; i < num_vdrms; i++) {
   100			struct of_phandle_args args;
   101			const struct device_node *np = rcdu->dev->of_node;
   102	
   103			ret = of_parse_phandle_with_fixed_args(np, "vdrms", 0, i,
   104							       &args);
   105			if (ret < 0) {
   106				DRM_WARN("VDRM: failed get vdrm%d.\n", i);
   107				goto err;
   108			}
   109	
   110			vdrm = vdrm_drv_init(&rcdu->ddev, args.np, 0, NULL,
   111					     &vdrm_funcs);
   112			of_node_put(args.np);
   113			if (IS_ERR(vdrm)) {
   114				ret = PTR_ERR(vdrm);
   115				goto err;
   116			}
   117	
   118			rcdu->vdrms[i] = vdrm;
   119			rcdu->num_vdrms++;
   120		}
   121	
   122		return 0;
   123	
   124	err:
   125		rcar_du_vdrms_fini(rcdu);
   126		rcdu->num_vdrms = 0;
   127		return ret;
   128	}
   129	
 > 130	int rcar_du_vdrm_plane_init(struct vdrm_device *vdrm,
   131				    struct rcar_du_vsp_plane *plane,
   132				    const struct drm_plane_funcs *funcs,
   133				    const struct drm_plane_helper_funcs *helper_funcs,
   134				    const u32 *formats, unsigned int num_formats,
   135				    int max_zpos)
   136	{
   137		return vdrm_drv_plane_init(vdrm, &plane->plane, funcs,
   138					   helper_funcs, formats, num_formats,
   139					   max_zpos);
   140	}
   141	
 > 142	int rcar_du_vdrm_crtc_init(struct rcar_du_crtc *crtc, int index)
   143	{
   144		struct rcar_du_device *rcdu;
   145		int i;
   146	
   147		rcdu = crtc->dev;
   148		for (i = 0; i < rcdu->num_vdrms; i++) {
   149			struct vdrm_display *vdisplay;
   150			int plane_index = crtc->vsp->num_planes + i;
   151			struct drm_plane *plane =
   152				&crtc->vsp->planes[plane_index].plane;
   153	
   154			vdisplay = vdrm_drv_display_init(rcdu->vdrms[i], &crtc->crtc,
   155							 plane);
   156			if (IS_ERR(vdisplay))
   157				return PTR_ERR(vdisplay);
   158	
   159			rcar_du_crtc_add_vdrm_display(crtc, vdisplay);
   160		}
   161	
   162		return 0;
   163	}
   164	
 > 165	int rcar_du_vdrms_register(struct rcar_du_device *rcdu)
   166	{
   167		int i, ret;
   168	
   169		for (i = 0; i < rcdu->num_vdrms; i++) {
   170			ret = vdrm_drv_register(rcdu->vdrms[i]);
   171			if (ret)
   172				return ret;
   173		}
   174	
   175		return 0;
   176	}
   177	
 > 178	void rcar_du_vdrms_fini(struct rcar_du_device *rcdu)

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 79102 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 1/4] drm: Add Virtual DRM device driver
  2021-06-21  6:44   ` Tomohito Esaki
  (?)
@ 2021-06-21 13:55     ` kernel test robot
  -1 siblings, 0 replies; 61+ messages in thread
From: kernel test robot @ 2021-06-21 13:55 UTC (permalink / raw)
  To: Tomohito Esaki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Daniel Vetter, Laurent Pinchart,
	Kieran Bingham
  Cc: kbuild-all, dri-devel, linux-renesas-soc, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2375 bytes --]

Hi Tomohito,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on drm-intel/for-linux-next drm-tip/drm-tip linus/master v5.13-rc7 next-20210618]
[cannot apply to pinchartl-media/drm/du/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Tomohito-Esaki/Support-virtual-DRM/20210621-144611
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arc-allyesconfig (attached as .config)
compiler: arceb-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/236425f4ac8488c7db1f37fc3e2b80626b2a2517
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Tomohito-Esaki/Support-virtual-DRM/20210621-144611
        git checkout 236425f4ac8488c7db1f37fc3e2b80626b2a2517
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> scripts/Makefile.build:44: drivers/gpu/drm/vdrm/Makefile: No such file or directory
>> make[5]: *** No rule to make target 'drivers/gpu/drm/vdrm/Makefile'.
   make[5]: Failed to remake makefile 'drivers/gpu/drm/vdrm/Makefile'.


vim +44 scripts/Makefile.build

20a468b51325b3 Sam Ravnborg   2006-01-22  40  
2a691470345a00 Sam Ravnborg   2005-07-25  41  # The filename Kbuild has precedence over Makefile
db8c1a7b2ca25f Sam Ravnborg   2005-07-27  42  kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
0c53c8e6eb456c Sam Ravnborg   2007-10-14  43  kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
0c53c8e6eb456c Sam Ravnborg   2007-10-14 @44  include $(kbuild-file)
^1da177e4c3f41 Linus Torvalds 2005-04-16  45  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 68135 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 1/4] drm: Add Virtual DRM device driver
@ 2021-06-21 13:55     ` kernel test robot
  0 siblings, 0 replies; 61+ messages in thread
From: kernel test robot @ 2021-06-21 13:55 UTC (permalink / raw)
  To: Tomohito Esaki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Daniel Vetter, Laurent Pinchart,
	Kieran Bingham
  Cc: linux-renesas-soc, kbuild-all, linux-kernel, dri-devel

[-- Attachment #1: Type: text/plain, Size: 2375 bytes --]

Hi Tomohito,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on drm-intel/for-linux-next drm-tip/drm-tip linus/master v5.13-rc7 next-20210618]
[cannot apply to pinchartl-media/drm/du/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Tomohito-Esaki/Support-virtual-DRM/20210621-144611
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arc-allyesconfig (attached as .config)
compiler: arceb-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/236425f4ac8488c7db1f37fc3e2b80626b2a2517
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Tomohito-Esaki/Support-virtual-DRM/20210621-144611
        git checkout 236425f4ac8488c7db1f37fc3e2b80626b2a2517
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> scripts/Makefile.build:44: drivers/gpu/drm/vdrm/Makefile: No such file or directory
>> make[5]: *** No rule to make target 'drivers/gpu/drm/vdrm/Makefile'.
   make[5]: Failed to remake makefile 'drivers/gpu/drm/vdrm/Makefile'.


vim +44 scripts/Makefile.build

20a468b51325b3 Sam Ravnborg   2006-01-22  40  
2a691470345a00 Sam Ravnborg   2005-07-25  41  # The filename Kbuild has precedence over Makefile
db8c1a7b2ca25f Sam Ravnborg   2005-07-27  42  kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
0c53c8e6eb456c Sam Ravnborg   2007-10-14  43  kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
0c53c8e6eb456c Sam Ravnborg   2007-10-14 @44  include $(kbuild-file)
^1da177e4c3f41 Linus Torvalds 2005-04-16  45  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 68135 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 1/4] drm: Add Virtual DRM device driver
@ 2021-06-21 13:55     ` kernel test robot
  0 siblings, 0 replies; 61+ messages in thread
From: kernel test robot @ 2021-06-21 13:55 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2424 bytes --]

Hi Tomohito,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on drm-intel/for-linux-next drm-tip/drm-tip linus/master v5.13-rc7 next-20210618]
[cannot apply to pinchartl-media/drm/du/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Tomohito-Esaki/Support-virtual-DRM/20210621-144611
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arc-allyesconfig (attached as .config)
compiler: arceb-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/236425f4ac8488c7db1f37fc3e2b80626b2a2517
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Tomohito-Esaki/Support-virtual-DRM/20210621-144611
        git checkout 236425f4ac8488c7db1f37fc3e2b80626b2a2517
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> scripts/Makefile.build:44: drivers/gpu/drm/vdrm/Makefile: No such file or directory
>> make[5]: *** No rule to make target 'drivers/gpu/drm/vdrm/Makefile'.
   make[5]: Failed to remake makefile 'drivers/gpu/drm/vdrm/Makefile'.


vim +44 scripts/Makefile.build

20a468b51325b3 Sam Ravnborg   2006-01-22  40  
2a691470345a00 Sam Ravnborg   2005-07-25  41  # The filename Kbuild has precedence over Makefile
db8c1a7b2ca25f Sam Ravnborg   2005-07-27  42  kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
0c53c8e6eb456c Sam Ravnborg   2007-10-14  43  kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
0c53c8e6eb456c Sam Ravnborg   2007-10-14 @44  include $(kbuild-file)
^1da177e4c3f41 Linus Torvalds 2005-04-16  45  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 68135 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 1/4] drm: Add Virtual DRM device driver
  2021-06-21  6:44   ` Tomohito Esaki
  (?)
  (?)
@ 2021-06-21 15:55   ` Sam Ravnborg
  2021-06-22  4:10       ` Esaki Tomohito
  -1 siblings, 1 reply; 61+ messages in thread
From: Sam Ravnborg @ 2021-06-21 15:55 UTC (permalink / raw)
  To: Tomohito Esaki
  Cc: devicetree, Thomas Zimmermann, linux-doc, David Airlie,
	dri-devel, linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart

Hi Tomohito

On Mon, Jun 21, 2021 at 03:44:00PM +0900, Tomohito Esaki wrote:
> Virtual DRM splits the resources of an overlay plane into multiple
> virtual devices to allow each plane to be accessed by each process.
> 
> This makes it possible to overlay images output from multiple processes
> on a display. For example, one process displays the camera image without
> compositor while another process overlays the compositor's drawing of
> the UI.
> 
> The virtual DRM creates standalone virtual device and make DRM planes
> from a master device (e.g. card0) accessible via one or more virtual
> devices. However, these plane are no longer accessible from the original
> device.
> Each virtual device (and plane) can be accessed via a separate
> device file.
> 
> Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
> ---
>  drivers/gpu/drm/Kconfig         |   7 +
>  drivers/gpu/drm/Makefile        |   1 +
>  drivers/gpu/drm/vdrm/vdrm_api.h |  68 +++
>  drivers/gpu/drm/vdrm/vdrm_drv.c | 859 ++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/vdrm/vdrm_drv.h |  80 +++

Plase consider making the header files self-contained.
So there are no hdden dependencies between the two.

Use forward declarations rahter than including header files is possible.

A few trivial comments in the following. I did not try to follow all the
functionality of the driver and I expect others to comment on the idea.

	Sam

>  5 files changed, 1015 insertions(+)
>  create mode 100644 drivers/gpu/drm/vdrm/vdrm_api.h
>  create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.c
>  create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.h
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 3c16bd1afd87..ba7f4eeab385 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -294,6 +294,13 @@ config DRM_VKMS
>  
>  	  If M is selected the module will be called vkms.
>  
> +config DRM_VDRM
> +	tristate "Virtual DRM"
> +	depends on DRM
> +	help
> +	  Virtual DRM splits the resources of an overlay plane into multiple
> +	  virtual devices to allow each plane to be accessed by each process.
Could you look into pulling a bit more info here. You made a very nice
intro to the patch, consider using it in the help text too.


> +
>  source "drivers/gpu/drm/exynos/Kconfig"
>  
>  source "drivers/gpu/drm/rockchip/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 5279db4392df..55dbf85e2579 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
>  obj-$(CONFIG_DRM_VIA)	+=via/
>  obj-$(CONFIG_DRM_VGEM)	+= vgem/
>  obj-$(CONFIG_DRM_VKMS)	+= vkms/
> +obj-$(CONFIG_DRM_VDRM)	+= vdrm/
Alphabetic order (mostly) so before vgem/

>  obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
>  obj-$(CONFIG_DRM_EXYNOS) +=exynos/
>  obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
> diff --git a/drivers/gpu/drm/vdrm/vdrm_api.h b/drivers/gpu/drm/vdrm/vdrm_api.h
> new file mode 100644
> index 000000000000..dd4d7e774800
> --- /dev/null
> +++ b/drivers/gpu/drm/vdrm/vdrm_api.h
> @@ -0,0 +1,68 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * vdrm_api.h -- Virtual DRM API
> + *
> + * Copyright (C) 2021 Renesas Electronics Corporation
> + */
> +
> +#ifndef __VDRM_API__
> +#define __VDRM_API__
> +
> +#include <linux/of_device.h>
> +#include <drm/drm_crtc.h>
> +
> +/**
> + * struct vdrm_property_info - Information about the properties passed from
> + *			       the DRM driver to vDRM
> + * @prop: Parent property to pass to vDRM
> + * @default_val: Default value for the property passed to vDRM
> + */
> +struct vdrm_property_info {
> +	struct drm_property *prop;
> +	uint64_t default_val;
> +};
It would be nice that all structs used inline comments - and then you
are consistent too.

> +
> +/**
> + * struct vdrm_funcs - Callbacks to parent DRM driver
> + */
> +struct vdrm_funcs {
> +	/**
> +	 * @dumb_create:
> +	 *
> +	 * Called by &drm_driver.dumb_create. Please read the documentation
> +	 * for the &drm_driver.dumb_create hook for more details.
> +	 */
> +	int (*dumb_create)(struct drm_file *file, struct drm_device *dev,
> +			   struct drm_mode_create_dumb *args);
> +
> +	/**
> +	 * @crtc_flush:
> +	 *
> +	 * Called by &drm_crtc_helper_funcs.atomic_flush. Please read the
> +	 * documentation for the &drm_crtc_helper_funcs.atomic_flush hook for
> +	 * more details.
> +	 */
> +	void (*crtc_flush)(struct drm_crtc *crtc);
> +};
> +
> +struct vdrm_device;
> +struct vdrm_display;
> +
> +void vdrm_drv_handle_vblank(struct vdrm_display *vdisplay);
> +void vdrm_drv_finish_page_flip(struct vdrm_display *vdisplay);
> +struct vdrm_device *vdrm_drv_init(struct drm_device *dev,
> +				  struct device_node *np, int num_props,
> +				  struct vdrm_property_info *props,
> +				  const struct vdrm_funcs *funcs);
> +int vdrm_drv_plane_init(struct vdrm_device *vdrm, struct drm_plane *plane,
> +			const struct drm_plane_funcs *funcs,
> +			const struct drm_plane_helper_funcs *helper_funcs,
> +			const u32 *formats, unsigned int num_formats,
> +			int max_zpos);
> +struct vdrm_display *vdrm_drv_display_init(struct vdrm_device *vdrm,
> +					   struct drm_crtc *crtc,
> +					   struct drm_plane *plane);
> +int vdrm_drv_register(struct vdrm_device *vdrm);
> +void vdrm_drv_fini(struct vdrm_device *vdrm);
> +
> +#endif /* __VDRM_API__ */
> diff --git a/drivers/gpu/drm/vdrm/vdrm_drv.c b/drivers/gpu/drm/vdrm/vdrm_drv.c
> new file mode 100644
> index 000000000000..835bdecfc8e6
> --- /dev/null
> +++ b/drivers/gpu/drm/vdrm/vdrm_drv.c
> @@ -0,0 +1,859 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * vdrm_drv.c -- Virtual DRM driver
> + *
> + * Copyright (C) 2021 Renesas Electronics Corporation
> + *
> + * This driver is based on drivers/gpu/drm/drm_simple_kms_helper.c.
> + */
> +
> +#include <linux/of_device.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_atomic_uapi.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/drm_vblank.h>
> +#include <drm/drm_gem_framebuffer_helper.h>
> +#include <video/videomode.h>
> +
> +#include "vdrm_drv.h"
> +
> +static inline struct vdrm_display *
> +to_vdrm_display(struct drm_connector *connector)
> +{
> +	return container_of(connector, struct vdrm_display, connector);
> +}
> +
> +static inline struct vdrm_display *
> +crtc_to_vdrm_display(struct drm_crtc *crtc)
> +{
> +	return container_of(crtc, struct vdrm_display, crtc);
> +}
> +
> +static int vdrm_dumb_create(struct drm_file *file, struct drm_device *dev,
> +			    struct drm_mode_create_dumb *args)
> +{
> +	struct vdrm_device *vdrm = to_vdrm_device(dev);
> +
> +	return vdrm->funcs->dumb_create(file, dev, args);
> +}
> +
> +struct vdrm_framebuffer {
> +	struct drm_framebuffer fb;
> +	struct drm_framebuffer *parent_fb;
> +};
> +
> +static inline struct vdrm_framebuffer *
> +to_vdrm_framebuffer(struct drm_framebuffer *fb)
> +{
> +	return container_of(fb, struct vdrm_framebuffer, fb);
> +}
> +
> +static void vdrm_fb_destroy(struct drm_framebuffer *fb)
> +{
> +	struct vdrm_framebuffer *vfb = to_vdrm_framebuffer(fb);
> +
> +	vfb->parent_fb->funcs->destroy(vfb->parent_fb);
> +	drm_framebuffer_cleanup(fb);
> +	kfree(vfb);
> +}
> +
> +static const struct drm_framebuffer_funcs vdrm_fb_funcs = {
> +	.destroy = vdrm_fb_destroy,
> +};
> +
> +static int vdrm_fb_init(struct drm_device *dev, struct vdrm_framebuffer *vfb)
> +{
> +	vfb->fb = *vfb->parent_fb;
> +	vfb->fb.dev = dev;
> +
> +	return drm_framebuffer_init(dev, &vfb->fb, &vdrm_fb_funcs);
> +}
> +
> +static struct drm_framebuffer *
> +vdrm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
> +	       const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	struct vdrm_device *vdrm = to_vdrm_device(dev);
> +	const struct drm_mode_config_funcs *mode_config_funcs =
> +		vdrm->parent->mode_config.funcs;
> +	struct vdrm_framebuffer *vfb;
> +	struct drm_framebuffer *fb;
> +	int ret;
> +
> +	vfb = kzalloc(sizeof(*vfb), GFP_KERNEL);
> +	if (!vfb)
> +		return ERR_PTR(-ENOMEM);
> +
> +	fb = mode_config_funcs->fb_create(vdrm->parent, file_priv, mode_cmd);
> +	if (IS_ERR(fb)) {
> +		kfree(vfb);
> +		return fb;
> +	}
> +
> +	vfb->parent_fb = fb;
> +	ret = vdrm_fb_init(dev, vfb);
> +	if (ret) {
> +		fb->funcs->destroy(fb);
> +		kfree(vfb);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return &vfb->fb;
> +}
> +
> +static const struct drm_mode_config_funcs vdrm_mode_config_funcs = {
> +	.fb_create = vdrm_fb_create,
> +	.atomic_check = drm_atomic_helper_check,
> +	.atomic_commit = drm_atomic_helper_commit,
> +};
> +
> +static struct drm_display_mode *vdrm_create_mode(struct vdrm_display *disp)
> +{
> +	struct drm_display_mode *mode;
> +	struct videomode videomode;
> +
> +	mode = drm_mode_create(&disp->dev->ddev);
> +	if (!mode)
> +		return NULL;
> +
> +	memset(&videomode, 0, sizeof(videomode));
> +	videomode.hactive = disp->plane_info.width;
> +	videomode.vactive = disp->plane_info.height;
> +	videomode.pixelclock =
> +		disp->parent_crtc->state->adjusted_mode.crtc_clock * 1000;
> +	mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
> +	drm_display_mode_from_videomode(&videomode, mode);
> +
If you create a drm_display_mode here then you can loose the videomode
dependency. And I do not need to tell you that a Kconfig dependency is missing
to use videomode. Do not forget to drop the include.


> +	return mode;
> +}
> +
> +static int vdrm_connector_get_mode(struct drm_connector *connector)
> +{
> +	struct vdrm_display *disp = to_vdrm_display(connector);
> +	struct drm_display_mode *mode = vdrm_create_mode(disp);
> +
> +	if (!mode)
> +		return 0;
> +
> +	drm_mode_probed_add(connector, mode);
> +	return 1;
> +}
> +
> +static const struct drm_connector_helper_funcs vdrm_conn_helper_funcs = {
> +	.get_modes = vdrm_connector_get_mode,
> +};
> +
> +/*
> + * TODO:
> + *  At the time this callback is called, the parent CRTC must be connected.
> + *  Since this callback will not be called when detect() callback of the
> + *  parent connector is called, vDRM driver desn't support hotplug.
> + *  In the future, it is necessary that hotplug is supported.
> + */
> +static enum drm_connector_status
> +vdrm_connector_detect(struct drm_connector *connector, bool force)
> +{
> +	struct vdrm_display *disp = to_vdrm_display(connector);
> +	struct vdrm_device *vdrm = to_vdrm_device(connector->dev);
> +	struct drm_connector *conn;
> +	struct drm_connector_list_iter conn_iter;
> +
> +	drm_connector_list_iter_begin(vdrm->parent, &conn_iter);
> +	drm_for_each_connector_iter(conn, &conn_iter) {
> +		if (!conn->state)
> +			continue;
> +
> +		if (conn->state->crtc == disp->parent_crtc) {
> +			drm_connector_list_iter_end(&conn_iter);
> +			return connector_status_connected;
> +		}
> +	}
> +	drm_connector_list_iter_end(&conn_iter);
> +	return connector_status_disconnected;
> +}
> +
> +static const struct drm_connector_funcs vdrm_conn_funcs = {
> +	.reset = drm_atomic_helper_connector_reset,
> +	.detect = vdrm_connector_detect,
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.destroy = drm_connector_cleanup,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static void vdrm_drv_finish_page_flip_internal(struct vdrm_display *disp)
> +{
> +	struct drm_device *dev = &disp->dev->ddev;
> +	struct drm_pending_vblank_event *event;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&dev->event_lock, flags);
> +	event = disp->event;
> +	disp->event = NULL;
> +	spin_unlock_irqrestore(&dev->event_lock, flags);
> +
> +	if (event == NULL)
> +		return;
> +
> +	spin_lock_irqsave(&dev->event_lock, flags);
> +	drm_crtc_send_vblank_event(&disp->crtc, event);
> +	spin_unlock_irqrestore(&dev->event_lock, flags);
> +
> +	if (disp->vblank_count) {
> +		drm_crtc_vblank_put(&disp->crtc);
> +		disp->vblank_count--;
> +	}
> +}
> +
> +static void vdrm_plane_update(struct drm_plane *plane,
> +			      struct drm_atomic_state *state)
> +{
> +	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
> +	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
> +	struct drm_crtc *vcrtc_old_state = old_state->crtc;
> +	struct drm_crtc *vcrtc_plane_state = new_state->crtc;
> +	struct drm_crtc *crtc;
> +	struct vdrm_display *vdisplay;
> +
> +	crtc = (old_state->crtc ? old_state->crtc : new_state->crtc);
> +	if (WARN_ON(!crtc))
> +		return;
> +
> +	vdisplay = crtc_to_vdrm_display(crtc);
> +
> +	old_state->crtc = vdisplay->parent_crtc;
> +	new_state->crtc = vdisplay->parent_crtc;
> +
> +	new_state->dst.x1 += vdisplay->plane_info.x;
> +	new_state->dst.y1 += vdisplay->plane_info.y;
> +	vdisplay->parent_plane_helper_funcs->atomic_update(plane, state);
> +
> +	old_state->crtc = vcrtc_old_state;
> +	new_state->crtc = vcrtc_plane_state;
> +}
> +
> +static struct vdrm_display *
> +vdrm_plane_find_display(struct vdrm_device *vdrm, struct drm_plane *plane)
> +{
> +	struct vdrm_display *disp;
> +
> +	list_for_each_entry(disp, &vdrm->disps, head) {
> +		if (disp->plane == plane)
> +			return disp;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void vdrm_plane_reset(struct drm_plane *plane)
> +{
> +	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
> +	struct vdrm_display *disp;
> +
> +	disp = vdrm_plane_find_display(vdrm, plane);
> +	if (WARN_ON(!disp))
> +		return;
> +
> +	disp->parent_plane_funcs->reset(plane);
> +	plane->state->zpos = disp->plane_info.z;
> +}
> +
> +static struct drm_property *
> +vdrm_find_parent_property(struct vdrm_device *vdrm, struct drm_property *prop)
> +{
> +	int i;
> +
> +	for (i = 0; i < vdrm->num_props; i++) {
> +		if (vdrm->props[i].prop == prop)
> +			return vdrm->props[i].parent_prop;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int vdrm_plane_set_property(struct drm_plane *plane,
> +				   struct drm_plane_state *state,
> +				   struct drm_property *property,
> +				   uint64_t val)
> +{
> +	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
> +	struct vdrm_display *disp;
> +	struct drm_property *parent_prop;
> +
> +	disp = vdrm_plane_find_display(vdrm, plane);
> +	if (WARN_ON(!disp))
> +		return -EINVAL;
> +
> +	parent_prop = vdrm_find_parent_property(vdrm, property);
> +	if (parent_prop && disp->parent_plane_funcs->atomic_set_property)
> +		return disp->parent_plane_funcs->atomic_set_property(plane,
> +								state,
> +								parent_prop,
> +								val);
> +
> +	if (vdrm->plane_props.offset_x == property) {
> +		if (val > disp->parent_crtc->mode.hdisplay)
> +			return -EINVAL;
> +		disp->plane_info.x = val;
> +	} else if (vdrm->plane_props.offset_y == property) {
> +		if (val > disp->parent_crtc->mode.vdisplay)
> +			return -EINVAL;
> +		disp->plane_info.y = val;
> +	} else if (vdrm->plane_props.width == property) {
> +		if (val > disp->parent_crtc->mode.hdisplay)
> +			return -EINVAL;
> +		disp->plane_info.width = val;
> +	} else if (vdrm->plane_props.height == property) {
> +		if (val > disp->parent_crtc->mode.vdisplay)
> +			return -EINVAL;
> +		disp->plane_info.height = val;
> +	} else {
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vdrm_plane_get_property(struct drm_plane *plane,
> +				   const struct drm_plane_state *state,
> +				   struct drm_property *property,
> +				   uint64_t *val)
> +{
> +	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
> +	struct vdrm_display *disp;
> +	struct drm_property *parent_prop;
> +
> +	disp = vdrm_plane_find_display(vdrm, plane);
> +	if (WARN_ON(!disp))
> +		return -EINVAL;
> +
> +	parent_prop = vdrm_find_parent_property(vdrm, property);
> +	if (parent_prop && disp->parent_plane_funcs->atomic_get_property)
> +		return disp->parent_plane_funcs->atomic_get_property(plane,
> +								state,
> +								parent_prop,
> +								val);
> +
> +	if (vdrm->plane_props.offset_x == property)
> +		*val = disp->plane_info.x;
> +	else if (vdrm->plane_props.offset_y == property)
> +		*val = disp->plane_info.y;
> +	else if (vdrm->plane_props.width == property)
> +		*val = disp->plane_info.width;
> +	else if (vdrm->plane_props.height == property)
> +		*val = disp->plane_info.height;
> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int vdrm_crtc_check(struct drm_crtc *crtc,
> +			   struct drm_atomic_state *state)
> +{
> +	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
> +									  crtc);
> +	bool has_primary = crtc_state->plane_mask &
> +				drm_plane_mask(crtc->primary);
> +
> +	/* We always want to have an active plane with an active CRTC */
> +	if (has_primary != crtc_state->enable)
> +		return -EINVAL;
> +
> +	return drm_atomic_add_affected_planes(state, crtc);
> +}
> +
> +static void vdrm_crtc_flush(struct drm_crtc *crtc,
> +			    struct drm_atomic_state *state)
> +{
> +	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
> +	struct vdrm_device *vdrm = disp->dev;
> +
> +	if (crtc->state->event) {
> +		struct drm_device *dev = crtc->dev;
> +		unsigned long flags;
> +
> +		if (disp->crtc_enabled) {
> +			WARN_ON(drm_crtc_vblank_get(crtc) != 0);
> +			disp->vblank_count++;
> +		}
> +
> +		spin_lock_irqsave(&dev->event_lock, flags);
> +		disp->event = crtc->state->event;
> +		crtc->state->event = NULL;
> +		spin_unlock_irqrestore(&dev->event_lock, flags);
> +	}
> +
> +	if (vdrm->funcs->crtc_flush)
> +		vdrm->funcs->crtc_flush(disp->parent_crtc);
> +}
> +
> +static void vdrm_crtc_enable(struct drm_crtc *crtc,
> +			     struct drm_atomic_state *state)
> +{
> +	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
> +
> +	drm_crtc_vblank_on(crtc);
> +	disp->crtc_enabled = true;
> +}
> +
> +static void vdrm_crtc_disable(struct drm_crtc *crtc,
> +			      struct drm_atomic_state *state)
> +{
> +	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
> +	unsigned long flags;
> +	bool pending;
> +
> +	disp->crtc_enabled = false;
> +	drm_crtc_vblank_off(crtc);
> +
> +	spin_lock_irqsave(&crtc->dev->event_lock, flags);
> +	pending = disp->event != NULL;
> +	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
> +
> +	if (!wait_event_timeout(disp->flip_wait, !pending,
> +				msecs_to_jiffies(50))) {
> +		DRM_WARN("VDRM: page flip timeout\n");
> +		vdrm_drv_finish_page_flip_internal(disp);
> +	}
> +
> +	spin_lock_irq(&crtc->dev->event_lock);
> +	if (crtc->state->event) {
> +		drm_crtc_send_vblank_event(crtc, crtc->state->event);
> +		crtc->state->event = NULL;
> +	}
> +	spin_unlock_irq(&crtc->dev->event_lock);
> +}
> +
> +static const struct drm_crtc_helper_funcs vdrm_crtc_helper_funcs = {
> +	.atomic_check = vdrm_crtc_check,
> +	.atomic_flush = vdrm_crtc_flush,
> +	.atomic_enable = vdrm_crtc_enable,
> +	.atomic_disable = vdrm_crtc_disable,
> +};
> +
> +static int vdrm_crtc_enable_vblank(struct drm_crtc *crtc)
> +{
> +	struct vdrm_display *disp;
> +
> +	disp = crtc_to_vdrm_display(crtc);
> +	disp->vblank_enabled = true;
> +
> +	return 0;
> +}
> +
> +static void vdrm_crtc_disable_vblank(struct drm_crtc *crtc)
> +{
> +	struct vdrm_display *disp;
> +
> +	disp = crtc_to_vdrm_display(crtc);
> +	disp->vblank_enabled = false;
> +}
> +
> +static const struct drm_crtc_funcs vdrm_crtc_funcs = {
> +	.reset = drm_atomic_helper_crtc_reset,
> +	.destroy = drm_crtc_cleanup,
> +	.set_config = drm_atomic_helper_set_config,
> +	.page_flip = drm_atomic_helper_page_flip,
> +	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
> +	.enable_vblank = vdrm_crtc_enable_vblank,
> +	.disable_vblank = vdrm_crtc_disable_vblank,
> +};
> +static const struct drm_encoder_funcs vdrm_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
> +static int vdrm_properties_init(struct vdrm_device *vdrm, int num_props,
> +				struct vdrm_property_info *props)
> +{
> +	int i;
> +	unsigned int w = vdrm->ddev.mode_config.max_width;
> +	unsigned int h = vdrm->ddev.mode_config.max_height;
> +
> +	vdrm->plane_props.offset_x =
> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_offset_x", 0, w);
> +	if (!vdrm->plane_props.offset_x)
> +		return -1;
> +	vdrm->plane_props.offset_y =
> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_offset_y", 0, h);
> +	if (!vdrm->plane_props.offset_y)
> +		return -1;
> +	vdrm->plane_props.width =
> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_width", 1, w);
> +	if (!vdrm->plane_props.width)
> +		return -1;
> +	vdrm->plane_props.height =
> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_height", 1, h);
> +	if (!vdrm->plane_props.height)
> +		return -1;
> +
> +	if (num_props == 0)
> +		return 0;
> +
> +	vdrm->props = devm_kzalloc(vdrm->parent->dev,
> +				    sizeof(*vdrm->props) * num_props,
> +				    GFP_KERNEL);
> +	if (!vdrm->props)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < num_props; i++) {
> +		struct drm_property *p = props[i].prop;
> +
> +		vdrm->props[i].prop =
> +			drm_property_create_range(&vdrm->ddev, p->flags,
> +						  p->name, p->values[0],
> +						  p->values[1]);
> +		if (!vdrm->props[i].prop)
> +			goto err;
> +
> +		vdrm->props[i].parent_prop = p;
> +		vdrm->props[i].default_val = props[i].default_val;
> +	}
> +	vdrm->num_props = num_props;
> +
> +	return 0;
> +
> +err:
> +	for (i--; i >= 0; i--)
> +		drm_property_destroy(&vdrm->ddev, vdrm->props[i].prop);
> +	devm_kfree(vdrm->parent->dev, vdrm->props);
> +	return -1;
> +}
> +
> +static int vdrm_of_get_plane(struct device_node *np,
> +			     int *x, int *y, int *width, int *height, int *z)
> +{
> +	struct device_node *child;
> +	int ret;
> +
> +	child = of_get_next_child(np, NULL);
> +	if (!child)
> +		return -ENODEV;
> +
> +	ret = of_property_read_u32(child, "x", x);
> +	ret |= of_property_read_u32(child, "y", y);
> +	ret |= of_property_read_u32(child, "width", width);
> +	ret |= of_property_read_u32(child, "height", height);
> +	ret |= of_property_read_u32(child, "zpos", z);
> +
> +	of_node_put(child);
> +	return ret;
> +}
> +
> +static void vdrm_dump(struct vdrm_device *vdrm)
> +{
> +	struct vdrm_display *disp;
> +
> +	DRM_INFO("Virtual DRM Info:\n");
> +	list_for_each_entry(disp, &vdrm->disps, head) {
> +		DRM_INFO("\tCONNECTOR: %d\n",
> +			 disp->connector.base.id);
> +		DRM_INFO("\tCRTC: %d\n",
> +			 disp->crtc.base.id);
> +		DRM_INFO("\tENCODER: %d\n",
> +			 disp->encoder.base.id);
> +		DRM_INFO("\tPLANE: %d\n",
> +			 disp->plane->base.id);
> +		DRM_INFO("\tParent CRTC: %d\n",
> +			 disp->parent_crtc->base.id);
> +	}
> +}
> +
> +/**
> + * vdrm_drv_handle_vblank - handle a vblank event for vDRM
> + * @vdisplay: vDRM display object
> + */
> +void vdrm_drv_handle_vblank(struct vdrm_display *vdisplay)
> +{
> +	if (vdisplay->vblank_enabled)
> +		drm_crtc_handle_vblank(&vdisplay->crtc);
> +}
> +
> +/**
> + * vdrm_drv_finish_page_flip - handle a page flip event for vDRM
> + * @vdisplay: vDRM display object
> + */
> +void vdrm_drv_finish_page_flip(struct vdrm_display *vdisplay)
> +{
> +	vdrm_drv_finish_page_flip_internal(vdisplay);
> +}
> +
> +DEFINE_DRM_GEM_CMA_FOPS(vdrm_fops);
> +
> +static struct drm_driver vdrm_driver = {
> +	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
> +	.dumb_create = vdrm_dumb_create,
> +	.fops = &vdrm_fops,
> +	.name = "virt-drm",
> +	.desc = "Virtual DRM driver",
> +	.date = "20201104",
> +	.major = 1,
> +	.minor = 0,
> +};
> +
> +/**
> + * vdrm_drv_init - Initialize vDRM device
> + * @dev: parent DRM device
> + * @np: vDRM device node in DTB
> + * @num_props: number of parent property objects
> + * @props: parent plane properties used in vDRM
> + * @funcs: callbacks for vDRM
> + *
> + * Allocates a new vDRM device, initializes mode_config of the vDRM device
> + * and allocates property objects. Not initialize plane, crtc, encoder and
> + * connector. Initialization of plane must be done in vdrm_drv_plane_init()
> + * and initialization of crtc, encoder and connector must be done by
> + * vdrm_drv_display_init(). Also, after initializing the plane, crtc,
> + * connector, and encoder, register vDRM device must be done by
> + * vdrm_drv_register().
> + *
> + * Returns:
> + * vDRM object (&vdrm_device) on success, error code encoded into the pointer
> + * on failure.
> + */
> +struct vdrm_device *vdrm_drv_init(struct drm_device *dev,
> +				  struct device_node *np, int num_props,
> +				  struct vdrm_property_info *props,
> +				  const struct vdrm_funcs *funcs)
> +{
> +	struct vdrm_device *vdrm;
> +	struct vdrm_plane_info plane_info;
> +	int ret;
> +
> +	if (!of_device_is_compatible(np, "virt-drm"))
> +		return ERR_PTR(-ENODEV);
> +
> +	/* get plane information from device tree */
> +	ret = vdrm_of_get_plane(np, &plane_info.x, &plane_info.y,
> +				&plane_info.width, &plane_info.height,
> +				&plane_info.z);
> +	if (ret < 0) {
> +		DRM_WARN("VDRM: failed get plane node of %s\n",
> +			 of_node_full_name(np));
> +		return ERR_PTR(ret);
> +	}
> +
> +	vdrm_driver.prime_handle_to_fd = dev->driver->prime_handle_to_fd;
> +	vdrm_driver.prime_fd_to_handle = dev->driver->prime_fd_to_handle;
> +	vdrm_driver.gem_prime_import_sg_table =
> +		dev->driver->gem_prime_import_sg_table;
> +	vdrm_driver.gem_prime_mmap = dev->driver->gem_prime_mmap;
> +
> +	vdrm = devm_drm_dev_alloc(dev->dev, &vdrm_driver, struct vdrm_device,
> +				  ddev);
> +	if (IS_ERR(vdrm))
> +		return vdrm;
> +
> +	vdrm->parent = dev;
> +	vdrm->funcs = funcs;
> +	vdrm->of_plane_info = plane_info;
> +
> +	INIT_LIST_HEAD(&vdrm->disps);
> +
> +	ret = drmm_mode_config_init(&vdrm->ddev);
> +	if (ret)
> +		goto failed;
> +
> +	vdrm->ddev.mode_config.min_width = 0;
> +	vdrm->ddev.mode_config.min_height = 0;
> +	vdrm->ddev.mode_config.max_width = 8190;
> +	vdrm->ddev.mode_config.max_height = 8190;
> +	vdrm->ddev.mode_config.normalize_zpos = true;
> +	vdrm->ddev.mode_config.funcs = &vdrm_mode_config_funcs;
> +
> +	ret = vdrm_properties_init(vdrm, num_props, props);
> +	if (ret < 0)
> +		goto failed;
> +
> +	drm_dev_set_unique(&vdrm->ddev, of_node_full_name(np));
> +	return vdrm;
> +
> +failed:
> +	kfree(vdrm);
> +	return ERR_PTR(ret);
> +}
> +
> +/**
> + * vdrm_drv_plane_init - Initialize the plane used by vDRM
> + * @vdrm: vDRM object
> + * @plane: plane to assign to vDRM
> + * @funcs: callbacks for the plane
> + * @helper_funcs: helper vtable to set for plane
> + * @formats: color formats
> + * @num_formats: number of color formats
> + * @max_zpos: max value for zpos property of plane
> + *
> + * Initializes a plane object of PRIMARY type by drm_universal_plane_init()
> + * and initializes @plane's properties. The property passed by vdrm_drv_init()
> + * is set to @plane.
> + *
> + * Returns:
> + * Zero on success, error code on failure.
> + */
> +int vdrm_drv_plane_init(struct vdrm_device *vdrm, struct drm_plane *plane,
> +			const struct drm_plane_funcs *funcs,
> +			const struct drm_plane_helper_funcs *helper_funcs,
> +			const u32 *formats, unsigned int num_formats,
> +			int max_zpos)
> +{
> +	struct vdrm_display *disp;
> +	int i, ret;
> +
> +	disp = kzalloc(sizeof(*disp), GFP_KERNEL);
> +	if (!disp)
> +		return -ENOMEM;
> +
> +	disp->dev = vdrm;
> +	disp->plane = plane;
> +	disp->plane_info = vdrm->of_plane_info;
> +
> +	disp->parent_plane_funcs = funcs;
> +	disp->parent_plane_helper_funcs = helper_funcs;
> +	disp->plane_funcs = *funcs;
> +	disp->plane_helper_funcs = *helper_funcs;
> +
> +	disp->plane_funcs.reset = vdrm_plane_reset;
> +	disp->plane_funcs.atomic_set_property = vdrm_plane_set_property;
> +	disp->plane_funcs.atomic_get_property = vdrm_plane_get_property;
> +	disp->plane_helper_funcs.atomic_update = vdrm_plane_update;
> +
> +	drm_plane_helper_add(disp->plane, &disp->plane_helper_funcs);
> +	ret = drm_universal_plane_init(&vdrm->ddev, plane, 0,
> +				       &disp->plane_funcs, formats,
> +				       num_formats, NULL,
> +				       DRM_PLANE_TYPE_PRIMARY, NULL);
> +	if (ret) {
> +		kfree(disp);
> +		return ret;
> +	}
> +
> +	drm_plane_create_alpha_property(plane);
> +	drm_plane_create_zpos_property(plane, disp->plane_info.z, 0, max_zpos);
> +	drm_object_attach_property(&plane->base,
> +				   vdrm->plane_props.offset_x,
> +				   disp->plane_info.x);
> +	drm_object_attach_property(&plane->base,
> +				   vdrm->plane_props.offset_y,
> +				   disp->plane_info.y);
> +	drm_object_attach_property(&plane->base,
> +				   vdrm->plane_props.width,
> +				   disp->plane_info.width);
> +	drm_object_attach_property(&plane->base,
> +				   vdrm->plane_props.height,
> +				   disp->plane_info.height);
> +	for (i = 0; i < vdrm->num_props; i++) {
> +		drm_object_attach_property(&plane->base,
> +					   vdrm->props[i].prop,
> +					   vdrm->props[i].default_val);
> +	}
> +
> +	INIT_LIST_HEAD(&disp->head);
> +	list_add_tail(&disp->head, &vdrm->disps);
> +	vdrm->num_crtcs++;
> +	return 0;
> +}
> +
> +/**
> + * vdrm_drv_display_init - Initialize the vDRM display object
> + * @vdrm: vDRM object
> + * @crtc: parent crtc to be linked with the vDRM crtc
> + * @plane: plane assigned to vDRM
> + *
> + * Initializes crtc, connector and encorder, and links @crtc to crtc of vDRM.
> + *
> + * Returns:
> + * vDRM display object on success, error code encoded into the pointer on
> + * failure.
> + */
> +struct vdrm_display *vdrm_drv_display_init(struct vdrm_device *vdrm,
> +					   struct drm_crtc *crtc,
> +					   struct drm_plane *plane)
> +{
> +	struct vdrm_display *disp;
> +	int ret;
> +
> +	disp = vdrm_plane_find_display(vdrm, plane);
> +	if (!disp)
> +		return ERR_PTR(-EINVAL);
> +
> +	drm_crtc_helper_add(&disp->crtc, &vdrm_crtc_helper_funcs);
> +	ret = drm_crtc_init_with_planes(&vdrm->ddev, &disp->crtc, plane, NULL,
> +					&vdrm_crtc_funcs, NULL);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	drm_connector_helper_add(&disp->connector, &vdrm_conn_helper_funcs);
> +	ret = drm_connector_init(&vdrm->ddev, &disp->connector,
> +				 &vdrm_conn_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	disp->encoder.possible_crtcs = drm_crtc_mask(&disp->crtc);
> +	ret = drm_encoder_init(&vdrm->ddev, &disp->encoder, &vdrm_encoder_funcs,
> +			       DRM_MODE_ENCODER_NONE, NULL);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	ret = drm_connector_attach_encoder(&disp->connector, &disp->encoder);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	init_waitqueue_head(&disp->flip_wait);
> +	disp->parent_crtc = crtc;
> +
> +	return disp;
> +}
> +
> +/**
> + * vdrm_drv_register - Register vDRM device
> + * @vdrm: vDRM object
> + *
> + * Returns:
> + * Zero on success, error code on failure.
> + */
> +int vdrm_drv_register(struct vdrm_device *vdrm)
> +{
> +	int ret;
> +	struct drm_device *dev = &vdrm->ddev;
> +
> +	ret = drm_vblank_init(dev, vdrm->num_crtcs);
> +	if (ret)
> +		return ret;
> +
> +	drm_mode_config_reset(dev);
> +
> +	ret = drm_dev_register(dev, 0);
> +	if (ret)
> +		return ret;
> +
> +	dev->irq_enabled = true;
> +
> +	DRM_INFO("Virtual Device is initialized.\n");
> +
> +	vdrm_dump(vdrm);
> +
> +	return 0;
> +}
> +
> +/**
> + * vdrm_drv_fini - release vDRM resources
> + * @vdrm: vDRM object
> + */
> +void vdrm_drv_fini(struct vdrm_device *vdrm)
> +{
> +	struct vdrm_display *disp;
> +
> +	if (vdrm->ddev.registered)
> +		drm_dev_unregister(&vdrm->ddev);
> +	drm_mode_config_cleanup(&vdrm->ddev);
> +
> +	list_for_each_entry(disp, &vdrm->disps, head)
> +		kfree(disp);
> +}
> diff --git a/drivers/gpu/drm/vdrm/vdrm_drv.h b/drivers/gpu/drm/vdrm/vdrm_drv.h
> new file mode 100644
> index 000000000000..67b8e02efddf
> --- /dev/null
> +++ b/drivers/gpu/drm/vdrm/vdrm_drv.h
> @@ -0,0 +1,80 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * vdrm_drv.h -- Virtual DRM driver
> + *
> + * Copyright (C) 2021 Renesas Electronics Corporation
> + */
> +
> +#ifndef __VDRM_DRV_H__
> +#define __VDRM_DRV_H__
> +
> +#include <drm/drm_device.h>
> +
> +#include "vdrm_api.h"
> +
> +struct vdrm_property {
> +	struct drm_property *prop;
> +	struct drm_property *parent_prop;
> +	uint64_t default_val;
> +};
> +
> +struct vdrm_plane_info {
> +	int x;
> +	int y;
> +	unsigned int width;
> +	unsigned int height;
> +	unsigned int z;
> +};
> +
> +struct vdrm_device;
> +
> +struct vdrm_display {
> +	struct drm_connector connector;
> +	struct drm_crtc crtc;
> +	struct drm_crtc *parent_crtc;
> +	struct drm_plane *plane;
> +	struct drm_encoder encoder;
> +	struct drm_pending_vblank_event *event;
> +	struct vdrm_device *dev;
> +	bool vblank_enabled;
> +	wait_queue_head_t flip_wait;
> +	bool crtc_enabled;
> +	int vblank_count;
> +
> +	struct list_head head;
> +
> +	struct vdrm_plane_info plane_info;
> +
> +	const struct drm_plane_funcs *parent_plane_funcs;
> +	const struct drm_plane_helper_funcs *parent_plane_helper_funcs;
> +	struct drm_plane_funcs plane_funcs;
> +	struct drm_plane_helper_funcs plane_helper_funcs;
> +};
> +
> +struct vdrm_device {
> +	struct drm_device ddev;
> +	struct drm_device *parent;
> +
> +	int num_crtcs;
> +	struct list_head disps;
> +
> +	const struct vdrm_funcs *funcs;
> +	struct vdrm_property *props;
> +	int num_props;
> +
> +	struct {
> +		struct drm_property *offset_x;
> +		struct drm_property *offset_y;
> +		struct drm_property *width;
> +		struct drm_property *height;
> +	} plane_props;
> +
> +	struct vdrm_plane_info of_plane_info;
> +};
> +
> +static inline struct vdrm_device *to_vdrm_device(struct drm_device *dev)
> +{
> +	return container_of(dev, struct vdrm_device, ddev);
> +}
> +
> +#endif /* __VDRM_DRV_H__ */
> -- 
> 2.25.1

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 2/4] rcar-du: Add support virtual DRM device
  2021-06-21  6:44   ` Tomohito Esaki
  (?)
  (?)
@ 2021-06-21 15:57   ` Sam Ravnborg
  -1 siblings, 0 replies; 61+ messages in thread
From: Sam Ravnborg @ 2021-06-21 15:57 UTC (permalink / raw)
  To: Tomohito Esaki
  Cc: devicetree, Thomas Zimmermann, linux-doc, David Airlie,
	dri-devel, linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart

On Mon, Jun 21, 2021 at 03:44:01PM +0900, Tomohito Esaki wrote:
> In order to use vDRM, it is necessary that the vDRM device is registered
> to du decice in the device tree.
> The "vdrms" key is added in du node and the vDRM device node is specified.
> For example:
> ----------
> & du {
>     ...
>     vdrms = <&vdrm0>;
> };
> ----------
> 
> Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
> ---
>  drivers/gpu/drm/rcar-du/Kconfig        |   4 +
>  drivers/gpu/drm/rcar-du/Makefile       |   1 +
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c |  42 ++++++
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  13 ++
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c  |  13 ++
>  drivers/gpu/drm/rcar-du/rcar_du_drv.h  |   3 +
>  drivers/gpu/drm/rcar-du/rcar_du_vdrm.c | 191 +++++++++++++++++++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_vdrm.h |  67 +++++++++
>  drivers/gpu/drm/rcar-du/rcar_du_vsp.c  |  22 +++
>  drivers/gpu/drm/rcar-du/rcar_du_vsp.h  |   1 +
>  10 files changed, 357 insertions(+)
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c
>  create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h
> 
> diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
> index b47e74421e34..6747f69c8593 100644
> --- a/drivers/gpu/drm/rcar-du/Kconfig
> +++ b/drivers/gpu/drm/rcar-du/Kconfig
> @@ -50,3 +50,7 @@ config DRM_RCAR_WRITEBACK
>  	bool
>  	default y if ARM64
>  	depends on DRM_RCAR_DU
> +
> +config DRM_RCAR_DU_VDRM
> +	tristate "Virtual DRM for R-Car DU"
> +	depends on DRM_RCAR_DU && DRM_VDRM
> diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
> index 4d1187ccc3e5..b589b974a9f3 100644
> --- a/drivers/gpu/drm/rcar-du/Makefile
> +++ b/drivers/gpu/drm/rcar-du/Makefile
> @@ -14,6 +14,7 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_of.o \
>  					   rcar_du_of_lvds_r8a7796.dtb.o
>  rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
>  rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o
> +rcar-du-drm-$(CONFIG_DRM_RCAR_DU_VDRM)	+= rcar_du_vdrm.o
>  
>  obj-$(CONFIG_DRM_RCAR_CMM)		+= rcar_cmm.o
>  obj-$(CONFIG_DRM_RCAR_DU)		+= rcar-du-drm.o
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index ea7e39d03545..7d48db24090b 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -32,6 +32,11 @@
>  #include "rcar_du_vsp.h"
>  #include "rcar_lvds.h"
>  
> +#include "rcar_du_vdrm.h"
> +#ifdef CONFIG_DRM_RCAR_DU_VDRM
> +#include "../vdrm/vdrm_api.h"
> +#endif

Seems like vdrm_api.h belongs in include/drm/ as we should not pull in
headers like this.

	Sam

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 3/4] dt-bindings: display: Add virtual DRM
  2021-06-21  6:44   ` Tomohito Esaki
  (?)
@ 2021-06-21 16:03   ` Sam Ravnborg
  -1 siblings, 0 replies; 61+ messages in thread
From: Sam Ravnborg @ 2021-06-21 16:03 UTC (permalink / raw)
  To: Tomohito Esaki
  Cc: devicetree, Thomas Zimmermann, linux-doc, David Airlie,
	dri-devel, linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart

Hi Tomohito

> +
> +description:
> +  This document defines device tree properties virtual DRM. The initial
> +  position, size and z-position of the plane used in the virtual DRM is
> +  specified.


> +  The current limitation is that these settings are applied to all crtc.
This comment (I think) refers to the actual implmentation which is
irrelevant for the binding. The implementation may refer to the binding,
but the binding must be implementation agnostic.

> +
> +properties:
> +  compatible:
> +    const: virt-drm
> +
> +patternProperties:
> +  "^plane(@.*)?$":
> +    description: Information of the planes used in virtual DRM
> +    type: object
> +
> +    properties:
> +      x:
> +        type: int
This syntax looks wrong, I had expected something like:
	
	$ref: "/schemas/types.yaml#/definitions/uint32"

> +        description: x-coordinate of the left-top of the plane in pixels
> +
> +      y:
> +        type: int
> +        description: y-coordinate of the left-top of the plane in pixels
> +
> +      width:
> +        type: int
> +        description: width of the plane in pixels
> +
> +      height:
> +        type: int
> +	description: height of the plane in pixels
> +
> +      zpos:
> +        type: int
> +        description: z-position of the plane
> +
> +    required:
> +      - x
> +      - y
> +      - width
> +      - height
> +      - zpos
> +
> +required:
> +  - compatible

> +  - "^plane(@.*)?$"
If there is no node to match this binding does not take effect.
So I think ^plane... do not need to be specified.

> +
> +examples:
> + - |
> +   vdrm@0 {
> +       compatible = "virt-drm";
> +       plane@0 {
> +           x = <200>;
> +	   y = <100>;
> +	   width = <800>;
> +	   height = <600>;
> +	   zpos = <1>;
> +       };
> +   };
Do not mix spaces and tabd, be consistent and use 4 spaces as indent in
all the example.

	Sam

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 3/4] dt-bindings: display: Add virtual DRM
  2021-06-21  6:44   ` Tomohito Esaki
@ 2021-06-21 17:40     ` Rob Herring
  -1 siblings, 0 replies; 61+ messages in thread
From: Rob Herring @ 2021-06-21 17:40 UTC (permalink / raw)
  To: Tomohito Esaki
  Cc: linux-kernel, Maarten Lankhorst, Daniel Vetter,
	Thomas Zimmermann, David Airlie, Laurent Pinchart,
	Kieran Bingham, dri-devel, linux-renesas-soc, linux-doc,
	devicetree, Maxime Ripard

On Mon, 21 Jun 2021 15:44:02 +0900, Tomohito Esaki wrote:
> Add device tree bindings documentation for virtual DRM.
> 
> Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
> ---
>  .../devicetree/bindings/display/vdrm.yaml     | 67 +++++++++++++++++++
>  1 file changed, 67 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:
./Documentation/devicetree/bindings/display/vdrm.yaml:39:1: [error] syntax error: found character '\t' that cannot start any token (syntax)

dtschema/dtc warnings/errors:
make[1]: *** Deleting file 'Documentation/devicetree/bindings/display/vdrm.example.dts'
Traceback (most recent call last):
  File "/usr/local/bin/dt-extract-example", line 45, in <module>
    binding = yaml.load(open(args.yamlfile, encoding='utf-8').read())
  File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/main.py", line 434, in load
    return constructor.get_single_data()
  File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/constructor.py", line 120, in get_single_data
    node = self.composer.get_single_node()
  File "_ruamel_yaml.pyx", line 706, in _ruamel_yaml.CParser.get_single_node
  File "_ruamel_yaml.pyx", line 724, in _ruamel_yaml.CParser._compose_document
  File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
  File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
  File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
  File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
  File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
  File "_ruamel_yaml.pyx", line 731, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 904, in _ruamel_yaml.CParser._parse_next_event
ruamel.yaml.scanner.ScannerError: while scanning a plain scalar
  in "<unicode string>", line 38, column 15
found a tab character that violates indentation
  in "<unicode string>", line 39, column 1
make[1]: *** [Documentation/devicetree/bindings/Makefile:20: Documentation/devicetree/bindings/display/vdrm.example.dts] Error 1
make[1]: *** Waiting for unfinished jobs....
./Documentation/devicetree/bindings/display/vdrm.yaml:  while scanning a plain scalar
  in "<unicode string>", line 38, column 15
found a tab character that violates indentation
  in "<unicode string>", line 39, column 1
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/display/vdrm.yaml: ignoring, error parsing file
warning: no schema found in file: ./Documentation/devicetree/bindings/display/vdrm.yaml
make: *** [Makefile:1416: dt_binding_check] Error 2
\ndoc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/patch/1494913

This check can fail if there are any dependencies. The base for a patch
series is generally the most recent rc1.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit.


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 3/4] dt-bindings: display: Add virtual DRM
@ 2021-06-21 17:40     ` Rob Herring
  0 siblings, 0 replies; 61+ messages in thread
From: Rob Herring @ 2021-06-21 17:40 UTC (permalink / raw)
  To: Tomohito Esaki
  Cc: devicetree, linux-doc, David Airlie, linux-kernel, dri-devel,
	linux-renesas-soc, Kieran Bingham, Laurent Pinchart,
	Thomas Zimmermann

On Mon, 21 Jun 2021 15:44:02 +0900, Tomohito Esaki wrote:
> Add device tree bindings documentation for virtual DRM.
> 
> Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
> ---
>  .../devicetree/bindings/display/vdrm.yaml     | 67 +++++++++++++++++++
>  1 file changed, 67 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:
./Documentation/devicetree/bindings/display/vdrm.yaml:39:1: [error] syntax error: found character '\t' that cannot start any token (syntax)

dtschema/dtc warnings/errors:
make[1]: *** Deleting file 'Documentation/devicetree/bindings/display/vdrm.example.dts'
Traceback (most recent call last):
  File "/usr/local/bin/dt-extract-example", line 45, in <module>
    binding = yaml.load(open(args.yamlfile, encoding='utf-8').read())
  File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/main.py", line 434, in load
    return constructor.get_single_data()
  File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/constructor.py", line 120, in get_single_data
    node = self.composer.get_single_node()
  File "_ruamel_yaml.pyx", line 706, in _ruamel_yaml.CParser.get_single_node
  File "_ruamel_yaml.pyx", line 724, in _ruamel_yaml.CParser._compose_document
  File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
  File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
  File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
  File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
  File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
  File "_ruamel_yaml.pyx", line 731, in _ruamel_yaml.CParser._compose_node
  File "_ruamel_yaml.pyx", line 904, in _ruamel_yaml.CParser._parse_next_event
ruamel.yaml.scanner.ScannerError: while scanning a plain scalar
  in "<unicode string>", line 38, column 15
found a tab character that violates indentation
  in "<unicode string>", line 39, column 1
make[1]: *** [Documentation/devicetree/bindings/Makefile:20: Documentation/devicetree/bindings/display/vdrm.example.dts] Error 1
make[1]: *** Waiting for unfinished jobs....
./Documentation/devicetree/bindings/display/vdrm.yaml:  while scanning a plain scalar
  in "<unicode string>", line 38, column 15
found a tab character that violates indentation
  in "<unicode string>", line 39, column 1
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/display/vdrm.yaml: ignoring, error parsing file
warning: no schema found in file: ./Documentation/devicetree/bindings/display/vdrm.yaml
make: *** [Makefile:1416: dt_binding_check] Error 2
\ndoc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/patch/1494913

This check can fail if there are any dependencies. The base for a patch
series is generally the most recent rc1.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit.


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 1/4] drm: Add Virtual DRM device driver
  2021-06-21 15:55   ` Sam Ravnborg
@ 2021-06-22  4:10       ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-22  4:10 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham,
	devicetree, linux-doc, linux-kernel, dri-devel,
	linux-renesas-soc, Damian Hobson-Garcia, Takanari Hayama

Hi, Sam

Thank you for looking at the details.
I will fix it according to your comment.

Best regards
Tomohito Esaki

On 2021/06/22 0:55, Sam Ravnborg wrote:
> Hi Tomohito
> 
> On Mon, Jun 21, 2021 at 03:44:00PM +0900, Tomohito Esaki wrote:
>> Virtual DRM splits the resources of an overlay plane into multiple
>> virtual devices to allow each plane to be accessed by each process.
>>
>> This makes it possible to overlay images output from multiple processes
>> on a display. For example, one process displays the camera image without
>> compositor while another process overlays the compositor's drawing of
>> the UI.
>>
>> The virtual DRM creates standalone virtual device and make DRM planes
>> from a master device (e.g. card0) accessible via one or more virtual
>> devices. However, these plane are no longer accessible from the original
>> device.
>> Each virtual device (and plane) can be accessed via a separate
>> device file.
>>
>> Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
>> ---
>>  drivers/gpu/drm/Kconfig         |   7 +
>>  drivers/gpu/drm/Makefile        |   1 +
>>  drivers/gpu/drm/vdrm/vdrm_api.h |  68 +++
>>  drivers/gpu/drm/vdrm/vdrm_drv.c | 859 ++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/vdrm/vdrm_drv.h |  80 +++
> 
> Plase consider making the header files self-contained.
> So there are no hdden dependencies between the two.
> 
> Use forward declarations rahter than including header files is possible.
> 
> A few trivial comments in the following. I did not try to follow all the
> functionality of the driver and I expect others to comment on the idea.
> 
> 	Sam
> 
>>  5 files changed, 1015 insertions(+)
>>  create mode 100644 drivers/gpu/drm/vdrm/vdrm_api.h
>>  create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.c
>>  create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.h
>>
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index 3c16bd1afd87..ba7f4eeab385 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -294,6 +294,13 @@ config DRM_VKMS
>>  
>>  	  If M is selected the module will be called vkms.
>>  
>> +config DRM_VDRM
>> +	tristate "Virtual DRM"
>> +	depends on DRM
>> +	help
>> +	  Virtual DRM splits the resources of an overlay plane into multiple
>> +	  virtual devices to allow each plane to be accessed by each process.
> Could you look into pulling a bit more info here. You made a very nice
> intro to the patch, consider using it in the help text too.
> 
> 
>> +
>>  source "drivers/gpu/drm/exynos/Kconfig"
>>  
>>  source "drivers/gpu/drm/rockchip/Kconfig"
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index 5279db4392df..55dbf85e2579 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
>>  obj-$(CONFIG_DRM_VIA)	+=via/
>>  obj-$(CONFIG_DRM_VGEM)	+= vgem/
>>  obj-$(CONFIG_DRM_VKMS)	+= vkms/
>> +obj-$(CONFIG_DRM_VDRM)	+= vdrm/
> Alphabetic order (mostly) so before vgem/
> 
>>  obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
>>  obj-$(CONFIG_DRM_EXYNOS) +=exynos/
>>  obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
>> diff --git a/drivers/gpu/drm/vdrm/vdrm_api.h b/drivers/gpu/drm/vdrm/vdrm_api.h
>> new file mode 100644
>> index 000000000000..dd4d7e774800
>> --- /dev/null
>> +++ b/drivers/gpu/drm/vdrm/vdrm_api.h
>> @@ -0,0 +1,68 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * vdrm_api.h -- Virtual DRM API
>> + *
>> + * Copyright (C) 2021 Renesas Electronics Corporation
>> + */
>> +
>> +#ifndef __VDRM_API__
>> +#define __VDRM_API__
>> +
>> +#include <linux/of_device.h>
>> +#include <drm/drm_crtc.h>
>> +
>> +/**
>> + * struct vdrm_property_info - Information about the properties passed from
>> + *			       the DRM driver to vDRM
>> + * @prop: Parent property to pass to vDRM
>> + * @default_val: Default value for the property passed to vDRM
>> + */
>> +struct vdrm_property_info {
>> +	struct drm_property *prop;
>> +	uint64_t default_val;
>> +};
> It would be nice that all structs used inline comments - and then you
> are consistent too.
> 
>> +
>> +/**
>> + * struct vdrm_funcs - Callbacks to parent DRM driver
>> + */
>> +struct vdrm_funcs {
>> +	/**
>> +	 * @dumb_create:
>> +	 *
>> +	 * Called by &drm_driver.dumb_create. Please read the documentation
>> +	 * for the &drm_driver.dumb_create hook for more details.
>> +	 */
>> +	int (*dumb_create)(struct drm_file *file, struct drm_device *dev,
>> +			   struct drm_mode_create_dumb *args);
>> +
>> +	/**
>> +	 * @crtc_flush:
>> +	 *
>> +	 * Called by &drm_crtc_helper_funcs.atomic_flush. Please read the
>> +	 * documentation for the &drm_crtc_helper_funcs.atomic_flush hook for
>> +	 * more details.
>> +	 */
>> +	void (*crtc_flush)(struct drm_crtc *crtc);
>> +};
>> +
>> +struct vdrm_device;
>> +struct vdrm_display;
>> +
>> +void vdrm_drv_handle_vblank(struct vdrm_display *vdisplay);
>> +void vdrm_drv_finish_page_flip(struct vdrm_display *vdisplay);
>> +struct vdrm_device *vdrm_drv_init(struct drm_device *dev,
>> +				  struct device_node *np, int num_props,
>> +				  struct vdrm_property_info *props,
>> +				  const struct vdrm_funcs *funcs);
>> +int vdrm_drv_plane_init(struct vdrm_device *vdrm, struct drm_plane *plane,
>> +			const struct drm_plane_funcs *funcs,
>> +			const struct drm_plane_helper_funcs *helper_funcs,
>> +			const u32 *formats, unsigned int num_formats,
>> +			int max_zpos);
>> +struct vdrm_display *vdrm_drv_display_init(struct vdrm_device *vdrm,
>> +					   struct drm_crtc *crtc,
>> +					   struct drm_plane *plane);
>> +int vdrm_drv_register(struct vdrm_device *vdrm);
>> +void vdrm_drv_fini(struct vdrm_device *vdrm);
>> +
>> +#endif /* __VDRM_API__ */
>> diff --git a/drivers/gpu/drm/vdrm/vdrm_drv.c b/drivers/gpu/drm/vdrm/vdrm_drv.c
>> new file mode 100644
>> index 000000000000..835bdecfc8e6
>> --- /dev/null
>> +++ b/drivers/gpu/drm/vdrm/vdrm_drv.c
>> @@ -0,0 +1,859 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * vdrm_drv.c -- Virtual DRM driver
>> + *
>> + * Copyright (C) 2021 Renesas Electronics Corporation
>> + *
>> + * This driver is based on drivers/gpu/drm/drm_simple_kms_helper.c.
>> + */
>> +
>> +#include <linux/of_device.h>
>> +#include <drm/drm_atomic.h>
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_atomic_uapi.h>
>> +#include <drm/drm_fb_cma_helper.h>
>> +#include <drm/drm_fb_helper.h>
>> +#include <drm/drm_drv.h>
>> +#include <drm/drm_gem_cma_helper.h>
>> +#include <drm/drm_plane_helper.h>
>> +#include <drm/drm_probe_helper.h>
>> +#include <drm/drm_vblank.h>
>> +#include <drm/drm_gem_framebuffer_helper.h>
>> +#include <video/videomode.h>
>> +
>> +#include "vdrm_drv.h"
>> +
>> +static inline struct vdrm_display *
>> +to_vdrm_display(struct drm_connector *connector)
>> +{
>> +	return container_of(connector, struct vdrm_display, connector);
>> +}
>> +
>> +static inline struct vdrm_display *
>> +crtc_to_vdrm_display(struct drm_crtc *crtc)
>> +{
>> +	return container_of(crtc, struct vdrm_display, crtc);
>> +}
>> +
>> +static int vdrm_dumb_create(struct drm_file *file, struct drm_device *dev,
>> +			    struct drm_mode_create_dumb *args)
>> +{
>> +	struct vdrm_device *vdrm = to_vdrm_device(dev);
>> +
>> +	return vdrm->funcs->dumb_create(file, dev, args);
>> +}
>> +
>> +struct vdrm_framebuffer {
>> +	struct drm_framebuffer fb;
>> +	struct drm_framebuffer *parent_fb;
>> +};
>> +
>> +static inline struct vdrm_framebuffer *
>> +to_vdrm_framebuffer(struct drm_framebuffer *fb)
>> +{
>> +	return container_of(fb, struct vdrm_framebuffer, fb);
>> +}
>> +
>> +static void vdrm_fb_destroy(struct drm_framebuffer *fb)
>> +{
>> +	struct vdrm_framebuffer *vfb = to_vdrm_framebuffer(fb);
>> +
>> +	vfb->parent_fb->funcs->destroy(vfb->parent_fb);
>> +	drm_framebuffer_cleanup(fb);
>> +	kfree(vfb);
>> +}
>> +
>> +static const struct drm_framebuffer_funcs vdrm_fb_funcs = {
>> +	.destroy = vdrm_fb_destroy,
>> +};
>> +
>> +static int vdrm_fb_init(struct drm_device *dev, struct vdrm_framebuffer *vfb)
>> +{
>> +	vfb->fb = *vfb->parent_fb;
>> +	vfb->fb.dev = dev;
>> +
>> +	return drm_framebuffer_init(dev, &vfb->fb, &vdrm_fb_funcs);
>> +}
>> +
>> +static struct drm_framebuffer *
>> +vdrm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
>> +	       const struct drm_mode_fb_cmd2 *mode_cmd)
>> +{
>> +	struct vdrm_device *vdrm = to_vdrm_device(dev);
>> +	const struct drm_mode_config_funcs *mode_config_funcs =
>> +		vdrm->parent->mode_config.funcs;
>> +	struct vdrm_framebuffer *vfb;
>> +	struct drm_framebuffer *fb;
>> +	int ret;
>> +
>> +	vfb = kzalloc(sizeof(*vfb), GFP_KERNEL);
>> +	if (!vfb)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	fb = mode_config_funcs->fb_create(vdrm->parent, file_priv, mode_cmd);
>> +	if (IS_ERR(fb)) {
>> +		kfree(vfb);
>> +		return fb;
>> +	}
>> +
>> +	vfb->parent_fb = fb;
>> +	ret = vdrm_fb_init(dev, vfb);
>> +	if (ret) {
>> +		fb->funcs->destroy(fb);
>> +		kfree(vfb);
>> +		return ERR_PTR(ret);
>> +	}
>> +
>> +	return &vfb->fb;
>> +}
>> +
>> +static const struct drm_mode_config_funcs vdrm_mode_config_funcs = {
>> +	.fb_create = vdrm_fb_create,
>> +	.atomic_check = drm_atomic_helper_check,
>> +	.atomic_commit = drm_atomic_helper_commit,
>> +};
>> +
>> +static struct drm_display_mode *vdrm_create_mode(struct vdrm_display *disp)
>> +{
>> +	struct drm_display_mode *mode;
>> +	struct videomode videomode;
>> +
>> +	mode = drm_mode_create(&disp->dev->ddev);
>> +	if (!mode)
>> +		return NULL;
>> +
>> +	memset(&videomode, 0, sizeof(videomode));
>> +	videomode.hactive = disp->plane_info.width;
>> +	videomode.vactive = disp->plane_info.height;
>> +	videomode.pixelclock =
>> +		disp->parent_crtc->state->adjusted_mode.crtc_clock * 1000;
>> +	mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
>> +	drm_display_mode_from_videomode(&videomode, mode);
>> +
> If you create a drm_display_mode here then you can loose the videomode
> dependency. And I do not need to tell you that a Kconfig dependency is missing
> to use videomode. Do not forget to drop the include.
> 
> 
>> +	return mode;
>> +}
>> +
>> +static int vdrm_connector_get_mode(struct drm_connector *connector)
>> +{
>> +	struct vdrm_display *disp = to_vdrm_display(connector);
>> +	struct drm_display_mode *mode = vdrm_create_mode(disp);
>> +
>> +	if (!mode)
>> +		return 0;
>> +
>> +	drm_mode_probed_add(connector, mode);
>> +	return 1;
>> +}
>> +
>> +static const struct drm_connector_helper_funcs vdrm_conn_helper_funcs = {
>> +	.get_modes = vdrm_connector_get_mode,
>> +};
>> +
>> +/*
>> + * TODO:
>> + *  At the time this callback is called, the parent CRTC must be connected.
>> + *  Since this callback will not be called when detect() callback of the
>> + *  parent connector is called, vDRM driver desn't support hotplug.
>> + *  In the future, it is necessary that hotplug is supported.
>> + */
>> +static enum drm_connector_status
>> +vdrm_connector_detect(struct drm_connector *connector, bool force)
>> +{
>> +	struct vdrm_display *disp = to_vdrm_display(connector);
>> +	struct vdrm_device *vdrm = to_vdrm_device(connector->dev);
>> +	struct drm_connector *conn;
>> +	struct drm_connector_list_iter conn_iter;
>> +
>> +	drm_connector_list_iter_begin(vdrm->parent, &conn_iter);
>> +	drm_for_each_connector_iter(conn, &conn_iter) {
>> +		if (!conn->state)
>> +			continue;
>> +
>> +		if (conn->state->crtc == disp->parent_crtc) {
>> +			drm_connector_list_iter_end(&conn_iter);
>> +			return connector_status_connected;
>> +		}
>> +	}
>> +	drm_connector_list_iter_end(&conn_iter);
>> +	return connector_status_disconnected;
>> +}
>> +
>> +static const struct drm_connector_funcs vdrm_conn_funcs = {
>> +	.reset = drm_atomic_helper_connector_reset,
>> +	.detect = vdrm_connector_detect,
>> +	.fill_modes = drm_helper_probe_single_connector_modes,
>> +	.destroy = drm_connector_cleanup,
>> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>> +};
>> +
>> +static void vdrm_drv_finish_page_flip_internal(struct vdrm_display *disp)
>> +{
>> +	struct drm_device *dev = &disp->dev->ddev;
>> +	struct drm_pending_vblank_event *event;
>> +	unsigned long flags;
>> +
>> +	spin_lock_irqsave(&dev->event_lock, flags);
>> +	event = disp->event;
>> +	disp->event = NULL;
>> +	spin_unlock_irqrestore(&dev->event_lock, flags);
>> +
>> +	if (event == NULL)
>> +		return;
>> +
>> +	spin_lock_irqsave(&dev->event_lock, flags);
>> +	drm_crtc_send_vblank_event(&disp->crtc, event);
>> +	spin_unlock_irqrestore(&dev->event_lock, flags);
>> +
>> +	if (disp->vblank_count) {
>> +		drm_crtc_vblank_put(&disp->crtc);
>> +		disp->vblank_count--;
>> +	}
>> +}
>> +
>> +static void vdrm_plane_update(struct drm_plane *plane,
>> +			      struct drm_atomic_state *state)
>> +{
>> +	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
>> +	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
>> +	struct drm_crtc *vcrtc_old_state = old_state->crtc;
>> +	struct drm_crtc *vcrtc_plane_state = new_state->crtc;
>> +	struct drm_crtc *crtc;
>> +	struct vdrm_display *vdisplay;
>> +
>> +	crtc = (old_state->crtc ? old_state->crtc : new_state->crtc);
>> +	if (WARN_ON(!crtc))
>> +		return;
>> +
>> +	vdisplay = crtc_to_vdrm_display(crtc);
>> +
>> +	old_state->crtc = vdisplay->parent_crtc;
>> +	new_state->crtc = vdisplay->parent_crtc;
>> +
>> +	new_state->dst.x1 += vdisplay->plane_info.x;
>> +	new_state->dst.y1 += vdisplay->plane_info.y;
>> +	vdisplay->parent_plane_helper_funcs->atomic_update(plane, state);
>> +
>> +	old_state->crtc = vcrtc_old_state;
>> +	new_state->crtc = vcrtc_plane_state;
>> +}
>> +
>> +static struct vdrm_display *
>> +vdrm_plane_find_display(struct vdrm_device *vdrm, struct drm_plane *plane)
>> +{
>> +	struct vdrm_display *disp;
>> +
>> +	list_for_each_entry(disp, &vdrm->disps, head) {
>> +		if (disp->plane == plane)
>> +			return disp;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +static void vdrm_plane_reset(struct drm_plane *plane)
>> +{
>> +	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
>> +	struct vdrm_display *disp;
>> +
>> +	disp = vdrm_plane_find_display(vdrm, plane);
>> +	if (WARN_ON(!disp))
>> +		return;
>> +
>> +	disp->parent_plane_funcs->reset(plane);
>> +	plane->state->zpos = disp->plane_info.z;
>> +}
>> +
>> +static struct drm_property *
>> +vdrm_find_parent_property(struct vdrm_device *vdrm, struct drm_property *prop)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < vdrm->num_props; i++) {
>> +		if (vdrm->props[i].prop == prop)
>> +			return vdrm->props[i].parent_prop;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +static int vdrm_plane_set_property(struct drm_plane *plane,
>> +				   struct drm_plane_state *state,
>> +				   struct drm_property *property,
>> +				   uint64_t val)
>> +{
>> +	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
>> +	struct vdrm_display *disp;
>> +	struct drm_property *parent_prop;
>> +
>> +	disp = vdrm_plane_find_display(vdrm, plane);
>> +	if (WARN_ON(!disp))
>> +		return -EINVAL;
>> +
>> +	parent_prop = vdrm_find_parent_property(vdrm, property);
>> +	if (parent_prop && disp->parent_plane_funcs->atomic_set_property)
>> +		return disp->parent_plane_funcs->atomic_set_property(plane,
>> +								state,
>> +								parent_prop,
>> +								val);
>> +
>> +	if (vdrm->plane_props.offset_x == property) {
>> +		if (val > disp->parent_crtc->mode.hdisplay)
>> +			return -EINVAL;
>> +		disp->plane_info.x = val;
>> +	} else if (vdrm->plane_props.offset_y == property) {
>> +		if (val > disp->parent_crtc->mode.vdisplay)
>> +			return -EINVAL;
>> +		disp->plane_info.y = val;
>> +	} else if (vdrm->plane_props.width == property) {
>> +		if (val > disp->parent_crtc->mode.hdisplay)
>> +			return -EINVAL;
>> +		disp->plane_info.width = val;
>> +	} else if (vdrm->plane_props.height == property) {
>> +		if (val > disp->parent_crtc->mode.vdisplay)
>> +			return -EINVAL;
>> +		disp->plane_info.height = val;
>> +	} else {
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int vdrm_plane_get_property(struct drm_plane *plane,
>> +				   const struct drm_plane_state *state,
>> +				   struct drm_property *property,
>> +				   uint64_t *val)
>> +{
>> +	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
>> +	struct vdrm_display *disp;
>> +	struct drm_property *parent_prop;
>> +
>> +	disp = vdrm_plane_find_display(vdrm, plane);
>> +	if (WARN_ON(!disp))
>> +		return -EINVAL;
>> +
>> +	parent_prop = vdrm_find_parent_property(vdrm, property);
>> +	if (parent_prop && disp->parent_plane_funcs->atomic_get_property)
>> +		return disp->parent_plane_funcs->atomic_get_property(plane,
>> +								state,
>> +								parent_prop,
>> +								val);
>> +
>> +	if (vdrm->plane_props.offset_x == property)
>> +		*val = disp->plane_info.x;
>> +	else if (vdrm->plane_props.offset_y == property)
>> +		*val = disp->plane_info.y;
>> +	else if (vdrm->plane_props.width == property)
>> +		*val = disp->plane_info.width;
>> +	else if (vdrm->plane_props.height == property)
>> +		*val = disp->plane_info.height;
>> +	else
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>> +static int vdrm_crtc_check(struct drm_crtc *crtc,
>> +			   struct drm_atomic_state *state)
>> +{
>> +	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
>> +									  crtc);
>> +	bool has_primary = crtc_state->plane_mask &
>> +				drm_plane_mask(crtc->primary);
>> +
>> +	/* We always want to have an active plane with an active CRTC */
>> +	if (has_primary != crtc_state->enable)
>> +		return -EINVAL;
>> +
>> +	return drm_atomic_add_affected_planes(state, crtc);
>> +}
>> +
>> +static void vdrm_crtc_flush(struct drm_crtc *crtc,
>> +			    struct drm_atomic_state *state)
>> +{
>> +	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
>> +	struct vdrm_device *vdrm = disp->dev;
>> +
>> +	if (crtc->state->event) {
>> +		struct drm_device *dev = crtc->dev;
>> +		unsigned long flags;
>> +
>> +		if (disp->crtc_enabled) {
>> +			WARN_ON(drm_crtc_vblank_get(crtc) != 0);
>> +			disp->vblank_count++;
>> +		}
>> +
>> +		spin_lock_irqsave(&dev->event_lock, flags);
>> +		disp->event = crtc->state->event;
>> +		crtc->state->event = NULL;
>> +		spin_unlock_irqrestore(&dev->event_lock, flags);
>> +	}
>> +
>> +	if (vdrm->funcs->crtc_flush)
>> +		vdrm->funcs->crtc_flush(disp->parent_crtc);
>> +}
>> +
>> +static void vdrm_crtc_enable(struct drm_crtc *crtc,
>> +			     struct drm_atomic_state *state)
>> +{
>> +	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
>> +
>> +	drm_crtc_vblank_on(crtc);
>> +	disp->crtc_enabled = true;
>> +}
>> +
>> +static void vdrm_crtc_disable(struct drm_crtc *crtc,
>> +			      struct drm_atomic_state *state)
>> +{
>> +	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
>> +	unsigned long flags;
>> +	bool pending;
>> +
>> +	disp->crtc_enabled = false;
>> +	drm_crtc_vblank_off(crtc);
>> +
>> +	spin_lock_irqsave(&crtc->dev->event_lock, flags);
>> +	pending = disp->event != NULL;
>> +	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
>> +
>> +	if (!wait_event_timeout(disp->flip_wait, !pending,
>> +				msecs_to_jiffies(50))) {
>> +		DRM_WARN("VDRM: page flip timeout\n");
>> +		vdrm_drv_finish_page_flip_internal(disp);
>> +	}
>> +
>> +	spin_lock_irq(&crtc->dev->event_lock);
>> +	if (crtc->state->event) {
>> +		drm_crtc_send_vblank_event(crtc, crtc->state->event);
>> +		crtc->state->event = NULL;
>> +	}
>> +	spin_unlock_irq(&crtc->dev->event_lock);
>> +}
>> +
>> +static const struct drm_crtc_helper_funcs vdrm_crtc_helper_funcs = {
>> +	.atomic_check = vdrm_crtc_check,
>> +	.atomic_flush = vdrm_crtc_flush,
>> +	.atomic_enable = vdrm_crtc_enable,
>> +	.atomic_disable = vdrm_crtc_disable,
>> +};
>> +
>> +static int vdrm_crtc_enable_vblank(struct drm_crtc *crtc)
>> +{
>> +	struct vdrm_display *disp;
>> +
>> +	disp = crtc_to_vdrm_display(crtc);
>> +	disp->vblank_enabled = true;
>> +
>> +	return 0;
>> +}
>> +
>> +static void vdrm_crtc_disable_vblank(struct drm_crtc *crtc)
>> +{
>> +	struct vdrm_display *disp;
>> +
>> +	disp = crtc_to_vdrm_display(crtc);
>> +	disp->vblank_enabled = false;
>> +}
>> +
>> +static const struct drm_crtc_funcs vdrm_crtc_funcs = {
>> +	.reset = drm_atomic_helper_crtc_reset,
>> +	.destroy = drm_crtc_cleanup,
>> +	.set_config = drm_atomic_helper_set_config,
>> +	.page_flip = drm_atomic_helper_page_flip,
>> +	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
>> +	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
>> +	.enable_vblank = vdrm_crtc_enable_vblank,
>> +	.disable_vblank = vdrm_crtc_disable_vblank,
>> +};
>> +static const struct drm_encoder_funcs vdrm_encoder_funcs = {
>> +	.destroy = drm_encoder_cleanup,
>> +};
>> +
>> +static int vdrm_properties_init(struct vdrm_device *vdrm, int num_props,
>> +				struct vdrm_property_info *props)
>> +{
>> +	int i;
>> +	unsigned int w = vdrm->ddev.mode_config.max_width;
>> +	unsigned int h = vdrm->ddev.mode_config.max_height;
>> +
>> +	vdrm->plane_props.offset_x =
>> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_offset_x", 0, w);
>> +	if (!vdrm->plane_props.offset_x)
>> +		return -1;
>> +	vdrm->plane_props.offset_y =
>> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_offset_y", 0, h);
>> +	if (!vdrm->plane_props.offset_y)
>> +		return -1;
>> +	vdrm->plane_props.width =
>> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_width", 1, w);
>> +	if (!vdrm->plane_props.width)
>> +		return -1;
>> +	vdrm->plane_props.height =
>> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_height", 1, h);
>> +	if (!vdrm->plane_props.height)
>> +		return -1;
>> +
>> +	if (num_props == 0)
>> +		return 0;
>> +
>> +	vdrm->props = devm_kzalloc(vdrm->parent->dev,
>> +				    sizeof(*vdrm->props) * num_props,
>> +				    GFP_KERNEL);
>> +	if (!vdrm->props)
>> +		return -ENOMEM;
>> +
>> +	for (i = 0; i < num_props; i++) {
>> +		struct drm_property *p = props[i].prop;
>> +
>> +		vdrm->props[i].prop =
>> +			drm_property_create_range(&vdrm->ddev, p->flags,
>> +						  p->name, p->values[0],
>> +						  p->values[1]);
>> +		if (!vdrm->props[i].prop)
>> +			goto err;
>> +
>> +		vdrm->props[i].parent_prop = p;
>> +		vdrm->props[i].default_val = props[i].default_val;
>> +	}
>> +	vdrm->num_props = num_props;
>> +
>> +	return 0;
>> +
>> +err:
>> +	for (i--; i >= 0; i--)
>> +		drm_property_destroy(&vdrm->ddev, vdrm->props[i].prop);
>> +	devm_kfree(vdrm->parent->dev, vdrm->props);
>> +	return -1;
>> +}
>> +
>> +static int vdrm_of_get_plane(struct device_node *np,
>> +			     int *x, int *y, int *width, int *height, int *z)
>> +{
>> +	struct device_node *child;
>> +	int ret;
>> +
>> +	child = of_get_next_child(np, NULL);
>> +	if (!child)
>> +		return -ENODEV;
>> +
>> +	ret = of_property_read_u32(child, "x", x);
>> +	ret |= of_property_read_u32(child, "y", y);
>> +	ret |= of_property_read_u32(child, "width", width);
>> +	ret |= of_property_read_u32(child, "height", height);
>> +	ret |= of_property_read_u32(child, "zpos", z);
>> +
>> +	of_node_put(child);
>> +	return ret;
>> +}
>> +
>> +static void vdrm_dump(struct vdrm_device *vdrm)
>> +{
>> +	struct vdrm_display *disp;
>> +
>> +	DRM_INFO("Virtual DRM Info:\n");
>> +	list_for_each_entry(disp, &vdrm->disps, head) {
>> +		DRM_INFO("\tCONNECTOR: %d\n",
>> +			 disp->connector.base.id);
>> +		DRM_INFO("\tCRTC: %d\n",
>> +			 disp->crtc.base.id);
>> +		DRM_INFO("\tENCODER: %d\n",
>> +			 disp->encoder.base.id);
>> +		DRM_INFO("\tPLANE: %d\n",
>> +			 disp->plane->base.id);
>> +		DRM_INFO("\tParent CRTC: %d\n",
>> +			 disp->parent_crtc->base.id);
>> +	}
>> +}
>> +
>> +/**
>> + * vdrm_drv_handle_vblank - handle a vblank event for vDRM
>> + * @vdisplay: vDRM display object
>> + */
>> +void vdrm_drv_handle_vblank(struct vdrm_display *vdisplay)
>> +{
>> +	if (vdisplay->vblank_enabled)
>> +		drm_crtc_handle_vblank(&vdisplay->crtc);
>> +}
>> +
>> +/**
>> + * vdrm_drv_finish_page_flip - handle a page flip event for vDRM
>> + * @vdisplay: vDRM display object
>> + */
>> +void vdrm_drv_finish_page_flip(struct vdrm_display *vdisplay)
>> +{
>> +	vdrm_drv_finish_page_flip_internal(vdisplay);
>> +}
>> +
>> +DEFINE_DRM_GEM_CMA_FOPS(vdrm_fops);
>> +
>> +static struct drm_driver vdrm_driver = {
>> +	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
>> +	.dumb_create = vdrm_dumb_create,
>> +	.fops = &vdrm_fops,
>> +	.name = "virt-drm",
>> +	.desc = "Virtual DRM driver",
>> +	.date = "20201104",
>> +	.major = 1,
>> +	.minor = 0,
>> +};
>> +
>> +/**
>> + * vdrm_drv_init - Initialize vDRM device
>> + * @dev: parent DRM device
>> + * @np: vDRM device node in DTB
>> + * @num_props: number of parent property objects
>> + * @props: parent plane properties used in vDRM
>> + * @funcs: callbacks for vDRM
>> + *
>> + * Allocates a new vDRM device, initializes mode_config of the vDRM device
>> + * and allocates property objects. Not initialize plane, crtc, encoder and
>> + * connector. Initialization of plane must be done in vdrm_drv_plane_init()
>> + * and initialization of crtc, encoder and connector must be done by
>> + * vdrm_drv_display_init(). Also, after initializing the plane, crtc,
>> + * connector, and encoder, register vDRM device must be done by
>> + * vdrm_drv_register().
>> + *
>> + * Returns:
>> + * vDRM object (&vdrm_device) on success, error code encoded into the pointer
>> + * on failure.
>> + */
>> +struct vdrm_device *vdrm_drv_init(struct drm_device *dev,
>> +				  struct device_node *np, int num_props,
>> +				  struct vdrm_property_info *props,
>> +				  const struct vdrm_funcs *funcs)
>> +{
>> +	struct vdrm_device *vdrm;
>> +	struct vdrm_plane_info plane_info;
>> +	int ret;
>> +
>> +	if (!of_device_is_compatible(np, "virt-drm"))
>> +		return ERR_PTR(-ENODEV);
>> +
>> +	/* get plane information from device tree */
>> +	ret = vdrm_of_get_plane(np, &plane_info.x, &plane_info.y,
>> +				&plane_info.width, &plane_info.height,
>> +				&plane_info.z);
>> +	if (ret < 0) {
>> +		DRM_WARN("VDRM: failed get plane node of %s\n",
>> +			 of_node_full_name(np));
>> +		return ERR_PTR(ret);
>> +	}
>> +
>> +	vdrm_driver.prime_handle_to_fd = dev->driver->prime_handle_to_fd;
>> +	vdrm_driver.prime_fd_to_handle = dev->driver->prime_fd_to_handle;
>> +	vdrm_driver.gem_prime_import_sg_table =
>> +		dev->driver->gem_prime_import_sg_table;
>> +	vdrm_driver.gem_prime_mmap = dev->driver->gem_prime_mmap;
>> +
>> +	vdrm = devm_drm_dev_alloc(dev->dev, &vdrm_driver, struct vdrm_device,
>> +				  ddev);
>> +	if (IS_ERR(vdrm))
>> +		return vdrm;
>> +
>> +	vdrm->parent = dev;
>> +	vdrm->funcs = funcs;
>> +	vdrm->of_plane_info = plane_info;
>> +
>> +	INIT_LIST_HEAD(&vdrm->disps);
>> +
>> +	ret = drmm_mode_config_init(&vdrm->ddev);
>> +	if (ret)
>> +		goto failed;
>> +
>> +	vdrm->ddev.mode_config.min_width = 0;
>> +	vdrm->ddev.mode_config.min_height = 0;
>> +	vdrm->ddev.mode_config.max_width = 8190;
>> +	vdrm->ddev.mode_config.max_height = 8190;
>> +	vdrm->ddev.mode_config.normalize_zpos = true;
>> +	vdrm->ddev.mode_config.funcs = &vdrm_mode_config_funcs;
>> +
>> +	ret = vdrm_properties_init(vdrm, num_props, props);
>> +	if (ret < 0)
>> +		goto failed;
>> +
>> +	drm_dev_set_unique(&vdrm->ddev, of_node_full_name(np));
>> +	return vdrm;
>> +
>> +failed:
>> +	kfree(vdrm);
>> +	return ERR_PTR(ret);
>> +}
>> +
>> +/**
>> + * vdrm_drv_plane_init - Initialize the plane used by vDRM
>> + * @vdrm: vDRM object
>> + * @plane: plane to assign to vDRM
>> + * @funcs: callbacks for the plane
>> + * @helper_funcs: helper vtable to set for plane
>> + * @formats: color formats
>> + * @num_formats: number of color formats
>> + * @max_zpos: max value for zpos property of plane
>> + *
>> + * Initializes a plane object of PRIMARY type by drm_universal_plane_init()
>> + * and initializes @plane's properties. The property passed by vdrm_drv_init()
>> + * is set to @plane.
>> + *
>> + * Returns:
>> + * Zero on success, error code on failure.
>> + */
>> +int vdrm_drv_plane_init(struct vdrm_device *vdrm, struct drm_plane *plane,
>> +			const struct drm_plane_funcs *funcs,
>> +			const struct drm_plane_helper_funcs *helper_funcs,
>> +			const u32 *formats, unsigned int num_formats,
>> +			int max_zpos)
>> +{
>> +	struct vdrm_display *disp;
>> +	int i, ret;
>> +
>> +	disp = kzalloc(sizeof(*disp), GFP_KERNEL);
>> +	if (!disp)
>> +		return -ENOMEM;
>> +
>> +	disp->dev = vdrm;
>> +	disp->plane = plane;
>> +	disp->plane_info = vdrm->of_plane_info;
>> +
>> +	disp->parent_plane_funcs = funcs;
>> +	disp->parent_plane_helper_funcs = helper_funcs;
>> +	disp->plane_funcs = *funcs;
>> +	disp->plane_helper_funcs = *helper_funcs;
>> +
>> +	disp->plane_funcs.reset = vdrm_plane_reset;
>> +	disp->plane_funcs.atomic_set_property = vdrm_plane_set_property;
>> +	disp->plane_funcs.atomic_get_property = vdrm_plane_get_property;
>> +	disp->plane_helper_funcs.atomic_update = vdrm_plane_update;
>> +
>> +	drm_plane_helper_add(disp->plane, &disp->plane_helper_funcs);
>> +	ret = drm_universal_plane_init(&vdrm->ddev, plane, 0,
>> +				       &disp->plane_funcs, formats,
>> +				       num_formats, NULL,
>> +				       DRM_PLANE_TYPE_PRIMARY, NULL);
>> +	if (ret) {
>> +		kfree(disp);
>> +		return ret;
>> +	}
>> +
>> +	drm_plane_create_alpha_property(plane);
>> +	drm_plane_create_zpos_property(plane, disp->plane_info.z, 0, max_zpos);
>> +	drm_object_attach_property(&plane->base,
>> +				   vdrm->plane_props.offset_x,
>> +				   disp->plane_info.x);
>> +	drm_object_attach_property(&plane->base,
>> +				   vdrm->plane_props.offset_y,
>> +				   disp->plane_info.y);
>> +	drm_object_attach_property(&plane->base,
>> +				   vdrm->plane_props.width,
>> +				   disp->plane_info.width);
>> +	drm_object_attach_property(&plane->base,
>> +				   vdrm->plane_props.height,
>> +				   disp->plane_info.height);
>> +	for (i = 0; i < vdrm->num_props; i++) {
>> +		drm_object_attach_property(&plane->base,
>> +					   vdrm->props[i].prop,
>> +					   vdrm->props[i].default_val);
>> +	}
>> +
>> +	INIT_LIST_HEAD(&disp->head);
>> +	list_add_tail(&disp->head, &vdrm->disps);
>> +	vdrm->num_crtcs++;
>> +	return 0;
>> +}
>> +
>> +/**
>> + * vdrm_drv_display_init - Initialize the vDRM display object
>> + * @vdrm: vDRM object
>> + * @crtc: parent crtc to be linked with the vDRM crtc
>> + * @plane: plane assigned to vDRM
>> + *
>> + * Initializes crtc, connector and encorder, and links @crtc to crtc of vDRM.
>> + *
>> + * Returns:
>> + * vDRM display object on success, error code encoded into the pointer on
>> + * failure.
>> + */
>> +struct vdrm_display *vdrm_drv_display_init(struct vdrm_device *vdrm,
>> +					   struct drm_crtc *crtc,
>> +					   struct drm_plane *plane)
>> +{
>> +	struct vdrm_display *disp;
>> +	int ret;
>> +
>> +	disp = vdrm_plane_find_display(vdrm, plane);
>> +	if (!disp)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	drm_crtc_helper_add(&disp->crtc, &vdrm_crtc_helper_funcs);
>> +	ret = drm_crtc_init_with_planes(&vdrm->ddev, &disp->crtc, plane, NULL,
>> +					&vdrm_crtc_funcs, NULL);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	drm_connector_helper_add(&disp->connector, &vdrm_conn_helper_funcs);
>> +	ret = drm_connector_init(&vdrm->ddev, &disp->connector,
>> +				 &vdrm_conn_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	disp->encoder.possible_crtcs = drm_crtc_mask(&disp->crtc);
>> +	ret = drm_encoder_init(&vdrm->ddev, &disp->encoder, &vdrm_encoder_funcs,
>> +			       DRM_MODE_ENCODER_NONE, NULL);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	ret = drm_connector_attach_encoder(&disp->connector, &disp->encoder);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	init_waitqueue_head(&disp->flip_wait);
>> +	disp->parent_crtc = crtc;
>> +
>> +	return disp;
>> +}
>> +
>> +/**
>> + * vdrm_drv_register - Register vDRM device
>> + * @vdrm: vDRM object
>> + *
>> + * Returns:
>> + * Zero on success, error code on failure.
>> + */
>> +int vdrm_drv_register(struct vdrm_device *vdrm)
>> +{
>> +	int ret;
>> +	struct drm_device *dev = &vdrm->ddev;
>> +
>> +	ret = drm_vblank_init(dev, vdrm->num_crtcs);
>> +	if (ret)
>> +		return ret;
>> +
>> +	drm_mode_config_reset(dev);
>> +
>> +	ret = drm_dev_register(dev, 0);
>> +	if (ret)
>> +		return ret;
>> +
>> +	dev->irq_enabled = true;
>> +
>> +	DRM_INFO("Virtual Device is initialized.\n");
>> +
>> +	vdrm_dump(vdrm);
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * vdrm_drv_fini - release vDRM resources
>> + * @vdrm: vDRM object
>> + */
>> +void vdrm_drv_fini(struct vdrm_device *vdrm)
>> +{
>> +	struct vdrm_display *disp;
>> +
>> +	if (vdrm->ddev.registered)
>> +		drm_dev_unregister(&vdrm->ddev);
>> +	drm_mode_config_cleanup(&vdrm->ddev);
>> +
>> +	list_for_each_entry(disp, &vdrm->disps, head)
>> +		kfree(disp);
>> +}
>> diff --git a/drivers/gpu/drm/vdrm/vdrm_drv.h b/drivers/gpu/drm/vdrm/vdrm_drv.h
>> new file mode 100644
>> index 000000000000..67b8e02efddf
>> --- /dev/null
>> +++ b/drivers/gpu/drm/vdrm/vdrm_drv.h
>> @@ -0,0 +1,80 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * vdrm_drv.h -- Virtual DRM driver
>> + *
>> + * Copyright (C) 2021 Renesas Electronics Corporation
>> + */
>> +
>> +#ifndef __VDRM_DRV_H__
>> +#define __VDRM_DRV_H__
>> +
>> +#include <drm/drm_device.h>
>> +
>> +#include "vdrm_api.h"
>> +
>> +struct vdrm_property {
>> +	struct drm_property *prop;
>> +	struct drm_property *parent_prop;
>> +	uint64_t default_val;
>> +};
>> +
>> +struct vdrm_plane_info {
>> +	int x;
>> +	int y;
>> +	unsigned int width;
>> +	unsigned int height;
>> +	unsigned int z;
>> +};
>> +
>> +struct vdrm_device;
>> +
>> +struct vdrm_display {
>> +	struct drm_connector connector;
>> +	struct drm_crtc crtc;
>> +	struct drm_crtc *parent_crtc;
>> +	struct drm_plane *plane;
>> +	struct drm_encoder encoder;
>> +	struct drm_pending_vblank_event *event;
>> +	struct vdrm_device *dev;
>> +	bool vblank_enabled;
>> +	wait_queue_head_t flip_wait;
>> +	bool crtc_enabled;
>> +	int vblank_count;
>> +
>> +	struct list_head head;
>> +
>> +	struct vdrm_plane_info plane_info;
>> +
>> +	const struct drm_plane_funcs *parent_plane_funcs;
>> +	const struct drm_plane_helper_funcs *parent_plane_helper_funcs;
>> +	struct drm_plane_funcs plane_funcs;
>> +	struct drm_plane_helper_funcs plane_helper_funcs;
>> +};
>> +
>> +struct vdrm_device {
>> +	struct drm_device ddev;
>> +	struct drm_device *parent;
>> +
>> +	int num_crtcs;
>> +	struct list_head disps;
>> +
>> +	const struct vdrm_funcs *funcs;
>> +	struct vdrm_property *props;
>> +	int num_props;
>> +
>> +	struct {
>> +		struct drm_property *offset_x;
>> +		struct drm_property *offset_y;
>> +		struct drm_property *width;
>> +		struct drm_property *height;
>> +	} plane_props;
>> +
>> +	struct vdrm_plane_info of_plane_info;
>> +};
>> +
>> +static inline struct vdrm_device *to_vdrm_device(struct drm_device *dev)
>> +{
>> +	return container_of(dev, struct vdrm_device, ddev);
>> +}
>> +
>> +#endif /* __VDRM_DRV_H__ */
>> -- 
>> 2.25.1

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 1/4] drm: Add Virtual DRM device driver
@ 2021-06-22  4:10       ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-22  4:10 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: devicetree, Takanari Hayama, Thomas Zimmermann, linux-doc,
	David Airlie, dri-devel, linux-kernel, linux-renesas-soc,
	Kieran Bingham, Laurent Pinchart, Damian Hobson-Garcia

Hi, Sam

Thank you for looking at the details.
I will fix it according to your comment.

Best regards
Tomohito Esaki

On 2021/06/22 0:55, Sam Ravnborg wrote:
> Hi Tomohito
> 
> On Mon, Jun 21, 2021 at 03:44:00PM +0900, Tomohito Esaki wrote:
>> Virtual DRM splits the resources of an overlay plane into multiple
>> virtual devices to allow each plane to be accessed by each process.
>>
>> This makes it possible to overlay images output from multiple processes
>> on a display. For example, one process displays the camera image without
>> compositor while another process overlays the compositor's drawing of
>> the UI.
>>
>> The virtual DRM creates standalone virtual device and make DRM planes
>> from a master device (e.g. card0) accessible via one or more virtual
>> devices. However, these plane are no longer accessible from the original
>> device.
>> Each virtual device (and plane) can be accessed via a separate
>> device file.
>>
>> Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
>> ---
>>  drivers/gpu/drm/Kconfig         |   7 +
>>  drivers/gpu/drm/Makefile        |   1 +
>>  drivers/gpu/drm/vdrm/vdrm_api.h |  68 +++
>>  drivers/gpu/drm/vdrm/vdrm_drv.c | 859 ++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/vdrm/vdrm_drv.h |  80 +++
> 
> Plase consider making the header files self-contained.
> So there are no hdden dependencies between the two.
> 
> Use forward declarations rahter than including header files is possible.
> 
> A few trivial comments in the following. I did not try to follow all the
> functionality of the driver and I expect others to comment on the idea.
> 
> 	Sam
> 
>>  5 files changed, 1015 insertions(+)
>>  create mode 100644 drivers/gpu/drm/vdrm/vdrm_api.h
>>  create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.c
>>  create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.h
>>
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index 3c16bd1afd87..ba7f4eeab385 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -294,6 +294,13 @@ config DRM_VKMS
>>  
>>  	  If M is selected the module will be called vkms.
>>  
>> +config DRM_VDRM
>> +	tristate "Virtual DRM"
>> +	depends on DRM
>> +	help
>> +	  Virtual DRM splits the resources of an overlay plane into multiple
>> +	  virtual devices to allow each plane to be accessed by each process.
> Could you look into pulling a bit more info here. You made a very nice
> intro to the patch, consider using it in the help text too.
> 
> 
>> +
>>  source "drivers/gpu/drm/exynos/Kconfig"
>>  
>>  source "drivers/gpu/drm/rockchip/Kconfig"
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index 5279db4392df..55dbf85e2579 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
>>  obj-$(CONFIG_DRM_VIA)	+=via/
>>  obj-$(CONFIG_DRM_VGEM)	+= vgem/
>>  obj-$(CONFIG_DRM_VKMS)	+= vkms/
>> +obj-$(CONFIG_DRM_VDRM)	+= vdrm/
> Alphabetic order (mostly) so before vgem/
> 
>>  obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
>>  obj-$(CONFIG_DRM_EXYNOS) +=exynos/
>>  obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
>> diff --git a/drivers/gpu/drm/vdrm/vdrm_api.h b/drivers/gpu/drm/vdrm/vdrm_api.h
>> new file mode 100644
>> index 000000000000..dd4d7e774800
>> --- /dev/null
>> +++ b/drivers/gpu/drm/vdrm/vdrm_api.h
>> @@ -0,0 +1,68 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * vdrm_api.h -- Virtual DRM API
>> + *
>> + * Copyright (C) 2021 Renesas Electronics Corporation
>> + */
>> +
>> +#ifndef __VDRM_API__
>> +#define __VDRM_API__
>> +
>> +#include <linux/of_device.h>
>> +#include <drm/drm_crtc.h>
>> +
>> +/**
>> + * struct vdrm_property_info - Information about the properties passed from
>> + *			       the DRM driver to vDRM
>> + * @prop: Parent property to pass to vDRM
>> + * @default_val: Default value for the property passed to vDRM
>> + */
>> +struct vdrm_property_info {
>> +	struct drm_property *prop;
>> +	uint64_t default_val;
>> +};
> It would be nice that all structs used inline comments - and then you
> are consistent too.
> 
>> +
>> +/**
>> + * struct vdrm_funcs - Callbacks to parent DRM driver
>> + */
>> +struct vdrm_funcs {
>> +	/**
>> +	 * @dumb_create:
>> +	 *
>> +	 * Called by &drm_driver.dumb_create. Please read the documentation
>> +	 * for the &drm_driver.dumb_create hook for more details.
>> +	 */
>> +	int (*dumb_create)(struct drm_file *file, struct drm_device *dev,
>> +			   struct drm_mode_create_dumb *args);
>> +
>> +	/**
>> +	 * @crtc_flush:
>> +	 *
>> +	 * Called by &drm_crtc_helper_funcs.atomic_flush. Please read the
>> +	 * documentation for the &drm_crtc_helper_funcs.atomic_flush hook for
>> +	 * more details.
>> +	 */
>> +	void (*crtc_flush)(struct drm_crtc *crtc);
>> +};
>> +
>> +struct vdrm_device;
>> +struct vdrm_display;
>> +
>> +void vdrm_drv_handle_vblank(struct vdrm_display *vdisplay);
>> +void vdrm_drv_finish_page_flip(struct vdrm_display *vdisplay);
>> +struct vdrm_device *vdrm_drv_init(struct drm_device *dev,
>> +				  struct device_node *np, int num_props,
>> +				  struct vdrm_property_info *props,
>> +				  const struct vdrm_funcs *funcs);
>> +int vdrm_drv_plane_init(struct vdrm_device *vdrm, struct drm_plane *plane,
>> +			const struct drm_plane_funcs *funcs,
>> +			const struct drm_plane_helper_funcs *helper_funcs,
>> +			const u32 *formats, unsigned int num_formats,
>> +			int max_zpos);
>> +struct vdrm_display *vdrm_drv_display_init(struct vdrm_device *vdrm,
>> +					   struct drm_crtc *crtc,
>> +					   struct drm_plane *plane);
>> +int vdrm_drv_register(struct vdrm_device *vdrm);
>> +void vdrm_drv_fini(struct vdrm_device *vdrm);
>> +
>> +#endif /* __VDRM_API__ */
>> diff --git a/drivers/gpu/drm/vdrm/vdrm_drv.c b/drivers/gpu/drm/vdrm/vdrm_drv.c
>> new file mode 100644
>> index 000000000000..835bdecfc8e6
>> --- /dev/null
>> +++ b/drivers/gpu/drm/vdrm/vdrm_drv.c
>> @@ -0,0 +1,859 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * vdrm_drv.c -- Virtual DRM driver
>> + *
>> + * Copyright (C) 2021 Renesas Electronics Corporation
>> + *
>> + * This driver is based on drivers/gpu/drm/drm_simple_kms_helper.c.
>> + */
>> +
>> +#include <linux/of_device.h>
>> +#include <drm/drm_atomic.h>
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_atomic_uapi.h>
>> +#include <drm/drm_fb_cma_helper.h>
>> +#include <drm/drm_fb_helper.h>
>> +#include <drm/drm_drv.h>
>> +#include <drm/drm_gem_cma_helper.h>
>> +#include <drm/drm_plane_helper.h>
>> +#include <drm/drm_probe_helper.h>
>> +#include <drm/drm_vblank.h>
>> +#include <drm/drm_gem_framebuffer_helper.h>
>> +#include <video/videomode.h>
>> +
>> +#include "vdrm_drv.h"
>> +
>> +static inline struct vdrm_display *
>> +to_vdrm_display(struct drm_connector *connector)
>> +{
>> +	return container_of(connector, struct vdrm_display, connector);
>> +}
>> +
>> +static inline struct vdrm_display *
>> +crtc_to_vdrm_display(struct drm_crtc *crtc)
>> +{
>> +	return container_of(crtc, struct vdrm_display, crtc);
>> +}
>> +
>> +static int vdrm_dumb_create(struct drm_file *file, struct drm_device *dev,
>> +			    struct drm_mode_create_dumb *args)
>> +{
>> +	struct vdrm_device *vdrm = to_vdrm_device(dev);
>> +
>> +	return vdrm->funcs->dumb_create(file, dev, args);
>> +}
>> +
>> +struct vdrm_framebuffer {
>> +	struct drm_framebuffer fb;
>> +	struct drm_framebuffer *parent_fb;
>> +};
>> +
>> +static inline struct vdrm_framebuffer *
>> +to_vdrm_framebuffer(struct drm_framebuffer *fb)
>> +{
>> +	return container_of(fb, struct vdrm_framebuffer, fb);
>> +}
>> +
>> +static void vdrm_fb_destroy(struct drm_framebuffer *fb)
>> +{
>> +	struct vdrm_framebuffer *vfb = to_vdrm_framebuffer(fb);
>> +
>> +	vfb->parent_fb->funcs->destroy(vfb->parent_fb);
>> +	drm_framebuffer_cleanup(fb);
>> +	kfree(vfb);
>> +}
>> +
>> +static const struct drm_framebuffer_funcs vdrm_fb_funcs = {
>> +	.destroy = vdrm_fb_destroy,
>> +};
>> +
>> +static int vdrm_fb_init(struct drm_device *dev, struct vdrm_framebuffer *vfb)
>> +{
>> +	vfb->fb = *vfb->parent_fb;
>> +	vfb->fb.dev = dev;
>> +
>> +	return drm_framebuffer_init(dev, &vfb->fb, &vdrm_fb_funcs);
>> +}
>> +
>> +static struct drm_framebuffer *
>> +vdrm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
>> +	       const struct drm_mode_fb_cmd2 *mode_cmd)
>> +{
>> +	struct vdrm_device *vdrm = to_vdrm_device(dev);
>> +	const struct drm_mode_config_funcs *mode_config_funcs =
>> +		vdrm->parent->mode_config.funcs;
>> +	struct vdrm_framebuffer *vfb;
>> +	struct drm_framebuffer *fb;
>> +	int ret;
>> +
>> +	vfb = kzalloc(sizeof(*vfb), GFP_KERNEL);
>> +	if (!vfb)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	fb = mode_config_funcs->fb_create(vdrm->parent, file_priv, mode_cmd);
>> +	if (IS_ERR(fb)) {
>> +		kfree(vfb);
>> +		return fb;
>> +	}
>> +
>> +	vfb->parent_fb = fb;
>> +	ret = vdrm_fb_init(dev, vfb);
>> +	if (ret) {
>> +		fb->funcs->destroy(fb);
>> +		kfree(vfb);
>> +		return ERR_PTR(ret);
>> +	}
>> +
>> +	return &vfb->fb;
>> +}
>> +
>> +static const struct drm_mode_config_funcs vdrm_mode_config_funcs = {
>> +	.fb_create = vdrm_fb_create,
>> +	.atomic_check = drm_atomic_helper_check,
>> +	.atomic_commit = drm_atomic_helper_commit,
>> +};
>> +
>> +static struct drm_display_mode *vdrm_create_mode(struct vdrm_display *disp)
>> +{
>> +	struct drm_display_mode *mode;
>> +	struct videomode videomode;
>> +
>> +	mode = drm_mode_create(&disp->dev->ddev);
>> +	if (!mode)
>> +		return NULL;
>> +
>> +	memset(&videomode, 0, sizeof(videomode));
>> +	videomode.hactive = disp->plane_info.width;
>> +	videomode.vactive = disp->plane_info.height;
>> +	videomode.pixelclock =
>> +		disp->parent_crtc->state->adjusted_mode.crtc_clock * 1000;
>> +	mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
>> +	drm_display_mode_from_videomode(&videomode, mode);
>> +
> If you create a drm_display_mode here then you can loose the videomode
> dependency. And I do not need to tell you that a Kconfig dependency is missing
> to use videomode. Do not forget to drop the include.
> 
> 
>> +	return mode;
>> +}
>> +
>> +static int vdrm_connector_get_mode(struct drm_connector *connector)
>> +{
>> +	struct vdrm_display *disp = to_vdrm_display(connector);
>> +	struct drm_display_mode *mode = vdrm_create_mode(disp);
>> +
>> +	if (!mode)
>> +		return 0;
>> +
>> +	drm_mode_probed_add(connector, mode);
>> +	return 1;
>> +}
>> +
>> +static const struct drm_connector_helper_funcs vdrm_conn_helper_funcs = {
>> +	.get_modes = vdrm_connector_get_mode,
>> +};
>> +
>> +/*
>> + * TODO:
>> + *  At the time this callback is called, the parent CRTC must be connected.
>> + *  Since this callback will not be called when detect() callback of the
>> + *  parent connector is called, vDRM driver desn't support hotplug.
>> + *  In the future, it is necessary that hotplug is supported.
>> + */
>> +static enum drm_connector_status
>> +vdrm_connector_detect(struct drm_connector *connector, bool force)
>> +{
>> +	struct vdrm_display *disp = to_vdrm_display(connector);
>> +	struct vdrm_device *vdrm = to_vdrm_device(connector->dev);
>> +	struct drm_connector *conn;
>> +	struct drm_connector_list_iter conn_iter;
>> +
>> +	drm_connector_list_iter_begin(vdrm->parent, &conn_iter);
>> +	drm_for_each_connector_iter(conn, &conn_iter) {
>> +		if (!conn->state)
>> +			continue;
>> +
>> +		if (conn->state->crtc == disp->parent_crtc) {
>> +			drm_connector_list_iter_end(&conn_iter);
>> +			return connector_status_connected;
>> +		}
>> +	}
>> +	drm_connector_list_iter_end(&conn_iter);
>> +	return connector_status_disconnected;
>> +}
>> +
>> +static const struct drm_connector_funcs vdrm_conn_funcs = {
>> +	.reset = drm_atomic_helper_connector_reset,
>> +	.detect = vdrm_connector_detect,
>> +	.fill_modes = drm_helper_probe_single_connector_modes,
>> +	.destroy = drm_connector_cleanup,
>> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>> +};
>> +
>> +static void vdrm_drv_finish_page_flip_internal(struct vdrm_display *disp)
>> +{
>> +	struct drm_device *dev = &disp->dev->ddev;
>> +	struct drm_pending_vblank_event *event;
>> +	unsigned long flags;
>> +
>> +	spin_lock_irqsave(&dev->event_lock, flags);
>> +	event = disp->event;
>> +	disp->event = NULL;
>> +	spin_unlock_irqrestore(&dev->event_lock, flags);
>> +
>> +	if (event == NULL)
>> +		return;
>> +
>> +	spin_lock_irqsave(&dev->event_lock, flags);
>> +	drm_crtc_send_vblank_event(&disp->crtc, event);
>> +	spin_unlock_irqrestore(&dev->event_lock, flags);
>> +
>> +	if (disp->vblank_count) {
>> +		drm_crtc_vblank_put(&disp->crtc);
>> +		disp->vblank_count--;
>> +	}
>> +}
>> +
>> +static void vdrm_plane_update(struct drm_plane *plane,
>> +			      struct drm_atomic_state *state)
>> +{
>> +	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
>> +	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
>> +	struct drm_crtc *vcrtc_old_state = old_state->crtc;
>> +	struct drm_crtc *vcrtc_plane_state = new_state->crtc;
>> +	struct drm_crtc *crtc;
>> +	struct vdrm_display *vdisplay;
>> +
>> +	crtc = (old_state->crtc ? old_state->crtc : new_state->crtc);
>> +	if (WARN_ON(!crtc))
>> +		return;
>> +
>> +	vdisplay = crtc_to_vdrm_display(crtc);
>> +
>> +	old_state->crtc = vdisplay->parent_crtc;
>> +	new_state->crtc = vdisplay->parent_crtc;
>> +
>> +	new_state->dst.x1 += vdisplay->plane_info.x;
>> +	new_state->dst.y1 += vdisplay->plane_info.y;
>> +	vdisplay->parent_plane_helper_funcs->atomic_update(plane, state);
>> +
>> +	old_state->crtc = vcrtc_old_state;
>> +	new_state->crtc = vcrtc_plane_state;
>> +}
>> +
>> +static struct vdrm_display *
>> +vdrm_plane_find_display(struct vdrm_device *vdrm, struct drm_plane *plane)
>> +{
>> +	struct vdrm_display *disp;
>> +
>> +	list_for_each_entry(disp, &vdrm->disps, head) {
>> +		if (disp->plane == plane)
>> +			return disp;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +static void vdrm_plane_reset(struct drm_plane *plane)
>> +{
>> +	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
>> +	struct vdrm_display *disp;
>> +
>> +	disp = vdrm_plane_find_display(vdrm, plane);
>> +	if (WARN_ON(!disp))
>> +		return;
>> +
>> +	disp->parent_plane_funcs->reset(plane);
>> +	plane->state->zpos = disp->plane_info.z;
>> +}
>> +
>> +static struct drm_property *
>> +vdrm_find_parent_property(struct vdrm_device *vdrm, struct drm_property *prop)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < vdrm->num_props; i++) {
>> +		if (vdrm->props[i].prop == prop)
>> +			return vdrm->props[i].parent_prop;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +static int vdrm_plane_set_property(struct drm_plane *plane,
>> +				   struct drm_plane_state *state,
>> +				   struct drm_property *property,
>> +				   uint64_t val)
>> +{
>> +	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
>> +	struct vdrm_display *disp;
>> +	struct drm_property *parent_prop;
>> +
>> +	disp = vdrm_plane_find_display(vdrm, plane);
>> +	if (WARN_ON(!disp))
>> +		return -EINVAL;
>> +
>> +	parent_prop = vdrm_find_parent_property(vdrm, property);
>> +	if (parent_prop && disp->parent_plane_funcs->atomic_set_property)
>> +		return disp->parent_plane_funcs->atomic_set_property(plane,
>> +								state,
>> +								parent_prop,
>> +								val);
>> +
>> +	if (vdrm->plane_props.offset_x == property) {
>> +		if (val > disp->parent_crtc->mode.hdisplay)
>> +			return -EINVAL;
>> +		disp->plane_info.x = val;
>> +	} else if (vdrm->plane_props.offset_y == property) {
>> +		if (val > disp->parent_crtc->mode.vdisplay)
>> +			return -EINVAL;
>> +		disp->plane_info.y = val;
>> +	} else if (vdrm->plane_props.width == property) {
>> +		if (val > disp->parent_crtc->mode.hdisplay)
>> +			return -EINVAL;
>> +		disp->plane_info.width = val;
>> +	} else if (vdrm->plane_props.height == property) {
>> +		if (val > disp->parent_crtc->mode.vdisplay)
>> +			return -EINVAL;
>> +		disp->plane_info.height = val;
>> +	} else {
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int vdrm_plane_get_property(struct drm_plane *plane,
>> +				   const struct drm_plane_state *state,
>> +				   struct drm_property *property,
>> +				   uint64_t *val)
>> +{
>> +	struct vdrm_device *vdrm = to_vdrm_device(plane->dev);
>> +	struct vdrm_display *disp;
>> +	struct drm_property *parent_prop;
>> +
>> +	disp = vdrm_plane_find_display(vdrm, plane);
>> +	if (WARN_ON(!disp))
>> +		return -EINVAL;
>> +
>> +	parent_prop = vdrm_find_parent_property(vdrm, property);
>> +	if (parent_prop && disp->parent_plane_funcs->atomic_get_property)
>> +		return disp->parent_plane_funcs->atomic_get_property(plane,
>> +								state,
>> +								parent_prop,
>> +								val);
>> +
>> +	if (vdrm->plane_props.offset_x == property)
>> +		*val = disp->plane_info.x;
>> +	else if (vdrm->plane_props.offset_y == property)
>> +		*val = disp->plane_info.y;
>> +	else if (vdrm->plane_props.width == property)
>> +		*val = disp->plane_info.width;
>> +	else if (vdrm->plane_props.height == property)
>> +		*val = disp->plane_info.height;
>> +	else
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>> +static int vdrm_crtc_check(struct drm_crtc *crtc,
>> +			   struct drm_atomic_state *state)
>> +{
>> +	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
>> +									  crtc);
>> +	bool has_primary = crtc_state->plane_mask &
>> +				drm_plane_mask(crtc->primary);
>> +
>> +	/* We always want to have an active plane with an active CRTC */
>> +	if (has_primary != crtc_state->enable)
>> +		return -EINVAL;
>> +
>> +	return drm_atomic_add_affected_planes(state, crtc);
>> +}
>> +
>> +static void vdrm_crtc_flush(struct drm_crtc *crtc,
>> +			    struct drm_atomic_state *state)
>> +{
>> +	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
>> +	struct vdrm_device *vdrm = disp->dev;
>> +
>> +	if (crtc->state->event) {
>> +		struct drm_device *dev = crtc->dev;
>> +		unsigned long flags;
>> +
>> +		if (disp->crtc_enabled) {
>> +			WARN_ON(drm_crtc_vblank_get(crtc) != 0);
>> +			disp->vblank_count++;
>> +		}
>> +
>> +		spin_lock_irqsave(&dev->event_lock, flags);
>> +		disp->event = crtc->state->event;
>> +		crtc->state->event = NULL;
>> +		spin_unlock_irqrestore(&dev->event_lock, flags);
>> +	}
>> +
>> +	if (vdrm->funcs->crtc_flush)
>> +		vdrm->funcs->crtc_flush(disp->parent_crtc);
>> +}
>> +
>> +static void vdrm_crtc_enable(struct drm_crtc *crtc,
>> +			     struct drm_atomic_state *state)
>> +{
>> +	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
>> +
>> +	drm_crtc_vblank_on(crtc);
>> +	disp->crtc_enabled = true;
>> +}
>> +
>> +static void vdrm_crtc_disable(struct drm_crtc *crtc,
>> +			      struct drm_atomic_state *state)
>> +{
>> +	struct vdrm_display *disp = crtc_to_vdrm_display(crtc);
>> +	unsigned long flags;
>> +	bool pending;
>> +
>> +	disp->crtc_enabled = false;
>> +	drm_crtc_vblank_off(crtc);
>> +
>> +	spin_lock_irqsave(&crtc->dev->event_lock, flags);
>> +	pending = disp->event != NULL;
>> +	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
>> +
>> +	if (!wait_event_timeout(disp->flip_wait, !pending,
>> +				msecs_to_jiffies(50))) {
>> +		DRM_WARN("VDRM: page flip timeout\n");
>> +		vdrm_drv_finish_page_flip_internal(disp);
>> +	}
>> +
>> +	spin_lock_irq(&crtc->dev->event_lock);
>> +	if (crtc->state->event) {
>> +		drm_crtc_send_vblank_event(crtc, crtc->state->event);
>> +		crtc->state->event = NULL;
>> +	}
>> +	spin_unlock_irq(&crtc->dev->event_lock);
>> +}
>> +
>> +static const struct drm_crtc_helper_funcs vdrm_crtc_helper_funcs = {
>> +	.atomic_check = vdrm_crtc_check,
>> +	.atomic_flush = vdrm_crtc_flush,
>> +	.atomic_enable = vdrm_crtc_enable,
>> +	.atomic_disable = vdrm_crtc_disable,
>> +};
>> +
>> +static int vdrm_crtc_enable_vblank(struct drm_crtc *crtc)
>> +{
>> +	struct vdrm_display *disp;
>> +
>> +	disp = crtc_to_vdrm_display(crtc);
>> +	disp->vblank_enabled = true;
>> +
>> +	return 0;
>> +}
>> +
>> +static void vdrm_crtc_disable_vblank(struct drm_crtc *crtc)
>> +{
>> +	struct vdrm_display *disp;
>> +
>> +	disp = crtc_to_vdrm_display(crtc);
>> +	disp->vblank_enabled = false;
>> +}
>> +
>> +static const struct drm_crtc_funcs vdrm_crtc_funcs = {
>> +	.reset = drm_atomic_helper_crtc_reset,
>> +	.destroy = drm_crtc_cleanup,
>> +	.set_config = drm_atomic_helper_set_config,
>> +	.page_flip = drm_atomic_helper_page_flip,
>> +	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
>> +	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
>> +	.enable_vblank = vdrm_crtc_enable_vblank,
>> +	.disable_vblank = vdrm_crtc_disable_vblank,
>> +};
>> +static const struct drm_encoder_funcs vdrm_encoder_funcs = {
>> +	.destroy = drm_encoder_cleanup,
>> +};
>> +
>> +static int vdrm_properties_init(struct vdrm_device *vdrm, int num_props,
>> +				struct vdrm_property_info *props)
>> +{
>> +	int i;
>> +	unsigned int w = vdrm->ddev.mode_config.max_width;
>> +	unsigned int h = vdrm->ddev.mode_config.max_height;
>> +
>> +	vdrm->plane_props.offset_x =
>> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_offset_x", 0, w);
>> +	if (!vdrm->plane_props.offset_x)
>> +		return -1;
>> +	vdrm->plane_props.offset_y =
>> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_offset_y", 0, h);
>> +	if (!vdrm->plane_props.offset_y)
>> +		return -1;
>> +	vdrm->plane_props.width =
>> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_width", 1, w);
>> +	if (!vdrm->plane_props.width)
>> +		return -1;
>> +	vdrm->plane_props.height =
>> +		drm_property_create_range(&vdrm->ddev, 0, "vdrm_height", 1, h);
>> +	if (!vdrm->plane_props.height)
>> +		return -1;
>> +
>> +	if (num_props == 0)
>> +		return 0;
>> +
>> +	vdrm->props = devm_kzalloc(vdrm->parent->dev,
>> +				    sizeof(*vdrm->props) * num_props,
>> +				    GFP_KERNEL);
>> +	if (!vdrm->props)
>> +		return -ENOMEM;
>> +
>> +	for (i = 0; i < num_props; i++) {
>> +		struct drm_property *p = props[i].prop;
>> +
>> +		vdrm->props[i].prop =
>> +			drm_property_create_range(&vdrm->ddev, p->flags,
>> +						  p->name, p->values[0],
>> +						  p->values[1]);
>> +		if (!vdrm->props[i].prop)
>> +			goto err;
>> +
>> +		vdrm->props[i].parent_prop = p;
>> +		vdrm->props[i].default_val = props[i].default_val;
>> +	}
>> +	vdrm->num_props = num_props;
>> +
>> +	return 0;
>> +
>> +err:
>> +	for (i--; i >= 0; i--)
>> +		drm_property_destroy(&vdrm->ddev, vdrm->props[i].prop);
>> +	devm_kfree(vdrm->parent->dev, vdrm->props);
>> +	return -1;
>> +}
>> +
>> +static int vdrm_of_get_plane(struct device_node *np,
>> +			     int *x, int *y, int *width, int *height, int *z)
>> +{
>> +	struct device_node *child;
>> +	int ret;
>> +
>> +	child = of_get_next_child(np, NULL);
>> +	if (!child)
>> +		return -ENODEV;
>> +
>> +	ret = of_property_read_u32(child, "x", x);
>> +	ret |= of_property_read_u32(child, "y", y);
>> +	ret |= of_property_read_u32(child, "width", width);
>> +	ret |= of_property_read_u32(child, "height", height);
>> +	ret |= of_property_read_u32(child, "zpos", z);
>> +
>> +	of_node_put(child);
>> +	return ret;
>> +}
>> +
>> +static void vdrm_dump(struct vdrm_device *vdrm)
>> +{
>> +	struct vdrm_display *disp;
>> +
>> +	DRM_INFO("Virtual DRM Info:\n");
>> +	list_for_each_entry(disp, &vdrm->disps, head) {
>> +		DRM_INFO("\tCONNECTOR: %d\n",
>> +			 disp->connector.base.id);
>> +		DRM_INFO("\tCRTC: %d\n",
>> +			 disp->crtc.base.id);
>> +		DRM_INFO("\tENCODER: %d\n",
>> +			 disp->encoder.base.id);
>> +		DRM_INFO("\tPLANE: %d\n",
>> +			 disp->plane->base.id);
>> +		DRM_INFO("\tParent CRTC: %d\n",
>> +			 disp->parent_crtc->base.id);
>> +	}
>> +}
>> +
>> +/**
>> + * vdrm_drv_handle_vblank - handle a vblank event for vDRM
>> + * @vdisplay: vDRM display object
>> + */
>> +void vdrm_drv_handle_vblank(struct vdrm_display *vdisplay)
>> +{
>> +	if (vdisplay->vblank_enabled)
>> +		drm_crtc_handle_vblank(&vdisplay->crtc);
>> +}
>> +
>> +/**
>> + * vdrm_drv_finish_page_flip - handle a page flip event for vDRM
>> + * @vdisplay: vDRM display object
>> + */
>> +void vdrm_drv_finish_page_flip(struct vdrm_display *vdisplay)
>> +{
>> +	vdrm_drv_finish_page_flip_internal(vdisplay);
>> +}
>> +
>> +DEFINE_DRM_GEM_CMA_FOPS(vdrm_fops);
>> +
>> +static struct drm_driver vdrm_driver = {
>> +	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
>> +	.dumb_create = vdrm_dumb_create,
>> +	.fops = &vdrm_fops,
>> +	.name = "virt-drm",
>> +	.desc = "Virtual DRM driver",
>> +	.date = "20201104",
>> +	.major = 1,
>> +	.minor = 0,
>> +};
>> +
>> +/**
>> + * vdrm_drv_init - Initialize vDRM device
>> + * @dev: parent DRM device
>> + * @np: vDRM device node in DTB
>> + * @num_props: number of parent property objects
>> + * @props: parent plane properties used in vDRM
>> + * @funcs: callbacks for vDRM
>> + *
>> + * Allocates a new vDRM device, initializes mode_config of the vDRM device
>> + * and allocates property objects. Not initialize plane, crtc, encoder and
>> + * connector. Initialization of plane must be done in vdrm_drv_plane_init()
>> + * and initialization of crtc, encoder and connector must be done by
>> + * vdrm_drv_display_init(). Also, after initializing the plane, crtc,
>> + * connector, and encoder, register vDRM device must be done by
>> + * vdrm_drv_register().
>> + *
>> + * Returns:
>> + * vDRM object (&vdrm_device) on success, error code encoded into the pointer
>> + * on failure.
>> + */
>> +struct vdrm_device *vdrm_drv_init(struct drm_device *dev,
>> +				  struct device_node *np, int num_props,
>> +				  struct vdrm_property_info *props,
>> +				  const struct vdrm_funcs *funcs)
>> +{
>> +	struct vdrm_device *vdrm;
>> +	struct vdrm_plane_info plane_info;
>> +	int ret;
>> +
>> +	if (!of_device_is_compatible(np, "virt-drm"))
>> +		return ERR_PTR(-ENODEV);
>> +
>> +	/* get plane information from device tree */
>> +	ret = vdrm_of_get_plane(np, &plane_info.x, &plane_info.y,
>> +				&plane_info.width, &plane_info.height,
>> +				&plane_info.z);
>> +	if (ret < 0) {
>> +		DRM_WARN("VDRM: failed get plane node of %s\n",
>> +			 of_node_full_name(np));
>> +		return ERR_PTR(ret);
>> +	}
>> +
>> +	vdrm_driver.prime_handle_to_fd = dev->driver->prime_handle_to_fd;
>> +	vdrm_driver.prime_fd_to_handle = dev->driver->prime_fd_to_handle;
>> +	vdrm_driver.gem_prime_import_sg_table =
>> +		dev->driver->gem_prime_import_sg_table;
>> +	vdrm_driver.gem_prime_mmap = dev->driver->gem_prime_mmap;
>> +
>> +	vdrm = devm_drm_dev_alloc(dev->dev, &vdrm_driver, struct vdrm_device,
>> +				  ddev);
>> +	if (IS_ERR(vdrm))
>> +		return vdrm;
>> +
>> +	vdrm->parent = dev;
>> +	vdrm->funcs = funcs;
>> +	vdrm->of_plane_info = plane_info;
>> +
>> +	INIT_LIST_HEAD(&vdrm->disps);
>> +
>> +	ret = drmm_mode_config_init(&vdrm->ddev);
>> +	if (ret)
>> +		goto failed;
>> +
>> +	vdrm->ddev.mode_config.min_width = 0;
>> +	vdrm->ddev.mode_config.min_height = 0;
>> +	vdrm->ddev.mode_config.max_width = 8190;
>> +	vdrm->ddev.mode_config.max_height = 8190;
>> +	vdrm->ddev.mode_config.normalize_zpos = true;
>> +	vdrm->ddev.mode_config.funcs = &vdrm_mode_config_funcs;
>> +
>> +	ret = vdrm_properties_init(vdrm, num_props, props);
>> +	if (ret < 0)
>> +		goto failed;
>> +
>> +	drm_dev_set_unique(&vdrm->ddev, of_node_full_name(np));
>> +	return vdrm;
>> +
>> +failed:
>> +	kfree(vdrm);
>> +	return ERR_PTR(ret);
>> +}
>> +
>> +/**
>> + * vdrm_drv_plane_init - Initialize the plane used by vDRM
>> + * @vdrm: vDRM object
>> + * @plane: plane to assign to vDRM
>> + * @funcs: callbacks for the plane
>> + * @helper_funcs: helper vtable to set for plane
>> + * @formats: color formats
>> + * @num_formats: number of color formats
>> + * @max_zpos: max value for zpos property of plane
>> + *
>> + * Initializes a plane object of PRIMARY type by drm_universal_plane_init()
>> + * and initializes @plane's properties. The property passed by vdrm_drv_init()
>> + * is set to @plane.
>> + *
>> + * Returns:
>> + * Zero on success, error code on failure.
>> + */
>> +int vdrm_drv_plane_init(struct vdrm_device *vdrm, struct drm_plane *plane,
>> +			const struct drm_plane_funcs *funcs,
>> +			const struct drm_plane_helper_funcs *helper_funcs,
>> +			const u32 *formats, unsigned int num_formats,
>> +			int max_zpos)
>> +{
>> +	struct vdrm_display *disp;
>> +	int i, ret;
>> +
>> +	disp = kzalloc(sizeof(*disp), GFP_KERNEL);
>> +	if (!disp)
>> +		return -ENOMEM;
>> +
>> +	disp->dev = vdrm;
>> +	disp->plane = plane;
>> +	disp->plane_info = vdrm->of_plane_info;
>> +
>> +	disp->parent_plane_funcs = funcs;
>> +	disp->parent_plane_helper_funcs = helper_funcs;
>> +	disp->plane_funcs = *funcs;
>> +	disp->plane_helper_funcs = *helper_funcs;
>> +
>> +	disp->plane_funcs.reset = vdrm_plane_reset;
>> +	disp->plane_funcs.atomic_set_property = vdrm_plane_set_property;
>> +	disp->plane_funcs.atomic_get_property = vdrm_plane_get_property;
>> +	disp->plane_helper_funcs.atomic_update = vdrm_plane_update;
>> +
>> +	drm_plane_helper_add(disp->plane, &disp->plane_helper_funcs);
>> +	ret = drm_universal_plane_init(&vdrm->ddev, plane, 0,
>> +				       &disp->plane_funcs, formats,
>> +				       num_formats, NULL,
>> +				       DRM_PLANE_TYPE_PRIMARY, NULL);
>> +	if (ret) {
>> +		kfree(disp);
>> +		return ret;
>> +	}
>> +
>> +	drm_plane_create_alpha_property(plane);
>> +	drm_plane_create_zpos_property(plane, disp->plane_info.z, 0, max_zpos);
>> +	drm_object_attach_property(&plane->base,
>> +				   vdrm->plane_props.offset_x,
>> +				   disp->plane_info.x);
>> +	drm_object_attach_property(&plane->base,
>> +				   vdrm->plane_props.offset_y,
>> +				   disp->plane_info.y);
>> +	drm_object_attach_property(&plane->base,
>> +				   vdrm->plane_props.width,
>> +				   disp->plane_info.width);
>> +	drm_object_attach_property(&plane->base,
>> +				   vdrm->plane_props.height,
>> +				   disp->plane_info.height);
>> +	for (i = 0; i < vdrm->num_props; i++) {
>> +		drm_object_attach_property(&plane->base,
>> +					   vdrm->props[i].prop,
>> +					   vdrm->props[i].default_val);
>> +	}
>> +
>> +	INIT_LIST_HEAD(&disp->head);
>> +	list_add_tail(&disp->head, &vdrm->disps);
>> +	vdrm->num_crtcs++;
>> +	return 0;
>> +}
>> +
>> +/**
>> + * vdrm_drv_display_init - Initialize the vDRM display object
>> + * @vdrm: vDRM object
>> + * @crtc: parent crtc to be linked with the vDRM crtc
>> + * @plane: plane assigned to vDRM
>> + *
>> + * Initializes crtc, connector and encorder, and links @crtc to crtc of vDRM.
>> + *
>> + * Returns:
>> + * vDRM display object on success, error code encoded into the pointer on
>> + * failure.
>> + */
>> +struct vdrm_display *vdrm_drv_display_init(struct vdrm_device *vdrm,
>> +					   struct drm_crtc *crtc,
>> +					   struct drm_plane *plane)
>> +{
>> +	struct vdrm_display *disp;
>> +	int ret;
>> +
>> +	disp = vdrm_plane_find_display(vdrm, plane);
>> +	if (!disp)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	drm_crtc_helper_add(&disp->crtc, &vdrm_crtc_helper_funcs);
>> +	ret = drm_crtc_init_with_planes(&vdrm->ddev, &disp->crtc, plane, NULL,
>> +					&vdrm_crtc_funcs, NULL);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	drm_connector_helper_add(&disp->connector, &vdrm_conn_helper_funcs);
>> +	ret = drm_connector_init(&vdrm->ddev, &disp->connector,
>> +				 &vdrm_conn_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	disp->encoder.possible_crtcs = drm_crtc_mask(&disp->crtc);
>> +	ret = drm_encoder_init(&vdrm->ddev, &disp->encoder, &vdrm_encoder_funcs,
>> +			       DRM_MODE_ENCODER_NONE, NULL);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	ret = drm_connector_attach_encoder(&disp->connector, &disp->encoder);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	init_waitqueue_head(&disp->flip_wait);
>> +	disp->parent_crtc = crtc;
>> +
>> +	return disp;
>> +}
>> +
>> +/**
>> + * vdrm_drv_register - Register vDRM device
>> + * @vdrm: vDRM object
>> + *
>> + * Returns:
>> + * Zero on success, error code on failure.
>> + */
>> +int vdrm_drv_register(struct vdrm_device *vdrm)
>> +{
>> +	int ret;
>> +	struct drm_device *dev = &vdrm->ddev;
>> +
>> +	ret = drm_vblank_init(dev, vdrm->num_crtcs);
>> +	if (ret)
>> +		return ret;
>> +
>> +	drm_mode_config_reset(dev);
>> +
>> +	ret = drm_dev_register(dev, 0);
>> +	if (ret)
>> +		return ret;
>> +
>> +	dev->irq_enabled = true;
>> +
>> +	DRM_INFO("Virtual Device is initialized.\n");
>> +
>> +	vdrm_dump(vdrm);
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * vdrm_drv_fini - release vDRM resources
>> + * @vdrm: vDRM object
>> + */
>> +void vdrm_drv_fini(struct vdrm_device *vdrm)
>> +{
>> +	struct vdrm_display *disp;
>> +
>> +	if (vdrm->ddev.registered)
>> +		drm_dev_unregister(&vdrm->ddev);
>> +	drm_mode_config_cleanup(&vdrm->ddev);
>> +
>> +	list_for_each_entry(disp, &vdrm->disps, head)
>> +		kfree(disp);
>> +}
>> diff --git a/drivers/gpu/drm/vdrm/vdrm_drv.h b/drivers/gpu/drm/vdrm/vdrm_drv.h
>> new file mode 100644
>> index 000000000000..67b8e02efddf
>> --- /dev/null
>> +++ b/drivers/gpu/drm/vdrm/vdrm_drv.h
>> @@ -0,0 +1,80 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * vdrm_drv.h -- Virtual DRM driver
>> + *
>> + * Copyright (C) 2021 Renesas Electronics Corporation
>> + */
>> +
>> +#ifndef __VDRM_DRV_H__
>> +#define __VDRM_DRV_H__
>> +
>> +#include <drm/drm_device.h>
>> +
>> +#include "vdrm_api.h"
>> +
>> +struct vdrm_property {
>> +	struct drm_property *prop;
>> +	struct drm_property *parent_prop;
>> +	uint64_t default_val;
>> +};
>> +
>> +struct vdrm_plane_info {
>> +	int x;
>> +	int y;
>> +	unsigned int width;
>> +	unsigned int height;
>> +	unsigned int z;
>> +};
>> +
>> +struct vdrm_device;
>> +
>> +struct vdrm_display {
>> +	struct drm_connector connector;
>> +	struct drm_crtc crtc;
>> +	struct drm_crtc *parent_crtc;
>> +	struct drm_plane *plane;
>> +	struct drm_encoder encoder;
>> +	struct drm_pending_vblank_event *event;
>> +	struct vdrm_device *dev;
>> +	bool vblank_enabled;
>> +	wait_queue_head_t flip_wait;
>> +	bool crtc_enabled;
>> +	int vblank_count;
>> +
>> +	struct list_head head;
>> +
>> +	struct vdrm_plane_info plane_info;
>> +
>> +	const struct drm_plane_funcs *parent_plane_funcs;
>> +	const struct drm_plane_helper_funcs *parent_plane_helper_funcs;
>> +	struct drm_plane_funcs plane_funcs;
>> +	struct drm_plane_helper_funcs plane_helper_funcs;
>> +};
>> +
>> +struct vdrm_device {
>> +	struct drm_device ddev;
>> +	struct drm_device *parent;
>> +
>> +	int num_crtcs;
>> +	struct list_head disps;
>> +
>> +	const struct vdrm_funcs *funcs;
>> +	struct vdrm_property *props;
>> +	int num_props;
>> +
>> +	struct {
>> +		struct drm_property *offset_x;
>> +		struct drm_property *offset_y;
>> +		struct drm_property *width;
>> +		struct drm_property *height;
>> +	} plane_props;
>> +
>> +	struct vdrm_plane_info of_plane_info;
>> +};
>> +
>> +static inline struct vdrm_device *to_vdrm_device(struct drm_device *dev)
>> +{
>> +	return container_of(dev, struct vdrm_device, ddev);
>> +}
>> +
>> +#endif /* __VDRM_DRV_H__ */
>> -- 
>> 2.25.1

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 3/4] dt-bindings: display: Add virtual DRM
  2021-06-21 17:40     ` Rob Herring
@ 2021-06-22  4:17       ` Esaki Tomohito
  -1 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-22  4:17 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-kernel, Maarten Lankhorst, Daniel Vetter,
	Thomas Zimmermann, David Airlie, Laurent Pinchart,
	Kieran Bingham, dri-devel, linux-renesas-soc, linux-doc,
	devicetree, Maxime Ripard, Damian Hobson-Garcia, Takanari Hayama

Hi, Rob

Thank you for the error report and advice.
I will recheck DT binding.

Best regards
Tomohito Esaki

On 2021/06/22 2:40, Rob Herring wrote:
> On Mon, 21 Jun 2021 15:44:02 +0900, Tomohito Esaki wrote:
>> Add device tree bindings documentation for virtual DRM.
>>
>> Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
>> ---
>>  .../devicetree/bindings/display/vdrm.yaml     | 67 +++++++++++++++++++
>>  1 file changed, 67 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml
>>
> 
> My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
> on your patch (DT_CHECKER_FLAGS is new in v5.13):
> 
> yamllint warnings/errors:
> ./Documentation/devicetree/bindings/display/vdrm.yaml:39:1: [error] syntax error: found character '\t' that cannot start any token (syntax)
> 
> dtschema/dtc warnings/errors:
> make[1]: *** Deleting file 'Documentation/devicetree/bindings/display/vdrm.example.dts'
> Traceback (most recent call last):
>   File "/usr/local/bin/dt-extract-example", line 45, in <module>
>     binding = yaml.load(open(args.yamlfile, encoding='utf-8').read())
>   File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/main.py", line 434, in load
>     return constructor.get_single_data()
>   File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/constructor.py", line 120, in get_single_data
>     node = self.composer.get_single_node()
>   File "_ruamel_yaml.pyx", line 706, in _ruamel_yaml.CParser.get_single_node
>   File "_ruamel_yaml.pyx", line 724, in _ruamel_yaml.CParser._compose_document
>   File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
>   File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
>   File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
>   File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
>   File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
>   File "_ruamel_yaml.pyx", line 731, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 904, in _ruamel_yaml.CParser._parse_next_event
> ruamel.yaml.scanner.ScannerError: while scanning a plain scalar
>   in "<unicode string>", line 38, column 15
> found a tab character that violates indentation
>   in "<unicode string>", line 39, column 1
> make[1]: *** [Documentation/devicetree/bindings/Makefile:20: Documentation/devicetree/bindings/display/vdrm.example.dts] Error 1
> make[1]: *** Waiting for unfinished jobs....
> ./Documentation/devicetree/bindings/display/vdrm.yaml:  while scanning a plain scalar
>   in "<unicode string>", line 38, column 15
> found a tab character that violates indentation
>   in "<unicode string>", line 39, column 1
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/display/vdrm.yaml: ignoring, error parsing file
> warning: no schema found in file: ./Documentation/devicetree/bindings/display/vdrm.yaml
> make: *** [Makefile:1416: dt_binding_check] Error 2
> \ndoc reference errors (make refcheckdocs):
> 
> See https://patchwork.ozlabs.org/patch/1494913
> 
> This check can fail if there are any dependencies. The base for a patch
> series is generally the most recent rc1.
> 
> If you already ran 'make dt_binding_check' and didn't see the above
> error(s), then make sure 'yamllint' is installed and dt-schema is up to
> date:
> 
> pip3 install dtschema --upgrade
> 
> Please check and re-submit.
> 

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 3/4] dt-bindings: display: Add virtual DRM
@ 2021-06-22  4:17       ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-22  4:17 UTC (permalink / raw)
  To: Rob Herring
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie,
	linux-kernel, dri-devel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Thomas Zimmermann, Damian Hobson-Garcia

Hi, Rob

Thank you for the error report and advice.
I will recheck DT binding.

Best regards
Tomohito Esaki

On 2021/06/22 2:40, Rob Herring wrote:
> On Mon, 21 Jun 2021 15:44:02 +0900, Tomohito Esaki wrote:
>> Add device tree bindings documentation for virtual DRM.
>>
>> Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
>> ---
>>  .../devicetree/bindings/display/vdrm.yaml     | 67 +++++++++++++++++++
>>  1 file changed, 67 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml
>>
> 
> My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
> on your patch (DT_CHECKER_FLAGS is new in v5.13):
> 
> yamllint warnings/errors:
> ./Documentation/devicetree/bindings/display/vdrm.yaml:39:1: [error] syntax error: found character '\t' that cannot start any token (syntax)
> 
> dtschema/dtc warnings/errors:
> make[1]: *** Deleting file 'Documentation/devicetree/bindings/display/vdrm.example.dts'
> Traceback (most recent call last):
>   File "/usr/local/bin/dt-extract-example", line 45, in <module>
>     binding = yaml.load(open(args.yamlfile, encoding='utf-8').read())
>   File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/main.py", line 434, in load
>     return constructor.get_single_data()
>   File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/constructor.py", line 120, in get_single_data
>     node = self.composer.get_single_node()
>   File "_ruamel_yaml.pyx", line 706, in _ruamel_yaml.CParser.get_single_node
>   File "_ruamel_yaml.pyx", line 724, in _ruamel_yaml.CParser._compose_document
>   File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
>   File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
>   File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
>   File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
>   File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node
>   File "_ruamel_yaml.pyx", line 731, in _ruamel_yaml.CParser._compose_node
>   File "_ruamel_yaml.pyx", line 904, in _ruamel_yaml.CParser._parse_next_event
> ruamel.yaml.scanner.ScannerError: while scanning a plain scalar
>   in "<unicode string>", line 38, column 15
> found a tab character that violates indentation
>   in "<unicode string>", line 39, column 1
> make[1]: *** [Documentation/devicetree/bindings/Makefile:20: Documentation/devicetree/bindings/display/vdrm.example.dts] Error 1
> make[1]: *** Waiting for unfinished jobs....
> ./Documentation/devicetree/bindings/display/vdrm.yaml:  while scanning a plain scalar
>   in "<unicode string>", line 38, column 15
> found a tab character that violates indentation
>   in "<unicode string>", line 39, column 1
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/display/vdrm.yaml: ignoring, error parsing file
> warning: no schema found in file: ./Documentation/devicetree/bindings/display/vdrm.yaml
> make: *** [Makefile:1416: dt_binding_check] Error 2
> \ndoc reference errors (make refcheckdocs):
> 
> See https://patchwork.ozlabs.org/patch/1494913
> 
> This check can fail if there are any dependencies. The base for a patch
> series is generally the most recent rc1.
> 
> If you already ran 'make dt_binding_check' and didn't see the above
> error(s), then make sure 'yamllint' is installed and dt-schema is up to
> date:
> 
> pip3 install dtschema --upgrade
> 
> Please check and re-submit.
> 

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-21  6:43 ` Tomohito Esaki
@ 2021-06-22  8:04   ` Simon Ser
  -1 siblings, 0 replies; 61+ messages in thread
From: Simon Ser @ 2021-06-22  8:04 UTC (permalink / raw)
  To: Tomohito Esaki
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham,
	devicetree, linux-doc, linux-kernel, dri-devel,
	linux-renesas-soc

On Monday, June 21st, 2021 at 08:43, Tomohito Esaki <etom@igel.co.jp> wrote:

> Virtual DRM splits the overlay planes of a display controller into multiple
> virtual devices to allow each plane to be accessed by each process.
> This makes it possible to overlay images output from multiple processes on a
> display. For example, one process displays the camera image without compositor
> while another process overlays the UI.

Updating the KMS state from multiple processes doesn't sound like a
good idea. This opens up synchronization and global device limits
issues.

Are you aware of DRM leasing?

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-22  8:04   ` Simon Ser
  0 siblings, 0 replies; 61+ messages in thread
From: Simon Ser @ 2021-06-22  8:04 UTC (permalink / raw)
  To: Tomohito Esaki
  Cc: devicetree, Thomas Zimmermann, linux-doc, David Airlie,
	dri-devel, linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart

On Monday, June 21st, 2021 at 08:43, Tomohito Esaki <etom@igel.co.jp> wrote:

> Virtual DRM splits the overlay planes of a display controller into multiple
> virtual devices to allow each plane to be accessed by each process.
> This makes it possible to overlay images output from multiple processes on a
> display. For example, one process displays the camera image without compositor
> while another process overlays the UI.

Updating the KMS state from multiple processes doesn't sound like a
good idea. This opens up synchronization and global device limits
issues.

Are you aware of DRM leasing?

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 3/4] dt-bindings: display: Add virtual DRM
  2021-06-21  6:44   ` Tomohito Esaki
@ 2021-06-22 16:54     ` Rob Herring
  -1 siblings, 0 replies; 61+ messages in thread
From: Rob Herring @ 2021-06-22 16:54 UTC (permalink / raw)
  To: Tomohito Esaki
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham,
	dri-devel, linux-renesas-soc, linux-kernel, devicetree,
	linux-doc

On Mon, Jun 21, 2021 at 03:44:02PM +0900, Tomohito Esaki wrote:
> Add device tree bindings documentation for virtual DRM.

DRM is a Linuxism. What's virtual DRM? Why does it need to be in DT? 
What's the usecase? You're going to need a lot more reasoning to justify 
this for DT.

> 
> Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
> ---
>  .../devicetree/bindings/display/vdrm.yaml     | 67 +++++++++++++++++++
>  1 file changed, 67 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/vdrm.yaml b/Documentation/devicetree/bindings/display/vdrm.yaml
> new file mode 100644
> index 000000000000..6493bb0fc09f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/vdrm.yaml
> @@ -0,0 +1,67 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/vdrm.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Virtual DRM Device Tree Bindings
> +
> +description:
> +  This document defines device tree properties virtual DRM. The initial
> +  position, size and z-position of the plane used in the virtual DRM is
> +  specified.
> +  The current limitation is that these settings are applied to all crtc.
> +
> +properties:
> +  compatible:
> +    const: virt-drm
> +
> +patternProperties:
> +  "^plane(@.*)?$":
> +    description: Information of the planes used in virtual DRM
> +    type: object
> +
> +    properties:
> +      x:
> +        type: int
> +        description: x-coordinate of the left-top of the plane in pixels
> +
> +      y:
> +        type: int
> +        description: y-coordinate of the left-top of the plane in pixels
> +
> +      width:
> +        type: int
> +        description: width of the plane in pixels
> +
> +      height:
> +        type: int
> +	description: height of the plane in pixels
> +
> +      zpos:
> +        type: int
> +        description: z-position of the plane
> +
> +    required:
> +      - x
> +      - y
> +      - width
> +      - height
> +      - zpos
> +
> +required:
> +  - compatible
> +  - "^plane(@.*)?$"
> +
> +examples:
> + - |
> +   vdrm@0 {
> +       compatible = "virt-drm";
> +       plane@0 {
> +           x = <200>;
> +	   y = <100>;
> +	   width = <800>;
> +	   height = <600>;
> +	   zpos = <1>;
> +       };
> +   };
> -- 
> 2.25.1
> 
> 

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 3/4] dt-bindings: display: Add virtual DRM
@ 2021-06-22 16:54     ` Rob Herring
  0 siblings, 0 replies; 61+ messages in thread
From: Rob Herring @ 2021-06-22 16:54 UTC (permalink / raw)
  To: Tomohito Esaki
  Cc: devicetree, Thomas Zimmermann, linux-doc, David Airlie,
	dri-devel, linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart

On Mon, Jun 21, 2021 at 03:44:02PM +0900, Tomohito Esaki wrote:
> Add device tree bindings documentation for virtual DRM.

DRM is a Linuxism. What's virtual DRM? Why does it need to be in DT? 
What's the usecase? You're going to need a lot more reasoning to justify 
this for DT.

> 
> Signed-off-by: Tomohito Esaki <etom@igel.co.jp>
> ---
>  .../devicetree/bindings/display/vdrm.yaml     | 67 +++++++++++++++++++
>  1 file changed, 67 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/vdrm.yaml b/Documentation/devicetree/bindings/display/vdrm.yaml
> new file mode 100644
> index 000000000000..6493bb0fc09f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/vdrm.yaml
> @@ -0,0 +1,67 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/vdrm.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Virtual DRM Device Tree Bindings
> +
> +description:
> +  This document defines device tree properties virtual DRM. The initial
> +  position, size and z-position of the plane used in the virtual DRM is
> +  specified.
> +  The current limitation is that these settings are applied to all crtc.
> +
> +properties:
> +  compatible:
> +    const: virt-drm
> +
> +patternProperties:
> +  "^plane(@.*)?$":
> +    description: Information of the planes used in virtual DRM
> +    type: object
> +
> +    properties:
> +      x:
> +        type: int
> +        description: x-coordinate of the left-top of the plane in pixels
> +
> +      y:
> +        type: int
> +        description: y-coordinate of the left-top of the plane in pixels
> +
> +      width:
> +        type: int
> +        description: width of the plane in pixels
> +
> +      height:
> +        type: int
> +	description: height of the plane in pixels
> +
> +      zpos:
> +        type: int
> +        description: z-position of the plane
> +
> +    required:
> +      - x
> +      - y
> +      - width
> +      - height
> +      - zpos
> +
> +required:
> +  - compatible
> +  - "^plane(@.*)?$"
> +
> +examples:
> + - |
> +   vdrm@0 {
> +       compatible = "virt-drm";
> +       plane@0 {
> +           x = <200>;
> +	   y = <100>;
> +	   width = <800>;
> +	   height = <600>;
> +	   zpos = <1>;
> +       };
> +   };
> -- 
> 2.25.1
> 
> 

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-23 11:41               ` Pekka Paalanen
@ 2021-06-25  1:55                 ` Esaki Tomohito
  -1 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-25  1:55 UTC (permalink / raw)
  To: Pekka Paalanen
  Cc: Enrico Weigelt, metux IT consult, devicetree, Takanari Hayama,
	Thomas Zimmermann, linux-doc, David Airlie, dri-devel,
	linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Damian Hobson-Garcia



On 2021/06/23 20:41, Pekka Paalanen wrote:
> On Wed, 23 Jun 2021 18:22:47 +0900
> Esaki Tomohito <etom@igel.co.jp> wrote:
> 
>> On 2021/06/23 17:39, Pekka Paalanen wrote:
>>> On Wed, 23 Jun 2021 15:56:05 +0900
>>> Esaki Tomohito <etom@igel.co.jp> wrote:
>>>   
>>>> Hi,
>>>> Thank you all for your comments.
>>>>
>>>> On 2021/06/22 17:12, Pekka Paalanen wrote:  
>>>>> On Tue, 22 Jun 2021 13:03:39 +0900
>>>>> Esaki Tomohito <etom@igel.co.jp> wrote:
>>>>>     
>>>>>> Hi, Enrico Weigelt
>>>>>> Thank you for reply.
>>>>>>
>>>>>> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:    
>>>>>>> On 21.06.21 08:27, Tomohito Esaki wrote:
>>>>>>>
>>>>>>> Hi,
>>>>>>>       
>>>>>>>> Virtual DRM splits the overlay planes of a display controller into multiple
>>>>>>>> virtual devices to allow each plane to be accessed by each process.
>>>>>>>>
>>>>>>>> This makes it possible to overlay images output from multiple processes on a
>>>>>>>> display. For example, one process displays the camera image without compositor
>>>>>>>> while another process overlays the UI.      
>>>>>>>
>>>>>>> Are you attempting to create an simple in-kernel compositor ?      
>>>>>>
>>>>>> I think the basic idea is the same as DRMlease.    
>>>>>
>>>>> Hi,
>>>>>
>>>>> indeed. Why not use DRM leases instead?
>>>>>     
>>>>
>>>> In this use case, I understand that this is not possible with DRM lease,
>>>> am I wrong?
>>>> I understand that it’s not possible to lease a plane and update planes
>>>> on the same output independently from different processes in current DRM
>>>> lease.
>>>>
>>>> If this is correct, what do you think of adding support for plane leases
>>>> to the DRM lease to handle this case?  
>>>
>>> Hi,
>>>
>>> I would love to see support added for leasing individual planes,
>>> especially to replace the virtual DRM proposal which seems to be
>>> eradicating everything that atomic modesetting and nuclear pageflip
>>> have built over the many years.
>>>
>>> However, please note that "on the same output independently" is
>>> physically impossible. Semantically, the planes define what a CRTC
>>> scans out, and the CRTC defines the scanout timings. Therefore it is not
>>> possible to update individual planes independently, they will all
>>> always share the timings of the CRTC.
>>>
>>> That combined with KMS not allowing multiple updates to be queued at
>>> the same time for the same CRTC (atomic commits and legacy pageflips
>>> returning EBUSY) makes the plane updates very much inter-dependent.
>>>
>>> If you want to avoid EBUSY and have planes update on the vblank you
>>> intended, you really need a userspace compositor to pull everything
>>> together *before* submitting anything to the kernel.  
>>
>> Hi,
>>
>> Thank you for your comments and advice.
>> I will consider leasing a plane.
> 
> Hi,
> 
> I wish you considered a userspace compositor first, once more, with
> passion.
> 
> It does not need to be Weston, and it does not need to use Wayland.
> Just a userspace daemon that owns the whole display device and somehow
> talks to whatever else wants stuff on screen.
> 
> I have not seen any evidence that leasing individual planes would do
> you any good. I can easily see it doing you harm. I'm only saying that
> it would be better than the virtual DRM proposal if you absolutely have
> to go there. Please, consider not going there at all.
> 
> "On the same output independently" is not possible for the very simple
> reason that the pixel data needs to be streamed serially to a monitor.
> 

Hi,

Thank you for your advice.
Once again, I'll consider a userspace compositor first.

Best regards
Esaki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-25  1:55                 ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-25  1:55 UTC (permalink / raw)
  To: Pekka Paalanen
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie,
	linux-kernel, dri-devel, linux-renesas-soc, Kieran Bingham,
	Enrico Weigelt, metux IT consult, Laurent Pinchart,
	Thomas Zimmermann, Damian Hobson-Garcia



On 2021/06/23 20:41, Pekka Paalanen wrote:
> On Wed, 23 Jun 2021 18:22:47 +0900
> Esaki Tomohito <etom@igel.co.jp> wrote:
> 
>> On 2021/06/23 17:39, Pekka Paalanen wrote:
>>> On Wed, 23 Jun 2021 15:56:05 +0900
>>> Esaki Tomohito <etom@igel.co.jp> wrote:
>>>   
>>>> Hi,
>>>> Thank you all for your comments.
>>>>
>>>> On 2021/06/22 17:12, Pekka Paalanen wrote:  
>>>>> On Tue, 22 Jun 2021 13:03:39 +0900
>>>>> Esaki Tomohito <etom@igel.co.jp> wrote:
>>>>>     
>>>>>> Hi, Enrico Weigelt
>>>>>> Thank you for reply.
>>>>>>
>>>>>> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:    
>>>>>>> On 21.06.21 08:27, Tomohito Esaki wrote:
>>>>>>>
>>>>>>> Hi,
>>>>>>>       
>>>>>>>> Virtual DRM splits the overlay planes of a display controller into multiple
>>>>>>>> virtual devices to allow each plane to be accessed by each process.
>>>>>>>>
>>>>>>>> This makes it possible to overlay images output from multiple processes on a
>>>>>>>> display. For example, one process displays the camera image without compositor
>>>>>>>> while another process overlays the UI.      
>>>>>>>
>>>>>>> Are you attempting to create an simple in-kernel compositor ?      
>>>>>>
>>>>>> I think the basic idea is the same as DRMlease.    
>>>>>
>>>>> Hi,
>>>>>
>>>>> indeed. Why not use DRM leases instead?
>>>>>     
>>>>
>>>> In this use case, I understand that this is not possible with DRM lease,
>>>> am I wrong?
>>>> I understand that it’s not possible to lease a plane and update planes
>>>> on the same output independently from different processes in current DRM
>>>> lease.
>>>>
>>>> If this is correct, what do you think of adding support for plane leases
>>>> to the DRM lease to handle this case?  
>>>
>>> Hi,
>>>
>>> I would love to see support added for leasing individual planes,
>>> especially to replace the virtual DRM proposal which seems to be
>>> eradicating everything that atomic modesetting and nuclear pageflip
>>> have built over the many years.
>>>
>>> However, please note that "on the same output independently" is
>>> physically impossible. Semantically, the planes define what a CRTC
>>> scans out, and the CRTC defines the scanout timings. Therefore it is not
>>> possible to update individual planes independently, they will all
>>> always share the timings of the CRTC.
>>>
>>> That combined with KMS not allowing multiple updates to be queued at
>>> the same time for the same CRTC (atomic commits and legacy pageflips
>>> returning EBUSY) makes the plane updates very much inter-dependent.
>>>
>>> If you want to avoid EBUSY and have planes update on the vblank you
>>> intended, you really need a userspace compositor to pull everything
>>> together *before* submitting anything to the kernel.  
>>
>> Hi,
>>
>> Thank you for your comments and advice.
>> I will consider leasing a plane.
> 
> Hi,
> 
> I wish you considered a userspace compositor first, once more, with
> passion.
> 
> It does not need to be Weston, and it does not need to use Wayland.
> Just a userspace daemon that owns the whole display device and somehow
> talks to whatever else wants stuff on screen.
> 
> I have not seen any evidence that leasing individual planes would do
> you any good. I can easily see it doing you harm. I'm only saying that
> it would be better than the virtual DRM proposal if you absolutely have
> to go there. Please, consider not going there at all.
> 
> "On the same output independently" is not possible for the very simple
> reason that the pixel data needs to be streamed serially to a monitor.
> 

Hi,

Thank you for your advice.
Once again, I'll consider a userspace compositor first.

Best regards
Esaki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-22  4:36       ` Esaki Tomohito
@ 2021-06-23 14:39         ` Maxime Ripard
  -1 siblings, 0 replies; 61+ messages in thread
From: Maxime Ripard @ 2021-06-23 14:39 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: Thomas Zimmermann, Maarten Lankhorst, David Airlie,
	Daniel Vetter, Laurent Pinchart, Kieran Bingham, dri-devel,
	linux-renesas-soc, linux-kernel, devicetree, linux-doc,
	Damian Hobson-Garcia, Takanari Hayama

[-- Attachment #1: Type: text/plain, Size: 2405 bytes --]

On Tue, Jun 22, 2021 at 01:36:48PM +0900, Esaki Tomohito wrote:
> Hi, Maxime
> Thank you for reply.
> 
> On 2021/06/21 18:24, Maxime Ripard wrote:
> > Hi,
> > 
> > On Mon, Jun 21, 2021 at 09:10:19AM +0200, Thomas Zimmermann wrote:
> >> Am 21.06.21 um 08:27 schrieb Tomohito Esaki:
> >>> Virtual DRM splits the overlay planes of a display controller into multiple
> >>> virtual devices to allow each plane to be accessed by each process.
> >>>
> >>> This makes it possible to overlay images output from multiple processes on a
> >>> display. For example, one process displays the camera image without compositor
> >>> while another process overlays the UI.
> >>
> >> I briefly looked over your patches. I didn't understand how this is
> >> different to the functionality of a compositor? Shouldn't this be solved in
> >> userspace?
> > 
> > I think there could be a bunch of use-cases for something that could
> > "steal" a plane without the compositor knowing.
> > 
> > Something I'd really like to work at some point for example is that the
> > downstream RaspberryPi display driver has a visual clue when it's
> > running too hot or is in over-current.
> > 
> > I don't think this is the right solution though. The DT binding makes it
> > far too static, and if there's a compositor I'd assume it would want to
> > know about it somehow (at least if it's from the userspace) ?
> > 
> 
> I will reconsider the DT bindings.
> 
> We want to separate the resources from the master in units of planes,
> so we proposed virtual DRM.
> By separating the plane from the master and making it appear as
> a virtual DRM devicein userland, the plane can be accessed from
> userland using the general DRM API.
> What do you think about this idea?

I guess you'd need to detail a bit more what your use case is exactly,
and what issue you're trying to address.

Generally speaking, I'm not really sure how you can separate a KMS
driver from its planes.

Like, assuming that you have that super important application putting
the rear-end camera on the display: I'd assume you want the connector
and bridges to remain enabled? How are you going to synchronize with the
compositor if it wants to disable it, or change resolution?

Similarly, some features exposed on the connector, like bpc, might
affect the input format you want to have for your planes?

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-23 14:39         ` Maxime Ripard
  0 siblings, 0 replies; 61+ messages in thread
From: Maxime Ripard @ 2021-06-23 14:39 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: devicetree, Takanari Hayama, Thomas Zimmermann, linux-doc,
	David Airlie, linux-kernel, dri-devel, linux-renesas-soc,
	Kieran Bingham, Laurent Pinchart, Damian Hobson-Garcia

[-- Attachment #1: Type: text/plain, Size: 2405 bytes --]

On Tue, Jun 22, 2021 at 01:36:48PM +0900, Esaki Tomohito wrote:
> Hi, Maxime
> Thank you for reply.
> 
> On 2021/06/21 18:24, Maxime Ripard wrote:
> > Hi,
> > 
> > On Mon, Jun 21, 2021 at 09:10:19AM +0200, Thomas Zimmermann wrote:
> >> Am 21.06.21 um 08:27 schrieb Tomohito Esaki:
> >>> Virtual DRM splits the overlay planes of a display controller into multiple
> >>> virtual devices to allow each plane to be accessed by each process.
> >>>
> >>> This makes it possible to overlay images output from multiple processes on a
> >>> display. For example, one process displays the camera image without compositor
> >>> while another process overlays the UI.
> >>
> >> I briefly looked over your patches. I didn't understand how this is
> >> different to the functionality of a compositor? Shouldn't this be solved in
> >> userspace?
> > 
> > I think there could be a bunch of use-cases for something that could
> > "steal" a plane without the compositor knowing.
> > 
> > Something I'd really like to work at some point for example is that the
> > downstream RaspberryPi display driver has a visual clue when it's
> > running too hot or is in over-current.
> > 
> > I don't think this is the right solution though. The DT binding makes it
> > far too static, and if there's a compositor I'd assume it would want to
> > know about it somehow (at least if it's from the userspace) ?
> > 
> 
> I will reconsider the DT bindings.
> 
> We want to separate the resources from the master in units of planes,
> so we proposed virtual DRM.
> By separating the plane from the master and making it appear as
> a virtual DRM devicein userland, the plane can be accessed from
> userland using the general DRM API.
> What do you think about this idea?

I guess you'd need to detail a bit more what your use case is exactly,
and what issue you're trying to address.

Generally speaking, I'm not really sure how you can separate a KMS
driver from its planes.

Like, assuming that you have that super important application putting
the rear-end camera on the display: I'd assume you want the connector
and bridges to remain enabled? How are you going to synchronize with the
compositor if it wants to disable it, or change resolution?

Similarly, some features exposed on the connector, like bpc, might
affect the input format you want to have for your planes?

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-23  9:22             ` Esaki Tomohito
@ 2021-06-23 11:41               ` Pekka Paalanen
  -1 siblings, 0 replies; 61+ messages in thread
From: Pekka Paalanen @ 2021-06-23 11:41 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: Enrico Weigelt, metux IT consult, devicetree, Takanari Hayama,
	Thomas Zimmermann, linux-doc, David Airlie, dri-devel,
	linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Damian Hobson-Garcia

[-- Attachment #1: Type: text/plain, Size: 3553 bytes --]

On Wed, 23 Jun 2021 18:22:47 +0900
Esaki Tomohito <etom@igel.co.jp> wrote:

> On 2021/06/23 17:39, Pekka Paalanen wrote:
> > On Wed, 23 Jun 2021 15:56:05 +0900
> > Esaki Tomohito <etom@igel.co.jp> wrote:
> >   
> >> Hi,
> >> Thank you all for your comments.
> >>
> >> On 2021/06/22 17:12, Pekka Paalanen wrote:  
> >>> On Tue, 22 Jun 2021 13:03:39 +0900
> >>> Esaki Tomohito <etom@igel.co.jp> wrote:
> >>>     
> >>>> Hi, Enrico Weigelt
> >>>> Thank you for reply.
> >>>>
> >>>> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:    
> >>>>> On 21.06.21 08:27, Tomohito Esaki wrote:
> >>>>>
> >>>>> Hi,
> >>>>>       
> >>>>>> Virtual DRM splits the overlay planes of a display controller into multiple
> >>>>>> virtual devices to allow each plane to be accessed by each process.
> >>>>>>
> >>>>>> This makes it possible to overlay images output from multiple processes on a
> >>>>>> display. For example, one process displays the camera image without compositor
> >>>>>> while another process overlays the UI.      
> >>>>>
> >>>>> Are you attempting to create an simple in-kernel compositor ?      
> >>>>
> >>>> I think the basic idea is the same as DRMlease.    
> >>>
> >>> Hi,
> >>>
> >>> indeed. Why not use DRM leases instead?
> >>>     
> >>
> >> In this use case, I understand that this is not possible with DRM lease,
> >> am I wrong?
> >> I understand that it’s not possible to lease a plane and update planes
> >> on the same output independently from different processes in current DRM
> >> lease.
> >>
> >> If this is correct, what do you think of adding support for plane leases
> >> to the DRM lease to handle this case?  
> > 
> > Hi,
> > 
> > I would love to see support added for leasing individual planes,
> > especially to replace the virtual DRM proposal which seems to be
> > eradicating everything that atomic modesetting and nuclear pageflip
> > have built over the many years.
> > 
> > However, please note that "on the same output independently" is
> > physically impossible. Semantically, the planes define what a CRTC
> > scans out, and the CRTC defines the scanout timings. Therefore it is not
> > possible to update individual planes independently, they will all
> > always share the timings of the CRTC.
> > 
> > That combined with KMS not allowing multiple updates to be queued at
> > the same time for the same CRTC (atomic commits and legacy pageflips
> > returning EBUSY) makes the plane updates very much inter-dependent.
> > 
> > If you want to avoid EBUSY and have planes update on the vblank you
> > intended, you really need a userspace compositor to pull everything
> > together *before* submitting anything to the kernel.  
> 
> Hi,
> 
> Thank you for your comments and advice.
> I will consider leasing a plane.

Hi,

I wish you considered a userspace compositor first, once more, with
passion.

It does not need to be Weston, and it does not need to use Wayland.
Just a userspace daemon that owns the whole display device and somehow
talks to whatever else wants stuff on screen.

I have not seen any evidence that leasing individual planes would do
you any good. I can easily see it doing you harm. I'm only saying that
it would be better than the virtual DRM proposal if you absolutely have
to go there. Please, consider not going there at all.

"On the same output independently" is not possible for the very simple
reason that the pixel data needs to be streamed serially to a monitor.


Thanks,
pq

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-23 11:41               ` Pekka Paalanen
  0 siblings, 0 replies; 61+ messages in thread
From: Pekka Paalanen @ 2021-06-23 11:41 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie,
	linux-kernel, dri-devel, linux-renesas-soc, Kieran Bingham,
	Enrico Weigelt, metux IT consult, Laurent Pinchart,
	Thomas Zimmermann, Damian Hobson-Garcia

[-- Attachment #1: Type: text/plain, Size: 3553 bytes --]

On Wed, 23 Jun 2021 18:22:47 +0900
Esaki Tomohito <etom@igel.co.jp> wrote:

> On 2021/06/23 17:39, Pekka Paalanen wrote:
> > On Wed, 23 Jun 2021 15:56:05 +0900
> > Esaki Tomohito <etom@igel.co.jp> wrote:
> >   
> >> Hi,
> >> Thank you all for your comments.
> >>
> >> On 2021/06/22 17:12, Pekka Paalanen wrote:  
> >>> On Tue, 22 Jun 2021 13:03:39 +0900
> >>> Esaki Tomohito <etom@igel.co.jp> wrote:
> >>>     
> >>>> Hi, Enrico Weigelt
> >>>> Thank you for reply.
> >>>>
> >>>> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:    
> >>>>> On 21.06.21 08:27, Tomohito Esaki wrote:
> >>>>>
> >>>>> Hi,
> >>>>>       
> >>>>>> Virtual DRM splits the overlay planes of a display controller into multiple
> >>>>>> virtual devices to allow each plane to be accessed by each process.
> >>>>>>
> >>>>>> This makes it possible to overlay images output from multiple processes on a
> >>>>>> display. For example, one process displays the camera image without compositor
> >>>>>> while another process overlays the UI.      
> >>>>>
> >>>>> Are you attempting to create an simple in-kernel compositor ?      
> >>>>
> >>>> I think the basic idea is the same as DRMlease.    
> >>>
> >>> Hi,
> >>>
> >>> indeed. Why not use DRM leases instead?
> >>>     
> >>
> >> In this use case, I understand that this is not possible with DRM lease,
> >> am I wrong?
> >> I understand that it’s not possible to lease a plane and update planes
> >> on the same output independently from different processes in current DRM
> >> lease.
> >>
> >> If this is correct, what do you think of adding support for plane leases
> >> to the DRM lease to handle this case?  
> > 
> > Hi,
> > 
> > I would love to see support added for leasing individual planes,
> > especially to replace the virtual DRM proposal which seems to be
> > eradicating everything that atomic modesetting and nuclear pageflip
> > have built over the many years.
> > 
> > However, please note that "on the same output independently" is
> > physically impossible. Semantically, the planes define what a CRTC
> > scans out, and the CRTC defines the scanout timings. Therefore it is not
> > possible to update individual planes independently, they will all
> > always share the timings of the CRTC.
> > 
> > That combined with KMS not allowing multiple updates to be queued at
> > the same time for the same CRTC (atomic commits and legacy pageflips
> > returning EBUSY) makes the plane updates very much inter-dependent.
> > 
> > If you want to avoid EBUSY and have planes update on the vblank you
> > intended, you really need a userspace compositor to pull everything
> > together *before* submitting anything to the kernel.  
> 
> Hi,
> 
> Thank you for your comments and advice.
> I will consider leasing a plane.

Hi,

I wish you considered a userspace compositor first, once more, with
passion.

It does not need to be Weston, and it does not need to use Wayland.
Just a userspace daemon that owns the whole display device and somehow
talks to whatever else wants stuff on screen.

I have not seen any evidence that leasing individual planes would do
you any good. I can easily see it doing you harm. I'm only saying that
it would be better than the virtual DRM proposal if you absolutely have
to go there. Please, consider not going there at all.

"On the same output independently" is not possible for the very simple
reason that the pixel data needs to be streamed serially to a monitor.


Thanks,
pq

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-23  8:39           ` Pekka Paalanen
@ 2021-06-23  9:22             ` Esaki Tomohito
  -1 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-23  9:22 UTC (permalink / raw)
  To: Pekka Paalanen
  Cc: Enrico Weigelt, metux IT consult, devicetree, Takanari Hayama,
	Thomas Zimmermann, linux-doc, David Airlie, dri-devel,
	linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Damian Hobson-Garcia

On 2021/06/23 17:39, Pekka Paalanen wrote:
> On Wed, 23 Jun 2021 15:56:05 +0900
> Esaki Tomohito <etom@igel.co.jp> wrote:
> 
>> Hi,
>> Thank you all for your comments.
>>
>> On 2021/06/22 17:12, Pekka Paalanen wrote:
>>> On Tue, 22 Jun 2021 13:03:39 +0900
>>> Esaki Tomohito <etom@igel.co.jp> wrote:
>>>   
>>>> Hi, Enrico Weigelt
>>>> Thank you for reply.
>>>>
>>>> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:  
>>>>> On 21.06.21 08:27, Tomohito Esaki wrote:
>>>>>
>>>>> Hi,
>>>>>     
>>>>>> Virtual DRM splits the overlay planes of a display controller into multiple
>>>>>> virtual devices to allow each plane to be accessed by each process.
>>>>>>
>>>>>> This makes it possible to overlay images output from multiple processes on a
>>>>>> display. For example, one process displays the camera image without compositor
>>>>>> while another process overlays the UI.    
>>>>>
>>>>> Are you attempting to create an simple in-kernel compositor ?    
>>>>
>>>> I think the basic idea is the same as DRMlease.  
>>>
>>> Hi,
>>>
>>> indeed. Why not use DRM leases instead?
>>>   
>>
>> In this use case, I understand that this is not possible with DRM lease,
>> am I wrong?
>> I understand that it’s not possible to lease a plane and update planes
>> on the same output independently from different processes in current DRM
>> lease.
>>
>> If this is correct, what do you think of adding support for plane leases
>> to the DRM lease to handle this case?
> 
> Hi,
> 
> I would love to see support added for leasing individual planes,
> especially to replace the virtual DRM proposal which seems to be
> eradicating everything that atomic modesetting and nuclear pageflip
> have built over the many years.
> 
> However, please note that "on the same output independently" is
> physically impossible. Semantically, the planes define what a CRTC
> scans out, and the CRTC defines the scanout timings. Therefore it is not
> possible to update individual planes independently, they will all
> always share the timings of the CRTC.
> 
> That combined with KMS not allowing multiple updates to be queued at
> the same time for the same CRTC (atomic commits and legacy pageflips
> returning EBUSY) makes the plane updates very much inter-dependent.
> 
> If you want to avoid EBUSY and have planes update on the vblank you
> intended, you really need a userspace compositor to pull everything
> together *before* submitting anything to the kernel.

Hi,

Thank you for your comments and advice.
I will consider leasing a plane.

Thanks,
Esaki



^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-23  9:22             ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-23  9:22 UTC (permalink / raw)
  To: Pekka Paalanen
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie,
	linux-kernel, dri-devel, linux-renesas-soc, Kieran Bingham,
	Enrico Weigelt, metux IT consult, Laurent Pinchart,
	Thomas Zimmermann, Damian Hobson-Garcia

On 2021/06/23 17:39, Pekka Paalanen wrote:
> On Wed, 23 Jun 2021 15:56:05 +0900
> Esaki Tomohito <etom@igel.co.jp> wrote:
> 
>> Hi,
>> Thank you all for your comments.
>>
>> On 2021/06/22 17:12, Pekka Paalanen wrote:
>>> On Tue, 22 Jun 2021 13:03:39 +0900
>>> Esaki Tomohito <etom@igel.co.jp> wrote:
>>>   
>>>> Hi, Enrico Weigelt
>>>> Thank you for reply.
>>>>
>>>> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:  
>>>>> On 21.06.21 08:27, Tomohito Esaki wrote:
>>>>>
>>>>> Hi,
>>>>>     
>>>>>> Virtual DRM splits the overlay planes of a display controller into multiple
>>>>>> virtual devices to allow each plane to be accessed by each process.
>>>>>>
>>>>>> This makes it possible to overlay images output from multiple processes on a
>>>>>> display. For example, one process displays the camera image without compositor
>>>>>> while another process overlays the UI.    
>>>>>
>>>>> Are you attempting to create an simple in-kernel compositor ?    
>>>>
>>>> I think the basic idea is the same as DRMlease.  
>>>
>>> Hi,
>>>
>>> indeed. Why not use DRM leases instead?
>>>   
>>
>> In this use case, I understand that this is not possible with DRM lease,
>> am I wrong?
>> I understand that it’s not possible to lease a plane and update planes
>> on the same output independently from different processes in current DRM
>> lease.
>>
>> If this is correct, what do you think of adding support for plane leases
>> to the DRM lease to handle this case?
> 
> Hi,
> 
> I would love to see support added for leasing individual planes,
> especially to replace the virtual DRM proposal which seems to be
> eradicating everything that atomic modesetting and nuclear pageflip
> have built over the many years.
> 
> However, please note that "on the same output independently" is
> physically impossible. Semantically, the planes define what a CRTC
> scans out, and the CRTC defines the scanout timings. Therefore it is not
> possible to update individual planes independently, they will all
> always share the timings of the CRTC.
> 
> That combined with KMS not allowing multiple updates to be queued at
> the same time for the same CRTC (atomic commits and legacy pageflips
> returning EBUSY) makes the plane updates very much inter-dependent.
> 
> If you want to avoid EBUSY and have planes update on the vblank you
> intended, you really need a userspace compositor to pull everything
> together *before* submitting anything to the kernel.

Hi,

Thank you for your comments and advice.
I will consider leasing a plane.

Thanks,
Esaki



^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-23  6:56         ` Esaki Tomohito
@ 2021-06-23  8:39           ` Pekka Paalanen
  -1 siblings, 0 replies; 61+ messages in thread
From: Pekka Paalanen @ 2021-06-23  8:39 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: Enrico Weigelt, metux IT consult, devicetree, Takanari Hayama,
	Thomas Zimmermann, linux-doc, David Airlie, dri-devel,
	linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Damian Hobson-Garcia

[-- Attachment #1: Type: text/plain, Size: 2434 bytes --]

On Wed, 23 Jun 2021 15:56:05 +0900
Esaki Tomohito <etom@igel.co.jp> wrote:

> Hi,
> Thank you all for your comments.
> 
> On 2021/06/22 17:12, Pekka Paalanen wrote:
> > On Tue, 22 Jun 2021 13:03:39 +0900
> > Esaki Tomohito <etom@igel.co.jp> wrote:
> >   
> >> Hi, Enrico Weigelt
> >> Thank you for reply.
> >>
> >> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:  
> >>> On 21.06.21 08:27, Tomohito Esaki wrote:
> >>>
> >>> Hi,
> >>>     
> >>>> Virtual DRM splits the overlay planes of a display controller into multiple
> >>>> virtual devices to allow each plane to be accessed by each process.
> >>>>
> >>>> This makes it possible to overlay images output from multiple processes on a
> >>>> display. For example, one process displays the camera image without compositor
> >>>> while another process overlays the UI.    
> >>>
> >>> Are you attempting to create an simple in-kernel compositor ?    
> >>
> >> I think the basic idea is the same as DRMlease.  
> > 
> > Hi,
> > 
> > indeed. Why not use DRM leases instead?
> >   
> 
> In this use case, I understand that this is not possible with DRM lease,
> am I wrong?
> I understand that it’s not possible to lease a plane and update planes
> on the same output independently from different processes in current DRM
> lease.
> 
> If this is correct, what do you think of adding support for plane leases
> to the DRM lease to handle this case?

Hi,

I would love to see support added for leasing individual planes,
especially to replace the virtual DRM proposal which seems to be
eradicating everything that atomic modesetting and nuclear pageflip
have built over the many years.

However, please note that "on the same output independently" is
physically impossible. Semantically, the planes define what a CRTC
scans out, and the CRTC defines the scanout timings. Therefore it is not
possible to update individual planes independently, they will all
always share the timings of the CRTC.

That combined with KMS not allowing multiple updates to be queued at
the same time for the same CRTC (atomic commits and legacy pageflips
returning EBUSY) makes the plane updates very much inter-dependent.

If you want to avoid EBUSY and have planes update on the vblank you
intended, you really need a userspace compositor to pull everything
together *before* submitting anything to the kernel.


Thanks,
pq

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-23  8:39           ` Pekka Paalanen
  0 siblings, 0 replies; 61+ messages in thread
From: Pekka Paalanen @ 2021-06-23  8:39 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie,
	linux-kernel, dri-devel, linux-renesas-soc, Kieran Bingham,
	Enrico Weigelt, metux IT consult, Laurent Pinchart,
	Thomas Zimmermann, Damian Hobson-Garcia

[-- Attachment #1: Type: text/plain, Size: 2434 bytes --]

On Wed, 23 Jun 2021 15:56:05 +0900
Esaki Tomohito <etom@igel.co.jp> wrote:

> Hi,
> Thank you all for your comments.
> 
> On 2021/06/22 17:12, Pekka Paalanen wrote:
> > On Tue, 22 Jun 2021 13:03:39 +0900
> > Esaki Tomohito <etom@igel.co.jp> wrote:
> >   
> >> Hi, Enrico Weigelt
> >> Thank you for reply.
> >>
> >> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:  
> >>> On 21.06.21 08:27, Tomohito Esaki wrote:
> >>>
> >>> Hi,
> >>>     
> >>>> Virtual DRM splits the overlay planes of a display controller into multiple
> >>>> virtual devices to allow each plane to be accessed by each process.
> >>>>
> >>>> This makes it possible to overlay images output from multiple processes on a
> >>>> display. For example, one process displays the camera image without compositor
> >>>> while another process overlays the UI.    
> >>>
> >>> Are you attempting to create an simple in-kernel compositor ?    
> >>
> >> I think the basic idea is the same as DRMlease.  
> > 
> > Hi,
> > 
> > indeed. Why not use DRM leases instead?
> >   
> 
> In this use case, I understand that this is not possible with DRM lease,
> am I wrong?
> I understand that it’s not possible to lease a plane and update planes
> on the same output independently from different processes in current DRM
> lease.
> 
> If this is correct, what do you think of adding support for plane leases
> to the DRM lease to handle this case?

Hi,

I would love to see support added for leasing individual planes,
especially to replace the virtual DRM proposal which seems to be
eradicating everything that atomic modesetting and nuclear pageflip
have built over the many years.

However, please note that "on the same output independently" is
physically impossible. Semantically, the planes define what a CRTC
scans out, and the CRTC defines the scanout timings. Therefore it is not
possible to update individual planes independently, they will all
always share the timings of the CRTC.

That combined with KMS not allowing multiple updates to be queued at
the same time for the same CRTC (atomic commits and legacy pageflips
returning EBUSY) makes the plane updates very much inter-dependent.

If you want to avoid EBUSY and have planes update on the vblank you
intended, you really need a userspace compositor to pull everything
together *before* submitting anything to the kernel.


Thanks,
pq

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-23  8:04       ` Michel Dänzer
@ 2021-06-23  8:21         ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-23  8:21 UTC (permalink / raw)
  To: Michel Dänzer, Pekka Paalanen
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie,
	linux-kernel, dri-devel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Thomas Zimmermann, Damian Hobson-Garcia


On 2021/06/23 17:04, Michel Dänzer wrote:
> On 2021-06-22 9:57 a.m., Pekka Paalanen wrote:
>> On Tue, 22 Jun 2021 13:02:59 +0900
>> Esaki Tomohito <etom@igel.co.jp> wrote:
>>
>>> Hi, Thomas
>>> Thank you for reply.
>>>
>>> On 2021/06/21 16:10, Thomas Zimmermann wrote:
>>>> Hi
>>>>
>>>> Am 21.06.21 um 08:27 schrieb Tomohito Esaki:  
>>>>> Virtual DRM splits the overlay planes of a display controller into
>>>>> multiple
>>>>> virtual devices to allow each plane to be accessed by each process.
>>>>>
>>>>> This makes it possible to overlay images output from multiple
>>>>> processes on a
>>>>> display. For example, one process displays the camera image without
>>>>> compositor
>>>>> while another process overlays the UI.  
>>>>
>>>> I briefly looked over your patches. I didn't understand how this is
>>>> different to the functionality of a compositor? Shouldn't this be solved
>>>> in userspace?  
>>>
>>> I think when latency is important (e.g., AR, VR, for displaying camera
>>> images in IVI systems), there may be use cases where the compositor
>>> cannot be used.
>>
>> Hi,
>>
>>> Normally, when the image is passed through the compositor, it is
>>> displayed after 2 VSYNC at most, because the compositor combines the
>>> image with VSYNC synchronization.
>>
>> This is not a universal fact. You can write a Wayland compositor that
>> consistently reaches app-to-screen latency of less than one monitor
>> refresh cycle, while also using KMS planes.
>>
>> I believe Weston succeeds in this already if you write the Wayland
>> application accordingly.
> 
> For a specific example, https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1620 allows app-to-screen latency as low as ~6 ms (including a fixed 2 ms buffer to avoid skipped frames). mutter doesn't use KMS planes yet, but if anything I'd expect that to help rather than hurt for latency (if the compositor doesn't need to draw anything).

Thank you for providing specific examples.

Best regards
Esaki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-22  7:57       ` Pekka Paalanen
  (?)
@ 2021-06-23  8:04       ` Michel Dänzer
  2021-06-23  8:21         ` Esaki Tomohito
  -1 siblings, 1 reply; 61+ messages in thread
From: Michel Dänzer @ 2021-06-23  8:04 UTC (permalink / raw)
  To: Pekka Paalanen, Esaki Tomohito
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie,
	linux-kernel, dri-devel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Thomas Zimmermann, Damian Hobson-Garcia

On 2021-06-22 9:57 a.m., Pekka Paalanen wrote:
> On Tue, 22 Jun 2021 13:02:59 +0900
> Esaki Tomohito <etom@igel.co.jp> wrote:
> 
>> Hi, Thomas
>> Thank you for reply.
>>
>> On 2021/06/21 16:10, Thomas Zimmermann wrote:
>>> Hi
>>>
>>> Am 21.06.21 um 08:27 schrieb Tomohito Esaki:  
>>>> Virtual DRM splits the overlay planes of a display controller into
>>>> multiple
>>>> virtual devices to allow each plane to be accessed by each process.
>>>>
>>>> This makes it possible to overlay images output from multiple
>>>> processes on a
>>>> display. For example, one process displays the camera image without
>>>> compositor
>>>> while another process overlays the UI.  
>>>
>>> I briefly looked over your patches. I didn't understand how this is
>>> different to the functionality of a compositor? Shouldn't this be solved
>>> in userspace?  
>>
>> I think when latency is important (e.g., AR, VR, for displaying camera
>> images in IVI systems), there may be use cases where the compositor
>> cannot be used.
> 
> Hi,
> 
>> Normally, when the image is passed through the compositor, it is
>> displayed after 2 VSYNC at most, because the compositor combines the
>> image with VSYNC synchronization.
> 
> This is not a universal fact. You can write a Wayland compositor that
> consistently reaches app-to-screen latency of less than one monitor
> refresh cycle, while also using KMS planes.
> 
> I believe Weston succeeds in this already if you write the Wayland
> application accordingly.

For a specific example, https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1620 allows app-to-screen latency as low as ~6 ms (including a fixed 2 ms buffer to avoid skipped frames). mutter doesn't use KMS planes yet, but if anything I'd expect that to help rather than hurt for latency (if the compositor doesn't need to draw anything).


-- 
Earthling Michel Dänzer               |               https://redhat.com
Libre software enthusiast             |             Mesa and X developer

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-22  8:12       ` Pekka Paalanen
@ 2021-06-23  6:56         ` Esaki Tomohito
  -1 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-23  6:56 UTC (permalink / raw)
  To: Pekka Paalanen
  Cc: Enrico Weigelt, metux IT consult, devicetree, Takanari Hayama,
	Thomas Zimmermann, linux-doc, David Airlie, dri-devel,
	linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Damian Hobson-Garcia

Hi,
Thank you all for your comments.

On 2021/06/22 17:12, Pekka Paalanen wrote:
> On Tue, 22 Jun 2021 13:03:39 +0900
> Esaki Tomohito <etom@igel.co.jp> wrote:
> 
>> Hi, Enrico Weigelt
>> Thank you for reply.
>>
>> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:
>>> On 21.06.21 08:27, Tomohito Esaki wrote:
>>>
>>> Hi,
>>>   
>>>> Virtual DRM splits the overlay planes of a display controller into multiple
>>>> virtual devices to allow each plane to be accessed by each process.
>>>>
>>>> This makes it possible to overlay images output from multiple processes on a
>>>> display. For example, one process displays the camera image without compositor
>>>> while another process overlays the UI.  
>>>
>>> Are you attempting to create an simple in-kernel compositor ?  
>>
>> I think the basic idea is the same as DRMlease.
> 
> Hi,
> 
> indeed. Why not use DRM leases instead?
> 

In this use case, I understand that this is not possible with DRM lease,
am I wrong?
I understand that it’s not possible to lease a plane and update planes
on the same output independently from different processes in current DRM
lease.

If this is correct, what do you think of adding support for plane leases
to the DRM lease to handle this case?

Thanks,
Tomohito Esaki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-23  6:56         ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-23  6:56 UTC (permalink / raw)
  To: Pekka Paalanen
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie,
	linux-kernel, dri-devel, linux-renesas-soc, Kieran Bingham,
	Enrico Weigelt, metux IT consult, Laurent Pinchart,
	Thomas Zimmermann, Damian Hobson-Garcia

Hi,
Thank you all for your comments.

On 2021/06/22 17:12, Pekka Paalanen wrote:
> On Tue, 22 Jun 2021 13:03:39 +0900
> Esaki Tomohito <etom@igel.co.jp> wrote:
> 
>> Hi, Enrico Weigelt
>> Thank you for reply.
>>
>> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:
>>> On 21.06.21 08:27, Tomohito Esaki wrote:
>>>
>>> Hi,
>>>   
>>>> Virtual DRM splits the overlay planes of a display controller into multiple
>>>> virtual devices to allow each plane to be accessed by each process.
>>>>
>>>> This makes it possible to overlay images output from multiple processes on a
>>>> display. For example, one process displays the camera image without compositor
>>>> while another process overlays the UI.  
>>>
>>> Are you attempting to create an simple in-kernel compositor ?  
>>
>> I think the basic idea is the same as DRMlease.
> 
> Hi,
> 
> indeed. Why not use DRM leases instead?
> 

In this use case, I understand that this is not possible with DRM lease,
am I wrong?
I understand that it’s not possible to lease a plane and update planes
on the same output independently from different processes in current DRM
lease.

If this is correct, what do you think of adding support for plane leases
to the DRM lease to handle this case?

Thanks,
Tomohito Esaki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-22  8:12       ` Pekka Paalanen
@ 2021-06-22 19:12         ` Daniel Vetter
  -1 siblings, 0 replies; 61+ messages in thread
From: Daniel Vetter @ 2021-06-22 19:12 UTC (permalink / raw)
  To: Pekka Paalanen
  Cc: Esaki Tomohito, devicetree, Takanari Hayama,
	Linux Doc Mailing List, David Airlie, Linux Kernel Mailing List,
	dri-devel, open list:DRM DRIVERS FOR RENESAS, Kieran Bingham,
	Enrico Weigelt, metux IT consult, Laurent Pinchart,
	Thomas Zimmermann, Damian Hobson-Garcia

On Tue, Jun 22, 2021 at 10:12 AM Pekka Paalanen <ppaalanen@gmail.com> wrote:
>
> On Tue, 22 Jun 2021 13:03:39 +0900
> Esaki Tomohito <etom@igel.co.jp> wrote:
>
> > Hi, Enrico Weigelt
> > Thank you for reply.
> >
> > On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:
> > > On 21.06.21 08:27, Tomohito Esaki wrote:
> > >
> > > Hi,
> > >
> > >> Virtual DRM splits the overlay planes of a display controller into multiple
> > >> virtual devices to allow each plane to be accessed by each process.
> > >>
> > >> This makes it possible to overlay images output from multiple processes on a
> > >> display. For example, one process displays the camera image without compositor
> > >> while another process overlays the UI.
> > >
> > > Are you attempting to create an simple in-kernel compositor ?
> >
> > I think the basic idea is the same as DRMlease.
>
> Hi,
>
> indeed. Why not use DRM leases instead?
>
> > We want to separate the resources from the master in units of planes,
> > so we proposed virtual DRM.
> > I think the advantage of vDRM is that you can use general DRM APIs
> > in userland.
>
> You do that with DRM leases too.
>
> > > I don't think that's not the way to go, at least not by touching each
> > > single display driver, and not hardcoding the planes in DT.
> >
> > Thank you for comment. I will reconsider about DT.
> >
> > > What's the actual use case you're doing that for ? Why not using some
> > > userland compositor ?
> >
> > I think when latency is important (e.g., AR, VR, for displaying camera
> > images in IVI systems), there may be use cases where the compositor
> > cannot be used.
> > Normally, when the image is passed through the compositor, it is
> > displayed after 2 VSYNC at most, because the compositor combines the
> > image with VSYNC synchronization. On the other hand, if we use vDRM, the
> > image will be displayed at the next VSYNC, so it will be displayed after
> > 1 VSYNC at most.
>
> As I said in my other email, this is false in the general sense.
>
> > Also, since the compositor is a single point of failure, we may not want
> > to make it dependent on it.
>
> This... I'm not quite sure I buy it. If any of all the programs using
> virtual KMS crashes, you still lose some crucial components from your
> display. Maybe that program, while crashing, uploads such a bad state
> to its very own KMS plane, that it causes other KMS planes to
> malfunction. Then you need to detect this situation and still restart
> everything, not just the crashed program.

This, a hundred times. At least in general it's impossible to
guarantee resource isolation between different parts of a kms device -
everything is shared at least in some driver in funny ways.

The only thing we try to guarantee is that if you keep flipping the
same plane with same pixel format, stride, offset, absolutely
everything except the memory block unchanged, then that's guaranteed
to work. Everything else is off the table.

This is why the drm-lease design ended up with revoke support, because
if something goes wrong a superior instance (the compositor, the
kernel can't decide that for userspace) needs to decide whom to shoot
and revoke their access.

> I would think a userspace compositor approach is actually more
> reliable. You write the compositor to be extremely robust. Exactly
> because the compositor is in control of the complete display device and
> not just little pieces of it, it can see what is happening and it can
> mitigate problems. If you have more unreliable components needing
> access to display, make those clients to the compositor, so they can
> crash and malfunction on their own without potentially killing the
> whole display device. If you are as concerned about latency as XR
> people are, then use DRM leases.
>
> Also, what if your virtual KMS driver has a bug? Restarting the kernel
> is much harder that restarting a userspace compositor that hands out
> DRM leases.
>
> The userspace compositor could even be such that it does nothing more
> than handing out DRM leases. However, DRM leases have the problem that
> there is no single entity responsible for keeping the display device
> working, but that responsibility is split between several processes and
> none of them sees the whole picture.

Yeah I think a compositor for this use-case, written in Rust and
heavily audited/proofed is probably a lot more reliable than cobbling
ill-defined kernel driver code on top of barely-defined hw semantics
in resource-sharing cases.

> Btw. VKMS is an existing DRM driver, so your name choice is conflicting.

Yeah that too :-)
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-22 19:12         ` Daniel Vetter
  0 siblings, 0 replies; 61+ messages in thread
From: Daniel Vetter @ 2021-06-22 19:12 UTC (permalink / raw)
  To: Pekka Paalanen
  Cc: devicetree, Takanari Hayama, Linux Doc Mailing List,
	David Airlie, Linux Kernel Mailing List, dri-devel,
	open list:DRM DRIVERS FOR RENESAS, Kieran Bingham,
	Enrico Weigelt, metux IT consult, Laurent Pinchart,
	Thomas Zimmermann, Damian Hobson-Garcia, Esaki Tomohito

On Tue, Jun 22, 2021 at 10:12 AM Pekka Paalanen <ppaalanen@gmail.com> wrote:
>
> On Tue, 22 Jun 2021 13:03:39 +0900
> Esaki Tomohito <etom@igel.co.jp> wrote:
>
> > Hi, Enrico Weigelt
> > Thank you for reply.
> >
> > On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:
> > > On 21.06.21 08:27, Tomohito Esaki wrote:
> > >
> > > Hi,
> > >
> > >> Virtual DRM splits the overlay planes of a display controller into multiple
> > >> virtual devices to allow each plane to be accessed by each process.
> > >>
> > >> This makes it possible to overlay images output from multiple processes on a
> > >> display. For example, one process displays the camera image without compositor
> > >> while another process overlays the UI.
> > >
> > > Are you attempting to create an simple in-kernel compositor ?
> >
> > I think the basic idea is the same as DRMlease.
>
> Hi,
>
> indeed. Why not use DRM leases instead?
>
> > We want to separate the resources from the master in units of planes,
> > so we proposed virtual DRM.
> > I think the advantage of vDRM is that you can use general DRM APIs
> > in userland.
>
> You do that with DRM leases too.
>
> > > I don't think that's not the way to go, at least not by touching each
> > > single display driver, and not hardcoding the planes in DT.
> >
> > Thank you for comment. I will reconsider about DT.
> >
> > > What's the actual use case you're doing that for ? Why not using some
> > > userland compositor ?
> >
> > I think when latency is important (e.g., AR, VR, for displaying camera
> > images in IVI systems), there may be use cases where the compositor
> > cannot be used.
> > Normally, when the image is passed through the compositor, it is
> > displayed after 2 VSYNC at most, because the compositor combines the
> > image with VSYNC synchronization. On the other hand, if we use vDRM, the
> > image will be displayed at the next VSYNC, so it will be displayed after
> > 1 VSYNC at most.
>
> As I said in my other email, this is false in the general sense.
>
> > Also, since the compositor is a single point of failure, we may not want
> > to make it dependent on it.
>
> This... I'm not quite sure I buy it. If any of all the programs using
> virtual KMS crashes, you still lose some crucial components from your
> display. Maybe that program, while crashing, uploads such a bad state
> to its very own KMS plane, that it causes other KMS planes to
> malfunction. Then you need to detect this situation and still restart
> everything, not just the crashed program.

This, a hundred times. At least in general it's impossible to
guarantee resource isolation between different parts of a kms device -
everything is shared at least in some driver in funny ways.

The only thing we try to guarantee is that if you keep flipping the
same plane with same pixel format, stride, offset, absolutely
everything except the memory block unchanged, then that's guaranteed
to work. Everything else is off the table.

This is why the drm-lease design ended up with revoke support, because
if something goes wrong a superior instance (the compositor, the
kernel can't decide that for userspace) needs to decide whom to shoot
and revoke their access.

> I would think a userspace compositor approach is actually more
> reliable. You write the compositor to be extremely robust. Exactly
> because the compositor is in control of the complete display device and
> not just little pieces of it, it can see what is happening and it can
> mitigate problems. If you have more unreliable components needing
> access to display, make those clients to the compositor, so they can
> crash and malfunction on their own without potentially killing the
> whole display device. If you are as concerned about latency as XR
> people are, then use DRM leases.
>
> Also, what if your virtual KMS driver has a bug? Restarting the kernel
> is much harder that restarting a userspace compositor that hands out
> DRM leases.
>
> The userspace compositor could even be such that it does nothing more
> than handing out DRM leases. However, DRM leases have the problem that
> there is no single entity responsible for keeping the display device
> working, but that responsibility is split between several processes and
> none of them sees the whole picture.

Yeah I think a compositor for this use-case, written in Rust and
heavily audited/proofed is probably a lot more reliable than cobbling
ill-defined kernel driver code on top of barely-defined hw semantics
in resource-sharing cases.

> Btw. VKMS is an existing DRM driver, so your name choice is conflicting.

Yeah that too :-)
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-22  4:02     ` Esaki Tomohito
@ 2021-06-22  9:12       ` Thomas Zimmermann
  -1 siblings, 0 replies; 61+ messages in thread
From: Thomas Zimmermann @ 2021-06-22  9:12 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie, dri-devel,
	linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Damian Hobson-Garcia


[-- Attachment #1.1: Type: text/plain, Size: 1854 bytes --]

Hi

Am 22.06.21 um 06:02 schrieb Esaki Tomohito:
> Hi, Thomas
> Thank you for reply.
> 
> On 2021/06/21 16:10, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 21.06.21 um 08:27 schrieb Tomohito Esaki:
>>> Virtual DRM splits the overlay planes of a display controller into
>>> multiple
>>> virtual devices to allow each plane to be accessed by each process.
>>>
>>> This makes it possible to overlay images output from multiple
>>> processes on a
>>> display. For example, one process displays the camera image without
>>> compositor
>>> while another process overlays the UI.
>>
>> I briefly looked over your patches. I didn't understand how this is
>> different to the functionality of a compositor? Shouldn't this be solved
>> in userspace?
> 
> I think when latency is important (e.g., AR, VR, for displaying camera
> images in IVI systems), there may be use cases where the compositor
> cannot be used.
> Normally, when the image is passed through the compositor, it is
> displayed after 2 VSYNC at most, because the compositor combines the
> image with VSYNC synchronization. On the other hand, if we use vDRM, the
> image will be displayed at the next VSYNC, so it will be displayed after
> 1 VSYNC at most.

Other commenters already addressed these points.

> 
> Also, since the compositor is a single point of failure, we may not want
> to make it dependent on it.

The kernel is also a single point of failure.

TBH I don't think this feature should be merged until there's a clear 
use case that cannot be solved in userspace idiomatically.

Best regards
Thomas

> 
> Best regards
> Tomohito Esaki
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-22  9:12       ` Thomas Zimmermann
  0 siblings, 0 replies; 61+ messages in thread
From: Thomas Zimmermann @ 2021-06-22  9:12 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie,
	linux-kernel, dri-devel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Damian Hobson-Garcia


[-- Attachment #1.1: Type: text/plain, Size: 1854 bytes --]

Hi

Am 22.06.21 um 06:02 schrieb Esaki Tomohito:
> Hi, Thomas
> Thank you for reply.
> 
> On 2021/06/21 16:10, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 21.06.21 um 08:27 schrieb Tomohito Esaki:
>>> Virtual DRM splits the overlay planes of a display controller into
>>> multiple
>>> virtual devices to allow each plane to be accessed by each process.
>>>
>>> This makes it possible to overlay images output from multiple
>>> processes on a
>>> display. For example, one process displays the camera image without
>>> compositor
>>> while another process overlays the UI.
>>
>> I briefly looked over your patches. I didn't understand how this is
>> different to the functionality of a compositor? Shouldn't this be solved
>> in userspace?
> 
> I think when latency is important (e.g., AR, VR, for displaying camera
> images in IVI systems), there may be use cases where the compositor
> cannot be used.
> Normally, when the image is passed through the compositor, it is
> displayed after 2 VSYNC at most, because the compositor combines the
> image with VSYNC synchronization. On the other hand, if we use vDRM, the
> image will be displayed at the next VSYNC, so it will be displayed after
> 1 VSYNC at most.

Other commenters already addressed these points.

> 
> Also, since the compositor is a single point of failure, we may not want
> to make it dependent on it.

The kernel is also a single point of failure.

TBH I don't think this feature should be merged until there's a clear 
use case that cannot be solved in userspace idiomatically.

Best regards
Thomas

> 
> Best regards
> Tomohito Esaki
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-22  4:03     ` Esaki Tomohito
@ 2021-06-22  8:12       ` Pekka Paalanen
  -1 siblings, 0 replies; 61+ messages in thread
From: Pekka Paalanen @ 2021-06-22  8:12 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: Enrico Weigelt, metux IT consult, devicetree, Takanari Hayama,
	Thomas Zimmermann, linux-doc, David Airlie, dri-devel,
	linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Damian Hobson-Garcia

[-- Attachment #1: Type: text/plain, Size: 3567 bytes --]

On Tue, 22 Jun 2021 13:03:39 +0900
Esaki Tomohito <etom@igel.co.jp> wrote:

> Hi, Enrico Weigelt
> Thank you for reply.
> 
> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:
> > On 21.06.21 08:27, Tomohito Esaki wrote:
> > 
> > Hi,
> >   
> >> Virtual DRM splits the overlay planes of a display controller into multiple
> >> virtual devices to allow each plane to be accessed by each process.
> >>
> >> This makes it possible to overlay images output from multiple processes on a
> >> display. For example, one process displays the camera image without compositor
> >> while another process overlays the UI.  
> > 
> > Are you attempting to create an simple in-kernel compositor ?  
> 
> I think the basic idea is the same as DRMlease.

Hi,

indeed. Why not use DRM leases instead?

> We want to separate the resources from the master in units of planes,
> so we proposed virtual DRM.
> I think the advantage of vDRM is that you can use general DRM APIs
> in userland.

You do that with DRM leases too.

> > I don't think that's not the way to go, at least not by touching each
> > single display driver, and not hardcoding the planes in DT.  
> 
> Thank you for comment. I will reconsider about DT.
> 
> > What's the actual use case you're doing that for ? Why not using some
> > userland compositor ?  
> 
> I think when latency is important (e.g., AR, VR, for displaying camera
> images in IVI systems), there may be use cases where the compositor
> cannot be used.
> Normally, when the image is passed through the compositor, it is
> displayed after 2 VSYNC at most, because the compositor combines the
> image with VSYNC synchronization. On the other hand, if we use vDRM, the
> image will be displayed at the next VSYNC, so it will be displayed after
> 1 VSYNC at most.

As I said in my other email, this is false in the general sense.

> Also, since the compositor is a single point of failure, we may not want
> to make it dependent on it.

This... I'm not quite sure I buy it. If any of all the programs using
virtual KMS crashes, you still lose some crucial components from your
display. Maybe that program, while crashing, uploads such a bad state
to its very own KMS plane, that it causes other KMS planes to
malfunction. Then you need to detect this situation and still restart
everything, not just the crashed program.

I would think a userspace compositor approach is actually more
reliable. You write the compositor to be extremely robust. Exactly
because the compositor is in control of the complete display device and
not just little pieces of it, it can see what is happening and it can
mitigate problems. If you have more unreliable components needing
access to display, make those clients to the compositor, so they can
crash and malfunction on their own without potentially killing the
whole display device. If you are as concerned about latency as XR
people are, then use DRM leases.

Also, what if your virtual KMS driver has a bug? Restarting the kernel
is much harder that restarting a userspace compositor that hands out
DRM leases.

The userspace compositor could even be such that it does nothing more
than handing out DRM leases. However, DRM leases have the problem that
there is no single entity responsible for keeping the display device
working, but that responsibility is split between several processes and
none of them sees the whole picture.


Btw. VKMS is an existing DRM driver, so your name choice is conflicting.


Thanks,
pq

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-22  8:12       ` Pekka Paalanen
  0 siblings, 0 replies; 61+ messages in thread
From: Pekka Paalanen @ 2021-06-22  8:12 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie,
	linux-kernel, dri-devel, linux-renesas-soc, Kieran Bingham,
	Enrico Weigelt, metux IT consult, Laurent Pinchart,
	Thomas Zimmermann, Damian Hobson-Garcia

[-- Attachment #1: Type: text/plain, Size: 3567 bytes --]

On Tue, 22 Jun 2021 13:03:39 +0900
Esaki Tomohito <etom@igel.co.jp> wrote:

> Hi, Enrico Weigelt
> Thank you for reply.
> 
> On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:
> > On 21.06.21 08:27, Tomohito Esaki wrote:
> > 
> > Hi,
> >   
> >> Virtual DRM splits the overlay planes of a display controller into multiple
> >> virtual devices to allow each plane to be accessed by each process.
> >>
> >> This makes it possible to overlay images output from multiple processes on a
> >> display. For example, one process displays the camera image without compositor
> >> while another process overlays the UI.  
> > 
> > Are you attempting to create an simple in-kernel compositor ?  
> 
> I think the basic idea is the same as DRMlease.

Hi,

indeed. Why not use DRM leases instead?

> We want to separate the resources from the master in units of planes,
> so we proposed virtual DRM.
> I think the advantage of vDRM is that you can use general DRM APIs
> in userland.

You do that with DRM leases too.

> > I don't think that's not the way to go, at least not by touching each
> > single display driver, and not hardcoding the planes in DT.  
> 
> Thank you for comment. I will reconsider about DT.
> 
> > What's the actual use case you're doing that for ? Why not using some
> > userland compositor ?  
> 
> I think when latency is important (e.g., AR, VR, for displaying camera
> images in IVI systems), there may be use cases where the compositor
> cannot be used.
> Normally, when the image is passed through the compositor, it is
> displayed after 2 VSYNC at most, because the compositor combines the
> image with VSYNC synchronization. On the other hand, if we use vDRM, the
> image will be displayed at the next VSYNC, so it will be displayed after
> 1 VSYNC at most.

As I said in my other email, this is false in the general sense.

> Also, since the compositor is a single point of failure, we may not want
> to make it dependent on it.

This... I'm not quite sure I buy it. If any of all the programs using
virtual KMS crashes, you still lose some crucial components from your
display. Maybe that program, while crashing, uploads such a bad state
to its very own KMS plane, that it causes other KMS planes to
malfunction. Then you need to detect this situation and still restart
everything, not just the crashed program.

I would think a userspace compositor approach is actually more
reliable. You write the compositor to be extremely robust. Exactly
because the compositor is in control of the complete display device and
not just little pieces of it, it can see what is happening and it can
mitigate problems. If you have more unreliable components needing
access to display, make those clients to the compositor, so they can
crash and malfunction on their own without potentially killing the
whole display device. If you are as concerned about latency as XR
people are, then use DRM leases.

Also, what if your virtual KMS driver has a bug? Restarting the kernel
is much harder that restarting a userspace compositor that hands out
DRM leases.

The userspace compositor could even be such that it does nothing more
than handing out DRM leases. However, DRM leases have the problem that
there is no single entity responsible for keeping the display device
working, but that responsibility is split between several processes and
none of them sees the whole picture.


Btw. VKMS is an existing DRM driver, so your name choice is conflicting.


Thanks,
pq

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-22  4:02     ` Esaki Tomohito
@ 2021-06-22  7:57       ` Pekka Paalanen
  -1 siblings, 0 replies; 61+ messages in thread
From: Pekka Paalanen @ 2021-06-22  7:57 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: Thomas Zimmermann, devicetree, Takanari Hayama, linux-doc,
	David Airlie, dri-devel, linux-kernel, linux-renesas-soc,
	Kieran Bingham, Laurent Pinchart, Damian Hobson-Garcia

[-- Attachment #1: Type: text/plain, Size: 1463 bytes --]

On Tue, 22 Jun 2021 13:02:59 +0900
Esaki Tomohito <etom@igel.co.jp> wrote:

> Hi, Thomas
> Thank you for reply.
> 
> On 2021/06/21 16:10, Thomas Zimmermann wrote:
> > Hi
> > 
> > Am 21.06.21 um 08:27 schrieb Tomohito Esaki:  
> >> Virtual DRM splits the overlay planes of a display controller into
> >> multiple
> >> virtual devices to allow each plane to be accessed by each process.
> >>
> >> This makes it possible to overlay images output from multiple
> >> processes on a
> >> display. For example, one process displays the camera image without
> >> compositor
> >> while another process overlays the UI.  
> > 
> > I briefly looked over your patches. I didn't understand how this is
> > different to the functionality of a compositor? Shouldn't this be solved
> > in userspace?  
> 
> I think when latency is important (e.g., AR, VR, for displaying camera
> images in IVI systems), there may be use cases where the compositor
> cannot be used.

Hi,

> Normally, when the image is passed through the compositor, it is
> displayed after 2 VSYNC at most, because the compositor combines the
> image with VSYNC synchronization.

This is not a universal fact. You can write a Wayland compositor that
consistently reaches app-to-screen latency of less than one monitor
refresh cycle, while also using KMS planes.

I believe Weston succeeds in this already if you write the Wayland
application accordingly.


Thanks,
pq

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-22  7:57       ` Pekka Paalanen
  0 siblings, 0 replies; 61+ messages in thread
From: Pekka Paalanen @ 2021-06-22  7:57 UTC (permalink / raw)
  To: Esaki Tomohito
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie,
	linux-kernel, dri-devel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Thomas Zimmermann, Damian Hobson-Garcia

[-- Attachment #1: Type: text/plain, Size: 1463 bytes --]

On Tue, 22 Jun 2021 13:02:59 +0900
Esaki Tomohito <etom@igel.co.jp> wrote:

> Hi, Thomas
> Thank you for reply.
> 
> On 2021/06/21 16:10, Thomas Zimmermann wrote:
> > Hi
> > 
> > Am 21.06.21 um 08:27 schrieb Tomohito Esaki:  
> >> Virtual DRM splits the overlay planes of a display controller into
> >> multiple
> >> virtual devices to allow each plane to be accessed by each process.
> >>
> >> This makes it possible to overlay images output from multiple
> >> processes on a
> >> display. For example, one process displays the camera image without
> >> compositor
> >> while another process overlays the UI.  
> > 
> > I briefly looked over your patches. I didn't understand how this is
> > different to the functionality of a compositor? Shouldn't this be solved
> > in userspace?  
> 
> I think when latency is important (e.g., AR, VR, for displaying camera
> images in IVI systems), there may be use cases where the compositor
> cannot be used.

Hi,

> Normally, when the image is passed through the compositor, it is
> displayed after 2 VSYNC at most, because the compositor combines the
> image with VSYNC synchronization.

This is not a universal fact. You can write a Wayland compositor that
consistently reaches app-to-screen latency of less than one monitor
refresh cycle, while also using KMS planes.

I believe Weston succeeds in this already if you write the Wayland
application accordingly.


Thanks,
pq

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-21  9:24   ` Maxime Ripard
@ 2021-06-22  4:36       ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-22  4:36 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Thomas Zimmermann, Maarten Lankhorst, David Airlie,
	Daniel Vetter, Laurent Pinchart, Kieran Bingham, dri-devel,
	linux-renesas-soc, linux-kernel, devicetree, linux-doc,
	Damian Hobson-Garcia, Takanari Hayama

Hi, Maxime
Thank you for reply.

On 2021/06/21 18:24, Maxime Ripard wrote:
> Hi,
> 
> On Mon, Jun 21, 2021 at 09:10:19AM +0200, Thomas Zimmermann wrote:
>> Am 21.06.21 um 08:27 schrieb Tomohito Esaki:
>>> Virtual DRM splits the overlay planes of a display controller into multiple
>>> virtual devices to allow each plane to be accessed by each process.
>>>
>>> This makes it possible to overlay images output from multiple processes on a
>>> display. For example, one process displays the camera image without compositor
>>> while another process overlays the UI.
>>
>> I briefly looked over your patches. I didn't understand how this is
>> different to the functionality of a compositor? Shouldn't this be solved in
>> userspace?
> 
> I think there could be a bunch of use-cases for something that could
> "steal" a plane without the compositor knowing.
> 
> Something I'd really like to work at some point for example is that the
> downstream RaspberryPi display driver has a visual clue when it's
> running too hot or is in over-current.
> 
> I don't think this is the right solution though. The DT binding makes it
> far too static, and if there's a compositor I'd assume it would want to
> know about it somehow (at least if it's from the userspace) ?
> 

I will reconsider the DT bindings.

We want to separate the resources from the master in units of planes,
so we proposed virtual DRM.
By separating the plane from the master and making it appear as
a virtual DRM devicein userland, the plane can be accessed from
userland using the general DRM API.
What do you think about this idea?

Best Regards
Tomohito Esaki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-22  4:36       ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-22  4:36 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: devicetree, Takanari Hayama, Thomas Zimmermann, linux-doc,
	David Airlie, linux-kernel, dri-devel, linux-renesas-soc,
	Kieran Bingham, Laurent Pinchart, Damian Hobson-Garcia

Hi, Maxime
Thank you for reply.

On 2021/06/21 18:24, Maxime Ripard wrote:
> Hi,
> 
> On Mon, Jun 21, 2021 at 09:10:19AM +0200, Thomas Zimmermann wrote:
>> Am 21.06.21 um 08:27 schrieb Tomohito Esaki:
>>> Virtual DRM splits the overlay planes of a display controller into multiple
>>> virtual devices to allow each plane to be accessed by each process.
>>>
>>> This makes it possible to overlay images output from multiple processes on a
>>> display. For example, one process displays the camera image without compositor
>>> while another process overlays the UI.
>>
>> I briefly looked over your patches. I didn't understand how this is
>> different to the functionality of a compositor? Shouldn't this be solved in
>> userspace?
> 
> I think there could be a bunch of use-cases for something that could
> "steal" a plane without the compositor knowing.
> 
> Something I'd really like to work at some point for example is that the
> downstream RaspberryPi display driver has a visual clue when it's
> running too hot or is in over-current.
> 
> I don't think this is the right solution though. The DT binding makes it
> far too static, and if there's a compositor I'd assume it would want to
> know about it somehow (at least if it's from the userspace) ?
> 

I will reconsider the DT bindings.

We want to separate the resources from the master in units of planes,
so we proposed virtual DRM.
By separating the plane from the master and making it appear as
a virtual DRM devicein userland, the plane can be accessed from
userland using the general DRM API.
What do you think about this idea?

Best Regards
Tomohito Esaki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-21 16:05 ` Enrico Weigelt, metux IT consult
@ 2021-06-22  4:03     ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-22  4:03 UTC (permalink / raw)
  To: Enrico Weigelt, metux IT consult
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham,
	dri-devel, linux-renesas-soc, linux-kernel, devicetree,
	linux-doc, Damian Hobson-Garcia, Takanari Hayama

Hi, Enrico Weigelt
Thank you for reply.

On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:
> On 21.06.21 08:27, Tomohito Esaki wrote:
> 
> Hi,
> 
>> Virtual DRM splits the overlay planes of a display controller into multiple
>> virtual devices to allow each plane to be accessed by each process.
>>
>> This makes it possible to overlay images output from multiple processes on a
>> display. For example, one process displays the camera image without compositor
>> while another process overlays the UI.
> 
> Are you attempting to create an simple in-kernel compositor ?

I think the basic idea is the same as DRMlease.
We want to separate the resources from the master in units of planes,
so we proposed virtual DRM.
I think the advantage of vDRM is that you can use general DRM APIs
in userland.

> I don't think that's not the way to go, at least not by touching each
> single display driver, and not hardcoding the planes in DT.

Thank you for comment. I will reconsider about DT.

> What's the actual use case you're doing that for ? Why not using some
> userland compositor ?

I think when latency is important (e.g., AR, VR, for displaying camera
images in IVI systems), there may be use cases where the compositor
cannot be used.
Normally, when the image is passed through the compositor, it is
displayed after 2 VSYNC at most, because the compositor combines the
image with VSYNC synchronization. On the other hand, if we use vDRM, the
image will be displayed at the next VSYNC, so it will be displayed after
1 VSYNC at most.

Also, since the compositor is a single point of failure, we may not want
to make it dependent on it.

Best regards
Tomohito Esaki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-22  4:03     ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-22  4:03 UTC (permalink / raw)
  To: Enrico Weigelt, metux IT consult
  Cc: devicetree, Takanari Hayama, Thomas Zimmermann, linux-doc,
	David Airlie, dri-devel, linux-kernel, linux-renesas-soc,
	Kieran Bingham, Laurent Pinchart, Damian Hobson-Garcia

Hi, Enrico Weigelt
Thank you for reply.

On 2021/06/22 1:05, Enrico Weigelt, metux IT consult wrote:
> On 21.06.21 08:27, Tomohito Esaki wrote:
> 
> Hi,
> 
>> Virtual DRM splits the overlay planes of a display controller into multiple
>> virtual devices to allow each plane to be accessed by each process.
>>
>> This makes it possible to overlay images output from multiple processes on a
>> display. For example, one process displays the camera image without compositor
>> while another process overlays the UI.
> 
> Are you attempting to create an simple in-kernel compositor ?

I think the basic idea is the same as DRMlease.
We want to separate the resources from the master in units of planes,
so we proposed virtual DRM.
I think the advantage of vDRM is that you can use general DRM APIs
in userland.

> I don't think that's not the way to go, at least not by touching each
> single display driver, and not hardcoding the planes in DT.

Thank you for comment. I will reconsider about DT.

> What's the actual use case you're doing that for ? Why not using some
> userland compositor ?

I think when latency is important (e.g., AR, VR, for displaying camera
images in IVI systems), there may be use cases where the compositor
cannot be used.
Normally, when the image is passed through the compositor, it is
displayed after 2 VSYNC at most, because the compositor combines the
image with VSYNC synchronization. On the other hand, if we use vDRM, the
image will be displayed at the next VSYNC, so it will be displayed after
1 VSYNC at most.

Also, since the compositor is a single point of failure, we may not want
to make it dependent on it.

Best regards
Tomohito Esaki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-21  7:10 ` Thomas Zimmermann
@ 2021-06-22  4:02     ` Esaki Tomohito
  2021-06-22  4:02     ` Esaki Tomohito
  1 sibling, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-22  4:02 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Maarten Lankhorst, Maxime Ripard, David Airlie, Daniel Vetter,
	Laurent Pinchart, Kieran Bingham, dri-devel, linux-renesas-soc,
	linux-kernel, devicetree, linux-doc, Damian Hobson-Garcia,
	Takanari Hayama

Hi, Thomas
Thank you for reply.

On 2021/06/21 16:10, Thomas Zimmermann wrote:
> Hi
> 
> Am 21.06.21 um 08:27 schrieb Tomohito Esaki:
>> Virtual DRM splits the overlay planes of a display controller into
>> multiple
>> virtual devices to allow each plane to be accessed by each process.
>>
>> This makes it possible to overlay images output from multiple
>> processes on a
>> display. For example, one process displays the camera image without
>> compositor
>> while another process overlays the UI.
> 
> I briefly looked over your patches. I didn't understand how this is
> different to the functionality of a compositor? Shouldn't this be solved
> in userspace?

I think when latency is important (e.g., AR, VR, for displaying camera
images in IVI systems), there may be use cases where the compositor
cannot be used.
Normally, when the image is passed through the compositor, it is
displayed after 2 VSYNC at most, because the compositor combines the
image with VSYNC synchronization. On the other hand, if we use vDRM, the
image will be displayed at the next VSYNC, so it will be displayed after
1 VSYNC at most.

Also, since the compositor is a single point of failure, we may not want
to make it dependent on it.

Best regards
Tomohito Esaki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-22  4:02     ` Esaki Tomohito
  0 siblings, 0 replies; 61+ messages in thread
From: Esaki Tomohito @ 2021-06-22  4:02 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: devicetree, Takanari Hayama, linux-doc, David Airlie, dri-devel,
	linux-kernel, linux-renesas-soc, Kieran Bingham,
	Laurent Pinchart, Damian Hobson-Garcia

Hi, Thomas
Thank you for reply.

On 2021/06/21 16:10, Thomas Zimmermann wrote:
> Hi
> 
> Am 21.06.21 um 08:27 schrieb Tomohito Esaki:
>> Virtual DRM splits the overlay planes of a display controller into
>> multiple
>> virtual devices to allow each plane to be accessed by each process.
>>
>> This makes it possible to overlay images output from multiple
>> processes on a
>> display. For example, one process displays the camera image without
>> compositor
>> while another process overlays the UI.
> 
> I briefly looked over your patches. I didn't understand how this is
> different to the functionality of a compositor? Shouldn't this be solved
> in userspace?

I think when latency is important (e.g., AR, VR, for displaying camera
images in IVI systems), there may be use cases where the compositor
cannot be used.
Normally, when the image is passed through the compositor, it is
displayed after 2 VSYNC at most, because the compositor combines the
image with VSYNC synchronization. On the other hand, if we use vDRM, the
image will be displayed at the next VSYNC, so it will be displayed after
1 VSYNC at most.

Also, since the compositor is a single point of failure, we may not want
to make it dependent on it.

Best regards
Tomohito Esaki

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-21  6:27 Tomohito Esaki
  2021-06-21  7:10 ` Thomas Zimmermann
@ 2021-06-21 16:05 ` Enrico Weigelt, metux IT consult
  2021-06-22  4:03     ` Esaki Tomohito
  1 sibling, 1 reply; 61+ messages in thread
From: Enrico Weigelt, metux IT consult @ 2021-06-21 16:05 UTC (permalink / raw)
  To: Tomohito Esaki, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Daniel Vetter, Laurent Pinchart,
	Kieran Bingham
  Cc: dri-devlel, linux-renesas-soc, linux-kernel, devicetree, linux-doc

On 21.06.21 08:27, Tomohito Esaki wrote:

Hi,

> Virtual DRM splits the overlay planes of a display controller into multiple
> virtual devices to allow each plane to be accessed by each process.
> 
> This makes it possible to overlay images output from multiple processes on a
> display. For example, one process displays the camera image without compositor
> while another process overlays the UI.

Are you attempting to create an simple in-kernel compositor ?

I don't think that's not the way to go, at least not by touching each
single display driver, and not hardcoding the planes in DT.

What's the actual use case you're doing that for ? Why not using some
userland compositor ?

If you really wanna build a kernel compositor, it should be completely
independent of hw drivers. (well, almost - in case of gpus shall be
used, the commands obviously need to be dispatched the actual driver)


--mtx

-- 
---
Hinweis: unverschlüsselte E-Mails können leicht abgehört und manipuliert
werden ! Für eine vertrauliche Kommunikation senden Sie bitte ihren
GPG/PGP-Schlüssel zu.
---
Enrico Weigelt, metux IT consult
Free software and Linux embedded engineering
info@metux.net -- +49-151-27565287

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-21  7:10 ` Thomas Zimmermann
@ 2021-06-21  9:24   ` Maxime Ripard
  2021-06-22  4:36       ` Esaki Tomohito
  2021-06-22  4:02     ` Esaki Tomohito
  1 sibling, 1 reply; 61+ messages in thread
From: Maxime Ripard @ 2021-06-21  9:24 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Tomohito Esaki, Maarten Lankhorst, David Airlie, Daniel Vetter,
	Laurent Pinchart, Kieran Bingham, dri-devlel, linux-renesas-soc,
	linux-kernel, devicetree, linux-doc

[-- Attachment #1: Type: text/plain, Size: 1186 bytes --]

Hi,

On Mon, Jun 21, 2021 at 09:10:19AM +0200, Thomas Zimmermann wrote:
> Am 21.06.21 um 08:27 schrieb Tomohito Esaki:
> > Virtual DRM splits the overlay planes of a display controller into multiple
> > virtual devices to allow each plane to be accessed by each process.
> > 
> > This makes it possible to overlay images output from multiple processes on a
> > display. For example, one process displays the camera image without compositor
> > while another process overlays the UI.
> 
> I briefly looked over your patches. I didn't understand how this is
> different to the functionality of a compositor? Shouldn't this be solved in
> userspace?

I think there could be a bunch of use-cases for something that could
"steal" a plane without the compositor knowing.

Something I'd really like to work at some point for example is that the
downstream RaspberryPi display driver has a visual clue when it's
running too hot or is in over-current.

I don't think this is the right solution though. The DT binding makes it
far too static, and if there's a compositor I'd assume it would want to
know about it somehow (at least if it's from the userspace) ?

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATH 0/4] [RFC] Support virtual DRM
  2021-06-21  6:27 Tomohito Esaki
@ 2021-06-21  7:10 ` Thomas Zimmermann
  2021-06-21  9:24   ` Maxime Ripard
  2021-06-22  4:02     ` Esaki Tomohito
  2021-06-21 16:05 ` Enrico Weigelt, metux IT consult
  1 sibling, 2 replies; 61+ messages in thread
From: Thomas Zimmermann @ 2021-06-21  7:10 UTC (permalink / raw)
  To: Tomohito Esaki, Maarten Lankhorst, Maxime Ripard, David Airlie,
	Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: dri-devlel, linux-renesas-soc, linux-kernel, devicetree, linux-doc


[-- Attachment #1.1: Type: text/plain, Size: 4332 bytes --]

Hi

Am 21.06.21 um 08:27 schrieb Tomohito Esaki:
> Virtual DRM splits the overlay planes of a display controller into multiple
> virtual devices to allow each plane to be accessed by each process.
> 
> This makes it possible to overlay images output from multiple processes on a
> display. For example, one process displays the camera image without compositor
> while another process overlays the UI.

I briefly looked over your patches. I didn't understand how this is 
different to the functionality of a compositor? Shouldn't this be solved 
in userspace?

Best regards
Thomas

> 
> Virtual DRM driver doesn’t directly control the display hardware and has no
> access to the physical bus. Instead, the virtual DRM driver issues requests to
> the standard DRM device driver (parent) when the hardware needs to be
> controlled. The parent is modified to notify the virtual DRM driver of
> interruptevents from the display hardware. Therefore, in order to use virtual
> DRM, each DRM device driver needs to add code to support virutal DRM.
> 
> The only driver supported in this patch series is rcar-du. This patch series
> is divided into multiple. The first patch adds vDRM feature to DRM, and the
> second patch support vDRM for the rcar-du driver. The other patches add
> documentation.
> 
> In particular, I would appreciate your advice on the following points:
> * virtual DRM generalization
>    I've only tested with rcar-du, is there anything I should consider to make
>    virtual DRM work with other drivers?
> 
> * Integration to upstream
>    I think it is a good idea to add virtual DRM to the DRM core functionality,
>    but I would appreciate any suggestions on what needs to be improved for
>    integration to upstream.
> 
> * dumb_create and fb_create callback
>    I think that the dumb_create and fb_create callbacks need to be done by the
>    parent, and it is preferable to use the parent's callbacks as they are.
>    However, since the dumb buffer needs to be registered in the parent and
>    the fb handle needs to be registered in the drm_file of the vDRM, the
>    dumb_create callbacks from the parent driver cannot be used as is.
>    Therefore, the current implementation of the dumb_create callback is
>    workarround.
>    What do you think is the best way to deal with this issue?
> 
> 
> Tomohito Esaki (4):
>    Add Virtual DRM device driver
>    rcar-du: Add support virtual DRM device
>    dt-bindings: display: Add virtual DRM
>    doc-rst: Add virtual DRM documentation
> 
>   .../devicetree/bindings/display/vdrm.yaml     |  67 ++
>   Documentation/gpu/drivers.rst                 |   1 +
>   Documentation/gpu/vdrm.rst                    |  51 ++
>   drivers/gpu/drm/Kconfig                       |   7 +
>   drivers/gpu/drm/Makefile                      |   1 +
>   drivers/gpu/drm/rcar-du/Kconfig               |   4 +
>   drivers/gpu/drm/rcar-du/Makefile              |   1 +
>   drivers/gpu/drm/rcar-du/rcar_du_crtc.c        |  42 +
>   drivers/gpu/drm/rcar-du/rcar_du_crtc.h        |  13 +
>   drivers/gpu/drm/rcar-du/rcar_du_drv.c         |  13 +
>   drivers/gpu/drm/rcar-du/rcar_du_drv.h         |   3 +
>   drivers/gpu/drm/rcar-du/rcar_du_vdrm.c        | 191 ++++
>   drivers/gpu/drm/rcar-du/rcar_du_vdrm.h        |  67 ++
>   drivers/gpu/drm/rcar-du/rcar_du_vsp.c         |  22 +
>   drivers/gpu/drm/rcar-du/rcar_du_vsp.h         |   1 +
>   drivers/gpu/drm/vdrm/vdrm_api.h               |  68 ++
>   drivers/gpu/drm/vdrm/vdrm_drv.c               | 859 ++++++++++++++++++
>   drivers/gpu/drm/vdrm/vdrm_drv.h               |  80 ++
>   18 files changed, 1491 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml
>   create mode 100644 Documentation/gpu/vdrm.rst
>   create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c
>   create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h
>   create mode 100644 drivers/gpu/drm/vdrm/vdrm_api.h
>   create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.c
>   create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.h
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* [PATH 0/4] [RFC] Support virtual DRM
@ 2021-06-21  6:27 Tomohito Esaki
  2021-06-21  7:10 ` Thomas Zimmermann
  2021-06-21 16:05 ` Enrico Weigelt, metux IT consult
  0 siblings, 2 replies; 61+ messages in thread
From: Tomohito Esaki @ 2021-06-21  6:27 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Daniel Vetter, Laurent Pinchart, Kieran Bingham
  Cc: dri-devlel, linux-renesas-soc, linux-kernel, devicetree,
	linux-doc, Tomohito Esaki

Virtual DRM splits the overlay planes of a display controller into multiple
virtual devices to allow each plane to be accessed by each process.

This makes it possible to overlay images output from multiple processes on a
display. For example, one process displays the camera image without compositor
while another process overlays the UI.

Virtual DRM driver doesn’t directly control the display hardware and has no
access to the physical bus. Instead, the virtual DRM driver issues requests to
the standard DRM device driver (parent) when the hardware needs to be
controlled. The parent is modified to notify the virtual DRM driver of
interruptevents from the display hardware. Therefore, in order to use virtual
DRM, each DRM device driver needs to add code to support virutal DRM.

The only driver supported in this patch series is rcar-du. This patch series
is divided into multiple. The first patch adds vDRM feature to DRM, and the
second patch support vDRM for the rcar-du driver. The other patches add
documentation.

In particular, I would appreciate your advice on the following points:
* virtual DRM generalization
  I've only tested with rcar-du, is there anything I should consider to make
  virtual DRM work with other drivers?

* Integration to upstream
  I think it is a good idea to add virtual DRM to the DRM core functionality,
  but I would appreciate any suggestions on what needs to be improved for
  integration to upstream.

* dumb_create and fb_create callback
  I think that the dumb_create and fb_create callbacks need to be done by the
  parent, and it is preferable to use the parent's callbacks as they are.
  However, since the dumb buffer needs to be registered in the parent and
  the fb handle needs to be registered in the drm_file of the vDRM, the
  dumb_create callbacks from the parent driver cannot be used as is.
  Therefore, the current implementation of the dumb_create callback is
  workarround.
  What do you think is the best way to deal with this issue?


Tomohito Esaki (4):
  Add Virtual DRM device driver
  rcar-du: Add support virtual DRM device
  dt-bindings: display: Add virtual DRM
  doc-rst: Add virtual DRM documentation

 .../devicetree/bindings/display/vdrm.yaml     |  67 ++
 Documentation/gpu/drivers.rst                 |   1 +
 Documentation/gpu/vdrm.rst                    |  51 ++
 drivers/gpu/drm/Kconfig                       |   7 +
 drivers/gpu/drm/Makefile                      |   1 +
 drivers/gpu/drm/rcar-du/Kconfig               |   4 +
 drivers/gpu/drm/rcar-du/Makefile              |   1 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c        |  42 +
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h        |  13 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.c         |  13 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.h         |   3 +
 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c        | 191 ++++
 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h        |  67 ++
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c         |  22 +
 drivers/gpu/drm/rcar-du/rcar_du_vsp.h         |   1 +
 drivers/gpu/drm/vdrm/vdrm_api.h               |  68 ++
 drivers/gpu/drm/vdrm/vdrm_drv.c               | 859 ++++++++++++++++++
 drivers/gpu/drm/vdrm/vdrm_drv.h               |  80 ++
 18 files changed, 1491 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/vdrm.yaml
 create mode 100644 Documentation/gpu/vdrm.rst
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.c
 create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vdrm.h
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_api.h
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.c
 create mode 100644 drivers/gpu/drm/vdrm/vdrm_drv.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 61+ messages in thread

end of thread, other threads:[~2021-06-25  1:55 UTC | newest]

Thread overview: 61+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-21  6:43 [PATH 0/4] [RFC] Support virtual DRM Tomohito Esaki
2021-06-21  6:43 ` Tomohito Esaki
2021-06-21  6:44 ` [PATH 1/4] drm: Add Virtual DRM device driver Tomohito Esaki
2021-06-21  6:44   ` Tomohito Esaki
2021-06-21 13:55   ` kernel test robot
2021-06-21 13:55     ` kernel test robot
2021-06-21 13:55     ` kernel test robot
2021-06-21 15:55   ` Sam Ravnborg
2021-06-22  4:10     ` Esaki Tomohito
2021-06-22  4:10       ` Esaki Tomohito
2021-06-21  6:44 ` [PATH 2/4] rcar-du: Add support virtual DRM device Tomohito Esaki
2021-06-21  6:44   ` Tomohito Esaki
2021-06-21 11:25   ` kernel test robot
2021-06-21 11:25     ` kernel test robot
2021-06-21 11:25     ` kernel test robot
2021-06-21 15:57   ` Sam Ravnborg
2021-06-21  6:44 ` [PATH 3/4] dt-bindings: display: Add virtual DRM Tomohito Esaki
2021-06-21  6:44   ` Tomohito Esaki
2021-06-21 16:03   ` Sam Ravnborg
2021-06-21 17:40   ` Rob Herring
2021-06-21 17:40     ` Rob Herring
2021-06-22  4:17     ` Esaki Tomohito
2021-06-22  4:17       ` Esaki Tomohito
2021-06-22 16:54   ` Rob Herring
2021-06-22 16:54     ` Rob Herring
2021-06-21  6:44 ` [PATH 4/4] doc-rst: Add virtual DRM documentation Tomohito Esaki
2021-06-21  6:44   ` Tomohito Esaki
2021-06-22  8:04 ` [PATH 0/4] [RFC] Support virtual DRM Simon Ser
2021-06-22  8:04   ` Simon Ser
  -- strict thread matches above, loose matches on Subject: below --
2021-06-21  6:27 Tomohito Esaki
2021-06-21  7:10 ` Thomas Zimmermann
2021-06-21  9:24   ` Maxime Ripard
2021-06-22  4:36     ` Esaki Tomohito
2021-06-22  4:36       ` Esaki Tomohito
2021-06-23 14:39       ` Maxime Ripard
2021-06-23 14:39         ` Maxime Ripard
2021-06-22  4:02   ` Esaki Tomohito
2021-06-22  4:02     ` Esaki Tomohito
2021-06-22  7:57     ` Pekka Paalanen
2021-06-22  7:57       ` Pekka Paalanen
2021-06-23  8:04       ` Michel Dänzer
2021-06-23  8:21         ` Esaki Tomohito
2021-06-22  9:12     ` Thomas Zimmermann
2021-06-22  9:12       ` Thomas Zimmermann
2021-06-21 16:05 ` Enrico Weigelt, metux IT consult
2021-06-22  4:03   ` Esaki Tomohito
2021-06-22  4:03     ` Esaki Tomohito
2021-06-22  8:12     ` Pekka Paalanen
2021-06-22  8:12       ` Pekka Paalanen
2021-06-22 19:12       ` Daniel Vetter
2021-06-22 19:12         ` Daniel Vetter
2021-06-23  6:56       ` Esaki Tomohito
2021-06-23  6:56         ` Esaki Tomohito
2021-06-23  8:39         ` Pekka Paalanen
2021-06-23  8:39           ` Pekka Paalanen
2021-06-23  9:22           ` Esaki Tomohito
2021-06-23  9:22             ` Esaki Tomohito
2021-06-23 11:41             ` Pekka Paalanen
2021-06-23 11:41               ` Pekka Paalanen
2021-06-25  1:55               ` Esaki Tomohito
2021-06-25  1:55                 ` Esaki Tomohito

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.