get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2217983/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2217983,
    "url": "http://patchwork.ozlabs.org/api/patches/2217983/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20260331075338.2391-5-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": "<20260331075338.2391-5-ansuelsmth@gmail.com>",
    "list_archive_url": null,
    "date": "2026-03-31T07:53:23",
    "name": "[v4,4/5] misc: fw_loader: introduce FIP loader driver",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "2e3e8eccc7dc61fb29a60587adc7abfc80503478",
    "submitter": {
        "id": 71108,
        "url": "http://patchwork.ozlabs.org/api/people/71108/?format=api",
        "name": "Christian Marangi",
        "email": "ansuelsmth@gmail.com"
    },
    "delegate": {
        "id": 3651,
        "url": "http://patchwork.ozlabs.org/api/users/3651/?format=api",
        "username": "trini",
        "first_name": "Tom",
        "last_name": "Rini",
        "email": "trini@ti.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20260331075338.2391-5-ansuelsmth@gmail.com/mbox/",
    "series": [
        {
            "id": 498136,
            "url": "http://patchwork.ozlabs.org/api/series/498136/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=498136",
            "date": "2026-03-31T07:53:19",
            "name": "misc: fs_loader: reorg and split to FS and FW loader + FIP loader",
            "version": 4,
            "mbox": "http://patchwork.ozlabs.org/series/498136/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2217983/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2217983/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=GafOoqAw;\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=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=\"GafOoqAw\";\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 [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 4flL461wrnz1xtJ\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 31 Mar 2026 18:54:30 +1100 (AEDT)",
            "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id 589008405B;\n\tTue, 31 Mar 2026 09:54:02 +0200 (CEST)",
            "by phobos.denx.de (Postfix, from userid 109)\n id D380084073; Tue, 31 Mar 2026 09:53:56 +0200 (CEST)",
            "from mail-wm1-x336.google.com (mail-wm1-x336.google.com\n [IPv6:2a00:1450:4864:20::336])\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 773218403D\n for <u-boot@lists.denx.de>; Tue, 31 Mar 2026 09:53:54 +0200 (CEST)",
            "by mail-wm1-x336.google.com with SMTP id\n 5b1f17b1804b1-4852c9b4158so42605255e9.0\n for <u-boot@lists.denx.de>; Tue, 31 Mar 2026 00:53:54 -0700 (PDT)",
            "from Ansuel-XPS24 (93-34-88-122.ip49.fastwebnet.it. [93.34.88.122])\n by smtp.googlemail.com with ESMTPSA id\n 5b1f17b1804b1-4887c561750sm23889915e9.2.2026.03.31.00.53.52\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 31 Mar 2026 00:53:52 -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=1774943634; x=1775548434; 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=ZdK7lHVgvkvGAem1Zj4MpCHRl9+c1nVNg70PTSmVryc=;\n b=GafOoqAwTMMvhL/altqo7lVu+RBucjVVQPWMBhBKnY79WqyHlmkOyP/qzfb33a85XQ\n XWKqQVeXBxXQCo+h7tig52IMSfvC+TPMaACQDH1Jmm79sSKJCPYwPTRpNvw3oslEbGGs\n I7iLUHVi4Hq0+vVghr397GZWX3bYG/qjpq8zYYeTMRRfT9uPNgzDXSvt8I/GmasClKjV\n JtOt8aK6GqsBCE5ku9/INY0jsd3H5f4kR2XHd3ZZjZZjQXFveX79GXVm99fsF6XzmymC\n gl7uoQc/yE9CP+DSLkYIg6jtnQygudJRIEW5Th4UYJPmkVxBgFkhptmeNRNrKpC/ua2Y\n kQGg==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1774943634; x=1775548434;\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=ZdK7lHVgvkvGAem1Zj4MpCHRl9+c1nVNg70PTSmVryc=;\n b=mcHEM2XyS538MOvBinHU/uOUUxxNdVhqRqhG4yS053/asjR0z5/MMp6JAn3RIgqxu0\n /bitURBDsuOX3aDhVHbH4F3s1PkHYianWL2OaLq2D4gcGJVeoPCVslvzluSj8TXUnutn\n nyV+uxnn1claItuwDcmd3Gj1nR+j/Deeck/NDxyShARB93g11am4qEsChtHXqde4LVoe\n NdchgJl22P//ZtCqtORmh/lWjFQQORZHKdCelr7LEJmK55VcVPQZcQr/2VOneZV2mwbI\n cTKbj5XSFRu+2IfhqXsp03CJ5Zm374LfhErXPp7ChDQj5rZcR5EgnNovBfmhb9Fr4FkD\n S6CQ==",
        "X-Forwarded-Encrypted": "i=1;\n AJvYcCXXWv8eueHXXVhDIRkAfQTJfIcAWfWiy1fgYEI+DasoHXor6N2xY0eKtc5lo/xX4NB2143CT3M=@lists.denx.de",
        "X-Gm-Message-State": "AOJu0Yw9Wf+Rn4XPxtAD6u4s5pftl0oYh5mcamJCnljiog/he1LtLW6y\n gy3ShAYiO8SLxRvOek8C2EjDoHkh0U9jJMYhdJwirfX0/BBtH/RxU3p6",
        "X-Gm-Gg": "ATEYQzxk7NjqicqIzykVHG+XaIMI15FN3mR/z3SzsCoCO3cy+RrQqnDY6KL3DVgId1X\n 9paaMWG0HL9sZ3GMpTWjgLLyzOsAwIvu2k4HTrF6wEMoIa/8BgbxfH55qSzvu6wuRulB7YPhRMd\n rgCwSqHHeqz2UXZWpYLQC8U4aoFuCh0bEKpgHe+YLNkBgk60ERqM4utd3G5n39v7SUDgP2lcBYC\n 4+IU6SFu4UhNkiJZbuAaMtrjIGQIbS2X2f5FkdepmckmabFY9koYzORD+fr5EH45CxwEs1x82WV\n ucL8jqAdNUW4iEzmjD/2APiUoRBSY5JUGDHa/Yz+lI1wQ1QoyTq3ZO8XzHviNW7yIicogOG3kNV\n +51rb7U1WVOP7dyBvMte6liJqRzNqR9jTevsu+REHRUWxtRr5f4czD7jUOX6YrCFb84iunazymy\n xpdb5tqZiq2q5YIxlqXK/JNo0jzl7O2zPNwFkASsGCgO13NJMjQWRmIx4xQ6qb/YVk3A==",
        "X-Received": "by 2002:a05:600c:1c1d:b0:485:3cf3:1010 with SMTP id\n 5b1f17b1804b1-48727d458fcmr12645275e9.2.1774943633394;\n Tue, 31 Mar 2026 00:53:53 -0700 (PDT)",
        "From": "Christian Marangi <ansuelsmth@gmail.com>",
        "To": "Tom Rini <trini@konsulko.com>, Simon Glass <sjg@chromium.org>,\n Casey Connolly <casey.connolly@linaro.org>,\n Quentin Schulz <quentin.schulz@cherry.de>,\n Christian Marangi <ansuelsmth@gmail.com>, Peng Fan <peng.fan@nxp.com>,\n Ilias Apalodimas <ilias.apalodimas@linaro.org>,\n Chen-Yu Tsai <wens@kernel.org>,\n Jamie Gibbons <jamie.gibbons@microchip.com>,\n Neha Malcom Francis <n-francis@ti.com>,\n Justin Klaassen <justin@tidylabs.net>, Harsha Vardhan V M <h-vm@ti.com>,\n Leo Yu-Chi Liang <ycliang@andestech.com>,\n Weijie Gao <weijie.gao@mediatek.com>,\n Marek Vasut <marek.vasut+renesas@mailbox.org>,\n Alif Zakuan Yuslaimi <alif.zakuan.yuslaimi@altera.com>,\n Sky Huang <SkyLake.Huang@mediatek.com>,\n \"Lucien.Jheng\" <lucienzx159@gmail.com>, u-boot@lists.denx.de",
        "Subject": "[PATCH v4 4/5] misc: fw_loader: introduce FIP loader driver",
        "Date": "Tue, 31 Mar 2026 09:53:23 +0200",
        "Message-ID": "<20260331075338.2391-5-ansuelsmth@gmail.com>",
        "X-Mailer": "git-send-email 2.53.0",
        "In-Reply-To": "<20260331075338.2391-1-ansuelsmth@gmail.com>",
        "References": "<20260331075338.2391-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\naccellerator 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 | 547 ++++++++++++++++++++++++++++\n drivers/misc/fw_loader/fw_loader.c  |   3 +\n drivers/misc/fw_loader/internal.h   |   2 +\n include/dm/uclass-id.h              |   3 +-\n 6 files changed, 566 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 818f93413b6b..5dbcf0da38e7 100644\n--- a/drivers/misc/Kconfig\n+++ b/drivers/misc/Kconfig\n@@ -615,6 +615,17 @@ config MPC83XX_SERDES\n config FW_LOADER\n \tbool\n \n+config FIP_LOADER\n+\tbool \"Enable loader driver from FIP partition\"\n+\tselect LIB_UUID\n+\tselect FW_LOADER\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\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..5c01013276d7\n--- /dev/null\n+++ b/drivers/misc/fw_loader/fip_loader.c\n@@ -0,0 +1,547 @@\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 <fs_loader.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 MIN(a, b) ((a) < (b) ? (a) : (b))\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+\tsize_t read = 0;\n+\tint i, ret;\n+\n+\tfor (i = 0; i < blkcnt && read < sizeof(*hdr); i++) {\n+\t\tunsigned int to_read = MIN(desc->blksz,\n+\t\t\t\t\t   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 int 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, 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, 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+\tpos = blk_read_fip_toc_header(desc, offset, read_buf, &hdr);\n+\tif (pos < 0) {\n+\t\tret = -EINVAL;\n+\t\tgoto out;\n+\t}\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 int 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, 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, 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+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+\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/fw_loader.c b/drivers/misc/fw_loader/fw_loader.c\nindex 2738d42d4721..26c2ce406ac9 100644\n--- a/drivers/misc/fw_loader/fw_loader.c\n+++ b/drivers/misc/fw_loader/fw_loader.c\n@@ -95,6 +95,9 @@ static int fw_loaders[] = {\n #if CONFIG_IS_ENABLED(FS_LOADER)\n \tUCLASS_FS_FIRMWARE_LOADER,\n #endif\n+#if CONFIG_IS_ENABLED(FIP_LOADER)\n+\tUCLASS_FIP_FIRMWARE_LOADER,\n+#endif\n };\n \n /**\ndiff --git a/drivers/misc/fw_loader/internal.h b/drivers/misc/fw_loader/internal.h\nindex fa006b7e6077..9e7585a92808 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": [
        "v4",
        "4/5"
    ]
}