[PATCH v1 00/12] Support SPI NAND in fastboot protocol

Currently, fastboot in U-Boot doens't support SPI NAND devices. This patchset adds support for SPI NAND in fastboot nand subsystem.
Alexey Romanov (12): nand: move NAND initialization API to nand/core.c nand: don't overwrite mtd name in nand_register() nand: move nand_util.c to NAND core folder nand: move nand_erase_opts() to core NAND folder spi: add board_nand_init() function spi: use nand_register() instead of add_mtd_device() mtdparts: use negative error codes jffs2: use negative error codes cmd: allow to enable CMD_NAND for SPI NAND devices fastboot: check device type for SPI NAND too fastboot: enable FASTBOOT_FLASH option for SPI NAND devices fastboot: fb_nand: add missing newlines in pr_err() macro
cmd/Kconfig | 2 +- cmd/jffs2.c | 45 +- cmd/mtdparts.c | 154 +++---- drivers/fastboot/Kconfig | 4 +- drivers/fastboot/fb_nand.c | 12 +- drivers/mtd/Kconfig | 2 +- drivers/mtd/nand/Kconfig | 10 + drivers/mtd/nand/Makefile | 2 +- drivers/mtd/nand/core.c | 140 ++++++ drivers/mtd/nand/raw/Kconfig | 10 - drivers/mtd/nand/raw/nand.c | 134 ------ drivers/mtd/nand/raw/nand_util.c | 664 ----------------------------- drivers/mtd/nand/spi/Kconfig | 1 + drivers/mtd/nand/spi/core.c | 17 +- drivers/mtd/nand/util.c | 709 +++++++++++++++++++++++++++++++ include/nand.h | 2 + 16 files changed, 989 insertions(+), 919 deletions(-) create mode 100644 drivers/mtd/nand/util.c

nand_register() and nand_init() is generic API for both RAW and SPI NAND's. We have to move this functions from drivers/mtd/nand/raw/nand.c to drivers/mtd/nand/core.c.
Functions designed to work with RAW NAND should remain in drivers/mtd/nand/raw/nand.c.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/mtd/Kconfig | 2 +- drivers/mtd/nand/Kconfig | 10 +++ drivers/mtd/nand/core.c | 136 +++++++++++++++++++++++++++++++++++ drivers/mtd/nand/raw/Kconfig | 10 --- drivers/mtd/nand/raw/nand.c | 134 ---------------------------------- include/nand.h | 2 + 6 files changed, 149 insertions(+), 145 deletions(-)
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index c56840c849..1902351719 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -260,7 +260,7 @@ config SYS_NAND_MAX_ECCPOS
config SYS_NAND_MAX_CHIPS int "NAND max chips" - depends on MTD_RAW_NAND || CMD_ONENAND || TARGET_S5PC210_UNIVERSAL || \ + depends on MTD_RAW_NAND || MTD_SPI_NAND || CMD_ONENAND || TARGET_S5PC210_UNIVERSAL || \ SPL_OMAP3_ID_NAND default 1 help diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 78ae04bdcb..9a1d4ac0dc 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,6 +1,16 @@ config MTD_NAND_CORE tristate
+config SYS_MAX_NAND_DEVICE + int "Maximum number of NAND devices to support" + default 1 + +config SYS_NAND_SELF_INIT + bool + help + This option, if enabled, provides more flexible and linux-like + NAND initialization process. + source "drivers/mtd/nand/raw/Kconfig"
source "drivers/mtd/nand/spi/Kconfig" diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c index 4b9dd6a926..ff298e3a0f 100644 --- a/drivers/mtd/nand/core.c +++ b/drivers/mtd/nand/core.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) "nand: " fmt
#include <common.h> +#include <nand.h> #include <watchdog.h> #ifndef __UBOOT__ #include <linux/compat.h> @@ -18,6 +19,12 @@ #include <linux/bitops.h> #include <linux/mtd/nand.h>
+int nand_curr_device = -1; + +static struct mtd_info *nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; +static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8]; +static unsigned long total_nand_size; /* in kiB */ + /** * nanddev_isbad() - Check if a block is bad * @nand: NAND device @@ -250,6 +257,135 @@ void nanddev_cleanup(struct nand_device *nand) } EXPORT_SYMBOL_GPL(nanddev_cleanup);
+struct mtd_info *get_nand_dev_by_index(int dev) +{ + if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev] || + !nand_info[dev]->name) + return NULL; + + return nand_info[dev]; +} +EXPORT_SYMBOL_GPL(get_nand_dev_by_index); + +int nand_mtd_to_devnum(struct mtd_info *mtd) +{ + int i; + + for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { + if (mtd && get_nand_dev_by_index(i) == mtd) + return i; + } + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(nand_mtd_to_devnum); + +/* Register an initialized NAND mtd device with the U-Boot NAND command. */ +int nand_register(int devnum, struct mtd_info *mtd) +{ + if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE) + return -EINVAL; + + nand_info[devnum] = mtd; + + sprintf(dev_name[devnum], "nand%d", devnum); + mtd->name = dev_name[devnum]; + +#ifdef CONFIG_MTD + /* + * Add MTD device so that we can reference it later + * via the mtdcore infrastructure (e.g. ubi). + */ + add_mtd_device(mtd); +#endif + + total_nand_size += mtd->size / 1024; + + if (nand_curr_device == -1) + nand_curr_device = devnum; + + return 0; +} +EXPORT_SYMBOL_GPL(nand_register); + +#ifdef CONFIG_MTD_CONCAT +static void create_mtd_concat(void) +{ + struct mtd_info *nand_info_list[CONFIG_SYS_MAX_NAND_DEVICE]; + int nand_devices_found = 0; + int i; + + for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { + struct mtd_info *mtd = get_nand_dev_by_index(i); + if (mtd != NULL) { + nand_info_list[nand_devices_found] = mtd; + nand_devices_found++; + } + } + if (nand_devices_found > 1) { + struct mtd_info *mtd; + char c_mtd_name[16]; + + /* + * We detected multiple devices. Concatenate them together. + */ + sprintf(c_mtd_name, "nand%d", nand_devices_found); + mtd = mtd_concat_create(nand_info_list, nand_devices_found, + c_mtd_name); + + if (mtd == NULL) + return; + + nand_register(nand_devices_found, mtd); + } + + return; +} +#else +static void create_mtd_concat(void) +{ +} +#endif + +unsigned long nand_size(void) +{ + return total_nand_size; +} +EXPORT_SYMBOL_GPL(nand_size); + +void nand_init(void) +{ + static int initialized; + + /* + * Avoid initializing NAND Flash multiple times, + * otherwise it will calculate a wrong total size. + */ + if (initialized) + return; + initialized = 1; + +#if CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT) + board_nand_init(); +#else + int i; + + for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) + nand_init_chip(i); +#endif + +#ifdef CONFIG_SYS_NAND_SELECT_DEVICE + /* + * Select the chip in the board/cpu specific driver + */ + board_nand_select_device(mtd_to_nand(get_nand_dev_by_index(nand_curr_device)), + nand_curr_device); +#endif + + create_mtd_concat(); +} +EXPORT_SYMBOL_GPL(nand_init); + MODULE_DESCRIPTION("Generic NAND framework"); MODULE_AUTHOR("Boris Brezillon boris.brezillon@free-electrons.com"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index f0100a601d..31949f1dff 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -3,12 +3,6 @@ menuconfig MTD_RAW_NAND bool "Raw NAND Device Support" if MTD_RAW_NAND
-config SYS_NAND_SELF_INIT - bool - help - This option, if enabled, provides more flexible and linux-like - NAND initialization process. - config SPL_SYS_NAND_SELF_INIT bool depends on !SPL_NAND_SIMPLE @@ -29,10 +23,6 @@ config TPL_NAND_INIT config SPL_NAND_INIT bool
-config SYS_MAX_NAND_DEVICE - int "Maximum number of NAND devices to support" - default 1 - config SYS_NAND_DRIVER_ECC_LAYOUT bool "Omit standard ECC layouts to save space" help diff --git a/drivers/mtd/nand/raw/nand.c b/drivers/mtd/nand/raw/nand.c index eacd99c4e2..edca824d77 100644 --- a/drivers/mtd/nand/raw/nand.c +++ b/drivers/mtd/nand/raw/nand.c @@ -15,68 +15,10 @@ #define CFG_SYS_NAND_BASE_LIST { CFG_SYS_NAND_BASE } #endif
-int nand_curr_device = -1; - -static struct mtd_info *nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; - #if !CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT) static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CFG_SYS_NAND_BASE_LIST; -#endif - -static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8]; - -static unsigned long total_nand_size; /* in kiB */ - -struct mtd_info *get_nand_dev_by_index(int dev) -{ - if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev] || - !nand_info[dev]->name) - return NULL;
- return nand_info[dev]; -} - -int nand_mtd_to_devnum(struct mtd_info *mtd) -{ - int i; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { - if (mtd && get_nand_dev_by_index(i) == mtd) - return i; - } - - return -ENODEV; -} - -/* Register an initialized NAND mtd device with the U-Boot NAND command. */ -int nand_register(int devnum, struct mtd_info *mtd) -{ - if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE) - return -EINVAL; - - nand_info[devnum] = mtd; - - sprintf(dev_name[devnum], "nand%d", devnum); - mtd->name = dev_name[devnum]; - -#ifdef CONFIG_MTD - /* - * Add MTD device so that we can reference it later - * via the mtdcore infrastructure (e.g. ubi). - */ - add_mtd_device(mtd); -#endif - - total_nand_size += mtd->size / 1024; - - if (nand_curr_device == -1) - nand_curr_device = devnum; - - return 0; -} - -#if !CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT) static void nand_init_chip(int i) { struct nand_chip *nand = &nand_chip[i]; @@ -98,79 +40,3 @@ static void nand_init_chip(int i) nand_register(i, mtd); } #endif - -#ifdef CONFIG_MTD_CONCAT -static void create_mtd_concat(void) -{ - struct mtd_info *nand_info_list[CONFIG_SYS_MAX_NAND_DEVICE]; - int nand_devices_found = 0; - int i; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { - struct mtd_info *mtd = get_nand_dev_by_index(i); - if (mtd != NULL) { - nand_info_list[nand_devices_found] = mtd; - nand_devices_found++; - } - } - if (nand_devices_found > 1) { - struct mtd_info *mtd; - char c_mtd_name[16]; - - /* - * We detected multiple devices. Concatenate them together. - */ - sprintf(c_mtd_name, "nand%d", nand_devices_found); - mtd = mtd_concat_create(nand_info_list, nand_devices_found, - c_mtd_name); - - if (mtd == NULL) - return; - - nand_register(nand_devices_found, mtd); - } - - return; -} -#else -static void create_mtd_concat(void) -{ -} -#endif - -unsigned long nand_size(void) -{ - return total_nand_size; -} - -void nand_init(void) -{ - static int initialized; - - /* - * Avoid initializing NAND Flash multiple times, - * otherwise it will calculate a wrong total size. - */ - if (initialized) - return; - initialized = 1; - -#if CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT) - board_nand_init(); -#else - int i; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) - nand_init_chip(i); -#endif - -#ifdef CONFIG_SYS_NAND_SELECT_DEVICE - /* - * Select the chip in the board/cpu specific driver - */ - board_nand_select_device(mtd_to_nand(get_nand_dev_by_index(nand_curr_device)), - nand_curr_device); -#endif - - create_mtd_concat(); -} diff --git a/include/nand.h b/include/nand.h index 70c1286ccb..16cfc2a24a 100644 --- a/include/nand.h +++ b/include/nand.h @@ -25,6 +25,8 @@ int nand_register(int devnum, struct mtd_info *mtd); struct nand_chip;
extern int board_nand_init(struct nand_chip *nand); + +void nand_init_chip(int index); #endif
extern int nand_curr_device;

