aboutsummaryrefslogtreecommitdiff
path: root/plat/arm/common/fconf/fconf_ethosn_getter.c
diff options
context:
space:
mode:
Diffstat (limited to 'plat/arm/common/fconf/fconf_ethosn_getter.c')
-rw-r--r--plat/arm/common/fconf/fconf_ethosn_getter.c108
1 files changed, 108 insertions, 0 deletions
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 000000000..1ba9f3a23
--- /dev/null
+++ b/plat/arm/common/fconf/fconf_ethosn_getter.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2021, 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;
+
+static uint8_t fdt_node_get_status(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 status;
+}
+
+int fconf_populate_ethosn_config(uintptr_t config)
+{
+ int ethosn_node;
+ int sub_node;
+ uint8_t ethosn_status;
+ uint32_t core_count = 0U;
+ uint32_t core_addr_idx = 0U;
+ const void *hw_conf_dtb = (const void *)config;
+
+ /* Find offset to node with 'ethosn' compatible property */
+ ethosn_node = fdt_node_offset_by_compatible(hw_conf_dtb, -1, "ethosn");
+ if (ethosn_node < 0) {
+ ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n");
+ return ethosn_node;
+ }
+
+ /* 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) {
+ return 0;
+ }
+
+ fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) {
+ int err;
+ uintptr_t addr;
+ uint8_t status;
+
+ /* 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;
+ }
+
+ /* Including disabled cores */
+ if (core_addr_idx >= ETHOSN_CORE_NUM_MAX) {
+ ERROR("FCONF: Reached max number of Arm Ethos-N NPU cores\n");
+ return -1;
+ }
+
+ status = fdt_node_get_status(hw_conf_dtb, ethosn_node);
+ if (status == ETHOSN_STATUS_DISABLED) {
+ ++core_addr_idx;
+ continue;
+ }
+
+ err = fdt_get_reg_props_by_index(hw_conf_dtb, ethosn_node,
+ core_addr_idx, &addr, NULL);
+ if (err < 0) {
+ ERROR("FCONF: Failed to read reg property for Arm Ethos-N NPU core %u\n",
+ core_addr_idx);
+ return err;
+ }
+
+ ethosn_config.core_addr[core_count++] = addr;
+ ++core_addr_idx;
+ }
+
+ if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
+ ERROR("FCONF: Failed to parse sub nodes\n");
+ return sub_node;
+ }
+
+ /* The Arm Ethos-N NPU can't be used if no cores were found */
+ if (core_count == 0) {
+ ERROR("FCONF: No Arm Ethos-N NPU cores found\n");
+ return -1;
+ }
+
+ ethosn_config.num_cores = core_count;
+ ethosn_config.status = ethosn_status;
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config);