176a21174SMikael Olsson /*
2*a19a0241SMikael Olsson * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
376a21174SMikael Olsson *
476a21174SMikael Olsson * SPDX-License-Identifier: BSD-3-Clause
576a21174SMikael Olsson */
676a21174SMikael Olsson
776a21174SMikael Olsson #include <assert.h>
876a21174SMikael Olsson #include <string.h>
976a21174SMikael Olsson
1076a21174SMikael Olsson #include <common/debug.h>
1176a21174SMikael Olsson #include <common/fdt_wrappers.h>
1276a21174SMikael Olsson #include <libfdt.h>
1376a21174SMikael Olsson #include <plat/arm/common/fconf_ethosn_getter.h>
1476a21174SMikael Olsson
15b139f1cfSMikael Olsson struct ethosn_config_t ethosn_config = {0};
1676a21174SMikael Olsson
17b139f1cfSMikael Olsson struct ethosn_sub_allocator_t {
18b139f1cfSMikael Olsson const char *name;
19b139f1cfSMikael Olsson size_t name_len;
20b139f1cfSMikael Olsson uint32_t stream_id;
21b139f1cfSMikael Olsson };
22b139f1cfSMikael Olsson
fdt_node_read_reserved_memory_addr(const void * fdt,int dev_node,uint64_t * reserved_mem_addrs)23*a19a0241SMikael Olsson static int fdt_node_read_reserved_memory_addr(const void *fdt,
24*a19a0241SMikael Olsson int dev_node,
25*a19a0241SMikael Olsson uint64_t *reserved_mem_addrs)
26*a19a0241SMikael Olsson {
27*a19a0241SMikael Olsson uintptr_t addr;
28*a19a0241SMikael Olsson uint32_t phandle;
29*a19a0241SMikael Olsson int err;
30*a19a0241SMikael Olsson int mem_node;
31*a19a0241SMikael Olsson
32*a19a0241SMikael Olsson err = fdt_read_uint32(fdt, dev_node, "memory-region", &phandle);
33*a19a0241SMikael Olsson if (err != 0) {
34*a19a0241SMikael Olsson ERROR("FCONF: Failed to get reserved memory phandle\n");
35*a19a0241SMikael Olsson return err;
36*a19a0241SMikael Olsson }
37*a19a0241SMikael Olsson
38*a19a0241SMikael Olsson mem_node = fdt_node_offset_by_phandle(fdt, phandle);
39*a19a0241SMikael Olsson if (mem_node < 0) {
40*a19a0241SMikael Olsson ERROR("FCONF: Failed to find reserved memory node from phandle\n");
41*a19a0241SMikael Olsson return mem_node;
42*a19a0241SMikael Olsson }
43*a19a0241SMikael Olsson
44*a19a0241SMikael Olsson err = fdt_get_reg_props_by_index(fdt, mem_node, 0U, &addr, NULL);
45*a19a0241SMikael Olsson if (err != 0) {
46*a19a0241SMikael Olsson ERROR("FCONF: Failed to read reserved memory address\n");
47*a19a0241SMikael Olsson return err;
48*a19a0241SMikael Olsson }
49*a19a0241SMikael Olsson
50*a19a0241SMikael Olsson *reserved_mem_addrs = addr;
51*a19a0241SMikael Olsson
52*a19a0241SMikael Olsson return 0;
53*a19a0241SMikael Olsson }
54*a19a0241SMikael Olsson
fdt_node_has_reserved_memory(const void * fdt,int dev_node)55b139f1cfSMikael Olsson static bool fdt_node_has_reserved_memory(const void *fdt, int dev_node)
56b139f1cfSMikael Olsson {
57b139f1cfSMikael Olsson return fdt_get_property(fdt, dev_node, "memory-region", NULL) != NULL;
58b139f1cfSMikael Olsson }
59b139f1cfSMikael Olsson
fdt_node_get_iommus_stream_id(const void * fdt,int node,uint32_t * stream_id)60b139f1cfSMikael Olsson static int fdt_node_get_iommus_stream_id(const void *fdt, int node, uint32_t *stream_id)
61b139f1cfSMikael Olsson {
62b139f1cfSMikael Olsson int err;
63b139f1cfSMikael Olsson uint32_t iommus_array[2] = {0U};
64b139f1cfSMikael Olsson
65b139f1cfSMikael Olsson err = fdt_read_uint32_array(fdt, node, "iommus", 2U, iommus_array);
66b139f1cfSMikael Olsson if (err) {
67b139f1cfSMikael Olsson return err;
68b139f1cfSMikael Olsson }
69b139f1cfSMikael Olsson
70b139f1cfSMikael Olsson *stream_id = iommus_array[1];
71b139f1cfSMikael Olsson return 0;
72b139f1cfSMikael Olsson }
73b139f1cfSMikael Olsson
fdt_node_populate_sub_allocators(const void * fdt,int alloc_node,struct ethosn_sub_allocator_t * sub_allocators,size_t num_allocs)74b139f1cfSMikael Olsson static int fdt_node_populate_sub_allocators(const void *fdt,
75b139f1cfSMikael Olsson int alloc_node,
76b139f1cfSMikael Olsson struct ethosn_sub_allocator_t *sub_allocators,
77b139f1cfSMikael Olsson size_t num_allocs)
78b139f1cfSMikael Olsson {
79b139f1cfSMikael Olsson int sub_node;
80b139f1cfSMikael Olsson size_t i;
81b139f1cfSMikael Olsson int err = -FDT_ERR_NOTFOUND;
82b139f1cfSMikael Olsson uint32_t found_sub_allocators = 0U;
83b139f1cfSMikael Olsson
84b139f1cfSMikael Olsson fdt_for_each_subnode(sub_node, fdt, alloc_node) {
85b139f1cfSMikael Olsson const char *node_name;
86b139f1cfSMikael Olsson
87b139f1cfSMikael Olsson if (!fdt_node_is_enabled(fdt, sub_node)) {
88b139f1cfSMikael Olsson /* Ignore disabled node */
89b139f1cfSMikael Olsson continue;
90b139f1cfSMikael Olsson }
91b139f1cfSMikael Olsson
92b139f1cfSMikael Olsson if (fdt_node_check_compatible(fdt, sub_node, "ethosn-memory") != 0) {
93b139f1cfSMikael Olsson continue;
94b139f1cfSMikael Olsson }
95b139f1cfSMikael Olsson
96b139f1cfSMikael Olsson node_name = fdt_get_name(fdt, sub_node, NULL);
97b139f1cfSMikael Olsson for (i = 0U; i < num_allocs; ++i) {
98b139f1cfSMikael Olsson if (strncmp(node_name, sub_allocators[i].name,
99b139f1cfSMikael Olsson sub_allocators[i].name_len) != 0) {
100b139f1cfSMikael Olsson continue;
101b139f1cfSMikael Olsson }
102b139f1cfSMikael Olsson
103b139f1cfSMikael Olsson err = fdt_node_get_iommus_stream_id(fdt, sub_node,
104b139f1cfSMikael Olsson &sub_allocators[i].stream_id);
105b139f1cfSMikael Olsson if (err) {
106b139f1cfSMikael Olsson ERROR("FCONF: Failed to get stream ID from sub-allocator %s\n",
107b139f1cfSMikael Olsson node_name);
108b139f1cfSMikael Olsson return err;
109b139f1cfSMikael Olsson }
110b139f1cfSMikael Olsson
111b139f1cfSMikael Olsson ++found_sub_allocators;
112b139f1cfSMikael Olsson /* Nothing more to do for this node */
113b139f1cfSMikael Olsson break;
114b139f1cfSMikael Olsson }
115b139f1cfSMikael Olsson
116b139f1cfSMikael Olsson /* Check that at least one of the sub-allocators matched */
117b139f1cfSMikael Olsson if (i == num_allocs) {
118b139f1cfSMikael Olsson ERROR("FCONF: Unknown sub-allocator %s\n", node_name);
119b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE;
120b139f1cfSMikael Olsson }
121b139f1cfSMikael Olsson }
122b139f1cfSMikael Olsson
123b139f1cfSMikael Olsson if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
124b139f1cfSMikael Olsson ERROR("FCONF: Failed to parse sub-allocators\n");
125b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE;
126b139f1cfSMikael Olsson }
127b139f1cfSMikael Olsson
128b139f1cfSMikael Olsson if (err == -FDT_ERR_NOTFOUND) {
129b139f1cfSMikael Olsson ERROR("FCONF: No matching sub-allocator found\n");
130b139f1cfSMikael Olsson return err;
131b139f1cfSMikael Olsson }
132b139f1cfSMikael Olsson
133b139f1cfSMikael Olsson if (found_sub_allocators != num_allocs) {
134b139f1cfSMikael Olsson ERROR("FCONF: Not all sub-allocators were found\n");
135b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE;
136b139f1cfSMikael Olsson }
137b139f1cfSMikael Olsson
138b139f1cfSMikael Olsson return 0;
139b139f1cfSMikael Olsson }
140b139f1cfSMikael Olsson
fdt_node_populate_main_allocator(const void * fdt,int alloc_node,struct ethosn_main_allocator_t * allocator)141b139f1cfSMikael Olsson static int fdt_node_populate_main_allocator(const void *fdt,
142b139f1cfSMikael Olsson int alloc_node,
143b139f1cfSMikael Olsson struct ethosn_main_allocator_t *allocator)
144b139f1cfSMikael Olsson {
145b139f1cfSMikael Olsson int err;
146b139f1cfSMikael Olsson struct ethosn_sub_allocator_t sub_allocators[] = {
147b139f1cfSMikael Olsson {.name = "firmware", .name_len = 8U},
148b139f1cfSMikael Olsson {.name = "working_data", .name_len = 12U}
149b139f1cfSMikael Olsson };
150b139f1cfSMikael Olsson
151b139f1cfSMikael Olsson err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
152b139f1cfSMikael Olsson ARRAY_SIZE(sub_allocators));
153b139f1cfSMikael Olsson if (err) {
154b139f1cfSMikael Olsson return err;
155b139f1cfSMikael Olsson }
156b139f1cfSMikael Olsson
157b139f1cfSMikael Olsson allocator->firmware.stream_id = sub_allocators[0].stream_id;
158b139f1cfSMikael Olsson allocator->working_data.stream_id = sub_allocators[1].stream_id;
159b139f1cfSMikael Olsson
160b139f1cfSMikael Olsson return 0;
161b139f1cfSMikael Olsson }
162b139f1cfSMikael Olsson
fdt_node_populate_asset_allocator(const void * fdt,int alloc_node,struct ethosn_asset_allocator_t * allocator)163b139f1cfSMikael Olsson static int fdt_node_populate_asset_allocator(const void *fdt,
164b139f1cfSMikael Olsson int alloc_node,
165b139f1cfSMikael Olsson struct ethosn_asset_allocator_t *allocator)
166b139f1cfSMikael Olsson {
167b139f1cfSMikael Olsson int err;
168b139f1cfSMikael Olsson struct ethosn_sub_allocator_t sub_allocators[] = {
169b139f1cfSMikael Olsson {.name = "command_stream", .name_len = 14U},
170b139f1cfSMikael Olsson {.name = "weight_data", .name_len = 11U},
171b139f1cfSMikael Olsson {.name = "buffer_data", .name_len = 11U},
172b139f1cfSMikael Olsson {.name = "intermediate_data", .name_len = 17U}
173b139f1cfSMikael Olsson };
174b139f1cfSMikael Olsson
175b139f1cfSMikael Olsson err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
176b139f1cfSMikael Olsson ARRAY_SIZE(sub_allocators));
177b139f1cfSMikael Olsson if (err) {
178b139f1cfSMikael Olsson return err;
179b139f1cfSMikael Olsson }
180b139f1cfSMikael Olsson
181b139f1cfSMikael Olsson
182b139f1cfSMikael Olsson allocator->command_stream.stream_id = sub_allocators[0].stream_id;
183b139f1cfSMikael Olsson allocator->weight_data.stream_id = sub_allocators[1].stream_id;
184b139f1cfSMikael Olsson allocator->buffer_data.stream_id = sub_allocators[2].stream_id;
185b139f1cfSMikael Olsson allocator->intermediate_data.stream_id = sub_allocators[3].stream_id;
186b139f1cfSMikael Olsson return 0;
187b139f1cfSMikael Olsson }
188b139f1cfSMikael Olsson
fdt_node_populate_core(const void * fdt,int device_node,int core_node,bool has_reserved_memory,uint32_t core_index,struct ethosn_core_t * core)189b139f1cfSMikael Olsson static int fdt_node_populate_core(const void *fdt,
190b139f1cfSMikael Olsson int device_node,
191b139f1cfSMikael Olsson int core_node,
192b139f1cfSMikael Olsson bool has_reserved_memory,
193b139f1cfSMikael Olsson uint32_t core_index,
194b139f1cfSMikael Olsson struct ethosn_core_t *core)
195b139f1cfSMikael Olsson {
196b139f1cfSMikael Olsson int err;
197b139f1cfSMikael Olsson int sub_node;
198b139f1cfSMikael Olsson uintptr_t core_addr;
199b139f1cfSMikael Olsson
200b139f1cfSMikael Olsson err = fdt_get_reg_props_by_index(fdt, device_node, core_index,
201b139f1cfSMikael Olsson &core_addr, NULL);
202b139f1cfSMikael Olsson if (err < 0) {
203b139f1cfSMikael Olsson ERROR("FCONF: Failed to read reg property for NPU core %u\n",
204b139f1cfSMikael Olsson core_index);
205b139f1cfSMikael Olsson return err;
206b139f1cfSMikael Olsson }
207b139f1cfSMikael Olsson
208b139f1cfSMikael Olsson err = -FDT_ERR_NOTFOUND;
209b139f1cfSMikael Olsson fdt_for_each_subnode(sub_node, fdt, core_node) {
210b139f1cfSMikael Olsson
211b139f1cfSMikael Olsson if (!fdt_node_is_enabled(fdt, sub_node)) {
212b139f1cfSMikael Olsson continue;
213b139f1cfSMikael Olsson }
214b139f1cfSMikael Olsson
215b139f1cfSMikael Olsson if (fdt_node_check_compatible(fdt,
216b139f1cfSMikael Olsson sub_node,
217b139f1cfSMikael Olsson "ethosn-main_allocator") != 0) {
218b139f1cfSMikael Olsson continue;
219b139f1cfSMikael Olsson }
220b139f1cfSMikael Olsson
221b139f1cfSMikael Olsson if (has_reserved_memory) {
222b139f1cfSMikael Olsson ERROR("FCONF: Main allocator not supported when using reserved memory\n");
223b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE;
224b139f1cfSMikael Olsson }
225b139f1cfSMikael Olsson
226b139f1cfSMikael Olsson if (err != -FDT_ERR_NOTFOUND) {
227b139f1cfSMikael Olsson ERROR("FCONF: NPU core 0x%lx has more than one main allocator\n",
228b139f1cfSMikael Olsson core_addr);
229b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE;
230b139f1cfSMikael Olsson }
231b139f1cfSMikael Olsson
232b139f1cfSMikael Olsson err = fdt_node_populate_main_allocator(fdt, sub_node, &core->main_allocator);
233b139f1cfSMikael Olsson if (err) {
234b139f1cfSMikael Olsson ERROR("FCONF: Failed to parse main allocator for NPU core 0x%lx\n",
235b139f1cfSMikael Olsson core_addr);
236b139f1cfSMikael Olsson return err;
237b139f1cfSMikael Olsson }
238b139f1cfSMikael Olsson }
239b139f1cfSMikael Olsson
240b139f1cfSMikael Olsson if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
241b139f1cfSMikael Olsson ERROR("FCONF: Failed to parse core sub nodes\n");
242b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE;
243b139f1cfSMikael Olsson }
244b139f1cfSMikael Olsson
245b139f1cfSMikael Olsson if (!has_reserved_memory && err) {
246b139f1cfSMikael Olsson ERROR("FCONF: Main allocator not found for NPU core 0x%lx\n",
247b139f1cfSMikael Olsson core_addr);
248b139f1cfSMikael Olsson return err;
249b139f1cfSMikael Olsson }
250b139f1cfSMikael Olsson
251b139f1cfSMikael Olsson core->addr = core_addr;
252b139f1cfSMikael Olsson
253b139f1cfSMikael Olsson return 0;
25476a21174SMikael Olsson }
25576a21174SMikael Olsson
fconf_populate_ethosn_config(uintptr_t config)25676a21174SMikael Olsson int fconf_populate_ethosn_config(uintptr_t config)
25776a21174SMikael Olsson {
25876a21174SMikael Olsson int ethosn_node;
259b139f1cfSMikael Olsson uint32_t dev_count = 0U;
26076a21174SMikael Olsson const void *hw_conf_dtb = (const void *)config;
26176a21174SMikael Olsson
262b139f1cfSMikael Olsson INFO("Probing Arm(R) Ethos(TM)-N NPU\n");
2631c65989eSLaurent Carlier
2641c65989eSLaurent Carlier fdt_for_each_compatible_node(hw_conf_dtb, ethosn_node, "ethosn") {
265b139f1cfSMikael Olsson struct ethosn_device_t *dev = ðosn_config.devices[dev_count];
266b139f1cfSMikael Olsson uint32_t dev_asset_alloc_count = 0U;
267b139f1cfSMikael Olsson uint32_t dev_core_count = 0U;
268*a19a0241SMikael Olsson uint64_t reserved_memory_addr = 0U;
269b139f1cfSMikael Olsson bool has_reserved_memory;
2701c65989eSLaurent Carlier int sub_node;
271*a19a0241SMikael Olsson int err;
27276a21174SMikael Olsson
273b139f1cfSMikael Olsson if (!fdt_node_is_enabled(hw_conf_dtb, ethosn_node)) {
2741c65989eSLaurent Carlier continue;
27576a21174SMikael Olsson }
27676a21174SMikael Olsson
277b139f1cfSMikael Olsson if (dev_count >= ETHOSN_DEV_NUM_MAX) {
278b139f1cfSMikael Olsson ERROR("FCONF: Reached max number of NPUs\n");
2791c65989eSLaurent Carlier return -FDT_ERR_BADSTRUCTURE;
2801c65989eSLaurent Carlier }
28176a21174SMikael Olsson
282b139f1cfSMikael Olsson has_reserved_memory = fdt_node_has_reserved_memory(hw_conf_dtb, ethosn_node);
283*a19a0241SMikael Olsson if (has_reserved_memory) {
284*a19a0241SMikael Olsson err = fdt_node_read_reserved_memory_addr(hw_conf_dtb,
285*a19a0241SMikael Olsson ethosn_node,
286*a19a0241SMikael Olsson &reserved_memory_addr);
287*a19a0241SMikael Olsson if (err != 0) {
288*a19a0241SMikael Olsson return err;
289*a19a0241SMikael Olsson }
290*a19a0241SMikael Olsson }
291*a19a0241SMikael Olsson
292b139f1cfSMikael Olsson fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) {
293b139f1cfSMikael Olsson
294b139f1cfSMikael Olsson if (!fdt_node_is_enabled(hw_conf_dtb, sub_node)) {
295b139f1cfSMikael Olsson /* Ignore disabled sub node */
296b139f1cfSMikael Olsson continue;
297b139f1cfSMikael Olsson }
298b139f1cfSMikael Olsson
2991c65989eSLaurent Carlier if (fdt_node_check_compatible(hw_conf_dtb,
3001c65989eSLaurent Carlier sub_node,
301b139f1cfSMikael Olsson "ethosn-core") == 0) {
302b139f1cfSMikael Olsson
303b139f1cfSMikael Olsson if (dev_core_count >= ETHOSN_DEV_CORE_NUM_MAX) {
304b139f1cfSMikael Olsson ERROR("FCONF: Reached max number of NPU cores for NPU %u\n",
305b139f1cfSMikael Olsson dev_count);
306b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE;
30776a21174SMikael Olsson }
30876a21174SMikael Olsson
309b139f1cfSMikael Olsson err = fdt_node_populate_core(hw_conf_dtb,
3101c65989eSLaurent Carlier ethosn_node,
311b139f1cfSMikael Olsson sub_node,
312b139f1cfSMikael Olsson has_reserved_memory,
313b139f1cfSMikael Olsson dev_core_count,
314b139f1cfSMikael Olsson &(dev->cores[dev_core_count]));
315b139f1cfSMikael Olsson if (err) {
31676a21174SMikael Olsson return err;
31776a21174SMikael Olsson }
318b139f1cfSMikael Olsson ++dev_core_count;
319b139f1cfSMikael Olsson } else if (fdt_node_check_compatible(hw_conf_dtb,
320b139f1cfSMikael Olsson sub_node,
321b139f1cfSMikael Olsson "ethosn-asset_allocator") == 0) {
32276a21174SMikael Olsson
323b139f1cfSMikael Olsson if (dev_asset_alloc_count >=
324b139f1cfSMikael Olsson ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX) {
325b139f1cfSMikael Olsson ERROR("FCONF: Reached max number of asset allocators for NPU %u\n",
326b139f1cfSMikael Olsson dev_count);
327b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE;
328b139f1cfSMikael Olsson }
329b139f1cfSMikael Olsson
330b139f1cfSMikael Olsson if (has_reserved_memory) {
331b139f1cfSMikael Olsson ERROR("FCONF: Asset allocator not supported when using reserved memory\n");
332b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE;
333b139f1cfSMikael Olsson }
334b139f1cfSMikael Olsson
335b139f1cfSMikael Olsson err = fdt_node_populate_asset_allocator(hw_conf_dtb,
336b139f1cfSMikael Olsson sub_node,
337b139f1cfSMikael Olsson &(dev->asset_allocators[dev_asset_alloc_count]));
338b139f1cfSMikael Olsson if (err) {
339b139f1cfSMikael Olsson ERROR("FCONF: Failed to parse asset allocator for NPU %u\n",
340b139f1cfSMikael Olsson dev_count);
341b139f1cfSMikael Olsson return err;
342b139f1cfSMikael Olsson }
343b139f1cfSMikael Olsson ++dev_asset_alloc_count;
344b139f1cfSMikael Olsson }
34576a21174SMikael Olsson }
34676a21174SMikael Olsson
34776a21174SMikael Olsson if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
348b139f1cfSMikael Olsson ERROR("FCONF: Failed to parse sub nodes for NPU %u\n",
349b139f1cfSMikael Olsson dev_count);
3501c65989eSLaurent Carlier return -FDT_ERR_BADSTRUCTURE;
35176a21174SMikael Olsson }
35276a21174SMikael Olsson
353b139f1cfSMikael Olsson if (dev_core_count == 0U) {
354b139f1cfSMikael Olsson ERROR("FCONF: NPU %u must have at least one enabled core\n",
355b139f1cfSMikael Olsson dev_count);
3561c65989eSLaurent Carlier return -FDT_ERR_BADSTRUCTURE;
3571c65989eSLaurent Carlier }
358b139f1cfSMikael Olsson
359b139f1cfSMikael Olsson if (!has_reserved_memory && dev_asset_alloc_count == 0U) {
360b139f1cfSMikael Olsson ERROR("FCONF: NPU %u must have at least one asset allocator\n",
361b139f1cfSMikael Olsson dev_count);
362b139f1cfSMikael Olsson return -FDT_ERR_BADSTRUCTURE;
36376a21174SMikael Olsson }
36476a21174SMikael Olsson
365b139f1cfSMikael Olsson dev->num_cores = dev_core_count;
366b139f1cfSMikael Olsson dev->num_allocators = dev_asset_alloc_count;
367b139f1cfSMikael Olsson dev->has_reserved_memory = has_reserved_memory;
368*a19a0241SMikael Olsson dev->reserved_memory_addr = reserved_memory_addr;
369b139f1cfSMikael Olsson ++dev_count;
370b139f1cfSMikael Olsson }
371b139f1cfSMikael Olsson
372b139f1cfSMikael Olsson if (dev_count == 0U) {
3731c65989eSLaurent Carlier ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n");
3741c65989eSLaurent Carlier return -FDT_ERR_BADSTRUCTURE;
3751c65989eSLaurent Carlier }
3761c65989eSLaurent Carlier
377b139f1cfSMikael Olsson ethosn_config.num_devices = dev_count;
37876a21174SMikael Olsson
37976a21174SMikael Olsson return 0;
38076a21174SMikael Olsson }
38176a21174SMikael Olsson
38276a21174SMikael Olsson FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config);
383