On 12/28/23 10:39, Alexey Romanov wrote:
nand_register() and nand_init() is generic API for both RAW and SPI NAND's. We have to move this functions from drivers/mtd/nand/raw/nand.c to drivers/mtd/nand/core.c.
Functions designed to work with RAW NAND should remain in drivers/mtd/nand/raw/nand.c.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
drivers/mtd/Kconfig | 2 +- drivers/mtd/nand/Kconfig | 10 +++ drivers/mtd/nand/core.c | 136 +++++++++++++++++++++++++++++++++++ drivers/mtd/nand/raw/Kconfig | 10 --- drivers/mtd/nand/raw/nand.c | 134 ---------------------------------- include/nand.h | 2 + 6 files changed, 149 insertions(+), 145 deletions(-)
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index c56840c849..1902351719 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -260,7 +260,7 @@ config SYS_NAND_MAX_ECCPOS
config SYS_NAND_MAX_CHIPS int "NAND max chips"
- depends on MTD_RAW_NAND || CMD_ONENAND || TARGET_S5PC210_UNIVERSAL || \
- depends on MTD_RAW_NAND || MTD_SPI_NAND || CMD_ONENAND || TARGET_S5PC210_UNIVERSAL || \ SPL_OMAP3_ID_NAND default 1 help
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 78ae04bdcb..9a1d4ac0dc 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,6 +1,16 @@ config MTD_NAND_CORE tristate
+config SYS_MAX_NAND_DEVICE
- int "Maximum number of NAND devices to support"
- default 1
+config SYS_NAND_SELF_INIT
- bool
- help
This option, if enabled, provides more flexible and linux-like
NAND initialization process.
source "drivers/mtd/nand/raw/Kconfig"
source "drivers/mtd/nand/spi/Kconfig" diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c index 4b9dd6a926..ff298e3a0f 100644 --- a/drivers/mtd/nand/core.c +++ b/drivers/mtd/nand/core.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) "nand: " fmt
#include <common.h> +#include <nand.h> #include <watchdog.h> #ifndef __UBOOT__ #include <linux/compat.h> @@ -18,6 +19,12 @@ #include <linux/bitops.h> #include <linux/mtd/nand.h>
+int nand_curr_device = -1;
+static struct mtd_info *nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; +static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8]; +static unsigned long total_nand_size; /* in kiB */
/**
- nanddev_isbad() - Check if a block is bad
- @nand: NAND device
@@ -250,6 +257,135 @@ void nanddev_cleanup(struct nand_device *nand) } EXPORT_SYMBOL_GPL(nanddev_cleanup);
+struct mtd_info *get_nand_dev_by_index(int dev) +{
- if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev] ||
!nand_info[dev]->name)
return NULL;
- return nand_info[dev];
+} +EXPORT_SYMBOL_GPL(get_nand_dev_by_index);
+int nand_mtd_to_devnum(struct mtd_info *mtd) +{
- int i;
- for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
if (mtd && get_nand_dev_by_index(i) == mtd)
return i;
- }
- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(nand_mtd_to_devnum);
+/* Register an initialized NAND mtd device with the U-Boot NAND command. */ +int nand_register(int devnum, struct mtd_info *mtd) +{
- if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE)
return -EINVAL;
- nand_info[devnum] = mtd;
- sprintf(dev_name[devnum], "nand%d", devnum);
- mtd->name = dev_name[devnum];
+#ifdef CONFIG_MTD
- /*
* Add MTD device so that we can reference it later
* via the mtdcore infrastructure (e.g. ubi).
*/
- add_mtd_device(mtd);
+#endif
- total_nand_size += mtd->size / 1024;
- if (nand_curr_device == -1)
nand_curr_device = devnum;
- return 0;
+} +EXPORT_SYMBOL_GPL(nand_register);
+#ifdef CONFIG_MTD_CONCAT +static void create_mtd_concat(void) +{
- struct mtd_info *nand_info_list[CONFIG_SYS_MAX_NAND_DEVICE];
- int nand_devices_found = 0;
- int i;
- for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
struct mtd_info *mtd = get_nand_dev_by_index(i);
if (mtd != NULL) {
nand_info_list[nand_devices_found] = mtd;
nand_devices_found++;
}
- }
- if (nand_devices_found > 1) {
struct mtd_info *mtd;
char c_mtd_name[16];
/*
* We detected multiple devices. Concatenate them together.
*/
sprintf(c_mtd_name, "nand%d", nand_devices_found);
mtd = mtd_concat_create(nand_info_list, nand_devices_found,
c_mtd_name);
if (mtd == NULL)
return;
nand_register(nand_devices_found, mtd);
- }
- return;
+} +#else +static void create_mtd_concat(void) +{ +} +#endif
+unsigned long nand_size(void) +{
- return total_nand_size;
+} +EXPORT_SYMBOL_GPL(nand_size);
+void nand_init(void) +{
- static int initialized;
- /*
* Avoid initializing NAND Flash multiple times,
* otherwise it will calculate a wrong total size.
*/
- if (initialized)
return;
- initialized = 1;
+#if CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT)
- board_nand_init();
+#else
- int i;
- for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
nand_init_chip(i);
+#endif
+#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
- /*
* Select the chip in the board/cpu specific driver
*/
- board_nand_select_device(mtd_to_nand(get_nand_dev_by_index(nand_curr_device)),
nand_curr_device);
+#endif
- create_mtd_concat();
+} +EXPORT_SYMBOL_GPL(nand_init);
MODULE_DESCRIPTION("Generic NAND framework"); MODULE_AUTHOR("Boris Brezillon boris.brezillon@free-electrons.com"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index f0100a601d..31949f1dff 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -3,12 +3,6 @@ menuconfig MTD_RAW_NAND bool "Raw NAND Device Support" if MTD_RAW_NAND
-config SYS_NAND_SELF_INIT
- bool
- help
This option, if enabled, provides more flexible and linux-like
NAND initialization process.
config SPL_SYS_NAND_SELF_INIT bool depends on !SPL_NAND_SIMPLE @@ -29,10 +23,6 @@ config TPL_NAND_INIT config SPL_NAND_INIT bool
-config SYS_MAX_NAND_DEVICE
- int "Maximum number of NAND devices to support"
- default 1
config SYS_NAND_DRIVER_ECC_LAYOUT bool "Omit standard ECC layouts to save space" help diff --git a/drivers/mtd/nand/raw/nand.c b/drivers/mtd/nand/raw/nand.c index eacd99c4e2..edca824d77 100644 --- a/drivers/mtd/nand/raw/nand.c +++ b/drivers/mtd/nand/raw/nand.c @@ -15,68 +15,10 @@ #define CFG_SYS_NAND_BASE_LIST { CFG_SYS_NAND_BASE } #endif
-int nand_curr_device = -1;
-static struct mtd_info *nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
#if !CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT) static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CFG_SYS_NAND_BASE_LIST; -#endif
-static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8];
-static unsigned long total_nand_size; /* in kiB */
-struct mtd_info *get_nand_dev_by_index(int dev) -{
if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev] ||
!nand_info[dev]->name)
return NULL;
return nand_info[dev];
-}
-int nand_mtd_to_devnum(struct mtd_info *mtd) -{
- int i;
- for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
if (mtd && get_nand_dev_by_index(i) == mtd)
return i;
- }
- return -ENODEV;
-}
-/* Register an initialized NAND mtd device with the U-Boot NAND command. */ -int nand_register(int devnum, struct mtd_info *mtd) -{
- if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE)
return -EINVAL;
- nand_info[devnum] = mtd;
- sprintf(dev_name[devnum], "nand%d", devnum);
- mtd->name = dev_name[devnum];
-#ifdef CONFIG_MTD
- /*
* Add MTD device so that we can reference it later
* via the mtdcore infrastructure (e.g. ubi).
*/
- add_mtd_device(mtd);
-#endif
- total_nand_size += mtd->size / 1024;
- if (nand_curr_device == -1)
nand_curr_device = devnum;
- return 0;
-}
-#if !CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT)
Please rebase on u-boot/next and also move nand_unregister.
--Sean
static void nand_init_chip(int i) { struct nand_chip *nand = &nand_chip[i]; @@ -98,79 +40,3 @@ static void nand_init_chip(int i) nand_register(i, mtd); } #endif
-#ifdef CONFIG_MTD_CONCAT -static void create_mtd_concat(void) -{
- struct mtd_info *nand_info_list[CONFIG_SYS_MAX_NAND_DEVICE];
- int nand_devices_found = 0;
- int i;
- for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
struct mtd_info *mtd = get_nand_dev_by_index(i);
if (mtd != NULL) {
nand_info_list[nand_devices_found] = mtd;
nand_devices_found++;
}
- }
- if (nand_devices_found > 1) {
struct mtd_info *mtd;
char c_mtd_name[16];
/*
* We detected multiple devices. Concatenate them together.
*/
sprintf(c_mtd_name, "nand%d", nand_devices_found);
mtd = mtd_concat_create(nand_info_list, nand_devices_found,
c_mtd_name);
if (mtd == NULL)
return;
nand_register(nand_devices_found, mtd);
- }
- return;
-} -#else -static void create_mtd_concat(void) -{ -} -#endif
-unsigned long nand_size(void) -{
- return total_nand_size;
-}
-void nand_init(void) -{
- static int initialized;
- /*
* Avoid initializing NAND Flash multiple times,
* otherwise it will calculate a wrong total size.
*/
- if (initialized)
return;
- initialized = 1;
-#if CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT)
- board_nand_init();
-#else
- int i;
- for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
nand_init_chip(i);
-#endif
-#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
- /*
* Select the chip in the board/cpu specific driver
*/
- board_nand_select_device(mtd_to_nand(get_nand_dev_by_index(nand_curr_device)),
nand_curr_device);
-#endif
- create_mtd_concat();
-} diff --git a/include/nand.h b/include/nand.h index 70c1286ccb..16cfc2a24a 100644 --- a/include/nand.h +++ b/include/nand.h @@ -25,6 +25,8 @@ int nand_register(int devnum, struct mtd_info *mtd); struct nand_chip;
extern int board_nand_init(struct nand_chip *nand);
+void nand_init_chip(int index); #endif
extern int nand_curr_device;

