mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 00/16] drm/vkms: Introduce detailed configuration
@ 2025-01-21 10:55 Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 01/16] drm/vkms: Extract vkms_config header Louis Chauvet
                   ` (15 more replies)
  0 siblings, 16 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet, José Expósito

The current code is not flexible to configure the VKMS device. In
preparation for ConfigFS interface introduce few structure that can be
used to configure the device creation: `vkms_config`.

This part is splitted from the ConfigFS implementation itself to avoid
mixing two complex interfaces.

The vkms_config structure will allows the configuration of:
- planes
    - name
    - possible_crtcs
    - supported_rotations
    - default_rotation
    - type
    - format
- crtcs
    - name
    - possible_planes [automatically filled by helpers]
    - possible_encoders [automatically filled by helpers]
- encoders
    - name
    - type
    - possible_crtcs
- connectors:
    - type
    - status
    - EDID

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Changes in v3:
- Remove the plane color encoding/range and not yet supported formats so 
  it does not have any dependencies
- Created a helper to get config for a connector
- Rebased on drm-misc-next
- Link to v2: https://lore.kernel.org/r/20241122-google-remove-crtc-index-from-parameter-v2-0-81540742535a@bootlin.com

Changes in v2:
- Rebased on drm-misc-next
- Added support for many new configuration
- Link to v1: https://lore.kernel.org/r/20240814-google-remove-crtc-index-from-parameter-v1-0-6e179abf9fd4@bootlin.com

---
Louis Chauvet (16):
      drm/vkms: Extract vkms_config header
      drm/vkms: Add a validation function for vkms configuration
      drm/vkms: Move default_config creation to its own function
      drm/vkms: Introduce config for plane
      drm/vkms: Introduce config for plane name
      drm/vkms: Introduce config for plane rotation
      drm/vkms: Introduce config for CRTCs and encoders
      drm/vkms: Introduce config for encoder name
      drm/vkms: Introduce config for CRTC name
      drm/vkms: Add test for config structure
      drm/vkms: Introduce config for connector
      drm/vkms: Introduce config for connector type
      drm/vkms: Introduce config for plane format
      drm/vkms: Introduce config for connector status
      drm/vkms: Introduce config for connector EDID
      drm/vkms: Introduce config for encoder type

 drivers/gpu/drm/vkms/Makefile                 |   3 +-
 drivers/gpu/drm/vkms/tests/Makefile           |   3 +
 drivers/gpu/drm/vkms/tests/vkms_config_test.c | 137 +++++++
 drivers/gpu/drm/vkms/vkms_config.c            | 556 ++++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_config.h            | 237 +++++++++++
 drivers/gpu/drm/vkms/vkms_crtc.c              |  10 +-
 drivers/gpu/drm/vkms/vkms_drv.c               |  42 +-
 drivers/gpu/drm/vkms/vkms_drv.h               |  25 +-
 drivers/gpu/drm/vkms/vkms_output.c            | 192 +++++----
 drivers/gpu/drm/vkms/vkms_plane.c             |  21 +-
 10 files changed, 1088 insertions(+), 138 deletions(-)
---
base-commit: 49a167c393b0ceb592b9d2e65cc4f46bcc707108
change-id: 20240521-google-remove-crtc-index-from-parameter-f9afb21c7a85

Best regards,
-- 
Louis Chauvet <louis.chauvet@bootlin.com>


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

* [PATCH v3 01/16] drm/vkms: Extract vkms_config header
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 02/16] drm/vkms: Add a validation function for vkms configuration Louis Chauvet
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet, José Expósito

Creating a new vkms_config structure will be more complex once we
start adding more options.

Extract the vkms_config structure to its own header and source files
and add functions to create and delete a vkms_config and to initialize
debugfs.

Refactor, no functional changes.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
[Changes: Cherry picked and conflict solve]
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/Makefile      |  3 ++-
 drivers/gpu/drm/vkms/vkms_config.c | 48 ++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_config.h | 32 +++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_drv.c    | 41 +++++++++-----------------------
 drivers/gpu/drm/vkms/vkms_drv.h    | 15 +-----------
 drivers/gpu/drm/vkms/vkms_output.c |  1 +
 6 files changed, 95 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile
index 1b28a6a32948b557867dda51d2ccfdea687a2b62..b371b5d70ee31e76343c2f09e6dc5a6e74a1c246 100644
--- a/drivers/gpu/drm/vkms/Makefile
+++ b/drivers/gpu/drm/vkms/Makefile
@@ -6,6 +6,7 @@ vkms-y := \
 	vkms_formats.o \
 	vkms_crtc.o \
 	vkms_composer.o \
-	vkms_writeback.o
+	vkms_writeback.o \
+	vkms_config.o
 
 obj-$(CONFIG_DRM_VKMS) += vkms.o
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
new file mode 100644
index 0000000000000000000000000000000000000000..76355174a6ca54b880218c2bd458c8339a3dabaa
--- /dev/null
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <kunit/visibility.h>
+#include <drm/drm_debugfs.h>
+
+#include "vkms_config.h"
+#include "vkms_drv.h"
+
+struct vkms_config *vkms_config_create(void)
+{
+	struct vkms_config *config;
+
+	config = kzalloc(sizeof(*config), GFP_KERNEL);
+	if (!config)
+		return ERR_PTR(-ENOMEM);
+
+	return config;
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_create);
+
+void vkms_config_destroy(struct vkms_config *config)
+{
+	kfree(config);
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy);
+
+static int vkms_config_show(struct seq_file *m, void *data)
+{
+	struct drm_debugfs_entry *entry = m->private;
+	struct drm_device *dev = entry->dev;
+	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
+
+	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
+	seq_printf(m, "cursor=%d\n", vkmsdev->config->cursor);
+	seq_printf(m, "overlay=%d\n", vkmsdev->config->overlay);
+
+	return 0;
+}
+
+static const struct drm_debugfs_info vkms_config_debugfs_list[] = {
+	{ "vkms_config", vkms_config_show, 0 },
+};
+
+void vkms_config_register_debugfs(struct vkms_device *vkms_device)
+{
+	drm_debugfs_add_files(&vkms_device->drm, vkms_config_debugfs_list,
+			      ARRAY_SIZE(vkms_config_debugfs_list));
+}
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..b284831738743f6d7c452be03f917a7d3975d173
--- /dev/null
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef _VKMS_CONFIG_H
+#define _VKMS_CONFIG_H
+
+#include <linux/types.h>
+#include "vkms_drv.h"
+
+/**
+ * struct vkms_config - General configuration for VKMS driver
+ *
+ * @writeback: If true, a writeback buffer can be attached to the CRTC
+ * @cursor: If true, a cursor plane is created in the VKMS device
+ * @overlay: If true, NUM_OVERLAY_PLANES will be created for the VKMS device
+ * @dev: Used to store the current vkms device. Only set when the device is instancied.
+ */
+struct vkms_config {
+	bool writeback;
+	bool cursor;
+	bool overlay;
+	struct vkms_device *dev;
+};
+
+/**
+ * vkms_config_register_debugfs() - Register the debugfs file to display current configuration
+ */
+void vkms_config_register_debugfs(struct vkms_device *vkms_device);
+
+struct vkms_config *vkms_config_create(void);
+void vkms_config_destroy(struct vkms_config *config);
+
+#endif //_VKMS_CONFIG_H
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 7c142bfc3bd9de9556621db3e7f570dc0a4fab3a..6b0e5fd0e26f04359b0d10252496c52b15d83896 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -28,6 +28,7 @@
 #include <drm/drm_vblank.h>
 
 #include "vkms_drv.h"
+#include "vkms_config.h"
 
 #include <drm/drm_print.h>
 #include <drm/drm_debugfs.h>
@@ -81,22 +82,6 @@ static void vkms_atomic_commit_tail(struct drm_atomic_state *old_state)
 	drm_atomic_helper_cleanup_planes(dev, old_state);
 }
 
-static int vkms_config_show(struct seq_file *m, void *data)
-{
-	struct drm_debugfs_entry *entry = m->private;
-	struct drm_device *dev = entry->dev;
-	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
-
-	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
-	seq_printf(m, "cursor=%d\n", vkmsdev->config->cursor);
-	seq_printf(m, "overlay=%d\n", vkmsdev->config->overlay);
-
-	return 0;
-}
-
-static const struct drm_debugfs_info vkms_config_debugfs_list[] = {
-	{ "vkms_config", vkms_config_show, 0 },
-};
 
 static const struct drm_driver vkms_driver = {
 	.driver_features	= DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
@@ -208,8 +193,7 @@ static int vkms_create(struct vkms_config *config)
 	if (ret)
 		goto out_devres;
 
-	drm_debugfs_add_files(&vkms_device->drm, vkms_config_debugfs_list,
-			      ARRAY_SIZE(vkms_config_debugfs_list));
+	vkms_config_register_debugfs(vkms_device);
 
 	ret = drm_dev_register(&vkms_device->drm, 0);
 	if (ret)
@@ -229,21 +213,18 @@ static int vkms_create(struct vkms_config *config)
 static int __init vkms_init(void)
 {
 	int ret;
-	struct vkms_config *config;
-
-	config = kmalloc(sizeof(*config), GFP_KERNEL);
-	if (!config)
-		return -ENOMEM;
 
-	default_config = config;
+	default_config = vkms_config_create();
+	if (IS_ERR(default_config))
+		return PTR_ERR(default_config);
 
-	config->cursor = enable_cursor;
-	config->writeback = enable_writeback;
-	config->overlay = enable_overlay;
+	default_config->cursor = enable_cursor;
+	default_config->writeback = enable_writeback;
+	default_config->overlay = enable_overlay;
 
-	ret = vkms_create(config);
+	ret = vkms_create(default_config);
 	if (ret)
-		kfree(config);
+		vkms_config_destroy(default_config);
 
 	return ret;
 }
@@ -272,7 +253,7 @@ static void __exit vkms_exit(void)
 	if (default_config->dev)
 		vkms_destroy(default_config);
 
-	kfree(default_config);
+	vkms_config_destroy(default_config);
 }
 
 module_init(vkms_init);
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index abbb652be2b5389f96cec78837117ceb9acef656..af7081c940d6c074dc01cf8180556a3d902e386d 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -189,20 +189,7 @@ struct vkms_output {
 	spinlock_t composer_lock;
 };
 
-/**
- * struct vkms_config - General configuration for VKMS driver
- *
- * @writeback: If true, a writeback buffer can be attached to the CRTC
- * @cursor: If true, a cursor plane is created in the VKMS device
- * @overlay: If true, NUM_OVERLAY_PLANES will be created for the VKMS device
- * @dev: Used to store the current VKMS device. Only set when the device is instantiated.
- */
-struct vkms_config {
-	bool writeback;
-	bool cursor;
-	bool overlay;
-	struct vkms_device *dev;
-};
+struct vkms_config;
 
 /**
  * struct vkms_device - Description of a VKMS device
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 22f0d678af3ac8177e43c4ea730af3f2109de5f3..78e389d832c16e4dbaccda34fbf3215f34adeadf 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 
 #include "vkms_drv.h"
+#include "vkms_config.h"
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_managed.h>

-- 
2.47.1


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

* [PATCH v3 02/16] drm/vkms: Add a validation function for vkms configuration
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 01/16] drm/vkms: Extract vkms_config header Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 03/16] drm/vkms: Move default_config creation to its own function Louis Chauvet
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

As the configuration will be used by userspace, add a validator to avoid
creating a broken DRM device

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c |  6 ++++++
 drivers/gpu/drm/vkms/vkms_config.h | 13 +++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 76355174a6ca54b880218c2bd458c8339a3dabaa..8d5c1429e6e196ef46c95c6ae73330bc4be2be39 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -24,6 +24,12 @@ void vkms_config_destroy(struct vkms_config *config)
 }
 EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy);
 
+bool vkms_config_is_valid(struct vkms_config *config)
+{
+	return true;
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_is_valid);
+
 static int vkms_config_show(struct seq_file *m, void *data)
 {
 	struct drm_debugfs_entry *entry = m->private;
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index b284831738743f6d7c452be03f917a7d3975d173..df571dd67352ca90fb47bd937fb9f11ceb95fcb2 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -29,4 +29,17 @@ void vkms_config_register_debugfs(struct vkms_device *vkms_device);
 struct vkms_config *vkms_config_create(void);
 void vkms_config_destroy(struct vkms_config *config);
 
+/**
+ * vkms_config_is_valid() - Validate a configuration
+ *
+ * Check if all the property defined in the configuration are valids. This will return false for
+ * example if:
+ * - no or many primary planes are present;
+ * - the default rotation of a plane is not in its supported rotation;
+ * - a CRTC don't have any encoder...
+ *
+ * @vkms_config: Configuration to validate
+ */
+bool vkms_config_is_valid(struct vkms_config *vkms_config);
+
 #endif //_VKMS_CONFIG_H

-- 
2.47.1


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

* [PATCH v3 03/16] drm/vkms: Move default_config creation to its own function
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 01/16] drm/vkms: Extract vkms_config header Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 02/16] drm/vkms: Add a validation function for vkms configuration Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 04/16] drm/vkms: Introduce config for plane Louis Chauvet
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet, José Expósito

Extract the initialization of the default configuration to a function.
Refactor, no functional changes.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
[Changes: Cherry pick and solve conflicts]
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 15 +++++++++++++++
 drivers/gpu/drm/vkms/vkms_config.h |  9 +++++++++
 drivers/gpu/drm/vkms/vkms_drv.c    |  7 +------
 3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 8d5c1429e6e196ef46c95c6ae73330bc4be2be39..e7c7f46303e8ce4c9de68878668b855ac0fc5d2e 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -18,6 +18,21 @@ struct vkms_config *vkms_config_create(void)
 }
 EXPORT_SYMBOL_IF_KUNIT(vkms_config_create);
 
+struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable_overlay,
+					      bool enable_cursor)
+{
+	struct vkms_config *vkms_config = vkms_config_create();
+
+	if (IS_ERR(vkms_config))
+		return vkms_config;
+
+	vkms_config->writeback = enable_writeback;
+	vkms_config->overlay = enable_overlay;
+	vkms_config->cursor = enable_cursor;
+
+	return vkms_config;
+}
+
 void vkms_config_destroy(struct vkms_config *config)
 {
 	kfree(config);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index df571dd67352ca90fb47bd937fb9f11ceb95fcb2..2afb795586c6924a46dd4ba777bf22a4f51cddda 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -42,4 +42,13 @@ void vkms_config_destroy(struct vkms_config *config);
  */
 bool vkms_config_is_valid(struct vkms_config *vkms_config);
 
+/**
+ * vkms_config_alloc_default() - Allocate the configuration for the default device
+ * @enable_writeback: Enable the writeback connector for this configuration
+ * @enable_overlay: Create some overlay planes
+ * @enable_cursor:  Create a cursor plane
+ */
+struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable_overlay,
+					      bool enable_cursor);
+
 #endif //_VKMS_CONFIG_H
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 6b0e5fd0e26f04359b0d10252496c52b15d83896..4440549c3084a341d03ec66119ba7998012bd662 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -213,15 +213,10 @@ static int vkms_create(struct vkms_config *config)
 static int __init vkms_init(void)
 {
 	int ret;
-
-	default_config = vkms_config_create();
+	default_config = vkms_config_alloc_default(enable_writeback, enable_overlay, enable_cursor);
 	if (IS_ERR(default_config))
 		return PTR_ERR(default_config);
 
-	default_config->cursor = enable_cursor;
-	default_config->writeback = enable_writeback;
-	default_config->overlay = enable_overlay;
-
 	ret = vkms_create(default_config);
 	if (ret)
 		vkms_config_destroy(default_config);

-- 
2.47.1


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

* [PATCH v3 04/16] drm/vkms: Introduce config for plane
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (2 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 03/16] drm/vkms: Move default_config creation to its own function Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 05/16] drm/vkms: Introduce config for plane name Louis Chauvet
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

The current vkms driver only allows the usage of one primary, eight
overlays and one cursor plane. This new configuration structure aims to
make the configuration more flexible.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 92 ++++++++++++++++++++++++++++++++++++--
 drivers/gpu/drm/vkms/vkms_config.h | 43 +++++++++++++++++-
 drivers/gpu/drm/vkms/vkms_drv.h    |  3 +-
 drivers/gpu/drm/vkms/vkms_output.c | 37 +++++----------
 drivers/gpu/drm/vkms/vkms_plane.c  |  5 ++-
 5 files changed, 145 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index e7c7f46303e8ce4c9de68878668b855ac0fc5d2e..495056ce988ab32738701f00c94c709457aefbd3 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -14,6 +14,8 @@ struct vkms_config *vkms_config_create(void)
 	if (!config)
 		return ERR_PTR(-ENOMEM);
 
+	INIT_LIST_HEAD(&config->planes);
+
 	return config;
 }
 EXPORT_SYMBOL_IF_KUNIT(vkms_config_create);
@@ -21,26 +23,105 @@ EXPORT_SYMBOL_IF_KUNIT(vkms_config_create);
 struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable_overlay,
 					      bool enable_cursor)
 {
+	struct vkms_config_plane *plane;
 	struct vkms_config *vkms_config = vkms_config_create();
 
 	if (IS_ERR(vkms_config))
 		return vkms_config;
 
 	vkms_config->writeback = enable_writeback;
-	vkms_config->overlay = enable_overlay;
-	vkms_config->cursor = enable_cursor;
 
+	plane = vkms_config_create_plane(vkms_config);
+	if (!plane)
+		goto err_alloc;
+
+	plane->type = DRM_PLANE_TYPE_PRIMARY;
+
+	if (enable_overlay) {
+		for (int i = 0; i < NUM_OVERLAY_PLANES; i++) {
+			plane = vkms_config_create_plane(vkms_config);
+			if (!plane)
+				goto err_alloc;
+			plane->type = DRM_PLANE_TYPE_OVERLAY;
+		}
+	}
+	if (enable_cursor) {
+		plane = vkms_config_create_plane(vkms_config);
+		if (!plane)
+			goto err_alloc;
+		plane->type = DRM_PLANE_TYPE_CURSOR;
+	}
 	return vkms_config;
+
+err_alloc:
+	vkms_config_destroy(vkms_config);
+	return ERR_PTR(-ENOMEM);
+}
+
+struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_config)
+{
+	if (!vkms_config)
+		return NULL;
+
+	struct vkms_config_plane *vkms_config_overlay = kzalloc(sizeof(*vkms_config_overlay),
+								GFP_KERNEL);
+
+	if (!vkms_config_overlay)
+		return NULL;
+
+	vkms_config_overlay->type = DRM_PLANE_TYPE_OVERLAY;
+
+	list_add(&vkms_config_overlay->link, &vkms_config->planes);
+
+	return vkms_config_overlay;
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_plane);
+
+void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_overlay)
+{
+	if (!vkms_config_overlay)
+		return;
+	list_del(&vkms_config_overlay->link);
+	kfree(vkms_config_overlay);
 }
 
 void vkms_config_destroy(struct vkms_config *config)
 {
+	struct vkms_config_plane *vkms_config_plane, *tmp_plane;
+
+	list_for_each_entry_safe(vkms_config_plane, tmp_plane, &config->planes, link) {
+		vkms_config_delete_plane(vkms_config_plane);
+	}
+
 	kfree(config);
 }
 EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy);
 
 bool vkms_config_is_valid(struct vkms_config *config)
 {
+	struct vkms_config_plane *config_plane;
+
+	bool has_cursor = false;
+	bool has_primary = false;
+
+	list_for_each_entry(config_plane, &config->planes, link) {
+		if (config_plane->type == DRM_PLANE_TYPE_PRIMARY) {
+			// Multiple primary planes for only one CRTC
+			if (has_primary)
+				return false;
+			has_primary = true;
+		}
+		if (config_plane->type == DRM_PLANE_TYPE_CURSOR) {
+			// Multiple cursor planes for only one CRTC
+			if (has_cursor)
+				return false;
+			has_cursor = true;
+		}
+	}
+
+	if (!has_primary)
+		return false;
+
 	return true;
 }
 EXPORT_SYMBOL_IF_KUNIT(vkms_config_is_valid);
@@ -50,10 +131,13 @@ static int vkms_config_show(struct seq_file *m, void *data)
 	struct drm_debugfs_entry *entry = m->private;
 	struct drm_device *dev = entry->dev;
 	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
+	struct vkms_config_plane *config_plane;
 
 	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
-	seq_printf(m, "cursor=%d\n", vkmsdev->config->cursor);
-	seq_printf(m, "overlay=%d\n", vkmsdev->config->overlay);
+	list_for_each_entry(config_plane, &vkmsdev->config->planes, link) {
+		seq_puts(m, "plane:\n");
+		seq_printf(m, "\ttype: %d\n", config_plane->type);
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 2afb795586c6924a46dd4ba777bf22a4f51cddda..ac99f1df6d9a17bd7040a1e7a6acce14cd8fd9d0 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -10,8 +10,8 @@
  * struct vkms_config - General configuration for VKMS driver
  *
  * @writeback: If true, a writeback buffer can be attached to the CRTC
- * @cursor: If true, a cursor plane is created in the VKMS device
- * @overlay: If true, NUM_OVERLAY_PLANES will be created for the VKMS device
+ * @planes: List of planes configured for this device. They are created by the function
+ *          vkms_config_create_plane().
  * @dev: Used to store the current vkms device. Only set when the device is instancied.
  */
 struct vkms_config {
@@ -19,6 +19,27 @@ struct vkms_config {
 	bool cursor;
 	bool overlay;
 	struct vkms_device *dev;
+
+	struct list_head planes;
+};
+
+/**
+ * struct vkms_config_plane
+ *
+ * @link: Link to the others planes
+ * @type: Type of the plane. The creator of configuration needs to ensures that at least one
+ *        plane is primary.
+ * @plane: Internal usage. This pointer should never be considered as valid. It can be used to
+ *         store a temporary reference to a vkms plane during device creation. This pointer is
+ *         not managed by the configuration and must be managed by other means.
+ */
+struct vkms_config_plane {
+	struct list_head link;
+
+	enum drm_plane_type type;
+
+	/* Internal usage */
+	struct vkms_plane *plane;
 };
 
 /**
@@ -42,6 +63,24 @@ void vkms_config_destroy(struct vkms_config *config);
  */
 bool vkms_config_is_valid(struct vkms_config *vkms_config);
 
+/**
+ * vkms_config_create_plane() - Create a plane configuration
+ *
+ * This will allocate and add a new plane to @vkms_config. This plane will have by default the
+ * maximum supported values.
+ * @vkms_config: Configuration where to insert new plane
+ */
+struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_config);
+
+/**
+ * vkms_config_delete_plane() - Remove a plane configuration and frees its memory
+ *
+ * This will delete a plane configuration from the parent configuration. This will NOT
+ * cleanup and frees the vkms_plane that can be stored in @vkms_config_plane.
+ * @vkms_config_plane: Plane configuration to cleanup
+ */
+void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_plane);
+
 /**
  * vkms_config_alloc_default() - Allocate the configuration for the default device
  * @enable_writeback: Enable the writeback connector for this configuration
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index af7081c940d6c074dc01cf8180556a3d902e386d..1b5add9536f503fe224425b924c14a5217bb09b1 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -190,6 +190,7 @@ struct vkms_output {
 };
 
 struct vkms_config;
+struct vkms_config_plane;
 
 /**
  * struct vkms_device - Description of a VKMS device
@@ -246,7 +247,7 @@ int vkms_output_init(struct vkms_device *vkmsdev);
  * @type: type of plane to initialize
  */
 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
-				   enum drm_plane_type type);
+				   struct vkms_config_plane *config);
 
 /* CRC Support */
 const char *const *vkms_get_crc_sources(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 78e389d832c16e4dbaccda34fbf3215f34adeadf..cf385f676ef7f45633b4ed69a8047c87fad95dbd 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -31,30 +31,14 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
 
 int vkms_output_init(struct vkms_device *vkmsdev)
 {
+	struct vkms_config_plane *config_plane;
 	struct drm_device *dev = &vkmsdev->drm;
 	struct drm_connector *connector;
 	struct drm_encoder *encoder;
 	struct vkms_output *output;
-	struct vkms_plane *primary, *overlay, *cursor = NULL;
+	struct vkms_plane *primary, *cursor = NULL;
 	int ret;
 	int writeback;
-	unsigned int n;
-
-	/*
-	 * Initialize used plane. One primary plane is required to perform the composition.
-	 *
-	 * The overlay and cursor planes are not mandatory, but can be used to perform complex
-	 * composition.
-	 */
-	primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY);
-	if (IS_ERR(primary))
-		return PTR_ERR(primary);
-
-	if (vkmsdev->config->cursor) {
-		cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR);
-		if (IS_ERR(cursor))
-			return PTR_ERR(cursor);
-	}
 
 	output = vkms_crtc_init(dev, &primary->base,
 				cursor ? &cursor->base : NULL);
@@ -63,15 +47,16 @@ int vkms_output_init(struct vkms_device *vkmsdev)
 		return PTR_ERR(output);
 	}
 
-	if (vkmsdev->config->overlay) {
-		for (n = 0; n < NUM_OVERLAY_PLANES; n++) {
-			overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY);
-			if (IS_ERR(overlay)) {
-				DRM_DEV_ERROR(dev->dev, "Failed to init vkms plane\n");
-				return PTR_ERR(overlay);
-			}
-			overlay->base.possible_crtcs = drm_crtc_mask(&output->crtc);
+	list_for_each_entry(config_plane, &vkmsdev->config->planes, link) {
+		config_plane->plane = vkms_plane_init(vkmsdev, config_plane);
+		if (IS_ERR(config_plane->plane)) {
+			ret = PTR_ERR(config_plane->plane);
+			return ret;
 		}
+		if (config_plane->type == DRM_PLANE_TYPE_PRIMARY)
+			primary = config_plane->plane;
+		else if (config_plane->type == DRM_PLANE_TYPE_CURSOR)
+			cursor = config_plane->plane;
 	}
 
 	connector = drmm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index e2fce471870f1899f2ccb66b339ce8c4332cc287..4663002c9c54030ff6243631a2a1cff26415e7a3 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -11,6 +11,7 @@
 
 #include "vkms_drv.h"
 #include "vkms_formats.h"
+#include "vkms_config.h"
 
 static const u32 vkms_formats[] = {
 	DRM_FORMAT_ARGB8888,
@@ -187,7 +188,7 @@ static const struct drm_plane_helper_funcs vkms_plane_helper_funcs = {
 };
 
 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
-				   enum drm_plane_type type)
+				   struct vkms_config_plane *config)
 {
 	struct drm_device *dev = &vkmsdev->drm;
 	struct vkms_plane *plane;
@@ -195,7 +196,7 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
 	plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 0,
 					   &vkms_plane_funcs,
 					   vkms_formats, ARRAY_SIZE(vkms_formats),
-					   NULL, type, NULL);
+					   NULL, config->type, NULL);
 	if (IS_ERR(plane))
 		return plane;
 

-- 
2.47.1


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

* [PATCH v3 05/16] drm/vkms: Introduce config for plane name
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (3 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 04/16] drm/vkms: Introduce config for plane Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 06/16] drm/vkms: Introduce config for plane rotation Louis Chauvet
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

As a plane will be a folder in ConfigFS, add name configuration for plane
so it will reflect the folder name.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 14 ++++++++++++++
 drivers/gpu/drm/vkms/vkms_config.h |  2 ++
 drivers/gpu/drm/vkms/vkms_plane.c  |  2 +-
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 495056ce988ab32738701f00c94c709457aefbd3..0caa6bfccb5e409efa37ea48a52299e0dc132728 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -36,6 +36,10 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
 		goto err_alloc;
 
 	plane->type = DRM_PLANE_TYPE_PRIMARY;
+	plane->name = kzalloc(sizeof("primary"), GFP_KERNEL);
+	if (!plane->name)
+		goto err_alloc;
+	sprintf(plane->name, "primary");
 
 	if (enable_overlay) {
 		for (int i = 0; i < NUM_OVERLAY_PLANES; i++) {
@@ -43,6 +47,10 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
 			if (!plane)
 				goto err_alloc;
 			plane->type = DRM_PLANE_TYPE_OVERLAY;
+			plane->name = kzalloc(10, GFP_KERNEL);
+			if (!plane->name)
+				goto err_alloc;
+			snprintf(plane->name, 10, "plane-%d", i);
 		}
 	}
 	if (enable_cursor) {
@@ -50,6 +58,10 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
 		if (!plane)
 			goto err_alloc;
 		plane->type = DRM_PLANE_TYPE_CURSOR;
+		plane->name = kzalloc(sizeof("cursor"), GFP_KERNEL);
+		if (!plane->name)
+			goto err_alloc;
+		sprintf(plane->name, "cursor");
 	}
 	return vkms_config;
 
@@ -82,6 +94,7 @@ void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_overlay)
 	if (!vkms_config_overlay)
 		return;
 	list_del(&vkms_config_overlay->link);
+	kfree(vkms_config_overlay->name);
 	kfree(vkms_config_overlay);
 }
 
@@ -136,6 +149,7 @@ static int vkms_config_show(struct seq_file *m, void *data)
 	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
 	list_for_each_entry(config_plane, &vkmsdev->config->planes, link) {
 		seq_puts(m, "plane:\n");
+		seq_printf(m, "\tname: %s\n", config_plane->name);
 		seq_printf(m, "\ttype: %d\n", config_plane->type);
 	}
 
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index ac99f1df6d9a17bd7040a1e7a6acce14cd8fd9d0..3e70bce8d4f7b06f44ec79b3a3d8e6897f9a44c7 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -27,6 +27,7 @@ struct vkms_config {
  * struct vkms_config_plane
  *
  * @link: Link to the others planes
+ * @name: Name of the plane
  * @type: Type of the plane. The creator of configuration needs to ensures that at least one
  *        plane is primary.
  * @plane: Internal usage. This pointer should never be considered as valid. It can be used to
@@ -36,6 +37,7 @@ struct vkms_config {
 struct vkms_config_plane {
 	struct list_head link;
 
+	char *name;
 	enum drm_plane_type type;
 
 	/* Internal usage */
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index 4663002c9c54030ff6243631a2a1cff26415e7a3..b3a9a42476ef340986c8961f076236d76a7c73e3 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -196,7 +196,7 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
 	plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 0,
 					   &vkms_plane_funcs,
 					   vkms_formats, ARRAY_SIZE(vkms_formats),
-					   NULL, config->type, NULL);
+					   NULL, config->type, config->name);
 	if (IS_ERR(plane))
 		return plane;
 

-- 
2.47.1


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

* [PATCH v3 06/16] drm/vkms: Introduce config for plane rotation
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (4 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 05/16] drm/vkms: Introduce config for plane name Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 07/16] drm/vkms: Introduce config for CRTCs and encoders Louis Chauvet
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

VKMS driver supports all the rotation on planes, but for testing it can be
useful to only advertise few of them. This new configuration interface
will allow configuring the rotation per planes.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 9 +++++++++
 drivers/gpu/drm/vkms/vkms_config.h | 4 ++++
 drivers/gpu/drm/vkms/vkms_plane.c  | 5 +++--
 3 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 0caa6bfccb5e409efa37ea48a52299e0dc132728..c7a39cde8cfbcd0ff4f5ae137cfb709b7a2240e2 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -82,6 +82,8 @@ struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_conf
 		return NULL;
 
 	vkms_config_overlay->type = DRM_PLANE_TYPE_OVERLAY;
+	vkms_config_overlay->supported_rotations = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
+	vkms_config_overlay->default_rotation = DRM_MODE_ROTATE_0;
 
 	list_add(&vkms_config_overlay->link, &vkms_config->planes);
 
@@ -118,6 +120,11 @@ bool vkms_config_is_valid(struct vkms_config *config)
 	bool has_primary = false;
 
 	list_for_each_entry(config_plane, &config->planes, link) {
+		// Default rotation not in supported rotations
+		if ((config_plane->default_rotation & config_plane->supported_rotations) !=
+		    config_plane->default_rotation)
+			return false;
+
 		if (config_plane->type == DRM_PLANE_TYPE_PRIMARY) {
 			// Multiple primary planes for only one CRTC
 			if (has_primary)
@@ -151,6 +158,8 @@ static int vkms_config_show(struct seq_file *m, void *data)
 		seq_puts(m, "plane:\n");
 		seq_printf(m, "\tname: %s\n", config_plane->name);
 		seq_printf(m, "\ttype: %d\n", config_plane->type);
+		seq_printf(m, "\tsupported rotations: 0x%x\n", config_plane->supported_rotations);
+		seq_printf(m, "\tdefault rotation: 0x%x\n", config_plane->default_rotation);
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 3e70bce8d4f7b06f44ec79b3a3d8e6897f9a44c7..fd5e0df11647f145d53e71a1b6a244951af3ec0d 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -30,6 +30,8 @@ struct vkms_config {
  * @name: Name of the plane
  * @type: Type of the plane. The creator of configuration needs to ensures that at least one
  *        plane is primary.
+ * @default_rotation: Default rotation that should be used by this plane
+ * @supported_rotation: Rotation that this plane will support
  * @plane: Internal usage. This pointer should never be considered as valid. It can be used to
  *         store a temporary reference to a vkms plane during device creation. This pointer is
  *         not managed by the configuration and must be managed by other means.
@@ -39,6 +41,8 @@ struct vkms_config_plane {
 
 	char *name;
 	enum drm_plane_type type;
+	unsigned int default_rotation;
+	unsigned int supported_rotations;
 
 	/* Internal usage */
 	struct vkms_plane *plane;
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index b3a9a42476ef340986c8961f076236d76a7c73e3..c23ac8687dedaa956cfd6622321f1026521ff13f 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -202,8 +202,9 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
 
 	drm_plane_helper_add(&plane->base, &vkms_plane_helper_funcs);
 
-	drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0,
-					   DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK);
+	drm_plane_create_rotation_property(&plane->base,
+					   config->default_rotation,
+					   config->supported_rotations);
 
 	return plane;
 }

-- 
2.47.1


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

* [PATCH v3 07/16] drm/vkms: Introduce config for CRTCs and encoders
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (5 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 06/16] drm/vkms: Introduce config for plane rotation Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 08/16] drm/vkms: Introduce config for encoder name Louis Chauvet
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

The current VKMS driver can only uses one CRTC and one encoder. This patch
introduce in the same time CRTC and encoders as they are tighly linked.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 269 +++++++++++++++++++++++++++++++++----
 drivers/gpu/drm/vkms/vkms_config.h | 104 +++++++++++++-
 drivers/gpu/drm/vkms/vkms_crtc.c   |   8 +-
 drivers/gpu/drm/vkms/vkms_drv.h    |   7 +-
 drivers/gpu/drm/vkms/vkms_output.c |  88 ++++++------
 5 files changed, 401 insertions(+), 75 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index c7a39cde8cfbcd0ff4f5ae137cfb709b7a2240e2..314d252aa9b6ed1772c8ef597bd9c6b08145723e 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -15,6 +15,8 @@ struct vkms_config *vkms_config_create(void)
 		return ERR_PTR(-ENOMEM);
 
 	INIT_LIST_HEAD(&config->planes);
+	INIT_LIST_HEAD(&config->crtcs);
+	INIT_LIST_HEAD(&config->encoders);
 
 	return config;
 }
@@ -24,12 +26,24 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
 					      bool enable_cursor)
 {
 	struct vkms_config_plane *plane;
+	struct vkms_config_encoder *encoder;
+	struct vkms_config_crtc *crtc;
 	struct vkms_config *vkms_config = vkms_config_create();
 
 	if (IS_ERR(vkms_config))
 		return vkms_config;
 
-	vkms_config->writeback = enable_writeback;
+	crtc = vkms_config_create_crtc(vkms_config);
+	if (!crtc)
+		goto err_alloc;
+	crtc->writeback = enable_writeback;
+
+	encoder = vkms_config_create_encoder(vkms_config);
+	if (!encoder)
+		goto err_alloc;
+
+	if (vkms_config_encoder_attach_crtc(encoder, crtc))
+		goto err_alloc;
 
 	plane = vkms_config_create_plane(vkms_config);
 	if (!plane)
@@ -41,6 +55,9 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
 		goto err_alloc;
 	sprintf(plane->name, "primary");
 
+	if (vkms_config_plane_attach_crtc(plane, crtc))
+		goto err_alloc;
+
 	if (enable_overlay) {
 		for (int i = 0; i < NUM_OVERLAY_PLANES; i++) {
 			plane = vkms_config_create_plane(vkms_config);
@@ -51,6 +68,9 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
 			if (!plane->name)
 				goto err_alloc;
 			snprintf(plane->name, 10, "plane-%d", i);
+
+			if (vkms_config_plane_attach_crtc(plane, crtc))
+				goto err_alloc;
 		}
 	}
 	if (enable_cursor) {
@@ -62,6 +82,9 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
 		if (!plane->name)
 			goto err_alloc;
 		sprintf(plane->name, "cursor");
+
+		if (vkms_config_plane_attach_crtc(plane, crtc))
+			goto err_alloc;
 	}
 	return vkms_config;
 
@@ -84,6 +107,7 @@ struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_conf
 	vkms_config_overlay->type = DRM_PLANE_TYPE_OVERLAY;
 	vkms_config_overlay->supported_rotations = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
 	vkms_config_overlay->default_rotation = DRM_MODE_ROTATE_0;
+	xa_init_flags(&vkms_config_overlay->possible_crtcs, XA_FLAGS_ALLOC);
 
 	list_add(&vkms_config_overlay->link, &vkms_config->planes);
 
@@ -91,33 +115,195 @@ struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_conf
 }
 EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_plane);
 
-void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_overlay)
+struct vkms_config_crtc *vkms_config_create_crtc(struct vkms_config *vkms_config)
 {
-	if (!vkms_config_overlay)
+	if (!vkms_config)
+		return NULL;
+
+	struct vkms_config_crtc *vkms_config_crtc = kzalloc(sizeof(*vkms_config_crtc),
+							    GFP_KERNEL);
+
+	if (!vkms_config_crtc)
+		return NULL;
+
+	list_add(&vkms_config_crtc->link, &vkms_config->crtcs);
+	xa_init_flags(&vkms_config_crtc->possible_planes, XA_FLAGS_ALLOC);
+	xa_init_flags(&vkms_config_crtc->possible_encoders, XA_FLAGS_ALLOC);
+
+	return vkms_config_crtc;
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_crtc);
+
+struct vkms_config_encoder *vkms_config_create_encoder(struct vkms_config *vkms_config)
+{
+	if (!vkms_config)
+		return NULL;
+
+	struct vkms_config_encoder *vkms_config_encoder = kzalloc(sizeof(*vkms_config_encoder),
+								  GFP_KERNEL);
+
+	if (!vkms_config_encoder)
+		return NULL;
+
+	list_add(&vkms_config_encoder->link, &vkms_config->encoders);
+	xa_init_flags(&vkms_config_encoder->possible_crtcs, XA_FLAGS_ALLOC);
+
+	return vkms_config_encoder;
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_encoder);
+
+void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_plane,
+			      struct vkms_config *vkms_config)
+{
+	struct vkms_config_crtc *crtc_config;
+	struct vkms_config_plane *plane;
+
+	if (!vkms_config_plane)
+		return;
+	list_del(&vkms_config_plane->link);
+	xa_destroy(&vkms_config_plane->possible_crtcs);
+
+	list_for_each_entry(crtc_config, &vkms_config->crtcs, link) {
+		unsigned long idx = 0;
+
+		xa_for_each(&crtc_config->possible_planes, idx, plane) {
+			if (plane == vkms_config_plane)
+				xa_erase(&crtc_config->possible_planes, idx);
+		}
+	}
+
+	kfree(vkms_config_plane->name);
+	kfree(vkms_config_plane);
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_delete_plane);
+
+void vkms_config_delete_crtc(struct vkms_config_crtc *vkms_config_crtc,
+			     struct vkms_config *vkms_config)
+{
+	struct vkms_config_crtc *crtc_config;
+	struct vkms_config_plane *plane_config;
+	struct vkms_config_encoder *encoder_config;
+
+	if (!vkms_config_crtc)
+		return;
+	list_del(&vkms_config_crtc->link);
+	xa_destroy(&vkms_config_crtc->possible_planes);
+	xa_destroy(&vkms_config_crtc->possible_encoders);
+
+	list_for_each_entry(plane_config, &vkms_config->planes, link) {
+		unsigned long idx = 0;
+
+		xa_for_each(&plane_config->possible_crtcs, idx, crtc_config) {
+			if (crtc_config == vkms_config_crtc)
+				xa_erase(&plane_config->possible_crtcs, idx);
+		}
+	}
+
+	list_for_each_entry(encoder_config, &vkms_config->encoders, link) {
+		unsigned long idx = 0;
+
+		xa_for_each(&encoder_config->possible_crtcs, idx, crtc_config) {
+			if (crtc_config == vkms_config_crtc)
+				xa_erase(&encoder_config->possible_crtcs, idx);
+		}
+	}
+
+	kfree(vkms_config_crtc);
+}
+
+void vkms_config_delete_encoder(struct vkms_config_encoder *vkms_config_encoder,
+				struct vkms_config *vkms_config)
+{
+	if (!vkms_config_encoder)
 		return;
-	list_del(&vkms_config_overlay->link);
-	kfree(vkms_config_overlay->name);
-	kfree(vkms_config_overlay);
+	list_del(&vkms_config_encoder->link);
+	xa_destroy(&vkms_config_encoder->possible_crtcs);
+
+	struct vkms_config_crtc *crtc_config;
+	struct vkms_config_encoder *encoder;
+
+	list_for_each_entry(crtc_config, &vkms_config->crtcs, link) {
+		unsigned long idx = 0;
+
+		xa_for_each(&crtc_config->possible_encoders, idx, encoder) {
+			if (encoder == vkms_config_encoder)
+				xa_erase(&crtc_config->possible_encoders, idx);
+		}
+	}
+
+	kfree(vkms_config_encoder);
 }
 
 void vkms_config_destroy(struct vkms_config *config)
 {
 	struct vkms_config_plane *vkms_config_plane, *tmp_plane;
+	struct vkms_config_encoder *vkms_config_encoder, *tmp_encoder;
+	struct vkms_config_crtc *vkms_config_crtc, *tmp_crtc;
 
 	list_for_each_entry_safe(vkms_config_plane, tmp_plane, &config->planes, link) {
-		vkms_config_delete_plane(vkms_config_plane);
+		vkms_config_delete_plane(vkms_config_plane, config);
+	}
+	list_for_each_entry_safe(vkms_config_encoder, tmp_encoder, &config->encoders, link) {
+		vkms_config_delete_encoder(vkms_config_encoder, config);
+	}
+	list_for_each_entry_safe(vkms_config_crtc, tmp_crtc, &config->crtcs, link) {
+		vkms_config_delete_crtc(vkms_config_crtc, config);
 	}
 
 	kfree(config);
 }
 EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy);
 
+int __must_check vkms_config_plane_attach_crtc(struct vkms_config_plane *vkms_config_plane,
+					       struct vkms_config_crtc *vkms_config_crtc)
+{
+	u32 crtc_idx, encoder_idx;
+	int ret;
+
+	ret = xa_alloc(&vkms_config_plane->possible_crtcs, &crtc_idx, vkms_config_crtc,
+		       xa_limit_32b, GFP_KERNEL);
+	if (ret)
+		return ret;
+
+	ret = xa_alloc(&vkms_config_crtc->possible_planes, &encoder_idx, vkms_config_plane,
+		       xa_limit_32b, GFP_KERNEL);
+	if (ret) {
+		xa_erase(&vkms_config_plane->possible_crtcs, crtc_idx);
+		return ret;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_plane_attach_crtc);
+
+int __must_check vkms_config_encoder_attach_crtc(struct vkms_config_encoder *vkms_config_encoder,
+						 struct vkms_config_crtc *vkms_config_crtc)
+{
+	u32 crtc_idx, encoder_idx;
+	int ret;
+
+	ret = xa_alloc(&vkms_config_encoder->possible_crtcs, &crtc_idx, vkms_config_crtc,
+		       xa_limit_32b, GFP_KERNEL);
+	if (ret)
+		return ret;
+
+	ret = xa_alloc(&vkms_config_crtc->possible_encoders, &encoder_idx, vkms_config_encoder,
+		       xa_limit_32b, GFP_KERNEL);
+	if (ret) {
+		xa_erase(&vkms_config_encoder->possible_crtcs, crtc_idx);
+		return ret;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_encoder_attach_crtc);
+
 bool vkms_config_is_valid(struct vkms_config *config)
 {
 	struct vkms_config_plane *config_plane;
 
-	bool has_cursor = false;
-	bool has_primary = false;
+	struct vkms_config_crtc *config_crtc;
+	struct vkms_config_encoder *config_encoder;
 
 	list_for_each_entry(config_plane, &config->planes, link) {
 		// Default rotation not in supported rotations
@@ -125,22 +311,47 @@ bool vkms_config_is_valid(struct vkms_config *config)
 		    config_plane->default_rotation)
 			return false;
 
-		if (config_plane->type == DRM_PLANE_TYPE_PRIMARY) {
-			// Multiple primary planes for only one CRTC
-			if (has_primary)
-				return false;
-			has_primary = true;
-		}
-		if (config_plane->type == DRM_PLANE_TYPE_CURSOR) {
-			// Multiple cursor planes for only one CRTC
-			if (has_cursor)
-				return false;
-			has_cursor = true;
-		}
+		// No CRTC linked to this plane
+		if (xa_empty(&config_plane->possible_crtcs))
+			return false;
+	}
+
+	list_for_each_entry(config_encoder, &config->encoders, link) {
+		// No CRTC linked to this encoder
+		if (xa_empty(&config_encoder->possible_crtcs))
+			return false;
 	}
 
-	if (!has_primary)
-		return false;
+	list_for_each_entry(config_crtc, &config->crtcs, link) {
+		bool has_primary = false;
+		bool has_cursor = false;
+		unsigned long idx = 0;
+
+		// No encoder attached to this CRTC
+		if (xa_empty(&config_crtc->possible_encoders))
+			return false;
+
+		xa_for_each(&config_crtc->possible_planes, idx, config_plane) {
+			if (config_plane->type == DRM_PLANE_TYPE_PRIMARY) {
+				// Multiple primary planes for only one CRTC
+				if (has_primary)
+					return false;
+
+				has_primary = true;
+			}
+			if (config_plane->type == DRM_PLANE_TYPE_CURSOR) {
+				// Multiple cursor planes for only one CRTC
+				if (has_cursor)
+					return false;
+
+				has_cursor = true;
+			}
+		}
+
+		// No primary plane for this CRTC
+		if (!has_primary)
+			return false;
+	}
 
 	return true;
 }
@@ -152,8 +363,9 @@ static int vkms_config_show(struct seq_file *m, void *data)
 	struct drm_device *dev = entry->dev;
 	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
 	struct vkms_config_plane *config_plane;
+	struct vkms_config_crtc *config_crtc;
+	struct vkms_config_encoder *config_encoder;
 
-	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
 	list_for_each_entry(config_plane, &vkmsdev->config->planes, link) {
 		seq_puts(m, "plane:\n");
 		seq_printf(m, "\tname: %s\n", config_plane->name);
@@ -162,6 +374,15 @@ static int vkms_config_show(struct seq_file *m, void *data)
 		seq_printf(m, "\tdefault rotation: 0x%x\n", config_plane->default_rotation);
 	}
 
+	list_for_each_entry(config_encoder, &vkmsdev->config->encoders, link) {
+		seq_puts(m, "encoder:\n");
+	}
+
+	list_for_each_entry(config_crtc, &vkmsdev->config->crtcs, link) {
+		seq_puts(m, "crtc:\n");
+		seq_printf(m, "\twriteback: %d\n", config_crtc->writeback);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index fd5e0df11647f145d53e71a1b6a244951af3ec0d..90ced83f5eb6dae5ccc14c37169606d833ba355a 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -9,18 +9,59 @@
 /**
  * struct vkms_config - General configuration for VKMS driver
  *
- * @writeback: If true, a writeback buffer can be attached to the CRTC
  * @planes: List of planes configured for this device. They are created by the function
  *          vkms_config_create_plane().
+ * @crtcs: List of crtcs configured for this device. They are created by the function
+ *         vkms_config_create_crtc().
+ * @encoders: List of encoders configured for this device. They are created by the function
+ *            vkms_config_create_encoder().
  * @dev: Used to store the current vkms device. Only set when the device is instancied.
  */
 struct vkms_config {
-	bool writeback;
-	bool cursor;
-	bool overlay;
 	struct vkms_device *dev;
 
 	struct list_head planes;
+	struct list_head crtcs;
+	struct list_head encoders;
+};
+
+/**
+ * struct vkms_config_crtc
+ *
+ * @link: Link to the others CRTCs
+ * @possible_planes: List of planes that can be used with this CRTC
+ * @possible_encoders: List of encoders that can be used with this CRTC
+ * @crtc: Internal usage. This pointer should never be considered as valid. It can be used to
+ *         store a temporary reference to a vkms crtc during device creation. This pointer is
+ *         not managed by the configuration and must be managed by other means.
+ */
+struct vkms_config_crtc {
+	struct list_head link;
+
+	bool writeback;
+	struct xarray possible_planes;
+	struct xarray possible_encoders;
+
+	/* Internal usage */
+	struct vkms_output *output;
+};
+
+/**
+ * struct vkms_config_encoder
+ *
+ * @link: Link to the others encoders
+ * @possible_crtcs: List of CRTC that can be used with this encoder
+ * @encoder: Internal usage. This pointer should never be considered as valid. It can be used to
+ *         store a temporary reference to a vkms encoder during device creation. This pointer is
+ *         not managed by the configuration and must be managed by other means.
+ */
+struct vkms_config_encoder {
+	struct list_head link;
+
+	struct xarray possible_crtcs;
+
+	/* Internal usage */
+	struct drm_encoder *encoder;
 };
 
 /**
@@ -32,6 +73,7 @@ struct vkms_config {
  *        plane is primary.
  * @default_rotation: Default rotation that should be used by this plane
  * @supported_rotation: Rotation that this plane will support
+ * @possible_crtcs: List of CRTC that can be used with this plane.
  * @plane: Internal usage. This pointer should never be considered as valid. It can be used to
  *         store a temporary reference to a vkms plane during device creation. This pointer is
  *         not managed by the configuration and must be managed by other means.
@@ -44,6 +86,7 @@ struct vkms_config_plane {
 	unsigned int default_rotation;
 	unsigned int supported_rotations;
 
+	struct xarray possible_crtcs;
 	/* Internal usage */
 	struct vkms_plane *plane;
 };
@@ -78,14 +121,63 @@ bool vkms_config_is_valid(struct vkms_config *vkms_config);
  */
 struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_config);
 
+/**
+ * vkms_config_create_crtc() - Create a crtc configuration
+ *
+ * This will allocate and add a new crtc configuration to @vkms_config.
+ * @vkms_config: Configuration where to insert new crtc configuration
+ */
+struct vkms_config_crtc *vkms_config_create_crtc(struct vkms_config *vkms_config);
+
+/**
+ * vkms_config_create_encoder() - Create an encoder configuration
+ *
+ * This will allocate and add a new encoder configuration to @vkms_config.
+ * @vkms_config: Configuration where to insert new encoder configuration
+ */
+struct vkms_config_encoder *vkms_config_create_encoder(struct vkms_config *vkms_config);
+
+int __must_check vkms_config_plane_attach_crtc(struct vkms_config_plane *vkms_config_plane,
+					       struct vkms_config_crtc *vkms_config_crtc);
+int __must_check vkms_config_encoder_attach_crtc(struct vkms_config_encoder *vkms_config_encoder,
+						 struct vkms_config_crtc *vkms_config_crtc);
+
 /**
  * vkms_config_delete_plane() - Remove a plane configuration and frees its memory
  *
  * This will delete a plane configuration from the parent configuration. This will NOT
- * cleanup and frees the vkms_plane that can be stored in @vkms_config_plane.
+ * cleanup and frees the vkms_plane that can be stored in @vkms_config_plane. It will also remove
+ * any reference to this plane in @vkms_config.
+ *
  * @vkms_config_plane: Plane configuration to cleanup
+ * @vkms_config: Parent configuration
+ */
+void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_plane,
+			      struct vkms_config *vkms_config);
+/**
+ * vkms_config_delete_crtc() - Remove a CRTC configuration and frees its memory
+ *
+ * This will delete a CRTC configuration from the parent configuration. This will NOT
+ * cleanup and frees the vkms_crtc that can be stored in @vkms_config_crtc. It will also remove
+ * any reference to this CRTC in @vkms_config.
+ *
+ * @vkms_config_crtc: Plane configuration to cleanup
+ * @vkms_config: Parent configuration
+ */
+void vkms_config_delete_crtc(struct vkms_config_crtc *vkms_config_crtc,
+			     struct vkms_config *vkms_config);
+/**
+ * vkms_config_delete_encoder() - Remove an encoder configuration and frees its memory
+ *
+ * This will delete an encoder configuration from the parent configuration. This will NOT
+ * cleanup and frees the vkms_encoder that can be stored in @vkms_config_encoder. It will also
+ * remove any reference to this CRTC in @vkms_config.
+ *
+ * @vkms_config_encoder: Plane configuration to cleanup
+ * @vkms_config: Parent configuration
  */
-void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_plane);
+void vkms_config_delete_encoder(struct vkms_config_encoder *vkms_config_encoder,
+				struct vkms_config *vkms_config);
 
 /**
  * vkms_config_alloc_default() - Allocate the configuration for the default device
diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index cf229aec71c3f03bb1306095e8dd44d63f80cd2a..f4da196fd7774ee1dcc5148e6420186f1384b3fa 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -9,6 +9,7 @@
 #include <drm/drm_vblank.h>
 
 #include "vkms_drv.h"
+#include "vkms_config.h"
 
 static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
 {
@@ -269,9 +270,12 @@ static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = {
 	.atomic_disable	= vkms_crtc_atomic_disable,
 };
 
-struct vkms_output *vkms_crtc_init(struct drm_device *dev, struct drm_plane *primary,
-				   struct drm_plane *cursor)
+struct vkms_output *vkms_crtc_init(struct vkms_device *vkms_device,
+				   struct drm_plane *primary,
+				   struct drm_plane *cursor,
+				   struct vkms_config_crtc *config)
 {
+	struct drm_device *dev = &vkms_device->drm;
 	struct vkms_output *vkms_out;
 	struct drm_crtc *crtc;
 	int ret;
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 1b5add9536f503fe224425b924c14a5217bb09b1..3a211cdb41bd1003366d9eaa1425e122d885e4a4 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -191,6 +191,8 @@ struct vkms_output {
 
 struct vkms_config;
 struct vkms_config_plane;
+struct vkms_config_crtc;
+struct vkms_config_encoder;
 
 /**
  * struct vkms_device - Description of a VKMS device
@@ -229,9 +231,10 @@ struct vkms_device {
  * @primary: primary plane to attach to the CRTC
  * @cursor: plane to attach to the CRTC
  */
-struct vkms_output *vkms_crtc_init(struct drm_device *dev,
+struct vkms_output *vkms_crtc_init(struct vkms_device *vkms_device,
 				   struct drm_plane *primary,
-				   struct drm_plane *cursor);
+				   struct drm_plane *cursor,
+				   struct vkms_config_crtc *config);
 
 /**
  * vkms_output_init() - Initialize all sub-components needed for a VKMS device.
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index cf385f676ef7f45633b4ed69a8047c87fad95dbd..dab949c983a5991696baf937f948c0f78710d6e1 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -31,21 +31,13 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
 
 int vkms_output_init(struct vkms_device *vkmsdev)
 {
-	struct vkms_config_plane *config_plane;
+	struct vkms_config_encoder *config_encoder;
 	struct drm_device *dev = &vkmsdev->drm;
+	struct vkms_config_plane *config_plane;
+	struct vkms_config_crtc *config_crtc;
 	struct drm_connector *connector;
-	struct drm_encoder *encoder;
-	struct vkms_output *output;
-	struct vkms_plane *primary, *cursor = NULL;
+	unsigned long idx;
 	int ret;
-	int writeback;
-
-	output = vkms_crtc_init(dev, &primary->base,
-				cursor ? &cursor->base : NULL);
-	if (IS_ERR(output)) {
-		DRM_ERROR("Failed to allocate CRTC\n");
-		return PTR_ERR(output);
-	}
 
 	list_for_each_entry(config_plane, &vkmsdev->config->planes, link) {
 		config_plane->plane = vkms_plane_init(vkmsdev, config_plane);
@@ -53,10 +45,30 @@ int vkms_output_init(struct vkms_device *vkmsdev)
 			ret = PTR_ERR(config_plane->plane);
 			return ret;
 		}
-		if (config_plane->type == DRM_PLANE_TYPE_PRIMARY)
-			primary = config_plane->plane;
-		else if (config_plane->type == DRM_PLANE_TYPE_CURSOR)
-			cursor = config_plane->plane;
+	}
+
+	list_for_each_entry(config_crtc, &vkmsdev->config->crtcs, link) {
+		struct drm_plane *primary = NULL, *cursor = NULL;
+
+		xa_for_each(&config_crtc->possible_planes, idx, config_plane) {
+			if (config_plane->type == DRM_PLANE_TYPE_PRIMARY)
+				primary = &config_plane->plane->base;
+			else if (config_plane->type == DRM_PLANE_TYPE_CURSOR)
+				cursor = &config_plane->plane->base;
+		}
+
+		config_crtc->output = vkms_crtc_init(vkmsdev, primary, cursor, config_crtc);
+
+		if (IS_ERR(config_crtc->output)) {
+			ret = PTR_ERR(config_crtc->output);
+			return ret;
+		}
+	}
+
+	list_for_each_entry(config_crtc, &vkmsdev->config->crtcs, link) {
+		xa_for_each(&config_crtc->possible_planes, idx, config_plane) {
+			config_plane->plane->base.possible_crtcs |= drm_crtc_mask(&config_crtc->output->crtc);
+		}
 	}
 
 	connector = drmm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
@@ -74,31 +86,25 @@ int vkms_output_init(struct vkms_device *vkmsdev)
 
 	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
 
-	encoder = drmm_kzalloc(dev, sizeof(*encoder), GFP_KERNEL);
-	if (!encoder) {
-		DRM_ERROR("Failed to allocate encoder\n");
-		return -ENOMEM;
-	}
-	ret = drmm_encoder_init(dev, encoder, NULL,
-				DRM_MODE_ENCODER_VIRTUAL, NULL);
-	if (ret) {
-		DRM_ERROR("Failed to init encoder\n");
-		return ret;
-	}
-	encoder->possible_crtcs = drm_crtc_mask(&output->crtc);
-
-	/* Attach the encoder and the connector */
-	ret = drm_connector_attach_encoder(connector, encoder);
-	if (ret) {
-		DRM_ERROR("Failed to attach connector to encoder\n");
-		return ret;
-	}
-
-	/* Initialize the writeback component */
-	if (vkmsdev->config->writeback) {
-		writeback = vkms_enable_writeback_connector(vkmsdev, output);
-		if (writeback)
-			DRM_ERROR("Failed to init writeback connector\n");
+	list_for_each_entry(config_encoder, &vkmsdev->config->encoders, link) {
+		config_encoder->encoder = drmm_kzalloc(dev, sizeof(*config_encoder->encoder),
+						       GFP_KERNEL);
+		if (!config_encoder->encoder)
+			return -ENOMEM;
+		ret = drmm_encoder_init(dev, config_encoder->encoder, NULL,
+					DRM_MODE_ENCODER_VIRTUAL, NULL);
+		if (ret) {
+			DRM_ERROR("Failed to init encoder\n");
+			return ret;
+		}
+		xa_for_each(&config_encoder->possible_crtcs, idx, config_crtc) {
+			config_encoder->encoder->possible_crtcs |= drm_crtc_mask(&config_crtc->output->crtc);
+		}
+		if (IS_ERR(config_encoder->encoder))
+			return PTR_ERR(config_encoder->encoder);
+		ret = drm_connector_attach_encoder(connector, config_encoder->encoder);
+		if (ret)
+			return ret;
 	}
 
 	drm_mode_config_reset(dev);

-- 
2.47.1


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

* [PATCH v3 08/16] drm/vkms: Introduce config for encoder name
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (6 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 07/16] drm/vkms: Introduce config for CRTCs and encoders Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 09/16] drm/vkms: Introduce config for CRTC name Louis Chauvet
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

As an encoder will be a directory in ConfigFS, add the configuration for
encoder name so we will be able to reflect the configfs directory name in
the drm name.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 6 ++++++
 drivers/gpu/drm/vkms/vkms_config.h | 2 ++
 drivers/gpu/drm/vkms/vkms_output.c | 2 +-
 3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 314d252aa9b6ed1772c8ef597bd9c6b08145723e..8c88af745eb208a52f58fbf5def3f16c29d31063 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -41,6 +41,10 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
 	encoder = vkms_config_create_encoder(vkms_config);
 	if (!encoder)
 		goto err_alloc;
+	encoder->name = kzalloc(sizeof("Main Encoder"), GFP_KERNEL);
+	if (!encoder->name)
+		goto err_alloc;
+	sprintf(encoder->name, "Main Encoder");
 
 	if (vkms_config_encoder_attach_crtc(encoder, crtc))
 		goto err_alloc;
@@ -231,6 +235,7 @@ void vkms_config_delete_encoder(struct vkms_config_encoder *vkms_config_encoder,
 		}
 	}
 
+	kfree(vkms_config_encoder->name);
 	kfree(vkms_config_encoder);
 }
 
@@ -376,6 +381,7 @@ static int vkms_config_show(struct seq_file *m, void *data)
 
 	list_for_each_entry(config_encoder, &vkmsdev->config->encoders, link) {
 		seq_puts(m, "encoder:\n");
+		seq_printf(m, "\tname: %s\n", config_encoder->name);
 	}
 
 	list_for_each_entry(config_crtc, &vkmsdev->config->crtcs, link) {
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 90ced83f5eb6dae5ccc14c37169606d833ba355a..874d631f8895c47eca6eba8bfe20b56b88966b67 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -50,6 +50,7 @@ struct vkms_config_crtc {
  * struct vkms_config_encoder
  *
  * @link: Link to the others encoders
+ * @name: Name of the encoder
  * @possible_crtcs: List of CRTC that can be used with this encoder
  * @encoder: Internal usage. This pointer should never be considered as valid. It can be used to
  *         store a temporary reference to a vkms encoder during device creation. This pointer is
@@ -58,6 +59,7 @@ struct vkms_config_crtc {
 struct vkms_config_encoder {
 	struct list_head link;
 
+	char *name;
 	struct xarray possible_crtcs;
 
 	/* Internal usage */
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index dab949c983a5991696baf937f948c0f78710d6e1..fd641fa750f20b1a95994acc2778a74942125fd9 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -92,7 +92,7 @@ int vkms_output_init(struct vkms_device *vkmsdev)
 		if (!config_encoder->encoder)
 			return -ENOMEM;
 		ret = drmm_encoder_init(dev, config_encoder->encoder, NULL,
-					DRM_MODE_ENCODER_VIRTUAL, NULL);
+					DRM_MODE_ENCODER_VIRTUAL, config_encoder->name);
 		if (ret) {
 			DRM_ERROR("Failed to init encoder\n");
 			return ret;

-- 
2.47.1


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

* [PATCH v3 09/16] drm/vkms: Introduce config for CRTC name
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (7 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 08/16] drm/vkms: Introduce config for encoder name Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 10/16] drm/vkms: Add test for config structure Louis Chauvet
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

As a CRTC will be a directory in ConfigFS, add the name configuration for
CRTC name so we will be able to reflect the configfs directory name in the
drm name.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 5 +++++
 drivers/gpu/drm/vkms/vkms_config.h | 2 ++
 drivers/gpu/drm/vkms/vkms_crtc.c   | 2 +-
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 8c88af745eb208a52f58fbf5def3f16c29d31063..b610d37b675efaea7ca717f08e525beaf18d8d9e 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -37,6 +37,10 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
 	if (!crtc)
 		goto err_alloc;
 	crtc->writeback = enable_writeback;
+	crtc->name = kzalloc(sizeof("Main CRTC"), GFP_KERNEL);
+	if (!crtc->name)
+		goto err_alloc;
+	sprintf(crtc->name, "Main CRTC");
 
 	encoder = vkms_config_create_encoder(vkms_config);
 	if (!encoder)
@@ -212,6 +216,7 @@ void vkms_config_delete_crtc(struct vkms_config_crtc *vkms_config_crtc,
 		}
 	}
 
+	kfree(vkms_config_crtc->name);
 	kfree(vkms_config_crtc);
 }
 
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 874d631f8895c47eca6eba8bfe20b56b88966b67..efe984113fb664ff38a68b3be90063c366bb2892 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -29,6 +29,7 @@ struct vkms_config {
  * struct vkms_config_crtc
  *
  * @link: Link to the others CRTCs
+ * @name: Name of the CRTC
  * @possible_planes: List of planes that can be used with this CRTC
  * @possible_encoders: List of encoders that can be used with this CRTC
  * @crtc: Internal usage. This pointer should never be considered as valid. It can be used to
@@ -38,6 +39,7 @@ struct vkms_config {
 struct vkms_config_crtc {
 	struct list_head link;
 
+	char *name;
 	bool writeback;
 	struct xarray possible_planes;
 	struct xarray possible_encoders;
diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index f4da196fd7774ee1dcc5148e6420186f1384b3fa..0c795de19db5359f968cb0c0a396626deb3f8e27 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -282,7 +282,7 @@ struct vkms_output *vkms_crtc_init(struct vkms_device *vkms_device,
 
 	vkms_out = drmm_crtc_alloc_with_planes(dev, struct vkms_output, crtc,
 					       primary, cursor,
-					       &vkms_crtc_funcs, NULL);
+					       &vkms_crtc_funcs, config->name);
 	if (IS_ERR(vkms_out)) {
 		DRM_DEV_ERROR(dev->dev, "Failed to init CRTC\n");
 		return vkms_out;

-- 
2.47.1


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

* [PATCH v3 10/16] drm/vkms: Add test for config structure
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (8 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 09/16] drm/vkms: Introduce config for CRTC name Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 11/16] drm/vkms: Introduce config for connector Louis Chauvet
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

The config structure is a bit complex in term of memory management. Add
basic test to avoid breaking it in the future.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/tests/Makefile           |   3 +
 drivers/gpu/drm/vkms/tests/vkms_config_test.c | 137 ++++++++++++++++++++++++++
 2 files changed, 140 insertions(+)

diff --git a/drivers/gpu/drm/vkms/tests/Makefile b/drivers/gpu/drm/vkms/tests/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..b78371d08aa9531a5151225cc33e34452225832c
--- /dev/null
+++ b/drivers/gpu/drm/vkms/tests/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_DRM_VKMS_KUNIT_TESTS) += vkms_config_test.o
diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..f7a2b8ecd4e1f791e9abc86659ef459e3ea8be43
--- /dev/null
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <kunit/test.h>
+
+#include "../vkms_config.h"
+
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+
+static void vkms_config_test_basic_allocation(struct kunit *test)
+{
+	struct vkms_config *config = vkms_config_create();
+
+	KUNIT_EXPECT_TRUE_MSG(test, list_empty(&config->encoders),
+			      "Encoder list is not empty after allocation");
+	KUNIT_EXPECT_TRUE_MSG(test, list_empty(&config->crtcs),
+			      "CRTC list is not empty after allocation");
+	KUNIT_EXPECT_TRUE_MSG(test, list_empty(&config->planes),
+			      "Plane list is not empty after allocation");
+
+	vkms_config_destroy(config);
+}
+
+static void vkms_config_test_simple_config(struct kunit *test)
+{
+	struct vkms_config *config = vkms_config_create();
+
+	struct vkms_config_plane *plane_1 = vkms_config_create_plane(config);
+	struct vkms_config_plane *plane_2 = vkms_config_create_plane(config);
+	struct vkms_config_crtc *crtc = vkms_config_create_crtc(config);
+	struct vkms_config_encoder *encoder = vkms_config_create_encoder(config);
+
+	KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->planes), 2);
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->crtcs), 1);
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->encoders), 1);
+
+	plane_1->type = DRM_PLANE_TYPE_PRIMARY;
+	plane_2->type = DRM_PLANE_TYPE_CURSOR;
+
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_1, crtc), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_2, crtc), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_encoder_attach_crtc(encoder, crtc), 0);
+
+	KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+	vkms_config_delete_plane(plane_1, config);
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->planes), 1);
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->crtcs), 1);
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->encoders), 1);
+
+	KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+
+	plane_2->type = DRM_PLANE_TYPE_PRIMARY;
+
+	KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+	vkms_config_destroy(config);
+}
+
+static void vkms_config_test_complex_config(struct kunit *test)
+{
+	struct vkms_config *config = vkms_config_create();
+
+	struct vkms_config_plane *plane_1 = vkms_config_create_plane(config);
+	struct vkms_config_plane *plane_2 = vkms_config_create_plane(config);
+	struct vkms_config_plane *plane_3 = vkms_config_create_plane(config);
+	struct vkms_config_plane *plane_4 = vkms_config_create_plane(config);
+	struct vkms_config_plane *plane_5 = vkms_config_create_plane(config);
+	struct vkms_config_plane *plane_6 = vkms_config_create_plane(config);
+	struct vkms_config_plane *plane_7 = vkms_config_create_plane(config);
+	struct vkms_config_plane *plane_8 = vkms_config_create_plane(config);
+	struct vkms_config_crtc *crtc_1 = vkms_config_create_crtc(config);
+	struct vkms_config_crtc *crtc_2 = vkms_config_create_crtc(config);
+	struct vkms_config_encoder *encoder_1 = vkms_config_create_encoder(config);
+	struct vkms_config_encoder *encoder_2 = vkms_config_create_encoder(config);
+	struct vkms_config_encoder *encoder_3 = vkms_config_create_encoder(config);
+	struct vkms_config_encoder *encoder_4 = vkms_config_create_encoder(config);
+
+	KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->planes), 8);
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->crtcs), 2);
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->encoders), 4);
+
+	plane_1->type = DRM_PLANE_TYPE_PRIMARY;
+	plane_2->type = DRM_PLANE_TYPE_CURSOR;
+	plane_3->type = DRM_PLANE_TYPE_OVERLAY;
+	plane_4->type = DRM_PLANE_TYPE_OVERLAY;
+	plane_5->type = DRM_PLANE_TYPE_PRIMARY;
+	plane_6->type = DRM_PLANE_TYPE_CURSOR;
+	plane_7->type = DRM_PLANE_TYPE_OVERLAY;
+	plane_8->type = DRM_PLANE_TYPE_OVERLAY;
+
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_1, crtc_1), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_2, crtc_1), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_3, crtc_1), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_4, crtc_1), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_5, crtc_2), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_6, crtc_2), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_7, crtc_2), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_8, crtc_2), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_3, crtc_2), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_plane_attach_crtc(plane_4, crtc_2), 0);
+
+	KUNIT_EXPECT_EQ(test, vkms_config_encoder_attach_crtc(encoder_1, crtc_1), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_encoder_attach_crtc(encoder_2, crtc_1), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_encoder_attach_crtc(encoder_3, crtc_1), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_encoder_attach_crtc(encoder_3, crtc_2), 0);
+	KUNIT_EXPECT_EQ(test, vkms_config_encoder_attach_crtc(encoder_4, crtc_2), 0);
+
+	KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+	vkms_config_delete_plane(plane_4, config);
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->planes), 7);
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->crtcs), 2);
+	KUNIT_EXPECT_EQ(test, list_count_nodes(&config->encoders), 4);
+
+	KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+	vkms_config_destroy(config);
+}
+
+static struct kunit_case vkms_config_test_cases[] = {
+	KUNIT_CASE(vkms_config_test_basic_allocation),
+	KUNIT_CASE(vkms_config_test_simple_config),
+	KUNIT_CASE(vkms_config_test_complex_config),
+	{}
+};
+
+static struct kunit_suite vkms_config_test_suite = {
+	.name = "vkms-config",
+	.test_cases = vkms_config_test_cases,
+};
+
+kunit_test_suite(vkms_config_test_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Kunit test for vkms config utility");

-- 
2.47.1


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

* [PATCH v3 11/16] drm/vkms: Introduce config for connector
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (9 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 10/16] drm/vkms: Add test for config structure Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 12/16] drm/vkms: Introduce config for connector type Louis Chauvet
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

The current vkms driver only allows the usage of one connector,
possibly with a writeback connector. This new configuration structure aims
to make the configuration more flexible.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 62 +++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/vkms/vkms_config.h | 18 +++++++++--
 drivers/gpu/drm/vkms/vkms_drv.c    |  2 +-
 drivers/gpu/drm/vkms/vkms_output.c | 37 ++++++++++++-----------
 4 files changed, 98 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index b610d37b675efaea7ca717f08e525beaf18d8d9e..f1f02c66755f9660b48dfa5cb786afa1e6ae553b 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -17,6 +17,7 @@ struct vkms_config *vkms_config_create(void)
 	INIT_LIST_HEAD(&config->planes);
 	INIT_LIST_HEAD(&config->crtcs);
 	INIT_LIST_HEAD(&config->encoders);
+	INIT_LIST_HEAD(&config->connectors);
 
 	return config;
 }
@@ -28,6 +29,7 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
 	struct vkms_config_plane *plane;
 	struct vkms_config_encoder *encoder;
 	struct vkms_config_crtc *crtc;
+	struct vkms_config_connector *connector;
 	struct vkms_config *vkms_config = vkms_config_create();
 
 	if (IS_ERR(vkms_config))
@@ -53,6 +55,12 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
 	if (vkms_config_encoder_attach_crtc(encoder, crtc))
 		goto err_alloc;
 
+	connector = vkms_config_create_connector(vkms_config);
+	if (!connector)
+		goto err_alloc;
+	if (vkms_config_connector_attach_encoder(connector, encoder))
+		goto err_alloc;
+
 	plane = vkms_config_create_plane(vkms_config);
 	if (!plane)
 		goto err_alloc;
@@ -123,6 +131,23 @@ struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_conf
 }
 EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_plane);
 
+struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *vkms_config)
+{
+	if (!vkms_config)
+		return NULL;
+
+	struct vkms_config_connector *vkms_config_connector =
+		kzalloc(sizeof(*vkms_config_connector), GFP_KERNEL);
+
+	if (!vkms_config_connector)
+		return NULL;
+
+	list_add(&vkms_config_connector->link, &vkms_config->connectors);
+	xa_init_flags(&vkms_config_connector->possible_encoders, XA_FLAGS_ALLOC);
+
+	return vkms_config_connector;
+}
+
 struct vkms_config_crtc *vkms_config_create_crtc(struct vkms_config *vkms_config)
 {
 	if (!vkms_config)
@@ -220,6 +245,15 @@ void vkms_config_delete_crtc(struct vkms_config_crtc *vkms_config_crtc,
 	kfree(vkms_config_crtc);
 }
 
+void vkms_config_delete_connector(struct vkms_config_connector *vkms_config_conector)
+{
+	if (!vkms_config_conector)
+		return;
+	list_del(&vkms_config_conector->link);
+
+	kfree(vkms_config_conector);
+}
+
 void vkms_config_delete_encoder(struct vkms_config_encoder *vkms_config_encoder,
 				struct vkms_config *vkms_config)
 {
@@ -240,6 +274,17 @@ void vkms_config_delete_encoder(struct vkms_config_encoder *vkms_config_encoder,
 		}
 	}
 
+	struct vkms_config_connector *connector_config;
+
+	list_for_each_entry(connector_config, &vkms_config->connectors, link) {
+		unsigned long idx = 0;
+
+		xa_for_each(&connector_config->possible_encoders, idx, encoder) {
+			if (encoder == vkms_config_encoder)
+				xa_erase(&connector_config->possible_encoders, idx);
+		}
+	}
+
 	kfree(vkms_config_encoder->name);
 	kfree(vkms_config_encoder);
 }
@@ -249,7 +294,7 @@ void vkms_config_destroy(struct vkms_config *config)
 	struct vkms_config_plane *vkms_config_plane, *tmp_plane;
 	struct vkms_config_encoder *vkms_config_encoder, *tmp_encoder;
 	struct vkms_config_crtc *vkms_config_crtc, *tmp_crtc;
-
+	struct vkms_config_connector *vkms_config_connector, *tmp_connector;
 	list_for_each_entry_safe(vkms_config_plane, tmp_plane, &config->planes, link) {
 		vkms_config_delete_plane(vkms_config_plane, config);
 	}
@@ -259,6 +304,9 @@ void vkms_config_destroy(struct vkms_config *config)
 	list_for_each_entry_safe(vkms_config_crtc, tmp_crtc, &config->crtcs, link) {
 		vkms_config_delete_crtc(vkms_config_crtc, config);
 	}
+	list_for_each_entry_safe(vkms_config_connector, tmp_connector, &config->connectors, link) {
+		vkms_config_delete_connector(vkms_config_connector);
+	}
 
 	kfree(config);
 }
@@ -308,6 +356,18 @@ int __must_check vkms_config_encoder_attach_crtc(struct vkms_config_encoder *vkm
 }
 EXPORT_SYMBOL_IF_KUNIT(vkms_config_encoder_attach_crtc);
 
+int __must_check
+vkms_config_connector_attach_encoder(struct vkms_config_connector *vkms_config_connector,
+				     struct vkms_config_encoder *vkms_config_encoder)
+{
+	u32 encoder_idx;
+	int ret;
+
+	ret = xa_alloc(&vkms_config_connector->possible_encoders, &encoder_idx, vkms_config_encoder,
+		       xa_limit_32b, GFP_KERNEL);
+	return ret;
+}
+
 bool vkms_config_is_valid(struct vkms_config *config)
 {
 	struct vkms_config_plane *config_plane;
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index efe984113fb664ff38a68b3be90063c366bb2892..584d015d6b8f420d82b2cfe38c991e93ad8288f3 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -23,6 +23,7 @@ struct vkms_config {
 	struct list_head planes;
 	struct list_head crtcs;
 	struct list_head encoders;
+	struct list_head connectors;
 };
 
 /**
@@ -95,6 +96,15 @@ struct vkms_config_plane {
 	struct vkms_plane *plane;
 };
 
+struct vkms_config_connector {
+	struct list_head link;
+
+	struct xarray possible_encoders;
+
+	/* Internal usage */
+	struct drm_connector *connector;
+};
+
 /**
  * vkms_config_register_debugfs() - Register the debugfs file to display current configuration
  */
@@ -125,6 +135,8 @@ bool vkms_config_is_valid(struct vkms_config *vkms_config);
  */
 struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_config);
 
+struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *vkms_config);
+
 /**
  * vkms_config_create_crtc() - Create a crtc configuration
  *
@@ -145,7 +157,9 @@ int __must_check vkms_config_plane_attach_crtc(struct vkms_config_plane *vkms_co
 					       struct vkms_config_crtc *vkms_config_crtc);
 int __must_check vkms_config_encoder_attach_crtc(struct vkms_config_encoder *vkms_config_encoder,
 						 struct vkms_config_crtc *vkms_config_crtc);
-
+int __must_check
+vkms_config_connector_attach_encoder(struct vkms_config_connector *vkms_config_connector,
+				     struct vkms_config_encoder *vkms_config_encoder);
 /**
  * vkms_config_delete_plane() - Remove a plane configuration and frees its memory
  *
@@ -182,7 +196,7 @@ void vkms_config_delete_crtc(struct vkms_config_crtc *vkms_config_crtc,
  */
 void vkms_config_delete_encoder(struct vkms_config_encoder *vkms_config_encoder,
 				struct vkms_config *vkms_config);
-
+void vkms_config_delete_connector(struct vkms_config_connector *vkms_config_conector);
 /**
  * vkms_config_alloc_default() - Allocate the configuration for the default device
  * @enable_writeback: Enable the writeback connector for this configuration
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 4440549c3084a341d03ec66119ba7998012bd662..95fde2fbd711fe52a3a3b5a55778f5bc2029beb7 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -183,7 +183,7 @@ static int vkms_create(struct vkms_config *config)
 		goto out_devres;
 	}
 
-	ret = drm_vblank_init(&vkms_device->drm, 1);
+	ret = drm_vblank_init(&vkms_device->drm, list_count_nodes(&config->crtcs));
 	if (ret) {
 		DRM_ERROR("Failed to vblank\n");
 		goto out_devres;
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index fd641fa750f20b1a95994acc2778a74942125fd9..146ce254a027c662ae275dd2ec0024a46fa8119d 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -35,7 +35,7 @@ int vkms_output_init(struct vkms_device *vkmsdev)
 	struct drm_device *dev = &vkmsdev->drm;
 	struct vkms_config_plane *config_plane;
 	struct vkms_config_crtc *config_crtc;
-	struct drm_connector *connector;
+	struct vkms_config_connector *config_connector;
 	unsigned long idx;
 	int ret;
 
@@ -71,21 +71,6 @@ int vkms_output_init(struct vkms_device *vkmsdev)
 		}
 	}
 
-	connector = drmm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
-	if (!connector) {
-		DRM_ERROR("Failed to allocate connector\n");
-		return -ENOMEM;
-	}
-
-	ret = drmm_connector_init(dev, connector, &vkms_connector_funcs,
-				  DRM_MODE_CONNECTOR_VIRTUAL, NULL);
-	if (ret) {
-		DRM_ERROR("Failed to init connector\n");
-		return ret;
-	}
-
-	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
-
 	list_for_each_entry(config_encoder, &vkmsdev->config->encoders, link) {
 		config_encoder->encoder = drmm_kzalloc(dev, sizeof(*config_encoder->encoder),
 						       GFP_KERNEL);
@@ -97,14 +82,32 @@ int vkms_output_init(struct vkms_device *vkmsdev)
 			DRM_ERROR("Failed to init encoder\n");
 			return ret;
 		}
+
 		xa_for_each(&config_encoder->possible_crtcs, idx, config_crtc) {
 			config_encoder->encoder->possible_crtcs |= drm_crtc_mask(&config_crtc->output->crtc);
 		}
 		if (IS_ERR(config_encoder->encoder))
 			return PTR_ERR(config_encoder->encoder);
-		ret = drm_connector_attach_encoder(connector, config_encoder->encoder);
+	}
+
+	list_for_each_entry(config_connector, &vkmsdev->config->connectors, link) {
+		config_connector->connector = drmm_kzalloc(&vkmsdev->drm,
+							   sizeof(*config_connector->connector),
+							   GFP_KERNEL);
+		if (!config_connector->connector)
+			return -ENOMEM;
+		ret = drmm_connector_init(&vkmsdev->drm, config_connector->connector,
+					  &vkms_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL, NULL);
 		if (ret)
 			return ret;
+		drm_connector_helper_add(config_connector->connector, &vkms_conn_helper_funcs);
+
+		xa_for_each(&config_connector->possible_encoders, idx, config_encoder) {
+			ret = drm_connector_attach_encoder(config_connector->connector,
+							   config_encoder->encoder);
+			if (ret)
+				return ret;
+		}
 	}
 
 	drm_mode_config_reset(dev);

-- 
2.47.1


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

* [PATCH v3 12/16] drm/vkms: Introduce config for connector type
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (10 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 11/16] drm/vkms: Introduce config for connector Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 13/16] drm/vkms: Introduce config for plane format Louis Chauvet
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

To allow emulation of different kind of connector, make the connector type
configurable.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 1 +
 drivers/gpu/drm/vkms/vkms_config.h | 1 +
 drivers/gpu/drm/vkms/vkms_output.c | 2 +-
 3 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index f1f02c66755f9660b48dfa5cb786afa1e6ae553b..d2006d7b47f9cf21487659cc3eacb6272d1904b0 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -144,6 +144,7 @@ struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *v
 
 	list_add(&vkms_config_connector->link, &vkms_config->connectors);
 	xa_init_flags(&vkms_config_connector->possible_encoders, XA_FLAGS_ALLOC);
+	vkms_config_connector->type = DRM_MODE_CONNECTOR_VIRTUAL;
 
 	return vkms_config_connector;
 }
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 584d015d6b8f420d82b2cfe38c991e93ad8288f3..18b8978b7b7b58c45fcf11f7130883013e34d8ed 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -100,6 +100,7 @@ struct vkms_config_connector {
 	struct list_head link;
 
 	struct xarray possible_encoders;
+	int type;
 
 	/* Internal usage */
 	struct drm_connector *connector;
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 146ce254a027c662ae275dd2ec0024a46fa8119d..50aa802da479e5ba383e5db49dc2c7c6981f0bef 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -97,7 +97,7 @@ int vkms_output_init(struct vkms_device *vkmsdev)
 		if (!config_connector->connector)
 			return -ENOMEM;
 		ret = drmm_connector_init(&vkmsdev->drm, config_connector->connector,
-					  &vkms_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL, NULL);
+					  &vkms_connector_funcs, config_connector->type, NULL);
 		if (ret)
 			return ret;
 		drm_connector_helper_add(config_connector->connector, &vkms_conn_helper_funcs);

-- 
2.47.1


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

* [PATCH v3 13/16] drm/vkms: Introduce config for plane format
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (11 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 12/16] drm/vkms: Introduce config for connector type Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 14/16] drm/vkms: Introduce config for connector status Louis Chauvet
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

VKMS driver supports all the pixel formats for planes, but for testing it
can be useful to only advertise few of them. This new configuration
interface will allow configuring the pixel format per planes.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 75 ++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_config.h | 19 ++++++++++
 drivers/gpu/drm/vkms/vkms_plane.c  | 13 ++-----
 3 files changed, 97 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index d2006d7b47f9cf21487659cc3eacb6272d1904b0..57e211e48a90d3a4d7f8677c40a2b35d44b847e5 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -6,6 +6,14 @@
 #include "vkms_config.h"
 #include "vkms_drv.h"
 
+static const u32 vkms_supported_plane_formats[] = {
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_XRGB16161616,
+	DRM_FORMAT_ARGB16161616,
+	DRM_FORMAT_RGB565,
+};
+
 struct vkms_config *vkms_config_create(void)
 {
 	struct vkms_config *config;
@@ -120,6 +128,13 @@ struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_conf
 	if (!vkms_config_overlay)
 		return NULL;
 
+	vkms_config_overlay->supported_formats = NULL;
+
+	if (vkms_config_plane_add_all_formats(vkms_config_overlay)) {
+		kfree(vkms_config_overlay);
+		return NULL;
+	}
+
 	vkms_config_overlay->type = DRM_PLANE_TYPE_OVERLAY;
 	vkms_config_overlay->supported_rotations = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
 	vkms_config_overlay->default_rotation = DRM_MODE_ROTATE_0;
@@ -186,6 +201,65 @@ struct vkms_config_encoder *vkms_config_create_encoder(struct vkms_config *vkms_
 }
 EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_encoder);
 
+int __must_check vkms_config_plane_add_all_formats(struct vkms_config_plane *vkms_config_plane)
+{
+	u32 *ret = krealloc_array(vkms_config_plane->supported_formats,
+				  ARRAY_SIZE(vkms_supported_plane_formats),
+				  sizeof(uint32_t), GFP_KERNEL);
+	if (!ret)
+		return -ENOMEM;
+	vkms_config_plane->supported_formats = ret;
+
+	memcpy(vkms_config_plane->supported_formats, vkms_supported_plane_formats,
+	       sizeof(vkms_supported_plane_formats));
+	vkms_config_plane->supported_formats_count = ARRAY_SIZE(vkms_supported_plane_formats);
+	return 0;
+}
+
+int __must_check vkms_config_plane_add_format(struct vkms_config_plane *vkms_config_plane,
+					      u32 drm_format)
+{
+	bool found = false;
+
+	for (int i = 0; i < ARRAY_SIZE(vkms_supported_plane_formats); i++) {
+		if (vkms_supported_plane_formats[i] == drm_format)
+			found = true;
+	}
+
+	if (!found)
+		return -EINVAL;
+	for (unsigned int i = 0; i < vkms_config_plane->supported_formats_count; i++) {
+		if (vkms_config_plane->supported_formats[i] == drm_format)
+			return 0;
+	}
+	u32 *new_ptr = krealloc_array(vkms_config_plane->supported_formats,
+				      vkms_config_plane->supported_formats_count + 1,
+				      sizeof(*vkms_config_plane->supported_formats), GFP_KERNEL);
+	if (!new_ptr)
+		return -ENOMEM;
+
+	vkms_config_plane->supported_formats = new_ptr;
+	vkms_config_plane->supported_formats[vkms_config_plane->supported_formats_count] = drm_format;
+	vkms_config_plane->supported_formats_count++;
+
+	return 0;
+}
+
+void vkms_config_plane_remove_all_formats(struct vkms_config_plane *vkms_config_plane)
+{
+	vkms_config_plane->supported_formats_count = 0;
+}
+
+void vkms_config_plane_remove_format(struct vkms_config_plane *vkms_config_plane, u32 drm_format)
+{
+	for (unsigned int i = 0; i < vkms_config_plane->supported_formats_count; i++) {
+		if (vkms_config_plane->supported_formats[i] == drm_format) {
+			vkms_config_plane->supported_formats[i] = vkms_config_plane->supported_formats[vkms_config_plane->supported_formats_count - 1];
+			vkms_config_plane->supported_formats_count--;
+		}
+	}
+}
+
 void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_plane,
 			      struct vkms_config *vkms_config)
 {
@@ -206,6 +280,7 @@ void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_plane,
 		}
 	}
 
+	kfree(vkms_config_plane->supported_formats);
 	kfree(vkms_config_plane->name);
 	kfree(vkms_config_plane);
 }
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 18b8978b7b7b58c45fcf11f7130883013e34d8ed..72bfaadd4322f9e1607a6b9425fb8aaf8bd9d5f6 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -90,6 +90,8 @@ struct vkms_config_plane {
 	enum drm_plane_type type;
 	unsigned int default_rotation;
 	unsigned int supported_rotations;
+	u32 *supported_formats;
+	unsigned int supported_formats_count;
 
 	struct xarray possible_crtcs;
 	/* Internal usage */
@@ -136,6 +138,23 @@ bool vkms_config_is_valid(struct vkms_config *vkms_config);
  */
 struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_config);
 
+/** vkms_config_plane_add_format - Add a format to the list of supported format of a plane
+ *
+ * The passed drm_format can already be present in the list. This may fail if the allocation of a
+ * bigger array fails.
+ *
+ * @vkms_config_plane: Plane to add the format to
+ * @drm_format: Format to add to this plane
+ *
+ * Returns: 0 on success, -ENOMEM if array allocation fails, -EINVAL if the format is not supported
+ * by VKMS
+ */
+int __must_check vkms_config_plane_add_format(struct vkms_config_plane *vkms_config_plane,
+					      u32 drm_format);
+int __must_check vkms_config_plane_add_all_formats(struct vkms_config_plane *vkms_config_plane);
+void vkms_config_plane_remove_format(struct vkms_config_plane *vkms_config_plane, u32 drm_format);
+void vkms_config_plane_remove_all_formats(struct vkms_config_plane *vkms_config_plane);
+
 struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *vkms_config);
 
 /**
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index c23ac8687dedaa956cfd6622321f1026521ff13f..e7ad161fd3d3f2d0bdaf63a4df86d6a2e91230c1 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -13,14 +13,6 @@
 #include "vkms_formats.h"
 #include "vkms_config.h"
 
-static const u32 vkms_formats[] = {
-	DRM_FORMAT_ARGB8888,
-	DRM_FORMAT_XRGB8888,
-	DRM_FORMAT_XRGB16161616,
-	DRM_FORMAT_ARGB16161616,
-	DRM_FORMAT_RGB565
-};
-
 static struct drm_plane_state *
 vkms_plane_duplicate_state(struct drm_plane *plane)
 {
@@ -195,8 +187,9 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
 
 	plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 0,
 					   &vkms_plane_funcs,
-					   vkms_formats, ARRAY_SIZE(vkms_formats),
-					   NULL, config->type, config->name);
+					   config->supported_formats,
+					   config->supported_formats_count, NULL, config->type,
+					   config->name);
 	if (IS_ERR(plane))
 		return plane;
 

-- 
2.47.1


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

* [PATCH v3 14/16] drm/vkms: Introduce config for connector status
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (12 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 13/16] drm/vkms: Introduce config for plane format Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 15/16] drm/vkms: Introduce config for connector EDID Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 16/16] drm/vkms: Introduce config for encoder type Louis Chauvet
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet, José Expósito

VKMS driver does not currently support connector hotpluging. Add
an option to change the connector status once a device is created.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
[adpated it for my implementation]
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 10 ++++++++++
 drivers/gpu/drm/vkms/vkms_config.h |  4 ++++
 drivers/gpu/drm/vkms/vkms_output.c | 24 ++++++++++++++++++++++++
 3 files changed, 38 insertions(+)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 57e211e48a90d3a4d7f8677c40a2b35d44b847e5..5eba4284269d058f12f78ddba96cb40215e85f72 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -2,6 +2,7 @@
 
 #include <kunit/visibility.h>
 #include <drm/drm_debugfs.h>
+#include <drm/drm_probe_helper.h>
 
 #include "vkms_config.h"
 #include "vkms_drv.h"
@@ -160,10 +161,19 @@ struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *v
 	list_add(&vkms_config_connector->link, &vkms_config->connectors);
 	xa_init_flags(&vkms_config_connector->possible_encoders, XA_FLAGS_ALLOC);
 	vkms_config_connector->type = DRM_MODE_CONNECTOR_VIRTUAL;
+	vkms_config_connector->status = connector_status_unknown;
 
 	return vkms_config_connector;
 }
 
+void vkms_config_connector_update_status(struct vkms_config_connector *vkms_config_connector,
+					 enum drm_connector_status status)
+{
+	vkms_config_connector->status = status;
+	if (vkms_config_connector->connector)
+		drm_kms_helper_hotplug_event(vkms_config_connector->connector->dev);
+}
+
 struct vkms_config_crtc *vkms_config_create_crtc(struct vkms_config *vkms_config)
 {
 	if (!vkms_config)
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 72bfaadd4322f9e1607a6b9425fb8aaf8bd9d5f6..8e0c9b753821f75f10b3090743905471d0abac36 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -103,11 +103,15 @@ struct vkms_config_connector {
 
 	struct xarray possible_encoders;
 	int type;
+	enum drm_connector_status status;
 
 	/* Internal usage */
 	struct drm_connector *connector;
 };
 
+void vkms_config_connector_update_status(struct vkms_config_connector *vkms_config_connector,
+					 enum drm_connector_status status);
+
 /**
  * vkms_config_register_debugfs() - Register the debugfs file to display current configuration
  */
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 50aa802da479e5ba383e5db49dc2c7c6981f0bef..75d90df44da3b6dd3ed3ae104a6bc6d51c9bf089 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -7,9 +7,33 @@
 #include <drm/drm_managed.h>
 #include <drm/drm_probe_helper.h>
 
+static struct vkms_config_connector *vkms_config_connector_from_vkms_connector(struct drm_connector *connector)
+{
+	struct vkms_device *vkms_device = drm_device_to_vkms_device(connector->dev);
+	struct vkms_config_connector *connector_cfg;
+
+	list_for_each_entry(connector_cfg, &vkms_device->config->connectors, link) {
+		if (connector_cfg->connector == connector)
+			return connector_cfg;
+	}
+	return NULL;
+}
+
+static enum drm_connector_status vkms_connector_detect(struct drm_connector *connector, bool force)
+{
+	enum drm_connector_status status = connector->status;
+	struct vkms_config_connector *connector_cfg = vkms_config_connector_from_vkms_connector(connector);
+
+	if (connector_cfg)
+		status = connector_cfg->status;
+
+	return status;
+}
+
 static const struct drm_connector_funcs vkms_connector_funcs = {
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.reset = drm_atomic_helper_connector_reset,
+	.detect = vkms_connector_detect,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };

-- 
2.47.1


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

* [PATCH v3 15/16] drm/vkms: Introduce config for connector EDID
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (13 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 14/16] drm/vkms: Introduce config for connector status Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  2025-01-21 10:55 ` [PATCH v3 16/16] drm/vkms: Introduce config for encoder type Louis Chauvet
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

