From 118dd6ed085c0a3a5e2f2dec2d6b20eac9dc5ac2 Mon Sep 17 00:00:00 2001 From: "Lukas F. Hartmann" Date: Tue, 25 Apr 2023 13:26:18 +0200 Subject: [PATCH 1/3] liblitespi/spiflash: add erase and write functions The code is based on norbert thiel's comment https://github.com/litex-hub/litespi/issues/52 But edited to work with W25Q128JVS flash used in MNT RKX7. --- litex/soc/software/liblitespi/spiflash.c | 129 +++++++++++++++++++++++ litex/soc/software/liblitespi/spiflash.h | 2 + 2 files changed, 131 insertions(+) diff --git a/litex/soc/software/liblitespi/spiflash.c b/litex/soc/software/liblitespi/spiflash.c index cdc4552e1..e7f0cd12a 100644 --- a/litex/soc/software/liblitespi/spiflash.c +++ b/litex/soc/software/liblitespi/spiflash.c @@ -91,6 +91,135 @@ static void spiflash_master_write(uint32_t val, size_t len, size_t width, uint32 spiflash_core_master_cs_write(0); } +static volatile uint8_t w_buf[SPI_FLASH_BLOCK_SIZE + 4]; +static volatile uint8_t r_buf[SPI_FLASH_BLOCK_SIZE + 4]; + +static uint32_t transfer_byte(uint8_t b) +{ + /* wait for tx ready */ + while (!spiflash_core_master_status_tx_ready_read()); + + spiflash_core_master_rxtx_write((uint32_t)b); + + /* wait for rx ready */ + while (!spiflash_core_master_status_rx_ready_read()); + + return spiflash_core_master_rxtx_read(); +} + +static void transfer_cmd(uint8_t *bs, uint8_t *resp, int len) +{ + spiflash_core_master_phyconfig_len_write(8); + spiflash_core_master_phyconfig_width_write(1); + spiflash_core_master_phyconfig_mask_write(1); + spiflash_core_master_cs_write(1); + + for (int i=0; i < len; i++) { + resp[i] = transfer_byte(bs[i]); + } + + spiflash_core_master_cs_write(0); +} + +static uint32_t spiflash_read_status_register(void) +{ + uint8_t buf[2]; + w_buf[0] = 0x05; + w_buf[1] = 0x00; + transfer_cmd(w_buf, buf, 2); + flush_cpu_dcache(); + + /* FIXME hack: sometimes, the result is in buf[0]. + * not sure why this happens. timing? */ + if (buf[1] == 0xff) return buf[0]; + return buf[1]; +} + +static void spiflash_write_enable(void) +{ + uint8_t buf[1]; + w_buf[0] = 0x06; + transfer_cmd(w_buf, buf, 1); +} + +static void page_program(uint32_t addr, uint8_t *data, int len) +{ + w_buf[0] = 0x02; + w_buf[1] = addr>>16; + w_buf[2] = addr>>8; + w_buf[3] = addr>>0; + memcpy(w_buf+4, data, len); + flush_cpu_dcache(); + transfer_cmd(w_buf, r_buf, len+4); +} + +static void spiflash_sector_erase(uint32_t addr) +{ + w_buf[0] = 0xd8; + w_buf[1] = addr>>16; + w_buf[2] = addr>>8; + w_buf[3] = addr>>0; + flush_cpu_dcache(); + transfer_cmd(w_buf, r_buf, 4); +} + +/* erase page size in bytes, check flash datasheet */ +#define SPI_FLASH_ERASE_SIZE (64*1024) + +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +void spiflash_erase_range(uint32_t addr, uint32_t len) +{ + uint32_t i = 0; + uint32_t j = 0; + for (i=0; i Date: Tue, 25 Apr 2023 13:30:07 +0200 Subject: [PATCH 2/3] bios/spiflash: bring back write and erase, add write from sdcard file cmd When shipping MNT RKX7, I pre-flash the SPI flash with a LiteX bitfile for testing. cmd_spiflash had regressed because of changed SPIFLASH defines and didn't offer the write functions anymore. This commit fixes that, and adds convenience functions: - flash_erase_range - flash_from_sdcard The latter reuses some boot code to copy the contents of the specified file from the boot FAT partition on the SD card to SPI flash (i.e. a bitstream). --- litex/soc/software/bios/cmds/cmd_spiflash.c | 111 ++++++++++++++++---- 1 file changed, 90 insertions(+), 21 deletions(-) diff --git a/litex/soc/software/bios/cmds/cmd_spiflash.c b/litex/soc/software/bios/cmds/cmd_spiflash.c index 1038f7a79..7b1dacc62 100644 --- a/litex/soc/software/bios/cmds/cmd_spiflash.c +++ b/litex/soc/software/bios/cmds/cmd_spiflash.c @@ -8,23 +8,26 @@ #include "../command.h" #include "../helpers.h" +#include +#include +#include + /** * Command "flash_write" * * Write data from a memory buffer to SPI flash * */ -#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) +#if (defined CSR_SPIFLASH_CORE_MASTER_CS_ADDR) static void flash_write_handler(int nb_params, char **params) { char *c; unsigned int addr; - unsigned int value; + unsigned int mem_addr; unsigned int count; - unsigned int i; if (nb_params < 2) { - printf("flash_write [count]"); + printf("flash_write [count (bytes)]"); return; } @@ -34,9 +37,9 @@ static void flash_write_handler(int nb_params, char **params) return; } - value = strtoul(params[1], &c, 0); + mem_addr = strtoul(params[1], &c, 0); if (*c != 0) { - printf("Incorrect value"); + printf("Incorrect mem_addr"); return; } @@ -50,26 +53,92 @@ static void flash_write_handler(int nb_params, char **params) } } - for (i = 0; i < count; i++) - write_to_flash(addr + i * 4, (unsigned char *)&value, 4); + spiflash_write_stream(addr, (unsigned char *)mem_addr, count); } define_command(flash_write, flash_write_handler, "Write to flash", SPIFLASH_CMDS); -#endif -/** - * Command "flash_erase" - * - * Flash erase - * - */ -#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) -static void flash_erase_handler(int nb_params, char **params) +static void flash_from_sdcard_handler(int nb_params, char **params) { - erase_flash(); - printf("Flash erased\n"); + FRESULT fr; + FATFS fs; + FIL file; + uint32_t br; + uint32_t offset; + unsigned long length; + uint8_t buf[512]; + + if (nb_params < 1) { + printf("flash_from_sdcard "); + return; + } + + char* filename = params[0]; + + fr = f_mount(&fs, "", 1); + if (fr != FR_OK) + return; + fr = f_open(&file, filename, FA_READ); + if (fr != FR_OK) { + printf("%s file not found.\n", filename); + f_mount(0, "", 0); + return; + } + + length = f_size(&file); + printf("Copying %s to SPI flash (%ld bytes)...\n", filename, length); + init_progression_bar(length); + offset = 0; + for (;;) { + fr = f_read(&file, (void*) buf, 512, (UINT *)&br); + if (fr != FR_OK) { + printf("file read error.\n"); + f_close(&file); + f_mount(0, "", 0); + return; + } + if (br == 0) { + break; + } else { + spiflash_write_stream(offset, buf, br); + } + + offset += br; + show_progress(offset); + } + show_progress(offset); + printf("\n"); + + f_close(&file); + f_mount(0, "", 0); +} +define_command(flash_from_sdcard, flash_from_sdcard_handler, "Write file from SD card to flash", SPIFLASH_CMDS); + +static void flash_erase_range_handler(int nb_params, char **params) +{ + char *c; + uint32_t addr; + uint32_t count; + + if (nb_params < 2) { + printf("flash_erase "); + return; + } + + addr = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect offset"); + return; + } + + count = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect count"); + return; + } + + spiflash_erase_range(addr, count); } -define_command(flash_erase, flash_erase_handler, "Erase whole flash", SPIFLASH_CMDS); +define_command(flash_erase_range, flash_erase_range_handler, "Erase flash range", SPIFLASH_CMDS); #endif - From e23fe832f00e46728200a3cff642716f8c1ad2e0 Mon Sep 17 00:00:00 2001 From: "Lukas F. Hartmann" Date: Tue, 25 Apr 2023 17:05:33 +0200 Subject: [PATCH 3/3] litespi/flash: fix status reg read; remove delays --- litex/soc/software/liblitespi/spiflash.c | 48 +++++++++++++++--------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/litex/soc/software/liblitespi/spiflash.c b/litex/soc/software/liblitespi/spiflash.c index e7f0cd12a..5bd827318 100644 --- a/litex/soc/software/liblitespi/spiflash.c +++ b/litex/soc/software/liblitespi/spiflash.c @@ -114,25 +114,30 @@ static void transfer_cmd(uint8_t *bs, uint8_t *resp, int len) spiflash_core_master_phyconfig_mask_write(1); spiflash_core_master_cs_write(1); + flush_cpu_dcache(); for (int i=0; i < len; i++) { resp[i] = transfer_byte(bs[i]); } spiflash_core_master_cs_write(0); + flush_cpu_dcache(); } static uint32_t spiflash_read_status_register(void) { - uint8_t buf[2]; + volatile uint8_t buf[4]; w_buf[0] = 0x05; w_buf[1] = 0x00; - transfer_cmd(w_buf, buf, 2); - flush_cpu_dcache(); + transfer_cmd(w_buf, buf, 4); - /* FIXME hack: sometimes, the result is in buf[0]. - * not sure why this happens. timing? */ - if (buf[1] == 0xff) return buf[0]; - return buf[1]; +#if SPIFLASH_DEBUG + printf("[SR: %02x %02x %02x %02x]", buf[0], buf[1], buf[2], buf[3]); +#endif + + /* FIXME normally the status should be in buf[1], + but we have to read it a few more times to be + stable for unknown reasons */ + return buf[3]; } static void spiflash_write_enable(void) @@ -149,7 +154,6 @@ static void page_program(uint32_t addr, uint8_t *data, int len) w_buf[2] = addr>>8; w_buf[3] = addr>>0; memcpy(w_buf+4, data, len); - flush_cpu_dcache(); transfer_cmd(w_buf, r_buf, len+4); } @@ -159,7 +163,6 @@ static void spiflash_sector_erase(uint32_t addr) w_buf[1] = addr>>16; w_buf[2] = addr>>8; w_buf[3] = addr>>0; - flush_cpu_dcache(); transfer_cmd(w_buf, r_buf, 4); } @@ -173,16 +176,15 @@ void spiflash_erase_range(uint32_t addr, uint32_t len) uint32_t i = 0; uint32_t j = 0; for (i=0; i