{"id":2222305,"url":"http://patchwork.ozlabs.org/api/1.2/patches/2222305/?format=json","web_url":"http://patchwork.ozlabs.org/project/uboot/patch/20260411-qcom_spl-v2-8-9609557cf562@seznam.cz/","project":{"id":18,"url":"http://patchwork.ozlabs.org/api/1.2/projects/18/?format=json","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":"<20260411-qcom_spl-v2-8-9609557cf562@seznam.cz>","list_archive_url":null,"date":"2026-04-11T00:00:13","name":"[v2,08/10] mach-snapdragon: add board-spl.c and split out common code","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"3652a1fedff9026eb0c87e8effade0eec6aa824f","submitter":{"id":77645,"url":"http://patchwork.ozlabs.org/api/1.2/people/77645/?format=json","name":"Michael Srba","email":"michael.srba@seznam.cz"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/uboot/patch/20260411-qcom_spl-v2-8-9609557cf562@seznam.cz/mbox/","series":[{"id":499535,"url":"http://patchwork.ozlabs.org/api/1.2/series/499535/?format=json","web_url":"http://patchwork.ozlabs.org/project/uboot/list/?series=499535","date":"2026-04-11T00:00:12","name":"Add SPL support for Qualcomm platforms, starting with sdm845","version":2,"mbox":"http://patchwork.ozlabs.org/series/499535/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2222305/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2222305/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 secure) header.d=seznam.cz header.i=@seznam.cz header.a=rsa-sha256\n header.s=szn1 header.b=mtzhoC4o;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org)","phobos.denx.de;\n dmarc=pass (p=none dis=none) header.from=seznam.cz","phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de","phobos.denx.de;\n\tdkim=pass (2048-bit key;\n secure) header.d=seznam.cz header.i=@seznam.cz header.b=\"mtzhoC4o\";\n\tdkim-atps=neutral","phobos.denx.de;\n dmarc=pass (p=none dis=none) header.from=seznam.cz","phobos.denx.de;\n spf=pass smtp.mailfrom=michael.srba@seznam.cz"],"Received":["from phobos.denx.de (phobos.denx.de\n [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01])\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 4ft4bM5kMQz1y2d\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 11 Apr 2026 17:11:27 +1000 (AEST)","from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id 6A4C284284;\n\tSat, 11 Apr 2026 09:09:09 +0200 (CEST)","by phobos.denx.de (Postfix, from userid 109)\n id A00B084099; Sat, 11 Apr 2026 02:04:05 +0200 (CEST)","from mxd-2-a16.seznam.cz (mxd-2-a16.seznam.cz\n [IPv6:2a02:598:64:8a00::1000:a16])\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 DA533840D8\n for <u-boot@lists.denx.de>; Sat, 11 Apr 2026 02:03:58 +0200 (CEST)","from email.seznam.cz by smtpc-mxd-7644845457-sbn6w\n (smtpc-mxd-7644845457-sbn6w [2a02:598:64:8a00::1000:a16])\n id 21c6a18b7ac8f5e2206f6dd5; Sat, 11 Apr 2026 02:03:07 +0200 (CEST)","from [127.0.0.1] (ip-111-27.static.ccinternet.cz [147.161.27.111])\n by smtpd-relay-6597cc8696-xddnz (szn-email-smtpd/2.0.72) with ESMTPA\n id 03c7c386-9411-492c-87c7-43411154e0b8;\n Sat, 11 Apr 2026 02:03:03 +0200"],"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,FREEMAIL_FROM,\n RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham\n autolearn_force=no version=3.4.2","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=seznam.cz; s=szn1;\n t=1775865787; bh=b0LfaEttJvfvAzc1ydd7or8d74JaYnvEQPFNsVciedA=;\n h=From:Date:Subject:MIME-Version:Content-Type:\n Content-Transfer-Encoding:Message-Id:To:Cc;\n b=mtzhoC4on73oWubJMWZkziHE6+wJp1WjhCaA1o5AolmnDIqbbCZrYcZsCffmBfWlP\n arqe2b1cs29LOkQux1iyfVgHq9okl9i+A/u3Y1tBeQegmaGJcaDeRNb/ihDS/XRMg9\n 5jbG3tIO73GbmHK3GjMrLHzsE8INrBMVa5d3RF92vYINzW9yTnnGmF61kPraPUFchS\n QlvXWmfT1R7XrZySwXtX9+A4TyrIRWbkGTBsmbS8vQVhWH4R+IdFYz/fZedc6jHunh\n bu+e3Uqq2Rqmbh+RQpdFiNkecUMKX4eXSvkhoXCYxau6xTCInFrRwxy4Eca34HCyvV\n hN4z4wmkczUnw==","From":"michael.srba@seznam.cz","Date":"Sat, 11 Apr 2026 02:00:13 +0200","Subject":"[PATCH v2 08/10] mach-snapdragon: add board-spl.c and split out\n common code","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"7bit","Message-Id":"<20260411-qcom_spl-v2-8-9609557cf562@seznam.cz>","References":"<20260411-qcom_spl-v2-0-9609557cf562@seznam.cz>","In-Reply-To":"<20260411-qcom_spl-v2-0-9609557cf562@seznam.cz>","To":"u-boot@lists.denx.de, Sumit Garg <sumit.garg@kernel.org>,\n u-boot-qcom@groups.io","Cc":"Tom Rini <trini@konsulko.com>,\n Ilias Apalodimas <ilias.apalodimas@linaro.org>,\n Simon Glass <sjg@chromium.org>, Sughosh Ganu <sughosh.ganu@arm.com>,\n Anshul Dalal <anshuld@ti.com>, Peng Fan <peng.fan@nxp.com>,\n Mattijs Korpershoek <mkorpershoek@kernel.org>,\n Quentin Schulz <quentin.schulz@cherry.de>,\n Heinrich Schuchardt <xypron.glpk@gmx.de>, Andrew Davis <afd@ti.com>,\n Hrushikesh Salunke <h-salunke@ti.com>,\n Dario Binacchi <dario.binacchi@amarulasolutions.com>, Ye Li <ye.li@nxp.com>,\n Andre Przywara <andre.przywara@arm.com>,\n Alif Zakuan Yuslaimi <alif.zakuan.yuslaimi@altera.com>,\n Leo Yu-Chi Liang <ycliang@andestech.com>,\n Andrew Goodbody <andrew.goodbody@linaro.org>, Dhruva Gole <d-gole@ti.com>,\n Kaustabh Chakraborty <kauschluss@disroot.org>,\n Jerome Forissier <jerome.forissier@arm.com>,\n Heiko Schocher <hs@nabladev.com>,\n Marek Vasut <marek.vasut+renesas@mailbox.org>,\n Lukasz Majewski <lukma@denx.de>,\n Mateusz Kulikowski <mateusz.kulikowski@gmail.com>,\n Dinesh Maniyam <dinesh.maniyam@altera.com>,\n Neil Armstrong <neil.armstrong@linaro.org>,\n Patrice Chotard <patrice.chotard@foss.st.com>,\n Patrick Delaunay <patrick.delaunay@foss.st.com>,\n Michal Simek <michal.simek@amd.com>, Yao Zi <me@ziyao.cc>,\n Peter Korsgaard <peter@korsgaard.com>,\n Rayagonda Kokatanur <rayagonda.kokatanur@broadcom.com>,\n Casey Connolly <casey.connolly@linaro.org>,\n Tingting Meng <tingting.meng@altera.com>,\n Tien Fong Chee <tien.fong.chee@altera.com>, Alice Guo <alice.guo@nxp.com>,\n George Chan <gchan9527@gmail.com>,\n Balaji Selvanathan <balaji.selvanathan@oss.qualcomm.com>,\n Alexey Charkov <alchark@gmail.com>, Ronald Wahl <ronald.wahl@legrand.com>,\n Michael Srba <Michael.Srba@seznam.cz>","X-Mailer":"b4 0.15.1","X-Mailman-Approved-At":"Sat, 11 Apr 2026 09:08:55 +0200","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":"From: Michael Srba <Michael.Srba@seznam.cz>\n\nCode in board.c will now only be compiled into U-Boot proper,\nand the new board_spl.c will only be built into SPL.\nCode in board_common.c is common to both phases.\n\nAlso split out mem_map.c, which is currently common to both\nphases since it seems to not cause issues in SPL. In the future\nit should probably behave differenly in SPL, especially if dram\ninitialization is supported.\n\nSigned-off-by: Michael Srba <Michael.Srba@seznam.cz>\n---\n arch/arm/mach-snapdragon/Makefile       |   8 +\n arch/arm/mach-snapdragon/board.c        | 358 +-------------------------------\n arch/arm/mach-snapdragon/board_common.c |  56 +++++\n arch/arm/mach-snapdragon/board_spl.c    |  35 ++++\n arch/arm/mach-snapdragon/mem_map.c      | 318 ++++++++++++++++++++++++++++\n arch/arm/mach-snapdragon/qcom-priv.h    |   4 +-\n 6 files changed, 429 insertions(+), 350 deletions(-)","diff":"diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile\nindex 343e825c6fd..4b265b746ce 100644\n--- a/arch/arm/mach-snapdragon/Makefile\n+++ b/arch/arm/mach-snapdragon/Makefile\n@@ -2,6 +2,14 @@\n #\n # (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>\n \n+obj-y += board_common.o\n+obj-y += mem_map.o\n+\n+ifeq ($(CONFIG_SPL_BUILD),y)\n+obj-y += board_spl.o\n+else\n obj-y += board.o\n obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += capsule_update.o\n+endif\n+\n obj-$(CONFIG_OF_LIVE) += of_fixup.o\ndiff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c\nindex 5fb3240acc5..00e1aba675b 100644\n--- a/arch/arm/mach-snapdragon/board.c\n+++ b/arch/arm/mach-snapdragon/board.c\n@@ -1,6 +1,7 @@\n // SPDX-License-Identifier: GPL-2.0+\n /*\n  * Common initialisation for Qualcomm Snapdragon boards.\n+ * U-Boot proper only, see board_common.c for parts shared with SPL\n  *\n  * Copyright (c) 2024 Linaro Ltd.\n  * Author: Casey Connolly <casey.connolly@linaro.org>\n@@ -9,155 +10,21 @@\n #define LOG_CATEGORY LOGC_BOARD\n #define pr_fmt(fmt) \"QCOM: \" fmt\n \n-#include <asm/armv8/mmu.h>\n-#include <asm/gpio.h>\n-#include <asm/io.h>\n-#include <asm/psci.h>\n-#include <asm/system.h>\n-#include <dm/device.h>\n-#include <dm/pinctrl.h>\n-#include <dm/uclass-internal.h>\n-#include <dm/read.h>\n-#include <power/regulator.h>\n+#include <dm/ofnode.h>\n #include <env.h>\n #include <fdt_support.h>\n #include <init.h>\n #include <linux/arm-smccc.h>\n-#include <linux/bug.h>\n+#include <linux/errno.h>\n #include <linux/psci.h>\n #include <linux/sizes.h>\n #include <lmb.h>\n-#include <malloc.h>\n-#include <fdt_support.h>\n-#include <usb.h>\n-#include <sort.h>\n-#include <time.h>\n \n #include \"qcom-priv.h\"\n \n-DECLARE_GLOBAL_DATA_PTR;\n-\n enum qcom_boot_source qcom_boot_source __section(\".data\") = 0;\n \n-static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } };\n-\n-struct mm_region *mem_map = rbx_mem_map;\n-\n-static struct {\n-\tphys_addr_t start;\n-\tphys_size_t size;\n-} prevbl_ddr_banks[CONFIG_NR_DRAM_BANKS] __section(\".data\") = { 0 };\n-\n-int dram_init(void)\n-{\n-\t/*\n-\t * gd->ram_base / ram_size have been setup already\n-\t * in qcom_parse_memory().\n-\t */\n-\treturn 0;\n-}\n-\n-static int ddr_bank_cmp(const void *v1, const void *v2)\n-{\n-\tconst struct {\n-\t\tphys_addr_t start;\n-\t\tphys_size_t size;\n-\t} *res1 = v1, *res2 = v2;\n-\n-\tif (!res1->size)\n-\t\treturn 1;\n-\tif (!res2->size)\n-\t\treturn -1;\n-\n-\treturn (res1->start >> 24) - (res2->start >> 24);\n-}\n-\n-/* This has to be done post-relocation since gd->bd isn't preserved */\n-static void qcom_configure_bi_dram(void)\n-{\n-\tint i;\n-\n-\tfor (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {\n-\t\tgd->bd->bi_dram[i].start = prevbl_ddr_banks[i].start;\n-\t\tgd->bd->bi_dram[i].size = prevbl_ddr_banks[i].size;\n-\t}\n-}\n-\n-int dram_init_banksize(void)\n-{\n-\tqcom_configure_bi_dram();\n-\n-\treturn 0;\n-}\n-\n-/**\n- * The generic memory parsing code in U-Boot lacks a few things that we\n- * need on Qualcomm:\n- *\n- * 1. It sets gd->ram_size and gd->ram_base to represent a single memory block\n- * 2. setup_dest_addr() later relocates U-Boot to ram_base + ram_size, the end\n- *    of that first memory block.\n- *\n- * This results in all memory beyond U-Boot being unusable in Linux when booting\n- * with EFI.\n- *\n- * Since the ranges in the memory node may be out of order, the only way for us\n- * to correctly determine the relocation address for U-Boot is to parse all\n- * memory regions and find the highest valid address.\n- *\n- * We can't use fdtdec_setup_memory_banksize() since it stores the result in\n- * gd->bd, which is not yet allocated.\n- *\n- * @fdt: FDT blob to parse /memory node from\n- *\n- * Return: 0 on success or -ENODATA if /memory node is missing or incomplete\n- */\n-static int qcom_parse_memory(const void *fdt)\n-{\n-\tint offset;\n-\tconst fdt64_t *memory;\n-\tint memsize;\n-\tphys_addr_t ram_end = 0;\n-\tint i, j, banks;\n-\n-\toffset = fdt_path_offset(fdt, \"/memory\");\n-\tif (offset < 0)\n-\t\treturn -ENODATA;\n-\n-\tmemory = fdt_getprop(fdt, offset, \"reg\", &memsize);\n-\tif (!memory)\n-\t\treturn -ENODATA;\n-\n-\tbanks = min(memsize / (2 * sizeof(u64)), (ulong)CONFIG_NR_DRAM_BANKS);\n-\n-\tif (memsize / sizeof(u64) > CONFIG_NR_DRAM_BANKS * 2)\n-\t\tlog_err(\"Provided more than the max of %d memory banks\\n\", CONFIG_NR_DRAM_BANKS);\n-\n-\tif (banks > CONFIG_NR_DRAM_BANKS)\n-\t\tlog_err(\"Provided more memory banks than we can handle\\n\");\n-\n-\tfor (i = 0, j = 0; i < banks * 2; i += 2, j++) {\n-\t\tprevbl_ddr_banks[j].start = get_unaligned_be64(&memory[i]);\n-\t\tprevbl_ddr_banks[j].size = get_unaligned_be64(&memory[i + 1]);\n-\t\tif (!prevbl_ddr_banks[j].size) {\n-\t\t\tj--;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tram_end = max(ram_end, prevbl_ddr_banks[j].start + prevbl_ddr_banks[j].size);\n-\t}\n-\n-\tif (!banks || !prevbl_ddr_banks[0].size)\n-\t\treturn -ENODATA;\n-\n-\t/* Sort our RAM banks -_- */\n-\tqsort(prevbl_ddr_banks, banks, sizeof(prevbl_ddr_banks[0]), ddr_bank_cmp);\n-\n-\tgd->ram_base = prevbl_ddr_banks[0].start;\n-\tgd->ram_size = ram_end - gd->ram_base;\n-\n-\treturn 0;\n-}\n-\n+#if CONFIG_IS_ENABLED(SYSRESET_PSCI)\n static void show_psci_version(void)\n {\n \tstruct arm_smccc_res res;\n@@ -199,6 +66,7 @@ static void qcom_psci_fixup(void *fdt)\n \tif (ret)\n \t\tlog_err(\"Failed to delete /psci node: %d\\n\", ret);\n }\n+#endif\n \n /* We support booting U-Boot with an internal DT when running as a first-stage bootloader\n  * or for supporting quirky devices where it's easier to leave the downstream DT in place\n@@ -258,49 +126,13 @@ int board_fdt_blob_setup(void **fdtp)\n \t\tret = 0;\n \t}\n \n+#if CONFIG_IS_ENABLED(SYSRESET_PSCI)\n \tqcom_psci_fixup(*fdtp);\n+#endif\n \n \treturn ret;\n }\n \n-/*\n- * Some Qualcomm boards require GPIO configuration when switching USB modes.\n- * Support setting this configuration via pinctrl state.\n- */\n-int board_usb_init(int index, enum usb_init_type init)\n-{\n-\tstruct udevice *usb;\n-\tint ret = 0;\n-\n-\t/* USB device */\n-\tret = uclass_find_device_by_seq(UCLASS_USB, index, &usb);\n-\tif (ret) {\n-\t\tprintf(\"Cannot find USB device\\n\");\n-\t\treturn ret;\n-\t}\n-\n-\tret = dev_read_stringlist_search(usb, \"pinctrl-names\",\n-\t\t\t\t\t \"device\");\n-\t/* No \"device\" pinctrl state, so just bail */\n-\tif (ret < 0)\n-\t\treturn 0;\n-\n-\t/* Select \"default\" or \"device\" pinctrl */\n-\tswitch (init) {\n-\tcase USB_INIT_HOST:\n-\t\tpinctrl_select_state(usb, \"default\");\n-\t\tbreak;\n-\tcase USB_INIT_DEVICE:\n-\t\tpinctrl_select_state(usb, \"device\");\n-\t\tbreak;\n-\tdefault:\n-\t\tdebug(\"Unknown usb_init_type %d\\n\", init);\n-\t\tbreak;\n-\t}\n-\n-\treturn 0;\n-}\n-\n /*\n  * Some boards still need board specific init code, they can implement that by\n  * overriding this function.\n@@ -313,7 +145,9 @@ void __weak qcom_board_init(void)\n \n int board_init(void)\n {\n+#if CONFIG_IS_ENABLED(SYSRESET_PSCI) && !defined(CONFIG_SPL_BUILD)\n \tshow_psci_version();\n+#endif\n \tqcom_board_init();\n \treturn 0;\n }\n@@ -575,177 +409,3 @@ int board_late_init(void)\n \n \treturn 0;\n }\n-\n-static void build_mem_map(void)\n-{\n-\tint i, j;\n-\n-\t/*\n-\t * Ensure the peripheral block is sized to correctly cover the address range\n-\t * up to the first memory bank.\n-\t * Don't map the first page to ensure that we actually trigger an abort on a\n-\t * null pointer access rather than just hanging.\n-\t * FIXME: we should probably split this into more precise regions\n-\t */\n-\tmem_map[0].phys = 0x1000;\n-\tmem_map[0].virt = mem_map[0].phys;\n-\tmem_map[0].size = gd->bd->bi_dram[0].start - mem_map[0].phys;\n-\tmem_map[0].attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |\n-\t\t\t PTE_BLOCK_NON_SHARE |\n-\t\t\t PTE_BLOCK_PXN | PTE_BLOCK_UXN;\n-\n-\tfor (i = 1, j = 0; i < ARRAY_SIZE(rbx_mem_map) - 1 && gd->bd->bi_dram[j].size; i++, j++) {\n-\t\tmem_map[i].phys = gd->bd->bi_dram[j].start;\n-\t\tmem_map[i].virt = mem_map[i].phys;\n-\t\tmem_map[i].size = gd->bd->bi_dram[j].size;\n-\t\tmem_map[i].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | \\\n-\t\t\t\t   PTE_BLOCK_INNER_SHARE;\n-\t}\n-\n-\tmem_map[i].phys = UINT64_MAX;\n-\tmem_map[i].size = 0;\n-\n-#ifdef DEBUG\n-\tdebug(\"Configured memory map:\\n\");\n-\tfor (i = 0; mem_map[i].size; i++)\n-\t\tdebug(\"  0x%016llx - 0x%016llx: entry %d\\n\",\n-\t\t      mem_map[i].phys, mem_map[i].phys + mem_map[i].size, i);\n-#endif\n-}\n-\n-u64 get_page_table_size(void)\n-{\n-\treturn SZ_1M;\n-}\n-\n-static int fdt_cmp_res(const void *v1, const void *v2)\n-{\n-\tconst struct fdt_resource *res1 = v1, *res2 = v2;\n-\n-\treturn res1->start - res2->start;\n-}\n-\n-#define N_RESERVED_REGIONS 32\n-\n-/* Mark all no-map regions as PTE_TYPE_FAULT to prevent speculative access.\n- * On some platforms this is enough to trigger a security violation and trap\n- * to EL3.\n- */\n-static void carve_out_reserved_memory(void)\n-{\n-\tstatic struct fdt_resource res[N_RESERVED_REGIONS] = { 0 };\n-\tint parent, rmem, count, i = 0;\n-\tphys_addr_t start;\n-\tsize_t size;\n-\n-\t/* Some reserved nodes must be carved out, as the cache-prefetcher may otherwise\n-\t * attempt to access them, causing a security exception.\n-\t */\n-\tparent = fdt_path_offset(gd->fdt_blob, \"/reserved-memory\");\n-\tif (parent <= 0) {\n-\t\tlog_err(\"No reserved memory regions found\\n\");\n-\t\treturn;\n-\t}\n-\n-\t/* Collect the reserved memory regions */\n-\tfdt_for_each_subnode(rmem, gd->fdt_blob, parent) {\n-\t\tconst fdt32_t *ptr;\n-\t\tint len;\n-\t\tif (!fdt_getprop(gd->fdt_blob, rmem, \"no-map\", NULL))\n-\t\t\tcontinue;\n-\n-\t\tif (i == N_RESERVED_REGIONS) {\n-\t\t\tlog_err(\"Too many reserved regions!\\n\");\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\t/* Read the address and size out from the reg property. Doing this \"properly\" with\n-\t\t * fdt_get_resource() takes ~70ms on SDM845, but open-coding the happy path here\n-\t\t * takes <1ms... Oh the woes of no dcache.\n-\t\t */\n-\t\tptr = fdt_getprop(gd->fdt_blob, rmem, \"reg\", &len);\n-\t\tif (ptr) {\n-\t\t\t/* Qualcomm devices use #address/size-cells = <2> but all reserved regions are within\n-\t\t\t * the 32-bit address space. So we can cheat here for speed.\n-\t\t\t */\n-\t\t\tres[i].start = fdt32_to_cpu(ptr[1]);\n-\t\t\tres[i].end = res[i].start + fdt32_to_cpu(ptr[3]);\n-\t\t\ti++;\n-\t\t}\n-\t}\n-\n-\t/* Sort the reserved memory regions by address */\n-\tcount = i;\n-\tqsort(res, count, sizeof(struct fdt_resource), fdt_cmp_res);\n-\n-\t/* Now set the right attributes for them. Often a lot of the regions are tightly packed together\n-\t * so we can optimise the number of calls to mmu_change_region_attr() by combining adjacent\n-\t * regions.\n-\t */\n-\tstart = ALIGN_DOWN(res[0].start, SZ_2M);\n-\tsize = ALIGN(res[0].end - start, SZ_2M);\n-\tfor (i = 1; i <= count; i++) {\n-\t\t/* We ideally want to 2M align everything for more efficient pagetables, but we must avoid\n-\t\t * overwriting reserved memory regions which shouldn't be mapped as FAULT (like those with\n-\t\t * compatible properties).\n-\t\t * If within 2M of the previous region, bump the size to include this region. Otherwise\n-\t\t * start a new region.\n-\t\t */\n-\t\tif (i == count || start + size < res[i].start - SZ_2M) {\n-\t\t\tdebug(\"  0x%016llx - 0x%016llx: reserved\\n\",\n-\t\t\t      start, start + size);\n-\t\t\tmmu_change_region_attr(start, size, PTE_TYPE_FAULT);\n-\t\t\t/* If this is the final region then quit here before we index\n-\t\t\t * out of bounds...\n-\t\t\t */\n-\t\t\tif (i == count)\n-\t\t\t\tbreak;\n-\t\t\tstart = ALIGN_DOWN(res[i].start, SZ_2M);\n-\t\t\tsize = ALIGN(res[i].end - start, SZ_2M);\n-\t\t} else {\n-\t\t\t/* Bump size if this region is immediately after the previous one */\n-\t\t\tsize = ALIGN(res[i].end - start, SZ_2M);\n-\t\t}\n-\t}\n-}\n-\n-/* This function open-codes setup_all_pgtables() so that we can\n- * insert additional mappings *before* turning on the MMU.\n- */\n-void enable_caches(void)\n-{\n-\tu64 tlb_addr = gd->arch.tlb_addr;\n-\tu64 tlb_size = gd->arch.tlb_size;\n-\tu64 pt_size;\n-\tulong carveout_start;\n-\n-\tgd->arch.tlb_fillptr = tlb_addr;\n-\n-\tbuild_mem_map();\n-\n-\ticache_enable();\n-\n-\t/* Create normal system page tables */\n-\tsetup_pgtables();\n-\n-\tpt_size = (uintptr_t)gd->arch.tlb_fillptr -\n-\t\t  (uintptr_t)gd->arch.tlb_addr;\n-\tdebug(\"Primary pagetable size: %lluKiB\\n\", pt_size / 1024);\n-\n-\t/* Create emergency page tables */\n-\tgd->arch.tlb_size -= pt_size;\n-\tgd->arch.tlb_addr = gd->arch.tlb_fillptr;\n-\tsetup_pgtables();\n-\tgd->arch.tlb_emerg = gd->arch.tlb_addr;\n-\tgd->arch.tlb_addr = tlb_addr;\n-\tgd->arch.tlb_size = tlb_size;\n-\n-\t/* We do the carveouts only for QCS404, for now. */\n-\tif (fdt_node_check_compatible(gd->fdt_blob, 0, \"qcom,qcs404\") == 0) {\n-\t\tcarveout_start = get_timer(0);\n-\t\t/* Takes ~20-50ms on SDM845 */\n-\t\tcarve_out_reserved_memory();\n-\t\tdebug(\"carveout time: %lums\\n\", get_timer(carveout_start));\n-\t}\n-\tdcache_enable();\n-}\ndiff --git a/arch/arm/mach-snapdragon/board_common.c b/arch/arm/mach-snapdragon/board_common.c\nnew file mode 100644\nindex 00000000000..f6daeb6edf4\n--- /dev/null\n+++ b/arch/arm/mach-snapdragon/board_common.c\n@@ -0,0 +1,56 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/*\n+ * Common initialisation for Qualcomm Snapdragon boards.\n+ *\n+ * Copyright (c) 2024 Linaro Ltd.\n+ * Author: Casey Connolly <casey.connolly@linaro.org>\n+ */\n+\n+#define LOG_CATEGORY LOGC_BOARD\n+#define pr_fmt(fmt) \"QCOM: \" fmt\n+\n+#include <dm/device.h>\n+#include <dm/pinctrl.h>\n+#include <dm/uclass-internal.h>\n+#include <dm/read.h>\n+#include <usb.h>\n+\n+#include \"qcom-priv.h\"\n+\n+/*\n+ * Some Qualcomm boards require GPIO configuration when switching USB modes.\n+ * Support setting this configuration via pinctrl state.\n+ */\n+int board_usb_init(int index, enum usb_init_type init)\n+{\n+\tstruct udevice *usb;\n+\tint ret = 0;\n+\n+\t/* USB device */\n+\tret = uclass_find_device_by_seq(UCLASS_USB, index, &usb);\n+\tif (ret) {\n+\t\tprintf(\"Cannot find USB device\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = dev_read_stringlist_search(usb, \"pinctrl-names\",\n+\t\t\t\t\t \"device\");\n+\t/* No \"device\" pinctrl state, so just bail */\n+\tif (ret < 0)\n+\t\treturn 0;\n+\n+\t/* Select \"default\" or \"device\" pinctrl */\n+\tswitch (init) {\n+\tcase USB_INIT_HOST:\n+\t\tpinctrl_select_state(usb, \"default\");\n+\t\tbreak;\n+\tcase USB_INIT_DEVICE:\n+\t\tpinctrl_select_state(usb, \"device\");\n+\t\tbreak;\n+\tdefault:\n+\t\tdebug(\"Unknown usb_init_type %d\\n\", init);\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/arch/arm/mach-snapdragon/board_spl.c b/arch/arm/mach-snapdragon/board_spl.c\nnew file mode 100644\nindex 00000000000..19260975063\n--- /dev/null\n+++ b/arch/arm/mach-snapdragon/board_spl.c\n@@ -0,0 +1,35 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/*\n+ * Common SPL code for Qualcomm Snapdragon boards.\n+ *\n+ * Copyright (c) 2026 Michael Srba <Michael.Srba@seznam.cz>\n+ */\n+\n+#include <hang.h>\n+#include <spl.h>\n+\n+/* in SPL, we always use internal DT */\n+int board_fdt_blob_setup(void **fdtp)\n+{\n+\treturn -EEXIST;\n+}\n+\n+int board_init(void)\n+{\n+\treturn 0;\n+}\n+\n+__weak void reset_cpu(void)\n+{\n+\t/* This should currently not get called in non-error paths, so just hang */\n+\tprintf(\"reset_cpu called, going to hang()\\n\");\n+\thang();\n+}\n+\n+u32 spl_boot_device(void)\n+{\n+\t/* TODO: check boot reason to support UFS and sdcard */\n+\tu32 boot_device = BOOT_DEVICE_DFU;\n+\n+\treturn boot_device;\n+}\ndiff --git a/arch/arm/mach-snapdragon/mem_map.c b/arch/arm/mach-snapdragon/mem_map.c\nnew file mode 100644\nindex 00000000000..70e3c1d1fcc\n--- /dev/null\n+++ b/arch/arm/mach-snapdragon/mem_map.c\n@@ -0,0 +1,318 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/*\n+ * Common initialisation for Qualcomm Snapdragon boards.\n+ *\n+ * Copyright (c) 2024 Linaro Ltd.\n+ * Author: Casey Connolly <casey.connolly@linaro.org>\n+ */\n+\n+#define LOG_CATEGORY LOGC_BOARD\n+#define pr_fmt(fmt) \"QCOM: \" fmt\n+\n+#include <asm/armv8/mmu.h>\n+#include <asm/global_data.h>\n+#include <asm/system.h>\n+#include <asm-generic/unaligned.h>\n+#include <cpu_func.h>\n+#include <fdt_support.h>\n+#include <linux/errno.h>\n+#include <linux/sizes.h>\n+#include <sort.h>\n+#include <time.h>\n+\n+#include \"qcom-priv.h\"\n+\n+DECLARE_GLOBAL_DATA_PTR;\n+\n+static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } };\n+\n+struct mm_region *mem_map = rbx_mem_map;\n+\n+static struct {\n+\tphys_addr_t start;\n+\tphys_size_t size;\n+} prevbl_ddr_banks[CONFIG_NR_DRAM_BANKS] __section(\".data\") = { 0 };\n+\n+int dram_init(void)\n+{\n+\t/*\n+\t * gd->ram_base / ram_size have been setup already\n+\t * in qcom_parse_memory().\n+\t */\n+\treturn 0;\n+}\n+\n+static int ddr_bank_cmp(const void *v1, const void *v2)\n+{\n+\tconst struct {\n+\t\tphys_addr_t start;\n+\t\tphys_size_t size;\n+\t} *res1 = v1, *res2 = v2;\n+\n+\tif (!res1->size)\n+\t\treturn 1;\n+\tif (!res2->size)\n+\t\treturn -1;\n+\n+\treturn (res1->start >> 24) - (res2->start >> 24);\n+}\n+\n+/* This has to be done post-relocation since gd->bd isn't preserved */\n+static void qcom_configure_bi_dram(void)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {\n+\t\tgd->bd->bi_dram[i].start = prevbl_ddr_banks[i].start;\n+\t\tgd->bd->bi_dram[i].size = prevbl_ddr_banks[i].size;\n+\t}\n+}\n+\n+int dram_init_banksize(void)\n+{\n+\tqcom_configure_bi_dram();\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * The generic memory parsing code in U-Boot lacks a few things that we\n+ * need on Qualcomm:\n+ *\n+ * 1. It sets gd->ram_size and gd->ram_base to represent a single memory block\n+ * 2. setup_dest_addr() later relocates U-Boot to ram_base + ram_size, the end\n+ *    of that first memory block.\n+ *\n+ * This results in all memory beyond U-Boot being unusable in Linux when booting\n+ * with EFI.\n+ *\n+ * Since the ranges in the memory node may be out of order, the only way for us\n+ * to correctly determine the relocation address for U-Boot is to parse all\n+ * memory regions and find the highest valid address.\n+ *\n+ * We can't use fdtdec_setup_memory_banksize() since it stores the result in\n+ * gd->bd, which is not yet allocated.\n+ *\n+ * @fdt: FDT blob to parse /memory node from\n+ *\n+ * Return: 0 on success or -ENODATA if /memory node is missing or incomplete\n+ */\n+int qcom_parse_memory(const void *fdt)\n+{\n+\tint offset;\n+\tconst fdt64_t *memory;\n+\tint memsize;\n+\tphys_addr_t ram_end = 0;\n+\tint i, j, banks;\n+\n+\toffset = fdt_path_offset(fdt, \"/memory\");\n+\tif (offset < 0)\n+\t\treturn -ENODATA;\n+\n+\tmemory = fdt_getprop(fdt, offset, \"reg\", &memsize);\n+\tif (!memory)\n+\t\treturn -ENODATA;\n+\n+\tbanks = min(memsize / (2 * sizeof(u64)), (ulong)CONFIG_NR_DRAM_BANKS);\n+\n+\tif (memsize / sizeof(u64) > CONFIG_NR_DRAM_BANKS * 2)\n+\t\tlog_err(\"Provided more than the max of %d memory banks\\n\", CONFIG_NR_DRAM_BANKS);\n+\n+\tif (banks > CONFIG_NR_DRAM_BANKS)\n+\t\tlog_err(\"Provided more memory banks than we can handle\\n\");\n+\n+\tfor (i = 0, j = 0; i < banks * 2; i += 2, j++) {\n+\t\tprevbl_ddr_banks[j].start = get_unaligned_be64(&memory[i]);\n+\t\tprevbl_ddr_banks[j].size = get_unaligned_be64(&memory[i + 1]);\n+\t\tif (!prevbl_ddr_banks[j].size) {\n+\t\t\tj--;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tram_end = max(ram_end, prevbl_ddr_banks[j].start + prevbl_ddr_banks[j].size);\n+\t}\n+\n+\tif (!banks || !prevbl_ddr_banks[0].size)\n+\t\treturn -ENODATA;\n+\n+\t/* Sort our RAM banks -_- */\n+\tqsort(prevbl_ddr_banks, banks, sizeof(prevbl_ddr_banks[0]), ddr_bank_cmp);\n+\n+\tgd->ram_base = prevbl_ddr_banks[0].start;\n+\tgd->ram_size = ram_end - gd->ram_base;\n+\n+\treturn 0;\n+}\n+\n+static void build_mem_map(void)\n+{\n+\tint i, j;\n+\n+\t/*\n+\t * Ensure the peripheral block is sized to correctly cover the address range\n+\t * up to the first memory bank.\n+\t * Don't map the first page to ensure that we actually trigger an abort on a\n+\t * null pointer access rather than just hanging.\n+\t * FIXME: we should probably split this into more precise regions\n+\t */\n+\tmem_map[0].phys = 0x1000;\n+\tmem_map[0].virt = mem_map[0].phys;\n+\tmem_map[0].size = gd->bd->bi_dram[0].start - mem_map[0].phys;\n+\tmem_map[0].attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |\n+\t\t\t PTE_BLOCK_NON_SHARE |\n+\t\t\t PTE_BLOCK_PXN | PTE_BLOCK_UXN;\n+\n+\tfor (i = 1, j = 0; i < ARRAY_SIZE(rbx_mem_map) - 1 && gd->bd->bi_dram[j].size; i++, j++) {\n+\t\tmem_map[i].phys = gd->bd->bi_dram[j].start;\n+\t\tmem_map[i].virt = mem_map[i].phys;\n+\t\tmem_map[i].size = gd->bd->bi_dram[j].size;\n+\t\tmem_map[i].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | \\\n+\t\t\t\t   PTE_BLOCK_INNER_SHARE;\n+\t}\n+\n+\tmem_map[i].phys = UINT64_MAX;\n+\tmem_map[i].size = 0;\n+\n+#ifdef DEBUG\n+\tdebug(\"Configured memory map:\\n\");\n+\tfor (i = 0; mem_map[i].size; i++)\n+\t\tdebug(\"  0x%016llx - 0x%016llx: entry %d\\n\",\n+\t\t      mem_map[i].phys, mem_map[i].phys + mem_map[i].size, i);\n+#endif\n+}\n+\n+u64 get_page_table_size(void)\n+{\n+\treturn SZ_1M;\n+}\n+\n+static int fdt_cmp_res(const void *v1, const void *v2)\n+{\n+\tconst struct fdt_resource *res1 = v1, *res2 = v2;\n+\n+\treturn res1->start - res2->start;\n+}\n+\n+#define N_RESERVED_REGIONS 32\n+\n+/* Mark all no-map regions as PTE_TYPE_FAULT to prevent speculative access.\n+ * On some platforms this is enough to trigger a security violation and trap\n+ * to EL3.\n+ */\n+static void carve_out_reserved_memory(void)\n+{\n+\tstatic struct fdt_resource res[N_RESERVED_REGIONS] = { 0 };\n+\tint parent, rmem, count, i = 0;\n+\tphys_addr_t start;\n+\tsize_t size;\n+\n+\t/* Some reserved nodes must be carved out, as the cache-prefetcher may otherwise\n+\t * attempt to access them, causing a security exception.\n+\t */\n+\tparent = fdt_path_offset(gd->fdt_blob, \"/reserved-memory\");\n+\tif (parent <= 0) {\n+\t\tlog_err(\"No reserved memory regions found\\n\");\n+\t\treturn;\n+\t}\n+\n+\t/* Collect the reserved memory regions */\n+\tfdt_for_each_subnode(rmem, gd->fdt_blob, parent) {\n+\t\tconst fdt32_t *ptr;\n+\t\tint len;\n+\t\tif (!fdt_getprop(gd->fdt_blob, rmem, \"no-map\", NULL))\n+\t\t\tcontinue;\n+\n+\t\tif (i == N_RESERVED_REGIONS) {\n+\t\t\tlog_err(\"Too many reserved regions!\\n\");\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* Read the address and size out from the reg property. Doing this \"properly\" with\n+\t\t * fdt_get_resource() takes ~70ms on SDM845, but open-coding the happy path here\n+\t\t * takes <1ms... Oh the woes of no dcache.\n+\t\t */\n+\t\tptr = fdt_getprop(gd->fdt_blob, rmem, \"reg\", &len);\n+\t\tif (ptr) {\n+\t\t\t/* Qualcomm devices use #address/size-cells = <2> but all reserved regions are within\n+\t\t\t * the 32-bit address space. So we can cheat here for speed.\n+\t\t\t */\n+\t\t\tres[i].start = fdt32_to_cpu(ptr[1]);\n+\t\t\tres[i].end = res[i].start + fdt32_to_cpu(ptr[3]);\n+\t\t\ti++;\n+\t\t}\n+\t}\n+\n+\t/* Sort the reserved memory regions by address */\n+\tcount = i;\n+\tqsort(res, count, sizeof(struct fdt_resource), fdt_cmp_res);\n+\n+\t/* Now set the right attributes for them. Often a lot of the regions are tightly packed together\n+\t * so we can optimise the number of calls to mmu_change_region_attr() by combining adjacent\n+\t * regions.\n+\t */\n+\tstart = ALIGN_DOWN(res[0].start, SZ_2M);\n+\tsize = ALIGN(res[0].end - start, SZ_2M);\n+\tfor (i = 1; i <= count; i++) {\n+\t\t/* We ideally want to 2M align everything for more efficient pagetables, but we must avoid\n+\t\t * overwriting reserved memory regions which shouldn't be mapped as FAULT (like those with\n+\t\t * compatible properties).\n+\t\t * If within 2M of the previous region, bump the size to include this region. Otherwise\n+\t\t * start a new region.\n+\t\t */\n+\t\tif (i == count || start + size < res[i].start - SZ_2M) {\n+\t\t\tdebug(\"  0x%016llx - 0x%016llx: reserved\\n\",\n+\t\t\t      start, start + size);\n+\t\t\tmmu_change_region_attr(start, size, PTE_TYPE_FAULT);\n+\t\t\t/* If this is the final region then quit here before we index\n+\t\t\t * out of bounds...\n+\t\t\t */\n+\t\t\tif (i == count)\n+\t\t\t\tbreak;\n+\t\t\tstart = ALIGN_DOWN(res[i].start, SZ_2M);\n+\t\t\tsize = ALIGN(res[i].end - start, SZ_2M);\n+\t\t} else {\n+\t\t\t/* Bump size if this region is immediately after the previous one */\n+\t\t\tsize = ALIGN(res[i].end - start, SZ_2M);\n+\t\t}\n+\t}\n+}\n+\n+/* This function open-codes setup_all_pgtables() so that we can\n+ * insert additional mappings *before* turning on the MMU.\n+ */\n+void enable_caches(void)\n+{\n+\tu64 tlb_addr = gd->arch.tlb_addr;\n+\tu64 tlb_size = gd->arch.tlb_size;\n+\tu64 pt_size;\n+\tulong carveout_start;\n+\n+\tgd->arch.tlb_fillptr = tlb_addr;\n+\n+\tbuild_mem_map();\n+\n+\ticache_enable();\n+\n+\t/* Create normal system page tables */\n+\tsetup_pgtables();\n+\n+\tpt_size = (uintptr_t)gd->arch.tlb_fillptr -\n+\t\t  (uintptr_t)gd->arch.tlb_addr;\n+\tdebug(\"Primary pagetable size: %lluKiB\\n\", pt_size / 1024);\n+\n+\t/* Create emergency page tables */\n+\tgd->arch.tlb_size -= pt_size;\n+\tgd->arch.tlb_addr = gd->arch.tlb_fillptr;\n+\tsetup_pgtables();\n+\tgd->arch.tlb_emerg = gd->arch.tlb_addr;\n+\tgd->arch.tlb_addr = tlb_addr;\n+\tgd->arch.tlb_size = tlb_size;\n+\n+\t/* We do the carveouts only for QCS404, for now. */\n+\tif (fdt_node_check_compatible(gd->fdt_blob, 0, \"qcom,qcs404\") == 0) {\n+\t\tcarveout_start = get_timer(0);\n+\t\t/* Takes ~20-50ms on SDM845 */\n+\t\tcarve_out_reserved_memory();\n+\t\tdebug(\"carveout time: %lums\\n\", get_timer(carveout_start));\n+\t}\n+\tdcache_enable();\n+}\ndiff --git a/arch/arm/mach-snapdragon/qcom-priv.h b/arch/arm/mach-snapdragon/qcom-priv.h\nindex b8bf574e8bb..b372465d125 100644\n--- a/arch/arm/mach-snapdragon/qcom-priv.h\n+++ b/arch/arm/mach-snapdragon/qcom-priv.h\n@@ -20,7 +20,9 @@ extern enum qcom_boot_source qcom_boot_source;\n #if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)\n void qcom_configure_capsule_updates(void);\n #else\n-void qcom_configure_capsule_updates(void) {}\n+static inline void qcom_configure_capsule_updates(void) {}\n #endif /* EFI_HAVE_CAPSULE_SUPPORT */\n \n+int qcom_parse_memory(const void *fdt);\n+\n #endif /* __QCOM_PRIV_H__ */\n","prefixes":["v2","08/10"]}