To properly test the EDID reading without using the DRM override, add an
option to configure the EDID for a connector.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c |  1 +
 drivers/gpu/drm/vkms/vkms_config.h |  2 ++
 drivers/gpu/drm/vkms/vkms_output.c | 37 ++++++++++++++++++++++++++++++++++---
 3 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 5eba4284269d058f12f78ddba96cb40215e85f72..3e8883298e73e75fb16ac05e449a7ee8fac72935 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -162,6 +162,7 @@ struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *v
 	xa_init_flags(&vkms_config_connector->possible_encoders, XA_FLAGS_ALLOC);
 	vkms_config_connector->type = DRM_MODE_CONNECTOR_VIRTUAL;
 	vkms_config_connector->status = connector_status_unknown;
+	vkms_config_connector->edid_blob_len = 0;
 
 	return vkms_config_connector;
 }
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 8e0c9b753821f75f10b3090743905471d0abac36..6844ca8523decd51116fb36f98ed40a09bc2284b 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -104,6 +104,8 @@ struct vkms_config_connector {
 	struct xarray possible_encoders;
 	int type;
 	enum drm_connector_status status;
+	char edid_blob[PAGE_SIZE];
+	int edid_blob_len;
 
 	/* Internal usage */
 	struct drm_connector *connector;
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 75d90df44da3b6dd3ed3ae104a6bc6d51c9bf089..8f7df59aa2c1517eb78e9b94b8611b15431fd234 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -38,13 +38,44 @@ static const struct drm_connector_funcs vkms_connector_funcs = {
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
+static int vkms_connector_read_block(void *context, u8 *buf, unsigned int block, size_t len)
+{
+	struct vkms_config_connector *config = context;
+
+	if (block * len + len > config->edid_blob_len)
+		return 1;
+	memcpy(buf, &config->edid_blob[block * len], len);
+	return 0;
+}
+
 static int vkms_conn_get_modes(struct drm_connector *connector)
 {
+	const struct drm_edid *drm_edid = NULL;
 	int count;
+	struct vkms_config_connector *connector_cfg;
+	struct vkms_device *vkmsdev = drm_device_to_vkms_device(connector->dev);
+	struct vkms_config_connector *context = NULL;
+
+	list_for_each_entry(connector_cfg, &vkmsdev->config->connectors, link) {
+		if (connector_cfg->connector == connector) {
+			context = connector_cfg;
+			break;
+		}
+	}
+	if (context)
+		drm_edid = drm_edid_read_custom(connector, vkms_connector_read_block, context);
+
+	/*
+	 * Unconditionally update the connector. If the EDID was read
+	 * successfully, fill in the connector information derived from the
+	 * EDID. Otherwise, if the EDID is NULL, clear the connector
+	 * information.
+	 */
+	drm_edid_connector_update(connector, drm_edid);
+
+	count = drm_edid_connector_add_modes(connector);
 
-	/* Use the default modes list from DRM */
-	count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
-	drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);
+	drm_edid_free(drm_edid);
 
 	return count;
 }

-- 
2.47.1


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

* [PATCH v3 16/16] drm/vkms: Introduce config for encoder type
  2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
                   ` (14 preceding siblings ...)
  2025-01-21 10:55 ` [PATCH v3 15/16] drm/vkms: Introduce config for connector EDID Louis Chauvet
@ 2025-01-21 10:55 ` Louis Chauvet
  15 siblings, 0 replies; 17+ messages in thread
From: Louis Chauvet @ 2025-01-21 10:55 UTC (permalink / raw)
  To: Maíra Canal, Haneen Mohammed, Simona Vetter, Melissa Wen,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie
  Cc: arthurgrillo, jeremie.dautheribes, miquel.raynal,
	thomas.petazzoni, seanpaul, nicolejadeyee, linux-kernel,
	dri-devel, Louis Chauvet

To allow emulation of different kind of encoders, make the encoder type
configurable.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 1 +
 drivers/gpu/drm/vkms/vkms_config.h | 2 ++
 drivers/gpu/drm/vkms/vkms_output.c | 2 +-
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 3e8883298e73e75fb16ac05e449a7ee8fac72935..a20644031ce923fad98d486a8bb2ec7859038dcd 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -205,6 +205,7 @@ struct vkms_config_encoder *vkms_config_create_encoder(struct vkms_config *vkms_
 	if (!vkms_config_encoder)
 		return NULL;
 
+	vkms_config_encoder->type = DRM_MODE_ENCODER_VIRTUAL;
 	list_add(&vkms_config_encoder->link, &vkms_config->encoders);
 	xa_init_flags(&vkms_config_encoder->possible_crtcs, XA_FLAGS_ALLOC);
 
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 6844ca8523decd51116fb36f98ed40a09bc2284b..23f420291cfc0044ccb2be90688d021aab10c1c0 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -55,6 +55,7 @@ struct vkms_config_crtc {
  * @link: Link to the others encoders
  * @name: Name of the encoder
  * @possible_crtcs: List of CRTC that can be used with this encoder
+ * @type: Type of encoder, see drm_mode.h, DRM_MODE_ENCODER_*
  * @encoder: Internal usage. This pointer should never be considered as valid. It can be used to
  *         store a temporary reference to a vkms encoder during device creation. This pointer is
  *         not managed by the configuration and must be managed by other means.
@@ -64,6 +65,7 @@ struct vkms_config_encoder {
 
 	char *name;
 	struct xarray possible_crtcs;
+	char type;
 
 	/* Internal usage */
 	struct drm_encoder *encoder;
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 8f7df59aa2c1517eb78e9b94b8611b15431fd234..a48625e879f59a33e18e636cafcdc7f841a0ff1f 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -132,7 +132,7 @@ int vkms_output_init(struct vkms_device *vkmsdev)
 		if (!config_encoder->encoder)
 			return -ENOMEM;
 		ret = drmm_encoder_init(dev, config_encoder->encoder, NULL,
-					DRM_MODE_ENCODER_VIRTUAL, config_encoder->name);
+					config_encoder->type, config_encoder->name);
 		if (ret) {
 			DRM_ERROR("Failed to init encoder\n");
 			return ret;

-- 
2.47.1


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

end of thread, other threads:[~2025-01-21 10:55 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-01-21 10:55 [PATCH v3 00/16] drm/vkms: Introduce detailed configuration Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 01/16] drm/vkms: Extract vkms_config header Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 02/16] drm/vkms: Add a validation function for vkms configuration Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 03/16] drm/vkms: Move default_config creation to its own function Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 04/16] drm/vkms: Introduce config for plane Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 05/16] drm/vkms: Introduce config for plane name Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 06/16] drm/vkms: Introduce config for plane rotation Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 07/16] drm/vkms: Introduce config for CRTCs and encoders Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 08/16] drm/vkms: Introduce config for encoder name Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 09/16] drm/vkms: Introduce config for CRTC name Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 10/16] drm/vkms: Add test for config structure Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 11/16] drm/vkms: Introduce config for connector Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 12/16] drm/vkms: Introduce config for connector type Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 13/16] drm/vkms: Introduce config for plane format Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 14/16] drm/vkms: Introduce config for connector status Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 15/16] drm/vkms: Introduce config for connector EDID Louis Chauvet
2025-01-21 10:55 ` [PATCH v3 16/16] drm/vkms: Introduce config for encoder type Louis Chauvet

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®