Mikael Olsson | 7da6619 | 2021-02-12 17:30:22 +0100 | [diff] [blame] | 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; |
| 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 | int sub_node; |
| 37 | uint8_t ethosn_status; |
| 38 | uint32_t core_count = 0U; |
| 39 | uint32_t core_addr_idx = 0U; |
| 40 | const void *hw_conf_dtb = (const void *)config; |
| 41 | |
| 42 | /* Find offset to node with 'ethosn' compatible property */ |
| 43 | ethosn_node = fdt_node_offset_by_compatible(hw_conf_dtb, -1, "ethosn"); |
| 44 | if (ethosn_node < 0) { |
| 45 | ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n"); |
| 46 | return ethosn_node; |
| 47 | } |
| 48 | |
| 49 | /* If the Arm Ethos-N NPU is disabled the core check can be skipped */ |
| 50 | ethosn_status = fdt_node_get_status(hw_conf_dtb, ethosn_node); |
| 51 | if (ethosn_status == ETHOSN_STATUS_DISABLED) { |
| 52 | return 0; |
| 53 | } |
| 54 | |
| 55 | fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) { |
| 56 | int err; |
| 57 | uintptr_t addr; |
| 58 | uint8_t status; |
| 59 | |
| 60 | /* Check that the sub node is "ethosn-core" compatible */ |
| 61 | if (fdt_node_check_compatible(hw_conf_dtb, sub_node, |
| 62 | "ethosn-core") != 0) { |
| 63 | /* Ignore incompatible sub node */ |
| 64 | continue; |
| 65 | } |
| 66 | |
| 67 | /* Including disabled cores */ |
| 68 | if (core_addr_idx >= ETHOSN_CORE_NUM_MAX) { |
| 69 | ERROR("FCONF: Reached max number of Arm Ethos-N NPU cores\n"); |
| 70 | return -1; |
| 71 | } |
| 72 | |
| 73 | status = fdt_node_get_status(hw_conf_dtb, ethosn_node); |
| 74 | if (status == ETHOSN_STATUS_DISABLED) { |
| 75 | ++core_addr_idx; |
| 76 | continue; |
| 77 | } |
| 78 | |
| 79 | err = fdt_get_reg_props_by_index(hw_conf_dtb, ethosn_node, |
| 80 | core_addr_idx, &addr, NULL); |
| 81 | if (err < 0) { |
| 82 | ERROR("FCONF: Failed to read reg property for Arm Ethos-N NPU core %u\n", |
| 83 | core_addr_idx); |
| 84 | return err; |
| 85 | } |
| 86 | |
| 87 | ethosn_config.core_addr[core_count++] = addr; |
| 88 | ++core_addr_idx; |
| 89 | } |
| 90 | |
| 91 | if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) { |
| 92 | ERROR("FCONF: Failed to parse sub nodes\n"); |
| 93 | return sub_node; |
| 94 | } |
| 95 | |
| 96 | /* The Arm Ethos-N NPU can't be used if no cores were found */ |
| 97 | if (core_count == 0) { |
| 98 | ERROR("FCONF: No Arm Ethos-N NPU cores found\n"); |
| 99 | return -1; |
| 100 | } |
| 101 | |
| 102 | ethosn_config.num_cores = core_count; |
| 103 | ethosn_config.status = ethosn_status; |
| 104 | |
| 105 | return 0; |
| 106 | } |
| 107 | |
| 108 | FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config); |