Line data Source code
1 0 : /*
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 1 : #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 1 : #define LINKER_DT_NODE_REGION_NAME(node_id) \
83 : STRINGIFY(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id))
84 :
85 : #define _DT_MEMORY_REGION_FLAGS_TOKEN(n) DT_STRING_TOKEN(n, zephyr_memory_region_flags)
86 : #define _DT_MEMORY_REGION_FLAGS_UNQUOTED(n) DT_STRING_UNQUOTED(n, zephyr_memory_region_flags)
87 :
88 : #define _LINKER_L_PAREN (
89 : #define _LINKER_R_PAREN )
90 : #define _LINKER_ENCLOSE_PAREN(x) _LINKER_L_PAREN x _LINKER_R_PAREN
91 :
92 : #define _LINKER_IS_EMPTY_TOKEN_ 1
93 : #define _LINKER_IS_EMPTY_TOKEN_EXPAND(x) _LINKER_IS_EMPTY_TOKEN_##x
94 : #define _LINKER_IS_EMPTY_TOKEN(x) _LINKER_IS_EMPTY_TOKEN_EXPAND(x)
95 :
96 : /**
97 : * @brief Get the linker memory-region flags with parentheses.
98 : *
99 : * This attempts to return the zephyr,memory-region-flags property
100 : * with parentheses.
101 : * Return empty string if not set the property.
102 : *
103 : * Example devicetree fragment:
104 : *
105 : * @code{.dts}
106 : * / {
107 : * soc {
108 : * rx: memory@2000000 {
109 : * zephyr,memory-region = "READ_EXEC";
110 : * zephyr,memory-region-flags = "rx";
111 : * };
112 : * rx_not_w: memory@2001000 {
113 : * zephyr,memory-region = "READ_EXEC_NOT_WRITE";
114 : * zephyr,memory-region-flags = "rx!w";
115 : * };
116 : * no_flags: memory@2001000 {
117 : * zephyr,memory-region = "NO_FLAGS";
118 : * };
119 : * };
120 : * };
121 : * @endcode
122 : *
123 : * Example usage:
124 : *
125 : * @code{.c}
126 : * LINKER_DT_NODE_REGION_FLAGS(DT_NODELABEL(rx)) // (rx)
127 : * LINKER_DT_NODE_REGION_FLAGS(DT_NODELABEL(rx_not_w)) // (rx!w)
128 : * LINKER_DT_NODE_REGION_FLAGS(DT_NODELABEL(no_flags)) // [flags will not be specified]
129 : * @endcode
130 : *
131 : * @param node_id node identifier
132 : * @return the value of the memory region flag specified in the device tree
133 : * enclosed in parentheses.
134 : */
135 :
136 1 : #define LINKER_DT_NODE_REGION_FLAGS(node_id) \
137 : COND_CODE_1(DT_NODE_HAS_PROP(node_id, zephyr_memory_region_flags), \
138 : (COND_CODE_1(_LINKER_IS_EMPTY_TOKEN(_DT_MEMORY_REGION_FLAGS_TOKEN(node_id)), \
139 : (), \
140 : (_LINKER_ENCLOSE_PAREN( \
141 : _DT_MEMORY_REGION_FLAGS_UNQUOTED(node_id)) \
142 : ))), \
143 : (_LINKER_ENCLOSE_PAREN(rw)))
144 :
145 : /** @cond INTERNAL_HIDDEN */
146 :
147 : #define _DT_COMPATIBLE zephyr_memory_region
148 :
149 : #define _DT_SECTION_PREFIX(node_id) UTIL_CAT(__, LINKER_DT_NODE_REGION_NAME_TOKEN(node_id))
150 : #define _DT_SECTION_START(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _start)
151 : #define _DT_SECTION_END(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _end)
152 : #define _DT_SECTION_SIZE(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _size)
153 : #define _DT_SECTION_LOAD(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _load_start)
154 :
155 : /**
156 : * @brief Declare a memory region
157 : *
158 : * Example devicetree fragment:
159 : *
160 : * @code{.dts}
161 : * test_sram: sram@20010000 {
162 : * compatible = "zephyr,memory-region", "mmio-sram";
163 : * reg = < 0x20010000 0x1000 >;
164 : * zephyr,memory-region = "FOOBAR";
165 : * zephyr,memory-region-flags = "rw";
166 : * };
167 : * @endcode
168 : *
169 : * will result in:
170 : *
171 : * @code{.unparsed}
172 : * FOOBAR (rw) : ORIGIN = (0x20010000), LENGTH = (0x1000)
173 : * @endcode
174 : *
175 : * @param node_id devicetree node identifier
176 : * @param attr region attributes
177 : */
178 : #define _REGION_DECLARE(node_id) \
179 : LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) \
180 : LINKER_DT_NODE_REGION_FLAGS(node_id) \
181 : : ORIGIN = DT_REG_ADDR(node_id), \
182 : LENGTH = DT_REG_SIZE(node_id)
183 :
184 : /**
185 : * @brief Declare a memory section from the device tree nodes with
186 : * compatible 'zephyr,memory-region'
187 : *
188 : * Example devicetree fragment:
189 : *
190 : * @code{.dts}
191 : * test_sram: sram@20010000 {
192 : * compatible = "zephyr,memory-region", "mmio-sram";
193 : * reg = < 0x20010000 0x1000 >;
194 : * zephyr,memory-region = "FOOBAR";
195 : * };
196 : * @endcode
197 : *
198 : * will result in:
199 : *
200 : * @code{.unparsed}
201 : * FOOBAR (NOLOAD) :
202 : * {
203 : * __FOOBAR_start = .;
204 : * KEEP(*(FOOBAR))
205 : * KEEP(*(FOOBAR.*))
206 : * __FOOBAR_end = .;
207 : * } > FOOBAR
208 : * __FOOBAR_size = __FOOBAR_end - __FOOBAR_start;
209 : * __FOOBAR_load_start = LOADADDR(FOOBAR);
210 : * @endcode
211 : *
212 : * @param node_id devicetree node identifier
213 : */
214 : #define _SECTION_DECLARE(node_id) \
215 : LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) (NOLOAD) : \
216 : { \
217 : _DT_SECTION_START(node_id) = .; \
218 : KEEP(*(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id))) \
219 : KEEP(*(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id).*)) \
220 : _DT_SECTION_END(node_id) = .; \
221 : } > LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) \
222 : _DT_SECTION_SIZE(node_id) = _DT_SECTION_END(node_id) - _DT_SECTION_START(node_id); \
223 : _DT_SECTION_LOAD(node_id) = LOADADDR(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id));
224 :
225 : /** @endcond */
226 :
227 : /**
228 : * @brief Generate linker memory regions from the device tree nodes with
229 : * compatible 'zephyr,memory-region'
230 : *
231 : * Note: for now we do not deal with MEMORY attributes since those are
232 : * optional, not actually used by Zephyr and they will likely conflict with the
233 : * MPU configuration.
234 : */
235 1 : #define LINKER_DT_REGIONS() \
236 : DT_FOREACH_STATUS_OKAY(_DT_COMPATIBLE, _REGION_DECLARE)
237 :
238 : /**
239 : * @brief Generate linker memory sections from the device tree nodes with
240 : * compatible 'zephyr,memory-region'
241 : */
242 1 : #define LINKER_DT_SECTIONS() \
243 : DT_FOREACH_STATUS_OKAY(_DT_COMPATIBLE, _SECTION_DECLARE)
244 :
245 : #endif /* ZEPHYR_INCLUDE_LINKER_DEVICETREE_REGIONS_H_ */
|