[PATCH 06/10] drm/client: Add a way to set modeset, properties and rotation

Noralf Trønnes
2020-04-29T12:57:59Z

This adds functions for clients that need more control over the
configuration than what's setup by drm_client_modeset_probe().
Connector, fb and display mode can be set using drm_client_modeset_set().
Plane rotation can be set using drm_client_modeset_set_rotation() and
other properties using drm_client_modeset_set_property(). Property
setting is only implemented for atomic drivers.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/gpu/drm/drm_client_modeset.c | 139 +++++++++++++++++++++++++++
include/drm/drm_client.h | 38 +++++++-
2 files changed, 176 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index 177158ff2a40..1eef6869cae1 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -83,6 +83,10 @@ static void drm_client_modeset_release(struct drm_client_dev *client)
}
modeset->num_connectors = 0;
}
+
+ kfree(client->properties);
+ client->properties = NULL;
+ client->num_properties = 0;
}

void drm_client_modeset_free(struct drm_client_dev *client)
@@ -879,6 +883,132 @@ int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width,
}
EXPORT_SYMBOL(drm_client_modeset_probe);

+/**
+ * drm_client_modeset_set() - Set modeset configuration
+ * @client: DRM client
+ * @connector: Connector
+ * @mode: Display mode
+ * @fb: Framebuffer
+ *
+ * This function releases any current modeset info, including properties, and
+ * sets the new modeset in the client's modeset array.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_modeset_set(struct drm_client_dev *client, struct drm_connector *connector,
+ struct drm_display_mode *mode, struct drm_framebuffer *fb)
+{
+ struct drm_mode_set *modeset;
+ int ret = -ENOENT;
+
+ mutex_lock(&client->modeset_mutex);
+
+ drm_client_modeset_release(client);
+
+ if (!connector || !mode || !fb) {
+ ret = 0;
+ goto unlock;
+ }
+
+ drm_client_for_each_modeset(modeset, client) {
+ if (!connector_has_possible_crtc(connector, modeset->crtc))
+ continue;
+
+ modeset->mode = drm_mode_duplicate(client->dev, mode);
+ if (!modeset->mode) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ drm_mode_set_crtcinfo(modeset->mode, CRTC_INTERLACE_HALVE_V);
+
+ drm_connector_get(connector);
+ modeset->connectors[modeset->num_connectors++] = connector;
+
+ modeset->fb = fb;
+ ret = 0;
+ break;
+ }
+unlock:
+ mutex_unlock(&client->modeset_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_client_modeset_set);
+
+/**
+ * drm_client_modeset_set_property() - Set a property on the current configuration
+ * @client: DRM client
+ * @obj: DRM Mode Object
+ * @prop: DRM Property
+ * @value: Property value
+ *
+ * Note: Currently only implemented for atomic drivers.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_modeset_set_property(struct drm_client_dev *client, struct drm_mode_object *obj,
+ struct drm_property *prop, u64 value)
+{
+ struct drm_client_property *properties;
+ int ret = 0;
+
+ if (!prop)
+ return -EINVAL;
+
+ mutex_lock(&client->modeset_mutex);
+
+ properties = krealloc(client->properties,
+ (client->num_properties + 1) * sizeof(*properties), GFP_KERNEL);
+ if (!properties) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ properties[client->num_properties].obj = obj;
+ properties[client->num_properties].prop = prop;
+ properties[client->num_properties].value = value;
+ client->properties = properties;
+ client->num_properties++;
+unlock:
+ mutex_unlock(&client->modeset_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_client_modeset_set_property);
+
+/**
+ * drm_client_modeset_set_rotation() - Set rotation on the current configuration
+ * @client: DRM client
+ * @value: Rotation value
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_modeset_set_rotation(struct drm_client_dev *client, u64 value)
+{
+ struct drm_plane *plane = NULL;
+ struct drm_mode_set *modeset;
+
+ mutex_lock(&client->modeset_mutex);
+ drm_client_for_each_modeset(modeset, client) {
+ if (modeset->mode) {
+ plane = modeset->crtc->primary;
+ break;
+ }
+ }
+ mutex_unlock(&client->modeset_mutex);
+
+ if (!plane)
+ return -ENOENT;
+
+ return drm_client_modeset_set_property(client, &plane->base,
+ plane->rotation_property, value);
+}
+EXPORT_SYMBOL(drm_client_modeset_set_rotation);
+
/**
* drm_client_rotation() - Check the initial rotation value
* @modeset: DRM modeset
@@ -973,6 +1103,7 @@ static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool
struct drm_atomic_state *state;
struct drm_modeset_acquire_ctx ctx;
struct drm_mode_set *mode_set;
+ unsigned int i;
int ret;

drm_modeset_acquire_init(&ctx, 0);
@@ -1033,6 +1164,14 @@ static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool
}
}

+ for (i = 0; i < client->num_properties; i++) {
+ struct drm_client_property *prop = &client->properties[i];
+
+ ret = drm_atomic_set_property(state, NULL, prop->obj, prop->prop, prop->value);
+ if (ret)
+ goto out_state;
+ }
+
if (check)
ret = drm_atomic_check_only(state);
else
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index b6ffa4863e45..4b266741ec0e 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -16,6 +16,7 @@ struct drm_file;
struct drm_framebuffer;
struct drm_gem_object;
struct drm_minor;
+struct drm_property;
struct module;

/**
@@ -64,6 +65,26 @@ struct drm_client_funcs {
int (*hotplug)(struct drm_client_dev *client);
};

+/**
+ * struct drm_client_property - DRM client property
+ */
+struct drm_client_property {
+ /**
+ * @obj: DRM Mode Object to which the property belongs.
+ */
+ struct drm_mode_object *obj;
+
+ /**
+ * @prop: DRM Property.
+ */
+ struct drm_property *prop;
+
+ /**
+ * @value: Property value.
+ */
+ u64 value;
+};
+
/**
* struct drm_client_dev - DRM client instance
*/
@@ -97,7 +118,7 @@ struct drm_client_dev {
struct drm_file *file;

/**
- * @modeset_mutex: Protects @modesets.
+ * @modeset_mutex: Protects @modesets and @properties.
*/
struct mutex modeset_mutex;

@@ -105,6 +126,16 @@ struct drm_client_dev {
* @modesets: CRTC configurations
*/
struct drm_mode_set *modesets;
+
+ /**
+ * @properties: DRM properties attached to the configuration.
+ */
+ struct drm_client_property *properties;
+
+ /**
+ * @num_properties: Number of attached properties.
+ */
+ unsigned int num_properties;
};

int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
@@ -163,6 +194,11 @@ void drm_client_buffer_vunmap(struct drm_client_buffer *buffer);
int drm_client_modeset_create(struct drm_client_dev *client);
void drm_client_modeset_free(struct drm_client_dev *client);
int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height);
+int drm_client_modeset_set(struct drm_client_dev *client, struct drm_connector *connector,
+ struct drm_display_mode *mode, struct drm_framebuffer *fb);
+int drm_client_modeset_set_property(struct drm_client_dev *client, struct drm_mode_object *obj,
+ struct drm_property *prop, u64 value);
+int drm_client_modeset_set_rotation(struct drm_client_dev *client, u64 value);
bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
int drm_client_modeset_check(struct drm_client_dev *client);
int drm_client_modeset_commit_locked(struct drm_client_dev *client);
--
2.23.0