We use this function in SPI NAND subsystem, which already filled mtd->name field with "spi-nand0" string.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/mtd/nand/core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c index ff298e3a0f..5a63e74ccb 100644 --- a/drivers/mtd/nand/core.c +++ b/drivers/mtd/nand/core.c @@ -22,7 +22,7 @@ int nand_curr_device = -1;
static struct mtd_info *nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; -static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8]; +static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][16]; static unsigned long total_nand_size; /* in kiB */
/** @@ -288,8 +288,12 @@ int nand_register(int devnum, struct mtd_info *mtd)
nand_info[devnum] = mtd;
- sprintf(dev_name[devnum], "nand%d", devnum); - mtd->name = dev_name[devnum]; + if (!strlen(mtd->name)) { + snprintf(dev_name[devnum], ARRAY_SIZE(dev_name[devnum]), "nand%d", devnum); + mtd->name = dev_name[devnum]; + } else { + strlcpy(dev_name[devnum], mtd->name, ARRAY_SIZE(dev_name[devnum])); + }
#ifdef CONFIG_MTD /*

This is right place for this API. Now, fastboot code uses this API: these functions should be available regardless of the selected NAND type (RAW / SPI).
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/mtd/nand/Makefile | 2 +- drivers/mtd/nand/raw/nand_util.c | 511 ----------------------------- drivers/mtd/nand/util.c | 543 +++++++++++++++++++++++++++++++ 3 files changed, 544 insertions(+), 512 deletions(-) create mode 100644 drivers/mtd/nand/util.c
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 96e186600a..301b1bceff 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+
ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TPL_BUILD),) -nandcore-objs := core.o bbt.o +nandcore-objs := core.o bbt.o util.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o obj-$(CONFIG_MTD_RAW_NAND) += raw/ obj-$(CONFIG_MTD_SPI_NAND) += spi/ diff --git a/drivers/mtd/nand/raw/nand_util.c b/drivers/mtd/nand/raw/nand_util.c index 72cc24f403..9c18ce63b9 100644 --- a/drivers/mtd/nand/raw/nand_util.c +++ b/drivers/mtd/nand/raw/nand_util.c @@ -35,7 +35,6 @@ #include <jffs2/jffs2.h>
typedef struct erase_info erase_info_t; -typedef struct mtd_info mtd_info_t;
/* support only for native endian JFFS2 */ #define cpu_to_je16(x) (x) @@ -395,513 +394,3 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, return ret; } #endif - -/** - * check_skip_len - * - * Check if there are any bad blocks, and whether length including bad - * blocks fits into device - * - * @param mtd nand mtd instance - * @param offset offset in flash - * @param length image length - * @param used length of flash needed for the requested length - * Return: 0 if the image fits and there are no bad blocks - * 1 if the image fits, but there are bad blocks - * -1 if the image does not fit - */ -static int check_skip_len(struct mtd_info *mtd, loff_t offset, size_t length, - size_t *used) -{ - size_t len_excl_bad = 0; - int ret = 0; - - while (len_excl_bad < length) { - size_t block_len, block_off; - loff_t block_start; - - if (offset >= mtd->size) - return -1; - - block_start = offset & ~(loff_t)(mtd->erasesize - 1); - block_off = offset & (mtd->erasesize - 1); - block_len = mtd->erasesize - block_off; - - if (!nand_block_isbad(mtd, block_start)) - len_excl_bad += block_len; - else - ret = 1; - - offset += block_len; - *used += block_len; - } - - /* If the length is not a multiple of block_len, adjust. */ - if (len_excl_bad > length) - *used -= (len_excl_bad - length); - - return ret; -} - -#ifdef CONFIG_CMD_NAND_TRIMFFS -static size_t drop_ffs(const struct mtd_info *mtd, const u_char *buf, - const size_t *len) -{ - size_t l = *len; - ssize_t i; - - for (i = l - 1; i >= 0; i--) - if (buf[i] != 0xFF) - break; - - /* The resulting length must be aligned to the minimum flash I/O size */ - l = i + 1; - l = (l + mtd->writesize - 1) / mtd->writesize; - l *= mtd->writesize; - - /* - * since the input length may be unaligned, prevent access past the end - * of the buffer - */ - return min(l, *len); -} -#endif - -/** - * nand_verify_page_oob: - * - * Verify a page of NAND flash, including the OOB. - * Reads page of NAND and verifies the contents and OOB against the - * values in ops. - * - * @param mtd nand mtd instance - * @param ops MTD operations, including data to verify - * @param ofs offset in flash - * Return: 0 in case of success - */ -int nand_verify_page_oob(struct mtd_info *mtd, struct mtd_oob_ops *ops, - loff_t ofs) -{ - int rval; - struct mtd_oob_ops vops; - size_t verlen = mtd->writesize + mtd->oobsize; - - memcpy(&vops, ops, sizeof(vops)); - - vops.datbuf = memalign(ARCH_DMA_MINALIGN, verlen); - - if (!vops.datbuf) - return -ENOMEM; - - vops.oobbuf = vops.datbuf + mtd->writesize; - - rval = mtd_read_oob(mtd, ofs, &vops); - if (!rval) - rval = memcmp(ops->datbuf, vops.datbuf, vops.len); - if (!rval) - rval = memcmp(ops->oobbuf, vops.oobbuf, vops.ooblen); - - free(vops.datbuf); - - return rval ? -EIO : 0; -} - -/** - * nand_verify: - * - * Verify a region of NAND flash. - * Reads NAND in page-sized chunks and verifies the contents against - * the contents of a buffer. The offset into the NAND must be - * page-aligned, and the function doesn't handle skipping bad blocks. - * - * @param mtd nand mtd instance - * @param ofs offset in flash - * @param len buffer length - * @param buf buffer to read from - * Return: 0 in case of success - */ -int nand_verify(struct mtd_info *mtd, loff_t ofs, size_t len, u_char *buf) -{ - int rval = 0; - size_t verofs; - size_t verlen = mtd->writesize; - uint8_t *verbuf = memalign(ARCH_DMA_MINALIGN, verlen); - - if (!verbuf) - return -ENOMEM; - - /* Read the NAND back in page-size groups to limit malloc size */ - for (verofs = ofs; verofs < ofs + len; - verofs += verlen, buf += verlen) { - verlen = min(mtd->writesize, (uint32_t)(ofs + len - verofs)); - rval = nand_read(mtd, verofs, &verlen, verbuf); - if (!rval || (rval == -EUCLEAN)) - rval = memcmp(buf, verbuf, verlen); - - if (rval) - break; - } - - free(verbuf); - - return rval ? -EIO : 0; -} - -/** - * nand_write_skip_bad: - * - * Write image to NAND flash. - * Blocks that are marked bad are skipped and the is written to the next - * block instead as long as the image is short enough to fit even after - * skipping the bad blocks. Due to bad blocks we may not be able to - * perform the requested write. In the case where the write would - * extend beyond the end of the NAND device, both length and actual (if - * not NULL) are set to 0. In the case where the write would extend - * beyond the limit we are passed, length is set to 0 and actual is set - * to the required length. - * - * @param mtd nand mtd instance - * @param offset offset in flash - * @param length buffer length - * @param actual set to size required to write length worth of - * buffer or 0 on error, if not NULL - * @param lim maximum size that actual may be in order to not - * exceed the buffer - * @param buffer buffer to read from - * @param flags flags modifying the behaviour of the write to NAND - * Return: 0 in case of success - */ -int nand_write_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length, - size_t *actual, loff_t lim, u_char *buffer, int flags) -{ - int rval = 0, blocksize; - size_t left_to_write = *length; - size_t used_for_write = 0; - u_char *p_buffer = buffer; - int need_skip; - - if (actual) - *actual = 0; - - blocksize = mtd->erasesize; - - /* - * nand_write() handles unaligned, partial page writes. - * - * We allow length to be unaligned, for convenience in - * using the $filesize variable. - * - * However, starting at an unaligned offset makes the - * semantics of bad block skipping ambiguous (really, - * you should only start a block skipping access at a - * partition boundary). So don't try to handle that. - */ - if ((offset & (mtd->writesize - 1)) != 0) { - printf("Attempt to write non page-aligned data\n"); - *length = 0; - return -EINVAL; - } - - need_skip = check_skip_len(mtd, offset, *length, &used_for_write); - - if (actual) - *actual = used_for_write; - - if (need_skip < 0) { - printf("Attempt to write outside the flash area\n"); - *length = 0; - return -EINVAL; - } - - if (used_for_write > lim) { - puts("Size of write exceeds partition or device limit\n"); - *length = 0; - return -EFBIG; - } - - if (!need_skip && !(flags & WITH_DROP_FFS)) { - rval = nand_write(mtd, offset, length, buffer); - - if ((flags & WITH_WR_VERIFY) && !rval) - rval = nand_verify(mtd, offset, *length, buffer); - - if (rval == 0) - return 0; - - *length = 0; - printf("NAND write to offset %llx failed %d\n", - offset, rval); - return rval; - } - - while (left_to_write > 0) { - loff_t block_start = offset & ~(loff_t)(mtd->erasesize - 1); - size_t block_offset = offset & (mtd->erasesize - 1); - size_t write_size, truncated_write_size; - - schedule(); - - if (nand_block_isbad(mtd, block_start)) { - printf("Skip bad block 0x%08llx\n", block_start); - offset += mtd->erasesize - block_offset; - continue; - } - - if (left_to_write < (blocksize - block_offset)) - write_size = left_to_write; - else - write_size = blocksize - block_offset; - - truncated_write_size = write_size; -#ifdef CONFIG_CMD_NAND_TRIMFFS - if (flags & WITH_DROP_FFS) - truncated_write_size = drop_ffs(mtd, p_buffer, - &write_size); -#endif - - rval = nand_write(mtd, offset, &truncated_write_size, - p_buffer); - - if ((flags & WITH_WR_VERIFY) && !rval) - rval = nand_verify(mtd, offset, - truncated_write_size, p_buffer); - - offset += write_size; - p_buffer += write_size; - - if (rval != 0) { - printf("NAND write to offset %llx failed %d\n", - offset, rval); - *length -= left_to_write; - return rval; - } - - left_to_write -= write_size; - } - - return 0; -} - -/** - * nand_read_skip_bad: - * - * Read image from NAND flash. - * Blocks that are marked bad are skipped and the next block is read - * instead as long as the image is short enough to fit even after - * skipping the bad blocks. Due to bad blocks we may not be able to - * perform the requested read. In the case where the read would extend - * beyond the end of the NAND device, both length and actual (if not - * NULL) are set to 0. In the case where the read would extend beyond - * the limit we are passed, length is set to 0 and actual is set to the - * required length. - * - * @param mtd nand mtd instance - * @param offset offset in flash - * @param length buffer length, on return holds number of read bytes - * @param actual set to size required to read length worth of buffer or 0 - * on error, if not NULL - * @param lim maximum size that actual may be in order to not exceed the - * buffer - * @param buffer buffer to write to - * Return: 0 in case of success - */ -int nand_read_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length, - size_t *actual, loff_t lim, u_char *buffer) -{ - int rval; - size_t left_to_read = *length; - size_t used_for_read = 0; - u_char *p_buffer = buffer; - int need_skip; - - if ((offset & (mtd->writesize - 1)) != 0) { - printf("Attempt to read non page-aligned data\n"); - *length = 0; - if (actual) - *actual = 0; - return -EINVAL; - } - - need_skip = check_skip_len(mtd, offset, *length, &used_for_read); - - if (actual) - *actual = used_for_read; - - if (need_skip < 0) { - printf("Attempt to read outside the flash area\n"); - *length = 0; - return -EINVAL; - } - - if (used_for_read > lim) { - puts("Size of read exceeds partition or device limit\n"); - *length = 0; - return -EFBIG; - } - - if (!need_skip) { - rval = nand_read(mtd, offset, length, buffer); - if (!rval || rval == -EUCLEAN) - return 0; - - *length = 0; - printf("NAND read from offset %llx failed %d\n", - offset, rval); - return rval; - } - - while (left_to_read > 0) { - size_t block_offset = offset & (mtd->erasesize - 1); - size_t read_length; - - schedule(); - - if (nand_block_isbad(mtd, offset & ~(mtd->erasesize - 1))) { - printf("Skipping bad block 0x%08llx\n", - offset & ~(mtd->erasesize - 1)); - offset += mtd->erasesize - block_offset; - continue; - } - - if (left_to_read < (mtd->erasesize - block_offset)) - read_length = left_to_read; - else - read_length = mtd->erasesize - block_offset; - - rval = nand_read(mtd, offset, &read_length, p_buffer); - if (rval && rval != -EUCLEAN) { - printf("NAND read from offset %llx failed %d\n", - offset, rval); - *length -= left_to_read; - return rval; - } - - left_to_read -= read_length; - offset += read_length; - p_buffer += read_length; - } - - return 0; -} - -#ifdef CONFIG_CMD_NAND_TORTURE - -/** - * check_pattern: - * - * Check if buffer contains only a certain byte pattern. - * - * @param buf buffer to check - * @param patt the pattern to check - * @param size buffer size in bytes - * Return: 1 if there are only patt bytes in buf - * 0 if something else was found - */ -static int check_pattern(const u_char *buf, u_char patt, int size) -{ - int i; - - for (i = 0; i < size; i++) - if (buf[i] != patt) - return 0; - return 1; -} - -/** - * nand_torture: - * - * Torture a block of NAND flash. - * This is useful to determine if a block that caused a write error is still - * good or should be marked as bad. - * - * @param mtd nand mtd instance - * @param offset offset in flash - * Return: 0 if the block is still good - */ -int nand_torture(struct mtd_info *mtd, loff_t offset) -{ - u_char patterns[] = {0xa5, 0x5a, 0x00}; - struct erase_info instr = { - .mtd = mtd, - .addr = offset, - .len = mtd->erasesize, - }; - size_t retlen; - int err, ret = -1, i, patt_count; - u_char *buf; - - if ((offset & (mtd->erasesize - 1)) != 0) { - puts("Attempt to torture a block at a non block-aligned offset\n"); - return -EINVAL; - } - - if (offset + mtd->erasesize > mtd->size) { - puts("Attempt to torture a block outside the flash area\n"); - return -EINVAL; - } - - patt_count = ARRAY_SIZE(patterns); - - buf = malloc_cache_aligned(mtd->erasesize); - if (buf == NULL) { - puts("Out of memory for erase block buffer\n"); - return -ENOMEM; - } - - for (i = 0; i < patt_count; i++) { - err = mtd_erase(mtd, &instr); - if (err) { - printf("%s: erase() failed for block at 0x%llx: %d\n", - mtd->name, instr.addr, err); - goto out; - } - - /* Make sure the block contains only 0xff bytes */ - err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf); - if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) { - printf("%s: read() failed for block at 0x%llx: %d\n", - mtd->name, instr.addr, err); - goto out; - } - - err = check_pattern(buf, 0xff, mtd->erasesize); - if (!err) { - printf("Erased block at 0x%llx, but a non-0xff byte was found\n", - offset); - ret = -EIO; - goto out; - } - - /* Write a pattern and check it */ - memset(buf, patterns[i], mtd->erasesize); - err = mtd_write(mtd, offset, mtd->erasesize, &retlen, buf); - if (err || retlen != mtd->erasesize) { - printf("%s: write() failed for block at 0x%llx: %d\n", - mtd->name, instr.addr, err); - goto out; - } - - err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf); - if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) { - printf("%s: read() failed for block at 0x%llx: %d\n", - mtd->name, instr.addr, err); - goto out; - } - - err = check_pattern(buf, patterns[i], mtd->erasesize); - if (!err) { - printf("Pattern 0x%.2x checking failed for block at " - "0x%llx\n", patterns[i], offset); - ret = -EIO; - goto out; - } - } - - ret = 0; - -out: - free(buf); - return ret; -} - -#endif diff --git a/drivers/mtd/nand/util.c b/drivers/mtd/nand/util.c new file mode 100644 index 0000000000..4a372bb67d --- /dev/null +++ b/drivers/mtd/nand/util.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * drivers/mtd/nand/util.c + * + * Copyright (C) 2006 by Weiss-Electronic GmbH. + * All rights reserved. + * + * @author: Guido Classen clagix@gmail.com + * @descr: NAND Flash support + * @references: borrowed heavily from Linux mtd-utils code: + * flash_eraseall.c by Arcom Control System Ltd + * nandwrite.c by Steven J. Hill (sjhill@realitydiluted.com) + * and Thomas Gleixner (tglx@linutronix.de) + * + * Copyright (C) 2008 Nokia Corporation: drop_ffs() function by + * Artem Bityutskiy dedekind1@gmail.com from mtd-utils + * + * Copyright 2010 Freescale Semiconductor + */ + +#include <common.h> +#include <command.h> +#include <log.h> +#include <watchdog.h> +#include <malloc.h> +#include <memalign.h> +#include <div64.h> +#include <asm/cache.h> +#include <dm/devres.h> + +#include <linux/errno.h> +#include <linux/mtd/mtd.h> +#include <nand.h> + +/** + * check_skip_len + * + * Check if there are any bad blocks, and whether length including bad + * blocks fits into device + * + * @param mtd nand mtd instance + * @param offset offset in flash + * @param length image length + * @param used length of flash needed for the requested length + * Return: 0 if the image fits and there are no bad blocks + * 1 if the image fits, but there are bad blocks + * -1 if the image does not fit + */ +static int check_skip_len(struct mtd_info *mtd, loff_t offset, size_t length, + size_t *used) +{ + size_t len_excl_bad = 0; + int ret = 0; + + while (len_excl_bad < length) { + size_t block_len, block_off; + loff_t block_start; + + if (offset >= mtd->size) + return -1; + + block_start = offset & ~(loff_t)(mtd->erasesize - 1); + block_off = offset & (mtd->erasesize - 1); + block_len = mtd->erasesize - block_off; + + if (!nand_block_isbad(mtd, block_start)) + len_excl_bad += block_len; + else + ret = 1; + + offset += block_len; + *used += block_len; + } + + /* If the length is not a multiple of block_len, adjust. */ + if (len_excl_bad > length) + *used -= (len_excl_bad - length); + + return ret; +} + +#ifdef CONFIG_CMD_NAND_TRIMFFS +static size_t drop_ffs(const struct mtd_info *mtd, const u_char *buf, + const size_t *len) +{ + size_t l = *len; + ssize_t i; + + for (i = l - 1; i >= 0; i--) + if (buf[i] != 0xFF) + break; + + /* The resulting length must be aligned to the minimum flash I/O size */ + l = i + 1; + l = (l + mtd->writesize - 1) / mtd->writesize; + l *= mtd->writesize; + + /* + * since the input length may be unaligned, prevent access past the end + * of the buffer + */ + return min(l, *len); +} +#endif + +/** + * nand_verify_page_oob: + * + * Verify a page of NAND flash, including the OOB. + * Reads page of NAND and verifies the contents and OOB against the + * values in ops. + * + * @param mtd nand mtd instance + * @param ops MTD operations, including data to verify + * @param ofs offset in flash + * Return: 0 in case of success + */ +int nand_verify_page_oob(struct mtd_info *mtd, struct mtd_oob_ops *ops, + loff_t ofs) +{ + int rval; + struct mtd_oob_ops vops; + size_t verlen = mtd->writesize + mtd->oobsize; + + memcpy(&vops, ops, sizeof(vops)); + + vops.datbuf = memalign(ARCH_DMA_MINALIGN, verlen); + + if (!vops.datbuf) + return -ENOMEM; + + vops.oobbuf = vops.datbuf + mtd->writesize; + + rval = mtd_read_oob(mtd, ofs, &vops); + if (!rval) + rval = memcmp(ops->datbuf, vops.datbuf, vops.len); + if (!rval) + rval = memcmp(ops->oobbuf, vops.oobbuf, vops.ooblen); + + free(vops.datbuf); + + return rval ? -EIO : 0; +} + +/** + * nand_verify: + * + * Verify a region of NAND flash. + * Reads NAND in page-sized chunks and verifies the contents against + * the contents of a buffer. The offset into the NAND must be + * page-aligned, and the function doesn't handle skipping bad blocks. + * + * @param mtd nand mtd instance + * @param ofs offset in flash + * @param len buffer length + * @param buf buffer to read from + * Return: 0 in case of success + */ +int nand_verify(struct mtd_info *mtd, loff_t ofs, size_t len, u_char *buf) +{ + int rval = 0; + size_t verofs; + size_t verlen = mtd->writesize; + uint8_t *verbuf = memalign(ARCH_DMA_MINALIGN, verlen); + + if (!verbuf) + return -ENOMEM; + + /* Read the NAND back in page-size groups to limit malloc size */ + for (verofs = ofs; verofs < ofs + len; + verofs += verlen, buf += verlen) { + verlen = min(mtd->writesize, (uint32_t)(ofs + len - verofs)); + rval = nand_read(mtd, verofs, &verlen, verbuf); + if (!rval || (rval == -EUCLEAN)) + rval = memcmp(buf, verbuf, verlen); + + if (rval) + break; + } + + free(verbuf); + + return rval ? -EIO : 0; +} + +/** + * nand_write_skip_bad: + * + * Write image to NAND flash. + * Blocks that are marked bad are skipped and the is written to the next + * block instead as long as the image is short enough to fit even after + * skipping the bad blocks. Due to bad blocks we may not be able to + * perform the requested write. In the case where the write would + * extend beyond the end of the NAND device, both length and actual (if + * not NULL) are set to 0. In the case where the write would extend + * beyond the limit we are passed, length is set to 0 and actual is set + * to the required length. + * + * @param mtd nand mtd instance + * @param offset offset in flash + * @param length buffer length + * @param actual set to size required to write length worth of + * buffer or 0 on error, if not NULL + * @param lim maximum size that actual may be in order to not + * exceed the buffer + * @param buffer buffer to read from + * @param flags flags modifying the behaviour of the write to NAND + * Return: 0 in case of success + */ +int nand_write_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length, + size_t *actual, loff_t lim, u_char *buffer, int flags) +{ + int rval = 0, blocksize; + size_t left_to_write = *length; + size_t used_for_write = 0; + u_char *p_buffer = buffer; + int need_skip; + + if (actual) + *actual = 0; + + blocksize = mtd->erasesize; + + /* + * nand_write() handles unaligned, partial page writes. + * + * We allow length to be unaligned, for convenience in + * using the $filesize variable. + * + * However, starting at an unaligned offset makes the + * semantics of bad block skipping ambiguous (really, + * you should only start a block skipping access at a + * partition boundary). So don't try to handle that. + */ + if ((offset & (mtd->writesize - 1)) != 0) { + printf("Attempt to write non page-aligned data\n"); + *length = 0; + return -EINVAL; + } + + need_skip = check_skip_len(mtd, offset, *length, &used_for_write); + + if (actual) + *actual = used_for_write; + + if (need_skip < 0) { + printf("Attempt to write outside the flash area\n"); + *length = 0; + return -EINVAL; + } + + if (used_for_write > lim) { + puts("Size of write exceeds partition or device limit\n"); + *length = 0; + return -EFBIG; + } + + if (!need_skip && !(flags & WITH_DROP_FFS)) { + rval = nand_write(mtd, offset, length, buffer); + + if ((flags & WITH_WR_VERIFY) && !rval) + rval = nand_verify(mtd, offset, *length, buffer); + + if (rval == 0) + return 0; + + *length = 0; + printf("NAND write to offset %llx failed %d\n", + offset, rval); + return rval; + } + + while (left_to_write > 0) { + loff_t block_start = offset & ~(loff_t)(mtd->erasesize - 1); + size_t block_offset = offset & (mtd->erasesize - 1); + size_t write_size, truncated_write_size; + + schedule(); + + if (nand_block_isbad(mtd, block_start)) { + printf("Skip bad block 0x%08llx\n", block_start); + offset += mtd->erasesize - block_offset; + continue; + } + + if (left_to_write < (blocksize - block_offset)) + write_size = left_to_write; + else + write_size = blocksize - block_offset; + + truncated_write_size = write_size; +#ifdef CONFIG_CMD_NAND_TRIMFFS + if (flags & WITH_DROP_FFS) + truncated_write_size = drop_ffs(mtd, p_buffer, + &write_size); +#endif + + rval = nand_write(mtd, offset, &truncated_write_size, + p_buffer); + + if ((flags & WITH_WR_VERIFY) && !rval) + rval = nand_verify(mtd, offset, + truncated_write_size, p_buffer); + + offset += write_size; + p_buffer += write_size; + + if (rval != 0) { + printf("NAND write to offset %llx failed %d\n", + offset, rval); + *length -= left_to_write; + return rval; + } + + left_to_write -= write_size; + } + + return 0; +} + +/** + * nand_read_skip_bad: + * + * Read image from NAND flash. + * Blocks that are marked bad are skipped and the next block is read + * instead as long as the image is short enough to fit even after + * skipping the bad blocks. Due to bad blocks we may not be able to + * perform the requested read. In the case where the read would extend + * beyond the end of the NAND device, both length and actual (if not + * NULL) are set to 0. In the case where the read would extend beyond + * the limit we are passed, length is set to 0 and actual is set to the + * required length. + * + * @param mtd nand mtd instance + * @param offset offset in flash + * @param length buffer length, on return holds number of read bytes + * @param actual set to size required to read length worth of buffer or 0 + * on error, if not NULL + * @param lim maximum size that actual may be in order to not exceed the + * buffer + * @param buffer buffer to write to + * Return: 0 in case of success + */ +int nand_read_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length, + size_t *actual, loff_t lim, u_char *buffer) +{ + int rval; + size_t left_to_read = *length; + size_t used_for_read = 0; + u_char *p_buffer = buffer; + int need_skip; + + if ((offset & (mtd->writesize - 1)) != 0) { + printf("Attempt to read non page-aligned data\n"); + *length = 0; + if (actual) + *actual = 0; + return -EINVAL; + } + + need_skip = check_skip_len(mtd, offset, *length, &used_for_read); + + if (actual) + *actual = used_for_read; + + if (need_skip < 0) { + printf("Attempt to read outside the flash area\n"); + *length = 0; + return -EINVAL; + } + + if (used_for_read > lim) { + puts("Size of read exceeds partition or device limit\n"); + *length = 0; + return -EFBIG; + } + + if (!need_skip) { + rval = nand_read(mtd, offset, length, buffer); + if (!rval || rval == -EUCLEAN) + return 0; + + *length = 0; + printf("NAND read from offset %llx failed %d\n", + offset, rval); + return rval; + } + + while (left_to_read > 0) { + size_t block_offset = offset & (mtd->erasesize - 1); + size_t read_length; + + schedule(); + + if (nand_block_isbad(mtd, offset & ~(mtd->erasesize - 1))) { + printf("Skipping bad block 0x%08llx\n", + offset & ~(mtd->erasesize - 1)); + offset += mtd->erasesize - block_offset; + continue; + } + + if (left_to_read < (mtd->erasesize - block_offset)) + read_length = left_to_read; + else + read_length = mtd->erasesize - block_offset; + + rval = nand_read(mtd, offset, &read_length, p_buffer); + if (rval && rval != -EUCLEAN) { + printf("NAND read from offset %llx failed %d\n", + offset, rval); + *length -= left_to_read; + return rval; + } + + left_to_read -= read_length; + offset += read_length; + p_buffer += read_length; + } + + return 0; +} + +#ifdef CONFIG_CMD_NAND_TORTURE + +/** + * check_pattern: + * + * Check if buffer contains only a certain byte pattern. + * + * @param buf buffer to check + * @param patt the pattern to check + * @param size buffer size in bytes + * Return: 1 if there are only patt bytes in buf + * 0 if something else was found + */ +static int check_pattern(const u_char *buf, u_char patt, int size) +{ + int i; + + for (i = 0; i < size; i++) + if (buf[i] != patt) + return 0; + return 1; +} + +/** + * nand_torture: + * + * Torture a block of NAND flash. + * This is useful to determine if a block that caused a write error is still + * good or should be marked as bad. + * + * @param mtd nand mtd instance + * @param offset offset in flash + * Return: 0 if the block is still good + */ +int nand_torture(struct mtd_info *mtd, loff_t offset) +{ + u_char patterns[] = {0xa5, 0x5a, 0x00}; + struct erase_info instr = { + .mtd = mtd, + .addr = offset, + .len = mtd->erasesize, + }; + size_t retlen; + int err, ret = -1, i, patt_count; + u_char *buf; + + if ((offset & (mtd->erasesize - 1)) != 0) { + puts("Attempt to torture a block at a non block-aligned offset\n"); + return -EINVAL; + } + + if (offset + mtd->erasesize > mtd->size) { + puts("Attempt to torture a block outside the flash area\n"); + return -EINVAL; + } + + patt_count = ARRAY_SIZE(patterns); + + buf = malloc_cache_aligned(mtd->erasesize); + if (buf == NULL) { + puts("Out of memory for erase block buffer\n"); + return -ENOMEM; + } + + for (i = 0; i < patt_count; i++) { + err = mtd_erase(mtd, &instr); + if (err) { + printf("%s: erase() failed for block at 0x%llx: %d\n", + mtd->name, instr.addr, err); + goto out; + } + + /* Make sure the block contains only 0xff bytes */ + err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf); + if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) { + printf("%s: read() failed for block at 0x%llx: %d\n", + mtd->name, instr.addr, err); + goto out; + } + + err = check_pattern(buf, 0xff, mtd->erasesize); + if (!err) { + printf("Erased block at 0x%llx, but a non-0xff byte was found\n", + offset); + ret = -EIO; + goto out; + } + + /* Write a pattern and check it */ + memset(buf, patterns[i], mtd->erasesize); + err = mtd_write(mtd, offset, mtd->erasesize, &retlen, buf); + if (err || retlen != mtd->erasesize) { + printf("%s: write() failed for block at 0x%llx: %d\n", + mtd->name, instr.addr, err); + goto out; + } + + err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf); + if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) { + printf("%s: read() failed for block at 0x%llx: %d\n", + mtd->name, instr.addr, err); + goto out; + } + + err = check_pattern(buf, patterns[i], mtd->erasesize); + if (!err) { + printf("Pattern 0x%.2x checking failed for block at " + "0x%llx\n", patterns[i], offset); + ret = -EIO; + goto out; + } + } + + ret = 0; + +out: + free(buf); + return ret; +} + +#endif

