From nobody Fri Oct 2 05:28:57 2026 Received: from mail-wm1-f42.google.com (mail-wm1-f42.google.com [209.85.128.42]) (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 412C53E3C62 for ; Tue, 4 Aug 2026 20:56:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876986; cv=none; b=JPHSCfRcFjjmEQc5eg3JRezKZwiF9zmiAQ92G7SCvtrgC0HOZQosve+R1EsfFTJtqynViD6RoMUCTHKPoC3o38LsYtYwaWQl0GS5+k2cncEKhMIDAidbTzo3EEace0OP9ICcC4fg1Q2G8zPiABMQnYKUNZjQ2scBo6KJfAGWMOA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876986; c=relaxed/simple; bh=ejJKKlrYGwvN9qLYU2KaaWwD3fSRaEkfSRQt+Gx4QQs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=eI8/EPGlbdsJ6k8YVa97dgD4Yu6Cez3WsoNK9H7IC4b1ln8axWFgEYJfn8/bVT49kc9XUkej9cFg09lwqO9GB6ThFIQcWuDvYLVntyXz5ZAgr7y6XZj3o3b9KZVq+ffvQnYuwchh+ATAw036mKn8tP0YeoP8fliVMyPedOXX9Ak= 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=EV+lMMqi; arc=none smtp.client-ip=209.85.128.42 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="EV+lMMqi" Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-4955aa106b1so1935835e9.0 for ; Tue, 04 Aug 2026 13:56:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785876983; x=1786481783; 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=FsSyzNurkU2AZCAgXzFDhA+4Szt1QyFprpuh+Ygbe6g=; b=EV+lMMqi43j3dOA2ThaWHAyvtxmWuHDbi/yiD9bCIaoOllDS4xOICsEcYSswj6Y7FQ OtMmhLsKmfGEjktM+qoPDzyckK5rO4Fzoqi/JlJuDWGcA/1ZvuQNvhppMHVylq17e/eS +4mILgWElzPtxFWYrBOeiPbMKYHAWE5EbDjymfnW2bdqodpo8VtvjM02QlI7V3fFCmNy pd04yHZbnO7dPGxTxLdDFkh7hucKmWpmibv/lVB36e2/V9vHur7wYOmKR3Bd1B+buRwz PaCAWL2Y8UC4uHyfQNNotCJ7usJGeFbJMloZ3SS36v7MWTaz3Kq70p5cwnmiEEaHZ+cY tC7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785876983; x=1786481783; 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=FsSyzNurkU2AZCAgXzFDhA+4Szt1QyFprpuh+Ygbe6g=; b=CbsK3Bqov3Jg569rON8ZR1GrjtjABkSYR+99wlY5bsLPl8rkAzRbF9x4lcdN76ypWx OAPYPc1um7Tdp0dqySeLUZqRBfdA7mikmnNLTUUemmoFH37Teqm0XyauHEgvE4dpb370 aJoaUVMXyGJapd8OIHspd8Fmf4o6PlIqfVo8JJ+ld/NylmTHFK5IjSTAmCspgSDN5w98 ZNk8DUGO0//5y+36yB21+wWPU5hbfCBDaIXWwOgKVFa4Bq8NaU4jehHpRpwCuX2PsBGo t8QdTfaPRwaRtibX3iZqnbOVwCJfbk4a8fYgr+CPHWuSrOBlV+N+WjONlu51bs6JZCwm G9pA== X-Forwarded-Encrypted: i=1; AHgh+RpnRvHPV8SLBuytfN7zYyH+lnAHZ9eOV1ZrDXX0EcOmP3Gbp1t2g9ipQQxKEsfOi8YHZnCDF39R1kUzHn0=@vger.kernel.org X-Gm-Message-State: AOJu0YyaRXgncSYQNfWwVkUa1Zcz0s40LpxSLAq6sZtwyBzyCflHWG9O rFe4Rze0nw0pGQXH+4w6E1RFELYPjIW38E+fAn2fE6BQV5ARnVunjtx6 X-Gm-Gg: AR+sD10yfOK6Gp2DwBs+Zp/jsD7quqbVu7ppp1vYcCZBGTM8QGtGFNuCmnqIAU0GfYr wH3Ny4I/BWP4Oj6ZqGZ8jRiDjMj4mF0REFMjpE/PYfgRSnZZ0FKdvwm3lFvJw0K+VSm3enjI9no wG3if+mAMSFLbNU4fbQyWP7HJLukCags5Fjf4WfBUa45PL0GU2libNMJm1dwP2GqpoZbHOHDMoX ruf4v1HZqy+nvNoE24SPgtzvW/Ejy0n3PuuGUSpy8G6MS2xmqezY4QSBUy8SVDBgg7oxz9sc9n2 9fb+WvhplqCfDnQVbNON9y+FLtxV0LrhtT7YlX5AWt8L7AT4jbGkQqdEd5cRl/Bv80bz7wpBjHW XGG5ORpGPjO563naxUlteF2vyT222OoWrEJdwedl3kuCjaKEkDALZ9YbB/z2ixLmOcUWvNkKUTt WDAgf8l1t4uVqaLR/5adhNbRsqbqKUtcu6Apb1M63lS+u5SH1i5gA6Uvhxl8CPeSv2pEV0At6oS XePLQqLQ599tTo5sm7v2L/x9w== X-Received: by 2002:a05:600c:4e94:b0:497:ff73:68d5 with SMTP id 5b1f17b1804b1-4994e6c5eafmr12299005e9.0.1785876983257; Tue, 04 Aug 2026 13:56:23 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.176.33]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4994e4bf820sm12070645e9.0.2026.08.04.13.56.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 13:56:22 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Geert Uytterhoeven , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza Subject: [PATCH v2 1/6] dt-bindings: display: add a device tree supplied boot logo Date: Wed, 5 Aug 2026 00:56:12 +0200 Message-Id: <20260804225617.264861-2-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260804225617.264861-1-maximpedraza@gmail.com> References: <20260804225617.264861-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 | 131 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 132 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..a6a206964 --- /dev/null +++ b/Documentation/devicetree/bindings/display/linux,boot-logo-clut224.yaml @@ -0,0 +1,131 @@ +# 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 that + means pointing CONFIG_LOGO_LINUX_CLUT224_FILE at a different image, which + bakes it into the kernel image: changing the logo means building and + deploying a new kernel. + + 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. + + Since a logo is configuration rather than a description of the hardware,= the + node lives under /chosen, next to the other things firmware hands to the + operating system. Open Firmware, which the device tree descends from, ca= rried + a boot logo in the same spirit as the oem-logo variable under /options. + + 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 + +# 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 + +additionalProperties: false + +examples: + - | + // A 4x2 logo using three colours, centred on the screen. + / { + #address-cells =3D <1>; + #size-cells =3D <1>; + + chosen { + 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 5114e6db7..8cf5163b8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10269,6 +10269,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 05:28:57 2026 Received: from mail-wm1-f51.google.com (mail-wm1-f51.google.com [209.85.128.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 9D651429CF7 for ; Tue, 4 Aug 2026 20:56:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876988; cv=none; b=Amyrm1/BjG2zxUZJZz3itr+dItnLC5wsxeb8xyqEAQr9O2Q2ULnKkoCr2TC91l25mue10co7jXCu0ZhOQfPgHfUMDaeWgZ0iKBJ7jhpuDKahsX18hwmyYV43031dqOZOKowTbC8k+GUNpr6lYNknb+gKRyuEqCu3ZqUosNGxqRQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876988; c=relaxed/simple; bh=lt0mcBR/xBSiSFpNw9TpFma/Wx/XqysIpYFDw49QURY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ubqYWZN9oCPGI1o4LwCCLTghQbiPt6SFnHzdJRc7jV1c31IoLLaoPPVUTIl/rBa1i+X3zVnKksb/8NAGCvBnZxd8LS/7q3c68fgytKMRAz1Ik6/F71wlI+EHZ61DKBNBMUiNlkExJzkfhXfYuB6iiNVtc6GtyNHELt0jV4K+Eoc= 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=TbSD8Mqr; arc=none smtp.client-ip=209.85.128.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="TbSD8Mqr" Received: by mail-wm1-f51.google.com with SMTP id 5b1f17b1804b1-4980dc26022so2030565e9.1 for ; Tue, 04 Aug 2026 13:56:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785876985; x=1786481785; 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=xEGbIZ53FjPXZVHPJc+jEB5q1hKyvKtu0OiAqfcxBNQ=; b=TbSD8MqrDqYP5d847lhWNiJw75ByTFAiAvXhC3TOvSyEGiG1yULS1FXvdcCRVtSci0 CTEEb80+Bf3Ns37H/p1HGve4QUxxrSxjQJLnlDe2AiHF4WZQZA6KuH2usR2Xop/OJUAm +awPLz4Sxl1dvL5XN9MkB9S+mLWvQ9vYo8VxVBtI7V43tGYSPB/zf0JaZrQYrvXrnxV0 r08b0UyfqmBbjzVKCf78MeoRiTqAvzMb1P+HHkqCYyEx2aT3XvXsL0BM4nzeR5c7OO/S ZR9/EFSL/moUyBhPnvlqkz4zEcP3Le1sc91B2uL/7HPox2cy70QKd90ZQGjCPYH8rOEG dByQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785876985; x=1786481785; 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=xEGbIZ53FjPXZVHPJc+jEB5q1hKyvKtu0OiAqfcxBNQ=; b=jZFYEcCNw0ggs+mQEqRavtgMfH4KDAKShGcfO1YYdzF6Ms+97zSZ1baOmM/XiXUbSP 2xMvrchhA0+1BrAtrIsmSI3NRFoD2IQqOqreXXcUgR7isTSRnxs9nOtqYnPI6oProsoQ at5XuNXJRX2CEkxhvqWY0QDZhEF4jNBGAyjCqcOubM9JV9aZyjBDnurJOk5gRE5KFcgd HRnSDZv0+i01iyW5DChyqBWNWcqWEZlCcM+znpRcg5VLF8tcLH7u56glRfPYtJOw0HDi Z3GFxNyXDO0hESi6oDWKcTDvrEdDfoDUSoF8AcvVsZsizxr/F0QmJJf5IiTIlclpA8mv eKPw== X-Forwarded-Encrypted: i=1; AHgh+Rq36CXcPpXBQKRhAQqqs3DWtidVUiqwhUoMyIVhl/eaz65zSbqM2JkrnCQxpxSJIf2UaO0LFvm7EYvoAkQ=@vger.kernel.org X-Gm-Message-State: AOJu0YylN4aPHand7Q6meAqgYQZQERUEO5iBNPNjzpAsrvGCp2gwHxVc Zm9uj2bzXMrz+RyHe7Wct96tLqBESUz0tlzuJ+HSJioz0O8POCBNrBBM X-Gm-Gg: AR+sD11eVyO4c8Q4NWagXrbgqNpMDLqS6C63BPBJ9nEa5tkuz80LB1dIo56UiXqQiJz GaVjehlz8zTgFROMfqgNwe02mETjPHY549XxJFXvMdlI98yvdUZA9IZQmUqsxJBMUo6aw+vRjGR YyVQH9zgPwWSm04cin9bUPKpRbOhDZ/ljRW+GjeYJI8G589OTunOqwjlIvnvhCIIirWnO6dYJuv jVu105FmvbLYmZI3iIhxv9Prtzci0C1opppetGHGsULVykV4pZdDKAwmCu1Y+uAIXTaTAhwjdaR N1TT0zYcM/Uw6IpuW0VFxD7rQE3RHSzi9JbGkvZeMMtY2nDUJJW1M5oAc/aEJE6YwiI9Ls24Z9q +DmoO8yeVVUEiHRAsjHcQYIGnfm/laaZv0cw0LN4jX7FAA8c1KJdPe5njlnnzFMbBdvY58HiHzQ d4wvqKmALVFD2LOH/lueu7yotM+XEXmaJFIxPDkAYU3Vcv0ikUW2vik2QopRqyhxWdMgnkobo/J C9jys2gRVcKfSs= X-Received: by 2002:a05:600c:a20b:b0:495:737a:7afe with SMTP id 5b1f17b1804b1-4994e7d5b82mr8732495e9.15.1785876984840; Tue, 04 Aug 2026 13:56:24 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.176.33]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4994e4bf820sm12070645e9.0.2026.08.04.13.56.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 13:56:24 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Geert Uytterhoeven , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza Subject: [PATCH v2 2/6] video: logo: allow the boot logo to come from the device tree Date: Wed, 5 Aug 2026 00:56:13 +0200 Message-Id: <20260804225617.264861-3-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260804225617.264861-1-maximpedraza@gmail.com> References: <20260804225617.264861-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" Add CONFIG_LOGO_DT_CLUT224, which makes fb_find_logo() look for a node compatible with "linux,boot-logo-clut224" under /chosen before falling back to the logos built into the kernel image. The image is validated before it is used: the palette must have at most 224 entries, the pixel data length must match the geometry, and every pixel must reference an entry that exists. A malformed node is reported and ignored rather than drawn, so a bad device tree cannot take the display down with it. The image is copied out of the device tree so that the 32 entry offset the frame buffer layer reserves for the console can be applied to the pixels, and the copy is released from fb_logo_late_init() alongside the built-in logos. The node lives under /chosen because a logo is configuration handed over by firmware rather than a description of the hardware, which is also where simple-framebuffer nodes live for the same reason. Signed-off-by: Max Pedraza --- drivers/video/logo/Kconfig | 12 +++ drivers/video/logo/logo.c | 160 +++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index cda15b958..215afa7ef 100644 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig @@ -76,4 +76,16 @@ config LOGO_LINUX_CLUT224_FILE =20 magick source_image -compress none -colors 224 destination.ppm =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" under /chosen, 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. + + If no such node is present, or it is disabled, the built-in logo + selected above is used, so saying Y here is safe. + endif # LOGO diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 91535f884..7f8b04ecf 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_get_compatible_child(of_chosen, 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 @@ -48,6 +201,13 @@ const struct linux_logo * __ref fb_find_logo(int depth) if (nologo || logos_freed) return NULL; =20 + /* A logo supplied by the device tree wins over the built-in ones */ + if (depth >=3D 8) { + logo =3D logo_dt_find(); + if (logo) + return logo; + } + #ifdef CONFIG_LOGO_LINUX_MONO if (depth >=3D 1) logo =3D &logo_linux_mono; --=20 2.39.5 From nobody Fri Oct 2 05:28:57 2026 Received: from mail-wm1-f44.google.com (mail-wm1-f44.google.com [209.85.128.44]) (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 4FE8D42AF9B for ; Tue, 4 Aug 2026 20:56:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876991; cv=none; b=l0VccQWccM9DXOjXo24jthuN4ldy5RDCD/NRJT0ojOwoyhP7oO0/WWrXiRKQzoHavIHwe52LaWlpaCpnUhXGgUJY5mWuhGZ66ilRFHz3lF3lBHzD4C5lZTWFycW42QNH9KD2JrZusJgPxdF3Nfy+/bCSZuDD3gRpPIQ7z11USoA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876991; c=relaxed/simple; bh=b6pkm9AbznuP6ASEvkFpmUaiFAyJ0vcaTsusVxEfRjM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=b7qcN/KtqJ6pGoJ8Go8Ydw4AndKo5tbFlorJ9fvXBrvSikXdLR/cAFo0dEwFxrFBEv9P4RtyhtWs3ZVte0zNlkgX39IWHV3yMhYPPr95VI0Y9/cPEF9yGeW3j9VxW+DKblOL5Yoj8qThky3kTPK9S2A+BRPUq+Pz88VxrmsjblQ= 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=neS7QGSu; arc=none smtp.client-ip=209.85.128.44 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="neS7QGSu" Received: by mail-wm1-f44.google.com with SMTP id 5b1f17b1804b1-496b7622a83so1558195e9.2 for ; Tue, 04 Aug 2026 13:56:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785876987; x=1786481787; 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=neS7QGSuJmPzeON1P1UrrzYjiKjK5L1nPJPEkNjarlFcPXy5Y5UMdB3HUSliNUXaPa u77EN8wR5fhSadZBhWwyk5FjrQzA8+1FBfCiufAu9ooKL4/I+IC6NMnQ94UJ1/pUlYOD CVvgJnLpD/QKJvJcRsU+X3NwHxcfylgVxu/EcBtvS54t/s7jQxOMneGru2LY7fyGIt+V ejs5jKzaedHd2c6o2Rsi0NzT3/qJ7b5APAvfwtLsp1TEREh9L5kHVCDI6Be76TKnwi99 +BC1yyqT06gSwG5P6iRbSRZgCLSTOdZgQPlN4bXkiSIQpMuhQMOoRm0fNj4whHFev4Be uHeA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785876987; x=1786481787; 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=pa6SSXBYXv2iwinSPmyRmJOUc5l/H3lpelzFSRN9Z1rTSUPsjerTZ8qtl3HORhV9Hc bcH9sbmC4PaMoZjIDKeYZQ79qLw98C3buzYyc9oRRAYpdT1MSI9zdZXPb/5gef4mSdwF mdsIlita8jBI6uMldqk2UO8CLLHTVqHtkgBi236nRky1SqnbEipGf5k+TIahUf9hTTpO HfUC1ViIs3TTDW7YrUxYd/hkO4FqiilxPVOn3G+gFPnPtRFRk35lImaYZ+6iksZ+9Xm2 udKWkrKbYMK9UtSc6P1hfDLDy5fD0jgTSVUzm2LU6HFfwZhRxVwwHY/dNnR2wyDJ2z50 lutw== X-Forwarded-Encrypted: i=1; AHgh+RpZvsWGnLMDHJbsDW95yOZz+MXhSPMKeUGrGr9EXrXIuY5rfgDpU0KG9s5bkU81QIL644VIRGoipPM6TE0=@vger.kernel.org X-Gm-Message-State: AOJu0YwU4ojJFp3Od/3vHu43NmE7rJZw8xvpWlLIwYaRWmqN+B9Vvuca QYTjJP4FcS3r05LRyqa1PUK207DpguzwZgFKP8CvwRghVplbKAV6rii1 X-Gm-Gg: AR+sD136DxJchASBiJjJz2Qt/4OT4pCZwu1D+Yao2tudPA03wcjNbeMH85IQiVwhlyA qLRLynSWESz7Jb3OmWwzIgzWKf7+rVOQlX5kQ5Pufso2PjS/VfB+z7llKlDYgSnaM7jQEc6nuLK hUDNCGiWUfjQFvXfRpC088f5dsVxJ4IQevRxUsO9We1pQ1Eo8pb7mq/88Ii/JfBQo8A/sbgqAwO 4YYpYeKxJhasCPDEcVmL0+7x3mO8j8Ieoiu3fNqNS22vZFGVYKf/4MqxnbyJcyzC7bd5XJBThKB y93QhCkcTioHXxnmTT7bUWZKAfiAlaYxVBZj6LmLmfFc7pc50cdR3sWNMN2976FHsOLJTSelHyr NnY4LEtTHPydEf25vx8/c1CR5zHNl6UqiDFiCrodrf/4TJbTy/GtjE8O4FdepR4c2a0GifvQaKr nsGCeMyY9Z8m2kifTXIzYXME7VauUb+WfpcVY+pKQO6JlZJMx3ZP2UBG33fb8vkmU16pBkkRoci i1RNg+/C+pukpE= X-Received: by 2002:a05:600c:1f87:b0:495:607e:5ee7 with SMTP id 5b1f17b1804b1-4994e7d8ab9mr9728935e9.17.1785876986562; Tue, 04 Aug 2026 13:56:26 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.176.33]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4994e4bf820sm12070645e9.0.2026.08.04.13.56.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 13:56:25 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Geert Uytterhoeven , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza Subject: [PATCH v2 3/6] fbdev: honour the device tree boot logo placement properties Date: Wed, 5 Aug 2026 00:56:14 +0200 Message-Id: <20260804225617.264861-4-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260804225617.264861-1-maximpedraza@gmail.com> References: <20260804225617.264861-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 05:28:57 2026 Received: from mail-wm1-f48.google.com (mail-wm1-f48.google.com [209.85.128.48]) (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 ED72542BC2A for ; Tue, 4 Aug 2026 20:56:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876991; cv=none; b=rr2vMqtFexOsYLPbjEVrREJNNzNQcbYeniIlGnHYgagmWvjGne5upXF3KGNAI1zixqHA6kZPc8Mg/TLhl5zndpHqxur75Xy0gbvJJ817MJrxJLFJTCJctuZwXxhQKhUAZ7rMmKdkrRHeE08v5vLVxJqAOLvFIeaPFH63qvTXS4g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876991; c=relaxed/simple; bh=yu7fTJEvu/WM6iPEXNZYvP9LNyFeTGKqeWmRli0lQx4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iDvAshsK3qRppd3/pESLQG6Owcm7qXB8bvTLYEC4OkspdFfhuwmTpQwvC1Ni9UkKD/dxyy+3xfHgKTietalPoNzYK/TSj52JmvdtcIAzNxbKkv+uEFxuPUOVqCT4hzU+oLlTxB5jwyrZwfeXz5poKN2JZZpyt0F1xYGjBqTFW0E= 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=Mo0GdF3Q; arc=none smtp.client-ip=209.85.128.48 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="Mo0GdF3Q" Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-4921eed3fa2so2098145e9.0 for ; Tue, 04 Aug 2026 13:56:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785876988; x=1786481788; 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=SHxdaaypANO4SJdv7vjmn9Syq8V3Ebhk1vARZd9Mr0s=; b=Mo0GdF3QcDQm4YHlRyfbx+lTUWgf6Mv/BK4DFeijlJ6PeSeIi31Yt1F+mT0KjBi4YC tB5oMX0imr0pKiZF8qhRSNGcd4QymbE7OqPrh0UycDm5FP40Jwkoyv0m30w1yTCZ/Y+B 7skLtt45Ap5j3WPY3LqjcsxdbY2k78Nje4RFrdLK89axRUFc4T9Jr3jePGNl1Vn+8KUU UJ/+BVdy7rrqRWpgUFewEMkNX55cb3eN8VRphrDHd92vYjChl3/jdYGJQwJL+kG76Ehf x/lZAicCg06959pEV87iqdit8ut1qps6yXaba5+9h+DOQvTwhbpPaGoqVWBDsXD+vi4B W0Uw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785876988; x=1786481788; 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=SHxdaaypANO4SJdv7vjmn9Syq8V3Ebhk1vARZd9Mr0s=; b=oh1L6ZwqKwke00preK/++3tzhz5CFWlHyV7Jvd+ppRy2bSI9g9Z9Nk4buM1JjOX295 PQJVlKluqdwUGn/FqqSAzjUUG6L4Eq6Sif2oLLc902HPXEowlwp62iO3clw0Smu8w/jo UXpshgfzZ7j0/HeV61VY2k7R0zMhmziA0Ev0YMfDVTqOyHE4sqNltg9/CUTV5yHkq1qS mlcgdH086xnTdm2L2FNrnHBsxgle+X4EvvpJX54onRkFXVqaVDuHYzM2lWLTMA0UGMGn wAp8Kd2pokqrz+EdFtktRAjWNp0hJloRB6u58kon5TdtQoeXS6gDDQbBjCJCehep6+P6 f6jw== X-Forwarded-Encrypted: i=1; AHgh+Rr+Ip8YTS8hG6aEvQ++XZGF74VnketoIPRKVdPl5UrLzd5klSjouX4XjkoY6qHHOtuAkR4TLoxfpP61LRk=@vger.kernel.org X-Gm-Message-State: AOJu0YyG4OBAKzYAGEr5ZygitZrSHNB+lS1N5YQW5itDqFOK50X7lmyk JmkGLSv+8KqPJ8byNMx6Y4279eAAxKlWS7MLFbxdni+WFAoa8EKN47Zz X-Gm-Gg: AR+sD11IN63fKxGBs1hkQouHZN7W3EkwwwWkO+LdlRqCejczlG+KhAc+O+ohaXTKPlI lB1RcFJL0YXHl1cmxn7Jfhk7XknmGYAmX/dM70EE8G+p22WhciKRns03r+B9ptcwdqtlnfouZhg IzHhII9ddm/i1sjs2Ui+Oj2LnBCbbOD7io8WZczVmTbJyv/s29Fl7OzJn4vVlX7y/KkM1AeOFvq 0xMlM6WzHO6g1L6xz6iP3SFPq5khczUaeOqUnDb2aKvvcd5GEMa0GViNGnvr//gP3YZcrt6len2 BocVd1NkQv1lC5D3S5w1QMMib90f86JrNcp20d+9Z/kU0ojQzoyBbi8hfQ6jYwK6DU737FU5z13 S3ZVsRFVQLewSdPw8QxbD2Ulecbaa18/1JdBjTN3g/bRxxy0offdnureZpSfZBWahGR3U6zOGfi PEHvz0eWEmnN3BBj0mixiTWieB64IWDXeJZWzEb/2ydAAC+XySkyFN03ybJMD1q+MX5IZIBCWAD 2CUx6K7KBrCy3c= X-Received: by 2002:a05:600c:1d22:b0:495:6338:1453 with SMTP id 5b1f17b1804b1-4994e7cfdcfmr12133965e9.16.1785876988197; Tue, 04 Aug 2026 13:56:28 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.176.33]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4994e4bf820sm12070645e9.0.2026.08.04.13.56.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 13:56:27 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Geert Uytterhoeven , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza Subject: [PATCH v2 4/6] dt-bindings: display: allow the boot logo in a reserved memory region Date: Wed, 5 Aug 2026 00:56:15 +0200 Message-Id: <20260804225617.264861-5-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260804225617.264861-1-maximpedraza@gmail.com> References: <20260804225617.264861-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 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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 a6a206964..7aec0cc2d 100644 --- a/Documentation/devicetree/bindings/display/linux,boot-logo-clut224.yaml +++ b/Documentation/devicetree/bindings/display/linux,boot-logo-clut224.yaml @@ -59,6 +59,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: --=20 2.39.5 From nobody Fri Oct 2 05:28:57 2026 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.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 9255442049C for ; Tue, 4 Aug 2026 20:56:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876996; cv=none; b=L3Qt0N2LuUrKY5PxdQK+hfbkAdW9AVKjvuaX9EDyrRfZdgEChPEwG8t6IBGZizgW/hbHARb0U3iwH2wYIbmpo9QWVrOMt8s7Gin83VLA07G/tP7s/jERWSzzPDdVHhWj0V1dcvxK6U8ODElvFB0uYJQ76dGrqbBU2VVLAzzvKZU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876996; c=relaxed/simple; bh=xGIABBsXaUoJaXPxJBCwzJ6/LRKxGWYYgzXd5in9Gl0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=qg0CBePkN2zagHG+mgyVdqohovhbQl/Ew+OqfJ9/jQyBv7zrcOpzUjK2R7GleU5il5gOvdQ1iVAYMXB4eNwLSdoJfN5auMYntrk7wGe89059PKrbkCY7iopqzCiMlhrWX2tG/CEgzM9WAlu3dd3o+ieMr8iEBVT6qQB41t6yt2w= 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=dp8jQCK1; arc=none smtp.client-ip=209.85.128.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="dp8jQCK1" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-4954dff6536so1661305e9.0 for ; Tue, 04 Aug 2026 13:56:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785876990; x=1786481790; 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=Ei4wu5HfRa2wxht5dmisRmUFZUNWVNZz+Xwp09rdeeM=; b=dp8jQCK1YaYirOoxHAGZTLCnTeS/buaok+RRZGMULE+p2axPEaXayjhtGmZ1HRvfP3 xB9af6sTkYd3wLR5tJdglDlWNy52hCKbp6tS0bHFlaxkjsTii+gy+vOfmSm2Ek0fugrX dg3bkh14ei6NS23THNwPOrjYTTuMssJDU5tCKvwC8F5U3JpF/WaDiz5Cq5iegfbjWDbm bgjIJTIchdeuk7vaz6Kvt4Lsaiqg0+ihz5AItnYj7iYrnxE+Nx915+14ZPhfl/vrOBmj YblI4XAPSHhDImTR669JSs5pd3kn7AY/mmd3KBerdeCTrQt4TdXGdHIxvUdhQpDPw2zb +B6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785876990; x=1786481790; 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=Ei4wu5HfRa2wxht5dmisRmUFZUNWVNZz+Xwp09rdeeM=; b=R37GAblE4/2HtYbmpC0+YpNPFfLlYRUMyHZDj+eWJorpsZKoP0J/lcxkHFu+2PWu3m koCnIHiQn9rusojRu+fgvmgVnH96KqSUKRodoowNjW1kMYUVX9lO7lW0H8Zq+6byYCCH 8IaUQw5REDA1d0aK9Gp40rLKJPmLZfVawCUHS1ZS2hEWXXDg/IckJB1EYXk/pboMM2g1 04kTkvUkdfQhwdrGpQ3x2U2XjNpuNOyraKJllPeDu9F81RZmO9Vn+1Ks72EiPMhAoPtO h9Dw1vzHKmQJoMV93vzrh2O9xrIeZPCTjBvQMcBb+aVyzzpMcqC4UdqI9zU2izHyjEpl 6kXg== X-Forwarded-Encrypted: i=1; AHgh+RqQ9EaI7pot3Ok+6e7MNrM8jh/iiigafuEJN75hdbwdeXorIPaMPfBYgm2HT2ML96+e6+KMUsbmfaHpkX8=@vger.kernel.org X-Gm-Message-State: AOJu0YwzqyfANura+3DLXPyHji8hRacnEkhpymdOC8PSszhUPgnYV4yd MBs6c5bz0phHseHYCfeEd9EAYCh3mIPNUVADx9ZPT1jra9RQvjiIROx5 X-Gm-Gg: AR+sD11+hqHRiZNnHYJPkWc4jA4r5zsGvTzsPWQUnOjMd1RoIFuQWotqQZhiPBN6pdC 4cITGbk7AdcBDPY2y0fW0zr0c0Oq+TRI3gbnli6/duGVSEjrK+vEHUKoZ7wTLuYD9p15Tlpgyb5 jRu6I75s4RMJ/oE2todAPZcAa2wYaSM4SfJdYJ5iBbLk7izeml4OmMYwcRLxu8Ts4La4uDzoqwh anvHPjFIe8YCkChaXkFS+7/bxjzuC138n0xohOvTQfSr5wesPnap86g9YTVgZiYNMHxq4Z3/O5k yYH9MLRGmXi/IjE29iRF5/uUAZSNTVa7CAST1XJtlOzWCNbQvaNM0SUQq0CQZ04COyKN1DO4+8Y 8h8scpDyDhvr62B3mMHJ0dj/+wpIuW8s2eS4+GPb58Z6768Wn76aYSkn5SO+X7tmodLwsHNIbOj 5xMYnZdnE8wZU48lrgU2VaFZDonBOydMsK0ksaIz6sqHKT0y/5VEPA+mp6jp7QsCVZOzXpR21M6 KS+iHb4955IOL0= X-Received: by 2002:a05:600c:1c22:b0:495:734e:4825 with SMTP id 5b1f17b1804b1-4994e7dcf28mr10141705e9.16.1785876989801; Tue, 04 Aug 2026 13:56:29 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.176.33]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4994e4bf820sm12070645e9.0.2026.08.04.13.56.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 13:56:29 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Geert Uytterhoeven , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza Subject: [PATCH v2 5/6] video: logo: allow the boot logo to come from a reserved memory region Date: Wed, 5 Aug 2026 00:56:16 +0200 Message-Id: <20260804225617.264861-6-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260804225617.264861-1-maximpedraza@gmail.com> References: <20260804225617.264861-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 7f8b04ecf..66bcb37e7 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 05:28:57 2026 Received: from mail-wm1-f44.google.com (mail-wm1-f44.google.com [209.85.128.44]) (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 ADF4F3E3C62 for ; Tue, 4 Aug 2026 20:56:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876997; cv=none; b=rcV0Pv5QynfUiTGuR3h4Xzex+PhBBDzCCrXHu789OHaNKEPmaH8M/z2Kmq43GRNk7nn8GR02j1xILStrvWBEKQ0jZYbl8b5lvF7JF9Hx5+YQyR4UVMbfVZUPqwzfnT39W4RUKqXZwQ22sFxrnpM75SQPgb4dQ9RxzqxwL1AIjDM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876997; c=relaxed/simple; bh=Sc3RdNoHAxHHoHapSrdLmmJERSIsY5kD1xNxOX6do8c=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=EH4apBUogK2jJVtjCTf7ov3zL3GMSdqpYUfP3HDGfZ+25YnxiHl8RiRomRaOlyl0y+qFgjUNq4Wd/tRRJrpV5gI8S+9QNX7TyxC4uGLSoIu/0MYNCOpiIRsbXBsGNRQaVikHFZjRSQhfVJNz3LMtR+zUHuw75FckyCCdq9srf6A= 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=WwnEmM8L; arc=none smtp.client-ip=209.85.128.44 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="WwnEmM8L" Received: by mail-wm1-f44.google.com with SMTP id 5b1f17b1804b1-49800c6a846so2013675e9.3 for ; Tue, 04 Aug 2026 13:56:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785876992; x=1786481792; 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=0rdtrk8XXOPPUZBCUeUX/HYP4M8McVi1CQOTrbTXLV8=; b=WwnEmM8LJQPLjY1BDkLpyYPIs/YcLAVU1NDYe5W7nrwPBVoc4OiFF255kC+U/gx+bo 78KAMOyslLFWh6DOu07N5J64/bQBRrDQtMrPsyBEX6/Nbg6K+0Lj/OZdAGbKsXjc6rcw cxXaEgS1xT9ncbjrVssBx3GLp9tEHiZCJpREiCjxBx42bpMQrwIE2zmqJg4y0GxYFRh7 8LmPR8WU+86zVSJSdblIZXMUKpdOPdzgYaqMMS1Lnvou52vmjWEbYloNvMvNZo5MsZGV iOudiMAQgbVHbAwzMV2QNDcDAbgQzwdJ7a27MI1WvmQEZcm2X+QP6vUWOPs0AzGAoi+d Uv6A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785876992; x=1786481792; 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=0rdtrk8XXOPPUZBCUeUX/HYP4M8McVi1CQOTrbTXLV8=; b=H1inuNS8AYnvbY/DIN3nGCvZep1eQz7BlUnB63pvWqulsRSiAUzGKIMDPkj6ZkKyLu KakklJ55IHiHiD4EfS5tFJQW7c9Y4MsjA+0g05qnQU1aNBTetfy2Lb73RlR7CfwJ5Esb 8osNLePqAbDTFwuuSzO/jeWX+qqNO3vAExCNDm0cBRj/iVGefsoHHvB6zr+bBlKXaEB/ iZQew8RClTSzB1CbEKccd6evCIqEZOz1itTu08fsHpsaC1QWW3cje6HQt02teBPInlbO fSjUAFmzXx3Gmz6LI9WRD/Th+xvQCY9HUgWMIVfEV9edgHaQTLhz1jvAIASjfawoWTdp cK3A== X-Forwarded-Encrypted: i=1; AHgh+RpUWPTBQ1L1xKpGSUtQvRGI9N5XU42Mw/0rW9x1NoH6VmHmNoAgcJFBVDOwIIMga5V9G+qzOlVwcB1QBeg=@vger.kernel.org X-Gm-Message-State: AOJu0YxAPx+qvcNyEdqqkVbkz5G0izA2a4i/f8Dai8ycSmqzr0rfsg8e kBqMSOf5IfPFPNCO46htg2PtH+N1GD+wmevlV4LGBNdNkEU+KjLqCOcE X-Gm-Gg: AR+sD13+MvccvwrY4uTpnrZJfIioeitpl0oQNhwaWuAEUhLlmaOUfmHszCJNmPdHJZc GLnktyltGmGReBQunzSVLvCm8U2jtRv38otbdSt3l0a0L/+pP0VSywFw2W2ER1yhde1dw0NI8sJ FGwdsy5Tng8SruUIKZZHvfdEM1OMV4Ux6S+z0Ea0EaHu1X+uRSHi6IUwdrj1GCLiROENwWVOgmf V/gcBHyl4H5VIREnOgi7PUQVhawENTjI3tVaao86mWg00TirAu+Lz/p6aXQ1sqwhBX6r9pyfn1k fIpitwHXluMjfDC2ZUdS9xmDb+5QWPF6xGnyIj/Xa4lCgrE+SeIf7aZUZuVLFcXM6Ic+WUIdU9m 2MU45KF+jTL4G6pole2qXR+k4JfWUlDz6YRcaQrYO7Iy+JXcNSZLHV3Ko3ekMyyAARQmDd9/MwG uybVa+Y2qJ9lnGrjb/1seNNWtFKn9A6nnju/TCwxThZaRF/toeRyh6yshxCDT9gXp3BG4QFjwql WjXxFSFkLY2pnw= X-Received: by 2002:a05:600c:8582:b0:492:3e69:a86f with SMTP id 5b1f17b1804b1-4994e79b93fmr11058805e9.1.1785876991477; Tue, 04 Aug 2026 13:56:31 -0700 (PDT) Received: from ingenieria31.oficinasStQ.local ([79.116.176.33]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4994e4bf820sm12070645e9.0.2026.08.04.13.56.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 13:56:31 -0700 (PDT) From: Max Pedraza To: Helge Deller Cc: Geert Uytterhoeven , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Zimmermann , Maxime Ripard , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= , linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Max Pedraza Subject: [PATCH v2 6/6] video: logo: add ppmtodtlogo host tool Date: Wed, 5 Aug 2026 00:56:17 +0200 Message-Id: <20260804225617.264861-7-maximpedraza@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260804225617.264861-1-maximpedraza@gmail.com> References: <20260804225617.264861-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 | 408 +++++++++++++++++++++++++++++++ 2 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 drivers/video/logo/ppmtodtlogo.c diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index 937b37d3b..49954272e 100644 --- a/drivers/video/logo/Makefile +++ b/drivers/video/logo/Makefile @@ -10,7 +10,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_linux_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..a52c61cec --- /dev/null +++ b/drivers/video/logo/ppmtodtlogo.c @@ -0,0 +1,408 @@ +// 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 node is emitted under /chosen, where the binding expects it: a logo= is + * configuration handed over by firmware rather than a description of the + * hardware. + * + * 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 \"/chosen\";\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, "chosen {\n"); + fprintf(out, "\tlogo {\n"); + write_node("\t\t"); + fprintf(out, "\t};\n"); + 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