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