Currently nand_erase_opts() placed in the nand/raw/ folder, because it uses the RAW NAND specific API (struct nand_chip). This patch move it to core NAND folder and make function generic, for both RAW/SPI NAND's usage.
Also, nand_erase_opts() used in fastboot/fb_nand.c, cmd/nand.c and env/nand.c code. This is also the reason why we should move it to core folder and make it more general.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/mtd/nand/raw/nand_util.c | 153 ---------------------------- drivers/mtd/nand/util.c | 166 +++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 153 deletions(-)
diff --git a/drivers/mtd/nand/raw/nand_util.c b/drivers/mtd/nand/raw/nand_util.c index 9c18ce63b9..f7704d4697 100644 --- a/drivers/mtd/nand/raw/nand_util.c +++ b/drivers/mtd/nand/raw/nand_util.c @@ -32,159 +32,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/rawnand.h> #include <nand.h> -#include <jffs2/jffs2.h> - -typedef struct erase_info erase_info_t; - -/* support only for native endian JFFS2 */ -#define cpu_to_je16(x) (x) -#define cpu_to_je32(x) (x) - -/** - * nand_erase_opts: - erase NAND flash with support for various options - * (jffs2 formatting) - * - * @param mtd nand mtd instance to erase - * @param opts options, @see struct nand_erase_options - * Return: 0 in case of success - * - * This code is ported from flash_eraseall.c from Linux mtd utils by - * Arcom Control System Ltd. - */ -int nand_erase_opts(struct mtd_info *mtd, - const nand_erase_options_t *opts) -{ - struct jffs2_unknown_node cleanmarker; - erase_info_t erase; - unsigned long erase_length, erased_length; /* in blocks */ - int result; - int percent_complete = -1; - const char *mtd_device = mtd->name; - struct mtd_oob_ops oob_opts; - struct nand_chip *chip = mtd_to_nand(mtd); - - if ((opts->offset & (mtd->erasesize - 1)) != 0) { - printf("Attempt to erase non block-aligned data\n"); - return -1; - } - - memset(&erase, 0, sizeof(erase)); - memset(&oob_opts, 0, sizeof(oob_opts)); - - erase.mtd = mtd; - erase.len = mtd->erasesize; - erase.addr = opts->offset; - erase_length = lldiv(opts->length + mtd->erasesize - 1, - mtd->erasesize); - - cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); - cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); - cleanmarker.totlen = cpu_to_je32(8); - - /* scrub option allows to erase badblock. To prevent internal - * check from erase() method, set block check method to dummy - * and disable bad block table while erasing. - */ - if (opts->scrub) { - erase.scrub = opts->scrub; - /* - * We don't need the bad block table anymore... - * after scrub, there are no bad blocks left! - */ - if (chip->bbt) { - kfree(chip->bbt); - } - chip->bbt = NULL; - chip->options &= ~NAND_BBT_SCANNED; - } - - for (erased_length = 0; - erased_length < erase_length; - erase.addr += mtd->erasesize) { - - schedule(); - - if (opts->lim && (erase.addr >= (opts->offset + opts->lim))) { - puts("Size of erase exceeds limit\n"); - return -EFBIG; - } - if (!opts->scrub) { - int ret = mtd_block_isbad(mtd, erase.addr); - if (ret > 0) { - if (!opts->quiet) - printf("\rSkipping %s at " - "0x%08llx " - " \n", - ret == 1 ? "bad block" : "bbt reserved", - erase.addr); - - if (!opts->spread) - erased_length++; - - continue; - - } else if (ret < 0) { - printf("\n%s: MTD get bad block failed: %d\n", - mtd_device, - ret); - return -1; - } - } - - erased_length++; - - result = mtd_erase(mtd, &erase); - if (result != 0) { - printf("\n%s: MTD Erase failure: %d\n", - mtd_device, result); - continue; - } - - /* format for JFFS2 ? */ - if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) { - struct mtd_oob_ops ops; - ops.ooblen = 8; - ops.datbuf = NULL; - ops.oobbuf = (uint8_t *)&cleanmarker; - ops.ooboffs = 0; - ops.mode = MTD_OPS_AUTO_OOB; - - result = mtd_write_oob(mtd, erase.addr, &ops); - if (result != 0) { - printf("\n%s: MTD writeoob failure: %d\n", - mtd_device, result); - continue; - } - } - - if (!opts->quiet) { - unsigned long long n = erased_length * 100ULL; - int percent; - - do_div(n, erase_length); - percent = (int)n; - - /* output progress message only at whole percent - * steps to reduce the number of messages printed - * on (slow) serial consoles - */ - if (percent != percent_complete) { - percent_complete = percent; - - printf("\rErasing at 0x%llx -- %3d%% complete.", - erase.addr, percent); - - if (opts->jffs2 && result == 0) - printf(" Cleanmarker written at 0x%llx.", - erase.addr); - } - } - } - if (!opts->quiet) - printf("\n"); - - return 0; -}
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
diff --git a/drivers/mtd/nand/util.c b/drivers/mtd/nand/util.c index 4a372bb67d..f02c1ef4ca 100644 --- a/drivers/mtd/nand/util.c +++ b/drivers/mtd/nand/util.c @@ -28,10 +28,176 @@ #include <asm/cache.h> #include <dm/devres.h>
+#include <jffs2/jffs2.h> #include <linux/errno.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/rawnand.h> #include <nand.h>
+typedef struct erase_info erase_info_t; + +/* support only for native endian JFFS2 */ +#define cpu_to_je16(x) (x) +#define cpu_to_je32(x) (x) + +/** + * nand_erase_opts: - erase NAND flash with support for various options + * (jffs2 formatting) + * + * @param mtd nand mtd instance to erase + * @param opts options, @see struct nand_erase_options + * Return: 0 in case of success + * + * This code is ported from flash_eraseall.c from Linux mtd utils by + * Arcom Control System Ltd. + */ +int nand_erase_opts(struct mtd_info *mtd, + const nand_erase_options_t *opts) +{ + struct jffs2_unknown_node cleanmarker; + erase_info_t erase; + unsigned long erase_length, erased_length; /* in blocks */ + int result; + int percent_complete = -1; + const char *mtd_device = mtd->name; + struct mtd_oob_ops oob_opts; + u32 oobavail = mtd->oobavail; +#if CONFIG_IS_ENABLED(MTD_RAW_NAND) + struct nand_chip *chip = mtd_to_nand(mtd); +#elif CONFIG_IS_ENABLED(MTD_SPI_NAND) + struct nand_device *nand = mtd_to_nanddev(mtd); +#endif + + if ((opts->offset & (mtd->erasesize - 1)) != 0) { + printf("Attempt to erase non block-aligned data\n"); + return -1; + } + + memset(&erase, 0, sizeof(erase)); + memset(&oob_opts, 0, sizeof(oob_opts)); + + erase.mtd = mtd; + erase.len = mtd->erasesize; + erase.addr = opts->offset; + erase_length = lldiv(opts->length + mtd->erasesize - 1, + mtd->erasesize); + + cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); + cleanmarker.totlen = cpu_to_je32(8); + + /* scrub option allows to erase badblock. To prevent internal + * check from erase() method, set block check method to dummy + * and disable bad block table while erasing. + */ + if (opts->scrub) { + erase.scrub = opts->scrub; + + /* + * We don't need the bad block table anymore... + * after scrub, there are no bad blocks left! + */ +#if CONFIG_IS_ENABLED(MTD_RAW_NAND) + if (chip->bbt) { + kfree(chip->bbt); + } + chip->bbt = NULL; + chip->options &= ~NAND_BBT_SCANNED; +#elif CONFIG_IS_ENABLED(MTD_SPI_NAND) + if (nanddev_bbt_is_initialized(nand)) + nanddev_bbt_cleanup(nand); +#endif + } + + for (erased_length = 0; + erased_length < erase_length; + erase.addr += mtd->erasesize) { + + schedule(); + + if (opts->lim && (erase.addr >= (opts->offset + opts->lim))) { + puts("Size of erase exceeds limit\n"); + return -EFBIG; + } + if (!opts->scrub) { + int ret = mtd_block_isbad(mtd, erase.addr); + if (ret > 0) { + if (!opts->quiet) + printf("\rSkipping %s at " + "0x%08llx " + " \n", + ret == 1 ? "bad block" : "bbt reserved", + erase.addr); + + if (!opts->spread) + erased_length++; + + continue; + + } else if (ret < 0) { + printf("\n%s: MTD get bad block failed: %d\n", + mtd_device, + ret); + return -1; + } + } + + erased_length++; + + result = mtd_erase(mtd, &erase); + if (result != 0) { + printf("\n%s: MTD Erase failure: %d\n", + mtd_device, result); + continue; + } + + /* format for JFFS2 ? */ + if (opts->jffs2 && oobavail >= 8) { + struct mtd_oob_ops ops; + ops.ooblen = 8; + ops.datbuf = NULL; + ops.oobbuf = (uint8_t *)&cleanmarker; + ops.ooboffs = 0; + ops.mode = MTD_OPS_AUTO_OOB; + + result = mtd_write_oob(mtd, erase.addr, &ops); + if (result != 0) { + printf("\n%s: MTD writeoob failure: %d\n", + mtd_device, result); + continue; + } + } + + if (!opts->quiet) { + unsigned long long n = erased_length * 100ULL; + int percent; + + do_div(n, erase_length); + percent = (int)n; + + /* output progress message only at whole percent + * steps to reduce the number of messages printed + * on (slow) serial consoles + */ + if (percent != percent_complete) { + percent_complete = percent; + + printf("\rErasing at 0x%llx -- %3d%% complete.", + erase.addr, percent); + + if (opts->jffs2 && result == 0) + printf(" Cleanmarker written at 0x%llx.", + erase.addr); + } + } + } + if (!opts->quiet) + printf("\n"); + + return 0; +} + /** * check_skip_len *

