.../display/linux,boot-logo-clut224.yaml | 152 +++++++ MAINTAINERS | 1 + drivers/video/fbdev/core/fb_logo.c | 174 ++++++++ drivers/video/logo/Kconfig | 13 + drivers/video/logo/Makefile | 6 +- drivers/video/logo/logo.c | 256 +++++++++++ drivers/video/logo/ppmtodtlogo.c | 402 ++++++++++++++++++ 7 files changed, 1003 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/display/linux,boot-logo-clut224.yaml create mode 100644 drivers/video/logo/ppmtodtlogo.c
This series lets the logo be described by the device tree instead: a node
compatible with "linux,boot-logo-clut224" under /chosen supplies the image in
the same paletted format the built-in CLUT224 logos already use, and the kernel
prefers it over the built-in ones when it is present and enabled. If the
node is absent or disabled, nothing changes.
The image can come from the node itself (patches 1-2) or from a reserved
memory region the bootloader filled in (patches 4-5), because the image and
its placement are independent axes of variation. One board sold to several
customers wants several device trees differing in the logo. One customer
with several products built on that board, with different panels, wants the
same logo placed differently on each: there the image belongs in a shared
binary and only the placement belongs in the device tree. Patch 3 adds that
placement.
We have been carrying a cruder version of this downstream on an AM335x
product since 2020, across a handful of board revisions, and it has removed
a real maintenance burden for us. This is an attempt to find out whether
something along these lines is wanted upstream, and if so in what shape --
hence RFC.
The v1 discussion turned on the obvious objection, that a bitmap is not
hardware and the device tree is not where it belongs. Geert pointed out that
configuration which is not hardware description goes under /chosen, and that
Open Firmware, which the device tree descends from, already carried a boot
logo in that spirit as the oem-logo variable under /options. The node has
moved to /chosen accordingly, which is also where simple-framebuffer nodes
live, for the same reason: they describe what firmware handed over rather
than what the hardware is.
Patches 4 and 5 are separable; the series is useful without them if the
reserved memory path is thought to be one mechanism too many.
Not included, though it exists in our downstream version: a hook in
drm_fb_helper so the logo is drawn when CONFIG_FRAMEBUFFER_CONSOLE is
disabled, which is the common case for a product that only wants a splash
screen. Today fb_show_logo() is reached from fbcon alone. That is a DRM
question rather than an fbdev one and deserves a separate posting.
Notes on the binding:
- The palette size is derived from the length of the "clut" property
instead of being a separate property, so it cannot disagree with the
palette actually supplied.
- "data" holds plain palette indices. The 32 entry offset the frame
buffer layer reserves for the console is an implementation detail and
is applied by the kernel.
- "logo-position" and "logo-offset" are spelled with the prefix because
plain "position" and "offset" are already used elsewhere in the tree
with an incompatible type, which dtschema rejects.
- "logo-centered" overlaps with the existing fb_center_logo, but it is
per device tree rather than per fbcon command line, and it composes
with "logo-offset". That combination is what panels with a partially
visible area need, where the usable region is not the centre of the
mode; the hardware this came from is an 800x480 panel of which only the
bottom 320 rows are visible.
- The reserved memory path takes a "memory-region" phandle rather than a
bare address. The reservation is what makes the memory safe to read at
all, and it is what gives the kernel a size to bounds check against.
The byte arrays are not written by hand: patch 6 adds ppmtodtlogo, a host
tool along the lines of the existing pnmtologo -- plain C, no dependencies,
no quantization of its own -- that turns a PPM image into the node or into
the memory region blob. It is what produced everything tested below.
Testing: build tested for arm with CONFIG_LOGO_DT_CLUT224 both enabled and
disabled, W=1 clean, checkpatch --strict clean, dt_binding_check clean. The
schema was also checked against deliberately malformed nodes, including
supplying both image sources at once and neither.
Boot tested under qemu-system-arm -M versatilepb with PL111 and fbcon, at
16bpp, both ways round. A 160x120 logo placed with "logo-centered" plus a
"logo-offset" of <0 120> lands at exactly the expected coordinates, and every
pixel matches the source image once the source is truncated to RGB565.
Supplying the same image through a reserved region instead produces a screen
whose logo area is identical. Blobs with a bad magic, a geometry larger than
the reservation and an out of range pixel are each rejected with a warning
and fall back to the built-in logo, with no crash.
That boot test earned its keep: the first version of patch 3 drew the logo
correctly and then had it erased, because fb_prepare_logo() still reserved
only the logo's own height while the logo itself had been moved further
down. Nothing in the build or the static checks catches that.
Also boot tested on real hardware with this exact tree: an AM335x board
(tilcdc) with an 800x480 panel, running the master this series is based on.
The product logo comes up where expected both ways, carried in the device
tree and taken from a bootloader-loaded reserved memory region, with the node
under /chosen and nothing reported in either case. That system
builds without CONFIG_FRAMEBUFFER_CONSOLE, so the drawing there goes through
the separate drm_fb_helper hook mentioned above as not included; the parsing,
validation and placement exercised are those of this series.
Changes since v1:
- Rebased onto Linus' master; v1 was based on the v6.19.14 stable release
and did not apply anywhere useful. Sorry for the noise.
- The node moved under /chosen, per Geert's observation that this is where
non-hardware configuration belongs. The binding and the tool follow.
- The binding notes that a product logo is normally covered by trademark or
copyright of its owner and that such a device tree is expected to be kept
with the product, after Ulrich raised the licensing angle.
- Dropped the second binding example: with the node under /chosen both
examples define /chosen/logo and dtc merges them, which then fails the
oneOf. The reserved memory form is documented on the property itself.
Max Pedraza (6):
dt-bindings: display: add a device tree supplied boot logo
video: logo: allow the boot logo to come from the device tree
fbdev: honour the device tree boot logo placement properties
dt-bindings: display: allow the boot logo in a reserved memory region
video: logo: allow the boot logo to come from a reserved memory region
video: logo: add ppmtodtlogo host tool
.../display/linux,boot-logo-clut224.yaml | 152 +++++++
MAINTAINERS | 1 +
drivers/video/fbdev/core/fb_logo.c | 174 ++++++++
drivers/video/logo/Kconfig | 13 +
drivers/video/logo/Makefile | 6 +-
drivers/video/logo/logo.c | 256 +++++++++++
drivers/video/logo/ppmtodtlogo.c | 402 ++++++++++++++++++
7 files changed, 1003 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/display/linux,boot-logo-clut224.yaml
create mode 100644 drivers/video/logo/ppmtodtlogo.c
--
2.39.5
On Wed, Aug 05, 2026 at 12:56:11AM +0200, Max Pedraza wrote: > This series lets the logo be described by the device tree instead: a node > compatible with "linux,boot-logo-clut224" under /chosen supplies the image in > the same paletted format the built-in CLUT224 logos already use, and the kernel > prefers it over the built-in ones when it is present and enabled. If the > node is absent or disabled, nothing changes. Why is this linux specific? Don't people want to do a splash screen in u-boot or other firmware? > > The image can come from the node itself (patches 1-2) or from a reserved > memory region the bootloader filled in (patches 4-5), because the image and > its placement are independent axes of variation. One board sold to several > customers wants several device trees differing in the logo. One customer > with several products built on that board, with different panels, wants the > same logo placed differently on each: there the image belongs in a shared > binary and only the placement belongs in the device tree. Patch 3 adds that > placement. > > We have been carrying a cruder version of this downstream on an AM335x > product since 2020, across a handful of board revisions, and it has removed > a real maintenance burden for us. This is an attempt to find out whether > something along these lines is wanted upstream, and if so in what shape -- > hence RFC. > > The v1 discussion turned on the obvious objection, that a bitmap is not > hardware and the device tree is not where it belongs. Geert pointed out that > configuration which is not hardware description goes under /chosen, and that > Open Firmware, which the device tree descends from, already carried a boot > logo in that spirit as the oem-logo variable under /options. The node has > moved to /chosen accordingly, which is also where simple-framebuffer nodes > live, for the same reason: they describe what firmware handed over rather > than what the hardware is. What does /options/oem-logo look like? Why can't that be used? > Patches 4 and 5 are separable; the series is useful without them if the > reserved memory path is thought to be one mechanism too many. If you are going to put it in memory, why not just draw it into the simple-framebuffer? Rob
El mié, 5 ago 2026 a las 16:09, Rob Herring (<robh@kernel.org>) escribió:
> Why is this linux specific? Don't people want to do a splash screen in
> u-boot or other firmware?
You are right, and I had not questioned the name. Looking at chosen.yaml,
the split is clear: the "linux," properties are kernel-internal structures
(initrd, kexec handover, the UEFI memory map), while anything a second
implementation could reasonably consume has no prefix at all -- bootargs,
bootsource, stdout-path, kaslr-seed. A boot logo is squarely in the second
group, and simple-framebuffer, which this sits next to, carries no vendor
prefix either.
There is a second Linux-ism in there that your question made me notice:
the 224 in the format. That is 256 minus the 32 palette entries fbcon
reserves for the console, which means nothing outside Linux. The 32 entry
offset itself is already applied by the kernel rather than by the binding,
so it is only the limit that leaks.
Rather than guess at the shape you would want, I would rather ask, since
both the name and the format follow from your answer.
On the name: dropping the prefix would give something like
"boot-logo-clut224", or "boot-logo" with the format named by a property.
Is a bare, unprefixed compatible acceptable here, the way
simple-framebuffer is, or would you rather see this described some other
way entirely?
On the format, two options that I can see:
a) Keep a palette, but allow the full 256 entries, so that the limit
Linux applies is a kernel limitation rather than part of the binding.
b) Reuse the simple-framebuffer vocabulary, format = "r5g6b5" and so on,
with raw pixels.
I lean towards (a), because the palette is what makes carrying the image
in the device tree viable at all: our own 800x480 logo is 17 KiB paletted
and 768 KiB raw. But (b) reuses an existing vocabulary instead of adding
one, and if you prefer it the reserved memory form still covers our case,
so the in-tree image could go entirely.
I will follow whichever you think is right; I would just rather not
respin the binding twice.
> What does /options/oem-logo look like? Why can't that be used?
Two reasons, and the second is the real one.
It is fixed at 64x64 monochrome (IEEE 1275-1994), stored in NVRAM. As a
precedent for "firmware may carry a logo" it is exactly right, which is
why the binding cites it, but it cannot express a product logo on a
modern panel.
More importantly, /options is the wrong node for something the kernel
reads. Its own schema in dt-schema says it is "for passing data into and
between firmware components" and that "it is ignored by operating
systems", while /chosen is firmware to OS. So the oem-logo precedent
argues for the idea and /chosen for the location, which is where Geert
pointed the node in v2.
> If you are going to put it in memory, why not just draw it into the
> simple-framebuffer?
I did not know about simplefb, and that is worth saying plainly: this
started as a patch against 4.19 for a product, simpledrm did not exist
then (5.14), and I never went looking for what the alternative would be
today. So thank you for the question.
I spent today testing it on the board rather than arguing about it. The
result is that it does not work here, and I could not make it work:
- Added a simple-framebuffer node under /chosen pointing at U-Boot's
framebuffer, with the region declared in reserved-memory. simpledrm
binds cleanly at 0.62s and registers fb0. Nothing is visible.
- The panel is dark for that entire window. The backlight is a
pwm-backlight owned by the panel, and it is drm_panel_enable() that
calls backlight_enable() (drm_panel.c), which only happens at the
native driver's modeset, around 2.2s. So for as long as
simple-framebuffer is the only driver, there is no light.
- Forced the backlight on from probe with a local hack to pwm_bl.c, so
the panel is lit from about 1s. The image is still not there.
- Disabled the LCDC target module in the device tree entirely and booted
with clk_ignore_unused, so that nothing in Linux touches the
controller and it keeps whatever U-Boot left. Still nothing.
- Repeated all of it with simplefb instead of simpledrm. Same result.
- Read back the framebuffer memory through fb0 after boot: all zeros.
So the pixels are gone by the time Linux can show them, and I have not
found what clears them. I can say what it is not: not the choice of
driver, not the modeset, and not the backlight. Somewhere between U-Boot
jumping to the kernel and simpledrm probing, this platform stops
displaying that memory.
One smaller thing I noticed on the way: tilcdc came up as card1 and
simpledrm stayed on card0, with no conflicting-framebuffer removal
between them. Two DRM devices with the real one second is not a state I
would want to ship either.
There is also a case against this that does not depend on our hardware at
all. U-Boot's Falcon mode boots the kernel straight from SPL, skipping
U-Boot proper, and display initialisation normally lives in U-Boot proper
rather than in SPL. On a Falcon boot there is therefore no firmware splash
to hand over and nothing for a simple-framebuffer node to point at. That is
not an obscure corner either: Falcon mode exists to shorten boot time,
which is the same reason one cares about how early the logo appears in the
first place. A logo the kernel can draw itself works the same way in both
cases.
I am not claiming the experimental result above generalises. It may well be
specific to AM335x, or to how our U-Boot hands over. But on the hardware
this series exists for, a firmware-drawn splash does not survive into the
kernel, and the logo has to be drawn again once the native driver owns the
display. That is the gap the series fills, and the reserved memory region
is what gives the kernel the pixels to do it with.
Max
© 2016 - 2026 Red Hat, Inc.