From: "Màxim Pedraza Padilla" <maximpedraza@gmail.com>
To: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
Maxime Ripard <mripard@kernel.org>,
Thomas Zimmermann <tzimmermann@suse.de>,
David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Ard Biesheuvel <ardb@kernel.org>,
Jonathan Corbet <corbet@lwn.net>
Cc: Francesco Valla <francesco@valla.it>,
Mario Limonciello <mario.limonciello@amd.com>,
Javier Martinez Canillas <javierm@redhat.com>,
Jocelyn Falempe <jfalempe@redhat.com>,
Sam Ravnborg <sam@ravnborg.org>,
Ilias Apalodimas <ilias.apalodimas@linaro.org>,
Shuah Khan <skhan@linuxfoundation.org>,
Randy Dunlap <rdunlap@infradead.org>,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-efi@vger.kernel.org, linux-doc@vger.kernel.org,
linux-embedded@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH RFC v4 07/13] drm/client: splash: add a device tree image source
Date: Thu, 1 Oct 2026 21:58:41 +0200 [thread overview]
Message-ID: <20261001195847.141192-8-maximpedraza@gmail.com> (raw)
In-Reply-To: <20261001195847.141192-1-maximpedraza@gmail.com>
Embedded products often share one kernel image and one board support
package across several models that differ in branding. The splash
client can show the firmware's BGRT image or a BMP loaded as firmware,
but a device tree system has no BGRT, and a BMP loaded as firmware is
either built into the kernel, which means one kernel per logo, or read
from a filesystem that is not there yet when the display comes up. With
U-Boot's Falcon mode the SPL starts the kernel directly, and the device
tree is the only thing that reaches it.
Add a source that takes the image from a "boot-logo" node under /chosen.
The BMP either sits in the node itself, in an "image" property that dtc
fills in with /incbin/, or in a reserved memory region the bootloader
loaded it into, named by "memory-region". Exactly one of the two must be
present; a node with both or neither is ignored with a warning.
The image in the node is used where it is: the device tree stays in
memory, so there is nothing to copy or release. The region is mapped
like the BGRT image, and the BMP header is checked against its size.
A node is only there if someone put it there for that board, so the
device tree goes first, then the BGRT, then the BMP loaded as firmware.
The boolean that chose between the latter two becomes an enum naming
the one source in use.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Màxim Pedraza Padilla <maximpedraza@gmail.com>
---
drivers/gpu/drm/clients/Kconfig | 15 +++
drivers/gpu/drm/clients/drm_splash.c | 166 ++++++++++++++++++++++++---
2 files changed, 165 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/clients/Kconfig b/drivers/gpu/drm/clients/Kconfig
index cbe271c3a23f..aef3781cc110 100644
--- a/drivers/gpu/drm/clients/Kconfig
+++ b/drivers/gpu/drm/clients/Kconfig
@@ -108,6 +108,21 @@ config DRM_CLIENT_SPLASH_BACKGROUND_COLOR
The color can be overridden through the drm_client_lib.splash_color
kernel command line parameter.
+config DRM_CLIENT_SPLASH_SRC_DT
+ bool "Device tree as splash source"
+ depends on DRM_CLIENT_SPLASH
+ depends on OF
+ select DRM_CLIENT_SPLASH_BMP_SUPPORT
+ help
+ Use a BMP image described by a "boot-logo" node under /chosen in
+ the device tree, either carried in the node itself or placed by the
+ bootloader in a reserved memory region. This lets one kernel image
+ show a different logo on each board or product, chosen by the
+ device tree it boots with.
+
+ When present, the device tree image is preferred over the other
+ sources.
+
config DRM_CLIENT_SPLASH_SRC_BGRT
bool "EFI BGRT as splash source"
depends on DRM_CLIENT_SPLASH
diff --git a/drivers/gpu/drm/clients/drm_splash.c b/drivers/gpu/drm/clients/drm_splash.c
index 66c192139d9c..444f612c48ac 100644
--- a/drivers/gpu/drm/clients/drm_splash.c
+++ b/drivers/gpu/drm/clients/drm_splash.c
@@ -9,9 +9,12 @@
#include <linux/efi-bgrt.h>
#include <linux/firmware.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/iosys-map.h>
#include <linux/kthread.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_reserved_mem.h>
#include <linux/overflow.h>
#include <linux/types.h>
#include <linux/unaligned.h>
@@ -71,6 +74,14 @@ struct bmp_dib_header {
__le32 colors_important;
} __packed;
+/* Where the image comes from, in order of preference */
+enum drm_splash_source {
+ DRM_SPLASH_SRC_NONE,
+ DRM_SPLASH_SRC_DT,
+ DRM_SPLASH_SRC_BGRT,
+ DRM_SPLASH_SRC_BMP,
+};
+
struct drm_splash_scanout {
int id;
/* Modesets scanning this buffer out, by position in the list */
@@ -108,7 +119,7 @@ struct drm_splash {
const struct firmware *fw;
void *map_data;
- bool use_bgrt;
+ enum drm_splash_source src;
};
static struct drm_splash *client_to_drm_splash(struct drm_client_dev *client)
@@ -204,6 +215,114 @@ static inline int drm_splash_fw_request_bmp(struct drm_splash *splash)
}
#endif // CONFIG_DRM_CLIENT_SPLASH_SRC_BMP
+#if IS_ENABLED(CONFIG_DRM_CLIENT_SPLASH_SRC_DT)
+#define DRM_SPLASH_DT_COMPATIBLE "boot-logo"
+
+/*
+ * The boot logo node, if the device tree has a usable one. Only a child of
+ * /chosen is considered, not anything compatible anywhere in the tree: the
+ * image is configuration handed over by the firmware, not a device.
+ */
+static struct device_node *drm_splash_dt_node(struct drm_splash *splash)
+{
+ struct drm_client_dev *client = &splash->client;
+ struct device_node *np;
+ bool image, region;
+
+ np = of_get_compatible_child(of_chosen, DRM_SPLASH_DT_COMPATIBLE);
+ if (!np)
+ return NULL;
+
+ if (!of_device_is_available(np))
+ goto out_put;
+
+ image = of_property_present(np, "image");
+ region = of_property_present(np, "memory-region");
+ if (image == region) {
+ drm_warn(client->dev,
+ "splash: %pOF needs exactly one of image or memory-region",
+ np);
+ goto out_put;
+ }
+
+ return np;
+
+out_put:
+ of_node_put(np);
+ return NULL;
+}
+
+static bool drm_splash_dt_available(struct drm_splash *splash)
+{
+ struct device_node *np = drm_splash_dt_node(splash);
+
+ of_node_put(np);
+
+ return np;
+}
+
+static int drm_splash_dt_load(struct drm_splash *splash, const u8 **data,
+ size_t *size)
+{
+ struct drm_client_dev *client = &splash->client;
+ struct device_node *np;
+ struct resource res;
+ const void *prop;
+ int len, ret = 0;
+
+ np = drm_splash_dt_node(splash);
+ if (!np)
+ return -ENOENT;
+
+ /*
+ * An image in the node is used in place: the device tree stays in
+ * memory for as long as the system runs, so there is nothing to copy
+ * and nothing to release.
+ */
+ prop = of_get_property(np, "image", &len);
+ if (prop) {
+ *data = prop;
+ *size = len;
+ goto out_put;
+ }
+
+ /* Otherwise the bootloader loaded it into a reserved region */
+ ret = of_reserved_mem_region_to_resource(np, 0, &res);
+ if (ret) {
+ drm_warn(client->dev, "splash: %pOF: no usable memory-region: %d",
+ np, ret);
+ goto out_put;
+ }
+
+ splash->map_data = memremap(res.start, resource_size(&res),
+ MEMREMAP_WB);
+ if (!splash->map_data) {
+ drm_warn(client->dev, "splash: failed to map %pR", &res);
+ ret = -ENOMEM;
+ goto out_put;
+ }
+
+ /* The BMP header, checked against this size, says how much is image */
+ *data = splash->map_data;
+ *size = resource_size(&res);
+
+out_put:
+ of_node_put(np);
+ return ret;
+}
+#else
+static inline bool drm_splash_dt_available(struct drm_splash *splash)
+{
+ return false;
+}
+
+static inline int drm_splash_dt_load(struct drm_splash *splash,
+ const u8 **data, size_t *size)
+{
+ return -EOPNOTSUPP;
+}
+#endif // CONFIG_DRM_CLIENT_SPLASH_SRC_DT
+
#if IS_ENABLED(CONFIG_DRM_CLIENT_SPLASH_SRC_BGRT)
static bool drm_splash_bgrt_available(struct drm_splash *splash)
{
@@ -510,7 +629,7 @@ static int drm_splash_bmp_to_scanout(struct drm_splash *splash,
return -EINVAL;
}
- if (splash->use_bgrt) {
+ if (splash->src == DRM_SPLASH_SRC_BGRT) {
x_pad = drm_splash_bgrt_get_xoffset();
y_pad = drm_splash_bgrt_get_yoffset();
@@ -603,19 +722,34 @@ static inline int drm_splash_bmp_to_scanout(struct drm_splash *splash,
static int drm_splash_image_load(struct drm_splash *splash, const u8 **img_data,
size_t *img_data_len)
{
- int ret = 0;
-
- if (splash->use_bgrt) {
- ret = drm_splash_bgrt_load(splash, img_data, img_data_len);
- if (ret)
- splash->use_bgrt = false;
+ switch (splash->src) {
+ case DRM_SPLASH_SRC_DT:
+ return drm_splash_dt_load(splash, img_data, img_data_len);
+ case DRM_SPLASH_SRC_BGRT:
+ return drm_splash_bgrt_load(splash, img_data, img_data_len);
+ case DRM_SPLASH_SRC_BMP:
+ return drm_splash_fw_load(splash, img_data, img_data_len);
+ default:
+ return -ENOENT;
}
+}
- /* BGRT failed to load */
- if (!splash->use_bgrt)
- ret = drm_splash_fw_load(splash, img_data, img_data_len);
-
- return ret;
+/*
+ * Pick the one source the image will come from. A device tree node is only
+ * there if someone put it there for this board, so it goes first; the BGRT
+ * is whatever the firmware shows, and the BMP loaded as firmware is the
+ * fallback. With none of them, only the background colour is drawn.
+ */
+static enum drm_splash_source drm_splash_pick_source(struct drm_splash *splash)
+{
+ if (drm_splash_dt_available(splash))
+ return DRM_SPLASH_SRC_DT;
+ if (drm_splash_bgrt_available(splash))
+ return DRM_SPLASH_SRC_BGRT;
+ if (IS_ENABLED(CONFIG_DRM_CLIENT_SPLASH_SRC_BMP))
+ return DRM_SPLASH_SRC_BMP;
+
+ return DRM_SPLASH_SRC_NONE;
}
static void drm_splash_image_cleanup(struct drm_splash *splash)
@@ -911,10 +1045,10 @@ static int drm_splash_client_hotplug(struct drm_client_dev *client)
get_task_struct(thread);
splash->thread = thread;
- splash->use_bgrt = drm_splash_bgrt_available(splash);
+ splash->src = drm_splash_pick_source(splash);
- /* If no other image has been loaded, try to load a BMP as firmware */
- if (IS_ENABLED(CONFIG_DRM_CLIENT_SPLASH_SRC_BMP) && !splash->use_bgrt) {
+ /* The BMP loaded as firmware is the only source that arrives later */
+ if (splash->src == DRM_SPLASH_SRC_BMP) {
WRITE_ONCE(splash->fw_pending, true);
ret = drm_splash_fw_request_bmp(splash);
splash->fw_requested = !ret;
--
2.39.5
next prev parent reply other threads:[~2026-10-01 19:59 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 19:58 [PATCH RFC v4 00/13] Add splash DRM client Màxim Pedraza Padilla
2026-10-01 19:58 ` [PATCH RFC v4 01/13] drm/clients: Kconfig: indent DRM_CLIENT_DEFAULT with tabs Màxim Pedraza Padilla
2026-10-01 19:58 ` [PATCH RFC v4 02/13] efi: bgrt: export the BGRT table and image size Màxim Pedraza Padilla
2026-10-01 19:58 ` [PATCH RFC v4 03/13] drm: client: add splash client Màxim Pedraza Padilla
2026-10-01 19:58 ` [PATCH RFC v4 04/13] MAINTAINERS: add entry for DRM " Màxim Pedraza Padilla
2026-10-01 19:58 ` [PATCH RFC v4 05/13] drm: docs: remove bootsplash from TODO Màxim Pedraza Padilla
2026-10-01 19:58 ` [PATCH RFC v4 06/13] dt-bindings: display: add a boot logo node under /chosen Màxim Pedraza Padilla
2026-10-01 19:58 ` Màxim Pedraza Padilla [this message]
2026-10-01 19:58 ` [PATCH RFC v4 08/13] drm/client: splash: place the device tree image where it asks Màxim Pedraza Padilla
2026-10-01 19:58 ` [PATCH RFC v4 09/13] drm/client: splash: turn the device tree image as " Màxim Pedraza Padilla
2026-10-01 19:58 ` [PATCH RFC v4 10/13] drm/client: splash: take the background colour from the image source Màxim Pedraza Padilla
2026-10-01 19:58 ` [PATCH RFC v4 11/13] drm/client: splash: turn the BGRT image on panels mounted turned Màxim Pedraza Padilla
2026-10-01 19:58 ` [PATCH RFC v4 12/13] drm/client: splash: prefer what the command line asks for Màxim Pedraza Padilla
2026-10-01 19:58 ` [PATCH RFC v4 13/13] drm/client: splash: document the image sources and parameters Màxim Pedraza Padilla
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=20261001195847.141192-8-maximpedraza@gmail.com \
--to=maximpedraza@gmail.com \
--cc=airlied@gmail.com \
--cc=ardb@kernel.org \
--cc=conor+dt@kernel.org \
--cc=corbet@lwn.net \
--cc=devicetree@vger.kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=francesco@valla.it \
--cc=ilias.apalodimas@linaro.org \
--cc=javierm@redhat.com \
--cc=jfalempe@redhat.com \
--cc=krzk+dt@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-efi@vger.kernel.org \
--cc=linux-embedded@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mario.limonciello@amd.com \
--cc=mripard@kernel.org \
--cc=rdunlap@infradead.org \
--cc=robh@kernel.org \
--cc=sam@ravnborg.org \
--cc=simona@ffwll.ch \
--cc=skhan@linuxfoundation.org \
--cc=tzimmermann@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®