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