qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

flash_spi.c (11962B)


      1 // Copyright 2021 Westberry Technology (ChangZhou) Corp., Ltd
      2 // Copyright 2024 Nick Brassel (@tzarc)
      3 // SPDX-License-Identifier: GPL-2.0-or-later
      4 
      5 #include <string.h>
      6 
      7 #include "flash.h"
      8 #include "util.h"
      9 #include "wait.h"
     10 #include "debug.h"
     11 #include "timer.h"
     12 #include "flash_spi.h"
     13 #include "spi_master.h"
     14 
     15 /*
     16     The time-out time of spi flash transmission.
     17 */
     18 #ifndef EXTERNAL_FLASH_SPI_TIMEOUT
     19 #    define EXTERNAL_FLASH_SPI_TIMEOUT 1000
     20 #endif
     21 
     22 /* ID comands */
     23 #define FLASH_CMD_RDID 0x9F /* RDID (Read Identification) */
     24 #define FLASH_CMD_RES 0xAB  /* RES (Read Electronic ID) */
     25 #define FLASH_CMD_REMS 0x90 /* REMS (Read Electronic & Device ID) */
     26 
     27 /* register comands */
     28 #define FLASH_CMD_WRSR 0x01 /* WRSR (Write Status register) */
     29 #define FLASH_CMD_RDSR 0x05 /* RDSR (Read Status register) */
     30 
     31 /* READ comands */
     32 #define FLASH_CMD_READ 0x03     /* READ (1 x I/O) */
     33 #define FLASH_CMD_FASTREAD 0x0B /* FAST READ (Fast read data) */
     34 #define FLASH_CMD_DREAD 0x3B    /* DREAD (1In/2 Out fast read) */
     35 
     36 /* Program comands */
     37 #define FLASH_CMD_WREN 0x06 /* WREN (Write Enable) */
     38 #define FLASH_CMD_WRDI 0x04 /* WRDI (Write Disable) */
     39 #define FLASH_CMD_PP 0x02   /* PP (page program) */
     40 
     41 /* Erase comands */
     42 #define FLASH_CMD_SE 0x20 /* SE (Sector Erase) */
     43 #define FLASH_CMD_BE 0xD8 /* BE (Block Erase) */
     44 #define FLASH_CMD_CE 0x60 /* CE (Chip Erase) hex code: 60 or C7 */
     45 
     46 /* Mode setting comands */
     47 #define FLASH_CMD_DP 0xB9  /* DP (Deep Power Down) */
     48 #define FLASH_CMD_RDP 0xAB /* RDP (Release from Deep Power Down) */
     49 
     50 /* Status register */
     51 #define FLASH_FLAG_WIP 0x01 /* Write in progress bit */
     52 #define FLASH_FLAG_WEL 0x02 /* Write enable latch bit */
     53 
     54 // #define DEBUG_FLASH_SPI_OUTPUT
     55 
     56 static bool spi_flash_start(void) {
     57     return spi_start(EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN, EXTERNAL_FLASH_SPI_LSBFIRST, EXTERNAL_FLASH_SPI_MODE, EXTERNAL_FLASH_SPI_CLOCK_DIVISOR);
     58 }
     59 
     60 static flash_status_t spi_flash_wait_while_busy_multiplier(int multiplier) {
     61     flash_status_t response = FLASH_STATUS_SUCCESS;
     62     uint32_t       deadline = timer_read32() + ((EXTERNAL_FLASH_SPI_TIMEOUT)*multiplier);
     63     do {
     64         if (timer_read32() >= deadline) {
     65             response = FLASH_STATUS_TIMEOUT;
     66             break;
     67         }
     68 
     69         response = flash_is_busy();
     70     } while (response == FLASH_STATUS_BUSY);
     71     return response;
     72 }
     73 
     74 static flash_status_t spi_flash_wait_while_busy(void) {
     75     return spi_flash_wait_while_busy_multiplier(1);
     76 }
     77 
     78 flash_status_t flash_is_busy(void) {
     79     bool res = spi_flash_start();
     80     if (!res) {
     81         dprint("Failed to start SPI! [spi flash wait while busy]\n");
     82         return FLASH_STATUS_ERROR;
     83     }
     84 
     85     spi_write(FLASH_CMD_RDSR);
     86     spi_status_t status = spi_read();
     87     spi_stop();
     88 
     89     if (status < 0) {
     90         return status;
     91     }
     92 
     93     uint8_t sr = (uint8_t)status;
     94     return (sr & FLASH_FLAG_WIP) ? FLASH_STATUS_BUSY : FLASH_STATUS_SUCCESS;
     95 }
     96 
     97 static flash_status_t spi_flash_write_enable(void) {
     98     bool res = spi_flash_start();
     99     if (!res) {
    100         dprint("Failed to start SPI! [spi flash write enable]\n");
    101         return FLASH_STATUS_ERROR;
    102     }
    103 
    104     spi_write(FLASH_CMD_WREN);
    105     spi_stop();
    106 
    107     return FLASH_STATUS_SUCCESS;
    108 }
    109 
    110 static flash_status_t spi_flash_write_disable(void) {
    111     bool res = spi_flash_start();
    112     if (!res) {
    113         dprint("Failed to start SPI! [spi flash write disable]\n");
    114         return FLASH_STATUS_ERROR;
    115     }
    116 
    117     spi_write(FLASH_CMD_WRDI);
    118     spi_stop();
    119 
    120     return FLASH_STATUS_SUCCESS;
    121 }
    122 
    123 /* This function is used for read transfer, write transfer and erase transfer. */
    124 static flash_status_t spi_flash_transaction(uint8_t cmd, uint32_t addr, uint8_t *data, size_t len) {
    125     flash_status_t response = FLASH_STATUS_SUCCESS;
    126     uint8_t        buffer[EXTERNAL_FLASH_ADDRESS_SIZE + 1];
    127 
    128     buffer[0] = cmd;
    129     for (int i = 0; i < EXTERNAL_FLASH_ADDRESS_SIZE; ++i) {
    130         buffer[EXTERNAL_FLASH_ADDRESS_SIZE - i] = addr & 0xFF;
    131         addr >>= 8;
    132     }
    133 
    134     bool res = spi_flash_start();
    135     if (!res) {
    136         dprint("Failed to start SPI! [spi flash transmit]\n");
    137         return FLASH_STATUS_ERROR;
    138     }
    139 
    140     response = spi_transmit(buffer, sizeof(buffer));
    141 
    142     if ((!response) && (data != NULL)) {
    143         switch (cmd) {
    144             case FLASH_CMD_READ:
    145                 response = spi_receive(data, len);
    146                 break;
    147             case FLASH_CMD_PP:
    148                 response = spi_transmit(data, len);
    149                 break;
    150             default:
    151                 response = FLASH_STATUS_ERROR;
    152                 break;
    153         }
    154     }
    155 
    156     spi_stop();
    157 
    158     return response;
    159 }
    160 
    161 void flash_init(void) {
    162     spi_init();
    163 }
    164 
    165 flash_status_t flash_begin_erase_chip(void) {
    166     flash_status_t response = FLASH_STATUS_SUCCESS;
    167 
    168     /* Wait for the write-in-progress bit to be cleared. */
    169     response = spi_flash_wait_while_busy();
    170     if (response != FLASH_STATUS_SUCCESS) {
    171         dprint("Failed to check WIP flag! [spi flash erase chip]\n");
    172         return response;
    173     }
    174 
    175     /* Enable writes. */
    176     response = spi_flash_write_enable();
    177     if (response != FLASH_STATUS_SUCCESS) {
    178         dprint("Failed to write-enable! [spi flash erase chip]\n");
    179         return response;
    180     }
    181 
    182     /* Erase Chip. */
    183     bool res = spi_flash_start();
    184     if (!res) {
    185         dprint("Failed to start SPI! [spi flash erase chip]\n");
    186         return FLASH_STATUS_ERROR;
    187     }
    188     spi_write(FLASH_CMD_CE);
    189     spi_stop();
    190     return FLASH_STATUS_SUCCESS;
    191 }
    192 
    193 flash_status_t flash_wait_erase_chip(void) {
    194     flash_status_t response = spi_flash_wait_while_busy_multiplier(250); // Chip erase can take a long time, wait 250x the usual timeout
    195     if (response != FLASH_STATUS_SUCCESS) {
    196         dprint("Failed to check WIP flag! [spi flash erase chip]\n");
    197         return response;
    198     }
    199     return response;
    200 }
    201 
    202 flash_status_t flash_erase_chip(void) {
    203     flash_status_t response = flash_begin_erase_chip();
    204     if (response != FLASH_STATUS_SUCCESS) {
    205         dprint("Failed to begin erase chip! [spi flash erase chip]\n");
    206         return response;
    207     }
    208 
    209     return flash_wait_erase_chip();
    210 }
    211 
    212 flash_status_t flash_erase_sector(uint32_t addr) {
    213     flash_status_t response = FLASH_STATUS_SUCCESS;
    214 
    215     /* Check that the address exceeds the limit. */
    216     if ((addr + (EXTERNAL_FLASH_SECTOR_SIZE)) >= (EXTERNAL_FLASH_SIZE) || ((addr % (EXTERNAL_FLASH_SECTOR_SIZE)) != 0)) {
    217         dprintf("Flash erase sector address over limit! [addr:0x%lx]\n", (uint32_t)addr);
    218         return FLASH_STATUS_ERROR;
    219     }
    220 
    221     /* Wait for the write-in-progress bit to be cleared. */
    222     response = spi_flash_wait_while_busy();
    223     if (response != FLASH_STATUS_SUCCESS) {
    224         dprint("Failed to check WIP flag! [spi flash erase sector]\n");
    225         return response;
    226     }
    227 
    228     /* Enable writes. */
    229     response = spi_flash_write_enable();
    230     if (response != FLASH_STATUS_SUCCESS) {
    231         dprint("Failed to write-enable! [spi flash erase sector]\n");
    232         return response;
    233     }
    234 
    235     /* Erase Sector. */
    236     response = spi_flash_transaction(FLASH_CMD_SE, addr, NULL, 0);
    237     if (response != FLASH_STATUS_SUCCESS) {
    238         dprint("Failed to erase sector! [spi flash erase sector]\n");
    239         return response;
    240     }
    241 
    242     /* Wait for the write-in-progress bit to be cleared.*/
    243     response = spi_flash_wait_while_busy();
    244     if (response != FLASH_STATUS_SUCCESS) {
    245         dprint("Failed to check WIP flag! [spi flash erase sector]\n");
    246         return response;
    247     }
    248 
    249     return response;
    250 }
    251 
    252 flash_status_t flash_erase_block(uint32_t addr) {
    253     flash_status_t response = FLASH_STATUS_SUCCESS;
    254 
    255     /* Check that the address exceeds the limit. */
    256     if ((addr + (EXTERNAL_FLASH_BLOCK_SIZE)) >= (EXTERNAL_FLASH_SIZE) || ((addr % (EXTERNAL_FLASH_BLOCK_SIZE)) != 0)) {
    257         dprintf("Flash erase block address over limit! [addr:0x%lx]\n", (uint32_t)addr);
    258         return FLASH_STATUS_ERROR;
    259     }
    260 
    261     /* Wait for the write-in-progress bit to be cleared. */
    262     response = spi_flash_wait_while_busy();
    263     if (response != FLASH_STATUS_SUCCESS) {
    264         dprint("Failed to check WIP flag! [spi flash erase block]\n");
    265         return response;
    266     }
    267 
    268     /* Enable writes. */
    269     response = spi_flash_write_enable();
    270     if (response != FLASH_STATUS_SUCCESS) {
    271         dprint("Failed to write-enable! [spi flash erase block]\n");
    272         return response;
    273     }
    274 
    275     /* Erase Block. */
    276     response = spi_flash_transaction(FLASH_CMD_BE, addr, NULL, 0);
    277     if (response != FLASH_STATUS_SUCCESS) {
    278         dprint("Failed to erase block! [spi flash erase block]\n");
    279         return response;
    280     }
    281 
    282     /* Wait for the write-in-progress bit to be cleared.*/
    283     response = spi_flash_wait_while_busy();
    284     if (response != FLASH_STATUS_SUCCESS) {
    285         dprint("Failed to check WIP flag! [spi flash erase block]\n");
    286         return response;
    287     }
    288 
    289     return response;
    290 }
    291 
    292 flash_status_t flash_read_range(uint32_t addr, void *buf, size_t len) {
    293     flash_status_t response = FLASH_STATUS_SUCCESS;
    294     uint8_t       *read_buf = (uint8_t *)buf;
    295 
    296     /* Wait for the write-in-progress bit to be cleared. */
    297     response = spi_flash_wait_while_busy();
    298     if (response != FLASH_STATUS_SUCCESS) {
    299         dprint("Failed to check WIP flag! [spi flash read block]\n");
    300         memset(read_buf, 0, len);
    301         return response;
    302     }
    303 
    304     /* Perform read. */
    305     response = spi_flash_transaction(FLASH_CMD_READ, addr, read_buf, len);
    306     if (response != FLASH_STATUS_SUCCESS) {
    307         dprint("Failed to read block! [spi flash read block]\n");
    308         memset(read_buf, 0, len);
    309         return response;
    310     }
    311 
    312 #if defined(CONSOLE_ENABLE) && defined(DEBUG_FLASH_SPI_OUTPUT)
    313     dprintf("[SPI FLASH R] 0x%08lx: ", addr);
    314     for (size_t i = 0; i < len; ++i) {
    315         dprintf(" %02X", (int)(((uint8_t *)read_buf)[i]));
    316     }
    317     dprintf("\n");
    318 #endif // DEBUG_FLASH_SPI_OUTPUT
    319 
    320     return response;
    321 }
    322 
    323 flash_status_t flash_write_range(uint32_t addr, const void *buf, size_t len) {
    324     flash_status_t response  = FLASH_STATUS_SUCCESS;
    325     uint8_t       *write_buf = (uint8_t *)buf;
    326 
    327     while (len > 0) {
    328         uint32_t page_offset  = addr % EXTERNAL_FLASH_PAGE_SIZE;
    329         size_t   write_length = EXTERNAL_FLASH_PAGE_SIZE - page_offset;
    330         if (write_length > len) {
    331             write_length = len;
    332         }
    333 
    334         /* Wait for the write-in-progress bit to be cleared. */
    335         response = spi_flash_wait_while_busy();
    336         if (response != FLASH_STATUS_SUCCESS) {
    337             dprint("Failed to check WIP flag! [spi flash write block]\n");
    338             return response;
    339         }
    340 
    341         /* Enable writes. */
    342         response = spi_flash_write_enable();
    343         if (response != FLASH_STATUS_SUCCESS) {
    344             dprint("Failed to write-enable! [spi flash write block]\n");
    345             return response;
    346         }
    347 
    348 #if defined(CONSOLE_ENABLE) && defined(DEBUG_FLASH_SPI_OUTPUT)
    349         dprintf("[SPI FLASH W] 0x%08lx: ", addr);
    350         for (size_t i = 0; i < write_length; i++) {
    351             dprintf(" %02X", (int)(uint8_t)(write_buf[i]));
    352         }
    353         dprintf("\n");
    354 #endif // DEBUG_FLASH_SPI_OUTPUT
    355 
    356         /* Perform the write. */
    357         response = spi_flash_transaction(FLASH_CMD_PP, addr, write_buf, write_length);
    358         if (response != FLASH_STATUS_SUCCESS) {
    359             dprint("Failed to write block! [spi flash write block]\n");
    360             return response;
    361         }
    362 
    363         write_buf += write_length;
    364         addr += write_length;
    365         len -= write_length;
    366     }
    367 
    368     /* Wait for the write-in-progress bit to be cleared. */
    369     response = spi_flash_wait_while_busy();
    370     if (response != FLASH_STATUS_SUCCESS) {
    371         dprint("Failed to check WIP flag! [spi flash write block]\n");
    372         return response;
    373     }
    374 
    375     /* Disable writes. */
    376     response = spi_flash_write_disable();
    377     if (response != FLASH_STATUS_SUCCESS) {
    378         dprint("Failed to write-disable! [spi flash write block]\n");
    379         return response;
    380     }
    381 
    382     return response;
    383 }