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