blob: 7394e4241269ce75ceb5d670ca6369c579f01bc7 [file] [log] [blame]
Mikael Olsson7da66192021-02-12 17:30:22 +01001/*
Mikael Olssonc4f16ef2023-02-10 11:39:40 +01002 * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
Mikael Olsson7da66192021-02-12 17:30:22 +01003 *
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
Mikael Olsson3288b462022-08-15 17:12:58 +020015struct ethosn_config_t ethosn_config = {0};
Mikael Olsson7da66192021-02-12 17:30:22 +010016
Mikael Olsson3288b462022-08-15 17:12:58 +020017struct ethosn_sub_allocator_t {
18 const char *name;
19 size_t name_len;
20 uint32_t stream_id;
21};
22
Mikael Olssonc4f16ef2023-02-10 11:39:40 +010023static int fdt_node_read_reserved_memory_addr(const void *fdt,
24 int dev_node,
25 uint64_t *reserved_mem_addrs)
26{
27 uintptr_t addr;
28 uint32_t phandle;
29 int err;
30 int mem_node;
31
32 err = fdt_read_uint32(fdt, dev_node, "memory-region", &phandle);
33 if (err != 0) {
34 ERROR("FCONF: Failed to get reserved memory phandle\n");
35 return err;
36 }
37
38 mem_node = fdt_node_offset_by_phandle(fdt, phandle);
39 if (mem_node < 0) {
40 ERROR("FCONF: Failed to find reserved memory node from phandle\n");
41 return mem_node;
42 }
43
44 err = fdt_get_reg_props_by_index(fdt, mem_node, 0U, &addr, NULL);
45 if (err != 0) {
46 ERROR("FCONF: Failed to read reserved memory address\n");
47 return err;
48 }
49
50 *reserved_mem_addrs = addr;
51
52 return 0;
53}
54
Mikael Olsson3288b462022-08-15 17:12:58 +020055static bool fdt_node_has_reserved_memory(const void *fdt, int dev_node)
56{
57 return fdt_get_property(fdt, dev_node, "memory-region", NULL) != NULL;
Mikael Olsson7da66192021-02-12 17:30:22 +010058}
59
Mikael Olsson3288b462022-08-15 17:12:58 +020060static int fdt_node_get_iommus_stream_id(const void *fdt, int node, uint32_t *stream_id)
61{
62 int err;
63 uint32_t iommus_array[2] = {0U};
64
65 err = fdt_read_uint32_array(fdt, node, "iommus", 2U, iommus_array);
66 if (err) {
67 return err;
68 }
69
70 *stream_id = iommus_array[1];
71 return 0;
72}
73
74static int fdt_node_populate_sub_allocators(const void *fdt,
75 int alloc_node,
76 struct ethosn_sub_allocator_t *sub_allocators,
77 size_t num_allocs)
78{
79 int sub_node;
80 size_t i;
81 int err = -FDT_ERR_NOTFOUND;
82 uint32_t found_sub_allocators = 0U;
83
84 fdt_for_each_subnode(sub_node, fdt, alloc_node) {
85 const char *node_name;
86
87 if (!fdt_node_is_enabled(fdt, sub_node)) {
88 /* Ignore disabled node */
89 continue;
90 }
91
92 if (fdt_node_check_compatible(fdt, sub_node, "ethosn-memory") != 0) {
93 continue;
94 }
95
96 node_name = fdt_get_name(fdt, sub_node, NULL);
97 for (i = 0U; i < num_allocs; ++i) {
98 if (strncmp(node_name, sub_allocators[i].name,
99 sub_allocators[i].name_len) != 0) {
100 continue;
101 }
102
103 err = fdt_node_get_iommus_stream_id(fdt, sub_node,
104 &sub_allocators[i].stream_id);
105 if (err) {
106 ERROR("FCONF: Failed to get stream ID from sub-allocator %s\n",
107 node_name);
108 return err;
109 }
110
111 ++found_sub_allocators;
112 /* Nothing more to do for this node */
113 break;
114 }
115
116 /* Check that at least one of the sub-allocators matched */
117 if (i == num_allocs) {
118 ERROR("FCONF: Unknown sub-allocator %s\n", node_name);
119 return -FDT_ERR_BADSTRUCTURE;
120 }
121 }
122
123 if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
124 ERROR("FCONF: Failed to parse sub-allocators\n");
125 return -FDT_ERR_BADSTRUCTURE;
126 }
127
128 if (err == -FDT_ERR_NOTFOUND) {
129 ERROR("FCONF: No matching sub-allocator found\n");
130 return err;
131 }
132
133 if (found_sub_allocators != num_allocs) {
134 ERROR("FCONF: Not all sub-allocators were found\n");
135 return -FDT_ERR_BADSTRUCTURE;
136 }
137
138 return 0;
139}
140
141static int fdt_node_populate_main_allocator(const void *fdt,
142 int alloc_node,
143 struct ethosn_main_allocator_t *allocator)
144{
145 int err;
146 struct ethosn_sub_allocator_t sub_allocators[] = {
147 {.name = "firmware", .name_len = 8U},
148 {.name = "working_data", .name_len = 12U}
149 };
150
151 err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
152 ARRAY_SIZE(sub_allocators));
153 if (err) {
154 return err;
155 }
156
157 allocator->firmware.stream_id = sub_allocators[0].stream_id;
158 allocator->working_data.stream_id = sub_allocators[1].stream_id;
159
160 return 0;
161}
162
163static int fdt_node_populate_asset_allocator(const void *fdt,
164 int alloc_node,
165 struct ethosn_asset_allocator_t *allocator)
166{
167 int err;
168 struct ethosn_sub_allocator_t sub_allocators[] = {
169 {.name = "command_stream", .name_len = 14U},
170 {.name = "weight_data", .name_len = 11U},
171 {.name = "buffer_data", .name_len = 11U},
172 {.name = "intermediate_data", .name_len = 17U}
173 };
174
175 err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
176 ARRAY_SIZE(sub_allocators));
177 if (err) {
178 return err;
179 }
180
181
182 allocator->command_stream.stream_id = sub_allocators[0].stream_id;
183 allocator->weight_data.stream_id = sub_allocators[1].stream_id;
184 allocator->buffer_data.stream_id = sub_allocators[2].stream_id;
185 allocator->intermediate_data.stream_id = sub_allocators[3].stream_id;
186 return 0;
187}
188
189static int fdt_node_populate_core(const void *fdt,
190 int device_node,
191 int core_node,
192 bool has_reserved_memory,
193 uint32_t core_index,
194 struct ethosn_core_t *core)
195{
196 int err;
197 int sub_node;
198 uintptr_t core_addr;
199
200 err = fdt_get_reg_props_by_index(fdt, device_node, core_index,
201 &core_addr, NULL);
202 if (err < 0) {
203 ERROR("FCONF: Failed to read reg property for NPU core %u\n",
204 core_index);
205 return err;
206 }
207
208 err = -FDT_ERR_NOTFOUND;
209 fdt_for_each_subnode(sub_node, fdt, core_node) {
210
211 if (!fdt_node_is_enabled(fdt, sub_node)) {
212 continue;
213 }
214
215 if (fdt_node_check_compatible(fdt,
216 sub_node,
217 "ethosn-main_allocator") != 0) {
218 continue;
219 }
220
221 if (has_reserved_memory) {
222 ERROR("FCONF: Main allocator not supported when using reserved memory\n");
223 return -FDT_ERR_BADSTRUCTURE;
224 }
225
226 if (err != -FDT_ERR_NOTFOUND) {
227 ERROR("FCONF: NPU core 0x%lx has more than one main allocator\n",
228 core_addr);
229 return -FDT_ERR_BADSTRUCTURE;
230 }
231
232 err = fdt_node_populate_main_allocator(fdt, sub_node, &core->main_allocator);
233 if (err) {
234 ERROR("FCONF: Failed to parse main allocator for NPU core 0x%lx\n",
235 core_addr);
236 return err;
237 }
238 }
239
240 if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
241 ERROR("FCONF: Failed to parse core sub nodes\n");
242 return -FDT_ERR_BADSTRUCTURE;
243 }
244
245 if (!has_reserved_memory && err) {
246 ERROR("FCONF: Main allocator not found for NPU core 0x%lx\n",
247 core_addr);
248 return err;
249 }
250
251 core->addr = core_addr;
252
253 return 0;
254}
255
Mikael Olsson7da66192021-02-12 17:30:22 +0100256int fconf_populate_ethosn_config(uintptr_t config)
257{
258 int ethosn_node;
Mikael Olsson3288b462022-08-15 17:12:58 +0200259 uint32_t dev_count = 0U;
Mikael Olsson7da66192021-02-12 17:30:22 +0100260 const void *hw_conf_dtb = (const void *)config;
261
Mikael Olsson3288b462022-08-15 17:12:58 +0200262 INFO("Probing Arm(R) Ethos(TM)-N NPU\n");
Mikael Olsson7da66192021-02-12 17:30:22 +0100263
Laurent Carlier5205df22021-09-16 15:10:35 +0100264 fdt_for_each_compatible_node(hw_conf_dtb, ethosn_node, "ethosn") {
Mikael Olsson3288b462022-08-15 17:12:58 +0200265 struct ethosn_device_t *dev = &ethosn_config.devices[dev_count];
266 uint32_t dev_asset_alloc_count = 0U;
267 uint32_t dev_core_count = 0U;
Mikael Olssonc4f16ef2023-02-10 11:39:40 +0100268 uint64_t reserved_memory_addr = 0U;
Mikael Olsson3288b462022-08-15 17:12:58 +0200269 bool has_reserved_memory;
Laurent Carlier5205df22021-09-16 15:10:35 +0100270 int sub_node;
Mikael Olssonc4f16ef2023-02-10 11:39:40 +0100271 int err;
Mikael Olsson7da66192021-02-12 17:30:22 +0100272
Mikael Olsson3288b462022-08-15 17:12:58 +0200273 if (!fdt_node_is_enabled(hw_conf_dtb, ethosn_node)) {
Mikael Olsson7da66192021-02-12 17:30:22 +0100274 continue;
275 }
276
Mikael Olsson3288b462022-08-15 17:12:58 +0200277 if (dev_count >= ETHOSN_DEV_NUM_MAX) {
278 ERROR("FCONF: Reached max number of NPUs\n");
279 return -FDT_ERR_BADSTRUCTURE;
280 }
281
282 has_reserved_memory = fdt_node_has_reserved_memory(hw_conf_dtb, ethosn_node);
Mikael Olssonc4f16ef2023-02-10 11:39:40 +0100283 if (has_reserved_memory) {
284 err = fdt_node_read_reserved_memory_addr(hw_conf_dtb,
285 ethosn_node,
286 &reserved_memory_addr);
287 if (err != 0) {
288 return err;
289 }
290 }
291
Laurent Carlier5205df22021-09-16 15:10:35 +0100292 fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) {
Mikael Olsson7da66192021-02-12 17:30:22 +0100293
Mikael Olsson3288b462022-08-15 17:12:58 +0200294 if (!fdt_node_is_enabled(hw_conf_dtb, sub_node)) {
295 /* Ignore disabled sub node */
296 continue;
Laurent Carlier5205df22021-09-16 15:10:35 +0100297 }
298
Laurent Carlier5205df22021-09-16 15:10:35 +0100299 if (fdt_node_check_compatible(hw_conf_dtb,
300 sub_node,
Mikael Olsson3288b462022-08-15 17:12:58 +0200301 "ethosn-core") == 0) {
Laurent Carlier5205df22021-09-16 15:10:35 +0100302
Mikael Olsson3288b462022-08-15 17:12:58 +0200303 if (dev_core_count >= ETHOSN_DEV_CORE_NUM_MAX) {
304 ERROR("FCONF: Reached max number of NPU cores for NPU %u\n",
305 dev_count);
306 return -FDT_ERR_BADSTRUCTURE;
307 }
Laurent Carlier5205df22021-09-16 15:10:35 +0100308
Mikael Olsson3288b462022-08-15 17:12:58 +0200309 err = fdt_node_populate_core(hw_conf_dtb,
310 ethosn_node,
311 sub_node,
312 has_reserved_memory,
313 dev_core_count,
314 &(dev->cores[dev_core_count]));
315 if (err) {
316 return err;
317 }
318 ++dev_core_count;
319 } else if (fdt_node_check_compatible(hw_conf_dtb,
320 sub_node,
321 "ethosn-asset_allocator") == 0) {
322
323 if (dev_asset_alloc_count >=
324 ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX) {
325 ERROR("FCONF: Reached max number of asset allocators for NPU %u\n",
326 dev_count);
327 return -FDT_ERR_BADSTRUCTURE;
328 }
329
330 if (has_reserved_memory) {
331 ERROR("FCONF: Asset allocator not supported when using reserved memory\n");
332 return -FDT_ERR_BADSTRUCTURE;
333 }
Laurent Carlier5205df22021-09-16 15:10:35 +0100334
Mikael Olsson3288b462022-08-15 17:12:58 +0200335 err = fdt_node_populate_asset_allocator(hw_conf_dtb,
336 sub_node,
337 &(dev->asset_allocators[dev_asset_alloc_count]));
338 if (err) {
339 ERROR("FCONF: Failed to parse asset allocator for NPU %u\n",
340 dev_count);
341 return err;
342 }
343 ++dev_asset_alloc_count;
344 }
Mikael Olsson7da66192021-02-12 17:30:22 +0100345 }
346
Laurent Carlier5205df22021-09-16 15:10:35 +0100347 if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
Mikael Olsson3288b462022-08-15 17:12:58 +0200348 ERROR("FCONF: Failed to parse sub nodes for NPU %u\n",
349 dev_count);
350 return -FDT_ERR_BADSTRUCTURE;
351 }
352
353 if (dev_core_count == 0U) {
354 ERROR("FCONF: NPU %u must have at least one enabled core\n",
355 dev_count);
Laurent Carlier5205df22021-09-16 15:10:35 +0100356 return -FDT_ERR_BADSTRUCTURE;
Mikael Olsson7da66192021-02-12 17:30:22 +0100357 }
358
Mikael Olsson3288b462022-08-15 17:12:58 +0200359 if (!has_reserved_memory && dev_asset_alloc_count == 0U) {
360 ERROR("FCONF: NPU %u must have at least one asset allocator\n",
361 dev_count);
Laurent Carlier5205df22021-09-16 15:10:35 +0100362 return -FDT_ERR_BADSTRUCTURE;
363 }
Mikael Olsson3288b462022-08-15 17:12:58 +0200364
365 dev->num_cores = dev_core_count;
366 dev->num_allocators = dev_asset_alloc_count;
367 dev->has_reserved_memory = has_reserved_memory;
Mikael Olssonc4f16ef2023-02-10 11:39:40 +0100368 dev->reserved_memory_addr = reserved_memory_addr;
Mikael Olsson3288b462022-08-15 17:12:58 +0200369 ++dev_count;
Mikael Olsson7da66192021-02-12 17:30:22 +0100370 }
371
Mikael Olsson3288b462022-08-15 17:12:58 +0200372 if (dev_count == 0U) {
Laurent Carlier5205df22021-09-16 15:10:35 +0100373 ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n");
374 return -FDT_ERR_BADSTRUCTURE;
Mikael Olsson7da66192021-02-12 17:30:22 +0100375 }
376
Mikael Olsson3288b462022-08-15 17:12:58 +0200377 ethosn_config.num_devices = dev_count;
Mikael Olsson7da66192021-02-12 17:30:22 +0100378
379 return 0;
380}
381
382FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config);