mirror of https://github.com/wolfSSL/wolfBoot.git
ls1028a: wait for the NOR program/erase cycle to finish
XSPI_IPCMDDONE only says the controller finished driving the sequence on the bus. The device keeps WIP set for the ~ms the cycle takes and ignores Write Enable while it is set, so the per-page WREN this PR added was dropped for pages 2..N and their Page Programs with it. The erase loops polled the same bit with inverted polarity: they exited as soon as WIP read *set*, i.e. once the erase had started, and would spin forever if they missed the busy window. FLASH_READY_MSK is renamed FLASH_SR_WIP_MSK so the sense is not guessable, and both paths now share xspi_wait_ready(). The test device models WIP, so a missing wait shows up as a rejected Write Enable.pull/862/head
parent
589550c612
commit
737bb55f76
|
|
@ -520,6 +520,20 @@ void xspi_read_sr(uint8_t* rxbuf, uint32_t addr, uint32_t len)
|
|||
XSPI_INTR = XSPI_IPCMDDONE;
|
||||
}
|
||||
|
||||
/* Block until the NOR device finishes its program/erase cycle.
|
||||
* XSPI_IPCMDDONE only reports that the controller finished driving the
|
||||
* sequence on the bus; the device keeps WIP set for the ~ms the cycle
|
||||
* takes, and ignores Write Enable and further program/erase commands
|
||||
* until it clears. */
|
||||
void xspi_wait_ready(uint32_t addr)
|
||||
{
|
||||
uint8_t status[4] = {0, 0, 0, 0};
|
||||
|
||||
do {
|
||||
xspi_read_sr(status, addr, 1);
|
||||
} while (status[0] & FLASH_SR_WIP_MSK);
|
||||
}
|
||||
|
||||
void xspi_sw_reset(void)
|
||||
{
|
||||
XSPI_SWRESET();
|
||||
|
|
@ -599,6 +613,10 @@ void xspi_flash_write(uintptr_t address, const uint8_t *data, uint32_t len)
|
|||
XSPI_IPTXFCR = XSPI_IPRCFCR_FLUSH;
|
||||
XSPI_INTR = XSPI_IPCMDDONE;
|
||||
|
||||
/* The program cycle is still running: the next iteration's
|
||||
* Write Enable would be ignored and its Page Program dropped. */
|
||||
xspi_wait_ready(address);
|
||||
|
||||
len -= size;
|
||||
address += size;
|
||||
}
|
||||
|
|
@ -639,14 +657,10 @@ int hal_flash_erase(uintptr_t address, int len)
|
|||
num_sectors += (len % FLASH_ERASE_SIZE) ? 1 : 0;
|
||||
|
||||
for (i = 0; i < num_sectors; i++) {
|
||||
uint8_t status[4] = {0, 0, 0, 0};
|
||||
|
||||
xspi_write_en(address + i * FLASH_ERASE_SIZE);
|
||||
xspi_flash_sec_erase(address + i * FLASH_ERASE_SIZE);
|
||||
|
||||
while (!(status[0] & FLASH_READY_MSK)) {
|
||||
xspi_read_sr(status, 0, 1);
|
||||
}
|
||||
xspi_wait_ready(address + i * FLASH_ERASE_SIZE);
|
||||
}
|
||||
|
||||
xspi_sw_reset();
|
||||
|
|
@ -685,14 +699,10 @@ int ext_flash_erase(uintptr_t address, int len)
|
|||
num_sectors += (len % FLASH_ERASE_SIZE) ? 1 : 0;
|
||||
|
||||
for (i = 0; i < num_sectors; i++) {
|
||||
uint8_t status[4] = {0, 0, 0, 0};
|
||||
|
||||
xspi_write_en(address + i * FLASH_ERASE_SIZE);
|
||||
xspi_flash_sec_erase(address + i * FLASH_ERASE_SIZE);
|
||||
|
||||
while (!(status[0] & FLASH_READY_MSK)) {
|
||||
xspi_read_sr(status, 0, 1);
|
||||
}
|
||||
xspi_wait_ready(address + i * FLASH_ERASE_SIZE);
|
||||
}
|
||||
|
||||
xspi_sw_reset();
|
||||
|
|
|
|||
|
|
@ -463,7 +463,10 @@
|
|||
#define FLASH_SECTOR_CNT (FLASH_BANK_SIZE / FLASH_ERASE_SIZE)
|
||||
#define FLASH_ERASE_TOUT 60000 /* Flash Erase Timeout (ms) */
|
||||
#define FLASH_WRITE_TOUT 500 /* Flash Write Timeout (ms) */
|
||||
#define FLASH_READY_MSK (0x1 << 0)
|
||||
/* RDSR (0x05) bit 0 is WIP: 1 while a program or erase is running,
|
||||
* 0 when the device is ready. The device ignores Write Enable and any
|
||||
* further program/erase while WIP is set. */
|
||||
#define FLASH_SR_WIP_MSK (0x1 << 0)
|
||||
#define MASK_32BIT 0xffffffff
|
||||
|
||||
/* LUT register helper */
|
||||
|
|
|
|||
|
|
@ -82,6 +82,11 @@ static int g_xspi_log_n;
|
|||
/* Emulated NOR flash plus the write-enable latch real NOR keeps. */
|
||||
static uint8_t g_nor[2 * 128 * 1024];
|
||||
static int g_wel;
|
||||
/* RDSR polls remaining before the emulated device reports WIP clear.
|
||||
* A program or erase arms it; Write Enable and program/erase issued
|
||||
* while it is armed are ignored, exactly as the device does. */
|
||||
#define NOR_BUSY_POLLS 2
|
||||
static int g_busy;
|
||||
|
||||
/* The FlexSPI drains the TX FIFO while the command runs, so the flash
|
||||
* receives the bytes in the order the driver hands them to the FIFO.
|
||||
|
|
@ -108,8 +113,21 @@ static void xspi_emu_start(void)
|
|||
uint32_t len = ipcr1 & 0xFFFF;
|
||||
uint32_t addr = XSPI_IPCR0;
|
||||
uint32_t i;
|
||||
int e = g_xspi_log_n < XSPI_LOG_MAX ? g_xspi_log_n : XSPI_LOG_MAX - 1;
|
||||
int e;
|
||||
|
||||
/* Status polls are not operations: answer them without taking a
|
||||
* log slot, so the assertions below stay about WEN/PP/SE order. */
|
||||
if (seq == LUT_INDEX_RDSR) {
|
||||
/* WIP stays set for a few polls after a program or erase */
|
||||
XSPI_RFD(0) = g_busy ? FLASH_SR_WIP_MSK : 0;
|
||||
if (g_busy)
|
||||
g_busy--;
|
||||
XSPI_INTR |= XSPI_IPCMDDONE;
|
||||
g_tfd_stream_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
e = g_xspi_log_n < XSPI_LOG_MAX ? g_xspi_log_n : XSPI_LOG_MAX - 1;
|
||||
if (g_xspi_log_n < XSPI_LOG_MAX)
|
||||
g_xspi_log_n++;
|
||||
g_xspi_log[e].addr = addr;
|
||||
|
|
@ -118,6 +136,9 @@ static void xspi_emu_start(void)
|
|||
|
||||
if (seq == LUT_INDEX_WRITE_EN) {
|
||||
g_xspi_log[e].cmd = XSPI_CMD_WEN;
|
||||
if (g_busy)
|
||||
g_xspi_log[e].rejected = 1; /* WREN ignored while WIP set */
|
||||
else
|
||||
g_wel = 1;
|
||||
}
|
||||
else if (seq == LUT_INDEX_PP) {
|
||||
|
|
@ -135,6 +156,7 @@ static void xspi_emu_start(void)
|
|||
g_tfd_stream[i];
|
||||
}
|
||||
g_wel = 0; /* the program consumes the latch */
|
||||
g_busy = NOR_BUSY_POLLS;
|
||||
}
|
||||
else {
|
||||
g_xspi_log[e].rejected = 1; /* NOR ignores PP without WEN */
|
||||
|
|
@ -145,15 +167,12 @@ static void xspi_emu_start(void)
|
|||
if (g_wel) {
|
||||
memset(&g_nor[addr], 0xFF, len);
|
||||
g_wel = 0;
|
||||
g_busy = NOR_BUSY_POLLS;
|
||||
}
|
||||
else {
|
||||
g_xspi_log[e].rejected = 1;
|
||||
}
|
||||
}
|
||||
else if (seq == LUT_INDEX_RDSR) {
|
||||
g_xspi_log[e].cmd = XSPI_CMD_RDSR;
|
||||
XSPI_RFD(0) = FLASH_READY_MSK; /* status: READY */
|
||||
}
|
||||
|
||||
XSPI_INTR |= XSPI_IPCMDDONE;
|
||||
g_tfd_stream_len = 0; /* the FIFO was drained by the command */
|
||||
|
|
@ -189,6 +208,7 @@ static void setup(void)
|
|||
memset(g_nor, 0xFF, sizeof(g_nor));
|
||||
g_xspi_log_n = 0;
|
||||
g_wel = 0;
|
||||
g_busy = 0;
|
||||
g_tfd_stream_len = 0;
|
||||
XSPI_INTR = 0x1 << 6; /* TX FIFO write enable */
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue