All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Noralf Trønnes" <noralf@tronnes.org>
To: dri-devel@lists.freedesktop.org
Cc: daniel.vetter@ffwll.ch, intel-gfx@lists.freedesktop.org,
	"Noralf Trønnes" <noralf@tronnes.org>,
	laurent.pinchart@ideasonboard.com, mstaudt@suse.de,
	dh.herrmann@gmail.com
Subject: [RFC v4 24/25] drm/client: Hack: Add bootsplash
Date: Thu, 12 Apr 2018 18:12:36 +0200	[thread overview]
Message-ID: <20180412161237.9314-13-noralf@tronnes.org> (raw)
In-Reply-To: <20180412161237.9314-1-noralf@tronnes.org>

A hack to test the client API.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/Kconfig                 |   2 +
 drivers/gpu/drm/Makefile                |   1 +
 drivers/gpu/drm/client/Kconfig          |   9 ++
 drivers/gpu/drm/client/drm_bootsplash.c | 248 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/client/internal.h       |  19 +++
 drivers/gpu/drm/drm_client.c            |   4 +
 6 files changed, 283 insertions(+)
 create mode 100644 drivers/gpu/drm/client/Kconfig
 create mode 100644 drivers/gpu/drm/client/drm_bootsplash.c
 create mode 100644 drivers/gpu/drm/client/internal.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 757825ac60df..1328202ce17d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -154,6 +154,8 @@ config DRM_SCHED
 	tristate
 	depends on DRM
 
+source "drivers/gpu/drm/client/Kconfig"
+
 source "drivers/gpu/drm/i2c/Kconfig"
 
 source "drivers/gpu/drm/arm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index d25afa136d8f..388527093f80 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -30,6 +30,7 @@ drm-$(CONFIG_OF) += drm_of.o
 drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
+drm-$(CONFIG_DRM_CLIENT_BOOTSPLASH) += client/drm_bootsplash.o
 
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
 		drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
