soc_flash.c (21317B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * Purpose: QSPI Flash Driver 8 */ 9 10 #include <shared/bsl.h> 11 12 #include <sal/core/libc.h> 13 #include <soc/mem.h> 14 #include <soc/error.h> 15 #include <sal/core/spl.h> 16 #include <sal/core/sync.h> 17 #include <sal/core/dpc.h> 18 #include <soc/drv.h> 19 #include <soc/debug.h> 20 #include <soc/soc_flash.h> 21 #ifdef BCM_CMICX_SUPPORT 22 #include <soc/cmicx_qspi.h> 23 #endif 24 #ifdef PCIEFW_QSPI_TEST_PERFORMANCE 25 #include <sal/core/time.h> 26 #endif 27 28 /* Common commands */ 29 #define CMD_READ_ID 0x9f 30 31 #define CMD_READ_ARRAY_SLOW 0x03 32 #define CMD_READ_ARRAY_FAST 0x0b 33 34 #define CMD_WRITE_STATUS 0x01 35 #define CMD_PAGE_PROGRAM 0x02 36 #define CMD_WRITE_DISABLE 0x04 37 #define CMD_READ_STATUS 0x05 38 #define CMD_WRITE_ENABLE 0x06 39 #define CMD_ERASE_4K 0x20 40 #define CMD_ERASE_32K 0x52 41 #define CMD_ERASE_64K 0xd8 42 #define CMD_ERASE_CHIP 0xc7 43 #define CMD_READ_FLAG_STATUS 0x70 44 #define CMD_READ_FLASH_DISCOVERY 0x5A 45 #define CMD_READ_CONFIG 0x35 46 47 #define SPI_FLASH_PROG_TIMEOUT (2 * 200U * 1000) 48 #define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * 200U * 1000) 49 #define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * 200U * 1000) 50 51 #define SPI_FLASH_ID_CYPRESS (0x01) 52 #define SPI_FLASH_ID_MICRON (0x20) 53 #define SPI_FLASH_ID_ISSI (0x9d) 54 #define SPI_FLASH_ID_MACRONIX (0xc2) 55 #define SPI_FLASH_ID_WINBOND (0xef) 56 57 /* SPI transfer flags */ 58 #define SPI_RW_BEGIN 0x01 /* Assert CS before transfer */ 59 #define SPI_RW_END 0x02 /* Deassert CS after transfer */ 60 61 62 /* Common status */ 63 #define STATUS_WIP 0x01 64 #ifndef __KERNEL__ 65 #define max(a, b) (((a) > (b)) ? (a) : (b)) 66 #define min(a, b) (((a) < (b)) ? (a) : (b)) 67 #endif 68 #define ID_LEN 11 69 70 71 /* Configuration register */ 72 #define CYPRESS_CFG_TBPARM (1 << 2) 73 74 typedef struct soc_flash_s { 75 uint8 init; 76 soc_flash_conf_t conf; 77 int (*qspi_init)(int unit, uint32 max_hz, uint32 mode); 78 int (*qspi_cleanup)(int unit); 79 int (*qspi_claim_bus)(int unit); 80 int (*qspi_release_bus)(int unit); 81 int (*qspi_rw)(int unit, uint32 len, const void *dout, 82 void *din, uint32 flags); 83 } soc_flash_t; 84 85 static const soc_flash_conf_t flash_table[] = { 86 /* id page_size sector sector nr_sectors size 87 size size type */ 88 /* Micron MT25QL128/MT25QL256 family */ 89 { SPI_FLASH_ID_MICRON, 0x100, 0x10000, 0, 0x1000, 0 }, 90 /* Cypress/Spansion S25FL128S/S25FL256S family */ 91 { SPI_FLASH_ID_CYPRESS, 0x100, 0x1000, 0, 0x1000, 0 }, 92 /* Macronix MX25L256/MX25L512 family */ 93 { SPI_FLASH_ID_MACRONIX, 0x100, 0x1000, 0, 0x2000, 0 }, 94 /* Winbond 25Q256FV */ 95 { SPI_FLASH_ID_WINBOND, 0x100, 0x10000, 0, 0x1000, 0 }, 96 /* ISSI IS25LP256D/IS25WP256D family */ 97 { SPI_FLASH_ID_ISSI, 0x100, 0x1000, 0, 0x10000, 0 }, 98 }; 99 100 STATIC soc_flash_t soc_flash[SOC_MAX_NUM_DEVICES]; 101 102 static void 103 soc_flash_addr(uint32 addr, uint8 *cmd) 104 { 105 /* cmd[0] is actual command */ 106 cmd[1] = (addr >> 16) & 0xFF; 107 cmd[2] = (addr >> 8) & 0xFF; 108 cmd[3] = (addr) & 0xFF; 109 } 110 111 static int 112 soc_flash_read_write(int unit, 113 const uint8 *cmd, 114 size_t cmd_len, 115 const uint8 *data_out, 116 uint8 *data_in, 117 size_t data_len) 118 { 119 soc_flash_t *flash = &soc_flash[unit]; 120 uint32 flags = SPI_RW_BEGIN; 121 int rv = SOC_E_NONE; 122 #ifdef PCIEFW_QSPI_TEST_PERFORMANCE 123 sal_usecs_t diff; 124 #define PCIEFW_MEASURE_START diff = sal_time_usecs(); 125 #define PCIEFW_MEASURE_END(testname) \ 126 diff = sal_time_usecs() - diff; \ 127 cli_out(" %s: %uus\n", #testname, diff); 128 #else 129 #define PCIEFW_MEASURE_START 130 #define PCIEFW_MEASURE_END(testname) 131 #endif /* PCIEFW_QSPI_TEST_PERFORMANCE */ 132 133 if (data_len == 0) { 134 flags |= SPI_RW_END; 135 } 136 137 PCIEFW_MEASURE_START; 138 rv = flash->qspi_rw(unit, cmd_len, cmd, NULL, flags); 139 PCIEFW_MEASURE_END(soc_flash_read_write_cmd); 140 if (SOC_FAILURE(rv)) { 141 LOG_ERROR(BSL_LS_SOC_SOCMEM, 142 (BSL_META_U(unit, 143 "Error to send command : %d\n"), rv)); 144 } else if (data_len != 0) { 145 PCIEFW_MEASURE_START; 146 rv = flash->qspi_rw(unit, data_len, data_out, 147 data_in, SPI_RW_END); 148 PCIEFW_MEASURE_END(soc_flash_read_write_data); 149 if (SOC_FAILURE(rv)) { 150 LOG_ERROR(BSL_LS_SOC_SOCMEM, 151 (BSL_META_U(unit, 152 "Error to transfer data: %d"), rv)); 153 } 154 } 155 156 return rv; 157 } 158 159 static int 160 soc_flash_cmd_read(int unit, 161 const uint8 *cmd, 162 size_t cmd_len, 163 void *data, 164 size_t data_len) 165 { 166 int rv = SOC_E_NONE; 167 168 rv = soc_flash_read_write(unit, cmd, cmd_len, NULL, data, data_len); 169 170 return rv; 171 } 172 173 static int 174 soc_flash_cmd(int unit, 175 uint8 cmd, 176 void *response, 177 size_t len) 178 { 179 int rv = SOC_E_NONE; 180 181 rv = soc_flash_cmd_read(unit, &cmd, 1, response, len); 182 183 return rv; 184 } 185 186 static int 187 soc_flash_wait_cmd_complete(int unit, uint32 timeout) 188 { 189 int rv = SOC_E_NONE; 190 soc_timeout_t to; 191 uint8 status; 192 uint8 cmd; 193 #ifdef PCIEFW_QSPI_TEST_PERFORMANCE 194 sal_usecs_t diff; 195 #endif /* PCIEFW_QSPI_TEST_PERFORMANCE */ 196 197 cmd = CMD_READ_STATUS; 198 199 soc_timeout_init(&to, timeout, 1); 200 while(1) { 201 PCIEFW_MEASURE_START; 202 rv = soc_flash_cmd_read(unit, &cmd, sizeof(cmd), &status, 1); 203 PCIEFW_MEASURE_END(soc_flash_wait_cmd_complete_read); 204 if (SOC_FAILURE(rv)) { 205 break; 206 } 207 208 if ((status & STATUS_WIP) == 0){ 209 break; 210 } 211 if (soc_timeout_check(&to)) { 212 /* Timed out */ 213 LOG_ERROR(BSL_LS_SOC_SOCMEM, 214 (BSL_META_U(unit, 215 "Time out:\n"))); 216 rv = SOC_E_TIMEOUT; 217 break; 218 } 219 } 220 LOG_VERBOSE(BSL_LS_SOC_SOCMEM, 221 (BSL_META_U(unit, 222 "Status Register = 0x%x\n"), status)); 223 return rv; 224 } 225 226 static int 227 soc_flash_cmd_write(int unit, 228 const uint8 *cmd, 229 size_t cmd_len, 230 const void *data, 231 size_t data_len, 232 uint32 timeout) 233 { 234 int rv = SOC_E_NONE; 235 236 rv = soc_flash_read_write(unit, cmd, cmd_len, data, NULL, data_len); 237 if (SOC_SUCCESS(rv)) { 238 rv = soc_flash_wait_cmd_complete(unit, timeout); 239 } 240 241 return rv; 242 } 243 244 /* 245 * Enable writing on the SPI flash. 246 */ 247 static int 248 soc_flash_cmd_write_enable(int unit) 249 { 250 int rv = SOC_E_NONE; 251 252 rv = soc_flash_cmd(unit, CMD_WRITE_ENABLE, NULL, 0); 253 254 return rv; 255 } 256 #if 0 257 /* 258 * Disable writing on the SPI flash. 259 */ 260 static int 261 soc_flash_cmd_write_disable(int unit) 262 { 263 int rv = SOC_E_NONE; 264 265 rv = soc_flash_cmd(unit, CMD_WRITE_DISABLE, NULL, 0); 266 267 return rv; 268 } 269 #endif 270 271 static int 272 soc_flash_read_common(int unit, 273 const uint8 *cmd, 274 size_t cmd_len, 275 void *data, 276 size_t data_len) 277 { 278 int rv = SOC_E_NONE; 279 soc_flash_t *flash = &soc_flash[unit]; 280 281 rv = flash->qspi_claim_bus(unit); 282 if (SOC_SUCCESS(rv)) { 283 rv = soc_flash_cmd_read(unit, cmd, cmd_len, data, data_len); 284 rv = flash->qspi_release_bus(unit); 285 } 286 287 return rv; 288 } 289 290 int 291 soc_flash_cmd_write_status(int unit, uint8 sr) 292 { 293 uint8 cmd; 294 int rv = SOC_E_NONE; 295 296 rv = soc_flash_cmd_write_enable(unit); 297 if (SOC_FAILURE(rv)) { 298 LOG_ERROR(BSL_LS_SOC_SOCMEM, 299 (BSL_META_U(unit, 300 "SF: enabling write failed\n"))); 301 return rv; 302 } 303 304 cmd = CMD_WRITE_STATUS; 305 rv = soc_flash_cmd_write(unit, &cmd, 1, &sr, 1, SPI_FLASH_PROG_TIMEOUT); 306 if (SOC_FAILURE(rv)) { 307 LOG_ERROR(BSL_LS_SOC_SOCMEM, 308 (BSL_META_U(unit, 309 "SF: fail to write status register\n"))); 310 return rv; 311 } 312 313 return 0; 314 } 315 316 static int 317 qspi_init(int unit, uint32 max_hz, uint32 mode) 318 { 319 return SOC_E_UNAVAIL; 320 } 321 static int 322 qspi_cleanup(int unit) 323 { 324 return SOC_E_UNAVAIL; 325 } 326 static int 327 qspi_claim_bus(int unit) 328 { 329 return SOC_E_UNAVAIL; 330 } 331 static int 332 qspi_release_bus(int unit) 333 { 334 return SOC_E_UNAVAIL; 335 } 336 static int 337 qspi_rw(int unit, uint32 len, const void *dout, void *din, uint32 flags) 338 { 339 return SOC_E_UNAVAIL; 340 } 341 342 int 343 soc_flash_discovery_read(int unit, 344 size_t len, 345 void *data) 346 { 347 int rv = SOC_E_NONE; 348 uint8 cmd[5]; 349 350 cmd[0] = CMD_READ_FLASH_DISCOVERY; 351 soc_flash_addr(0, cmd); 352 cmd[4] = 0; 353 rv = soc_flash_read_common(unit, cmd, sizeof(cmd), data, len); 354 355 return rv; 356 } 357 358 359 int 360 soc_flash_init(int unit, 361 uint32 max_hz, 362 uint32 mode, 363 soc_flash_conf_t *flash_conf) 364 { 365 soc_flash_t *flash = &soc_flash[unit]; 366 int i; 367 uint8 id[ID_LEN]; 368 uint8 param[128]; 369 int rv = SOC_E_NONE; 370 uint8 status; 371 372 sal_memset(flash, 0 , sizeof(soc_flash_t)); 373 374 flash->qspi_init = qspi_init; 375 flash->qspi_cleanup = qspi_cleanup; 376 flash->qspi_rw = qspi_rw; 377 flash->qspi_claim_bus = qspi_claim_bus; 378 flash->qspi_release_bus = qspi_release_bus; 379 380 #ifdef BCM_CMICX_SUPPORT 381 if (soc_feature(unit, soc_feature_cmicx)) { 382 flash->qspi_init = cmicx_qspi_init; 383 flash->qspi_cleanup = cmicx_qspi_cleanup; 384 flash->qspi_rw = cmicx_qspi_rw; 385 flash->qspi_claim_bus = cmicx_qspi_claim_bus; 386 flash->qspi_release_bus = cmicx_qspi_release_bus; 387 } 388 #endif 389 rv = flash->qspi_init(unit, max_hz, mode); 390 if (SOC_FAILURE(rv)) { 391 goto error_init; 392 } 393 rv = flash->qspi_claim_bus(unit); 394 if (SOC_FAILURE(rv)) { 395 LOG_ERROR(BSL_LS_SOC_SOCMEM, 396 (BSL_META_U(unit, 397 "Error to claim SPI bus: %d\n"), 398 rv)); 399 goto err_claim_bus; 400 } 401 /* Read the ID codes */ 402 rv = soc_flash_cmd(unit, CMD_READ_ID, id, sizeof(id)); 403 if (SOC_FAILURE(rv)) { 404 goto err_read_id; 405 } 406 /* search the table for matches in shift and id */ 407 rv = SOC_E_UNAVAIL; 408 for (i = 0; i < sizeof(flash_table) / sizeof(soc_flash_conf_t); ++i) { 409 if (flash_table[i].id == id[0]) { 410 /* we have a match */ 411 flash->conf.id = flash_table[i].id; 412 flash->conf.size = 1 << id[2]; 413 if (id[0] == SPI_FLASH_ID_CYPRESS) { 414 /* Cypress/Spansion */ 415 if (id[4]) { 416 /* Hybrid sector size, 32x4KB at top or bottom, 417 rest of them 64KB size */ 418 flash->conf.sector_type = SOC_FLASH_SECTOR_TYPE_HYBRID; 419 flash->conf.sector_size = 0x10000; /* Set to 64K */ 420 flash->conf.nr_sectors = flash->conf.size / 0x10000 + 30; 421 flash->conf.page_size = 256; 422 } 423 else { 424 /* Uniform 256KB sectors */ 425 flash->conf.sector_type = SOC_FLASH_SECTOR_TYPE_UNIFORM; 426 flash->conf.sector_size = 0x40000; 427 flash->conf.nr_sectors = flash->conf.size / 428 flash->conf.sector_size; 429 flash->conf.page_size = 512; 430 } 431 } 432 else { 433 flash->conf.page_size = flash_table[i].page_size; 434 flash->conf.sector_type = SOC_FLASH_SECTOR_TYPE_UNIFORM; 435 flash->conf.sector_size = flash_table[i].sector_size; 436 flash->conf.nr_sectors = flash->conf.size / 437 flash->conf.sector_size; 438 } 439 rv = SOC_E_NONE; 440 break; 441 } 442 } 443 444 if (SOC_FAILURE(rv)) { 445 LOG_ERROR(BSL_LS_SOC_SOCMEM, 446 (BSL_META_U(unit, 447 "Flash not supported = 0x%x\n"), id[0])); 448 goto err_read_id; 449 } 450 else { 451 LOG_ERROR(BSL_LS_SOC_SOCMEM, 452 (BSL_META_U(unit, 453 "Flash supported ID = 0x%x\n"), id[0])); 454 } 455 /* Read the Discovery parameter */ 456 rv = soc_flash_discovery_read(unit, sizeof(param), param); 457 /* Read Flag Status Register */ 458 rv = soc_flash_cmd(unit, CMD_READ_FLAG_STATUS, &status, 1); 459 if (SOC_FAILURE(rv)) { 460 LOG_ERROR(BSL_LS_SOC_SOCMEM, 461 (BSL_META_U(unit, 462 "Error reading Flag Status\n"))); 463 goto err_read_id; 464 } else { 465 LOG_VERBOSE(BSL_LS_SOC_SOCMEM, 466 (BSL_META_U(unit, 467 "Flag Status = 0x%x\n"), status)); 468 } 469 flash->init = 1; 470 sal_memcpy(flash_conf, &flash->conf, sizeof(soc_flash_conf_t)); 471 flash->qspi_release_bus(unit); 472 473 return rv; 474 475 err_read_id: 476 flash->qspi_release_bus(unit); 477 err_claim_bus: 478 flash->qspi_cleanup(unit); 479 error_init: 480 return rv; 481 } 482 483 int 484 soc_flash_cleanup(int unit) 485 { 486 soc_flash_t *flash = &soc_flash[unit]; 487 int rv = SOC_E_NONE; 488 489 if (!flash->init) { 490 return SOC_E_INIT; 491 } 492 493 rv = flash->qspi_cleanup(unit); 494 flash->init = 0; 495 496 return rv; 497 } 498 499 int 500 soc_flash_read(int unit, 501 uint32 offset, 502 size_t len, 503 void *data) 504 { 505 int rv = SOC_E_NONE; 506 soc_flash_t *flash = &soc_flash[unit]; 507 uint8 cmd[5]; 508 509 if (!flash->init) { 510 return SOC_E_INIT; 511 } 512 cmd[0] = CMD_READ_ARRAY_FAST; 513 soc_flash_addr(offset, cmd); 514 cmd[4] = 0; 515 rv = soc_flash_read_common(unit, cmd, sizeof(cmd), data, len); 516 517 return rv; 518 } 519 520 int 521 soc_flash_write(int unit, 522 uint32 offset, 523 size_t len, 524 const void *buf) 525 { 526 soc_flash_t *flash = &soc_flash[unit]; 527 uint32 page_size, data_offset; 528 int rv = SOC_E_NONE; 529 uint8 cmd[5]; 530 #ifdef PCIEFW_QSPI_TEST_PERFORMANCE 531 sal_usecs_t diff; 532 #endif /* PCIEFW_QSPI_TEST_PERFORMANCE */ 533 534 if (!flash->init) { 535 return SOC_E_INIT; 536 } 537 538 page_size = flash->conf.page_size; 539 rv = flash->qspi_claim_bus(unit); 540 if (SOC_FAILURE(rv)) { 541 LOG_ERROR(BSL_LS_SOC_SOCMEM, 542 (BSL_META_U(unit, 543 "Error to claim SPI bus\n"))); 544 return rv; 545 } 546 547 cmd[0] = CMD_PAGE_PROGRAM; 548 cmd[4] = 0; 549 550 /* Distance from the page boundary */ 551 data_offset = (page_size - (offset & 0xFF) ) & 0xFF; 552 if (data_offset > len) { 553 data_offset = len; 554 } 555 /* first page if non aligned */ 556 if (data_offset > 0) { 557 PCIEFW_MEASURE_START; 558 rv = soc_flash_cmd_write_enable(unit); 559 PCIEFW_MEASURE_END(soc_flash_cmd_write_enable); 560 if (SOC_FAILURE(rv)) { 561 LOG_ERROR(BSL_LS_SOC_SOCMEM, 562 (BSL_META_U(unit, 563 "Write enable failed"))); 564 goto error; 565 } 566 soc_flash_addr(offset, cmd); 567 PCIEFW_MEASURE_START; 568 rv = soc_flash_cmd_write(unit, cmd, 4, 569 buf, data_offset, SPI_FLASH_PROG_TIMEOUT); 570 PCIEFW_MEASURE_END(soc_flash_cmd_write); 571 if (SOC_FAILURE(rv)) { 572 LOG_ERROR(BSL_LS_SOC_SOCMEM, 573 (BSL_META_U(unit, 574 "Write failed"))); 575 goto error; 576 } 577 LOG_CLI(("\n.")); 578 } 579 580 for ( ; (data_offset + page_size) < len; data_offset += page_size) { 581 PCIEFW_MEASURE_START; 582 rv = soc_flash_cmd_write_enable(unit); 583 PCIEFW_MEASURE_END(soc_flash_cmd_write_enable); 584 if (SOC_FAILURE(rv)) { 585 LOG_ERROR(BSL_LS_SOC_SOCMEM, 586 (BSL_META_U(unit, 587 "Write enable failed"))); 588 goto error; 589 } 590 591 soc_flash_addr(offset + data_offset, cmd); 592 rv = soc_flash_cmd_write(unit, cmd, 4, ((uint8*)buf) + data_offset, 593 page_size, SPI_FLASH_PROG_TIMEOUT); 594 if (SOC_FAILURE(rv)) { 595 LOG_ERROR(BSL_LS_SOC_SOCMEM, 596 (BSL_META_U(unit, 597 "Write failed"))); 598 goto error; 599 } 600 LOG_CLI((".")); 601 } 602 /* last partial page */ 603 if (len > data_offset) { 604 PCIEFW_MEASURE_START; 605 rv = soc_flash_cmd_write_enable(unit); 606 PCIEFW_MEASURE_END(soc_flash_cmd_write_enable); 607 if (SOC_FAILURE(rv)) { 608 LOG_ERROR(BSL_LS_SOC_SOCMEM, 609 (BSL_META_U(unit, 610 "Write enable failed"))); 611 goto error; 612 } 613 614 soc_flash_addr(offset + data_offset, cmd); 615 PCIEFW_MEASURE_START; 616 rv = soc_flash_cmd_write(unit, cmd, 4, ((uint8*)buf) + data_offset, 617 (len - data_offset), SPI_FLASH_PROG_TIMEOUT); 618 PCIEFW_MEASURE_END(soc_flash_cmd_write); 619 } 620 if (SOC_FAILURE(rv)) { 621 LOG_ERROR(BSL_LS_SOC_SOCMEM, 622 (BSL_META_U(unit, 623 "Write failed"))); 624 goto error; 625 } 626 LOG_CLI((". Done\n")); 627 628 error: 629 630 rv = flash->qspi_release_bus(unit); 631 return rv; 632 } 633 634 static int 635 _soc_flash_erase_hybrid(int unit, 636 uint32 offset, 637 size_t len) 638 { 639 uint32 start, end, erase_size, start_hybrid, end_hybrid; 640 int rv = SOC_E_NONE; 641 soc_flash_t *flash = &soc_flash[unit]; 642 uint8 cmd[4], cfg; 643 644 rv = soc_flash_cmd(unit, CMD_READ_CONFIG, &cfg, 1); 645 if (SOC_FAILURE(rv)) { 646 LOG_ERROR(BSL_LS_SOC_SOCMEM, 647 (BSL_META_U(unit, 648 "Configuration register read failed\n"))); 649 return rv; 650 } 651 if (cfg & CYPRESS_CFG_TBPARM) { 652 /* 4KB sectors at high address */ 653 end_hybrid = flash->conf.size; 654 start_hybrid = flash->conf.size - (32 * 0x1000); 655 } 656 else { 657 /* 4KB sectors at low address */ 658 end_hybrid = 32 * 0x1000; 659 start_hybrid = 0; 660 } 661 662 if (offset >= start_hybrid && offset < end_hybrid) { 663 erase_size = 0x1000; /* 4KB */ 664 } 665 else { 666 erase_size = flash->conf.sector_size; 667 } 668 if ((offset > 0) && (offset % erase_size)){ 669 LOG_ERROR(BSL_LS_SOC_SOCMEM, 670 (BSL_META_U(unit, 671 "Erase offset is not sector boudary\n"))); 672 return SOC_E_PARAM; 673 } 674 675 rv = flash->qspi_claim_bus(unit); 676 if (SOC_FAILURE(rv)) { 677 LOG_ERROR(BSL_LS_SOC_SOCMEM, 678 (BSL_META_U(unit, 679 "Unable to claim SPI bus\n"))); 680 return rv; 681 } 682 683 start = offset; 684 end = start + len; 685 686 while (offset < end) { 687 if (offset >= start_hybrid && offset < end_hybrid) { 688 erase_size = 0x1000; /* 4KB */ 689 cmd[0] = CMD_ERASE_4K; 690 } 691 else { 692 erase_size = flash->conf.sector_size; 693 cmd[0] = CMD_ERASE_64K; 694 } 695 soc_flash_addr(offset, cmd); 696 offset += erase_size; 697 rv = soc_flash_cmd_write_enable(unit); 698 if (SOC_FAILURE(rv)) { 699 goto error; 700 } 701 rv = soc_flash_cmd_write(unit, cmd, sizeof(cmd), 702 NULL, 0, SPI_FLASH_PAGE_ERASE_TIMEOUT); 703 if (SOC_FAILURE(rv)) { 704 goto error; 705 } 706 } 707 error: 708 flash->qspi_release_bus(unit); 709 return rv; 710 } 711 712 int 713 soc_flash_erase(int unit, 714 uint32 offset, 715 size_t len) 716 { 717 uint32 start, end, erase_size; 718 int rv = SOC_E_NONE; 719 soc_flash_t *flash = &soc_flash[unit]; 720 uint8 cmd[4]; 721 722 if (!flash->init) { 723 return SOC_E_INIT; 724 } 725 726 if (flash->conf.sector_type == SOC_FLASH_SECTOR_TYPE_HYBRID) { 727 return(_soc_flash_erase_hybrid(unit, offset, len)); 728 } 729 erase_size = flash->conf.sector_size; 730 if ((offset > 0) && (offset % erase_size)){ 731 LOG_ERROR(BSL_LS_SOC_SOCMEM, 732 (BSL_META_U(unit, 733 "Erase offset is not sector boundary\n"))); 734 return SOC_E_PARAM; 735 } 736 /* make erase length at sector boundary */ 737 len = (len % erase_size) ? (len / erase_size + 1) : (len / erase_size); 738 len *= erase_size; 739 740 rv = flash->qspi_claim_bus(unit); 741 if (SOC_FAILURE(rv)) { 742 LOG_ERROR(BSL_LS_SOC_SOCMEM, 743 (BSL_META_U(unit, 744 "Unable to claim SPI bus\n"))); 745 return rv; 746 } 747 if (erase_size == 4096) { 748 cmd[0] = CMD_ERASE_4K; 749 } else { 750 cmd[0] = CMD_ERASE_64K; 751 } 752 start = offset; 753 end = start + len; 754 755 while (offset < end) { 756 soc_flash_addr(offset, cmd); 757 offset += erase_size; 758 rv = soc_flash_cmd_write_enable(unit); 759 if (SOC_FAILURE(rv)) { 760 goto error; 761 } 762 rv = soc_flash_cmd_write(unit, cmd, sizeof(cmd), 763 NULL, 0, SPI_FLASH_PAGE_ERASE_TIMEOUT); 764 if (SOC_FAILURE(rv)) { 765 goto error; 766 } 767 } 768 error: 769 flash->qspi_release_bus(unit); 770 return rv; 771 } 772