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.
This commit is contained in:
parent
b1694dfab9
commit
53672f1fc3
|
@ -48,6 +48,16 @@
|
||||||
#define XIP_FLASH_START 0x10000000
|
#define XIP_FLASH_START 0x10000000
|
||||||
#define SRAM_START 0x20000000
|
#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 {
|
struct rp_priv_s {
|
||||||
uint16_t _debug_trampoline;
|
uint16_t _debug_trampoline;
|
||||||
uint16_t _debug_trampoline_end;
|
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,
|
static int rp_flash_erase(struct target_flash *f, target_addr addr,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
if (addr & 0xfff) {
|
if (addr & (FLASHSIZE_4K_SECTOR - 1)) {
|
||||||
DEBUG_WARN("Unaligned erase\n");
|
DEBUG_WARN("Unaligned erase\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (len & 0xfff) {
|
if (len & (FLASHSIZE_4K_SECTOR - 1)) {
|
||||||
DEBUG_WARN("Unaligned len\n");
|
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;
|
target *t = f->t;
|
||||||
rp_flash_prepare(t);
|
rp_flash_prepare(t);
|
||||||
struct rp_priv_s *ps = (struct rp_priv_s*)t->target_storage;
|
struct rp_priv_s *ps = (struct rp_priv_s*)t->target_storage;
|
||||||
/* Register playground*/
|
/* Register playground*/
|
||||||
/* erase */
|
/* erase */
|
||||||
#define MAX_FLASH (16 * 1024 * 1024)
|
addr -= t->flash->start;
|
||||||
#define FLASHCMD_SECTOR_ERASE 0x20
|
len = MIN(len, t->flash->length);
|
||||||
#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;
|
|
||||||
bool ret = 0;
|
bool ret = 0;
|
||||||
while (len) {
|
while (len) {
|
||||||
ps->regs[0] = addr;
|
if (len >= FLASHSIZE_64K_BLOCK) {
|
||||||
ps->regs[2] = -1;
|
uint32_t chunk = len & ~(FLASHSIZE_64K_BLOCK - 1);
|
||||||
if (len >= MAX_FLASH) { /* Bulk erase */
|
ps->regs[0] = addr;
|
||||||
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);
|
|
||||||
ps->regs[1] = chunk;
|
ps->regs[1] = chunk;
|
||||||
|
ps->regs[2] = FLASHSIZE_64K_BLOCK;
|
||||||
ps->regs[3] = FLASHCMD_BLOCK64K_ERASE;
|
ps->regs[3] = FLASHCMD_BLOCK64K_ERASE;
|
||||||
DEBUG_WARN("64k_ERASE\n");
|
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, 2100);
|
ret = rp_rom_call(t, ps->regs, ps->_flash_range_erase, 25100);
|
||||||
len -= chunk ;
|
len -= chunk ;
|
||||||
addr += chunk;
|
addr += chunk;
|
||||||
} else if (len >= (32 * 1024)) {
|
} else if (len >= FLASHSIZE_32K_BLOCK) {
|
||||||
uint32_t chunk = len & ~((1 << 15) - 1);
|
uint32_t chunk = len & ~(FLASHSIZE_32K_BLOCK - 1);
|
||||||
|
ps->regs[0] = addr;
|
||||||
ps->regs[1] = chunk;
|
ps->regs[1] = chunk;
|
||||||
|
ps->regs[2] = FLASHSIZE_32K_BLOCK;
|
||||||
ps->regs[3] = FLASHCMD_BLOCK32K_ERASE;
|
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);
|
ret = rp_rom_call(t, ps->regs, ps->_flash_range_erase, 1700);
|
||||||
len -= chunk;
|
len -= chunk;
|
||||||
addr += chunk;
|
addr += chunk;
|
||||||
} else {
|
} else {
|
||||||
|
ps->regs[0] = addr;
|
||||||
ps->regs[1] = len;
|
ps->regs[1] = len;
|
||||||
ps->regs[2] = MAX_FLASH;
|
ps->regs[2] = FLASHSIZE_4K_SECTOR;
|
||||||
ps->regs[3] = FLASHCMD_SECTOR_ERASE;
|
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);
|
ret = rp_rom_call(t, ps->regs, ps->_flash_range_erase, 410);
|
||||||
len = 0;
|
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,
|
static int rp_flash_write(struct target_flash *f,
|
||||||
target_addr dest, const void *src, size_t len)
|
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)) {
|
if ((dest & 0xff) || (len & 0xff)) {
|
||||||
DEBUG_WARN("Unaligned erase\n");
|
DEBUG_WARN("Unaligned erase\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -327,7 +328,7 @@ static bool rp_cmd_erase_mass(target *t, int argc, const char *argv[])
|
||||||
f.t = t;
|
f.t = t;
|
||||||
struct rp_priv_s *ps = (struct rp_priv_s*)t->target_storage;
|
struct rp_priv_s *ps = (struct rp_priv_s*)t->target_storage;
|
||||||
ps->is_monitor = true;
|
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;
|
ps->is_monitor = false;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue