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