1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/devicetree.h>
8 #include <zephyr/sys/util_macro.h>
9 #include <zephyr/toolchain.h>
10 
11 #define PAIR__(f, sep, arg_first, ...) FOR_EACH_FIXED_ARG(f, sep, arg_first, __VA_ARGS__)
12 #define PAIR_(f, sep, args_to_expand)  PAIR__(f, sep, args_to_expand)
13 #define PAIR(n, f, sep, ...)	       PAIR_(f, sep, GET_ARGS_LESS_N(n, __VA_ARGS__))
14 
15 /**
16  * @brief Call a macro on every unique pair of the given variadic arguments.
17  *
18  * For example, FOR_EACH_PAIR(f, (,), 1, 2, 3, 4) should expand to:
19  *
20  *     f(2, 1) , f(3, 1) , f(4, 1) , f(3, 2) , f(4, 2) , f(4, 3)
21  *
22  * @param f   Macro to call. Must accept two arguments.
23  * @param sep Separator between macro calls. Must be in parentheses.
24  *
25  * @see FOR_EACH
26  */
27 #define FOR_EACH_PAIR(f, sep, ...)                                                                 \
28 	LISTIFY(NUM_VA_ARGS_LESS_1(__VA_ARGS__), PAIR, sep, f, sep, __VA_ARGS__)
29 
30 /**
31  * @brief Get a node's non-secure register block start address.
32  *
33  * @param node_id Node identifier.
34  */
35 #define REG_ADDR_NS(node_id) (DT_REG_ADDR(node_id) & 0xEFFFFFFFUL)
36 
37 /**
38  * @brief Get a node's non-secure register block end address.
39  *
40  * @param node_id Node identifier.
41  */
42 #define REG_END_NS(node_id) (REG_ADDR_NS(node_id) + DT_REG_SIZE(node_id))
43 
44 /* clang-format off */
45 
46 #define RRAM_BASE REG_ADDR_NS(DT_CHOSEN(zephyr_flash))
47 #define RRAM_CONTROLLER DT_NODELABEL(rram_controller)
48 
49 #if !DT_NODE_EXISTS(RRAM_CONTROLLER)
50 #error "Missing \"rram-controller\" node"
51 #endif
52 
53 #define CHECK_RRAM_NODE_COMPATIBLE(node_id)                                         \
54 	BUILD_ASSERT(DT_NODE_HAS_COMPAT(node_id, soc_nv_flash),                         \
55 			"Missing compatible \"soc-nv-flash\" from " DT_NODE_FULL_NAME(node_id)  \
56 			" (required for all children of " DT_NODE_PATH(RRAM_CONTROLLER) ")")
57 
58 #define CHECK_RRAM_PARTITION_WITHIN_PARENT(node_id)                                            \
59 	BUILD_ASSERT(RRAM_BASE + REG_ADDR_NS(node_id) >= REG_ADDR_NS(DT_GPARENT(node_id)) && \
60 			RRAM_BASE + REG_END_NS(node_id) <= REG_END_NS(DT_GPARENT(node_id)),      \
61 			DT_NODE_FULL_NAME(node_id) " is not fully contained within its parent "  \
62 			DT_NODE_PATH(DT_GPARENT(node_id)))
63 
64 #define CHECK_NODES_NON_OVERLAPPING(node_id_1, node_id_2)                                \
65 	BUILD_ASSERT(REG_ADDR_NS(node_id_1) >= REG_END_NS(node_id_2) ||                \
66 			REG_ADDR_NS(node_id_2) >= REG_END_NS(node_id_1),                       \
67 			DT_NODE_PATH(node_id_1) " and " DT_NODE_PATH(node_id_2) " are overlapping")
68 
69 /* Retrieve all RRAM nodes that are children of "rram-controller". */
70 #define COMMA(x) x,
71 #define RRAM_NODES_LIST LIST_DROP_EMPTY(DT_FOREACH_CHILD(RRAM_CONTROLLER, COMMA))
72 
73 #if !IS_EMPTY(RRAM_NODES_LIST)
74 
75 /* Check that every RRAM node matches the "soc-nv-flash" compatible. */
76 FOR_EACH(CHECK_RRAM_NODE_COMPATIBLE, (;), RRAM_NODES_LIST);
77 
78 /* Check that no two RRAM nodes are overlapping. */
79 FOR_EACH_PAIR(CHECK_NODES_NON_OVERLAPPING, (;), RRAM_NODES_LIST);
80 
81 #endif
82 
83 /* Retrieve all RRAM partitions by looking for "fixed-partitions" compatibles in each RRAM node. */
84 #define PARTITION_(x)                                                                              \
85 	COND_CODE_1(DT_NODE_HAS_COMPAT(x, fixed_partitions), (DT_FOREACH_CHILD(x, COMMA)), ())
86 #define PARTITION(x, ...) DT_FOREACH_CHILD_STATUS_OKAY(x, PARTITION_)
87 #define RRAM_PARTITION_LIST LIST_DROP_EMPTY(DT_FOREACH_CHILD_VARGS(RRAM_CONTROLLER, PARTITION))
88 
89 #if !IS_EMPTY(RRAM_PARTITION_LIST)
90 
91 /* Check that every RRAM partition is within the bounds of its parent RRAM node. */
92 FOR_EACH(CHECK_RRAM_PARTITION_WITHIN_PARENT, (;), RRAM_PARTITION_LIST);
93 
94 /* Check that no two RRAM partitions are overlapping. */
95 FOR_EACH_PAIR(CHECK_NODES_NON_OVERLAPPING, (;), RRAM_PARTITION_LIST);
96 
97 #endif
98