From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm1-f50.google.com (mail-wm1-f50.google.com [209.85.128.50]) (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 B5DA442BC26 for ; Tue, 4 Aug 2026 20:56:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.50 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785876988; cv=none; b=mk67lt9hoCQSth+lXhgXymJTVBh2GDpGn9T6N2dqnnVXrTRfgyS9pSJj0WpEFdQFaz529q8y3lu923ly23Y4cOArkVmeCfXl3/mmt6Abx+k33lyFKzSHhlbEF+i9+f6GQ8hF6NO59G+E/+JzK/WWZRQgAbYRW8c7tsB79f2Oc9k= 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.50 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-f50.google.com with SMTP id 5b1f17b1804b1-4980dc26022so2030555e9.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=mZ+ypnxcHCByDUPtr7P5vu844I+qOwvu8QP8WsALuA2IZ9ynNZ+Bs9kZ8/uAL9I5hK Uwzg5FLyt3uXNlGYyNOcfvXt9F9OVlGjftUHjuPy06+ZPAZmePfI5YeaJdm3UeyAM3Gp N5Iqdg4A3exrITCphK5F0lXgBM99EuFbJZnPkUD6tvt4FSTybSgO4eWESf+Zv9zqqUeB y+N7UDCkbWyadmMHs5ij6x+JvHFfecN2UQ9fYKTFbyaGV02DaTuNgvTSFEx1AVlSBrcO HnujefC3S7GWlCAjR5PWXPqyvUi4iaqOCzdNpcDOBDL8z8v5nTHHV+59GgGe6QoG/0N/ QwfA== X-Forwarded-Encrypted: i=1; AHgh+RqCl+QJVb0NOYh7Yr6SWqnebWH2zoWuwpAQmlHpsb18uAfeHMZErc9VxdLn/tL5cWTTD5jrbAK8HY2A@vger.kernel.org X-Gm-Message-State: AOJu0YwxZtHUYQU8YpF9JJVnvkJ1pDGuT76J9civuqHRGKoSkhc7c3+0 vobVVYeYwic08DYvGXrMxxpQ4VwSZ1+DVElcCb88jxuZ0hHDEXfK4GMY X-Gm-Gg: AR+sD139LYkjUDgkcLnBtbXC0cfa/U5E0UZJRxgUHyGrve4CSHSS5hXvynPg0t84H3U lPC98YaC6BRH+xmyWPp2gKXB+KIr00+/qvnYsSOdRymbMJSmGIOr5CWF/wxS6pVWO63N6VEXINT 5LCRciM9dgUh5M++sOIVw74r8ehTxvIdb8OsES16GAdY0XvcB+AEoFZVHFFN9PauIP/LtCDys4K uoMqXKZR71srGU+xIVriF58s1GADf001+lvJboVa77clJUxrdjWHOTkNNdd2Wan2duTewWblEfB WaUkiQb9OZeQ2pGwZ60OkY76t4B1PekyP7zykqzG+T4XMm5bDKt+xxV43haY/3zQrCrqKDWvzca 0dIh7VvN5CLwV4VG7ZJkLC0BrujJsPN/8okOM0w+Vpjuxrwe5hL6+CuOmZVIauzX6DnRl4e4i0V nqYBM2jS0Kv74ujnnyR+JxkIVyW/TnP4Z5NCpsQygsX65ZTcMDzQsDPNA7VveGPwdmrbIl6W/hl 990sxhsKf5pvBE= 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: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 magick source_image -compress none -colors 224 destination.ppm +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 @@ */ #include +#include +#include +#include #include #include @@ -22,6 +25,155 @@ static bool nologo; module_param(nologo, bool, 0); MODULE_PARM_DESC(nologo, "Disables startup logo"); +#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 stores + * 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 more */ +#define LOGO_DT_MAX_PIXELS SZ_32M + +static struct linux_logo logo_dt_clut224 = { + .type = 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 = of_property_read_u32(np, "width", &width); + if (ret) + return ret; + + ret = of_property_read_u32(np, "height", &height); + if (ret) + return ret; + + if (!width || !height || (u64)width * height > LOGO_DT_MAX_PIXELS) + return -EINVAL; + + npixels = width * height; + + len = of_property_count_u8_elems(np, "clut"); + if (len < 3 || len % 3) + return -EINVAL; + + clutsize = len / 3; + if (clutsize > LOGO_DT_MAX_CLUT) + return -EINVAL; + + ret = of_property_count_u8_elems(np, "data"); + if (ret < 0) + return ret; + if ((unsigned int)ret != npixels) + return -EINVAL; + + clut = kmalloc(len, GFP_KERNEL); + if (!clut) + return -ENOMEM; + + data = kmalloc(npixels, GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto err_free_clut; + } + + ret = of_property_read_u8_array(np, "clut", clut, len); + if (ret) + goto err_free_data; + + ret = of_property_read_u8_array(np, "data", data, npixels); + if (ret) + goto err_free_data; + + for (i = 0; i < npixels; i++) { + if (data[i] >= clutsize) { + ret = -ERANGE; + goto err_free_data; + } + data[i] += LOGO_DT_CLUT_OFFSET; + } + + logo_dt_clut = clut; + logo_dt_data = data; + + logo_dt_clut224.width = width; + logo_dt_clut224.height = height; + logo_dt_clut224.clutsize = clutsize; + logo_dt_clut224.clut = clut; + logo_dt_clut224.data = 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 = true; + + np = of_get_compatible_child(of_chosen, LOGO_DT_COMPATIBLE); + if (!np) + return NULL; + + if (of_device_is_available(np)) { + ret = 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 = NULL; + logo_dt_clut224.data = NULL; + + kfree(logo_dt_clut); + logo_dt_clut = NULL; + + kfree(logo_dt_data); + logo_dt_data = 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 = true; + logo_dt_free(); return 0; } @@ -48,6 +201,13 @@ const struct linux_logo * __ref fb_find_logo(int depth) if (nologo || logos_freed) return NULL; + /* A logo supplied by the device tree wins over the built-in ones */ + if (depth >= 8) { + logo = logo_dt_find(); + if (logo) + return logo; + } + #ifdef CONFIG_LOGO_LINUX_MONO if (depth >= 1) logo = &logo_linux_mono; -- 2.39.5