Merge branch 'u-boot-nand-20241212' of https://source.denx.de/u-boot/custodians/u-boot-nand-flash into next
CI: https://source.denx.de/u-boot/custodians/u-boot-nand-flash/-/pipelines/23837 Small addition to uboot-nand. Nothing relevant for now. Anyway a nice new command coming from Miquel Raynal and small changes.
This commit is contained in:
@@ -1497,6 +1497,11 @@ config CMD_NAND_TORTURE
|
||||
help
|
||||
NAND torture support.
|
||||
|
||||
config CMD_NAND_WATCH
|
||||
bool "nand watch"
|
||||
help
|
||||
NAND watch bitflip support.
|
||||
|
||||
endif # CMD_NAND
|
||||
|
||||
config CMD_NVME
|
||||
|
@@ -122,13 +122,11 @@ static void mtd_show_device(struct mtd_info *mtd)
|
||||
{
|
||||
/* Device */
|
||||
printf("* %s\n", mtd->name);
|
||||
#if defined(CONFIG_DM)
|
||||
if (mtd->dev) {
|
||||
printf(" - device: %s\n", mtd->dev->name);
|
||||
printf(" - parent: %s\n", mtd->dev->parent->name);
|
||||
printf(" - driver: %s\n", mtd->dev->driver->name);
|
||||
}
|
||||
#endif
|
||||
if (IS_ENABLED(CONFIG_OF_CONTROL) && mtd->dev) {
|
||||
char buf[256];
|
||||
int res;
|
||||
|
103
cmd/nand.c
103
cmd/nand.c
@@ -231,6 +231,54 @@ free_dat:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_NAND_WATCH
|
||||
static int nand_watch_bf(struct mtd_info *mtd, ulong off, ulong size, bool quiet)
|
||||
{
|
||||
unsigned int max_bf = 0, pages_wbf = 0;
|
||||
unsigned int first_page, pages, i;
|
||||
struct mtd_oob_ops ops = {};
|
||||
u_char *buf;
|
||||
int ret;
|
||||
|
||||
buf = memalign(ARCH_DMA_MINALIGN, mtd->writesize);
|
||||
if (!buf) {
|
||||
puts("No memory for page buffer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
first_page = off / mtd->writesize;
|
||||
pages = size / mtd->writesize;
|
||||
|
||||
ops.datbuf = buf;
|
||||
ops.len = mtd->writesize;
|
||||
for (i = first_page; i < first_page + pages; i++) {
|
||||
ulong addr = mtd->writesize * i;
|
||||
ret = mtd_read_oob_bf(mtd, addr, &ops);
|
||||
if (ret < 0) {
|
||||
if (quiet)
|
||||
continue;
|
||||
|
||||
printf("Page %7d (0x%08lx) -> error %d\n",
|
||||
i, addr, ret);
|
||||
} else if (ret) {
|
||||
max_bf = max(max_bf, (unsigned int)ret);
|
||||
pages_wbf++;
|
||||
if (quiet)
|
||||
continue;
|
||||
printf("Page %7d (0x%08lx) -> up to %2d bf/chunk\n",
|
||||
i, addr, ret);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Maximum number of bitflips: %u\n", max_bf);
|
||||
printf("Pages with bitflips: %u/%u\n", pages_wbf, pages);
|
||||
|
||||
free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int set_dev(int dev)
|
||||
@@ -781,6 +829,55 @@ static int do_nand(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
return ret == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_NAND_WATCH
|
||||
if (strncmp(cmd, "watch", 5) == 0) {
|
||||
int args = 2;
|
||||
|
||||
if (cmd[5]) {
|
||||
if (!strncmp(&cmd[5], ".part", 5)) {
|
||||
args = 1;
|
||||
} else if (!strncmp(&cmd[5], ".chip", 5)) {
|
||||
args = 0;
|
||||
} else {
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd[10])
|
||||
if (!strncmp(&cmd[10], ".quiet", 6))
|
||||
quiet = true;
|
||||
|
||||
if (argc != 2 + args)
|
||||
goto usage;
|
||||
|
||||
ret = mtd_arg_off_size(argc - 2, argv + 2, &dev, &off, &size,
|
||||
&maxsize, MTD_DEV_TYPE_NAND, mtd->size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* size is unspecified */
|
||||
if (argc < 4)
|
||||
adjust_size_for_badblocks(&size, off, dev);
|
||||
|
||||
if ((off & (mtd->writesize - 1)) ||
|
||||
(size & (mtd->writesize - 1))) {
|
||||
printf("Attempt to read non page-aligned data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = set_dev(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mtd = get_nand_dev_by_index(dev);
|
||||
|
||||
printf("\nNAND watch for bitflips in area 0x%llx-0x%llx:\n",
|
||||
off, off + size);
|
||||
|
||||
return nand_watch_bf(mtd, off, size, quiet);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CMD_NAND_TORTURE
|
||||
if (strcmp(cmd, "torture") == 0) {
|
||||
loff_t endoff;
|
||||
@@ -946,6 +1043,12 @@ U_BOOT_LONGHELP(nand,
|
||||
"nand erase.chip [clean] - erase entire chip'\n"
|
||||
"nand bad - show bad blocks\n"
|
||||
"nand dump[.oob] off - dump page\n"
|
||||
#ifdef CONFIG_CMD_NAND_WATCH
|
||||
"nand watch <off> <size> - check an area for bitflips\n"
|
||||
"nand watch.part <part> - check a partition for bitflips\n"
|
||||
"nand watch.chip - check the whole device for bitflips\n"
|
||||
"\t\t.quiet - Query only the summary, not the details\n"
|
||||
#endif
|
||||
#ifdef CONFIG_CMD_NAND_TORTURE
|
||||
"nand torture off - torture one block at offset\n"
|
||||
"nand torture off [size] - torture blocks from off to off+size\n"
|
||||
|
@@ -1124,6 +1124,28 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtd_read_oob);
|
||||
|
||||
/* This is a bare copy of mtd_read_oob returning the actual number of bitflips */
|
||||
int mtd_read_oob_bf(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
|
||||
{
|
||||
int ret_code;
|
||||
ops->retlen = ops->oobretlen = 0;
|
||||
if (!mtd->_read_oob)
|
||||
return -EOPNOTSUPP;
|
||||
/*
|
||||
* In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
|
||||
* similar to mtd->_read(), returning a non-negative integer
|
||||
* representing max bitflips. In other cases, mtd->_read_oob() may
|
||||
* return -EUCLEAN. In all cases, perform similar logic to mtd_read().
|
||||
*/
|
||||
ret_code = mtd->_read_oob(mtd, from, ops);
|
||||
if (unlikely(ret_code < 0))
|
||||
return ret_code;
|
||||
if (mtd->ecc_strength == 0)
|
||||
return 0; /* device lacks ecc */
|
||||
return ret_code;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtd_read_oob_bf);
|
||||
|
||||
int mtd_write_oob(struct mtd_info *mtd, loff_t to,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
|
@@ -568,11 +568,8 @@ static void atmel_nfc_copy_to_sram(struct nand_chip *chip, const u8 *buf,
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
struct atmel_hsmc_nand_controller *nc;
|
||||
int ret = -EIO;
|
||||
|
||||
nc = to_hsmc_nand_controller(nand->controller);
|
||||
|
||||
if (ret)
|
||||
memcpy_toio(nc->sram.virt, buf, mtd->writesize);
|
||||
|
||||
if (oob_required)
|
||||
@@ -586,11 +583,8 @@ static void atmel_nfc_copy_from_sram(struct nand_chip *chip, u8 *buf,
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
struct atmel_hsmc_nand_controller *nc;
|
||||
int ret = -EIO;
|
||||
|
||||
nc = to_hsmc_nand_controller(nand->controller);
|
||||
|
||||
if (ret)
|
||||
memcpy_fromio(buf, nc->sram.virt, mtd->writesize);
|
||||
|
||||
if (oob_required)
|
||||
|
Reference in New Issue
Block a user