]> git.baikalelectronics.ru Git - arm-tf.git/commitdiff
feat(ethos-n)!: add support for SMMU streams
authorMikael Olsson <mikael.olsson@arm.com>
Mon, 15 Aug 2022 15:12:58 +0000 (17:12 +0200)
committerMikael Olsson <mikael.olsson@arm.com>
Tue, 4 Oct 2022 13:15:04 +0000 (15:15 +0200)
The Arm(R) Ethos(TM)-N NPU driver now supports configuring the SMMU
streams that the NPU shall use and will therefore no longer delegate
access to these registers to the non-secure world. In order for the
driver to support this, the device tree parsing has been updated to
support parsing the allocators used by the NPU and what SMMU stream that
is associated with each allocator.

To keep track of what NPU device each allocator is associated with, the
resulting config from the device tree parsing will now group the NPU
cores and allocators into their respective NPU device.

The SMC API has been changed to allow the caller to specify what
allocator the NPU shall be configured to use and the API version has
been bumped to indicate this change.

Signed-off-by: Mikael Olsson <mikael.olsson@arm.com>
Change-Id: I6ac43819133138614e3f55a014e93466fe3d5277

docs/plat/arm/arm-build-options.rst
drivers/arm/ethosn/ethosn_smc.c
fdts/juno-ethosn.dtsi
include/drivers/arm/ethosn.h
include/plat/arm/common/arm_sip_svc.h
include/plat/arm/common/fconf_ethosn_getter.h
plat/arm/common/arm_common.mk
plat/arm/common/fconf/fconf_ethosn_getter.c

index afe89b9367dabcfd8c443f09cf966b09429560cb..407c04bbb4ff53e20b826b5db555bfa82dd456fd 100644 (file)
@@ -92,7 +92,7 @@ Arm Platform Build Options
    SBROM library must be specified via ``CCSBROM_LIB_PATH`` flag.
 
 -  ``ARM_ETHOSN_NPU_DRIVER``: boolean option to enable a SiP service that can
-   configure an Arm Ethos-N NPU. To use this service the target platform's
+   configure an Arm® Ethos™-N NPU. To use this service the target platform's
    ``HW_CONFIG`` must include the device tree nodes for the NPU. Currently, only
    the Arm Juno platform has this included in its ``HW_CONFIG`` and the platform
    only loads the ``HW_CONFIG`` in AArch64 builds. Default is 0.
index 60364cdb27ffe557e0cf79f5a71e290fb1452ab1..915a0d87ac62281cbd5207bd948be7dcfb236c38 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 #include <drivers/arm/ethosn.h>
 #include <drivers/delay_timer.h>
 #include <lib/mmio.h>
+#include <lib/utils_def.h>
 #include <plat/arm/common/fconf_ethosn_getter.h>
 
 /*
- * Number of Arm Ethos-N NPU (NPU) cores available for a
- * particular parent device
+ * Number of Arm(R) Ethos(TM)-N NPU (NPU) devices available
  */
-#define ETHOSN_NUM_CORES \
-       FCONF_GET_PROPERTY(hw_config, ethosn_config, num_cores)
+#define ETHOSN_NUM_DEVICES \
+       FCONF_GET_PROPERTY(hw_config, ethosn_config, num_devices)
 
-/* Address to an NPU core  */
-#define ETHOSN_CORE_ADDR(core_idx) \
-       FCONF_GET_PROPERTY(hw_config, ethosn_core_addr, core_idx)
+#define ETHOSN_GET_DEVICE(dev_idx) \
+       FCONF_GET_PROPERTY(hw_config, ethosn_device, dev_idx)
 
 /* NPU core sec registry address */
 #define ETHOSN_CORE_SEC_REG(core_addr, reg_offset) \
@@ -40,9 +39,6 @@
 #define SEC_SECCTLR_REG                        U(0x0010)
 #define SEC_SECCTLR_VAL                        U(0x3)
 
-#define SEC_DEL_MMUSID_REG             U(0x2008)
-#define SEC_DEL_MMUSID_VAL             U(0x3FFFF)
-
 #define SEC_DEL_ADDR_EXT_REG           U(0x201C)
 #define SEC_DEL_ADDR_EXT_VAL           U(0x15)
 
 #define SEC_SYSCTRL0_SOFT_RESET                U(3U << 29)
 #define SEC_SYSCTRL0_HARD_RESET                U(1U << 31)
 
