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 */ 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 */ 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 */ 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 */ 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 */ 161 const sfud_flash *sfud_get_device_table(void) { 162 return flash_table; 163 } 164 165 #ifdef SFUD_USING_QSPI 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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