1 /*
2  * Copyright (c) 2021, Commonwealth Scientific and Industrial Research
3  * Organisation (CSIRO) ABN 41 687 119 230.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Generate memory regions from devicetree nodes.
8  */
9 
10 #ifndef ZEPHYR_INCLUDE_LINKER_DEVICETREE_REGIONS_H_
11 #define ZEPHYR_INCLUDE_LINKER_DEVICETREE_REGIONS_H_
12 
13 #include <zephyr/devicetree.h>
14 #include <zephyr/sys/util.h>
15 #include <zephyr/toolchain.h>
16 
17 /**
18  * @brief Get the linker memory-region name in a token form
19  *
20  * This attempts to use the zephyr,memory-region property (with
21  * non-alphanumeric characters replaced with underscores) returning a token.
22  *
23  * Example devicetree fragment:
24  *
25  * @code{.dts}
26  *     / {
27  *             soc {
28  *                     sram1: memory@2000000 {
29  *                         zephyr,memory-region = "MY_NAME";
30  *                     };
31  *                     sram2: memory@2001000 {
32  *                         zephyr,memory-region = "MY@OTHER@NAME";
33  *                     };
34  *             };
35  *     };
36  * @endcode
37  *
38  * Example usage:
39  *
40  * @code{.c}
41  *    LINKER_DT_NODE_REGION_NAME_TOKEN(DT_NODELABEL(sram1)) // MY_NAME
42  *    LINKER_DT_NODE_REGION_NAME_TOKEN(DT_NODELABEL(sram2)) // MY_OTHER_NAME
43  * @endcode
44  *
45  * @param node_id node identifier
46  * @return the name of the memory memory region the node will generate
47  */
48 #define LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) \
49 	DT_STRING_TOKEN(node_id, zephyr_memory_region)
50 
51 /**
52  * @brief Get the linker memory-region name
53  *
54  * This attempts to use the zephyr,memory-region property (with
55  * non-alphanumeric characters replaced with underscores).
56  *
57  * Example devicetree fragment:
58  *
59  * @code{.dts}
60  *     / {
61  *             soc {
62  *                     sram1: memory@2000000 {
63  *                         zephyr,memory-region = "MY_NAME";
64  *                     };
65  *                     sram2: memory@2001000 {
66  *                         zephyr,memory-region = "MY@OTHER@NAME";
67  *                     };
68  *             };
69  *     };
70  * @endcode
71  *
72  * Example usage:
73  *
74  * @code{.c}
75  *    LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram1)) // "MY_NAME"
76  *    LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram2)) // "MY_OTHER_NAME"
77  * @endcode
78  *
79  * @param node_id node identifier
80  * @return the name of the memory memory region the node will generate
81  */
82 #define LINKER_DT_NODE_REGION_NAME(node_id) \
83 	STRINGIFY(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id))
84 
85 /** @cond INTERNAL_HIDDEN */
86 
87 #define _DT_COMPATIBLE	zephyr_memory_region
88 
89 #define _DT_SECTION_PREFIX(node_id)	UTIL_CAT(__, LINKER_DT_NODE_REGION_NAME_TOKEN(node_id))
90 #define _DT_SECTION_START(node_id)	UTIL_CAT(_DT_SECTION_PREFIX(node_id), _start)
91 #define _DT_SECTION_END(node_id)	UTIL_CAT(_DT_SECTION_PREFIX(node_id), _end)
92 #define _DT_SECTION_SIZE(node_id)	UTIL_CAT(_DT_SECTION_PREFIX(node_id), _size)
93 #define _DT_SECTION_LOAD(node_id)	UTIL_CAT(_DT_SECTION_PREFIX(node_id), _load_start)
94 
95 /**
96  * @brief Declare a memory region
97  *
98  * Example devicetree fragment:
99  *
100  * @code{.dts}
101  *    test_sram: sram@20010000 {
102  *        compatible = "zephyr,memory-region", "mmio-sram";
103  *        reg = < 0x20010000 0x1000 >;
104  *        zephyr,memory-region = "FOOBAR";
105  *    };
106  * @endcode
107  *
108  * will result in:
109  *
110  * @code{.unparsed}
111  *    FOOBAR (rw) : ORIGIN = (0x20010000), LENGTH = (0x1000)
112  * @endcode
113  *
114  * @param node_id devicetree node identifier
115  * @param attr region attributes
116  */
117 #define _REGION_DECLARE(node_id)			\
118 	LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) :	\
119 	ORIGIN = DT_REG_ADDR(node_id),			\
120 	LENGTH = DT_REG_SIZE(node_id)
121 
122 /**
123  * @brief Declare a memory section from the device tree nodes with
124  *	  compatible 'zephyr,memory-region'
125  *
126  * Example devicetree fragment:
127  *
128  * @code{.dts}
129  *    test_sram: sram@20010000 {
130  *        compatible = "zephyr,memory-region", "mmio-sram";
131  *        reg = < 0x20010000 0x1000 >;
132  *        zephyr,memory-region = "FOOBAR";
133  *    };
134  * @endcode
135  *
136  * will result in:
137  *
138  * @code{.unparsed}
139  *    FOOBAR (NOLOAD) :
140  *    {
141  *        __FOOBAR_start = .;
142  *        KEEP(*(FOOBAR))
143  *        KEEP(*(FOOBAR.*))
144  *        __FOOBAR_end = .;
145  *    } > FOOBAR
146  *    __FOOBAR_size = __FOOBAR_end - __FOOBAR_start;
147  *    __FOOBAR_load_start = LOADADDR(FOOBAR);
148  * @endcode
149  *
150  * @param node_id devicetree node identifier
151  */
152 #define _SECTION_DECLARE(node_id)								\
153 	LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) (NOLOAD) :					\
154 	{											\
155 		_DT_SECTION_START(node_id) = .;							\
156 		KEEP(*(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id)))				\
157 		KEEP(*(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id).*))				\
158 		_DT_SECTION_END(node_id) = .;							\
159 	} > LINKER_DT_NODE_REGION_NAME_TOKEN(node_id)						\
160 	_DT_SECTION_SIZE(node_id) = _DT_SECTION_END(node_id) - _DT_SECTION_START(node_id);	\
161 	_DT_SECTION_LOAD(node_id) = LOADADDR(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id));
162 
163 /** @endcond */
164 
165 /**
166  * @brief Generate linker memory regions from the device tree nodes with
167  *        compatible 'zephyr,memory-region'
168  *
169  * Note: for now we do not deal with MEMORY attributes since those are
170  * optional, not actually used by Zephyr and they will likely conflict with the
171  * MPU configuration.
172  */
173 #define LINKER_DT_REGIONS() \
174 	DT_FOREACH_STATUS_OKAY(_DT_COMPATIBLE, _REGION_DECLARE)
175 
176 /**
177  * @brief Generate linker memory sections from the device tree nodes with
178  *        compatible 'zephyr,memory-region'
179  */
180 #define LINKER_DT_SECTIONS() \
181 	DT_FOREACH_STATUS_OKAY(_DT_COMPATIBLE, _SECTION_DECLARE)
182 
183 #endif /* ZEPHYR_INCLUDE_LINKER_DEVICETREE_REGIONS_H_ */
184