-static bool ethosn_is_core_addr_valid(uintptr_t core_addr)
+#define SEC_MMUSID_REG_BASE            U(0x3008)
+#define SEC_MMUSID_OFFSET              U(0x1000)
+
+static bool ethosn_get_device_and_core(uintptr_t core_addr,
+                                      const struct ethosn_device_t **dev_match,
+                                      const struct ethosn_core_t **core_match)
 {
-       for (uint32_t core_idx = 0U; core_idx < ETHOSN_NUM_CORES; core_idx++) {
-               if (ETHOSN_CORE_ADDR(core_idx) == core_addr) {
-                       return true;
+       uint32_t dev_idx;
+       uint32_t core_idx;
+
+       for (dev_idx = 0U; dev_idx < ETHOSN_NUM_DEVICES; ++dev_idx) {
+               const struct ethosn_device_t *dev = ETHOSN_GET_DEVICE(dev_idx);
+
+               for (core_idx = 0U; core_idx < dev->num_cores; ++core_idx) {
+                       const struct ethosn_core_t *core = &(dev->cores[core_idx]);
+
+                       if (core->addr == core_addr) {
+                               *dev_match = dev;
+                               *core_match = core;
+                               return true;
+                       }
                }
        }
 
+       WARN("ETHOSN: Unknown core address given to SMC call.\n");
        return false;
 }
 
+static void ethosn_configure_smmu_streams(const struct ethosn_device_t *device,
+                                         const struct ethosn_core_t *core,
+                                         uint32_t asset_alloc_idx)
+{
+       const struct ethosn_main_allocator_t *main_alloc =
+               &(core->main_allocator);
+       const struct ethosn_asset_allocator_t *asset_alloc =
+               &(device->asset_allocators[asset_alloc_idx]);
+       const uint32_t streams[9] = {
+               main_alloc->firmware.stream_id,
+               main_alloc->working_data.stream_id,
+               asset_alloc->command_stream.stream_id,
+               0U, /* Not used*/
+               main_alloc->firmware.stream_id,
+               asset_alloc->weight_data.stream_id,
+               asset_alloc->buffer_data.stream_id,
+               asset_alloc->intermediate_data.stream_id,
+               asset_alloc->buffer_data.stream_id
+       };
+       size_t i;
+
+       for (i = 0U; i < ARRAY_SIZE(streams); ++i) {
+               const uintptr_t reg_addr = SEC_MMUSID_REG_BASE +
+                       (SEC_MMUSID_OFFSET * i);
+               mmio_write_32(ETHOSN_CORE_SEC_REG(core->addr, reg_addr),
+                             streams[i]);
+       }
+}
+
 static void ethosn_delegate_to_ns(uintptr_t core_addr)
 {
        mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SECCTLR_REG),
@@ -69,9 +111,6 @@ static void ethosn_delegate_to_ns(uintptr_t core_addr)
        mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG),
                        SEC_DEL_VAL);
 
-       mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_MMUSID_REG),
-                       SEC_DEL_MMUSID_VAL);
-
        mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_ADDR_EXT_REG),
                        SEC_DEL_ADDR_EXT_VAL);
 }
