1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * NRF54L
9 *
10 * RRAMC - Resistive random access memory controller
11 * &
12 * UICR - User information configuration registers
13 *
14 * A very simple model, which creates a memory mapped RRAMC and UICR area
15 * backed by either a file on disk or host RAM.
16 * The RRAM (and UICR) is memory is not mapped in the same addresses as in
17 * real HW. Accesses need to be done relative to nhw_RRAMC_get_RRAM_base_address()
18 * (or NRF_UICR_BASE for the UICR)
19 *
20 * Note: The SICR is not yet included
21 *
22 * Notes for the RRAM(C):
23 *
24 * * Reads and writes are instantaneous.
25 *
26 * * READY and READYNEXT are reset to 1 and never cleared.
27 *
28 * * Task, events and interrupts are not connected.
29 *
30 * * Writes are assumed always enabled and write buffering disabled.
31 * i.e. CONFIG, READYNEXTTIMEOUT are ignored,
32 * writes are immediately reflected in the RRAM,
33 * BUFSTATUS.EMPTY is reset to 1 and never cleared.
34 *
35 * * There is no model of the optional immutable boot region write protection
36 * (all RRAM can be written)
37 *
38 * * Reads do not go thru the CACHE
39 *
40 * * There is no models of the RRAM and controller power states
41 * (POWER.* are ignored)
42 *
43 * * There is no models of bit errors, or ECC corrections
44 *
45 * * ACCESSERRORADDR is not modeled (it is never set after reset)
46 *
47 * * Access port protection is not modeled. The UICR can always be erased.
48 *
49 *
50 * Notes for the UICR
51 * * The APPROTECT, SECUREAPPROTECT, AUXAPPROTECT, ERASEPROTECT
52 * and BOOTCONF are ignored.
53 * Their equivalent functionality is not implemented
54 *
55 *
56 * Implementation notes:
57 * This file includes models for a nrf54L RRAMController, the RRAM itself
58 * and of an empty UICR.
59 * And instantiates 1 set for the nrf54L15
60 * (and initializes them at startup and frees them on exit),
61 */
62
63 #include <string.h>
64 #include <stdint.h>
65 #include "bs_tracing.h"
66 #include "bs_cmd_line.h"
67 #include "bs_dynargs.h"
68 #include "bs_oswrap.h"
69 #include "nsi_hw_scheduler.h"
70 #include "nsi_tasks.h"
71 #include "nsi_hws_models_if.h"
72 #include "NHW_common_types.h"
73 #include "NHW_config.h"
74 #include "NHW_peri_types.h"
75 #include "NHW_RRAMC.h"
76 #include "NHW_NVM_backend.h"
77
78 NRF_UICR_Type *NRF_UICR_regs_p[NHW_RRAMC_UICR_TOTAL_INST];
79 NRF_RRAMC_Type *NRF_RRAMC_regs_p[NHW_RRAMC_UICR_TOTAL_INST];
80 NRF_RRAMC_Type NRF_RRAMC_regs[NHW_RRAMC_UICR_TOTAL_INST] = {0};
81
82 struct hw_rramc_st_t {
83 NRF_RRAMC_Type *RRAMC_regs;
84 nvm_storage_state_t rram_st;
85 nvm_storage_state_t uicr_st;
86
87 uint rram_start_addr;
88 uint rram_size;
89 uint uicr_size;
90 };
91
92 static struct hw_rramc_st_t hw_rramc_st[NHW_RRAMC_UICR_TOTAL_INST];
93
94 struct nvmc_args_t {
95 struct nhw_nvm_st_args_t uicr[NHW_RRAMC_UICR_TOTAL_INST];
96 struct nhw_nvm_st_args_t rram[NHW_RRAMC_UICR_TOTAL_INST];
97 } nvmc_args;
98
99 /**
100 * Initialize the RRAM(C) and UICR models
101 */
nhw_RRAMC_uicr_init(void)102 static void nhw_RRAMC_uicr_init(void)
103 {
104 uint rram_start_addr[NHW_RRAMC_UICR_TOTAL_INST] = NHW_RRAM_START_ADDR;
105 uint rram_size[NHW_RRAMC_UICR_TOTAL_INST] = NHW_RRAM_SIZE;
106 uint uicr_size[NHW_RRAMC_UICR_TOTAL_INST] = NHW_UICR_SIZE;
107
108 memset(NRF_RRAMC_regs, 0x00, sizeof(NRF_RRAMC_regs));
109
110 for (int inst = 0; inst < NHW_RRAMC_UICR_TOTAL_INST; inst++) {
111 struct hw_rramc_st_t *this = &hw_rramc_st[inst];
112 this->RRAMC_regs = &NRF_RRAMC_regs[inst];
113 NRF_RRAMC_regs_p[inst] = &NRF_RRAMC_regs[inst];
114
115 NRF_RRAMC_regs[inst].READY = 1;
116 NRF_RRAMC_regs[inst].READYNEXT = 1;
117 NRF_RRAMC_regs[inst].EVENTS_READY = 1;
118 NRF_RRAMC_regs[inst].EVENTS_READYNEXT = 1;
119 NRF_RRAMC_regs[inst].ACCESSERRORADDR = 0x00FFFFFF;
120 NRF_RRAMC_regs[inst].BUFSTATUS.WRITEBUFEMPTY = 1;
121 NRF_RRAMC_regs[inst].READYNEXTTIMEOUT = 0x00000080;
122 NRF_RRAMC_regs[inst].POWER.CONFIG = 0x00000100;
123
124 this->rram_start_addr = rram_start_addr[inst];
125 this->rram_size = rram_size[inst];
126
127 nhw_nvm_init_storage(&this->rram_st, &nvmc_args.rram[inst],
128 this->rram_size, "RRAM");
129
130 this->uicr_size = uicr_size[inst];
131 nhw_nvm_init_storage(&this->uicr_st, &nvmc_args.uicr[inst],
132 this->uicr_size, "UICR");
133
134 NRF_UICR_regs_p[inst] = (NRF_UICR_Type *)this->uicr_st.storage;
135 }
136 }
137
138 NSI_TASK(nhw_RRAMC_uicr_init, HW_INIT, 100);
139
140 /**
141 * Clean up the RRAM(C) and UICR model before program exit
142 */
nhw_RRAMC_uicr_clean_up(void)143 static void nhw_RRAMC_uicr_clean_up(void) {
144 for (int inst = 0; inst < NHW_RRAMC_UICR_TOTAL_INST; inst++) {
145 struct hw_rramc_st_t *this = &hw_rramc_st[inst];
146 nhw_nvm_clear_storage(&this->rram_st);
147 nhw_nvm_clear_storage(&this->uicr_st);
148 }
149 }
150
151 NSI_TASK(nhw_RRAMC_uicr_clean_up, ON_EXIT_PRE, 100);
152
153 /*
154 * Do the actual erase of the UICR area
155 */
nhw_RRAMC_erase_uicr(uint inst)156 static void nhw_RRAMC_erase_uicr(uint inst){
157 struct hw_rramc_st_t *this = &hw_rramc_st[inst];
158 (void)memset(this->uicr_st.storage, 0xFF, this->uicr_st.size);
159 }
160
161 /*
162 * Do the actual erase of all RRAM and UICR areas
163 */
nhw_RRAMC_erase_all(uint inst)164 static void nhw_RRAMC_erase_all(uint inst){
165 struct hw_rramc_st_t *this = &hw_rramc_st[inst];
166 nhw_RRAMC_erase_uicr(inst);
167 (void)memset(this->rram_st.storage, 0xFF, this->rram_st.size);
168 }
169
nhw_RRAMC_regw_sideeffects_ERASEALL(uint inst)170 void nhw_RRAMC_regw_sideeffects_ERASEALL(uint inst) {
171 NRF_RRAMC_regs[inst].ERASE.ERASEALL &= 1;
172
173 if (NRF_RRAMC_regs[inst].ERASE.ERASEALL) {
174 NRF_RRAMC_regs[inst].ERASE.ERASEALL = 0;
175 nhw_RRAMC_erase_all(inst);
176 }
177 }
178
179 #define OUT_OF_RRAM_ERROR(addr) \
180 bs_trace_error_time_line("%s: Attempted access outside of RRAM and UICR areas (0x%X)\n",\
181 __func__, address)
182
183 /*
184 * Check if an address is in range of any RRAM or UICR
185 * and if so, set the inst, storage and offset accordingly.
186 *
187 * Where address is an address in either a "hard" RRAM address
188 * (meaning in the 0x00..00 range for nrf52, or also in the 0x010..00 range for nrf53)
189 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
190 * NRF_UICR_*_BASE)
191 *
192 * If the address is not in range, the function does not return, but produces an error
193 */
nhw_RRAMC_address_location(uint32_t address,uint * inst,nvm_storage_state_t ** storage,int * offset)194 static void nhw_RRAMC_address_location(uint32_t address, uint *inst, nvm_storage_state_t **storage, int *offset){
195 for (int i = 0; i < NHW_RRAMC_UICR_TOTAL_INST; i ++) {
196 *inst = i;
197 if ((address >= hw_rramc_st[i].rram_start_addr) \
198 && (address < hw_rramc_st[i].rram_start_addr + hw_rramc_st[i].rram_size)) {
199 *storage = &hw_rramc_st[i].rram_st;
200 *offset = address - hw_rramc_st[i].rram_start_addr;
201 return;
202 }
203 if ((address >= (uint32_t)hw_rramc_st[i].uicr_st.storage) \
204 && (address < (uint32_t)hw_rramc_st[i].uicr_st.storage + hw_rramc_st[i].uicr_size)) {
205 *storage = &hw_rramc_st[i].uicr_st;
206 *offset = address - (uint32_t)hw_rramc_st[i].uicr_st.storage;
207 return;
208 }
209 }
210 OUT_OF_RRAM_ERROR(address);
211 }
212
213 /*
214 * Write to a RRAM array (RRAM or UICR)
215 *
216 * Where address is an address in either a "hard" RRAM address
217 * (meaning in the 0x00..00 range)
218 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
219 * NRF_UICR_*_BASE)
220 */
nhw_RRAMC_write_word(uint32_t address,uint32_t value)221 void nhw_RRAMC_write_word(uint32_t address, uint32_t value){
222 if ((address & 3) != 0){
223 bs_trace_error_line_time("%s: write to non word aligned address %u, "
224 "this would have hard-faulted in real HW\n",
225 __func__, address);
226 }
227
228 int offset;
229 nvm_storage_state_t *backend;
230 uint inst;
231
232 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
233
234 *(uint32_t*)&backend->storage[offset] = value;
235 }
236
237 /**
238 * Read from the RRAM array (RRAM or UICR)
239 *
240 * Where address is an address in either a "hard" RRAM address
241 * (meaning in the 0x00..00 range)
242 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
243 * NRF_UICR_*_BASE)
244 *
245 * This operation is instantaneous in simulation.
246 */
nhw_RRAMC_read_word(uint32_t address)247 uint32_t nhw_RRAMC_read_word(uint32_t address) {
248 int offset;
249 nvm_storage_state_t *backend;
250 uint inst;
251
252 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
253
254 return *(uint32_t*)&backend->storage[offset];
255 }
256
nhw_RRAMC_read_halfword(uint32_t address)257 uint16_t nhw_RRAMC_read_halfword(uint32_t address) {
258 int offset;
259 nvm_storage_state_t *backend;
260 uint inst;
261
262 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
263
264 return *(uint16_t*)&backend->storage[offset];
265 }
266
nhw_RRAMC_read_byte(uint32_t address)267 uint8_t nhw_RRAMC_read_byte(uint32_t address) {
268 int offset;
269 nvm_storage_state_t *backend;
270 uint inst;
271
272 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
273
274 return *(uint8_t*)&backend->storage[offset];
275 }
276
277 /**
278 * memcpy from the RRAM/UICR array from <address> <size> bytes.
279 *
280 * Where address is an address in either a "hard" RRAM address
281 * (meaning in the 0x00..00 range)
282 * Or a "soft" address inside an UICR range (meaning an address gotten as an offset from
283 * NRF_UICR_*_BASE)
284 *
285 * This is a convenience function in the model.
286 * It can be used from DMA controller models or the like.
287 *
288 * This operation is instantaneous in simulation.
289 * In real HW it is as "fast" as all those AHB accesses
290 * can be dispatched by the interconnect and handled by
291 * the RRAMC peripheral
292 */
nhw_RRAMC_read_buffer(void * dest,uint32_t address,size_t size)293 void nhw_RRAMC_read_buffer(void *dest, uint32_t address, size_t size) {
294 int offset;
295 nvm_storage_state_t *backend;
296 uint inst;
297
298 nhw_RRAMC_address_location(address, &inst, &backend, &offset);
299
300 if (offset + size >= backend->size) {
301 OUT_OF_RRAM_ERROR(address + size);
302 }
303
304 (void)memcpy(dest, &backend->storage[offset], size);
305 }
306
nhw_RRAMC_get_RRAM_base_address(uint inst)307 void* nhw_RRAMC_get_RRAM_base_address(uint inst) {
308 return (void*)hw_rramc_st[inst].rram_st.storage;
309 }
310
NVM_BACKEND_PARAMS_CALLBACS(uicr,uicr[0])311 NVM_BACKEND_PARAMS_CALLBACS(uicr, uicr[0])
312 NVM_BACKEND_PARAMS_CALLBACS(rram, rram[0])
313
314 static void RRAMC_register_cmd_args(void){
315 for (int i = 0; i < NHW_RRAMC_UICR_TOTAL_INST; i++) {
316 nvmc_args.uicr[i].in_ram = true;
317 nvmc_args.rram[i].in_ram = true;
318 }
319
320 static bs_args_struct_t args_struct_toadd[] = {
321 NVM_BACKEND_PARAMS(uicr, uicr[0], UICR),
322 NVM_BACKEND_PARAMS(rram, rram[0], FLASH),
323 ARG_TABLE_ENDMARKER
324 };
325
326 bs_add_extra_dynargs(args_struct_toadd);
327 }
328
329 NSI_TASK(RRAMC_register_cmd_args, PRE_BOOT_1, 100);
330