1
2 /**
3 * \file
4 *
5 * \brief Non-Volatile Memory Controller
6 *
7 * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
8 *
9 * \asf_license_start
10 *
11 * \page License
12 *
13 * Subject to your compliance with these terms, you may use Microchip
14 * software and any derivatives exclusively with Microchip products.
15 * It is your responsibility to comply with third party license terms applicable
16 * to your use of third party software (including open source software) that
17 * may accompany Microchip software.
18 *
19 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
21 * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
22 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
23 * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
24 * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
25 * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
26 * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
27 * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
28 * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
29 * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
30 *
31 * \asf_license_stop
32 *
33 */
34
35 #include <hpl_flash.h>
36 #include <hpl_user_area.h>
37 #include <string.h>
38 #include <utils_assert.h>
39 #include <utils.h>
40 #include <hpl_nvmctrl_config.h>
41
42 #define NVM_MEMORY ((volatile uint16_t *)FLASH_ADDR)
43
44 /**
45 * \brief NVM configuration type
46 */
47 struct nvm_configuration {
48 hri_nvmctrl_ctrlb_reg_t ctrlb; /*!< Control B Register */
49 };
50
51 /**
52 * \brief Array of NVM configurations
53 */
54 static struct nvm_configuration _nvm
55 = {(CONF_NVM_CACHE << NVMCTRL_CTRLB_CACHEDIS_Pos) | (CONF_NVM_READ_MODE << NVMCTRL_CTRLB_READMODE_Pos)
56 | (CONF_NVM_SLEEPPRM << NVMCTRL_CTRLB_SLEEPPRM_Pos)};
57
58 /*!< Pointer to hpl device */
59 static struct _flash_device *_nvm_dev = NULL;
60
61 static void _flash_erase_row(void *const hw, const uint32_t dst_addr, uint32_t nvmctrl_cmd);
62 static void _flash_program(void *const hw, const uint32_t dst_addr, const uint8_t *buffer, const uint16_t size,
63 uint32_t nvmctrl_cmd);
64
65 /**
66 * \brief Initialize NVM
67 */
_flash_init(struct _flash_device * const device,void * const hw)68 int32_t _flash_init(struct _flash_device *const device, void *const hw)
69 {
70 ASSERT(device && (hw == NVMCTRL));
71 uint32_t ctrlb;
72
73 device->hw = hw;
74 ctrlb = _nvm.ctrlb & ~(NVMCTRL_CTRLB_RWS_Msk | NVMCTRL_CTRLB_MANW);
75 ctrlb |= hri_nvmctrl_get_CTRLB_reg(device->hw, NVMCTRL_CTRLB_RWS_Msk | NVMCTRL_CTRLB_MANW);
76 hri_nvmctrl_write_CTRLB_reg(device->hw, ctrlb);
77
78 _nvm_dev = device;
79 NVIC_DisableIRQ(NVMCTRL_IRQn);
80 NVIC_ClearPendingIRQ(NVMCTRL_IRQn);
81 NVIC_EnableIRQ(NVMCTRL_IRQn);
82 return ERR_NONE;
83 }
84
85 /**
86 * \brief De-initialize NVM
87 */
_flash_deinit(struct _flash_device * const device)88 void _flash_deinit(struct _flash_device *const device)
89 {
90 device->hw = NULL;
91 NVIC_DisableIRQ(NVMCTRL_IRQn);
92 }
93
94 /**
95 * \brief Get the flash page size.
96 */
_flash_get_page_size(struct _flash_device * const device)97 uint32_t _flash_get_page_size(struct _flash_device *const device)
98 {
99 (void)device;
100 return (uint32_t)NVMCTRL_PAGE_SIZE;
101 }
102
103 /**
104 * \brief Get the numbers of flash page.
105 */
_flash_get_total_pages(struct _flash_device * const device)106 uint32_t _flash_get_total_pages(struct _flash_device *const device)
107 {
108 (void)device;
109 return (uint32_t)FLASH_NB_OF_PAGES;
110 }
111
112 /**
113 * \brief Get the number of wait states for read and write operations.
114 */
_flash_get_wait_state(struct _flash_device * const device)115 uint8_t _flash_get_wait_state(struct _flash_device *const device)
116 {
117 return hri_nvmctrl_get_CTRLB_reg(device->hw, NVMCTRL_CTRLB_RWS_Msk);
118 }
119
120 /**
121 * \brief Set the number of wait states for read and write operations.
122 */
_flash_set_wait_state(struct _flash_device * const device,uint8_t state)123 void _flash_set_wait_state(struct _flash_device *const device, uint8_t state)
124 {
125 hri_nvmctrl_write_CTRLB_RWS_bf(device->hw, state);
126 }
127
128 /**
129 * \brief Reads a number of bytes to a page in the internal Flash.
130 */
_flash_read(struct _flash_device * const device,const uint32_t src_addr,uint8_t * buffer,uint32_t length)131 void _flash_read(struct _flash_device *const device, const uint32_t src_addr, uint8_t *buffer, uint32_t length)
132 {
133 uint32_t nvm_address = src_addr / 2;
134 uint32_t i;
135 uint16_t data;
136
137 /* Check if the module is busy */
138 while (!hri_nvmctrl_get_interrupt_READY_bit(device->hw)) {
139 /* Wait until this module isn't busy */
140 }
141
142 /* Clear flags */
143 hri_nvmctrl_clear_STATUS_reg(device->hw, NVMCTRL_STATUS_MASK);
144
145 /* Check whether byte address is word-aligned*/
146 if (src_addr % 2) {
147 data = NVM_MEMORY[nvm_address++];
148 buffer[0] = data >> 8;
149 i = 1;
150 } else {
151 i = 0;
152 }
153
154 /* NVM _must_ be accessed as a series of 16-bit words, perform manual copy
155 * to ensure alignment */
156 while (i < length) {
157 data = NVM_MEMORY[nvm_address++];
158 buffer[i] = (data & 0xFF);
159 if (i < (length - 1)) {
160 buffer[i + 1] = (data >> 8);
161 }
162 i += 2;
163 }
164 }
165
166 /**
167 * \brief Writes a number of bytes to a page in the internal Flash.
168 */
_flash_write(struct _flash_device * const device,const uint32_t dst_addr,uint8_t * buffer,uint32_t length)169 void _flash_write(struct _flash_device *const device, const uint32_t dst_addr, uint8_t *buffer, uint32_t length)
170 {
171 uint8_t tmp_buffer[NVMCTRL_ROW_PAGES][NVMCTRL_PAGE_SIZE];
172 uint32_t row_start_addr, row_end_addr;
173 uint32_t i, j, k;
174 uint32_t wr_start_addr = dst_addr;
175
176 do {
177 row_start_addr = wr_start_addr & ~((NVMCTRL_PAGE_SIZE * NVMCTRL_ROW_PAGES) - 1);
178 row_end_addr = row_start_addr + NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE - 1;
179
180 /* store the erase data into temp buffer before write */
181 for (i = 0; i < NVMCTRL_ROW_PAGES; i++) {
182 _flash_read(device, row_start_addr + i * NVMCTRL_PAGE_SIZE, tmp_buffer[i], NVMCTRL_PAGE_SIZE);
183 }
184
185 /* temp buffer update */
186 j = (wr_start_addr - row_start_addr) / NVMCTRL_PAGE_SIZE;
187 k = wr_start_addr - row_start_addr - j * NVMCTRL_PAGE_SIZE;
188 while ((wr_start_addr <= row_end_addr) && (length > 0)) {
189 tmp_buffer[j][k] = *buffer;
190 k = (k + 1) % NVMCTRL_PAGE_SIZE;
191 if (0 == k) {
192 j++;
193 }
194 wr_start_addr++;
195 buffer++;
196 length--;
197 }
198
199 /* erase row before write */
200 _flash_erase_row(device->hw, row_start_addr, NVMCTRL_CTRLA_CMD_ER);
201
202 /* write buffer to flash */
203 for (i = 0; i < NVMCTRL_ROW_PAGES; i++) {
204 _flash_program(device->hw,
205 row_start_addr + i * NVMCTRL_PAGE_SIZE,
206 tmp_buffer[i],
207 NVMCTRL_PAGE_SIZE,
208 NVMCTRL_CTRLA_CMD_WP);
209 }
210
211 } while (row_end_addr < (wr_start_addr + length - 1));
212 }
213
214 /**
215 * \brief Appends a number of bytes in the internal Flash.
216 */
_flash_append(struct _flash_device * const device,const uint32_t dst_addr,uint8_t * buffer,uint32_t length)217 void _flash_append(struct _flash_device *const device, const uint32_t dst_addr, uint8_t *buffer, uint32_t length)
218 {
219 uint32_t page_start_addr = dst_addr & ~(NVMCTRL_PAGE_SIZE - 1);
220 uint32_t size;
221 uint32_t offset = 0;
222
223 if (dst_addr != page_start_addr) {
224 /* Need to write some data to the end of a page */
225 size = min(length, NVMCTRL_PAGE_SIZE - (dst_addr - page_start_addr));
226 _flash_program(device->hw, dst_addr, buffer, size, NVMCTRL_CTRLA_CMD_WP);
227 page_start_addr += NVMCTRL_PAGE_SIZE;
228 offset += size;
229 }
230
231 while (offset < length) {
232 size = min(length - offset, NVMCTRL_PAGE_SIZE);
233 _flash_program(device->hw, page_start_addr, buffer + offset, size, NVMCTRL_CTRLA_CMD_WP);
234 page_start_addr += NVMCTRL_PAGE_SIZE;
235 offset += size;
236 }
237 }
238
239 /**
240 * \brief Execute erase in the internal flash
241 */
_flash_erase(struct _flash_device * const device,uint32_t dst_addr,uint32_t page_nums)242 void _flash_erase(struct _flash_device *const device, uint32_t dst_addr, uint32_t page_nums)
243 {
244 uint8_t tmp_buffer[NVMCTRL_PAGE_SIZE];
245 uint32_t row_start_addr;
246 uint32_t i;
247
248 row_start_addr = dst_addr & ~((NVMCTRL_PAGE_SIZE * NVMCTRL_ROW_PAGES) - 1);
249
250 memset(tmp_buffer, 0xFF, NVMCTRL_PAGE_SIZE);
251
252 /* when address is not aligned with row start address */
253 if (dst_addr != row_start_addr) {
254 row_start_addr += NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE;
255 for (i = 0; i < NVMCTRL_ROW_PAGES - 1; i++) {
256 _flash_write(device, dst_addr, tmp_buffer, NVMCTRL_PAGE_SIZE);
257 if (--page_nums == 0) {
258 return;
259 }
260 dst_addr += NVMCTRL_PAGE_SIZE;
261 if (dst_addr == row_start_addr) {
262 break;
263 }
264 }
265 }
266
267 while (page_nums >= NVMCTRL_ROW_PAGES) {
268 _flash_erase_row(device->hw, row_start_addr, NVMCTRL_CTRLA_CMD_ER);
269 row_start_addr += NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE;
270 page_nums -= NVMCTRL_ROW_PAGES;
271 }
272
273 if (page_nums != 0) {
274 for (i = 0; i < page_nums; i++) {
275 _flash_write(device, row_start_addr, tmp_buffer, NVMCTRL_PAGE_SIZE);
276 row_start_addr += NVMCTRL_PAGE_SIZE;
277 }
278 }
279 }
280
281 /**
282 * \brief Execute lock in the internal flash
283 */
_flash_lock(struct _flash_device * const device,const uint32_t dst_addr,uint32_t page_nums)284 int32_t _flash_lock(struct _flash_device *const device, const uint32_t dst_addr, uint32_t page_nums)
285 {
286 uint32_t region_pages;
287 uint32_t row_start_addr;
288
289 region_pages = (uint32_t)NVMCTRL_FLASH_SIZE / (16 * NVMCTRL_PAGE_SIZE);
290 row_start_addr = dst_addr & ~((NVMCTRL_PAGE_SIZE * NVMCTRL_ROW_PAGES) - 1);
291
292 if ((page_nums != region_pages) || (dst_addr != row_start_addr)) {
293 return ERR_INVALID_ARG;
294 }
295
296 while (!hri_nvmctrl_get_interrupt_READY_bit(device->hw)) {
297 /* Wait until this module isn't busy */
298 }
299
300 /* Clear flags */
301 hri_nvmctrl_clear_STATUS_reg(device->hw, NVMCTRL_STATUS_MASK);
302
303 hri_nvmctrl_write_ADDR_reg(device->hw, dst_addr / 2);
304 hri_nvmctrl_write_CTRLA_reg(device->hw, NVMCTRL_CTRLA_CMD_LR | NVMCTRL_CTRLA_CMDEX_KEY);
305
306 return (int32_t)NVMCTRL_FLASH_SIZE / (16 * NVMCTRL_PAGE_SIZE);
307 }
308
309 /**
310 * \brief Execute unlock in the internal flash
311 */
_flash_unlock(struct _flash_device * const device,const uint32_t dst_addr,uint32_t page_nums)312 int32_t _flash_unlock(struct _flash_device *const device, const uint32_t dst_addr, uint32_t page_nums)
313 {
314 uint32_t region_pages;
315 uint32_t row_start_addr;
316
317 region_pages = (uint32_t)NVMCTRL_FLASH_SIZE / (16 * NVMCTRL_PAGE_SIZE);
318 row_start_addr = dst_addr & ~((NVMCTRL_PAGE_SIZE * NVMCTRL_ROW_PAGES) - 1);
319
320 if ((page_nums != region_pages) || (dst_addr != row_start_addr)) {
321 return ERR_INVALID_ARG;
322 }
323
324 while (!hri_nvmctrl_get_interrupt_READY_bit(device->hw)) {
325 /* Wait until this module isn't busy */
326 }
327
328 /* Clear flags */
329 hri_nvmctrl_clear_STATUS_reg(device->hw, NVMCTRL_STATUS_MASK);
330
331 hri_nvmctrl_write_ADDR_reg(device->hw, dst_addr / 2);
332 hri_nvmctrl_write_CTRLA_reg(device->hw, NVMCTRL_CTRLA_CMD_UR | NVMCTRL_CTRLA_CMDEX_KEY);
333
334 return (int32_t)NVMCTRL_FLASH_SIZE / (16 * NVMCTRL_PAGE_SIZE);
335 }
336
337 /**
338 * \brief check whether the region which is pointed by address
339 */
_flash_is_locked(struct _flash_device * const device,const uint32_t dst_addr)340 bool _flash_is_locked(struct _flash_device *const device, const uint32_t dst_addr)
341 {
342 uint16_t region_id;
343
344 /* Get region for given page */
345 region_id = dst_addr / (NVMCTRL_FLASH_SIZE / 16);
346
347 return !(hri_nvmctrl_get_LOCK_reg(device->hw, 1 << region_id));
348 }
349
350 /**
351 * \brief Enable/disable Flash interrupt
352 */
_flash_set_irq_state(struct _flash_device * const device,const enum _flash_cb_type type,const bool state)353 void _flash_set_irq_state(struct _flash_device *const device, const enum _flash_cb_type type, const bool state)
354 {
355 ASSERT(device);
356
357 if (FLASH_DEVICE_CB_READY == type) {
358 hri_nvmctrl_write_INTEN_READY_bit(device->hw, state);
359 } else if (FLASH_DEVICE_CB_ERROR == type) {
360 hri_nvmctrl_write_INTEN_ERROR_bit(device->hw, state);
361 }
362 }
363
364 /**
365 * \internal erase a row in flash
366 * \param[in] hw The pointer to hardware instance
367 * \param[in] dst_addr Destination page address to erase
368 */
_flash_erase_row(void * const hw,const uint32_t dst_addr,uint32_t nvmctrl_cmd)369 static void _flash_erase_row(void *const hw, const uint32_t dst_addr, uint32_t nvmctrl_cmd)
370 {
371 while (!hri_nvmctrl_get_interrupt_READY_bit(hw)) {
372 /* Wait until this module isn't busy */
373 }
374
375 /* Clear flags */
376 hri_nvmctrl_clear_STATUS_reg(hw, NVMCTRL_STATUS_MASK);
377
378 /* Set address and command */
379 hri_nvmctrl_write_ADDR_reg(hw, dst_addr / 2);
380 hri_nvmctrl_write_CTRLA_reg(hw, nvmctrl_cmd | NVMCTRL_CTRLA_CMDEX_KEY);
381 }
382
383 /**
384 * \internal write a page in flash
385 * \param[in] hw The pointer to hardware instance
386 * \param[in] dst_addr Destination page address to write
387 * \param[in] buffer Pointer to buffer where the data to
388 * write is stored
389 * \param[in] size The size of data to write to a page
390 */
_flash_program(void * const hw,const uint32_t dst_addr,const uint8_t * buffer,const uint16_t size,uint32_t nvmctrl_cmd)391 static void _flash_program(void *const hw, const uint32_t dst_addr, const uint8_t *buffer, const uint16_t size,
392 uint32_t nvmctrl_cmd)
393 {
394 ASSERT(!(dst_addr % 2));
395
396 uint32_t nvm_address = dst_addr / 2;
397 uint16_t i, data;
398
399 while (!hri_nvmctrl_get_interrupt_READY_bit(hw)) {
400 /* Wait until this module isn't busy */
401 }
402
403 hri_nvmctrl_write_CTRLA_reg(hw, NVMCTRL_CTRLA_CMD_PBC | NVMCTRL_CTRLA_CMDEX_KEY);
404
405 while (!hri_nvmctrl_get_interrupt_READY_bit(hw)) {
406 /* Wait until this module isn't busy */
407 }
408
409 /* Clear flags */
410 hri_nvmctrl_clear_STATUS_reg(hw, NVMCTRL_STATUS_MASK);
411
412 for (i = 0; i < size; i += 2) {
413 data = buffer[i];
414 if (i < NVMCTRL_PAGE_SIZE - 1) {
415 data |= (buffer[i + 1] << 8);
416 }
417 NVM_MEMORY[nvm_address++] = data;
418 }
419
420 while (!hri_nvmctrl_get_interrupt_READY_bit(hw)) {
421 /* Wait until this module isn't busy */
422 }
423
424 hri_nvmctrl_write_ADDR_reg(hw, dst_addr / 2);
425 hri_nvmctrl_write_CTRLA_reg(hw, nvmctrl_cmd | NVMCTRL_CTRLA_CMDEX_KEY);
426 }
427
428 /**
429 * \internal NVM interrupt handler
430 */
NVMCTRL_Handler(void)431 void NVMCTRL_Handler(void)
432 {
433 void *const hw = _nvm_dev->hw;
434
435 if (hri_nvmctrl_get_interrupt_READY_bit(hw)) {
436 if (NULL != _nvm_dev->flash_cb.ready_cb) {
437 _nvm_dev->flash_cb.ready_cb(_nvm_dev);
438 }
439 } else if (hri_nvmctrl_get_interrupt_ERROR_bit(hw)) {
440 hri_nvmctrl_clear_interrupt_ERROR_bit(hw);
441 if (NULL != _nvm_dev->flash_cb.error_cb) {
442 _nvm_dev->flash_cb.error_cb(_nvm_dev);
443 }
444 }
445 }
446
447 /*
448 The NVM User Row contains calibration data that are automatically read at device
449 power on.
450 The NVM User Row can be read at address 0x804000.
451 */
452 #ifndef _NVM_USER_ROW_BASE
453 #define _NVM_USER_ROW_BASE 0x804000
454 #endif
455 #define _NVM_USER_ROW_N_BITS 64
456 #define _NVM_USER_ROW_N_BYTES (_NVM_USER_ROW_N_BITS / 8)
457 #define _NVM_USER_ROW_END (((uint8_t *)_NVM_USER_ROW_BASE) + _NVM_USER_ROW_N_BYTES - 1)
458 #define _IS_NVM_USER_ROW(b) \
459 (((uint8_t *)(b) >= (uint8_t *)(_NVM_USER_ROW_BASE)) && ((uint8_t *)(b) <= (uint8_t *)(_NVM_USER_ROW_END)))
460 #define _IN_NVM_USER_ROW(b, o) (((uint8_t *)(b) + (o)) <= (uint8_t *)(_NVM_USER_ROW_END))
461
462 /*
463 The NVM Software Calibration Area can be read at address 0x806020.
464 The NVM Software Calibration Area can not be written.
465 */
466 #ifndef _NVM_SW_CALIB_AREA_BASE
467 #define _NVM_SW_CALIB_AREA_BASE 0x806020
468 #endif
469 #define _NVM_SW_CALIB_AREA_N_BITS 128
470 #define _NVM_SW_CALIB_AREA_N_BYTES (_NVM_SW_CALIB_AREA_N_BITS / 8)
471 #define _NVM_SW_CALIB_AREA_END (((uint8_t *)_NVM_SW_CALIB_AREA_BASE) + _NVM_SW_CALIB_AREA_N_BYTES - 1)
472 #define _IS_NVM_SW_CALIB_AREA(b) \
473 (((uint8_t *)(b) >= (uint8_t *)_NVM_SW_CALIB_AREA_BASE) && ((uint8_t *)(b) <= (uint8_t *)_NVM_SW_CALIB_AREA_END))
474 #define _IN_NVM_SW_CALIB_AREA(b, o) (((uint8_t *)(b) + (o)) <= (uint8_t *)(_NVM_SW_CALIB_AREA_END))
475
476 /**
477 * \internal Read left aligned data bits
478 * \param[in] base Base address for the data
479 * \param[in] bit_offset Offset for the bitfield start
480 * \param[in] n_bits Number of bits in the bitfield
481 */
_user_area_read_l32_bits(const volatile uint32_t * base,const uint32_t bit_offset,const uint8_t n_bits)482 static inline uint32_t _user_area_read_l32_bits(const volatile uint32_t *base, const uint32_t bit_offset,
483 const uint8_t n_bits)
484 {
485 return base[bit_offset >> 5] & ((1 << n_bits) - 1);
486 }
487
488 /**
489 * \internal Read right aligned data bits
490 * \param[in] base Base address for the data
491 * \param[in] bit_offset Offset for the bitfield start
492 * \param[in] n_bits Number of bits in the bitfield
493 */
_user_area_read_r32_bits(const volatile uint32_t * base,const uint32_t bit_offset,const uint8_t n_bits)494 static inline uint32_t _user_area_read_r32_bits(const volatile uint32_t *base, const uint32_t bit_offset,
495 const uint8_t n_bits)
496 {
497 return (base[bit_offset >> 5] >> (bit_offset & 0x1F)) & ((1 << n_bits) - 1);
498 }
499
_user_area_read(const void * base,const uint32_t offset,uint8_t * buf,uint32_t size)500 int32_t _user_area_read(const void *base, const uint32_t offset, uint8_t *buf, uint32_t size)
501 {
502 ASSERT(buf);
503
504 /** Parameter check. */
505 if (_IS_NVM_USER_ROW(base)) {
506 if (!_IN_NVM_USER_ROW(base, offset)) {
507 return ERR_BAD_ADDRESS;
508 }
509 /* Cut off if request too many bytes */
510 if (!_IN_NVM_USER_ROW(base, offset + size - 1)) {
511 return ERR_INVALID_ARG;
512 }
513 } else if (_IS_NVM_SW_CALIB_AREA(base)) {
514 if (!_IN_NVM_SW_CALIB_AREA(base, offset)) {
515 return ERR_BAD_ADDRESS;
516 }
517 /* Cut off if request too many bytes */
518 if (!_IN_NVM_SW_CALIB_AREA(base, offset + size - 1)) {
519 return ERR_INVALID_ARG;
520 }
521 } else {
522 return ERR_UNSUPPORTED_OP;
523 }
524
525 /* Copy data */
526 memcpy(buf, ((uint8_t *)base) + offset, size);
527 return ERR_NONE;
528 }
529
_user_area_read_bits(const void * base,const uint32_t bit_offset,const uint8_t n_bits)530 uint32_t _user_area_read_bits(const void *base, const uint32_t bit_offset, const uint8_t n_bits)
531 {
532 volatile uint32_t *mem_base = (volatile uint32_t *)base;
533 uint32_t l_off, l_bits;
534 uint32_t r_off, r_bits;
535
536 /** Parameter check. */
537 if (_IS_NVM_USER_ROW(base)) {
538 ASSERT(_IN_NVM_USER_ROW(base, bit_offset >> 3) && _IN_NVM_USER_ROW(base, (bit_offset + n_bits - 1) >> 3));
539 } else if (_IS_NVM_SW_CALIB_AREA(base)) {
540 ASSERT(_IN_NVM_SW_CALIB_AREA(base, bit_offset >> 3)
541 && _IN_NVM_SW_CALIB_AREA(base, (bit_offset + n_bits - 1) >> 3));
542 } else {
543 ASSERT(false);
544 }
545
546 /* Since the bitfield can cross 32-bits boundaries,
547 * left and right bits are read from 32-bit aligned address
548 * and then combined together. */
549 l_off = bit_offset & (~(32 - 1));
550 r_off = l_off + 32;
551 l_bits = 32 - (bit_offset & (32 - 1));
552 if (n_bits > l_bits) {
553 r_bits = n_bits - l_bits;
554 } else {
555 l_bits = n_bits;
556 r_bits = 0;
557 }
558 return _user_area_read_r32_bits(mem_base, bit_offset, l_bits)
559 + (_user_area_read_l32_bits(mem_base, r_off, r_bits) << l_bits);
560 }
561
562 /** \internal Write 64-bit user row
563 * \param[in] _row Pointer to 64-bit user row data.
564 */
_user_row_write_exec(const uint32_t * _row)565 static int32_t _user_row_write_exec(const uint32_t *_row)
566 {
567 Nvmctrl *hw = NVMCTRL;
568 uint32_t ctrlb = hri_nvmctrl_read_CTRLB_reg(NVMCTRL);
569
570 /* Denie if Security Bit is set */
571 if (hri_nvmctrl_get_STATUS_reg(hw, NVMCTRL_STATUS_SB)) {
572 return ERR_DENIED;
573 }
574
575 /* Do Save */
576
577 /* - Prepare. */
578 while (!hri_nvmctrl_get_INTFLAG_reg(hw, NVMCTRL_INTFLAG_READY)) {
579 /* Wait until this module isn't busy */
580 }
581 hri_nvmctrl_clear_STATUS_reg(hw, NVMCTRL_STATUS_MASK);
582 hri_nvmctrl_set_CTRLB_MANW_bit(hw);
583
584 /* - Erase AUX row. */
585 hri_nvmctrl_write_ADDR_reg(hw, (hri_nvmctrl_addr_reg_t)(_NVM_USER_ROW_BASE / 2));
586 hri_nvmctrl_write_CTRLA_reg(hw, NVMCTRL_CTRLA_CMD_EAR | NVMCTRL_CTRLA_CMDEX_KEY);
587 while (!hri_nvmctrl_get_INTFLAG_reg(hw, NVMCTRL_INTFLAG_READY)) {
588 /* Wait until this module isn't busy */
589 }
590
591 /* - Page buffer clear & write. */
592 hri_nvmctrl_write_CTRLA_reg(hw, NVMCTRL_CTRLA_CMD_PBC | NVMCTRL_CTRLA_CMDEX_KEY);
593 while (!hri_nvmctrl_get_INTFLAG_reg(hw, NVMCTRL_INTFLAG_READY)) {
594 /* Wait until this module isn't busy */
595 }
596 *((uint32_t *)NVMCTRL_AUX0_ADDRESS) = _row[0];
597 *(((uint32_t *)NVMCTRL_AUX0_ADDRESS) + 1) = _row[1];
598
599 /* - Write AUX row. */
600 hri_nvmctrl_write_ADDR_reg(hw, (hri_nvmctrl_addr_reg_t)(_NVM_USER_ROW_BASE / 2));
601 hri_nvmctrl_write_CTRLA_reg(hw, NVMCTRL_CTRLA_CMD_WAP | NVMCTRL_CTRLA_CMDEX_KEY);
602 while (!hri_nvmctrl_get_INTFLAG_reg(hw, NVMCTRL_INTFLAG_READY)) {
603 /* Wait until this module isn't busy */
604 }
605
606 /* Restore CTRLB */
607 hri_nvmctrl_write_CTRLB_reg(NVMCTRL, ctrlb);
608
609 return ERR_NONE;
610 }
611
_user_area_write(void * base,const uint32_t offset,const uint8_t * buf,const uint32_t size)612 int32_t _user_area_write(void *base, const uint32_t offset, const uint8_t *buf, const uint32_t size)
613 {
614 uint32_t _row[2]; /* Copy of user row. */
615
616 /** Parameter check. */
617 if (_IS_NVM_USER_ROW(base)) {
618 if (!_IN_NVM_USER_ROW(base, offset)) {
619 return ERR_BAD_ADDRESS;
620 } else if (!_IN_NVM_USER_ROW(base, offset + size - 1)) {
621 return ERR_INVALID_ARG;
622 }
623 } else if (_IS_NVM_SW_CALIB_AREA(base)) {
624 return ERR_DENIED;
625 } else {
626 return ERR_UNSUPPORTED_OP;
627 }
628
629 memcpy(_row, base, 8); /* Store previous data. */
630 memcpy((uint8_t *)_row + offset, buf, size); /* Modify with buf data. */
631
632 return _user_row_write_exec(_row);
633 }
634
_user_area_write_bits(void * base,const uint32_t bit_offset,const uint32_t bits,const uint8_t n_bits)635 int32_t _user_area_write_bits(void *base, const uint32_t bit_offset, const uint32_t bits, const uint8_t n_bits)
636 {
637 uint32_t _row[2]; /* Copy of user row. */
638 uint32_t l_off, l_bits;
639 uint32_t r_off, r_bits;
640
641 /** Parameter check. */
642 if (_IS_NVM_USER_ROW(base)) {
643 if (!_IN_NVM_USER_ROW(base, bit_offset >> 3)) {
644 return ERR_BAD_ADDRESS;
645 } else if (!_IN_NVM_USER_ROW(base, (bit_offset + n_bits - 1) >> 3)) {
646 return ERR_INVALID_ARG;
647 }
648 } else if (_IS_NVM_SW_CALIB_AREA(base)) {
649 return ERR_DENIED;
650 } else {
651 return ERR_UNSUPPORTED_OP;
652 }
653
654 /* Since the bitfield can cross 32-bits boundaries,
655 * left and right bits are splitted for 32-bit aligned address
656 * and then saved. */
657 l_off = bit_offset & (~(32 - 1));
658 r_off = l_off + 32;
659 l_bits = 32 - (bit_offset & (32 - 1));
660 if (n_bits > l_bits) {
661 r_bits = n_bits - l_bits;
662 } else {
663 l_bits = n_bits;
664 r_bits = 0;
665 }
666
667 memcpy(_row, base, 8); /* Store previous data. */
668 if (l_bits) {
669 uint32_t l_mask = ((1 << l_bits) - 1) << (bit_offset & (32 - 1));
670 _row[bit_offset >> 5] &= ~l_mask;
671 _row[bit_offset >> 5] |= (bits << (bit_offset & (32 - 1))) & l_mask;
672 }
673 if (r_bits) {
674 uint32_t r_mask = (1 << r_bits) - 1;
675 _row[r_off >> 5] &= ~r_mask;
676 _row[r_off >> 5] |= bits >> l_bits;
677 }
678 return _user_row_write_exec(_row);
679 }
680
681 /**
682 * \brief Return if given address is in Flash RWWEE array range.
683 */
_is_valid_rww_flash_address(uint32_t addr)684 static bool _is_valid_rww_flash_address(uint32_t addr)
685 {
686 #define RWWEE_ADDR_START NVMCTRL_RWW_EEPROM_ADDR
687 #define RWWEE_ADDR_END (NVMCTRL_RWW_EEPROM_ADDR + NVMCTRL_PAGE_SIZE * NVMCTRL_RWWEE_PAGES)
688
689 if ((addr < NVMCTRL_RWW_EEPROM_ADDR)
690 || (addr > (NVMCTRL_RWW_EEPROM_ADDR + NVMCTRL_PAGE_SIZE * NVMCTRL_RWWEE_PAGES))) {
691 return false;
692 }
693 return true;
694 }
695
696 /**
697 * \brief Get the RWWEE flash page size.
698 */
_rww_flash_get_page_size(struct _flash_device * const device)699 uint32_t _rww_flash_get_page_size(struct _flash_device *const device)
700 {
701 (void)device;
702 return (uint32_t)NVMCTRL_PAGE_SIZE;
703 }
704
705 /**
706 * \brief Get the total page numbers of RWWEE flash.
707 */
_rww_flash_get_total_pages(struct _flash_device * const device)708 uint32_t _rww_flash_get_total_pages(struct _flash_device *const device)
709 {
710 (void)device;
711 return (uint32_t)NVMCTRL_RWWEE_PAGES;
712 }
713
714 /**
715 * \brief Reads a number of bytes in the internal RWWEE Flash.
716 */
_rww_flash_read(struct _flash_device * const device,const uint32_t src_addr,uint8_t * buffer,uint32_t length)717 int32_t _rww_flash_read(struct _flash_device *const device, const uint32_t src_addr, uint8_t *buffer, uint32_t length)
718 {
719 /* Check if the address is valid */
720 if (!_is_valid_rww_flash_address(src_addr) || !_is_valid_rww_flash_address(src_addr + length)) {
721 return ERR_BAD_ADDRESS;
722 }
723
724 _flash_read(device, src_addr, buffer, length);
725
726 return ERR_NONE;
727 }
728
729 /**
730 * \brief Writes a number of bytes in the internal RWWEE Flash.
731 */
_rww_flash_write(struct _flash_device * const device,const uint32_t dst_addr,uint8_t * buffer,uint32_t length)732 int32_t _rww_flash_write(struct _flash_device *const device, const uint32_t dst_addr, uint8_t *buffer, uint32_t length)
733 {
734 uint8_t tmp_buffer[NVMCTRL_ROW_PAGES][NVMCTRL_PAGE_SIZE];
735 uint32_t row_start_addr, row_end_addr;
736 uint32_t i, j, k;
737 uint32_t wr_start_addr = dst_addr;
738
739 /* Check if the address is valid */
740 if (!_is_valid_rww_flash_address(dst_addr) || !_is_valid_rww_flash_address(dst_addr + length)) {
741 return ERR_BAD_ADDRESS;
742 }
743
744 do {
745 row_start_addr = wr_start_addr & ~((NVMCTRL_PAGE_SIZE * NVMCTRL_ROW_PAGES) - 1);
746 row_end_addr = row_start_addr + NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE - 1;
747
748 /* store the erase data into temp buffer before write */
749 for (i = 0; i < NVMCTRL_ROW_PAGES; i++) {
750 _rww_flash_read(device, row_start_addr + i * NVMCTRL_PAGE_SIZE, tmp_buffer[i], NVMCTRL_PAGE_SIZE);
751 }
752
753 /* temp buffer update */
754 j = (wr_start_addr - row_start_addr) / NVMCTRL_PAGE_SIZE;
755 k = wr_start_addr - row_start_addr - j * NVMCTRL_PAGE_SIZE;
756 while ((wr_start_addr <= row_end_addr) && (length > 0)) {
757 tmp_buffer[j][k] = *buffer;
758 k = (k + 1) % NVMCTRL_PAGE_SIZE;
759 if (0 == k) {
760 j++;
761 }
762 wr_start_addr++;
763 buffer++;
764 length--;
765 }
766
767 /* erase row before write */
768 _flash_erase_row(device->hw, row_start_addr, NVMCTRL_CTRLA_CMD_RWWEEER);
769
770 /* write buffer to flash */
771 for (i = 0; i < NVMCTRL_ROW_PAGES; i++) {
772 _flash_program(device->hw,
773 row_start_addr + i * NVMCTRL_PAGE_SIZE,
774 tmp_buffer[i],
775 NVMCTRL_PAGE_SIZE,
776 NVMCTRL_CTRLA_CMD_RWWEEWP);
777 }
778
779 } while (row_end_addr < (wr_start_addr + length - 1));
780
781 return ERR_NONE;
782 }
783