1 /*
2  * This file is part of the Serial Flash Universal Driver Library.
3  *
4  * Copyright (c) 2016-2018, Armink, <armink.ztl@gmail.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * 'Software'), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  * Function: serial flash operate functions by SFUD lib.
26  * Created on: 2016-04-23
27  */
28 
29 #include "../inc/sfud.h"
30 #include <string.h>
31 
32 /* send dummy data for read data */
33 #define DUMMY_DATA                               0xFF
34 
35 #ifndef SFUD_FLASH_DEVICE_TABLE
36 #error "Please configure the flash device information table in (in sfud_cfg.h)."
37 #endif
38 
39 /* user configured flash device information table */
40 static sfud_flash flash_table[] = SFUD_FLASH_DEVICE_TABLE;
41 /* supported manufacturer information table */
42 static const sfud_mf mf_table[] = SFUD_MF_TABLE;
43 
44 #ifdef SFUD_USING_FLASH_INFO_TABLE
45 /* supported flash chip information table */
46 static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE;
47 #endif
48 
49 #ifdef SFUD_USING_QSPI
50 /**
51  * flash read data mode
52  */
53 enum sfud_qspi_read_mode {
54     NORMAL_SPI_READ = 1 << 0,               /**< mormal spi read mode */
55     DUAL_OUTPUT = 1 << 1,                   /**< qspi fast read dual output */
56     DUAL_IO = 1 << 2,                       /**< qspi fast read dual input/output */
57     QUAD_OUTPUT = 1 << 3,                   /**< qspi fast read quad output */
58     QUAD_IO = 1 << 4,                       /**< qspi fast read quad input/output */
59 };
60 
61 /* QSPI flash chip's extended information table */
62 static const sfud_qspi_flash_ext_info qspi_flash_ext_info_table[] = SFUD_FLASH_EXT_INFO_TABLE;
63 #endif /* SFUD_USING_QSPI */
64 
65 static sfud_err software_init(const sfud_flash *flash);
66 static sfud_err hardware_init(sfud_flash *flash);
67 static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
68         const uint8_t *data);
69 static sfud_err aai_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data);
70 static sfud_err wait_busy(const sfud_flash *flash);
71 static sfud_err reset(const sfud_flash *flash);
72 static sfud_err read_jedec_id(sfud_flash *flash);
73 static sfud_err set_write_enabled(const sfud_flash *flash, bool enabled);
74 static sfud_err set_4_byte_address_mode(sfud_flash *flash, bool enabled);
75 static void make_address_byte_array(const sfud_flash *flash, uint32_t addr, uint8_t *array);
76 
77 /* ../port/sfup_port.c */
78 extern void sfud_log_debug(const char *file, const long line, const char *format, ...);
79 extern void sfud_log_info(const char *format, ...);
80 
81 /**
82  * SFUD initialize by flash device
83  *
84  * @param flash flash device
85  *
86  * @return result
87  */
sfud_device_init(sfud_flash * flash)88 sfud_err sfud_device_init(sfud_flash *flash) {
89     sfud_err result = SFUD_SUCCESS;
90 
91     /* hardware initialize */
92     result = hardware_init(flash);
93     if (result == SFUD_SUCCESS) {
94         result = software_init(flash);
95     }
96     if (result == SFUD_SUCCESS) {
97         flash->init_ok = true;
98         SFUD_INFO("%s flash device initialized successfully.", flash->name);
99     } else {
100         flash->init_ok = false;
101         SFUD_INFO("Error: %s flash device initialization failed.", flash->name);
102     }
103 
104     return result;
105 }
106 
107 /**
108  * SFUD library initialize.
109  *
110  * @return result
111  */
sfud_init(void)112 sfud_err sfud_init(void) {
113     sfud_err cur_flash_result = SFUD_SUCCESS, all_flash_result = SFUD_SUCCESS;
114     size_t i;
115 
116     SFUD_DEBUG("Start initialize Serial Flash Universal Driver(SFUD) V%s.", SFUD_SW_VERSION);
117     SFUD_DEBUG("You can get the latest version on https://github.com/armink/SFUD .");
118     /* initialize all flash device in flash device table */
119     for (i = 0; i < sizeof(flash_table) / sizeof(sfud_flash); i++) {
120         /* initialize flash device index of flash device information table */
121         flash_table[i].index = i;
122         cur_flash_result = sfud_device_init(&flash_table[i]);
123 
124         if (cur_flash_result != SFUD_SUCCESS) {
125             all_flash_result = cur_flash_result;
126         }
127     }
128 
129     return all_flash_result;
130 }
131 
132 /**
133  * get flash device by its index which in the flash information table
134  *
135  * @param index the index which in the flash information table  @see flash_table
136  *
137  * @return flash device
138  */
sfud_get_device(size_t index)139 sfud_flash *sfud_get_device(size_t index) {
140     if (index < sfud_get_device_num()) {
141         return &flash_table[index];
142     } else {
143         return NULL;
144     }
145 }
146 
147 /**
148  * get flash device total number on flash device information table  @see flash_table
149  *
150  * @return flash device total number
151  */
sfud_get_device_num(void)152 size_t sfud_get_device_num(void) {
153     return sizeof(flash_table) / sizeof(sfud_flash);
154 }
155 
156 /**
157  * get flash device information table  @see flash_table
158  *
159  * @return flash device table pointer
160  */
sfud_get_device_table(void)161 const sfud_flash *sfud_get_device_table(void) {
162     return flash_table;
163 }
164 
165 #ifdef SFUD_USING_QSPI
qspi_set_read_cmd_format(sfud_flash * flash,uint8_t ins,uint8_t ins_lines,uint8_t addr_lines,uint8_t dummy_cycles,uint8_t data_lines)166 static void qspi_set_read_cmd_format(sfud_flash *flash, uint8_t ins, uint8_t ins_lines, uint8_t addr_lines,
167         uint8_t dummy_cycles, uint8_t data_lines) {
168     /* if medium size greater than 16Mb, use 4-Byte address, instruction should be added one */
169     if (flash->chip.capacity <= 0x1000000) {
170         flash->read_cmd_format.instruction = ins;
171         flash->read_cmd_format.address_size = 24;
172     } else {
173         if(ins == SFUD_CMD_READ_DATA){
174             flash->read_cmd_format.instruction = ins + 0x10;
175         }
176         else{
177             flash->read_cmd_format.instruction = ins + 1;
178         }
179         flash->read_cmd_format.address_size = 32;
180     }
181 
182     flash->read_cmd_format.instruction_lines = ins_lines;
183     flash->read_cmd_format.address_lines = addr_lines;
184     flash->read_cmd_format.alternate_bytes_lines = 0;
185     flash->read_cmd_format.dummy_cycles = dummy_cycles;
186     flash->read_cmd_format.data_lines = data_lines;
187 }
188 
189 /**
190  * Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode.
191  *
192  * it will find the appropriate fast-read instruction to replace the read instruction(0x03)
193  * fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE
194  *
195  * @note When Flash is in QSPI mode, the method must be called after sfud_device_init().
196  *
197  * @param flash flash device
198  * @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4
199  *
200  * @return result
201  */
sfud_qspi_fast_read_enable(sfud_flash * flash,uint8_t data_line_width)202 sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width) {
203     size_t i = 0;
204     uint8_t read_mode = NORMAL_SPI_READ;
205     sfud_err result = SFUD_SUCCESS;
206 
207     SFUD_ASSERT(flash);
208     SFUD_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
209 
210     /* get read_mode, If don't found, the default is SFUD_QSPI_NORMAL_SPI_READ */
211     for (i = 0; i < sizeof(qspi_flash_ext_info_table) / sizeof(sfud_qspi_flash_ext_info); i++) {
212         if ((qspi_flash_ext_info_table[i].mf_id == flash->chip.mf_id)
213                 && (qspi_flash_ext_info_table[i].type_id == flash->chip.type_id)
214                 && (qspi_flash_ext_info_table[i].capacity_id == flash->chip.capacity_id)) {
215             read_mode = qspi_flash_ext_info_table[i].read_mode;
216         }
217     }
218 
219     /* determine qspi supports which read mode and set read_cmd_format struct */
220     switch (data_line_width) {
221     case 1:
222         qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
223         break;
224     case 2:
225         if (read_mode & DUAL_IO) {
226             qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_IO_READ_DATA, 1, 2, 4, 2);
227         } else if (read_mode & DUAL_OUTPUT) {
228             qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_OUTPUT_READ_DATA, 1, 1, 8, 2);
229         } else {
230             qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
231         }
232         break;
233     case 4:
234         if (read_mode & QUAD_IO) {
235             qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_IO_READ_DATA, 1, 4, 6, 4);
236         } else if (read_mode & QUAD_OUTPUT) {
237             qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_OUTPUT_READ_DATA, 1, 1, 8, 4);
238         } else {
239             qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
240         }
241         break;
242     }
243 
244     return result;
245 }
246 #endif /* SFUD_USING_QSPI */
247 
248 /**
249  * hardware initialize
250  */
hardware_init(sfud_flash * flash)251 static sfud_err hardware_init(sfud_flash *flash) {
252     extern sfud_err sfud_spi_port_init(sfud_flash * flash);
253 
254     sfud_err result = SFUD_SUCCESS;
255     size_t i;
256 
257     SFUD_ASSERT(flash);
258 
259     result = sfud_spi_port_init(flash);
260     if (result != SFUD_SUCCESS) {
261         return result;
262     }
263 
264 #ifdef SFUD_USING_QSPI
265     /* set default read instruction */
266     flash->read_cmd_format.instruction = SFUD_CMD_READ_DATA;
267 #endif /* SFUD_USING_QSPI */
268 
269     /* SPI write read function must be initialize */
270     SFUD_ASSERT(flash->spi.wr);
271     /* if the user don't configure flash chip information then using SFDP parameter or static flash parameter table */
272     if (flash->chip.capacity == 0 || flash->chip.write_mode == 0 || flash->chip.erase_gran == 0
273             || flash->chip.erase_gran_cmd == 0) {
274         /* read JEDEC ID include manufacturer ID, memory type ID and flash capacity ID */
275         result = read_jedec_id(flash);
276         if (result != SFUD_SUCCESS) {
277             return result;
278         }
279 
280 #ifdef SFUD_USING_SFDP
281         extern bool sfud_read_sfdp(sfud_flash *flash);
282         /* read SFDP parameters */
283         if (sfud_read_sfdp(flash)) {
284             flash->chip.name = NULL;
285             flash->chip.capacity = flash->sfdp.capacity;
286             /* only 1 byte or 256 bytes write mode for SFDP */
287             if (flash->sfdp.write_gran == 1) {
288                 flash->chip.write_mode = SFUD_WM_BYTE;
289             } else {
290                 flash->chip.write_mode = SFUD_WM_PAGE_256B;
291             }
292             /* find the the smallest erase sector size for eraser. then will use this size for erase granularity */
293             flash->chip.erase_gran = flash->sfdp.eraser[0].size;
294             flash->chip.erase_gran_cmd = flash->sfdp.eraser[0].cmd;
295             for (i = 1; i < SFUD_SFDP_ERASE_TYPE_MAX_NUM; i++) {
296                 if (flash->sfdp.eraser[i].size != 0 && flash->chip.erase_gran > flash->sfdp.eraser[i].size) {
297                     flash->chip.erase_gran = flash->sfdp.eraser[i].size;
298                     flash->chip.erase_gran_cmd = flash->sfdp.eraser[i].cmd;
299                 }
300             }
301         } else {
302 #endif
303 
304 #ifdef SFUD_USING_FLASH_INFO_TABLE
305             /* read SFDP parameters failed then using SFUD library provided static parameter */
306             for (i = 0; i < sizeof(flash_chip_table) / sizeof(sfud_flash_chip); i++) {
307                 if ((flash_chip_table[i].mf_id == flash->chip.mf_id)
308                         && (flash_chip_table[i].type_id == flash->chip.type_id)
309                         && (flash_chip_table[i].capacity_id == flash->chip.capacity_id)) {
310                     flash->chip.name = flash_chip_table[i].name;
311                     flash->chip.capacity = flash_chip_table[i].capacity;
312                     flash->chip.write_mode = flash_chip_table[i].write_mode;
313                     flash->chip.erase_gran = flash_chip_table[i].erase_gran;
314                     flash->chip.erase_gran_cmd = flash_chip_table[i].erase_gran_cmd;
315                     break;
316                 }
317             }
318 #endif
319 
320 #ifdef SFUD_USING_SFDP
321         }
322 #endif
323 
324     }
325 
326     if (flash->chip.capacity == 0 || flash->chip.write_mode == 0 || flash->chip.erase_gran == 0
327             || flash->chip.erase_gran_cmd == 0) {
328         SFUD_INFO("Warning: This flash device is not found or not supported.");
329         return SFUD_ERR_NOT_FOUND;
330     } else {
331         const char *flash_mf_name = NULL;
332         /* find the manufacturer information */
333         for (i = 0; i < sizeof(mf_table) / sizeof(sfud_mf); i++) {
334             if (mf_table[i].id == flash->chip.mf_id) {
335                 flash_mf_name = mf_table[i].name;
336                 break;
337             }
338         }
339         /* print manufacturer and flash chip name */
340         if (flash_mf_name && flash->chip.name) {
341             SFUD_INFO("Found a %s %s flash chip. Size is %ld bytes.", flash_mf_name, flash->chip.name,
342                     flash->chip.capacity);
343         } else if (flash_mf_name) {
344             SFUD_INFO("Found a %s flash chip. Size is %ld bytes.", flash_mf_name, flash->chip.capacity);
345         } else {
346             SFUD_INFO("Found a flash chip. Size is %ld bytes.", flash->chip.capacity);
347         }
348     }
349 
350     /* reset flash device */
351     result = reset(flash);
352     if (result != SFUD_SUCCESS) {
353         return result;
354     }
355 
356     /* The flash all blocks is protected,so need change the flash status to unprotected before write and erase operate. */
357     if (flash->chip.write_mode & SFUD_WM_AAI) {
358         result = sfud_write_status(flash, true, 0x00);
359     } else {
360         /* MX25L3206E */
361         if ((0xC2 == flash->chip.mf_id) && (0x20 == flash->chip.type_id) && (0x16 == flash->chip.capacity_id)) {
362             result = sfud_write_status(flash, false, 0x00);
363         }
364     }
365     if (result != SFUD_SUCCESS) {
366         return result;
367     }
368 
369     /* if the flash is large than 16MB (256Mb) then enter in 4-Byte addressing mode */
370     if (flash->chip.capacity > (1L << 24)) {
371         result = set_4_byte_address_mode(flash, true);
372     } else {
373         flash->addr_in_4_byte = false;
374     }
375 
376     return result;
377 }
378 
379 /**
380  * software initialize
381  *
382  * @param flash flash device
383  *
384  * @return result
385  */
software_init(const sfud_flash * flash)386 static sfud_err software_init(const sfud_flash *flash) {
387     sfud_err result = SFUD_SUCCESS;
388 
389     SFUD_ASSERT(flash);
390 
391     return result;
392 }
393 
394 /**
395  * read flash data
396  *
397  * @param flash flash device
398  * @param addr start address
399  * @param size read size
400  * @param data read data pointer
401  *
402  * @return result
403  */
sfud_read(const sfud_flash * flash,uint32_t addr,size_t size,uint8_t * data)404 sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data) {
405     sfud_err result = SFUD_SUCCESS;
406     const sfud_spi *spi = &flash->spi;
407     uint8_t cmd_data[5], cmd_size;
408 
409     SFUD_ASSERT(flash);
410     SFUD_ASSERT(data);
411     /* must be call this function after initialize OK */
412     SFUD_ASSERT(flash->init_ok);
413     /* check the flash address bound */
414     if (addr + size > flash->chip.capacity) {
415         SFUD_INFO("Error: Flash address is out of bound.");
416         return SFUD_ERR_ADDR_OUT_OF_BOUND;
417     }
418     /* lock SPI */
419     if (spi->lock) {
420         spi->lock(spi);
421     }
422 
423     result = wait_busy(flash);
424 
425     if (result == SFUD_SUCCESS) {
426 #ifdef SFUD_USING_QSPI
427         if (flash->read_cmd_format.instruction != SFUD_CMD_READ_DATA) {
428             result = spi->qspi_read(spi, addr, (sfud_qspi_read_cmd_format *)&flash->read_cmd_format, data, size);
429         } else
430 #endif
431         {
432             cmd_data[0] = SFUD_CMD_READ_DATA;
433             make_address_byte_array(flash, addr, &cmd_data[1]);
434             cmd_size = flash->addr_in_4_byte ? 5 : 4;
435             result = spi->wr(spi, cmd_data, cmd_size, data, size);
436         }
437     }
438     /* unlock SPI */
439     if (spi->unlock) {
440         spi->unlock(spi);
441     }
442 
443     return result;
444 }
445 
446 /**
447  * erase all flash data
448  *
449  * @param flash flash device
450  *
451  * @return result
452  */
sfud_chip_erase(const sfud_flash * flash)453 sfud_err sfud_chip_erase(const sfud_flash *flash) {
454     sfud_err result = SFUD_SUCCESS;
455     const sfud_spi *spi = &flash->spi;
456     uint8_t cmd_data[4];
457 
458     SFUD_ASSERT(flash);
459     /* must be call this function after initialize OK */
460     SFUD_ASSERT(flash->init_ok);
461     /* lock SPI */
462     if (spi->lock) {
463         spi->lock(spi);
464     }
465 
466     /* set the flash write enable */
467     result = set_write_enabled(flash, true);
468     if (result != SFUD_SUCCESS) {
469         goto __exit;
470     }
471 
472     cmd_data[0] = SFUD_CMD_ERASE_CHIP;
473     /* dual-buffer write, like AT45DB series flash chip erase operate is different for other flash */
474     if (flash->chip.write_mode & SFUD_WM_DUAL_BUFFER) {
475         cmd_data[1] = 0x94;
476         cmd_data[2] = 0x80;
477         cmd_data[3] = 0x9A;
478         result = spi->wr(spi, cmd_data, 4, NULL, 0);
479     } else {
480         result = spi->wr(spi, cmd_data, 1, NULL, 0);
481     }
482     if (result != SFUD_SUCCESS) {
483         SFUD_INFO("Error: Flash chip erase SPI communicate error.");
484         goto __exit;
485     }
486     result = wait_busy(flash);
487 
488 __exit:
489     /* set the flash write disable */
490     set_write_enabled(flash, false);
491     /* unlock SPI */
492     if (spi->unlock) {
493         spi->unlock(spi);
494     }
495 
496     return result;
497 }
498 
499 /**
500  * erase flash data
501  *
502  * @note It will erase align by erase granularity.
503  *
504  * @param flash flash device
505  * @param addr start address
506  * @param size erase size
507  *
508  * @return result
509  */
sfud_erase(const sfud_flash * flash,uint32_t addr,size_t size)510 sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size) {
511     extern size_t sfud_sfdp_get_suitable_eraser(const sfud_flash *flash, uint32_t addr, size_t erase_size);
512 
513     sfud_err result = SFUD_SUCCESS;
514     const sfud_spi *spi = &flash->spi;
515     uint8_t cmd_data[5], cmd_size, cur_erase_cmd;
516     size_t cur_erase_size;
517 
518     SFUD_ASSERT(flash);
519     /* must be call this function after initialize OK */
520     SFUD_ASSERT(flash->init_ok);
521     /* check the flash address bound */
522     if (addr + size > flash->chip.capacity) {
523         SFUD_INFO("Error: Flash address is out of bound.");
524         return SFUD_ERR_ADDR_OUT_OF_BOUND;
525     }
526 
527     if (addr == 0 && size == flash->chip.capacity) {
528         return sfud_chip_erase(flash);
529     }
530 
531     /* lock SPI */
532     if (spi->lock) {
533         spi->lock(spi);
534     }
535 
536     /* loop erase operate. erase unit is erase granularity */
537     while (size) {
538         /* if this flash is support SFDP parameter, then used SFDP parameter supplies eraser */
539 #ifdef SFUD_USING_SFDP
540         size_t eraser_index;
541         if (flash->sfdp.available) {
542             /* get the suitable eraser for erase process from SFDP parameter */
543             eraser_index = sfud_sfdp_get_suitable_eraser(flash, addr, size);
544             cur_erase_cmd = flash->sfdp.eraser[eraser_index].cmd;
545             cur_erase_size = flash->sfdp.eraser[eraser_index].size;
546         } else {
547 #else
548         {
549 #endif
550             cur_erase_cmd = flash->chip.erase_gran_cmd;
551             cur_erase_size = flash->chip.erase_gran;
552         }
553         /* set the flash write enable */
554         result = set_write_enabled(flash, true);
555         if (result != SFUD_SUCCESS) {
556             goto __exit;
557         }
558 
559         cmd_data[0] = cur_erase_cmd;
560         make_address_byte_array(flash, addr, &cmd_data[1]);
561         cmd_size = flash->addr_in_4_byte ? 5 : 4;
562         result = spi->wr(spi, cmd_data, cmd_size, NULL, 0);
563         if (result != SFUD_SUCCESS) {
564             SFUD_INFO("Error: Flash erase SPI communicate error.");
565             goto __exit;
566         }
567         result = wait_busy(flash);
568         if (result != SFUD_SUCCESS) {
569             goto __exit;
570         }
571         /* make erase align and calculate next erase address */
572         if (addr % cur_erase_size != 0) {
573             if (size > cur_erase_size - (addr % cur_erase_size)) {
574                 size -= cur_erase_size - (addr % cur_erase_size);
575                 addr += cur_erase_size - (addr % cur_erase_size);
576             } else {
577                 goto __exit;
578             }
579         } else {
580             if (size > cur_erase_size) {
581                 size -= cur_erase_size;
582                 addr += cur_erase_size;
583             } else {
584                 goto __exit;
585             }
586         }
587     }
588 
589 __exit:
590     /* set the flash write disable */
591     set_write_enabled(flash, false);
592     /* unlock SPI */
593     if (spi->unlock) {
594         spi->unlock(spi);
595     }
596 
597     return result;
598 }
599 
600 /**
601  * write flash data (no erase operate) for write 1 to 256 bytes per page mode or byte write mode
602  *
603  * @param flash flash device
604  * @param addr start address
605  * @param size write size
606  * @param write_gran write granularity bytes, only support 1 or 256
607  * @param data write data
608  *
609  * @return result
610  */
611 static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
612         const uint8_t *data) {
613     sfud_err result = SFUD_SUCCESS;
614     const sfud_spi *spi = &flash->spi;
615     static uint8_t cmd_data[5 + SFUD_WRITE_MAX_PAGE_SIZE];
616     uint8_t cmd_size;
617     size_t data_size;
618 
619     SFUD_ASSERT(flash);
620     /* only support 1 or 256 */
621     SFUD_ASSERT(write_gran == 1 || write_gran == 256);
622     /* must be call this function after initialize OK */
623     SFUD_ASSERT(flash->init_ok);
624     /* check the flash address bound */
625     if (addr + size > flash->chip.capacity) {
626         SFUD_INFO("Error: Flash address is out of bound.");
627         return SFUD_ERR_ADDR_OUT_OF_BOUND;
628     }
629     /* lock SPI */
630     if (spi->lock) {
631         spi->lock(spi);
632     }
633 
634     /* loop write operate. write unit is write granularity */
635     while (size) {
636         /* set the flash write enable */
637         result = set_write_enabled(flash, true);
638         if (result != SFUD_SUCCESS) {
639             goto __exit;
640         }
641         cmd_data[0] = SFUD_CMD_PAGE_PROGRAM;
642         make_address_byte_array(flash, addr, &cmd_data[1]);
643         cmd_size = flash->addr_in_4_byte ? 5 : 4;
644 
645         /* make write align and calculate next write address */
646         if (addr % write_gran != 0) {
647             if (size > write_gran - (addr % write_gran)) {
648                 data_size = write_gran - (addr % write_gran);
649             } else {
650                 data_size = size;
651             }
652         } else {
653             if (size > write_gran) {
654                 data_size = write_gran;
655             } else {
656                 data_size = size;
657             }
658         }
659         size -= data_size;
660         addr += data_size;
661 
662         rt_memcpy(&cmd_data[cmd_size], data, data_size);
663 
664         result = spi->wr(spi, cmd_data, cmd_size + data_size, NULL, 0);
665         if (result != SFUD_SUCCESS) {
666             SFUD_INFO("Error: Flash write SPI communicate error.");
667             goto __exit;
668         }
669         result = wait_busy(flash);
670         if (result != SFUD_SUCCESS) {
671             goto __exit;
672         }
673         data += data_size;
674     }
675 
676 __exit:
677     /* set the flash write disable */
678     set_write_enabled(flash, false);
679     /* unlock SPI */
680     if (spi->unlock) {
681         spi->unlock(spi);
682     }
683 
684     return result;
685 }
686 
687 /**
688  * write flash data (no erase operate) for auto address increment mode
689  *
690  * If the address is odd number, it will place one 0xFF before the start of data for protect the old data.
691  * If the latest remain size is 1, it will append one 0xFF at the end of data for protect the old data.
692  *
693  * @param flash flash device
694  * @param addr start address
695  * @param size write size
696  * @param data write data
697  *
698  * @return result
699  */
700 static sfud_err aai_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
701     sfud_err result = SFUD_SUCCESS;
702     const sfud_spi *spi = &flash->spi;
703     uint8_t cmd_data[8], cmd_size;
704     bool first_write = true;
705 
706     SFUD_ASSERT(flash);
707     SFUD_ASSERT(flash->init_ok);
708     /* check the flash address bound */
709     if (addr + size > flash->chip.capacity) {
710         SFUD_INFO("Error: Flash address is out of bound.");
711         return SFUD_ERR_ADDR_OUT_OF_BOUND;
712     }
713     /* lock SPI */
714     if (spi->lock) {
715         spi->lock(spi);
716     }
717     /* The address must be even for AAI write mode. So it must write one byte first when address is odd. */
718     if (addr % 2 != 0) {
719         result = page256_or_1_byte_write(flash, addr++, 1, 1, data++);
720         if (result != SFUD_SUCCESS) {
721             goto __exit;
722         }
723         size--;
724     }
725     /* set the flash write enable */
726     result = set_write_enabled(flash, true);
727     if (result != SFUD_SUCCESS) {
728         goto __exit;
729     }
730     /* loop write operate. */
731     cmd_data[0] = SFUD_CMD_AAI_WORD_PROGRAM;
732     while (size >= 2) {
733         if (first_write) {
734             make_address_byte_array(flash, addr, &cmd_data[1]);
735             cmd_size = flash->addr_in_4_byte ? 5 : 4;
736             cmd_data[cmd_size] = *data;
737             cmd_data[cmd_size + 1] = *(data + 1);
738             first_write = false;
739         } else {
740             cmd_size = 1;
741             cmd_data[1] = *data;
742             cmd_data[2] = *(data + 1);
743         }
744 
745         result = spi->wr(spi, cmd_data, cmd_size + 2, NULL, 0);
746         if (result != SFUD_SUCCESS) {
747             SFUD_INFO("Error: Flash write SPI communicate error.");
748             goto __exit;
749         }
750 
751         result = wait_busy(flash);
752         if (result != SFUD_SUCCESS) {
753             goto __exit;
754         }
755 
756         size -= 2;
757         addr += 2;
758         data += 2;
759     }
760     /* set the flash write disable for exit AAI mode */
761     result = set_write_enabled(flash, false);
762     /* write last one byte data when origin write size is odd */
763     if (result == SFUD_SUCCESS && size == 1) {
764         result = page256_or_1_byte_write(flash, addr, 1, 1, data);
765     }
766 
767 __exit:
768     if (result != SFUD_SUCCESS) {
769         set_write_enabled(flash, false);
770     }
771     /* unlock SPI */
772     if (spi->unlock) {
773         spi->unlock(spi);
774     }
775 
776     return result;
777 }
778 
779 /**
780  * write flash data (no erase operate)
781  *
782  * @param flash flash device
783  * @param addr start address
784  * @param size write size
785  * @param data write data
786  *
787  * @return result
788  */
789 sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
790     sfud_err result = SFUD_SUCCESS;
791 
792     if (flash->chip.write_mode & SFUD_WM_PAGE_256B) {
793         result = page256_or_1_byte_write(flash, addr, size, 256, data);
794     } else if (flash->chip.write_mode & SFUD_WM_AAI) {
795         result = aai_write(flash, addr, size, data);
796     } else if (flash->chip.write_mode & SFUD_WM_DUAL_BUFFER) {
797         //TODO dual-buffer write mode
798     }
799 
800     return result;
801 }
802 
803 /**
804  * erase and write flash data
805  *
806  * @param flash flash device
807  * @param addr start address
808  * @param size write size
809  * @param data write data
810  *
811  * @return result
812  */
813 sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
814     sfud_err result = SFUD_SUCCESS;
815 
816     result = sfud_erase(flash, addr, size);
817 
818     if (result == SFUD_SUCCESS) {
819         result = sfud_write(flash, addr, size, data);
820     }
821 
822     return result;
823 }
824 
825 static sfud_err reset(const sfud_flash *flash) {
826     sfud_err result = SFUD_SUCCESS;
827     const sfud_spi *spi = &flash->spi;
828     uint8_t cmd_data[2];
829 
830     SFUD_ASSERT(flash);
831 
832     cmd_data[0] = SFUD_CMD_ENABLE_RESET;
833     result = spi->wr(spi, cmd_data, 1, NULL, 0);
834     if (result == SFUD_SUCCESS) {
835         result = wait_busy(flash);
836     } else {
837         SFUD_INFO("Error: Flash device reset failed.");
838         return result;
839     }
840 
841     cmd_data[1] = SFUD_CMD_RESET;
842     result = spi->wr(spi, &cmd_data[1], 1, NULL, 0);
843 
844     if (result == SFUD_SUCCESS) {
845         result = wait_busy(flash);
846     }
847 
848     if (result == SFUD_SUCCESS) {
849         SFUD_DEBUG("Flash device reset success.");
850     } else {
851         SFUD_INFO("Error: Flash device reset failed.");
852     }
853 
854     return result;
855 }
856 
857 static sfud_err read_jedec_id(sfud_flash *flash) {
858     sfud_err result = SFUD_SUCCESS;
859     const sfud_spi *spi = &flash->spi;
860     uint8_t cmd_data[1], recv_data[3];
861 
862     SFUD_ASSERT(flash);
863 
864     cmd_data[0] = SFUD_CMD_JEDEC_ID;
865     result = spi->wr(spi, cmd_data, sizeof(cmd_data), recv_data, sizeof(recv_data));
866     if (result == SFUD_SUCCESS) {
867         flash->chip.mf_id = recv_data[0];
868         flash->chip.type_id = recv_data[1];
869         flash->chip.capacity_id = recv_data[2];
870         SFUD_DEBUG("The flash device manufacturer ID is 0x%02X, memory type ID is 0x%02X, capacity ID is 0x%02X.",
871                 flash->chip.mf_id, flash->chip.type_id, flash->chip.capacity_id);
872     } else {
873         SFUD_INFO("Error: Read flash device JEDEC ID error.");
874     }
875 
876     return result;
877 }
878 
879 /**
880  * set the flash write enable or write disable
881  *
882  * @param flash flash device
883  * @param enabled true: enable  false: disable
884  *
885  * @return result
886  */
887 static sfud_err set_write_enabled(const sfud_flash *flash, bool enabled) {
888     sfud_err result = SFUD_SUCCESS;
889     uint8_t cmd, register_status;
890 
891     SFUD_ASSERT(flash);
892 
893     if (enabled) {
894         cmd = SFUD_CMD_WRITE_ENABLE;
895     } else {
896         cmd = SFUD_CMD_WRITE_DISABLE;
897     }
898 
899     result = flash->spi.wr(&flash->spi, &cmd, 1, NULL, 0);
900 
901     if (result == SFUD_SUCCESS) {
902         result = sfud_read_status(flash, &register_status);
903     }
904 
905     if (result == SFUD_SUCCESS) {
906         if (enabled && (register_status & SFUD_STATUS_REGISTER_WEL) == 0) {
907             SFUD_INFO("Error: Can't enable write status.");
908             return SFUD_ERR_WRITE;
909         } else if (!enabled && (register_status & SFUD_STATUS_REGISTER_WEL) != 0) {
910             SFUD_INFO("Error: Can't disable write status.");
911             return SFUD_ERR_WRITE;
912         }
913     }
914 
915     return result;
916 }
917 
918 /**
919  * enable or disable 4-Byte addressing for flash
920  *
921  * @note The 4-Byte addressing just supported for the flash capacity which is large then 16MB (256Mb).
922  *
923  * @param flash flash device
924  * @param enabled true: enable   false: disable
925  *
926  * @return result
927  */
928 static sfud_err set_4_byte_address_mode(sfud_flash *flash, bool enabled) {
929     sfud_err result = SFUD_SUCCESS;
930     uint8_t cmd;
931 
932     SFUD_ASSERT(flash);
933 
934     /* set the flash write enable */
935     result = set_write_enabled(flash, true);
936     if (result != SFUD_SUCCESS) {
937         return result;
938     }
939 
940     if (enabled) {
941         cmd = SFUD_CMD_ENTER_4B_ADDRESS_MODE;
942     } else {
943         cmd = SFUD_CMD_EXIT_4B_ADDRESS_MODE;
944     }
945 
946     result = flash->spi.wr(&flash->spi, &cmd, 1, NULL, 0);
947 
948     if (result == SFUD_SUCCESS) {
949         flash->addr_in_4_byte = enabled ? true : false;
950         SFUD_DEBUG("%s 4-Byte addressing mode success.", enabled ? "Enter" : "Exit");
951     } else {
952         SFUD_INFO("Error: %s 4-Byte addressing mode failed.", enabled ? "Enter" : "Exit");
953     }
954 
955     return result;
956 }
957 
958 /**
959  * read flash register status
960  *
961  * @param flash flash device
962  * @param status register status
963  *
964  * @return result
965  */
966 sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status) {
967     uint8_t cmd = SFUD_CMD_READ_STATUS_REGISTER;
968 
969     SFUD_ASSERT(flash);
970     SFUD_ASSERT(status);
971 
972     return flash->spi.wr(&flash->spi, &cmd, 1, status, 1);
973 }
974 
975 static sfud_err wait_busy(const sfud_flash *flash) {
976     sfud_err result = SFUD_SUCCESS;
977     uint8_t status;
978     size_t retry_times = flash->retry.times;
979 
980     SFUD_ASSERT(flash);
981 
982     while (true) {
983         result = sfud_read_status(flash, &status);
984         if (result == SFUD_SUCCESS && ((status & SFUD_STATUS_REGISTER_BUSY)) == 0) {
985             break;
986         }
987         /* retry counts */
988         SFUD_RETRY_PROCESS(flash->retry.delay, retry_times, result);
989     }
990 
991     if (result != SFUD_SUCCESS || ((status & SFUD_STATUS_REGISTER_BUSY)) != 0) {
992         SFUD_INFO("Error: Flash wait busy has an error.");
993     }
994 
995     return result;
996 }
997 
998 static void make_address_byte_array(const sfud_flash *flash, uint32_t addr, uint8_t *array) {
999     uint8_t len, i;
1000 
1001     SFUD_ASSERT(flash);
1002     SFUD_ASSERT(array);
1003 
1004     len = flash->addr_in_4_byte ? 4 : 3;
1005 
1006     for (i = 0; i < len; i++) {
1007         array[i] = (addr >> ((len - (i + 1)) * 8)) & 0xFF;
1008     }
1009 }
1010 
1011 /**
1012  * write status register
1013  *
1014  * @param flash flash device
1015  * @param is_volatile true: volatile mode, false: non-volatile mode
1016  * @param status register status
1017  *
1018  * @return result
1019  */
1020 sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status) {
1021     sfud_err result = SFUD_SUCCESS;
1022     const sfud_spi *spi = &flash->spi;
1023     uint8_t cmd_data[2];
1024 
1025     SFUD_ASSERT(flash);
1026 
1027     if (is_volatile) {
1028         cmd_data[0] = SFUD_VOLATILE_SR_WRITE_ENABLE;
1029         result = spi->wr(spi, cmd_data, 1, NULL, 0);
1030     } else {
1031         result = set_write_enabled(flash, true);
1032     }
1033 
1034     if (result == SFUD_SUCCESS) {
1035         cmd_data[0] = SFUD_CMD_WRITE_STATUS_REGISTER;
1036         cmd_data[1] = status;
1037         result = spi->wr(spi, cmd_data, 2, NULL, 0);
1038     }
1039 
1040     if (result != SFUD_SUCCESS) {
1041         SFUD_INFO("Error: Write_status register failed.");
1042     }
1043 
1044     return result;
1045 }
1046