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 3/6] fbdev: honour the device tree boot logo placement properties
Date: Fri, 31 Jul 2026 23:50:40 +0200 [thread overview]
Message-ID: <20260731215043.30392-4-maximpedraza@gmail.com> (raw)
In-Reply-To: <20260731215043.30392-1-maximpedraza@gmail.com>
A logo supplied by the device tree describes a specific product, so where
it lands on the panel matters in a way it does not for the built-in Tux.
Honour the optional "logo-position", "logo-offset", "logo-centered" and
"logo-rotation" properties of the "linux,boot-logo-clut224" node.
The rotation is folded into the rotate argument at the entry points, so
fb_prepare_logo() reserves the right amount of space and fb_do_show_logo()
tiles in the same direction the image was rotated in.
Placement is applied after fb_rotate_logo(), since a rotation swaps the
image width and height and centring needs the final dimensions.
fb_prepare_logo() has to grow its reservation to cover wherever the logo
ends up, the way fb_center_logo already does: fbcon only leaves the first
n rows alone, so a logo placed further down is drawn and then immediately
cleared by the console.
"logo-centered" is deliberately close to the existing fb_center_logo, but
it is per device tree rather than per fbcon command line, and it composes
with "logo-offset" so that a logo can be centred and then nudged. That
combination is what panels with a partially visible area need, where the
usable region is not the centre of the mode.
Signed-off-by: Max Pedraza <maximpedraza@gmail.com>
---
drivers/video/fbdev/core/fb_logo.c | 174 +++++++++++++++++++++++++++++
1 file changed, 174 insertions(+)
diff --git a/drivers/video/fbdev/core/fb_logo.c b/drivers/video/fbdev/core/fb_logo.c
index 0bab8352b..bfc1b72ce 100644
--- a/drivers/video/fbdev/core/fb_logo.c
+++ b/drivers/video/fbdev/core/fb_logo.c
@@ -2,12 +2,178 @@
#include <linux/fb.h>
#include <linux/linux_logo.h>
+#include <linux/of.h>
#include "fb_internal.h"
bool fb_center_logo __read_mostly;
int fb_logo_count __read_mostly = -1;
+#ifdef CONFIG_LOGO_DT_CLUT224
+
+/*
+ * Placement of a logo supplied by the device tree. The image itself is parsed
+ * by drivers/video/logo/logo.c, here we only care about where it goes.
+ */
+struct fb_logo_dt_placement {
+ bool valid;
+ bool centered;
+ bool has_position;
+ int rotation; /* FB_ROTATE_*, or -1 when unspecified */
+ u32 x, y;
+ s32 offset_x, offset_y;
+};
+
+static struct fb_logo_dt_placement fb_logo_dt;
+
+static int fb_logo_dt_parse_rotation(const char *rotation)
+{
+ if (!strcmp(rotation, "none"))
+ return FB_ROTATE_UR;
+ if (!strcmp(rotation, "cw"))
+ return FB_ROTATE_CW;
+ if (!strcmp(rotation, "ud"))
+ return FB_ROTATE_UD;
+ if (!strcmp(rotation, "ccw"))
+ return FB_ROTATE_CCW;
+
+ return -EINVAL;
+}
+
+static void fb_logo_dt_read(void)
+{
+ struct fb_logo_dt_placement *p = &fb_logo_dt;
+ static bool read_done;
+ struct device_node *np;
+ const char *rotation;
+ u32 val[2];
+ int rot;
+
+ if (read_done)
+ return;
+
+ read_done = true;
+
+ np = of_find_compatible_node(NULL, NULL, "linux,boot-logo-clut224");
+ if (!np)
+ return;
+
+ if (!of_device_is_available(np))
+ goto out;
+
+ p->valid = true;
+ p->rotation = -1;
+ p->centered = of_property_read_bool(np, "logo-centered");
+
+ if (!of_property_read_u32_array(np, "logo-position", val, 2)) {
+ p->has_position = true;
+ p->x = val[0];
+ p->y = val[1];
+ }
+
+ if (!of_property_read_u32_array(np, "logo-offset", val, 2)) {
+ p->offset_x = (s32)val[0];
+ p->offset_y = (s32)val[1];
+ }
+
+ if (!of_property_read_string(np, "logo-rotation", &rotation)) {
+ rot = fb_logo_dt_parse_rotation(rotation);
+ if (rot < 0)
+ pr_warn("fb: %pOF: unknown logo-rotation \"%s\"\n",
+ np, rotation);
+ else
+ p->rotation = rot;
+ }
+
+out:
+ of_node_put(np);
+}
+
+static int fb_logo_dt_rotation(int rotate)
+{
+ fb_logo_dt_read();
+
+ if (fb_logo_dt.valid && fb_logo_dt.rotation >= 0)
+ return fb_logo_dt.rotation;
+
+ return rotate;
+}
+
+/* Top edge of the logo, in the coordinate space the caller works in */
+static int fb_logo_dt_top(unsigned int yres, unsigned int logo_height)
+{
+ struct fb_logo_dt_placement *p = &fb_logo_dt;
+ int top;
+
+ if (p->centered)
+ top = ((int)yres - (int)logo_height) / 2;
+ else if (p->has_position)
+ top = p->y;
+ else
+ top = 0;
+
+ return max(top + p->offset_y, 0);
+}
+
+static void fb_logo_dt_place(struct fb_info *info, struct fb_image *image)
+{
+ struct fb_logo_dt_placement *p = &fb_logo_dt;
+ int dx;
+
+ fb_logo_dt_read();
+
+ if (!p->valid)
+ return;
+
+ if (p->centered)
+ dx = ((int)info->var.xres - (int)image->width) / 2;
+ else if (p->has_position)
+ dx = p->x;
+ else
+ dx = image->dx;
+
+ image->dx = max(dx + p->offset_x, 0);
+ image->dy = fb_logo_dt_top(info->var.yres, image->height);
+}
+
+/*
+ * fbcon only leaves the first @height rows of the screen alone, so a logo
+ * placed further down would be drawn and then immediately cleared. Grow the
+ * reservation to cover wherever the logo actually ends up, the same way
+ * fb_center_logo does.
+ */
+static int fb_logo_dt_reserve(unsigned int yres, unsigned int logo_height,
+ int height)
+{
+ fb_logo_dt_read();
+
+ if (!fb_logo_dt.valid)
+ return height;
+
+ return max(height, fb_logo_dt_top(yres, logo_height) +
+ (int)logo_height);
+}
+
+#else /* !CONFIG_LOGO_DT_CLUT224 */
+
+static inline int fb_logo_dt_rotation(int rotate)
+{
+ return rotate;
+}
+
+static inline void fb_logo_dt_place(struct fb_info *info,
+ struct fb_image *image)
+{
+}
+
+static inline int fb_logo_dt_reserve(unsigned int yres,
+ unsigned int logo_height, int height)
+{
+ return height;
+}
+
+#endif /* CONFIG_LOGO_DT_CLUT224 */
+
static inline unsigned int safe_shift(unsigned int d, int n)
{
return n < 0 ? d >> -n : d << n;
@@ -350,6 +516,9 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
fb_rotate_logo(info, logo_rotate, &image, rotate);
}
+ /* Done last, image dimensions are only final after the rotation */
+ fb_logo_dt_place(info, &image);
+
fb_do_show_logo(info, &image, rotate, n);
kfree(palette);
@@ -423,6 +592,8 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
memset(&fb_logo, 0, sizeof(struct logo_data));
+ rotate = fb_logo_dt_rotation(rotate);
+
if (info->flags & FBINFO_MISC_TILEBLITTING ||
info->fbops->owner || !fb_logo_count)
return 0;
@@ -483,6 +654,7 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
height = fb_logo.logo->height;
if (fb_center_logo)
height += (yres - fb_logo.logo->height) / 2;
+ height = fb_logo_dt_reserve(yres, fb_logo.logo->height, height);
#ifdef CONFIG_FB_LOGO_EXTRA
height = fb_prepare_extra_logos(info, height, yres);
#endif
@@ -498,6 +670,8 @@ int fb_show_logo(struct fb_info *info, int rotate)
if (!fb_logo_count)
return 0;
+ rotate = fb_logo_dt_rotation(rotate);
+
count = fb_logo_count < 0 ? num_online_cpus() : fb_logo_count;
y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, count);
#ifdef CONFIG_FB_LOGO_EXTRA
--
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 ` [RFC PATCH 2/6] video: logo: allow the boot logo to come from the device tree Max Pedraza
2026-07-31 21:50 ` Max Pedraza [this message]
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-4-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 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.