summaryrefslogtreecommitdiffstats
path: root/plat/arm/common/fconf
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:13:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:13:47 +0000
commit102b0d2daa97dae68d3eed54d8fe37a9cc38a892 (patch)
treebcf648efac40ca6139842707f0eba5a4496a6dd2 /plat/arm/common/fconf
parentInitial commit. (diff)
downloadarm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.tar.xz
arm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.zip
Adding upstream version 2.8.0+dfsg.upstream/2.8.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plat/arm/common/fconf')
-rw-r--r--plat/arm/common/fconf/arm_fconf_io.c381
-rw-r--r--plat/arm/common/fconf/arm_fconf_sp.c165
-rw-r--r--plat/arm/common/fconf/fconf_ethosn_getter.c354
-rw-r--r--plat/arm/common/fconf/fconf_nv_cntr_getter.c62
-rw-r--r--plat/arm/common/fconf/fconf_sdei_getter.c103
-rw-r--r--plat/arm/common/fconf/fconf_sec_intr_config.c131
6 files changed, 1196 insertions, 0 deletions
diff --git a/plat/arm/common/fconf/arm_fconf_io.c b/plat/arm/common/fconf/arm_fconf_io.c
new file mode 100644
index 0000000..6c32331
--- /dev/null
+++ b/plat/arm/common/fconf/arm_fconf_io.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/partition/partition.h>
+#include <lib/object_pool.h>
+#include <libfdt.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <plat/arm/common/arm_fconf_getter.h>
+#include <plat/arm/common/arm_fconf_io_storage.h>
+#include <platform_def.h>
+
+#if PSA_FWU_SUPPORT
+/* metadata entry details */
+static io_block_spec_t fwu_metadata_spec;
+#endif /* PSA_FWU_SUPPORT */
+
+io_block_spec_t fip_block_spec = {
+/*
+ * This is fixed FIP address used by BL1, BL2 loads partition table
+ * to get FIP address.
+ */
+#if ARM_GPT_SUPPORT
+ .offset = PLAT_ARM_FLASH_IMAGE_BASE + PLAT_ARM_FIP_OFFSET_IN_GPT,
+#else
+ .offset = PLAT_ARM_FLASH_IMAGE_BASE,
+#endif /* ARM_GPT_SUPPORT */
+ .length = PLAT_ARM_FLASH_IMAGE_MAX_SIZE
+};
+
+#if ARM_GPT_SUPPORT
+static const io_block_spec_t gpt_spec = {
+ .offset = PLAT_ARM_FLASH_IMAGE_BASE,
+ /*
+ * PLAT_PARTITION_BLOCK_SIZE = 512
+ * PLAT_PARTITION_MAX_ENTRIES = 128
+ * each sector has 4 partition entries, and there are
+ * 2 reserved sectors i.e. protective MBR and primary
+ * GPT header hence length gets calculated as,
+ * length = 512 * (128/4 + 2)
+ */
+ .length = PLAT_PARTITION_BLOCK_SIZE *
+ (PLAT_PARTITION_MAX_ENTRIES / 4 + 2),
+};
+#endif /* ARM_GPT_SUPPORT */
+
+const io_uuid_spec_t arm_uuid_spec[MAX_NUMBER_IDS] = {
+ [BL2_IMAGE_ID] = {UUID_TRUSTED_BOOT_FIRMWARE_BL2},
+ [TB_FW_CONFIG_ID] = {UUID_TB_FW_CONFIG},
+ [FW_CONFIG_ID] = {UUID_FW_CONFIG},
+#if !ARM_IO_IN_DTB
+ [SCP_BL2_IMAGE_ID] = {UUID_SCP_FIRMWARE_SCP_BL2},
+ [BL31_IMAGE_ID] = {UUID_EL3_RUNTIME_FIRMWARE_BL31},
+ [BL32_IMAGE_ID] = {UUID_SECURE_PAYLOAD_BL32},
+ [BL32_EXTRA1_IMAGE_ID] = {UUID_SECURE_PAYLOAD_BL32_EXTRA1},
+ [BL32_EXTRA2_IMAGE_ID] = {UUID_SECURE_PAYLOAD_BL32_EXTRA2},
+ [BL33_IMAGE_ID] = {UUID_NON_TRUSTED_FIRMWARE_BL33},
+ [HW_CONFIG_ID] = {UUID_HW_CONFIG},
+ [SOC_FW_CONFIG_ID] = {UUID_SOC_FW_CONFIG},
+ [TOS_FW_CONFIG_ID] = {UUID_TOS_FW_CONFIG},
+ [NT_FW_CONFIG_ID] = {UUID_NT_FW_CONFIG},
+ [RMM_IMAGE_ID] = {UUID_REALM_MONITOR_MGMT_FIRMWARE},
+#endif /* ARM_IO_IN_DTB */
+#if TRUSTED_BOARD_BOOT
+ [TRUSTED_BOOT_FW_CERT_ID] = {UUID_TRUSTED_BOOT_FW_CERT},
+#if !ARM_IO_IN_DTB
+ [CCA_CONTENT_CERT_ID] = {UUID_CCA_CONTENT_CERT},
+ [CORE_SWD_KEY_CERT_ID] = {UUID_CORE_SWD_KEY_CERT},
+ [PLAT_KEY_CERT_ID] = {UUID_PLAT_KEY_CERT},
+ [TRUSTED_KEY_CERT_ID] = {UUID_TRUSTED_KEY_CERT},
+ [SCP_FW_KEY_CERT_ID] = {UUID_SCP_FW_KEY_CERT},
+ [SOC_FW_KEY_CERT_ID] = {UUID_SOC_FW_KEY_CERT},
+ [TRUSTED_OS_FW_KEY_CERT_ID] = {UUID_TRUSTED_OS_FW_KEY_CERT},
+ [NON_TRUSTED_FW_KEY_CERT_ID] = {UUID_NON_TRUSTED_FW_KEY_CERT},
+ [SCP_FW_CONTENT_CERT_ID] = {UUID_SCP_FW_CONTENT_CERT},
+ [SOC_FW_CONTENT_CERT_ID] = {UUID_SOC_FW_CONTENT_CERT},
+ [TRUSTED_OS_FW_CONTENT_CERT_ID] = {UUID_TRUSTED_OS_FW_CONTENT_CERT},
+ [NON_TRUSTED_FW_CONTENT_CERT_ID] = {UUID_NON_TRUSTED_FW_CONTENT_CERT},
+#if defined(SPD_spmd)
+ [SIP_SP_CONTENT_CERT_ID] = {UUID_SIP_SECURE_PARTITION_CONTENT_CERT},
+ [PLAT_SP_CONTENT_CERT_ID] = {UUID_PLAT_SECURE_PARTITION_CONTENT_CERT},
+#endif
+#endif /* ARM_IO_IN_DTB */
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+/* By default, ARM platforms load images from the FIP */
+struct plat_io_policy policies[MAX_NUMBER_IDS] = {
+#if ARM_GPT_SUPPORT
+ [GPT_IMAGE_ID] = {
+ &memmap_dev_handle,
+ (uintptr_t)&gpt_spec,
+ open_memmap
+ },
+#endif /* ARM_GPT_SUPPORT */
+#if PSA_FWU_SUPPORT
+ [FWU_METADATA_IMAGE_ID] = {
+ &memmap_dev_handle,
+ /* filled runtime from partition information */
+ (uintptr_t)&fwu_metadata_spec,
+ open_memmap
+ },
+ [BKUP_FWU_METADATA_IMAGE_ID] = {
+ &memmap_dev_handle,
+ /* filled runtime from partition information */
+ (uintptr_t)&fwu_metadata_spec,
+ open_memmap
+ },
+#endif /* PSA_FWU_SUPPORT */
+ [FIP_IMAGE_ID] = {
+ &memmap_dev_handle,
+ (uintptr_t)&fip_block_spec,
+ open_memmap
+ },
+ [BL2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL2_IMAGE_ID],
+ open_fip
+ },
+ [TB_FW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TB_FW_CONFIG_ID],
+ open_fip
+ },
+ [FW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[FW_CONFIG_ID],
+ open_fip
+ },
+#if !ARM_IO_IN_DTB
+ [SCP_BL2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SCP_BL2_IMAGE_ID],
+ open_fip
+ },
+ [BL31_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL31_IMAGE_ID],
+ open_fip
+ },
+ [BL32_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL32_IMAGE_ID],
+ open_fip
+ },
+ [BL32_EXTRA1_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL32_EXTRA1_IMAGE_ID],
+ open_fip
+ },
+ [BL32_EXTRA2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL32_EXTRA2_IMAGE_ID],
+ open_fip
+ },
+ [BL33_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL33_IMAGE_ID],
+ open_fip
+ },
+ [RMM_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[RMM_IMAGE_ID],
+ open_fip
+ },
+ [HW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[HW_CONFIG_ID],
+ open_fip
+ },
+ [SOC_FW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SOC_FW_CONFIG_ID],
+ open_fip
+ },
+ [TOS_FW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TOS_FW_CONFIG_ID],
+ open_fip
+ },
+ [NT_FW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[NT_FW_CONFIG_ID],
+ open_fip
+ },
+#endif /* ARM_IO_IN_DTB */
+#if TRUSTED_BOARD_BOOT
+ [TRUSTED_BOOT_FW_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TRUSTED_BOOT_FW_CERT_ID],
+ open_fip
+ },
+#if !ARM_IO_IN_DTB
+ [CCA_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[CCA_CONTENT_CERT_ID],
+ open_fip
+ },
+ [CORE_SWD_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[CORE_SWD_KEY_CERT_ID],
+ open_fip
+ },
+ [PLAT_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[PLAT_KEY_CERT_ID],
+ open_fip
+ },
+ [TRUSTED_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TRUSTED_KEY_CERT_ID],
+ open_fip
+ },
+ [SCP_FW_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SCP_FW_KEY_CERT_ID],
+ open_fip
+ },
+ [SOC_FW_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SOC_FW_KEY_CERT_ID],
+ open_fip
+ },
+ [TRUSTED_OS_FW_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TRUSTED_OS_FW_KEY_CERT_ID],
+ open_fip
+ },
+ [NON_TRUSTED_FW_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[NON_TRUSTED_FW_KEY_CERT_ID],
+ open_fip
+ },
+ [SCP_FW_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SCP_FW_CONTENT_CERT_ID],
+ open_fip
+ },
+ [SOC_FW_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SOC_FW_CONTENT_CERT_ID],
+ open_fip
+ },
+ [TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TRUSTED_OS_FW_CONTENT_CERT_ID],
+ open_fip
+ },
+ [NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[NON_TRUSTED_FW_CONTENT_CERT_ID],
+ open_fip
+ },
+#if defined(SPD_spmd)
+ [SIP_SP_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SIP_SP_CONTENT_CERT_ID],
+ open_fip
+ },
+ [PLAT_SP_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[PLAT_SP_CONTENT_CERT_ID],
+ open_fip
+ },
+#endif
+#endif /* ARM_IO_IN_DTB */
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+#ifdef IMAGE_BL2
+
+#if TRUSTED_BOARD_BOOT
+#define FCONF_ARM_IO_UUID_NUMBER U(24)
+#else
+#define FCONF_ARM_IO_UUID_NUMBER U(10)
+#endif
+
+static io_uuid_spec_t fconf_arm_uuids[FCONF_ARM_IO_UUID_NUMBER];
+static OBJECT_POOL_ARRAY(fconf_arm_uuids_pool, fconf_arm_uuids);
+
+struct policies_load_info {
+ unsigned int image_id;
+ const char *name;
+};
+
+/* image id to property name table */
+static const struct policies_load_info load_info[FCONF_ARM_IO_UUID_NUMBER] = {
+ {SCP_BL2_IMAGE_ID, "scp_bl2_uuid"},
+ {BL31_IMAGE_ID, "bl31_uuid"},
+ {BL32_IMAGE_ID, "bl32_uuid"},
+ {BL32_EXTRA1_IMAGE_ID, "bl32_extra1_uuid"},
+ {BL32_EXTRA2_IMAGE_ID, "bl32_extra2_uuid"},
+ {BL33_IMAGE_ID, "bl33_uuid"},
+ {HW_CONFIG_ID, "hw_cfg_uuid"},
+ {SOC_FW_CONFIG_ID, "soc_fw_cfg_uuid"},
+ {TOS_FW_CONFIG_ID, "tos_fw_cfg_uuid"},
+ {NT_FW_CONFIG_ID, "nt_fw_cfg_uuid"},
+#if TRUSTED_BOARD_BOOT
+ {CCA_CONTENT_CERT_ID, "cca_cert_uuid"},
+ {CORE_SWD_KEY_CERT_ID, "core_swd_cert_uuid"},
+ {PLAT_KEY_CERT_ID, "plat_cert_uuid"},
+ {TRUSTED_KEY_CERT_ID, "t_key_cert_uuid"},
+ {SCP_FW_KEY_CERT_ID, "scp_fw_key_uuid"},
+ {SOC_FW_KEY_CERT_ID, "soc_fw_key_uuid"},
+ {TRUSTED_OS_FW_KEY_CERT_ID, "tos_fw_key_cert_uuid"},
+ {NON_TRUSTED_FW_KEY_CERT_ID, "nt_fw_key_cert_uuid"},
+ {SCP_FW_CONTENT_CERT_ID, "scp_fw_content_cert_uuid"},
+ {SOC_FW_CONTENT_CERT_ID, "soc_fw_content_cert_uuid"},
+ {TRUSTED_OS_FW_CONTENT_CERT_ID, "tos_fw_content_cert_uuid"},
+ {NON_TRUSTED_FW_CONTENT_CERT_ID, "nt_fw_content_cert_uuid"},
+#if defined(SPD_spmd)
+ {SIP_SP_CONTENT_CERT_ID, "sip_sp_content_cert_uuid"},
+ {PLAT_SP_CONTENT_CERT_ID, "plat_sp_content_cert_uuid"},
+#endif
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+int fconf_populate_arm_io_policies(uintptr_t config)
+{
+ int err, node;
+ unsigned int i;
+
+ union uuid_helper_t uuid_helper;
+ io_uuid_spec_t *uuid_ptr;
+
+ /* As libfdt uses void *, we can't avoid this cast */
+ const void *dtb = (void *)config;
+
+ /* Assert the node offset point to "arm,io-fip-handle" compatible property */
+ const char *compatible_str = "arm,io-fip-handle";
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str);
+ return node;
+ }
+
+ /* Locate the uuid cells and read the value for all the load info uuid */
+ for (i = 0; i < FCONF_ARM_IO_UUID_NUMBER; i++) {
+ uuid_ptr = pool_alloc(&fconf_arm_uuids_pool);
+ err = fdtw_read_uuid(dtb, node, load_info[i].name, 16,
+ (uint8_t *)&uuid_helper);
+ if (err < 0) {
+ WARN("FCONF: Read cell failed for %s\n", load_info[i].name);
+ return err;
+ }
+
+ VERBOSE("FCONF: arm-io_policies.%s cell found with value = "
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+ load_info[i].name,
+ uuid_helper.uuid_struct.time_low[0], uuid_helper.uuid_struct.time_low[1],
+ uuid_helper.uuid_struct.time_low[2], uuid_helper.uuid_struct.time_low[3],
+ uuid_helper.uuid_struct.time_mid[0], uuid_helper.uuid_struct.time_mid[1],
+ uuid_helper.uuid_struct.time_hi_and_version[0],
+ uuid_helper.uuid_struct.time_hi_and_version[1],
+ uuid_helper.uuid_struct.clock_seq_hi_and_reserved,
+ uuid_helper.uuid_struct.clock_seq_low,
+ uuid_helper.uuid_struct.node[0], uuid_helper.uuid_struct.node[1],
+ uuid_helper.uuid_struct.node[2], uuid_helper.uuid_struct.node[3],
+ uuid_helper.uuid_struct.node[4], uuid_helper.uuid_struct.node[5]);
+
+ uuid_ptr->uuid = uuid_helper.uuid_struct;
+ policies[load_info[i].image_id].image_spec = (uintptr_t)uuid_ptr;
+ policies[load_info[i].image_id].dev_handle = &fip_dev_handle;
+ policies[load_info[i].image_id].check = open_fip;
+ }
+ return 0;
+}
+
+#if ARM_IO_IN_DTB
+FCONF_REGISTER_POPULATOR(TB_FW, arm_io, fconf_populate_arm_io_policies);
+#endif /* ARM_IO_IN_DTB */
+
+#endif /* IMAGE_BL2 */
diff --git a/plat/arm/common/fconf/arm_fconf_sp.c b/plat/arm/common/fconf/arm_fconf_sp.c
new file mode 100644
index 0000000..18c83c7
--- /dev/null
+++ b/plat/arm/common/fconf/arm_fconf_sp.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/io/io_storage.h>
+#include <lib/object_pool.h>
+#include <libfdt.h>
+#include <plat/arm/common/arm_fconf_getter.h>
+#include <plat/arm/common/arm_fconf_io_storage.h>
+#include <plat/arm/common/fconf_arm_sp_getter.h>
+#include <platform_def.h>
+#include <tools_share/firmware_image_package.h>
+
+#ifdef IMAGE_BL2
+
+bl_mem_params_node_t sp_mem_params_descs[MAX_SP_IDS];
+
+struct arm_sp_t arm_sp;
+
+int fconf_populate_arm_sp(uintptr_t config)
+{
+ int sp_node, node, err;
+ union uuid_helper_t uuid_helper;
+ unsigned int index = 0;
+ uint32_t val32;
+ const unsigned int sip_start = SP_PKG1_ID;
+ unsigned int sip_index = sip_start;
+#if defined(ARM_COT_dualroot)
+ const unsigned int sip_end = sip_start + MAX_SP_IDS / 2;
+ /* Allocating index range for platform SPs */
+ const unsigned int plat_start = SP_PKG5_ID;
+ unsigned int plat_index = plat_start;
+ const unsigned int plat_end = plat_start + MAX_SP_IDS / 2;
+ bool is_plat_owned = false;
+#endif /* ARM_COT_dualroot */
+
+ /* As libfdt use void *, we can't avoid this cast */
+ const void *dtb = (void *)config;
+
+ /* Assert the node offset point to "arm,sp" compatible property */
+ const char *compatible_str = "arm,sp";
+
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find %s in dtb\n", compatible_str);
+ return node;
+ }
+
+ fdt_for_each_subnode(sp_node, dtb, node) {
+ if (index == MAX_SP_IDS) {
+ ERROR("FCONF: Reached max number of SPs\n");
+ return -1;
+ }
+
+#if defined(ARM_COT_dualroot)
+ if ((sip_index == sip_end) || (plat_index == plat_end)) {
+ ERROR("FCONF: Reached max number of plat/SiP SPs\n");
+ return -1;
+ }
+#endif /* ARM_COT_dualroot */
+
+ /* Read UUID */
+ err = fdtw_read_uuid(dtb, sp_node, "uuid", 16,
+ (uint8_t *)&uuid_helper);
+ if (err < 0) {
+ ERROR("FCONF: cannot read SP uuid\n");
+ return -1;
+ }
+
+ arm_sp.uuids[index] = uuid_helper;
+
+ /* Read Load address */
+ err = fdt_read_uint32(dtb, sp_node, "load-address", &val32);
+ if (err < 0) {
+ ERROR("FCONF: cannot read SP load address\n");
+ return -1;
+ }
+ arm_sp.load_addr[index] = val32;
+
+ VERBOSE("FCONF: %s UUID"
+ " %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+ " load_addr=%lx\n",
+ __func__,
+ uuid_helper.uuid_struct.time_low[0], uuid_helper.uuid_struct.time_low[1],
+ uuid_helper.uuid_struct.time_low[2], uuid_helper.uuid_struct.time_low[3],
+ uuid_helper.uuid_struct.time_mid[0], uuid_helper.uuid_struct.time_mid[1],
+ uuid_helper.uuid_struct.time_hi_and_version[0],
+ uuid_helper.uuid_struct.time_hi_and_version[1],
+ uuid_helper.uuid_struct.clock_seq_hi_and_reserved,
+ uuid_helper.uuid_struct.clock_seq_low,
+ uuid_helper.uuid_struct.node[0], uuid_helper.uuid_struct.node[1],
+ uuid_helper.uuid_struct.node[2], uuid_helper.uuid_struct.node[3],
+ uuid_helper.uuid_struct.node[4], uuid_helper.uuid_struct.node[5],
+ arm_sp.load_addr[index]);
+
+ /* Read owner field only for dualroot CoT */
+#if defined(ARM_COT_dualroot)
+ /* Owner is an optional field, no need to catch error */
+ fdtw_read_string(dtb, sp_node, "owner",
+ arm_sp.owner[index], ARM_SP_OWNER_NAME_LEN);
+
+ /* If owner is empty mark it as SiP owned */
+ if ((strncmp(arm_sp.owner[index], "SiP",
+ ARM_SP_OWNER_NAME_LEN) == 0) ||
+ (strncmp(arm_sp.owner[index], "",
+ ARM_SP_OWNER_NAME_LEN) == 0)) {
+ is_plat_owned = false;
+ } else if (strcmp(arm_sp.owner[index], "Plat") == 0) {
+ is_plat_owned = true;
+ } else {
+ ERROR("FCONF: %s is not a valid SP owner\n",
+ arm_sp.owner[index]);
+ return -1;
+ }
+ /*
+ * Add SP information in mem param descriptor and IO policies
+ * structure.
+ */
+ if (is_plat_owned) {
+ sp_mem_params_descs[index].image_id = plat_index;
+ policies[plat_index].image_spec =
+ (uintptr_t)&arm_sp.uuids[index];
+ policies[plat_index].dev_handle = &fip_dev_handle;
+ policies[plat_index].check = open_fip;
+ plat_index++;
+ } else
+#endif /* ARM_COT_dualroot */
+ {
+ sp_mem_params_descs[index].image_id = sip_index;
+ policies[sip_index].image_spec =
+ (uintptr_t)&arm_sp.uuids[index];
+ policies[sip_index].dev_handle = &fip_dev_handle;
+ policies[sip_index].check = open_fip;
+ sip_index++;
+ }
+ SET_PARAM_HEAD(&sp_mem_params_descs[index].image_info,
+ PARAM_IMAGE_BINARY, VERSION_2, 0);
+ sp_mem_params_descs[index].image_info.image_max_size =
+ ARM_SP_MAX_SIZE;
+ sp_mem_params_descs[index].next_handoff_image_id =
+ INVALID_IMAGE_ID;
+ sp_mem_params_descs[index].image_info.image_base =
+ arm_sp.load_addr[index];
+ index++;
+ }
+
+ if ((sp_node < 0) && (sp_node != -FDT_ERR_NOTFOUND)) {
+ ERROR("%u: fdt_for_each_subnode(): %d\n", __LINE__, node);
+ return sp_node;
+ }
+
+ arm_sp.number_of_sp = index;
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(TB_FW, arm_sp, fconf_populate_arm_sp);
+
+#endif /* IMAGE_BL2 */
diff --git a/plat/arm/common/fconf/fconf_ethosn_getter.c b/plat/arm/common/fconf/fconf_ethosn_getter.c
new file mode 100644
index 0000000..0b48a98
--- /dev/null
+++ b/plat/arm/common/fconf/fconf_ethosn_getter.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <plat/arm/common/fconf_ethosn_getter.h>
+
+struct ethosn_config_t ethosn_config = {0};
+
+struct ethosn_sub_allocator_t {
+ const char *name;
+ size_t name_len;
+ uint32_t stream_id;
+};
+
+static bool fdt_node_is_enabled(const void *fdt, int node)
+{
+ int len;
+ const char *node_status;
+
+ node_status = fdt_getprop(fdt, node, "status", &len);
+ if (node_status == NULL ||
+ (len == 5 && /* Includes null character */
+ strncmp(node_status, "okay", 4U) == 0)) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool fdt_node_has_reserved_memory(const void *fdt, int dev_node)
+{
+ return fdt_get_property(fdt, dev_node, "memory-region", NULL) != NULL;
+}
+
+static int fdt_node_get_iommus_stream_id(const void *fdt, int node, uint32_t *stream_id)
+{
+ int err;
+ uint32_t iommus_array[2] = {0U};
+
+ err = fdt_read_uint32_array(fdt, node, "iommus", 2U, iommus_array);
+ if (err) {
+ return err;
+ }
+
+ *stream_id = iommus_array[1];
+ return 0;
+}
+
+static int fdt_node_populate_sub_allocators(const void *fdt,
+ int alloc_node,
+ struct ethosn_sub_allocator_t *sub_allocators,
+ size_t num_allocs)
+{
+ int sub_node;
+ size_t i;
+ int err = -FDT_ERR_NOTFOUND;
+ uint32_t found_sub_allocators = 0U;
+
+ fdt_for_each_subnode(sub_node, fdt, alloc_node) {
+ const char *node_name;
+
+ if (!fdt_node_is_enabled(fdt, sub_node)) {
+ /* Ignore disabled node */
+ continue;
+ }
+
+ if (fdt_node_check_compatible(fdt, sub_node, "ethosn-memory") != 0) {
+ continue;
+ }
+
+ node_name = fdt_get_name(fdt, sub_node, NULL);
+ for (i = 0U; i < num_allocs; ++i) {
+ if (strncmp(node_name, sub_allocators[i].name,
+ sub_allocators[i].name_len) != 0) {
+ continue;
+ }
+
+ err = fdt_node_get_iommus_stream_id(fdt, sub_node,
+ &sub_allocators[i].stream_id);
+ if (err) {
+ ERROR("FCONF: Failed to get stream ID from sub-allocator %s\n",
+ node_name);
+ return err;
+ }
+
+ ++found_sub_allocators;
+ /* Nothing more to do for this node */
+ break;
+ }
+
+ /* Check that at least one of the sub-allocators matched */
+ if (i == num_allocs) {
+ ERROR("FCONF: Unknown sub-allocator %s\n", node_name);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ }
+
+ if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
+ ERROR("FCONF: Failed to parse sub-allocators\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (err == -FDT_ERR_NOTFOUND) {
+ ERROR("FCONF: No matching sub-allocator found\n");
+ return err;
+ }
+
+ if (found_sub_allocators != num_allocs) {
+ ERROR("FCONF: Not all sub-allocators were found\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ return 0;
+}
+
+static int fdt_node_populate_main_allocator(const void *fdt,
+ int alloc_node,
+ struct ethosn_main_allocator_t *allocator)
+{
+ int err;
+ struct ethosn_sub_allocator_t sub_allocators[] = {
+ {.name = "firmware", .name_len = 8U},
+ {.name = "working_data", .name_len = 12U}
+ };
+
+ err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
+ ARRAY_SIZE(sub_allocators));
+ if (err) {
+ return err;
+ }
+
+ allocator->firmware.stream_id = sub_allocators[0].stream_id;
+ allocator->working_data.stream_id = sub_allocators[1].stream_id;
+
+ return 0;
+}
+
+static int fdt_node_populate_asset_allocator(const void *fdt,
+ int alloc_node,
+ struct ethosn_asset_allocator_t *allocator)
+{
+ int err;
+ struct ethosn_sub_allocator_t sub_allocators[] = {
+ {.name = "command_stream", .name_len = 14U},
+ {.name = "weight_data", .name_len = 11U},
+ {.name = "buffer_data", .name_len = 11U},
+ {.name = "intermediate_data", .name_len = 17U}
+ };
+
+ err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
+ ARRAY_SIZE(sub_allocators));
+ if (err) {
+ return err;
+ }
+
+
+ allocator->command_stream.stream_id = sub_allocators[0].stream_id;
+ allocator->weight_data.stream_id = sub_allocators[1].stream_id;
+ allocator->buffer_data.stream_id = sub_allocators[2].stream_id;
+ allocator->intermediate_data.stream_id = sub_allocators[3].stream_id;
+ return 0;
+}
+
+static int fdt_node_populate_core(const void *fdt,
+ int device_node,
+ int core_node,
+ bool has_reserved_memory,
+ uint32_t core_index,
+ struct ethosn_core_t *core)
+{
+ int err;
+ int sub_node;
+ uintptr_t core_addr;
+
+ err = fdt_get_reg_props_by_index(fdt, device_node, core_index,
+ &core_addr, NULL);
+ if (err < 0) {
+ ERROR("FCONF: Failed to read reg property for NPU core %u\n",
+ core_index);
+ return err;
+ }
+
+ err = -FDT_ERR_NOTFOUND;
+ fdt_for_each_subnode(sub_node, fdt, core_node) {
+
+ if (!fdt_node_is_enabled(fdt, sub_node)) {
+ continue;
+ }
+
+ if (fdt_node_check_compatible(fdt,
+ sub_node,
+ "ethosn-main_allocator") != 0) {
+ continue;
+ }
+
+ if (has_reserved_memory) {
+ ERROR("FCONF: Main allocator not supported when using reserved memory\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (err != -FDT_ERR_NOTFOUND) {
+ ERROR("FCONF: NPU core 0x%lx has more than one main allocator\n",
+ core_addr);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ err = fdt_node_populate_main_allocator(fdt, sub_node, &core->main_allocator);
+ if (err) {
+ ERROR("FCONF: Failed to parse main allocator for NPU core 0x%lx\n",
+ core_addr);
+ return err;
+ }
+ }
+
+ if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
+ ERROR("FCONF: Failed to parse core sub nodes\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (!has_reserved_memory && err) {
+ ERROR("FCONF: Main allocator not found for NPU core 0x%lx\n",
+ core_addr);
+ return err;
+ }
+
+ core->addr = core_addr;
+
+ return 0;
+}
+
+int fconf_populate_ethosn_config(uintptr_t config)
+{
+ int ethosn_node;
+ uint32_t dev_count = 0U;
+ const void *hw_conf_dtb = (const void *)config;
+
+ INFO("Probing Arm(R) Ethos(TM)-N NPU\n");
+
+ fdt_for_each_compatible_node(hw_conf_dtb, ethosn_node, "ethosn") {
+ struct ethosn_device_t *dev = &ethosn_config.devices[dev_count];
+ uint32_t dev_asset_alloc_count = 0U;
+ uint32_t dev_core_count = 0U;
+ bool has_reserved_memory;
+ int sub_node;
+
+ if (!fdt_node_is_enabled(hw_conf_dtb, ethosn_node)) {
+ continue;
+ }
+
+ if (dev_count >= ETHOSN_DEV_NUM_MAX) {
+ ERROR("FCONF: Reached max number of NPUs\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ has_reserved_memory = fdt_node_has_reserved_memory(hw_conf_dtb, ethosn_node);
+ fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) {
+ int err;
+
+ if (!fdt_node_is_enabled(hw_conf_dtb, sub_node)) {
+ /* Ignore disabled sub node */
+ continue;
+ }
+
+ if (fdt_node_check_compatible(hw_conf_dtb,
+ sub_node,
+ "ethosn-core") == 0) {
+
+ if (dev_core_count >= ETHOSN_DEV_CORE_NUM_MAX) {
+ ERROR("FCONF: Reached max number of NPU cores for NPU %u\n",
+ dev_count);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ err = fdt_node_populate_core(hw_conf_dtb,
+ ethosn_node,
+ sub_node,
+ has_reserved_memory,
+ dev_core_count,
+ &(dev->cores[dev_core_count]));
+ if (err) {
+ return err;
+ }
+ ++dev_core_count;
+ } else if (fdt_node_check_compatible(hw_conf_dtb,
+ sub_node,
+ "ethosn-asset_allocator") == 0) {
+
+ if (dev_asset_alloc_count >=
+ ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX) {
+ ERROR("FCONF: Reached max number of asset allocators for NPU %u\n",
+ dev_count);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (has_reserved_memory) {
+ ERROR("FCONF: Asset allocator not supported when using reserved memory\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ err = fdt_node_populate_asset_allocator(hw_conf_dtb,
+ sub_node,
+ &(dev->asset_allocators[dev_asset_alloc_count]));
+ if (err) {
+ ERROR("FCONF: Failed to parse asset allocator for NPU %u\n",
+ dev_count);
+ return err;
+ }
+ ++dev_asset_alloc_count;
+ }
+ }
+
+ if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
+ ERROR("FCONF: Failed to parse sub nodes for NPU %u\n",
+ dev_count);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (dev_core_count == 0U) {
+ ERROR("FCONF: NPU %u must have at least one enabled core\n",
+ dev_count);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (!has_reserved_memory && dev_asset_alloc_count == 0U) {
+ ERROR("FCONF: NPU %u must have at least one asset allocator\n",
+ dev_count);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ dev->num_cores = dev_core_count;
+ dev->num_allocators = dev_asset_alloc_count;
+ dev->has_reserved_memory = has_reserved_memory;
+ ++dev_count;
+ }
+
+ if (dev_count == 0U) {
+ ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ ethosn_config.num_devices = dev_count;
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config);
diff --git a/plat/arm/common/fconf/fconf_nv_cntr_getter.c b/plat/arm/common/fconf/fconf_nv_cntr_getter.c
new file mode 100644
index 0000000..8d645ef
--- /dev/null
+++ b/plat/arm/common/fconf/fconf_nv_cntr_getter.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+
+#include <libfdt.h>
+
+#include <plat/arm/common/fconf_nv_cntr_getter.h>
+
+/*******************************************************************************
+ * fconf_populate_cot_descs() - Populate available nv-counters and update global
+ * structure.
+ * @config[in]: Pointer to the device tree blob in memory
+ *
+ * Return 0 on success or an error value otherwise.
+ ******************************************************************************/
+static int fconf_populate_nv_cntrs(uintptr_t config)
+{
+ int rc, node, child;
+ uint32_t id;
+ uintptr_t reg;
+
+ /* As libfdt uses void *, we can't avoid this cast */
+ const void *dtb = (void *)config;
+ const char *compatible_str = "arm, non-volatile-counter";
+
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find %s compatible in node\n",
+ compatible_str);
+ return node;
+ }
+
+ fdt_for_each_subnode(child, dtb, node) {
+
+ rc = fdt_read_uint32(dtb, child, "id", &id);
+ if (rc < 0) {
+ ERROR("FCONF: Can't find %s property in node\n", "id");
+ return rc;
+ }
+
+ assert(id < MAX_NV_CTR_IDS);
+
+ rc = fdt_get_reg_props_by_index(dtb, child, 0, &reg, NULL);
+ if (rc < 0) {
+ ERROR("FCONF: Can't find %s property in node\n", "reg");
+ return rc;
+ }
+
+ nv_cntr_base_addr[id] = reg;
+ }
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(TB_FW, nv_cntrs, fconf_populate_nv_cntrs);
diff --git a/plat/arm/common/fconf/fconf_sdei_getter.c b/plat/arm/common/fconf/fconf_sdei_getter.c
new file mode 100644
index 0000000..c26e316
--- /dev/null
+++ b/plat/arm/common/fconf/fconf_sdei_getter.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <plat/arm/common/fconf_sdei_getter.h>
+
+#define PRIVATE_EVENT_NUM(i) private_events[3 * (i)]
+#define PRIVATE_EVENT_INTR(i) private_events[3 * (i) + 1]
+#define PRIVATE_EVENT_FLAGS(i) private_events[3 * (i) + 2]
+
+#define SHARED_EVENT_NUM(i) shared_events[3 * (i)]
+#define SHARED_EVENT_INTR(i) shared_events[3 * (i) + 1]
+#define SHARED_EVENT_FLAGS(i) shared_events[3 * (i) + 2]
+
+struct sdei_dyn_config_t sdei_dyn_config;
+
+int fconf_populate_sdei_dyn_config(uintptr_t config)
+{
+ uint32_t i;
+ int node, err;
+ uint32_t private_events[PLAT_SDEI_DP_EVENT_MAX_CNT * 3];
+ uint32_t shared_events[PLAT_SDEI_DS_EVENT_MAX_CNT * 3];
+
+ const void *dtb = (void *)config;
+
+ /* Check that the node offset points to compatible property */
+ node = fdt_node_offset_by_compatible(dtb, -1, "arm,sdei-1.0");
+ if (node < 0) {
+ ERROR("FCONF: Can't find 'arm,sdei-1.0' compatible node in dtb\n");
+ return node;
+ }
+
+ /* Read number of private mappings */
+ err = fdt_read_uint32(dtb, node, "private_event_count",
+ &sdei_dyn_config.private_ev_cnt);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'private_event_count': %u\n",
+ sdei_dyn_config.private_ev_cnt);
+ return err;
+ }
+
+ /* Check if the value is in range */
+ if (sdei_dyn_config.private_ev_cnt > PLAT_SDEI_DP_EVENT_MAX_CNT) {
+ ERROR("FCONF: Invalid value for 'private_event_count': %u\n",
+ sdei_dyn_config.private_ev_cnt);
+ return -1;
+ }
+
+ /* Read private mappings */
+ err = fdt_read_uint32_array(dtb, node, "private_events",
+ sdei_dyn_config.private_ev_cnt * 3, private_events);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'private_events': %d\n", err);
+ return err;
+ }
+
+ /* Move data to fconf struct */
+ for (i = 0; i < sdei_dyn_config.private_ev_cnt; i++) {
+ sdei_dyn_config.private_ev_nums[i] = PRIVATE_EVENT_NUM(i);
+ sdei_dyn_config.private_ev_intrs[i] = PRIVATE_EVENT_INTR(i);
+ sdei_dyn_config.private_ev_flags[i] = PRIVATE_EVENT_FLAGS(i);
+ }
+
+ /* Read number of shared mappings */
+ err = fdt_read_uint32(dtb, node, "shared_event_count",
+ &sdei_dyn_config.shared_ev_cnt);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'shared_event_count'\n");
+ return err;
+ }
+
+ /* Check if the value is in range */
+ if (sdei_dyn_config.shared_ev_cnt > PLAT_SDEI_DS_EVENT_MAX_CNT) {
+ ERROR("FCONF: Invalid value for 'shared_event_count': %u\n",
+ sdei_dyn_config.shared_ev_cnt);
+ return -1;
+ }
+
+ /* Read shared mappings */
+ err = fdt_read_uint32_array(dtb, node, "shared_events",
+ sdei_dyn_config.shared_ev_cnt * 3, shared_events);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'shared_events': %d\n", err);
+ return err;
+ }
+
+ /* Move data to fconf struct */
+ for (i = 0; i < sdei_dyn_config.shared_ev_cnt; i++) {
+ sdei_dyn_config.shared_ev_nums[i] = SHARED_EVENT_NUM(i);
+ sdei_dyn_config.shared_ev_intrs[i] = SHARED_EVENT_INTR(i);
+ sdei_dyn_config.shared_ev_flags[i] = SHARED_EVENT_FLAGS(i);
+ }
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, sdei, fconf_populate_sdei_dyn_config);
diff --git a/plat/arm/common/fconf/fconf_sec_intr_config.c b/plat/arm/common/fconf/fconf_sec_intr_config.c
new file mode 100644
index 0000000..f28be24
--- /dev/null
+++ b/plat/arm/common/fconf/fconf_sec_intr_config.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <plat/arm/common/fconf_sec_intr_config.h>
+
+#define G0_INTR_NUM(i) g0_intr_prop[3U * (i)]
+#define G0_INTR_PRIORITY(i) g0_intr_prop[3U * (i) + 1]
+#define G0_INTR_CONFIG(i) g0_intr_prop[3U * (i) + 2]
+
+#define G1S_INTR_NUM(i) g1s_intr_prop[3U * (i)]
+#define G1S_INTR_PRIORITY(i) g1s_intr_prop[3U * (i) + 1]
+#define G1S_INTR_CONFIG(i) g1s_intr_prop[3U * (i) + 2]
+
+struct sec_intr_prop_t sec_intr_prop;
+
+static void print_intr_prop(interrupt_prop_t prop)
+{
+ VERBOSE("FCONF: Secure Interrupt NUM: %d, PRI: %d, TYPE: %d\n",
+ prop.intr_num, prop.intr_pri, prop.intr_cfg);
+}
+
+int fconf_populate_sec_intr_config(uintptr_t config)
+{
+ int node, err;
+ uint32_t g0_intr_count, g1s_intr_count;
+ uint32_t g0_intr_prop[SEC_INT_COUNT_MAX * 3];
+ uint32_t g1s_intr_prop[SEC_INT_COUNT_MAX * 3];
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)config;
+
+ node = fdt_node_offset_by_compatible(hw_config_dtb, -1,
+ "arm,secure_interrupt_desc");
+ if (node < 0) {
+ ERROR("FCONF: Unable to locate node with %s compatible property\n",
+ "arm,secure_interrupt_desc");
+ return node;
+ }
+
+ /* Read number of Group 0 interrupts specified by platform */
+ err = fdt_read_uint32(hw_config_dtb, node, "g0_intr_cnt", &g0_intr_count);
+ if (err < 0) {
+ ERROR("FCONF: Could not locate g0s_intr_cnt property\n");
+ return err;
+ }
+
+ /* At least 1 Group 0 interrupt description has to be provided*/
+ if (g0_intr_count < 1U) {
+ ERROR("FCONF: Invalid number of Group 0 interrupts count specified\n");
+ return -1;
+ }
+
+ /* Read number of Group 1 secure interrupts specified by platform */
+ err = fdt_read_uint32(hw_config_dtb, node, "g1s_intr_cnt",
+ &g1s_intr_count);
+ if (err < 0) {
+ ERROR("FCONF: Could not locate g1s_intr_cnt property\n");
+ return err;
+ }
+
+ /* At least one Group 1 interrupt description has to be provided*/
+ if (g1s_intr_count < 1U) {
+ ERROR("FCONF: Invalid number of Group 1 secure interrupts count specified\n");
+ return -1;
+ }
+
+ /*
+ * Check if the total number of secure interrupts described are within
+ * the limit defined statically by the platform.
+ */
+ if ((g0_intr_count + g1s_intr_count) > SEC_INT_COUNT_MAX) {
+ ERROR("FCONF: Total number of secure interrupts exceed limit the of %d\n",
+ SEC_INT_COUNT_MAX);
+ return -1;
+ }
+
+ sec_intr_prop.count = g0_intr_count + g1s_intr_count;
+
+ /* Read the Group 0 interrupt descriptors */
+ err = fdt_read_uint32_array(hw_config_dtb, node, "g0_intr_desc",
+ g0_intr_count * 3, g0_intr_prop);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'g0s_intr_desc': %d\n", err);
+ return err;
+ }
+
+ /* Read the Group 1 secure interrupt descriptors */
+ err = fdt_read_uint32_array(hw_config_dtb, node, "g1s_intr_desc",
+ g1s_intr_count * 3, g1s_intr_prop);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'g1s_intr_desc': %d\n", err);
+ return err;
+ }
+
+ /* Populate Group 0 interrupt descriptors into fconf based C struct */
+ for (uint32_t i = 0; i < g0_intr_count; i++) {
+ interrupt_prop_t sec_intr_property;
+
+ /* Secure Interrupt Group: INTR_GROUP0 i.e., 0x1 */
+ sec_intr_property.intr_grp = 1;
+ sec_intr_property.intr_num = G0_INTR_NUM(i);
+ sec_intr_property.intr_pri = G0_INTR_PRIORITY(i);
+ sec_intr_property.intr_cfg = G0_INTR_CONFIG(i);
+ sec_intr_prop.descriptor[i] = sec_intr_property;
+ print_intr_prop(sec_intr_property);
+ }
+
+ /* Populate G1 secure interrupt descriptors into fconf based C struct */
+ for (uint32_t i = 0; i < g1s_intr_count; i++) {
+ interrupt_prop_t sec_intr_property;
+
+ /* Secure Interrupt Group: INTR_GROUP1S i.e., 0x0 */
+ sec_intr_property.intr_grp = 0;
+ sec_intr_property.intr_num = G1S_INTR_NUM(i);
+ sec_intr_property.intr_pri = G1S_INTR_PRIORITY(i);
+ sec_intr_property.intr_cfg = G1S_INTR_CONFIG(i);
+ sec_intr_prop.descriptor[i + g0_intr_count] = sec_intr_property;
+ print_intr_prop(sec_intr_property);
+ }
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, sec_intr_prop, fconf_populate_sec_intr_config);