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>, Helge Deller <deller@gmx.de>,
Peter Jones <pjones@redhat.com>
Cc: Francesco Valla <francesco@valla.it>,
Jani Nikula <jani.nikula@linux.intel.com>,
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-fbdev@vger.kernel.org,
linux-doc@vger.kernel.org, linux-embedded@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v6 11/15] drm/client: splash: turn the device tree image as it asks
Date: Tue, 27 Oct 2026 14:53:38 +0100 [thread overview]
Message-ID: <20261027135342.2003632-12-maximpedraza@gmail.com> (raw)
In-Reply-To: <20261027135342.2003632-1-maximpedraza@gmail.com>
Let the device tree node ask for the image to be turned, for a logo
drawn in one orientation and meant to be seen in another, with a
"rotation" property counting degrees counter clockwise, as panels
already do and as DRM_MODE_ROTATE_* count, which is what it is kept as.
It describes the image only: a panel mounted turned is described on the
panel, and a later patch in this series makes the splash follow it.
The rotation turns the image and not the screen: "logo-position" and
"logo-offset" stay in screen pixels, and a quarter turn only swaps how
much room the image takes up. Placing it in a frame that turned with it
would make the same pair of coordinates mean different places on the
same panel, decided by a property that describes the image.
The turn happens in the first of the two drawing steps, which reads
the BMP into an XRGB8888 buffer: it walks the source through the
rotation, so the buffer holds the image as it is to be seen. The second
step, into the framebuffer's format, does not change.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Màxim Pedraza Padilla <maximpedraza@gmail.com>
---
drivers/gpu/drm/clients/drm_splash.c | 109 +++++++++++++++++++++++----
1 file changed, 93 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/clients/drm_splash.c b/drivers/gpu/drm/clients/drm_splash.c
index 81070547390f..a50036155763 100644
--- a/drivers/gpu/drm/clients/drm_splash.c
+++ b/drivers/gpu/drm/clients/drm_splash.c
@@ -28,6 +28,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
+#include <drm/drm_mode.h>
#include <drm/drm_plane.h>
#include <drm/drm_print.h>
@@ -114,6 +115,8 @@ struct drm_splash {
*/
s32 pos_x, pos_y;
s32 off_x, off_y;
+ /* One of DRM_MODE_ROTATE_*: turns the image, not the screen */
+ unsigned int rotation;
};
static struct drm_splash *client_to_drm_splash(struct drm_client_dev *client)
@@ -273,10 +276,34 @@ static void drm_splash_dt_pair(struct drm_splash *splash,
static void drm_splash_dt_placement(struct drm_splash *splash,
struct device_node *np)
{
+ u32 val;
+
drm_splash_dt_pair(splash, np, "logo-position", -1, 65535,
&splash->pos_x, &splash->pos_y);
drm_splash_dt_pair(splash, np, "logo-offset", -65535, 65535,
&splash->off_x, &splash->off_y);
+
+ /* Degrees counter clockwise, as for panels, and as DRM counts them */
+ if (!of_property_read_u32(np, "rotation", &val)) {
+ switch (val) {
+ case 0:
+ splash->rotation = DRM_MODE_ROTATE_0;
+ break;
+ case 90:
+ splash->rotation = DRM_MODE_ROTATE_90;
+ break;
+ case 180:
+ splash->rotation = DRM_MODE_ROTATE_180;
+ break;
+ case 270:
+ splash->rotation = DRM_MODE_ROTATE_270;
+ break;
+ default:
+ drm_warn(splash->client.dev,
+ "splash: %pOF: unsupported rotation %u\n",
+ np, val);
+ }
+ }
}
/*
@@ -494,19 +521,59 @@ static unsigned int drm_splash_place_axis(s32 pos, s32 off, unsigned int span,
return clamp_t(s64, coord + off, 0, last);
}
-/* The rows of a 24 bpp BMP, bottom up or top down, upright in XRGB8888 */
-static void drm_splash_bmp_decode(u32 *dst, const u8 *src, unsigned int spitch,
+/*
+ * The pixels of a 24 bpp BMP, whose rows go bottom up or top down, into
+ * XRGB8888, turned by @rotation, one of DRM_MODE_ROTATE_*, which count
+ * counter clockwise. A quarter turn swaps width and height in @dst.
+ *
+ * Each source pixel is three bytes read on their own, since a BMP row is
+ * only padded to four bytes as a whole and the image need not be aligned.
+ */
+static void drm_splash_bmp_decode(u32 *dst, const u8 *sbuf8, unsigned int spitch,
unsigned int width, unsigned int height,
- bool invert_y)
+ bool invert_y, unsigned int rotation)
{
+ bool quarter = rotation & (DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270);
+ unsigned int dw = quarter ? height : width;
+ unsigned int dh = quarter ? width : height;
+ /* A positive BMP height stores the rows bottom up */
+ ptrdiff_t down = invert_y ? -(ptrdiff_t)spitch : spitch;
+ const u8 *first = sbuf8 + (invert_y ? (height - 1) * spitch : 0);
+ const u8 *last = first + (height - 1) * down;
+ ptrdiff_t step_x, step_y;
+ const u8 *src, *p;
unsigned int x, y;
- for (y = 0; y < height; y++) {
- const u8 *p = src + (invert_y ? height - 1 - y : y) * spitch;
+ /*
+ * Where the source pixel for the top left of the turned image is, and
+ * how far one step right and one step down in it move in the source
+ */
+ switch (rotation) {
+ case DRM_MODE_ROTATE_90:
+ src = first + 3 * (width - 1);
+ step_x = down;
+ step_y = -3;
+ break;
+ case DRM_MODE_ROTATE_180:
+ src = last + 3 * (width - 1);
+ step_x = -3;
+ step_y = -down;
+ break;
+ case DRM_MODE_ROTATE_270:
+ src = last;
+ step_x = -down;
+ step_y = 3;
+ break;
+ default:
+ src = first;
+ step_x = 3;
+ step_y = down;
+ break;
+ }
- for (x = 0; x < width; x++, p += 3)
+ for (y = 0; y < dh; y++, src += step_y)
+ for (x = 0, p = src; x < dw; x++, p += step_x)
*dst++ = get_unaligned_le24(p);
- }
}
/* An XRGB8888 image into a buffer of another format, at x0, y0 */
@@ -564,7 +631,7 @@ static int drm_splash_bmp_to_scanout(struct drm_splash *splash,
bool bmp_invert_y;
u32 bitmap_offset;
size_t row_len, pixels_len, end;
- unsigned int x_pad, y_pad;
+ unsigned int x_pad, y_pad, img_w, img_h;
const u8 *image_data;
struct iosys_map map;
struct drm_rect r;
@@ -629,7 +696,16 @@ static int drm_splash_bmp_to_scanout(struct drm_splash *splash,
}
bmp_pitch = row_len & ~(size_t)3;
- if (bmp_width > scanout->width || bmp_height > scanout->height) {
+ /* The room the image takes up on screen, once turned */
+ if (splash->rotation & (DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270)) {
+ img_w = bmp_height;
+ img_h = bmp_width;
+ } else {
+ img_w = bmp_width;
+ img_h = bmp_height;
+ }
+
+ if (img_w > scanout->width || img_h > scanout->height) {
drm_err(client->dev, "splash: BMP image is too big for the screen\n");
return -EINVAL;
}
@@ -662,19 +738,19 @@ static int drm_splash_bmp_to_scanout(struct drm_splash *splash,
#endif
} else {
x_pad = drm_splash_place_axis(splash->pos_x, splash->off_x,
- scanout->width, bmp_width);
+ scanout->width, img_w);
y_pad = drm_splash_place_axis(splash->pos_y, splash->off_y,
- scanout->height, bmp_height);
+ scanout->height, img_h);
}
image_data = data + bitmap_offset;
- /* First the image upright in XRGB8888, then into the buffer's format */
+ /* First the image turned in XRGB8888, then into the buffer's format */
img = kvmalloc_array(bmp_width, bmp_height * sizeof(*img), GFP_KERNEL);
if (!img)
return -ENOMEM;
drm_splash_bmp_decode(img, image_data, bmp_pitch, bmp_width, bmp_height,
- bmp_invert_y);
+ bmp_invert_y, splash->rotation);
ret = drm_client_buffer_vmap_local(buffer, &map);
if (ret) {
@@ -683,9 +759,9 @@ static int drm_splash_bmp_to_scanout(struct drm_splash *splash,
return ret;
}
- r = DRM_RECT_INIT(x_pad, y_pad, bmp_width, bmp_height);
+ r = DRM_RECT_INIT(x_pad, y_pad, img_w, img_h);
drm_splash_blit(&map, fb->pitches[0], fb->format, x_pad, y_pad, img,
- bmp_width, bmp_height);
+ img_w, img_h);
kvfree(img);
drm_client_buffer_vunmap_local(buffer);
@@ -1184,9 +1260,10 @@ void drm_splash_register(struct drm_device *dev,
mutex_init(&splash->lock);
init_completion(&splash->fw_done);
- /* Centred unless the image source asks otherwise */
+ /* Centred and upright unless the image source asks otherwise */
splash->pos_x = -1;
splash->pos_y = -1;
+ splash->rotation = DRM_MODE_ROTATE_0;
if (format && format->num_planes == 1) {
splash->preferred_format = format->format;
--
2.39.5
next prev parent reply other threads:[~2026-10-27 13:54 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 13:53 [PATCH v6 00/15] Add splash DRM client Màxim Pedraza Padilla
2026-10-27 13:53 ` [PATCH v6 01/15] drm/clients: Kconfig: indent DRM_CLIENT_DEFAULT with tabs Màxim Pedraza Padilla
2026-10-27 13:53 ` [PATCH v6 02/15] efi: bgrt: add accessors for the boot graphics Màxim Pedraza Padilla
2026-10-27 13:53 ` [PATCH v6 03/15] fbdev: efifb: move the BMP headers to <video/bmp.h> Màxim Pedraza Padilla
2026-10-27 13:53 ` [PATCH v6 04/15] drm: client: add splash client Màxim Pedraza Padilla
2026-10-27 14:19 ` sashiko-bot
2026-10-27 13:53 ` [PATCH v6 05/15] MAINTAINERS: add entry for DRM " Màxim Pedraza Padilla
2026-10-27 13:53 ` [PATCH v6 06/15] drm: docs: remove bootsplash from TODO Màxim Pedraza Padilla
2026-10-27 13:53 ` [PATCH v6 07/15] dt-bindings: display: add a boot logo node under /chosen Màxim Pedraza Padilla
2026-10-27 18:59 ` Rob Herring (Arm)
2026-10-27 13:53 ` [PATCH v6 08/15] drm/client: splash: pick the image source in one place Màxim Pedraza Padilla
2026-10-27 13:53 ` [PATCH v6 09/15] drm/client: splash: add a device tree image source Màxim Pedraza Padilla
2026-10-27 13:53 ` [PATCH v6 10/15] drm/client: splash: place the device tree image where it asks Màxim Pedraza Padilla
2026-10-27 13:53 ` Màxim Pedraza Padilla [this message]
2026-10-27 13:53 ` [PATCH v6 12/15] drm/client: splash: take the background colour from the image source Màxim Pedraza Padilla
2026-10-27 13:53 ` [PATCH v6 13/15] drm/client: splash: turn the BGRT image on panels mounted turned Màxim Pedraza Padilla
2026-10-27 13:53 ` [PATCH v6 14/15] drm/client: splash: follow the connector's orientation Màxim Pedraza Padilla
2026-10-27 13:53 ` [PATCH v6 15/15] drm/client: splash: document the image sources 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=20261027135342.2003632-12-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=deller@gmx.de \
--cc=devicetree@vger.kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=francesco@valla.it \
--cc=ilias.apalodimas@linaro.org \
--cc=jani.nikula@linux.intel.com \
--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-fbdev@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=pjones@redhat.com \
--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 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.