openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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