Skip to content

Commit 7483e43

Browse files
carlocaionecarlescufi
authored andcommitted
devicetree: Add 'zephyr,memory-attr' and DT helpers
The 'zephyr,memory-region-mpu' property was addede gqas a convenient way to create and configure MPU regions using information coming from DT. It has been used a lot since it was introduced so I guess we can consider it a Zephyr success story ™ . Unfortunately it has been proved to be a bit limited and with some important limitations: 1. It was introduced as a property of the compatible zephyr,memory-region that is used to create linker regions and sections from DT data. This means that we can actually create MPU regions only for DT-defined regions and sections. 2. The naming is unfortunate because it is implying that it is used only for MPU. 3. It is misplaced being in include/zephyr/linker/devicetree_regions.h and still it has nothing to do with the linker at all. 4. It is exporting a function called LINKER_DT_REGION_MPU that again has nothing to do with the linker. Point (1) is also particularly limiting because it is preventing us to characterize memory regions that are not generated using the 'zephyr,memory-region' compatible, like generic mmio-sram regions. While we fix all the issues, we also want to extend a bit the range of usefulness of this property. We are renaming it 'zephyr,memory-attr' and it is now carrying information about the type of memory the property is attached to (cacheable, non-cacheable, IO, eXecutable, etc...). The user can use this property and the DT API coming with it to act on the memory node it is accompanied by. We are still providing the DT_MEMORY_ATTR_APPLY() macro that can be used to create the MPU regions as before, but we are adding also a DT_MEMORY_ATTR_FOREACH_NODE() macro that can be used to cycle through the memory nodes and act on those. Signed-off-by: Carlo Caione <[email protected]>
1 parent 0a8bbbd commit 7483e43

File tree

7 files changed

+278
-0
lines changed

7 files changed

+278
-0
lines changed

doc/build/dts/api/api.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,15 @@ and properties related to them.
294294

295295
.. doxygengroup:: devicetree-mbox
296296

297+
.. _devicetree-memory-attr-api:
298+
299+
Memory attributes
300+
=================
301+
302+
These conveniences may be used for nodes with a memory attribute property.
303+
304+
.. doxygengroup:: devicetree-memory-attr
305+
297306
.. _devicetree-pinctrl-api:
298307

299308
Pinctrl (pin control)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) 2023, Carlo Caione <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
include: [base.yaml]
5+
6+
properties:
7+
zephyr,memory-attr:
8+
type: string
9+
enum:
10+
- "RAM"
11+
- "RAM_NOCACHE"
12+
- "FLASH"
13+
- "PPB"
14+
- "IO"
15+
- "EXTMEM"
16+
description: |
17+
Attribute for the memory region.
18+
19+
reg:
20+
required: true
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2020 Linaro Ltd.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Test memory and memory attributes
5+
6+
compatible: "vnd,memory-attr"
7+
8+
include: [base.yaml, "zephyr,memory-attr.yaml"]

include/zephyr/devicetree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4286,5 +4286,6 @@
42864286
#include <zephyr/devicetree/can.h>
42874287
#include <zephyr/devicetree/reset.h>
42884288
#include <zephyr/devicetree/mbox.h>
4289+
#include <zephyr/devicetree/memory-attr.h>
42894290

