[PATCH v1 4/5] cmd: mvebu: add emmcboot for Nodebox image format

Stefan Roese stefan.roese at mailbox.org
Tue Mar 31 14:46:21 CEST 2026


On 3/10/26 15:12, Vincent Jardin wrote:
> The Nodebox 10G stores firmware in a board-specific format
> (mvebu_image_tag) at fixed offsets in eMMC. Each image bundles a
> kernel and device tree under a CRC32-validated tag header.
> 
> Include a board-specific rollback support based on a reboot counter
> in order to track consecutive boot failures and then to boot from
> the fallback image.

So is all this board-specific or platform specific? If it's board-
specific, wouldn't this command better reside in the board directory?

Thinking about this a bit more, is there something board-specific or
even platform-specific in this emmc boot cmd and/or format? Could other
targets perhaps use this as well? Seems to be a pretty "lightweight"
failsafe boot method, even though I did not look too deep into it.

Another thought / question:
Not sure if we need new methods though. What is the reasoning for
introducing this emmc boot method?

> Signed-off-by: Vincent Jardin <vjardin at free.fr>
> ---
>   cmd/mvebu/Kconfig                   |  53 +++++
>   cmd/mvebu/Makefile                  |   1 +
>   cmd/mvebu/mvebu_emmcboot.c          | 340 ++++++++++++++++++++++++++++
>   configs/mvebu_nbx_88f8040_defconfig |   1 +
>   include/mvebu_imagetag.h            |  82 +++++++
>   include/mvebu_nrboot.h              |  51 +++++
>   6 files changed, 528 insertions(+)
>   create mode 100644 cmd/mvebu/mvebu_emmcboot.c
>   create mode 100644 include/mvebu_imagetag.h
>   create mode 100644 include/mvebu_nrboot.h
> 
> diff --git a/cmd/mvebu/Kconfig b/cmd/mvebu/Kconfig
> index e83a9829491..ea03f581280 100644
> --- a/cmd/mvebu/Kconfig
> +++ b/cmd/mvebu/Kconfig
> @@ -79,4 +79,57 @@ config CMD_MVEBU_COMPHY_RX_TRAINING
>   	help
>   	  Perform COMPHY RX training sequence
>   
> +config CMD_NBX_EMMCBOOT
> +	bool "Nodebox emmcboot command"
> +	depends on ARMADA_8K && MMC_SDHCI_XENON
> +	help
> +	  Enable the emmcboot command for Nodebox 10G boards. The command
> +	  loads and boots firmware stored in the board-specific image format
> +	  (mvebu_image_tag) at fixed eMMC offsets. Each image bundles a
> +	  kernel and device tree under a CRC32-validated tag header.
> +
> +	  Two image banks are supported (Bank0 stable, Bank1 newer) with
> +	  automatic fallback based on a reboot tracking counter (nrboot).
> +
> +	  Requires image_addr and fdt_addr environment variables to be set.
> +
> +if CMD_NBX_EMMCBOOT
> +
> +config MVEBU_MMC_PART_NRBOOT_OFFSET
> +	hex "NRBoot counter offset in eMMC"
> +	default 0x802000
> +	help
> +	  Byte offset in eMMC where the reboot tracking counter is stored.
> +	  Default: 0x802000 (8MB + 8KB)
> +
> +config MVEBU_MMC_PART_BANK0_OFFSET
> +	hex "Bank0 image offset in eMMC"
> +	default 0x804000
> +	help
> +	  Byte offset in eMMC where the stable (Bank0) boot image starts.
> +	  Default: 0x804000 (8MB + 16KB)
> +
> +config MVEBU_MMC_PART_BANK0_SIZE
> +	hex "Bank0 image maximum size"
> +	default 0x10000000
> +	help
> +	  Maximum size of the Bank0 boot image.
> +	  Default: 0x10000000 (256MB)
> +
> +config MVEBU_MMC_PART_BANK1_OFFSET
> +	hex "Bank1 image offset in eMMC"
> +	default 0x10804000
> +	help
> +	  Byte offset in eMMC where the newer (Bank1) boot image starts.
> +	  Default: 0x10804000 (264MB + 16KB)
> +
> +config MVEBU_MMC_PART_BANK1_SIZE
> +	hex "Bank1 image maximum size"
> +	default 0x10000000
> +	help
> +	  Maximum size of the Bank1 boot image.
> +	  Default: 0x10000000 (256MB)
> +
> +endif
> +
>   endmenu
> diff --git a/cmd/mvebu/Makefile b/cmd/mvebu/Makefile
> index ca96ad01d91..c096f507e26 100644
> --- a/cmd/mvebu/Makefile
> +++ b/cmd/mvebu/Makefile
> @@ -6,3 +6,4 @@
>   
>   obj-$(CONFIG_CMD_MVEBU_BUBT) += bubt.o
>   obj-$(CONFIG_CMD_MVEBU_COMPHY_RX_TRAINING) += comphy_rx_training.o
> +obj-$(CONFIG_CMD_NBX_EMMCBOOT) += mvebu_emmcboot.o
> diff --git a/cmd/mvebu/mvebu_emmcboot.c b/cmd/mvebu/mvebu_emmcboot.c
> new file mode 100644
> index 00000000000..3d85f82670a
> --- /dev/null
> +++ b/cmd/mvebu/mvebu_emmcboot.c
> @@ -0,0 +1,340 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * MVEBU eMMC boot command for Nodebox 10G boot image format
> + *
> + * Copyright (C) 2026 Free Mobile, Freebox
> + *
> + * The Nodebox 10G stores firmware images in a board-specific format
> + * (mvebu_image_tag) at fixed offsets in eMMC. Each image bundles a
> + * kernel, device tree, and optional rootfs under a CRC32-validated
> + * tag header.
> + *
> + * Two image banks are laid out in eMMC (Bank0 stable, Bank1 newer).
> + * A reboot counter (nrboot) selects which bank to try first.
> + */
> +
> +#include <command.h>
> +#include <env.h>
> +#include <mmc.h>
> +#include <malloc.h>
> +#include <memalign.h>
> +#include <vsprintf.h>
> +#include <u-boot/crc.h>
> +#include <u-boot/schedule.h>
> +#include <asm/byteorder.h>
> +#include <linux/bitops.h>
> +#include <mvebu_imagetag.h>
> +#include <mvebu_nrboot.h>
> +
> +/* Image Tag Functions */
> +
> +static int mvebu_imagetag_check(struct mvebu_image_tag *tag,
> +				unsigned long maxsize, const char *name)
> +{
> +	if (be32_to_cpu(tag->magic) != MVEBU_IMAGE_TAG_MAGIC) {
> +		if (name)
> +			printf("%s: invalid TAG magic: %.8x\n", name,
> +			       be32_to_cpu(tag->magic));
> +		return -1;

Could you use an actuall errno code instead? And in other places as
well?

> +	}
> +
> +	if (be32_to_cpu(tag->version) != MVEBU_IMAGE_TAG_VERSION) {
> +		if (name)
> +			printf("%s: invalid TAG version: %.8x\n", name,
> +			       be32_to_cpu(tag->version));
> +		return -1;
> +	}
> +
> +	if (be32_to_cpu(tag->total_size) < sizeof(*tag)) {
> +		if (name)
> +			printf("%s: tag size is too small!\n", name);
> +		return -1;
> +	}
> +
> +	if (be32_to_cpu(tag->total_size) > maxsize) {
> +		if (name)
> +			printf("%s: tag size is too big!\n", name);
> +		return -1;
> +	}
> +
> +	if (be32_to_cpu(tag->device_tree_offset) < sizeof(*tag) ||
> +	    be32_to_cpu(tag->device_tree_offset) +
> +	    be32_to_cpu(tag->device_tree_size) > maxsize) {
> +		if (name)
> +			printf("%s: bogus device tree offset/size!\n", name);
> +		return -1;
> +	}
> +
> +	if (be32_to_cpu(tag->kernel_offset) < sizeof(*tag) ||
> +	    be32_to_cpu(tag->kernel_offset) +
> +	    be32_to_cpu(tag->kernel_size) > maxsize) {
> +		if (name)
> +			printf("%s: bogus kernel offset/size!\n", name);
> +		return -1;
> +	}
> +
> +	if (be32_to_cpu(tag->rootfs_offset) < sizeof(*tag) ||
> +	    be32_to_cpu(tag->rootfs_offset) +
> +	    be32_to_cpu(tag->rootfs_size) > maxsize) {
> +		if (name)
> +			printf("%s: bogus rootfs offset/size!\n", name);
> +		return -1;
> +	}
> +
> +	if (name) {
> +		/*
> +		 * Ensure null-termination within the 32-byte fields
> +		 * before printing to avoid displaying garbage.
> +		 */
> +		tag->image_name[sizeof(tag->image_name) - 1] = '\0';
> +		tag->build_date[sizeof(tag->build_date) - 1] = '\0';
> +		tag->build_user[sizeof(tag->build_user) - 1] = '\0';
> +
> +		printf("%s: Found valid tag: %s / %s / %s\n", name,
> +		       tag->image_name, tag->build_date, tag->build_user);
> +	}
> +
> +	return 0;
> +}
> +
> +static int mvebu_imagetag_crc(struct mvebu_image_tag *tag, const char *name)
> +{
> +	u32 crc = ~0;
> +
> +	crc = crc32(crc, ((unsigned char *)tag) + 4,
> +		    be32_to_cpu(tag->total_size) - 4);
> +
> +	if (be32_to_cpu(tag->crc) != crc) {
> +		if (name)
> +			printf("%s: invalid tag CRC!\n", name);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +/* NRBoot (Reboot Tracking) Functions */
> +
> +int mvebu_check_nrboot(struct mmc *mmc, unsigned long offset)
> +{
> +	struct blk_desc *bd = mmc_get_blk_desc(mmc);
> +	struct mvebu_nrboot *nr;
> +	uint blk_start = ALIGN(offset, bd->blksz) / bd->blksz;
> +	uint blk_cnt = ALIGN(sizeof(*nr), bd->blksz) / bd->blksz;
> +	uint n;
> +
> +	ALLOC_CACHE_ALIGN_BUFFER(char, buf, blk_cnt * bd->blksz);
> +	nr = (void *)buf;
> +
> +	n = blk_dread(bd, blk_start, blk_cnt, buf);
> +	if (n != blk_cnt)
> +		return 0;
> +
> +	printf(" - nr.nrboot = %04x\n", nr->nrboot);
> +	printf(" - nr.nrsuccess = %04x\n", nr->nrsuccess);
> +
> +	/* Sanity check: values must be valid bit-field counters */
> +	if (generic_hweight16(~nr->nrboot + 1) <= 1 &&
> +	    generic_hweight16(~nr->nrsuccess + 1) <= 1) {
> +		int boot, success;
> +
> +		boot = 16 - generic_hweight16(nr->nrboot);
> +		success = 16 - generic_hweight16(nr->nrsuccess);
> +
> +		printf(" - Nrboot: %d / Nrsuccess: %d\n", boot, success);
> +
> +		if (boot == 16 || boot < success ||
> +		    boot - success >= MVEBU_MAX_FAILURE) {
> +			printf(" - Nrboot exceeded\n");
> +			return 0;
> +		}
> +
> +		/* Increment boot attempt counter */
> +		boot++;
> +		nr->nrboot = ~((1 << boot) - 1);
> +
> +		printf(" - Setting Nrboot to %d\n", boot);
> +
> +		n = blk_dwrite(bd, blk_start, blk_cnt, buf);
> +		if (n != blk_cnt)
> +			return 0;
> +
> +		return 1;
> +	}
> +
> +	printf(" - Invalid NR values\n");
> +
> +	return 0;
> +}
> +
> +/* emmcboot Command */
> +
> +static int mvebu_load_image(struct blk_desc *bd, unsigned long offset,
> +			    unsigned long maxsize, ulong tag_addr,
> +			    const char *bank)
> +{
> +	struct mvebu_image_tag *tag;
> +	uint blk_start = ALIGN(offset, bd->blksz) / bd->blksz;
> +	uint blk_cnt;
> +	uint n;
> +
> +	ALLOC_CACHE_ALIGN_BUFFER(char, tag_buf,
> +				 ALIGN(sizeof(*tag), bd->blksz));
> +	tag = (void *)tag_buf;
> +
> +	/* Load and validate tag header */
> +	blk_cnt = ALIGN(sizeof(*tag), bd->blksz) / bd->blksz;
> +	n = blk_dread(bd, blk_start, blk_cnt, tag_buf);
> +	if (n != blk_cnt) {
> +		printf("%s: failed to read tag header\n", bank);
> +		return -1;
> +	}
> +
> +	if (mvebu_imagetag_check(tag, maxsize, bank) != 0)
> +		return -1;
> +
> +	if (tag->rootfs_size != 0) {
> +		printf("%s: rootfs in tag not supported\n", bank);
> +		return -1;
> +	}
> +
> +	/* Load full image to tag_addr */
> +	blk_cnt = ALIGN(mvebu_imagetag_total_size(tag), bd->blksz) / bd->blksz;
> +	n = blk_dread(bd, blk_start, blk_cnt, (void *)tag_addr);
> +	if (n != blk_cnt) {
> +		printf("%s: failed to read full image\n", bank);
> +		return -1;
> +	}
> +
> +	if (mvebu_imagetag_crc((void *)tag_addr, bank) != 0)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static void mvebu_relocate_and_boot(ulong image_addr, ulong fdt_addr,
> +				    const char *bank)
> +{
> +	struct mvebu_image_tag *tag = (void *)image_addr;
> +	char bootargs[256];
> +	char cmd[128];
> +	char *console_env;
> +
> +	/* Copy DTB and kernel to their final addresses */
> +	memcpy((void *)fdt_addr,
> +	       ((void *)image_addr) + mvebu_imagetag_device_tree_offset(tag),
> +	       mvebu_imagetag_device_tree_size(tag));
> +	memmove((void *)image_addr,
> +		((void *)image_addr) + mvebu_imagetag_kernel_offset(tag),
> +		mvebu_imagetag_kernel_size(tag));
> +
> +	schedule();
> +
> +	/* Set bootargs */
> +	console_env = env_get("console");
> +	if (console_env)
> +		snprintf(bootargs, sizeof(bootargs),
> +			 "console=%s bank=%s", console_env, bank);
> +	else
> +		snprintf(bootargs, sizeof(bootargs), "bank=%s", bank);
> +
> +	env_set("bootargs", bootargs);
> +
> +	printf("## Booting kernel from %s...\n", bank);
> +	printf("   Image addr: 0x%lx\n", image_addr);
> +	printf("   FDT addr:   0x%lx\n", fdt_addr);
> +
> +	snprintf(cmd, sizeof(cmd), "booti 0x%lx - 0x%lx",
> +		 image_addr, fdt_addr);
> +	run_command(cmd, 0);
> +}
> +
> +static void mvebu_try_emmcboot(struct mmc *mmc, unsigned long offset,
> +			       unsigned long maxsize, const char *bank)
> +{
> +	struct blk_desc *bd = mmc_get_blk_desc(mmc);
> +	ulong image_addr;
> +	ulong fdt_addr;
> +
> +	schedule();
> +
> +	printf("## Trying %s boot...\n", bank);
> +
> +	/* Get load addresses from environment */
> +	image_addr = env_get_ulong("image_addr", 16, 0);
> +	if (!image_addr) {
> +		puts("emmcboot needs image_addr\n");
> +		return;
> +	}
> +
> +	fdt_addr = env_get_ulong("fdt_addr", 16, 0);
> +	if (!fdt_addr) {
> +		puts("emmcboot needs fdt_addr\n");
> +		return;
> +	}
> +
> +	if (mvebu_load_image(bd, offset, maxsize, image_addr, bank) != 0)
> +		return;
> +
> +	schedule();
> +
> +	mvebu_relocate_and_boot(image_addr, fdt_addr, bank);
> +
> +	printf("## %s boot failed\n", bank);
> +}
> +
> +static int do_emmcboot(struct cmd_tbl *cmdtp, int flag, int argc,
> +		       char *const argv[])
> +{
> +	int dev;
> +	struct mmc *mmc;
> +
> +	dev = 0;
> +	if (argc >= 2)
> +		dev = dectoul(argv[1], NULL);
> +
> +	mmc = find_mmc_device(dev);
> +	if (!mmc) {
> +		printf("No MMC device %d found\n", dev);
> +		return CMD_RET_FAILURE;
> +	}
> +
> +	if (mmc_init(mmc)) {
> +		puts("MMC init failed\n");
> +		return CMD_RET_FAILURE;
> +	}
> +
> +	/* Switch to partition 0 (user data area) */
> +	if (blk_select_hwpart_devnum(UCLASS_MMC, dev, 0)) {
> +		puts("MMC partition switch failed\n");
> +		return CMD_RET_FAILURE;
> +	}
> +
> +	if (mvebu_check_nrboot(mmc, CONFIG_MVEBU_MMC_PART_NRBOOT_OFFSET)) {
> +		/* System is healthy: try newer bank first */
> +		mvebu_try_emmcboot(mmc, CONFIG_MVEBU_MMC_PART_BANK1_OFFSET,
> +				   CONFIG_MVEBU_MMC_PART_BANK1_SIZE, "bank1");
> +		mvebu_try_emmcboot(mmc, CONFIG_MVEBU_MMC_PART_BANK0_OFFSET,
> +				   CONFIG_MVEBU_MMC_PART_BANK0_SIZE, "bank0");
> +	} else {
> +		/* System is degraded: use stable bank first */
> +		mvebu_try_emmcboot(mmc, CONFIG_MVEBU_MMC_PART_BANK0_OFFSET,
> +				   CONFIG_MVEBU_MMC_PART_BANK0_SIZE, "bank0");
> +		mvebu_try_emmcboot(mmc, CONFIG_MVEBU_MMC_PART_BANK1_OFFSET,
> +				   CONFIG_MVEBU_MMC_PART_BANK1_SIZE, "bank1");
> +	}
> +
> +	puts("emmcboot: all boot attempts failed\n");
> +
> +	return CMD_RET_FAILURE;
> +}
> +
> +U_BOOT_CMD(
> +	emmcboot, 2, 0, do_emmcboot,
> +	"boot from Nodebox eMMC image banks",
> +	"[dev]\n"
> +	"    - Load and boot a Nodebox image from eMMC device <dev> (default 0)\n"
> +	"    - Requires image_addr and fdt_addr environment variables\n"
> +	"    - Two banks: Bank0 (stable) and Bank1 (newer)\n"
> +	"    - Bank order selected by reboot tracking counter (nrboot)"
> +);
> diff --git a/configs/mvebu_nbx_88f8040_defconfig b/configs/mvebu_nbx_88f8040_defconfig
> index 975c53e9a92..2fd58e4ad64 100644
> --- a/configs/mvebu_nbx_88f8040_defconfig
> +++ b/configs/mvebu_nbx_88f8040_defconfig
> @@ -40,6 +40,7 @@ CONFIG_CMD_PING=y
>   CONFIG_CMD_CACHE=y
>   CONFIG_CMD_TIME=y
>   CONFIG_CMD_TIMER=y
> +CONFIG_CMD_NBX_EMMCBOOT=y
>   CONFIG_CMD_EXT2=y
>   CONFIG_CMD_EXT4=y
>   CONFIG_CMD_EXT4_WRITE=y
> diff --git a/include/mvebu_imagetag.h b/include/mvebu_imagetag.h
> new file mode 100644
> index 00000000000..d513038aaf6
> --- /dev/null
> +++ b/include/mvebu_imagetag.h
> @@ -0,0 +1,82 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Nodebox 10G boot image tag format
> + *
> + * Copyright (C) 2026 Free Mobile, Freebox
> + *
> + * Defines the on-eMMC image layout used by Nodebox 10G boards.
> + * Each image carries a CRC32-validated tag header that describes
> + * the kernel, device tree, and rootfs components.
> + */
> +
> +#ifndef __MVEBU_IMAGETAG_H
> +#define __MVEBU_IMAGETAG_H
> +
> +#include <linux/types.h>
> +
> +#define MVEBU_IMAGE_TAG_MAGIC	0x8d7c90bc
> +#define MVEBU_IMAGE_TAG_VERSION	1
> +
> +/**
> + * struct mvebu_image_tag - Nodebox boot image tag stored in eMMC
> + *
> + * All multi-byte fields are stored in big-endian format.
> + */
> +struct mvebu_image_tag {
> +	u32 crc;			/* CRC32-LE checksum (from offset 4) */
> +	u32 magic;			/* Magic: 0x8d7c90bc */
> +	u32 version;			/* Version: 1 */
> +	u32 total_size;			/* Total image size including tag */
> +	u32 flags;			/* Feature flags (reserved) */
> +
> +	u32 device_tree_offset;		/* Offset from tag start to DTB */
> +	u32 device_tree_size;		/* DTB size in bytes */
> +
> +	u32 kernel_offset;		/* Offset from tag start to kernel */
> +	u32 kernel_size;		/* Kernel size in bytes */
> +
> +	u32 rootfs_offset;		/* Offset from tag start to rootfs */
> +	u32 rootfs_size;		/* Rootfs size (must be 0) */
> +
> +	char image_name[32];		/* Image name (null-terminated) */
> +	char build_user[32];		/* Build user info */
> +	char build_date[32];		/* Build date info */
> +};
> +
> +/* Accessor functions for big-endian fields */
> +static inline u32 mvebu_imagetag_device_tree_offset(struct mvebu_image_tag *tag)
> +{
> +	return be32_to_cpu(tag->device_tree_offset);
> +}
> +
> +static inline u32 mvebu_imagetag_device_tree_size(struct mvebu_image_tag *tag)
> +{
> +	return be32_to_cpu(tag->device_tree_size);
> +}
> +
> +static inline u32 mvebu_imagetag_kernel_offset(struct mvebu_image_tag *tag)
> +{
> +	return be32_to_cpu(tag->kernel_offset);
> +}
> +
> +static inline u32 mvebu_imagetag_kernel_size(struct mvebu_image_tag *tag)
> +{
> +	return be32_to_cpu(tag->kernel_size);
> +}
> +
> +static inline u32 mvebu_imagetag_rootfs_offset(struct mvebu_image_tag *tag)
> +{
> +	return be32_to_cpu(tag->rootfs_offset);
> +}
> +
> +static inline u32 mvebu_imagetag_rootfs_size(struct mvebu_image_tag *tag)
> +{
> +	return be32_to_cpu(tag->rootfs_size);
> +}
> +
> +static inline u32 mvebu_imagetag_total_size(struct mvebu_image_tag *tag)
> +{
> +	return be32_to_cpu(tag->total_size);
> +}
> +
> +#endif /* __MVEBU_IMAGETAG_H */
> diff --git a/include/mvebu_nrboot.h b/include/mvebu_nrboot.h
> new file mode 100644
> index 00000000000..11d59d7680f
> --- /dev/null
> +++ b/include/mvebu_nrboot.h
> @@ -0,0 +1,51 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Nodebox 10G reboot tracking counter (NRBoot)
> + *
> + * Copyright (C) 2026 Free Mobile, Freebox
> + *
> + * Part of the Nodebox eMMC image format: a small bit-field counter
> + * stored between the serial info and the image banks that tracks
> + * consecutive boot failures to select the right bank.
> + */
> +
> +#ifndef __MVEBU_NRBOOT_H
> +#define __MVEBU_NRBOOT_H
> +
> +#include <linux/types.h>
> +#include <mmc.h>
> +
> +#define MVEBU_MAX_FAILURE	4
> +
> +/**
> + * struct mvebu_nrboot - Reboot tracking counter stored in eMMC
> + * @nrboot: Bit-field counter of boot attempts (0-bits = attempt count)
> + * @nrsuccess: Bit-field counter of successful boots
> + */
> +struct mvebu_nrboot {
> +	u16 nrboot;
> +	u16 nrsuccess;
> +};
> +
> +/**
> + * mvebu_check_nrboot() - Check and update reboot tracking counter
> + * @mmc: MMC device
> + * @offset: Byte offset in MMC where nrboot data is stored
> + *
> + * Reads the reboot tracking counter, checks if the maximum number of
> + * failed boots (4) has been exceeded, and updates the counter for the
> + * current boot attempt.
> + *
> + * The counter uses a bit-field encoding for wear leveling:
> + * - nrboot: Running count of boot attempts (counted as cleared bits)
> + * - nrsuccess: Count of successful boots (counted as cleared bits)
> + *
> + * If boot - success >= MAX_FAILURE (4), the system is considered
> + * degraded and should use the fallback boot bank.
> + *
> + * Return: 1 if system is healthy (try newer bank first),
> + *         0 if system is degraded (use stable bank first)
> + */
> +int mvebu_check_nrboot(struct mmc *mmc, unsigned long offset);
> +
> +#endif /* __MVEBU_NRBOOT_H */



More information about the U-Boot mailing list