@@ -84,7 +84,7 @@ uint32_t nrf_mram_safe_read_word(uint32_t addr)
8484 barrier_isync_fence_full ();
8585
8686 /* Read operation that may fault */
87- memcpy (rbuf , (void * )( addr & ~ MRAM_WORD_MASK ) , MRAM_WORD_SIZE );
87+ memcpy (rbuf , (void * )addr , MRAM_WORD_SIZE );
8888
8989 /* DSB ensures the load and any resulting fault status write complete */
9090 barrier_dsync_fence_full ();
@@ -106,22 +106,9 @@ uint32_t nrf_mram_safe_read_word(uint32_t addr)
106106 return faulted ; /* 0 = read succeeded, non-zero = bus fault occurred */
107107}
108108
109- static int nrf_mram_write_and_verify (uint32_t addr , const void * data , size_t len )
109+ static int nrf_mram_write_and_verify_word (uint32_t addr , const void * data , size_t len )
110110{
111111 uint8_t retries = CONFIG_NRF_MRAM_MAX_RETRIES ;
112- #if (WRITE_BLOCK_SIZE & MRAM_WORD_MASK )
113- uint8_t rbuf [MRAM_WORD_SIZE ];
114-
115- if (len % MRAM_WORD_SIZE ) {
116- /* For partial word writes, we need to read the existing data first to avoid
117- * overwriting the unwritten bytes in the same word.
118- */
119- memcpy (rbuf + len , (void * )(addr + len ), MRAM_WORD_SIZE - len );
120- memcpy (rbuf , data , len );
121- data = rbuf ;
122- len = MRAM_WORD_SIZE ;
123- }
124- #endif
125112
126113 while (retries -- ) {
127114 memcpy ((void * )addr , data , len );
@@ -136,27 +123,27 @@ static int nrf_mram_write_and_verify(uint32_t addr, const void *data, size_t len
136123 return - EIO ;
137124}
138125
139- static int nrf_mram_erase_and_verify (uint32_t addr , size_t len )
140- {
141- uint8_t retries = CONFIG_NRF_MRAM_MAX_RETRIES ;
142126#if (WRITE_BLOCK_SIZE & MRAM_WORD_MASK )
127+ static int nrf_mram_write_and_verify_partial (uint32_t addr , const void * data , size_t len )
128+ {
143129 uint8_t rbuf [MRAM_WORD_SIZE ];
144130
145- if (len % MRAM_WORD_SIZE ) {
146- /* For partial word writes, we need to read the existing data first to avoid
147- * overwriting the unwritten bytes in the same word.
148- */
149- memcpy (rbuf , (void * )(addr + len ), MRAM_WORD_SIZE - len );
150- }
131+ /* For partial word writes, we need to read the existing data first to avoid
132+ * overwriting the unwritten bytes in the same word.
133+ */
134+ memcpy (rbuf , (void * )(addr & ~MRAM_WORD_MASK ), MRAM_WORD_SIZE );
135+ memcpy (rbuf + (addr & MRAM_WORD_MASK ), data , len );
136+
137+ return nrf_mram_write_and_verify_word (addr & ~MRAM_WORD_MASK , rbuf , MRAM_WORD_SIZE );
138+ }
151139#endif
152140
141+ static int nrf_mram_erase_and_verify_word (uint32_t addr , size_t len )
142+ {
143+ uint8_t retries = CONFIG_NRF_MRAM_MAX_RETRIES ;
144+
153145 while (retries -- ) {
154146 memset ((void * )addr , ERASE_VALUE , len );
155- #if (WRITE_BLOCK_SIZE & MRAM_WORD_MASK )
156- if (len % MRAM_WORD_SIZE ) {
157- memcpy ((void * )addr , rbuf , MRAM_WORD_SIZE - len );
158- }
159- #endif
160147 if (!nrf_mram_safe_read_word (addr )) {
161148 return 0 ;
162149 }
@@ -168,8 +155,23 @@ static int nrf_mram_erase_and_verify(uint32_t addr, size_t len)
168155 return - EIO ;
169156}
170157
158+ #if (WRITE_BLOCK_SIZE & MRAM_WORD_MASK )
159+ static int nrf_mram_erase_and_verify_partial (uint32_t addr , size_t len )
160+ {
161+ uint8_t rbuf [MRAM_WORD_SIZE ];
162+
163+ /* For partial word erases, we need to read the existing data first to avoid
164+ * overwriting the unwritten bytes in the same word.
165+ */
166+ memcpy (rbuf , (void * )(addr & ~MRAM_WORD_MASK ), MRAM_WORD_SIZE );
167+ memset (rbuf + (addr & MRAM_WORD_MASK ), ERASE_VALUE , len );
168+
169+ return nrf_mram_write_and_verify_word (addr & ~MRAM_WORD_MASK , rbuf , MRAM_WORD_SIZE );
170+ }
171+ #endif
172+
171173#ifdef CONFIG_MRAM_LATENCY
172- static inline bool nrf_mram_ready (uint32_t addr , uint8_t ironside_se_ver )
174+ static inline uint32_t nrf_mram_ready (uint32_t addr , uint8_t ironside_se_ver )
173175{
174176 if (ironside_se_ver < IRONSIDE_SE_SUPPORT_READY_VER ) {
175177 return true;
@@ -233,6 +235,50 @@ static int nrf_mram_read(const struct device *dev, off_t offset, void *data, siz
233235 return 0 ;
234236}
235237
238+ #if (WRITE_BLOCK_SIZE & MRAM_WORD_MASK )
239+ /**
240+ * @brief Structure to hold divided byte lengths for MRAM operations.
241+ */
242+ struct nrf_mram_length_breakdown {
243+ size_t first_word_bytes ; /**< Number of bytes in the first partial MRAM word */
244+ size_t aligned_bytes ; /**< Number of bytes in fully aligned MRAM words */
245+ size_t last_word_bytes ; /**< Number of bytes in the last partial MRAM word */
246+ };
247+
248+ /**
249+ * @brief Divide operation length into first word, aligned words, and last word components.
250+ *
251+ * Calculates how many bytes belong to:
252+ * - The first partial MRAM word (if offset is not word-aligned)
253+ * - Fully aligned MRAM words in the middle
254+ * - The last partial MRAM word (if total length doesn't end on word boundary)
255+ *
256+ * @param offset Relative offset into memory.
257+ * @param len Number of bytes for the intended operation.
258+ *
259+ * @return Structure containing the divided byte lengths.
260+ */
261+ static inline struct nrf_mram_length_breakdown nrf_mram_divide_length (off_t offset , size_t len )
262+ {
263+ struct nrf_mram_length_breakdown len_break = {0 };
264+ size_t first_word_bytes = MRAM_WORD_SIZE - (offset & MRAM_WORD_MASK );
265+ size_t remaining = 0 ;
266+
267+ if (len > first_word_bytes ) {
268+ len_break .first_word_bytes = first_word_bytes ;
269+ remaining = len - first_word_bytes ;
270+ len_break .aligned_bytes = remaining & ~MRAM_WORD_MASK ;
271+ len_break .last_word_bytes = remaining & MRAM_WORD_MASK ;
272+ } else {
273+ len_break .first_word_bytes = len ;
274+ len_break .aligned_bytes = 0 ;
275+ len_break .last_word_bytes = 0 ;
276+ }
277+
278+ return len_break ;
279+ }
280+ #endif
281+
236282static int nrf_mram_write (const struct device * dev , off_t offset , const void * data , size_t len )
237283{
238284 struct nrf_mram_data_t * nrf_mram_data = dev -> data ;
@@ -255,25 +301,44 @@ static int nrf_mram_write(const struct device *dev, off_t offset, const void *da
255301#endif
256302 }
257303
304+ #if (WRITE_BLOCK_SIZE & MRAM_WORD_MASK )
305+ struct nrf_mram_length_breakdown len_break = nrf_mram_divide_length (offset , len );
306+
307+ /* First, write the partial bytes from the first word */
308+ if (len_break .first_word_bytes ) {
309+ while (!nrf_mram_ready (addr , ironside_se_ver )) {
310+ /* Wait until MRAM controller is ready */
311+ }
312+ ret = nrf_mram_write_and_verify_partial (addr , data , len_break .first_word_bytes );
313+ if (ret ) {
314+ goto unlock ;
315+ }
316+ /* align to the next word boundary */
317+ len = len_break .aligned_bytes ;
318+ data = (const void * )((uintptr_t )data + len_break .first_word_bytes );
319+ addr += len_break .first_word_bytes ;
320+ }
321+ #endif
258322 for (uint32_t i = 0 ; i < (len / MRAM_WORD_SIZE ); i ++ ) {
259323 while (!nrf_mram_ready (addr + (i * MRAM_WORD_SIZE ), ironside_se_ver )) {
260324 /* Wait until MRAM controller is ready */
261325 }
262- ret = nrf_mram_write_and_verify ( addr + ( i * MRAM_WORD_SIZE ),
263- ( void * )(( uintptr_t ) data + (i * MRAM_WORD_SIZE ) ),
264- MRAM_WORD_SIZE );
326+ ret = nrf_mram_write_and_verify_word (
327+ addr + (i * MRAM_WORD_SIZE ),
328+ ( void * )(( uintptr_t ) data + ( i * MRAM_WORD_SIZE )), MRAM_WORD_SIZE );
265329 if (ret ) {
266330 goto unlock ;
267331 }
268332 }
269333#if (WRITE_BLOCK_SIZE & MRAM_WORD_MASK )
270- if (len % MRAM_WORD_SIZE ) {
271- while (!nrf_mram_ready (addr + ( len & ~ MRAM_WORD_MASK ) , ironside_se_ver )) {
334+ if (len_break . last_word_bytes ) {
335+ while (!nrf_mram_ready (addr + len_break . aligned_bytes , ironside_se_ver )) {
272336 /* Wait until MRAM controller is ready */
273337 }
274- ret = nrf_mram_write_and_verify (addr + (len & ~MRAM_WORD_MASK ),
275- (void * )((uintptr_t )data + (len & ~MRAM_WORD_MASK )),
276- len & MRAM_WORD_MASK );
338+ ret = nrf_mram_write_and_verify_partial (
339+ addr + len_break .aligned_bytes ,
340+ (void * )((uintptr_t )data + len_break .aligned_bytes ),
341+ len_break .last_word_bytes );
277342 if (ret ) {
278343 goto unlock ;
279344 }
@@ -312,23 +377,42 @@ static int nrf_mram_erase(const struct device *dev, off_t offset, size_t size)
312377 mram_no_latency_sync_request ();
313378#endif
314379 }
380+
381+ #if (WRITE_BLOCK_SIZE & MRAM_WORD_MASK )
382+ struct nrf_mram_length_breakdown len_break = nrf_mram_divide_length (offset , size );
383+
384+ /* First, erase the partial bytes from the first word */
385+ if (len_break .first_word_bytes ) {
386+ while (!nrf_mram_ready (addr , ironside_se_ver )) {
387+ /* Wait until MRAM controller is ready */
388+ }
389+ ret = nrf_mram_erase_and_verify_partial (addr , len_break .first_word_bytes );
390+ if (ret ) {
391+ goto unlock ;
392+ }
393+ /* align to the next word boundary */
394+ size = len_break .aligned_bytes ;
395+ addr += len_break .first_word_bytes ;
396+ }
397+ #endif
398+
315399 for (uint32_t i = 0 ; i < (size / MRAM_WORD_SIZE ); i ++ ) {
316400 while (!nrf_mram_ready (addr + (i * MRAM_WORD_SIZE ), ironside_se_ver )) {
317401 /* Wait until MRAM controller is ready */
318402 }
319- ret = nrf_mram_erase_and_verify (addr + (i * MRAM_WORD_SIZE ), MRAM_WORD_SIZE );
403+ ret = nrf_mram_erase_and_verify_word (addr + (i * MRAM_WORD_SIZE ), MRAM_WORD_SIZE );
320404 if (ret ) {
321405 goto unlock ;
322406 }
323407 }
324408
325409#if (WRITE_BLOCK_SIZE & MRAM_WORD_MASK )
326- if (size % MRAM_WORD_SIZE ) {
327- while (!nrf_mram_ready (addr + ( size & ~ MRAM_WORD_MASK ) , ironside_se_ver )) {
410+ if (len_break . last_word_bytes ) {
411+ while (!nrf_mram_ready (addr + len_break . aligned_bytes , ironside_se_ver )) {
328412 /* Wait until MRAM controller is ready */
329413 }
330- ret = nrf_mram_erase_and_verify (addr + ( size & ~ MRAM_WORD_MASK ) ,
331- size & MRAM_WORD_MASK );
414+ ret = nrf_mram_erase_and_verify_partial (addr + len_break . aligned_bytes ,
415+ len_break . last_word_bytes );
332416 if (ret ) {
333417 goto unlock ;
334418 }
0 commit comments