42904291
#endif /* DEVICETREE_H */
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright (c) 2023 Carlo Caione <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_MEMORY_ATTR_H_
8+
#define ZEPHYR_INCLUDE_MEMORY_ATTR_H_
9+
10+
#include <zephyr/devicetree.h>
11+
#include <zephyr/linker/devicetree_regions.h>
12+
#include <zephyr/sys/util.h>
13+
14+
/**
15+
* @file
16+
* @brief Memory-attr helpers
17+
*/
18+
19+
/**
20+
* @defgroup devicetree-memory-attr Memory attributes
21+
* @ingroup devicetree
22+
* @{
23+
*/
24+
25+
/** @cond INTERNAL_HIDDEN */
26+
27+
#define _DT_MEM_ATTR zephyr_memory_attr
28+
#define _DT_ATTR(token) UTIL_CAT(UTIL_CAT(REGION_, token), _ATTR)
29+
30+
#define _UNPACK(node_id, fn) \
31+
fn(COND_CODE_1(DT_NODE_HAS_PROP(node_id, zephyr_memory_region), \
32+
(LINKER_DT_NODE_REGION_NAME(node_id)), \
33+
(DT_NODE_FULL_NAME(node_id))), \
34+
DT_REG_ADDR(node_id), \
35+
DT_REG_SIZE(node_id), \
36+
_DT_ATTR(DT_STRING_TOKEN(node_id, _DT_MEM_ATTR))),
37+
38+
#define _APPLY(node_id, fn) \
39+
COND_CODE_1(DT_NODE_HAS_PROP(node_id, _DT_MEM_ATTR), \
40+
(_UNPACK(node_id, fn)), \
41+
())
42+
43+
44+
#define _FILTER(node_id, fn) \
45+
COND_CODE_1(DT_NODE_HAS_PROP(node_id, _DT_MEM_ATTR), \
46+
(fn(node_id)), \
47+
())
48+
49+
/** @endcond */
50+
51+
/**
52+
* @brief Invokes @p fn for every node in the tree with property
53+
* `zephyr,memory-attr`
54+
*
55+
* The macro @p fn must take one parameter, which will be a node identifier
56+
* with the `zephyr,memory-attr` property. The macro is expanded once for each
57+
* node in the tree. The order that nodes are visited in is not specified.
58+
*
59+
* @param fn macro to invoke
60+
*/
61+
#define DT_MEMORY_ATTR_FOREACH_NODE(fn) \
62+
DT_FOREACH_STATUS_OKAY_NODE_VARGS(_FILTER, fn)
63+
64+
/**
65+
* @brief Invokes @p fn for MPU/MMU regions generation from the device tree
66+
* nodes with `zephyr,memory-attr` property.
67+
*
68+
* Helper macro to invoke a @p fn macro on all the memory regions declared
69+
* using the `zephyr,memory-attr` property
70+
*
71+
* The macro @p fn must take the form:
72+
*
73+
* @code{.c}
74+
* #define MPU_FN(name, base, size, attr) ...
75+
* @endcode
76+
*
77+
* The @p name, @p base and @p size parameters are retrieved from the DT node.
78+
* When the `zephyr,memory-region` property is present in the node, the @p name
79+
* parameter is retrived from there, otherwise the full node name is used.
80+
*
81+
* The `zephyr,memory-attr` enum property is passed as an extended token
82+
* to the @p fn macro using the @p attr parameter in the form of a macro
83+
* REGION_{attr}_ATTR.
84+
*
85+
* The following enums are supported for the `zephyr,memory-attr` property (see
86+
* `zephyr,memory-attr.yaml` for a complete list):
87+
*
88+
* - RAM
89+
* - RAM_NOCACHE
90+
* - FLASH
91+
* - PPB
92+
* - IO
93+
* - EXTMEM
94+
*
95+
* This means that usually the user code would provide some macros or defines
96+
* with the same name of the extended property, that is:
97+
*
98+
* - REGION_RAM_ATTR
99+
* - REGION_RAM_NOCACHE_ATTR
100+
* - REGION_FLASH_ATTR
101+
* - REGION_PPB_ATTR
102+
* - REGION_IO_ATTR
103+
* - REGION_EXTMEM_ATTR
104+
*
105+
* Example devicetree fragment:
106+
*
107+
* @code{.dts}
108+
* / {
109+
* soc {
110+
* res0: memory@20000000 {
111+
* reg = <0x20000000 0x4000>;
112+
* zephyr,memory-region = "MY_NAME";
113+
* zephyr,memory-attr = "RAM_NOCACHE";
114+
* };
115+
*
116+
* res1: memory@30000000 {
117+
* reg = <0x30000000 0x2000>;
118+
* zephyr,memory-attr = "RAM";
119+
* };
120+
121+
* };
122+
* };
123+
* @endcode
124+
*
125+
* Example usage:
126+
*
127+
* @code{.c}
128+
* #define REGION_RAM_NOCACHE_ATTR 0xAAAA
129+
* #define REGION_RAM_ATTR 0xBBBB
130+
* #define REGION_FLASH_ATTR 0xCCCC
131+
*
132+
* #define MPU_FN(p_name, p_base, p_size, p_attr) \
133+
* { \
134+
* .name = p_name, \
135+
* .base = p_base, \
136+
* .size = p_size, \
137+
* .attr = p_attr, \
138+
* }
139+
*
140+
* static const struct arm_mpu_region mpu_regions[] = {
141+
* DT_MEMORY_ATTR_APPLY(MPU_FN)
142+
* };
143+
* @endcode
144+
*
145+
* This expands to:
146+
*
147+
* @code{.c}
148+
* static const struct arm_mpu_region mpu_regions[] = {
149+
* { "MY_NAME", 0x20000000, 0x4000, 0xAAAA },
150+
* { "memory@30000000", 0x30000000, 0x2000, 0xBBBB },
151+
* };
152+
* @endcode
153+
*
154+
* @param fn macro to invoke
155+
*/
156+
#define DT_MEMORY_ATTR_APPLY(fn) \
157+
DT_FOREACH_STATUS_OKAY_NODE_VARGS(_APPLY, fn)
158+
159+
/**
160+
* @}
161+
*/
162+
163+
#endif /* ZEPHYR_INCLUDE_MEMORY_ATTR_H_ */

