An example of how we use fastboot oeam board subcommand for Sean Anderson. 1 - OEM_BOARD_WRITE_BOOTLOADER_CMD:
We use it for custom Amlogic bootloader + tpl flashing protocol. 2 - OEM_BOARD_ERASE_CMD: Custom logic for erasing the env-emulated partition, which isn't in the mtd markup map. Example of the script which completely flashes the device: $ fastboot erase bootloader $ fastboot stage u-boot.bin $ fastboot oem board:write_bootloader $ fastboot reboot-bootloader $ fastboot oem board:erase_env $ fastboot erase misc $ fastboot erase super $ fastboot flash super rootfs $ fastboot reboot Signed-off-by: Alexey Romanov <avroma...@salutedevices.com> --- board/amlogic/ad401/fastboot.c | 222 +++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 board/amlogic/ad401/fastboot.c diff --git a/board/amlogic/ad401/fastboot.c b/board/amlogic/ad401/fastboot.c new file mode 100644 index 0000000000..01da8efa5b --- /dev/null +++ b/board/amlogic/ad401/fastboot.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2023 SaluteDevices, Inc. + */ + +#include <common.h> +#include <env.h> +#include <fastboot.h> +#include <nand.h> +#include <asm/arch/nand.h> +#include <jffs2/load_kernel.h> +#include <linux/sizes.h> +#include <linux/types.h> +#include <linux/mtd/mtd.h> + +enum { + OEM_BOARD_ERASE_CMD, + OEM_BOARD_WRITE_BOOTLOADER_CMD, +}; + +struct defenv { + char *name; + char value[256]; +}; + +static void save_defenv(struct defenv *e, size_t cnt) +{ + int i; + + for (i = 0; i < cnt; i++) { + const char *env_val = env_get(e[i].name); + + if (env_val) + strlcpy(e[i].value, env_val, sizeof(e[i].value)); + else + e[i].value[0] = '\0'; + } +} + +static void set_defenv(struct defenv *e, size_t cnt) +{ + int i; + + for (i = 0; i < cnt; i++) + env_set(e[i].name, e[i].value); +} + +static int fastboot_erase_env(void) +{ + char *const defenv_names[] = { "lock", "mtdparts", "mtdids" }; + struct defenv env[ARRAY_SIZE(defenv_names)]; + int err, i; + + for (i = 0; i < ARRAY_SIZE(env); i++) + env[i].name = defenv_names[i]; + + printf("ENV is being erased...\n"); + + /* + * Reset environment to the default, excluding 'lock' variable, + * because it reflects the fastboot's state after execution of + * 'flashing unlock' command, hence it must survive the env-erasing. + * Otherwise, further erase commands will fail on check_lock(). + * + * Also, we have to save 'mtdparts' and 'mtdids' variables + * because they are necessary to obtain partition map. + */ + + save_defenv(env, ARRAY_SIZE(env)); + env_set_default(NULL, 0); + set_defenv(env, ARRAY_SIZE(env)); + + err = env_save(); + if (err) { + pr_err("Can't overwrite ENV-partition\n"); + return err; + } + + return 0; +} + +static int fastboot_nand_write_tpl(struct mtd_info *mtd, void *buffer, + u32 offset, size_t size, int flags) +{ + int boot_cpy_num = meson_bootloader_copy_num(BOOT_TPL); + u64 size_per_copy = meson_bootloader_copy_size(mtd, BOOT_TPL); + int i; + + for (i = 0; i < boot_cpy_num; i++) { + size_t retlen, len = size; + int ret; + + ret = nand_write_skip_bad(mtd, offset + (i * size_per_copy), + &len, &retlen, offset + size_per_copy, + buffer, flags); + if (ret) + return ret; + } + + return 0; +} + +static int fastboot_nand_write_bl2(struct mtd_info *mtd, void *buffer, + u32 offset, size_t size, int flags) +{ + int boot_cpy_num = meson_bootloader_copy_num(BOOT_BL2); + u64 size_per_copy = meson_bootloader_copy_size(mtd, BOOT_BL2); + int i; + + for (i = 0; i < boot_cpy_num; i++) { + int ret; + + ret = meson_bootloader_write_bl2(mtd, buffer, + offset + (i * size_per_copy), + size, flags); + if (ret) + return ret; + } + + return meson_bootloader_write_info_pages(); +} + +static int fastboot_nand_write_bootloader(void *buffer, u32 size) +{ + struct part_info *part; + struct mtd_info *mtd = NULL; + struct mtd_device *dev; + u8 pnum; + int ret; + + if (size < BL2_SIZE) + return 0; + + if (!buffer) + return -EINVAL; + + ret = mtdparts_init(); + if (ret) { + pr_err("Cannot initialize MTD partitions\n"); + return ret; + } + + ret = find_dev_and_part("bootloader", &dev, &pnum, &part); + if (ret) { + pr_err("cannot find 'bootloader' partition\n"); + return ret; + } + + mtd = get_nand_dev_by_index(dev->id->num); + if (!mtd) + return -EINVAL; + + ret = fastboot_nand_write_bl2(mtd, buffer, part->offset, + BL2_SIZE, WITH_WR_VERIFY); + if (ret) { + pr_err("fastboot: failed to write BL2\n"); + return ret; + } + + ret = find_dev_and_part("tpl", &dev, &pnum, &part); + if (ret) { + pr_err("cannot find 'bootloader' partition\n"); + return ret; + } + + mtd = get_nand_dev_by_index(dev->id->num); + if (!mtd) + return -EINVAL; + + ret = fastboot_nand_write_tpl(mtd, buffer + BL2_SIZE, part->offset, + size - BL2_SIZE, WITH_WR_VERIFY); + if (ret) { + pr_err("fastboot: failed to write TPL\n"); + return ret; + } + + return 0; +} + +int get_oem_board_command(const char *cmd) +{ + const char *oem_commands[] = { + [OEM_BOARD_ERASE_CMD] = "erase_env", + [OEM_BOARD_WRITE_BOOTLOADER_CMD] = "write_bootloader", + }; + int i; + + for (i = 0; i < ARRAY_SIZE(oem_commands); i++) + if (!strcmp(cmd, oem_commands[i])) + return i; + + return -EINVAL; +} + +void fastboot_oem_board(const char *cmd_parameter, void *data, u32 size, + char *response) +{ + char buf[128] = { 0 }; + int ret, cmd; + + cmd = get_oem_board_command(cmd_parameter); + + switch (cmd) { + case OEM_BOARD_ERASE_CMD: + ret = fastboot_erase_env(); + break; + case OEM_BOARD_WRITE_BOOTLOADER_CMD: + ret = fastboot_nand_write_bootloader(data, size); + break; + default: + snprintf(buf, sizeof(buf), + "Command 'oem board %s' not supported", + cmd_parameter); + fastboot_fail(buf, response); + return; + } + + if (ret < 0) + fastboot_fail("Failed to erase env partition", response); + else + fastboot_okay(NULL, response); +} -- 2.30.1