Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2219580/?format=api
{ "id": 2219580, "url": "http://patchwork.ozlabs.org/api/patches/2219580/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20260403135205.26979-6-ansuelsmth@gmail.com/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/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": "<20260403135205.26979-6-ansuelsmth@gmail.com>", "list_archive_url": null, "date": "2026-04-03T13:52:02", "name": "[v5,5/6] misc: fw_loader: introduce FIP loader driver", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "565ee61926306f0fd4d2171fcee90f14125d2b20", "submitter": { "id": 71108, "url": "http://patchwork.ozlabs.org/api/people/71108/?format=api", "name": "Christian Marangi", "email": "ansuelsmth@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20260403135205.26979-6-ansuelsmth@gmail.com/mbox/", "series": [ { "id": 498633, "url": "http://patchwork.ozlabs.org/api/series/498633/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=498633", "date": "2026-04-03T13:51:57", "name": "misc: fs_loader: reorg and split to FS and FW loader + FIP loader", "version": 5, "mbox": "http://patchwork.ozlabs.org/series/498633/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2219580/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2219580/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=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=ZY0flBFM;\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=gmail.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=gmail.com header.i=@gmail.com header.b=\"ZY0flBFM\";\n\tdkim-atps=neutral", "phobos.denx.de;\n dmarc=pass (p=none dis=none) header.from=gmail.com", "phobos.denx.de;\n spf=pass smtp.mailfrom=ansuelsmth@gmail.com" ], "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 4fnKtT328dz1yCs\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 04 Apr 2026 00:53:05 +1100 (AEDT)", "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id E93F78412A;\n\tFri, 3 Apr 2026 15:52:30 +0200 (CEST)", "by phobos.denx.de (Postfix, from userid 109)\n id 862738412A; Fri, 3 Apr 2026 15:52:29 +0200 (CEST)", "from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com\n [IPv6:2a00:1450:4864:20::32a])\n (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id 2DDA184101\n for <u-boot@lists.denx.de>; Fri, 3 Apr 2026 15:52:27 +0200 (CEST)", "by mail-wm1-x32a.google.com with SMTP id\n 5b1f17b1804b1-486ff3a0fc1so17693135e9.2\n for <u-boot@lists.denx.de>; Fri, 03 Apr 2026 06:52:27 -0700 (PDT)", "from Ansuel-XPS24 ([217.202.87.54])\n by smtp.googlemail.com with ESMTPSA id\n 5b1f17b1804b1-4888a7162cesm196732895e9.13.2026.04.03.06.52.24\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 03 Apr 2026 06:52:26 -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,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;\n d=gmail.com; s=20251104; t=1775224347; x=1775829147; 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=XC5uWtKoliXHahUG6xZcDWM9Q/kzFk37Ld8G3b4Ph5o=;\n b=ZY0flBFMxdMUhp31VGOsYz62h4j6qOtsayyZkBZU+qhQvOiH6TfF+1s7NQSraz+hgb\n +VEORltGHhXO7aBjIZcInEyH6TNyUQTfubBh0Y7p8PAw0+UPS1CipD4ZsYuzsamrkUmg\n Yj0FSm3WfRZ5HOZBr6A5dR8zq6k9oNqpVpPJc8B+zut3OiwqcFWXZel+gctBGppm9/yJ\n 8EfGlyjaVoV+9UsGrSUGL9PmehoGfT6aW0ilz2IFI9zPGD5fFzC54h0U26ja2q8CBT2S\n 7JGqMToHxIS5VPnyaYY5HiGyiT4z/x8ctAASp0dc3zoMbdioWt8b6RczloyHpiOtrHvE\n UnVw==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775224347; x=1775829147;\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=XC5uWtKoliXHahUG6xZcDWM9Q/kzFk37Ld8G3b4Ph5o=;\n b=bXZ0t81WmwPvqxSINr+1hDIzqAdlISr27shybyYhan2A3SqaGf1npJycYNFP7WRNKq\n VLLmk9tA2AZS7nIOV4Mdd2ieSy/9nGE1PIgh94YzcdzP0o0PsX+C2mIbz9JyZ0u35EhM\n GCDSewTw2m8T80SQEKT+GzH8WYAovggozbJlLVawPnq3MLbe0Nng3VJVv0ueTlBYDfU1\n xdNuEtXSxuL/9kkMTcQfBwRsi+bc8vVYGUVGejAH/10btBkqS1vpBLO3XfHV/5G2tEaE\n kqBZvfWccOGRg0PQRoQNyq2wQ5GuO8+3NHUBdU3YYA9hsDp0+jbBzkZ/rpTyR3WtQMo4\n siXg==", "X-Forwarded-Encrypted": "i=1;\n AJvYcCWmNveoAYPE2SrFeepgCA6LukdrWzu6G86NzG+/X9fupl0NYxUCOBSFxrIHAb6BlHHzMcgRGW0=@lists.denx.de", "X-Gm-Message-State": "AOJu0YwquaF/VtiYDG3wAWLFyoVKcmrTJgVUGm7Yk0vnBbaptgbBGVcs\n PPPfJLyFqOlkHyQHoTb1qBmVX5efKXJo+jZUHIZGp9MzjUZMo1lHIJeL", "X-Gm-Gg": "ATEYQzzoqTvXKRCSDum73MXUGkW7YP4TbxIIdgdgqT0mLBwgdPFoM0oT/AxXk1pOIDs\n vSr3irqFPwMQNS+8btxDwUEsq4QL7Wz9HnVmuvxKs8ESecoUA9iGgfr/nHx2Hy4sFVLGBqnjToA\n cPffHkgwgQPRIyOwIyrcplX+Ndn4Bn6sJi7qSdlXBVP6LB6JPhCoEhGJQpWYqgvB/nzxE4Fnxlt\n +7E8ImBUwWxhWvqV1nQZPop2aBpm3PlHfQWB1IucGhjI7+9gNpJeW6SrRbu5ftIWpkiw64Gt4YC\n SjGPGR7aHtWAp9c75Gxse3JjbQrI8+yoYfOKbwxl9BdNTyB7FAnabynbU0V18VE6K3ee508RTxw\n 41mHWlcJB5idnY4dzjtmGWDNnEGlTJW63cl1i1elQ0NZPXaxPKmZrks6/TXStGwS32H2EWPzHVY\n mLDX86EIpH1j/RgTSo1uSSidg=", "X-Received": "by 2002:a05:600c:638e:b0:480:2521:4d92 with SMTP id\n 5b1f17b1804b1-488997b23c6mr49094935e9.24.1775224346390;\n Fri, 03 Apr 2026 06:52:26 -0700 (PDT)", "From": "Christian Marangi <ansuelsmth@gmail.com>", "To": "Tom Rini <trini@konsulko.com>, Simon Glass <sjg@chromium.org>,\n Christian Marangi <ansuelsmth@gmail.com>,\n Casey Connolly <casey.connolly@linaro.org>,\n Quentin Schulz <quentin.schulz@cherry.de>, Peng Fan <peng.fan@nxp.com>,\n Justin Klaassen <justin@tidylabs.net>,\n Neha Malcom Francis <n-francis@ti.com>,\n Heinrich Schuchardt <xypron.glpk@gmx.de>,\n Jamie Gibbons <jamie.gibbons@microchip.com>,\n Leo Yu-Chi Liang <ycliang@andestech.com>, Harsha Vardhan V M <h-vm@ti.com>,\n Weijie Gao <weijie.gao@mediatek.com>,\n Marek Vasut <marek.vasut+renesas@mailbox.org>,\n Patrice Chotard <patrice.chotard@foss.st.com>, Yao Zi <me@ziyao.cc>,\n Alif Zakuan Yuslaimi <alif.zakuan.yuslaimi@altera.com>,\n \"Lucien.Jheng\" <lucienzx159@gmail.com>, u-boot@lists.denx.de", "Subject": "[PATCH v5 5/6] misc: fw_loader: introduce FIP loader driver", "Date": "Fri, 3 Apr 2026 15:52:02 +0200", "Message-ID": "<20260403135205.26979-6-ansuelsmth@gmail.com>", "X-Mailer": "git-send-email 2.53.0", "In-Reply-To": "<20260403135205.26979-1-ansuelsmth@gmail.com>", "References": "<20260403135205.26979-1-ansuelsmth@gmail.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "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": "Introduce a variant of the FS loader driver to extract images from FIP\nimage. These image can contain additional binary used to init Network\naccelerator or PHY firmware blob.\n\nThe way FIP handle image type is with the usage of UUID.\n\nThis FIP loader driver implement a simple FIP image parser that check\nevery entry for a matching UUID.\n\nSimilar to FS loader, this driver also support both UBI and Block\ndevices.\n\nAlso an additional property is added to handle special case with eMMC\nthat doesn't have a GPT partition and require a global offset to\nreference the FIP partition.\n\nAn example usage of this driver is the following:\n\nEntry in DTS:\n\n\tfs_loader0: fip-loader {\n\t\tbootph-all;\n\t\tcompatible = \"u-boot,fip-loader\";\n\t\tphandlepart = <&mmc0 0>;\n\t\tpartoffset = <0x100>;\n\t};\n\n\tethernet@1fb50000 {\n\t\tfirmware-loader = <&fs_loader0>;\n\t}\n\nFIP loader user:\n\n\t/* get the FW loader from the ethernet node */\n\tget_fw_loader_from_node(dev_ofnode(dev), &fw_loader);\n\n\t/* read the blob identified by \"58704aef-389f-3e52-b475-e0bf2234a6a2\" UUID */\n\trequest_firmware_into_buf(fw_loader, \"58704aef-389f-3e52-b475-e0bf2234a6a2\",\n\t\t\t\t buf, 261400, 0);\n\nSigned-off-by: Christian Marangi <ansuelsmth@gmail.com>\n---\n drivers/misc/Kconfig | 11 +\n drivers/misc/fw_loader/Makefile | 1 +\n drivers/misc/fw_loader/fip_loader.c | 578 ++++++++++++++++++++++++++++\n drivers/misc/fw_loader/internal.h | 2 +\n include/dm/uclass-id.h | 3 +-\n 5 files changed, 594 insertions(+), 1 deletion(-)\n create mode 100644 drivers/misc/fw_loader/fip_loader.c", "diff": "diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig\nindex 58f1a4c07ff5..d56513b71cbb 100644\n--- a/drivers/misc/Kconfig\n+++ b/drivers/misc/Kconfig\n@@ -615,6 +615,17 @@ config MPC83XX_SERDES\n config FW_LOADER_LIB\n \tbool\n \n+config FIP_LOADER\n+\tbool \"Enable loader driver from FIP partition\"\n+\tselect LIB_UUID\n+\tselect FW_LOADER_DRV\n+\thelp\n+\t This is FIP partition generic loader which can be used to load\n+\t the file image from the FIP image into target such as memory.\n+\n+\t The consumer driver would then use this loader to program whatever,\n+\t ie. the FPGA device/PHY firmware.\n+\n config FS_LOADER\n \tbool \"Enable loader driver for file system\"\n \tselect FW_LOADER_DRV\ndiff --git a/drivers/misc/fw_loader/Makefile b/drivers/misc/fw_loader/Makefile\nindex 96baebede788..7854b64148e6 100644\n--- a/drivers/misc/fw_loader/Makefile\n+++ b/drivers/misc/fw_loader/Makefile\n@@ -1,4 +1,5 @@\n # SPDX-License-Identifier: GPL-2.0+\n \n obj-y += fw_loader.o\n+obj-$(CONFIG_FIP_LOADER) += fip_loader.o\n obj-$(CONFIG_$(PHASE_)FS_LOADER) += fs_loader.o\ndiff --git a/drivers/misc/fw_loader/fip_loader.c b/drivers/misc/fw_loader/fip_loader.c\nnew file mode 100644\nindex 000000000000..dac471d72af9\n--- /dev/null\n+++ b/drivers/misc/fw_loader/fip_loader.c\n@@ -0,0 +1,578 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * Copyright (C) 2025 Christian Marangi <ansuelsmth@gmail.com>\n+ *\n+ */\n+\n+#define LOG_CATEGORY UCLASS_FIP_FIRMWARE_LOADER\n+\n+#include <dm.h>\n+#include <div64.h>\n+#include <env.h>\n+#include <errno.h>\n+#include <blk.h>\n+#include <fs.h>\n+#include <linux/kernel.h>\n+#include <log.h>\n+#include <mapmem.h>\n+#include <malloc.h>\n+#include <memalign.h>\n+#include <part.h>\n+#include <u-boot/uuid.h>\n+\n+#include \"internal.h\"\n+\n+#define TOC_HEADER_NAME\t0xaa640001\n+\n+struct fip_toc_header {\n+\tu32 name;\n+\tu32 serial_number;\n+\tu64 flags;\n+};\n+\n+struct fip_toc_entry {\n+\tstruct uuid uuid;\n+\tu64 offset_address;\n+\tu64 size;\n+\tu64 flags;\n+};\n+\n+enum fip_storage_interface {\n+\tFIP_STORAGE_INTERFACE_BLK,\n+\tFIP_STORAGE_INTERFACE_UBI,\n+};\n+\n+struct fip_storage_info {\n+\tenum fip_storage_interface storage_interface;\n+\n+\t/* BLK info */\n+\tstruct disk_partition part_info;\n+\tstruct blk_desc *desc;\n+\tunsigned int part_offset;\n+\n+\t/* UBI info */\n+\tchar *ubi_volume;\n+};\n+\n+static bool validate_fip_toc_header(struct fip_toc_header *hdr)\n+{\n+\tif (hdr->name != TOC_HEADER_NAME) {\n+\t\tlog_err(\"Invalid FIP header\\n\");\n+\t\treturn false;\n+\t}\n+\n+\treturn true;\n+}\n+\n+static int firmware_name_to_uuid(struct firmware *firmwarep,\n+\t\t\t\t struct uuid *uuid)\n+{\n+\tconst char *uuid_str = firmwarep->name;\n+\tint ret;\n+\n+\tret = uuid_str_to_bin(uuid_str, (unsigned char *)uuid,\n+\t\t\t UUID_STR_FORMAT_STD);\n+\tif (ret)\n+\t\tlog_err(\"Invalid UUID str: %s\\n\", uuid_str);\n+\n+\treturn ret;\n+}\n+\n+static int check_fip_toc_entry(struct fip_toc_entry *ent,\n+\t\t\t struct uuid *uuid,\n+\t\t\t struct fip_toc_entry *dent)\n+{\n+\tstruct uuid uuid_null = { };\n+\n+\t/* NULL uuid. We parsed every entry */\n+\tif (!memcmp(&ent->uuid, &uuid_null, sizeof(uuid_null)))\n+\t\treturn -ENOENT;\n+\n+\t/* We found the related uuid */\n+\tif (!memcmp(&ent->uuid, uuid, sizeof(*uuid))) {\n+\t\tlog_debug(\"Found matching FIP entry. offset: 0x%llx size: %lld\\n\",\n+\t\t\t ent->offset_address, ent->size);\n+\t\tmemcpy(dent, ent, sizeof(*ent));\n+\t\treturn 0;\n+\t}\n+\n+\treturn -EAGAIN;\n+}\n+\n+static int blk_read_fip_toc_header(struct blk_desc *desc, u32 offset,\n+\t\t\t\t char *buf, struct fip_toc_header *hdr)\n+{\n+\tunsigned int blkcnt = BLOCK_CNT(sizeof(*hdr), desc);\n+\tunsigned long to_read;\n+\tsize_t read = 0;\n+\tint i, ret;\n+\n+\tfor (i = 0; i < blkcnt && read < sizeof(*hdr); i++) {\n+\t\tto_read = min(desc->blksz,\n+\t\t\t (unsigned long)(sizeof(*hdr) - read));\n+\n+\t\tret = blk_dread(desc, offset + i, 1, buf);\n+\t\tif (ret != 1)\n+\t\t\treturn -EINVAL;\n+\n+\t\tmemcpy((u8 *)hdr + read, buf, to_read);\n+\t\tread += to_read;\n+\t}\n+\n+\treturn read;\n+}\n+\n+static int blk_read_fip_toc_entry(struct blk_desc *desc, u32 offset,\n+\t\t\t\t int pos, char *buf,\n+\t\t\t\t struct fip_toc_entry *ent)\n+{\n+\tunsigned long left, consumed, to_read, read = 0;\n+\tunsigned int blkstart, blkcnt;\n+\tint i, ret;\n+\n+\tconsumed = pos % desc->blksz;\n+\tleft = desc->blksz - consumed;\n+\tto_read = min(left, (unsigned long)sizeof(*ent));\n+\n+\tblkstart = BLOCK_CNT(pos, desc);\n+\tblkcnt = BLOCK_CNT(sizeof(*ent) - to_read, desc);\n+\n+\t/* Read data from previous cached block if present */\n+\tif (left) {\n+\t\tmemcpy(ent, buf + consumed, to_read);\n+\t\tread += to_read;\n+\t}\n+\n+\tfor (i = 0; i < blkcnt && read < sizeof(*ent); i++) {\n+\t\tto_read = min(desc->blksz,\n+\t\t\t (unsigned long)(sizeof(*ent) - read));\n+\n+\t\tret = blk_dread(desc, offset + blkstart + i, 1, buf);\n+\t\tif (ret != 1)\n+\t\t\treturn -EINVAL;\n+\n+\t\tmemcpy((u8 *)ent + read, buf, to_read);\n+\t\tread += to_read;\n+\t}\n+\n+\treturn read;\n+}\n+\n+static int blk_parse_fip_firmware(struct firmware *firmwarep,\n+\t\t\t\t struct blk_desc *desc,\n+\t\t\t\t struct disk_partition *part_info,\n+\t\t\t\t unsigned int part_offset,\n+\t\t\t\t struct fip_toc_entry *dent)\n+{\n+\tunsigned int offset = part_info->start + part_offset;\n+\tstruct fip_toc_header hdr;\n+\tstruct fip_toc_entry ent;\n+\tstruct uuid uuid;\n+\tunsigned int pos;\n+\tchar *read_buf;\n+\tint ret;\n+\n+\t/* Allocate a Scratch Buffer for FIP parsing */\n+\tread_buf = malloc(desc->blksz);\n+\tif (!read_buf)\n+\t\treturn -ENOMEM;\n+\n+\tret = blk_read_fip_toc_header(desc, offset, read_buf, &hdr);\n+\tif (ret < 0) {\n+\t\tret = -EINVAL;\n+\t\tgoto out;\n+\t}\n+\n+\tpos = ret;\n+\n+\tif (!validate_fip_toc_header(&hdr)) {\n+\t\tret = -EINVAL;\n+\t\tgoto out;\n+\t}\n+\n+\tret = firmware_name_to_uuid(firmwarep, &uuid);\n+\tif (ret)\n+\t\tgoto out;\n+\n+\t/* Loop for every FIP entry searching for uuid */\n+\twhile (true) {\n+\t\tret = blk_read_fip_toc_entry(desc, offset, pos,\n+\t\t\t\t\t read_buf, &ent);\n+\t\tif (ret < 0)\n+\t\t\tgoto out;\n+\n+\t\tpos += ret;\n+\n+\t\tret = check_fip_toc_entry(&ent, &uuid, dent);\n+\t\tif (ret != -EAGAIN)\n+\t\t\tbreak;\n+\t}\n+\n+out:\n+\tfree(read_buf);\n+\treturn ret;\n+}\n+\n+#ifdef CONFIG_CMD_UBIFS\n+static int ubi_parse_fip_firmware(struct firmware *firmwarep,\n+\t\t\t\t char *ubi_vol,\n+\t\t\t\t struct fip_toc_entry *dent)\n+{\n+\tstruct fip_toc_header hdr;\n+\tstruct fip_toc_entry ent;\n+\tstruct uuid uuid;\n+\tunsigned int pos;\n+\tint ret;\n+\n+\tret = ubi_volume_read(ubi_vol, (char *)&hdr, 0, sizeof(hdr));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tpos = sizeof(hdr);\n+\n+\tif (!validate_fip_toc_header(&hdr))\n+\t\treturn -EINVAL;\n+\n+\tret = firmware_name_to_uuid(firmwarep, &uuid);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* Loop for every FIP entry searching for uuid */\n+\twhile (true) {\n+\t\tret = ubi_volume_read(ubi_vol, (char *)&ent, pos,\n+\t\t\t\t sizeof(ent));\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tret = check_fip_toc_entry(&ent, &uuid, dent);\n+\t\tif (ret != -EAGAIN)\n+\t\t\tbreak;\n+\n+\t\tpos += sizeof(ent);\n+\t}\n+\n+\treturn ret;\n+}\n+#endif\n+\n+static int parse_fip_firmware(struct firmware *firmwarep,\n+\t\t\t struct fip_storage_info *info,\n+\t\t\t struct fip_toc_entry *dent)\n+{\n+\tswitch (info->storage_interface) {\n+\tcase FIP_STORAGE_INTERFACE_BLK:\n+\t\treturn blk_parse_fip_firmware(firmwarep, info->desc,\n+\t\t\t\t\t &info->part_info,\n+\t\t\t\t\t info->part_offset,\n+\t\t\t\t\t dent);\n+#ifdef CONFIG_CMD_UBIFS\n+\tcase FIP_STORAGE_INTERFACE_UBI:\n+\t\treturn ubi_parse_fip_firmware(firmwarep,\n+\t\t\t\t\t info->ubi_volume,\n+\t\t\t\t\t dent);\n+#endif\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\n+\n+static int blk_read_fip_firmware(struct firmware *firmwarep,\n+\t\t\t\t struct blk_desc *desc,\n+\t\t\t\t struct disk_partition *part_info,\n+\t\t\t\t unsigned int part_offset,\n+\t\t\t\t const struct fip_toc_entry *ent)\n+{\n+\tunsigned int offset = part_info->start + part_offset;\n+\tunsigned long pos, to_read, read = 0;\n+\tunsigned long long blkstart;\n+\tsize_t size = ent->size;\n+\tunsigned int blkcnt;\n+\tchar *read_buf;\n+\tint i, ret;\n+\n+\tread_buf = malloc(desc->blksz);\n+\tif (!read_buf)\n+\t\treturn -ENOMEM;\n+\n+\tblkcnt = BLOCK_CNT(size + firmwarep->offset, desc);\n+\tblkstart = ent->offset_address + firmwarep->offset;\n+\tpos = do_div(blkstart, desc->blksz);\n+\n+\t/* Read data in the middle of a block */\n+\tif (pos) {\n+\t\tto_read = min(desc->blksz - pos, (unsigned long)size);\n+\t\tret = blk_dread(desc, offset + blkstart, 1, read_buf);\n+\t\tif (ret != 1) {\n+\t\t\tret = -EINVAL;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tmemcpy((u8 *)firmwarep->data, read_buf + pos, to_read);\n+\t\tread += to_read;\n+\t\tblkstart++;\n+\t}\n+\n+\t/* Consume all the remaining block */\n+\tfor (i = 0; i < blkcnt && read < size; i++) {\n+\t\tto_read = min(desc->blksz, (unsigned long)(size - read));\n+\t\tret = blk_dread(desc, offset + blkstart + i, 1, read_buf);\n+\t\tif (ret != 1) {\n+\t\t\tret = -EINVAL;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tmemcpy((u8 *)firmwarep->data + read, read_buf, to_read);\n+\t\tread += to_read;\n+\t}\n+\n+\tret = read;\n+\n+out:\n+\tfree(read_buf);\n+\treturn ret;\n+}\n+\n+#ifdef CONFIG_CMD_UBIFS\n+static int ubi_read_fip_firmware(struct firmware *firmwarep,\n+\t\t\t\t char *ubi_vol,\n+\t\t\t\t const struct fip_toc_entry *ent)\n+{\n+\tunsigned int offset = firmwarep->offset;\n+\tsize_t size = ent->size;\n+\tint ret;\n+\n+\tret = ubi_volume_read(ubi_vol,\n+\t\t\t (u8 *)firmwarep->data,\n+\t\t\t ent->offset_address + offset,\n+\t\t\t size - offset);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn size - firmwarep->offset;\n+}\n+#endif\n+\n+static int read_fip_firmware(struct firmware *firmwarep,\n+\t\t\t struct fip_storage_info *info,\n+\t\t\t const struct fip_toc_entry *dent)\n+{\n+\tswitch (info->storage_interface) {\n+\tcase FIP_STORAGE_INTERFACE_BLK:\n+\t\treturn blk_read_fip_firmware(firmwarep, info->desc,\n+\t\t\t\t\t &info->part_info,\n+\t\t\t\t\t info->part_offset,\n+\t\t\t\t\t dent);\n+#ifdef CONFIG_CMD_UBIFS\n+\tcase FIP_STORAGE_INTERFACE_UBI:\n+\t\treturn ubi_read_fip_firmware(firmwarep,\n+\t\t\t\t\t info->ubi_volume,\n+\t\t\t\t\t dent);\n+#endif\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\n+\n+static int fw_parse_storage_info(struct udevice *dev,\n+\t\t\t\t struct fip_storage_info *info)\n+{\n+\tchar *storage_interface, *dev_part, *ubi_mtdpart, *ubi_volume;\n+\tstruct device_plat *plat = dev_get_plat(dev);\n+\tint ret;\n+\n+\tstorage_interface = env_get(\"storage_interface\");\n+\tdev_part = env_get(\"fw_dev_part\");\n+\tubi_mtdpart = env_get(\"fw_ubi_mtdpart\");\n+\tubi_volume = env_get(\"fw_ubi_volume\");\n+\tinfo->part_offset = env_get_hex(\"fw_partoffset\", 0);\n+\n+\tif (storage_interface && dev_part) {\n+\t\tint part;\n+\n+\t\tpart = part_get_info_by_dev_and_name_or_num(storage_interface,\n+\t\t\t\t\t\t\t dev_part,\n+\t\t\t\t\t\t\t &info->desc,\n+\t\t\t\t\t\t\t &info->part_info, 1);\n+\t\tif (part < 0)\n+\t\t\treturn part;\n+\n+\t\tinfo->storage_interface = FIP_STORAGE_INTERFACE_BLK;\n+\n+\t\treturn 0;\n+\t}\n+\n+\tif (storage_interface && ubi_mtdpart && ubi_volume) {\n+\t\tif (strcmp(\"ubi\", storage_interface))\n+\t\t\treturn -ENODEV;\n+\n+\t\tret = generic_fw_loader_ubi_select(ubi_mtdpart);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tinfo->ubi_volume = ubi_volume;\n+\t\tinfo->storage_interface = FIP_STORAGE_INTERFACE_UBI;\n+\n+\t\treturn 0;\n+\t}\n+\n+\tinfo->part_offset = plat->partoffset;\n+\n+\tif (plat->phandlepart.phandle) {\n+\t\tstruct udevice *disk_dev;\n+\t\tofnode node;\n+\t\tint part;\n+\n+\t\tnode = ofnode_get_by_phandle(plat->phandlepart.phandle);\n+\n+\t\tret = device_get_global_by_ofnode(node, &disk_dev);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tinfo->desc = blk_get_by_device(disk_dev);\n+\t\tif (!info->desc)\n+\t\t\treturn -ENODEV;\n+\n+\t\tpart = plat->phandlepart.partition;\n+\t\tif (part >= 1)\n+\t\t\tret = part_get_info(info->desc, part,\n+\t\t\t\t\t &info->part_info);\n+\t\telse\n+\t\t\tret = part_get_info_whole_disk(info->desc,\n+\t\t\t\t\t\t &info->part_info);\n+\n+\t\tinfo->storage_interface = FIP_STORAGE_INTERFACE_BLK;\n+\n+\t\treturn ret;\n+\t}\n+\n+\tif (plat->mtdpart && plat->ubivol) {\n+\t\tret = generic_fw_loader_ubi_select(plat->mtdpart);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tinfo->ubi_volume = plat->ubivol;\n+\t\tinfo->storage_interface = FIP_STORAGE_INTERFACE_UBI;\n+\n+\t\treturn 0;\n+\t}\n+\n+\treturn -EINVAL;\n+}\n+\n+/**\n+ * fw_get_fip_firmware - load firmware into an allocated buffer.\n+ * @dev: An instance of a driver.\n+ *\n+ * Return: Size of total read, negative value when error.\n+ */\n+static int fw_get_fip_firmware(struct udevice *dev)\n+{\n+\tstruct fip_toc_entry ent;\n+\tstruct fip_storage_info info = { };\n+\tint ret;\n+\n+\tret = fw_parse_storage_info(dev, &info);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tstruct firmware *firmwarep = dev_get_priv(dev);\n+\n+\tif (!firmwarep)\n+\t\treturn -EINVAL;\n+\n+\tret = parse_fip_firmware(firmwarep, &info, &ent);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (ent.size + firmwarep->offset > firmwarep->size) {\n+\t\tlog_err(\"Not enough space to read firmware\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tret = read_fip_firmware(firmwarep, &info, &ent);\n+\tif (ret < 0)\n+\t\tlog_err(\"Failed to read %s from FIP: %d.\\n\",\n+\t\t\tfirmwarep->name, ret);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * fw_get_fip_firmware_size - get firmware size.\n+ * @dev: An instance of a driver.\n+ *\n+ * Return: Size of firmware, negative value when error.\n+ */\n+static int fw_get_fip_firmware_size(struct udevice *dev)\n+{\n+\tstruct fip_toc_entry ent;\n+\tstruct fip_storage_info info = { };\n+\tint ret;\n+\n+\tret = fw_parse_storage_info(dev, &info);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tstruct firmware *firmwarep = dev_get_priv(dev);\n+\n+\tif (!firmwarep)\n+\t\treturn -EINVAL;\n+\n+\tret = parse_fip_firmware(firmwarep, &info, &ent);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn ent.size;\n+}\n+\n+static int fip_loader_probe(struct udevice *dev)\n+{\n+\tstruct device_plat *plat = dev_get_plat(dev);\n+\tint ret;\n+\n+\tret = generic_fw_loader_probe(dev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tplat->get_firmware = fw_get_fip_firmware;\n+\tplat->get_size = fw_get_fip_firmware_size;\n+\n+\treturn 0;\n+};\n+\n+static int fip_loader_of_to_plat(struct udevice *dev)\n+{\n+\tstruct device_plat *plat = dev_get_plat(dev);\n+\tofnode fip_loader_node = dev_ofnode(dev);\n+\tint ret;\n+\n+\tret = generic_fw_loader_of_to_plat(dev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* Node validation is already done by the generic function */\n+\tofnode_read_u32(fip_loader_node, \"partoffset\",\n+\t\t\t&plat->partoffset);\n+\n+\treturn 0;\n+}\n+\n+static const struct udevice_id fip_loader_ids[] = {\n+\t{ .compatible = \"u-boot,fip-loader\"},\n+\t{ }\n+};\n+\n+U_BOOT_DRIVER(fip_loader) = {\n+\t.name\t\t= \"fip-loader\",\n+\t.id\t\t= UCLASS_FIP_FIRMWARE_LOADER,\n+\t.of_match\t= fip_loader_ids,\n+\t.probe\t\t= fip_loader_probe,\n+\t.of_to_plat\t= fip_loader_of_to_plat,\n+\t.plat_auto\t= sizeof(struct device_plat),\n+\t.priv_auto\t= sizeof(struct firmware),\n+};\n+\n+UCLASS_DRIVER(fip_loader) = {\n+\t.id\t\t= UCLASS_FIP_FIRMWARE_LOADER,\n+\t.name\t\t= \"fip-loader\",\n+};\ndiff --git a/drivers/misc/fw_loader/internal.h b/drivers/misc/fw_loader/internal.h\nindex a94de609d0b6..d823d56e53f5 100644\n--- a/drivers/misc/fw_loader/internal.h\n+++ b/drivers/misc/fw_loader/internal.h\n@@ -25,11 +25,13 @@ struct phandle_part {\n * This holds information about all supported storage devices for driver use.\n *\n * @phandlepart: Attribute data for block device.\n+ * @partoffset: Global offset for BLK partition.\n * @mtdpart: MTD partition for ubi partition.\n * @ubivol: UBI volume-name for ubifsmount.\n */\n struct device_plat {\n \tstruct phandle_part phandlepart;\n+\tint partoffset;\n \tchar *mtdpart;\n \tchar *ubivol;\n \ndiff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h\nindex 36b5d87c304f..641d8e1e42fa 100644\n--- a/include/dm/uclass-id.h\n+++ b/include/dm/uclass-id.h\n@@ -69,7 +69,8 @@ enum uclass_id {\n \tUCLASS_FIRMWARE,\t/* Firmware */\n \tUCLASS_FPGA,\t\t/* FPGA device */\n \tUCLASS_FUZZING_ENGINE,\t/* Fuzzing engine */\n-\tUCLASS_FS_FIRMWARE_LOADER,\t\t/* Generic loader */\n+\tUCLASS_FIP_FIRMWARE_LOADER, /* FIP image loader */\n+\tUCLASS_FS_FIRMWARE_LOADER, /* Generic loader */\n \tUCLASS_FWU_MDATA,\t/* FWU Metadata Access */\n \tUCLASS_GPIO,\t\t/* Bank of general-purpose I/O pins */\n \tUCLASS_HASH,\t\t/* Hash device */\n", "prefixes": [ "v5", "5/6" ] }