176a21174SMikael Olsson /* 2*b139f1cfSMikael Olsson * Copyright (c) 2021-2022, Arm Limited. All rights reserved. 376a21174SMikael Olsson * 476a21174SMikael Olsson * SPDX-License-Identifier: BSD-3-Clause 576a21174SMikael Olsson */ 676a21174SMikael Olsson 776a21174SMikael Olsson #include <assert.h> 876a21174SMikael Olsson #include <string.h> 976a21174SMikael Olsson 1076a21174SMikael Olsson #include <common/debug.h> 1176a21174SMikael Olsson #include <common/fdt_wrappers.h> 1276a21174SMikael Olsson #include <libfdt.h> 1376a21174SMikael Olsson #include <plat/arm/common/fconf_ethosn_getter.h> 1476a21174SMikael Olsson 15*b139f1cfSMikael Olsson struct ethosn_config_t ethosn_config = {0}; 1676a21174SMikael Olsson 17*b139f1cfSMikael Olsson struct ethosn_sub_allocator_t { 18*b139f1cfSMikael Olsson const char *name; 19*b139f1cfSMikael Olsson size_t name_len; 20*b139f1cfSMikael Olsson uint32_t stream_id; 21*b139f1cfSMikael Olsson }; 22*b139f1cfSMikael Olsson 23*b139f1cfSMikael Olsson static bool fdt_node_is_enabled(const void *fdt, int node) 2476a21174SMikael Olsson { 2576a21174SMikael Olsson int len; 2676a21174SMikael Olsson const char *node_status; 2776a21174SMikael Olsson 2876a21174SMikael Olsson node_status = fdt_getprop(fdt, node, "status", &len); 2976a21174SMikael Olsson if (node_status == NULL || 3076a21174SMikael Olsson (len == 5 && /* Includes null character */ 3176a21174SMikael Olsson strncmp(node_status, "okay", 4U) == 0)) { 32*b139f1cfSMikael Olsson return true; 3376a21174SMikael Olsson } 3476a21174SMikael Olsson 35*b139f1cfSMikael Olsson return false; 36*b139f1cfSMikael Olsson } 37*b139f1cfSMikael Olsson 38*b139f1cfSMikael Olsson static bool fdt_node_has_reserved_memory(const void *fdt, int dev_node) 39*b139f1cfSMikael Olsson { 40*b139f1cfSMikael Olsson return fdt_get_property(fdt, dev_node, "memory-region", NULL) != NULL; 41*b139f1cfSMikael Olsson } 42*b139f1cfSMikael Olsson 43*b139f1cfSMikael Olsson static int fdt_node_get_iommus_stream_id(const void *fdt, int node, uint32_t *stream_id) 44*b139f1cfSMikael Olsson { 45*b139f1cfSMikael Olsson int err; 46*b139f1cfSMikael Olsson uint32_t iommus_array[2] = {0U}; 47*b139f1cfSMikael Olsson 48*b139f1cfSMikael Olsson err = fdt_read_uint32_array(fdt, node, "iommus", 2U, iommus_array); 49*b139f1cfSMikael Olsson if (err) { 50*b139f1cfSMikael Olsson return err; 51*b139f1cfSMikael Olsson } 52*b139f1cfSMikael Olsson 53*b139f1cfSMikael Olsson *stream_id = iommus_array[1]; 54*b139f1cfSMikael Olsson return 0; 55*b139f1cfSMikael Olsson } 56*b139f1cfSMikael Olsson 57*b139f1cfSMikael Olsson static int fdt_node_populate_sub_allocators(const void *fdt, 58*b139f1cfSMikael Olsson int alloc_node, 59*b139f1cfSMikael Olsson struct ethosn_sub_allocator_t *sub_allocators, 60*b139f1cfSMikael Olsson size_t num_allocs) 61*b139f1cfSMikael Olsson { 62*b139f1cfSMikael Olsson int sub_node; 63*b139f1cfSMikael Olsson size_t i; 64*b139f1cfSMikael Olsson int err = -FDT_ERR_NOTFOUND; 65*b139f1cfSMikael Olsson uint32_t found_sub_allocators = 0U; 66*b139f1cfSMikael Olsson 67*b139f1cfSMikael Olsson fdt_for_each_subnode(sub_node, fdt, alloc_node) { 68*b139f1cfSMikael Olsson const char *node_name; 69*b139f1cfSMikael Olsson 70*b139f1cfSMikael Olsson if (!fdt_node_is_enabled(fdt, sub_node)) { 71*b139f1cfSMikael Olsson /* Ignore disabled node */ 72*b139f1cfSMikael Olsson continue; 73*b139f1cfSMikael Olsson } 74*b139f1cfSMikael Olsson 75*b139f1cfSMikael Olsson if (fdt_node_check_compatible(fdt, sub_node, "ethosn-memory") != 0) { 76*b139f1cfSMikael Olsson continue; 77*b139f1cfSMikael Olsson } 78*b139f1cfSMikael Olsson 79*b139f1cfSMikael Olsson node_name = fdt_get_name(fdt, sub_node, NULL); 80*b139f1cfSMikael Olsson for (i = 0U; i < num_allocs; ++i) { 81*b139f1cfSMikael Olsson if (strncmp(node_name, sub_allocators[i].name, 82*b139f1cfSMikael Olsson sub_allocators[i].name_len) != 0) { 83*b139f1cfSMikael Olsson continue; 84*b139f1cfSMikael Olsson } 85*b139f1cfSMikael Olsson 86*b139f1cfSMikael Olsson err = fdt_node_get_iommus_stream_id(fdt, sub_node, 87*b139f1cfSMikael Olsson &sub_allocators[i].stream_id); 88*b139f1cfSMikael Olsson if (err) { 89*b139f1cfSMikael Olsson ERROR("FCONF: Failed to get stream ID from sub-allocator %s\n", 90*b139f1cfSMikael Olsson node_name); 91*b139f1cfSMikael Olsson return err; 92*b139f1cfSMikael Olsson } 93*b139f1cfSMikael Olsson 94*b139f1cfSMikael Olsson ++found_sub_allocators; 95*b139f1cfSMikael Olsson /* Nothing more to do for this node */ 96*b139f1cfSMikael Olsson break; 97*b139f1cfSMikael Olsson } 98*b139f1cfSMikael Olsson 99*b139f1cfSMikael Olsson /* Check that at least one of the sub-allocators matched */ 100*b139f1cfSMikael Olsson if (i == num_allocs) { 101*b139f1cfSMikael Olsson ERROR("FCONF: Unknown sub-allocator %s\n", node_name); 102*b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE; 103*b139f1cfSMikael Olsson } 104*b139f1cfSMikael Olsson } 105*b139f1cfSMikael Olsson 106*b139f1cfSMikael Olsson if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) { 107*b139f1cfSMikael Olsson ERROR("FCONF: Failed to parse sub-allocators\n"); 108*b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE; 109*b139f1cfSMikael Olsson } 110*b139f1cfSMikael Olsson 111*b139f1cfSMikael Olsson if (err == -FDT_ERR_NOTFOUND) { 112*b139f1cfSMikael Olsson ERROR("FCONF: No matching sub-allocator found\n"); 113*b139f1cfSMikael Olsson return err; 114*b139f1cfSMikael Olsson } 115*b139f1cfSMikael Olsson 116*b139f1cfSMikael Olsson if (found_sub_allocators != num_allocs) { 117*b139f1cfSMikael Olsson ERROR("FCONF: Not all sub-allocators were found\n"); 118*b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE; 119*b139f1cfSMikael Olsson } 120*b139f1cfSMikael Olsson 121*b139f1cfSMikael Olsson return 0; 122*b139f1cfSMikael Olsson } 123*b139f1cfSMikael Olsson 124*b139f1cfSMikael Olsson static int fdt_node_populate_main_allocator(const void *fdt, 125*b139f1cfSMikael Olsson int alloc_node, 126*b139f1cfSMikael Olsson struct ethosn_main_allocator_t *allocator) 127*b139f1cfSMikael Olsson { 128*b139f1cfSMikael Olsson int err; 129*b139f1cfSMikael Olsson struct ethosn_sub_allocator_t sub_allocators[] = { 130*b139f1cfSMikael Olsson {.name = "firmware", .name_len = 8U}, 131*b139f1cfSMikael Olsson {.name = "working_data", .name_len = 12U} 132*b139f1cfSMikael Olsson }; 133*b139f1cfSMikael Olsson 134*b139f1cfSMikael Olsson err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators, 135*b139f1cfSMikael Olsson ARRAY_SIZE(sub_allocators)); 136*b139f1cfSMikael Olsson if (err) { 137*b139f1cfSMikael Olsson return err; 138*b139f1cfSMikael Olsson } 139*b139f1cfSMikael Olsson 140*b139f1cfSMikael Olsson allocator->firmware.stream_id = sub_allocators[0].stream_id; 141*b139f1cfSMikael Olsson allocator->working_data.stream_id = sub_allocators[1].stream_id; 142*b139f1cfSMikael Olsson 143*b139f1cfSMikael Olsson return 0; 144*b139f1cfSMikael Olsson } 145*b139f1cfSMikael Olsson 146*b139f1cfSMikael Olsson static int fdt_node_populate_asset_allocator(const void *fdt, 147*b139f1cfSMikael Olsson int alloc_node, 148*b139f1cfSMikael Olsson struct ethosn_asset_allocator_t *allocator) 149*b139f1cfSMikael Olsson { 150*b139f1cfSMikael Olsson int err; 151*b139f1cfSMikael Olsson struct ethosn_sub_allocator_t sub_allocators[] = { 152*b139f1cfSMikael Olsson {.name = "command_stream", .name_len = 14U}, 153*b139f1cfSMikael Olsson {.name = "weight_data", .name_len = 11U}, 154*b139f1cfSMikael Olsson {.name = "buffer_data", .name_len = 11U}, 155*b139f1cfSMikael Olsson {.name = "intermediate_data", .name_len = 17U} 156*b139f1cfSMikael Olsson }; 157*b139f1cfSMikael Olsson 158*b139f1cfSMikael Olsson err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators, 159*b139f1cfSMikael Olsson ARRAY_SIZE(sub_allocators)); 160*b139f1cfSMikael Olsson if (err) { 161*b139f1cfSMikael Olsson return err; 162*b139f1cfSMikael Olsson } 163*b139f1cfSMikael Olsson 164*b139f1cfSMikael Olsson 165*b139f1cfSMikael Olsson allocator->command_stream.stream_id = sub_allocators[0].stream_id; 166*b139f1cfSMikael Olsson allocator->weight_data.stream_id = sub_allocators[1].stream_id; 167*b139f1cfSMikael Olsson allocator->buffer_data.stream_id = sub_allocators[2].stream_id; 168*b139f1cfSMikael Olsson allocator->intermediate_data.stream_id = sub_allocators[3].stream_id; 169*b139f1cfSMikael Olsson return 0; 170*b139f1cfSMikael Olsson } 171*b139f1cfSMikael Olsson 172*b139f1cfSMikael Olsson static int fdt_node_populate_core(const void *fdt, 173*b139f1cfSMikael Olsson int device_node, 174*b139f1cfSMikael Olsson int core_node, 175*b139f1cfSMikael Olsson bool has_reserved_memory, 176*b139f1cfSMikael Olsson uint32_t core_index, 177*b139f1cfSMikael Olsson struct ethosn_core_t *core) 178*b139f1cfSMikael Olsson { 179*b139f1cfSMikael Olsson int err; 180*b139f1cfSMikael Olsson int sub_node; 181*b139f1cfSMikael Olsson uintptr_t core_addr; 182*b139f1cfSMikael Olsson 183*b139f1cfSMikael Olsson err = fdt_get_reg_props_by_index(fdt, device_node, core_index, 184*b139f1cfSMikael Olsson &core_addr, NULL); 185*b139f1cfSMikael Olsson if (err < 0) { 186*b139f1cfSMikael Olsson ERROR("FCONF: Failed to read reg property for NPU core %u\n", 187*b139f1cfSMikael Olsson core_index); 188*b139f1cfSMikael Olsson return err; 189*b139f1cfSMikael Olsson } 190*b139f1cfSMikael Olsson 191*b139f1cfSMikael Olsson err = -FDT_ERR_NOTFOUND; 192*b139f1cfSMikael Olsson fdt_for_each_subnode(sub_node, fdt, core_node) { 193*b139f1cfSMikael Olsson 194*b139f1cfSMikael Olsson if (!fdt_node_is_enabled(fdt, sub_node)) { 195*b139f1cfSMikael Olsson continue; 196*b139f1cfSMikael Olsson } 197*b139f1cfSMikael Olsson 198*b139f1cfSMikael Olsson if (fdt_node_check_compatible(fdt, 199*b139f1cfSMikael Olsson sub_node, 200*b139f1cfSMikael Olsson "ethosn-main_allocator") != 0) { 201*b139f1cfSMikael Olsson continue; 202*b139f1cfSMikael Olsson } 203*b139f1cfSMikael Olsson 204*b139f1cfSMikael Olsson if (has_reserved_memory) { 205*b139f1cfSMikael Olsson ERROR("FCONF: Main allocator not supported when using reserved memory\n"); 206*b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE; 207*b139f1cfSMikael Olsson } 208*b139f1cfSMikael Olsson 209*b139f1cfSMikael Olsson if (err != -FDT_ERR_NOTFOUND) { 210*b139f1cfSMikael Olsson ERROR("FCONF: NPU core 0x%lx has more than one main allocator\n", 211*b139f1cfSMikael Olsson core_addr); 212*b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE; 213*b139f1cfSMikael Olsson } 214*b139f1cfSMikael Olsson 215*b139f1cfSMikael Olsson err = fdt_node_populate_main_allocator(fdt, sub_node, &core->main_allocator); 216*b139f1cfSMikael Olsson if (err) { 217*b139f1cfSMikael Olsson ERROR("FCONF: Failed to parse main allocator for NPU core 0x%lx\n", 218*b139f1cfSMikael Olsson core_addr); 219*b139f1cfSMikael Olsson return err; 220*b139f1cfSMikael Olsson } 221*b139f1cfSMikael Olsson } 222*b139f1cfSMikael Olsson 223*b139f1cfSMikael Olsson if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) { 224*b139f1cfSMikael Olsson ERROR("FCONF: Failed to parse core sub nodes\n"); 225*b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE; 226*b139f1cfSMikael Olsson } 227*b139f1cfSMikael Olsson 228*b139f1cfSMikael Olsson if (!has_reserved_memory && err) { 229*b139f1cfSMikael Olsson ERROR("FCONF: Main allocator not found for NPU core 0x%lx\n", 230*b139f1cfSMikael Olsson core_addr); 231*b139f1cfSMikael Olsson return err; 232*b139f1cfSMikael Olsson } 233*b139f1cfSMikael Olsson 234*b139f1cfSMikael Olsson core->addr = core_addr; 235*b139f1cfSMikael Olsson 236*b139f1cfSMikael Olsson return 0; 23776a21174SMikael Olsson } 23876a21174SMikael Olsson 23976a21174SMikael Olsson int fconf_populate_ethosn_config(uintptr_t config) 24076a21174SMikael Olsson { 24176a21174SMikael Olsson int ethosn_node; 242*b139f1cfSMikael Olsson uint32_t dev_count = 0U; 24376a21174SMikael Olsson const void *hw_conf_dtb = (const void *)config; 24476a21174SMikael Olsson 245*b139f1cfSMikael Olsson INFO("Probing Arm(R) Ethos(TM)-N NPU\n"); 2461c65989eSLaurent Carlier 2471c65989eSLaurent Carlier fdt_for_each_compatible_node(hw_conf_dtb, ethosn_node, "ethosn") { 248*b139f1cfSMikael Olsson struct ethosn_device_t *dev = ðosn_config.devices[dev_count]; 249*b139f1cfSMikael Olsson uint32_t dev_asset_alloc_count = 0U; 250*b139f1cfSMikael Olsson uint32_t dev_core_count = 0U; 251*b139f1cfSMikael Olsson bool has_reserved_memory; 2521c65989eSLaurent Carlier int sub_node; 25376a21174SMikael Olsson 254*b139f1cfSMikael Olsson if (!fdt_node_is_enabled(hw_conf_dtb, ethosn_node)) { 2551c65989eSLaurent Carlier continue; 25676a21174SMikael Olsson } 25776a21174SMikael Olsson 258*b139f1cfSMikael Olsson if (dev_count >= ETHOSN_DEV_NUM_MAX) { 259*b139f1cfSMikael Olsson ERROR("FCONF: Reached max number of NPUs\n"); 2601c65989eSLaurent Carlier return -FDT_ERR_BADSTRUCTURE; 2611c65989eSLaurent Carlier } 26276a21174SMikael Olsson 263*b139f1cfSMikael Olsson has_reserved_memory = fdt_node_has_reserved_memory(hw_conf_dtb, ethosn_node); 264*b139f1cfSMikael Olsson fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) { 265*b139f1cfSMikael Olsson int err; 266*b139f1cfSMikael Olsson 267*b139f1cfSMikael Olsson if (!fdt_node_is_enabled(hw_conf_dtb, sub_node)) { 268*b139f1cfSMikael Olsson /* Ignore disabled sub node */ 269*b139f1cfSMikael Olsson continue; 270*b139f1cfSMikael Olsson } 271*b139f1cfSMikael Olsson 2721c65989eSLaurent Carlier if (fdt_node_check_compatible(hw_conf_dtb, 2731c65989eSLaurent Carlier sub_node, 274*b139f1cfSMikael Olsson "ethosn-core") == 0) { 275*b139f1cfSMikael Olsson 276*b139f1cfSMikael Olsson if (dev_core_count >= ETHOSN_DEV_CORE_NUM_MAX) { 277*b139f1cfSMikael Olsson ERROR("FCONF: Reached max number of NPU cores for NPU %u\n", 278*b139f1cfSMikael Olsson dev_count); 279*b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE; 28076a21174SMikael Olsson } 28176a21174SMikael Olsson 282*b139f1cfSMikael Olsson err = fdt_node_populate_core(hw_conf_dtb, 2831c65989eSLaurent Carlier ethosn_node, 284*b139f1cfSMikael Olsson sub_node, 285*b139f1cfSMikael Olsson has_reserved_memory, 286*b139f1cfSMikael Olsson dev_core_count, 287*b139f1cfSMikael Olsson &(dev->cores[dev_core_count])); 288*b139f1cfSMikael Olsson if (err) { 28976a21174SMikael Olsson return err; 29076a21174SMikael Olsson } 291*b139f1cfSMikael Olsson ++dev_core_count; 292*b139f1cfSMikael Olsson } else if (fdt_node_check_compatible(hw_conf_dtb, 293*b139f1cfSMikael Olsson sub_node, 294*b139f1cfSMikael Olsson "ethosn-asset_allocator") == 0) { 29576a21174SMikael Olsson 296*b139f1cfSMikael Olsson if (dev_asset_alloc_count >= 297*b139f1cfSMikael Olsson ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX) { 298*b139f1cfSMikael Olsson ERROR("FCONF: Reached max number of asset allocators for NPU %u\n", 299*b139f1cfSMikael Olsson dev_count); 300*b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE; 301*b139f1cfSMikael Olsson } 302*b139f1cfSMikael Olsson 303*b139f1cfSMikael Olsson if (has_reserved_memory) { 304*b139f1cfSMikael Olsson ERROR("FCONF: Asset allocator not supported when using reserved memory\n"); 305*b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE; 306*b139f1cfSMikael Olsson } 307*b139f1cfSMikael Olsson 308*b139f1cfSMikael Olsson err = fdt_node_populate_asset_allocator(hw_conf_dtb, 309*b139f1cfSMikael Olsson sub_node, 310*b139f1cfSMikael Olsson &(dev->asset_allocators[dev_asset_alloc_count])); 311*b139f1cfSMikael Olsson if (err) { 312*b139f1cfSMikael Olsson ERROR("FCONF: Failed to parse asset allocator for NPU %u\n", 313*b139f1cfSMikael Olsson dev_count); 314*b139f1cfSMikael Olsson return err; 315*b139f1cfSMikael Olsson } 316*b139f1cfSMikael Olsson ++dev_asset_alloc_count; 317*b139f1cfSMikael Olsson } 31876a21174SMikael Olsson } 31976a21174SMikael Olsson 32076a21174SMikael Olsson if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) { 321*b139f1cfSMikael Olsson ERROR("FCONF: Failed to parse sub nodes for NPU %u\n", 322*b139f1cfSMikael Olsson dev_count); 3231c65989eSLaurent Carlier return -FDT_ERR_BADSTRUCTURE; 32476a21174SMikael Olsson } 32576a21174SMikael Olsson 326*b139f1cfSMikael Olsson if (dev_core_count == 0U) { 327*b139f1cfSMikael Olsson ERROR("FCONF: NPU %u must have at least one enabled core\n", 328*b139f1cfSMikael Olsson dev_count); 3291c65989eSLaurent Carlier return -FDT_ERR_BADSTRUCTURE; 3301c65989eSLaurent Carlier } 331*b139f1cfSMikael Olsson 332*b139f1cfSMikael Olsson if (!has_reserved_memory && dev_asset_alloc_count == 0U) { 333*b139f1cfSMikael Olsson ERROR("FCONF: NPU %u must have at least one asset allocator\n", 334*b139f1cfSMikael Olsson dev_count); 335*b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE; 33676a21174SMikael Olsson } 33776a21174SMikael Olsson 338*b139f1cfSMikael Olsson dev->num_cores = dev_core_count; 339*b139f1cfSMikael Olsson dev->num_allocators = dev_asset_alloc_count; 340*b139f1cfSMikael Olsson dev->has_reserved_memory = has_reserved_memory; 341*b139f1cfSMikael Olsson ++dev_count; 342*b139f1cfSMikael Olsson } 343*b139f1cfSMikael Olsson 344*b139f1cfSMikael Olsson if (dev_count == 0U) { 3451c65989eSLaurent Carlier ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n"); 3461c65989eSLaurent Carlier return -FDT_ERR_BADSTRUCTURE; 3471c65989eSLaurent Carlier } 3481c65989eSLaurent Carlier 349*b139f1cfSMikael Olsson ethosn_config.num_devices = dev_count; 35076a21174SMikael Olsson 35176a21174SMikael Olsson return 0; 35276a21174SMikael Olsson } 35376a21174SMikael Olsson 35476a21174SMikael Olsson FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config); 355