blob: 251471e63b6ae313b4260c6258a44d4baecb4e54 [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
Mikael Olsson3288b462022-08-15 17:12:58 +020023static 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;
Mikael Olsson7da66192021-02-12 17:30:22 +010026}
27
Mikael Olsson3288b462022-08-15 17:12:58 +020028static 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
42static 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
109static 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
131static 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
157static 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
Mikael Olsson7da66192021-02-12 17:30:22 +0100224int fconf_populate_ethosn_config(uintptr_t config)
225{
226 int ethosn_node;
Mikael Olsson3288b462022-08-15 17:12:58 +0200227 uint32_t dev_count = 0U;
Mikael Olsson7da66192021-02-12 17:30:22 +0100228 const void *hw_conf_dtb = (const void *)config;
229
Mikael Olsson3288b462022-08-15 17:12:58 +0200230 INFO("Probing Arm(R) Ethos(TM)-N NPU\n");
Mikael Olsson7da66192021-02-12 17:30:22 +0100231
Laurent Carlier5205df22021-09-16 15:10:35 +0100232 fdt_for_each_compatible_node(hw_conf_dtb, ethosn_node, "ethosn") {
Mikael Olsson3288b462022-08-15 17:12:58 +0200233 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;
Laurent Carlier5205df22021-09-16 15:10:35 +0100237 int sub_node;
Mikael Olsson7da66192021-02-12 17:30:22 +0100238
Mikael Olsson3288b462022-08-15 17:12:58 +0200239 if (!fdt_node_is_enabled(hw_conf_dtb, ethosn_node)) {
Mikael Olsson7da66192021-02-12 17:30:22 +0100240 continue;
241 }
242
Mikael Olsson3288b462022-08-15 17:12:58 +0200243 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);
Laurent Carlier5205df22021-09-16 15:10:35 +0100249 fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) {
250 int err;
Mikael Olsson7da66192021-02-12 17:30:22 +0100251
Mikael Olsson3288b462022-08-15 17:12:58 +0200252 if (!fdt_node_is_enabled(hw_conf_dtb, sub_node)) {
253 /* Ignore disabled sub node */
254 continue;
Laurent Carlier5205df22021-09-16 15:10:35 +0100255 }
256
Laurent Carlier5205df22021-09-16 15:10:35 +0100257 if (fdt_node_check_compatible(hw_conf_dtb,
258 sub_node,
Mikael Olsson3288b462022-08-15 17:12:58 +0200259 "ethosn-core") == 0) {
Laurent Carlier5205df22021-09-16 15:10:35 +0100260
Mikael Olsson3288b462022-08-15 17:12:58 +0200261 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 }
Laurent Carlier5205df22021-09-16 15:10:35 +0100266
Mikael Olsson3288b462022-08-15 17:12:58 +0200267 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 }
Laurent Carlier5205df22021-09-16 15:10:35 +0100292
Mikael Olsson3288b462022-08-15 17:12:58 +0200293 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 }
Mikael Olsson7da66192021-02-12 17:30:22 +0100303 }
304
Laurent Carlier5205df22021-09-16 15:10:35 +0100305 if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
Mikael Olsson3288b462022-08-15 17:12:58 +0200306 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);
Laurent Carlier5205df22021-09-16 15:10:35 +0100314 return -FDT_ERR_BADSTRUCTURE;
Mikael Olsson7da66192021-02-12 17:30:22 +0100315 }
316
Mikael Olsson3288b462022-08-15 17:12:58 +0200317 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);
Laurent Carlier5205df22021-09-16 15:10:35 +0100320 return -FDT_ERR_BADSTRUCTURE;
321 }
Mikael Olsson3288b462022-08-15 17:12:58 +0200322
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;
Mikael Olsson7da66192021-02-12 17:30:22 +0100327 }
328
Mikael Olsson3288b462022-08-15 17:12:58 +0200329 if (dev_count == 0U) {
Laurent Carlier5205df22021-09-16 15:10:35 +0100330 ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n");
331 return -FDT_ERR_BADSTRUCTURE;
Mikael Olsson7da66192021-02-12 17:30:22 +0100332 }
333
Mikael Olsson3288b462022-08-15 17:12:58 +0200334 ethosn_config.num_devices = dev_count;
Mikael Olsson7da66192021-02-12 17:30:22 +0100335
336 return 0;
337}
338
339FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config);