summaryrefslogtreecommitdiff
path: root/drivers/fastboot
diff options
context:
space:
mode:
authorAlex Kiernan <alex.kiernan@gmail.com>2018-05-29 15:30:53 +0000
committerMarek Vasut <marex@denx.de>2018-05-30 11:59:21 +0200
commitf73a7df984a9820d9beb829b32ccb5c3d55dc152 (patch)
tree8a9513b9aadb40cde8e02ca93124a40532166256 /drivers/fastboot
parentc232d14d11e29c88f2c6149d2c152f496caa5889 (diff)
net: fastboot: Merge AOSP UDP fastboot
Merge UDP fastboot support from AOSP: https://android.googlesource.com/platform/external/u-boot/+/android-o-mr1-iot-preview-8 Signed-off-by: Alex Kiernan <alex.kiernan@gmail.com> Signed-off-by: Alex Deymo <deymo@google.com> Signed-off-by: Jocelyn Bohr <bohr@google.com> Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/fastboot')
-rw-r--r--drivers/fastboot/Kconfig7
-rw-r--r--drivers/fastboot/Makefile3
-rw-r--r--drivers/fastboot/fb_command.c302
-rw-r--r--drivers/fastboot/fb_common.c93
-rw-r--r--drivers/fastboot/fb_getvar.c230
-rw-r--r--drivers/fastboot/fb_mmc.c84
-rw-r--r--drivers/fastboot/fb_nand.c19
7 files changed, 729 insertions, 9 deletions
diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig
index 0c9ced53de..625f016600 100644
--- a/drivers/fastboot/Kconfig
+++ b/drivers/fastboot/Kconfig
@@ -14,6 +14,13 @@ config USB_FUNCTION_FASTBOOT
help
This enables the USB part of the fastboot gadget.
+config UDP_FUNCTION_FASTBOOT
+ depends on NET
+ select FASTBOOT
+ bool "Enable fastboot protocol over UDP"
+ help
+ This enables the fastboot protocol over UDP.
+
if FASTBOOT
config FASTBOOT_BUF_ADDR
diff --git a/drivers/fastboot/Makefile b/drivers/fastboot/Makefile
index e4bd389adf..8831096181 100644
--- a/drivers/fastboot/Makefile
+++ b/drivers/fastboot/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += fb_common.o
-
+obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fb_getvar.o
+obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fb_command.o
obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fb_mmc.o
obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o
diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c
new file mode 100644
index 0000000000..af4f500694
--- /dev/null
+++ b/drivers/fastboot/fb_command.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include <common.h>
+#include <fastboot.h>
+#include <fastboot-internal.h>
+#include <fb_mmc.h>
+#include <fb_nand.h>
+#include <part.h>
+#include <stdlib.h>
+
+/**
+ * image_size - final fastboot image size
+ */
+static u32 image_size;
+
+/**
+ * fastboot_bytes_received - number of bytes received in the current download
+ */
+static u32 fastboot_bytes_received;
+
+/**
+ * fastboot_bytes_expected - number of bytes expected in the current download
+ */
+static u32 fastboot_bytes_expected;
+
+static void okay(char *, char *);
+static void getvar(char *, char *);
+static void download(char *, char *);
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+static void flash(char *, char *);
+static void erase(char *, char *);
+#endif
+static void reboot_bootloader(char *, char *);
+
+static const struct {
+ const char *command;
+ void (*dispatch)(char *cmd_parameter, char *response);
+} commands[FASTBOOT_COMMAND_COUNT] = {
+ [FASTBOOT_COMMAND_GETVAR] = {
+ .command = "getvar",
+ .dispatch = getvar
+ },
+ [FASTBOOT_COMMAND_DOWNLOAD] = {
+ .command = "download",
+ .dispatch = download
+ },
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+ [FASTBOOT_COMMAND_FLASH] = {
+ .command = "flash",
+ .dispatch = flash
+ },
+ [FASTBOOT_COMMAND_ERASE] = {
+ .command = "erase",
+ .dispatch = erase
+ },
+#endif
+ [FASTBOOT_COMMAND_BOOT] = {
+ .command = "boot",
+ .dispatch = okay
+ },
+ [FASTBOOT_COMMAND_CONTINUE] = {
+ .command = "continue",
+ .dispatch = okay
+ },
+ [FASTBOOT_COMMAND_REBOOT] = {
+ .command = "reboot",
+ .dispatch = okay
+ },
+ [FASTBOOT_COMMAND_REBOOT_BOOTLOADER] = {
+ .command = "reboot-bootloader",
+ .dispatch = reboot_bootloader
+ },
+ [FASTBOOT_COMMAND_SET_ACTIVE] = {
+ .command = "set_active",
+ .dispatch = okay
+ },
+};
+
+/**
+ * fastboot_handle_command - Handle fastboot command
+ *
+ * @cmd_string: Pointer to command string
+ * @response: Pointer to fastboot response buffer
+ *
+ * Return: Executed command, or -1 if not recognized
+ */
+int fastboot_handle_command(char *cmd_string, char *response)
+{
+ int i;
+ char *cmd_parameter;
+
+ cmd_parameter = cmd_string;
+ strsep(&cmd_parameter, ":");
+
+ for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
+ if (!strcmp(commands[i].command, cmd_string)) {
+ if (commands[i].dispatch) {
+ commands[i].dispatch(cmd_parameter,
+ response);
+ return i;
+ } else {
+ break;
+ }
+ }
+ }
+
+ pr_err("command %s not recognized.\n", cmd_string);
+ fastboot_fail("unrecognized command", response);
+ return -1;
+}
+
+/**
+ * okay() - Send bare OKAY response
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ *
+ * Send a bare OKAY fastboot response. This is used where the command is
+ * valid, but all the work is done after the response has been sent (e.g.
+ * boot, reboot etc.)
+ */
+static void okay(char *cmd_parameter, char *response)
+{
+ fastboot_okay(NULL, response);
+}
+
+/**
+ * getvar() - Read a config/version variable
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void getvar(char *cmd_parameter, char *response)
+{
+ fastboot_getvar(cmd_parameter, response);
+}
+
+/**
+ * fastboot_download() - Start a download transfer from the client
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void download(char *cmd_parameter, char *response)
+{
+ char *tmp;
+
+ if (!cmd_parameter) {
+ fastboot_fail("Expected command parameter", response);
+ return;
+ }
+ fastboot_bytes_received = 0;
+ fastboot_bytes_expected = simple_strtoul(cmd_parameter, &tmp, 16);
+ if (fastboot_bytes_expected == 0) {
+ fastboot_fail("Expected nonzero image size", response);
+ return;
+ }
+ /*
+ * Nothing to download yet. Response is of the form:
+ * [DATA|FAIL]$cmd_parameter
+ *
+ * where cmd_parameter is an 8 digit hexadecimal number
+ */
+ if (fastboot_bytes_expected > fastboot_buf_size) {
+ fastboot_fail(cmd_parameter, response);
+ } else {
+ printf("Starting download of %d bytes\n",
+ fastboot_bytes_expected);
+ fastboot_response("DATA", response, "%s", cmd_parameter);
+ }
+}
+
+/**
+ * fastboot_data_remaining() - return bytes remaining in current transfer
+ *
+ * Return: Number of bytes left in the current download
+ */
+u32 fastboot_data_remaining(void)
+{
+ return fastboot_bytes_expected - fastboot_bytes_received;
+}
+
+/**
+ * fastboot_data_download() - Copy image data to fastboot_buf_addr.
+ *
+ * @fastboot_data: Pointer to received fastboot data
+ * @fastboot_data_len: Length of received fastboot data
+ * @response: Pointer to fastboot response buffer
+ *
+ * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
+ * response. fastboot_bytes_received is updated to indicate the number
+ * of bytes that have been transferred.
+ *
+ * On completion sets image_size and ${filesize} to the total size of the
+ * downloaded image.
+ */
+void fastboot_data_download(const void *fastboot_data,
+ unsigned int fastboot_data_len,
+ char *response)
+{
+#define BYTES_PER_DOT 0x20000
+ u32 pre_dot_num, now_dot_num;
+
+ if (fastboot_data_len == 0 ||
+ (fastboot_bytes_received + fastboot_data_len) >
+ fastboot_bytes_expected) {
+ fastboot_fail("Received invalid data length",
+ response);
+ return;
+ }
+ /* Download data to fastboot_buf_addr */
+ memcpy(fastboot_buf_addr + fastboot_bytes_received,
+ fastboot_data, fastboot_data_len);
+
+ pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
+ fastboot_bytes_received += fastboot_data_len;
+ now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
+
+ if (pre_dot_num != now_dot_num) {
+ putc('.');
+ if (!(now_dot_num % 74))
+ putc('\n');
+ }
+ *response = '\0';
+}
+
+/**
+ * fastboot_data_complete() - Mark current transfer complete
+ *
+ * @response: Pointer to fastboot response buffer
+ *
+ * Set image_size and ${filesize} to the total size of the downloaded image.
+ */
+void fastboot_data_complete(char *response)
+{
+ /* Download complete. Respond with "OKAY" */
+ fastboot_okay(NULL, response);
+ printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
+ image_size = fastboot_bytes_received;
+ env_set_hex("filesize", image_size);
+ fastboot_bytes_expected = 0;
+ fastboot_bytes_received = 0;
+}
+
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+/**
+ * flash() - write the downloaded image to the indicated partition.
+ *
+ * @cmd_parameter: Pointer to partition name
+ * @response: Pointer to fastboot response buffer
+ *
+ * Writes the previously downloaded image to the partition indicated by
+ * cmd_parameter. Writes to response.
+ */
+static void flash(char *cmd_parameter, char *response)
+{
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+ fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
+ response);
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
+ fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
+ response);
+#endif
+}
+
+/**
+ * erase() - erase the indicated partition.
+ *
+ * @cmd_parameter: Pointer to partition name
+ * @response: Pointer to fastboot response buffer
+ *
+ * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
+ * to response.
+ */
+static void erase(char *cmd_parameter, char *response)
+{
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+ fastboot_mmc_erase(cmd_parameter, response);
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
+ fastboot_nand_erase(cmd_parameter, response);
+#endif
+}
+#endif
+
+/**
+ * reboot_bootloader() - Sets reboot bootloader flag.
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void reboot_bootloader(char *cmd_parameter, char *response)
+{
+ if (fastboot_set_reboot_flag())
+ fastboot_fail("Cannot set reboot flag", response);
+ else
+ fastboot_okay(NULL, response);
+}
diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c
index 79e080ac87..c6e06aab7a 100644
--- a/drivers/fastboot/fb_common.c
+++ b/drivers/fastboot/fb_common.c
@@ -12,6 +12,22 @@
#include <common.h>
#include <fastboot.h>
+#include <net/fastboot.h>
+
+/**
+ * fastboot_buf_addr - base address of the fastboot download buffer
+ */
+void *fastboot_buf_addr;
+
+/**
+ * fastboot_buf_size - size of the fastboot download buffer
+ */
+u32 fastboot_buf_size;
+
+/**
+ * fastboot_progress_callback - callback executed during long operations
+ */
+void (*fastboot_progress_callback)(const char *msg);
/**
* fastboot_response() - Writes a response of the form "$tag$reason".
@@ -74,3 +90,80 @@ int __weak fastboot_set_reboot_flag(void)
{
return -ENOSYS;
}
+
+/**
+ * fastboot_get_progress_callback() - Return progress callback
+ *
+ * Return: Pointer to function called during long operations
+ */
+void (*fastboot_get_progress_callback(void))(const char *)
+{
+ return fastboot_progress_callback;
+}
+
+/**
+ * fastboot_boot() - Execute fastboot boot command
+ *
+ * If ${fastboot_bootcmd} is set, run that command to execute the boot
+ * process, if that returns, then exit the fastboot server and return
+ * control to the caller.
+ *
+ * Otherwise execute "bootm <fastboot_buf_addr>", if that fails, reset
+ * the board.
+ */
+void fastboot_boot(void)
+{
+ char *s;
+
+ s = env_get("fastboot_bootcmd");
+ if (s) {
+ run_command(s, CMD_FLAG_ENV);
+ } else {
+ static char boot_addr_start[12];
+ static char *const bootm_args[] = {
+ "bootm", boot_addr_start, NULL
+ };
+
+ snprintf(boot_addr_start, sizeof(boot_addr_start) - 1,
+ "0x%p", fastboot_buf_addr);
+ printf("Booting kernel at %s...\n\n\n", boot_addr_start);
+
+ do_bootm(NULL, 0, 2, bootm_args);
+
+ /*
+ * This only happens if image is somehow faulty so we start
+ * over. We deliberately leave this policy to the invocation
+ * of fastbootcmd if that's what's being run
+ */
+ do_reset(NULL, 0, 0, NULL);
+ }
+}
+
+/**
+ * fastboot_set_progress_callback() - set progress callback
+ *
+ * @progress: Pointer to progress callback
+ *
+ * Set a callback which is invoked periodically during long running operations
+ * (flash and erase). This can be used (for example) by the UDP transport to
+ * send INFO responses to keep the client alive whilst those commands are
+ * executing.
+ */
+void fastboot_set_progress_callback(void (*progress)(const char *msg))
+{
+ fastboot_progress_callback = progress;
+}
+
+/*
+ * fastboot_init() - initialise new fastboot protocol session
+ *
+ * @buf_addr: Pointer to download buffer, or NULL for default
+ * @buf_size: Size of download buffer, or zero for default
+ */
+void fastboot_init(void *buf_addr, u32 buf_size)
+{
+ fastboot_buf_addr = buf_addr ? buf_addr :
+ (void *)CONFIG_FASTBOOT_BUF_ADDR;
+ fastboot_buf_size = buf_size ? buf_size : CONFIG_FASTBOOT_BUF_SIZE;
+ fastboot_set_progress_callback(NULL);
+}
diff --git a/drivers/fastboot/fb_getvar.c b/drivers/fastboot/fb_getvar.c
new file mode 100644
index 0000000000..4d264c985d
--- /dev/null
+++ b/drivers/fastboot/fb_getvar.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include <common.h>
+#include <fastboot.h>
+#include <fastboot-internal.h>
+#include <fb_mmc.h>
+#include <fb_nand.h>
+#include <fs.h>
+#include <version.h>
+
+static void getvar_version(char *var_parameter, char *response);
+static void getvar_bootloader_version(char *var_parameter, char *response);
+static void getvar_downloadsize(char *var_parameter, char *response);
+static void getvar_serialno(char *var_parameter, char *response);
+static void getvar_version_baseband(char *var_parameter, char *response);
+static void getvar_product(char *var_parameter, char *response);
+static void getvar_current_slot(char *var_parameter, char *response);
+static void getvar_slot_suffixes(char *var_parameter, char *response);
+static void getvar_has_slot(char *var_parameter, char *response);
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+static void getvar_partition_type(char *part_name, char *response);
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+static void getvar_partition_size(char *part_name, char *response);
+#endif
+
+static const struct {
+ const char *variable;
+ void (*dispatch)(char *var_parameter, char *response);
+} getvar_dispatch[] = {
+ {
+ .variable = "version",
+ .dispatch = getvar_version
+ }, {
+ .variable = "bootloader-version",
+ .dispatch = getvar_bootloader_version
+ }, {
+ .variable = "version-bootloader",
+ .dispatch = getvar_bootloader_version
+ }, {
+ .variable = "downloadsize",
+ .dispatch = getvar_downloadsize
+ }, {
+ .variable = "max-download-size",
+ .dispatch = getvar_downloadsize
+ }, {
+ .variable = "serialno",
+ .dispatch = getvar_serialno
+ }, {
+ .variable = "version-baseband",
+ .dispatch = getvar_version_baseband
+ }, {
+ .variable = "product",
+ .dispatch = getvar_product
+ }, {
+ .variable = "current-slot",
+ .dispatch = getvar_current_slot
+ }, {
+ .variable = "slot-suffixes",
+ .dispatch = getvar_slot_suffixes
+ }, {
+ .variable = "has_slot",
+ .dispatch = getvar_has_slot
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+ }, {
+ .variable = "partition-type",
+ .dispatch = getvar_partition_type
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+ }, {
+ .variable = "partition-size",
+ .dispatch = getvar_partition_size
+#endif
+ }
+};
+
+static void getvar_version(char *var_parameter, char *response)
+{
+ fastboot_okay(FASTBOOT_VERSION, response);
+}
+
+static void getvar_bootloader_version(char *var_parameter, char *response)
+{
+ fastboot_okay(U_BOOT_VERSION, response);
+}
+
+static void getvar_downloadsize(char *var_parameter, char *response)
+{
+ fastboot_response("OKAY", response, "0x%08x", fastboot_buf_size);
+}
+
+static void getvar_serialno(char *var_parameter, char *response)
+{
+ const char *tmp = env_get("serial#");
+
+ if (tmp)
+ fastboot_okay(tmp, response);
+ else
+ fastboot_fail("Value not set", response);
+}
+
+static void getvar_version_baseband(char *var_parameter, char *response)
+{
+ fastboot_okay("N/A", response);
+}
+
+static void getvar_product(char *var_parameter, char *response)
+{
+ const char *board = env_get("board");
+
+ if (board)
+ fastboot_okay(board, response);
+ else
+ fastboot_fail("Board not set", response);
+}
+
+static void getvar_current_slot(char *var_parameter, char *response)
+{
+ /* A/B not implemented, for now always return _a */
+ fastboot_okay("_a", response);
+}
+
+static void getvar_slot_suffixes(char *var_parameter, char *response)
+{
+ fastboot_okay("_a,_b", response);
+}
+
+static void getvar_has_slot(char *part_name, char *response)
+{
+ if (part_name && (!strcmp(part_name, "boot") ||
+ !strcmp(part_name, "system")))
+ fastboot_okay("yes", response);
+ else
+ fastboot_okay("no", response);
+}
+
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+static void getvar_partition_type(char *part_name, char *response)
+{
+ int r;
+ struct blk_desc *dev_desc;
+ disk_partition_t part_info;
+
+ r = fastboot_mmc_get_part_info(part_name, &dev_desc, &part_info,
+ response);
+ if (r >= 0) {
+ r = fs_set_blk_dev_with_part(dev_desc, r);
+ if (r < 0)
+ fastboot_fail("failed to set partition", response);
+ else
+ fastboot_okay(fs_get_type_name(), response);
+ }
+}
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+static void getvar_partition_size(char *part_name, char *response)
+{
+ int r;
+ size_t size;
+
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+ struct blk_desc *dev_desc;
+ disk_partition_t part_info;
+
+ r = fastboot_mmc_get_part_info(part_name, &dev_desc, &part_info,
+ response);
+ if (r >= 0)
+ size = part_info.size;
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
+ struct part_info *part_info;
+
+ r = fastboot_nand_get_part_info(part_name, &part_info, response);
+ if (r >= 0)
+ size = part_info->size;
+#endif
+ if (r >= 0)
+ fastboot_response("OKAY", response, "0x%016zx", size);
+}
+#endif
+
+/**
+ * fastboot_getvar() - Writes variable indicated by cmd_parameter to response.
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ *
+ * Look up cmd_parameter first as an environment variable of the form
+ * fastboot.<cmd_parameter>, if that exists return use its value to set
+ * response.
+ *
+ * Otherwise lookup the name of variable and execute the appropriate
+ * function to return the requested value.
+ */
+void fastboot_getvar(char *cmd_parameter, char *response)
+{
+ if (!cmd_parameter) {
+ fastboot_fail("missing var", response);
+ } else {
+#define FASTBOOT_ENV_PREFIX "fastboot."
+ int i;
+ char *var_parameter = cmd_parameter;
+ char envstr[FASTBOOT_RESPONSE_LEN];
+ const char *s;
+
+ snprintf(envstr, sizeof(envstr) - 1,
+ FASTBOOT_ENV_PREFIX "%s", cmd_parameter);
+ s = env_get(envstr);
+ if (s) {
+ fastboot_response("OKAY", response, "%s", s);
+ return;
+ }
+
+ strsep(&var_parameter, ":");
+ for (i = 0; i < ARRAY_SIZE(getvar_dispatch); ++i) {
+ if (!strcmp(getvar_dispatch[i].variable,
+ cmd_parameter)) {
+ getvar_dispatch[i].dispatch(var_parameter,
+ response);
+ return;
+ }
+ }
+ pr_warn("WARNING: unknown variable: %s\n", cmd_parameter);
+ fastboot_fail("Variable not implemented", response);
+ }
+}
diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c
index 47fcf74b69..4c1c7fd2cd 100644
--- a/drivers/fastboot/fb_mmc.c
+++ b/drivers/fastboot/fb_mmc.c
@@ -7,6 +7,7 @@
#include <common.h>
#include <blk.h>
#include <fastboot.h>
+#include <fastboot-internal.h>
#include <fb_mmc.h>
#include <image-sparse.h>
#include <part.h>
@@ -15,6 +16,8 @@
#include <linux/compat.h>
#include <android_image.h>
+#define FASTBOOT_MAX_BLK_WRITE 16384
+
#define BOOT_PARTITION_NAME "boot"
struct fb_mmc_sparse {
@@ -43,13 +46,48 @@ static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc,
return ret;
}
+/**
+ * fb_mmc_blk_write() - Write/erase MMC in chunks of FASTBOOT_MAX_BLK_WRITE
+ *
+ * @block_dev: Pointer to block device
+ * @start: First block to write/erase
+ * @blkcnt: Count of blocks
+ * @buffer: Pointer to data buffer for write or NULL for erase
+ */
+static lbaint_t fb_mmc_blk_write(struct blk_desc *block_dev, lbaint_t start,
+ lbaint_t blkcnt, const void *buffer)
+{
+ lbaint_t blk = start;
+ lbaint_t blks_written;
+ lbaint_t cur_blkcnt;
+ lbaint_t blks = 0;
+ int i;
+
+ for (i = 0; i < blkcnt; i += FASTBOOT_MAX_BLK_WRITE) {
+ cur_blkcnt = min((int)blkcnt - i, FASTBOOT_MAX_BLK_WRITE);
+ if (buffer) {
+ if (fastboot_progress_callback)
+ fastboot_progress_callback("writing");
+ blks_written = blk_dwrite(block_dev, blk, cur_blkcnt,
+ buffer + (i * block_dev->blksz));
+ } else {
+ if (fastboot_progress_callback)
+ fastboot_progress_callback("erasing");
+ blks_written = blk_derase(block_dev, blk, cur_blkcnt);
+ }
+ blk += blks_written;
+ blks += blks_written;
+ }
+ return blks;
+}
+
static lbaint_t fb_mmc_sparse_write(struct sparse_storage *info,
lbaint_t blk, lbaint_t blkcnt, const void *buffer)
{
struct fb_mmc_sparse *sparse = info->priv;
struct blk_desc *dev_desc = sparse->dev_desc;
- return blk_dwrite(dev_desc, blk, blkcnt, buffer);
+ return fb_mmc_blk_write(dev_desc, blk, blkcnt, buffer);
}
static lbaint_t fb_mmc_sparse_reserve(struct sparse_storage *info,
@@ -60,7 +98,7 @@ static lbaint_t fb_mmc_sparse_reserve(struct sparse_storage *info,
static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info,
const char *part_name, void *buffer,
- unsigned int download_bytes, char *response)
+ u32 download_bytes, char *response)
{
lbaint_t blkcnt;
lbaint_t blks;
@@ -77,7 +115,8 @@ static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info,
puts("Flashing Raw Image\n");
- blks = blk_dwrite(dev_desc, info->start, blkcnt, buffer);
+ blks = fb_mmc_blk_write(dev_desc, info->start, blkcnt, buffer);
+
if (blks != blkcnt) {
pr_err("failed writing to device %d\n", dev_desc->devnum);
fastboot_fail("failed writing to device", response);
@@ -148,7 +187,7 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc,
*/
static int fb_mmc_update_zimage(struct blk_desc *dev_desc,
void *download_buffer,
- unsigned int download_bytes,
+ u32 download_bytes,
char *response)
{
uintptr_t hdr_addr; /* boot image header address */
@@ -252,6 +291,38 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc,
#endif
/**
+ * fastboot_mmc_get_part_info() - Lookup eMMC partion by name
+ *
+ * @part_name: Named partition to lookup
+ * @dev_desc: Pointer to returned blk_desc pointer
+ * @part_info: Pointer to returned disk_partition_t
+ * @response: Pointer to fastboot response buffer
+ */
+int fastboot_mmc_get_part_info(char *part_name, struct blk_desc **dev_desc,
+ disk_partition_t *part_info, char *response)
+{
+ int r;
+
+ *dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
+ if (!*dev_desc) {
+ fastboot_fail("block device not found", response);
+ return -ENOENT;
+ }
+ if (!part_name) {
+ fastboot_fail("partition not found", response);
+ return -ENOENT;
+ }
+
+ r = part_get_info_by_name_or_alias(*dev_desc, part_name, part_info);
+ if (r < 0) {
+ fastboot_fail("partition not found", response);
+ return r;
+ }
+
+ return r;
+}
+
+/**
* fastboot_mmc_flash_write() - Write image to eMMC for fastboot
*
* @cmd: Named partition to write image to
@@ -260,7 +331,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc,
* @response: Pointer to fastboot response buffer
*/
void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
- unsigned int download_bytes, char *response)
+ u32 download_bytes, char *response)
{
struct blk_desc *dev_desc;
disk_partition_t info;
@@ -403,7 +474,8 @@ void fastboot_mmc_erase(const char *cmd, char *response)
printf("Erasing blocks " LBAFU " to " LBAFU " due to alignment\n",
blks_start, blks_start + blks_size);
- blks = blk_derase(dev_desc, blks_start, blks_size);
+ blks = fb_mmc_blk_write(dev_desc, blks_start, blks_size, NULL);
+
if (blks != blks_size) {
pr_err("failed erasing from device %d\n", dev_desc->devnum);
fastboot_fail("failed erasing from device", response);
diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c
index 535f541eb8..526bc12307 100644
--- a/drivers/fastboot/fb_nand.c
+++ b/drivers/fastboot/fb_nand.c
@@ -88,7 +88,7 @@ static int _fb_nand_erase(struct mtd_info *mtd, struct part_info *part)
}
static int _fb_nand_write(struct mtd_info *mtd, struct part_info *part,
- void *buffer, unsigned int offset,
+ void *buffer, u32 offset,
size_t length, size_t *written)
{
int flags = WITH_WR_VERIFY;
@@ -146,6 +146,21 @@ static lbaint_t fb_nand_sparse_reserve(struct sparse_storage *info,
}
/**
+ * fastboot_nand_get_part_info() - Lookup NAND partion by name
+ *
+ * @part_name: Named device to lookup
+ * @part_info: Pointer to returned part_info pointer
+ * @response: Pointer to fastboot response buffer
+ */
+int fastboot_nand_get_part_info(char *part_name, struct part_info **part_info,
+ char *response)
+{
+ struct mtd_info *mtd = NULL;
+
+ return fb_nand_lookup(part_name, &mtd, part_info, response);
+}
+
+/**
* fastboot_nand_flash_write() - Write image to NAND for fastboot
*
* @cmd: Named device to write image to
@@ -154,7 +169,7 @@ static lbaint_t fb_nand_sparse_reserve(struct sparse_storage *info,
* @response: Pointer to fastboot response buffer
*/
void fastboot_nand_flash_write(const char *cmd, void *download_buffer,
- unsigned int download_bytes, char *response)
+ u32 download_bytes, char *response)
{
struct part_info *part;
struct mtd_info *mtd = NULL;