From nobody Fri Oct 2 12:19:51 2026 Received: from mail-wr1-f54.google.com (mail-wr1-f54.google.com [209.85.221.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BB7FC334C3D for ; Fri, 31 Jul 2026 21:50:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534650; cv=none; b=hFb+Z8L83aQBmXxdmF65GBm9tnrU5rWvEtGB1FeTttqRcKBP7xcAeNXGpqzvfPEHrHvRgZTTqFLZedm8IN7JQpXBgN2YL7/f2Z2t6CU99hFsOJljGWR6EQxcAu2T50oR6eJfaaDna75T/QzkQeML7L6oe9nISNolADVQnfzUNiA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534650; c=relaxed/simple; bh=ZLAM9BbgNPYw/mC8BH1vW2Quj4ZGWesTFdSgyL5Rgpo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=c4H5V3CFoj7R4vxqUGt79+jCEC1FiBd90p7s3V9bxINhbkfj0zF+fL2d3238K/zbnz4LO+xZBT2NBwfwT2ADQv+fLofgsp4RQxFCDW4nlbx1fEvHG8HH3baAEYpNfxj/T10vNDb5s+oJhedpDUdqxRS/X6CEnwvsiueWXcL4dF0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=QWWO20uI; arc=none smtp.client-ip=209.85.221.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="QWWO20uI" Received: by mail-wr1-f54.google.com with SMTP id ffacd0b85a97d-47362928f65so1543431f8f.2 for ; Fri, 31 Jul 2026 14:50:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785534647; x=1786139447; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Ne8gXxsmxHvirJEKTA6WZrzb+m1RGc3+hgsbJk4xAkg=; b=QWWO20uIGmnoQE0eRWMAbH9X/TdGiIY6+A8MxrjXLEgBzqMQpUlDlGqK8265FpnzCg OFtscShnRcfyeW/WXQTalwbLorb5b8xhTx9yDZ7vmPmL5pJgC23j4vGJRtUPbQkgjOL+ 7in7eidEbpf9y4yv68KCANz70AB8fCOx7TXtDhDyLQwgMoslOLT3CmRXlMmligW+B3q9 wXsLvlGaujexpmDMvUNITaGIlTQW2lwTp8wrbZ70ahKL2Qvrg1LayTCJa8ameiwRAh6T hM3HZC/CaTr3OSV3Og1BTnsz4WhLX+Wzi9OPcU4dd1mnnPf4jcciBRdDQil1C9/qzWt0 QccA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785534647; x=1786139447; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Ne8gXxsmxHvirJEKTA6WZrzb+m1RGc3+hgsbJk4xAkg=; b=erK3IWR1sz1pBT9AcF9ZAvKPHyZsmjA8wyvrmVCsPYD1u0SF/Z0ZnYXGxr2xUjUu9F vDS7QvIumO5/z8R7mQKoLdjqeTbGPqSb9gBX6dQkXhmnZ8gpV2HT71jJ48nncBKBm7+l GL60dL5wgOgqlXDl38YZaeg0lWMXFlzDo5gqn5qHTENF6/JIWIwUzHp2NcRiQ07nXmGN 14Xd8WQQnZBLrQ+w+lfuvNhZ8V/gZK4cBJHjjCXP3fSfEWqBj/S8xNSLPI29p3LCQBT7 jZ+ber+NcNc6BV9gIHt4Yn/6D5cp0x18AVbAbfKjUKppVkl4mVXFzGbvGEHjeA/Rp16y CBwg== X-Forwarded-Encrypted: i=1; AHgh+RpOgNAr4rCF0HlLnbn18eCXrKtbpdl7GgJg9YJ5adI7QTm/NDtXu+F234AHgc1p2FVwDFUGCOudnqKgaIA=@vger.kernel.org X-Gm-Message-State: AOJu0YxgLf3qNjBGYa1iC6boLC4WAPCTfB9JCvbzEtbEGkwfUe644RRY +ecVATZokSS/EyCSug/ZUq8rxC2jdwNs9O3pMlbkPqz691TKeQj1J6D6 X-Gm-Gg: AR+sD10LGbqAv9FSomf10QicpZyZuSwYX0HVzUb/l0lQ84mDIRgTcMnnFg5/4ReNKso jT1CnjFc0vT4HqSHg0EhBIJxOKk68hUchKuzIWdbIKlRqJ/usqcQzxx/B6d+27F3v967r0c0D7J +BsShUK+A5kWmbNwLb7PFoveGtVLU6O9F0XrQgLq11ajudLo3VWMaYV6RxsvDsT3OuYxsrWZEv1 Gcaz+K0/R8LxedL8m5C8YFAz+uTQwv40ftCr1KKIN5zWD63vyW6G6avGvUUN1ODTKOL6+Uyz+iD 7Dazz4IENKo2C06lwSOlHG2hibuLtlKO5qrsPrXT0MPoKM3Kh4+F7SKKSuEjLGBwS3Oq9P/hsfu 2az+iajQlWRYJfUjugz0D0aohmVDCBhyJLFSiRpccNGPV/rA+DVdCisYLvv3CYBI6QN6y8x8DcT Src0RUVN71FajTpWZnvsQ/XhoLvRpcU/dcnDLtb7hgudD91VqhCgNWXUxY0jPPcAQn7+E4gra0S oEL85SUMwuxGcwCSA7tpPlikw== X-Received: by 2002:a05:6000:607:b0:475:f0d1:eb63 with SMTP id ffacd0b85a97d-47fd7320f88mr2386045f8f.48.1785534646973; Fri, 31 Jul 2026 14:50:46 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.62.64]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47fd41e2484sm10186342f8f.11.2026.07.31.14.50.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Jul 2026 14:50:46 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza Subject: [RFC PATCH 1/6] dt-bindings: display: add a device tree supplied boot logo Date: Fri, 31 Jul 2026 23:50:38 +0200 Message-Id: <20260731215043.30392-2-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260731215043.30392-1-maximpedraza@gmail.com> References: <20260731215043.30392-1-maximpedraza@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Embedded products frequently need a product specific boot logo. Today the only way to get one is to replace one of the logo_*_clut224.ppm files in the kernel source tree, which bakes the image into the kernel image: a change of branding, or a second product sharing the same board support, requires a separate kernel build. Add a binding for a "linux,boot-logo-clut224" node, which carries the logo in the same paletted format the built-in CLUT224 logos already use, plus a few optional properties describing where on the screen it is drawn. The palette size is derived from the length of the "clut" property rather than spelled out separately, and "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, not by the binding. Signed-off-by: Max Pedraza --- .../display/linux,boot-logo-clut224.yaml | 108 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 109 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/linux,boot-lo= go-clut224.yaml diff --git a/Documentation/devicetree/bindings/display/linux,boot-logo-clut= 224.yaml b/Documentation/devicetree/bindings/display/linux,boot-logo-clut22= 4.yaml new file mode 100644 index 000000000..10845378d --- /dev/null +++ b/Documentation/devicetree/bindings/display/linux,boot-logo-clut224.yaml @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/linux,boot-logo-clut224.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Boot logo supplied by the device tree + +maintainers: + - Max Pedraza + +description: | + Embedded systems commonly need a product specific boot logo. Today the o= nly + way to get one is to replace one of the logo_*_clut224.ppm files in the + kernel source tree, which means the image is baked into the kernel image= and + a new kernel has to be built and deployed to change it. + + This node lets the boot logo be described by the device tree instead, so= that + a single kernel image can serve several products, or several revisions o= f the + same product, that only differ in branding. + + The image is stored in the same paletted format the in-kernel CLUT224 lo= gos + use: a palette of at most 224 RGB entries plus one palette index per pix= el. + +properties: + compatible: + const: linux,boot-logo-clut224 + + width: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Logo width in pixels. + minimum: 1 + maximum: 65535 + + height: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Logo height in pixels. + minimum: 1 + maximum: 65535 + + clut: + $ref: /schemas/types.yaml#/definitions/uint8-array + description: + Colour lookup table, as consecutive red, green and blue bytes per en= try. + The number of entries is derived from the property length and must n= ot + exceed 224. + minItems: 3 + maxItems: 672 + + data: + $ref: /schemas/types.yaml#/definitions/uint8-array + description: + One byte per pixel, left to right and top to bottom, each byte being= an + index into the colour lookup table. The property length must be equa= l to + width multiplied by height. + + logo-position: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + X and Y coordinates, in pixels, of the top left corner of the logo. + Defaults to the top left corner of the screen. + items: + - description: X coordinate + - description: Y coordinate + + logo-offset: + $ref: /schemas/types.yaml#/definitions/int32-array + description: + X and Y displacement, in pixels, applied after the logo has been pla= ced. + Mostly useful together with logo-centered. + items: + - description: X displacement + - description: Y displacement + + logo-centered: + type: boolean + description: + Centre the logo on the screen, overriding logo-position. + + logo-rotation: + $ref: /schemas/types.yaml#/definitions/string + description: Rotation applied to the logo before it is drawn. + enum: [none, cw, ccw, ud] + default: none + +required: + - compatible + - width + - height + - clut + - data + +additionalProperties: false + +examples: + - | + // A 4x2 logo using three colours, centred on the screen. + logo { + compatible =3D "linux,boot-logo-clut224"; + width =3D <4>; + height =3D <2>; + clut =3D /bits/ 8 <0xff 0x00 0x00 + 0x00 0xff 0x00 + 0x00 0x00 0xff>; + data =3D /bits/ 8 <0x00 0x01 0x01 0x00 + 0x02 0x00 0x00 0x02>; + logo-centered; + }; diff --git a/MAINTAINERS b/MAINTAINERS index e08767323..3f0ede165 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9951,6 +9951,7 @@ L: dri-devel@lists.freedesktop.org S: Maintained Q: http://patchwork.kernel.org/project/linux-fbdev/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev.git +F: Documentation/devicetree/bindings/display/linux,boot-logo-clut224.yaml F: Documentation/fb/ F: drivers/video/ F: include/linux/fb.h --=20 2.39.5 From nobody Fri Oct 2 12:19:51 2026 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1C504330652 for ; Fri, 31 Jul 2026 21:50:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534651; cv=none; b=tggojDmlnGLVgDYsGqDh+Xi0B8WX5XJwr5+iuWTnLm+hP4lNMAjkmnmwFDQkMkAXS3vYJaMdNmG00tz1/CNPhcCcgEG2YoObG6uGJSjGTBw5uhW/eHrNiRxjfcwdx+wTMNgPDY3R4cDE6oGAB2UwRGJo2Xlw9FeVaKLL8J2RoTA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534651; c=relaxed/simple; bh=1t1Xcl0vx0rLkiOp8M9P11f9v6z8fBleVFwCSvlK7k0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=QKulSpkVfAbX+yurs4bXPi1tab7JR0SVPXWGj7ldfYweNalZ/MduvnsUiaYEd88abUR5IVqITQUwGUyR0FL/zfKRI7JPUzjG2l/M/iiDvAJNORGtNMa1zFV3PGSVJsK4sanyT57CrFGJMZvXmL6nAPxce8dyarQXGayar3rVtL4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=p5H/4bsg; arc=none smtp.client-ip=209.85.221.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="p5H/4bsg" Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-472326ca506so1172178f8f.2 for ; Fri, 31 Jul 2026 14:50:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785534648; x=1786139448; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=xecpazbmAHToNRI7HHvo3rBeU785pIEnzPP95T0hHMQ=; b=p5H/4bsg+Y5P7YGEF3/HYA1SYqhUxHmtGkKcjCKKAzZY90Z8Eot4ZVFphXqYwsgJ/l SPvMd+vpjK/zXNThrNdb0MWGsZ6XjQbqbKtspZ1/kCACdFyjFtXFTdUl+9CC1zAjAJC/ 5PZIvS3IVo5ugQsWUs+MB1AaR28MfIOuhrq3kgA7GIx60zBDrXL2P+c4MWPXZKLXjo+Z JcpICBk1W7EiQwEMsUT/zc4O8PDCgzwQCPGsZp9IcIPTgPvZgwlOoS6bmwMfMiurU3Ly YgWWLhIQY0jTuubVk1U99csM/n3bMnyidPfET4K+400p4DegmejAgX08ERsejoKvyCJX Nrqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785534648; x=1786139448; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=xecpazbmAHToNRI7HHvo3rBeU785pIEnzPP95T0hHMQ=; b=OhK4ZxaCdWof5ENUKCBi1tIGyqwGPx8AwZb9ljJn8dhcRpPV0ImmvS8s706kICyQIy V0hslfUCJ9RkHuAwvv4kxPHnpI6d3Y9Ja1gJE2hA/XbhI8XjcUhDdLlAGGtom4czxg/4 DzXrZ2VbCKFf5v4R2pdHTuXq59gF+6WeJ8N1z3zFOFhHO0qmmuN52KiXObboCtmbezsA nb7w5QZD+I6KM1on3AHFRiRBzzONwv+8Xve2PGlbNrH5FCIt/u78CRYvOzAysIzoejul bMZ6k8tBMXitmbCZ/AYAaweTriZa518KqF6uYyGYBDB26AbdvF3ryQkgGx47jj17Hmzu eHlA== X-Forwarded-Encrypted: i=1; AHgh+RqfJ7G6q0BRYKlu3d4vXSZpfsnncZsmHuxpqT1S2gDBSIKic9SQA1kiJY771reaR2w33YkYGkLps81Cl9M=@vger.kernel.org X-Gm-Message-State: AOJu0Yw7EuSdk3y75XpBwGhe8zTdrzMPY+uQP6FvjtEqbKeQOQ4pHXkt 9z2e9gMTHp5JcI4EQwJqhZaiOmNWKoTUqsuD6mygrlwPxPVPNbm2LE1V X-Gm-Gg: AR+sD13Iz7rjqQVApgic36Z0X0W/VJZ2Bx8KQibucCN4SWGHnAc4gWE05BYfBqeBm9D GVvM4suZv32486sFXc9gbi57mMDmeT6VkjDZMmDrF4pulWdv12y1X8qXevyYYuCp3S6YE2Ab+v3 re8pXNirOVOWAScmjqrKK7nBV1b/GaA4WDOoZ13WJnERNxx4+lkaE798jgwJ++xfWHGdCm6MWHp ARgYCc+0f3OnL8nyI6G6h+zsSBQ9qExNn7nCNyPod0pfI8RrPsuh6RXVcrfiQWGWEgZuf+xAzmW qAMnK7kd462Fd8uuP60v0tGu2c3WbdCQ5S/gFeK4ED0iOwJVPKxK0Ud/c0e3UOtE7JyuqdVrLve chOYXwbvLCpny/+EsA7zoPdJH4j7nGYrv2d/aFsldisVYwZKiZRo0yGoTPvXZtoF6XC4ZFcafFx c9L7vSFEextEp/o0bTzIVVgitIhgTfMn8z6lSG2zLa075XuG96OFZ32JwjMvwc34a4nNYFBB0Zl v4EFjmDCQ04kVw+NyX2p3bn X-Received: by 2002:a5d:64ed:0:b0:47f:77dc:b072 with SMTP id ffacd0b85a97d-47fd72c65f5mr2415622f8f.18.1785534648239; Fri, 31 Jul 2026 14:50:48 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.62.64]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47fd41e2484sm10186342f8f.11.2026.07.31.14.50.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Jul 2026 14:50:47 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza 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 Message-Id: <20260731215043.30392-3-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260731215043.30392-1-maximpedraza@gmail.com> References: <20260731215043.30392-1-maximpedraza@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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 =20 +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 @@ */ =20 #include +#include +#include +#include #include #include =20 @@ -22,6 +25,155 @@ static bool nologo; module_param(nologo, bool, 0); MODULE_PARM_DESC(nologo, "Disables startup logo"); =20 +#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 st= ores + * 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 m= ore */ +#define LOGO_DT_MAX_PIXELS SZ_32M + +static struct linux_logo logo_dt_clut224 =3D { + .type =3D 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 =3D of_property_read_u32(np, "width", &width); + if (ret) + return ret; + + ret =3D of_property_read_u32(np, "height", &height); + if (ret) + return ret; + + if (!width || !height || (u64)width * height > LOGO_DT_MAX_PIXELS) + return -EINVAL; + + npixels =3D width * height; + + len =3D of_property_count_u8_elems(np, "clut"); + if (len < 3 || len % 3) + return -EINVAL; + + clutsize =3D len / 3; + if (clutsize > LOGO_DT_MAX_CLUT) + return -EINVAL; + + ret =3D of_property_count_u8_elems(np, "data"); + if (ret < 0) + return ret; + if ((unsigned int)ret !=3D npixels) + return -EINVAL; + + clut =3D kmalloc(len, GFP_KERNEL); + if (!clut) + return -ENOMEM; + + data =3D kmalloc(npixels, GFP_KERNEL); + if (!data) { + ret =3D -ENOMEM; + goto err_free_clut; + } + + ret =3D of_property_read_u8_array(np, "clut", clut, len); + if (ret) + goto err_free_data; + + ret =3D of_property_read_u8_array(np, "data", data, npixels); + if (ret) + goto err_free_data; + + for (i =3D 0; i < npixels; i++) { + if (data[i] >=3D clutsize) { + ret =3D -ERANGE; + goto err_free_data; + } + data[i] +=3D LOGO_DT_CLUT_OFFSET; + } + + logo_dt_clut =3D clut; + logo_dt_data =3D data; + + logo_dt_clut224.width =3D width; + logo_dt_clut224.height =3D height; + logo_dt_clut224.clutsize =3D clutsize; + logo_dt_clut224.clut =3D clut; + logo_dt_clut224.data =3D 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 =3D true; + + np =3D of_find_compatible_node(NULL, NULL, LOGO_DT_COMPATIBLE); + if (!np) + return NULL; + + if (of_device_is_available(np)) { + ret =3D 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 =3D NULL; + logo_dt_clut224.data =3D NULL; + + kfree(logo_dt_clut); + logo_dt_clut =3D NULL; + + kfree(logo_dt_data); + logo_dt_data =3D 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 =3D true; + logo_dt_free(); return 0; } =20 @@ -71,6 +224,10 @@ const struct linux_logo * __ref fb_find_logo(int depth) } =09 if (depth >=3D 8) { + /* A logo supplied by the device tree wins over the built-in ones */ + logo =3D logo_dt_find(); + if (logo) + return logo; #ifdef CONFIG_LOGO_LINUX_CLUT224 /* Generic Linux logo */ logo =3D &logo_linux_clut224; --=20 2.39.5 From nobody Fri Oct 2 12:19:51 2026 Received: from mail-wr1-f51.google.com (mail-wr1-f51.google.com [209.85.221.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3940535F185 for ; Fri, 31 Jul 2026 21:50:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534653; cv=none; b=MvrjAzYrQ/o7AsnvJ5ovUt6z1sbsDgCp6O0NxoQmfSxVCybDgERnqDg7It151RwN8gb6T1cYjxZinhTSul0JMy+Muu2NW8YK2K1WaeEyGCcxId5weLAE90ieZGkYzD9q5Ra3jvA3L/WSgtpSRcuEfAJEBfjVhEzis8FdKTRDgvc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534653; c=relaxed/simple; bh=b6pkm9AbznuP6ASEvkFpmUaiFAyJ0vcaTsusVxEfRjM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=VsSHkPcAgHima6oXyNhjij/8R3RKZg+2bhRPZ78FMfwt/cHZrTKP+clP7idMkC5dH4Y49lT7p71SwhxQJCUY8k5Z/GGgeA58oaO4t+81QdalIqneB3UpzFNTsZare+SSKv5xToNnRGC2wl5VDZYdVIZhIumVeUH7jUiHdhJMuSA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=DZ9BmdLn; arc=none smtp.client-ip=209.85.221.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DZ9BmdLn" Received: by mail-wr1-f51.google.com with SMTP id ffacd0b85a97d-47f7854678cso627919f8f.1 for ; Fri, 31 Jul 2026 14:50:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785534649; x=1786139449; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=aPWyvzGNLa7rHTsTZpFRCraZCWg00Qf6Fr76L45avBk=; b=DZ9BmdLnQsFk0ZT4RFggRR92v28xs/0K0HGxjTJwXElFPttsg33loK71/J66aDPLo8 sYf0d1pyM0HmcZ237OxoL/wBnSc3WG/YFgQQ1Hq+059N5dsSy8PwBMocgCITIjWjvbZP 3krrzRy5gV3ypRxM2Yiul5mPCsY91rgW9w5w5aCOB0oQ0JgvPEsIsW+yc+RwDoT4hr95 n7fDpr/IUBV/mJc1jqk+Zmol5Z+bEcYeh6yJ1AWQWL51wzY357oMlF1FrpDd4OPTjkkV zkI29k7Ylk7lHi8X1SmMXu0CFlce0FZLHC/bFH2iRQpOVpJtwyN5yah4yoHZVMf6q/U0 cQxw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785534649; x=1786139449; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=aPWyvzGNLa7rHTsTZpFRCraZCWg00Qf6Fr76L45avBk=; b=nXsvWASYis2BhcmA6oKfcUHPX/34pakRDFAHmSIg26QmYAVt48XdIB61dU9wSKSP+/ 36iYtK7Myz6mnqL0Cf9XR6KFx2W022KlbxklpbSXD1tdE+478dztI+E7QEEHP4iTJhOE jGkfS17LynNgAgal2Hv8goDSgThCjHXSfh+BIXGEWsjwSooa0+4ibOOpy7/kMy5BOTkI xBjvWeOf4ziJYGnI2nGKaOFEc7M6848tyhNtT0l17wiv9j/MrSDdjF/84hc1Vq31jYd9 g0AoFktuNB4sCEJsdrT43nMsWzxF/Oi+SdfK7J58CCjEPhyM+8dMNYzhgsJDxp3Y4eI7 kG9Q== X-Forwarded-Encrypted: i=1; AHgh+RrDO1OajGTGhoiUqp7JJbv1nWUimegvlkq9eIFT6gNFbSyTV6XnsAKGx7pQqVSDkawQXpDO6Xt4jFrz78U=@vger.kernel.org X-Gm-Message-State: AOJu0YykFtIG9Gy1YrGph+c3+8Gtr9WU+CfnMmK8FXNniVKUjAN2B1VP ozX1QUML57+vmmAKCnHVeM9sg6tbqw+YCPSHVGz6k+zpHFjngHBNvV38 X-Gm-Gg: AR+sD13XWG14X5O9kYP/rJptkP8t3Unq0uV+F0Pf0zwU04HM98FtoI8hJ2WOr6ptbY/ Zq1lKRl0MzzrnXgJC21zlxt2puttUFRbR0dZnnLmfGSor/SFGV35rrM+zT4hCKe4yHcXgKgkZsO HLWfvgTZ/WfexVL9HipJiOt+mrkZb06n5iXRPepFCzwpO/qp9Uvuhy4jnGEs+bNy68plnSPb9Cf P5gzaiMlRJhUEJp/3iUgyqQ1V6M3DEie4uqubXClUyYSCWBRuJNvOD+OS8bn2JqnP+P85Yl8r00 2tovP0RReSMq0gEQqFbY4stOKgi8kSP2Ryu6Lda8vaENebb3fcaLcKhESvCzrY6FKI+yuz0M3J3 SgkNh6MdgaGr3v7puyTvaC5Mql6kIknpf0LNsulqcH2mqOGMGu3pxx0rTOYeeBJqYDuI35024nN MDmqpKYJ/kOpauyyXo31eKrmc89TOK7A9OzcjMBl6dj9aCWGZw5xLQ9WQsyBit/GIuHUc/6/HY7 aSZKXRQjDMkdVZWxcJMu9lP X-Received: by 2002:a05:6000:40e0:b0:47f:92d6:f710 with SMTP id ffacd0b85a97d-47fd72f9de0mr2367841f8f.46.1785534649429; Fri, 31 Jul 2026 14:50:49 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.62.64]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47fd41e2484sm10186342f8f.11.2026.07.31.14.50.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Jul 2026 14:50:49 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza Subject: [RFC PATCH 3/6] fbdev: honour the device tree boot logo placement properties Date: Fri, 31 Jul 2026 23:50:40 +0200 Message-Id: <20260731215043.30392-4-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260731215043.30392-1-maximpedraza@gmail.com> References: <20260731215043.30392-1-maximpedraza@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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 @@ =20 #include #include +#include =20 #include "fb_internal.h" =20 bool fb_center_logo __read_mostly; int fb_logo_count __read_mostly =3D -1; =20 +#ifdef CONFIG_LOGO_DT_CLUT224 + +/* + * Placement of a logo supplied by the device tree. The image itself is pa= rsed + * 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 =3D &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 =3D true; + + np =3D of_find_compatible_node(NULL, NULL, "linux,boot-logo-clut224"); + if (!np) + return; + + if (!of_device_is_available(np)) + goto out; + + p->valid =3D true; + p->rotation =3D -1; + p->centered =3D of_property_read_bool(np, "logo-centered"); + + if (!of_property_read_u32_array(np, "logo-position", val, 2)) { + p->has_position =3D true; + p->x =3D val[0]; + p->y =3D val[1]; + } + + if (!of_property_read_u32_array(np, "logo-offset", val, 2)) { + p->offset_x =3D (s32)val[0]; + p->offset_y =3D (s32)val[1]; + } + + if (!of_property_read_string(np, "logo-rotation", &rotation)) { + rot =3D fb_logo_dt_parse_rotation(rotation); + if (rot < 0) + pr_warn("fb: %pOF: unknown logo-rotation \"%s\"\n", + np, rotation); + else + p->rotation =3D 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 >=3D 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 =3D &fb_logo_dt; + int top; + + if (p->centered) + top =3D ((int)yres - (int)logo_height) / 2; + else if (p->has_position) + top =3D p->y; + else + top =3D 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 =3D &fb_logo_dt; + int dx; + + fb_logo_dt_read(); + + if (!p->valid) + return; + + if (p->centered) + dx =3D ((int)info->var.xres - (int)image->width) / 2; + else if (p->has_position) + dx =3D p->x; + else + dx =3D image->dx; + + image->dx =3D max(dx + p->offset_x, 0); + image->dy =3D 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 t= he + * 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); } =20 + /* Done last, image dimensions are only final after the rotation */ + fb_logo_dt_place(info, &image); + fb_do_show_logo(info, &image, rotate, n); =20 kfree(palette); @@ -423,6 +592,8 @@ int fb_prepare_logo(struct fb_info *info, int rotate) =20 memset(&fb_logo, 0, sizeof(struct logo_data)); =20 + rotate =3D 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 =3D fb_logo.logo->height; if (fb_center_logo) height +=3D (yres - fb_logo.logo->height) / 2; + height =3D fb_logo_dt_reserve(yres, fb_logo.logo->height, height); #ifdef CONFIG_FB_LOGO_EXTRA height =3D 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; =20 + rotate =3D fb_logo_dt_rotation(rotate); + count =3D fb_logo_count < 0 ? num_online_cpus() : fb_logo_count; y =3D fb_show_logo_line(info, rotate, fb_logo.logo, 0, count); #ifdef CONFIG_FB_LOGO_EXTRA --=20 2.39.5 From nobody Fri Oct 2 12:19:51 2026 Received: from mail-wr1-f54.google.com (mail-wr1-f54.google.com [209.85.221.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 93A113314B9 for ; Fri, 31 Jul 2026 21:50:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534654; cv=none; b=tWaM4mFGck8lL3kWfcTWIB7CDo0Fov+BoRuny/oyXBJmopn1oLRcdp1cxEl0XjQBEMU8Xzz6h8MOAOaqIGqyBC7FU8YtIu0ZH74JFwkvv5zT29u9c93CGzgpU/kag3WIBipqup1NL1Bn0WuvRJp0QO8wSzkyA0U0ssXO3neMIrQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534654; c=relaxed/simple; bh=iFSPgHBWWRh4oFZA9jZRHcfuqAwXJJvxV1p63pLcggg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=gf0jS+78W4CWhPnJTz4IzTXAc/BkI213Gzj/ZkFUS/BG/6v9lLkZbC7flueoCbC9VfZgGasJ2A1Dj3vPMdrIrL3Pb772pPDQxe9K64kl/NmeGhW67Ba68ftTHBeaHV0HDsDH1yhK9YjGG7X7bKjsF/8w3L2EbQkZpwodU5ZD1Hw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Bld6LTxu; arc=none smtp.client-ip=209.85.221.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Bld6LTxu" Received: by mail-wr1-f54.google.com with SMTP id ffacd0b85a97d-4798bea72f9so1104444f8f.1 for ; Fri, 31 Jul 2026 14:50:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785534651; x=1786139451; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=luqMKmTQhbao04KxZsM9dM3mm5nhaixuuCx8YNHFEpY=; b=Bld6LTxuYETiqgbm+TlKIv38xWmnlqfLU6oSnXQoHG8DAFFsy4qNoS5j4FJhYjb5fy LtZ92wvNax2mvOQjL615Vj1CV/KccHpmyoGGYT2YrHy72A+XzqkgQYVJXUhCn6bLiPVd veKB+AaCuqr3grLB7VCDST5TYDEOn5ET5ne4BolJm6O4V3ZX+bp5tnx84pYZ7wv5ahVI g3UfZCCSk9Sk1r3GnwM3wHHQMi//OOowmq/zYHYu3Vuwecv3QAQ3VYSsRJVLOTXp0KfZ eoPHvil+OKn5CNGwqCOdaIcvdc0WlZkIpYErP2SL3Im0I3wORYF5TxPyjK/AJ8VPZdHD 41+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785534651; x=1786139451; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=luqMKmTQhbao04KxZsM9dM3mm5nhaixuuCx8YNHFEpY=; b=K1uUDKqXKkuIe7WQ2Z5HRVYMoFvjM0orBpQNfdcpuJYmtm5r7VpbejZ2tMcfIkJfpN 5uLrUz2sKXTcFUgcp1SUVDqA5wNAbRmyCD2iQPi9SgfmUjdG5xW6Tx9pJTTvZZlIHKEy nkfMrFO+OMpGn6UAGJdtSES+urag/jhoQZvGH3NRkTmX0rS4tr+lJ/wonV8HG35CQ0ky 9lVmKiPdgzaueKhOBBwh+930/PbpAn2z3A2bpFMJ3S4wOS/OXFISn/swZ7NsQjoArzTE JHJMUz7p3Nc+uHfAFb5L1VQpGSomz6GDyaQB6vAnMXKUgD+A+U00AxvVt1fqGVS8kVx3 wPZw== X-Forwarded-Encrypted: i=1; AHgh+RoCjQ+Kry4J3/AtWMhA6oJIK40rVLRV2f4QIn2+p5PDMQhNTepIXBOw7VhG3+JZwR/jMN+lHeaaAVA+sbE=@vger.kernel.org X-Gm-Message-State: AOJu0YxSuFT8DcE9Ue+lNtZBSgFLnE0CSCVvWocyrOO8AqioaSLPTmB3 ZyeNXSQtEiomfoALCNSIfZN0n2y1vTQ6z8cFMG4GHm6TLFC0KIUHR+0F X-Gm-Gg: AR+sD11yIoWi0wwc4Vqsll5Ikj/q24uQeLnwLJXg4p6o1yN36O7nmZcRlhb9PHtVHLQ Vu3CDfn4eL+TomERXExM0JiczO4T6D8lSF47qUE9CZ5WlJbr3aNQSdMDD5GjnAB8O4/onWimc0m MlTwfQh2H3yC9WTfb+MjkFZPDYcIIKJpFUR8SZaXpOvEXMfcb9Ej4FQxEh5UbDrNmcQRtSrRWO7 xf3eD6wgqKTELtx1NuMfZrWUbAPiD1MNF2p7nBMd7j0X59g1mAS9fW4nlnoKuixuZUjQ1P3DNP2 oON2Boqp+n7E3l7/SPH8etiGRyNF9+szDpFCM2zTXyVoN99hjG2xpX99boTMGZiBeY00x4X6A07 brLhzI3otIGdZDvmSCZrnU7yt56t5EUag32SXLY6znjoClInNDtzZDdIxzhYWxRqla88ef/O1ZJ 6Pc8gh4fFdFH5CjSDITOPiy8oDUM2ek6fhnk0iEjm63LqFbeuSBLOiyj+jS7GEXynNqrNOsD8I4 iHo8FFISBCHSywRpsUywYHr X-Received: by 2002:a05:6000:2404:b0:47f:9557:8daf with SMTP id ffacd0b85a97d-47fd7329f01mr2280434f8f.61.1785534650742; Fri, 31 Jul 2026 14:50:50 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.62.64]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47fd41e2484sm10186342f8f.11.2026.07.31.14.50.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Jul 2026 14:50:50 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza Subject: [RFC PATCH 4/6] dt-bindings: display: allow the boot logo in a reserved memory region Date: Fri, 31 Jul 2026 23:50:41 +0200 Message-Id: <20260731215043.30392-5-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260731215043.30392-1-maximpedraza@gmail.com> References: <20260731215043.30392-1-maximpedraza@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Carrying the image in the device tree ties it to the device tree, but the image and where it goes on screen are independent axes of variation. One board sold to several customers wants several device trees that differ in the logo; one customer with several products built on that board wants the same logo placed differently on each panel. The second case would otherwise mean duplicating the same image into every device tree. Let the node point at a reserved memory region filled in by the bootloader instead, so one image can be shared by device trees that differ only in placement. The region starts with a small header carrying a magic number and the geometry, so the kernel can tell a logo from an empty or stale region and bounds check everything against the reservation. A phandle to a declared region is used rather than a bare address: the reservation is what makes the memory safe to read and what gives the kernel a size to validate against. The two ways of supplying the image are mutually exclusive. Signed-off-by: Max Pedraza --- .../display/linux,boot-logo-clut224.yaml | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/display/linux,boot-logo-clut= 224.yaml b/Documentation/devicetree/bindings/display/linux,boot-logo-clut22= 4.yaml index 10845378d..c40683f3a 100644 --- a/Documentation/devicetree/bindings/display/linux,boot-logo-clut224.yaml +++ b/Documentation/devicetree/bindings/display/linux,boot-logo-clut224.yaml @@ -54,6 +54,23 @@ properties: index into the colour lookup table. The property length must be equa= l to width multiplied by height. =20 + memory-region: + maxItems: 1 + description: | + Reserved memory region holding the logo, as an alternative to carryi= ng + it in the width, height, clut and data properties. The bootloader is + expected to have placed the image there before starting the kernel. + + This lets one image be shared by several device trees that differ on= ly + in where the logo goes, which is what a family of products built on = the + same board but with different panels needs. + + The region starts with a header of four little endian 32 bit words: + the magic number 0x4f474f4c ("LOGO"), the width, the height and the + number of palette entries. The palette follows, as consecutive red, + green and blue bytes per entry, and then one byte per pixel, each an + index into that palette. + logo-position: $ref: /schemas/types.yaml#/definitions/uint32-array description: @@ -85,10 +102,17 @@ properties: =20 required: - compatible - - width - - height - - clut - - data + +# The image either lives in the device tree or in a reserved memory region, +# never both. +oneOf: + - required: + - width + - height + - clut + - data + - required: + - memory-region =20 additionalProperties: false =20 @@ -106,3 +130,23 @@ examples: 0x02 0x00 0x00 0x02>; logo-centered; }; + - | + // The same logo taken from a region the bootloader filled in, centred= on + // a panel whose usable area is not the centre of the mode. + reserved-memory { + #address-cells =3D <1>; + #size-cells =3D <1>; + ranges; + + logo_mem: logo@9c000000 { + reg =3D <0x9c000000 0x100000>; + no-map; + }; + }; + + logo { + compatible =3D "linux,boot-logo-clut224"; + memory-region =3D <&logo_mem>; + logo-centered; + logo-offset =3D <0 120>; + }; --=20 2.39.5 From nobody Fri Oct 2 12:19:51 2026 Received: from mail-wr1-f53.google.com (mail-wr1-f53.google.com [209.85.221.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D5E0A37DE83 for ; Fri, 31 Jul 2026 21:50:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534657; cv=none; b=J9OYWKFNYhscTafMSJkE90CWDNSdR0tMGah/w3je5PaE/YMhMrSXQMB8k1z/QywTm1rp6HwXH9MpgMb2cZpHXM4pvpNRVITDRINnnIJtL7G5V3USfYR9Jq2yE3CpW/ytgDH+Yqi2LLaeytvzvMxYLt9n/6JK82V5FndW783uyuQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534657; c=relaxed/simple; bh=4elGExiqb/CWf4gkl+dBDCh6SXY0uWu2hMm5yoGfMlY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=tLxisxYKLEpNjfUZscJ/Z1sOEF8pU08v5ZvkIKMsE0eVCSy71Aei3WN1jV+yoN7WjG13lT7mGNV2eNHMVQwdp8mwtTyBa4A4yE0txI0P3TfJCdrY+JKmne3XWNECXCNFlM04KZ5bn7Rz+UeUwGiukxNjOQ/t/gVNMtkHi/3vkts= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=g4UGDSRH; arc=none smtp.client-ip=209.85.221.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="g4UGDSRH" Received: by mail-wr1-f53.google.com with SMTP id ffacd0b85a97d-47f752b3423so1364401f8f.3 for ; Fri, 31 Jul 2026 14:50:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785534652; x=1786139452; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=mmFMZ3fYEoGkcqSYuP3/MajdLDfVjK6tOo68kSisc3k=; b=g4UGDSRHCHXGXr3FxXh+3ft4jySONAdMVxxOgUFgcGMDNF6XuFbjBfPQGyhJ8YH7ZM sHNdW6tKs0a/svL0ujUAQLkFSUV8qz/cJHOaANxfrX41NUhd4hhs5v6tjEvTUTSa3bM8 R0lyLTyhcA/i581RuxPk1cd66XUeFkJbw0uq7vvp6IrZp6MNM7T6YpJbw/73UBzR4Efb VhUm8XVaA0C/arTPZARe4r+qodXVr/uz75RSkDfDWoDWe6T2HlnCtav3Mn03C3bq9bpI +fHyf+FZjhwrWhfM8oro2bNA1Vv0U2KYRn0LPPOnqQCkRZn6wc7UD77ucOiexl9r/0it gQQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785534652; x=1786139452; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=mmFMZ3fYEoGkcqSYuP3/MajdLDfVjK6tOo68kSisc3k=; b=fHSOsNUXS9mWH86qQtOhes00k9CniR92SM9/DjTWfN2fA0pWNjVuCE8xtLCKK15oKj erkdbBgfceyF8xLlUbEZUfmD2jbTflZP1PWoQ1GHn7U+MCNmIITelOilp0WYI9r/UhdR k/cjx4nyCbDRZvRgXfmThHGaw8FISwUQ9XmE9cy+ArkwJPQ4WKOENy4sgmXPIFZ8aOa6 l46AGI+MKCfdACRmaNtYaumOtkAGGgjV268+u+Y2gOHyZPGLmcPzbewHXNTQ1fHxllFI dn2sam4l3L1ZiNc/C0F2MBh63bC9dauc06SiYHf8qHMk9YnfbS5gpSsXnuADl65RqFX1 rNGA== X-Forwarded-Encrypted: i=1; AHgh+Rob8Cwr8Hud01Je8hNu+2ZjeV3tPpQtFCa1nliRjEsp4TTizzMcX0jKcEiLRpyu6WhrGsbKY+AB4uFd9NQ=@vger.kernel.org X-Gm-Message-State: AOJu0Ywcyvck97DRLcbGvlH/OFsqLquEqGKzYAiTHCpGle83Z1UblLaZ KhLvtOvMI7nlJmzbvCW7e5Eyu27I8TpfK9BCJBo6c7RF1JD9wBuilWXc X-Gm-Gg: AR+sD11zSum2Hyn1laLds9H+S9KrXIZ9Hp3e2I37QIEXSbtPcCySo+KHw9rF4lNEj+1 7vTxGst8Qgk9LpfLZIWCt8I7FWQ7CpwWBfnn8+SOdpnrsYfEOUhe8jb5GyAb5HNXwV1xNapPOtW O6K/SGx7qKNp9Vr2CT7JgU+y3/7hzi6tPIK7wW7Z14dyqlhZk5WrGi/inVqjVYGdHHsY0FtKIQp E+zRCBvd2R3U2cQ7xJrqyrc5z2b7nc3f6YHsoMncM3mRCwGxaFuy+UMuQuKzEFtgl9cwUGUcNZa TnrjMOSchofQYHjo1xoCCg2dCH/Hfc3nbjKSEi5bTHuVpvzjFVyzlwtnZPRamZkmDGUP4I0/GWD diUYLYZ4cPMUcfmxs7OYZ5nox0EJUhGGI3A21iyKMmKp4ffFNl8pi1yMuE+AnNh5VUcwDo5c1E+ oS3ECVHy2ibgrGmRTgJMdY0unWeGPAp4vi4R0u7QOQRio5UF9ZzPssS60ISVQgl00FwrA9JxKmP CaMeIDbpUsPWw== X-Received: by 2002:a5d:68cb:0:b0:47f:d01b:a691 with SMTP id ffacd0b85a97d-47fd72c6d17mr2157623f8f.14.1785534651962; Fri, 31 Jul 2026 14:50:51 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.62.64]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47fd41e2484sm10186342f8f.11.2026.07.31.14.50.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Jul 2026 14:50:51 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza Subject: [RFC PATCH 5/6] video: logo: allow the boot logo to come from a reserved memory region Date: Fri, 31 Jul 2026 23:50:42 +0200 Message-Id: <20260731215043.30392-6-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260731215043.30392-1-maximpedraza@gmail.com> References: <20260731215043.30392-1-maximpedraza@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Take the image from the region a "memory-region" phandle points at, when the node has one, instead of from the width, height, clut and data properties. Only a declared region is accepted, never a bare physical address. That matters for more than tidiness: the region is reserved before the allocator starts, so the logo code can never be pointed at memory the kernel is using for something else, and a size is known, so every field can be bounds checked. The region is mapped with memremap(), which copes with a no-map reservation and fails cleanly instead of handing back a bogus pointer the way phys_to_virt() on an arbitrary address would. The image is validated and copied out rather than used in place: the magic number has to match, the geometry has to be sane, the palette and pixels have to fit inside the reserved region, and every pixel has to reference an existing palette entry. Anything else is reported and ignored, falling back to the built-in logo. Copying also means nothing that happens to the region afterwards can affect what has already been validated, and it keeps the pixel data in the same shape both paths produce. Signed-off-by: Max Pedraza --- drivers/video/logo/logo.c | 171 ++++++++++++++++++++++++++++++-------- 1 file changed, 135 insertions(+), 36 deletions(-) diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index b4f533df0..95d75b905 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -10,8 +10,10 @@ * Copyright (C) 2003 Geert Uytterhoeven */ =20 +#include #include #include +#include #include #include #include @@ -38,6 +40,15 @@ MODULE_PARM_DESC(nologo, "Disables startup logo"); #define LOGO_DT_CLUT_OFFSET 32 /* Sanity limit on the image size, a device tree is not a good place for m= ore */ #define LOGO_DT_MAX_PIXELS SZ_32M +/* "LOGO", little endian, at the start of a handed over memory region */ +#define LOGO_DT_MAGIC 0x4f474f4c + +struct logo_dt_header { + __le32 magic; + __le32 width; + __le32 height; + __le32 clutsize; +}; =20 static struct linux_logo logo_dt_clut224 =3D { .type =3D LINUX_LOGO_CLUT224, @@ -46,58 +57,41 @@ static struct linux_logo logo_dt_clut224 =3D { static unsigned char *logo_dt_clut; static unsigned char *logo_dt_data; =20 -static int logo_dt_parse(struct device_node *np) +/* Reject geometries that cannot describe a sane image before using them */ +static int logo_dt_check_geometry(u32 width, u32 height, u32 clutsize) { - unsigned int clutsize, npixels, i; - unsigned char *clut, *data; - u32 width, height; - int len, ret; - - ret =3D of_property_read_u32(np, "width", &width); - if (ret) - return ret; - - ret =3D of_property_read_u32(np, "height", &height); - if (ret) - return ret; - if (!width || !height || (u64)width * height > LOGO_DT_MAX_PIXELS) return -EINVAL; =20 - npixels =3D width * height; - - len =3D of_property_count_u8_elems(np, "clut"); - if (len < 3 || len % 3) + if (!clutsize || clutsize > LOGO_DT_MAX_CLUT) return -EINVAL; =20 - clutsize =3D len / 3; - if (clutsize > LOGO_DT_MAX_CLUT) - return -EINVAL; + return 0; +} =20 - ret =3D of_property_count_u8_elems(np, "data"); - if (ret < 0) - return ret; - if ((unsigned int)ret !=3D npixels) - return -EINVAL; +/* + * Take a private copy of an image that has already been range checked, so + * that nothing else can change it under us, and shift the pixels into the + * palette slots the frame buffer layer leaves to the logo. + */ +static int logo_dt_store(u32 width, u32 height, u32 clutsize, + const u8 *clut_src, const u8 *data_src) +{ + unsigned int npixels =3D width * height; + unsigned char *clut, *data; + unsigned int i; + int ret; =20 - clut =3D kmalloc(len, GFP_KERNEL); + clut =3D kmemdup(clut_src, clutsize * 3, GFP_KERNEL); if (!clut) return -ENOMEM; =20 - data =3D kmalloc(npixels, GFP_KERNEL); + data =3D kmemdup(data_src, npixels, GFP_KERNEL); if (!data) { ret =3D -ENOMEM; goto err_free_clut; } =20 - ret =3D of_property_read_u8_array(np, "clut", clut, len); - if (ret) - goto err_free_data; - - ret =3D of_property_read_u8_array(np, "data", data, npixels); - if (ret) - goto err_free_data; - for (i =3D 0; i < npixels; i++) { if (data[i] >=3D clutsize) { ret =3D -ERANGE; @@ -124,6 +118,111 @@ static int logo_dt_parse(struct device_node *np) return ret; } =20 +static int logo_dt_parse_properties(struct device_node *np) +{ + const u8 *clut, *data; + u32 width, height; + int len, ret; + + ret =3D of_property_read_u32(np, "width", &width); + if (ret) + return ret; + + ret =3D of_property_read_u32(np, "height", &height); + if (ret) + return ret; + + len =3D of_property_count_u8_elems(np, "clut"); + if (len < 3 || len % 3) + return -EINVAL; + + ret =3D logo_dt_check_geometry(width, height, len / 3); + if (ret) + return ret; + + if (of_property_count_u8_elems(np, "data") !=3D width * height) + return -EINVAL; + + clut =3D of_get_property(np, "clut", NULL); + data =3D of_get_property(np, "data", NULL); + if (!clut || !data) + return -EINVAL; + + return logo_dt_store(width, height, len / 3, clut, data); +} + +/* + * Image handed over by the bootloader in a reserved memory region. Only a + * region the device tree declared is accepted, never a bare address, so t= he + * kernel can never be pointed at memory it is using for something else, a= nd + * so that a size is known and every access can be bounds checked. + */ +static int logo_dt_parse_memory_region(struct device_node *np) +{ + u32 width, height, clutsize; + const struct logo_dt_header *hdr; + struct device_node *mem_np; + struct reserved_mem *rmem; + size_t clutlen, datalen; + const u8 *payload; + void *mem; + int ret; + + mem_np =3D of_parse_phandle(np, "memory-region", 0); + if (!mem_np) + return -ENOENT; + + rmem =3D of_reserved_mem_lookup(mem_np); + of_node_put(mem_np); + if (!rmem) + return -EINVAL; + + if (rmem->size < sizeof(*hdr)) + return -EINVAL; + + mem =3D memremap(rmem->base, rmem->size, MEMREMAP_WB); + if (!mem) + return -ENOMEM; + + hdr =3D mem; + if (le32_to_cpu(hdr->magic) !=3D LOGO_DT_MAGIC) { + ret =3D -EINVAL; + goto out_unmap; + } + + width =3D le32_to_cpu(hdr->width); + height =3D le32_to_cpu(hdr->height); + clutsize =3D le32_to_cpu(hdr->clutsize); + + ret =3D logo_dt_check_geometry(width, height, clutsize); + if (ret) + goto out_unmap; + + clutlen =3D (size_t)clutsize * 3; + datalen =3D (size_t)width * height; + + /* Everything the header promises has to fit inside the region */ + if (sizeof(*hdr) + clutlen + datalen > rmem->size) { + ret =3D -EINVAL; + goto out_unmap; + } + + payload =3D (const u8 *)(hdr + 1); + ret =3D logo_dt_store(width, height, clutsize, payload, payload + clutlen= ); + +out_unmap: + memunmap(mem); + return ret; +} + +static int logo_dt_parse(struct device_node *np) +{ + if (of_property_present(np, "memory-region")) + return logo_dt_parse_memory_region(np); + + return logo_dt_parse_properties(np); +} + static const struct linux_logo *logo_dt_find(void) { static bool probed; --=20 2.39.5 From nobody Fri Oct 2 12:19:51 2026 Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 29CB93803C2 for ; Fri, 31 Jul 2026 21:50:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534657; cv=none; b=sgobreKGmRdhdDG+XUMJbnFnCPBW8VfgKhpNeb4tWLTvOrKvhBMCYZWdCgWJpvjYfo4fL7hWh8xQWdnuyKfI0wv8xEYBKyR3gTeiw6lhFpQZHF8dDpHhHXZELiwebu4rSkzqNRLBke1HeNMrw+kYBDAIzSwPwSyZ+OWqgW+tmHc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785534657; c=relaxed/simple; bh=FUSb4djeAKTsB6gFNwuUzmazTZ/koeaQrRWuyzt4COo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=KL+B9T7RcopTP0saTH0RVg8v99TuO5OMBjk3SqPqVJOeepDeVqo+KlBINKvYqGrYW56LVSdTVr30MKPEQy+Kj1U4enaKcJ05h6cTBBANQSDHSfv4YKTNNv3vsI4hpWBMhgRx9CXFy0ITu4YQCHYcoekpTGX+DjiEeGuBdyGOEvw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=JBWC/f5e; arc=none smtp.client-ip=209.85.221.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="JBWC/f5e" Received: by mail-wr1-f45.google.com with SMTP id ffacd0b85a97d-47f6609c657so794985f8f.2 for ; Fri, 31 Jul 2026 14:50:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785534653; x=1786139453; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=UhDpqiiaD6DYnxd51cG0Til5Fllj5+soFBiJbl5gk3M=; b=JBWC/f5eO0ReLaSApU6jFnCuvOodlNVctGhn2Y7Kt4RBzZog1e1ann1rww5sPsIZkl sUtwhsBuUtHuttago8vD5p/Cgn+aDAA+8KJtSvuTaHIz0W8+CB15VPq17wCtxH+eZHEN YnemIZcPCI2o33NmwGPXhj0hm5fTC2ZpWh32SlqyyL2Qn3xduXCbz9yDRsvGsSzpjL5A 6Dvvo86+3ZxJyXDXf9NLgD+UVkDRnVSqMMOKstWdXA5+O3lrskFMHOzZv/dRLSeBfdLG wI5p6Q4IPlB6gOEXFemh004eIZFL1lV87MF5ONlIOytGZ2/+eGlbso4ZEp8C7RrLv5AC v56Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785534653; x=1786139453; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=UhDpqiiaD6DYnxd51cG0Til5Fllj5+soFBiJbl5gk3M=; b=OsBud0NyFepN5cjfWHScKkzs2hq7t9OqgfYkOM7UFeXZoIqNYfYhfOFHMrAGiGxxqD Ani3foS6a5e558LgoXtrYHMJUQ060i4qPy7TDKuWeJR/d8gprBzwjiBtir1NiHDOnXFL J1oi62Syx+kaWBnHHH0nJUtftQxSk95xwjjZfsyG7aALQ4pnkwNkPuA9wmp5NsOcQtLx PPWVyok9+lcXxec/4VsNXjkcw5PSNpJVNJTVe9usCtD8CB0l8M4nSqAqdmP5a4bZDhVf x/cAvfnnxWg3If1eINi3dwadbzJcvWow4mx7XbVGIbrtvGXbKCzmPCMVkbF3jOyNuTMN lkDQ== X-Forwarded-Encrypted: i=1; AHgh+RqlIh6WNQtpJqS1LychieEcDlYTYq5IWvwpypZAFhb3z6vUsxZwozwJxCU2cmcc2zngLMuCSezbh9cAraE=@vger.kernel.org X-Gm-Message-State: AOJu0YyROJU7KWCJ8HOSss1QdiMoNqu0jRovoYOnBHMZz9ZAkHrLbIhg wYvM/YEZuQtvtRSb+knCuUcvonof1kEXY4K3Dji9xxn9M4xAQEnERx+G X-Gm-Gg: AR+sD10xtwe38I947TvDrtB/Z80wXMvvwGvLBaiT6ZOp5uJSK7herddVkyubOE27H2d zBx8g7mPYbUC3C6U0APwQ7YwSFAJLiKaL98zvJS3zuo5aLBhVzas+xLQkYRn9CahIcAPnZNMz8z B8rxk3w0xyTyqlmDjmbit1plMbj/pdu0tnOSFLo8kTSASTvLOT4vxe3XHSA4UKiD0O9cXjv2VUz i3jIb8/vhOBPC8Q5I4SKIDCXcREyjrpWROdJ6POjqT8YGsbiSneDG3ZFK7TwCxdB0nNYJ4BtcKg bXdGxIKyZyKYcX562150rP2Fn42NxLSV6hZsdqr46nJW9/8bzrrH+ZOpls1lqe3xyhDBenegV1X UESe116Gr+v3unkuBNab1pjx0X3eIfCJ/Or42+rjwhAN8caVPqrpcAYfshUescAw9SwsOcDfYsv FfM20MLHDo6KScPuJGjLHH7ET61jrLrs3gjBsrpWbpJaTzpEkBeYIHMtsw/Of3UiG9+OayXke2T 8RTisJN98wQSA== X-Received: by 2002:adf:f191:0:b0:47f:921f:3a2f with SMTP id ffacd0b85a97d-47fd72e1c69mr1704509f8f.25.1785534653209; Fri, 31 Jul 2026 14:50:53 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.62.64]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47fd41e2484sm10186342f8f.11.2026.07.31.14.50.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 31 Jul 2026 14:50:52 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza Subject: [RFC PATCH 6/6] video: logo: add ppmtodtlogo host tool Date: Fri, 31 Jul 2026 23:50:43 +0200 Message-Id: <20260731215043.30392-7-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260731215043.30392-1-maximpedraza@gmail.com> References: <20260731215043.30392-1-maximpedraza@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The byte arrays a "linux,boot-logo-clut224" node carries are not meant to be written by hand. Add a host tool that converts a PPM image into the node, along the lines of the existing pnmtologo: plain C, no dependencies, and no quantization of its own -- the image must already use at most 224 distinct colours, and the tool points at ImageMagick when it does not. Three output flavours: ppmtodtlogo logo.ppm a complete overlay ppmtodtlogo -t dtsi logo.ppm a bare node, for inclusion ppmtodtlogo -t bin -o logo.bin ... the blob for a reserved memory region, header included The devicetree outputs also carry the optional placement properties, commented out unless requested on the command line, so the generated file documents what can be tuned without regenerating the image. The tool is built when CONFIG_LOGO_DT_CLUT224 is enabled but is not used by the kernel build itself. Signed-off-by: Max Pedraza --- drivers/video/logo/Makefile | 6 +- drivers/video/logo/ppmtodtlogo.c | 402 +++++++++++++++++++++++++++++++ 2 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 drivers/video/logo/ppmtodtlogo.c diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index 895c60b84..e7c77bf7e 100644 --- a/drivers/video/logo/Makefile +++ b/drivers/video/logo/Makefile @@ -18,7 +18,11 @@ obj-$(CONFIG_SPU_BASE) +=3D logo_spe_clut224.o =20 # How to generate logo's =20 -hostprogs :=3D pnmtologo +hostprogs :=3D pnmtologo ppmtodtlogo + +# Not used by the build itself: converts a user's image into the devicetree +# node or memory blob the "linux,boot-logo-clut224" binding consumes. +always-$(CONFIG_LOGO_DT_CLUT224) +=3D ppmtodtlogo =20 # Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..." quiet_cmd_logo =3D LOGO $@ diff --git a/drivers/video/logo/ppmtodtlogo.c b/drivers/video/logo/ppmtodtl= ogo.c new file mode 100644 index 000000000..de823131a --- /dev/null +++ b/drivers/video/logo/ppmtodtlogo.c @@ -0,0 +1,402 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Convert a PPM image into a devicetree boot logo node, or into the binary + * blob the "linux,boot-logo-clut224" binding reads from a reserved memory + * region. + * + * Like pnmtologo, this tool does not quantize: the image must already use + * at most 224 distinct colours. Reduce it first if needed, for instance: + * + * magick logo.png -colors 224 logo.ppm + * + * The devicetree output stores plain palette indices; the 32 entry offset + * the frame buffer layer reserves for the console is applied by the kerne= l. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_CLUT_COLORS 224 +#define MAX_PIXELS (32U * 1024 * 1024) +#define BLOB_MAGIC 0x4f474f4cU /* "LOGO", little endian */ +#define BYTES_PER_LINE 12 + +static const char *programname; +static const char *filename; +static const char *outputname; +static FILE *out; + +enum output_type { + OUTPUT_DTS, /* complete overlay */ + OUTPUT_DTSI, /* bare node, for inclusion */ + OUTPUT_BIN, /* blob for a reserved memory region */ +}; + +static enum output_type output_type =3D OUTPUT_DTS; + +/* Placement options, emitted into the node */ +static int opt_centered; +static char *opt_position; +static char *opt_offset; +static const char *opt_rotation; + +struct color { + unsigned char red; + unsigned char green; + unsigned char blue; +}; + +static unsigned int logo_width; +static unsigned int logo_height; +static unsigned char *logo_data; +static struct color logo_clut[MAX_CLUT_COLORS]; +static unsigned int logo_clutsize; + +static void die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +static void usage(void) +{ + die("Usage: %s [options] \n" + "\n" + "Convert a PPM image into a \"linux,boot-logo-clut224\" node.\n" + "The image must use at most %d distinct colours.\n" + "\n" + " -o write to file instead of stdout\n" + " -t dts (default), dtsi or bin\n" + " -c centre the logo (logo-centered)\n" + " -p , logo-position\n" + " -f , logo-offset\n" + " -r logo-rotation: cw, ccw, ud or none\n" + " -h this help\n", + programname, MAX_CLUT_COLORS); +} + +static unsigned int get_number(FILE *fp) +{ + int c; + unsigned int val; + + /* Skip leading whitespace */ + do { + c =3D fgetc(fp); + if (c =3D=3D EOF) + die("%s: end of file\n", filename); + if (c =3D=3D '#') { + /* Ignore comments 'till end of line */ + do { + c =3D fgetc(fp); + if (c =3D=3D EOF) + die("%s: end of file\n", filename); + } while (c !=3D '\n'); + } + } while (isspace(c)); + + if (!isdigit(c)) + die("%s: expected a number\n", filename); + + /* Parse decimal number */ + val =3D 0; + while (isdigit(c)) { + val =3D 10 * val + c - '0'; + c =3D fgetc(fp); + if (c =3D=3D EOF) + break; + } + return val; +} + +static unsigned char get_byte(FILE *fp) +{ + int c =3D fgetc(fp); + + if (c =3D=3D EOF) + die("%s: end of file\n", filename); + return c; +} + +static unsigned int find_clut_entry(struct color color) +{ + unsigned int i; + + for (i =3D 0; i < logo_clutsize; i++) + if (logo_clut[i].red =3D=3D color.red && + logo_clut[i].green =3D=3D color.green && + logo_clut[i].blue =3D=3D color.blue) + return i; + + if (logo_clutsize =3D=3D MAX_CLUT_COLORS) + die("%s: more than %d colors, reduce the image first, e.g.\n" + " magick %s -colors %d out.ppm\n", + filename, MAX_CLUT_COLORS, filename, MAX_CLUT_COLORS); + + logo_clut[logo_clutsize] =3D color; + return logo_clutsize++; +} + +static void read_image(void) +{ + unsigned int i, npixels, maxval; + int magic, raw; + FILE *fp; + + fp =3D fopen(filename, "rb"); + if (!fp) + die("Cannot open file %s: %s\n", filename, strerror(errno)); + + if (fgetc(fp) !=3D 'P') + die("%s is not a PPM file\n", filename); + + magic =3D fgetc(fp); + switch (magic) { + case '3': + raw =3D 0; + break; + case '6': + raw =3D 1; + break; + default: + die("%s is not a PPM file (only P3 and P6 are supported)\n", + filename); + } + + logo_width =3D get_number(fp); + logo_height =3D get_number(fp); + maxval =3D get_number(fp); + if (maxval !=3D 255) + die("%s: maximum color value must be 255\n", filename); + + if (!logo_width || !logo_height) + die("%s: zero sized image\n", filename); + if ((unsigned long long)logo_width * logo_height > MAX_PIXELS) + die("%s: image too large\n", filename); + + npixels =3D logo_width * logo_height; + logo_data =3D malloc(npixels); + if (!logo_data) + die("%s\n", strerror(errno)); + + for (i =3D 0; i < npixels; i++) { + struct color color; + + if (raw) { + color.red =3D get_byte(fp); + color.green =3D get_byte(fp); + color.blue =3D get_byte(fp); + } else { + color.red =3D get_number(fp); + color.green =3D get_number(fp); + color.blue =3D get_number(fp); + } + logo_data[i] =3D find_clut_entry(color); + } + + fclose(fp); +} + +static void write_bytes(const unsigned char *data, unsigned int len, + const char *indent) +{ + unsigned int i; + + for (i =3D 0; i < len; i++) { + if (i % BYTES_PER_LINE =3D=3D 0) + fprintf(out, "%s%s", i ? "\n" : "", indent); + else + fputc(' ', out); + fprintf(out, "0x%02x", data[i]); + } +} + +static void write_placement(const char *indent) +{ + fprintf(out, "%s/* Placement. logo-centered and logo-position are exclusi= ve;\n", + indent); + fprintf(out, "%s * logo-offset is added after either of the two. */\n", + indent); + + fprintf(out, "%s%slogo-centered;\n", indent, opt_centered ? "" : "// "); + fprintf(out, "%s%slogo-position =3D <%s>;\n", indent, + opt_position ? "" : "// ", opt_position ? opt_position : "0 0"); + fprintf(out, "%s%slogo-offset =3D <%s>;\n", indent, + opt_offset ? "" : "// ", opt_offset ? opt_offset : "0 0"); + fprintf(out, "%s%slogo-rotation =3D \"%s\";\t/* cw, ccw, ud, none */\n", + indent, opt_rotation ? "" : "// ", + opt_rotation ? opt_rotation : "ccw"); +} + +static void write_node(const char *indent) +{ + char subindent[16]; + + snprintf(subindent, sizeof(subindent), "%s\t\t", indent); + + fprintf(out, "%scompatible =3D \"linux,boot-logo-clut224\";\n", indent); + fprintf(out, "\n"); + write_placement(indent); + fprintf(out, "\n"); + fprintf(out, "%swidth =3D <%u>;\n", indent, logo_width); + fprintf(out, "%sheight =3D <%u>;\n", indent, logo_height); + fprintf(out, "\n"); + fprintf(out, "%sclut =3D /bits/ 8 <", indent); + write_bytes((const unsigned char *)logo_clut, logo_clutsize * 3, + subindent); + fprintf(out, ">;\n"); + fprintf(out, "\n"); + fprintf(out, "%sdata =3D /bits/ 8 <", indent); + write_bytes(logo_data, logo_width * logo_height, subindent); + fprintf(out, ">;\n"); +} + +static void write_header_comment(void) +{ + fprintf(out, "/*\n"); + fprintf(out, " * Boot logo generated by ppmtodtlogo from %s\n", + filename); + fprintf(out, " * %ux%u pixels, %u colours.\n", logo_width, logo_height, + logo_clutsize); + fprintf(out, " */\n"); +} + +static void write_dts(void) +{ + fprintf(out, "/dts-v1/;\n/plugin/;\n\n"); + write_header_comment(); + fprintf(out, "\n"); + fprintf(out, "/ {\n"); + fprintf(out, "\tfragment@101 {\n"); + fprintf(out, "\t\ttarget-path =3D \"/\";\n"); + fprintf(out, "\n"); + fprintf(out, "\t\t__overlay__ {\n"); + fprintf(out, "\t\t\tlogo {\n"); + write_node("\t\t\t\t"); + fprintf(out, "\t\t\t};\n"); + fprintf(out, "\t\t};\n"); + fprintf(out, "\t};\n"); + fprintf(out, "};\n"); +} + +static void write_dtsi(void) +{ + write_header_comment(); + fprintf(out, "\n"); + fprintf(out, "logo {\n"); + write_node("\t"); + fprintf(out, "};\n"); +} + +static void put_le32(unsigned int val) +{ + fputc(val & 0xff, out); + fputc((val >> 8) & 0xff, out); + fputc((val >> 16) & 0xff, out); + fputc((val >> 24) & 0xff, out); +} + +static void write_bin(void) +{ + put_le32(BLOB_MAGIC); + put_le32(logo_width); + put_le32(logo_height); + put_le32(logo_clutsize); + fwrite(logo_clut, 3, logo_clutsize, out); + fwrite(logo_data, 1, logo_width * logo_height, out); +} + +int main(int argc, char *argv[]) +{ + int opt; + char *p; + + programname =3D argv[0]; + + while ((opt =3D getopt(argc, argv, "o:t:cp:f:r:h")) !=3D -1) { + switch (opt) { + case 'o': + outputname =3D optarg; + break; + case 't': + if (!strcmp(optarg, "dts")) + output_type =3D OUTPUT_DTS; + else if (!strcmp(optarg, "dtsi")) + output_type =3D OUTPUT_DTSI; + else if (!strcmp(optarg, "bin")) + output_type =3D OUTPUT_BIN; + else + usage(); + break; + case 'c': + opt_centered =3D 1; + break; + case 'p': + opt_position =3D optarg; + break; + case 'f': + opt_offset =3D optarg; + break; + case 'r': + if (strcmp(optarg, "cw") && strcmp(optarg, "ccw") && + strcmp(optarg, "ud") && strcmp(optarg, "none")) + usage(); + opt_rotation =3D optarg; + break; + default: + usage(); + } + } + if (optind !=3D argc - 1) + usage(); + filename =3D argv[optind]; + + /* "10,20" and "10 20" are both accepted for -p and -f */ + for (p =3D opt_position; p && *p; p++) + if (*p =3D=3D ',') + *p =3D ' '; + for (p =3D opt_offset; p && *p; p++) + if (*p =3D=3D ',') + *p =3D ' '; + + read_image(); + + if (outputname) { + out =3D fopen(outputname, + output_type =3D=3D OUTPUT_BIN ? "wb" : "w"); + if (!out) + die("Cannot create file %s: %s\n", outputname, + strerror(errno)); + } else { + out =3D stdout; + } + + switch (output_type) { + case OUTPUT_DTS: + write_dts(); + break; + case OUTPUT_DTSI: + write_dtsi(); + break; + case OUTPUT_BIN: + write_bin(); + break; + } + + if (outputname) + fclose(out); + + fprintf(stderr, "%s: %ux%u pixels, %u colours\n", filename, logo_width, + logo_height, logo_clutsize); + + return 0; +} --=20 2.39.5