tests/lib/devicetree/api/app.overlay

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,19 @@
636636
compatible = "vnd,string-array-unquoted";
637637
val = "XA XPLUS XB", "XC XPLUS XD", "XA XMINUS XB", "XC XMINUS XD";
638638
};
639+
640+
test_mem_ram: memory@aabbccdd {
641+
compatible = "vnd,memory-attr";
642+
reg = < 0xaabbccdd 0x4000 >;
643+
zephyr,memory-attr = "RAM";
644+
};
645+
646+
test_mem_ram_nocache: memory@44332211 {
647+
compatible = "vnd,memory-attr";
648+
reg = < 0x44332211 0x2000 >;
649+
zephyr,memory-attr = "RAM_NOCACHE";
650+
};
651+
639652
};
640653

641654
test_64 {

tests/lib/devicetree/api/src/main.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2667,6 +2667,70 @@ ZTEST(devicetree_api, test_mbox)
26672667
DT_NODELABEL(test_mbox_zero_cell)), "");
26682668
}
26692669

2670+
ZTEST(devicetree_api, test_memory_attr)
2671+
{
2672+
#define REGION_RAM_ATTR (0xDEDE)
2673+
#define REGION_RAM_NOCACHE_ATTR (0xCACA)
2674+
2675+
#define TEST_FUNC(p_name, p_base, p_size, p_attr) \
2676+
{ .name = (p_name), \
2677+
.base = (p_base), \
2678+
.size = (p_size), \
2679+
.attr = (p_attr), \
2680+
}
2681+
2682+
struct vnd_memory_binding {
2683+
char *name;
2684+
uintptr_t base;
2685+
size_t size;
2686+
unsigned int attr;
2687+
};
2688+
2689+
struct vnd_memory_binding val_apply[] = {
2690+
DT_MEMORY_ATTR_APPLY(TEST_FUNC)
2691+
};
2692+
2693+
zassert_true(!strcmp(val_apply[0].name, "memory@aabbccdd"), "");
2694+
zassert_equal(val_apply[0].base, 0xaabbccdd, "");
2695+
zassert_equal(val_apply[0].size, 0x4000, "");
2696+
zassert_equal(val_apply[0].attr, 0xDEDE, "");
2697+
2698+
zassert_true(!strcmp(val_apply[1].name, "memory@44332211"), "");
2699+
zassert_equal(val_apply[1].base, 0x44332211, "");
2700+
zassert_equal(val_apply[1].size, 0x2000, "");
2701+
zassert_equal(val_apply[1].attr, 0xCACA, "");
2702+
2703+
#undef TEST_FUNC
2704+
#undef REGION_RAM_ATTR
2705+
#undef REGION_RAM_NOCACHE_ATTR
2706+
2707+
#define TEST_FUNC(node_id) DT_NODE_FULL_NAME(node_id),
2708+
2709+
static const char * const val_func[] = {
2710+
DT_MEMORY_ATTR_FOREACH_NODE(TEST_FUNC)
2711+
};
2712+
2713+
zassert_true(!strcmp(val_func[0], "memory@aabbccdd"), "");
2714+
zassert_true(!strcmp(val_func[1], "memory@44332211"), "");
2715+
2716+
#undef TEST_FUNC
2717+
2718+
#define TEST_FUNC(node_id) \
2719+
COND_CODE_1(DT_ENUM_HAS_VALUE(node_id, \
2720+
zephyr_memory_attr, \
2721+
RAM_NOCACHE), \
2722+
(DT_REG_ADDR(node_id)), \
2723+
())
2724+
2725+
uintptr_t val_filt[] = {
2726+
DT_MEMORY_ATTR_FOREACH_NODE(TEST_FUNC)
2727+
};
2728+
2729+
zassert_equal(val_filt[0], 0x44332211, "");
2730+
2731+
#undef TEST_FUNC
2732+
}
2733+
26702734
ZTEST(devicetree_api, test_string_token)
26712735
{
26722736
#undef DT_DRV_COMPAT

0 commit comments

Comments
 (0)