mirror of https://github.com/wolfSSL/wolfBoot.git
F-12881: p1021: check NAND program/erase status and ECC results
The write/erase loops discarded the JEDEC status byte from MDR and hal_flash_command ignored the PAR (uncorrectable ECC) and FCT (FCM timeout) bits, so failed programs, erases and uncorrectable reads all reported success. Check P/WPS in the status byte and stop the loop, and fail the command on PAR/FCT. The small-page FCM sequence now ends with the status command (CM3+RSW) so MDR holds a valid status like the large-page path; not verified on real P1021 hardware. config_io_pin now uses a single masked store for CPDIR/ CPPAR (F-12880): the clear-then-set pair could drop a concurrent update to another pin in the same register. F-12880, F-12881, F-12882pull/892/head
parent
63f1ce7872
commit
4e01a45e3b
|
|
@ -336,6 +336,10 @@ enum elbc_amask_sizes {
|
|||
|
||||
#define NAND_CMD_READSTART 0x30 /* Extended command for large page devices */
|
||||
|
||||
/* NAND device status byte (JEDEC), returned in MDR by the RS/RSW ops */
|
||||
#define NAND_STATUS_WPS (1 << 1) /* write protect status */
|
||||
#define NAND_STATUS_FAIL (1 << 3) /* P: program/erase fail */
|
||||
|
||||
|
||||
/* DDR */
|
||||
/* DDR3: 512MB, 333.333 MHz (666.667 MT/s) */
|
||||
|
|
@ -689,6 +693,15 @@ static int hal_flash_command(uint8_t iswrite)
|
|||
if (!(ltesr & ELBC_LTESR_CC)) {
|
||||
ret = -1;
|
||||
}
|
||||
else if (ltesr & ELBC_LTESR_FCT) {
|
||||
/* a CW/RSW wait timed out: the device never became ready */
|
||||
ret = -1;
|
||||
}
|
||||
else if (iswrite == 0 && (ltesr & ELBC_LTESR_PAR)) {
|
||||
/* uncorrectable ECC error during the FCM read: the data in the
|
||||
* FCM buffer cannot be trusted */
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
/* clear interrupt */
|
||||
set32(ELBC_LTESR, ltesr & ELBC_NAND_MASK);
|
||||
|
|
@ -1063,18 +1076,18 @@ static void config_io_pin(uint8_t port, uint8_t pin, int dir, int open_drain,
|
|||
pin_2bit_dir = (uint32_t)(dir << (NUM_OF_PINS -
|
||||
(pin % (NUM_OF_PINS / 2) + 1) * 2));
|
||||
|
||||
/* Setup the direction */
|
||||
/* Setup the direction: one masked store - a clear-then-set pair
|
||||
* would drop a concurrent update to another pin in the same
|
||||
* register */
|
||||
tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
|
||||
get32(GUTS_CPDIR2(port)) :
|
||||
get32(GUTS_CPDIR1(port));
|
||||
|
||||
if (pin > (NUM_OF_PINS / 2) - 1) {
|
||||
set32(GUTS_CPDIR2(port), ~pin_2bit_mask & tmp_val);
|
||||
set32(GUTS_CPDIR2(port), pin_2bit_dir | tmp_val);
|
||||
set32(GUTS_CPDIR2(port), (~pin_2bit_mask & tmp_val) | pin_2bit_dir);
|
||||
}
|
||||
else {
|
||||
set32(GUTS_CPDIR1(port), ~pin_2bit_mask & tmp_val);
|
||||
set32(GUTS_CPDIR1(port), pin_2bit_dir | tmp_val);
|
||||
set32(GUTS_CPDIR1(port), (~pin_2bit_mask & tmp_val) | pin_2bit_dir);
|
||||
}
|
||||
|
||||
/* Calculate pin location for 1bit mask */
|
||||
|
|
@ -1089,21 +1102,21 @@ static void config_io_pin(uint8_t port, uint8_t pin, int dir, int open_drain,
|
|||
set32(GUTS_CPODR(port), ~pin_1bit_mask & tmp_val);
|
||||
}
|
||||
|
||||
/* Setup the assignment */
|
||||
/* Setup the assignment: one masked store (same reason as the
|
||||
* direction write above) */
|
||||
tmp_val = (pin > (NUM_OF_PINS/2) - 1) ?
|
||||
get32(GUTS_CPPAR2(port)):
|
||||
get32(GUTS_CPPAR1(port));
|
||||
pin_2bit_assign = (uint32_t)(assign <<
|
||||
(NUM_OF_PINS - (pin % (NUM_OF_PINS / 2) + 1) * 2));
|
||||
|
||||
/* Clear and set 2 bits mask */
|
||||
if (pin > (NUM_OF_PINS/2) - 1) {
|
||||
set32(GUTS_CPPAR2(port), ~pin_2bit_mask & tmp_val);
|
||||
set32(GUTS_CPPAR2(port), pin_2bit_assign | tmp_val);
|
||||
set32(GUTS_CPPAR2(port), (~pin_2bit_mask & tmp_val) |
|
||||
pin_2bit_assign);
|
||||
}
|
||||
else {
|
||||
set32(GUTS_CPPAR1(port), ~pin_2bit_mask & tmp_val);
|
||||
set32(GUTS_CPPAR1(port), pin_2bit_assign | tmp_val);
|
||||
set32(GUTS_CPPAR1(port), (~pin_2bit_mask & tmp_val) |
|
||||
pin_2bit_assign);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1641,13 +1654,19 @@ int ext_flash_write(uintptr_t address, const uint8_t *data, int len)
|
|||
page_size = 512;
|
||||
set32(ELBC_FCR, ELBC_FCR_CMD(0, NAND_CMD_READA) |
|
||||
ELBC_FCR_CMD(1, NAND_CMD_PAGE_PROG2) |
|
||||
ELBC_FCR_CMD(2, NAND_CMD_PAGE_PROG1));
|
||||
ELBC_FCR_CMD(2, NAND_CMD_PAGE_PROG1) |
|
||||
ELBC_FCR_CMD(3, NAND_CMD_STATUS));
|
||||
/* the CM3+RSW pair issues the status command after the program
|
||||
* execute and waits for it, so MDR holds the page status like the
|
||||
* large page path */
|
||||
set32(ELBC_FIR, ELBC_FIR_OP(0, ELBC_FIR_OP_CW0) |
|
||||
ELBC_FIR_OP(1, ELBC_FIR_OP_CM2) |
|
||||
ELBC_FIR_OP(2, ELBC_FIR_OP_CA) |
|
||||
ELBC_FIR_OP(3, ELBC_FIR_OP_PA) |
|
||||
ELBC_FIR_OP(4, ELBC_FIR_OP_WB) |
|
||||
ELBC_FIR_OP(5, ELBC_FIR_OP_CW1));
|
||||
ELBC_FIR_OP(5, ELBC_FIR_OP_CW1) |
|
||||
ELBC_FIR_OP(6, ELBC_FIR_OP_CM3) |
|
||||
ELBC_FIR_OP(7, ELBC_FIR_OP_RSW));
|
||||
#endif
|
||||
(void)block_size; /* not used - shown for reference */
|
||||
|
||||
|
|
@ -1690,7 +1709,12 @@ int ext_flash_write(uintptr_t address, const uint8_t *data, int len)
|
|||
wolfBoot_printf("write page %d, col %d, status %x\n",
|
||||
page, col, status);
|
||||
#endif
|
||||
(void)status;
|
||||
/* P (program fail) or WPS (write protect) set: the page did not
|
||||
* program. Stop; retrying the same page fails the same way. */
|
||||
if (status & (NAND_STATUS_FAIL | NAND_STATUS_WPS)) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
address += write_size;
|
||||
pos += write_size;
|
||||
data += write_size;
|
||||
|
|
@ -1851,7 +1875,12 @@ int ext_flash_erase(uintptr_t address, int len)
|
|||
#ifdef DEBUG_EXT_FLASH
|
||||
wolfBoot_printf("erase page %d, status %x\n", page, status);
|
||||
#endif
|
||||
(void)status;
|
||||
/* P (erase fail) or WPS (write protect) set: the block did not
|
||||
* erase. Stop; erasing the same block fails the same way. */
|
||||
if (status & (NAND_STATUS_FAIL | NAND_STATUS_WPS)) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
address += block_size;
|
||||
len -= block_size;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue