@@ -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;
@@ -91,6 +114,7 @@ struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_conf
vkms_config_overlay->supported_color_range = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
BIT(DRM_COLOR_YCBCR_FULL_RANGE);
vkms_config_overlay->default_color_range = DRM_COLOR_YCBCR_FULL_RANGE;
+ xa_init_flags(&vkms_config_overlay->possible_crtcs, XA_FLAGS_ALLOC);
list_add(&vkms_config_overlay->link, &vkms_config->planes);
@@ -98,33 +122,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
@@ -144,22 +330,47 @@ bool vkms_config_is_valid(struct vkms_config *config)
BIT(config_plane->default_color_range))
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;
}
@@ -171,8 +382,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);
@@ -189,6 +401,15 @@ static int vkms_config_show(struct seq_file *m, void *data)
config_plane->default_color_range);
}
+ 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;
}
@@ -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_crtc *crtc;
+};
+
+/**
+ * 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;
};
/**
@@ -36,6 +77,7 @@ struct vkms_config {
* @supported_color_encoding: Color encoding that this plane will support
* @default_color_range: Default color range that should be used by this plane
* @supported_color_range: Color range 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.
@@ -52,6 +94,7 @@ struct vkms_config_plane {
enum drm_color_range default_color_range;
unsigned int supported_color_range;
+ struct xarray possible_crtcs;
/* Internal usage */
struct vkms_plane *plane;
};
@@ -86,14 +129,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
@@ -9,6 +9,7 @@
#include <drm/drm_managed.h>
#include "vkms_drv.h"
+#include "vkms_config.h"
static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
{
@@ -279,9 +280,12 @@ static void vkms_crtc_destroy_workqueue(struct drm_device *dev,
destroy_workqueue(vkms_crtc->composer_workq);
}
-struct vkms_crtc *vkms_crtc_init(struct drm_device *dev, struct drm_plane *primary,
- struct drm_plane *cursor)
+struct vkms_crtc *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_crtc *vkms_crtc;
struct drm_crtc *crtc;
int ret;
@@ -318,5 +322,11 @@ struct vkms_crtc *vkms_crtc_init(struct drm_device *dev, struct drm_plane *prima
if (ret)
return ERR_PTR(ret);
+ if (config->writeback) {
+ ret = vkms_enable_writeback_connector(vkms_device, vkms_crtc);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+
return vkms_crtc;
}
@@ -214,6 +214,8 @@ struct vkms_crtc {
struct vkms_config;
struct vkms_config_plane;
+struct vkms_config_crtc;
+struct vkms_config_encoder;
/**
* struct vkms_device - Description of a VKMS device
@@ -252,9 +254,10 @@ struct vkms_device {
* @primary: primary plane to attach to the CRTC
* @cursor: plane to attach to the CRTC
*/
-struct vkms_crtc *vkms_crtc_init(struct drm_device *dev,
+struct vkms_crtc *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.
@@ -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_crtc *vkms_crtc;
- struct vkms_plane *primary, *cursor = NULL;
+ unsigned long idx;
int ret;
- int writeback;
-
- vkms_crtc = vkms_crtc_init(dev, &primary->base,
- cursor ? &cursor->base : NULL);
- if (IS_ERR(vkms_crtc)) {
- DRM_ERROR("Failed to allocate CRTC\n");
- return PTR_ERR(vkms_crtc);
- }
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->crtc = vkms_crtc_init(vkmsdev, primary, cursor, config_crtc);
+
+ if (IS_ERR(config_crtc->crtc)) {
+ ret = PTR_ERR(config_crtc->crtc);
+ 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->crtc->base);
+ }
}
connector = drmm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
@@ -74,33 +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(&vkms_crtc->base);
-
- /* 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, vkms_crtc);
- 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->crtc->base);
+ }
+ 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);
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 | 14 +- drivers/gpu/drm/vkms/vkms_drv.h | 7 +- drivers/gpu/drm/vkms/vkms_output.c | 86 ++++++------ 5 files changed, 405 insertions(+), 75 deletions(-)