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