1 /* 2 * Copyright (c) 2021-2022, 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 = {0}; 16 17 struct ethosn_sub_allocator_t { 18 const char *name; 19 size_t name_len; 20 uint32_t stream_id; 21 }; 22 23 static bool fdt_node_has_reserved_memory(const void *fdt, int dev_node) 24 { 25 return fdt_get_property(fdt, dev_node, "memory-region", NULL) != NULL; 26 } 27 28 static int fdt_node_get_iommus_stream_id(const void *fdt, int node, uint32_t *stream_id) 29 { 30 int err; 31 uint32_t iommus_array[2] = {0U}; 32 33 err = fdt_read_uint32_array(fdt, node, "iommus", 2U, iommus_array); 34 if (err) { 35 return err; 36 } 37 38 *stream_id = iommus_array[1]; 39 return 0; 40 } 41 42 static int fdt_node_populate_sub_allocators(const void *fdt, 43 int alloc_node, 44 struct ethosn_sub_allocator_t *sub_allocators, 45 size_t num_allocs) 46 { 47 int sub_node; 48 size_t i; 49 int err = -FDT_ERR_NOTFOUND; 50 uint32_t found_sub_allocators = 0U; 51 52 fdt_for_each_subnode(sub_node, fdt, alloc_node) { 53 const char *node_name; 54 55 if (!fdt_node_is_enabled(fdt, sub_node)) { 56 /* Ignore disabled node */ 57 continue; 58 } 59 60 if (fdt_node_check_compatible(fdt, sub_node, "ethosn-memory") != 0) { 61 continue; 62 } 63 64 node_name = fdt_get_name(fdt, sub_node, NULL); 65 for (i = 0U; i < num_allocs; ++i) { 66 if (strncmp(node_name, sub_allocators[i].name, 67 sub_allocators[i].name_len) != 0) { 68 continue; 69 } 70 71 err = fdt_node_get_iommus_stream_id(fdt, sub_node, 72 &sub_allocators[i].stream_id); 73 if (err) { 74 ERROR("FCONF: Failed to get stream ID from sub-allocator %s\n", 75 node_name); 76 return err; 77 } 78 79 ++found_sub_allocators; 80 /* Nothing more to do for this node */ 81 break; 82 } 83 84 /* Check that at least one of the sub-allocators matched */ 85 if (i == num_allocs) { 86 ERROR("FCONF: Unknown sub-allocator %s\n", node_name); 87 return -FDT_ERR_BADSTRUCTURE; 88 } 89 } 90 91 if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) { 92 ERROR("FCONF: Failed to parse sub-allocators\n"); 93 return -FDT_ERR_BADSTRUCTURE; 94 } 95 96 if (err == -FDT_ERR_NOTFOUND) { 97 ERROR("FCONF: No matching sub-allocator found\n"); 98 return err; 99 } 100 101 if (found_sub_allocators != num_allocs) { 102 ERROR("FCONF: Not all sub-allocators were found\n"); 103 return -FDT_ERR_BADSTRUCTURE; 104 } 105 106 return 0; 107 } 108 109 static int fdt_node_populate_main_allocator(const void *fdt, 110 int alloc_node, 111 struct ethosn_main_allocator_t *allocator) 112 { 113 int err; 114 struct ethosn_sub_allocator_t sub_allocators[] = { 115 {.name = "firmware", .name_len = 8U}, 116 {.name = "working_data", .name_len = 12U} 117 }; 118 119 err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators, 120 ARRAY_SIZE(sub_allocators)); 121 if (err) { 122 return err; 123 } 124 125 allocator->firmware.stream_id = sub_allocators[0].stream_id; 126 allocator->working_data.stream_id = sub_allocators[1].stream_id; 127 128 return 0; 129 } 130 131 static int fdt_node_populate_asset_allocator(const void *fdt, 132 int alloc_node, 133 struct ethosn_asset_allocator_t *allocator) 134 { 135 int err; 136 struct ethosn_sub_allocator_t sub_allocators[] = { 137 {.name = "command_stream", .name_len = 14U}, 138 {.name = "weight_data", .name_len = 11U}, 139 {.name = "buffer_data", .name_len = 11U}, 140 {.name = "intermediate_data", .name_len = 17U} 141 }; 142 143 err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators, 144 ARRAY_SIZE(sub_allocators)); 145 if (err) { 146 return err; 147 } 148 149 150 allocator->command_stream.stream_id = sub_allocators[0].stream_id; 151 allocator->weight_data.stream_id = sub_allocators[1].stream_id; 152 allocator->buffer_data.stream_id = sub_allocators[2].stream_id; 153 allocator->intermediate_data.stream_id = sub_allocators[3].stream_id; 154 return 0; 155 } 156 157 static int fdt_node_populate_core(const void *fdt, 158 int device_node, 159 int core_node, 160 bool has_reserved_memory, 161 uint32_t core_index, 162 struct ethosn_core_t *core) 163 { 164 int err; 165 int sub_node; 166 uintptr_t core_addr; 167 168 err = fdt_get_reg_props_by_index(fdt, device_node, core_index, 169 &core_addr, NULL); 170 if (err < 0) { 171 ERROR("FCONF: Failed to read reg property for NPU core %u\n", 172 core_index); 173 return err; 174 } 175 176 err = -FDT_ERR_NOTFOUND; 177 fdt_for_each_subnode(sub_node, fdt, core_node) { 178 179 if (!fdt_node_is_enabled(fdt, sub_node)) { 180 continue; 181 } 182 183 if (fdt_node_check_compatible(fdt, 184 sub_node, 185 "ethosn-main_allocator") != 0) { 186 continue; 187 } 188 189 if (has_reserved_memory) { 190 ERROR("FCONF: Main allocator not supported when using reserved memory\n"); 191 return -FDT_ERR_BADSTRUCTURE; 192 } 193 194 if (err != -FDT_ERR_NOTFOUND) { 195 ERROR("FCONF: NPU core 0x%lx has more than one main allocator\n", 196 core_addr); 197 return -FDT_ERR_BADSTRUCTURE; 198 } 199 200 err = fdt_node_populate_main_allocator(fdt, sub_node, &core->main_allocator); 201 if (err) { 202 ERROR("FCONF: Failed to parse main allocator for NPU core 0x%lx\n", 203 core_addr); 204 return err; 205 } 206 } 207 208 if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) { 209 ERROR("FCONF: Failed to parse core sub nodes\n"); 210 return -FDT_ERR_BADSTRUCTURE; 211 } 212 213 if (!has_reserved_memory && err) { 214 ERROR("FCONF: Main allocator not found for NPU core 0x%lx\n", 215 core_addr); 216 return err; 217 } 218 219 core->addr = core_addr; 220 221 return 0; 222 } 223 224 int fconf_populate_ethosn_config(uintptr_t config) 225 { 226 int ethosn_node; 227 uint32_t dev_count = 0U; 228 const void *hw_conf_dtb = (const void *)config; 229 230 INFO("Probing Arm(R) Ethos(TM)-N NPU\n"); 231 232 fdt_for_each_compatible_node(hw_conf_dtb, ethosn_node, "ethosn") { 233 struct ethosn_device_t *dev = ðosn_config.devices[dev_count]; 234 uint32_t dev_asset_alloc_count = 0U; 235 uint32_t dev_core_count = 0U; 236 bool has_reserved_memory; 237 int sub_node; 238 239 if (!fdt_node_is_enabled(hw_conf_dtb, ethosn_node)) { 240 continue; 241 } 242 243 if (dev_count >= ETHOSN_DEV_NUM_MAX) { 244 ERROR("FCONF: Reached max number of NPUs\n"); 245 return -FDT_ERR_BADSTRUCTURE; 246 } 247 248 has_reserved_memory = fdt_node_has_reserved_memory(hw_conf_dtb, ethosn_node); 249 fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) { 250 int err; 251 252 if (!fdt_node_is_enabled(hw_conf_dtb, sub_node)) { 253 /* Ignore disabled sub node */ 254 continue; 255 } 256 257 if (fdt_node_check_compatible(hw_conf_dtb, 258 sub_node, 259 "ethosn-core") == 0) { 260 261 if (dev_core_count >= ETHOSN_DEV_CORE_NUM_MAX) { 262 ERROR("FCONF: Reached max number of NPU cores for NPU %u\n", 263 dev_count); 264 return -FDT_ERR_BADSTRUCTURE; 265 } 266 267 err = fdt_node_populate_core(hw_conf_dtb, 268 ethosn_node, 269 sub_node, 270 has_reserved_memory, 271 dev_core_count, 272 &(dev->cores[dev_core_count])); 273 if (err) { 274 return err; 275 } 276 ++dev_core_count; 277 } else if (fdt_node_check_compatible(hw_conf_dtb, 278 sub_node, 279 "ethosn-asset_allocator") == 0) { 280 281 if (dev_asset_alloc_count >= 282 ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX) { 283 ERROR("FCONF: Reached max number of asset allocators for NPU %u\n", 284 dev_count); 285 return -FDT_ERR_BADSTRUCTURE; 286 } 287 288 if (has_reserved_memory) { 289 ERROR("FCONF: Asset allocator not supported when using reserved memory\n"); 290 return -FDT_ERR_BADSTRUCTURE; 291 } 292 293 err = fdt_node_populate_asset_allocator(hw_conf_dtb, 294 sub_node, 295 &(dev->asset_allocators[dev_asset_alloc_count])); 296 if (err) { 297 ERROR("FCONF: Failed to parse asset allocator for NPU %u\n", 298 dev_count); 299 return err; 300 } 301 ++dev_asset_alloc_count; 302 } 303 } 304 305 if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) { 306 ERROR("FCONF: Failed to parse sub nodes for NPU %u\n", 307 dev_count); 308 return -FDT_ERR_BADSTRUCTURE; 309 } 310 311 if (dev_core_count == 0U) { 312 ERROR("FCONF: NPU %u must have at least one enabled core\n", 313 dev_count); 314 return -FDT_ERR_BADSTRUCTURE; 315 } 316 317 if (!has_reserved_memory && dev_asset_alloc_count == 0U) { 318 ERROR("FCONF: NPU %u must have at least one asset allocator\n", 319 dev_count); 320 return -FDT_ERR_BADSTRUCTURE; 321 } 322 323 dev->num_cores = dev_core_count; 324 dev->num_allocators = dev_asset_alloc_count; 325 dev->has_reserved_memory = has_reserved_memory; 326 ++dev_count; 327 } 328 329 if (dev_count == 0U) { 330 ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n"); 331 return -FDT_ERR_BADSTRUCTURE; 332 } 333 334 ethosn_config.num_devices = dev_count; 335 336 return 0; 337 } 338 339 FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config); 340