diff --git a/doc/build/dts/api/api.rst b/doc/build/dts/api/api.rst index 7d802838041..f3a8c2bcb0d 100644 --- a/doc/build/dts/api/api.rst +++ b/doc/build/dts/api/api.rst @@ -294,6 +294,15 @@ and properties related to them. .. doxygengroup:: devicetree-mbox +.. _devicetree-memory-attr-api: + +Memory attributes +================= + +These conveniences may be used for nodes with a memory attribute property. + +.. doxygengroup:: devicetree-memory-attr + .. _devicetree-pinctrl-api: Pinctrl (pin control) diff --git a/dts/bindings/base/zephyr,memory-attr.yaml b/dts/bindings/base/zephyr,memory-attr.yaml new file mode 100644 index 00000000000..e3c19b9b288 --- /dev/null +++ b/dts/bindings/base/zephyr,memory-attr.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2023, Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +include: [base.yaml] + +properties: + zephyr,memory-attr: + type: string + enum: + - "RAM" + - "RAM_NOCACHE" + - "FLASH" + - "PPB" + - "IO" + - "EXTMEM" + description: | + Attribute for the memory region. + + reg: + required: true diff --git a/dts/bindings/test/vnd,memory-attr.yaml b/dts/bindings/test/vnd,memory-attr.yaml new file mode 100644 index 00000000000..0303d255c54 --- /dev/null +++ b/dts/bindings/test/vnd,memory-attr.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Linaro Ltd. +# SPDX-License-Identifier: Apache-2.0 + +description: Test memory and memory attributes + +compatible: "vnd,memory-attr" + +include: [base.yaml, "zephyr,memory-attr.yaml"] diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index 94ab5b8d3ad..ff0ecb0a33f 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -4286,5 +4286,6 @@ #include #include #include +#include #endif /* DEVICETREE_H */ diff --git a/include/zephyr/devicetree/memory-attr.h b/include/zephyr/devicetree/memory-attr.h new file mode 100644 index 00000000000..65fcfe0ca50 --- /dev/null +++ b/include/zephyr/devicetree/memory-attr.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2023 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_MEMORY_ATTR_H_ +#define ZEPHYR_INCLUDE_MEMORY_ATTR_H_ + +#include +#include +#include + +/** + * @file + * @brief Memory-attr helpers + */ + +/** + * @defgroup devicetree-memory-attr Memory attributes + * @ingroup devicetree + * @{ + */ + +/** @cond INTERNAL_HIDDEN */ + +#define _DT_MEM_ATTR zephyr_memory_attr +#define _DT_ATTR(token) UTIL_CAT(UTIL_CAT(REGION_, token), _ATTR) + +#define _UNPACK(node_id, fn) \ + fn(COND_CODE_1(DT_NODE_HAS_PROP(node_id, zephyr_memory_region), \ + (LINKER_DT_NODE_REGION_NAME(node_id)), \ + (DT_NODE_FULL_NAME(node_id))), \ + DT_REG_ADDR(node_id), \ + DT_REG_SIZE(node_id), \ + _DT_ATTR(DT_STRING_TOKEN(node_id, _DT_MEM_ATTR))), + +#define _APPLY(node_id, fn) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, _DT_MEM_ATTR), \ + (_UNPACK(node_id, fn)), \ + ()) + + +#define _FILTER(node_id, fn) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, _DT_MEM_ATTR), \ + (fn(node_id)), \ + ()) + +/** @endcond */ + +/** + * @brief Invokes @p fn for every node in the tree with property + * `zephyr,memory-attr` + * + * The macro @p fn must take one parameter, which will be a node identifier + * with the `zephyr,memory-attr` property. The macro is expanded once for each + * node in the tree. The order that nodes are visited in is not specified. + * + * @param fn macro to invoke + */ +#define DT_MEMORY_ATTR_FOREACH_NODE(fn) \ + DT_FOREACH_STATUS_OKAY_NODE_VARGS(_FILTER, fn) + +/** + * @brief Invokes @p fn for MPU/MMU regions generation from the device tree + * nodes with `zephyr,memory-attr` property. + * + * Helper macro to invoke a @p fn macro on all the memory regions declared + * using the `zephyr,memory-attr` property + * + * The macro @p fn must take the form: + * + * @code{.c} + * #define MPU_FN(name, base, size, attr) ... + * @endcode + * + * The @p name, @p base and @p size parameters are retrieved from the DT node. + * When the `zephyr,memory-region` property is present in the node, the @p name + * parameter is retrived from there, otherwise the full node name is used. + * + * The `zephyr,memory-attr` enum property is passed as an extended token + * to the @p fn macro using the @p attr parameter in the form of a macro + * REGION_{attr}_ATTR. + * + * The following enums are supported for the `zephyr,memory-attr` property (see + * `zephyr,memory-attr.yaml` for a complete list): + * + * - RAM + * - RAM_NOCACHE + * - FLASH + * - PPB + * - IO + * - EXTMEM + * + * This means that usually the user code would provide some macros or defines + * with the same name of the extended property, that is: + * + * - REGION_RAM_ATTR + * - REGION_RAM_NOCACHE_ATTR + * - REGION_FLASH_ATTR + * - REGION_PPB_ATTR + * - REGION_IO_ATTR + * - REGION_EXTMEM_ATTR + * + * Example devicetree fragment: + * + * @code{.dts} + * / { + * soc { + * res0: memory@20000000 { + * reg = <0x20000000 0x4000>; + * zephyr,memory-region = "MY_NAME"; + * zephyr,memory-attr = "RAM_NOCACHE"; + * }; + * + * res1: memory@30000000 { + * reg = <0x30000000 0x2000>; + * zephyr,memory-attr = "RAM"; + * }; + + * }; + * }; + * @endcode + * + * Example usage: + * + * @code{.c} + * #define REGION_RAM_NOCACHE_ATTR 0xAAAA + * #define REGION_RAM_ATTR 0xBBBB + * #define REGION_FLASH_ATTR 0xCCCC + * + * #define MPU_FN(p_name, p_base, p_size, p_attr) \ + * { \ + * .name = p_name, \ + * .base = p_base, \ + * .size = p_size, \ + * .attr = p_attr, \ + * } + * + * static const struct arm_mpu_region mpu_regions[] = { + * DT_MEMORY_ATTR_APPLY(MPU_FN) + * }; + * @endcode + * + * This expands to: + * + * @code{.c} + * static const struct arm_mpu_region mpu_regions[] = { + * { "MY_NAME", 0x20000000, 0x4000, 0xAAAA }, + * { "memory@30000000", 0x30000000, 0x2000, 0xBBBB }, + * }; + * @endcode + * + * @param fn macro to invoke + */ +#define DT_MEMORY_ATTR_APPLY(fn) \ + DT_FOREACH_STATUS_OKAY_NODE_VARGS(_APPLY, fn) + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_MEMORY_ATTR_H_ */ diff --git a/tests/lib/devicetree/api/app.overlay b/tests/lib/devicetree/api/app.overlay index 03fd7765570..446fcfc2029 100644 --- a/tests/lib/devicetree/api/app.overlay +++ b/tests/lib/devicetree/api/app.overlay @@ -636,6 +636,19 @@ compatible = "vnd,string-array-unquoted"; val = "XA XPLUS XB", "XC XPLUS XD", "XA XMINUS XB", "XC XMINUS XD"; }; + + test_mem_ram: memory@aabbccdd { + compatible = "vnd,memory-attr"; + reg = < 0xaabbccdd 0x4000 >; + zephyr,memory-attr = "RAM"; + }; + + test_mem_ram_nocache: memory@44332211 { + compatible = "vnd,memory-attr"; + reg = < 0x44332211 0x2000 >; + zephyr,memory-attr = "RAM_NOCACHE"; + }; + }; test_64 { diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index eb96de5a81d..adeee59bf1f 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -2667,6 +2667,70 @@ ZTEST(devicetree_api, test_mbox) DT_NODELABEL(test_mbox_zero_cell)), ""); } +ZTEST(devicetree_api, test_memory_attr) +{ + #define REGION_RAM_ATTR (0xDEDE) + #define REGION_RAM_NOCACHE_ATTR (0xCACA) + + #define TEST_FUNC(p_name, p_base, p_size, p_attr) \ + { .name = (p_name), \ + .base = (p_base), \ + .size = (p_size), \ + .attr = (p_attr), \ + } + + struct vnd_memory_binding { + char *name; + uintptr_t base; + size_t size; + unsigned int attr; + }; + + struct vnd_memory_binding val_apply[] = { + DT_MEMORY_ATTR_APPLY(TEST_FUNC) + }; + + zassert_true(!strcmp(val_apply[0].name, "memory@aabbccdd"), ""); + zassert_equal(val_apply[0].base, 0xaabbccdd, ""); + zassert_equal(val_apply[0].size, 0x4000, ""); + zassert_equal(val_apply[0].attr, 0xDEDE, ""); + + zassert_true(!strcmp(val_apply[1].name, "memory@44332211"), ""); + zassert_equal(val_apply[1].base, 0x44332211, ""); + zassert_equal(val_apply[1].size, 0x2000, ""); + zassert_equal(val_apply[1].attr, 0xCACA, ""); + + #undef TEST_FUNC + #undef REGION_RAM_ATTR + #undef REGION_RAM_NOCACHE_ATTR + + #define TEST_FUNC(node_id) DT_NODE_FULL_NAME(node_id), + + static const char * const val_func[] = { + DT_MEMORY_ATTR_FOREACH_NODE(TEST_FUNC) + }; + + zassert_true(!strcmp(val_func[0], "memory@aabbccdd"), ""); + zassert_true(!strcmp(val_func[1], "memory@44332211"), ""); + + #undef TEST_FUNC + + #define TEST_FUNC(node_id) \ + COND_CODE_1(DT_ENUM_HAS_VALUE(node_id, \ + zephyr_memory_attr, \ + RAM_NOCACHE), \ + (DT_REG_ADDR(node_id)), \ + ()) + + uintptr_t val_filt[] = { + DT_MEMORY_ATTR_FOREACH_NODE(TEST_FUNC) + }; + + zassert_equal(val_filt[0], 0x44332211, ""); + + #undef TEST_FUNC +} + ZTEST(devicetree_api, test_string_token) { #undef DT_DRV_COMPAT