1 /* 2 * Copyright (c) 2021, Arm Limited. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <string.h> 9 10 #include <common/debug.h> 11 #include <common/fdt_wrappers.h> 12 #include <libfdt.h> 13 #include <plat/arm/common/fconf_ethosn_getter.h> 14 15 struct ethosn_config_t ethosn_config = {.num_cores = 0}; 16 17 static uint8_t fdt_node_get_status(const void *fdt, int node) 18 { 19 int len; 20 uint8_t status = ETHOSN_STATUS_DISABLED; 21 const char *node_status; 22 23 node_status = fdt_getprop(fdt, node, "status", &len); 24 if (node_status == NULL || 25 (len == 5 && /* Includes null character */ 26 strncmp(node_status, "okay", 4U) == 0)) { 27 status = ETHOSN_STATUS_ENABLED; 28 } 29 30 return status; 31 } 32 33 int fconf_populate_ethosn_config(uintptr_t config) 34 { 35 int ethosn_node; 36 const void *hw_conf_dtb = (const void *)config; 37 38 /* Find offset to node with 'ethosn' compatible property */ 39 INFO("Probing Arm Ethos-N NPU\n"); 40 uint32_t total_core_count = 0U; 41 42 fdt_for_each_compatible_node(hw_conf_dtb, ethosn_node, "ethosn") { 43 int sub_node; 44 uint8_t ethosn_status; 45 uint32_t device_core_count = 0U; 46 47 /* If the Arm Ethos-N NPU is disabled the core check can be skipped */ 48 ethosn_status = fdt_node_get_status(hw_conf_dtb, ethosn_node); 49 if (ethosn_status == ETHOSN_STATUS_DISABLED) { 50 continue; 51 } 52 53 fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) { 54 int err; 55 uintptr_t core_addr; 56 uint8_t core_status; 57 58 if (total_core_count >= ETHOSN_CORE_NUM_MAX) { 59 ERROR("FCONF: Reached max number of Arm Ethos-N NPU cores\n"); 60 return -FDT_ERR_BADSTRUCTURE; 61 } 62 63 /* Check that the sub node is "ethosn-core" compatible */ 64 if (fdt_node_check_compatible(hw_conf_dtb, 65 sub_node, 66 "ethosn-core") != 0) { 67 /* Ignore incompatible sub node */ 68 continue; 69 } 70 71 core_status = fdt_node_get_status(hw_conf_dtb, sub_node); 72 if (core_status == ETHOSN_STATUS_DISABLED) { 73 continue; 74 } 75 76 err = fdt_get_reg_props_by_index(hw_conf_dtb, 77 ethosn_node, 78 device_core_count, 79 &core_addr, 80 NULL); 81 if (err < 0) { 82 ERROR( 83 "FCONF: Failed to read reg property for Arm Ethos-N NPU core %u\n", 84 device_core_count); 85 return err; 86 } 87 88 INFO("NPU core probed at address 0x%lx\n", core_addr); 89 ethosn_config.core[total_core_count].addr = core_addr; 90 total_core_count++; 91 device_core_count++; 92 } 93 94 if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) { 95 ERROR("FCONF: Failed to parse sub nodes\n"); 96 return -FDT_ERR_BADSTRUCTURE; 97 } 98 99 if (device_core_count == 0U) { 100 ERROR( 101 "FCONF: Enabled Arm Ethos-N NPU device must have at least one enabled core\n"); 102 return -FDT_ERR_BADSTRUCTURE; 103 } 104 } 105 106 if (total_core_count == 0U) { 107 ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n"); 108 return -FDT_ERR_BADSTRUCTURE; 109 } 110 111 ethosn_config.num_cores = total_core_count; 112 113 INFO("%d NPU core%s probed\n", 114 ethosn_config.num_cores, 115 ethosn_config.num_cores > 1 ? "s" : ""); 116 117 return 0; 118 } 119 120 FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config); 121