1 /*
2  * Copyright (c) 2023 - 2024, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <helpers/nrfx_ram_ctrl.h>
35 
36 typedef struct
37 {
38     uint8_t block:4;
39     uint8_t section:4;
40 } ram_block_section_t;
41 
42 typedef union
43 {
44     ram_block_section_t decoded;
45     uint8_t             raw;
46 } ram_unit_t;
47 
48 #if !defined(NRF_MEMORY_RAM_BASE) && defined(NRF_MEMORY_RAM0_BASE)
49 #define NRF_MEMORY_RAM_BASE NRF_MEMORY_RAM0_BASE
50 #endif
51 
52 #define RAM_NON_UNIFORM_SECTION_DECLARE(i, _block, _section) {.decoded = {_block, _section}}
53 
54 #if defined(NRF51)
55 #define RAM_SECTION_UNIT_SIZE          8192
56 #define RAM_UNIFORM_BLOCKS             4
57 #define RAM_UNIFORM_SECTIONS_PER_BLOCK 1
58 #define RAM_UNIFORM_SECTIONS_TOTAL     4
59 #error "Unsupported device."
60 #elif defined(NRF52805_XXAA) || defined(NRF52810_XXAA) || defined(NRF52811_XXAA)
61 #define RAM_SECTION_UNIT_SIZE          4096
62 #define RAM_UNIFORM_BLOCKS             3
63 #define RAM_UNIFORM_SECTIONS_PER_BLOCK 2
64 #define RAM_UNIFORM_SECTIONS_TOTAL     6
65 #elif defined(NRF52820_XXAA)
66 #define RAM_SECTION_UNIT_SIZE          4096
67 #define RAM_UNIFORM_BLOCKS             4
68 #define RAM_UNIFORM_SECTIONS_PER_BLOCK 2
69 #define RAM_UNIFORM_SECTIONS_TOTAL     8
70 #elif defined(NRF52832_XXAA)
71 #define RAM_SECTION_UNIT_SIZE          4096
72 #define RAM_UNIFORM_BLOCKS             8
73 #define RAM_UNIFORM_SECTIONS_PER_BLOCK 2
74 #define RAM_UNIFORM_SECTIONS_TOTAL     16
75 #elif defined(NRF52833_XXAA)
76 #define RAM_SECTION_UNIT_SIZE          4096
77 #define RAM_UNIFORM_BLOCKS             8
78 #define RAM_UNIFORM_SECTIONS_PER_BLOCK 2
79 #define RAM_UNIFORM_SECTIONS_TOTAL     16
80 #define RAM_NON_UNIFORM_BLOCK_INDEX    8
81 #define RAM_NON_UNIFORM_BLOCK_UNITS    8
82 #define RAM_NON_UNIFORM_SECTIONS                                                               \
83     NRFX_LISTIFY(RAM_NON_UNIFORM_BLOCK_UNITS,                                                  \
84                  RAM_NON_UNIFORM_SECTION_DECLARE, (,),                                         \
85                  RAM_NON_UNIFORM_BLOCK_INDEX, 0), /* Section 0 of block 8 - 8 * 4 kB units. */ \
86     NRFX_LISTIFY(RAM_NON_UNIFORM_BLOCK_UNITS,                                                  \
87                  RAM_NON_UNIFORM_SECTION_DECLARE, (,),                                         \
88                  RAM_NON_UNIFORM_BLOCK_INDEX, 1)  /* Section 1 of block 8 - 8 * 4 kB units. */
89 #elif defined(NRF52840_XXAA)
90 #define RAM_SECTION_UNIT_SIZE          4096
91 #define RAM_UNIFORM_BLOCKS             8
92 #define RAM_UNIFORM_SECTIONS_PER_BLOCK 2
93 #define RAM_UNIFORM_SECTIONS_TOTAL     16
94 #define RAM_NON_UNIFORM_BLOCK_INDEX    8
95 #define RAM_NON_UNIFORM_BLOCK_UNITS    8
96 #define RAM_NON_UNIFORM_SECTIONS                                                               \
97     NRFX_LISTIFY(RAM_NON_UNIFORM_BLOCK_UNITS,                                                  \
98                  RAM_NON_UNIFORM_SECTION_DECLARE, (,),                                         \
99                  RAM_NON_UNIFORM_BLOCK_INDEX, 0), /* Section 0 of block 8 - 8 * 4 kB units. */ \
100     NRFX_LISTIFY(RAM_NON_UNIFORM_BLOCK_UNITS,                                                  \
101                  RAM_NON_UNIFORM_SECTION_DECLARE, (,),                                         \
102                  RAM_NON_UNIFORM_BLOCK_INDEX, 1), /* Section 1 of block 8 - 8 * 4 kB units. */ \
103     NRFX_LISTIFY(RAM_NON_UNIFORM_BLOCK_UNITS,                                                  \
104                  RAM_NON_UNIFORM_SECTION_DECLARE, (,),                                         \
105                  RAM_NON_UNIFORM_BLOCK_INDEX, 2), /* Section 2 of block 8 - 8 * 4 kB units. */ \
106     NRFX_LISTIFY(RAM_NON_UNIFORM_BLOCK_UNITS,                                                  \
107                  RAM_NON_UNIFORM_SECTION_DECLARE, (,),                                         \
108                  RAM_NON_UNIFORM_BLOCK_INDEX, 3), /* Section 3 of block 8 - 8 * 4 kB units. */ \
109     NRFX_LISTIFY(RAM_NON_UNIFORM_BLOCK_UNITS,                                                  \
110                  RAM_NON_UNIFORM_SECTION_DECLARE, (,),                                         \
111                  RAM_NON_UNIFORM_BLOCK_INDEX, 4), /* Section 4 of block 8 - 8 * 4 kB units. */ \
112     NRFX_LISTIFY(RAM_NON_UNIFORM_BLOCK_UNITS,                                                  \
113                  RAM_NON_UNIFORM_SECTION_DECLARE, (,),                                         \
114                  RAM_NON_UNIFORM_BLOCK_INDEX, 5)  /* Section 5 of block 8 - 8 * 4 kB units. */
115 #elif defined(NRF5340_XXAA_APPLICATION)
116 #define RAM_SECTION_UNIT_SIZE          4096
117 #define RAM_UNIFORM_BLOCKS             8
118 #define RAM_UNIFORM_SECTIONS_PER_BLOCK 16
119 #define RAM_UNIFORM_SECTIONS_TOTAL     128
120 #elif defined(NRF5340_XXAA_NETWORK)
121 #define RAM_SECTION_UNIT_SIZE          4096
122 #define RAM_UNIFORM_BLOCKS             4
123 #define RAM_UNIFORM_SECTIONS_PER_BLOCK 4
124 #define RAM_UNIFORM_SECTIONS_TOTAL     16
125 #elif defined(NRF54H20_ENGA_XXAA)
126 #define RAM_SECTION_UNIT_SIZE          (32UL * 1024UL)
127 #define RAM_UNIFORM_BLOCKS             1
128 #define RAM_UNIFORM_SECTIONS_PER_BLOCK 1
129 #define RAM_UNIFORM_SECTIONS_TOTAL     1
130 #elif defined(NRF54L15_XXAA) || defined(NRF54L15_ENGA_XXAA)
131 #define RAM_SECTION_UNIT_SIZE          (16UL * 1024UL)
132 #define RAM_NON_UNIFORM_SECTIONS                                      \
133     NRFX_LISTIFY(4, RAM_NON_UNIFORM_SECTION_DECLARE, (,),             \
134                  0, 0), /* Section 0 of block 0 - 4 * 16 kB units. */ \
135     NRFX_LISTIFY(4, RAM_NON_UNIFORM_SECTION_DECLARE, (,),             \
136                  0, 1), /* Section 1 of block 0 - 4 * 16 kB units. */ \
137     NRFX_LISTIFY(2, RAM_NON_UNIFORM_SECTION_DECLARE, (,),             \
138                  1, 0), /* Section 0 of block 1 - 2 * 16 kB units. */ \
139     NRFX_LISTIFY(2, RAM_NON_UNIFORM_SECTION_DECLARE, (,),             \
140                  1, 1), /* Section 1 of block 1 - 2 * 16 kB units. */ \
141     NRFX_LISTIFY(1, RAM_NON_UNIFORM_SECTION_DECLARE, (,),             \
142                  1, 2), /* Section 2 of block 1 - 1 * 16 kB units. */ \
143     NRFX_LISTIFY(1, RAM_NON_UNIFORM_SECTION_DECLARE, (,),             \
144                  1, 3)  /* Section 3 of block 1 - 1 * 16 kB units. */
145 #elif defined(NRF9120_XXAA) || defined(NRF9160_XXAA)
146 #define RAM_SECTION_UNIT_SIZE          8192
147 #define RAM_UNIFORM_BLOCKS             8
148 #define RAM_UNIFORM_SECTIONS_PER_BLOCK 4
149 #define RAM_UNIFORM_SECTIONS_TOTAL     32
150 #elif !defined(RAM_SECTION_UNIT_SIZE)
151 #error "Unsupported device."
152 #endif
153 
154 #define RAM_UNIFORM_SECTION_DECLARE(i, ...) \
155     {.decoded = {i / RAM_UNIFORM_SECTIONS_PER_BLOCK, i % RAM_UNIFORM_SECTIONS_PER_BLOCK}}
156 
157 #if defined(RAM_NON_UNIFORM_SECTIONS)
158 static const ram_unit_t unit_to_block_section_lut[] =
159 {
160 #if defined(RAM_UNIFORM_SECTIONS_TOTAL)
161     NRFX_LISTIFY(RAM_UNIFORM_SECTIONS_TOTAL, RAM_UNIFORM_SECTION_DECLARE, (,)),
162 #endif
163     RAM_NON_UNIFORM_SECTIONS,
164 };
165 #endif
166 
167 typedef void (* ram_ctrl_block_section_op_t)(uint8_t  block_idx,
168                                              uint32_t section_mask,
169                                              bool     enable);
170 
ram_ctrl_block_section_power_enable_set(uint8_t block_idx,uint32_t section_mask,bool enable)171 static void ram_ctrl_block_section_power_enable_set(uint8_t  block_idx,
172                                                     uint32_t section_mask,
173                                                     bool     enable)
174 {
175     nrfx_ram_ctrl_section_power_mask_enable_set(block_idx, section_mask, enable);
176 }
177 
ram_ctrl_block_section_retention_enable_set(uint8_t block_idx,uint32_t section_mask,bool enable)178 static void ram_ctrl_block_section_retention_enable_set(uint8_t  block_idx,
179                                                         uint32_t section_mask,
180                                                         bool     enable)
181 {
182     nrfx_ram_ctrl_section_retention_mask_enable_set(block_idx, section_mask, enable);
183 }
184 
ram_ctrl_block_section_iterate(void const * p_object,size_t length,bool enable,ram_ctrl_block_section_op_t handler)185 static void ram_ctrl_block_section_iterate(void const *                p_object,
186                                            size_t                      length,
187                                            bool                        enable,
188                                            ram_ctrl_block_section_op_t handler)
189 {
190     NRFX_ASSERT(nrfx_is_in_ram(p_object));
191     NRFX_ASSERT(length);
192 
193     size_t rel_obj_adr    = (size_t)p_object - NRF_MEMORY_RAM_BASE;
194     size_t obj_start_addr = rel_obj_adr;
195     size_t obj_end_addr   = rel_obj_adr + length;
196 
197     /* Handle case when the object is aligned to section boundaries,
198      * which could cause additional section being incorrectly iterated over. */
199     obj_end_addr--;
200 
201     size_t ram_unit_start_idx = obj_start_addr / RAM_SECTION_UNIT_SIZE;
202     size_t ram_unit_end_idx   = obj_end_addr / RAM_SECTION_UNIT_SIZE;
203 
204     uint8_t block;
205     uint8_t section;
206     ram_unit_t prev_ram_unit = {.raw = UINT8_MAX};
207     for (size_t idx = ram_unit_start_idx; idx <= ram_unit_end_idx; idx++)
208     {
209 #if defined(RAM_NON_UNIFORM_SECTIONS)
210         ram_unit_t const * p_ram_unit = &unit_to_block_section_lut[idx];
211         block = p_ram_unit->decoded.block;
212         section = p_ram_unit->decoded.section;
213 
214         ram_unit_t prev_ram_unit_copy = prev_ram_unit;
215         prev_ram_unit.raw = p_ram_unit->raw;
216         if (p_ram_unit->raw == prev_ram_unit_copy.raw)
217         {
218             continue;
219         }
220 #else
221         block   = (uint8_t)idx / RAM_UNIFORM_SECTIONS_PER_BLOCK;
222         section = idx % RAM_UNIFORM_SECTIONS_PER_BLOCK;
223         (void)prev_ram_unit;
224 #endif
225         handler(block, 1UL << section, enable);
226     }
227 }
228 
nrfx_ram_ctrl_power_enable_set(void const * p_object,size_t length,bool enable)229 void nrfx_ram_ctrl_power_enable_set(void const * p_object, size_t length, bool enable)
230 {
231     ram_ctrl_block_section_iterate(p_object,
232                                    length,
233                                    enable,
234                                    ram_ctrl_block_section_power_enable_set);
235 }
236 
nrfx_ram_ctrl_retention_enable_set(void const * p_object,size_t length,bool enable)237 void nrfx_ram_ctrl_retention_enable_set(void const * p_object, size_t length, bool enable)
238 {
239     ram_ctrl_block_section_iterate(p_object,
240                                    length,
241                                    enable,
242                                    ram_ctrl_block_section_retention_enable_set);
243 }
244