1 /**
2 * \file
3 *
4 * \brief XMEGA PDI NVM command driver
5 *
6 * Copyright (C) 2009 Atmel Corporation. All rights reserved.
7 *
8 * \page License
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 *
20 * 3. The name of Atmel may not be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * 4. This software may only be redistributed and used in connection with an
24 * Atmel AVR product.
25 *
26 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
29 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
30 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
36 * DAMAGE.
37 */
38
39 /* Adaptation to xc3sprog
40 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de 2011
41 */
42 #include <string.h>
43
44 #include "progalgnvm.h"
45 #include "atxmega128a1_nvm_regs.h"
46
ProgAlgNVM(PDIoverJTAG * protocoll)47 ProgAlgNVM::ProgAlgNVM(PDIoverJTAG *protocoll)
48 {
49 prot = protocoll;
50 initialized = 0;
51 }
52
~ProgAlgNVM(void)53 ProgAlgNVM::~ProgAlgNVM(void)
54 {
55 prot = 0;
56 initialized = 0;
57 }
58
59 /**
60 * \brief Initiliazation function for the PDI interface
61 *
62 * This function initializes the PDI interface agains
63 * the connected target device.
64 *
65 * \retval STATUS_OK init ok
66 * \retval ERR_TIMEOUT the init timed out
67 */
xnvm_init(void)68 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_init(void)
69 {
70 PDI_STATUS_CODE retval;
71 if(initialized == 0){
72
73 /* Put the device in reset mode */
74 xnvm_put_dev_in_reset();
75
76 /* Create the key command */
77 cmd_buffer[0] = XNVM_PDI_KEY_INSTR;
78 cmd_buffer[1] = NVM_KEY_BYTE0;
79 cmd_buffer[2] = NVM_KEY_BYTE1;
80 cmd_buffer[3] = NVM_KEY_BYTE2;
81 cmd_buffer[4] = NVM_KEY_BYTE3;
82 cmd_buffer[5] = NVM_KEY_BYTE4;
83 cmd_buffer[6] = NVM_KEY_BYTE5;
84 cmd_buffer[7] = NVM_KEY_BYTE6;
85 cmd_buffer[8] = NVM_KEY_BYTE7;
86
87 prot->pdi_write(cmd_buffer, 9);
88
89 retval = xnvm_ctrl_wait_nvmbusy(WAIT_RETRIES_NUM);
90
91 initialized = 1;
92 }
93
94 return retval;
95 }
96
97 /**
98 * \brief Function for putting the device into reset
99 *
100 * \retval STATUS_OK if all went well
101 * \retval ERR_IO_ERROR if the pdi write failed
102 */
xnvm_put_dev_in_reset(void)103 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_put_dev_in_reset (void)
104 {
105 /* Reset the device */
106 cmd_buffer[0] = XNVM_PDI_STCS_INSTR | XOCD_RESET_REGISTER_ADDRESS;
107 cmd_buffer[1] = XOCD_RESET_SIGNATURE;
108 if(prot->pdi_write(cmd_buffer, 2)){
109 return ERR_IO_ERROR;
110 }
111 return STATUS_OK;
112 }
113
114 /**
115 * \brief Function for releasing the reset of the device
116 *
117 * \retval STATUS_OK if all went well
118 * \retval ERR_IO_ERROR if the pdi write failed
119 */
xnvm_pull_dev_out_of_reset(void)120 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_pull_dev_out_of_reset (void)
121 {
122
123 /* Pull device out of reset */
124 cmd_buffer[0] = XNVM_PDI_STCS_INSTR | XOCD_RESET_REGISTER_ADDRESS;
125 cmd_buffer[1] = 0;
126 if(prot->pdi_write(cmd_buffer, 2)){
127 return ERR_IO_ERROR;
128 }
129 return STATUS_OK;
130 }
131
132 /**
133 * \internal
134 * \brief Wait until the NVM module has completed initialization
135 *
136 * \param retries the retry count.
137 * \retval STATUS_OK the NVMEN was set successfully.
138 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
139 * \retval ERR_TIMEOUT Time out.
140 */
xnvm_wait_for_nvmen(uint32_t retries)141 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_wait_for_nvmen(uint32_t retries)
142 {
143 uint8_t pdi_status;
144
145 while (retries != 0) {
146 if (xnvm_read_pdi_status(&pdi_status) != STATUS_OK) {
147 fprintf(stderr,"xnvm_wait_for_nvmen failed retries %d\n", retries);
148 return ERR_BAD_DATA;
149 }
150 if ((pdi_status & XNVM_NVMEN) != 0) {
151 return STATUS_OK;
152 }
153 --retries;
154 }
155 return ERR_TIMEOUT;
156
157 }
158
159 /**
160 * \internal
161 * \brief Read the PDI Controller's STATUS register
162 *
163 * \param status the status buffer pointer.
164 * \retval STATUS_OK read successfully.
165 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
166 * \retval ERR_TIMEOUT Time out.
167 */
xnvm_read_pdi_status(uint8_t * status)168 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_read_pdi_status(uint8_t *status)
169 {
170 enum PDI_STATUS_CODE ret = STATUS_OK;
171
172 cmd_buffer[0] = XNVM_PDI_LDCS_INSTR;
173 if (STATUS_OK != prot->pdi_write(cmd_buffer, 1)) {
174 ret = ERR_BAD_DATA;
175 }
176 if (prot->pdi_read(status, 1, WAIT_RETRIES_NUM) == 0) {
177 ret = ERR_TIMEOUT;
178 }
179
180 return ret;
181 }
182
183 /**
184 * \brief Read the IO space register with NVM controller
185 *
186 * \param address the register address in the IO space.
187 * \param value the value buffer pointer.
188 * \retval STATUS_OK read successfully.
189 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
190 * \retval ERR_TIMEOUT Time out.
191 */
xnvm_ioread_byte(uint16_t address,uint8_t * value)192 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_ioread_byte(uint16_t address, uint8_t *value)
193 {
194 enum PDI_STATUS_CODE ret = STATUS_OK;
195 uint32_t register_address;
196 int res;
197
198 cmd_buffer[0] = XNVM_PDI_LDS_INSTR | XNVM_PDI_LONG_ADDRESS_MASK |
199 XNVM_PDI_BYTE_DATA_MASK;
200
201 register_address = XNVM_DATA_BASE + address;
202
203 memmove((cmd_buffer + 1), (uint8_t*)®ister_address, 4);
204
205 ret = prot->pdi_write(cmd_buffer, 5);
206 if( ret == STATUS_OK)
207 {
208 res = prot->pdi_read(value, 1, WAIT_RETRIES_NUM);
209 if (res != 0)
210 ret = ERR_BAD_DATA;
211 }
212 return ret;
213 }
214
215 /**
216 * \brief Write the IO space register with NVM controller
217 *
218 * \param address the register address in the IO space.
219 * \param value the value which should be write into the address.
220 * \retval STATUS_OK write successfully.
221 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
222 * \retval ERR_TIMEOUT Time out.
223 */
xnvm_iowrite_byte(uint16_t address,uint8_t value)224 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_iowrite_byte(uint16_t address, uint8_t value)
225 {
226
227 uint32_t register_address = XNVM_DATA_BASE + address;
228
229 cmd_buffer[0] = XNVM_PDI_STS_INSTR | XNVM_PDI_LONG_ADDRESS_MASK |
230 XNVM_PDI_BYTE_DATA_MASK;
231
232 memmove((cmd_buffer + 1), (uint8_t*)®ister_address, 4);
233 cmd_buffer[5] = value;
234
235 return (prot->pdi_write(cmd_buffer, 6));
236 }
237
238 /**
239 * \internal
240 * \brief Read the NVM Controller's status register
241 *
242 * \param value the NVM Controller's status buffer pointer.
243 * \retval STATUS_OK read successfully.
244 * \retval ERR_TIMEOUT Time out.
245 */
xnvm_ctrl_read_status(uint8_t * value)246 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_ctrl_read_status(uint8_t *value)
247 {
248 return xnvm_ctrl_read_reg(XNVM_CONTROLLER_STATUS_REG_OFFSET, value);
249 }
250
251 /**
252 * \internal
253 * \brief Read the NVM Controller's register
254 *
255 * \param reg the offset of the NVM Controller register.
256 * \param value the pointer of the value buffer.
257 * \retval STATUS_OK read succussfully.
258 * \retval ERR_TIMEOUT Time out.
259 */
xnvm_ctrl_read_reg(uint16_t reg,uint8_t * value)260 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_ctrl_read_reg(uint16_t reg, uint8_t *value)
261 {
262 uint16_t address;
263
264 address = XNVM_CONTROLLER_BASE + reg;
265 return xnvm_ioread_byte(address, value);
266 }
267
268 /**
269 * \internal
270 * \brief Write the NVM Controller's register
271 *
272 * \param reg the offset of the NVM Controller register.
273 * \param value the value which should be write into the register.
274 * \retval STATUS_OK write succussfully.
275 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
276 * \retval ERR_TIMEOUT Time out.
277 */
xnvm_ctrl_write_reg(uint16_t reg,uint8_t value)278 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_ctrl_write_reg(uint16_t reg, uint8_t value)
279 {
280 uint16_t address;
281
282 address = XNVM_CONTROLLER_BASE + reg;
283 return xnvm_iowrite_byte(address, value);
284 }
285
286 /**
287 * \internal
288 * \brief Write the NVM CTRLA register CMDEX
289 *
290 * \retval STATUS_OK write successful.
291 * \retval STATUS_OK write successfully.
292 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
293 * \retval ERR_TIMEOUT Time out.
294 */
xnvm_ctrl_cmdex_write(void)295 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_ctrl_cmdex_write(void)
296 {
297 return xnvm_ctrl_write_reg(XNVM_CONTROLLER_CTRLA_REG_OFFSET, XNVM_CTRLA_CMDEX);
298 }
299
300 /**
301 * \internal
302 * \brief Write NVM command register
303 *
304 * \param cmd_id the command code which should be write into the NVM command register.
305 * \retval STATUS_OK write successfully.
306 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
307 * \retval ERR_TIMEOUT Time out.
308 */
xnvm_ctrl_cmd_write(uint8_t cmd_id)309 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_ctrl_cmd_write(uint8_t cmd_id)
310 {
311 return xnvm_ctrl_write_reg(XNVM_CONTROLLER_CMD_REG_OFFSET, cmd_id);
312 }
313
314 /**
315 * \brief Erase the whole chip
316 *
317 * \retval STATUS_OK erase chip succussfully.
318 * \retval ERR_TIMEOUT Time out.
319 */
xnvm_chip_erase(void)320 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_chip_erase(void)
321 {
322 /* Write the chip erase command to the NVM command reg */
323 xnvm_ctrl_cmd_write(XNVM_CMD_CHIP_ERASE);
324 /* Write the CMDEX to execute command */
325 xnvm_ctrl_cmdex_write();
326 return xnvm_wait_for_nvmen(WAIT_RETRIES_NUM);
327 }
328
329 /**
330 * \brief Erase the application section chip
331 *
332 * \retval STATUS_OK erase chip succussfully.
333 * \retval ERR_TIMEOUT Time out.
334 */
xnvm_application_erase(void)335 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_application_erase(void)
336 {
337 /* Write the chip erase command to the NVM command reg */
338 xnvm_ctrl_cmd_write(XNVM_CMD_ERASE_APP_SECTION);
339 /* Write the CMDEX to execute command */
340 xnvm_st_ptr(XNVM_FLASH_BASE);
341 xnvm_st_star_ptr_postinc(DUMMY_BYTE);
342 return xnvm_wait_for_nvmen(WAIT_RETRIES_NUM);
343 }
344
345 /**
346 * \brief Erase the boot section chip
347 *
348 * \retval STATUS_OK erase chip succussfully.
349 * \retval ERR_TIMEOUT Time out.
350 */
xnvm_boot_erase(uint32_t address)351 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_boot_erase(uint32_t address)
352 {
353 /* Write the chip erase command to the NVM command reg */
354 xnvm_ctrl_cmd_write(XNVM_CMD_ERASE_BOOT_SECTION);
355 /* Write the CMDEX to execute command */
356 xnvm_st_ptr(address);
357 xnvm_st_star_ptr_postinc(DUMMY_BYTE);
358 return xnvm_ctrl_wait_nvmbusy(WAIT_RETRIES_NUM);
359 }
360
361 /**
362 * \brief Erase the eeprom section chip
363 *
364 * \retval STATUS_OK erase chip succussfully.
365 * \retval ERR_TIMEOUT Time out.
366 */
xnvm_erase_eeprom(void)367 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_erase_eeprom(void)
368 {
369 /* Write the chip erase command to the NVM command reg */
370 xnvm_ctrl_cmd_write(XNVM_CMD_ERASE_EEPROM);
371 /* Write the CMDEX to execute command */
372 xnvm_st_ptr(XNVM_EEPROM_BASE);
373 xnvm_st_star_ptr_postinc(DUMMY_BYTE);
374 return xnvm_ctrl_wait_nvmbusy(WAIT_RETRIES_NUM);
375 }
376
377 /**
378 * \internal
379 * \brief Load the flash page buffer
380 *
381 * \param addr the flash address.
382 * \param buf the pointer which points to the data buffer.
383 * \param len the length of data.
384 * \retval STATUS_OK write succussfully.
385 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
386 * \retval ERR_INVALID_ARG Invalid argument.
387 */
xnvm_load_flash_page_buffer(uint32_t addr,uint8_t * buf,uint16_t len)388 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_load_flash_page_buffer(uint32_t addr, uint8_t *buf, uint16_t len)
389 {
390 if (buf == NULL || len == 0) {
391 return ERR_INVALID_ARG;
392 }
393
394 xnvm_ctrl_cmd_write(XNVM_CMD_LOAD_FLASH_PAGE_BUFFER);
395 xnvm_st_ptr(addr);
396
397 if (len > 1) {
398 xnvm_write_repeat(len);
399 } else {
400 return xnvm_st_star_ptr_postinc(*buf);
401 }
402
403 cmd_buffer[0] = XNVM_PDI_ST_INSTR | XNVM_PDI_LD_PTR_STAR_INC_MASK |
404 XNVM_PDI_BYTE_DATA_MASK;
405 prot->pdi_write(cmd_buffer, 1);
406
407 return prot->pdi_write(buf, len);
408 }
409
410 /**
411 * \internal
412 * \brief Erase the flash buffer with NVM controller.
413 *
414 * \param retries the time out delay number.
415 * \retval STATUS_OK erase successfully.
416 * \retval ERR_TIMEOUT Time out.
417 */
xnvm_erase_flash_buffer(uint32_t retries)418 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_erase_flash_buffer(uint32_t retries)
419 {
420 xnvm_st_ptr(0);
421 xnvm_ctrl_cmd_write(XNVM_CMD_ERASE_FLASH_PAGE_BUFFER);
422 xnvm_ctrl_cmdex_write();
423
424 return xnvm_ctrl_wait_nvmbusy(retries);
425 }
426
427 /**
428 * \internal
429 * \brief Program the flash page buffer with NVM controller.
430 *
431 * \param address the address of the flash IN PDI address space
432 * \param dat_buf the pointer which points to the data buffer.
433 * \param length the data length.
434 * \retval STATUS_OK program succussfully.
435 * \retval ERR_TIMEOUT Time out.
436 */
xnvm_program_flash_page(uint32_t address,uint8_t * dat_buf,uint16_t length)437 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_program_flash_page(
438 uint32_t address, uint8_t *dat_buf, uint16_t length)
439 {
440 xnvm_erase_flash_buffer(WAIT_RETRIES_NUM);
441 xnvm_load_flash_page_buffer(address, dat_buf, length);
442 xnvm_ctrl_cmd_write(XNVM_CMD_WRITE_FLASH_PAGE);
443
444 /* Dummy write for starting the erase and write command */
445 xnvm_st_ptr(address);
446 xnvm_st_star_ptr_postinc(DUMMY_BYTE);
447
448 return xnvm_ctrl_wait_nvmbusy(WAIT_RETRIES_NUM);
449 }
450
451 /**
452 * \internal
453 * \brief Erase and program the flash page buffer with NVM controller.
454 *
455 * \param address the address of the flash.
456 * \param dat_buf the pointer which points to the data buffer.
457 * \param length the data length.
458 * \retval STATUS_OK program succussfully.
459 * \retval ERR_TIMEOUT Time out.
460 */
xnvm_erase_program_flash_page(uint32_t address,uint8_t * dat_buf,uint16_t length)461 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_erase_program_flash_page(
462 uint32_t address, uint8_t *dat_buf, uint16_t length)
463 {
464 xnvm_erase_flash_buffer(WAIT_RETRIES_NUM);
465 xnvm_load_flash_page_buffer(address, dat_buf, length);
466 xnvm_ctrl_cmd_write(XNVM_CMD_ERASE_AND_WRITE_FLASH_PAGE);
467
468 /* Dummy write for starting the erase and write command */
469 xnvm_st_ptr(address);
470 xnvm_st_star_ptr_postinc(DUMMY_BYTE);
471
472 return xnvm_ctrl_wait_nvmbusy(WAIT_RETRIES_NUM);
473 }
474
475 /**
476 * \internal
477 * \brief Erase and program the flash page buffer with NVM controller.
478 *
479 * \param address the address of the flash.
480 * \param dat_buf the pointer which points to the data buffer.
481 * \param length the data length.
482 * \retval STATUS_OK program succussfully.
483 * \retval ERR_TIMEOUT Time out.
484 */
xnvm_erase_application_flash_page(uint32_t address,uint8_t * dat_buf,uint16_t length)485 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_erase_application_flash_page(uint32_t address, uint8_t *dat_buf, uint16_t length)
486 {
487 address = address + XNVM_FLASH_BASE;
488
489 xnvm_erase_flash_buffer(WAIT_RETRIES_NUM);
490 xnvm_load_flash_page_buffer(address, dat_buf, length);
491 xnvm_ctrl_cmd_write(XNVM_CMD_ERASE_AND_WRITE_APP_SECTION);
492
493 /* Dummy write for starting the erase and write command */
494 xnvm_st_ptr(address);
495 xnvm_st_star_ptr_postinc(DUMMY_BYTE);
496
497 return xnvm_ctrl_wait_nvmbusy(WAIT_RETRIES_NUM);
498 }
499
500 /**
501 * \internal
502 * \brief Write the repeating number with PDI port
503 *
504 * \param count the repeating number.
505 * \retval STATUS_OK write succussfully.
506 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
507 */
xnvm_write_repeat(uint32_t count)508 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_write_repeat(uint32_t count)
509 {
510 uint8_t cmd_len;
511
512 --count;
513
514 if (count < (1 << 8)) {
515 cmd_buffer[0] = XNVM_PDI_REPEAT_INSTR | XNVM_PDI_BYTE_DATA_MASK;
516 cmd_buffer[1] = count;
517 cmd_len = 2;
518 } else if (count < ((uint32_t)(1) << 16)) {
519 cmd_buffer[0] = XNVM_PDI_REPEAT_INSTR | XNVM_PDI_WORD_DATA_MASK;
520 memmove((cmd_buffer + 1), (uint8_t*)&count, 2);
521 cmd_len = 3;
522 } else if (count < ((uint32_t)(1) << 24)) {
523 cmd_buffer[0] = XNVM_PDI_REPEAT_INSTR | XNVM_PDI_3BYTES_DATA_MASK;
524 memmove((cmd_buffer + 1), (uint8_t*)&count, 3);
525 cmd_len = 4;
526 } else {
527 cmd_buffer[0] = XNVM_PDI_REPEAT_INSTR | XNVM_PDI_LONG_DATA_MASK;
528 memmove((cmd_buffer + 1), (uint8_t*)&count, 4);
529 cmd_len = 5;
530 }
531
532 return prot->pdi_write(cmd_buffer, cmd_len);
533 }
534
535 /**
536 * \internal
537 * \brief Write a value to a address with *(ptr++) instruction through the PDI Controller.
538 *
539 * \param value the value should be write into the *ptr.
540 * \retval STATUS_OK write succussfully.
541 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
542 */
xnvm_st_star_ptr_postinc(uint8_t value)543 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_st_star_ptr_postinc(uint8_t value)
544 {
545 cmd_buffer[0] = XNVM_PDI_ST_INSTR | XNVM_PDI_LD_PTR_STAR_INC_MASK |
546 XNVM_PDI_BYTE_DATA_MASK;
547 cmd_buffer[1] = value;
548
549 return prot->pdi_write(cmd_buffer, 2);
550 }
551
552 /**
553 * \internal
554 * \brief Write a address in PDI Controller's pointer.
555 *
556 * \param address the address which should be written into the ptr.
557 * \retval STATUS_OK write successfully.
558 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
559 */
xnvm_st_ptr(uint32_t address)560 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_st_ptr(uint32_t address)
561 {
562 cmd_buffer[0] = XNVM_PDI_ST_INSTR | XNVM_PDI_LD_PTR_ADDRESS_MASK |
563 XNVM_PDI_LONG_DATA_MASK;
564
565 memmove((cmd_buffer + 1), (uint8_t*)&address, 4);
566
567 return prot->pdi_write(cmd_buffer, 5);
568 }
569
570 /**
571 * \brief Read the memory (include flash, eeprom, user signature, fuse bits)with NVM controller.
572 *
573 * \param address the address of the memory.
574 * \param data the pointer which points to the data buffer.
575 * \param length the data length.
576 * \retval non-zero the read byte length.
577 * \retval zero read fail.
578 */
xnvm_read_memory(uint32_t address,uint8_t * data,uint32_t length)579 uint16_t ProgAlgNVM::xnvm_read_memory
580 (uint32_t address, uint8_t *data, uint32_t length)
581 {
582 xnvm_ctrl_cmd_write(XNVM_CMD_READ_NVM_PDI);
583 xnvm_st_ptr(address);
584
585 if (length > 1) {
586 xnvm_write_repeat(length);
587 }
588
589 cmd_buffer[0] = XNVM_PDI_LD_INSTR | XNVM_PDI_LD_PTR_STAR_INC_MASK |
590 XNVM_PDI_BYTE_DATA_MASK;
591 prot->pdi_write(cmd_buffer, 1);
592
593 return prot->pdi_read(data, length, WAIT_RETRIES_NUM);
594 }
595
596 /**
597 * \internal
598 * \brief Erase and program the eeprom page buffer with NVM controller.
599 *
600 * \param address the address of the eeprom.
601 * \param dat_buf the pointer which points to the data buffer.
602 * \param length the data length.
603 * \retval STATUS_OK program succussfully.
604 * \retval ERR_TIMEOUT Time out.
605 */
xnvm_erase_program_eeprom_page(uint32_t address,uint8_t * dat_buf,uint16_t length)606 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_erase_program_eeprom_page(uint32_t address, uint8_t *dat_buf, uint16_t length)
607 {
608 address = address + XNVM_EEPROM_BASE;
609
610 xnvm_erase_eeprom_buffer(WAIT_RETRIES_NUM);
611 xnvm_load_eeprom_page_buffer(address, dat_buf, length);
612 xnvm_ctrl_cmd_write(XNVM_CMD_ERASE_AND_WRITE_EEPROM);
613
614 /* Dummy write for starting the erase and write command */
615 xnvm_st_ptr(address);
616 xnvm_st_star_ptr_postinc(DUMMY_BYTE);
617
618 return xnvm_ctrl_wait_nvmbusy(WAIT_RETRIES_NUM);
619 }
620
621 /**
622 * \internal
623 * \brief Erase the eeprom buffer with NVM controller.
624 *
625 * \param retries the time out delay number.
626 * \retval STATUS_OK erase succussfully.
627 * \retval ERR_TIMEOUT Time out.
628 */
xnvm_erase_eeprom_buffer(uint32_t retries)629 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_erase_eeprom_buffer(uint32_t retries)
630 {
631 xnvm_st_ptr(0);
632 xnvm_ctrl_cmd_write(XNVM_CMD_ERASE_EEPROM_PAGE_BUFFER);
633
634 /* Execute command by setting CMDEX */
635 xnvm_ctrl_cmdex_write();
636
637 return xnvm_ctrl_wait_nvmbusy(retries);
638 }
639
640 /**
641 * \internal
642 * \brief Load the eeprom page buffer
643 *
644 * \param addr the eeprom address.
645 * \param buf the pointer which points to the data buffer.
646 * \param len the length of data.
647 * \retval STATUS_OK load succussfully.
648 * \retval ERR_BAD_DATA One of the bytes sent was corrupted during transmission.
649 * \retval ERR_INVALID_ARG Invalid argument.
650 */
xnvm_load_eeprom_page_buffer(uint32_t addr,uint8_t * buf,uint16_t len)651 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_load_eeprom_page_buffer(uint32_t addr, uint8_t *buf, uint16_t len)
652 {
653 if (buf == NULL || len == 0) {
654 return ERR_INVALID_ARG;
655 }
656
657 xnvm_ctrl_cmd_write(XNVM_CMD_LOAD_EEPROM_PAGE_BUFFER);
658 xnvm_st_ptr(addr);
659
660 if (len > 1) {
661 xnvm_write_repeat(len);
662 } else {
663 xnvm_st_star_ptr_postinc(*buf);
664 return STATUS_OK;
665 }
666
667 cmd_buffer[0] = XNVM_PDI_ST_INSTR | XNVM_PDI_LD_PTR_STAR_INC_MASK |
668 XNVM_PDI_BYTE_DATA_MASK;
669 prot->pdi_write(cmd_buffer, 1);
670
671 return prot->pdi_write(buf, len);
672 }
673
674 /**
675 * \internal
676 * \brief Erase the user signature with NVM controller.
677 *
678 * \retval STATUS_OK erase succussfully.
679 * \retval ERR_TIMEOUT time out.
680 */
xnvm_erase_user_sign(void)681 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_erase_user_sign(void)
682 {
683 xnvm_ctrl_cmd_write(XNVM_CMD_ERASE_USER_SIGN);
684
685 /* Dummy write for starting the erase command */
686 xnvm_st_ptr(XNVM_SIGNATURE_BASE);
687 xnvm_st_star_ptr_postinc(DUMMY_BYTE);
688
689 return xnvm_ctrl_wait_nvmbusy(WAIT_RETRIES_NUM);
690 }
691
692 /**
693 * \internal
694 * \brief Erase and program the user signature with NVM controller.
695 *
696 * \param address the address of the user signature.
697 * \param dat_buf the pointer which points to the data buffer.
698 * \param length the data length.
699 * \retval STATUS_OK program succussfully.
700 * \retval ERR_TIMEOUT time out.
701 */
xnvm_erase_program_user_sign(uint32_t address,uint8_t * dat_buf,uint16_t length)702 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_erase_program_user_sign
703 (uint32_t address, uint8_t *dat_buf, uint16_t length)
704 {
705 address = address + XNVM_SIGNATURE_BASE;
706
707 xnvm_erase_flash_buffer(WAIT_RETRIES_NUM);
708 xnvm_load_flash_page_buffer(address, dat_buf, length);
709 xnvm_erase_user_sign();
710 xnvm_ctrl_cmd_write(XNVM_CMD_WRITE_USER_SIGN);
711
712 /* Dummy write for starting the write command. */
713 xnvm_st_ptr(address);
714 xnvm_st_star_ptr_postinc(DUMMY_BYTE);
715
716 return xnvm_ctrl_wait_nvmbusy(WAIT_RETRIES_NUM);
717 }
718
719 /**
720 * \brief Write a single fuse byte with NVM controller
721 *
722 * \param address the fuse bit address.
723 * \param value which should be write into the fuse bit.
724 * \retval STATUS_OK write succussfully.
725 * \retval ERR_TIMEOUT time out.
726 */
xnvm_write_fuse_byte(uint32_t address,uint8_t value)727 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_write_fuse_byte(uint32_t address, uint8_t value)
728 {
729 uint32_t register_address;
730
731 xnvm_ctrl_cmd_write(XNVM_CMD_WRITE_FUSE);
732
733 cmd_buffer[0] = XNVM_PDI_STS_INSTR | XNVM_PDI_LONG_ADDRESS_MASK |
734 XNVM_PDI_BYTE_DATA_MASK;
735
736 register_address = XNVM_FUSE_BASE + address;
737
738 memmove((cmd_buffer + 1), (uint8_t*)®ister_address, 4);
739 cmd_buffer[5] = value;
740
741 prot->pdi_write(cmd_buffer, 6);
742
743 return xnvm_ctrl_wait_nvmbusy(WAIT_RETRIES_NUM);
744 }
745
746 /**
747 * \brief Write the lock byte with NVM controller
748 *
749 * \param value which should be write into the lock byte.
750 * \retval STATUS_OK write succussfully.
751 * \retval ERR_TIMEOUT time out.
752 */
xnvm_write_lock_byte(uint8_t value)753 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_write_lock_byte(uint8_t value)
754 {
755 uint32_t register_address;
756
757 xnvm_ctrl_cmd_write(XNVM_CMD_WRITE_LOCK_BITS);
758
759 cmd_buffer[0] = XNVM_PDI_STS_INSTR | XNVM_PDI_LONG_ADDRESS_MASK |
760 XNVM_PDI_BYTE_DATA_MASK;
761
762 register_address = XNVM_FUSE_BASE + NVM_LOCKBIT_ADDR;
763
764 memmove((cmd_buffer + 1), (uint8_t*)®ister_address, 4);
765 cmd_buffer[5] = value;
766
767 prot->pdi_write(cmd_buffer, 6);
768
769 return xnvm_ctrl_wait_nvmbusy(WAIT_RETRIES_NUM);
770 }
771
772 /**
773 * \internal
774 * \brief Wait until the NVM Controller is ready.
775 *
776 * \param retries the retry count.
777 * \retval STATUS_OK BUSY bit was set.
778 * \retval ERR_TIMEOUT Time out.
779 */
xnvm_ctrl_wait_nvmbusy(uint32_t retries)780 enum PDI_STATUS_CODE ProgAlgNVM::xnvm_ctrl_wait_nvmbusy(uint32_t retries)
781 {
782 uint8_t status;
783
784 while (retries != 0) {
785 xnvm_ctrl_read_status(&status);
786
787 /* Check if the NVMBUSY bit is clear in the NVM_STATUS register. */
788 if ((status & XNVM_NVM_BUSY) == 0) {
789 return STATUS_OK;
790 }
791 --retries;
792 }
793 return ERR_TIMEOUT;
794 }
795