[U-Boot] [PATCH 2/2 v2] fastboot: Flash command support
Steve Rae
srae at broadcom.com
Mon Aug 11 21:52:11 CEST 2014
On 14-08-10 06:59 PM, Dileep Katta wrote:
> Flash command internally uses DFU, and Fastboot command initialization is modified to add DFU and partition initialization
> Added oem format functionality for GPT table creation
> partitioning code is added as disk/part_fastboot.c for better usability
>
> Fastboot flash command code is enabled and being tested on BeagleBone Black.
> OMAP3 Beagle configuration is modified to fix the build errors, but this configuration needs to be updated as per the flash functionality.
>
> Signed-off-by: Dileep Katta <dileep.katta at linaro.org>
> ---
> Changes for v2:
> - Fixed coding style issues
>
> common/cmd_fastboot.c | 5 +
> common/cmd_mmc.c | 2 +-
> common/cmd_nvedit.c | 2 +-
> disk/Makefile | 1 +
> disk/part_fastboot.c | 379 ++++++++++++++++++++++++++++++++++++++++
> doc/README.android-fastboot | 26 +++
> drivers/usb/gadget/f_fastboot.c | 178 ++++++++++++++++++-
> include/configs/am335x_evm.h | 23 ++-
> include/configs/omap3_beagle.h | 12 ++
> include/usb/fastboot.h | 182 +++++++++++++++++++
> 10 files changed, 796 insertions(+), 14 deletions(-)
> create mode 100644 disk/part_fastboot.c
> create mode 100644 include/usb/fastboot.h
>
> diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
> index 83fa7bd..6d0d0a4 100644
> --- a/common/cmd_fastboot.c
> +++ b/common/cmd_fastboot.c
> @@ -10,11 +10,15 @@
> #include <common.h>
> #include <command.h>
> #include <g_dnl.h>
> +#include <dfu.h>
> +#include <usb/fastboot.h>
>
> static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
> {
> int ret;
>
> + board_partition_init();
> + dfu_init_env_entities("mmc", CONFIG_FB_MMCDEV);
> ret = g_dnl_register("usb_dnl_fastboot");
> if (ret)
> return ret;
> @@ -26,6 +30,7 @@ static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
> }
>
> g_dnl_unregister();
> + dfu_free_entities();
> return CMD_RET_SUCCESS;
> }
>
> diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c
> index 1e40983..dd7170d 100644
> --- a/common/cmd_mmc.c
> +++ b/common/cmd_mmc.c
> @@ -612,7 +612,7 @@ static cmd_tbl_t cmd_mmc[] = {
> U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""),
> };
>
> -static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> {
> cmd_tbl_t *cp;
>
> diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
> index 855808c..a100109 100644
> --- a/common/cmd_nvedit.c
> +++ b/common/cmd_nvedit.c
> @@ -686,7 +686,7 @@ ulong getenv_ulong(const char *name, int base, ulong default_val)
>
> #ifndef CONFIG_SPL_BUILD
> #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
> -static int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc,
> +int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc,
> char * const argv[])
> {
> printf("Saving Environment to %s...\n", env_name_spec);
> diff --git a/disk/Makefile b/disk/Makefile
> index 6970cec..4b7a9ef 100644
> --- a/disk/Makefile
> +++ b/disk/Makefile
> @@ -13,3 +13,4 @@ obj-$(CONFIG_DOS_PARTITION) += part_dos.o
> obj-$(CONFIG_ISO_PARTITION) += part_iso.o
> obj-$(CONFIG_AMIGA_PARTITION) += part_amiga.o
> obj-$(CONFIG_EFI_PARTITION) += part_efi.o
> +obj-$(CONFIG_CMD_FASTBOOT) += part_fastboot.o
> diff --git a/disk/part_fastboot.c b/disk/part_fastboot.c
> new file mode 100644
> index 0000000..4fa9f85
> --- /dev/null
> +++ b/disk/part_fastboot.c
> @@ -0,0 +1,379 @@
> +/*
> + * Copyright (C) 2013 Texas Instruments
> + *
> + * Author : Pankaj Bharadiya <pankaj.bharadiya at ti.com>
> + *
> + * Tom Rix <Tom.Rix at windriver.com> and Sitara 2011 u-boot by
> + * Mohammed Afzal M A <afzal at ti.com>
> + *
> + * Copyright (C) 2008 The Android Open Source Project
> + * All rights reserved.
> + *
> + * Copyright 2014 Linaro, Ltd.
> + * Dileep Katta <dileep.katta at linaro.org>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <usb/fastboot.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +#include <environment.h>
> +#include <mmc.h>
> +#include <dfu.h>
> +
> +#define EFI_VERSION 0x00010000
> +#define EFI_ENTRIES 128
> +#define EFI_NAMELEN 36
> +
> +struct partition_emmc {
> + const char *name;
> + unsigned size_kb;
> +};
> +
> +/* eMMC partition layout (All sizes are in kB)
> + * Modify the below partition table to change the GPT configuration.
> + * The entry for each partition can be modified as per the requirement.
> + */
> +static struct partition_emmc partitions[] = {
> + { "-", 128 }, /* Master Boot Record and GUID Partition Table */
> + { "spl", 128 }, /* First stage bootloader */
> + { "bootloader", 512 }, /* Second stage bootloader */
> + { "misc", 128 }, /* Rserved for internal purpose */
> + { "-", 128 }, /* Reserved */
> + { "recovery", 8*1024 }, /* Recovery partition */
> + { "boot", 8*1024 }, /* Partition contains kernel + ramdisk images */
> + { "system", 256*1024 }, /* Android file system */
> + { "cache", 256*1024 }, /* Store Application Cache */
> + { "userdata", 256*1024 }, /* User data */
> + { "media", 0 }, /* Media files */
> + { 0, 0 },
This hard-coded partition does not work for our boards -- what is your
plan for supporting partition tables?
[ have you considered allowing the host to format, download and flash
the partition table? (that is what we are doing...) ]
> +};
> +
> +
> +static const u8 partition_type[16] = {
> + 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
> + 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7,
> +};
> +
> +static const u8 random_uuid[16] = {
> + 0xff, 0x1f, 0xf2, 0xf9, 0xd4, 0xa8, 0x0e, 0x5f,
> + 0x97, 0x46, 0x59, 0x48, 0x69, 0xae, 0xc3, 0x4e,
> +};
> +
> +struct efi_entry {
> + u8 type_uuid[16];
> + u8 uniq_uuid[16];
> + u64 first_lba;
> + u64 last_lba;
> + u64 attr;
> + u16 name[EFI_NAMELEN];
> +};
> +
> +struct efi_header {
> + u8 magic[8];
> +
> + u32 version;
> + u32 header_sz;
> +
> + u32 crc32;
> + u32 reserved;
> +
> + u64 header_lba;
> + u64 backup_lba;
> + u64 first_lba;
> + u64 last_lba;
> +
> + u8 volume_uuid[16];
> +
> + u64 entries_lba;
> +
> + u32 entries_count;
> + u32 entries_size;
> + u32 entries_crc32;
> +} __packed;
> +
> +struct ptable {
> + u8 mbr[512];
> + union {
> + struct efi_header header;
> + u8 block[512];
> + };
> + struct efi_entry entry[EFI_ENTRIES];
> +};
> +
> +static void init_mbr(u8 *mbr, u32 blocks)
> +{
> + mbr[0x1be] = 0x00; /* nonbootable */
> + mbr[0x1bf] = 0xFF; /* bogus CHS */
> + mbr[0x1c0] = 0xFF;
> + mbr[0x1c1] = 0xFF;
> +
> + mbr[0x1c2] = 0xEE; /* GPT partition */
> + mbr[0x1c3] = 0xFF; /* bogus CHS */
> + mbr[0x1c4] = 0xFF;
> + mbr[0x1c5] = 0xFF;
> +
> + mbr[0x1c6] = 0x01; /* start */
> + mbr[0x1c7] = 0x00;
> + mbr[0x1c8] = 0x00;
> + mbr[0x1c9] = 0x00;
> +
> + memcpy(mbr + 0x1ca, &blocks, sizeof(u32));
> +
> + mbr[0x1fe] = 0x55;
> + mbr[0x1ff] = 0xaa;
> +}
> +
> +
> +static void start_ptbl(struct ptable *ptbl, unsigned blocks)
> +{
> + struct efi_header *hdr = &ptbl->header;
> +
> + memset(ptbl, 0, sizeof(*ptbl));
> +
> + init_mbr(ptbl->mbr, blocks - 1);
> +
> + memcpy(hdr->magic, "EFI PART", 8);
> + hdr->version = EFI_VERSION;
> + hdr->header_sz = sizeof(struct efi_header);
> + hdr->header_lba = 1;
> + hdr->backup_lba = blocks - 1;
> + hdr->first_lba = 34;
> + hdr->last_lba = blocks - 1;
> + memcpy(hdr->volume_uuid, random_uuid, 16);
> + hdr->entries_lba = 2;
> + hdr->entries_count = EFI_ENTRIES;
> + hdr->entries_size = sizeof(struct efi_entry);
> +}
> +
> +static void end_ptbl(struct ptable *ptbl)
> +{
> + struct efi_header *hdr = &ptbl->header;
> + u32 n;
> +
> + n = crc32(0, 0, 0);
> + n = crc32(n, (void *)ptbl->entry, sizeof(ptbl->entry));
> + hdr->entries_crc32 = n;
> +
> + n = crc32(0, 0, 0);
> + n = crc32(0, (void *)&ptbl->header, sizeof(ptbl->header));
> + hdr->crc32 = n;
> +}
> +
> +int add_ptn(struct ptable *ptbl, u64 first, u64 last, const char *name)
> +{
> + struct efi_header *hdr = &ptbl->header;
> + struct efi_entry *entry = ptbl->entry;
> + unsigned n;
> +
> + if (first < 34) {
> + printf("partition '%s' overlaps partition table\n", name);
> + return -1;
> + }
> +
> + if (last > hdr->last_lba) {
> + printf("partition '%s' does not fit\n", name);
> + return -1;
> + }
> + for (n = 0; n < EFI_ENTRIES; n++, entry++) {
> + if (entry->last_lba)
> + continue;
> + memcpy(entry->type_uuid, partition_type, 16);
> + memcpy(entry->uniq_uuid, random_uuid, 16);
> + entry->uniq_uuid[0] = n;
> + entry->first_lba = first;
> + entry->last_lba = last;
> + for (n = 0; (n < EFI_NAMELEN) && *name; n++)
> + entry->name[n] = *name++;
> + return 0;
> + }
> + printf("out of partition table entries\n");
> + return -1;
> +}
> +
> +void import_efi_partition(struct efi_entry *entry)
> +{
> + struct fastboot_ptentry e;
> + int n;
> + if (memcmp(entry->type_uuid, partition_type, sizeof(partition_type)))
> + return;
> + for (n = 0; n < (sizeof(e.name)-1); n++)
> + e.name[n] = entry->name[n];
> + e.name[n] = 0;
> + e.start = entry->first_lba;
> + e.length = (entry->last_lba - entry->first_lba + 1) * 512;
> + e.flags = 0;
> +
> + if (!strcmp(e.name, "environment"))
> + e.flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_ENV;
> + fastboot_flash_add_ptn(&e);
> +
> + if (e.length > 0x100000)
> + printf("%8d %7dM %s\n", e.start, e.length/0x100000, e.name);
> + else
> + printf("%8d %7dK %s\n", e.start, e.length/0x400, e.name);
> +}
> +
> +static int load_ptbl(void)
> +{
> + static unsigned char data[512];
> + static struct efi_entry entry[4];
> + int n, m;
> + char source[32], dest[32], length[32];
> +
> + char *mmc_read[5] = {"mmc", "read", NULL, NULL, NULL};
> +
> + /* read mbr */
> + mmc_read[2] = source;
> + mmc_read[3] = dest;
> + mmc_read[4] = length;
> +
> + sprintf(source, "%p", data);
> + sprintf(dest, "0x%x", 0x1);
> + sprintf(length, "0x%x", 1);
> +
> + if (do_mmcops(NULL, 0, 5, mmc_read)) {
> + printf("Reading boot magic FAILED!\n");
> + return -1;
> + }
REALLY -- building a string and passing to the command interpreter !?!?!
> +
> + if (memcmp(data, "EFI PART", 8)) {
> + printf("efi partition table not found\n");
> + return -1;
> + }
> + for (n = 0; n < (128/4); n++) {
> + /* read partition */
> + source[0] = '\0';
> + dest[0] = '\0';
> + length[0] = '\0';
> + mmc_read[2] = source;
> + mmc_read[3] = dest;
> + mmc_read[4] = length;
> +
> + sprintf(source, "%p", entry);
> + sprintf(dest, "0x%x", 0x1+n);
> + sprintf(length, "0x%x", 1);
> +
> + if (do_mmcops(NULL, 0, 5, mmc_read)) {
> + printf("Reading boot magic FAILED!\n");
> + return -1;
> + }
> + for (m = 0; m < 4; m++)
> + import_efi_partition(entry + m);
> + }
> + return 0;
> +}
> +
> +int board_mmc_fbtptn_init(void)
> +{
> + char *mmc_init[2] = {"mmc", "rescan",};
> + char dev[2];
> + char *mmc_dev[3] = {"mmc", "dev", NULL};
> +
> + mmc_dev[2] = dev;
> + sprintf(dev, "0x%x", CONFIG_FB_MMCDEV);
> +
> + if (do_mmcops(NULL, 0, 3, mmc_dev)) {
> + printf("MMC DEV: %d selection FAILED!\n", CONFIG_FB_MMCDEV);
> + return -1;
> + }
> +
> + if (do_mmcops(NULL, 0, 2, mmc_init)) {
> + printf("FAIL:Init of MMC card\n");
> + return 1;
> + }
> +
> + printf("Loading efi partition table:\n");
> + return load_ptbl();
> +}
> +
> +
> +static struct ptable the_ptable;
> +
> +int do_format(void)
> +{
> + struct ptable *ptbl = &the_ptable;
> + /* unsigned sector_sz; */
> + unsigned blocks;
> + unsigned next;
> + int n;
> +
> + printf("\ndo_format ..!!");
> + /* get mmc info */
> + struct mmc *mmc = find_mmc_device(CONFIG_FB_MMCDEV);
> + if (mmc == 0) {
> + printf("no mmc device at slot %d", CONFIG_FB_MMCDEV);
> + return -1;
> + }
> +
> + mmc->has_init = 0;
> + if (mmc_init(mmc)) {
> + printf("\n mmc init FAILED");
> + return -1;
> + } else{
> + printf("\nmmc capacity is: %llu", mmc->capacity);
> + printf("\nmmc: number of blocks:0x%lx", mmc->block_dev.lba);
> + printf("\nmmc: block size:0x%lx", mmc->block_dev.blksz);
> + }
> +
> + blocks = mmc->block_dev.lba;
> + /* sector_sz = mmc->block_dev.blksz; */
> +
> + start_ptbl(ptbl, blocks);
> + n = 0;
> + next = 0;
> + for (n = 0, next = 0; partitions[n].name; n++) {
> + /* 10/11 : below line change size from KB to no of blocks */
> + unsigned sz = partitions[n].size_kb*2;
> + if (!strcmp(partitions[n].name, "-")) {
> + next += sz;
> + continue;
> + }
> + if (sz == 0)
> + sz = blocks - next;
> + if (add_ptn(ptbl, next, next + sz - 1, partitions[n].name))
> + return -1;
> + next += sz;
> + }
> + end_ptbl(ptbl);
> +
> + fastboot_flash_reset_ptn();
> +
> + /* 10/11:modified as per PSP release support */
> + char *mmc_write[5] = {"mmc", "write", NULL, NULL, NULL};
> + char source[32], dest[32], length[32];
> +
> + char dev[2];
> + char *mmc_dev[3] = {"mmc", "dev", NULL};
> +
> + mmc_dev[2] = dev;
> + sprintf(dev, "0x%x", CONFIG_FB_MMCDEV);
> +
> + if (do_mmcops(NULL, 0, 3, mmc_dev)) {
> + printf("MMC DEV: %d selection FAILED!\n", CONFIG_FB_MMCDEV);
> + return -1;
> + }
> +
> + mmc_write[2] = source;
> + mmc_write[3] = dest;
> + mmc_write[4] = length;
> +
> + sprintf(source, "%p", (void *)ptbl);
> + sprintf(dest, "0x%x", 0x00);
> + sprintf(length, "0x%x", (sizeof(struct ptable)/512)+1);
> +
> + if (do_mmcops(NULL, 0, 5, mmc_write)) {
> + printf("Writing mbr is FAILED!\n");
> + return -1;
> + } else {
> + printf("Writing mbr is DONE!\n");
> + }
> +
> + printf("\nnew partition table:\n");
> + load_ptbl();
> +
> + return 0;
> +}
> diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot
> index f1d128c..5420e5e 100644
> --- a/doc/README.android-fastboot
> +++ b/doc/README.android-fastboot
> @@ -46,6 +46,14 @@ buffer should be as large as possible for a platform. The location of the
> buffer and size are set with CONFIG_USB_FASTBOOT_BUF_ADDR and
> CONFIG_USB_FASTBOOT_BUF_SIZE.
>
> +Fastboot flash command uses DFU and storage(NAND/MMC) specific
> +functionality, and hence related definitions needs to be defined:
> +
> +DFU_ALT_INFO
> +CONFIG_STORAGE_EMMC
> +CONFIG_FB_MMCDEV
> +
> +
> In Action
> =========
> Enter into fastboot by executing the fastboot command in u-boot and you
> @@ -89,3 +97,21 @@ and on the gadget side you should see:
> |OK
> |
> |Starting kernel ...
> +
> +Flash command in action, on the client side:
> +
> +|>fastboot flash bootloader u-boot.img
> +|target reported max download size of 1835008 bytes
> +|sending 'bootloader' (395 KB)...
> +|OKAY [ 0.144s]
> +|writing 'bootloader'...
> +|OKAY [ 0.009s]
> +|finished. total time: 0.153s
> +
> +and on the gadget side you should see:
> +|Starting download of 405019 bytes
> +|...
> +|downloading of 405019 bytes finished
> +|download_bytes: 0x62e1b
> +|Writing 'bootloader'
> +|Writing 'bootloader' DONE!
> diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
> index 7a1acb9..da2117c 100644
> --- a/drivers/usb/gadget/f_fastboot.c
> +++ b/drivers/usb/gadget/f_fastboot.c
> @@ -19,6 +19,9 @@
> #include <linux/compiler.h>
> #include <version.h>
> #include <g_dnl.h>
> +#include <usb/fastboot.h>
> +#include <command.h>
> +#include <dfu.h>
>
> #define FASTBOOT_VERSION "0.4"
>
> @@ -35,6 +38,15 @@
>
> #define EP_BUFFER_SIZE 4096
>
> +static struct fastboot_config *fb_cfg;
> +static char *transfer_buffer = (void *)CONFIG_USB_FASTBOOT_BUF_ADDR;
is this "transfer_buffer" really needed?
> +
> +/* To support the Android-style naming of flash */
> +#define MAX_PTN 16
> +static fastboot_ptentry ptable[MAX_PTN];
> +static unsigned int pcount;
> +/* static int static_pcount = -1; */
> +
> struct f_fastboot {
> struct usb_function usb_function;
>
> @@ -119,6 +131,39 @@ static struct usb_gadget_strings *fastboot_strings[] = {
>
> static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
>
> +void set_fb_config(struct fastboot_config *cfg)
> +{
> + fb_cfg = cfg;
> +}
> +
> +/*
> + * Android style flash utilties */
> +void fastboot_flash_reset_ptn(void)
> +{
> +#ifdef DEBUG
> + printf("fastboot flash reset partition..!!");
> +#endif
> + pcount = 0;
> +}
> +
> +void fastboot_flash_add_ptn(fastboot_ptentry *ptn)
> +{
> + if (pcount < MAX_PTN) {
> + memcpy((ptable + pcount), ptn, sizeof(*ptn));
> + pcount++;
> + }
> +}
> +
> +void fastboot_flash_dump_ptn(void)
> +{
> + unsigned int n;
> + for (n = 0; n < pcount; n++) {
> + fastboot_ptentry *ptn = ptable + n;
> + printf("ptn %d name='%s'", n, ptn->name);
> + printf(" start=%d len=%d\n", ptn->start, ptn->length);
> + }
> +}
> +
> static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
> {
> int status = req->status;
> @@ -308,6 +353,21 @@ static int fastboot_tx_write_str(const char *buffer)
> return fastboot_tx_write(buffer, strlen(buffer));
> }
>
> +fastboot_ptentry *fastboot_flash_find_ptn(const char *name)
> +{
> + unsigned int n;
> +
> + for (n = 0; n < pcount; n++) {
> + /* Make sure a substring is not accepted */
> + if (strlen(name) == strlen(ptable[n].name)) {
> + if (0 == strcmp(ptable[n].name, name))
> + return ptable + n;
> + }
> + }
> + return 0;
> +}
> +
> +
> static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
> {
> do_reset(NULL, 0, 0, NULL);
> @@ -346,7 +406,7 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
> strncat(response, FASTBOOT_VERSION, chars_left);
> } else if (!strcmp_l1("bootloader-version", cmd)) {
> strncat(response, U_BOOT_VERSION, chars_left);
> - } else if (!strcmp_l1("downloadsize", cmd)) {
> + } else if (!strcmp_l1("max-download-size", cmd)) {
why did this change?
> char str_num[12];
>
> sprintf(str_num, "%08x", CONFIG_USB_FASTBOOT_BUF_SIZE);
> @@ -380,6 +440,7 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
> unsigned int transfer_size = download_size - download_bytes;
> const unsigned char *buffer = req->buf;
> unsigned int buffer_size = req->actual;
> + int dnl_complete = 0;
what is the purpose of this flag (and the code-change below) ???
>
> if (req->status != 0) {
> printf("Bad status: %d\n", req->status);
> @@ -389,11 +450,9 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
> if (buffer_size < transfer_size)
> transfer_size = buffer_size;
>
> - memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes,
> - buffer, transfer_size);
> + memcpy((void *)transfer_buffer + download_bytes, buffer, transfer_size);
>
> download_bytes += transfer_size;
> -
> /* Check if transfer is done */
> if (download_bytes >= download_size) {
> /*
> @@ -403,9 +462,7 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
> download_size = 0;
> req->complete = rx_handler_command;
> req->length = EP_BUFFER_SIZE;
> -
> - sprintf(response, "OKAY");
> - fastboot_tx_write_str(response);
> + dnl_complete = 1;
>
> printf("\ndownloading of %d bytes finished\n", download_bytes);
> } else {
> @@ -419,6 +476,11 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
> if (!(download_bytes % (74 * BYTES_PER_DOT)))
> putc('\n');
> }
> +
> + if (dnl_complete) {
> + sprintf(response, "OKAY");
> + fastboot_tx_write_str(response);
> + }
> req->actual = 0;
> usb_ep_queue(ep, req, 0);
> }
> @@ -469,6 +531,37 @@ static void cb_boot(struct usb_ep *ep, struct usb_request *req)
> fastboot_tx_write_str("OKAY");
> }
>
> +static void cb_flash(struct usb_ep *ep, struct usb_request *req)
> +{
> + char *cmdbuf = req->buf;
> + char response[32];
> + char part_name[20] = {0,};
> + strncpy(part_name, cmdbuf + 6, req->actual - 6);
> + handle_flash(part_name, response, transfer_buffer);
> + fastboot_tx_write_str(response);
> +}
> +
> +int fastboot_oem(const char *cmd)
> +{
> + printf("fastboot_oem:%s", cmd);
> + if (!strcmp(cmd, "format"))
> + return do_format();
> + return -1;
> +}
> +
> +static void cb_oem(struct usb_ep *ep, struct usb_request *req)
> +{
> + char *cmd = req->buf;
> +
> + printf("calling fastboot oem!! : %s\n", cmd);
> + int r = fastboot_oem(cmd + 4);
> + if (r < 0) {
> + fastboot_tx_write_str("FAIL");
> + } else {
> + fastboot_tx_write_str("OKAY");
> + }
> +}
> +
> struct cmd_dispatch_info {
> char *cmd;
> void (*cb)(struct usb_ep *ep, struct usb_request *req);
> @@ -487,6 +580,12 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = {
> }, {
> .cmd = "boot",
> .cb = cb_boot,
> + }, {
> + .cmd = "flash",
> + .cb = cb_flash,
> + }, {
> + .cmd = "oem",
> + .cb = cb_oem,
> },
> };
>
> @@ -496,6 +595,8 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
> void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
> int i;
>
> + *(cmdbuf + req->actual) = '\0';
> +
> for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
> if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
> func_cb = cmd_dispatch_info[i].cb;
> @@ -514,3 +615,66 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
> usb_ep_queue(ep, req, 0);
> }
> }
> +
> +static int alt_setting_num;
> +
> +int handle_flash(char *part_name, char *response, char *transfer_buffer)
> +{
> + int status = 0;
> + printf("download_bytes: 0x%x\n", download_bytes);
> + if (download_bytes) {
> + struct fastboot_ptentry *ptn;
> +
> + /* Next is the partition name */
> + ptn = fastboot_flash_find_ptn(part_name);
FYI - disk/part_efi.c provides:
get_partition_info_efi_by_name()
> +
> + if (ptn == 0) {
> + printf("Partition:[%s] does not exist\n", part_name);
> + sprintf(response, "FAILpartition does not exist");
> + } else if ((download_bytes > ptn->length) &&
> + !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
> + printf("Image too large for the partition\n");
> + sprintf(response, "FAILimage too large for partition");
> + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
> + /* Check if this is not really a flash write,
> + * but instead a saveenv
> + */
> + unsigned int i = 0;
> + /* Env file is expected with a NULL delimeter between
> + * env variables So replace New line Feeds(0x0a) with
> + * NULL (0x00)
> + */
> + for (i = 0; i < download_bytes; i++) {
> + if (transfer_buffer[i] == 0x0a)
> + transfer_buffer[i] = 0x00;
> + }
> + memset(env_ptr->data, 0, ENV_SIZE);
> + memcpy(env_ptr->data, transfer_buffer, download_bytes);
> + do_env_save(NULL, 0, 1, NULL);
> + printf("saveenv to '%s' DONE!\n", ptn->name);
> + sprintf(response, "OKAY");
> + } else {
> + /* Normal case */
> + alt_setting_num = dfu_get_alt(part_name);
> + status = dfu_write(dfu_get_entity(alt_setting_num),
> + transfer_buffer, download_bytes, 0);
> + printf("Writing '%s'\n", ptn->name);
> + if (status) {
> + printf("Writing '%s' FAILED!\n", ptn->name);
> + sprintf(response, "FAIL: Write partition");
> + } else {
> + printf("Writing '%s' DONE!\n", ptn->name);
> + sprintf(response, "OKAY");
> + }
> + }
> + } else {
> + sprintf(response, "FAILno image downloaded");
> + }
> + return status;
> +}
> +
> +int board_partition_init(void)
> +{
> + board_mmc_fbtptn_init();
> + return 1;
> +}
> diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h
> index 3999405..2227a88 100644
> --- a/include/configs/am335x_evm.h
> +++ b/include/configs/am335x_evm.h
> @@ -87,6 +87,7 @@
> "uuid_disk=${uuid_gpt_disk};" \
> "name=rootfs,start=2MiB,size=-,uuid=${uuid_gpt_rootfs}\0" \
> "optargs=\0" \
> + "dfu_alt_info=" DFU_ALT_INFO "\0" \
> "mmcdev=0\0" \
> "mmcroot=/dev/mmcblk0p2 ro\0" \
> "mmcrootfstype=ext4 rootwait\0" \
> @@ -303,6 +304,16 @@
> #endif
>
> #ifdef CONFIG_MUSB_GADGET
> +
> +#define CONFIG_FB_MMCDEV 1
> +
> +/*Uncomment this to enable NAND fastboot*/
> +/*#define CONFIG_NAND */
> +
> +/*Uncomment this to support eMMC booting*/
> +#define CONFIG_STORAGE_EMMC
> +
> +
> #define CONFIG_USB_ETHER
> #define CONFIG_USB_ETH_RNDIS
> #define CONFIG_USBNET_HOST_ADDR "de:ad:be:af:00:00"
> @@ -336,14 +347,13 @@
> #define CONFIG_DFU_MMC
> #define CONFIG_CMD_DFU
> #define DFU_ALT_INFO_MMC \
> - "dfu_alt_info_mmc=" \
> "boot part 0 1;" \
> "rootfs part 0 2;" \
> "MLO fat 0 1;" \
> - "MLO.raw mmc 0x100 0x100;" \
> - "u-boot.img.raw mmc 0x300 0x400;" \
> - "spl-os-args.raw mmc 0x80 0x80;" \
> - "spl-os-image.raw mmc 0x900 0x2000;" \
> + "MLO.raw raw 0x100 0x100;" \
> + "u-boot.img.raw raw 0x300 0x400;" \
> + "spl-os-args.raw raw 0x80 0x80;" \
> + "spl-os-image.raw raw 0x900 0x2000;" \
> "spl-os-args fat 0 1;" \
> "spl-os-image fat 0 1;" \
> "u-boot.img fat 0 1;" \
> @@ -374,6 +384,9 @@
> DFU_ALT_INFO_MMC \
> DFU_ALT_INFO_RAM \
> DFU_ALT_INFO_NAND
> +#ifdef CONFIG_DFU_MMC
> +#define DFU_ALT_INFO DFU_ALT_INFO_MMC
> +#endif
> #endif
>
> /*
> diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h
> index 644e97f..84594a0 100644
> --- a/include/configs/omap3_beagle.h
> +++ b/include/configs/omap3_beagle.h
> @@ -77,6 +77,18 @@
> #define CONFIG_USB_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR
> #define CONFIG_USB_FASTBOOT_BUF_SIZE 0x07000000
>
> +#ifdef CONFIG_CMD_FASTBOOT
> +#define CONFIG_FB_MMCDEV 1
> +#define CONFIG_DFU_FUNCTION
> +#define CONFIG_DFU_MMC
> +#define CONFIG_CMD_DFU
> +#define DFU_ALT_INFO_MMC ""
> +#endif
> +
> +#ifdef CONFIG_DFU_MMC
> +#define DFU_ALT_INFO DFU_ALT_INFO_MMC
> +#endif
> +
> /* USB EHCI */
> #define CONFIG_CMD_USB
> #define CONFIG_USB_EHCI
> diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
> new file mode 100644
> index 0000000..a54778e
> --- /dev/null
> +++ b/include/usb/fastboot.h
> @@ -0,0 +1,182 @@
> +/*
> + * (C) Copyright 2008 - 2009
> + * Windriver, <www.windriver.com>
> + * Tom Rix <Tom.Rix at windriver.com>
> + *
> + * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy at linutronix.de>
> + *
> + *
> + * Copyright (C) 2008 The Android Open Source Project
> + * All rights reserved.
> + *
> + * Copyright 2014 Linaro, Ltd.
> + * Dileep Katta <dileep.katta at linaro.org>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#ifndef FASTBOOT_H
> +#define FASTBOOT_H
> +
> +#include <common.h>
> +#include <command.h>
> +#include <environment.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +
> +#ifdef DEBUG
> +#define FBTDBG(fmt, args...)\
> + printf("DEBUG: [%s]: %d:\n"fmt, __func__, __LINE__, ##args)
> +#else
> +#define FBTDBG(fmt, args...) do {} while (0)
> +#endif
> +
> +#ifdef INFO
> +#define FBTINFO(fmt, args...)\
> + printf("INFO: [%s]: "fmt, __func__, ##args)
> +#else
> +#define FBTINFO(fmt, args...) do {} while (0)
> +#endif
> +
> +#ifdef WARN
> +#define FBTWARN(fmt, args...)\
> + printf("WARNING: [%s]: "fmt, __func__, ##args)
> +#else
> +#define FBTWARN(fmt, args...) do {} while (0)
> +#endif
> +
> +#ifdef ERR
> +#define FBTERR(fmt, args...)\
> + printf("ERROR: [%s]: "fmt, __func__, ##args)
> +#else
> +#define FBTERR(fmt, args...) do {} while (0)
> +#endif
> +
> +struct fastboot_config {
> + /*
> + * Transfer buffer for storing data sent by the client. It should be
> + * able to hold a kernel image and flash partitions. Care should be
> + * take so it does not overrun bootloader memory
> + */
> + unsigned char *transfer_buffer;
> +
> + /* Size of the buffer mentioned above */
> + unsigned int transfer_buffer_size;
> +
> + /* Total data to be downloaded */
> + unsigned int download_size;
> +
> + /* Data downloaded so far */
> + unsigned int download_bytes;
> +
> + unsigned int nand_block_size;
> +
> + unsigned int nand_oob_size;
> +
> + unsigned int download_bytes_unpadded;
> +};
> +
> +#define FB_STR_PRODUCT_IDX 1
> +#define FB_STR_SERIAL_IDX 2
> +#define FB_STR_CONFIG_IDX 3
> +#define FB_STR_INTERFACE_IDX 4
> +#define FB_STR_MANUFACTURER_IDX 5
> +#define FB_STR_PROC_REV_IDX 6
> +#define FB_STR_PROC_TYPE_IDX 7
> +
> +#ifdef CONFIG_CMD_FASTBOOT
> +
> +int fastboot_init(void);
> +void fastboot_shutdown(void);
> +int fastboot_poll(void);
> +
> +int fastboot_board_init(struct fastboot_config *interface,
> + struct usb_gadget_strings **str);
> +
> +
> +/* Android-style flash naming */
> +typedef struct fastboot_ptentry fastboot_ptentry;
> +
> +/* flash partitions are defined in terms of blocks
> + ** (flash erase units)
> + */
> +struct fastboot_ptentry {
> + /* The logical name for this partition, null terminated */
> + char name[16];
> + /* The start wrt the nand part, must be multiple of nand block size */
> + unsigned int start;
> + /* The length of the partition, must be multiple of nand block size */
> + unsigned int length;
> + /* Controls the details of how operations are done on the partition
> + See the FASTBOOT_PTENTRY_FLAGS_*'s defined below */
> + unsigned int flags;
> +};
> +
> +/* Lower byte shows if the read/write/erase operation in
> + repeated. The base address is incremented.
> + Either 0 or 1 is ok for a default */
> +
> +#define FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK(n) (n & 0x0f)
> +#define FASTBOOT_PTENTRY_FLAGS_REPEAT_4 0x00000004
> +
> +/* Writes happen a block at a time.
> + If the write fails, go to next block
> + NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK 0x00000010
> +
> +/* Find a contiguous block big enough for a the whole file
> + NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK 0x00000020
> +
> +/* Sets the ECC to software before writing
> + HW and SW ECC should not both be set. */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC 0x00000040
> +
> +/* Sets the ECC to hardware before writing
> + HW and SW ECC should not both be set. */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC 0x00000080
> +
> +/* Sets the ECC to hardware before writing
> + HW and SW ECC should not both be set. */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH4_ECC 0x00000100
> +
> +/* Sets the ECC to hardware before writing
> + HW and SW ECC should not both be set. */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC 0x00000200
> +
> +/* Sets the ECC to hardware before writing
> + HW and SW ECC should not both be set. */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH16_ECC 0x00000400
> +
> +/* Write the file with write.i */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_I 0x00000800
> +
> +/* Write the file with write.jffs2 */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_JFFS2 0x00001000
> +
> +/* Write the file as a series of variable/value pairs
> + using the setenv and saveenv commands */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_ENV 0x00002000
> +
> +
> +/* The Android-style flash handling */
> +
> +/* tools to populate and query the partition table */
> +void fastboot_flash_add_ptn(fastboot_ptentry *ptn);
> +fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
> +fastboot_ptentry *fastboot_flash_get_ptn(unsigned n);
> +unsigned int fastboot_flash_get_ptn_count(void);
> +void fastboot_flash_dump_ptn(void);
> +int fastboot_oem(const char *cmd);
> +int do_format(void);
> +int board_mmc_fbtptn_init(void);
> +void fastboot_flash_reset_ptn(void);
> +int board_partition_init(void);
> +int handle_flash(char *part_name, char *response, char *transfer_buffer);
> +
> +extern int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
> +extern int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
> +extern env_t *env_ptr;
> +
> +#endif
> +#endif
>
My initial comments and questions
Thanks, Steve
More information about the U-Boot
mailing list