blob: 0b48a9816338541e621920f268838e8942e1809b [file] [log] [blame]
Mikael Olsson7da66192021-02-12 17:30:22 +01001/*
Mikael Olsson3288b462022-08-15 17:12:58 +02002 * Copyright (c) 2021-2022, 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
23static bool fdt_node_is_enabled(const void *fdt, int node)
Mikael Olsson7da66192021-02-12 17:30:22 +010024{
25 int len;
Mikael Olsson7da66192021-02-12 17:30:22 +010026 const char *node_status;
27
28 node_status = fdt_getprop(fdt, node, "status", &len);
29 if (node_status == NULL ||
30 (len == 5 && /* Includes null character */
31 strncmp(node_status, "okay", 4U) == 0)) {
Mikael Olsson3288b462022-08-15 17:12:58 +020032 return true;
Mikael Olsson7da66192021-02-12 17:30:22 +010033 }
34
Mikael Olsson3288b462022-08-15 17:12:58 +020035 return false;
36}
37
38static bool fdt_node_has_reserved_memory(const void *fdt, int dev_node)
39{
40 return fdt_get_property(fdt, dev_node, "memory-region", NULL) != NULL;
Mikael Olsson7da66192021-02-12 17:30:22 +010041}
42
Mikael Olsson3288b462022-08-15 17:12:58 +020043static int fdt_node_get_iommus_stream_id(const void *fdt, int node, uint32_t *stream_id)
44{
45 int err;
46 uint32_t iommus_array[2] = {0U};
47
48 err = fdt_read_uint32_array(fdt, node, "iommus", 2U, iommus_array);
49 if (err) {
50 return err;
51 }
52
53 *stream_id = iommus_array[1];
54 return 0;
55}
56
57static int fdt_node_populate_sub_allocators(const void *fdt,
58 int alloc_node,
59 struct ethosn_sub_allocator_t *sub_allocators,
60 size_t num_allocs)
61{
62 int sub_node;
63 size_t i;
64 int err = -FDT_ERR_NOTFOUND;
65 uint32_t found_sub_allocators = 0U;
66
67 fdt_for_each_subnode(sub_node, fdt, alloc_node) {
68 const char *node_name;
69
70 if (!fdt_node_is_enabled(fdt, sub_node)) {
71 /* Ignore disabled node */
72 continue;
73 }
74
75 if (fdt_node_check_compatible(fdt, sub_node, "ethosn-memory") != 0) {
76 continue;
77 }
78
79 node_name = fdt_get_name(fdt, sub_node, NULL);
80 for (i = 0U; i < num_allocs; ++i) {
81 if (strncmp(node_name, sub_allocators[i].name,
82 sub_allocators[i].name_len) != 0) {
83 continue;
84 }
85
86 err = fdt_node_get_iommus_stream_id(fdt, sub_node,
87 &sub_allocators[i].stream_id);
88 if (err) {
89 ERROR("FCONF: Failed to get stream ID from sub-allocator %s\n",
90 node_name);
91 return err;
92 }
93
94 ++found_sub_allocators;
95 /* Nothing more to do for this node */
96 break;
97 }
98
99 /* Check that at least one of the sub-allocators matched */
100 if (i == num_allocs) {
101 ERROR("FCONF: Unknown sub-allocator %s\n", node_name);
102 return -FDT_ERR_BADSTRUCTURE;
103 }
104 }
105
106 if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
107 ERROR("FCONF: Failed to parse sub-allocators\n");
108 return -FDT_ERR_BADSTRUCTURE;
109 }
110
111 if (err == -FDT_ERR_NOTFOUND) {
112 ERROR("FCONF: No matching sub-allocator found\n");
113 return err;
114 }
115
116 if (found_sub_allocators != num_allocs) {
117 ERROR("FCONF: Not all sub-allocators were found\n");
118 return -FDT_ERR_BADSTRUCTURE;
119 }
120
121 return 0;
122}
123
124static int fdt_node_populate_main_allocator(const void *fdt,
125 int alloc_node,
126 struct ethosn_main_allocator_t *allocator)
127{
128 int err;
129 struct ethosn_sub_allocator_t sub_allocators[] = {
130 {.name = "firmware", .name_len = 8U},
131 {.name = "working_data", .name_len = 12U}
132 };
133
134 err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
135 ARRAY_SIZE(sub_allocators));
136 if (err) {
137 return err;
138 }
139
140 allocator->firmware.stream_id = sub_allocators[0].stream_id;
141 allocator->working_data.stream_id = sub_allocators[1].stream_id;
142
143 return 0;
144}
145
146static int fdt_node_populate_asset_allocator(const void *fdt,
147 int alloc_node,
148 struct ethosn_asset_allocator_t *allocator)
149{
150 int err;
151 struct ethosn_sub_allocator_t sub_allocators[] = {
152 {.name = "command_stream", .name_len = 14U},
153 {.name = "weight_data", .name_len = 11U},
154 {.name = "buffer_data", .name_len = 11U},
155 {.name = "intermediate_data", .name_len = 17U}
156 };
157
158 err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
159 ARRAY_SIZE(sub_allocators));
160 if (err) {
161 return err;
162 }
163
164
165 allocator->command_stream.stream_id = sub_allocators[0].stream_id;
166 allocator->weight_data.stream_id = sub_allocators[1].stream_id;
167 allocator->buffer_data.stream_id = sub_allocators[2].stream_id;
168 allocator->intermediate_data.stream_id = sub_allocators[3].stream_id;
169 return 0;
170}
171
172static int fdt_node_populate_core(const void *fdt,
173 int device_node,
174 int core_node,
175 bool has_reserved_memory,
176 uint32_t core_index,
177 struct ethosn_core_t *core)
178{
179 int err;
180 int sub_node;
181 uintptr_t core_addr;
182
183 err = fdt_get_reg_props_by_index(fdt, device_node, core_index,
184 &core_addr, NULL);
185 if (err < 0) {
186 ERROR("FCONF: Failed to read reg property for NPU core %u\n",
187 core_index);
188 return err;
189 }
190
191 err = -FDT_ERR_NOTFOUND;
192 fdt_for_each_subnode(sub_node, fdt, core_node) {
193
194 if (!fdt_node_is_enabled(fdt, sub_node)) {
195 continue;
196 }
197
198 if (fdt_node_check_compatible(fdt,
199 sub_node,
200 "ethosn-main_allocator") != 0) {
201 continue;
202 }
203
204 if (has_reserved_memory) {
205 ERROR("FCONF: Main allocator not supported when using reserved memory\n");
206 return -FDT_ERR_BADSTRUCTURE;
207 }
208
209 if (err != -FDT_ERR_NOTFOUND) {
210 ERROR("FCONF: NPU core 0x%lx has more than one main allocator\n",
211 core_addr);
212 return -FDT_ERR_BADSTRUCTURE;
213 }
214
215 err = fdt_node_populate_main_allocator(fdt, sub_node, &core->main_allocator);
216 if (err) {
217 ERROR("FCONF: Failed to parse main allocator for NPU core 0x%lx\n",
218 core_addr);
219 return err;
220 }
221 }
222
223 if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
224 ERROR("FCONF: Failed to parse core sub nodes\n");
225 return -FDT_ERR_BADSTRUCTURE;
226 }
227
228 if (!has_reserved_memory && err) {
229 ERROR("FCONF: Main allocator not found for NPU core 0x%lx\n",
230 core_addr);
231 return err;
232 }
233
234 core->addr = core_addr;
235
236 return 0;
237}
238
Mikael Olsson7da66192021-02-12 17:30:22 +0100239int fconf_populate_ethosn_config(uintptr_t config)
240{
241 int ethosn_node;
Mikael Olsson3288b462022-08-15 17:12:58 +0200242 uint32_t dev_count = 0U;
Mikael Olsson7da66192021-02-12 17:30:22 +0100243 const void *hw_conf_dtb = (const void *)config;
244
Mikael Olsson3288b462022-08-15 17:12:58 +0200245 INFO("Probing Arm(R) Ethos(TM)-N NPU\n");
Mikael Olsson7da66192021-02-12 17:30:22 +0100246
Laurent Carlier5205df22021-09-16 15:10:35 +0100247 fdt_for_each_compatible_node(hw_conf_dtb, ethosn_node, "ethosn") {
Mikael Olsson3288b462022-08-15 17:12:58 +0200248 struct ethosn_device_t *dev = &ethosn_config.devices[dev_count];
249 uint32_t dev_asset_alloc_count = 0U;
250 uint32_t dev_core_count = 0U;
251 bool has_reserved_memory;
Laurent Carlier5205df22021-09-16 15:10:35 +0100252 int sub_node;
Mikael Olsson7da66192021-02-12 17:30:22 +0100253
Mikael Olsson3288b462022-08-15 17:12:58 +0200254 if (!fdt_node_is_enabled(hw_conf_dtb, ethosn_node)) {
Mikael Olsson7da66192021-02-12 17:30:22 +0100255 continue;
256 }
257
Mikael Olsson3288b462022-08-15 17:12:58 +0200258 if (dev_count >= ETHOSN_DEV_NUM_MAX) {
259 ERROR("FCONF: Reached max number of NPUs\n");
260 return -FDT_ERR_BADSTRUCTURE;
261 }
262
263 has_reserved_memory = fdt_node_has_reserved_memory(hw_conf_dtb, ethosn_node);
Laurent Carlier5205df22021-09-16 15:10:35 +0100264 fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) {
265 int err;
Mikael Olsson7da66192021-02-12 17:30:22 +0100266
Mikael Olsson3288b462022-08-15 17:12:58 +0200267 if (!fdt_node_is_enabled(hw_conf_dtb, sub_node)) {
268 /* Ignore disabled sub node */
269 continue;
Laurent Carlier5205df22021-09-16 15:10:35 +0100270 }
271
Laurent Carlier5205df22021-09-16 15:10:35 +0100272 if (fdt_node_check_compatible(hw_conf_dtb,
273 sub_node,
Mikael Olsson3288b462022-08-15 17:12:58 +0200274 "ethosn-core") == 0) {
Laurent Carlier5205df22021-09-16 15:10:35 +0100275
Mikael Olsson3288b462022-08-15 17:12:58 +0200276 if (dev_core_count >= ETHOSN_DEV_CORE_NUM_MAX) {
277 ERROR("FCONF: Reached max number of NPU cores for NPU %u\n",
278 dev_count);
279 return -FDT_ERR_BADSTRUCTURE;
280 }
Laurent Carlier5205df22021-09-16 15:10:35 +0100281
Mikael Olsson3288b462022-08-15 17:12:58 +0200282 err = fdt_node_populate_core(hw_conf_dtb,
283 ethosn_node,
284 sub_node,
285 has_reserved_memory,
286 dev_core_count,
287 &(dev->cores[dev_core_count]));
288 if (err) {
289 return err;
290 }
291 ++dev_core_count;
292 } else if (fdt_node_check_compatible(hw_conf_dtb,
293 sub_node,
294 "ethosn-asset_allocator") == 0) {
295
296 if (dev_asset_alloc_count >=
297 ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX) {
298 ERROR("FCONF: Reached max number of asset allocators for NPU %u\n",
299 dev_count);
300 return -FDT_ERR_BADSTRUCTURE;
301 }
302
303 if (has_reserved_memory) {
304 ERROR("FCONF: Asset allocator not supported when using reserved memory\n");
305 return -FDT_ERR_BADSTRUCTURE;
306 }
Laurent Carlier5205df22021-09-16 15:10:35 +0100307
Mikael Olsson3288b462022-08-15 17:12:58 +0200308 err = fdt_node_populate_asset_allocator(hw_conf_dtb,
309 sub_node,
310 &(dev->asset_allocators[dev_asset_alloc_count]));
311 if (err) {
312 ERROR("FCONF: Failed to parse asset allocator for NPU %u\n",
313 dev_count);
314 return err;
315 }
316 ++dev_asset_alloc_count;
317 }
Mikael Olsson7da66192021-02-12 17:30:22 +0100318 }
319
Laurent Carlier5205df22021-09-16 15:10:35 +0100320 if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
Mikael Olsson3288b462022-08-15 17:12:58 +0200321 ERROR("FCONF: Failed to parse sub nodes for NPU %u\n",
322 dev_count);
323 return -FDT_ERR_BADSTRUCTURE;
324 }
325
326 if (dev_core_count == 0U) {
327 ERROR("FCONF: NPU %u must have at least one enabled core\n",
328 dev_count);
Laurent Carlier5205df22021-09-16 15:10:35 +0100329 return -FDT_ERR_BADSTRUCTURE;
Mikael Olsson7da66192021-02-12 17:30:22 +0100330 }
331
Mikael Olsson3288b462022-08-15 17:12:58 +0200332 if (!has_reserved_memory && dev_asset_alloc_count == 0U) {
333 ERROR("FCONF: NPU %u must have at least one asset allocator\n",
334 dev_count);
Laurent Carlier5205df22021-09-16 15:10:35 +0100335 return -FDT_ERR_BADSTRUCTURE;
336 }
Mikael Olsson3288b462022-08-15 17:12:58 +0200337
338 dev->num_cores = dev_core_count;
339 dev->num_allocators = dev_asset_alloc_count;
340 dev->has_reserved_memory = has_reserved_memory;
341 ++dev_count;
Mikael Olsson7da66192021-02-12 17:30:22 +0100342 }
343
Mikael Olsson3288b462022-08-15 17:12:58 +0200344 if (dev_count == 0U) {
Laurent Carlier5205df22021-09-16 15:10:35 +0100345 ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n");
346 return -FDT_ERR_BADSTRUCTURE;
Mikael Olsson7da66192021-02-12 17:30:22 +0100347 }
348
Mikael Olsson3288b462022-08-15 17:12:58 +0200349 ethosn_config.num_devices = dev_count;
Mikael Olsson7da66192021-02-12 17:30:22 +0100350
351 return 0;
352}
353
354FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config);