From 53672f1fc3831fe2a672268beddee6d4b490a032 Mon Sep 17 00:00:00 2001 From: James Turton Date: Wed, 8 Jun 2022 23:34:07 +0300 Subject: [PATCH] rp: Remove CHIP_ERASE command from rp_flash_erase There seems to be a bug in the bootrom for the rp2040 which means that the chip erase command is not accepted. This is because the CS pin must be released (set high) directly after sending the chip erase command (0x60 or 0xC7) (see Winbond W25Q128JV datasheet for details). Instead the bootrom sends the address after the command, thus the SPI flash silently ignores the command. Instead, we must erase each 64KB block one at a time, but thankfull the bootrom handles this correctly for us. --- src/target/rp.c | 63 +++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/src/target/rp.c b/src/target/rp.c index bd7df41..30b0a2d 100644 --- a/src/target/rp.c +++ b/src/target/rp.c @@ -48,6 +48,16 @@ #define XIP_FLASH_START 0x10000000 #define SRAM_START 0x20000000 +#define FLASHSIZE_4K_SECTOR (4 * 1024) +#define FLASHSIZE_32K_BLOCK (32 * 1024) +#define FLASHSIZE_64K_BLOCK (64 * 1024) +#define MAX_FLASH (16 * 1024 * 1024) +#define FLASHCMD_SECTOR_ERASE 0x20 +#define FLASHCMD_BLOCK32K_ERASE 0x52 +#define FLASHCMD_BLOCK64K_ERASE 0xd8 +#define FLASHCMD_CHIP_ERASE 0x60 +#define FLASHCMD_READ_ID 0x9F + struct rp_priv_s { uint16_t _debug_trampoline; uint16_t _debug_trampoline_end; @@ -197,59 +207,50 @@ static void rp_flash_resume(target *t) static int rp_flash_erase(struct target_flash *f, target_addr addr, size_t len) { - if (addr & 0xfff) { + if (addr & (FLASHSIZE_4K_SECTOR - 1)) { DEBUG_WARN("Unaligned erase\n"); return -1; } - if (len & 0xfff) { + if (len & (FLASHSIZE_4K_SECTOR - 1)) { DEBUG_WARN("Unaligned len\n"); - len = (len + 0xfff) & ~0xfff; + len = ALIGN(len, FLASHSIZE_4K_SECTOR); } - DEBUG_INFO("Erase addr %08" PRIx32 " len 0x%" PRIx32 "\n", addr, (uint32_t)len); + DEBUG_INFO("Erase addr 0x%08" PRIx32 " len 0x%" PRIx32 "\n", addr, (uint32_t)len); target *t = f->t; rp_flash_prepare(t); struct rp_priv_s *ps = (struct rp_priv_s*)t->target_storage; /* Register playground*/ /* erase */ -#define MAX_FLASH (16 * 1024 * 1024) -#define FLASHCMD_SECTOR_ERASE 0x20 -#define FLASHCMD_BLOCK32K_ERASE 0x52 -#define FLASHCMD_BLOCK64K_ERASE 0xd8 -#define FLASHCMD_CHIP_ERASE 0x72 - addr -= XIP_FLASH_START; - if (len > MAX_FLASH) - len = MAX_FLASH; + addr -= t->flash->start; + len = MIN(len, t->flash->length); bool ret = 0; while (len) { - ps->regs[0] = addr; - ps->regs[2] = -1; - if (len >= MAX_FLASH) { /* Bulk erase */ - ps->regs[1] = MAX_FLASH; - ps->regs[3] = FLASHCMD_CHIP_ERASE; - DEBUG_WARN("BULK_ERASE\n"); - ret = rp_rom_call(t, ps->regs, ps->_flash_range_erase, 25100); - len = 0; - } else if (len >= (64 * 1024)) { - uint32_t chunk = len & ~((1 << 16) - 1); + if (len >= FLASHSIZE_64K_BLOCK) { + uint32_t chunk = len & ~(FLASHSIZE_64K_BLOCK - 1); + ps->regs[0] = addr; ps->regs[1] = chunk; + ps->regs[2] = FLASHSIZE_64K_BLOCK; ps->regs[3] = FLASHCMD_BLOCK64K_ERASE; - DEBUG_WARN("64k_ERASE\n"); - ret = rp_rom_call(t, ps->regs, ps->_flash_range_erase, 2100); + DEBUG_WARN("64k_ERASE addr 0x%08" PRIx32 " len 0x%" PRIx32 "\n", addr, chunk); + ret = rp_rom_call(t, ps->regs, ps->_flash_range_erase, 25100); len -= chunk ; addr += chunk; - } else if (len >= (32 * 1024)) { - uint32_t chunk = len & ~((1 << 15) - 1); + } else if (len >= FLASHSIZE_32K_BLOCK) { + uint32_t chunk = len & ~(FLASHSIZE_32K_BLOCK - 1); + ps->regs[0] = addr; ps->regs[1] = chunk; + ps->regs[2] = FLASHSIZE_32K_BLOCK; ps->regs[3] = FLASHCMD_BLOCK32K_ERASE; - DEBUG_WARN("32k_ERASE\n"); + DEBUG_WARN("32k_ERASE addr 0x%08" PRIx32 " len 0x%" PRIx32 "\n", addr, chunk); ret = rp_rom_call(t, ps->regs, ps->_flash_range_erase, 1700); len -= chunk; addr += chunk; } else { + ps->regs[0] = addr; ps->regs[1] = len; - ps->regs[2] = MAX_FLASH; + ps->regs[2] = FLASHSIZE_4K_SECTOR; ps->regs[3] = FLASHCMD_SECTOR_ERASE; - DEBUG_WARN("Sector_ERASE\n"); + DEBUG_WARN("Sector_ERASE addr 0x%08" PRIx32 " len 0x%" PRIx32 "\n", addr, (uint32_t)len); ret = rp_rom_call(t, ps->regs, ps->_flash_range_erase, 410); len = 0; } @@ -266,7 +267,7 @@ static int rp_flash_erase(struct target_flash *f, target_addr addr, static int rp_flash_write(struct target_flash *f, target_addr dest, const void *src, size_t len) { - DEBUG_INFO("RP Write %08" PRIx32 " len 0x%" PRIx32 "\n", dest, (uint32_t)len); + DEBUG_INFO("RP Write 0x%08" PRIx32 " len 0x%" PRIx32 "\n", dest, (uint32_t)len); if ((dest & 0xff) || (len & 0xff)) { DEBUG_WARN("Unaligned erase\n"); return -1; @@ -327,7 +328,7 @@ static bool rp_cmd_erase_mass(target *t, int argc, const char *argv[]) f.t = t; struct rp_priv_s *ps = (struct rp_priv_s*)t->target_storage; ps->is_monitor = true; - bool res = (rp_flash_erase(&f, XIP_FLASH_START, MAX_FLASH)) ? false: true; + bool res = (rp_flash_erase(&f, t->flash->start, t->flash->length)) ? false: true; ps->is_monitor = false; return res; }