1 /*
2 * This file is part of the Serial Flash Universal Driver Library.
3 *
4 * Copyright (c) 2016-2018, Armink, <[email protected]>
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_adress_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 is initialize success.", flash->name);
99 } else {
100 flash->init_ok = false;
101 SFUD_INFO("Error: %s flash device is initialize fail.", 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 flash->read_cmd_format.instruction = ins + 1;
174 flash->read_cmd_format.address_size = 32;
175 }
176
177 flash->read_cmd_format.instruction_lines = ins_lines;
178 flash->read_cmd_format.address_lines = addr_lines;
179 flash->read_cmd_format.alternate_bytes_lines = 0;
180 flash->read_cmd_format.dummy_cycles = dummy_cycles;
181 flash->read_cmd_format.data_lines = data_lines;
182 }
183
184 /**
185 * Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode.
186 *
187 * it will find the appropriate fast-read instruction to replace the read instruction(0x03)
188 * fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE
189 *
190 * @note When Flash is in QSPI mode, the method must be called after sfud_device_init().
191 *
192 * @param flash flash device
193 * @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4
194 *
195 * @return result
196 */
sfud_qspi_fast_read_enable(sfud_flash * flash,uint8_t data_line_width)197 sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width) {
198 size_t i = 0;
199 uint8_t read_mode = NORMAL_SPI_READ;
200 sfud_err result = SFUD_SUCCESS;
201
202 SFUD_ASSERT(flash);
203 SFUD_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
204
205 /* get read_mode, If don't found, the default is SFUD_QSPI_NORMAL_SPI_READ */
206 for (i = 0; i < sizeof(qspi_flash_ext_info_table) / sizeof(sfud_qspi_flash_ext_info); i++) {
207 if ((qspi_flash_ext_info_table[i].mf_id == flash->chip.mf_id)
208 && (qspi_flash_ext_info_table[i].type_id == flash->chip.type_id)
209 && (qspi_flash_ext_info_table[i].capacity_id == flash->chip.capacity_id)) {
210 read_mode = qspi_flash_ext_info_table[i].read_mode;
211 }
212 }
213
214 /* determine qspi supports which read mode and set read_cmd_format struct */
215 switch (data_line_width) {
216 case 1:
217 qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
218 break;
219 case 2:
220 if (read_mode & DUAL_IO) {
221 qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_IO_READ_DATA, 1, 2, 8, 2);
222 } else if (read_mode & DUAL_OUTPUT) {
223 qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_OUTPUT_READ_DATA, 1, 1, 8, 2);
224 } else {
225 qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
226 }
227 break;
228 case 4:
229 if (read_mode & QUAD_IO) {
230 qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_IO_READ_DATA, 1, 4, 6, 4);
231 } else if (read_mode & QUAD_OUTPUT) {
232 qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_OUTPUT_READ_DATA, 1, 1, 8, 4);
233 } else {
234 qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
235 }
236 break;
237 }
238
239 return result;
240 }
241 #endif /* SFUD_USING_QSPI */
242
243 /**
244 * hardware initialize
245 */
hardware_init(sfud_flash * flash)246 static sfud_err hardware_init(sfud_flash *flash) {
247 extern sfud_err sfud_spi_port_init(sfud_flash * flash);
248
249 sfud_err result = SFUD_SUCCESS;
250 size_t i;
251
252 SFUD_ASSERT(flash);
253
254 result = sfud_spi_port_init(flash);
255 if (result != SFUD_SUCCESS) {
256 return result;
257 }
258
259 #ifdef SFUD_USING_QSPI
260 /* set default read instruction */
261 flash->read_cmd_format.instruction = SFUD_CMD_READ_DATA;
262 #endif /* SFUD_USING_QSPI */
263
264 /* SPI write read function must be initialize */
265 SFUD_ASSERT(flash->spi.wr);
266 /* if the user don't configure flash chip information then using SFDP parameter or static flash parameter table */
267 if (flash->chip.capacity == 0 || flash->chip.write_mode == 0 || flash->chip.erase_gran == 0
268 || flash->chip.erase_gran_cmd == 0) {
269 /* read JEDEC ID include manufacturer ID, memory type ID and flash capacity ID */
270 result = read_jedec_id(flash);
271 if (result != SFUD_SUCCESS) {
272 return result;
273 }
274
275 #ifdef SFUD_USING_SFDP
276 extern bool sfud_read_sfdp(sfud_flash *flash);
277 /* read SFDP parameters */
278 if (sfud_read_sfdp(flash)) {
279 flash->chip.name = NULL;
280 flash->chip.capacity = flash->sfdp.capacity;
281 /* only 1 byte or 256 bytes write mode for SFDP */
282 if (flash->sfdp.write_gran == 1) {
283 flash->chip.write_mode = SFUD_WM_BYTE;
284 } else {
285 flash->chip.write_mode = SFUD_WM_PAGE_256B;
286 }
287 /* find the the smallest erase sector size for eraser. then will use this size for erase granularity */
288 flash->chip.erase_gran = flash->sfdp.eraser[0].size;
289 flash->chip.erase_gran_cmd = flash->sfdp.eraser[0].cmd;
290 for (i = 1; i < SFUD_SFDP_ERASE_TYPE_MAX_NUM; i++) {
291 if (flash->sfdp.eraser[i].size != 0 && flash->chip.erase_gran > flash->sfdp.eraser[i].size) {
292 flash->chip.erase_gran = flash->sfdp.eraser[i].size;
293 flash->chip.erase_gran_cmd = flash->sfdp.eraser[i].cmd;
294 }
295 }
296 } else {
297 #endif
298
299 #ifdef SFUD_USING_FLASH_INFO_TABLE
300 /* read SFDP parameters failed then using SFUD library provided static parameter */
301 for (i = 0; i < sizeof(flash_chip_table) / sizeof(sfud_flash_chip); i++) {
302 if ((flash_chip_table[i].mf_id == flash->chip.mf_id)
303 && (flash_chip_table[i].type_id == flash->chip.type_id)
304 && (flash_chip_table[i].capacity_id == flash->chip.capacity_id)) {
305 flash->chip.name = flash_chip_table[i].name;
306 flash->chip.capacity = flash_chip_table[i].capacity;
307 flash->chip.write_mode = flash_chip_table[i].write_mode;
308 flash->chip.erase_gran = flash_chip_table[i].erase_gran;
309 flash->chip.erase_gran_cmd = flash_chip_table[i].erase_gran_cmd;
310 break;
311 }
312 }
313 #endif
314
315 #ifdef SFUD_USING_SFDP
316 }
317 #endif
318
319 }
320
321 if (flash->chip.capacity == 0 || flash->chip.write_mode == 0 || flash->chip.erase_gran == 0
322 || flash->chip.erase_gran_cmd == 0) {
323 SFUD_INFO("Warning: This flash device is not found or not support.");
324 return SFUD_ERR_NOT_FOUND;
325 } else {
326 const char *flash_mf_name = NULL;
327 /* find the manufacturer information */
328 for (i = 0; i < sizeof(mf_table) / sizeof(sfud_mf); i++) {
329 if (mf_table[i].id == flash->chip.mf_id) {
330 flash_mf_name = mf_table[i].name;
331 break;
332 }
333 }
334 /* print manufacturer and flash chip name */
335 if (flash_mf_name && flash->chip.name) {
336 SFUD_INFO("Find a %s %s flash chip. Size is %ld bytes.", flash_mf_name, flash->chip.name,
337 flash->chip.capacity);
338 } else if (flash_mf_name) {
339 SFUD_INFO("Find a %s flash chip. Size is %ld bytes.", flash_mf_name, flash->chip.capacity);
340 } else {
341 SFUD_INFO("Find a flash chip. Size is %ld bytes.", flash->chip.capacity);
342 }
343 }
344
345 /* reset flash device */
346 result = reset(flash);
347 if (result != SFUD_SUCCESS) {
348 return result;
349 }
350
351 /* I found when the flash write mode is supported AAI mode. The flash all blocks is protected,
352 * so need change the flash status to unprotected before write and erase operate. */
353 if (flash->chip.write_mode & SFUD_WM_AAI) {
354 result = sfud_write_status(flash, true, 0x00);
355 if (result != SFUD_SUCCESS) {
356 return result;
357 }
358 }
359
360 /* if the flash is large than 16MB (256Mb) then enter in 4-Byte addressing mode */
361 if (flash->chip.capacity > (1L << 24)) {
362 result = set_4_byte_address_mode(flash, true);
363 } else {
364 flash->addr_in_4_byte = false;
365 }
366
367 return result;
368 }
369
370 /**
371 * software initialize
372 *
373 * @param flash flash device
374 *
375 * @return result
376 */
software_init(const sfud_flash * flash)377 static sfud_err software_init(const sfud_flash *flash) {
378 sfud_err result = SFUD_SUCCESS;
379
380 SFUD_ASSERT(flash);
381
382 return result;
383 }
384
385 /**
386 * read flash data
387 *
388 * @param flash flash device
389 * @param addr start address
390 * @param size read size
391 * @param data read data pointer
392 *
393 * @return result
394 */
sfud_read(const sfud_flash * flash,uint32_t addr,size_t size,uint8_t * data)395 sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data) {
396 sfud_err result = SFUD_SUCCESS;
397 const sfud_spi *spi = &flash->spi;
398 uint8_t cmd_data[5], cmd_size;
399
400 SFUD_ASSERT(flash);
401 SFUD_ASSERT(data);
402 /* must be call this function after initialize OK */
403 SFUD_ASSERT(flash->init_ok);
404 /* check the flash address bound */
405 if (addr + size > flash->chip.capacity) {
406 SFUD_INFO("Error: Flash address is out of bound.");
407 return SFUD_ERR_ADDR_OUT_OF_BOUND;
408 }
409 /* lock SPI */
410 if (spi->lock) {
411 spi->lock(spi);
412 }
413
414 result = wait_busy(flash);
415
416 if (result == SFUD_SUCCESS) {
417 #ifdef SFUD_USING_QSPI
418 if (flash->read_cmd_format.instruction != SFUD_CMD_READ_DATA) {
419 result = spi->qspi_read(spi, addr, (sfud_qspi_read_cmd_format *)&flash->read_cmd_format, data, size);
420 } else
421 #endif
422 {
423 cmd_data[0] = SFUD_CMD_READ_DATA;
424 make_adress_byte_array(flash, addr, &cmd_data[1]);
425 cmd_size = flash->addr_in_4_byte ? 5 : 4;
426 result = spi->wr(spi, cmd_data, cmd_size, data, size);
427 }
428 }
429 /* unlock SPI */
430 if (spi->unlock) {
431 spi->unlock(spi);
432 }
433
434 return result;
435 }
436
437 /**
438 * erase all flash data
439 *
440 * @param flash flash device
441 *
442 * @return result
443 */
sfud_chip_erase(const sfud_flash * flash)444 sfud_err sfud_chip_erase(const sfud_flash *flash) {
445 sfud_err result = SFUD_SUCCESS;
446 const sfud_spi *spi = &flash->spi;
447 uint8_t cmd_data[4];
448
449 SFUD_ASSERT(flash);
450 /* must be call this function after initialize OK */
451 SFUD_ASSERT(flash->init_ok);
452 /* lock SPI */
453 if (spi->lock) {
454 spi->lock(spi);
455 }
456
457 /* set the flash write enable */
458 result = set_write_enabled(flash, true);
459 if (result != SFUD_SUCCESS) {
460 goto __exit;
461 }
462
463 cmd_data[0] = SFUD_CMD_ERASE_CHIP;
464 /* dual-buffer write, like AT45DB series flash chip erase operate is different for other flash */
465 if (flash->chip.write_mode & SFUD_WM_DUAL_BUFFER) {
466 cmd_data[1] = 0x94;
467 cmd_data[2] = 0x80;
468 cmd_data[3] = 0x9A;
469 result = spi->wr(spi, cmd_data, 4, NULL, 0);
470 } else {
471 result = spi->wr(spi, cmd_data, 1, NULL, 0);
472 }
473 if (result != SFUD_SUCCESS) {
474 SFUD_INFO("Error: Flash chip erase SPI communicate error.");
475 goto __exit;
476 }
477 result = wait_busy(flash);
478
479 __exit:
480 /* set the flash write disable */
481 set_write_enabled(flash, false);
482 /* unlock SPI */
483 if (spi->unlock) {
484 spi->unlock(spi);
485 }
486
487 return result;
488 }
489
490 /**
491 * erase flash data
492 *
493 * @note It will erase align by erase granularity.
494 *
495 * @param flash flash device
496 * @param addr start address
497 * @param size erase size
498 *
499 * @return result
500 */
sfud_erase(const sfud_flash * flash,uint32_t addr,size_t size)501 sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size) {
502 extern size_t sfud_sfdp_get_suitable_eraser(const sfud_flash *flash, uint32_t addr, size_t erase_size);
503
504 sfud_err result = SFUD_SUCCESS;
505 const sfud_spi *spi = &flash->spi;
506 uint8_t cmd_data[5], cmd_size, cur_erase_cmd;
507 size_t cur_erase_size;
508
509 SFUD_ASSERT(flash);
510 /* must be call this function after initialize OK */
511 SFUD_ASSERT(flash->init_ok);
512 /* check the flash address bound */
513 if (addr + size > flash->chip.capacity) {
514 SFUD_INFO("Error: Flash address is out of bound.");
515 return SFUD_ERR_ADDR_OUT_OF_BOUND;
516 }
517
518 if (addr == 0 && size == flash->chip.capacity) {
519 return sfud_chip_erase(flash);
520 }
521
522 /* lock SPI */
523 if (spi->lock) {
524 spi->lock(spi);
525 }
526
527 /* loop erase operate. erase unit is erase granularity */
528 while (size) {
529 /* if this flash is support SFDP parameter, then used SFDP parameter supplies eraser */
530 #ifdef SFUD_USING_SFDP
531 size_t eraser_index;
532 if (flash->sfdp.available) {
533 /* get the suitable eraser for erase process from SFDP parameter */
534 eraser_index = sfud_sfdp_get_suitable_eraser(flash, addr, size);
535 cur_erase_cmd = flash->sfdp.eraser[eraser_index].cmd;
536 cur_erase_size = flash->sfdp.eraser[eraser_index].size;
537 } else {
538 #else
539 {
540 #endif
541 cur_erase_cmd = flash->chip.erase_gran_cmd;
542 cur_erase_size = flash->chip.erase_gran;
543 }
544 /* set the flash write enable */
545 result = set_write_enabled(flash, true);
546 if (result != SFUD_SUCCESS) {
547 goto __exit;
548 }
549
550 cmd_data[0] = cur_erase_cmd;
551 make_adress_byte_array(flash, addr, &cmd_data[1]);
552 cmd_size = flash->addr_in_4_byte ? 5 : 4;
553 result = spi->wr(spi, cmd_data, cmd_size, NULL, 0);
554 if (result != SFUD_SUCCESS) {
555 SFUD_INFO("Error: Flash erase SPI communicate error.");
556 goto __exit;
557 }
558 result = wait_busy(flash);
559 if (result != SFUD_SUCCESS) {
560 goto __exit;
561 }
562 /* make erase align and calculate next erase address */
563 if (addr % cur_erase_size != 0) {
564 if (size > cur_erase_size - (addr % cur_erase_size)) {
565 size -= cur_erase_size - (addr % cur_erase_size);
566 addr += cur_erase_size - (addr % cur_erase_size);
567 } else {
568 goto __exit;
569 }
570 } else {
571 if (size > cur_erase_size) {
572 size -= cur_erase_size;
573 addr += cur_erase_size;
574 } else {
575 goto __exit;
576 }
577 }
578 }
579
580 __exit:
581 /* set the flash write disable */
582 set_write_enabled(flash, false);
583 /* unlock SPI */
584 if (spi->unlock) {
585 spi->unlock(spi);
586 }
587
588 return result;
589 }
590
591 /**
592 * write flash data (no erase operate) for write 1 to 256 bytes per page mode or byte write mode
593 *
594 * @param flash flash device
595 * @param addr start address
596 * @param size write size
597 * @param write_gran write granularity bytes, only support 1 or 256
598 * @param data write data
599 *
600 * @return result
601 */
602 static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
603 const uint8_t *data) {
604 sfud_err result = SFUD_SUCCESS;
605 const sfud_spi *spi = &flash->spi;
606 static uint8_t cmd_data[5 + SFUD_WRITE_MAX_PAGE_SIZE];
607 uint8_t cmd_size;
608 size_t data_size;
609
610 SFUD_ASSERT(flash);
611 /* only support 1 or 256 */
612 SFUD_ASSERT(write_gran == 1 || write_gran == 256);
613 /* must be call this function after initialize OK */
614 SFUD_ASSERT(flash->init_ok);
615 /* check the flash address bound */
616 if (addr + size > flash->chip.capacity) {
617 SFUD_INFO("Error: Flash address is out of bound.");
618 return SFUD_ERR_ADDR_OUT_OF_BOUND;
619 }
620 /* lock SPI */
621 if (spi->lock) {
622 spi->lock(spi);
623 }
624
625 /* loop write operate. write unit is write granularity */
626 while (size) {
627 /* set the flash write enable */
628 result = set_write_enabled(flash, true);
629 if (result != SFUD_SUCCESS) {
630 goto __exit;
631 }
632 cmd_data[0] = SFUD_CMD_PAGE_PROGRAM;
633 make_adress_byte_array(flash, addr, &cmd_data[1]);
634 cmd_size = flash->addr_in_4_byte ? 5 : 4;
635
636 /* make write align and calculate next write address */
637 if (addr % write_gran != 0) {
638 if (size > write_gran - (addr % write_gran)) {
639 data_size = write_gran - (addr % write_gran);
640 } else {
641 data_size = size;
642 }
643 } else {
644 if (size > write_gran) {
645 data_size = write_gran;
646 } else {
647 data_size = size;
648 }
649 }
650 size -= data_size;
651 addr += data_size;
652
653 memcpy(&cmd_data[cmd_size], data, data_size);
654
655 result = spi->wr(spi, cmd_data, cmd_size + data_size, NULL, 0);
656 if (result != SFUD_SUCCESS) {
657 SFUD_INFO("Error: Flash write SPI communicate error.");
658 goto __exit;
659 }
660 result = wait_busy(flash);
661 if (result != SFUD_SUCCESS) {
662 goto __exit;
663 }
664 data += data_size;
665 }
666
667 __exit:
668 /* set the flash write disable */
669 set_write_enabled(flash, false);
670 /* unlock SPI */
671 if (spi->unlock) {
672 spi->unlock(spi);
673 }
674
675 return result;
676 }
677
678 /**
679 * write flash data (no erase operate) for auto address increment mode
680 *
681 * If the address is odd number, it will place one 0xFF before the start of data for protect the old data.
682 * If the latest remain size is 1, it will append one 0xFF at the end of data for protect the old data.
683 *
684 * @param flash flash device
685 * @param addr start address
686 * @param size write size
687 * @param data write data
688 *
689 * @return result
690 */
691 static sfud_err aai_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
692 sfud_err result = SFUD_SUCCESS;
693 const sfud_spi *spi = &flash->spi;
694 uint8_t cmd_data[6], cmd_size;
695 bool first_write = true;
696
697 SFUD_ASSERT(flash);
698 SFUD_ASSERT(flash->init_ok);
699 /* check the flash address bound */
700 if (addr + size > flash->chip.capacity) {
701 SFUD_INFO("Error: Flash address is out of bound.");
702 return SFUD_ERR_ADDR_OUT_OF_BOUND;
703 }
704 /* lock SPI */
705 if (spi->lock) {
706 spi->lock(spi);
707 }
708 /* The address must be even for AAI write mode. So it must write one byte first when address is odd. */
709 if (addr % 2 != 0) {
710 result = page256_or_1_byte_write(flash, addr++, 1, 1, data++);
711 if (result != SFUD_SUCCESS) {
712 goto __exit;
713 }
714 size--;
715 }
716 /* set the flash write enable */
717 result = set_write_enabled(flash, true);
718 if (result != SFUD_SUCCESS) {
719 goto __exit;
720 }
721 /* loop write operate. */
722 cmd_data[0] = SFUD_CMD_AAI_WORD_PROGRAM;
723 while (size >= 2) {
724 if (first_write) {
725 make_adress_byte_array(flash, addr, &cmd_data[1]);
726 cmd_size = flash->addr_in_4_byte ? 5 : 4;
727 cmd_data[cmd_size] = *data;
728 cmd_data[cmd_size + 1] = *(data + 1);
729 first_write = false;
730 } else {
731 cmd_size = 1;
732 cmd_data[1] = *data;
733 cmd_data[2] = *(data + 1);
734 }
735
736 result = spi->wr(spi, cmd_data, cmd_size + 2, NULL, 0);
737 if (result != SFUD_SUCCESS) {
738 SFUD_INFO("Error: Flash write SPI communicate error.");
739 goto __exit;
740 }
741
742 result = wait_busy(flash);
743 if (result != SFUD_SUCCESS) {
744 goto __exit;
745 }
746
747 size -= 2;
748 addr += 2;
749 data += 2;
750 }
751 /* set the flash write disable for exit AAI mode */
752 result = set_write_enabled(flash, false);
753 /* write last one byte data when origin write size is odd */
754 if (result == SFUD_SUCCESS && size == 1) {
755 result = page256_or_1_byte_write(flash, addr, 1, 1, data);
756 }
757
758 __exit:
759 if (result != SFUD_SUCCESS) {
760 set_write_enabled(flash, false);
761 }
762 /* unlock SPI */
763 if (spi->unlock) {
764 spi->unlock(spi);
765 }
766
767 return result;
768 }
769
770 /**
771 * write flash data (no erase operate)
772 *
773 * @param flash flash device
774 * @param addr start address
775 * @param size write size
776 * @param data write data
777 *
778 * @return result
779 */
780 sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
781 sfud_err result = SFUD_SUCCESS;
782
783 if (flash->chip.write_mode & SFUD_WM_PAGE_256B) {
784 result = page256_or_1_byte_write(flash, addr, size, 256, data);
785 } else if (flash->chip.write_mode & SFUD_WM_AAI) {
786 result = aai_write(flash, addr, size, data);
787 } else if (flash->chip.write_mode & SFUD_WM_DUAL_BUFFER) {
788 //TODO dual-buffer write mode
789 }
790
791 return result;
792 }
793
794 /**
795 * erase and write flash data
796 *
797 * @param flash flash device
798 * @param addr start address
799 * @param size write size
800 * @param data write data
801 *
802 * @return result
803 */
804 sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
805 sfud_err result = SFUD_SUCCESS;
806
807 result = sfud_erase(flash, addr, size);
808
809 if (result == SFUD_SUCCESS) {
810 result = sfud_write(flash, addr, size, data);
811 }
812
813 return result;
814 }
815
816 static sfud_err reset(const sfud_flash *flash) {
817 sfud_err result = SFUD_SUCCESS;
818 const sfud_spi *spi = &flash->spi;
819 uint8_t cmd_data[2];
820
821 SFUD_ASSERT(flash);
822
823 cmd_data[0] = SFUD_CMD_ENABLE_RESET;
824 result = spi->wr(spi, cmd_data, 1, NULL, 0);
825 if (result == SFUD_SUCCESS) {
826 result = wait_busy(flash);
827 } else {
828 SFUD_INFO("Error: Flash device reset failed.");
829 return result;
830 }
831
832 cmd_data[1] = SFUD_CMD_RESET;
833 result = spi->wr(spi, &cmd_data[1], 1, NULL, 0);
834
835 if (result == SFUD_SUCCESS) {
836 result = wait_busy(flash);
837 }
838
839 if (result == SFUD_SUCCESS) {
840 SFUD_DEBUG("Flash device reset success.");
841 } else {
842 SFUD_INFO("Error: Flash device reset failed.");
843 }
844
845 return result;
846 }
847
848 static sfud_err read_jedec_id(sfud_flash *flash) {
849 sfud_err result = SFUD_SUCCESS;
850 const sfud_spi *spi = &flash->spi;
851 uint8_t cmd_data[1], recv_data[3];
852
853 SFUD_ASSERT(flash);
854
855 cmd_data[0] = SFUD_CMD_JEDEC_ID;
856 result = spi->wr(spi, cmd_data, sizeof(cmd_data), recv_data, sizeof(recv_data));
857 if (result == SFUD_SUCCESS) {
858 flash->chip.mf_id = recv_data[0];
859 flash->chip.type_id = recv_data[1];
860 flash->chip.capacity_id = recv_data[2];
861 SFUD_DEBUG("The flash device manufacturer ID is 0x%02X, memory type ID is 0x%02X, capacity ID is 0x%02X.",
862 flash->chip.mf_id, flash->chip.type_id, flash->chip.capacity_id);
863 } else {
864 SFUD_INFO("Error: Read flash device JEDEC ID error.");
865 }
866
867 return result;
868 }
869
870 /**
871 * set the flash write enable or write disable
872 *
873 * @param flash flash device
874 * @param enabled true: enable false: disable
875 *
876 * @return result
877 */
878 static sfud_err set_write_enabled(const sfud_flash *flash, bool enabled) {
879 sfud_err result = SFUD_SUCCESS;
880 uint8_t cmd, register_status;
881
882 SFUD_ASSERT(flash);
883
884 if (enabled) {
885 cmd = SFUD_CMD_WRITE_ENABLE;
886 } else {
887 cmd = SFUD_CMD_WRITE_DISABLE;
888 }
889
890 result = flash->spi.wr(&flash->spi, &cmd, 1, NULL, 0);
891
892 if (result == SFUD_SUCCESS) {
893 result = sfud_read_status(flash, ®ister_status);
894 }
895
896 if (result == SFUD_SUCCESS) {
897 if (enabled && (register_status & SFUD_STATUS_REGISTER_WEL) == 0) {
898 SFUD_INFO("Error: Can't enable write status.");
899 return SFUD_ERR_WRITE;
900 } else if (!enabled && (register_status & SFUD_STATUS_REGISTER_WEL) == 1) {
901 SFUD_INFO("Error: Can't disable write status.");
902 return SFUD_ERR_WRITE;
903 }
904 }
905
906 return result;
907 }
908
909 /**
910 * enable or disable 4-Byte addressing for flash
911 *
912 * @note The 4-Byte addressing just supported for the flash capacity which is large then 16MB (256Mb).
913 *
914 * @param flash flash device
915 * @param enabled true: enable false: disable
916 *
917 * @return result
918 */
919 static sfud_err set_4_byte_address_mode(sfud_flash *flash, bool enabled) {
920 sfud_err result = SFUD_SUCCESS;
921 uint8_t cmd;
922
923 SFUD_ASSERT(flash);
924
925 /* set the flash write enable */
926 result = set_write_enabled(flash, true);
927 if (result != SFUD_SUCCESS) {
928 return result;
929 }
930
931 if (enabled) {
932 cmd = SFUD_CMD_ENTER_4B_ADDRESS_MODE;
933 } else {
934 cmd = SFUD_CMD_EXIT_4B_ADDRESS_MODE;
935 }
936
937 result = flash->spi.wr(&flash->spi, &cmd, 1, NULL, 0);
938
939 if (result == SFUD_SUCCESS) {
940 flash->addr_in_4_byte = enabled ? true : false;
941 SFUD_DEBUG("%s 4-Byte addressing mode success.", enabled ? "Enter" : "Exit");
942 } else {
943 SFUD_INFO("Error: %s 4-Byte addressing mode failed.", enabled ? "Enter" : "Exit");
944 }
945
946 return result;
947 }
948
949 /**
950 * read flash register status
951 *
952 * @param flash flash device
953 * @param status register status
954 *
955 * @return result
956 */
957 sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status) {
958 uint8_t cmd = SFUD_CMD_READ_STATUS_REGISTER;
959
960 SFUD_ASSERT(flash);
961 SFUD_ASSERT(status);
962
963 return flash->spi.wr(&flash->spi, &cmd, 1, status, 1);
964 }
965
966 static sfud_err wait_busy(const sfud_flash *flash) {
967 sfud_err result = SFUD_SUCCESS;
968 uint8_t status;
969 size_t retry_times = flash->retry.times;
970
971 SFUD_ASSERT(flash);
972
973 while (true) {
974 result = sfud_read_status(flash, &status);
975 if (result == SFUD_SUCCESS && ((status & SFUD_STATUS_REGISTER_BUSY)) == 0) {
976 break;
977 }
978 /* retry counts */
979 SFUD_RETRY_PROCESS(flash->retry.delay, retry_times, result);
980 }
981
982 if (result != SFUD_SUCCESS || ((status & SFUD_STATUS_REGISTER_BUSY)) != 0) {
983 SFUD_INFO("Error: Flash wait busy has an error.");
984 }
985
986 return result;
987 }
988
989 static void make_adress_byte_array(const sfud_flash *flash, uint32_t addr, uint8_t *array) {
990 uint8_t len, i;
991
992 SFUD_ASSERT(flash);
993 SFUD_ASSERT(array);
994
995 len = flash->addr_in_4_byte ? 4 : 3;
996
997 for (i = 0; i < len; i++) {
998 array[i] = (addr >> ((len - (i + 1)) * 8)) & 0xFF;
999 }
1000 }
1001
1002 /**
1003 * write status register
1004 *
1005 * @param flash flash device
1006 * @param is_volatile true: volatile mode, false: non-volatile mode
1007 * @param status register status
1008 *
1009 * @return result
1010 */
1011 sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status) {
1012 sfud_err result = SFUD_SUCCESS;
1013 const sfud_spi *spi = &flash->spi;
1014 uint8_t cmd_data[2];
1015
1016 SFUD_ASSERT(flash);
1017
1018 if (is_volatile) {
1019 cmd_data[0] = SFUD_VOLATILE_SR_WRITE_ENABLE;
1020 result = spi->wr(spi, cmd_data, 1, NULL, 0);
1021 } else {
1022 result = set_write_enabled(flash, true);
1023 }
1024
1025 if (result == SFUD_SUCCESS) {
1026 cmd_data[0] = SFUD_CMD_WRITE_STATUS_REGISTER;
1027 cmd_data[1] = status;
1028 result = spi->wr(spi, cmd_data, 2, NULL, 0);
1029 }
1030
1031 if (result != SFUD_SUCCESS) {
1032 SFUD_INFO("Error: Write_status register failed.");
1033 }
1034
1035 return result;
1036 }
1037