Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2224432/?format=api
{ "id": 2224432, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2224432/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20260417120951.3454249-3-aswin.murugan@oss.qualcomm.com/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/1.2/projects/18/?format=api", "name": "U-Boot", "link_name": "uboot", "list_id": "u-boot.lists.denx.de", "list_email": "u-boot@lists.denx.de", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260417120951.3454249-3-aswin.murugan@oss.qualcomm.com>", "list_archive_url": null, "date": "2026-04-17T12:09:46", "name": "[v3,2/7] mach-snapdragon: Add FIT multi-DTB selection support", "commit_ref": null, "pull_url": null, "state": "changes-requested", "archived": false, "hash": "94d8a8dbe46a16310038570b7f2b9e0f8f822327", "submitter": { "id": 90811, "url": "http://patchwork.ozlabs.org/api/1.2/people/90811/?format=api", "name": "Aswin Murugan", "email": "aswin.murugan@oss.qualcomm.com" }, "delegate": { "id": 3651, "url": "http://patchwork.ozlabs.org/api/1.2/users/3651/?format=api", "username": "trini", "first_name": "Tom", "last_name": "Rini", "email": "trini@ti.com" }, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20260417120951.3454249-3-aswin.murugan@oss.qualcomm.com/mbox/", "series": [ { "id": 500319, "url": "http://patchwork.ozlabs.org/api/1.2/series/500319/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=500319", "date": "2026-04-17T12:09:44", "name": "Add FIT multi-DTB selection for Qualcomm platforms", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/500319/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2224432/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2224432/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<u-boot-bounces@lists.denx.de>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=qualcomm.com header.i=@qualcomm.com header.a=rsa-sha256\n header.s=qcppdkim1 header.b=ceIYi+aj;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com\n header.a=rsa-sha256 header.s=google header.b=ZJyIm8MR;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=85.214.62.61; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org)", "phobos.denx.de;\n dmarc=none (p=none dis=none) header.from=oss.qualcomm.com", "phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de", "phobos.denx.de;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=qualcomm.com header.i=@qualcomm.com\n header.b=\"ceIYi+aj\";\n\tdkim=pass (2048-bit key;\n unprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com\n header.b=\"ZJyIm8MR\";\n\tdkim-atps=neutral", "phobos.denx.de; dmarc=none (p=none dis=none)\n header.from=oss.qualcomm.com", "phobos.denx.de;\n spf=pass smtp.mailfrom=aswin.murugan@oss.qualcomm.com" ], "Received": [ "from phobos.denx.de (phobos.denx.de [85.214.62.61])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fxtyR3qnKz1yD3\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 17 Apr 2026 22:11:11 +1000 (AEST)", "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id 621D18426C;\n\tFri, 17 Apr 2026 14:11:09 +0200 (CEST)", "by phobos.denx.de (Postfix, from userid 109)\n id 22FB38426E; Fri, 17 Apr 2026 14:11:08 +0200 (CEST)", "from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com\n [205.220.180.131])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id F0C8683B99\n for <u-boot@lists.denx.de>; Fri, 17 Apr 2026 14:11:04 +0200 (CEST)", "from pps.filterd (m0279872.ppops.net [127.0.0.1])\n by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id\n 63H7jep61092082\n for <u-boot@lists.denx.de>; Fri, 17 Apr 2026 12:10:58 GMT", "from mail-pf1-f198.google.com (mail-pf1-f198.google.com\n [209.85.210.198])\n by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4dk227v3ea-1\n (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT)\n for <u-boot@lists.denx.de>; Fri, 17 Apr 2026 12:10:58 +0000 (GMT)", "by mail-pf1-f198.google.com with SMTP id\n d2e1a72fcca58-82f32d67ba7so361402b3a.0\n for <u-boot@lists.denx.de>; Fri, 17 Apr 2026 05:10:58 -0700 (PDT)", "from hu-aswinm-blr.qualcomm.com\n (blr-bdr-fw-01_GlobalNAT_AllZones-Outside.qualcomm.com. [103.229.18.19])\n by smtp.gmail.com with ESMTPSA id\n d2e1a72fcca58-82f8e9cbb28sm1744641b3a.13.2026.04.17.05.10.47\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 17 Apr 2026 05:10:55 -0700 (PDT)" ], "X-Spam-Checker-Version": "SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de", "X-Spam-Level": "", "X-Spam-Status": "No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED,\n RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED,\n SPF_HELO_NONE,SPF_PASS,T_FILL_THIS_FORM_SHORT autolearn=ham\n autolearn_force=no version=3.4.2", "DKIM-Signature": [ "v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h=\n content-transfer-encoding:date:from:in-reply-to:message-id\n :mime-version:references:subject:to; s=qcppdkim1; bh=avlpq7oHPS3\n IA38gznl4EdpFS2TES0J3b3QJLodzb9o=; b=ceIYi+ajZ52lsaLcDumrziTlW3R\n YwK8aemNlUebQ1QPJ5vQTJw4aNSz78xK1esFxGCIvRZbvzsalMrP4QDXm1IDU6tj\n s5UsR8Cg8gEkKlPZ+iiI2tY0NoOhCIf0Z0YKN01sfKUIWBbGXD7yzlgd+xR9Nkq6\n 1rS/pISmeqwAko54Uic0mg4isM1gOom7dx05HbqVIJoYIhb5mz7gGsYGUJ217Nty\n T/RhqBQ2KnAa7TFqdIfNJRFXBdcZNIfqVy55fPNeZgdDfEv8E7wjyheE5q0am6e2\n DJJ334zwsMBvxyuduqqH13/+SYI1zhiOVDUZe2OPIQ+kJqwOQOMFMKGIBIw==", "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=oss.qualcomm.com; s=google; t=1776427857; x=1777032657; darn=lists.denx.de;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:to:from:from:to:cc:subject:date:message-id\n :reply-to; bh=avlpq7oHPS3IA38gznl4EdpFS2TES0J3b3QJLodzb9o=;\n b=ZJyIm8MR6nRgA1l005AXIwJ4fiBMwkiUh0Rzc4ppoh8qTjnLnUh4mfAFCg+fFMOCH8\n pDgP11fX79Wkwud33jzqYB/chvMIwS2wkzWfoTT0PbVwc/ym00w/cZtxB8AaMNj0tLg3\n ENp62l1miYMqJvvviM30jZI3uEjxZRGQEOj1djeA8o4uyyC7ow/fDuY4belEH4MzjJDw\n Ic8EKHPYudDEvfZfjOWpFCY54SfGb68x/J/njIhS935rLa5Iu7QHnI9c+8e2Ejjcafwr\n zPc24pPZVrC+d+Ct7b37L7F+O+qPY4E9d071rZxunRNu5NKmzCC1GmBsNhDUYrtkMzUo\n 82XQ==" ], "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776427857; x=1777032657;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to\n :cc:subject:date:message-id:reply-to;\n bh=avlpq7oHPS3IA38gznl4EdpFS2TES0J3b3QJLodzb9o=;\n b=m8o3DSUrW3tL8JS0rUdivl/9TwOMTvmTj3o2T+Z6nF2Ll6ZnxxG3Y4+XwPWHLCMLp6\n /YR/ZchZXBEN8KvI4wyYrBFFiRXLD12y8Uwcg79vnmfwqq2gtHGIOsUiFVOQsURm561X\n 8DVpIPatRQnlpcJfScoZGwLjiou/dS5o0bu7SHiaEfmOR9g8J4H/neRoFqFdLVDt0cxz\n BPZYmtW6LMGujj0YTd5mCXG6hd7oLNan3dFxeGwO0HNv9nMehit1+kFNhh83XCl+yWAT\n BxWHG9Lj6VpXtk7Il7nIOr4EpVKsQUVa4DHaEh8qY2dxyWrQ+6oEzGmskD5SqOWGRBz2\n 3RqA==", "X-Forwarded-Encrypted": "i=1;\n AFNElJ9Rn5dTUOjWzP8Z1TwINfm2yL92YAByR52bwvs/3rjGNo+B6OFqwZR+n8hwljtPqM4Z2FdMuXo=@lists.denx.de", "X-Gm-Message-State": "AOJu0YyBHCCCWgJluOmxsCupcfA41+5tgnyWcHmA9dfoo/PLBgxYxMm7\n WCOcG2kt8VUqHm/vAULaUAQgIGj+ZLIyz8L7STee53uG2mRVlhEhKwjwO9Wsl+bs98P9qw5MMH6\n 4D5tjYxRFNBu+qM/DSqmgrLdZDfQCdt4OWjxNVVWjTU+3CBtQG03rxks4", "X-Gm-Gg": "AeBDiesRQrVmCgjaQSILtlkAiRF3Kr8boUXr/aX0EE01CfBkep1uakY5Yd7cCjEcgxO\n D+kGZbq1ztHA2sxssAwWzNHCCRfeNSEvHLSm5oHCA/GP+5lFdPLyqbPeXz4Gw/bgAZwtSFj78Wn\n zB18Pul858d8/9BQCPjncZZaRoW1S8Lj5JUuIOEFDhPhNhm3w6jkkzrPG2JneNa8sxTULGmgbZO\n QdgRPy7It/D3ziq9TVdEnSOWjBaN3D8wEtmeESXYhNQ7JQSJBNFwPmWSfNKWFQkNT/LPN1F4GOG\n L8CmcVphhsyTtr7zwXeTa2wVEzG07/MnLm5CCrsFzw9LuLV/ow3jzZS7u9OAMB7o127tLet9si0\n QIdLtKwKNlxM/nw7J4vmjcBYNuUGngu5qNLXddpHY7esgyhwJUuhyroO5Hd1Ywhe6DZl9vGR+Y0\n x5Jr7B9gK99Zcv4ZlxmZjYljgMhaxnUMKZQZY4MYK77eajAXHr/YA=", "X-Received": [ "by 2002:a05:6a00:2191:b0:82f:5726:be23 with SMTP id\n d2e1a72fcca58-82f8c9ed41emr2741384b3a.49.1776427856463;\n Fri, 17 Apr 2026 05:10:56 -0700 (PDT)", "by 2002:a05:6a00:2191:b0:82f:5726:be23 with SMTP id\n d2e1a72fcca58-82f8c9ed41emr2741316b3a.49.1776427855690;\n Fri, 17 Apr 2026 05:10:55 -0700 (PDT)" ], "From": "Aswin Murugan <aswin.murugan@oss.qualcomm.com>", "To": "trini@konsulko.com, casey.connolly@linaro.org, neil.armstrong@linaro.org,\n sumit.garg@kernel.org, aswin.murugan@oss.qualcomm.com,\n sughosh.ganu@arm.com, ilias.apalodimas@linaro.org, gchan9527@gmail.com,\n mchitale@ventanamicro.com, maximmosk4@gmail.com, jonas@kwiboo.se,\n marek.vasut@mailbox.org, quentin.schulz@cherry.de, peng.fan@nxp.com,\n sajattack@postmarketos.org, balaji.selvanathan@oss.qualcomm.com,\n wolfgang.wallner@at.abb.com, e@freeshell.de, yangshiji66@outlook.com,\n jan.kiszka@siemens.com, funderscore@postmarketos.org, hs@nabladev.com,\n kory.maincent@bootlin.com, jj251510319013@gmail.com,\n carlos.lopezr4096@gmail.com, u-boot-qcom@groups.io, u-boot@lists.denx.de", "Subject": "[PATCH v3 2/7] mach-snapdragon: Add FIT multi-DTB selection support", "Date": "Fri, 17 Apr 2026 17:39:46 +0530", "Message-Id": "<20260417120951.3454249-3-aswin.murugan@oss.qualcomm.com>", "X-Mailer": "git-send-email 2.34.1", "In-Reply-To": "<20260417120951.3454249-1-aswin.murugan@oss.qualcomm.com>", "References": "<20260417120951.3454249-1-aswin.murugan@oss.qualcomm.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-Proofpoint-Spam-Details-Enc": "AW1haW4tMjYwNDE3MDEyMiBTYWx0ZWRfXzx8JpeZWTh6c\n Zn4OgofIxOS/YvIu5IUxYmoHVcUemXdVSVr3VFmX/JOB/dsSgXP4eKwNE3UtG++IhL7q9jZi9oN\n ThpGrYZaJV72OpQDYunZn/KE3iRv2mP5AH/Y1xT6DMnw4u5TS+GXdahXMWniAqoKIWaKBIHAD+e\n 3aSUvoRnIwiSiKxAwltMs7yjzhbPhMg9jUWgI5yEoTYBuzivTvoT/Oy+G4UFC1hNGbc/71t+76p\n aDvgN41KTTZulDXrvlmjl3XqB2qNx+OM9fnxnliOoYDckEmC4jT0pccyYVwrXlu3u38SNib7xwQ\n 3A+qJPhgzFnHRCEuw4OpSnEJqyyEk33Ay1CyVT1bHi7L7ja6PFKcZnnpvSElSFeQGVBmQjynvIs\n rSyZaay00qY8LiuHzI+OV382cFIqXGPw49PnO1jyHe+aZJbX83Rc43ezUEu2SkNbt02VvsWZ2Py\n HUI45fow0eGmiBbfLmQ==", "X-Proofpoint-ORIG-GUID": "Y0xCiDXiT9iQBkisKOxZJ1GMqac8zORW", "X-Proofpoint-GUID": "Y0xCiDXiT9iQBkisKOxZJ1GMqac8zORW", "X-Authority-Analysis": "v=2.4 cv=Iuoutr/g c=1 sm=1 tr=0 ts=69e22352 cx=c_pps\n a=m5Vt/hrsBiPMCU0y4gIsQw==:117 a=Ou0eQOY4+eZoSc0qltEV5Q==:17\n a=A5OVakUREuEA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22\n a=u7WPNUs3qKkmUXheDGA7:22 a=yx91gb_oNiZeI1HMLzn7:22 a=EUspDBNiAAAA:8\n a=eWZCHF7YNRQTzhUL8lUA:9 a=0lg15e8vmr8byGcQ:21 a=IoOABgeZipijB_acs4fv:22", "X-Proofpoint-Virus-Version": "vendor=baseguard\n engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49\n definitions=2026-04-17_01,2026-04-17_01,2025-10-01_01", "X-Proofpoint-Spam-Details": "rule=outbound_notspam policy=outbound score=0\n bulkscore=0 adultscore=0 suspectscore=0 clxscore=1015 impostorscore=0\n malwarescore=0 priorityscore=1501 spamscore=0 lowpriorityscore=0 phishscore=0\n classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0\n reason=mlx scancount=1 engine=8.22.0-2604070000 definitions=main-2604170122", "X-BeenThere": "u-boot@lists.denx.de", "X-Mailman-Version": "2.1.39", "Precedence": "list", "List-Id": "U-Boot discussion <u-boot.lists.denx.de>", "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>", "List-Archive": "<https://lists.denx.de/pipermail/u-boot/>", "List-Post": "<mailto:u-boot@lists.denx.de>", "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>", "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=subscribe>", "Errors-To": "u-boot-bounces@lists.denx.de", "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>", "X-Virus-Scanned": "clamav-milter 0.103.8 at phobos.denx.de", "X-Virus-Status": "Clean" }, "content": "Implement multi DTB selection from FIT images based on hardware\ndetection via SMEM.\n\nThe implementation provides:\n\n1. Hardware Detection: Reads SoC parameters from SMEM including chip ID,\n version, platform ID, OEM variant, DDR size, and storage type from IMEM.\n\n2. Metadata DTB Processing: Parses a metadata DTB (first image in FIT)\n to build a \"bucket list\" of hardware-specific node names that match\n the detected hardware parameters.\n\n3. FIT Configuration Matching: Uses standard FIT mechanisms to find the\n configuration with the most matching tokens in its compatible string\n compared to the hardware-derived bucket list.\n\n4. DTB Loading and Overlays: Loads the base DTB and applies any DTBOs\n specified in the selected configuration using standard FIT overlay\n application.\n\n5. EFI Integration: Loads selected dtb from qclinux_fit.img and sets\n fdt_addr for use by the EFI boot flow.\n\nThis enables multi DTB selection across hardware variants.\n\nSigned-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>\n---\nChanges in v3:\n1. Runtime IMEM address lookup via DT: Removed CONFIG_QCOM_IMEM_SIZE Kconfig option.\n Added qcom_imem_table[] mapping SoC compatible strings to IMEM addresses.\n\n2. Split SoC version sources: SoC hardware version now read from TCSR register via\n qcom_read_tcsr_soc_version(). The soc_info->plat_ver from SMEM is stored separately\n as board_version. Added socver and boardrev metadata node matching for finer-grained DTB selection.\n\n3. qcom_load_fit_image() returns int: Changed return type from efi_status_t to int,\n returning standard Linux error codes for consistency with the rest of the driver.\n\n4. Code cleanup: strtok() replaced with strsep(); memcpy + manual null-termination replaced with strlcpy();\n DDR thresholds use SZ_* macros; compatible matching and FDT loading extracted into dedicated helpers.\n---\n arch/arm/mach-snapdragon/Kconfig | 8 +\n arch/arm/mach-snapdragon/Makefile | 1 +\n arch/arm/mach-snapdragon/board.c | 7 +\n arch/arm/mach-snapdragon/qcom_fit_multidtb.c | 1103 ++++++++++++++++++\n arch/arm/mach-snapdragon/qcom_fit_multidtb.h | 189 +++\n 5 files changed, 1308 insertions(+)\n create mode 100644 arch/arm/mach-snapdragon/qcom_fit_multidtb.c\n create mode 100644 arch/arm/mach-snapdragon/qcom_fit_multidtb.h", "diff": "diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig\nindex d3de8693b5a..0f03672ee6b 100644\n--- a/arch/arm/mach-snapdragon/Kconfig\n+++ b/arch/arm/mach-snapdragon/Kconfig\n@@ -42,4 +42,12 @@ config SYS_CONFIG_NAME\n \t Based on this option include/configs/<CONFIG_SYS_CONFIG_NAME>.h header\n \t will be used for board configuration.\n \n+config QCOM_FIT_MULTIDTB\n+\tbool \"Enable FIT multi-DTB selection for Qualcomm platforms\"\n+\tdepends on FIT\n+\thelp\n+\t Enable FIT multi-DTB selection for Qualcomm platforms.\n+\t This allows U-Boot to select the appropriate device tree\n+\t from a FIT image.\n+\n endif\ndiff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile\nindex 343e825c6fd..76e285021a1 100644\n--- a/arch/arm/mach-snapdragon/Makefile\n+++ b/arch/arm/mach-snapdragon/Makefile\n@@ -5,3 +5,4 @@\n obj-y += board.o\n obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += capsule_update.o\n obj-$(CONFIG_OF_LIVE) += of_fixup.o\n+obj-$(CONFIG_QCOM_FIT_MULTIDTB) += qcom_fit_multidtb.o\ndiff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c\nindex 6edb61b5b36..6a482ed186e 100644\n--- a/arch/arm/mach-snapdragon/board.c\n+++ b/arch/arm/mach-snapdragon/board.c\n@@ -35,6 +35,7 @@\n #include <sort.h>\n #include <time.h>\n \n+#include \"qcom_fit_multidtb.h\"\n #include \"qcom-priv.h\"\n \n DECLARE_GLOBAL_DATA_PTR;\n@@ -585,6 +586,12 @@ int board_late_init(void)\n \t/* Configure the dfu_string for capsule updates */\n \tqcom_configure_capsule_updates();\n \n+\t/* Try FIT multi-DTB selection if enabled */\n+\tif (IS_ENABLED(CONFIG_QCOM_FIT_MULTIDTB)) {\n+\t\tif (!qcom_fit_multidtb_setup())\n+\t\t\tlog_debug(\"FIT multi-DTB selection not available or failed\\n\");\n+\t}\n+\n \treturn 0;\n }\n \ndiff --git a/arch/arm/mach-snapdragon/qcom_fit_multidtb.c b/arch/arm/mach-snapdragon/qcom_fit_multidtb.c\nnew file mode 100644\nindex 00000000000..7bf4449ea03\n--- /dev/null\n+++ b/arch/arm/mach-snapdragon/qcom_fit_multidtb.c\n@@ -0,0 +1,1103 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * Qualcomm FIT Multi-DTB Selection\n+ *\n+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.\n+ *\n+ * Automatic DTB selection from FIT images based on hardware detection via SMEM.\n+ * Loads qclinux_fit.img from dtb partition, detects hardware parameters,\n+ * and selects the best matching DTB configuration.\n+ */\n+\n+#include <blk.h>\n+#include <dm.h>\n+#include <efi_api.h>\n+#include <efi_loader.h>\n+#include <env.h>\n+#include <image.h>\n+#include <lmb.h>\n+#include <log.h>\n+#include <malloc.h>\n+#include <part.h>\n+#include <smem.h>\n+#include <asm/io.h>\n+#include <linux/errno.h>\n+#include <linux/libfdt.h>\n+#include <linux/list.h>\n+#include <linux/sizes.h>\n+#include <linux/string.h>\n+#include <soc/qcom/socinfo.h>\n+\n+#include \"qcom_fit_multidtb.h\"\n+#include \"qcom-priv.h\"\n+\n+#define TCSR_SOC_HW_VERSION 0x01fc8000\n+#define TCSR_MAJOR_VERSION_MASK 0x0000ff00\n+#define TCSR_MAJOR_VERSION_SHIFT 8\n+#define TCSR_MINOR_VERSION_MASK 0x000000ff\n+#define TCSR_MINOR_VERSION_SHIFT 0\n+\n+#define lmb_alloc(size, addr) lmb_alloc_mem(LMB_MEM_ALLOC_ANY, SZ_2M, addr, size, LMB_NONE)\n+\n+/* Maximum values to match (SOC needs 2) */\n+#define MAX_MATCH_VALUES 2\n+\n+/* Metadata DTB node names */\n+#define META_NODE_OEM \"oem\"\n+#define META_NODE_SOC \"soc\"\n+#define META_NODE_SOCVER \"socver\"\n+#define META_NODE_BOARD \"board\"\n+#define META_NODE_BOARDREV \"boardrev\"\n+#define META_NODE_SOC_SKU \"soc-sku\"\n+#define META_NODE_BOARD_SUBTYPE_PERIPHERAL \"board-subtype-peripheral-subtype\"\n+#define META_NODE_BOARD_SUBTYPE_STORAGE \"board-subtype-storage-type\"\n+#define META_NODE_BOARD_SUBTYPE_DDR_SIZE \"board-subtype-memory-size\"\n+#define META_NODE_SOFTSKU \"softsku\"\n+\n+/* Property names */\n+#define PROP_OEM_ID \"oem-id\"\n+#define PROP_MSM_ID \"msm-id\"\n+#define PROP_SOCVER_ID \"socver-id\"\n+#define PROP_BOARD_ID \"board-id\"\n+#define PROP_BOARDREV_ID \"boardrev-id\"\n+#define PROP_BOARD_SUBTYPE \"board-subtype\"\n+#define PROP_SOFTSKU_ID \"softsku-id\"\n+#define PROP_COMPATIBLE \"compatible\"\n+#define PROP_FDT \"fdt\"\n+#define PROP_DATA \"data\"\n+\n+/**\n+ * add_to_bucket() - Add a node name to the bucket list\n+ * @name: Node name to add\n+ * @name_len: Length of the name\n+ * @bucket_head: Head of the bucket list\n+ *\n+ * Return: 0 on success, negative error code on failure\n+ */\n+static int add_to_bucket(const char *name, int name_len, struct list_head *bucket_head)\n+{\n+\tstruct bucket_node *node;\n+\n+\tnode = malloc(sizeof(*node));\n+\tif (!node)\n+\t\treturn -ENOMEM;\n+\n+\tnode->name = malloc(name_len + 1);\n+\tif (!node->name) {\n+\t\tfree(node);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tstrlcpy(node->name, name, name_len + 1);\n+\n+\tlist_add_tail(&node->list, bucket_head);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * search_in_bucket() - Check if a name exists in the bucket list\n+ * @name: Name to search for\n+ * @bucket_head: Head of the bucket list\n+ *\n+ * Return: true if found, false otherwise\n+ */\n+static bool search_in_bucket(const char *name, struct list_head *bucket_head)\n+{\n+\tstruct bucket_node *node;\n+\n+\tlist_for_each_entry(node, bucket_head, list) {\n+\t\tif (!strcmp(node->name, name))\n+\t\t\treturn true;\n+\t}\n+\n+\treturn false;\n+}\n+\n+/**\n+ * free_bucket_list() - Free all nodes in the bucket list\n+ * @bucket_head: Head of the bucket list\n+ */\n+static void free_bucket_list(struct list_head *bucket_head)\n+{\n+\tstruct bucket_node *node, *tmp;\n+\n+\tlist_for_each_entry_safe(node, tmp, bucket_head, list) {\n+\t\tlist_del(&node->list);\n+\t\tfree(node->name);\n+\t\tfree(node);\n+\t}\n+}\n+\n+/**\n+ * qcom_get_ddr_size_type() - Get DDR size type from SMEM RAM partitions\n+ * @ddr_type: Pointer to store DDR type\n+ *\n+ * This function reads RAM partition information from SMEM and calculates\n+ * the total DDR size, then maps it to a DDR type constant (0-10).\n+ *\n+ * Return: 0 on success, negative on failure\n+ */\n+static int qcom_get_ddr_size_type(u32 *ddr_type)\n+{\n+\tstruct usable_ram_partition_table *rpt;\n+\tstruct ram_partition_entry *rpe;\n+\tu64 total_ddr_size = 0;\n+\tint part;\n+\n+\trpt = qcom_get_ram_partitions();\n+\tif (!rpt) {\n+\t\tlog_err(\"Failed to get RAM partition table\\n\");\n+\t\treturn -ENOENT;\n+\t}\n+\n+\trpe = &rpt->ram_part_entry[0];\n+\tfor (part = 0; part < rpt->num_partitions; part++, rpe++) {\n+\t\tif (rpe->partition_category == RAM_PARTITION_SDRAM &&\n+\t\t rpe->partition_type == RAM_PARTITION_SYS_MEMORY) {\n+\t\t\ttotal_ddr_size += rpe->available_length;\n+\t\t\tlog_debug(\"RAM partition %d: start=0x%llx size=0x%llx\\n\",\n+\t\t\t\t part, rpe->start_address, rpe->available_length);\n+\t\t}\n+\t}\n+\n+\tlog_info(\"Total DDR Size: 0x%llx (%llu MB)\\n\",\n+\t\t total_ddr_size, total_ddr_size / SZ_1M);\n+\n+\t*ddr_type = 0;\n+\tif (total_ddr_size <= DDR_128MB)\n+\t\t*ddr_type = DDRTYPE_128MB;\n+\telse if (total_ddr_size <= DDR_256MB)\n+\t\t*ddr_type = DDRTYPE_256MB;\n+\telse if (total_ddr_size <= DDR_512MB)\n+\t\t*ddr_type = DDRTYPE_512MB;\n+\telse if (total_ddr_size <= DDR_1024MB)\n+\t\t*ddr_type = DDRTYPE_1024MB;\n+\telse if (total_ddr_size <= DDR_2048MB)\n+\t\t*ddr_type = DDRTYPE_2048MB;\n+\telse if (total_ddr_size <= DDR_3072MB)\n+\t\t*ddr_type = DDRTYPE_3072MB;\n+\telse if (total_ddr_size <= DDR_4096MB)\n+\t\t*ddr_type = DDRTYPE_4096MB;\n+\n+\tlog_debug(\"DDR Type: %u\\n\", *ddr_type);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * qcom_get_imem_address() - Look up shared IMEM cookie address for this SoC\n+ *\n+ * Reads the root node compatible string from the device tree and searches\n+ * the qcom_imem_table for a matching entry.\n+ *\n+ * Return: Physical address of shared IMEM cookie, or 0 if not found\n+ */\n+static uintptr_t qcom_get_imem_address(void)\n+{\n+\tconst struct qcom_imem_info *entry;\n+\tconst char *soc_compat;\n+\tint len;\n+\n+\tsoc_compat = fdt_getprop(gd->fdt_blob, 0, \"compatible\", &len);\n+\tif (!soc_compat) {\n+\t\tlog_warning(\"Cannot read SoC compatible from DT\\n\");\n+\t\treturn 0;\n+\t}\n+\n+\tfor (entry = qcom_imem_table; entry->compatible; entry++) {\n+\t\tif (fdt_stringlist_contains(soc_compat, len, entry->compatible))\n+\t\t\treturn entry->shared_imem_addr;\n+\t}\n+\n+\tlog_warning(\"SoC not found in IMEM table\\n\");\n+\treturn 0;\n+}\n+\n+/**\n+ * qcom_get_storage_type() - Detect storage type (UFS/EMMC/NAND)\n+ *\n+ * Reads the boot device type from the shared IMEM cookie structure populated\n+ * by the bootloader. The shared IMEM address is looked up from a per-SoC\n+ * table (qcom_imem_table) using the device tree compatible string.\n+ *\n+ * Falls back to UFS if the SoC is not in the table or if the IMEM cookie\n+ * magic/version validation fails.\n+ *\n+ * Return: mem_card_type enum value (UFS/EMMC/NAND), or UFS as fallback\n+ */\n+static enum mem_card_type qcom_get_storage_type(void)\n+{\n+\tstruct boot_imem_cookie *imem;\n+\tuintptr_t shared_imem_addr;\n+\n+\tshared_imem_addr = qcom_get_imem_address();\n+\tif (!shared_imem_addr) {\n+\t\tlog_warning(\"SoC not in IMEM table, defaulting to UFS\\n\");\n+\t\treturn UFS;\n+\t}\n+\n+\timem = (struct boot_imem_cookie *)shared_imem_addr;\n+\n+\tif (imem->shared_imem_magic != BOOT_SHARED_IMEM_MAGIC_NUM) {\n+\t\tlog_warning(\"Invalid shared IMEM magic: 0x%x, defaulting to UFS\\n\",\n+\t\t\t imem->shared_imem_magic);\n+\t\treturn UFS;\n+\t}\n+\n+\tif (imem->shared_imem_version < BOOT_SHARED_IMEM_VERSION_NUM) {\n+\t\tlog_warning(\"Invalid shared IMEM version: %u, defaulting to UFS\\n\",\n+\t\t\t imem->shared_imem_version);\n+\t\treturn UFS;\n+\t}\n+\n+\tlog_info(\"Shared IMEM: magic=0x%x, version=%u, boot_device_type=%u\\n\",\n+\t\t imem->shared_imem_magic, imem->shared_imem_version,\n+\t\t imem->boot_device_type);\n+\n+\tswitch (imem->boot_device_type) {\n+\tcase UFS_FLASH:\n+\t\treturn UFS;\n+\tcase MMC_FLASH:\n+\tcase SDC_FLASH:\n+\t\treturn EMMC;\n+\tcase NAND_FLASH:\n+\t\treturn NAND;\n+\tdefault:\n+\t\tlog_warning(\"Unknown shared IMEM boot device: %u, defaulting to UFS\\n\",\n+\t\t\t imem->boot_device_type);\n+\t\treturn UFS;\n+\t}\n+}\n+\n+static u32 qcom_read_tcsr_soc_version(void)\n+{\n+\tu32 reg_val = readl(TCSR_SOC_HW_VERSION);\n+\tu32 major = (reg_val & TCSR_MAJOR_VERSION_MASK) >> TCSR_MAJOR_VERSION_SHIFT;\n+\tu32 minor = (reg_val & TCSR_MINOR_VERSION_MASK) >> TCSR_MINOR_VERSION_SHIFT;\n+\n+\treturn (major << 4) | minor;\n+}\n+\n+/**\n+ * qcom_detect_hardware_params() - Detect all hardware parameters from SMEM\n+ * @params: Pointer to hardware parameters structure\n+ *\n+ * This function reads hardware information from SMEM and populates the\n+ * qcom_hw_params structure with all necessary data for DTB selection.\n+ *\n+ * Return: 0 on success, negative error code on failure\n+ */\n+static int qcom_detect_hardware_params(struct qcom_hw_params *params)\n+{\n+\tstruct socinfo *soc_info;\n+\tint ret;\n+\tu32 raw_version;\n+\n+\tmemset(params, 0, sizeof(*params));\n+\n+\tsoc_info = qcom_get_socinfo();\n+\tif (!soc_info) {\n+\t\tlog_err(\"Failed to get SOC info from SMEM\\n\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tparams->chip_id = le32_to_cpu(soc_info->id) & 0xffff;\n+\n+\traw_version = le32_to_cpu(soc_info->plat_ver);\n+\tparams->board_version = (SOCINFO_MAJOR(raw_version) << 4) | SOCINFO_MINOR(raw_version);\n+\n+\tparams->chip_version = qcom_read_tcsr_soc_version();\n+\n+\tparams->platform = le32_to_cpu(soc_info->hw_plat);\n+\tparams->subtype = le32_to_cpu(soc_info->hw_plat_subtype);\n+\n+\tif (le32_to_cpu(soc_info->fmt) >= 17)\n+\t\tparams->oem_variant_id = le32_to_cpu(soc_info->oem_variant);\n+\n+\tif (le32_to_cpu(soc_info->fmt) >= 9)\n+\t\tparams->foundry_id = le32_to_cpu(soc_info->foundry_id);\n+\n+\tret = qcom_get_ddr_size_type(¶ms->ddr_size_type);\n+\tif (ret)\n+\t\tlog_warning(\"Failed to get DDR size, defaulting to 0\\n\");\n+\n+\tparams->storage_type = qcom_get_storage_type();\n+\n+\tlog_info(\"Hardware Parameters:\\n\");\n+\tlog_info(\" Chip ID: 0x%x\\n\", params->chip_id);\n+\tlog_info(\" Chip Version: 0x%x\\n\", params->chip_version);\n+\tlog_info(\" Board Version: 0x%x\\n\", params->board_version);\n+\tlog_info(\" Platform: 0x%x\\n\", params->platform);\n+\tlog_info(\" Subtype: 0x%x\\n\", params->subtype);\n+\tlog_info(\" OEM Variant ID: 0x%x\\n\", params->oem_variant_id);\n+\tlog_info(\" DDR Size Type: %u\\n\", params->ddr_size_type);\n+\tlog_info(\" Storage Type: %u\\n\", params->storage_type);\n+\tlog_info(\" Foundry ID: 0x%x\\n\", params->foundry_id);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * log_match_values() - Log matched hardware parameter values\n+ * @log_type: Type label for logging (e.g., \"SOC\", \"Board\")\n+ * @subnode_name: Name of the matched node\n+ * @num_match_values: Number of values to log\n+ * @match_values: Array of matched values\n+ */\n+static void log_match_values(const char *log_type, const char *subnode_name,\n+\t\t\t int num_match_values, const u32 *match_values)\n+{\n+\tint i;\n+\n+\tlog_info(\"Matched %s: %s (\", log_type, subnode_name);\n+\n+\tfor (i = 0; i < num_match_values; i++) {\n+\t\tif (i > 0)\n+\t\t\tlog_info(\", \");\n+\t\tlog_info(\"val%d=0x%x\", i + 1, match_values[i]);\n+\t}\n+\n+\tlog_info(\")\\n\");\n+}\n+\n+/**\n+ * process_node() - Generic metadata node processor\n+ * @type: Type of node to process\n+ * @metadata: Metadata DTB pointer\n+ * @root_offset: Root node offset\n+ * @params: Hardware parameters\n+ * @bucket_head: Bucket list head\n+ *\n+ * Processes different types of nodes in the metadata DTB. Handles matching\n+ * hardware parameters against DTB properties, with support for bit masking/shifting\n+ * and fallback values.\n+ *\n+ * Return: 0 on success, -ENOENT if no match, other negative on error\n+ */\n+static int process_node(enum node_process_type type,\n+\t\t void *metadata,\n+\t\t int root_offset,\n+\t\t struct qcom_hw_params *params,\n+\t\t struct list_head *bucket_head)\n+{\n+\tconst char *node_name, *prop_name, *log_type;\n+\tconst char *fallback;\n+\tconst char *subnode_name;\n+\tint node_offset, subnode, len, name_len;\n+\tint num_match_values, i;\n+\tu32 match_values[MAX_MATCH_VALUES];\n+\tu32 masks[MAX_MATCH_VALUES];\n+\tint shifts[MAX_MATCH_VALUES];\n+\tbool all_match;\n+\n+\tfallback = NULL;\n+\tnum_match_values = 1;\n+\tmemset(shifts, 0, sizeof(shifts));\n+\tmemset(masks, 0xff, sizeof(masks));\n+\n+\tswitch (type) {\n+\tcase NODE_TYPE_OEM:\n+\t\tnode_name = META_NODE_OEM;\n+\t\tprop_name = PROP_OEM_ID;\n+\t\tmatch_values[0] = params->oem_variant_id;\n+\t\tlog_type = \"OEM\";\n+\t\tfallback = \"qcom\";\n+\t\tbreak;\n+\tcase NODE_TYPE_SOC:\n+\t\tnode_name = META_NODE_SOC;\n+\t\tprop_name = PROP_MSM_ID;\n+\t\tmatch_values[0] = params->chip_id;\n+\t\tmasks[0] = 0xffff;\n+\t\tnum_match_values = 1;\n+\t\tlog_type = \"SOC\";\n+\t\tbreak;\n+\tcase NODE_TYPE_SOCVER:\n+\t\tnode_name = META_NODE_SOCVER;\n+\t\tprop_name = PROP_SOCVER_ID;\n+\t\tmatch_values[0] = params->chip_version;\n+\t\tnum_match_values = 1;\n+\t\tlog_type = \"SOCVER\";\n+\t\tbreak;\n+\tcase NODE_TYPE_BOARD:\n+\t\tnode_name = META_NODE_BOARD;\n+\t\tprop_name = PROP_BOARD_ID;\n+\t\tmatch_values[0] = params->platform;\n+\t\tlog_type = \"Board\";\n+\t\tbreak;\n+\tcase NODE_TYPE_BOARDREV:\n+\t\tnode_name = META_NODE_BOARDREV;\n+\t\tprop_name = PROP_BOARDREV_ID;\n+\t\tmatch_values[0] = params->board_version;\n+\t\tnum_match_values = 1;\n+\t\tlog_type = \"BoardRev\";\n+\t\tbreak;\n+\tcase NODE_TYPE_PERIPHERAL:\n+\t\tnode_name = META_NODE_BOARD_SUBTYPE_PERIPHERAL;\n+\t\tprop_name = PROP_BOARD_SUBTYPE;\n+\t\tmatch_values[0] = params->subtype;\n+\t\tlog_type = \"Peripheral Subtype\";\n+\t\tbreak;\n+\tcase NODE_TYPE_STORAGE:\n+\t\tnode_name = META_NODE_BOARD_SUBTYPE_STORAGE;\n+\t\tprop_name = PROP_BOARD_SUBTYPE;\n+\t\tmatch_values[0] = params->storage_type;\n+\t\tmasks[0] = 0x7000;\n+\t\tshifts[0] = 12;\n+\t\tlog_type = \"Storage\";\n+\t\tbreak;\n+\tcase NODE_TYPE_DDR_SIZE:\n+\t\tnode_name = META_NODE_BOARD_SUBTYPE_DDR_SIZE;\n+\t\tprop_name = PROP_BOARD_SUBTYPE;\n+\t\tmatch_values[0] = params->ddr_size_type;\n+\t\tmasks[0] = 0xf00;\n+\t\tshifts[0] = 8;\n+\t\tlog_type = \"DDR Size\";\n+\t\tbreak;\n+\tcase NODE_TYPE_SOFTSKU:\n+\t\tnode_name = META_NODE_SOFTSKU;\n+\t\tprop_name = PROP_SOFTSKU_ID;\n+\t\tmatch_values[0] = params->softsku_id;\n+\t\tlog_type = \"SoftSKU\";\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tnode_offset = fdt_subnode_offset(metadata, root_offset, node_name);\n+\tif (node_offset < 0) {\n+\t\tlog_debug(\"%s node not found\\n\", log_type);\n+\t\treturn node_offset;\n+\t}\n+\n+\tfdt_for_each_subnode(subnode, metadata, node_offset) {\n+\t\tconst u32 *prop = fdt_getprop(metadata, subnode, prop_name, &len);\n+\n+\t\tif (!prop || len < (int)(num_match_values * sizeof(u32)))\n+\t\t\tcontinue;\n+\n+\t\tall_match = true;\n+\t\tfor (i = 0; i < num_match_values; i++) {\n+\t\t\tu32 dtb_value = fdt32_to_cpu(prop[i]);\n+\n+\t\t\tdtb_value = (dtb_value & masks[i]) >> shifts[i];\n+\n+\t\t\tif (dtb_value != match_values[i]) {\n+\t\t\t\tall_match = false;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (!all_match)\n+\t\t\tcontinue;\n+\n+\t\tsubnode_name = fdt_get_name(metadata, subnode, &name_len);\n+\t\tif (subnode_name) {\n+\t\t\tlog_match_values(log_type, subnode_name, num_match_values,\n+\t\t\t\t\t match_values);\n+\t\t\treturn add_to_bucket(subnode_name, name_len, bucket_head);\n+\t\t}\n+\t}\n+\n+\tif (fallback) {\n+\t\tlog_info(\"No %s match, using fallback '%s'\\n\", log_type, fallback);\n+\t\treturn add_to_bucket(fallback, strlen(fallback), bucket_head);\n+\t}\n+\n+\tlog_debug(\"No %s match\\n\", log_type);\n+\n+\treturn -ENOENT;\n+}\n+\n+/**\n+ * qcom_build_bucket_list() - Build bucket list from metadata DTB\n+ * @metadata: Metadata DTB pointer\n+ * @params: Hardware parameters\n+ * @bucket_head: Bucket list head\n+ *\n+ * This function parses the metadata DTB and builds a list of matching\n+ * node names based on the detected hardware parameters.\n+ *\n+ * Return: 0 on success, negative error code on failure\n+ */\n+static int qcom_build_bucket_list(void *metadata,\n+\t\t\t\t struct qcom_hw_params *params,\n+\t\t\t\t struct list_head *bucket_head)\n+{\n+\tint root_offset;\n+\tint ret;\n+\tstruct bucket_node *node;\n+\n+\tlog_debug(\"Building bucket list from hardware parameters\\n\");\n+\n+\troot_offset = fdt_path_offset(metadata, \"/\");\n+\tif (root_offset < 0) {\n+\t\tlog_err(\"Failed to find root node in metadata DTB\\n\");\n+\t\treturn root_offset;\n+\t}\n+\n+\tret = process_node(NODE_TYPE_OEM, metadata, root_offset,\n+\t\t\t params, bucket_head);\n+\tif (ret < 0 && ret != -ENOENT)\n+\t\treturn ret;\n+\n+\tret = process_node(NODE_TYPE_SOC, metadata, root_offset,\n+\t\t\t params, bucket_head);\n+\tif (ret < 0 && ret != -ENOENT)\n+\t\treturn ret;\n+\n+\tret = process_node(NODE_TYPE_SOCVER, metadata, root_offset,\n+\t\t\t params, bucket_head);\n+\tif (ret < 0 && ret != -ENOENT)\n+\t\treturn ret;\n+\n+\tret = process_node(NODE_TYPE_BOARD, metadata, root_offset,\n+\t\t\t params, bucket_head);\n+\tif (ret < 0 && ret != -ENOENT)\n+\t\treturn ret;\n+\n+\tret = process_node(NODE_TYPE_BOARDREV, metadata, root_offset,\n+\t\t\t params, bucket_head);\n+\tif (ret < 0 && ret != -ENOENT)\n+\t\treturn ret;\n+\n+\tprocess_node(NODE_TYPE_PERIPHERAL, metadata, root_offset,\n+\t\t params, bucket_head);\n+\n+\tprocess_node(NODE_TYPE_STORAGE, metadata, root_offset,\n+\t\t params, bucket_head);\n+\n+\tprocess_node(NODE_TYPE_DDR_SIZE, metadata, root_offset,\n+\t\t params, bucket_head);\n+\n+\tprocess_node(NODE_TYPE_SOFTSKU, metadata, root_offset,\n+\t\t params, bucket_head);\n+\n+\tlog_debug(\"Bucket list: \");\n+\tlist_for_each_entry(node, bucket_head, list)\n+\t\tlog_debug(\"%s \", node->name);\n+\tlog_debug(\"\\n\");\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * qcom_load_fit_image() - Load FIT image from EFI partition\n+ * @fitp: Pointer to store FIT image address\n+ * @fit_sizep: Pointer to store FIT image size\n+ *\n+ * This function loads qclinux_fit.img from the EFI partition using the\n+ * EFI Simple File System Protocol, matching the pattern from efi_fdt.c\n+ *\n+ * Return: 0 on success, negative error code on failure\n+ */\n+static int qcom_load_fit_image(void **fitp, efi_uintn_t *fit_sizep)\n+{\n+\tefi_status_t ret;\n+\tefi_handle_t *volume_handles = NULL;\n+\tefi_uintn_t count;\n+\tstruct efi_handler *handler;\n+\tstruct efi_simple_file_system_protocol *fs;\n+\tstruct efi_file_handle *root = NULL;\n+\tstruct efi_file_handle *file = NULL;\n+\tu16 fit_name[] = u\"/qclinux_fit.img\";\n+\tu32 i;\n+\n+\tlog_info(\"%s: Loading FIT image from EFI partition\\n\", __func__);\n+\n+\tret = efi_locate_handle_buffer_int(BY_PROTOCOL,\n+\t\t\t\t\t &efi_simple_file_system_protocol_guid,\n+\t\t\t\t\t NULL, &count, &volume_handles);\n+\tif (ret != EFI_SUCCESS) {\n+\t\tlog_err(\"Failed to locate file system volumes: %lu\\n\", ret);\n+\t\treturn -EIO;\n+\t}\n+\n+\tfor (i = 0; i < count; i++) {\n+\t\tret = efi_search_protocol(volume_handles[i],\n+\t\t\t\t\t &efi_simple_file_system_protocol_guid,\n+\t\t\t\t\t &handler);\n+\t\tif (ret != EFI_SUCCESS)\n+\t\t\tcontinue;\n+\n+\t\tret = efi_protocol_open(handler, (void **)&fs, efi_root, NULL,\n+\t\t\t\t\tEFI_OPEN_PROTOCOL_GET_PROTOCOL);\n+\t\tif (ret != EFI_SUCCESS)\n+\t\t\tcontinue;\n+\n+\t\tret = EFI_CALL(fs->open_volume(fs, &root));\n+\t\tif (ret != EFI_SUCCESS)\n+\t\t\tcontinue;\n+\n+\t\tret = EFI_CALL(root->open(root, &file, fit_name,\n+\t\t\t\t\t EFI_FILE_MODE_READ, 0));\n+\t\tif (ret == EFI_SUCCESS) {\n+\t\t\tlog_info(\"%s: %ls found!\\n\", __func__, fit_name);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tEFI_CALL(root->close(root));\n+\t\troot = NULL;\n+\t}\n+\n+\tif (!file) {\n+\t\tlog_err(\"FIT image not found on any volume\\n\");\n+\t\tefi_free_pool(volume_handles);\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tret = efi_file_size(file, fit_sizep);\n+\tif (ret != EFI_SUCCESS) {\n+\t\tlog_err(\"Failed to get FIT file size: %lu\\n\", ret);\n+\t\tgoto out;\n+\t}\n+\n+\tlog_info(\"FIT image size: %lu bytes\\n\", *fit_sizep);\n+\n+\tret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,\n+\t\t\t\t EFI_BOOT_SERVICES_DATA,\n+\t\t\t\t efi_size_in_pages(*fit_sizep),\n+\t\t\t\t (efi_physical_addr_t *)fitp);\n+\tif (ret != EFI_SUCCESS) {\n+\t\tlog_err(\"Failed to allocate memory for FIT image: %lu\\n\", ret);\n+\t\tgoto out;\n+\t}\n+\n+\tret = EFI_CALL(file->read(file, fit_sizep, *fitp));\n+\tif (ret != EFI_SUCCESS) {\n+\t\tlog_err(\"Failed to read FIT image: %lu\\n\", ret);\n+\t\tefi_free_pages((uintptr_t)*fitp, efi_size_in_pages(*fit_sizep));\n+\t\t*fitp = NULL;\n+\t}\n+\n+out:\n+\tif (file)\n+\t\tEFI_CALL(file->close(file));\n+\tif (root)\n+\t\tEFI_CALL(root->close(root));\n+\tefi_free_pool(volume_handles);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * qcom_extract_metadata_dtb() - Extract metadata DTB from FIT image\n+ * @fit: FIT image pointer\n+ * @metadata: Pointer to store metadata DTB address\n+ * @metadata_size: Pointer to store metadata DTB size\n+ *\n+ * The metadata DTB is the first image in the FIT (fdt-0).\n+ *\n+ * Return: 0 on success, negative error code on failure\n+ */\n+static int qcom_extract_metadata_dtb(void *fit, void **metadata,\n+\t\t\t\t size_t *metadata_size)\n+{\n+\tint images_node, first_image;\n+\tconst void *data;\n+\tsize_t size;\n+\tint ret;\n+\n+\timages_node = fdt_path_offset(fit, FIT_IMAGES_PATH);\n+\tif (images_node < 0) {\n+\t\tlog_err(\"Cannot find /images node in FIT\\n\");\n+\t\treturn images_node;\n+\t}\n+\n+\tfirst_image = fdt_first_subnode(fit, images_node);\n+\tif (first_image < 0) {\n+\t\tlog_err(\"Cannot find first image in FIT\\n\");\n+\t\treturn first_image;\n+\t}\n+\n+\tret = fit_image_get_data(fit, first_image, &data, &size);\n+\tif (ret) {\n+\t\tlog_err(\"Failed to get metadata DTB data\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\t*metadata = malloc(size);\n+\tif (!*metadata) {\n+\t\tlog_err(\"Failed to allocate memory for metadata DTB\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tmemcpy(*metadata, data, size);\n+\t*metadata_size = size;\n+\n+\tlog_info(\"Extracted metadata DTB: %zu bytes\\n\", size);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * qcom_count_compatible_matches() - Count matching tokens in compatible string\n+ * @compatible: Compatible string from FIT configuration\n+ * @compat_len: Length of compatible string\n+ * @bucket_head: Bucket list head\n+ *\n+ * Parses the compatible string and counts how many tokens match entries\n+ * in the bucket list. The compatible string format is typically:\n+ * \"vendor,device-variant-subtype\" where tokens are separated by commas and dashes.\n+ *\n+ * Return: Number of matching tokens\n+ */\n+static int qcom_count_compatible_matches(const char *compatible, int compat_len,\n+\t\t\t\t\t struct list_head *bucket_head)\n+{\n+\tchar *compat_copy;\n+\tchar *str_ptr;\n+\tchar *token;\n+\tint match_count = 0;\n+\n+\tcompat_copy = malloc(compat_len + 1);\n+\tif (!compat_copy)\n+\t\treturn 0;\n+\n+\tmemcpy(compat_copy, compatible, compat_len);\n+\tcompat_copy[compat_len] = '\\0';\n+\n+\tstr_ptr = compat_copy;\n+\n+\t/* First split by comma to get vendor prefix (e.g., \"qcom\") */\n+\ttoken = strsep(&str_ptr, \",\");\n+\tif (token && search_in_bucket(token, bucket_head))\n+\t\tmatch_count++;\n+\n+\t/* Then split remaining parts by dash */\n+\ttoken = strsep(&str_ptr, \"-\");\n+\twhile (token) {\n+\t\tif (search_in_bucket(token, bucket_head))\n+\t\t\tmatch_count++;\n+\t\ttoken = strsep(&str_ptr, \"-\");\n+\t}\n+\n+\tfree(compat_copy);\n+\treturn match_count;\n+}\n+\n+/**\n+ * qcom_find_matching_config() - Find matching FIT configuration\n+ * @fit: FIT image pointer\n+ * @bucket_head: Bucket list head\n+ * @config_node: Pointer to store matching configuration node offset\n+ *\n+ * This function iterates through all FIT configurations and finds the one\n+ * with the most matching tokens in its compatible string against the bucket list.\n+ *\n+ * Return: 0 on success, negative error code on failure\n+ */\n+static int qcom_find_matching_config(void *fit, struct list_head *bucket_head,\n+\t\t\t\t int *config_node)\n+{\n+\tint configs_node, cfg;\n+\tconst char *compatible;\n+\tint compat_len;\n+\tconst char *cfg_name;\n+\tint name_len;\n+\tint best_match_count = 0;\n+\tint best_config = -1;\n+\tint match_count;\n+\n+\tconfigs_node = fdt_path_offset(fit, FIT_CONFS_PATH);\n+\tif (configs_node < 0) {\n+\t\tlog_err(\"Cannot find /configurations node in FIT\\n\");\n+\t\treturn configs_node;\n+\t}\n+\n+\tfdt_for_each_subnode(cfg, fit, configs_node) {\n+\t\tcfg_name = fdt_get_name(fit, cfg, &name_len);\n+\t\tcompatible = fdt_getprop(fit, cfg, PROP_COMPATIBLE, &compat_len);\n+\n+\t\tif (!compatible || compat_len <= 0) {\n+\t\t\tlog_debug(\"Config %s has no compatible property\\n\", cfg_name);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tlog_debug(\"Checking config: %s, compatible: %s\\n\",\n+\t\t\t cfg_name, compatible);\n+\n+\t\tmatch_count = qcom_count_compatible_matches(compatible, compat_len,\n+\t\t\t\t\t\t\t bucket_head);\n+\n+\t\tlog_debug(\"Config %s: %d matches\\n\", cfg_name, match_count);\n+\n+\t\tif (match_count > best_match_count) {\n+\t\t\tbest_match_count = match_count;\n+\t\t\tbest_config = cfg;\n+\t\t}\n+\t}\n+\n+\tif (best_config < 0) {\n+\t\tlog_err(\"No matching configuration found\\n\");\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tcfg_name = fdt_get_name(fit, best_config, &name_len);\n+\tcompatible = fdt_getprop(fit, best_config, PROP_COMPATIBLE, &compat_len);\n+\tlog_info(\"Selected configuration: %s (compatible: %s, matches: %d)\\n\",\n+\t\t cfg_name, compatible, best_match_count);\n+\n+\t*config_node = best_config;\n+\treturn 0;\n+}\n+\n+/**\n+ * qcom_get_fdt_image_data() - Get FDT image data from FIT\n+ * @fit: FIT image pointer\n+ * @images_node: Images node offset\n+ * @fdt_name: FDT image name to load\n+ * @fdt_datap: Pointer to store FDT data address\n+ * @fdt_sizep: Pointer to store FDT data size\n+ *\n+ * Helper function to load an FDT image from the FIT by name.\n+ *\n+ * Return: 0 on success, negative error code on failure\n+ */\n+static int qcom_get_fdt_image_data(void *fit, int images_node,\n+\t\t\t\t const char *fdt_name,\n+\t\t\t\t const void **fdt_datap, size_t *fdt_sizep)\n+{\n+\tint fdt_node;\n+\tint ret;\n+\n+\tfdt_node = fdt_subnode_offset(fit, images_node, fdt_name);\n+\tif (fdt_node < 0) {\n+\t\tlog_err(\"Cannot find FDT node: %s\\n\", fdt_name);\n+\t\treturn fdt_node;\n+\t}\n+\n+\tret = fit_image_get_data(fit, fdt_node, fdt_datap, fdt_sizep);\n+\tif (ret) {\n+\t\tlog_err(\"Failed to get FDT data for %s\\n\", fdt_name);\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * qcom_load_dtb_with_overlays() - Load DTB and apply overlays\n+ * @fit: FIT image pointer\n+ * @config_node: Configuration node offset\n+ * @final_dtb: Pointer to store final DTB address\n+ * @final_dtb_size: Pointer to store final DTB size\n+ *\n+ * This function loads the base DTB and applies all DTBOs specified in the\n+ * configuration's \"fdt\" property.\n+ *\n+ * Return: 0 on success, negative error code on failure\n+ */\n+static int qcom_load_dtb_with_overlays(void *fit, int config_node,\n+\t\t\t\t void **final_dtb,\n+\t\t\t\t size_t *final_dtb_size)\n+{\n+\tint images_node;\n+\tconst char *fdt_name;\n+\tint fdt_name_len;\n+\tconst void *fdt_data;\n+\tsize_t fdt_size;\n+\tvoid *base_dtb = NULL;\n+\tsize_t base_dtb_size = 0;\n+\tphys_addr_t dtb_addr;\n+\tint i, ret;\n+\tint fixups_offset;\n+\n+\timages_node = fdt_path_offset(fit, FIT_IMAGES_PATH);\n+\tif (images_node < 0)\n+\t\treturn images_node;\n+\n+\tfdt_name = fdt_stringlist_get(fit, config_node, PROP_FDT, 0, &fdt_name_len);\n+\tif (!fdt_name) {\n+\t\tlog_err(\"No fdt property in configuration\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tprintf(\"DTB: %s\\n\", fdt_name);\n+\n+\tret = qcom_get_fdt_image_data(fit, images_node, fdt_name,\n+\t\t\t\t &fdt_data, &fdt_size);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* Allocate base DTB with extra space for overlays using LMB */\n+\tbase_dtb_size = fdt_size + (8 * 1024); /* Add 8KB for overlays */\n+\tret = lmb_alloc(base_dtb_size, &dtb_addr);\n+\tif (ret) {\n+\t\tlog_err(\"Failed to allocate LMB memory for base DTB: %zu bytes\\n\", base_dtb_size);\n+\t\treturn -ENOMEM;\n+\t}\n+\tbase_dtb = (void *)dtb_addr;\n+\n+\tmemcpy(base_dtb, fdt_data, fdt_size);\n+\tret = fdt_open_into(base_dtb, base_dtb, base_dtb_size);\n+\tif (ret) {\n+\t\tlog_err(\"Failed to open DTB: %d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/* Apply overlays (remaining fdt entries) */\n+\tfor (i = 1; ; i++) {\n+\t\tfdt_name = fdt_stringlist_get(fit, config_node, PROP_FDT, i,\n+\t\t\t\t\t &fdt_name_len);\n+\t\tif (!fdt_name)\n+\t\t\tbreak;\n+\n+\t\tlog_info(\"Applying overlay: %s\\n\", fdt_name);\n+\n+\t\tret = qcom_get_fdt_image_data(fit, images_node, fdt_name,\n+\t\t\t\t\t &fdt_data, &fdt_size);\n+\t\tif (ret)\n+\t\t\tcontinue;\n+\n+\t\tfixups_offset = fdt_path_offset(fdt_data, \"/__fixups__\");\n+\t\tif (fixups_offset == -FDT_ERR_NOTFOUND) {\n+\t\t\tlog_warning(\"%s is not a valid overlay (no __fixups__)\\n\", fdt_name);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tret = fdt_overlay_apply_verbose(base_dtb, (void *)fdt_data);\n+\t\tif (ret)\n+\t\t\tlog_err(\"Failed to apply overlay %s: %d\\n\", fdt_name, ret);\n+\t}\n+\n+\tret = fdt_pack(base_dtb);\n+\tif (ret) {\n+\t\tlog_err(\"Failed to pack DTB: %d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\t*final_dtb = base_dtb;\n+\t*final_dtb_size = fdt_totalsize(base_dtb);\n+\n+\tlog_info(\"Final DTB size: %zu bytes\\n\", *final_dtb_size);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * qcom_fit_multidtb_setup() - Main entry point for FIT multi-DTB selection\n+ *\n+ * This is the main function that orchestrates the entire DTB selection process:\n+ * 1. Load qclinux_fit.img from EFI partition\n+ * 2. Extract metadata DTB\n+ * 3. Detect hardware parameters from SMEM\n+ * 4. Build bucket list from metadata\n+ * 5. Find matching FIT configuration\n+ * 6. Load DTB and apply overlays\n+ * 7. Install FDT for EFI\n+ *\n+ * Return: 0 on success, negative error code on failure\n+ */\n+int qcom_fit_multidtb_setup(void)\n+{\n+\tvoid *fit = NULL;\n+\tefi_uintn_t fit_size = 0;\n+\tvoid *metadata = NULL;\n+\tsize_t metadata_size = 0;\n+\tstruct qcom_hw_params hw_params;\n+\tLIST_HEAD(bucket_list);\n+\tint config_node;\n+\tvoid *final_dtb = NULL;\n+\tsize_t final_dtb_size = 0;\n+\tint ret;\n+\n+\tlog_debug(\"=== FIT Multi-DTB Selection ===\\n\");\n+\n+\tlog_debug(\"Loading FIT image\\n\");\n+\tret = qcom_load_fit_image(&fit, &fit_size);\n+\tif (ret) {\n+\t\tlog_err(\"Failed to load FIT image\\n\");\n+\t\tgoto cleanup_fit;\n+\t}\n+\n+\tret = fdt_check_header(fit);\n+\tif (ret) {\n+\t\tlog_err(\"Invalid FIT header\\n\");\n+\t\tret = -EINVAL;\n+\t\tgoto cleanup_fit;\n+\t}\n+\n+\tret = fit_check_format(fit, IMAGE_SIZE_INVAL);\n+\tif (ret) {\n+\t\tlog_err(\"Invalid FIT format\\n\");\n+\t\tret = -EINVAL;\n+\t\tgoto cleanup_fit;\n+\t}\n+\n+\tlog_debug(\"Extracting metadata DTB\\n\");\n+\tret = qcom_extract_metadata_dtb(fit, &metadata, &metadata_size);\n+\tif (ret) {\n+\t\tlog_err(\"Failed to extract metadata DTB\\n\");\n+\t\tgoto cleanup_metadata;\n+\t}\n+\n+\tlog_debug(\"Detecting hardware parameters\\n\");\n+\tret = qcom_detect_hardware_params(&hw_params);\n+\tif (ret) {\n+\t\tlog_err(\"Failed to detect hardware parameters\\n\");\n+\t\tgoto cleanup_metadata;\n+\t}\n+\n+\tlog_debug(\"Building bucket list\\n\");\n+\tret = qcom_build_bucket_list(metadata, &hw_params, &bucket_list);\n+\tif (ret) {\n+\t\tlog_err(\"Failed to build bucket list\\n\");\n+\t\tgoto cleanup_bucket;\n+\t}\n+\n+\tlog_debug(\"Finding matching configuration\\n\");\n+\tret = qcom_find_matching_config(fit, &bucket_list, &config_node);\n+\tif (ret) {\n+\t\tlog_err(\"Failed to find matching configuration\\n\");\n+\t\tgoto cleanup_bucket;\n+\t}\n+\n+\tlog_debug(\"Loading DTB and applying overlays\\n\");\n+\tret = qcom_load_dtb_with_overlays(fit, config_node, &final_dtb,\n+\t\t\t\t\t &final_dtb_size);\n+\tif (ret) {\n+\t\tlog_err(\"Failed to load DTB with overlays\\n\");\n+\t\tgoto cleanup_dtb;\n+\t}\n+\n+\tlog_debug(\"Setting fdt_addr to selected DTB address\\n\");\n+\n+\tret = fdt_check_header(final_dtb);\n+\tif (ret) {\n+\t\tlog_err(\"Invalid final DTB header: %d\\n\", ret);\n+\t\tret = -EINVAL;\n+\t\tgoto cleanup_dtb;\n+\t}\n+\n+\t/* Update fdt_addr environment variable to point to our DTB */\n+\tenv_set_hex(\"fdt_addr\", (ulong)final_dtb);\n+\tlog_info(\"Updated fdt_addr=0x%lx, DTB size=%zu bytes\\n\", (ulong)final_dtb, final_dtb_size);\n+\tlog_info(\"EFI boot flow will use DTB directly from this address\\n\");\n+\n+\t/* Don't free final_dtb - LMB manages memory and EFI boot flow will use it */\n+\tfinal_dtb = NULL;\n+\n+\tlog_debug(\"=== FIT Multi-DTB Selection Complete ===\\n\");\n+\n+\tret = 0;\n+\tgoto cleanup_success;\n+\n+cleanup_dtb:\n+\tif (ret && final_dtb)\n+\t\tfinal_dtb = NULL;\n+\n+cleanup_success:\n+cleanup_bucket:\n+\tfree_bucket_list(&bucket_list);\n+\n+cleanup_metadata:\n+\tif (metadata)\n+\t\tfree(metadata);\n+\n+cleanup_fit:\n+\tif (fit)\n+\t\tefi_free_pages((uintptr_t)fit, efi_size_in_pages(fit_size));\n+\n+\treturn ret;\n+}\ndiff --git a/arch/arm/mach-snapdragon/qcom_fit_multidtb.h b/arch/arm/mach-snapdragon/qcom_fit_multidtb.h\nnew file mode 100644\nindex 00000000000..b568d31777e\n--- /dev/null\n+++ b/arch/arm/mach-snapdragon/qcom_fit_multidtb.h\n@@ -0,0 +1,189 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/*\n+ * Qualcomm FIT Multi-DTB Selection\n+ *\n+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.\n+ *\n+ * This implements automatic DTB selection from FIT images based on hardware\n+ * detection via SMEM.\n+ */\n+\n+#ifndef __QCOM_FIT_MULTIDTB_H__\n+#define __QCOM_FIT_MULTIDTB_H__\n+\n+#include <linux/types.h>\n+#include <linux/list.h>\n+#include <linux/sizes.h>\n+\n+/* DDR size thresholds */\n+#define DDR_128MB SZ_128M\n+#define DDR_256MB SZ_256M\n+#define DDR_512MB SZ_512M\n+#define DDR_1024MB SZ_1G\n+#define DDR_2048MB SZ_2G\n+#define DDR_3072MB (SZ_2G + SZ_1G)\n+#define DDR_4096MB SZ_4G\n+\n+/* DDR type enum */\n+enum ddr_type {\n+\tDDRTYPE_256MB = 1,\n+\tDDRTYPE_512MB,\t\t/* 2 */\n+\tDDRTYPE_1024MB,\t\t/* 3 */\n+\tDDRTYPE_2048MB,\t\t/* 4 */\n+\tDDRTYPE_3072MB,\t\t/* 5 */\n+\tDDRTYPE_4096MB,\t\t/* 6 */\n+\tDDRTYPE_128MB,\t\t/* 7 */\n+};\n+\n+/* Storage type enum */\n+enum mem_card_type {\n+\tUFS = 0,\n+\tEMMC = 1,\n+\tNAND = 2,\n+\tSTORAGE_UNKNOWN,\n+};\n+\n+/* Boot device types from shared IMEM */\n+enum boot_media_type {\n+\tNO_FLASH = 0,\n+\tNOR_FLASH = 1,\n+\tNAND_FLASH = 2,\n+\tONENAND_FLASH = 3,\n+\tSDC_FLASH = 4,\n+\tMMC_FLASH = 5,\n+\tSPI_FLASH = 6,\n+\tPCIE_FLASHLESS = 7,\n+\tUFS_FLASH = 8,\n+\tRESERVED_0_FLASH = 9,\n+\tRESERVED_1_FLASH = 10,\n+\tUSB_FLASHLESS = 11\n+};\n+\n+/* Shared IMEM constants */\n+#define BOOT_SHARED_IMEM_MAGIC_NUM 0xc1f8db40\n+#define BOOT_SHARED_IMEM_VERSION_NUM 0x3\n+\n+/**\n+ * struct qcom_imem_info - SoC-specific shared IMEM cookie address mapping\n+ * @compatible: SoC compatible string (e.g., \"qcom,qcs6490\")\n+ * @shared_imem_addr: Physical address of the boot shared IMEM cookie\n+ *\n+ * The shared IMEM cookie is populated by the bootloader and contains\n+ * boot device type and other boot parameters. Its location varies per SoC\n+ * and is calculated as: SCL_IMEM_BASE + IMEM_SIZE - 0x1000 (4KB cookie).\n+ * Only SoCs with CONFIG_QCOM_FIT_MULTIDTB support are listed here.\n+ */\n+struct qcom_imem_info {\n+\tconst char *compatible;\n+\tuintptr_t shared_imem_addr;\n+};\n+\n+/*\n+ * Per-SoC shared IMEM cookie address table.\n+ * Address = SCL_IMEM_BASE(0x14680000) + IMEM_SIZE - 0x1000\n+ * QCM6490/QCS6490/QCS615: IMEM_SIZE=0x2B000 -> 0x146aa000\n+ * QCS9100: IMEM_SIZE=0x59000 -> 0x146d8000\n+ */\n+static const struct qcom_imem_info qcom_imem_table[] = {\n+\t{ \"qcom,qcm6490\", 0x146aa000 },\n+\t{ \"qcom,qcs6490\", 0x146aa000 },\n+\t{ \"qcom,qcs615\", 0x146aa000 },\n+\t{ \"qcom,qcs9100\", 0x146d8000 },\n+\t{ }\n+};\n+\n+/* Boot shared IMEM cookie structure */\n+struct boot_imem_cookie {\n+\tu32 shared_imem_magic;\n+\tu32 shared_imem_version;\n+\tu64 etb_buf_addr;\n+\tu64 l2_cache_dump_buff_addr;\n+\tu32 a64_pointer_padding;\n+\tu32 uefi_ram_dump_magic;\n+\tu32 ddr_training_cookie;\n+\tu32 abnormal_reset_occurred;\n+\tu32 reset_status_register;\n+\tu32 rpm_sync_cookie;\n+\tu32 debug_config;\n+\tu64 boot_log_addr;\n+\tu32 boot_log_size;\n+\tu32 boot_fail_count;\n+\tu32 sbl1_error_type;\n+\tu32 uefi_image_magic;\n+\tu32 boot_device_type;\n+\tu64 boot_devtree_addr;\n+\tu64 boot_devtree_size;\n+};\n+\n+/**\n+ * struct qcom_hw_params - Hardware parameters detected from SMEM\n+ * @chip_id: SoC chip ID (from socinfo->id)\n+ * @chip_version: SoC version (from socinfo->plat_ver)\n+ * @platform: Hardware platform ID (from socinfo->hw_plat)\n+ * @subtype: Hardware platform subtype (from socinfo->hw_plat_subtype)\n+ * @oem_variant_id: OEM variant ID (from socinfo->oem_variant)\n+ * @ddr_size_type: DDR size type (0-10, calculated from RAM partitions)\n+ * @storage_type: Storage type (UFS=1, EMMC=2, NAND=3)\n+ * @foundry_id: Foundry ID (from socinfo->foundry_id)\n+ * @softsku_id: Software SKU ID (if available)\n+ *\n+ * This structure holds all hardware parameters needed for DTB selection.\n+ */\n+struct qcom_hw_params {\n+\tu32 chip_id;\n+\tu32 chip_version;\n+\tu32 platform;\n+\tu32 board_version;\n+\tu32 subtype;\n+\tu32 oem_variant_id;\n+\tu32 ddr_size_type;\n+\tu32 storage_type;\n+\tu32 foundry_id;\n+\tu32 softsku_id;\n+};\n+\n+/**\n+ * struct bucket_node - Node in the bucket list\n+ * @list: List head for linking nodes\n+ * @name: Node name string (e.g., \"qcom\", \"sa8775p-v2\", \"ride\", \"ufs\", \"8gb\")\n+ *\n+ * The bucket list contains all matching node names from the metadata DTB.\n+ * These are used to match against FIT configuration compatible strings.\n+ */\n+struct bucket_node {\n+\tstruct list_head list;\n+\tchar *name;\n+};\n+\n+/* Node processing types for metadata DTB parsing */\n+enum node_process_type {\n+\tNODE_TYPE_OEM,\n+\tNODE_TYPE_SOC,\n+\tNODE_TYPE_SOCVER,\n+\tNODE_TYPE_BOARD,\n+\tNODE_TYPE_BOARDREV,\n+\tNODE_TYPE_PERIPHERAL,\n+\tNODE_TYPE_STORAGE,\n+\tNODE_TYPE_DDR_SIZE,\n+\tNODE_TYPE_SOFTSKU,\n+};\n+\n+/* Function prototypes */\n+\n+/**\n+ * qcom_fit_multidtb_setup() - Main entry point for FIT multi-DTB selection\n+ *\n+ * This function:\n+ * 1. Loads qclinux_fit.img from EFI partition\n+ * 2. Extracts metadata DTB\n+ * 3. Detects hardware parameters from SMEM\n+ * 4. Builds bucket list from metadata\n+ * 5. Finds matching FIT configuration\n+ * 6. Loads DTB and applies overlays\n+ * 7. Sets FDT for EFI\n+ *\n+ * Return: 0 on success, negative error code on failure\n+ */\n+int qcom_fit_multidtb_setup(void);\n+\n+#endif /* __QCOM_FIT_MULTIDTB_H__ */\n", "prefixes": [ "v3", "2/7" ] }