[U-Boot] [PATCH 2/2] fastboot: Flash command support

Dileep Katta dileep.katta at linaro.org
Sat Aug 2 20:30:18 CEST 2014


Flash command 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>
---
 common/cmd_fastboot.c           |   6 +
 common/cmd_mmc.c                |   2 +-
 common/cmd_nvedit.c             |   2 +-
 disk/Makefile                   |   1 +
 disk/part_fastboot.c            | 383 ++++++++++++++++++++++++++++++++++++++++
 doc/README.android-fastboot     |  26 +++
 drivers/usb/gadget/f_fastboot.c | 185 ++++++++++++++++++-
 include/configs/am335x_evm.h    |  23 ++-
 include/configs/omap3_beagle.h  |  12 ++
 include/usb/fastboot.h          | 175 ++++++++++++++++++
 10 files changed, 803 insertions(+), 12 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..7c91415 100644
--- a/common/cmd_fastboot.c
+++ b/common/cmd_fastboot.c
@@ -10,11 +10,16 @@
 #include <common.h>
 #include <command.h>
 #include <g_dnl.h>
+extern int board_partition_init(void);
+extern int dfu_init_env_entities(char *interface, int dev);
+extern void dfu_free_entities(void);
 
 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_MMC_FASTBOOT_DEV);
 	ret = g_dnl_register("usb_dnl_fastboot");
 	if (ret)
 		return ret;
@@ -26,6 +31,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..681f3da
--- /dev/null
+++ b/disk/part_fastboot.c
@@ -0,0 +1,383 @@
+/*
+ * 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 },
+};
+
+
+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;
+} __attribute__((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;
+}
+
+extern int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+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;
+	}
+
+	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_MMC_FASTBOOT_DEV);
+
+	if (do_mmcops(NULL, 0, 3, mmc_dev)) {
+		printf("MMC DEV: %d selection FAILED!\n", CONFIG_MMC_FASTBOOT_DEV);
+		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;
+extern void fastboot_flash_reset_ptn(void);
+
+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_MMC_FASTBOOT_DEV);
+	if (mmc == 0) {
+		printf("no mmc device at slot %d", CONFIG_MMC_FASTBOOT_DEV);
+		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_MMC_FASTBOOT_DEV);
+
+	if (do_mmcops(NULL, 0, 3, mmc_dev)) {
+		printf("MMC DEV: %d selection FAILED!\n", CONFIG_MMC_FASTBOOT_DEV);
+		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..e2a330a 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_MMC_FASTBOOT_DEV
+
+
 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..f4b9a62 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -19,6 +19,10 @@
 #include <linux/compiler.h>
 #include <version.h>
 #include <g_dnl.h>
+#include <usb/fastboot.h>
+#include <command.h>
+#include <environment.h>
+#include <dfu.h>
 
 #define FASTBOOT_VERSION		"0.4"
 
@@ -35,6 +39,15 @@
 
 #define EP_BUFFER_SIZE			4096
 
+static struct fastboot_config *fb_cfg;
+static char *transfer_buffer = (void *)CONFIG_USB_FASTBOOT_BUF_ADDR;
+
+/* 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;
 
@@ -118,6 +131,40 @@ static struct usb_gadget_strings *fastboot_strings[] = {
 };
 
 static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+int handle_flash(char *part_name, char *response, char *transfer_buffer);
+
+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' start=%d len=%d\n",
+                               n, ptn->name, ptn->start, ptn->length);
+       }
+}
 
 static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
 {
@@ -308,6 +355,22 @@ 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 +409,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)) {
 		char str_num[12];
 
 		sprintf(str_num, "%08x", CONFIG_USB_FASTBOOT_BUF_SIZE);
@@ -380,6 +443,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;
 
 	if (req->status != 0) {
 		printf("Bad status: %d\n", req->status);
@@ -389,7 +453,7 @@ 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,
+	memcpy((void *)transfer_buffer + download_bytes,
 	       buffer, transfer_size);
 
 	download_bytes += transfer_size;
@@ -403,9 +467,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 +481,12 @@ 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 +537,39 @@ 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);
+}
+
+extern int do_format(void);
+
+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 +588,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 +603,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 +623,69 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
 		usb_ep_queue(ep, req, 0);
 	}
 }
+extern env_t *env_ptr;
+extern int do_env_save (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+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);
+
+                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;
+}
+
+extern int board_mmc_fbtptn_init(void);
+
+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..8856276 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_MMC_FASTBOOT_DEV			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..2935208 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_MMC_FASTBOOT_DEV			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..8079c53
--- /dev/null
+++ b/include/usb/fastboot.h
@@ -0,0 +1,175 @@
+/*
+ * (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 <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#ifdef DEBUG
+#define FBTDBG(fmt,args...)\
+        printf("DEBUG: [%s]: %d: \n"fmt, __FUNCTION__, __LINE__,##args)
+#else
+#define FBTDBG(fmt,args...) do{}while(0)
+#endif
+
+#ifdef INFO
+#define FBTINFO(fmt,args...)\
+        printf("INFO: [%s]: "fmt, __FUNCTION__, ##args)
+#else
+#define FBTINFO(fmt,args...) do{}while(0)
+#endif
+
+#ifdef WARN
+#define FBTWARN(fmt,args...)\
+        printf("WARNING: [%s]: "fmt, __FUNCTION__, ##args)
+#else
+#define FBTWARN(fmt,args...) do{}while(0)
+#endif
+
+#ifdef ERR
+#define FBTERR(fmt,args...)\
+        printf("ERROR: [%s]: "fmt, __FUNCTION__, ##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 */
+extern void fastboot_flash_add_ptn(fastboot_ptentry *ptn);
+extern fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
+extern fastboot_ptentry *fastboot_flash_get_ptn(unsigned n);
+extern unsigned int fastboot_flash_get_ptn_count(void);
+extern void fastboot_flash_dump_ptn(void);
+extern int fastboot_oem(const char *cmd);
+
+
+#endif
+#endif
-- 
1.8.3.2



More information about the U-Boot mailing list