This adds a NAND update handler which automatically detects on the filetype which stage shall be updated. It takes a single partition for both the xload images and the barebox images. It uses a fixed layout on this partition, so there's no need to configure anything on the board side. Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> --- arch/arm/mach-omap/am33xx_bbu_nand.c | 146 ++++++++++++++++++++++++++ arch/arm/mach-omap/include/mach/bbu.h | 6 ++ 2 files changed, 152 insertions(+) diff --git a/arch/arm/mach-omap/am33xx_bbu_nand.c b/arch/arm/mach-omap/am33xx_bbu_nand.c index 4c1a28d37e..8c487c8ebb 100644 --- a/arch/arm/mach-omap/am33xx_bbu_nand.c +++ b/arch/arm/mach-omap/am33xx_bbu_nand.c @@ -22,6 +22,8 @@ #include <fcntl.h> #include <libfile.h> #include <filetype.h> +#include <linux/mtd/mtd.h> +#include <mtd/mtd-peb.h> #include <mach/bbu.h> struct nand_bbu_handler { @@ -134,3 +136,147 @@ int am33xx_bbu_nand_slots_register_handler(const char *name, char **devicefile, return ret; } + +#define XLOAD_BLOCKS 4 + +static int nand_update_handler_complete(struct bbu_handler *handler, + struct bbu_data *data) +{ + const void *image = data->image; + size_t size = data->len; + enum filetype filetype; + struct cdev *cdev; + struct mtd_info *mtd; + int ret, i; + int npebs; + + filetype = file_detect_type(image, size); + + cdev = cdev_by_name(handler->devicefile); + if (!cdev) { + pr_err("%s: No NAND device found\n", __func__); + return -ENODEV; + } + + mtd = cdev->mtd; + if (!mtd) { + pr_err("%s: %s is not a mtd device\n", __func__, + handler->devicefile); + return -EINVAL; + } + + npebs = mtd_div_by_eb(mtd->size, mtd); + + /* + * Sanity check: We need at minimum 6 eraseblocks: 4 for the four xload + * binaries and 2 for the barebox images. + */ + if (npebs < XLOAD_BLOCKS + 2) + return -EINVAL; + + if (filetype == filetype_arm_barebox) { + int npebs_bb = (npebs - XLOAD_BLOCKS) / 2; + + pr_info("Barebox image detected, updating 2nd stage\n"); + + /* last chance before erasing the flash */ + ret = bbu_confirm(data); + if (ret) + goto out; + + ret = mtd_peb_write_file(mtd, XLOAD_BLOCKS, npebs_bb, data->image, + data->len); + if (ret) + goto out; + + ret = mtd_peb_write_file(mtd, XLOAD_BLOCKS + npebs_bb, npebs_bb, + data->image, data->len); + if (ret) + goto out; + + } else if (filetype == filetype_ch_image) { + int written = 0; + void *buf; + + pr_info("xload image detected, updating 1st stage\n"); + + if (data->len > mtd->erasesize) { + pr_err("Image is bigger than eraseblock, this is not supported\n"); + ret = -EINVAL; + goto out; + } + + /* last chance before erasing the flash */ + ret = bbu_confirm(data); + if (ret) + goto out; + + buf = xzalloc(mtd->erasesize); + memcpy(buf, data->image, data->len); + + for (i = 0; i < 4; i++) { + if (mtd_peb_is_bad(mtd, i)) { + pr_info("PEB%d is bad, skipping\n", i); + continue; + } + + ret = mtd_peb_erase(mtd, i); + if (ret) + continue; + + ret = mtd_peb_write(mtd, buf, i, 0, mtd->erasesize); + if (ret) { + pr_err("Failed to write MLO to PEB%d: %s\n", i, + strerror(-ret)); + continue; + } + written++; + } + + free(buf); + + if (written) + ret = 0; + else + ret = -EIO; + } else { + pr_err("%s of type %s is not a valid update file image\n", + data->imagefile, file_type_to_string(filetype)); + return -EINVAL; + } +out: + return ret; +} + +/** + * am33xx_bbu_nand_register_handler - register a NAND update handler + * @device: The nand cdev name (usually "nand0.barebox") + * + * This registers an update handler suitable for updating barebox to NAND. This + * update handler takes a single NAND partition for both the xload images and the + * barebox images. The first four blocks are used for the 4 xload copies, the + * remaining space is divided into two equally sized parts for two barebox images. + * The update handler automatically detects based on the filetype if the xload + * or the 2nd stage barebox shall be updated. + * + * FIXME: Currently for actually loading a barebox image from an xload image + * flashed with this layout a suitable layout has to be registered by the xload + * image using omap_set_barebox_part(). In the next step this should be the + * default. + */ +int am33xx_bbu_nand_register_handler(const char *device) +{ + struct bbu_handler *handler; + int ret; + + handler = xzalloc(sizeof(*handler)); + handler->devicefile = device; + handler->handler = nand_update_handler_complete; + handler->name = "nand"; + + ret = bbu_register_handler(handler); + if (ret) + free(handler); + + return ret; +} diff --git a/arch/arm/mach-omap/include/mach/bbu.h b/arch/arm/mach-omap/include/mach/bbu.h index c8b0a55acb..94d3f96bb4 100644 --- a/arch/arm/mach-omap/include/mach/bbu.h +++ b/arch/arm/mach-omap/include/mach/bbu.h @@ -23,6 +23,7 @@ int am33xx_bbu_nand_xloadslots_register_handler(const char *name, int num_devicefiles); int am33xx_bbu_nand_slots_register_handler(const char *name, char **devicefile, int num_devicefiles); +int am33xx_bbu_nand_register_handler(const char *device); #else static inline int am33xx_bbu_nand_xloadslots_register_handler(const char *name, char **devicefile, @@ -37,6 +38,11 @@ static inline int am33xx_bbu_nand_slots_register_handler(const char *name, { return 0; } + +static inline int am33xx_bbu_nand_register_handler(const char *device) +{ + return 0; +} #endif #ifdef CONFIG_BAREBOX_UPDATE_AM33XX_EMMC -- 2.23.0 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox