1 /**
2  * \file
3  *
4  * \brief Non volatile memories management for SAM devices
5  *
6  * Copyright (c) 2012-2015 Atmel Corporation. All rights reserved.
7  *
8  * \asf_license_start
9  *
10  * \page License
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * 3. The name of Atmel may not be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * 4. This software may only be redistributed and used in connection with an
26  *    Atmel microcontroller product.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * \asf_license_stop
41  *
42  */
43 /*
44  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45  */
46 #include "common_nvm.h"
47 #include "conf_board.h"
48 #include "flash_efc.h"
49 #include "string.h"
50 
nvm_init(mem_type_t mem)51 status_code_t nvm_init(mem_type_t mem)
52 {
53 	switch (mem) {
54 	case INT_FLASH:
55 #if SAM4S
56 	case INT_USERPAGE:
57 #endif
58 		break;
59 
60 #if defined(USE_EXTMEM) && defined(CONF_BOARD_AT45DBX)
61 	case AT45DBX:
62 		/* Initialize dataflash */
63 		at45dbx_init();
64 		/* Perform memory check */
65 		if (!at45dbx_mem_check()) {
66 			return ERR_NO_MEMORY;
67 		}
68 		break;
69 #endif
70 
71 	default:
72 		return ERR_INVALID_ARG;
73 	}
74 
75 	return STATUS_OK;
76 }
77 
nvm_read_char(mem_type_t mem,uint32_t address,uint8_t * data)78 status_code_t nvm_read_char(mem_type_t mem, uint32_t address, uint8_t *data)
79 {
80 	switch (mem) {
81 	case INT_FLASH:
82 		*data = *((uint8_t *)(address));
83 		break;
84 
85 #if SAM4S
86 	case INT_USERPAGE:
87 	{
88 		/*! This function creates a buffer of IFLASH_PAGE_SIZE to
89 		 * read the data from starting of user signature */
90 		uint32_t buffer[IFLASH_PAGE_SIZE];
91 		uint32_t offset = address - IFLASH_ADDR;
92 		if (offset < 0) {
93 			return ERR_INVALID_ARG;
94 		}
95 
96 		flash_read_user_signature(buffer, offset);
97 		*data = buffer[offset];
98 		break;
99 	}
100 #endif
101 
102 #if defined(USE_EXTMEM) && defined(CONF_BOARD_AT45DBX)
103 	case AT45DBX:
104 		if (!at45dbx_read_byte_open(address)) {
105 			return ERR_BAD_ADDRESS;
106 		}
107 
108 		*data = at45dbx_read_byte();
109 		at45dbx_read_close();
110 		break;
111 #endif
112 
113 	default:
114 		return ERR_INVALID_ARG;
115 	}
116 
117 	return STATUS_OK;
118 }
119 
nvm_write_char(mem_type_t mem,uint32_t address,uint8_t data)120 status_code_t nvm_write_char(mem_type_t mem, uint32_t address, uint8_t data)
121 {
122 	switch (mem) {
123 	case INT_FLASH:
124 #if SAM4S
125 
126 		if (flash_write(address, (const void *)&data, 1,
127 				false)) {
128 			return ERR_INVALID_ARG;
129 		}
130 
131 #else
132 		if (flash_write(address, (const void *)&data, 1, true)) {
133 			return ERR_INVALID_ARG;
134 		}
135 
136 #endif
137 		break;
138 
139 #if SAM4S
140 	case INT_USERPAGE:
141 		if (flash_write_user_signature((const void *)&data,	1)) {
142 			return ERR_INVALID_ARG;
143 		}
144 		break;
145 #endif
146 
147 #if defined(USE_EXTMEM) && defined(CONF_BOARD_AT45DBX)
148 	case AT45DBX:
149 		if (!at45dbx_write_byte_open(address)) {
150 			return ERR_BAD_ADDRESS;
151 		}
152 
153 		at45dbx_write_byte(data);
154 		at45dbx_write_close();
155 		break;
156 #endif
157 
158 	default:
159 		return ERR_INVALID_ARG;
160 	}
161 
162 	return STATUS_OK;
163 }
164 
nvm_read(mem_type_t mem,uint32_t address,void * buffer,uint32_t len)165 status_code_t nvm_read(mem_type_t mem, uint32_t address, void *buffer,
166 		uint32_t len)
167 {
168 	switch (mem) {
169 	case INT_FLASH:
170 		memcpy(buffer, (const void *)address, len);
171 		break;
172 
173 #if SAM4S
174 	case INT_USERPAGE:
175 	{
176 		/*! This function creates a buffer of IFLASH_PAGE_SIZE to
177 		 * read the data from starting of user signature */
178 		uint32_t temp_buff[IFLASH_PAGE_SIZE], *buff = buffer;
179 
180 		/* Read from the starting of user signature */
181 		if (flash_read_user_signature(temp_buff, len)) {
182 			return ERR_INVALID_ARG;
183 		}
184 
185 		/* Calculate offset and copy required number of bytes */
186 		for (uint16_t i = 0; i < len; i++) {
187 			*buff = temp_buff[address - IFLASH_ADDR + i];
188 			buff++;
189 		}
190 		break;
191 	}
192 #endif
193 
194 #if defined(USE_EXTMEM) && defined(CONF_BOARD_AT45DBX)
195 	case AT45DBX:
196 	{
197 		if (len == AT45DBX_SECTOR_SIZE) {
198 			uint32_t sector = address / AT45DBX_SECTOR_SIZE;
199 			if (!at45dbx_read_sector_open(sector)) {
200 				return ERR_BAD_ADDRESS;
201 			}
202 
203 			at45dbx_read_sector_to_ram(buffer);
204 			at45dbx_read_close();
205 		} else {
206 			if (!at45dbx_read_byte_open(address)) {
207 				return ERR_BAD_ADDRESS;
208 			}
209 			uint8_t *buf = (uint8_t *)buffer;
210 			while (len--) {
211 				*buf++ = at45dbx_read_byte();
212 			}
213 			at45dbx_read_close();
214 		}
215 
216 	}
217 	break;
218 #endif
219 
220 	default:
221 		return ERR_INVALID_ARG;
222 	}
223 
224 	return STATUS_OK;
225 }
226 
nvm_write(mem_type_t mem,uint32_t address,void * buffer,uint32_t len)227 status_code_t nvm_write(mem_type_t mem, uint32_t address, void *buffer,
228 		uint32_t len)
229 {
230 	switch (mem) {
231 	case INT_FLASH:
232 #if SAM4S
233 
234 		if (flash_write(address, (const void *)buffer, len, false)) {
235 			return ERR_INVALID_ARG;
236 		}
237 
238 #else
239 		if (flash_write(address, (const void *)buffer, len, true)) {
240 			return ERR_INVALID_ARG;
241 		}
242 
243 #endif
244 		break;
245 
246 #if SAM4S
247 	case INT_USERPAGE:
248 		if (flash_write_user_signature((const void *)buffer, len)) {
249 			return ERR_INVALID_ARG;
250 		}
251 		break;
252 #endif
253 
254 #if defined(USE_EXTMEM) && defined(CONF_BOARD_AT45DBX)
255 	case AT45DBX:
256 	{
257 		if (len == AT45DBX_SECTOR_SIZE) {
258 			uint32_t sector = address / AT45DBX_SECTOR_SIZE;
259 			if (!at45dbx_write_sector_open(sector)) {
260 				return ERR_BAD_ADDRESS;
261 			}
262 
263 			at45dbx_write_sector_from_ram((const void *)buffer);
264 			at45dbx_write_close();
265 		} else {
266 			if (!at45dbx_write_byte_open(address)) {
267 				return ERR_BAD_ADDRESS;
268 			}
269 			uint8_t *buf = (uint8_t *)buffer;
270 			while (len--) {
271 				at45dbx_write_byte(*buf++);
272 			}
273 			at45dbx_write_close();
274 		}
275 	}
276 	break;
277 #endif
278 
279 	default:
280 		return ERR_INVALID_ARG;
281 	}
282 
283 	return STATUS_OK;
284 }
285 
nvm_page_erase(mem_type_t mem,uint32_t page_number)286 status_code_t nvm_page_erase(mem_type_t mem, uint32_t page_number)
287 {
288 	switch (mem) {
289 	case INT_FLASH:
290 	{
291 #if SAM4S
292 		/*! Page erase function erases minimum 8 pages in Flash */
293 		if (flash_erase_page((uint32_t)(page_number * IFLASH_PAGE_SIZE),
294 				IFLASH_ERASE_PAGES_8)) {
295 			return ERR_INVALID_ARG;
296 		}
297 
298 #else
299 		uint32_t buffer[IFLASH_PAGE_SIZE], byte_address;
300 		for (uint16_t i = 0; i < IFLASH_PAGE_SIZE; i++) {
301 			buffer[i] = 0xFFFFFFFF;
302 		}
303 		byte_address = page_number * IFLASH_PAGE_SIZE;
304 
305 		/* Erase and write FFs to a page as there is no function for
306 		 * erase */
307 		if (!flash_write(byte_address, (const void *)buffer,
308 				IFLASH_PAGE_SIZE, true)) {
309 			return ERR_INVALID_ARG;
310 		}
311 
312 #endif
313 		break;
314 	}
315 
316 #if SAM4S
317 	case INT_USERPAGE:
318 		flash_erase_user_signature();
319 		break;
320 #endif
321 
322 	default:
323 		return ERR_INVALID_ARG;
324 	}
325 
326 	return STATUS_OK;
327 }
328 
nvm_get_size(mem_type_t mem,uint32_t * size)329 status_code_t nvm_get_size(mem_type_t mem, uint32_t *size)
330 {
331 	switch (mem) {
332 	case INT_FLASH:
333 		*size = (uint32_t)IFLASH_SIZE;
334 		break;
335 
336 #if SAM4S
337 	case INT_USERPAGE:
338 		*size = (uint32_t)IFLASH_PAGE_SIZE;
339 		break;
340 #endif
341 
342 #if defined(USE_EXTMEM) && defined(CONF_BOARD_AT45DBX)
343 	case AT45DBX:
344 		*size = (uint32_t)AT45DBX_MEM_SIZE;
345 		break;
346 #endif
347 
348 	default:
349 		return ERR_INVALID_ARG;
350 	}
351 
352 	return STATUS_OK;
353 }
354 
nvm_get_page_size(mem_type_t mem,uint32_t * size)355 status_code_t nvm_get_page_size(mem_type_t mem, uint32_t *size)
356 {
357 	switch (mem) {
358 	case INT_FLASH:
359 #if SAM4S
360 	case INT_USERPAGE:
361 #endif
362 		*size = (uint32_t)IFLASH_PAGE_SIZE;
363 		break;
364 
365 	default:
366 		return ERR_INVALID_ARG;
367 	}
368 
369 	return STATUS_OK;
370 }
371 
nvm_get_pagenumber(mem_type_t mem,uint32_t address,uint32_t * num)372 status_code_t nvm_get_pagenumber(mem_type_t mem, uint32_t address,
373 		uint32_t *num)
374 {
375 	switch (mem) {
376 	case INT_FLASH:
377 		*num = (uint32_t)(address / IFLASH_PAGE_SIZE);
378 		break;
379 
380 	default:
381 		return ERR_INVALID_ARG;
382 	}
383 
384 	return STATUS_OK;
385 }
386 
nvm_set_security_bit(void)387 status_code_t nvm_set_security_bit(void)
388 {
389 	if (!flash_enable_security_bit()) {
390 		return ERR_INVALID_ARG;
391 	}
392 
393 	return STATUS_OK;
394 }
395