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