diff --git a/drivers/gpu/drm/client/Kconfig b/drivers/gpu/drm/client/Kconfig
new file mode 100644
index 000000000000..6b01f2e51fb3
--- /dev/null
+++ b/drivers/gpu/drm/client/Kconfig
@@ -0,0 +1,9 @@
+menu "DRM Clients"
+	depends on DRM
+
+config DRM_CLIENT_BOOTSPLASH
+	bool "DRM Bootsplash"
+	help
+	  DRM Bootsplash
+
+endmenu
diff --git a/drivers/gpu/drm/client/drm_bootsplash.c b/drivers/gpu/drm/client/drm_bootsplash.c
new file mode 100644
index 000000000000..bec3105f9b02
--- /dev/null
+++ b/drivers/gpu/drm/client/drm_bootsplash.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/keyboard.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include <drm/drm_client.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_print.h>
+
+// drm_lastclose()
+#include <drm/drmP.h>
+#include "drm_internal.h"
+
+static bool drm_bootsplash_enabled = true;
+module_param_named(bootsplash_enabled, drm_bootsplash_enabled, bool, 0600);
+MODULE_PARM_DESC(bootsplash_enabled, "Enable bootsplash client [default=true]");
+
+struct drm_bootsplash {
+	struct drm_client_dev *client;
+	struct drm_client_display *display;
+	struct drm_client_buffer *buffer[2];
+	struct work_struct worker;
+	bool stop;
+};
+
+static bool drm_bootsplash_key_pressed;
+
+static int drm_bootsplash_keyboard_notifier_call(struct notifier_block *blk,
+				  unsigned long code, void *_param)
+{
+	/* Any key is good */
+	drm_bootsplash_key_pressed = true;
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block drm_bootsplash_keyboard_notifier_block = {
+	.notifier_call = drm_bootsplash_keyboard_notifier_call,
+};
+
+static u32 drm_bootsplash_color_table[3] = {
+	0x00ff0000, 0x0000ff00, 0x000000ff,
+};
+
+/* Draw a box with changing colors */
+static void
+drm_bootsplash_draw(struct drm_client_buffer *buffer, unsigned int sequence)
+{
+	unsigned int x, y;
+	u32 *pix;
+
+	pix = buffer->vaddr;
+	pix += ((buffer->height / 2) - 50) * buffer->width;
+	pix += (buffer->width / 2) - 50;
+
+	for (y = 0; y < 100; y++) {
+		for (x = 0; x < 100; x++)
+			*pix++ = drm_bootsplash_color_table[sequence];
+		pix += buffer->width - 100;
+	}
+}
+
+static void drm_bootsplash_worker(struct work_struct *work)
+{
+	struct drm_bootsplash *splash = container_of(work, struct drm_bootsplash, worker);
+	struct drm_device *dev = splash->client->dev;
+	unsigned int i = 0, sequence = 0;
+	struct drm_framebuffer *fb;
+	int ret = 0;
+
+	while (!splash->stop && !drm_bootsplash_key_pressed) {
+		/* Did someone take over, like another in-kernel client, except fbdev? */
+		fb = drm_client_display_current_fb(splash->display);
+		if (splash->buffer[i]->fb != fb &&
+		    !(dev->fb_helper && dev->fb_helper->fb == fb))
+			break;
+
+		i = !i;
+		drm_bootsplash_draw(splash->buffer[i], sequence++);
+		if (sequence == 3)
+			sequence = 0;
+
+		ret = drm_client_display_commit(splash->display, splash->buffer[i]->fb, NULL);
+		/* Is userspace in charge or is the device unplugged? */
+		if (ret == -EBUSY || ret == -ENODEV)
+			break;
+
+		msleep(500);
+	}
+
+	/* Restore fbdev (or other) on key press. */
+	/* TODO: Check if it's OK to call drm_lastclose here. */
+	if (drm_bootsplash_key_pressed)
+		drm_lastclose(dev);
+
+	for (i = 0; i < 2; i++)
+		drm_client_framebuffer_delete(splash->buffer[i]);
+	drm_client_display_free(splash->display);
+	drm_client_remove_defer(splash->client);
+	DRM_DEV_DEBUG_KMS(dev->dev, "Bootsplash has stopped (key=%u stop=%u ret=%d).\n",
+			  drm_bootsplash_key_pressed, splash->stop, ret);
+}
+
+static int drm_bootsplash_setup(struct drm_bootsplash *splash)
+{
+	struct drm_client_dev *client = splash->client;
+	struct drm_client_buffer *buffer[2];
+	struct drm_client_display *display;
+	int ret, i;
+
+	display = drm_client_find_display(client->dev, 0, 0);
+	if (IS_ERR(display))
+		return PTR_ERR(display);
+	if (!display)
+		return -ENOENT;
+
+	if (WARN_ON(!display->mode))
+		return -ENOENT;
+
+	for (i = 0; i < 2; i++) {
+		buffer[i] = drm_client_framebuffer_create(client, display->mode,
+							  DRM_FORMAT_XRGB8888);
+		if (IS_ERR(buffer[i])) {
+			ret = PTR_ERR(buffer[i]);
+			goto err_free_buffer;
+		}
+	}
+
+	ret = drm_client_display_commit(display, buffer[0]->fb, display->mode);
+	if (ret)
+		goto err_free_buffer;
+
+	splash->display = display;
+	splash->buffer[0] = buffer[0];
+	splash->buffer[1] = buffer[1];
+
+	schedule_work(&splash->worker);
+
+	return 0;
+
+err_free_buffer:
+	for (i--; i >= 0; i--)
+		drm_client_framebuffer_delete(buffer[i]);
+	drm_client_display_free(display);
+
+	return ret;
+}
+
+static int drm_bootsplash_client_hotplug(struct drm_client_dev *client)
+{
+	struct drm_bootsplash *splash = client->private;
+	int ret = 0;
+
+	if (splash->display)
+		return 0;
+
+	ret = drm_bootsplash_setup(splash);
+	if (ret) {
+		DRM_DEV_DEBUG_KMS(client->dev->dev, "ret=%d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int drm_bootsplash_client_remove(struct drm_client_dev *client)
+{
+	struct drm_bootsplash *splash = client->private;
+
+	/* Don't hook up to any new devices showing up */
+	drm_bootsplash_enabled = false;
+
+	splash->stop = true;
+	flush_work(&splash->worker);
+	kfree(splash);
+
+	return 0;
+}
+
+static const struct drm_client_funcs drm_bootsplash_client_funcs = {
+	.name		= "bootsplash",
+	.remove		= drm_bootsplash_client_remove,
+	.hotplug	= drm_bootsplash_client_hotplug,
+};
+
+static int drm_bootsplash_dev_notify(struct notifier_block *nb,
+				     unsigned long action, void *data)
+{
+	struct drm_device *dev = data;
+	struct drm_client_dev *client;
+	struct drm_bootsplash *splash;
+
+	if (!drm_bootsplash_enabled)
+		return 0;
+
+	splash = kzalloc(sizeof(*splash), GFP_KERNEL);
+	if (!splash)
+		return 0;
+
+	client = drm_client_new(dev, &drm_bootsplash_client_funcs);
+	if (IS_ERR(client)) {
+		DRM_DEV_ERROR(dev->dev, "Failed to create client, ret=%ld\n", PTR_ERR(client));
+		kfree(splash);
+		return 0;
+	}
+
+	INIT_WORK(&splash->worker, drm_bootsplash_worker);
+
+	splash->client = client;
+	client->private = splash;
+
+	/*
+	 * vc4 isn't done with it's setup when drm_dev_register() is called.
+	 * It should have shouldn't it?
+	 * So to keep it from crashing defer setup to hotplug...
+	 */
+	if (client->dev->mode_config.max_width)
+		drm_bootsplash_client_hotplug(client);
+
+	return 0;
+}
+
+static struct notifier_block drm_bootsplash_dev_notifier = {
+	.notifier_call	= drm_bootsplash_dev_notify,
+};
+
+void drm_bootsplash_register(void)
+{
+	register_keyboard_notifier(&drm_bootsplash_keyboard_notifier_block);
+
+	if (!drm_bootsplash_enabled)
+		return;
+
+	drm_dev_register_notifier(&drm_bootsplash_dev_notifier);
+}
+
+void drm_bootsplash_unregister(void)
+{
+	drm_dev_unregister_notifier(&drm_bootsplash_dev_notifier);
+	unregister_keyboard_notifier(&drm_bootsplash_keyboard_notifier_block);
+}
diff --git a/drivers/gpu/drm/client/internal.h b/drivers/gpu/drm/client/internal.h
new file mode 100644
index 000000000000..22e2120c493b
--- /dev/null
+++ b/drivers/gpu/drm/client/internal.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _DRM_CLIENT_INTERNAL_H_
+#define _DRM_CLIENT_INTERNAL_H_
+
+#ifdef CONFIG_DRM_CLIENT_BOOTSPLASH
+void drm_bootsplash_register(void);
+void drm_bootsplash_unregister(void);
+#else
+static inline void drm_bootsplash_register(void)
+{
+}
+
+static inline void drm_bootsplash_unregister(void)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 760f1795f812..cd8c084c8801 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -24,6 +24,7 @@
 
 #include "drm_crtc_internal.h"
 #include "drm_internal.h"
+#include "client/internal.h"
 
 struct drm_client_display_offset {
 	int x, y;
@@ -234,10 +235,13 @@ EXPORT_SYMBOL(drm_client_remove_defer);
 
 void drm_client_init(void)
 {
+	drm_bootsplash_register();
 }
 
 void drm_client_exit(void)
 {
+	drm_bootsplash_unregister();
+
 	flush_work(&drm_client_remove_defer_work);
 }
 
-- 
2.15.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

  parent reply	other threads:[~2018-04-12 16:12 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-12 16:12 [RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 13/25] drm/fb-helper: Remove struct drm_fb_helper_crtc Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 14/25] drm/fb-helper: Remove struct drm_fb_helper_connector Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 15/25] drm/fb-helper: Move modeset config code to drm_client Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 16/25] drm: Make ioctls available for in-kernel clients Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 17/25] drm/client: Bail out if there's a DRM master Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 18/25] drm/client: Make the display modes available to clients Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 19/25] drm/client: Finish the in-kernel client API Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 20/25] drm/prime: Don't pin module on export for in-kernel clients Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 21/25] drm/fb-helper: Add drm_fb_helper_fb_open/release() Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 23/25] drm: Add DRM device registered notifier Noralf Trønnes
2018-04-12 16:12 ` Noralf Trønnes [this message]
2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
2018-04-14 11:53 ` [RFC v4 24/25] drm/client: Hack: Add bootsplash Noralf Trønnes

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180412161237.9314-13-noralf@tronnes.org \
    --to=noralf@tronnes.org \
    --cc=daniel.vetter@ffwll.ch \
    --cc=dh.herrmann@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=mstaudt@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.