Hi Alexey
On Thu, Dec 28, 2023 at 4:39 PM Alexey Romanov avromanov@salutedevices.com wrote:
Currently nand_erase_opts() placed in the nand/raw/ folder, because it uses the RAW NAND specific API (struct nand_chip). This patch move it to core NAND folder and make function generic, for both RAW/SPI NAND's usage.
Also, nand_erase_opts() used in fastboot/fb_nand.c, cmd/nand.c and env/nand.c code. This is also the reason why we should move it to core folder and make it more general.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
drivers/mtd/nand/raw/nand_util.c | 153 ---------------------------- drivers/mtd/nand/util.c | 166 +++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 153 deletions(-)
diff --git a/drivers/mtd/nand/raw/nand_util.c b/drivers/mtd/nand/raw/nand_util.c index 9c18ce63b9..f7704d4697 100644 --- a/drivers/mtd/nand/raw/nand_util.c +++ b/drivers/mtd/nand/raw/nand_util.c @@ -32,159 +32,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/rawnand.h> #include <nand.h> -#include <jffs2/jffs2.h>
-typedef struct erase_info erase_info_t;
-/* support only for native endian JFFS2 */ -#define cpu_to_je16(x) (x) -#define cpu_to_je32(x) (x)
-/**
- nand_erase_opts: - erase NAND flash with support for various options
(jffs2 formatting)
- @param mtd nand mtd instance to erase
- @param opts options, @see struct nand_erase_options
- Return: 0 in case of success
- This code is ported from flash_eraseall.c from Linux mtd utils by
- Arcom Control System Ltd.
- */
-int nand_erase_opts(struct mtd_info *mtd,
const nand_erase_options_t *opts)
-{
struct jffs2_unknown_node cleanmarker;
erase_info_t erase;
unsigned long erase_length, erased_length; /* in blocks */
int result;
int percent_complete = -1;
const char *mtd_device = mtd->name;
struct mtd_oob_ops oob_opts;
struct nand_chip *chip = mtd_to_nand(mtd);
if ((opts->offset & (mtd->erasesize - 1)) != 0) {
printf("Attempt to erase non block-aligned data\n");
return -1;
}
memset(&erase, 0, sizeof(erase));
memset(&oob_opts, 0, sizeof(oob_opts));
erase.mtd = mtd;
erase.len = mtd->erasesize;
erase.addr = opts->offset;
erase_length = lldiv(opts->length + mtd->erasesize - 1,
mtd->erasesize);
cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
cleanmarker.totlen = cpu_to_je32(8);
/* scrub option allows to erase badblock. To prevent internal
* check from erase() method, set block check method to dummy
* and disable bad block table while erasing.
*/
if (opts->scrub) {
erase.scrub = opts->scrub;
/*
* We don't need the bad block table anymore...
* after scrub, there are no bad blocks left!
*/
if (chip->bbt) {
kfree(chip->bbt);
}
chip->bbt = NULL;
chip->options &= ~NAND_BBT_SCANNED;
}
for (erased_length = 0;
erased_length < erase_length;
erase.addr += mtd->erasesize) {
schedule();
if (opts->lim && (erase.addr >= (opts->offset + opts->lim))) {
puts("Size of erase exceeds limit\n");
return -EFBIG;
}
if (!opts->scrub) {
int ret = mtd_block_isbad(mtd, erase.addr);
if (ret > 0) {
if (!opts->quiet)
printf("\rSkipping %s at "
"0x%08llx "
" \n",
ret == 1 ? "bad block" : "bbt reserved",
erase.addr);
if (!opts->spread)
erased_length++;
continue;
} else if (ret < 0) {
printf("\n%s: MTD get bad block failed: %d\n",
mtd_device,
ret);
return -1;
}
}
erased_length++;
result = mtd_erase(mtd, &erase);
if (result != 0) {
printf("\n%s: MTD Erase failure: %d\n",
mtd_device, result);
continue;
}
/* format for JFFS2 ? */
if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) {
struct mtd_oob_ops ops;
ops.ooblen = 8;
ops.datbuf = NULL;
ops.oobbuf = (uint8_t *)&cleanmarker;
ops.ooboffs = 0;
ops.mode = MTD_OPS_AUTO_OOB;
result = mtd_write_oob(mtd, erase.addr, &ops);
if (result != 0) {
printf("\n%s: MTD writeoob failure: %d\n",
mtd_device, result);
continue;
}
}
if (!opts->quiet) {
unsigned long long n = erased_length * 100ULL;
int percent;
do_div(n, erase_length);
percent = (int)n;
/* output progress message only at whole percent
* steps to reduce the number of messages printed
* on (slow) serial consoles
*/
if (percent != percent_complete) {
percent_complete = percent;
printf("\rErasing at 0x%llx -- %3d%% complete.",
erase.addr, percent);
if (opts->jffs2 && result == 0)
printf(" Cleanmarker written at 0x%llx.",
erase.addr);
}
}
}
if (!opts->quiet)
printf("\n");
return 0;
-}
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
diff --git a/drivers/mtd/nand/util.c b/drivers/mtd/nand/util.c index 4a372bb67d..f02c1ef4ca 100644 --- a/drivers/mtd/nand/util.c +++ b/drivers/mtd/nand/util.c @@ -28,10 +28,176 @@ #include <asm/cache.h> #include <dm/devres.h>
+#include <jffs2/jffs2.h> #include <linux/errno.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/rawnand.h> #include <nand.h>
+typedef struct erase_info erase_info_t;
+/* support only for native endian JFFS2 */ +#define cpu_to_je16(x) (x) +#define cpu_to_je32(x) (x)
+/**
- nand_erase_opts: - erase NAND flash with support for various options
(jffs2 formatting)
- @param mtd nand mtd instance to erase
- @param opts options, @see struct nand_erase_options
- Return: 0 in case of success
- This code is ported from flash_eraseall.c from Linux mtd utils by
- Arcom Control System Ltd.
- */
+int nand_erase_opts(struct mtd_info *mtd,
const nand_erase_options_t *opts)
+{
struct jffs2_unknown_node cleanmarker;
erase_info_t erase;
unsigned long erase_length, erased_length; /* in blocks */
int result;
int percent_complete = -1;
const char *mtd_device = mtd->name;
struct mtd_oob_ops oob_opts;
u32 oobavail = mtd->oobavail;
+#if CONFIG_IS_ENABLED(MTD_RAW_NAND)
struct nand_chip *chip = mtd_to_nand(mtd);
+#elif CONFIG_IS_ENABLED(MTD_SPI_NAND)
struct nand_device *nand = mtd_to_nanddev(mtd);
+#endif
if ((opts->offset & (mtd->erasesize - 1)) != 0) {
printf("Attempt to erase non block-aligned data\n");
return -1;
}
memset(&erase, 0, sizeof(erase));
memset(&oob_opts, 0, sizeof(oob_opts));
erase.mtd = mtd;
erase.len = mtd->erasesize;
erase.addr = opts->offset;
erase_length = lldiv(opts->length + mtd->erasesize - 1,
mtd->erasesize);
cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
cleanmarker.totlen = cpu_to_je32(8);
/* scrub option allows to erase badblock. To prevent internal
* check from erase() method, set block check method to dummy
* and disable bad block table while erasing.
*/
if (opts->scrub) {
erase.scrub = opts->scrub;
/*
* We don't need the bad block table anymore...
* after scrub, there are no bad blocks left!
*/
+#if CONFIG_IS_ENABLED(MTD_RAW_NAND)
if (chip->bbt) {
kfree(chip->bbt);
}
chip->bbt = NULL;
chip->options &= ~NAND_BBT_SCANNED;
+#elif CONFIG_IS_ENABLED(MTD_SPI_NAND)
if (nanddev_bbt_is_initialized(nand))
nanddev_bbt_cleanup(nand);
+#endif
}
for (erased_length = 0;
erased_length < erase_length;
erase.addr += mtd->erasesize) {
schedule();
if (opts->lim && (erase.addr >= (opts->offset + opts->lim))) {
puts("Size of erase exceeds limit\n");
return -EFBIG;
}
if (!opts->scrub) {
int ret = mtd_block_isbad(mtd, erase.addr);
if (ret > 0) {
if (!opts->quiet)
printf("\rSkipping %s at "
"0x%08llx "
" \n",
ret == 1 ? "bad block" : "bbt reserved",
erase.addr);
if (!opts->spread)
erased_length++;
continue;
} else if (ret < 0) {
printf("\n%s: MTD get bad block failed: %d\n",
mtd_device,
ret);
return -1;
}
}
erased_length++;
result = mtd_erase(mtd, &erase);
if (result != 0) {
printf("\n%s: MTD Erase failure: %d\n",
mtd_device, result);
continue;
}
/* format for JFFS2 ? */
if (opts->jffs2 && oobavail >= 8) {
struct mtd_oob_ops ops;
ops.ooblen = 8;
ops.datbuf = NULL;
ops.oobbuf = (uint8_t *)&cleanmarker;
ops.ooboffs = 0;
ops.mode = MTD_OPS_AUTO_OOB;
result = mtd_write_oob(mtd, erase.addr, &ops);
if (result != 0) {
printf("\n%s: MTD writeoob failure: %d\n",
mtd_device, result);
continue;
}
}
if (!opts->quiet) {
unsigned long long n = erased_length * 100ULL;
int percent;
do_div(n, erase_length);
percent = (int)n;
/* output progress message only at whole percent
* steps to reduce the number of messages printed
* on (slow) serial consoles
*/
if (percent != percent_complete) {
percent_complete = percent;
printf("\rErasing at 0x%llx -- %3d%% complete.",
erase.addr, percent);
if (opts->jffs2 && result == 0)
printf(" Cleanmarker written at 0x%llx.",
erase.addr);
}
}
}
if (!opts->quiet)
printf("\n");
return 0;
+}
/**
- check_skip_len
-- 2.30.1
Reviewed-By: Michael Trimarchi michael@amarulasolutions.com

By analogy with RAW NAND drivers, select SYS_NAND_SELF_INIT option and implement board_nand_init() function. It will be called from nand_init().
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/mtd/nand/spi/Kconfig | 1 + drivers/mtd/nand/spi/core.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+)
diff --git a/drivers/mtd/nand/spi/Kconfig b/drivers/mtd/nand/spi/Kconfig index 0777dfdf0a..c9ca76a1c9 100644 --- a/drivers/mtd/nand/spi/Kconfig +++ b/drivers/mtd/nand/spi/Kconfig @@ -2,6 +2,7 @@ menuconfig MTD_SPI_NAND bool "SPI NAND device Support" depends on DM_MTD && DM_SPI select MTD_NAND_CORE + select SYS_NAND_SELF_INIT select SPI_MEM help This is the framework for the SPI NAND device drivers. diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 202e3f11ec..27ad6fefdb 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -28,6 +28,7 @@ #include <spi-mem.h> #include <dm/device_compat.h> #include <dm/devres.h> +#include <dm/uclass.h> #include <linux/bitops.h> #include <linux/bug.h> #include <linux/mtd/spinand.h> @@ -1296,3 +1297,16 @@ U_BOOT_DRIVER(spinand) = { .priv_auto = sizeof(struct spinand_device), .probe = spinand_probe, }; + +void board_nand_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_SPI, + DM_DRIVER_GET(spinand), + &dev); + if (ret && ret != -ENODEV) + log_err("Failed to initialize SPI NAND driver. (error %d)\n", + ret); +}

Most functions that work with NAND device (for example fastboot), use the get_nand_dev_by_index() function to work with NAND MTD. In order to use this feature, SPI NAND must be registered via nand_register().
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/mtd/nand/spi/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 27ad6fefdb..5210332712 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -23,6 +23,7 @@ #else #include <common.h> #include <errno.h> +#include <nand.h> #include <watchdog.h> #include <spi.h> #include <spi-mem.h> @@ -1222,7 +1223,7 @@ static int spinand_probe(struct udevice *dev) #ifndef __UBOOT__ ret = mtd_device_register(mtd, NULL, 0); #else - ret = add_mtd_device(mtd); + ret = nand_register(0, mtd); #endif if (ret) goto err_spinand_cleanup;

It is bad practice to use such error codes. Error codes must be negative.
Also, fastboot code expects that if successful, mtdparts functions will return a value greater than 0. You can see fastboot_nand_get_part_info() functions calls inside getvar_get_part_info().
And use 'return CMD_RET_FAILURE' define instead of 'return 1'.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- cmd/mtdparts.c | 154 ++++++++++++++++++++++++------------------------- 1 file changed, 77 insertions(+), 77 deletions(-)
diff --git a/cmd/mtdparts.c b/cmd/mtdparts.c index 0984158f41..08e5b794db 100644 --- a/cmd/mtdparts.c +++ b/cmd/mtdparts.c @@ -299,7 +299,7 @@ static void current_save(void) * @param type mtd type * @param num mtd number * @param mtd a pointer to an mtd_info instance (output) - * Return: 0 if device is valid, 1 otherwise + * Return: 0 if device is valid, -errno otherwise */ static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd) { @@ -309,7 +309,7 @@ static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd) *mtd = get_mtd_device_nm(mtd_dev); if (IS_ERR(*mtd)) { printf("Device %s not found!\n", mtd_dev); - return 1; + return -ENODEV; } put_mtd_device(*mtd);
@@ -323,7 +323,7 @@ static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd) * * @param id of the parent device * @param part partition to validate - * Return: 0 if partition is valid, 1 otherwise + * Return: 0 if partition is valid, -errno otherwise */ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part) { @@ -333,7 +333,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part) u64 offset, size;
if (get_mtd_info(id->type, id->num, &mtd)) - return 1; + return -EINVAL;
part->sector_size = mtd->erasesize;
@@ -347,14 +347,14 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part) printf("%s%d: partition (%s) start offset" "alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name); - return 1; + return -EINVAL; }
size = part->size; if (do_div(size, mtd->erasesize)) { printf("%s%d: partition (%s) size alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name); - return 1; + return -EINVAL; } } else { /* @@ -374,7 +374,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
printf("%s%d: partition (%s) start offset alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name); - return 1; + return -EINVAL;
start_ok:
@@ -393,7 +393,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
printf("%s%d: partition (%s) size alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name); - return 1; + return -EINVAL;
end_ok: return 0; @@ -410,7 +410,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part) * * @param id of the parent device * @param part partition to validate - * Return: 0 if partition is valid, 1 otherwise + * Return: 0 if partition is valid, -errno otherwise */ static int part_validate(struct mtdids *id, struct part_info *part) { @@ -420,18 +420,18 @@ static int part_validate(struct mtdids *id, struct part_info *part) if (part->offset > id->size) { printf("%s: offset %08llx beyond flash size %08llx\n", id->mtd_id, part->offset, id->size); - return 1; + return -EINVAL; }
if ((part->offset + part->size) <= part->offset) { printf("%s%d: partition (%s) size too big\n", MTD_DEV_TYPE(id->type), id->num, part->name); - return 1; + return -EINVAL; }
if (part->offset + part->size > id->size) { printf("%s: partitioning exceeds flash size\n", id->mtd_id); - return 1; + return -EINVAL; }
/* @@ -446,7 +446,7 @@ static int part_validate(struct mtdids *id, struct part_info *part) * * @param dev device to delete partition from * @param part partition to delete - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -ernno otherwise */ static int part_del(struct mtd_device *dev, struct part_info *part) { @@ -544,7 +544,7 @@ static int part_sort_add(struct mtd_device *dev, struct part_info *part) /* be compliant with kernel cmdline, allow only one partition at offset zero */ if ((new_pi->offset == pi->offset) && (pi->offset == 0)) { printf("cannot add second partition at offset 0\n"); - return 1; + return -EINVAL; }
if (new_pi->offset <= pi->offset) { @@ -574,17 +574,17 @@ static int part_sort_add(struct mtd_device *dev, struct part_info *part) * * @param dev device to which partition is added * @param part partition to be added - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int part_add(struct mtd_device *dev, struct part_info *part) { /* verify alignment and size */ if (part_validate(dev->id, part) != 0) - return 1; + return -EINVAL;
/* partition is ok, add it to the list */ if (part_sort_add(dev, part) != 0) - return 1; + return -EINVAL;
return 0; } @@ -596,7 +596,7 @@ static int part_add(struct mtd_device *dev, struct part_info *part) * @param partdef pointer to the partition definition string i.e. <part-def> * @param ret output pointer to next char after parse completes (output) * @param retpart pointer to the allocated partition (output) - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart) { @@ -622,7 +622,7 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i size = memsize_parse(p, &p); if (size < MIN_PART_SIZE) { printf("partition size too small (%llx)\n", size); - return 1; + return -EINVAL; } }
@@ -638,12 +638,12 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i name = ++p; if ((p = strchr(name, ')')) == NULL) { printf("no closing ) found in partition name\n"); - return 1; + return -EINVAL; } name_len = p - name + 1; if ((name_len - 1) == 0) { printf("empty partition name\n"); - return 1; + return -EINVAL; } p++; } else { @@ -664,7 +664,7 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i if (size == SIZE_REMAINING) { *ret = NULL; printf("no partitions allowed after a fill-up partition\n"); - return 1; + return -EINVAL; } *ret = ++p; } else if ((*p == ';') || (*p == '\0')) { @@ -672,14 +672,14 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i } else { printf("unexpected character '%c' at the end of partition\n", *p); *ret = NULL; - return 1; + return -EINVAL; }
/* allocate memory */ part = (struct part_info *)malloc(sizeof(struct part_info) + name_len); if (!part) { printf("out of memory\n"); - return 1; + return -ENOMEM; } memset(part, 0, sizeof(struct part_info) + name_len); part->size = size; @@ -714,14 +714,14 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i * @param type mtd type * @param num mtd number * @param size a pointer to the size of the mtd device (output) - * Return: 0 if device is valid, 1 otherwise + * Return: 0 if device is valid, -errno otherwise */ static int mtd_device_validate(u8 type, u8 num, u64 *size) { struct mtd_info *mtd = NULL;
if (get_mtd_info(type, num, &mtd)) - return 1; + return -EINVAL;
*size = mtd->size;
@@ -732,7 +732,7 @@ static int mtd_device_validate(u8 type, u8 num, u64 *size) * Delete all mtd devices from a supplied devices list, free memory allocated for * each device and delete all device partitions. * - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int device_delall(struct list_head *head) { @@ -756,7 +756,7 @@ static int device_delall(struct list_head *head) * from device list and device memory is freed. * * @param dev device to be deleted - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int device_del(struct mtd_device *dev) { @@ -835,7 +835,7 @@ static void device_add(struct mtd_device *dev) * @param mtd_dev pointer to the device definition string i.e. <mtd-dev> * @param ret output pointer to next char after parse completes (output) * @param retdev pointer to the allocated device (output) - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev) { @@ -864,7 +864,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ mtd_id = p = mtd_dev; if (!(p = strchr(mtd_id, ':'))) { printf("no <mtd-id> identifier\n"); - return 1; + return -EINVAL; } mtd_id_len = p - mtd_id + 1; p++; @@ -872,7 +872,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ /* verify if we have a valid device specified */ if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) { printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id); - return 1; + return -ENODEV; }
pend = strchr(p, ';'); @@ -915,7 +915,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ } if (err == 1) { part_delall(&tmp_list); - return 1; + return -EINVAL; }
debug("\ntotal partitions: %d\n", num_parts); @@ -932,14 +932,14 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ printf("unexpected character '%c' at the end of device\n", *p); if (ret) *ret = NULL; - return 1; + return -EINVAL; } }
/* allocate memory for mtd_device structure */ if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) { printf("out of memory\n"); - return 1; + return -ENOMEM; } memset(dev, 0, sizeof(struct mtd_device)); dev->id = id; @@ -953,7 +953,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ list_del(entry); if (part_sort_add(dev, part) != 0) { device_del(dev); - return 1; + return -EINVAL; } }
@@ -966,7 +966,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ /** * Initialize global device list. * - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int mtd_devices_init(void) { @@ -1037,7 +1037,7 @@ static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_ * @param ret_id output pointer to next char after parse completes (output) * @param dev_type parsed device type (output) * @param dev_num parsed device number (output) - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num) @@ -1059,12 +1059,12 @@ int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, p += 8; } else { printf("incorrect device type in %s\n", id); - return 1; + return -EINVAL; }
if (!isdigit(*p)) { printf("incorrect device number in %s\n", id); - return 1; + return -EINVAL; }
*dev_num = simple_strtoul(p, (char **)&p, 0); @@ -1079,7 +1079,7 @@ int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, * * @param buf output buffer holding generated mtdparts string (output) * @param buflen buffer size - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int generate_mtdparts(char *buf, u32 buflen) { @@ -1195,7 +1195,7 @@ static int generate_mtdparts(char *buf, u32 buflen)
cleanup: last_parts[0] = '\0'; - return 1; + return -EINVAL; }
/** @@ -1204,7 +1204,7 @@ cleanup: * * @param buf output buffer holding generated mtdparts string (output) * @param buflen buffer size - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int generate_mtdparts_save(char *buf, u32 buflen) { @@ -1342,7 +1342,7 @@ static void list_partitions(void) * @param dev pointer to the requested device (output) * @param part_num verified partition number (output) * @param part pointer to requested partition (output) - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ int find_dev_and_part(const char *id, struct mtd_device **dev, u8 *part_num, struct part_info **part) @@ -1370,27 +1370,27 @@ int find_dev_and_part(const char *id, struct mtd_device **dev, *part_num = 0;
if (mtd_id_parse(p, &p, &type, &dnum) != 0) - return 1; + return -EINVAL;
if ((*p++ != ',') || (*p == '\0')) { printf("no partition number specified\n"); - return 1; + return -EINVAL; } pnum = simple_strtoul(p, (char **)&p, 0); if (*p != '\0') { printf("unexpected trailing character '%c'\n", *p); - return 1; + return -EINVAL; }
if ((*dev = device_find(type, dnum)) == NULL) { printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum); - return 1; + return -ENODEV; }
if ((*part = mtd_part_info(*dev, pnum)) == NULL) { printf("no such partition\n"); *dev = NULL; - return 1; + return -EINVAL; }
*part_num = pnum; @@ -1402,7 +1402,7 @@ int find_dev_and_part(const char *id, struct mtd_device **dev, * Find and delete partition. For partition id format see find_dev_and_part(). * * @param id string describing device and partition - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int delete_partition(const char *id) { @@ -1417,17 +1417,17 @@ static int delete_partition(const char *id) part->name, part->size, part->offset);
if (part_del(dev, part) != 0) - return 1; + return -EINVAL;
if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { printf("generated mtdparts too long, resetting to null\n"); - return 1; + return -EINVAL; } return 0; }
printf("partition %s not found\n", id); - return 1; + return -ENOENT; }
#if defined(CONFIG_CMD_MTDPARTS_SPREAD) @@ -1478,7 +1478,7 @@ static void spread_partition(struct mtd_info *mtd, struct part_info *part, * as big as their mtdparts environment variable sizes and they each start * on a good block. * - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int spread_partitions(void) { @@ -1493,7 +1493,7 @@ static int spread_partitions(void) dev = list_entry(dentry, struct mtd_device, link);
if (get_mtd_info(dev->id->type, dev->id->num, &mtd)) - return 1; + return -EINVAL;
part_num = 0; cur_offs = 0; @@ -1519,7 +1519,7 @@ static int spread_partitions(void)
if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { printf("generated mtdparts too long, resetting to null\n"); - return 1; + return -EINVAL; } return 0; } @@ -1547,7 +1547,7 @@ static const char *env_get_mtdparts(char *buf) * for each entry. Add created devices to the global devices list. * * @param mtdparts string specifing mtd partitions - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int parse_mtdparts(const char *const mtdparts) { @@ -1605,7 +1605,7 @@ static int parse_mtdparts(const char *const mtdparts) * to the global mtdids list. * * @param ids mapping string - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int parse_mtdids(const char *const ids) { @@ -1646,7 +1646,7 @@ static int parse_mtdids(const char *const ids)
/* check if requested device exists */ if (mtd_device_validate(type, num, &size) != 0) - return 1; + return -EINVAL;
/* locate <mtd-id> */ mtd_id = p; @@ -1704,7 +1704,7 @@ static int parse_mtdids(const char *const ids) list_del(entry); free(id_tmp); } - return 1; + return -EINVAL; }
return 0; @@ -1715,7 +1715,7 @@ static int parse_mtdids(const char *const ids) * Parse and initialize global mtdids mapping and create global * device/partition list. * - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ int mtdparts_init(void) { @@ -1768,12 +1768,12 @@ int mtdparts_init(void) env_set("mtdids", (char *)ids); } else { printf("mtdids not defined, no default present\n"); - return 1; + return -ENXIO; } } if (strlen(ids) > MTDIDS_MAXLEN - 1) { printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN); - return 1; + return -EINVAL; }
/* use defaults when mtdparts variable is not defined @@ -1789,7 +1789,7 @@ int mtdparts_init(void)
if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) { printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN); - return 1; + return -EINVAL; }
/* check if we have already parsed those mtdids */ @@ -1800,7 +1800,7 @@ int mtdparts_init(void)
if (parse_mtdids(ids) != 0) { mtd_devices_init(); - return 1; + return -EINVAL; }
/* ok it's good, save new ids */ @@ -1810,11 +1810,11 @@ int mtdparts_init(void) /* parse partitions if either mtdparts or mtdids were updated */ if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) { if (parse_mtdparts(parts) != 0) - return 1; + return -EINVAL;
if (list_empty(&devices)) { printf("mtdparts_init: no valid partitions\n"); - return 1; + return -ENXIO; }
/* ok it's good, save new parts */ @@ -1923,15 +1923,15 @@ static int do_chpart(struct cmd_tbl *cmdtp, int flag, int argc, u8 pnum;
if (mtdparts_init() !=0) - return 1; + return CMD_RET_FAILURE;
if (argc < 2) { printf("no partition id specified\n"); - return 1; + return CMD_RET_FAILURE; }
if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0) - return 1; + return CMD_RET_FAILURE;
current_mtd_dev = dev; current_mtd_partnum = pnum; @@ -1978,7 +1978,7 @@ static int do_mtdparts(struct cmd_tbl *cmdtp, int flag, int argc,
/* make sure we are in sync with env variables */ if (mtdparts_init() != 0) - return 1; + return CMD_RET_FAILURE;
if (argc == 1) { list_partitions(); @@ -2000,11 +2000,11 @@ static int do_mtdparts(struct cmd_tbl *cmdtp, int flag, int argc, struct part_info *p;
if (mtd_id_parse(argv[2], NULL, &type, &num) != 0) - return 1; + return CMD_RET_FAILURE;
if ((id = id_find(type, num)) == NULL) { printf("no such device %s defined in mtdids variable\n", argv[2]); - return 1; + return CMD_RET_FAILURE; }
len = strlen(id->mtd_id) + 1; /* 'mtd_id:' */ @@ -2015,14 +2015,14 @@ static int do_mtdparts(struct cmd_tbl *cmdtp, int flag, int argc,
if (len >= PART_ADD_DESC_MAXLEN) { printf("too long partition description\n"); - return 1; + return CMD_RET_FAILURE; } sprintf(tmpbuf, "%s:%s(%s)%s", id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : ""); debug("add tmpbuf: %s\n", tmpbuf);
if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev)) - return 1; + return -EINVAL;
debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type), dev->id->num, dev->id->mtd_id); @@ -2031,7 +2031,7 @@ static int do_mtdparts(struct cmd_tbl *cmdtp, int flag, int argc,
#if defined(CONFIG_CMD_MTDPARTS_SPREAD) if (get_mtd_info(dev->id->type, dev->id->num, &mtd)) - return 1; + return CMD_RET_FAILURE;
if (!strcmp(&argv[1][3], ".spread")) { spread_partition(mtd, p, &next_offset); @@ -2045,12 +2045,12 @@ static int do_mtdparts(struct cmd_tbl *cmdtp, int flag, int argc, } else if (part_add(dev_tmp, p) != 0) { /* merge new partition with existing ones*/ device_del(dev); - return 1; + return CMD_RET_FAILURE; }
if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { printf("generated mtdparts too long, resetting to null\n"); - return 1; + return CMD_RET_FAILURE; }
return 0;

Hi
On Thu, Dec 28, 2023 at 4:39 PM Alexey Romanov avromanov@salutedevices.com wrote:
It is bad practice to use such error codes. Error codes must be negative.
Also, fastboot code expects that if successful, mtdparts functions will return a value greater than 0. You can see fastboot_nand_get_part_info() functions calls inside getvar_get_part_info().
And use 'return CMD_RET_FAILURE' define instead of 'return 1'.
Can you split the CMD_RET_FAILURE in a separate patch?
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
cmd/mtdparts.c | 154 ++++++++++++++++++++++++------------------------- 1 file changed, 77 insertions(+), 77 deletions(-)
diff --git a/cmd/mtdparts.c b/cmd/mtdparts.c index 0984158f41..08e5b794db 100644 --- a/cmd/mtdparts.c +++ b/cmd/mtdparts.c @@ -299,7 +299,7 @@ static void current_save(void)
- @param type mtd type
- @param num mtd number
- @param mtd a pointer to an mtd_info instance (output)
- Return: 0 if device is valid, 1 otherwise
*/
- Return: 0 if device is valid, -errno otherwise
static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd) { @@ -309,7 +309,7 @@ static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd) *mtd = get_mtd_device_nm(mtd_dev); if (IS_ERR(*mtd)) { printf("Device %s not found!\n", mtd_dev);
return 1;
return -ENODEV; } put_mtd_device(*mtd);
@@ -323,7 +323,7 @@ static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd)
- @param id of the parent device
- @param part partition to validate
- Return: 0 if partition is valid, 1 otherwise
*/
- Return: 0 if partition is valid, -errno otherwise
static int part_validate_eraseblock(struct mtdids *id, struct part_info *part) { @@ -333,7 +333,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part) u64 offset, size;
if (get_mtd_info(id->type, id->num, &mtd))
return 1;
return -EINVAL; part->sector_size = mtd->erasesize;
@@ -347,14 +347,14 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part) printf("%s%d: partition (%s) start offset" "alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name);
return 1;
return -EINVAL; } size = part->size; if (do_div(size, mtd->erasesize)) { printf("%s%d: partition (%s) size alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name);
return 1;
return -EINVAL; } } else { /*
@@ -374,7 +374,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
printf("%s%d: partition (%s) start offset alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name);
return 1;
return -EINVAL; start_ok:
@@ -393,7 +393,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
printf("%s%d: partition (%s) size alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name);
return 1;
return -EINVAL; end_ok: return 0;
@@ -410,7 +410,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
- @param id of the parent device
- @param part partition to validate
- Return: 0 if partition is valid, 1 otherwise
*/
- Return: 0 if partition is valid, -errno otherwise
static int part_validate(struct mtdids *id, struct part_info *part) { @@ -420,18 +420,18 @@ static int part_validate(struct mtdids *id, struct part_info *part) if (part->offset > id->size) { printf("%s: offset %08llx beyond flash size %08llx\n", id->mtd_id, part->offset, id->size);
return 1;
return -EINVAL; } if ((part->offset + part->size) <= part->offset) { printf("%s%d: partition (%s) size too big\n", MTD_DEV_TYPE(id->type), id->num, part->name);
return 1;
return -EINVAL; } if (part->offset + part->size > id->size) { printf("%s: partitioning exceeds flash size\n", id->mtd_id);
return 1;
return -EINVAL; } /*
@@ -446,7 +446,7 @@ static int part_validate(struct mtdids *id, struct part_info *part)
- @param dev device to delete partition from
- @param part partition to delete
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -ernno otherwise
static int part_del(struct mtd_device *dev, struct part_info *part) { @@ -544,7 +544,7 @@ static int part_sort_add(struct mtd_device *dev, struct part_info *part) /* be compliant with kernel cmdline, allow only one partition at offset zero */ if ((new_pi->offset == pi->offset) && (pi->offset == 0)) { printf("cannot add second partition at offset 0\n");
return 1;
return -EINVAL; } if (new_pi->offset <= pi->offset) {
@@ -574,17 +574,17 @@ static int part_sort_add(struct mtd_device *dev, struct part_info *part)
- @param dev device to which partition is added
- @param part partition to be added
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int part_add(struct mtd_device *dev, struct part_info *part) { /* verify alignment and size */ if (part_validate(dev->id, part) != 0)
return 1;
return -EINVAL; /* partition is ok, add it to the list */ if (part_sort_add(dev, part) != 0)
return 1;
return -EINVAL; return 0;
} @@ -596,7 +596,7 @@ static int part_add(struct mtd_device *dev, struct part_info *part)
- @param partdef pointer to the partition definition string i.e. <part-def>
- @param ret output pointer to next char after parse completes (output)
- @param retpart pointer to the allocated partition (output)
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart) { @@ -622,7 +622,7 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i size = memsize_parse(p, &p); if (size < MIN_PART_SIZE) { printf("partition size too small (%llx)\n", size);
return 1;
return -EINVAL; } }
@@ -638,12 +638,12 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i name = ++p; if ((p = strchr(name, ')')) == NULL) { printf("no closing ) found in partition name\n");
return 1;
return -EINVAL; } name_len = p - name + 1; if ((name_len - 1) == 0) { printf("empty partition name\n");
return 1;
return -EINVAL; } p++; } else {
@@ -664,7 +664,7 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i if (size == SIZE_REMAINING) { *ret = NULL; printf("no partitions allowed after a fill-up partition\n");
return 1;
return -EINVAL; } *ret = ++p; } else if ((*p == ';') || (*p == '\0')) {
@@ -672,14 +672,14 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i } else { printf("unexpected character '%c' at the end of partition\n", *p); *ret = NULL;
return 1;
return -EINVAL; } /* allocate memory */ part = (struct part_info *)malloc(sizeof(struct part_info) + name_len); if (!part) { printf("out of memory\n");
return 1;
return -ENOMEM; } memset(part, 0, sizeof(struct part_info) + name_len); part->size = size;
@@ -714,14 +714,14 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
- @param type mtd type
- @param num mtd number
- @param size a pointer to the size of the mtd device (output)
- Return: 0 if device is valid, 1 otherwise
*/
- Return: 0 if device is valid, -errno otherwise
static int mtd_device_validate(u8 type, u8 num, u64 *size) { struct mtd_info *mtd = NULL;
if (get_mtd_info(type, num, &mtd))
return 1;
return -EINVAL; *size = mtd->size;
@@ -732,7 +732,7 @@ static int mtd_device_validate(u8 type, u8 num, u64 *size)
- Delete all mtd devices from a supplied devices list, free memory allocated for
- each device and delete all device partitions.
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int device_delall(struct list_head *head) { @@ -756,7 +756,7 @@ static int device_delall(struct list_head *head)
- from device list and device memory is freed.
- @param dev device to be deleted
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int device_del(struct mtd_device *dev) { @@ -835,7 +835,7 @@ static void device_add(struct mtd_device *dev)
- @param mtd_dev pointer to the device definition string i.e. <mtd-dev>
- @param ret output pointer to next char after parse completes (output)
- @param retdev pointer to the allocated device (output)
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev) { @@ -864,7 +864,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ mtd_id = p = mtd_dev; if (!(p = strchr(mtd_id, ':'))) { printf("no <mtd-id> identifier\n");
return 1;
return -EINVAL; } mtd_id_len = p - mtd_id + 1; p++;
@@ -872,7 +872,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ /* verify if we have a valid device specified */ if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) { printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id);
return 1;
return -ENODEV; } pend = strchr(p, ';');
@@ -915,7 +915,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ } if (err == 1) { part_delall(&tmp_list);
return 1;
return -EINVAL; } debug("\ntotal partitions: %d\n", num_parts);
@@ -932,14 +932,14 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ printf("unexpected character '%c' at the end of device\n", *p); if (ret) *ret = NULL;
return 1;
return -EINVAL; } } /* allocate memory for mtd_device structure */ if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) { printf("out of memory\n");
return 1;
return -ENOMEM; } memset(dev, 0, sizeof(struct mtd_device)); dev->id = id;
@@ -953,7 +953,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ list_del(entry); if (part_sort_add(dev, part) != 0) { device_del(dev);
return 1;
return -EINVAL; } }
@@ -966,7 +966,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ /**
- Initialize global device list.
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int mtd_devices_init(void) { @@ -1037,7 +1037,7 @@ static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_
- @param ret_id output pointer to next char after parse completes (output)
- @param dev_type parsed device type (output)
- @param dev_num parsed device number (output)
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num) @@ -1059,12 +1059,12 @@ int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, p += 8; } else { printf("incorrect device type in %s\n", id);
return 1;
return -EINVAL; } if (!isdigit(*p)) { printf("incorrect device number in %s\n", id);
return 1;
return -EINVAL; } *dev_num = simple_strtoul(p, (char **)&p, 0);
@@ -1079,7 +1079,7 @@ int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type,
- @param buf output buffer holding generated mtdparts string (output)
- @param buflen buffer size
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int generate_mtdparts(char *buf, u32 buflen) { @@ -1195,7 +1195,7 @@ static int generate_mtdparts(char *buf, u32 buflen)
cleanup: last_parts[0] = '\0';
return 1;
return -EINVAL;
}
/** @@ -1204,7 +1204,7 @@ cleanup:
- @param buf output buffer holding generated mtdparts string (output)
- @param buflen buffer size
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int generate_mtdparts_save(char *buf, u32 buflen) { @@ -1342,7 +1342,7 @@ static void list_partitions(void)
- @param dev pointer to the requested device (output)
- @param part_num verified partition number (output)
- @param part pointer to requested partition (output)
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
int find_dev_and_part(const char *id, struct mtd_device **dev, u8 *part_num, struct part_info **part) @@ -1370,27 +1370,27 @@ int find_dev_and_part(const char *id, struct mtd_device **dev, *part_num = 0;
if (mtd_id_parse(p, &p, &type, &dnum) != 0)
return 1;
return -EINVAL; if ((*p++ != ',') || (*p == '\0')) { printf("no partition number specified\n");
return 1;
return -EINVAL; } pnum = simple_strtoul(p, (char **)&p, 0); if (*p != '\0') { printf("unexpected trailing character '%c'\n", *p);
return 1;
return -EINVAL; } if ((*dev = device_find(type, dnum)) == NULL) { printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum);
return 1;
return -ENODEV; } if ((*part = mtd_part_info(*dev, pnum)) == NULL) { printf("no such partition\n"); *dev = NULL;
return 1;
return -EINVAL; } *part_num = pnum;
@@ -1402,7 +1402,7 @@ int find_dev_and_part(const char *id, struct mtd_device **dev,
- Find and delete partition. For partition id format see find_dev_and_part().
- @param id string describing device and partition
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int delete_partition(const char *id) { @@ -1417,17 +1417,17 @@ static int delete_partition(const char *id) part->name, part->size, part->offset);
if (part_del(dev, part) != 0)
return 1;
return -EINVAL; if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { printf("generated mtdparts too long, resetting to null\n");
return 1;
return -EINVAL; } return 0; } printf("partition %s not found\n", id);
return 1;
return -ENOENT;
}
#if defined(CONFIG_CMD_MTDPARTS_SPREAD) @@ -1478,7 +1478,7 @@ static void spread_partition(struct mtd_info *mtd, struct part_info *part,
- as big as their mtdparts environment variable sizes and they each start
- on a good block.
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int spread_partitions(void) { @@ -1493,7 +1493,7 @@ static int spread_partitions(void) dev = list_entry(dentry, struct mtd_device, link);
if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
return 1;
return -EINVAL; part_num = 0; cur_offs = 0;
@@ -1519,7 +1519,7 @@ static int spread_partitions(void)
if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { printf("generated mtdparts too long, resetting to null\n");
return 1;
return -EINVAL; } return 0;
} @@ -1547,7 +1547,7 @@ static const char *env_get_mtdparts(char *buf)
- for each entry. Add created devices to the global devices list.
- @param mtdparts string specifing mtd partitions
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int parse_mtdparts(const char *const mtdparts) { @@ -1605,7 +1605,7 @@ static int parse_mtdparts(const char *const mtdparts)
- to the global mtdids list.
- @param ids mapping string
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
static int parse_mtdids(const char *const ids) { @@ -1646,7 +1646,7 @@ static int parse_mtdids(const char *const ids)
/* check if requested device exists */ if (mtd_device_validate(type, num, &size) != 0)
return 1;
return -EINVAL; /* locate <mtd-id> */ mtd_id = p;
@@ -1704,7 +1704,7 @@ static int parse_mtdids(const char *const ids) list_del(entry); free(id_tmp); }
return 1;
return -EINVAL; } return 0;
@@ -1715,7 +1715,7 @@ static int parse_mtdids(const char *const ids)
- Parse and initialize global mtdids mapping and create global
- device/partition list.
- Return: 0 on success, 1 otherwise
*/
- Return: 0 on success, -errno otherwise
int mtdparts_init(void) { @@ -1768,12 +1768,12 @@ int mtdparts_init(void) env_set("mtdids", (char *)ids); } else { printf("mtdids not defined, no default present\n");
return 1;
return -ENXIO; } } if (strlen(ids) > MTDIDS_MAXLEN - 1) { printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN);
return 1;
return -EINVAL; } /* use defaults when mtdparts variable is not defined
@@ -1789,7 +1789,7 @@ int mtdparts_init(void)
if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) { printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN);
return 1;
return -EINVAL; } /* check if we have already parsed those mtdids */
@@ -1800,7 +1800,7 @@ int mtdparts_init(void)
if (parse_mtdids(ids) != 0) { mtd_devices_init();
return 1;
return -EINVAL; } /* ok it's good, save new ids */
@@ -1810,11 +1810,11 @@ int mtdparts_init(void) /* parse partitions if either mtdparts or mtdids were updated */ if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) { if (parse_mtdparts(parts) != 0)
return 1;
return -EINVAL; if (list_empty(&devices)) { printf("mtdparts_init: no valid partitions\n");
return 1;
return -ENXIO; } /* ok it's good, save new parts */
@@ -1923,15 +1923,15 @@ static int do_chpart(struct cmd_tbl *cmdtp, int flag, int argc, u8 pnum;
if (mtdparts_init() !=0)
return 1;
return CMD_RET_FAILURE; if (argc < 2) { printf("no partition id specified\n");
return 1;
return CMD_RET_FAILURE; } if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0)
return 1;
return CMD_RET_FAILURE; current_mtd_dev = dev; current_mtd_partnum = pnum;
@@ -1978,7 +1978,7 @@ static int do_mtdparts(struct cmd_tbl *cmdtp, int flag, int argc,
/* make sure we are in sync with env variables */ if (mtdparts_init() != 0)
return 1;
return CMD_RET_FAILURE; if (argc == 1) { list_partitions();
@@ -2000,11 +2000,11 @@ static int do_mtdparts(struct cmd_tbl *cmdtp, int flag, int argc, struct part_info *p;
if (mtd_id_parse(argv[2], NULL, &type, &num) != 0)
return 1;
return CMD_RET_FAILURE; if ((id = id_find(type, num)) == NULL) { printf("no such device %s defined in mtdids variable\n", argv[2]);
return 1;
return CMD_RET_FAILURE; } len = strlen(id->mtd_id) + 1; /* 'mtd_id:' */
@@ -2015,14 +2015,14 @@ static int do_mtdparts(struct cmd_tbl *cmdtp, int flag, int argc,
if (len >= PART_ADD_DESC_MAXLEN) { printf("too long partition description\n");
return 1;
return CMD_RET_FAILURE; } sprintf(tmpbuf, "%s:%s(%s)%s", id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : ""); debug("add tmpbuf: %s\n", tmpbuf); if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev))
return 1;
return -EINVAL; debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type), dev->id->num, dev->id->mtd_id);
@@ -2031,7 +2031,7 @@ static int do_mtdparts(struct cmd_tbl *cmdtp, int flag, int argc,
#if defined(CONFIG_CMD_MTDPARTS_SPREAD) if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
return 1;
return CMD_RET_FAILURE; if (!strcmp(&argv[1][3], ".spread")) { spread_partition(mtd, p, &next_offset);
@@ -2045,12 +2045,12 @@ static int do_mtdparts(struct cmd_tbl *cmdtp, int flag, int argc, } else if (part_add(dev_tmp, p) != 0) { /* merge new partition with existing ones*/ device_del(dev);
return 1;
return CMD_RET_FAILURE; } if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { printf("generated mtdparts too long, resetting to null\n");
return 1;
return CMD_RET_FAILURE; } return 0;
-- 2.30.1
Reviewed-by: Michael Trimarchi michael@amarulasolutions.com

It is bad practice to use such error codes. Error codes must be negative.
And use CMD_RET_FAILURE and CMD_RET_SUCCESS defines instead of 1 and 0.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- cmd/jffs2.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-)
diff --git a/cmd/jffs2.c b/cmd/jffs2.c index e00fcc2022..068eeedc58 100644 --- a/cmd/jffs2.c +++ b/cmd/jffs2.c @@ -151,7 +151,7 @@ extern int cramfs_info (struct part_info *info); * Check device number to be within valid range for given device type. * * @param dev device to validate - * Return: 0 if device is valid, 1 otherwise + * Return: 0 if device is valid, -errno otherwise */ static int mtd_device_validate(u8 type, u8 num, u32 *size) { @@ -191,7 +191,7 @@ static int mtd_device_validate(u8 type, u8 num, u32 *size) } else printf("Unknown defice type %d\n", type);
- return 1; + return -EINVAL; }
/** @@ -202,7 +202,7 @@ static int mtd_device_validate(u8 type, u8 num, u32 *size) * @param ret_id output pointer to next char after parse completes (output) * @param dev_type parsed device type (output) * @param dev_num parsed device number (output) - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ static int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num) { @@ -220,12 +220,12 @@ static int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *d p += 7; } else { printf("incorrect device type in %s\n", id); - return 1; + return -EINVAL; }
if (!isdigit(*p)) { printf("incorrect device number in %s\n", id); - return 1; + return -EINVAL; }
*dev_num = simple_strtoul(p, (char **)&p, 0); @@ -328,7 +328,7 @@ static inline u32 get_part_sector_size(struct mtdids *id, struct part_info *part * 'Static' version of command line mtdparts_init() routine. Single partition on * a single device configuration. * - * Return: 0 on success, 1 otherwise + * Return: 0 on success, -errno otherwise */ int mtdparts_init(void) { @@ -348,7 +348,7 @@ int mtdparts_init(void) sizeof(struct mtdids)); if (!current_mtd_dev) { printf("out of memory\n"); - return 1; + return -ENOMEM; } memset(current_mtd_dev, 0, sizeof(struct mtd_device) + sizeof(struct part_info) + sizeof(struct mtdids)); @@ -365,7 +365,7 @@ int mtdparts_init(void) (mtd_device_validate(id->type, id->num, &size) != 0)) { printf("incorrect device: %s%d\n", MTD_DEV_TYPE(id->type), id->num); free(current_mtd_dev); - return 1; + return -EINVAL; } id->size = size; INIT_LIST_HEAD(&id->link); @@ -485,7 +485,7 @@ int do_jffs2_fsload(struct cmd_tbl *cmdtp, int flag, int argc,
/* make sure we are in sync with env variables */ if (mtdparts_init() !=0) - return 1; + return CMD_RET_FAILURE;
if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
@@ -500,17 +500,18 @@ int do_jffs2_fsload(struct cmd_tbl *cmdtp, int flag, int argc, size = jffs2_1pass_load((char *)offset, part, filename); }
- if (size > 0) { - printf("### %s load complete: %d bytes loaded to 0x%lx\n", - fsname, size, offset); - env_set_hex("filesize", size); - } else { + if (size <= 0) { printf("### %s LOAD ERROR<%x> for %s!\n", fsname, size, filename); + return CMD_RET_FAILURE; }
- return !(size > 0); + printf("### %s load complete: %d bytes loaded to 0x%lx\n", + fsname, size, offset); + env_set_hex("filesize", size); + + return 0; } - return 1; + return CMD_RET_FAILURE; }
/** @@ -534,7 +535,7 @@ int do_jffs2_ls(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
/* make sure we are in sync with env variables */ if (mtdparts_init() !=0) - return 1; + return CMD_RET_FAILURE;
if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
@@ -546,9 +547,9 @@ int do_jffs2_ls(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) ret = jffs2_1pass_ls(part, filename); }
- return ret ? 0 : 1; + return ret ? CMD_RET_SUCCESS : CMD_RET_FAILURE; } - return 1; + return CMD_RET_FAILURE; }
/** @@ -570,7 +571,7 @@ int do_jffs2_fsinfo(struct cmd_tbl *cmdtp, int flag, int argc,
/* make sure we are in sync with env variables */ if (mtdparts_init() !=0) - return 1; + return CMD_RET_FAILURE;
if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
@@ -585,9 +586,9 @@ int do_jffs2_fsinfo(struct cmd_tbl *cmdtp, int flag, int argc, ret = jffs2_1pass_info(part); }
- return ret ? 0 : 1; + return ret ? CMD_RET_SUCCESS : CMD_RET_FAILURE; } - return 1; + return CMD_RET_FAILURE; }
/***************************************************/

