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 
fdt_node_get_status(const void * fdt,int node)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 
fconf_populate_ethosn_config(uintptr_t config)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);
109