@@ -112,7 +151,7 @@ static bool ethosn_reset(uintptr_t core_addr, int hard_reset)
 
 uintptr_t ethosn_smc_handler(uint32_t smc_fid,
                             u_register_t core_addr,
-                            u_register_t x2,
+                            u_register_t asset_alloc_idx,
                             u_register_t x3,
                             u_register_t x4,
                             void *cookie,
@@ -120,6 +159,8 @@ uintptr_t ethosn_smc_handler(uint32_t smc_fid,
                             u_register_t flags)
 {
        int hard_reset = 0;
+       const struct ethosn_device_t *device = NULL;
+       const struct ethosn_core_t *core = NULL;
        const uint32_t fid = smc_fid & FUNCID_NUM_MASK;
 
        /* Only SiP fast calls are expected */
@@ -131,12 +172,14 @@ uintptr_t ethosn_smc_handler(uint32_t smc_fid,
        /* Truncate parameters to 32-bits for SMC32 */
        if (GET_SMC_CC(smc_fid) == SMC_32) {
                core_addr &= 0xFFFFFFFF;
-               x2 &= 0xFFFFFFFF;
+               asset_alloc_idx &= 0xFFFFFFFF;
                x3 &= 0xFFFFFFFF;
                x4 &= 0xFFFFFFFF;
        }
 
-       if (!is_ethosn_fid(smc_fid)) {
+       if (!is_ethosn_fid(smc_fid) ||
+           (fid < ETHOSN_FNUM_VERSION || fid > ETHOSN_FNUM_SOFT_RESET)) {
+               WARN("ETHOSN: Unknown SMC call: 0x%x\n", smc_fid);
                SMC_RET1(handle, SMC_UNK);
        }
 
@@ -146,25 +189,41 @@ uintptr_t ethosn_smc_handler(uint32_t smc_fid,
                SMC_RET2(handle, ETHOSN_VERSION_MAJOR, ETHOSN_VERSION_MINOR);
        }
 
-       if (!ethosn_is_core_addr_valid(core_addr)) {
-               WARN("ETHOSN: Unknown core address given to SMC call.\n");
+       if (!ethosn_get_device_and_core(core_addr, &device, &core))  {
                SMC_RET1(handle, ETHOSN_UNKNOWN_CORE_ADDRESS);
        }
 
-       /* Commands that require a valid addr */
+       /* Commands that require a valid core address */
        switch (fid) {
        case ETHOSN_FNUM_IS_SEC:
-               SMC_RET1(handle, ethosn_is_sec(core_addr));
+               SMC_RET1(handle, ethosn_is_sec(core->addr));
+       }
+
+       if (!device->has_reserved_memory &&
+           asset_alloc_idx >= device->num_allocators) {
+               WARN("ETHOSN: Unknown asset allocator index given to SMC call.\n");
+               SMC_RET1(handle, ETHOSN_UNKNOWN_ALLOCATOR_IDX);
+       }
+
+       /* Commands that require a valid device, core and asset allocator */
+       switch (fid) {
        case ETHOSN_FNUM_HARD_RESET:
                hard_reset = 1;
                /* Fallthrough */
        case ETHOSN_FNUM_SOFT_RESET:
-               if (!ethosn_reset(core_addr, hard_reset)) {
+               if (!ethosn_reset(core->addr, hard_reset)) {
                        SMC_RET1(handle, ETHOSN_FAILURE);
                }
-               ethosn_delegate_to_ns(core_addr);
+
+               if (!device->has_reserved_memory) {
+                       ethosn_configure_smmu_streams(device, core,
+                                                     asset_alloc_idx);
+               }
+
+               ethosn_delegate_to_ns(core->addr);
                SMC_RET1(handle, ETHOSN_SUCCESS);
        default:
+               WARN("ETHOSN: Unimplemented SMC call: 0x%x\n", fid);
                SMC_RET1(handle, SMC_UNK);
        }
 }
index e2f33550e53ab65c5d404ce1a78ac96986f2d8ae..4609524829f11065a09baa4ac7a594b0f7bcd6cd 100644 (file)
@@ -1,12 +1,13 @@
 /*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 /*
- * For examples of multi-core and multi-device NPU, refer to the examples given in the
- * Arm Ethos-N NPU driver stack.
+ * This device tree is only an example and some properties have been omitted.
+ *
+ * Refer to the Arm(R) Ethos(TM)-N driver stack for complete device tree examples.
  * https://github.com/ARM-software/ethos-n-driver-stack
  */
 
        #address-cells = <2>;
        #size-cells = <2>;
 
-       ethosn0: ethosn@6f300000 {
-               compatible = "ethosn";
-               reg = <0 0x6f300000 0 0x00100000>;
+       smmu_ethosn0: iommu@6f400000 {
+               compatible = "arm,smmu-v3";
+               reg = <0 0x6f400000 0 0x80000>;
                status = "okay";
-
-               core0 {
-                       compatible = "ethosn-core";
-                       status = "okay";
-               };
+               /* msi-parent omitted */
+               #iommu-cells = <0x1>;
        };
+
+       ethosn0: ethosn@6f300000 {
+                compatible = "ethosn";
+                reg = <0 0x6f300000 0 0x00100000>;
+                status = "okay";
+
+                core0 {
+                        compatible = "ethosn-core";
+                        status = "okay";
+
+                        main_allocator {
+                                compatible = "ethosn-main_allocator";
+                                status = "okay";
+
+                                firmware {
+                                        compatible = "ethosn-memory";
+                                        iommus = <&smmu_ethosn0 0>;
+                                };
+
+                                working_data {
+                                        compatible = "ethosn-memory";
+                                        iommus = <&smmu_ethosn0 1>;
+                                };
+                        };
+                };
+
+                asset_allocator {
+                        compatible = "ethosn-asset_allocator";
+                        status = "okay";
+
+                        command_stream {
+                                compatible = "ethosn-memory";
+                                iommus = <&smmu_ethosn0 2>;
+                        };
+
+                        weight_data {
+                                compatible = "ethosn-memory";
+                                iommus = <&smmu_ethosn0 3>;
+                        };
+
+                        buffer_data {
+                                compatible = "ethosn-memory";
+                                iommus = <&smmu_ethosn0 4>;
+                        };
+
+                        intermediate_data {
+                                compatible = "ethosn-memory";
+                                iommus = <&smmu_ethosn0 5>;
+                        };
+                };
+        };
 };
index 93107333867b58545e3a34812e96b5b975d1d982..dbaf16cd722b18c8014efc167e3a659b0f5d51d0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -38,7 +38,7 @@
 #define is_ethosn_fid(_fid) (((_fid) & ETHOSN_FID_MASK) == ETHOSN_FID_VALUE)
 
 /* Service version  */
-#define ETHOSN_VERSION_MAJOR U(1)
+#define ETHOSN_VERSION_MAJOR U(2)
 #define ETHOSN_VERSION_MINOR U(0)
 
 /* Return codes for function calls */
 /* -3 Reserved for INVALID_PARAMETER */
 #define ETHOSN_FAILURE                 -4
 #define ETHOSN_UNKNOWN_CORE_ADDRESS    -5
+#define ETHOSN_UNKNOWN_ALLOCATOR_IDX   -6
 
 uintptr_t ethosn_smc_handler(uint32_t smc_fid,
                             u_register_t core_addr,
-                            u_register_t x2,
+                            u_register_t asset_alloc_idx,
                             u_register_t x3,
                             u_register_t x4,
                             void *cookie,
index 2eeed95f0229c876473b00ae94a1a0850904b4a7..025d10efc09d98dc719dbb7e1e75406a09f63bbe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019,2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2019,2021-2022, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -26,7 +26,7 @@
 /* DEBUGFS_SMC_64                      0xC2000030U */
 
 /*
- * Arm Ethos-N NPU SiP SMC function IDs
+ * Arm(R) Ethos(TM)-N NPU SiP SMC function IDs
  * 0xC2000050-0xC200005F
  * 0x82000050-0x8200005F
  */
index fcdc31f8b20329812c4dd427e6ec817c60e3ca8b..5b9a7ed9d05c5d63ee1ea4b5cd333286b29d3516 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,27 +8,52 @@
 #define FCONF_ETHOSN_GETTER_H
 
 #include <assert.h>
+#include <stdbool.h>
 
 #include <lib/fconf/fconf.h>
 
 #define hw_config__ethosn_config_getter(prop) ethosn_config.prop
-#define hw_config__ethosn_core_addr_getter(idx) __extension__ ({       \
-       assert(idx < ethosn_config.num_cores);                          \
-       ethosn_config.core[idx].addr;                                   \
+#define hw_config__ethosn_device_getter(dev_idx) __extension__ ({      \
+       assert(dev_idx < ethosn_config.num_devices);                    \
+       &ethosn_config.devices[dev_idx];                                \
 })
 
-#define ETHOSN_STATUS_DISABLED U(0)
-#define ETHOSN_STATUS_ENABLED  U(1)
+#define ETHOSN_DEV_NUM_MAX U(2)
+#define ETHOSN_DEV_CORE_NUM_MAX U(8)
+#define ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX U(16)
 
-#define ETHOSN_CORE_NUM_MAX U(64)
+struct ethosn_allocator_t {
+       uint32_t stream_id;
+};
+
+struct ethosn_main_allocator_t {
+       struct ethosn_allocator_t firmware;
+       struct ethosn_allocator_t working_data;
+};
+
+struct ethosn_asset_allocator_t {
+       struct ethosn_allocator_t command_stream;
+       struct ethosn_allocator_t weight_data;
+       struct ethosn_allocator_t buffer_data;
+       struct ethosn_allocator_t intermediate_data;
+};
 
 struct ethosn_core_t {
        uint64_t addr;
+       struct ethosn_main_allocator_t main_allocator;
 };
 
-struct ethosn_config_t {
+struct ethosn_device_t {
+       bool has_reserved_memory;
        uint32_t num_cores;
-       struct ethosn_core_t core[ETHOSN_CORE_NUM_MAX];
+       struct ethosn_core_t cores[ETHOSN_DEV_CORE_NUM_MAX];
+       uint32_t num_allocators;
+       struct ethosn_asset_allocator_t asset_allocators[ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX];
+};
+
+struct ethosn_config_t {
+       uint32_t num_devices;
+       struct ethosn_device_t devices[ETHOSN_DEV_NUM_MAX];
 };
 
 int fconf_populate_arm_ethosn(uintptr_t config);
index bd59ec00a8a001e495fdf128d32126a02537243a..184b51740fadb3c0863ba5ab29185986777f88b5 100644 (file)
@@ -114,7 +114,7 @@ ifeq (${ARM_LINUX_KERNEL_AS_BL33},1)
   endif
 endif
 
-# Arm Ethos-N NPU SiP service
+# Arm(R) Ethos(TM)-N NPU SiP service
 ARM_ETHOSN_NPU_DRIVER                  :=      0
 $(eval $(call assert_boolean,ARM_ETHOSN_NPU_DRIVER))
 $(eval $(call add_define,ARM_ETHOSN_NPU_DRIVER))
index 0af1a20fb4513af607dee16b7b985b1831e3b459..0b48a9816338541e621920f268838e8942e1809b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 #include <libfdt.h>
 #include <plat/arm/common/fconf_ethosn_getter.h>
 
-struct ethosn_config_t ethosn_config = {.num_cores = 0};
+struct ethosn_config_t ethosn_config = {0};
 
-static uint8_t fdt_node_get_status(const void *fdt, int node)
+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;
-       uint8_t status = ETHOSN_STATUS_DISABLED;
        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)) {
-               status = ETHOSN_STATUS_ENABLED;
+               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;
        }
 
-       return status;
+
+       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;
 
-       /* Find offset to node with 'ethosn' compatible property */
-       INFO("Probing Arm Ethos-N NPU\n");
-       uint32_t total_core_count = 0U;
+       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;
-               uint8_t ethosn_status;
-               uint32_t device_core_count = 0U;
 
-               /* If the Arm Ethos-N NPU is disabled the core check can be skipped */
-               ethosn_status = fdt_node_get_status(hw_conf_dtb, ethosn_node);
-               if (ethosn_status == ETHOSN_STATUS_DISABLED) {
+               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;
-                       uintptr_t core_addr;
-                       uint8_t core_status;
 
-                       if (total_core_count >= ETHOSN_CORE_NUM_MAX) {
-                               ERROR("FCONF: Reached max number of Arm Ethos-N NPU cores\n");
-                               return -FDT_ERR_BADSTRUCTURE;
+                       if (!fdt_node_is_enabled(hw_conf_dtb, sub_node)) {
+                               /* Ignore disabled sub node */
+                               continue;
                        }
 
-                       /* Check that the sub node is "ethosn-core" compatible */
                        if (fdt_node_check_compatible(hw_conf_dtb,
                                                      sub_node,
-                                                     "ethosn-core") != 0) {
-                               /* Ignore incompatible sub node */
-                               continue;
-                       }
+                                                     "ethosn-core") == 0) {
 
-                       core_status = fdt_node_get_status(hw_conf_dtb, sub_node);
-                       if (core_status == ETHOSN_STATUS_DISABLED) {
-                               continue;
-                       }
+                               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_get_reg_props_by_index(hw_conf_dtb,
-                                                        ethosn_node,
-                                                        device_core_count,
-                                                        &core_addr,
-                                                        NULL);
-                       if (err < 0) {
-                               ERROR(
-                               "FCONF: Failed to read reg property for Arm Ethos-N NPU core %u\n",
-                                               device_core_count);
-                               return err;
-                       }
+                               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;
+                               }
 
-                       INFO("NPU core probed at address 0x%lx\n", core_addr);
-                       ethosn_config.core[total_core_count].addr = core_addr;
-                       total_core_count++;
-                       device_core_count++;
+                               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\n");
+                       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 (device_core_count == 0U) {
-                       ERROR(
-                       "FCONF: Enabled Arm Ethos-N NPU device must have at least one enabled core\n");
+               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 (total_core_count == 0U) {
+       if (dev_count == 0U) {
                ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n");
                return -FDT_ERR_BADSTRUCTURE;
        }
 
-       ethosn_config.num_cores = total_core_count;
-
-       INFO("%d NPU core%s probed\n",
-            ethosn_config.num_cores,
-            ethosn_config.num_cores > 1 ? "s" : "");
+       ethosn_config.num_devices = dev_count;
 
        return 0;
 }