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, ®ister_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