@@ -18,7 +18,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_encoder.o drm_mode_object.o drm_property.o \
drm_plane.o drm_color_mgmt.o drm_print.o \
drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
- drm_syncobj.o drm_lease.o
+ drm_syncobj.o drm_lease.o drm_client.o
drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
drm-$(CONFIG_DRM_VM) += drm_vm.o
new file mode 100644
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018 Noralf Trønnes
+ *
+ * For parts copied from drm_fb_helper:
+ * Copyright (c) 2006-2009 Red Hat Inc.
+ * Copyright (c) 2006-2008 Intel Corporation
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ */
+
+#include <linux/slab.h>
+
+#include <drm/drm_client.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_modes.h>
+
+/**
+ * drm_client_display_create() - Create display structure
+ * @dev: DRM device
+ *
+ * This function creates a display structure for clients backed by an array of
+ * &drm_mode_set, one per CRTC.
+ *
+ * Returns:
+ * A &drm_client_display or an error pointer on allocation failure.
+ */
+struct drm_client_display *drm_client_display_create(struct drm_device *dev)
+{
+ unsigned int num_crtc = dev->mode_config.num_crtc;
+ struct drm_client_display *display;
+ struct drm_mode_set *modeset;
+ struct drm_crtc *crtc;
+ unsigned int i = 0;
+
+ display = kzalloc(sizeof(*display), GFP_KERNEL);
+ if (!display)
+ return ERR_PTR(-ENOMEM);
+
+ /* Add NULL terminating entry to enable index less iteration */
+ display->modesets = kcalloc(num_crtc + 1, sizeof(*display->modesets), GFP_KERNEL);
+ if (!display->modesets) {
+ kfree(display);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ display->dev = dev;
+ display->modeset_count = num_crtc;
+
+ drm_for_each_crtc(crtc, dev)
+ display->modesets[i++].crtc = crtc;
+
+ drm_client_display_for_each_modeset(modeset, display) {
+ /* One connector per crtc except for the cloned case */
+ modeset->connectors = kcalloc(2, sizeof(*modeset->connectors), GFP_KERNEL);
+ if (!modeset->connectors)
+ goto err_free;
+ }
+
+ return display;
+
+err_free:
+ drm_client_display_free(display);
+
+ return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL(drm_client_display_create);
+
+/**
+ * drm_client_display_free() - Free display structure
+ * @display: Client display
+ *
+ * This function frees the structure allocated by drm_client_display_create().
+ * It also destroys display modes and puts connectors.
+ */
+void drm_client_display_free(struct drm_client_display *display)
+{
+ struct drm_mode_set *modeset;
+ unsigned int i;
+
+ if (!display)
+ return;
+
+ drm_client_display_for_each_modeset(modeset, display) {
+ if (modeset->mode)
+ drm_mode_destroy(display->dev, modeset->mode);
+
+ for (i = 0; i < modeset->num_connectors; i++)
+ drm_connector_put(modeset->connectors[i]);
+ kfree(modeset->connectors);
+ }
+ kfree(display->modesets);
+ kfree(display);
+}
+EXPORT_SYMBOL(drm_client_display_free);
+
+/**
+ * drm_client_display_find_modeset() - Find modeset matching a CRTC
+ * @display: Client display
+ * @crtc: CRTC
+ *
+ * This function looks up the @display modeset connected to @crtc.
+ *
+ * Returns:
+ * A &drm_mode_set or NULL.
+ */
+struct drm_mode_set *
+drm_client_display_find_modeset(struct drm_client_display *display, struct drm_crtc *crtc)
+{
+ struct drm_mode_set *modeset;
+
+ drm_client_display_for_each_modeset(modeset, display)
+ if (modeset->crtc == crtc)
+ return modeset;
+
+ return NULL;
+}
+EXPORT_SYMBOL(drm_client_display_find_modeset);
new file mode 100644
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _DRM_CLIENT_H_
+#define _DRM_CLIENT_H_
+
+struct drm_crtc;
+struct drm_device;
+struct drm_mode_set;
+
+/**
+ * struct drm_client_display - DRM client display
+ */
+struct drm_client_display {
+ /**
+ * @dev:
+ *
+ * DRM device.
+ */
+ struct drm_device *dev;
+
+ /**
+ * @modesets:
+ *
+ * Per CRTC array of modeset configurations.
+ */
+ struct drm_mode_set *modesets;
+
+ /**
+ * @modeset_count:
+ *
+ * Number of modesets
+ */
+ unsigned int modeset_count;
+};
+
+struct drm_client_display *drm_client_display_create(struct drm_device *dev);
+void drm_client_display_free(struct drm_client_display *display);
+struct drm_mode_set *
+drm_client_display_find_modeset(struct drm_client_display *display, struct drm_crtc *crtc);
+
+#define drm_client_display_for_each_modeset(modeset, display) \
+ for (modeset = display->modesets; modeset->crtc; modeset++)
+
+#endif
This the beginning of an API for in-kernel clients. First out is a display representation that will be used by drm_fb_helper in order to move out its mode setting code. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> --- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_client.c | 119 +++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_client.h | 44 ++++++++++++++++ 3 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_client.c create mode 100644 include/drm/drm_client.h