new file mode 100644
@@ -0,0 +1,63 @@
+From 16f183e3c09d64fee92638ea9d0017ac7973ddf8 Mon Sep 17 00:00:00 2001
+From: Tudor Cretu <tudor.cretu@arm.com>
+Date: Fri, 24 Sep 2021 12:09:53 +0000
+Subject: [PATCH 1/2] feat(plat/tc): add firmware update secure partition
+
+Firmware update is a trusted service secure partition that implements
+the PSA firmware update specification. It executes in the secure world
+in total compute platform.
+
+Signed-off-by: Davidson K <davidson.kumaresan@arm.com>
+Signed-off-by: Tudor Cretu <tudor.cretu@arm.com>
+Change-Id: I6223d247b078de8c03b068185bf120b3d502f500
+Upstream-Status: Pending [Not submitted to upstream yet]
+---
+ plat/arm/board/tc/fdts/tc_spmc_optee_sp_manifest.dts | 9 ++++++++-
+ plat/arm/board/tc/fdts/tc_tb_fw_config.dts | 4 ++++
+ 2 files changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/plat/arm/board/tc/fdts/tc_spmc_optee_sp_manifest.dts b/plat/arm/board/tc/fdts/tc_spmc_optee_sp_manifest.dts
+index 92e2ddda6..23ad06888 100644
+--- a/plat/arm/board/tc/fdts/tc_spmc_optee_sp_manifest.dts
++++ b/plat/arm/board/tc/fdts/tc_spmc_optee_sp_manifest.dts
+@@ -28,7 +28,7 @@
+ load_address = <0xfd280000>;
+ vcpu_count = <8>;
+ #ifdef TS_SP_FW_CONFIG
+- mem_size = <26738688>; /* 25MB TZC DRAM */
++ mem_size = <20447232>; /* 19MB TZC DRAM */
+ #else
+ mem_size = <30928896>; /* 29MB TZC DRAM */
+ #endif
+@@ -48,6 +48,13 @@
+ vcpu_count = <1>;
+ mem_size = <2097152>; /* 2MB TZC DRAM */
+ };
++ vm4 {
++ is_ffa_partition;
++ debug_name = "firmware-update";
++ load_address = <0xfe600000>;
++ vcpu_count = <1>;
++ mem_size = <6291456>; /* 6MB TZC DRAM */
++ };
+ #endif
+ };
+
+diff --git a/plat/arm/board/tc/fdts/tc_tb_fw_config.dts b/plat/arm/board/tc/fdts/tc_tb_fw_config.dts
+index a5bb520fe..2c640b363 100644
+--- a/plat/arm/board/tc/fdts/tc_tb_fw_config.dts
++++ b/plat/arm/board/tc/fdts/tc_tb_fw_config.dts
+@@ -41,6 +41,10 @@
+ uuid = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0";
+ load-address = <0xfec00000>;
+ };
++ firmware-update {
++ uuid = "6823a838-1b06-470e-9774-0cce8bfb53fd";
++ load-address = <0xfe600000>;
++ };
+ #endif
+ #if OPTEE_SP_FW_CONFIG
+ op-tee {
+--
+2.34.1
+
new file mode 100644
@@ -0,0 +1,35 @@
+From a8cdd6c67d26c15642338a45279db5e39cf4e565 Mon Sep 17 00:00:00 2001
+From: Davidson K <davidson.kumaresan@arm.com>
+Date: Fri, 3 Jun 2022 18:16:31 +0530
+Subject: [PATCH 2/2] feat(plat/tc): reserve 4 MB for stmm communication used
+ for firmware update
+
+The firmware update secure partition and u-boot communicates using
+the stmm communication layer and it needs a dedicated memory region.
+
+Signed-off-by: Davidson K <davidson.kumaresan@arm.com>
+Change-Id: I8d4da5c26843d225983dcaee0757694a6d43234c
+Upstream-Status: Pending [Not submitted to upstream yet]
+---
+ fdts/tc.dts | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/fdts/tc.dts b/fdts/tc.dts
+index dc86958bf..cb504c4a2 100644
+--- a/fdts/tc.dts
++++ b/fdts/tc.dts
+@@ -217,6 +217,11 @@
+ reg = <0x00000000 0xf8e00000 0 0x00200000>;
+ no-map;
+ };
++
++ fwu_mm@0xfca00000 {
++ reg = <0x00000000 0xfca00000 0 0x00400000>;
++ no-map;
++ };
+ };
+
+ psci {
+--
+2.34.1
+
@@ -15,6 +15,8 @@ SRC_URI:append = " \
file://0005-feat-plat-tc-add-spmc-manifest-with-trusty-sp.patch \
file://0006-feat-plat-tc-update-dts-with-trusty-compatible-strin.patch \
file://0007-feat-arm-tc-Update-trusty-load-address-in-dts-files.patch \
+ file://0008-feat-plat-tc-add-firmware-update-secure-partition.patch \
+ file://0009-feat-plat-tc-reserve-4-MB-for-stmm-communication-use.patch \
file://generate_metadata.py \
"
new file mode 100644
@@ -0,0 +1,2611 @@
+From 42fd69fb5ec0c441b3d31ec544ed03bedab28d45 Mon Sep 17 00:00:00 2001
+From: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+Date: Tue, 16 Nov 2021 12:34:52 +0000
+Subject: [PATCH 2/7] arm_ffa: introducing Arm FF-A low-level driver
+
+This driver implements Arm Firmware Framework for Armv8-A on u-boot
+
+The Firmware Framework for Arm A-profile processors (FF-A)
+describes interfaces (ABIs) that standardize communication
+between the Secure World and Normal World leveraging TrustZone
+technology.
+
+This driver is based on FF-A specification v1.0 and uses SMC32
+calling convention.
+
+FF-A specification:
+
+https://developer.arm.com/documentation/den0077/a/?lang=en
+
+The driver provides helper FF-A interfaces for user layers.
+These helper functions allow clients to pass data and select the
+FF-A function to use for the communication with secure world.
+
+Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
+Upstream-Status: Submitted [https://patchwork.ozlabs.org/project/uboot/patch/20220801172053.20163-4-abdellatif.elkhlifi@arm.com/]
+---
+ MAINTAINERS | 8 +
+ arch/arm/cpu/armv8/smccc-call.S | 27 +
+ arch/arm/lib/asm-offsets.c | 6 +
+ common/board_r.c | 6 +
+ drivers/Kconfig | 2 +
+ drivers/Makefile | 1 +
+ drivers/arm-ffa/Kconfig | 26 +
+ drivers/arm-ffa/Makefile | 3 +
+ drivers/arm-ffa/arm-ffa-uclass.c | 67 ++
+ drivers/arm-ffa/arm_ffa_prv.h | 199 ++++
+ drivers/arm-ffa/core.c | 1484 ++++++++++++++++++++++++++++++
+ include/arm_ffa.h | 191 ++++
+ include/arm_ffa_helper.h | 45 +
+ include/dm/uclass-id.h | 1 +
+ include/linux/arm-smccc.h | 28 +-
+ lib/Kconfig | 1 +
+ lib/Makefile | 1 +
+ lib/arm-ffa/Kconfig | 6 +
+ lib/arm-ffa/Makefile | 8 +
+ lib/arm-ffa/arm_ffa_helper.c | 188 ++++
+ lib/efi_loader/efi_boottime.c | 17 +
+ 21 files changed, 2314 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/arm-ffa/Kconfig
+ create mode 100644 drivers/arm-ffa/Makefile
+ create mode 100644 drivers/arm-ffa/arm-ffa-uclass.c
+ create mode 100644 drivers/arm-ffa/arm_ffa_prv.h
+ create mode 100644 drivers/arm-ffa/core.c
+ create mode 100644 include/arm_ffa.h
+ create mode 100644 include/arm_ffa_helper.h
+ create mode 100644 lib/arm-ffa/Kconfig
+ create mode 100644 lib/arm-ffa/Makefile
+ create mode 100644 lib/arm-ffa/arm_ffa_helper.c
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 96582fc677..14307e6da6 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -232,6 +232,14 @@ F: board/CZ.NIC/
+ F: configs/turris_*_defconfig
+ F: include/configs/turris_*.h
+
++ARM FF-A
++M: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
++S: Maintained
++F: drivers/arm-ffa/
++F: include/arm_ffa.h
++F: include/arm_ffa_helper.h
++F: lib/arm-ffa/
++
+ ARM FREESCALE IMX
+ M: Stefano Babic <sbabic@denx.de>
+ M: Fabio Estevam <festevam@gmail.com>
+diff --git a/arch/arm/cpu/armv8/smccc-call.S b/arch/arm/cpu/armv8/smccc-call.S
+index dc92b28777..ffc39c9fef 100644
+--- a/arch/arm/cpu/armv8/smccc-call.S
++++ b/arch/arm/cpu/armv8/smccc-call.S
+@@ -1,6 +1,8 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+ /*
+ * Copyright (c) 2015, Linaro Limited
++ * (C) Copyright 2021 ARM Limited
++ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ */
+ #include <linux/linkage.h>
+ #include <linux/arm-smccc.h>
+@@ -45,3 +47,28 @@ ENDPROC(__arm_smccc_smc)
+ ENTRY(__arm_smccc_hvc)
+ SMCCC hvc
+ ENDPROC(__arm_smccc_hvc)
++
++#if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT))
++
++ .macro FFASMCCC instr
++ .cfi_startproc
++ \instr #0
++ ldr x9, [sp]
++ stp x0, x1, [x9, #ARM_SMCCC_RES_X0_OFFS]
++ stp x2, x3, [x9, #ARM_SMCCC_RES_X2_OFFS]
++ stp x4, x5, [x9, #ARM_SMCCC_RES_X4_OFFS]
++ stp x6, x7, [x9, #ARM_SMCCC_RES_X6_OFFS]
++ ret
++ .cfi_endproc
++ .endm
++
++/*
++ * void arm_ffa_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
++ * unsigned long a3, unsigned long a4, unsigned long a5,
++ * unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
++ */
++ENTRY(__arm_ffa_smccc_smc)
++ FFASMCCC smc
++ENDPROC(__arm_ffa_smccc_smc)
++
++#endif
+diff --git a/arch/arm/lib/asm-offsets.c b/arch/arm/lib/asm-offsets.c
+index 22fd541f9a..45eca83a47 100644
+--- a/arch/arm/lib/asm-offsets.c
++++ b/arch/arm/lib/asm-offsets.c
+@@ -9,6 +9,8 @@
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
++ *
++ * (C) Copyright 2021 ARM Limited
+ */
+
+ #include <common.h>
+@@ -115,6 +117,10 @@ int main(void)
+ #ifdef CONFIG_ARM_SMCCC
+ DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0));
+ DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2));
++#if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT))
++ DEFINE(ARM_SMCCC_RES_X4_OFFS, offsetof(struct arm_smccc_res, a4));
++ DEFINE(ARM_SMCCC_RES_X6_OFFS, offsetof(struct arm_smccc_res, a6));
++#endif
+ DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id));
+ DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state));
+ #endif
+diff --git a/common/board_r.c b/common/board_r.c
+index c24d9b4e22..af20f38b10 100644
+--- a/common/board_r.c
++++ b/common/board_r.c
+@@ -61,6 +61,9 @@
+ #include <wdt.h>
+ #include <asm-generic/gpio.h>
+ #include <efi_loader.h>
++#ifdef CONFIG_ARM_FFA_TRANSPORT
++#include <arm_ffa_helper.h>
++#endif
+
+ DECLARE_GLOBAL_DATA_PTR;
+
+@@ -770,6 +773,9 @@ static init_fnc_t init_sequence_r[] = {
+ INIT_FUNC_WATCHDOG_RESET
+ initr_net,
+ #endif
++#ifdef CONFIG_ARM_FFA_TRANSPORT
++ ffa_helper_init_device,
++#endif
+ #ifdef CONFIG_POST
+ initr_post,
+ #endif
+diff --git a/drivers/Kconfig b/drivers/Kconfig
+index b26ca8cf70..e83c23789d 100644
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -6,6 +6,8 @@ source "drivers/core/Kconfig"
+
+ source "drivers/adc/Kconfig"
+
++source "drivers/arm-ffa/Kconfig"
++
+ source "drivers/ata/Kconfig"
+
+ source "drivers/axi/Kconfig"
+diff --git a/drivers/Makefile b/drivers/Makefile
+index 4e7cf28440..6671d2a604 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -107,6 +107,7 @@ obj-y += iommu/
+ obj-y += smem/
+ obj-y += thermal/
+ obj-$(CONFIG_TEE) += tee/
++obj-$(CONFIG_ARM_FFA_TRANSPORT) += arm-ffa/
+ obj-y += axi/
+ obj-y += ufs/
+ obj-$(CONFIG_W1) += w1/
+diff --git a/drivers/arm-ffa/Kconfig b/drivers/arm-ffa/Kconfig
+new file mode 100644
+index 0000000000..d71444c1fa
+--- /dev/null
++++ b/drivers/arm-ffa/Kconfig
+@@ -0,0 +1,26 @@
++# SPDX-License-Identifier: GPL-2.0
++
++config ARM_FFA_TRANSPORT
++ bool "Enable Arm Firmware Framework for Armv8-A driver"
++ depends on DM && ARM64
++ select ARM_SMCCC
++ select LIB_UUID
++ select ARM_FFA_TRANSPORT_HELPERS
++ select CMD_ARMFFA
++ help
++ The Firmware Framework for Arm A-profile processors (FF-A)
++ describes interfaces (ABIs) that standardize communication
++ between the Secure World and Normal World leveraging TrustZone
++ technology.
++
++ This driver is based on FF-A specification v1.0 and uses SMC32
++ calling convention.
++
++ FF-A specification:
++
++ https://developer.arm.com/documentation/den0077/a/?lang=en
++
++ In u-boot FF-A design, the Secure World is considered as one
++ entity to communicate with. FF-A communication is handled by
++ one device and one instance. This device takes care of
++ all the interactions between Normal world and Secure World.
+diff --git a/drivers/arm-ffa/Makefile b/drivers/arm-ffa/Makefile
+new file mode 100644
+index 0000000000..9fb5bea522
+--- /dev/null
++++ b/drivers/arm-ffa/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0+
++
++obj-y += arm-ffa-uclass.o core.o
+diff --git a/drivers/arm-ffa/arm-ffa-uclass.c b/drivers/arm-ffa/arm-ffa-uclass.c
+new file mode 100644
+index 0000000000..43f6066281
+--- /dev/null
++++ b/drivers/arm-ffa/arm-ffa-uclass.c
+@@ -0,0 +1,67 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * (C) Copyright 2021 ARM Limited
++ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
++ */
++
++#include <common.h>
++#include <dm.h>
++#include <arm_ffa.h>
++#include <errno.h>
++#include <log.h>
++#include <asm/global_data.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++UCLASS_DRIVER(ffa) = {
++ .name = "ffa",
++ .id = UCLASS_FFA,
++};
++
++/**
++ * ffa_get_invoke_func - performs a call to the FF-A driver dispatcher
++ * @func_id: The FF-A function to be used
++ * @func_data: Pointer to the FF-A function arguments
++ * container structure. This also includes
++ * pointers to the returned data needed by
++ * clients.
++ *
++ * This runtime function passes the FF-A function ID and its arguments to
++ * the FF-A driver dispatcher.
++ * This function is called by the FF-A helper functions.
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++int __ffa_runtime ffa_get_invoke_func(u32 func_id, struct ffa_interface_data *func_data)
++{
++ if (!ffa_device_get_ops()->invoke_func)
++ return -EINVAL;
++
++ return ffa_device_get_ops()->invoke_func(func_id, func_data);
++}
++
++/**
++ * ffa_init_device - probes the arm_ffa device
++ *
++ * This boot time function makes sure the arm_ffa device is probed
++ * and ready for use.
++ * This function is called automatically at initcalls
++ * level (after u-boot relocation).
++ *
++ * Arm FF-A transport is implemented through a single u-boot
++ * device (arm_ffa). So, there is only one device belonging to UCLASS_FFA.
++ * All FF-A clients should use the arm_ffa device to use the FF-A
++ * transport.
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++int ffa_init_device(void)
++{
++ ffa_dbg("[%s]", __func__);
++
++ return ffa_get_device();
++}
+diff --git a/drivers/arm-ffa/arm_ffa_prv.h b/drivers/arm-ffa/arm_ffa_prv.h
+new file mode 100644
+index 0000000000..38ea4ba83e
+--- /dev/null
++++ b/drivers/arm-ffa/arm_ffa_prv.h
+@@ -0,0 +1,199 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * (C) Copyright 2021 ARM Limited
++ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
++ */
++
++#ifndef __ARM_FFA_PRV_H
++#define __ARM_FFA_PRV_H
++
++#include <arm_ffa.h>
++#include <linux/bitfield.h>
++#include <linux/bitops.h>
++
++/*
++ * This header is private. It is exclusively used by the FF-A driver
++ */
++
++/* FF-A driver version definitions */
++
++#define MAJOR_VERSION_MASK GENMASK(30, 16)
++#define MINOR_VERSION_MASK GENMASK(15, 0)
++#define GET_FFA_MAJOR_VERSION(x) \
++ ((u16)(FIELD_GET(MAJOR_VERSION_MASK, (x))))
++#define GET_FFA_MINOR_VERSION(x) \
++ ((u16)(FIELD_GET(MINOR_VERSION_MASK, (x))))
++#define PACK_VERSION_INFO(major, minor) \
++ (FIELD_PREP(MAJOR_VERSION_MASK, (major)) | \
++ FIELD_PREP(MINOR_VERSION_MASK, (minor)))
++
++#define FFA_MAJOR_VERSION (1)
++#define FFA_MINOR_VERSION (0)
++#define FFA_VERSION_1_0 \
++ PACK_VERSION_INFO(FFA_MAJOR_VERSION, FFA_MINOR_VERSION)
++
++/* Endpoint ID mask (u-boot endpoint ID) */
++
++#define GET_SELF_ENDPOINT_ID_MASK GENMASK(15, 0)
++#define GET_SELF_ENDPOINT_ID(x) \
++ ((u16)(FIELD_GET(GET_SELF_ENDPOINT_ID_MASK, (x))))
++
++#define PREP_SELF_ENDPOINT_ID_MASK GENMASK(31, 16)
++#define PREP_SELF_ENDPOINT_ID(x) \
++ ((u16)(FIELD_PREP(PREP_SELF_ENDPOINT_ID_MASK, (x))))
++
++/* Partition endpoint ID mask (partition with which u-boot communicates with) */
++
++#define PREP_PART_ENDPOINT_ID_MASK GENMASK(15, 0)
++#define PREP_PART_ENDPOINT_ID(x) \
++ ((u16)(FIELD_PREP(PREP_PART_ENDPOINT_ID_MASK, (x))))
++
++/* The FF-A SMC function prototype definition */
++
++typedef void (*invoke_ffa_fn_t)(unsigned long a0, unsigned long a1,
++ unsigned long a2, unsigned long a3, unsigned long a4,
++ unsigned long a5, unsigned long a6, unsigned long a7,
++ struct arm_smccc_res *res);
++
++/**
++ * enum ffa_conduit - Arm FF-A conduits supported by the Arm FF-A driver
++ * Currently only SMC32 is supported.
++ */
++enum ffa_conduit {
++ FFA_CONDUIT_SMC = 0,
++};
++
++/**
++ * FFA_DECLARE_ARGS - FF-A functions local variables
++ * @a0-a7: local variables used to set registers x0-x7
++ * @res: the structure hosting the FF-A function return data
++ *
++ * A helper macro for declaring local variables for the FF-A functions arguments.
++ * The x0-x7 registers are used to exchange data with the secure world.
++ * But, only the bottom 32-bit of thes registers contains the data.
++ */
++#define FFA_DECLARE_ARGS \
++ unsigned long a0 = 0; \
++ unsigned long a1 = 0; \
++ unsigned long a2 = 0; \
++ unsigned long a3 = 0; \
++ unsigned long a4 = 0; \
++ unsigned long a5 = 0; \
++ unsigned long a6 = 0; \
++ unsigned long a7 = 0; \
++ struct arm_smccc_res res = {0}
++
++/* FF-A error codes */
++#define FFA_ERR_STAT_NOT_SUPPORTED (-1)
++#define FFA_ERR_STAT_INVALID_PARAMETERS (-2)
++#define FFA_ERR_STAT_NO_MEMORY (-3)
++#define FFA_ERR_STAT_BUSY (-4)
++#define FFA_ERR_STAT_INTERRUPTED (-5)
++#define FFA_ERR_STAT_DENIED (-6)
++#define FFA_ERR_STAT_RETRY (-7)
++#define FFA_ERR_STAT_ABORTED (-8)
++
++/**
++ * struct ffa_features_desc - FF-A functions features
++ * @func_id: FF-A function
++ * @field1: features read from register w2
++ * @field2: features read from register w3
++ *
++ * Data structure describing the features of the FF-A functions queried by
++ * FFA_FEATURES
++ */
++struct ffa_features_desc {
++ u32 func_id;
++ u32 field1;
++ u32 field2;
++};
++
++/**
++ * enum ffa_rxtx_buf_sizes - minimum sizes supported
++ * for the RX/TX buffers
++ */
++enum ffa_rxtx_buf_sizes {
++ RXTX_4K,
++ RXTX_64K,
++ RXTX_16K
++};
++
++/*
++ * Number of the FF-A interfaces features descriptors
++ * currently only FFA_RXTX_MAP descriptor is supported
++ */
++#define FFA_FEATURE_DESC_CNT (1)
++
++/**
++ * struct ffa_pdata - platform data for the arm_ffa device
++ * @conduit: The FF-A conduit used
++ *
++ * Platform data structure read from the device tree
++ */
++struct ffa_pdata {
++ enum ffa_conduit conduit;
++};
++
++/**
++ * struct ffa_rxtxpair - structure hosting the RX/TX buffers physical addresses
++ * @rxbuf: physical address of the RX buffer
++ * @txbuf: physical address of the TX buffer
++ *
++ * Data structure hosting the physical addresses of the mapped RX/TX buffers
++ * These physical address are used by the FF-A functions that use the RX/TX buffers
++ */
++struct ffa_rxtxpair {
++ u64 rxbuf; /* physical address */
++ u64 txbuf; /* physical address */
++};
++
++/**
++ * struct ffa_partition_desc - the secure partition descriptor
++ * @info: partition information
++ * @UUID: UUID
++ *
++ * Each partition has its descriptor containing the partitions information and the UUID
++ */
++struct ffa_partition_desc {
++ struct ffa_partition_info info;
++ union ffa_partition_uuid UUID;
++};
++
++/**
++ * struct ffa_partitions - descriptors for all secure partitions
++ * @count: The number of partitions descriptors
++ * @descs The partitions descriptors table
++ *
++ * This data structure contains the partitions descriptors table
++ */
++struct ffa_partitions {
++ u32 count;
++ struct ffa_partition_desc *descs; /* virtual address */
++};
++
++/**
++ * struct ffa_prvdata - the driver private data structure
++ *
++ * @dev: The arm_ffa device under u-boot driver model
++ * @fwk_version: FF-A framework version
++ * @id: u-boot endpoint ID
++ * @partitions: The partitions descriptors structure
++ * @pair: The RX/TX buffers pair
++ * @conduit: The selected conduit
++ * @invoke_ffa_fn: The function executing the FF-A function
++ * @features: Table of the FF-A functions having features
++ *
++ * The driver data structure hosting all resident data.
++ */
++struct ffa_prvdata {
++ struct udevice *dev;
++ u32 fwk_version;
++ u16 id;
++ struct ffa_partitions partitions;
++ struct ffa_rxtxpair pair;
++ enum ffa_conduit conduit;
++ invoke_ffa_fn_t invoke_ffa_fn;
++ struct ffa_features_desc features[FFA_FEATURE_DESC_CNT];
++};
++
++#endif
+diff --git a/drivers/arm-ffa/core.c b/drivers/arm-ffa/core.c
+new file mode 100644
+index 0000000000..98e2d2fa17
+--- /dev/null
++++ b/drivers/arm-ffa/core.c
+@@ -0,0 +1,1484 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * (C) Copyright 2021 ARM Limited
++ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
++ */
++
++#include "arm_ffa_prv.h"
++#include <asm/global_data.h>
++#include <asm/io.h>
++#include <common.h>
++#include <dm.h>
++#include <fdtdec.h>
++#include <linux/errno.h>
++#include <linux/sizes.h>
++#include <log.h>
++#include <malloc.h>
++#include <mapmem.h>
++#include <string.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++/**
++ * The device private data structure containing all the resident
++ * data read from secure world
++ */
++struct ffa_prvdata __ffa_runtime_data ffa_priv_data = {0};
++
++/*
++ * Driver functions
++ */
++
++/**
++ * ffa_get_device - probes the arm_ffa device
++ *
++ * This boot time function makes sure the arm_ffa device is probed
++ * and ready for use. This is done using uclass_get_device.
++ * The arm_ffa driver belongs to UCLASS_FFA.
++ * This function should be called before using the driver.
++ *
++ * Arm FF-A transport is implemented through a single u-boot
++ * device (arm_ffa). So, there is only one device belonging to UCLASS_FFA.
++ * All FF-A clients should use the arm_ffa device to use the FF-A
++ * transport.
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++int ffa_get_device(void)
++{
++ int ret;
++ int devnum = 0;
++
++ ffa_dbg("[%s]", __func__);
++
++ if (ffa_priv_data.dev)
++ return FFA_ERR_STAT_SUCCESS;
++
++ /*
++ * searching and probing the device
++ */
++ ret = uclass_get_device(UCLASS_FFA, devnum, &ffa_priv_data.dev);
++ if (ret) {
++ ffa_err("can not find the device");
++ ffa_priv_data.dev = NULL;
++ return -ENODEV;
++ }
++
++ return FFA_ERR_STAT_SUCCESS;
++}
++
++/**
++ * ffa_get_version - FFA_VERSION handler function
++ *
++ * This is the boot time function that implements FFA_VERSION FF-A function
++ * to get from the secure world the FF-A framework version
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_get_version(void)
++{
++ u16 major, minor;
++
++ FFA_DECLARE_ARGS;
++
++ ffa_dbg("[%s]", __func__);
++
++ if (!ffa_priv_data.invoke_ffa_fn)
++ panic("[FFA] no private data found\n");
++
++ a0 = FFA_VERSION;
++ a1 = FFA_VERSION_1_0;
++ ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res);
++
++ if (res.a0 == FFA_ERR_STAT_NOT_SUPPORTED) {
++ ffa_err("A Firmware Framework implementation does not exist");
++ return -EOPNOTSUPP;
++ }
++
++ major = GET_FFA_MAJOR_VERSION(res.a0);
++ minor = GET_FFA_MINOR_VERSION(res.a0);
++
++ ffa_info("FF-A driver %d.%d\nFF-A framework %d.%d",
++ FFA_MAJOR_VERSION, FFA_MINOR_VERSION, major, minor);
++
++ if ((major == FFA_MAJOR_VERSION && minor >= FFA_MINOR_VERSION)) {
++ ffa_info("Versions are compatible ");
++
++ ffa_priv_data.fwk_version = res.a0;
++
++ return FFA_ERR_STAT_SUCCESS;
++ }
++
++ ffa_info("Versions are incompatible ");
++ return -EPROTONOSUPPORT;
++}
++
++/**
++ * ffa_get_endpoint_id - FFA_ID_GET handler function
++ *
++ * This is the boot time function that implements FFA_ID_GET FF-A function
++ * to get from the secure world u-boot endpoint ID
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_get_endpoint_id(void)
++{
++ FFA_DECLARE_ARGS;
++
++ ffa_dbg("[%s]", __func__);
++
++ if (!ffa_priv_data.invoke_ffa_fn)
++ panic("[FFA] no private data found\n");
++
++ a0 = FFA_ID_GET;
++
++ ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res);
++
++ switch (res.a0) {
++ case FFA_ERROR:
++ {
++ if (((int)res.a2) == FFA_ERR_STAT_NOT_SUPPORTED) {
++ ffa_err("This function is not implemented at this FF-A instance");
++ return -EOPNOTSUPP;
++ }
++
++ ffa_err("Undefined error code (%d)", ((int)res.a2));
++ return -EINVAL;
++ }
++ case FFA_SUCCESS:
++ {
++ ffa_priv_data.id = GET_SELF_ENDPOINT_ID(res.a2);
++ ffa_info("endpoint ID is %u", ffa_priv_data.id);
++
++ return FFA_ERR_STAT_SUCCESS;
++ }
++ default:
++ {
++ ffa_err("Undefined response function (0x%lx)", res.a0);
++ return -EINVAL;
++ }
++ }
++}
++
++/**
++ * ffa_get_features_desc - returns the features descriptor of the specified
++ * FF-A function
++ * @func_id: the FF-A function which the features are to be retrieved
++ *
++ * This is a boot time function that searches the features descriptor of the
++ * specified FF-A function
++ *
++ * Return:
++ *
++ * When found, the address of the features descriptor is returned. Otherwise, NULL.
++ */
++static struct ffa_features_desc *ffa_get_features_desc(u32 func_id)
++{
++ u32 desc_idx;
++
++ /*
++ * search for the descriptor of the selected FF-A interface
++ */
++ for (desc_idx = 0; desc_idx < FFA_FEATURE_DESC_CNT ; desc_idx++)
++ if (ffa_priv_data.features[desc_idx].func_id == func_id)
++ return &ffa_priv_data.features[desc_idx];
++
++ return NULL;
++}
++
++/**
++ * ffa_get_rxtx_map_features - FFA_FEATURES handler function with FFA_RXTX_MAP
++ * argument
++ *
++ * This is the boot time function that implements FFA_FEATURES FF-A function
++ * to retrieve the FFA_RXTX_MAP features
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_get_rxtx_map_features(void)
++{
++ FFA_DECLARE_ARGS;
++
++ ffa_dbg("[%s]", __func__);
++
++ if (!ffa_priv_data.invoke_ffa_fn)
++ panic("[FFA] no private data found\n");
++
++ a0 = FFA_FEATURES;
++ a1 = FFA_RXTX_MAP;
++
++ ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res);
++
++ switch (res.a0) {
++ case FFA_ERROR:
++ {
++ if (((int)res.a2) == FFA_ERR_STAT_NOT_SUPPORTED) {
++ ffa_err("FFA_RXTX_MAP is not implemented at this FF-A instance");
++ return -EOPNOTSUPP;
++ }
++
++ ffa_err("Undefined error code (%d)", ((int)res.a2));
++ return -EINVAL;
++ }
++ case FFA_SUCCESS:
++ {
++ u32 desc_idx;
++
++ /*
++ * search for an empty descriptor
++ */
++ for (desc_idx = 0; desc_idx < FFA_FEATURE_DESC_CNT ; desc_idx++)
++ if (!ffa_priv_data.features[desc_idx].func_id) {
++ /*
++ * populate the descriptor with
++ * the interface features data
++ */
++ ffa_priv_data.features[desc_idx].func_id =
++ FFA_RXTX_MAP;
++ ffa_priv_data.features[desc_idx].field1 =
++ res.a2;
++
++ ffa_info("FFA_RXTX_MAP features data 0x%lx",
++ res.a2);
++
++ return FFA_ERR_STAT_SUCCESS;
++ }
++
++ ffa_err("Cannot save FFA_RXTX_MAP features data. Descriptors table full");
++ return -ENOBUFS;
++ }
++ default:
++ {
++ ffa_err("Undefined response function (0x%lx)",
++ res.a0);
++ return -EINVAL;
++ }
++ }
++}
++
++/**
++ * ffa_get_rxtx_buffers_pages_cnt - reads from the features data descriptors
++ * the minimum number of pages in each of the RX/TX
++ * buffers
++ * @buf_4k_pages: Pointer to the minimum number of pages
++ *
++ * This is the boot time function that returns the minimum number of pages
++ * in each of the RX/TX buffers
++ *
++ * Return:
++ *
++ * buf_4k_pages points to the returned number of pages
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_get_rxtx_buffers_pages_cnt(size_t *buf_4k_pages)
++{
++ struct ffa_features_desc *desc = NULL;
++
++ ffa_dbg("[%s]", __func__);
++
++ if (!buf_4k_pages)
++ return -EINVAL;
++
++ desc = ffa_get_features_desc(FFA_RXTX_MAP);
++ if (!desc)
++ return -EINVAL;
++
++ ffa_dbg("FFA_RXTX_MAP descriptor found");
++
++ switch (desc->field1) {
++ case RXTX_4K:
++ *buf_4k_pages = 1;
++ break;
++ case RXTX_16K:
++ *buf_4k_pages = 4;
++ break;
++ case RXTX_64K:
++ *buf_4k_pages = 16;
++ break;
++ default:
++ ffa_err("RX/TX buffer size not supported");
++ return -EINVAL;
++ }
++
++ return FFA_ERR_STAT_SUCCESS;
++}
++
++/**
++ * ffa_free_rxtx_buffers - frees the RX/TX buffers
++ * @buf_4k_pages: the minimum number of pages in each of the RX/TX
++ * buffers
++ *
++ * This is the boot time function used to free the RX/TX buffers
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_free_rxtx_buffers(size_t buf_4k_pages)
++{
++ efi_status_t free_rxbuf_ret, free_txbuf_ret;
++
++ ffa_info("Freeing RX/TX buffers");
++
++ free_rxbuf_ret = efi_free_pages(ffa_priv_data.pair.rxbuf, buf_4k_pages);
++ free_txbuf_ret = efi_free_pages(ffa_priv_data.pair.txbuf, buf_4k_pages);
++
++ if (free_rxbuf_ret != EFI_SUCCESS || free_txbuf_ret != EFI_SUCCESS) {
++ ffa_err("Failed to free RX/TX buffers (rx: %lu , tx: %lu)",
++ free_rxbuf_ret,
++ free_txbuf_ret);
++ return -EINVAL;
++ }
++
++ return FFA_ERR_STAT_SUCCESS;
++}
++
++/**
++ * ffa_alloc_rxtx_buffers - allocates the RX/TX buffers
++ * @buf_4k_pages: the minimum number of pages in each of the RX/TX
++ * buffers
++ *
++ * This is the boot time function used by ffa_map_rxtx_buffers to allocate
++ * the RX/TX buffers before mapping them
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_alloc_rxtx_buffers(size_t buf_4k_pages)
++{
++ ffa_dbg("[%s]", __func__);
++
++#if CONFIG_IS_ENABLED(EFI_LOADER)
++
++ efi_status_t efi_ret;
++ void *virt_txbuf;
++ void *virt_rxbuf;
++
++ ffa_info("Using %lu 4KB page(s) for RX/TX buffers size",
++ buf_4k_pages);
++
++ efi_ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
++ EFI_BOOT_SERVICES_DATA,
++ buf_4k_pages,
++ &ffa_priv_data.pair.rxbuf);
++
++ if (efi_ret != EFI_SUCCESS) {
++ ffa_priv_data.pair.rxbuf = 0;
++ ffa_err("Failure to allocate RX buffer (EFI error: 0x%lx)",
++ efi_ret);
++
++ return -ENOBUFS;
++ }
++
++ ffa_info("RX buffer at phys 0x%llx",
++ ffa_priv_data.pair.rxbuf);
++
++ /*
++ * convert the RX buffer physical address to virtual address
++ */
++ virt_rxbuf = (void *)map_sysmem((phys_addr_t)ffa_priv_data.pair.rxbuf, 0);
++
++ /*
++ * make sure the buffer is clean before use
++ */
++ memset(virt_rxbuf, 0, buf_4k_pages * SZ_4K);
++
++ unmap_sysmem(virt_rxbuf);
++
++ efi_ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
++ EFI_RUNTIME_SERVICES_DATA,
++ buf_4k_pages,
++ &ffa_priv_data.pair.txbuf);
++
++ if (efi_ret != EFI_SUCCESS) {
++ ffa_dbg("FFA_RXTX_MAP: freeing RX buffer");
++ efi_free_pages(ffa_priv_data.pair.rxbuf, buf_4k_pages);
++ ffa_priv_data.pair.rxbuf = 0;
++ ffa_priv_data.pair.txbuf = 0;
++ ffa_err("Failure to allocate the TX buffer (EFI error: 0x%lx)"
++ , efi_ret);
++
++ return -ENOBUFS;
++ }
++
++ ffa_info("TX buffer at phys 0x%llx",
++ ffa_priv_data.pair.txbuf);
++
++ /*
++ * convert the TX buffer physical address to virtual address
++ */
++ virt_txbuf = (void *)map_sysmem((phys_addr_t)ffa_priv_data.pair.txbuf, 0);
++
++ /*
++ * make sure the buffer is clean before use
++ */
++ memset(virt_txbuf, 0, buf_4k_pages * SZ_4K);
++
++ unmap_sysmem(virt_txbuf);
++
++ return FFA_ERR_STAT_SUCCESS;
++
++#else
++ return -ENOBUFS;
++#endif
++}
++
++/**
++ * ffa_map_rxtx_buffers - FFA_RXTX_MAP handler function
++ * @buf_4k_pages: the minimum number of pages in each of the RX/TX
++ * buffers
++ *
++ * This is the boot time function that implements FFA_RXTX_MAP FF-A function
++ * to map the RX/TX buffers
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_map_rxtx_buffers(size_t buf_4k_pages)
++{
++ int ret;
++
++ FFA_DECLARE_ARGS;
++
++ ffa_dbg("[%s]", __func__);
++
++ if (!ffa_priv_data.invoke_ffa_fn)
++ panic("[FFA] no private data found\n");
++
++ ret = ffa_alloc_rxtx_buffers(buf_4k_pages);
++ if (ret != FFA_ERR_STAT_SUCCESS)
++ return ret;
++
++ a0 = FFA_RXTX_MAP;
++ a1 = ffa_priv_data.pair.txbuf;
++ a2 = ffa_priv_data.pair.rxbuf;
++ a3 = buf_4k_pages;
++
++ ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res);
++
++ switch (res.a0) {
++ case FFA_ERROR:
++ {
++ switch (((int)res.a2)) {
++ case FFA_ERR_STAT_INVALID_PARAMETERS:
++ ffa_err("One or more fields in input parameters is incorrectly encoded");
++ ret = -EPERM;
++ break;
++ case FFA_ERR_STAT_NO_MEMORY:
++ ffa_err("Not enough memory");
++ ret = -ENOMEM;
++ break;
++ case FFA_ERR_STAT_DENIED:
++ ffa_err("Buffer pair already registered");
++ ret = -EACCES;
++ break;
++ case FFA_ERR_STAT_NOT_SUPPORTED:
++ ffa_err("This function is not implemented at this FF-A instance");
++ ret = -EOPNOTSUPP;
++ break;
++ default:
++ ffa_err("Undefined error (%d)",
++ ((int)res.a2));
++ ret = -EINVAL;
++ }
++ break;
++ }
++ case FFA_SUCCESS:
++ ffa_info("RX/TX buffers mapped");
++ return FFA_ERR_STAT_SUCCESS;
++ default:
++ ffa_err("Undefined response function (0x%lx)",
++ res.a0);
++ ret = -EINVAL;
++ }
++
++ ffa_free_rxtx_buffers(buf_4k_pages);
++
++ return ret;
++}
++
++/**
++ * ffa_unmap_rxtx_buffers - FFA_RXTX_UNMAP handler function
++ *
++ * This is the boot time function that implements FFA_RXTX_UNMAP FF-A function
++ * to unmap the RX/TX buffers
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_unmap_rxtx_buffers(void)
++{
++ FFA_DECLARE_ARGS;
++
++ ffa_dbg("[%s]", __func__);
++
++ if (!ffa_priv_data.invoke_ffa_fn)
++ panic("[FFA] no private data found\n");
++
++ a0 = FFA_RXTX_UNMAP;
++ a1 = PREP_SELF_ENDPOINT_ID(ffa_priv_data.id);
++
++ ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res);
++
++ switch (res.a0) {
++ case FFA_ERROR:
++ {
++ if (((int)res.a2) == FFA_ERR_STAT_NOT_SUPPORTED)
++ panic("[FFA] FFA_RXTX_UNMAP is not implemented at this FF-A instance\n");
++ else if (((int)res.a2) == FFA_ERR_STAT_INVALID_PARAMETERS)
++ panic("[FFA] There is no buffer pair registered on behalf of the caller\n");
++ else
++ panic("[FFA] Undefined error (%d)\n", ((int)res.a2));
++ }
++ case FFA_SUCCESS:
++ {
++ size_t buf_4k_pages = 0;
++ int ret;
++
++ ret = ffa_get_rxtx_buffers_pages_cnt(&buf_4k_pages);
++ if (ret != FFA_ERR_STAT_SUCCESS)
++ panic("[FFA] RX/TX buffers unmapped but failure in getting pages count\n");
++
++ ret = ffa_free_rxtx_buffers(buf_4k_pages);
++ if (ret != FFA_ERR_STAT_SUCCESS)
++ panic("[FFA] RX/TX buffers unmapped but failure in freeing the memory\n");
++
++ ffa_info("RX/TX buffers unmapped and memory freed");
++
++ return FFA_ERR_STAT_SUCCESS;
++ }
++ default:
++ panic("[FFA] Undefined response function (0x%lx)", res.a0);
++ }
++}
++
++/**
++ * ffa_release_rx_buffer - FFA_RX_RELEASE handler function
++ *
++ * This is the boot time function that invokes FFA_RX_RELEASE FF-A function
++ * to release the ownership of the RX buffer
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_release_rx_buffer(void)
++{
++ FFA_DECLARE_ARGS;
++
++ ffa_dbg("[%s]", __func__);
++
++ if (!ffa_priv_data.invoke_ffa_fn)
++ panic("[FFA] no private data found\n");
++
++ a0 = FFA_RX_RELEASE;
++
++ ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res);
++
++ switch (res.a0) {
++ case FFA_ERROR:
++ {
++ if (((int)res.a2) == FFA_ERR_STAT_NOT_SUPPORTED)
++ panic("[FFA] FFA_RX_RELEASE is not implemented at this FF-A instance\n");
++ else if (((int)res.a2) == FFA_ERR_STAT_DENIED)
++ panic("[FFA] Caller did not have ownership of the RX buffer\n");
++ else
++ panic("[FFA] Undefined error (%d)\n", ((int)res.a2));
++ }
++ case FFA_SUCCESS:
++ ffa_info("RX buffer released");
++ return FFA_ERR_STAT_SUCCESS;
++
++ default:
++ panic("[FFA] Undefined response function (0x%lx)\n", res.a0);
++ }
++}
++
++/**
++ * ffa_uuid_are_identical - checks whether two given UUIDs are identical
++ * @uuid1: first UUID
++ * @uuid2: second UUID
++ *
++ * This is a boot time function used by ffa_read_partitions_info to search
++ * for a UUID in the partitions descriptors table
++ *
++ * Return:
++ *
++ * 1 when UUIDs match. Otherwise, 0
++ */
++int ffa_uuid_are_identical(const union ffa_partition_uuid *uuid1,
++ const union ffa_partition_uuid *uuid2)
++{
++ if (!uuid1 || !uuid2)
++ return 0;
++
++ return (!memcmp(uuid1, uuid2, sizeof(union ffa_partition_uuid)));
++}
++
++/**
++ * ffa_read_partitions_info - reads the data queried by FFA_PARTITION_INFO_GET
++ * and saves it in the private structure
++ * @count: The number of partitions queried
++ * @part_uuid: Pointer to the partition(s) UUID
++ *
++ * This is the boot time function that reads the partitions information
++ * returned by the FFA_PARTITION_INFO_GET and saves it in the private
++ * data structure.
++ *
++ * Return:
++ *
++ * The private data structure is updated with the partition(s) information
++ * FFA_ERR_STAT_SUCCESS is returned on success. Otherwise, failure
++ */
++static int ffa_read_partitions_info(u32 count, union ffa_partition_uuid *part_uuid)
++{
++ ffa_dbg("[%s]", __func__);
++
++ if (!count) {
++ ffa_err("No partition detected");
++ return -ENODATA;
++ }
++
++ ffa_info("Reading partitions data from the RX buffer");
++
++#if CONFIG_IS_ENABLED(EFI_LOADER)
++
++ if (!part_uuid) {
++ /*
++ * querying information of all partitions
++ */
++ u64 data_pages;
++ u64 data_bytes;
++ efi_status_t efi_ret;
++ size_t buf_4k_pages = 0;
++ u32 desc_idx;
++ struct ffa_partition_info *parts_info;
++ int ret;
++
++ data_bytes = count * sizeof(struct ffa_partition_desc);
++ data_pages = efi_size_in_pages(data_bytes);
++
++ /*
++ * get the RX buffer size in pages
++ */
++ ret = ffa_get_rxtx_buffers_pages_cnt(&buf_4k_pages);
++ if (ret != FFA_ERR_STAT_SUCCESS) {
++ ffa_err("Can not get the RX buffer size (error %d)", ret);
++ return ret;
++ }
++
++ if (data_pages > buf_4k_pages) {
++ ffa_err("Partitions data size exceeds the RX buffer size:");
++ ffa_err(" Sizes in pages: data %llu , RX buffer %lu ",
++ data_pages,
++ buf_4k_pages);
++
++ return -ENOMEM;
++ }
++
++ efi_ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
++ EFI_RUNTIME_SERVICES_DATA,
++ data_pages,
++ (u64 *)&ffa_priv_data.partitions.descs);
++
++ if (efi_ret != EFI_SUCCESS) {
++ ffa_priv_data.partitions.descs = NULL;
++
++ ffa_err("Cannot allocate partitions data buffer (EFI error 0x%lx)",
++ efi_ret);
++
++ return -ENOBUFS;
++ }
++
++ /*
++ * convert the descs buffer physical address
++ * to virtual address
++ * This virtual address should not be unmapped
++ * descs is expected to be a virtual address
++ */
++ ffa_priv_data.partitions.descs =
++ (struct ffa_partition_desc *)
++ map_sysmem((phys_addr_t)
++ ffa_priv_data.partitions.descs, 0);
++
++ /*
++ * make sure the buffer is clean before use
++ */
++ memset(ffa_priv_data.partitions.descs, 0,
++ data_pages * SZ_4K);
++
++ ffa_info("Copying %lld page(s) of partitions data from RX buffer",
++ data_pages);
++
++ /*
++ * convert the RX buffer physical address to
++ * virtual address
++ */
++ parts_info = (struct ffa_partition_info *)
++ map_sysmem((phys_addr_t)
++ ffa_priv_data.pair.rxbuf, 0);
++
++ for (desc_idx = 0 ; desc_idx < count ; desc_idx++) {
++ ffa_priv_data.partitions.descs[desc_idx].info =
++ parts_info[desc_idx];
++
++ ffa_info("Partition ID %x : info cached",
++ ffa_priv_data.partitions.descs[desc_idx].info.id);
++ }
++ unmap_sysmem(parts_info);
++
++ ffa_priv_data.partitions.count = count;
++
++ ffa_info("%d partition(s) found and cached", count);
++
++ } else {
++ u32 rx_desc_idx, cached_desc_idx;
++ struct ffa_partition_info *parts_info;
++ u8 desc_found;
++
++ /*
++ * convert the RX buffer physical address to virtual address
++ */
++ parts_info = (struct ffa_partition_info *)
++ map_sysmem((phys_addr_t)ffa_priv_data.pair.rxbuf, 0);
++
++ /*
++ * search for the SP IDs read from the RX buffer
++ * in the already cached SPs.
++ * Update the UUID when ID found.
++ */
++ for (rx_desc_idx = 0; rx_desc_idx < count ; rx_desc_idx++) {
++ desc_found = 0;
++
++ /*
++ * search the current ID in the cached partitions
++ */
++ for (cached_desc_idx = 0;
++ cached_desc_idx < ffa_priv_data.partitions.count;
++ cached_desc_idx++) {
++ /*
++ * save the UUID
++ */
++ if (ffa_priv_data.partitions.descs[cached_desc_idx].info.id ==
++ parts_info[rx_desc_idx].id) {
++ ffa_priv_data.partitions.descs[cached_desc_idx].UUID =
++ *part_uuid;
++
++ desc_found = 1;
++ break;
++ }
++ }
++
++ if (!desc_found) {
++ unmap_sysmem(parts_info);
++ return -ENODATA;
++ }
++ }
++ unmap_sysmem(parts_info);
++ }
++#else
++#warning "arm_ffa: reading FFA_PARTITION_INFO_GET data not implemented"
++#endif
++
++ return FFA_ERR_STAT_SUCCESS;
++}
++
++/**
++ * ffa_query_partitions_info - invokes FFA_PARTITION_INFO_GET
++ * and saves partitions data
++ * @part_uuid: Pointer to the partition(s) UUID
++ * @pcount: Pointer to the number of partitions variable filled when querying
++ *
++ * This is the boot time function that executes the FFA_PARTITION_INFO_GET
++ * to query the partitions data. Then, it calls ffa_read_partitions_info
++ * to save the data in the private data structure.
++ *
++ * After reading the data the RX buffer is released using ffa_release_rx_buffer
++ *
++ * Return:
++ *
++ * When part_uuid is NULL, all partitions data are retrieved from secure world
++ * When part_uuid is non NULL, data for partitions matching the given UUID are
++ * retrieved and the number of partitions is returned
++ * FFA_ERR_STAT_SUCCESS is returned on success. Otherwise, failure
++ */
++static int ffa_query_partitions_info(union ffa_partition_uuid *part_uuid,
++ u32 *pcount)
++{
++ unsigned long a0 = 0;
++ union ffa_partition_uuid query_uuid = {0};
++ unsigned long a5 = 0;
++ unsigned long a6 = 0;
++ unsigned long a7 = 0;
++ struct arm_smccc_res res = {0};
++
++ ffa_dbg("[%s]", __func__);
++
++ if (!ffa_priv_data.invoke_ffa_fn)
++ panic("[FFA] no private data found\n");
++
++ a0 = FFA_PARTITION_INFO_GET;
++
++ /*
++ * If a UUID is specified. Information for one or more
++ * partitions in the system is queried. Otherwise, information
++ * for all installed partitions is queried
++ */
++
++ if (part_uuid) {
++ if (!pcount)
++ return -EINVAL;
++
++ query_uuid = *part_uuid;
++ }
++
++ ffa_priv_data.invoke_ffa_fn(a0, query_uuid.words.a1, query_uuid.words.a2,
++ query_uuid.words.a3, query_uuid.words.a4,
++ a5, a6, a7, &res);
++
++ switch (res.a0) {
++ case FFA_ERROR:
++ {
++ switch (((int)res.a2)) {
++ case FFA_ERR_STAT_INVALID_PARAMETERS:
++ ffa_err("Unrecognized UUID");
++ return -EPERM;
++ case FFA_ERR_STAT_NO_MEMORY:
++ ffa_err("Results cannot fit in RX buffer of the caller");
++ return -ENOMEM;
++ case FFA_ERR_STAT_DENIED:
++ ffa_err("Callee is not in a state to handle this request");
++ return -EACCES;
++ case FFA_ERR_STAT_NOT_SUPPORTED:
++ ffa_err("This function is not implemented at this FF-A instance");
++ return -EOPNOTSUPP;
++ case FFA_ERR_STAT_BUSY:
++ ffa_err("RX buffer of the caller is not free");
++ return -EBUSY;
++ default:
++ ffa_err("Undefined error (%d)", ((int)res.a2));
++ return -EINVAL;
++ }
++ }
++ case FFA_SUCCESS:
++ {
++ int ret;
++
++ /*
++ * res.a2 contains the count of partition information descriptors
++ * populated in the RX buffer
++ */
++ if (res.a2) {
++ ret = ffa_read_partitions_info(res.a2, part_uuid);
++ if (ret)
++ ffa_err("Failed to read partition(s) data , error (%d)", ret);
++ }
++
++ /*
++ * return the SP count
++ */
++ if (part_uuid) {
++ if (!ret)
++ *pcount = res.a2;
++ else
++ *pcount = 0;
++ }
++ /*
++ * After calling FFA_PARTITION_INFO_GET the buffer ownership
++ * is assigned to the consumer (u-boot). So, we need to give
++ * the ownership back to the secure world
++ */
++ ret = ffa_release_rx_buffer();
++
++ if (!part_uuid && !res.a2) {
++ ffa_err("[FFA] no partition installed in the system");
++ return -ENODEV;
++ }
++
++ return ret;
++ }
++ default:
++ ffa_err("Undefined response function (0x%lx)", res.a0);
++ return -EINVAL;
++ }
++}
++
++/**
++ * ffa_get_partitions_info - FFA_PARTITION_INFO_GET handler function
++ * @func_data: Pointer to the FF-A function arguments container structure.
++ * The passed arguments:
++ * Mode 1: When getting from the driver the number of
++ * secure partitions:
++ * @data0_size: UUID size
++ * @data0: pointer to the UUID (little endian)
++ * @data1_size: size of the number of partitions
++ * variable
++ * @data1: pointer to the number of partitions
++ * variable. The variable will be set
++ * by the driver
++ * Mode 2: When requesting the driver to return the
++ * partitions information:
++ * @data0_size: UUID size
++ * @data0: pointer to the UUID (little endian)
++ * @data1_size: size of the SPs information buffer
++ * @data1: pointer to SPs information buffer
++ * (allocated by the client).
++ * The buffer will be filled by the driver
++ *
++ * This is the boot time function that queries the secure partition data from
++ * the private data structure. If not found, it invokes FFA_PARTITION_INFO_GET
++ * FF-A function to query the partition information from secure world.
++ *
++ * A client of the FF-A driver should know the UUID of the service it wants to
++ * access. It should use the UUID to request the FF-A driver to provide the
++ * partition(s) information of the service. The FF-A driver uses
++ * PARTITION_INFO_GET to obtain this information. This is implemented through
++ * ffa_get_partitions_info function.
++ * A new FFA_PARTITION_INFO_GET call is issued (first one performed through
++ * ffa_cache_partitions_info) allowing to retrieve the partition(s) information.
++ * They are not saved (already done). We only update the UUID in the cached area.
++ * This assumes that partitions data does not change in the secure world.
++ * Otherwise u-boot will have an outdated partition data. The benefit of caching
++ * the information in the FF-A driver is to accommodate discovery after
++ * ExitBootServices().
++ *
++ * When invoked through a client request, ffa_get_partitions_info should be
++ * called twice. First call is to get from the driver the number of secure
++ * partitions (SPs) associated to a particular UUID.
++ * Then, the caller (client) allocates the buffer to host the SPs data and
++ * issues a 2nd call. Then, the driver fills the SPs data in the pre-allocated
++ * buffer.
++ *
++ * To achieve the mechanism described above, ffa_get_partitions_info uses the
++ * following functions:
++ * ffa_read_partitions_info
++ * ffa_query_partitions_info
++ *
++ * Return:
++ *
++ * @data1: When pointing to the number of partitions variable, the number is
++ * set by the driver.
++ * When pointing to the partitions information buffer, the buffer will be
++ * filled by the driver.
++ *
++ * On success FFA_ERR_STAT_SUCCESS is returned. Otherwise, failure
++ */
++static int ffa_get_partitions_info(struct ffa_interface_data *func_data)
++{
++ /*
++ * fill_data:
++ * 0: return the SP count
++ * 1: fill SP data and return it to the caller
++ * -1: undefined mode
++ */
++ int fill_data = -1;
++ u32 desc_idx, client_desc_idx;
++ union ffa_partition_uuid *part_uuid;
++ u32 client_desc_max_cnt;
++ u32 parts_found = 0;
++
++ ffa_dbg("[%s]", __func__);
++
++ if (!func_data) {
++ ffa_err("No function data provided");
++ return -EINVAL;
++ }
++
++ if (!ffa_priv_data.partitions.count || !ffa_priv_data.partitions.descs)
++ panic("[FFA] No partition installed\n");
++
++ if (func_data->data0_size == sizeof(union ffa_partition_uuid) &&
++ func_data->data0 &&
++ func_data->data1_size == sizeof(u32) &&
++ func_data->data1) {
++ /*
++ * data0 (in): pointer to UUID
++ * data1 (in): pointer to SP count
++ * Out: SP count returned in the count variable pointed by data1
++ */
++
++ fill_data = 0;
++
++ ffa_info("Preparing for checking partitions count");
++
++ } else if ((func_data->data0_size == sizeof(union ffa_partition_uuid)) &&
++ func_data->data0 &&
++ (func_data->data1_size >= sizeof(struct ffa_partition_info)) &&
++ !(func_data->data1_size % sizeof(struct ffa_partition_info)) &&
++ func_data->data1) {
++ /*
++ * data0 (in): pointer to UUID
++ * data1 (in): pointer to SPs descriptors buffer
++ * (created by the client)
++ * Out: SPs descriptors returned in the buffer
++ * pointed by data1
++ */
++
++ fill_data = 1;
++
++ client_desc_idx = 0;
++
++ /*
++ * number of empty descriptors preallocated by the caller
++ */
++ client_desc_max_cnt =
++ func_data->data1_size / sizeof(struct ffa_partition_info);
++
++ ffa_info("Preparing for filling partitions info");
++
++ } else {
++ ffa_err("Invalid function arguments provided");
++ return -EINVAL;
++ }
++
++ part_uuid = (union ffa_partition_uuid *)func_data->data0;
++
++ ffa_info("Searching partitions using the provided UUID");
++
++#ifdef DEBUG
++ {
++ u32 dbg_uuid_cnt;
++
++ ffa_dbg("UUID: [LSB]");
++
++ for (dbg_uuid_cnt = 0 ; dbg_uuid_cnt < UUID_SIZE ; dbg_uuid_cnt++)
++ ffa_dbg(" %02x", part_uuid->bytes[dbg_uuid_cnt]);
++ }
++#endif
++
++ /*
++ * search in the cached partitions
++ */
++ for (desc_idx = 0;
++ desc_idx < ffa_priv_data.partitions.count;
++ desc_idx++) {
++ if (ffa_uuid_are_identical(&ffa_priv_data.partitions.descs[desc_idx].UUID,
++ part_uuid)) {
++ ffa_info("Partition ID %x matches the provided UUID",
++ ffa_priv_data.partitions.descs[desc_idx].info.id);
++
++ parts_found++;
++
++ if (fill_data) {
++ /*
++ * trying to fill the partition info in data1
++ */
++
++ if (client_desc_idx < client_desc_max_cnt) {
++ ((struct ffa_partition_info *)
++ func_data->data1)[client_desc_idx++] =
++ ffa_priv_data.partitions.descs[desc_idx].info;
++ continue;
++ }
++
++ ffa_err("Failed to fill the current descriptor client buffer full");
++ return -ENOBUFS;
++ }
++ }
++ }
++
++ if (!parts_found) {
++ int ret;
++
++ ffa_info("No partition found. Querying framework ...");
++
++ ret = ffa_query_partitions_info(part_uuid, &parts_found);
++
++ if (ret == FFA_ERR_STAT_SUCCESS) {
++ if (!fill_data) {
++ *((u32 *)func_data->data1) = parts_found;
++
++ ffa_info("Number of partition(s) found matching the UUID: %d",
++ parts_found);
++ } else {
++ /*
++ * we want to read SPs info
++ */
++
++ /*
++ * If SPs data filled, retry searching SP info again
++ */
++ if (parts_found)
++ ret = ffa_get_partitions_info(func_data);
++ else
++ ret = -ENODATA;
++ }
++ }
++
++ return ret;
++ }
++
++ /* partition(s) found */
++ if (!fill_data)
++ *((u32 *)func_data->data1) = parts_found;
++
++ return FFA_ERR_STAT_SUCCESS;
++}
++
++/**
++ * ffa_cache_partitions_info - Queries and saves all secure partitions data
++ *
++ * This is a boot time function that invokes FFA_PARTITION_INFO_GET FF-A
++ * function to query from secure world all partitions information.
++ *
++ * The FFA_PARTITION_INFO_GET call is issued with nil UUID as an argument.
++ * All installed partitions information are returned. We cache them in the
++ * resident private data structure and we keep the UUID field empty
++ * (in FF-A 1.0 UUID is not provided by the partition descriptor)
++ *
++ * This function is called at the device probing level.
++ * ffa_cache_partitions_info uses ffa_query_partitions_info to get the data
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_cache_partitions_info(void)
++{
++ ffa_dbg("[%s]", __func__);
++ return ffa_query_partitions_info(NULL, NULL);
++}
++
++/**
++ * ffa_msg_send_direct_req - FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
++ * @func_data: Pointer to the FF-A function arguments container structure.
++ * The passed arguments:
++ * @data0_size: partition ID size
++ * @data0: pointer to the partition ID
++ * @data1_size: exchanged data size
++ * @data1: pointer to the data buffer preallocated by
++ * the client (in/out)
++ *
++ * This is the runtime function that implements FFA_MSG_SEND_DIRECT_{REQ,RESP}
++ * FF-A functions.
++ *
++ * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition.
++ * The response from the secure partition is handled by reading the
++ * FFA_MSG_SEND_DIRECT_RESP arguments.
++ *
++ * The maximum size of the data that can be exchanged is 20 bytes which is
++ * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
++ * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int __ffa_runtime ffa_msg_send_direct_req(struct ffa_interface_data
++ *func_data)
++{
++ u16 dst_part_id;
++ unsigned long a0 = 0;
++ unsigned long a1 = 0;
++ unsigned long a2 = 0;
++ struct ffa_send_direct_data *msg;
++ struct arm_smccc_res res = {0};
++
++ ffa_dbg("[%s]", __func__);
++
++ if (!ffa_priv_data.invoke_ffa_fn)
++ panic("[FFA] no private data found\n");
++
++ if (!func_data)
++ return -EINVAL;
++
++ if (!ffa_priv_data.partitions.count || !ffa_priv_data.partitions.descs)
++ panic("[FFA] no partition installed\n");
++
++ if (func_data->data0_size != sizeof(u16) ||
++ !func_data->data0 ||
++ func_data->data1_size != FFA_MSG_SEND_DIRECT_MAX_SIZE ||
++ !func_data->data1) {
++ ffa_err("Undefined interface parameters");
++ return -EINVAL;
++ }
++
++ dst_part_id = *((u16 *)func_data->data0);
++ msg = func_data->data1;
++
++ ffa_dbg("Sending data to partition ID 0x%x", dst_part_id);
++
++ a0 = FFA_MSG_SEND_DIRECT_REQ;
++
++ a1 = PREP_SELF_ENDPOINT_ID(ffa_priv_data.id) |
++ PREP_PART_ENDPOINT_ID(dst_part_id);
++
++ ffa_priv_data.invoke_ffa_fn(a0, a1, a2,
++ msg->a3,
++ msg->a4,
++ msg->a5,
++ msg->a6,
++ msg->a7,
++ &res);
++
++ while (res.a0 == FFA_INTERRUPT)
++ ffa_priv_data.invoke_ffa_fn(FFA_RUN, res.a1,
++ 0, 0, 0, 0, 0, 0,
++ &res);
++
++ switch (res.a0) {
++ case FFA_ERROR:
++ {
++ switch (((int)res.a2)) {
++ case FFA_ERR_STAT_INVALID_PARAMETERS:
++ ffa_err("Invalid endpoint ID or non-zero reserved register");
++ return -EPERM;
++ case FFA_ERR_STAT_ABORTED:
++ panic("[FFA] Message target ran into unexpected error and has aborted\n");
++ case FFA_ERR_STAT_DENIED:
++ panic("[FFA] Callee is not in a state to handle this request\n");
++ case FFA_ERR_STAT_NOT_SUPPORTED:
++ panic("[FFA] This function is not implemented at this FF-A instance\n");
++ case FFA_ERR_STAT_BUSY:
++ panic("[FFA] Message target is busy\n");
++ default:
++ panic("[FFA] Undefined error (%d)\n", ((int)res.a2));
++ }
++ }
++ case FFA_SUCCESS:
++
++ ffa_dbg("Message sent with no response");
++ return FFA_ERR_STAT_SUCCESS;
++
++ case FFA_MSG_SEND_DIRECT_RESP:
++
++ ffa_dbg("Message sent with response");
++
++ /*
++ * extract the 32-bit wide return data
++ */
++ msg->a3 = (u32)res.a3;
++ msg->a4 = (u32)res.a4;
++ msg->a5 = (u32)res.a5;
++ msg->a6 = (u32)res.a6;
++ msg->a7 = (u32)res.a7;
++
++ return FFA_ERR_STAT_SUCCESS;
++
++ default:
++ panic("[FFA] Undefined response function (0x%lx)\n", res.a0);
++ }
++}
++
++/**
++ * invoke_ffa_drv_api - The driver dispatcher function
++ * @func_id: The FF-A function to be used
++ * @func_data: Pointer to the FF-A function arguments container
++ * structure. This also includes pointers to the
++ * returned data needed by clients.
++ * The dispatcher is a runtime function that selects the FF-A function handler
++ * based on the input FF-A function ID.
++ * The input arguments are passed to the handler function.
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++int __ffa_runtime invoke_ffa_drv_api(u32 func_id,
++ struct ffa_interface_data *func_data)
++{
++ if (!ffa_priv_data.dev)
++ panic("[FFA] no device found\n");
++
++ switch (func_id) {
++ case FFA_PARTITION_INFO_GET:
++ return ffa_get_partitions_info(func_data);
++ case FFA_RXTX_UNMAP:
++ return ffa_unmap_rxtx_buffers();
++ case FFA_MSG_SEND_DIRECT_REQ:
++ return ffa_msg_send_direct_req(func_data);
++ default:
++
++ ffa_err("Undefined FF-A interface (%d)", func_id);
++
++ return -EINVAL;
++ }
++}
++
++/**
++ * ffa_init_private_data - Initialization of the private data
++ * @dev: the arm_ffa device
++ *
++ * This boot time function reads data from the platform data structure
++ * and populates the private data structure
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_init_private_data(struct udevice *dev)
++{
++ struct ffa_pdata *pdata = dev_get_plat(dev);
++
++ ffa_priv_data.conduit = pdata->conduit;
++
++ if (ffa_priv_data.conduit == FFA_CONDUIT_SMC) {
++ ffa_priv_data.invoke_ffa_fn = arm_ffa_smccc_smc;
++ } else {
++ ffa_err("Undefined FF-A conduit (%d)", ffa_priv_data.conduit);
++ return -EINVAL;
++ }
++
++ ffa_info("Conduit is %s",
++ ((ffa_priv_data.conduit == FFA_CONDUIT_SMC) ?
++ "SMC" : "NOT SUPPORTED"));
++
++ return FFA_ERR_STAT_SUCCESS;
++}
++
++/**
++ * ffa_probe - The driver probe function
++ * @dev: the arm_ffa device
++ *
++ * Probing is done at boot time and triggered by the uclass device discovery.
++ * At probe level the following actions are done:
++ * - initialization of the driver private data structure
++ * - querying from secure world the FF-A framework version
++ * - querying from secure world the u-boot endpoint ID
++ * - querying from secure world the supported features of the specified FF-A calls
++ * - mapping the RX/TX buffers
++ * - querying from secure world all the partitions information
++ *
++ * All data queried from secure world is saved in the resident private data structure.
++ *
++ * The probe will fail if either FF-A framework is not detected or the
++ * FF-A requests are not behaving correctly. This ensures that the
++ * driver is not installed and its operations are not exported to the clients.
++ * However, once the driver is successfully probed and an FF-A anomaly is
++ * detected when clients invoke the driver operations, the driver cause
++ * u-boot to panic because the client would not know what to do in such conditions.
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_probe(struct udevice *dev)
++{
++ int ret;
++ size_t buf_4k_pages = 0;
++
++ ffa_dbg("[%s]: initializing the FF-A driver", __func__);
++
++ ret = ffa_init_private_data(dev);
++
++ if (ret != FFA_ERR_STAT_SUCCESS)
++ return ret;
++
++ ret = ffa_get_version();
++
++ if (ret != FFA_ERR_STAT_SUCCESS)
++ return ret;
++
++ ret = ffa_get_endpoint_id();
++
++ if (ret != FFA_ERR_STAT_SUCCESS)
++ return ret;
++
++ ret = ffa_get_rxtx_map_features();
++
++ if (ret != FFA_ERR_STAT_SUCCESS)
++ return ret;
++
++ ret = ffa_get_rxtx_buffers_pages_cnt(&buf_4k_pages);
++
++ if (ret != FFA_ERR_STAT_SUCCESS)
++ return ret;
++
++ ret = ffa_map_rxtx_buffers(buf_4k_pages);
++
++ if (ret != FFA_ERR_STAT_SUCCESS)
++ return ret;
++
++ ret = ffa_cache_partitions_info();
++
++ if (ret != FFA_ERR_STAT_SUCCESS) {
++ ffa_free_rxtx_buffers(buf_4k_pages);
++ return ret;
++ }
++
++ ffa_dbg("[%s]: initialization done", __func__);
++
++ return FFA_ERR_STAT_SUCCESS;
++}
++
++/**
++ * ffa_of_to_plat - Reads the device tree node
++ * @dev: the arm_ffa device
++ *
++ * This boot time function reads data from the device tree node and populates
++ * the platform data structure
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++static int ffa_of_to_plat(struct udevice *dev)
++{
++ struct ffa_pdata *pdata = dev_get_plat(dev);
++ const char *conduit;
++
++ ffa_dbg("[%s]", __func__);
++
++ conduit = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "method", NULL);
++
++ if (strcmp("smc", conduit)) {
++ ffa_err("Unsupported conduit");
++ return -EINVAL;
++ }
++
++ pdata->conduit = FFA_CONDUIT_SMC;
++
++ return FFA_ERR_STAT_SUCCESS;
++}
++
++/**
++ * ffa_drv_ops - The driver operations runtime structure
++ * @invoke_func: The driver dispatcher
++ */
++struct ffa_ops __ffa_runtime_data ffa_drv_ops = {
++ .invoke_func = invoke_ffa_drv_api
++};
++
++/**
++ * ffa_device_get_ops - driver operations getter
++ *
++ * Return:
++ * This runtime function returns a pointer to the driver operations structure
++ */
++const struct ffa_ops * __ffa_runtime ffa_device_get_ops(void)
++{
++ return &ffa_drv_ops;
++}
++
++/**
++ * Defining the device tree compatible string
++ */
++
++static const struct udevice_id ffa_match_id[] = {
++ {"arm,ffa", 0},
++ {},
++};
++
++/**
++ * Declaring the arm_ffa driver under UCLASS_FFA
++ */
++
++U_BOOT_DRIVER(arm_ffa) = {
++ .name = "arm_ffa",
++ .of_match = ffa_match_id,
++ .id = UCLASS_FFA,
++ .of_to_plat = ffa_of_to_plat,
++ .probe = ffa_probe,
++ .plat_auto = sizeof(struct ffa_pdata),
++};
+diff --git a/include/arm_ffa.h b/include/arm_ffa.h
+new file mode 100644
+index 0000000000..313f46f747
+--- /dev/null
++++ b/include/arm_ffa.h
+@@ -0,0 +1,191 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * (C) Copyright 2021 ARM Limited
++ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
++ */
++
++#ifndef __ARM_FFA_H
++#define __ARM_FFA_H
++
++#include <linux/arm-smccc.h>
++#include <linux/printk.h>
++
++/*
++ * This header is public. It can be used by clients to access
++ * data structures and definitions they need
++ */
++
++/*
++ * Macros for displaying logs
++ */
++
++#define ffa_dbg(fmt, ...) pr_debug("[FFA] " fmt "\n", ##__VA_ARGS__)
++#define ffa_info(fmt, ...) pr_info("[FFA] " fmt "\n", ##__VA_ARGS__)
++#define ffa_err(fmt, ...) pr_err("[FFA] " fmt "\n", ##__VA_ARGS__)
++
++/*
++ * The driver operations success error code
++ */
++#define FFA_ERR_STAT_SUCCESS (0)
++
++#if CONFIG_IS_ENABLED(EFI_LOADER)
++
++#include <efi_loader.h>
++
++/*
++ * __ffa_runtime_data and __ffa_runtime - controls whether data/code are
++ * available after calling the EFI ExitBootServices service.
++ * Data/code tagged with these keywords are resident (available at boot time and
++ * at runtime)
++ */
++
++#define __ffa_runtime_data __efi_runtime_data
++#define __ffa_runtime __efi_runtime
++
++#else
++
++#define __ffa_runtime_data
++#define __ffa_runtime
++
++#endif
++
++/*
++ * Definitions of the Arm FF-A interfaces supported by the Arm FF-A driver
++ */
++
++#define FFA_SMC(calling_convention, func_num) \
++ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention), \
++ ARM_SMCCC_OWNER_STANDARD, (func_num))
++
++#define FFA_SMC_32(func_num) FFA_SMC(ARM_SMCCC_SMC_32, (func_num))
++
++#define FFA_VERSION FFA_SMC_32(0x63)
++#define FFA_ID_GET FFA_SMC_32(0x69)
++#define FFA_FEATURES FFA_SMC_32(0x64)
++#define FFA_PARTITION_INFO_GET FFA_SMC_32(0x68)
++#define FFA_RXTX_MAP FFA_SMC_32(0x66)
++#define FFA_RXTX_UNMAP FFA_SMC_32(0x67)
++#define FFA_RX_RELEASE FFA_SMC_32(0x65)
++#define FFA_MSG_SEND_DIRECT_REQ FFA_SMC_32(0x6F)
++#define FFA_MSG_SEND_DIRECT_RESP FFA_SMC_32(0x70)
++#define FFA_RUN FFA_SMC_32(0x6D)
++#define FFA_ERROR FFA_SMC_32(0x60)
++#define FFA_SUCCESS FFA_SMC_32(0x61)
++#define FFA_INTERRUPT FFA_SMC_32(0x62)
++
++/*
++ * struct ffa_partition_info - Partition information descriptor
++ * @id: Partition ID
++ * @exec_ctxt: Execution context count
++ * @properties: Partition properties
++ *
++ * Data structure containing information about partitions instantiated in the system
++ * This structure is filled with the data queried by FFA_PARTITION_INFO_GET
++ */
++struct __packed ffa_partition_info {
++ u16 id;
++ u16 exec_ctxt;
++/* partition supports receipt of direct requests */
++#define FFA_PARTITION_DIRECT_RECV BIT(0)
++/* partition can send direct requests. */
++#define FFA_PARTITION_DIRECT_SEND BIT(1)
++/* partition can send and receive indirect messages. */
++#define FFA_PARTITION_INDIRECT_MSG BIT(2)
++ u32 properties;
++};
++
++/*
++ * struct ffa_send_direct_data - Data structure hosting the data
++ * used by FFA_MSG_SEND_DIRECT_{REQ,RESP}
++ * @a3-a7: Data read/written from/to w3-w7 registers
++ *
++ * Data structure containing the data to be sent by FFA_MSG_SEND_DIRECT_REQ
++ * or read from FFA_MSG_SEND_DIRECT_RESP
++ */
++struct __packed ffa_send_direct_data {
++ u32 a3; /* w3 */
++ u32 a4; /* w4 */
++ u32 a5; /* w5 */
++ u32 a6; /* w6 */
++ u32 a7; /* w7 */
++};
++
++#define FFA_MSG_SEND_DIRECT_MAX_SIZE (sizeof(struct ffa_send_direct_data))
++
++/* UUID data size */
++#define UUID_SIZE (16)
++
++/*
++ * union ffa_partition_uuid - Data union hosting the UUID
++ * transmitted by FFA_PARTITION_INFO_GET
++ * @words: data structure giving 32-bit words access to the UUID data
++ * @bytes: data structure giving byte access to the UUID data
++ *
++ * The structure holds little-endian UUID data.
++ */
++union ffa_partition_uuid {
++ struct __packed words {
++ u32 a1; /* w1 */
++ u32 a2; /* w2 */
++ u32 a3; /* w3 */
++ u32 a4; /* w4 */
++ } words;
++ u8 bytes[UUID_SIZE];
++};
++
++/**
++ * struct ffa_interface_data - generic FF-A interface data structure used to exchange
++ * data between user layers and the driver
++ * @data0_size: size of the first argument
++ * @data0: pointer to the first argument
++ * @data1_size>: size of the second argument
++ * @data1: pointer to the second argument
++ *
++ * Using this structure user layers can pass various types of data with different sizes.
++ * The driver internal functions can detect the nature of this data, verfy compliance
++ * then execute the request when appropriate.
++ */
++struct ffa_interface_data {
++ u32 data0_size; /* size of the first argument */
++ void *data0; /* pointer to the first argument */
++ u32 data1_size; /* size of the second argument */
++ void *data1; /* pointer to the second argument */
++};
++
++/**
++ * struct ffa_ops - The driver operations structure
++ * @invoke_func: function pointer to the invoke function
++ *
++ * The data structure providing all the operations supported by the driver.
++ * This structure is resident.
++ */
++struct ffa_ops {
++ /* the driver dispatcher */
++ int (*invoke_func)(u32 func_id, struct ffa_interface_data *func_data);
++};
++
++/**
++ * The device driver and the Uclass driver public functions
++ */
++
++/**
++ * ffa_get_invoke_func - performs a call to the FF-A driver dispatcher
++ */
++int __ffa_runtime ffa_get_invoke_func(u32 func_id,
++ struct ffa_interface_data *func_data);
++
++/**
++ * ffa_device_get_ops - driver operations getter
++ */
++const struct ffa_ops * __ffa_runtime ffa_device_get_ops(void);
++
++/**
++ * ffa_get_device - probes the arm_ffa device
++ */
++int ffa_get_device(void);
++
++/**
++ * ffa_init_device - probes the arm_ffa device
++ */
++int ffa_init_device(void);
++#endif
+diff --git a/include/arm_ffa_helper.h b/include/arm_ffa_helper.h
+new file mode 100644
+index 0000000000..0e143e5451
+--- /dev/null
++++ b/include/arm_ffa_helper.h
+@@ -0,0 +1,45 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * (C) Copyright 2021 ARM Limited
++ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
++ */
++
++#ifndef __ARM_FFA_HELPER_H
++#define __ARM_FFA_HELPER_H
++
++#include <arm_ffa.h>
++
++/*
++ * This header is public. Including this header provides all data structures
++ * and definitions needed by clients to use the FF-A transport driver
++ *
++ * It also provides helper functions allowing to pass data and invoke FF-A functions
++ */
++
++/**
++ * ffa_helper_get_partitions_info - Wrapper function for FFA_PARTITION_INFO_GET
++ */
++int ffa_helper_get_partitions_info(struct ffa_interface_data *func_data);
++
++/**
++ * ffa_helper_unmap_rxtx_buffers - Wrapper function for FFA_RXTX_UNMAP
++ */
++int ffa_helper_unmap_rxtx_buffers(void);
++
++/**
++ * ffa_helper_msg_send_direct_req - Wrapper function for
++ * FFA_MSG_SEND_DIRECT_{REQ,RESP}
++ */
++int __ffa_runtime ffa_helper_msg_send_direct_req(struct ffa_interface_data
++ *func_data);
++
++/**
++ * ffa_helper_init_device - Wrapper function for probing the arm_ffa device
++ */
++int ffa_helper_init_device(void);
++
++/**
++ * ffa_uuid_str_to_bin - Converts a big endian UUID string to a little endian buffer
++ */
++int ffa_uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin);
++#endif
+diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
+index 0e26e1d138..a1181b8f48 100644
+--- a/include/dm/uclass-id.h
++++ b/include/dm/uclass-id.h
+@@ -52,6 +52,7 @@ enum uclass_id {
+ UCLASS_EFI_MEDIA, /* Devices provided by UEFI firmware */
+ UCLASS_ETH, /* Ethernet device */
+ UCLASS_ETH_PHY, /* Ethernet PHY device */
++ UCLASS_FFA, /* Arm Firmware Framework for Armv8-A */
+ UCLASS_FIRMWARE, /* Firmware */
+ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
+ UCLASS_GPIO, /* Bank of general-purpose I/O pins */
+diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
+index 7f2be23394..54980a130f 100644
+--- a/include/linux/arm-smccc.h
++++ b/include/linux/arm-smccc.h
+@@ -1,6 +1,8 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+ /*
+ * Copyright (c) 2015, Linaro Limited
++ * (C) Copyright 2021 ARM Limited
++ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ */
+ #ifndef __LINUX_ARM_SMCCC_H
+ #define __LINUX_ARM_SMCCC_H
+@@ -57,13 +59,17 @@
+ #include <linux/types.h>
+ /**
+ * struct arm_smccc_res - Result from SMC/HVC call
+- * @a0-a3 result values from registers 0 to 3
++ * @a0-a7 result values from registers 0 to 7
+ */
+ struct arm_smccc_res {
+ unsigned long a0;
+ unsigned long a1;
+ unsigned long a2;
+ unsigned long a3;
++ unsigned long a4;
++ unsigned long a5;
++ unsigned long a6;
++ unsigned long a7;
+ };
+
+ /**
+@@ -113,6 +119,26 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
+ unsigned long a5, unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res, struct arm_smccc_quirk *quirk);
+
++#if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT))
++/**
++ * __arm_ffa_smccc_smc() - make SMC calls used for FF-A transport
++ * @a0-a7: arguments passed in 64-bit registers x0 to x7
++ * @res: result values from 64-bit registers x0 to x7
++ *
++ * This function is used to make SMC calls following SMC32 Calling Convention.
++ * The content of the supplied parameters is copied to registers x0 to x7 prior
++ * to the SMC instruction. The SMC call return data is 32-bit data read from
++ * registers x0 tp x7.
++ */
++asmlinkage void __arm_ffa_smccc_smc(unsigned long a0, unsigned long a1,
++ unsigned long a2, unsigned long a3, unsigned long a4,
++ unsigned long a5, unsigned long a6, unsigned long a7,
++ struct arm_smccc_res *res);
++
++#define arm_ffa_smccc_smc __arm_ffa_smccc_smc
++
++#endif
++
+ #define arm_smccc_smc(...) __arm_smccc_smc(__VA_ARGS__, NULL)
+
+ #define arm_smccc_smc_quirk(...) __arm_smccc_smc(__VA_ARGS__)
+diff --git a/lib/Kconfig b/lib/Kconfig
+index 3c6fa99b1a..473821b882 100644
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -810,6 +810,7 @@ config SMBIOS_PARSER
+ source lib/efi/Kconfig
+ source lib/efi_loader/Kconfig
+ source lib/optee/Kconfig
++source lib/arm-ffa/Kconfig
+
+ config TEST_FDTDEC
+ bool "enable fdtdec test"
+diff --git a/lib/Makefile b/lib/Makefile
+index 11b03d1cbe..8e6fad6130 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -9,6 +9,7 @@ obj-$(CONFIG_EFI) += efi/
+ obj-$(CONFIG_EFI_LOADER) += efi_driver/
+ obj-$(CONFIG_EFI_LOADER) += efi_loader/
+ obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest/
++obj-$(CONFIG_ARM_FFA_TRANSPORT_HELPERS) += arm-ffa/
+ obj-$(CONFIG_LZMA) += lzma/
+ obj-$(CONFIG_BZIP2) += bzip2/
+ obj-$(CONFIG_TIZEN) += tizen/
+diff --git a/lib/arm-ffa/Kconfig b/lib/arm-ffa/Kconfig
+new file mode 100644
+index 0000000000..79acbc5a8f
+--- /dev/null
++++ b/lib/arm-ffa/Kconfig
+@@ -0,0 +1,6 @@
++config ARM_FFA_TRANSPORT_HELPERS
++ bool "Enable interface helpers for Arm Firmware Framework for Armv8-A"
++ depends on ARM_FFA_TRANSPORT
++ help
++ User layers call FF-A interfaces using helper functions which
++ pass the data and the FF-A function ID to the low level driver
+diff --git a/lib/arm-ffa/Makefile b/lib/arm-ffa/Makefile
+new file mode 100644
+index 0000000000..c30c0f3981
+--- /dev/null
++++ b/lib/arm-ffa/Makefile
+@@ -0,0 +1,8 @@
++# SPDX-License-Identifier: GPL-2.0+
++#
++# (C) Copyright 2021 Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
++#
++
++# This file only gets included when CONFIG_ARM_FFA_TRANSPORT_HELPERS is set
++
++obj-y += arm_ffa_helper.o
+diff --git a/lib/arm-ffa/arm_ffa_helper.c b/lib/arm-ffa/arm_ffa_helper.c
+new file mode 100644
+index 0000000000..623899d380
+--- /dev/null
++++ b/lib/arm-ffa/arm_ffa_helper.c
+@@ -0,0 +1,188 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * (C) Copyright 2021 ARM Limited
++ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
++ */
++
++#include <common.h>
++#include <arm_ffa_helper.h>
++#include <uuid.h>
++
++/**
++ * ffa_helper_get_partitions_info - Wrapper function for FFA_PARTITION_INFO_GET
++ *
++ * @func_data: Pointer to the FF-A function arguments container
++ * structure.
++ * The passed arguments:
++ * Mode 1: When getting from the driver the number of
++ * secure partitions:
++ * @data0_size: UUID size
++ * @data0: pointer to the UUID (little endian)
++ * @data1_size: size of the number of partitions
++ * variable
++ * @data1: pointer to the number of partitions
++ * variable. The variable will be set
++ * by the driver
++ * Mode 2: When requesting the driver to return the
++ * partitions information:
++ * @data0_size: UUID size
++ * @data0: pointer to the UUID (little endian)
++ * @data1_size: size of the SPs information buffer
++ * @data1: pointer to SPs information buffer
++ * (allocated by the client).
++ * The buffer will be filled by the driver
++ *
++ * This is the boot time function used by clients who wants to get from secure
++ * world the partition(s) information.
++ *
++ * A client of the FF-A driver should know the UUID of the service it wants to
++ * access. It should use the UUID to request the FF-A driver to provide the
++ * partition(s) information of the service. The client should use
++ * ffa_helper_get_partitions_info to pass the UUID information to the driver
++ * which uses PARTITION_INFO_GET to obtain the partition(s) information.
++ *
++ * ffa_helper_get_partitions_info should be called twice. First call is to get
++ * from the driver the number of secure partitions (SPs) associated to a
++ * particular UUID. Then, the caller (client) allocates the buffer to host the
++ * SPs data and issues a 2nd call. Then, the driver fills the SPs data in the
++ * pre-allocated buffer.
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++int ffa_helper_get_partitions_info(struct ffa_interface_data *func_data)
++{
++ return ffa_get_invoke_func(FFA_PARTITION_INFO_GET, func_data);
++}
++
++/**
++ * ffa_helper_unmap_rxtx_buffers - Wrapper function for FFA_RXTX_UNMAP
++ *
++ * This is the boot time function that allows clients to unmap the RX/TX
++ * buffers
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++int ffa_helper_unmap_rxtx_buffers(void)
++{
++ return ffa_get_invoke_func(FFA_RXTX_UNMAP, NULL);
++}
++
++/**
++ * ffa_helper_msg_send_direct_req - Wrapper function for
++ * FFA_MSG_SEND_DIRECT_{REQ,RESP}
++ * @func_data: Pointer to the FF-A function arguments container structure.
++ * The passed arguments:
++ * @data0_size: partition ID size
++ * @data0: pointer to the partition ID
++ * @data1_size: exchanged data size
++ * @data1: pointer to the data buffer preallocated by the client (in/out)
++ *
++ * This is the runtime function that allows clients to send data to the secure
++ * world partitions. The arm_ffa driver uses FFA_MSG_SEND_DIRECT_REQ to send the
++ * data to the secure partition. The response from the secure partition is
++ * handled internally by the driver using FFA_MSG_SEND_DIRECT_RESP and returned
++ * to ffa_helper_msg_send_direct_req through @func_data
++ *
++ * The maximum size of the data that can be exchanged is 20 bytes which is
++ * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
++ * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
++ *
++ * The client should pre-allocate a buffer pointed by @data1 which the size
++ * is sizeof(struct ffa_send_direct_data)
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++int __ffa_runtime ffa_helper_msg_send_direct_req(struct ffa_interface_data
++ *func_data)
++{
++ return ffa_get_invoke_func(FFA_MSG_SEND_DIRECT_REQ, func_data);
++}
++
++/**
++ * ffa_helper_init_device - Wrapper function for probing the arm_ffa device
++ *
++ * This boot time function should be called to probe the arm_ffa device so
++ * it becomes ready for use.
++ * To achieve that, this function is called automatically at initcalls
++ * level (after u-boot relocation).
++ *
++ * Return:
++ *
++ * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
++ */
++int ffa_helper_init_device(void)
++{
++ return ffa_init_device();
++}
++
++/**
++ * ffa_uuid_str_to_bin - Converts a big endian UUID string to a little endian buffer
++ * @uuid_str: UUID string in big endian format (36 bytes wide + '/0')
++ * @uuid_bin: preallocated 16 bytes UUID buffer in little endian format
++ *
++ * UUID binary format used by the FF-A framework (16 bytes):
++ *
++ * [LSB] 4B-2B-2B-2B-6B (little endian data fields)
++ *
++ * UUID string is 36 length of characters (36 bytes):
++ *
++ * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
++ * be be be be be
++ *
++ * where x is a hexadecimal character. Fields are separated by '-'s.
++ * When converting to a binary UUID, these endianness rules apply:
++ * be: means the field in the string is considered a big endian hex number
++ * and should be converted to little endian binary format
++ *
++ * Return:
++ *
++ * uuid_bin filled with little endian UUID data
++ * On success 0 is returned. Otherwise, failure code.
++ */
++int ffa_uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin)
++{
++ u16 tmp16 = 0;
++ u32 tmp32 = 0;
++ u64 tmp64 = 0;
++
++ if (!uuid_str_valid(uuid_str) || !uuid_bin)
++ return -EINVAL;
++
++ /*
++ * reverse bytes from big to little endian
++ */
++ tmp32 = simple_strtoul(uuid_str, NULL, 16);
++ memcpy(uuid_bin, &tmp32, 4);
++
++ /*
++ * reverse bytes from big to little endian
++ */
++ tmp16 = simple_strtoul(uuid_str + 9, NULL, 16);
++ memcpy(uuid_bin + 4, &tmp16, 2);
++
++ /*
++ * reverse bytes from big to little endian
++ */
++ tmp16 = simple_strtoul(uuid_str + 14, NULL, 16);
++ memcpy(uuid_bin + 6, &tmp16, 2);
++
++ /*
++ * reverse bytes from big to little endian
++ */
++ tmp16 = simple_strtoul(uuid_str + 19, NULL, 16);
++ memcpy(uuid_bin + 8, &tmp16, 2);
++
++ /*
++ * reverse bytes from big to little endian
++ */
++ tmp64 = simple_strtoull(uuid_str + 24, NULL, 16);
++ memcpy(uuid_bin + 10, (char *)&tmp64, 6);
++
++ return 0;
++}
+diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
+index 5bcb8253ed..cffa2c69d6 100644
+--- a/lib/efi_loader/efi_boottime.c
++++ b/lib/efi_loader/efi_boottime.c
+@@ -23,6 +23,10 @@
+ #include <asm/setjmp.h>
+ #include <linux/libfdt_env.h>
+
++#if defined(CONFIG_ARM_FFA_TRANSPORT)
++#include <arm_ffa_helper.h>
++#endif
++
+ DECLARE_GLOBAL_DATA_PTR;
+
+ /* Task priority level */
+@@ -2114,6 +2118,10 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
+ struct efi_event *evt, *next_event;
+ efi_status_t ret = EFI_SUCCESS;
+
++#if defined(CONFIG_ARM_FFA_TRANSPORT)
++ int ffa_ret;
++#endif
++
+ EFI_ENTRY("%p, %zx", image_handle, map_key);
+
+ /* Check that the caller has read the current memory map */
+@@ -2174,6 +2182,15 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
+ dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
+ }
+
++#if defined(CONFIG_ARM_FFA_TRANSPORT)
++ /* unmap FF-A RX/TX buffers */
++ ffa_ret = ffa_helper_unmap_rxtx_buffers();
++ if (ffa_ret)
++ debug("[efi_boottime][ERROR]: can not unmap FF-A RX/TX buffers\n");
++ else
++ debug("[efi_boottime][INFO]: FF-A RX/TX buffers unmapped\n");
++#endif
++
+ /* Patch out unsupported runtime function */
+ efi_runtime_detach();
+
+--
+2.34.1
+
new file mode 100644
@@ -0,0 +1,30 @@
+From 8dd3e03bd83939746b6a849dce37435ea7581032 Mon Sep 17 00:00:00 2001
+From: Davidson K <davidson.kumaresan@arm.com>
+Date: Thu, 14 Jul 2022 19:35:41 +0530
+Subject: [PATCH 3/7] arm: total_compute: enable psci
+
+psci is used for system reset
+
+Signed-off-by: Davidson K <davidson.kumaresan@arm.com>
+Change-Id: Iff4f769dc5e64b6000e892d77a011102b090acfd
+Upstream-Status: Submitted [https://patchwork.ozlabs.org/project/uboot/patch/20220809102652.23776-1-davidson.kumaresan@arm.com/]
+---
+ arch/arm/dts/total_compute.dts | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/arch/arm/dts/total_compute.dts b/arch/arm/dts/total_compute.dts
+index 4399269a44..96edacda0b 100644
+--- a/arch/arm/dts/total_compute.dts
++++ b/arch/arm/dts/total_compute.dts
+@@ -45,4 +45,8 @@
+ clock-frequency = <24000000>;
+ clock-output-names = "bp:clock24mhz";
+ };
++ psci {
++ compatible = "arm,psci-1.0", "arm,psci-0.2";
++ method = "smc";
++ };
+ };
+--
+2.34.1
+
new file mode 100644
@@ -0,0 +1,37 @@
+From 6eee50e5376356b1faeb30507b411120a8b5c7d1 Mon Sep 17 00:00:00 2001
+From: Davidson K <davidson.kumaresan@arm.com>
+Date: Mon, 6 Jun 2022 15:13:15 +0530
+Subject: [PATCH 4/7] arm_ffa: rxtx_map should use 64 bit calls
+
+rxtx_map deals with the 64 bit addresses and hence the 64 bit calls
+should be used
+
+Signed-off-by: Davidson K <davidson.kumaresan@arm.com>
+Change-Id: Iec1251266e61139767588d683d60bada1ed10abe
+Upstream-Status: Pending [Not submitted to upstream yet]
+---
+ include/arm_ffa.h | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/include/arm_ffa.h b/include/arm_ffa.h
+index 313f46f747..9627107079 100644
+--- a/include/arm_ffa.h
++++ b/include/arm_ffa.h
+@@ -58,12 +58,13 @@
+ ARM_SMCCC_OWNER_STANDARD, (func_num))
+
+ #define FFA_SMC_32(func_num) FFA_SMC(ARM_SMCCC_SMC_32, (func_num))
++#define FFA_SMC_64(func_num) FFA_SMC(ARM_SMCCC_SMC_64, (func_num))
+
+ #define FFA_VERSION FFA_SMC_32(0x63)
+ #define FFA_ID_GET FFA_SMC_32(0x69)
+ #define FFA_FEATURES FFA_SMC_32(0x64)
+ #define FFA_PARTITION_INFO_GET FFA_SMC_32(0x68)
+-#define FFA_RXTX_MAP FFA_SMC_32(0x66)
++#define FFA_RXTX_MAP FFA_SMC_64(0x66)
+ #define FFA_RXTX_UNMAP FFA_SMC_32(0x67)
+ #define FFA_RX_RELEASE FFA_SMC_32(0x65)
+ #define FFA_MSG_SEND_DIRECT_REQ FFA_SMC_32(0x6F)
+--
+2.34.1
+
new file mode 100644
@@ -0,0 +1,993 @@
+From 6d26058401bce6012173b5341cdf4de72772a1c2 Mon Sep 17 00:00:00 2001
+From: Davidson K <davidson.kumaresan@arm.com>
+Date: Mon, 6 Jun 2022 13:19:07 +0530
+Subject: [PATCH 5/7] efi_firmware: add new fmp driver that supports arm fwu
+ specification
+
+This fmp driver communicates to the firmware update secure partition
+executing in the secure world which is an implementation of the arm
+psa specification for the firmware update. The communication to the
+firmware update secure partition is based on stmm and arm ff-a framework.
+
+It implements only the get_image_info and set_image api.
+
+Signed-off-by: Davidson K <davidson.kumaresan@arm.com>
+Change-Id: I94c2cad210c32a60a8a0594cacf530b68ab6a09d
+Upstream-Status: Pending [Not submitted to upstream yet]
+---
+ include/efi_firmware_arm_psa.h | 218 +++++++++++
+ include/efi_loader.h | 1 +
+ lib/efi_loader/Kconfig | 9 +
+ lib/efi_loader/Makefile | 1 +
+ lib/efi_loader/efi_capsule.c | 8 +
+ lib/efi_loader/efi_firmware.c | 134 +++++++
+ lib/efi_loader/efi_firmware_arm_psa.c | 520 ++++++++++++++++++++++++++
+ 7 files changed, 891 insertions(+)
+ create mode 100644 include/efi_firmware_arm_psa.h
+ create mode 100644 lib/efi_loader/efi_firmware_arm_psa.c
+
+diff --git a/include/efi_firmware_arm_psa.h b/include/efi_firmware_arm_psa.h
+new file mode 100644
+index 0000000000..82f932066c
+--- /dev/null
++++ b/include/efi_firmware_arm_psa.h
+@@ -0,0 +1,218 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2022 Arm Limited
++ */
++
++#ifndef _EFI_FIRMWARE_ARM_PSA_H
++#define _EFI_FIRMWARE_ARM_PSA_H
++
++#include <efi_loader.h>
++#include <mm_communication.h>
++#include <stdint.h>
++
++#define PSA_FWU_DIRECTORY_UUID \
++ EFI_GUID(0xdeee58d9, 0x5147, 0x4ad3, \
++ 0xa2, 0x90, 0x77, 0x66, 0x6e, 0x23, 0x41, 0xa5)
++
++#define PSA_FWU_SP_UUID \
++ EFI_GUID(0x6823a838, 0x1b06, 0x470e, \
++ 0x97, 0x74, 0x0c, 0xce, 0x8b, 0xfb, 0x53, 0xfd)
++
++#define FFA_FWU_SP_UUID \
++ {0x68, 0x23, 0xa8, 0x38, 0x1b, 0x06, 0x47, \
++ 0x0e, 0x97, 0x74, 0x0c, 0xce, 0x8b, 0xfb, 0x53, 0xfd}
++
++#define FWU_DISCOVER 0
++#define FWU_BEGIN_STAGING 1
++#define FWU_END_STAGING 2
++#define FWU_CANCEL_STAGING 3
++#define FWU_OPEN 4
++#define FWU_WRITE_STREAM 5
++#define FWU_READ_STREAM 6
++#define FWU_COMMIT 7
++#define FWU_ACCEPT_IMAGE 9
++#define FWU_SELECT_PREVIOUS 10
++
++#define FWU_SUCCESS 0
++#define FWU_UNKNOWN ((int32_t)-1)
++#define FWU_BUSY ((int32_t)-2)
++#define FWU_OUT_OF_BOUNDS ((int32_t)-3)
++#define FWU_AUTH_FAIL ((int32_t)-4)
++#define FWU_NO_PERMISSION ((int32_t)-5)
++#define FWU_DENIED ((int32_t)-6)
++#define FWU_RESUME ((int32_t)-7)
++
++#define MAX_IMAGES 5
++
++typedef int32_t fwu_status_t;
++
++struct fwu_image_info_entry {
++ efi_guid_t image_guid;
++ uint32_t client_permissions;
++ uint32_t img_max_size;
++ uint32_t lowest_acceptable_version;
++ uint32_t img_version;
++ uint32_t accepted;
++ uint32_t reserved;
++}__packed;
++
++struct fwu_image_directory {
++ uint32_t directory_version;
++ uint32_t num_images;
++ uint32_t active_index;
++ uint32_t boot_index;
++ struct fwu_image_info_entry entries[MAX_IMAGES];
++}__packed;
++
++int __efi_runtime arm_psa_get_image_info(
++ efi_uintn_t *image_info_size,
++ struct efi_firmware_image_descriptor *image_info,
++ u32 *descriptor_version,
++ u8 *descriptor_count,
++ efi_uintn_t *descriptor_size,
++ u32 *package_version,
++ u16 **package_version_name
++);
++
++int __efi_runtime arm_psa_update(
++ const void *image,
++ u8 image_index,
++ efi_uintn_t image_size
++);
++
++struct mm_fwu_discover_arg {
++ uint32_t func_id;
++}__packed;
++
++struct mm_fwu_discover_ret {
++ uint32_t status;
++ uint8_t version_major;
++ uint8_t version_minor;
++ uint16_t num_func;
++ uint8_t function_presence[];
++}__packed;
++
++struct mm_fwu_begin_staging_arg {
++ uint32_t func_id;
++}__packed;
++
++struct mm_fwu_begin_staging_ret {
++ uint32_t status;
++}__packed;
++
++struct mm_fwu_end_staging_arg {
++ uint32_t func_id;
++}__packed;
++
++struct mm_fwu_end_staging_ret {
++ uint32_t status;
++}__packed;
++
++struct mm_fwu_cancel_staging_arg {
++ uint32_t func_id;
++}__packed;
++
++struct mm_fwu_cancel_staging_ret {
++ uint32_t status;
++}__packed;
++
++struct mm_fwu_open_arg {
++ uint32_t func_id;
++ efi_guid_t image_guid;
++}__packed;
++
++struct mm_fwu_open_ret {
++ uint32_t status;
++ uint32_t handle;
++}__packed;
++
++struct mm_fwu_write_stream_arg {
++ uint32_t func_id;
++ uint32_t handle;
++ uint32_t data_len;
++ uint8_t payload[];
++}__packed;
++
++struct mm_fwu_write_stream_ret {
++ uint32_t status;
++};
++
++struct mm_fwu_read_stream_arg {
++ uint32_t func_id;
++ uint32_t handle;
++}__packed;
++
++struct mm_fwu_read_stream_ret {
++ uint32_t status;
++ uint32_t read_bytes;
++ uint32_t total_bytes;
++ uint8_t payload[];
++}__packed;
++
++struct mm_fwu_commit_arg {
++ uint32_t func_id;
++ uint32_t handle;
++ uint32_t acceptance_req;
++ uint32_t max_atomic_len;
++}__packed;
++
++struct mm_fwu_commit_ret {
++ uint32_t status;
++ uint32_t progress;
++ uint32_t total_work;
++}__packed;
++
++struct mm_fwu_accept_arg {
++ uint32_t func_id;
++ uint32_t reserved;
++ efi_guid_t image_type_uuid;
++}__packed;
++
++struct mm_fwu_accept_ret {
++ uint32_t status;
++};
++
++struct mm_fwu_select_previous_arg {
++ uint32_t func_id;
++}__packed;
++
++struct mm_fwu_select_previous_ret {
++ uint32_t status;
++}__packed;
++
++inline static void *get_fwu_hdr(struct efi_mm_communicate_header *mm_hdr)
++{
++ const efi_guid_t fwu_sp_guid = PSA_FWU_SP_UUID;
++ guidcpy(&mm_hdr->header_guid, &fwu_sp_guid);
++ return mm_hdr->data;
++}
++
++#define GET_HDR(name) \
++static inline struct mm_fwu_##name * \
++get_fwu_##name (struct efi_mm_communicate_header *mm_hdr) \
++{ \
++ return (struct mm_fwu_##name *)get_fwu_hdr(mm_hdr); \
++} \
++
++GET_HDR(discover_arg)
++GET_HDR(discover_ret)
++GET_HDR(begin_staging_arg)
++GET_HDR(begin_staging_ret)
++GET_HDR(end_staging_arg)
++GET_HDR(end_staging_ret)
++GET_HDR(cancel_staging_arg)
++GET_HDR(cancel_staging_ret)
++GET_HDR(open_arg)
++GET_HDR(open_ret)
++GET_HDR(write_stream_arg)
++GET_HDR(write_stream_ret)
++GET_HDR(read_stream_arg)
++GET_HDR(read_stream_ret)
++GET_HDR(commit_arg)
++GET_HDR(commit_ret)
++GET_HDR(accept_arg)
++GET_HDR(accept_ret)
++GET_HDR(select_previous_arg)
++GET_HDR(select_previous_ret)
++
++#endif /* _EFI_FIRMWARE_ARM_PSA_H */
+diff --git a/include/efi_loader.h b/include/efi_loader.h
+index af36639ec6..7327c87497 100644
+--- a/include/efi_loader.h
++++ b/include/efi_loader.h
+@@ -961,6 +961,7 @@ u16 *efi_create_indexed_name(u16 *buffer, size_t buffer_size, const char *name,
+
+ extern const struct efi_firmware_management_protocol efi_fmp_fit;
+ extern const struct efi_firmware_management_protocol efi_fmp_raw;
++extern const struct efi_firmware_management_protocol efi_fmp_arm_psa;
+
+ /* Capsule update */
+ efi_status_t EFIAPI efi_update_capsule(
+diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
+index e5e35fe51f..f99d436f16 100644
+--- a/lib/efi_loader/Kconfig
++++ b/lib/efi_loader/Kconfig
+@@ -168,6 +168,15 @@ config EFI_CAPSULE_FIRMWARE_MANAGEMENT
+ Select this option if you want to enable capsule-based
+ firmware update using Firmware Management Protocol.
+
++config EFI_CAPSULE_FIRMWARE_ARM_PSA
++ bool "FMP driver for ARM PSA FWU specification"
++ depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT
++ select EFI_CAPSULE_FIRMWARE
++ help
++ Select this option if you want to enable firmware management protocol
++ driver that supports the ARM PSA firmware update specification as
++ mentioned in https://developer.arm.com/documentation/den0118/a/
++
+ config EFI_CAPSULE_FIRMWARE_FIT
+ bool "FMP driver for FIT images"
+ depends on FIT
+diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
+index 034d26cf01..f986ac6417 100644
+--- a/lib/efi_loader/Makefile
++++ b/lib/efi_loader/Makefile
+@@ -38,6 +38,7 @@ obj-y += efi_boottime.o
+ obj-y += efi_helper.o
+ obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o
+ obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o
++obj-$(CONFIG_EFI_CAPSULE_FIRMWARE_ARM_PSA) += efi_firmware_arm_psa.o
+ obj-y += efi_console.o
+ obj-y += efi_device_path.o
+ obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o
+diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
+index f00440163d..3154fc51d3 100644
+--- a/lib/efi_loader/efi_capsule.c
++++ b/lib/efi_loader/efi_capsule.c
+@@ -1041,6 +1041,14 @@ efi_status_t __weak efi_load_capsule_drivers(void)
+ &efi_fmp_raw, NULL));
+ }
+
++ if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_ARM_PSA)) {
++ handle = NULL;
++ ret = EFI_CALL(efi_install_multiple_protocol_interfaces(
++ &handle,
++ &efi_guid_firmware_management_protocol,
++ &efi_fmp_arm_psa, NULL));
++ }
++
+ return ret;
+ }
+
+diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
+index a5ff32f121..3356559af8 100644
+--- a/lib/efi_loader/efi_firmware.c
++++ b/lib/efi_loader/efi_firmware.c
+@@ -9,6 +9,7 @@
+ #include <common.h>
+ #include <charset.h>
+ #include <dfu.h>
++#include <efi_firmware_arm_psa.h>
+ #include <efi_loader.h>
+ #include <image.h>
+ #include <signatures.h>
+@@ -478,3 +479,136 @@ const struct efi_firmware_management_protocol efi_fmp_raw = {
+ .set_package_info = efi_firmware_set_package_info_unsupported,
+ };
+ #endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */
++
++#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_ARM_PSA
++/*
++ * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
++ * method that supports the arm psa firmware update specification.
++ */
++
++/**
++ * efi_firmware_arm_psa_get_image_info - return information about the
++ * current firmware image
++ * @this: Protocol instance
++ * @image_info_size: Size of @image_info
++ * @image_info: Image information
++ * @descriptor_version: Pointer to version number
++ * @descriptor_count: Pointer to number of descriptors
++ * @descriptor_size: Pointer to descriptor size
++ * package_version: Package version
++ * package_version_name: Package version's name
++ *
++ * Return information bout the current firmware image in @image_info.
++ * @image_info will consist of a number of descriptors.
++ *
++ * Return status code
++ */
++
++static
++efi_status_t EFIAPI efi_firmware_arm_psa_get_image_info(
++ struct efi_firmware_management_protocol *this,
++ efi_uintn_t *image_info_size,
++ struct efi_firmware_image_descriptor *image_info,
++ u32 *descriptor_version,
++ u8 *descriptor_count,
++ efi_uintn_t *descriptor_size,
++ u32 *package_version,
++ u16 **package_version_name)
++{
++ int ret;
++
++ EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
++ image_info_size, image_info,
++ descriptor_version, descriptor_count, descriptor_size,
++ package_version, package_version_name);
++
++ if (!image_info_size)
++ return EFI_EXIT(EFI_INVALID_PARAMETER);
++
++ if (*image_info_size &&
++ (!image_info || !descriptor_version || !descriptor_count ||
++ !descriptor_size || !package_version || !package_version_name))
++ return EFI_EXIT(EFI_INVALID_PARAMETER);
++
++ ret = arm_psa_get_image_info(image_info_size, image_info,
++ descriptor_version, descriptor_count,
++ descriptor_size,
++ package_version, package_version_name);
++
++ if (ret) {
++ if (ret == -ENOMEM)
++ return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
++ else
++ return EFI_EXIT(EFI_DEVICE_ERROR);
++ }
++
++ return EFI_EXIT(EFI_SUCCESS);
++}
++
++/**
++ * efi_firmware_arm_psa_set_image - update the firmware image
++ * @this: Protocol instance
++ * @image_index: Image index number
++ * @image: New image
++ * @image_size: Size of new image
++ * @vendor_code: Vendor-specific update policy
++ * @progress: Function to report the progress of update
++ * @abort_reason: Pointer to string of abort reason
++ *
++ * Update the firmware to new image, following the arm psa firmware
++ * update specification.
++ * @vendor_code, @progress and @abort_reason are not supported.
++ *
++ * Return: status code
++ */
++static
++efi_status_t EFIAPI efi_firmware_arm_psa_set_image(
++ struct efi_firmware_management_protocol *this,
++ u8 image_index,
++ const void *image,
++ efi_uintn_t image_size,
++ const void *vendor_code,
++ efi_status_t (*progress)(efi_uintn_t completion),
++ u16 **abort_reason)
++{
++ u32 fmp_hdr_signature;
++ const struct fmp_payload_header *header;
++
++ EFI_ENTRY("%p %d %p %zd %p %p %p\n", this, image_index, image,
++ image_size, vendor_code, progress, abort_reason);
++
++ if (!image)
++ return EFI_EXIT(EFI_INVALID_PARAMETER);
++
++ /* TODO: capsule authentication */
++
++ fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
++ header = (void *)image;
++
++ if (!memcmp(&header->signature, &fmp_hdr_signature,
++ sizeof(fmp_hdr_signature))) {
++ /*
++ * When building the capsule with the scripts in
++ * edk2, a FMP header is inserted above the capsule
++ * payload. Compensate for this header to get the
++ * actual payload that is to be updated.
++ */
++ image = (unsigned char *)image + header->header_size;
++ image_size -= header->header_size;
++ }
++
++ if (arm_psa_update(image, image_index, image_size))
++ return EFI_EXIT(EFI_DEVICE_ERROR);
++
++ return EFI_EXIT(EFI_SUCCESS);
++}
++
++const struct efi_firmware_management_protocol efi_fmp_arm_psa = {
++ .get_image_info = efi_firmware_arm_psa_get_image_info,
++ .get_image = efi_firmware_get_image_unsupported,
++ .set_image = efi_firmware_arm_psa_set_image,
++ .check_image = efi_firmware_check_image_unsupported,
++ .get_package_info = efi_firmware_get_package_info_unsupported,
++ .set_package_info = efi_firmware_set_package_info_unsupported,
++};
++#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_ARM_PSA */
+diff --git a/lib/efi_loader/efi_firmware_arm_psa.c b/lib/efi_loader/efi_firmware_arm_psa.c
+new file mode 100644
+index 0000000000..ab575f0124
+--- /dev/null
++++ b/lib/efi_loader/efi_firmware_arm_psa.c
+@@ -0,0 +1,520 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2022 Arm Limited
++ */
++
++#include <arm_ffa_helper.h>
++#include <configs/total_compute.h>
++#include <efi_firmware_arm_psa.h>
++#include <efi_loader.h>
++#include <malloc.h>
++#include <mapmem.h>
++#include <mm_communication.h>
++
++/* MM return codes */
++#define MM_SUCCESS 0
++
++#define ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64 0xC4000061
++#define ARM_SVC_ID_SP_EVENT_COMPLETE ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64
++
++__efi_runtime_data static u16 mm_sp_id;
++__efi_runtime_data static int fwu_initialized = 0;
++__efi_runtime_data struct fwu_image_directory cached_image_directory;
++__efi_runtime_data struct efi_mm_communicate_header *mm_hdr;
++__efi_runtime_data void *mm_comm_buf;
++
++/**
++ * ffa_discover_mm_sp_id() - Query the MM partition ID
++ *
++ * Use the FF-A driver to get the MM partition ID.
++ * If multiple partitions are found, use the first one
++ *
++ * Return:
++ *
++ * 0 on success
++ */
++static int __efi_runtime ffa_discover_mm_sp_id(void)
++{
++ struct ffa_interface_data func_data = {0};
++ u32 count = 0;
++ int ret;
++ struct ffa_partition_info *parts_info;
++ static union ffa_partition_uuid fwu_sp_uuid = {.bytes = FFA_FWU_SP_UUID};
++
++ /*
++ * get from the driver the count of the SPs matching the UUID
++ */
++ func_data.data0_size = sizeof(fwu_sp_uuid);
++ func_data.data0 = &fwu_sp_uuid;
++ func_data.data1_size = sizeof(count);
++ func_data.data1 = &count;
++
++ ret = ffa_helper_get_partitions_info(&func_data);
++ if (ret != FFA_ERR_STAT_SUCCESS) {
++ log_err("EFI: Failure in querying partitions count (error code: %d)\n", ret);
++ return ret;
++ }
++
++ if (!count) {
++ log_info("EFI: No MM partition found\n");
++ return ret;
++ }
++
++ /*
++ * pre-allocate a buffer to be filled by the driver
++ * with ffa_partition_info structs
++ */
++ parts_info = calloc(count, sizeof(struct ffa_partition_info));
++ if (!parts_info)
++ return -EINVAL;
++
++ log_info("EFI: Pre-allocating %d partition(s) info structures\n", count);
++
++ func_data.data1_size = count * sizeof(struct ffa_partition_info);
++ func_data.data1 = parts_info;
++
++ /*
++ * ask the driver to fill the
++ * buffer with the SPs info
++ */
++ ret = ffa_helper_get_partitions_info(&func_data);
++ if (ret != FFA_ERR_STAT_SUCCESS) {
++ log_err("EFI: Failure in querying partition(s) info (error code: %d)\n", ret);
++ free(parts_info);
++ return ret;
++ }
++
++ /*
++ * MM SPs found , use the first one
++ */
++
++ mm_sp_id = parts_info[0].id;
++
++ log_info("EFI: MM partition ID 0x%x\n", mm_sp_id);
++
++ free(parts_info);
++
++ return 0;
++}
++
++/**
++ * ffa_notify_mm_sp() - Announce there is data in the shared buffer
++ *
++ * Notifies the MM partition in the trusted world that
++ * data is available in the shared buffer.
++ * This is a blocking call during which trusted world has exclusive access
++ * to the MM shared buffer.
++ *
++ * Return:
++ *
++ * 0 on success
++ */
++static int __efi_runtime ffa_notify_mm_sp(void)
++{
++ struct ffa_interface_data func_data = {0};
++ struct ffa_send_direct_data msg = {0};
++ int ret;
++ u32 sp_event_complete;
++ int sp_event_ret;
++
++ func_data.data0_size = sizeof(mm_sp_id);
++ func_data.data0 = &mm_sp_id;
++
++ msg.a3 = FFA_SHARED_MM_BUFFER_ADDR;
++ msg.a4 = FFA_SHARED_MM_BUFFER_SIZE;
++ func_data.data1_size = sizeof(msg);
++ func_data.data1 = &msg;
++
++ ret = ffa_helper_msg_send_direct_req(&func_data);
++ if (ret != FFA_ERR_STAT_SUCCESS) {
++ log_err("EFI: Failure to notify the MM SP , FF-A error (%d)\n", ret);
++ return ret;
++ }
++
++ sp_event_complete = msg.a3;
++ sp_event_ret = (int)msg.a4;
++
++ if (sp_event_complete == ARM_SVC_ID_SP_EVENT_COMPLETE && sp_event_ret == MM_SUCCESS)
++ return 0;
++
++ log_err("EFI: Failure to notify the MM SP (0x%x , %d)\n",
++ sp_event_complete,
++ sp_event_ret);
++
++ return -EACCES;
++}
++
++static fwu_status_t __efi_runtime fwu_discover(void)
++{
++ int ret;
++ struct mm_fwu_discover_arg *discover_arg = get_fwu_discover_arg(mm_hdr);
++ struct mm_fwu_discover_ret *discover_ret = get_fwu_discover_ret(mm_hdr);
++
++ discover_arg->func_id = FWU_DISCOVER;
++
++ mm_hdr->message_len = sizeof(struct mm_fwu_discover_arg);
++
++ ret = ffa_notify_mm_sp();
++ if (ret)
++ return ret;
++
++ if (discover_ret->version_major != 1) {
++ log_err("FWU: Unsupported Update Agent version\n");
++ return -EINVAL;
++ }
++ /* TODO: check other parameters as well */
++
++ return discover_ret->status;
++}
++
++static fwu_status_t __efi_runtime fwu_begin_staging(void)
++{
++ int ret;
++ struct mm_fwu_begin_staging_arg *begin_staging_arg = get_fwu_begin_staging_arg(mm_hdr);
++ struct mm_fwu_begin_staging_ret *begin_staging_ret = get_fwu_begin_staging_ret(mm_hdr);
++
++ begin_staging_arg->func_id = FWU_BEGIN_STAGING;
++
++ mm_hdr->message_len = sizeof(struct mm_fwu_begin_staging_arg);
++
++ ret = ffa_notify_mm_sp();
++ if (ret)
++ return ret;
++
++ return begin_staging_ret->status;
++}
++
++static fwu_status_t __efi_runtime fwu_end_staging(void)
++{
++ int ret;
++ struct mm_fwu_end_staging_arg *end_staging_arg = get_fwu_end_staging_arg(mm_hdr);
++ struct mm_fwu_end_staging_ret *end_staging_ret = get_fwu_end_staging_ret(mm_hdr);
++
++ end_staging_arg->func_id = FWU_END_STAGING;
++
++ mm_hdr->message_len = sizeof(struct mm_fwu_end_staging_arg);
++
++ ret = ffa_notify_mm_sp();
++ if (ret)
++ return ret;
++
++ return end_staging_ret->status;
++}
++
++static fwu_status_t __efi_runtime fwu_cancel_staging(void)
++{
++ int ret;
++ struct mm_fwu_cancel_staging_arg *cancel_staging_arg = get_fwu_cancel_staging_arg(mm_hdr);
++ struct mm_fwu_cancel_staging_ret *cancel_staging_ret = get_fwu_cancel_staging_ret(mm_hdr);
++
++ cancel_staging_arg->func_id = FWU_CANCEL_STAGING;
++
++ mm_hdr->message_len = sizeof(struct mm_fwu_cancel_staging_arg);
++
++ ret = ffa_notify_mm_sp();
++ if (ret)
++ return ret;
++
++ return cancel_staging_ret->status;
++}
++
++static fwu_status_t __efi_runtime fwu_open(const efi_guid_t *img_uuid, uint32_t *handle)
++{
++ int ret;
++ struct mm_fwu_open_arg *open_hdr = get_fwu_open_arg(mm_hdr);
++ struct mm_fwu_open_ret *open_ret = get_fwu_open_ret(mm_hdr);
++
++ open_hdr->func_id = FWU_OPEN;
++ guidcpy(&open_hdr->image_guid, img_uuid);
++
++ mm_hdr->message_len = sizeof(struct mm_fwu_open_arg);
++
++ ret = ffa_notify_mm_sp();
++ if (ret)
++ return ret;
++
++ *handle = open_ret->handle;
++
++ return open_ret->status;
++}
++
++static fwu_status_t __efi_runtime fwu_read_stream(uint32_t handle, uint8_t *buffer, uint32_t buffer_size)
++{
++ int ret;
++ struct mm_fwu_read_stream_arg *read_stream_hdr = get_fwu_read_stream_arg(mm_hdr);
++ struct mm_fwu_read_stream_ret *read_stream_ret = get_fwu_read_stream_ret(mm_hdr);
++ uint32_t payload_size = FFA_SHARED_MM_BUFFER_SIZE - sizeof(struct mm_fwu_read_stream_ret)
++ - sizeof(struct efi_mm_communicate_header);
++ uint32_t read_offset = 0, read_size, total_size;
++
++ do {
++ read_stream_hdr->func_id = FWU_READ_STREAM;
++ read_stream_hdr->handle = handle;
++
++ mm_hdr->message_len = sizeof(struct mm_fwu_read_stream_arg);
++
++ ret = ffa_notify_mm_sp();
++ if (ret)
++ return ret;
++
++ if (read_stream_ret->status)
++ return read_stream_ret->status;
++
++ read_size = read_stream_ret->read_bytes;
++ total_size = read_stream_ret->total_bytes;
++
++ log_info("FWU: read bytes / total bytes : %d/%d\n", read_size, total_size);
++
++ if ((read_size <= payload_size) && (read_offset + read_size <= buffer_size))
++ memcpy(buffer + read_offset, read_stream_ret->payload, read_size);
++ else
++ return -EINVAL;
++
++ read_offset += read_size;
++
++ if (read_offset > total_size)
++ return -EINVAL;
++ } while (total_size != read_offset);
++
++ return read_stream_ret->status;
++}
++
++static fwu_status_t __efi_runtime fwu_write_stream(uint32_t handle, const uint8_t *buffer, uint32_t remaining_size)
++{
++ int ret;
++ struct mm_fwu_write_stream_arg *write_stream_arg = get_fwu_write_stream_arg(mm_hdr);
++ struct mm_fwu_write_stream_ret *write_stream_ret = get_fwu_write_stream_ret(mm_hdr);
++ uint32_t write_size;
++ uint32_t payload_size = FFA_SHARED_MM_BUFFER_SIZE - sizeof(struct mm_fwu_write_stream_arg)
++ - sizeof(struct efi_mm_communicate_header);
++
++ while (remaining_size) {
++ write_size = (remaining_size < payload_size) ? remaining_size : payload_size;
++ write_stream_arg->func_id = FWU_WRITE_STREAM;
++ write_stream_arg->handle = handle;
++ write_stream_arg->data_len = write_size;
++ memcpy(write_stream_arg->payload, buffer, write_size);
++
++ mm_hdr->message_len = sizeof(struct mm_fwu_write_stream_arg) + write_size;
++
++ ret = ffa_notify_mm_sp();
++ if (ret)
++ return ret;
++
++ if(write_stream_ret->status)
++ return write_stream_ret->status;
++
++ remaining_size -= write_size;
++ buffer += write_size;
++
++ log_info("FWU: write size = %d, remaining size = %d\n",
++ write_size, remaining_size);
++ }
++
++ return write_stream_ret->status;
++}
++
++static fwu_status_t __efi_runtime fwu_commit(uint32_t handle, bool client_accept)
++{
++ int ret;
++ struct mm_fwu_commit_arg *commit_arg = get_fwu_commit_arg(mm_hdr);
++ struct mm_fwu_commit_ret *commit_ret = get_fwu_commit_ret(mm_hdr);
++
++ do {
++ commit_arg->func_id = FWU_COMMIT;
++ commit_arg->handle = handle;
++ commit_arg->acceptance_req = client_accept;
++ commit_arg->max_atomic_len = 0;
++
++ mm_hdr->message_len = sizeof(struct mm_fwu_commit_arg);
++
++ ret = ffa_notify_mm_sp();
++ if (ret)
++ return ret;
++
++ log_info("FWU: commit progress %d/%d (work/total_work)\n",
++ commit_ret->progress, commit_ret->total_work);
++
++ } while(commit_ret->status==FWU_RESUME);
++
++ return commit_ret->status;
++}
++
++int __efi_runtime arm_psa_update(
++ const void *image,
++ u8 image_index,
++ efi_uintn_t image_size
++)
++{
++ int ret = 0;
++ uint32_t handle;
++
++ if(image_index >= cached_image_directory.num_images)
++ return -EINVAL;
++
++ ret = fwu_begin_staging();
++ if (ret) {
++ log_err("FWU: begin staging failed, ret = %d\n", ret);
++ return ret;
++ }
++
++ ret = fwu_open(&cached_image_directory.entries[image_index].image_guid, &handle);
++ if (ret) {
++ log_err("FWU: firmware image open failed, ret = %d\n", ret);
++ goto cancel_staging;
++ }
++
++ ret = fwu_write_stream(handle, (uint8_t *)image, image_size);
++ if (ret) {
++ log_err("FWU: write stream failed, ret = %d\n", ret);
++ goto cancel_staging;
++ }
++
++ /* TODO: implement client driven image acceptance */
++ ret = fwu_commit(handle, 0);
++ if (ret) {
++ log_err("FWU: commit failed, ret = %d\n", ret);
++ goto cancel_staging;
++ }
++
++ ret = fwu_end_staging();
++ if (ret) {
++ log_err("FWU: end staging failed, ret = %d\n", ret);
++ goto cancel_staging;
++ }
++
++ log_info("successfully updated the image at index %d\n", image_index);
++ return ret;
++
++cancel_staging:
++ if (fwu_cancel_staging())
++ log_err("FWU: cancel staging failed, ret = %d\n", ret);
++
++ return ret;
++}
++
++static int __efi_runtime read_image_directory(void)
++{
++ int ret;
++ uint32_t handle;
++
++ const efi_guid_t fwu_directory_uuid = PSA_FWU_DIRECTORY_UUID;
++
++ ret = fwu_open(&fwu_directory_uuid, &handle);
++ if (ret) {
++ log_err("FWU: open image directory failed, ret = %d\n", ret);
++ return ret;
++ }
++
++ ret = fwu_read_stream(handle, (uint8_t *)&cached_image_directory, sizeof(cached_image_directory));
++ if (ret) {
++ log_err("FWU: read stream failed, ret = %d\n", ret);
++ return ret;
++ }
++
++ if(cached_image_directory.num_images > MAX_IMAGES) {
++ log_err("FWU: image limit exceeded.\n");
++ log_err("FWU: number of images present: %d, max number of images supported: %d\n",
++ cached_image_directory.num_images, MAX_IMAGES);
++ return -EINVAL;
++ }
++
++ return ret;
++}
++
++static int update_agent_init(void)
++{
++ int ret;
++
++ ret = ffa_discover_mm_sp_id();
++ if (ret) {
++ log_err("FWU: discover update agent failed, ret = %d\n", ret);
++ return ret;
++ }
++
++ mm_comm_buf = (void *)map_sysmem((phys_addr_t)FFA_SHARED_MM_BUFFER_ADDR, 0);
++ mm_hdr = (struct efi_mm_communicate_header *)mm_comm_buf;
++
++ ret = fwu_discover();
++ if (ret) {
++ log_err("FWU: discover failed, ret = %d\n", ret);
++ goto out;
++ }
++
++ ret = read_image_directory();
++ if (ret) {
++ log_err("FWU: reading image directory failed, ret = %d\n", ret);
++ goto out;
++ }
++
++ fwu_initialized = 1;
++ return ret;
++out:
++ unmap_sysmem(mm_comm_buf);
++ return ret;
++}
++
++int __efi_runtime arm_psa_get_image_info(
++ efi_uintn_t *image_info_size,
++ struct efi_firmware_image_descriptor *image_info,
++ u32 *descriptor_version,
++ u8 *descriptor_count,
++ efi_uintn_t *descriptor_size,
++ u32 *package_version,
++ u16 **package_version_name)
++{
++ int ret = 0;
++ int required_image_info_size;
++
++ if (!fwu_initialized) {
++ ret = update_agent_init();
++ if (ret) {
++ log_err("update agent init failed, ret = %d\n", ret);
++ return ret;
++ }
++ }
++
++ required_image_info_size = cached_image_directory.num_images *
++ sizeof(struct efi_firmware_image_descriptor);
++
++ if (*image_info_size < required_image_info_size) {
++ *image_info_size = required_image_info_size;
++ return -ENOMEM;
++ }
++
++ *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
++ *descriptor_count = cached_image_directory.num_images;
++ *descriptor_size = required_image_info_size;
++ *package_version = 0xffffffff; /* not supported */
++ *package_version_name = NULL; /* not supported */
++
++ for (int i = 0; i < cached_image_directory.num_images; i++) {
++ image_info[i].image_index = i+1;
++ guidcpy(&image_info[i].image_type_id, &cached_image_directory.entries[i].image_guid);
++ image_info[i].image_id = i;
++ image_info[i].image_id_name = NULL; /* not supported */
++ image_info[i].version = cached_image_directory.entries[i].img_version;
++ image_info[i].version_name = NULL; /* not supported */
++ image_info[i].size = cached_image_directory.entries[i].img_max_size;
++
++ image_info[i].attributes_supported =
++ IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
++ IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
++ image_info[i].attributes_setting =
++ IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
++
++ /* Check if the capsule authentication is enabled */
++ if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE))
++ image_info[i].attributes_setting |=
++ IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
++
++ image_info[i].lowest_supported_image_version =
++ cached_image_directory.entries[i].lowest_acceptable_version;
++ image_info[i].last_attempt_version = 0;
++ image_info[i].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
++ image_info[i].hardware_instance = 1;
++ image_info[i].dependencies = NULL; /* not supported */
++ }
++
++ return ret;
++}
+--
+2.34.1
+
new file mode 100644
@@ -0,0 +1,70 @@
+From 2ab887402b9e22842d07e5f2fe1ac54518555af5 Mon Sep 17 00:00:00 2001
+From: Davidson K <davidson.kumaresan@arm.com>
+Date: Mon, 6 Jun 2022 13:24:42 +0530
+Subject: [PATCH 6/7] arm: total_compute: enable capsule update
+
+It includes:
+* Enabling runtime capsule update
+* Enabling efidebug command line tool
+* Enabling the FMP driver that supports ARM PSA firmware update specification
+* Predefining the carved out memory to be used for MM communication
+* Enabling FF-A transport driver and adding an entry in dts
+
+Signed-off-by: Davidson K <davidson.kumaresan@arm.com>
+Change-Id: I6d6c70c6fc386d6c40def800a7417c1ce4b8acf5
+Upstream-Status: Pending [Not submitted to upstream yet]
+---
+ arch/arm/dts/total_compute.dts | 7 +++++++
+ configs/total_compute_defconfig | 5 +++++
+ include/configs/total_compute.h | 4 ++++
+ 3 files changed, 16 insertions(+)
+
+diff --git a/arch/arm/dts/total_compute.dts b/arch/arm/dts/total_compute.dts
+index 96edacda0b..9b2cbfb452 100644
+--- a/arch/arm/dts/total_compute.dts
++++ b/arch/arm/dts/total_compute.dts
+@@ -45,8 +45,15 @@
+ clock-frequency = <24000000>;
+ clock-output-names = "bp:clock24mhz";
+ };
++
+ psci {
+ compatible = "arm,psci-1.0", "arm,psci-0.2";
+ method = "smc";
+ };
++
++ arm_ffa {
++ compatible = "arm,ffa";
++ method = "smc";
++ status = "okay";
++ };
+ };
+diff --git a/configs/total_compute_defconfig b/configs/total_compute_defconfig
+index 6a375543cd..531ce41cd3 100644
+--- a/configs/total_compute_defconfig
++++ b/configs/total_compute_defconfig
+@@ -52,3 +52,8 @@ CONFIG_SYS_FLASH_PROTECTION=y
+ CONFIG_SYS_FLASH_CFI=y
+ CONFIG_LIBAVB=y
+ CONFIG_OF_LIBFDT_OVERLAY=y
++CONFIG_ARM_FFA_TRANSPORT=y
++CONFIG_CMD_EFIDEBUG=y
++CONFIG_EFI_CAPSULE_FIRMWARE_ARM_PSA=y
++CONFIG_EFI_CAPSULE_ON_DISK=y
++CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
+diff --git a/include/configs/total_compute.h b/include/configs/total_compute.h
+index 62bdb4f6a3..4b00f47ec6 100644
+--- a/include/configs/total_compute.h
++++ b/include/configs/total_compute.h
+@@ -59,4 +59,8 @@
+ #define CONFIG_SYS_FLASH_EMPTY_INFO /* flinfo indicates empty blocks */
+ #define FLASH_MAX_SECTOR_SIZE 0x00040000
+
++/* Shared buffer used for communication between u-boot and the FWU SP */
++#define FFA_SHARED_MM_BUFFER_SIZE 4 * 1024 * 1024 /* 4 MB */
++#define FFA_SHARED_MM_BUFFER_ADDR (0xFCA00000)
++
+ #endif /* __TOTAL_COMPUTE_H */
+--
+2.34.1
+
new file mode 100644
@@ -0,0 +1,51 @@
+From 47be0456ea1760837d2de857e57842e595e9ea5e Mon Sep 17 00:00:00 2001
+From: Davidson K <davidson.kumaresan@arm.com>
+Date: Mon, 27 Jun 2022 14:11:27 +0530
+Subject: [PATCH 7/7] arm_ffa: unmap rxtx buffer before exiting u-boot
+
+The linux kernel ffa driver will be used after the kernel boots. It
+will try to map its own rxtx buffer. But there can be only one rxtx
+buffer mapped from the non secure world. Since the rxtx buffer of
+the u-boot is no longer used and we have to map the rxtx buffer of
+the linux kernel, the rxtx buffer of the u-boot should be unmapped.
+
+This will not be needed after the efi runtime services are enabled
+
+Signed-off-by: Davidson K <davidson.kumaresan@arm.com>
+Change-Id: I9deb6283d81f791185aa0a32d205b394d6d91f76
+Upstream-Status: Pending [Not submitted to upstream yet]
+---
+ drivers/arm-ffa/core.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/drivers/arm-ffa/core.c b/drivers/arm-ffa/core.c
+index 98e2d2fa17..0c619439cb 100644
+--- a/drivers/arm-ffa/core.c
++++ b/drivers/arm-ffa/core.c
+@@ -1470,6 +1470,16 @@ static const struct udevice_id ffa_match_id[] = {
+ {},
+ };
+
++/**
++ * Unmap the rxtx buffer before exiting u-boot
++ * This avoids conflicts with the linux kernel ffa driver
++ */
++
++static int ffa_remove(struct udevice *dev)
++{
++ return ffa_unmap_rxtx_buffers();
++}
++
+ /**
+ * Declaring the arm_ffa driver under UCLASS_FFA
+ */
+@@ -1481,4 +1491,6 @@ U_BOOT_DRIVER(arm_ffa) = {
+ .of_to_plat = ffa_of_to_plat,
+ .probe = ffa_probe,
+ .plat_auto = sizeof(struct ffa_pdata),
++ .remove = ffa_remove,
++ .flags = DM_FLAG_OS_PREPARE,
+ };
+--
+2.34.1
+
@@ -87,4 +87,10 @@ SRC_URI:append:juno = " file://0001-arm-juno-add-custom-bootcmd-to-autoboot-from
SRC_URI:append:tc = " \
file://bootargs.cfg \
file://0001-arm-total_compute-update-secure-dram-size.patch \
+ file://0002-arm_ffa-introducing-Arm-FF-A-low-level-driver.patch \
+ file://0003-arm-total_compute-enable-psci.patch \
+ file://0004-arm_ffa-rxtx_map-should-use-64-bit-calls.patch \
+ file://0005-efi_firmware-add-new-fmp-driver-that-supports-arm-fw.patch \
+ file://0006-arm-total_compute-enable-capsule-update.patch \
+ file://0007-arm_ffa-unmap-rxtx-buffer-before-exiting-u-boot.patch \
"
Signed-off-by: Davidson K <davidson.kumaresan@arm.com> Change-Id: Ice2396de4705ed7859c2334678170ef7f17e4709 --- ...add-firmware-update-secure-partition.patch | 63 + ...erve-4-MB-for-stmm-communication-use.patch | 35 + .../trusted-firmware-a-tc.inc | 2 + ...ntroducing-Arm-FF-A-low-level-driver.patch | 2611 +++++++++++++++++ .../0003-arm-total_compute-enable-psci.patch | 30 + ...ffa-rxtx_map-should-use-64-bit-calls.patch | 37 + ...-new-fmp-driver-that-supports-arm-fw.patch | 993 +++++++ ...-total_compute-enable-capsule-update.patch | 70 + ...ap-rxtx-buffer-before-exiting-u-boot.patch | 51 + .../recipes-bsp/u-boot/u-boot_%.bbappend | 6 + 10 files changed, 3898 insertions(+) create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0008-feat-plat-tc-add-firmware-update-secure-partition.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0009-feat-plat-tc-reserve-4-MB-for-stmm-communication-use.patch create mode 100644 meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0002-arm_ffa-introducing-Arm-FF-A-low-level-driver.patch create mode 100644 meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0003-arm-total_compute-enable-psci.patch create mode 100644 meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0004-arm_ffa-rxtx_map-should-use-64-bit-calls.patch create mode 100644 meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0005-efi_firmware-add-new-fmp-driver-that-supports-arm-fw.patch create mode 100644 meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0006-arm-total_compute-enable-capsule-update.patch create mode 100644 meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0007-arm_ffa-unmap-rxtx-buffer-before-exiting-u-boot.patch