From: Max Pedraza <maximpedraza@gmail.com>
To: Helge Deller <deller@gmx.de>
Cc: Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Thomas Zimmermann <tzimmermann@suse.de>,
Maxime Ripard <mripard@kernel.org>,
linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
Max Pedraza <maximpedraza@gmail.com>
Subject: [RFC PATCH 2/6] video: logo: allow the boot logo to come from the device tree
Date: Fri, 31 Jul 2026 23:50:39 +0200 [thread overview]
Message-ID: <20260731215043.30392-3-maximpedraza@gmail.com> (raw)
In-Reply-To: <20260731215043.30392-1-maximpedraza@gmail.com>
With CONFIG_LOGO_DT_CLUT224 enabled, look for a node compatible with
"linux,boot-logo-clut224" and, when one is present and enabled, use the
image it carries in preference to the logos built into the kernel image.
This lets a single kernel image serve several products, or several
revisions of one product, that differ only in branding, at the cost of a
larger device tree blob.
The image is validated while it is parsed: the palette must be at most 224
entries, the pixel data length must match the declared geometry, and every
pixel must reference an existing palette entry. A malformed node is
reported and ignored, falling back to the built-in logo.
The two allocations live for as long as the built-in logos do; they are
released from fb_logo_late_init(), next to where the __initdata logos are
marked as freed.
If the node is absent or disabled, behaviour is unchanged.
Signed-off-by: Max Pedraza <maximpedraza@gmail.com>
---
drivers/video/logo/Kconfig | 13 +++
drivers/video/logo/logo.c | 157 +++++++++++++++++++++++++++++++++++++
2 files changed, 170 insertions(+)
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index ce6bb7535..4af349b20 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -70,4 +70,17 @@ config LOGO_SUPERH_CLUT224
depends on SUPERH
default y
+config LOGO_DT_CLUT224
+ bool "224-color logo supplied by the device tree"
+ depends on OF
+ help
+ Look for a boot logo in the device tree, in a node compatible with
+ "linux,boot-logo-clut224", instead of using one of the logos built
+ into the kernel image. This allows a single kernel image to be used
+ by several products that only differ in branding, at the cost of
+ making the device tree blob larger.
+
+ If no such node is present, or it is disabled, the built-in logo
+ selected above is used, so saying Y here is safe. If unsure, say N.
+
endif # LOGO
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 141f15a9a..b4f533df0 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -11,6 +11,9 @@
*/
#include <linux/linux_logo.h>
+#include <linux/of.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
#include <linux/stddef.h>
#include <linux/module.h>
@@ -22,6 +25,155 @@ static bool nologo;
module_param(nologo, bool, 0);
MODULE_PARM_DESC(nologo, "Disables startup logo");
+#ifdef CONFIG_LOGO_DT_CLUT224
+
+#define LOGO_DT_COMPATIBLE "linux,boot-logo-clut224"
+#define LOGO_DT_MAX_CLUT 224
+/*
+ * The first 32 palette entries are reserved for the console, so the logo
+ * colours start at index 32. That is an implementation detail of the frame
+ * buffer layer rather than a property of the image, so the device tree stores
+ * plain indices and the offset is applied here.
+ */
+#define LOGO_DT_CLUT_OFFSET 32
+/* Sanity limit on the image size, a device tree is not a good place for more */
+#define LOGO_DT_MAX_PIXELS SZ_32M
+
+static struct linux_logo logo_dt_clut224 = {
+ .type = LINUX_LOGO_CLUT224,
+};
+
+static unsigned char *logo_dt_clut;
+static unsigned char *logo_dt_data;
+
+static int logo_dt_parse(struct device_node *np)
+{
+ unsigned int clutsize, npixels, i;
+ unsigned char *clut, *data;
+ u32 width, height;
+ int len, ret;
+
+ ret = of_property_read_u32(np, "width", &width);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(np, "height", &height);
+ if (ret)
+ return ret;
+
+ if (!width || !height || (u64)width * height > LOGO_DT_MAX_PIXELS)
+ return -EINVAL;
+
+ npixels = width * height;
+
+ len = of_property_count_u8_elems(np, "clut");
+ if (len < 3 || len % 3)
+ return -EINVAL;
+
+ clutsize = len / 3;
+ if (clutsize > LOGO_DT_MAX_CLUT)
+ return -EINVAL;
+
+ ret = of_property_count_u8_elems(np, "data");
+ if (ret < 0)
+ return ret;
+ if ((unsigned int)ret != npixels)
+ return -EINVAL;
+
+ clut = kmalloc(len, GFP_KERNEL);
+ if (!clut)
+ return -ENOMEM;
+
+ data = kmalloc(npixels, GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto err_free_clut;
+ }
+
+ ret = of_property_read_u8_array(np, "clut", clut, len);
+ if (ret)
+ goto err_free_data;
+
+ ret = of_property_read_u8_array(np, "data", data, npixels);
+ if (ret)
+ goto err_free_data;
+
+ for (i = 0; i < npixels; i++) {
+ if (data[i] >= clutsize) {
+ ret = -ERANGE;
+ goto err_free_data;
+ }
+ data[i] += LOGO_DT_CLUT_OFFSET;
+ }
+
+ logo_dt_clut = clut;
+ logo_dt_data = data;
+
+ logo_dt_clut224.width = width;
+ logo_dt_clut224.height = height;
+ logo_dt_clut224.clutsize = clutsize;
+ logo_dt_clut224.clut = clut;
+ logo_dt_clut224.data = data;
+
+ return 0;
+
+err_free_data:
+ kfree(data);
+err_free_clut:
+ kfree(clut);
+ return ret;
+}
+
+static const struct linux_logo *logo_dt_find(void)
+{
+ static bool probed;
+ struct device_node *np;
+ int ret;
+
+ if (probed)
+ return logo_dt_data ? &logo_dt_clut224 : NULL;
+
+ probed = true;
+
+ np = of_find_compatible_node(NULL, NULL, LOGO_DT_COMPATIBLE);
+ if (!np)
+ return NULL;
+
+ if (of_device_is_available(np)) {
+ ret = logo_dt_parse(np);
+ if (ret)
+ pr_warn("logo: ignoring malformed %pOF node (%d)\n",
+ np, ret);
+ }
+
+ of_node_put(np);
+
+ return logo_dt_data ? &logo_dt_clut224 : NULL;
+}
+
+static void logo_dt_free(void)
+{
+ logo_dt_clut224.clut = NULL;
+ logo_dt_clut224.data = NULL;
+
+ kfree(logo_dt_clut);
+ logo_dt_clut = NULL;
+
+ kfree(logo_dt_data);
+ logo_dt_data = NULL;
+}
+
+#else /* !CONFIG_LOGO_DT_CLUT224 */
+
+static inline const struct linux_logo *logo_dt_find(void)
+{
+ return NULL;
+}
+
+static inline void logo_dt_free(void) { }
+
+#endif /* CONFIG_LOGO_DT_CLUT224 */
+
/*
* Logos are located in the initdata, and will be freed in kernel_init.
* Use late_init to mark the logos as freed to prevent any further use.
@@ -32,6 +184,7 @@ static bool logos_freed;
static int __init fb_logo_late_init(void)
{
logos_freed = true;
+ logo_dt_free();
return 0;
}
@@ -71,6 +224,10 @@ const struct linux_logo * __ref fb_find_logo(int depth)
}
if (depth >= 8) {
+ /* A logo supplied by the device tree wins over the built-in ones */
+ logo = logo_dt_find();
+ if (logo)
+ return logo;
#ifdef CONFIG_LOGO_LINUX_CLUT224
/* Generic Linux logo */
logo = &logo_linux_clut224;
--
2.39.5
next prev parent reply other threads:[~2026-07-31 21:50 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-31 21:50 [RFC PATCH 0/6] Boot logo supplied by the device tree Max Pedraza
2026-07-31 21:50 ` [RFC PATCH 1/6] dt-bindings: display: add a device tree supplied boot logo Max Pedraza
2026-07-31 21:50 ` Max Pedraza [this message]
2026-07-31 21:50 ` [RFC PATCH 3/6] fbdev: honour the device tree boot logo placement properties Max Pedraza
2026-07-31 21:50 ` [RFC PATCH 4/6] dt-bindings: display: allow the boot logo in a reserved memory region Max Pedraza
2026-07-31 21:50 ` [RFC PATCH 5/6] video: logo: allow the boot logo to come from " Max Pedraza
2026-07-31 21:50 ` [RFC PATCH 6/6] video: logo: add ppmtodtlogo host tool Max Pedraza
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=20260731215043.30392-3-maximpedraza@gmail.com \
--to=maximpedraza@gmail.com \
--cc=conor+dt@kernel.org \
--cc=deller@gmx.de \
--cc=devicetree@vger.kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=krzk+dt@kernel.org \
--cc=linux-fbdev@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mripard@kernel.org \
--cc=robh@kernel.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