diff --git a/dts/bindings/base/mpu-region.yaml b/dts/bindings/base/mpu-region.yaml new file mode 100644 index 0000000000000..b00c5db4de07b --- /dev/null +++ b/dts/bindings/base/mpu-region.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2021, Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +description: MPU region + +compatible: "mpu-region" + +include: [base.yaml, mem-region.yaml] + +properties: + zephyr,memory-region: + required: true + + zephyr,memory-region-mpu: + type: string + required: true + description: | + Signify that this node should result in a dedicated MPU region. The + region address and size are taken from the property, while the MPU + attribute is the value of this property. diff --git a/include/linker/devicetree_regions_mpu.h b/include/linker/devicetree_regions_mpu.h new file mode 100644 index 0000000000000..ea241b51b4236 --- /dev/null +++ b/include/linker/devicetree_regions_mpu.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021, Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/** + * @cond INTERNAL_HIDDEN + */ + +#define _DT_COMPATIBLE mpu_region + +/** + * Check that the node_id has both properties: + * - zephyr,memory-region-mpu + * - zephyr,memory-region + * + * and call the EXPAND_MPU_FN() macro + */ +#define _CHECK_ATTR_FN(node_id, EXPAND_MPU_FN, ...) \ + COND_CODE_1(UTIL_AND(DT_NODE_HAS_PROP(node_id, zephyr_memory_region_mpu), \ + DT_NODE_HAS_PROP(node_id, zephyr_memory_region)), \ + (EXPAND_MPU_FN(node_id, __VA_ARGS__)), \ + ()) + +/** + * Call the user-provided MPU_FN() macro passing the expected arguments + */ +#define _EXPAND_MPU_FN(node_id, MPU_FN, ...) \ + MPU_FN(LINKER_DT_NODE_REGION_NAME(node_id), \ + DT_REG_ADDR(node_id), \ + DT_REG_SIZE(node_id), \ + DT_STRING_TOKEN(node_id, zephyr_memory_region_mpu)), + +/** + * Call _CHECK_ATTR_FN() for each enabled node passing EXPAND_MPU_FN() as + * explicit argument and the user-provided MPU_FN() macro in __VA_ARGS__ + */ +#define _CHECK_APPLY_FN(compat, EXPAND_MPU_FN, ...) \ + DT_FOREACH_STATUS_OKAY_VARGS(compat, _CHECK_ATTR_FN, EXPAND_MPU_FN, __VA_ARGS__) + +/** + * @endcond + */ + +/** + * Helper macro to apply an MPU_FN macro to all the memory regions declared + * using the 'zephyr,memory-region-mpu' property and the 'mpu-region' + * compatible. + * + * @p mpu_fn must take the form: + * + * @code{.c} + * #define MPU_FN(name, base, size, attr) ... + * @endcode + * + * Example: + * + * @code{.c} + * static const struct arm_mpu_region mpu_regions[] = { + * ... + * DT_REGION_MPU(MPU_FN) + * ... + * }; + * @endcode + */ +#define DT_REGION_MPU(mpu_fn) _CHECK_APPLY_FN(_DT_COMPATIBLE, _EXPAND_MPU_FN, mpu_fn) diff --git a/soc/arm/common/cortex_m/arm_mpu_mem_cfg.h b/soc/arm/common/cortex_m/arm_mpu_mem_cfg.h index dbcaa55330268..34dbbe9cd8054 100644 --- a/soc/arm/common/cortex_m/arm_mpu_mem_cfg.h +++ b/soc/arm/common/cortex_m/arm_mpu_mem_cfg.h @@ -62,6 +62,48 @@ #error "Unsupported sram size configuration" #endif +#define MPU_REGION_SIZE_32 REGION_32B +#define MPU_REGION_SIZE_64 REGION_64B +#define MPU_REGION_SIZE_128 REGION_128B +#define MPU_REGION_SIZE_256 REGION_256B +#define MPU_REGION_SIZE_512 REGION_512B +#define MPU_REGION_SIZE_1024 REGION_1K +#define MPU_REGION_SIZE_2048 REGION_2K +#define MPU_REGION_SIZE_4096 REGION_4K +#define MPU_REGION_SIZE_8192 REGION_8K +#define MPU_REGION_SIZE_16384 REGION_16K +#define MPU_REGION_SIZE_32768 REGION_32K +#define MPU_REGION_SIZE_65536 REGION_64K +#define MPU_REGION_SIZE_131072 REGION_128K +#define MPU_REGION_SIZE_262144 REGION_256K +#define MPU_REGION_SIZE_524288 REGION_512K +#define MPU_REGION_SIZE_1048576 REGION_1M +#define MPU_REGION_SIZE_2097152 REGION_2M +#define MPU_REGION_SIZE_4194304 REGION_4M +#define MPU_REGION_SIZE_8388608 REGION_8M +#define MPU_REGION_SIZE_16777216 REGION_16M +#define MPU_REGION_SIZE_33554432 REGION_32M +#define MPU_REGION_SIZE_67108864 REGION_64M +#define MPU_REGION_SIZE_134217728 REGION_128M +#define MPU_REGION_SIZE_268435456 REGION_256M +#define MPU_REGION_SIZE_536870912 REGION_512M + +#define MPU_REGION_SIZE(x) MPU_REGION_SIZE_ ## x + +#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \ + { .name = p_name, \ + .base = p_base, \ + .attr = p_attr(MPU_REGION_SIZE(p_size)), \ + } + +#else + +#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \ + { .name = p_name, \ + .base = p_base, \ + .attr = p_attr(p_base, p_size), \ + } + #endif /* !ARMV8_M_BASELINE && !ARMV8_M_MAINLINE */ #endif /* _ARM_CORTEX_M_MPU_MEM_CFG_H_ */ diff --git a/soc/arm/common/cortex_m/arm_mpu_regions.c b/soc/arm/common/cortex_m/arm_mpu_regions.c index 6ba05377ba531..22fac0e00daaa 100644 --- a/soc/arm/common/cortex_m/arm_mpu_regions.c +++ b/soc/arm/common/cortex_m/arm_mpu_regions.c @@ -6,6 +6,7 @@ #include #include +#include #include "arm_mpu_mem_cfg.h" @@ -28,6 +29,9 @@ static const struct arm_mpu_region mpu_regions[] = { #else REGION_RAM_ATTR(REGION_SRAM_SIZE)), #endif + + /* DT-defined regions */ + DT_REGION_MPU(ARM_MPU_REGION_INIT) }; const struct arm_mpu_config mpu_config = { diff --git a/tests/misc/arm_mpu_regions/CMakeLists.txt b/tests/misc/arm_mpu_regions/CMakeLists.txt new file mode 100644 index 0000000000000..b847ef0b65da9 --- /dev/null +++ b/tests/misc/arm_mpu_regions/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(arm_mpu_regions) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/misc/arm_mpu_regions/boards/mps2_an385.overlay b/tests/misc/arm_mpu_regions/boards/mps2_an385.overlay new file mode 100644 index 0000000000000..8bae56de2a13c --- /dev/null +++ b/tests/misc/arm_mpu_regions/boards/mps2_an385.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + /delete-node/ memory@20000000; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x200000>; + }; + + sram_cache: memory@20200000 { + compatible = "mpu-region", "mmio-sram"; + reg = <0x20200000 0x100000>; + zephyr,memory-region = "SRAM_CACHE"; + zephyr,memory-region-mpu = "REGION_RAM_ATTR"; + }; + + sram_no_cache: memory@20300000 { + compatible = "mpu-region", "mmio-sram"; + reg = <0x20300000 0x100000>; + zephyr,memory-region = "SRAM_NO_CACHE"; + zephyr,memory-region-mpu = "REGION_RAM_NOCACHE_ATTR"; + }; + + sram_dtcm_fake: memory@abcdabcd { + compatible = "mpu-region", "arm,dtcm"; + reg = <0xabcdabcd 0x100000>; + zephyr,memory-region = "SRAM_DTCM_FAKE"; + zephyr,memory-region-mpu = "REGION_RAM_ATTR"; + }; +}; diff --git a/tests/misc/arm_mpu_regions/linker_sram_regions.ld b/tests/misc/arm_mpu_regions/linker_sram_regions.ld new file mode 100644 index 0000000000000..9fec10d12cdcc --- /dev/null +++ b/tests/misc/arm_mpu_regions/linker_sram_regions.ld @@ -0,0 +1,22 @@ +/* + * Copyright (c) Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include + +MEMORY +{ + LINKER_DT_REGION_FROM_NODE(DT_NODELABEL(sram_cache), rw) + LINKER_DT_REGION_FROM_NODE(DT_NODELABEL(sram_no_cache), rw) + LINKER_DT_REGION_FROM_NODE(DT_NODELABEL(sram_dtcm_fake), rw) +} + +#include diff --git a/tests/misc/arm_mpu_regions/prj.conf b/tests/misc/arm_mpu_regions/prj.conf new file mode 100644 index 0000000000000..a0a5dc105b92e --- /dev/null +++ b/tests/misc/arm_mpu_regions/prj.conf @@ -0,0 +1,3 @@ +CONFIG_ZTEST=y +CONFIG_HAVE_CUSTOM_LINKER_SCRIPT=y +CONFIG_CUSTOM_LINKER_SCRIPT="linker_sram_regions.ld" diff --git a/tests/misc/arm_mpu_regions/src/main.c b/tests/misc/arm_mpu_regions/src/main.c new file mode 100644 index 0000000000000..90bbc7a00ceb1 --- /dev/null +++ b/tests/misc/arm_mpu_regions/src/main.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +extern const struct arm_mpu_config mpu_config; + +static arm_mpu_region_attr_t cacheable = REGION_RAM_ATTR(REGION_1M); +static arm_mpu_region_attr_t noncacheable = REGION_RAM_NOCACHE_ATTR(REGION_1M); + +static void test_regions(void) +{ + int cnt = 0; + + for (size_t i = 0; i < mpu_config.num_regions; i++) { + const struct arm_mpu_region *r = &mpu_config.mpu_regions[i]; + + if (!strcmp(r->name, "SRAM_CACHE")) { + zassert_equal(r->base, 0x20200000, "Wrong base"); + zassert_equal(r->attr.rasr, cacheable.rasr, + "Wrong attr for SRAM_CACHE"); + cnt++; + } else if (!strcmp(r->name, "SRAM_NO_CACHE")) { + zassert_equal(r->base, 0x20300000, "Wrong base"); + zassert_equal(r->attr.rasr, noncacheable.rasr, + "Wrong attr for SRAM_NO_CACHE"); + cnt++; + } else if (!strcmp(r->name, "SRAM_DTCM_FAKE")) { + zassert_equal(r->base, 0xabcdabcd, "Wrong base"); + zassert_equal(r->attr.rasr, cacheable.rasr, + "Wrong attr for SRAM_DTCM_FAKE"); + cnt++; + } + } + + if (cnt != 3) { + ztest_test_fail(); + } +} + +void test_main(void) +{ + ztest_test_suite(test_c_arm_mpu_regions, + ztest_unit_test(test_regions) + ); + + ztest_run_test_suite(test_c_arm_mpu_regions); +} diff --git a/tests/misc/arm_mpu_regions/testcase.yaml b/tests/misc/arm_mpu_regions/testcase.yaml new file mode 100644 index 0000000000000..500f426868696 --- /dev/null +++ b/tests/misc/arm_mpu_regions/testcase.yaml @@ -0,0 +1,4 @@ +tests: + misc.arm_mpu_regions: + platform_allow: mps2_an385 + tags: sample board sram mpu