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