aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vkms/vkms_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vkms/vkms_config.c')
-rw-r--r--drivers/gpu/drm/vkms/vkms_config.c154
1 files changed, 140 insertions, 14 deletions
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index d195db770fae..458385413648 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -52,13 +52,20 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
goto err_alloc;
vkms_config_crtc_set_writeback(crtc_cfg, enable_writeback);
+ if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg))
+ goto err_alloc;
+
if (enable_overlay) {
for (n = 0; n < NUM_OVERLAY_PLANES; n++) {
plane_cfg = vkms_config_create_plane(config);
if (IS_ERR(plane_cfg))
goto err_alloc;
+
vkms_config_plane_set_type(plane_cfg,
DRM_PLANE_TYPE_OVERLAY);
+
+ if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg))
+ goto err_alloc;
}
}
@@ -66,7 +73,11 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
plane_cfg = vkms_config_create_plane(config);
if (IS_ERR(plane_cfg))
goto err_alloc;
+
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_CURSOR);
+
+ if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg))
+ goto err_alloc;
}
return config;
@@ -107,7 +118,8 @@ static bool valid_plane_number(const struct vkms_config *config)
return true;
}
-static bool valid_plane_type(const struct vkms_config *config)
+static bool valid_planes_for_crtc(const struct vkms_config *config,
+ struct vkms_config_crtc *crtc_cfg)
{
struct drm_device *dev = config->dev ? &config->dev->drm : NULL;
struct vkms_config_plane *plane_cfg;
@@ -115,24 +127,31 @@ static bool valid_plane_type(const struct vkms_config *config)
bool has_cursor_plane = false;
vkms_config_for_each_plane(config, plane_cfg) {
+ struct vkms_config_crtc *possible_crtc;
+ unsigned long idx = 0;
enum drm_plane_type type;
type = vkms_config_plane_get_type(plane_cfg);
- if (type == DRM_PLANE_TYPE_PRIMARY) {
- if (has_primary_plane) {
- drm_info(dev, "Multiple primary planes\n");
- return false;
- }
+ vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) {
+ if (possible_crtc != crtc_cfg)
+ continue;
- has_primary_plane = true;
- } else if (type == DRM_PLANE_TYPE_CURSOR) {
- if (has_cursor_plane) {
- drm_info(dev, "Multiple cursor planes\n");
- return false;
- }
+ if (type == DRM_PLANE_TYPE_PRIMARY) {
+ if (has_primary_plane) {
+ drm_info(dev, "Multiple primary planes\n");
+ return false;
+ }
- has_cursor_plane = true;
+ has_primary_plane = true;
+ } else if (type == DRM_PLANE_TYPE_CURSOR) {
+ if (has_cursor_plane) {
+ drm_info(dev, "Multiple cursor planes\n");
+ return false;
+ }
+
+ has_cursor_plane = true;
+ }
}
}
@@ -144,6 +163,21 @@ static bool valid_plane_type(const struct vkms_config *config)
return true;
}
+static bool valid_plane_possible_crtcs(const struct vkms_config *config)
+{
+ struct drm_device *dev = config->dev ? &config->dev->drm : NULL;
+ struct vkms_config_plane *plane_cfg;
+
+ vkms_config_for_each_plane(config, plane_cfg) {
+ if (xa_empty(&plane_cfg->possible_crtcs)) {
+ drm_info(dev, "All planes must have at least one possible CRTC\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool valid_crtc_number(const struct vkms_config *config)
{
struct drm_device *dev = config->dev ? &config->dev->drm : NULL;
@@ -160,15 +194,22 @@ static bool valid_crtc_number(const struct vkms_config *config)
bool vkms_config_is_valid(const struct vkms_config *config)
{
+ struct vkms_config_crtc *crtc_cfg;
+
if (!valid_plane_number(config))
return false;
if (!valid_crtc_number(config))
return false;
- if (!valid_plane_type(config))
+ if (!valid_plane_possible_crtcs(config))
return false;
+ vkms_config_for_each_crtc(config, crtc_cfg) {
+ if (!valid_planes_for_crtc(config, crtc_cfg))
+ return false;
+ }
+
return true;
}
EXPORT_SYMBOL_IF_KUNIT(vkms_config_is_valid);
@@ -220,6 +261,7 @@ struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *config)
plane_cfg->config = config;
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_OVERLAY);
+ xa_init_flags(&plane_cfg->possible_crtcs, XA_FLAGS_ALLOC);
list_add_tail(&plane_cfg->link, &config->planes);
@@ -229,11 +271,45 @@ EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_plane);
void vkms_config_destroy_plane(struct vkms_config_plane *plane_cfg)
{
+ xa_destroy(&plane_cfg->possible_crtcs);
list_del(&plane_cfg->link);
kfree(plane_cfg);
}
EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_plane);
+int __must_check vkms_config_plane_attach_crtc(struct vkms_config_plane *plane_cfg,
+ struct vkms_config_crtc *crtc_cfg)
+{
+ struct vkms_config_crtc *possible_crtc;
+ unsigned long idx = 0;
+ u32 crtc_idx = 0;
+
+ if (plane_cfg->config != crtc_cfg->config)
+ return -EINVAL;
+
+ vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) {
+ if (possible_crtc == crtc_cfg)
+ return -EEXIST;
+ }
+
+ return xa_alloc(&plane_cfg->possible_crtcs, &crtc_idx, crtc_cfg,
+ xa_limit_32b, GFP_KERNEL);
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_plane_attach_crtc);
+
+void vkms_config_plane_detach_crtc(struct vkms_config_plane *plane_cfg,
+ struct vkms_config_crtc *crtc_cfg)
+{
+ struct vkms_config_crtc *possible_crtc;
+ unsigned long idx = 0;
+
+ vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) {
+ if (possible_crtc == crtc_cfg)
+ xa_erase(&plane_cfg->possible_crtcs, idx);
+ }
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_plane_detach_crtc);
+
struct vkms_config_crtc *vkms_config_create_crtc(struct vkms_config *config)
{
struct vkms_config_crtc *crtc_cfg;
@@ -254,7 +330,57 @@ EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_crtc);
void vkms_config_destroy_crtc(struct vkms_config *config,
struct vkms_config_crtc *crtc_cfg)
{
+ struct vkms_config_plane *plane_cfg;
+
+ vkms_config_for_each_plane(config, plane_cfg)
+ vkms_config_plane_detach_crtc(plane_cfg, crtc_cfg);
+
list_del(&crtc_cfg->link);
kfree(crtc_cfg);
}
EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_crtc);
+
+/**
+ * vkms_config_crtc_get_plane() - Return the first attached plane to a CRTC with
+ * the specific type
+ * @config: Configuration containing the CRTC and the plane
+ * @crtc_cfg: Only find planes attached to this CRTC
+ * @type: Plane type to search
+ *
+ * Returns:
+ * The first plane found attached to @crtc_cfg with the type @type.
+ */
+static struct vkms_config_plane *vkms_config_crtc_get_plane(const struct vkms_config *config,
+ struct vkms_config_crtc *crtc_cfg,
+ enum drm_plane_type type)
+{
+ struct vkms_config_plane *plane_cfg;
+ struct vkms_config_crtc *possible_crtc;
+ enum drm_plane_type current_type;
+ unsigned long idx = 0;
+
+ vkms_config_for_each_plane(config, plane_cfg) {
+ current_type = vkms_config_plane_get_type(plane_cfg);
+
+ vkms_config_plane_for_each_possible_crtc(plane_cfg, idx, possible_crtc) {
+ if (possible_crtc == crtc_cfg && current_type == type)
+ return plane_cfg;
+ }
+ }
+
+ return NULL;
+}
+
+struct vkms_config_plane *vkms_config_crtc_primary_plane(const struct vkms_config *config,
+ struct vkms_config_crtc *crtc_cfg)
+{
+ return vkms_config_crtc_get_plane(config, crtc_cfg, DRM_PLANE_TYPE_PRIMARY);
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_crtc_primary_plane);
+
+struct vkms_config_plane *vkms_config_crtc_cursor_plane(const struct vkms_config *config,
+ struct vkms_config_crtc *crtc_cfg)
+{
+ return vkms_config_crtc_get_plane(config, crtc_cfg, DRM_PLANE_TYPE_CURSOR);
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_crtc_cursor_plane);