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*)&register_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*)&register_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*)&register_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*)&register_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