Boards with SPI NAND also can use this command.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- cmd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cmd/Kconfig b/cmd/Kconfig index c47523a03b..c8484576e2 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1367,7 +1367,7 @@ config CMD_MUX config CMD_NAND bool "nand" default y if NAND_SUNXI - depends on MTD_RAW_NAND + depends on MTD_RAW_NAND || MTD_SPI_NAND help NAND support.

On 12/28/23 10:39, Alexey Romanov wrote:
Boards with SPI NAND also can use this command.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
cmd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cmd/Kconfig b/cmd/Kconfig index c47523a03b..c8484576e2 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1367,7 +1367,7 @@ config CMD_MUX config CMD_NAND bool "nand" default y if NAND_SUNXI
- depends on MTD_RAW_NAND
- depends on MTD_RAW_NAND || MTD_SPI_NAND help NAND support.
Reviewed-by: Sean Anderson sean.anderson@seco.com

SPI NAND devices also supports 'fastboot erase / flash' commands.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/fastboot/fb_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index 6d3a900c77..39d888301f 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -53,7 +53,7 @@ static int fb_nand_lookup(const char *partname, return ret; }
- if (dev->id->type != MTD_DEV_TYPE_NAND) { + if (dev->id->type != MTD_DEV_TYPE_NAND && dev->id->type != MTD_DEV_TYPE_SPINAND) { pr_err("partition '%s' is not stored on a NAND device", partname); fastboot_fail("not a NAND device", response);

On 12/28/23 10:39, Alexey Romanov wrote:
SPI NAND devices also supports 'fastboot erase / flash' commands.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
drivers/fastboot/fb_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index 6d3a900c77..39d888301f 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -53,7 +53,7 @@ static int fb_nand_lookup(const char *partname, return ret; }
- if (dev->id->type != MTD_DEV_TYPE_NAND) {
- if (dev->id->type != MTD_DEV_TYPE_NAND && dev->id->type != MTD_DEV_TYPE_SPINAND) { pr_err("partition '%s' is not stored on a NAND device", partname); fastboot_fail("not a NAND device", response);
Reviewed-by: Sean Anderson sean.anderson@seco.com

Hi Alexey,
Thank you for the patch.
On Thu, Dec 28, 2023 at 18:39, Alexey Romanov avromanov@salutedevices.com wrote:
SPI NAND devices also supports 'fastboot erase / flash' commands.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
Reviewed-by: Mattijs Korpershoek mkorpershoek@baylibre.com
drivers/fastboot/fb_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index 6d3a900c77..39d888301f 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -53,7 +53,7 @@ static int fb_nand_lookup(const char *partname, return ret; }
- if (dev->id->type != MTD_DEV_TYPE_NAND) {
- if (dev->id->type != MTD_DEV_TYPE_NAND && dev->id->type != MTD_DEV_TYPE_SPINAND) { pr_err("partition '%s' is not stored on a NAND device", partname); fastboot_fail("not a NAND device", response);
-- 2.30.1

From now we can use FASTBOOT_FLASH_NAND option for SPI NAND.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/fastboot/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index a3df9aa3d0..3cfeea4837 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -86,7 +86,7 @@ config FASTBOOT_USB_DEV config FASTBOOT_FLASH bool "Enable FASTBOOT FLASH command" default y if ARCH_SUNXI || ARCH_ROCKCHIP - depends on MMC || (MTD_RAW_NAND && CMD_MTDPARTS) + depends on MMC || ((MTD_RAW_NAND || MTD_SPI_NAND) && CMD_MTDPARTS) select IMAGE_SPARSE help The fastboot protocol includes a "flash" command for writing @@ -112,7 +112,7 @@ config FASTBOOT_FLASH_MMC
config FASTBOOT_FLASH_NAND bool "FASTBOOT on NAND" - depends on MTD_RAW_NAND && CMD_MTDPARTS + depends on (MTD_RAW_NAND || MTD_SPI_NAND) && CMD_MTDPARTS
endchoice

On 12/28/23 10:39, Alexey Romanov wrote:
From now we can use FASTBOOT_FLASH_NAND option for SPI NAND.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
drivers/fastboot/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index a3df9aa3d0..3cfeea4837 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -86,7 +86,7 @@ config FASTBOOT_USB_DEV config FASTBOOT_FLASH bool "Enable FASTBOOT FLASH command" default y if ARCH_SUNXI || ARCH_ROCKCHIP
- depends on MMC || (MTD_RAW_NAND && CMD_MTDPARTS)
- depends on MMC || ((MTD_RAW_NAND || MTD_SPI_NAND) && CMD_MTDPARTS) select IMAGE_SPARSE help The fastboot protocol includes a "flash" command for writing
@@ -112,7 +112,7 @@ config FASTBOOT_FLASH_MMC
config FASTBOOT_FLASH_NAND bool "FASTBOOT on NAND"
- depends on MTD_RAW_NAND && CMD_MTDPARTS
- depends on (MTD_RAW_NAND || MTD_SPI_NAND) && CMD_MTDPARTS
endchoice
Reviewed-by: Sean Anderson sean.anderson@seco.com

Hi Alexey,
Thank you for the patch.
On Thu, Dec 28, 2023 at 18:39, Alexey Romanov avromanov@salutedevices.com wrote:
From now we can use FASTBOOT_FLASH_NAND option for SPI NAND.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
Reviewed-by: Mattijs Korpershoek mkorpershoek@baylibre.com
drivers/fastboot/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index a3df9aa3d0..3cfeea4837 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -86,7 +86,7 @@ config FASTBOOT_USB_DEV config FASTBOOT_FLASH bool "Enable FASTBOOT FLASH command" default y if ARCH_SUNXI || ARCH_ROCKCHIP
- depends on MMC || (MTD_RAW_NAND && CMD_MTDPARTS)
- depends on MMC || ((MTD_RAW_NAND || MTD_SPI_NAND) && CMD_MTDPARTS) select IMAGE_SPARSE help The fastboot protocol includes a "flash" command for writing
@@ -112,7 +112,7 @@ config FASTBOOT_FLASH_MMC
config FASTBOOT_FLASH_NAND bool "FASTBOOT on NAND"
- depends on MTD_RAW_NAND && CMD_MTDPARTS
- depends on (MTD_RAW_NAND || MTD_SPI_NAND) && CMD_MTDPARTS
endchoice
-- 2.30.1

pr_err() doesn't add an newline symbol when printing.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/fastboot/fb_nand.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index 39d888301f..9db1903e41 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -48,13 +48,13 @@ static int fb_nand_lookup(const char *partname,
ret = find_dev_and_part(partname, &dev, &pnum, part); if (ret) { - pr_err("cannot find partition: '%s'", partname); + pr_err("cannot find partition: '%s'\n", partname); fastboot_fail("cannot find partition", response); return ret; }
if (dev->id->type != MTD_DEV_TYPE_NAND && dev->id->type != MTD_DEV_TYPE_SPINAND) { - pr_err("partition '%s' is not stored on a NAND device", + pr_err("partition '%s' is not stored on a NAND device\n", partname); fastboot_fail("not a NAND device", response); return -EINVAL; @@ -178,7 +178,7 @@ void fastboot_nand_flash_write(const char *cmd, void *download_buffer,
ret = fb_nand_lookup(cmd, &mtd, &part, response); if (ret) { - pr_err("invalid NAND device"); + pr_err("invalid NAND device\n"); fastboot_fail("invalid NAND device", response); return; } @@ -242,7 +242,7 @@ void fastboot_nand_erase(const char *cmd, char *response)
ret = fb_nand_lookup(cmd, &mtd, &part, response); if (ret) { - pr_err("invalid NAND device"); + pr_err("invalid NAND device\n"); fastboot_fail("invalid NAND device", response); return; } @@ -253,7 +253,7 @@ void fastboot_nand_erase(const char *cmd, char *response)
ret = _fb_nand_erase(mtd, part); if (ret) { - pr_err("failed erasing from device %s", mtd->name); + pr_err("failed erasing from device %s\n", mtd->name); fastboot_fail("failed erasing from device", response); return; }

On 12/28/23 10:39, Alexey Romanov wrote:
pr_err() doesn't add an newline symbol when printing.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
drivers/fastboot/fb_nand.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index 39d888301f..9db1903e41 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -48,13 +48,13 @@ static int fb_nand_lookup(const char *partname,
ret = find_dev_and_part(partname, &dev, &pnum, part); if (ret) {
pr_err("cannot find partition: '%s'", partname);
pr_err("cannot find partition: '%s'\n", partname);
fastboot_fail("cannot find partition", response); return ret; }
if (dev->id->type != MTD_DEV_TYPE_NAND && dev->id->type != MTD_DEV_TYPE_SPINAND) {
pr_err("partition '%s' is not stored on a NAND device",
fastboot_fail("not a NAND device", response); return -EINVAL;pr_err("partition '%s' is not stored on a NAND device\n", partname);
@@ -178,7 +178,7 @@ void fastboot_nand_flash_write(const char *cmd, void *download_buffer,
ret = fb_nand_lookup(cmd, &mtd, &part, response); if (ret) {
pr_err("invalid NAND device");
fastboot_fail("invalid NAND device", response); return; }pr_err("invalid NAND device\n");
@@ -242,7 +242,7 @@ void fastboot_nand_erase(const char *cmd, char *response)
ret = fb_nand_lookup(cmd, &mtd, &part, response); if (ret) {
pr_err("invalid NAND device");
fastboot_fail("invalid NAND device", response); return; }pr_err("invalid NAND device\n");
@@ -253,7 +253,7 @@ void fastboot_nand_erase(const char *cmd, char *response)
ret = _fb_nand_erase(mtd, part); if (ret) {
pr_err("failed erasing from device %s", mtd->name);
fastboot_fail("failed erasing from device", response); return; }pr_err("failed erasing from device %s\n", mtd->name);
Reviewed-by: Sean Anderson sean.anderson@seco.com

Hi Alexey,
Thank you for the patch.
On Thu, Dec 28, 2023 at 18:39, Alexey Romanov avromanov@salutedevices.com wrote:
pr_err() doesn't add an newline symbol when printing.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
Reviewed-by: Mattijs Korpershoek mkorpershoek@baylibre.com
drivers/fastboot/fb_nand.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index 39d888301f..9db1903e41 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -48,13 +48,13 @@ static int fb_nand_lookup(const char *partname,
ret = find_dev_and_part(partname, &dev, &pnum, part); if (ret) {
pr_err("cannot find partition: '%s'", partname);
pr_err("cannot find partition: '%s'\n", partname);
fastboot_fail("cannot find partition", response); return ret; }
if (dev->id->type != MTD_DEV_TYPE_NAND && dev->id->type != MTD_DEV_TYPE_SPINAND) {
pr_err("partition '%s' is not stored on a NAND device",
fastboot_fail("not a NAND device", response); return -EINVAL;pr_err("partition '%s' is not stored on a NAND device\n", partname);
@@ -178,7 +178,7 @@ void fastboot_nand_flash_write(const char *cmd, void *download_buffer,
ret = fb_nand_lookup(cmd, &mtd, &part, response); if (ret) {
pr_err("invalid NAND device");
fastboot_fail("invalid NAND device", response); return; }pr_err("invalid NAND device\n");
@@ -242,7 +242,7 @@ void fastboot_nand_erase(const char *cmd, char *response)
ret = fb_nand_lookup(cmd, &mtd, &part, response); if (ret) {
pr_err("invalid NAND device");
fastboot_fail("invalid NAND device", response); return; }pr_err("invalid NAND device\n");
@@ -253,7 +253,7 @@ void fastboot_nand_erase(const char *cmd, char *response)
ret = _fb_nand_erase(mtd, part); if (ret) {
pr_err("failed erasing from device %s", mtd->name);
fastboot_fail("failed erasing from device", response); return; }pr_err("failed erasing from device %s\n", mtd->name);
-- 2.30.1
participants (4)
-
Alexey Romanov
-
Mattijs Korpershoek
-
Michael Nazzareno Trimarchi
-
Sean Anderson