diff mbox

[v1,1/1] fastboot: oem format command implementation

Message ID 1422618891-15613-1-git-send-email-dileep.katta@linaro.org
State New
Headers show

Commit Message

Dileep Katta Jan. 30, 2015, 11:54 a.m. UTC
This is the Modified version of http://patchwork.ozlabs.org/patch/388084/
 - As flash support is already in mainline, it is removed
 - 'oem' command support is present
 - 'oem format' command is implemented
 - Handled review comments of the original patch

Signed-off-by: Dileep Katta <dileep.katta@linaro.org>
---
 common/cmd_fastboot.c           |   4 +
 common/cmd_mmc.c                |   2 +-
 disk/Makefile                   |   1 +
 disk/part_fastboot.c            | 363 ++++++++++++++++++++++++++++++++++++++++
 doc/README.android-fastboot     |   5 +-
 drivers/usb/gadget/f_fastboot.c |  85 ++++++++++
 include/usb/fastboot.h          | 108 ++++++++++++
 7 files changed, 564 insertions(+), 4 deletions(-)
 create mode 100644 disk/part_fastboot.c
 create mode 100644 include/usb/fastboot.h

Comments

Dileep Katta Feb. 9, 2015, 8:03 p.m. UTC | #1
On 30 January 2015 at 22:27, Lukasz Majewski <l.majewski@samsung.com> wrote:

> Hi Dileep,
>
> > This is the Modified version of
> > http://patchwork.ozlabs.org/patch/388084/
> >  - As flash support is already in mainline, it is removed
> >  - 'oem' command support is present
> >  - 'oem format' command is implemented
> >  - Handled review comments of the original patch
> >
> > Signed-off-by: Dileep Katta <dileep.katta@linaro.org>
> > ---
> >  common/cmd_fastboot.c           |   4 +
> >  common/cmd_mmc.c                |   2 +-
> >  disk/Makefile                   |   1 +
> >  disk/part_fastboot.c            | 363
> > ++++++++++++++++++++++++++++++++++++++++
> > doc/README.android-fastboot     |   5 +-
> > drivers/usb/gadget/f_fastboot.c |  85 ++++++++++
> > include/usb/fastboot.h          | 108 ++++++++++++ 7 files changed,
> > 564 insertions(+), 4 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 b72f4f3..efdf461 100644
> > --- a/common/cmd_fastboot.c
> > +++ b/common/cmd_fastboot.c
> > @@ -10,12 +10,16 @@
> >  #include <common.h>
> >  #include <command.h>
> >  #include <g_dnl.h>
> > +#include <usb/fastboot.h>
> >
> >  static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char
> > *const argv[]) {
> >       int ret;
> >
> >       g_dnl_clear_detach();
> > +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
> > +     board_partition_init();
> > +#endif
> >       ret = g_dnl_register("usb_dnl_fastboot");
> >       if (ret)
> >               return ret;
> > diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c
> > index 4e28c9d..0ce747b 100644
> > --- a/common/cmd_mmc.c
> > +++ b/common/cmd_mmc.c
> > @@ -809,7 +809,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/disk/Makefile b/disk/Makefile
> > index 6970cec..4969656 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_FASTBOOT_FLASH_MMC_DEV) +=part_fastboot.o
> > diff --git a/disk/part_fastboot.c b/disk/part_fastboot.c
> > new file mode 100644
> > index 0000000..adf37af
> > --- /dev/null
> > +++ b/disk/part_fastboot.c
> > @@ -0,0 +1,363 @@
> > +/*
> > + * Copyright (C) 2013 Texas Instruments
> > + *
> > + * Author : Pankaj Bharadiya <pankaj.bharadiya@ti.com>
> > + *
> > + * Tom Rix <Tom.Rix@windriver.com> and Sitara 2011 u-boot by
> > + * Mohammed Afzal M A <afzal@ti.com>
> > + *
> > + * Copyright (C) 2008 The Android Open Source Project
> > + * All rights reserved.
> > + *
> > + * Copyright 2014 Linaro, Ltd.
> > + * Dileep Katta <dileep.katta@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>
> > +#include <asm/arch/mmc_host_def.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[] = {
>
> Defining mmc partitions as a static struct in the code IMHO is not
> flexible.
>
> > +     { "-", 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 },
> > +};
>
> Maybe it would be better if we could reuse $partitions ?
> With above code we introduce another (not compatible and flexible) way
> to specify eMMC partitions for the board.
>
> > +
> > +
> > +static const u8 partition_type[16] = {
> > +     0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
> > +     0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7,
> > +};
> > +
>
> Please look into ./include/part_efi.h [1]
>
> > +static const u8 random_uuid[16] = {
> > +     0xff, 0x1f, 0xf2, 0xf9, 0xd4, 0xa8, 0x0e, 0x5f,
> > +     0x97, 0x46, 0x59, 0x48, 0x69, 0xae, 0xc3, 0x4e,
> > +};
>
> I'm not sure if specifying "random" uuids via static const table is
> what you wanted.
>
> For more flexible solution please refer to Trats2 automatic generation
> of UUIDs (either from HW or in SW).
>
> > +
> > +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];
> > +};
> > +
>
> Already defined at [1].
>
> > +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;
> > +}
> > +
>
> Please refer to part_efi.c - code for mbr initialization is already
> there.
>
> > +
> > +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;
> > +
> > +     /* Get the initial checksum by passing buf as NULL */
> > +     n = crc32(0, NULL, 0);
> > +     n = crc32(n, (void *)ptbl->entry, sizeof(ptbl->entry));
> > +     hdr->entries_crc32 = n;
> > +
> > +     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;
> > +}
>
> The same as above.
>
> BTW - please use proper error values instead of -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); +}
>
> The above condition looks like a hard codded one. Please add rationale
> for this (#defines would help there)
>
> > +
> > +static int load_ptbl(void)
> > +{
> > +     u64 ptbl_sectors = 0;
> > +     int i = 0, r = 0;
> > +
> > +     struct ptable gpt[sizeof(struct ptable)];
> > +     struct mmc *mmc = NULL;
> > +
> > +     mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV);
> > +     if (mmc == NULL) {
> > +             printf("No MMC in slot 1\n");
> > +             return -1;
> > +     }
> > +
> > +     int gpt_size = sizeof(struct ptable);
> > +
> > +     ptbl_sectors = (u64)(gpt_size / MMCSD_SECTOR_SIZE);
> > +
> > +     r = mmc->block_dev.block_read(1, 0, ptbl_sectors, (void
> > *)gpt);
> > +     if (r == -1) {
> > +             printf("error reading GPT\n");
>
>                 ^^^^^ error()
>
> > +             goto fail;
> > +     }
> > +
> > +     if (memcmp(gpt->header.magic, "EFI PART", 8)) {
> > +             printf("efi partition table not found\n");
> > +             r = -1;
>
>                 ^^^ more often ret is used than r.
>
> > +             goto fail;
> > +     }
> > +
> > +     for (i = 0; i < EFI_ENTRIES; i++)
> > +             import_efi_partition(&gpt->entry[i]);
> > +
> > +fail:
> > +     return r;
> > +}
> > +
> > +int board_mmc_fbtptn_init(void)
> > +{
> > +     char *mmc_init[2] = {"mmc", "rescan",};
> > +     char dev[2];
> > +     char *mmc_dev[3] = {"mmc", "dev", dev};
> > +     unsigned fb_mmcdev = CONFIG_FASTOOT_FLASH_MMC_DEV;
>
>                         Is your code working with either eMMC or SD
>                         card?
> > +
> > +     sprintf(dev, "0x%x", fb_mmcdev);
> > +
> > +     if (do_mmcops(NULL, 0, 3, mmc_dev)) {
> > +             printf("MMC DEV: %d selection FAILED!\n", fb_mmcdev);
> > +             return -1;
> > +     }
> > +
> > +     if (do_mmcops(NULL, 0, 2, mmc_init)) {
> > +                     printf("FAIL:Init of MMC card\n");
> > +                     return -1;
> > +     }
> > +
> > +     return load_ptbl();
> > +}
> > +
> > +
> > +static struct ptable the_ptable;
> > +
> > +int do_format(void)
> > +{
> > +     struct ptable *ptbl = &the_ptable;
> > +     struct mmc *mmc = NULL;
> > +     unsigned blocks;
> > +     unsigned next;
> > +     unsigned sz;
> > +     int n;
> > +     unsigned fb_mmcdev = CONFIG_FASTBOOT_FLASH_MMC_DEV;
> > +
> > +     /* get mmc info */
> > +     mmc = find_mmc_device(fb_mmcdev);
> > +     if (mmc == 0) {
> > +             printf("no mmc device at slot %d", fb_mmcdev);
> > +             return -1;
> > +     }
> > +
> > +     mmc->has_init = 0;
> > +     if (mmc_init(mmc)) {
> > +             printf("\n mmc init FAILED");
> > +             return -1;
> > +     }
> > +
> > +     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;
> > +
> > +     start_ptbl(ptbl, blocks);
> > +     n = 0;
> > +     next = 0;
> > +     for (n = 0, next = 0; partitions[n].name; n++) {
> > +             /* below line change size from KB to no of blocks */
> > +             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();
> > +
> > +     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", fb_mmcdev);
> > +
> > +     if (do_mmcops(NULL, 0, 3, mmc_dev)) {
> > +             printf("MMC DEV: %d selection FAILED!\n", 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("mbr write FAILED!\n");
> > +             return -1;
> > +     }
> > +
> > +     printf("\nnew partition table:\n");
> > +     load_ptbl();
> > +
> > +     return 0;
> > +}
> > diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot
> > index 1677609..77cce8e 100644
> > --- a/doc/README.android-fastboot
> > +++ b/doc/README.android-fastboot
> > @@ -6,9 +6,8 @@ Overview
> >  The protocol that is used over USB is described in
> >  README.android-fastboot-protocol in same directory.
> >
> > -The current implementation does not yet support the erase command or
> > the -"oem format" command, and there is minimal support for the flash
> > command; -it only supports eMMC devices.
> > +The current implementation does not yet support the erase command,
> > and +there is minimal support for the flash command;it only supports
> > eMMC devices.
> >  Client installation
> >  ===================
> > diff --git a/drivers/usb/gadget/f_fastboot.c
> > b/drivers/usb/gadget/f_fastboot.c index 310175a..76ccc55 100644
> > --- a/drivers/usb/gadget/f_fastboot.c
> > +++ b/drivers/usb/gadget/f_fastboot.c
> > @@ -23,6 +23,8 @@
> >  #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
> >  #include <fb_mmc.h>
> >  #endif
> > +#include <usb/fastboot.h>
> > +#include <command.h>
> >
> >  #define FASTBOOT_VERSION             "0.4"
> >
> > @@ -39,6 +41,12 @@
> >
> >  #define EP_BUFFER_SIZE                       4096
> >
> > +/* To support the Android-style naming of flash */
> > +#define MAX_PTN 16
> > +static struct fastboot_ptentry ptable[MAX_PTN];
> > +static unsigned int pcount;
> > +/* static int static_pcount = -1; */
> > +
> >  struct f_fastboot {
> >       struct usb_function usb_function;
> >
> > @@ -123,6 +131,33 @@ static struct usb_gadget_strings
> > *fastboot_strings[] = {
> >  static void rx_handler_command(struct usb_ep *ep, struct usb_request
> > *req);
> > +/* Android style flash utilties */
> > +void fastboot_flash_reset_ptn(void)
> > +{
> > +#ifdef DEBUG
> > +     printf("fastboot flash reset partition..!!");
> > +#endif
>
>         Please use debug().
>
> > +     pcount = 0;
> > +}
> > +
> > +void fastboot_flash_add_ptn(struct 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++) {
> > +             struct 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;
> > @@ -312,6 +347,21 @@ static int fastboot_tx_write_str(const char
> > *buffer) return fastboot_tx_write(buffer, strlen(buffer));
> >  }
> >
> > +struct 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);
> > @@ -513,6 +563,27 @@ static void cb_flash(struct usb_ep *ep, struct
> > usb_request *req) }
> >  #endif
> >
> > +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
> > +int fastboot_oem(const char *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;
> > +
> > +     int r = fastboot_oem(cmd + 4);
> > +     if (r < 0) {
> > +             fastboot_tx_write_str("FAIL");
> > +     } else {
> > +             fastboot_tx_write_str("OKAY");
> > +     }
>
>         Braces could be removed.
>
> > +}
> > +#endif
> > +
> >  struct cmd_dispatch_info {
> >       char *cmd;
> >       void (*cb)(struct usb_ep *ep, struct usb_request *req);
> > @@ -541,6 +612,12 @@ static const struct cmd_dispatch_info
> > cmd_dispatch_info[] = { .cb = cb_flash,
> >       },
> >  #endif
> > +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
> > +     {
> > +             .cmd = "oem",
> > +             .cb = cb_oem,
> > +     },
> > +#endif
> >  };
> >
> >  static void rx_handler_command(struct usb_ep *ep, struct usb_request
> > *req) @@ -576,3 +653,11 @@ static void rx_handler_command(struct
> > usb_ep *ep, struct usb_request *req) usb_ep_queue(ep, req, 0);
> >       }
> >  }
> > +
> > +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
> > +int board_partition_init(void)
> > +{
> > +     board_mmc_fbtptn_init();
> > +     return 1;
> > +}
> > +#endif
> > diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
> > new file mode 100644
> > index 0000000..8fee6fc
> > --- /dev/null
> > +++ b/include/usb/fastboot.h
> > @@ -0,0 +1,108 @@
> > +/*
> > + * (C) Copyright 2008 - 2009
> > + * Windriver, <www.windriver.com>
> > + * Tom Rix <Tom.Rix@windriver.com>
> > + *
> > + * Copyright (c) 2011 Sebastian Andrzej Siewior
> > <bigeasy@linutronix.de>
> > + *
> > + *
> > + * Copyright (C) 2008 The Android Open Source Project
> > + * All rights reserved.
> > + *
> > + * Copyright 2014 Linaro, Ltd.
> > + * Dileep Katta <dileep.katta@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 CONFIG_CMD_FASTBOOT
> > +
> > +/* Android-style flash naming */
> > +
> > +/* flash partitions are defined in blocks (flash erase units) */
> > +struct fastboot_ptentry {
> > +     /* The logical name for this partition, null terminated */
> > +     char name[16];
> > +     /* start wrt the nand part, must be multiple of nand block
> > size */
> > +     unsigned int start;
> > +     /* 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 is 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
> > +
> > +/*
> > + * Following definitions are to set the ECC to software/Hardware
> > + * before writing. HW and SW ECC should not both be set.
> > + */
> > +
> > +
> > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC           0x00000040
> > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC           0x00000080
> > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH4_ECC      0x00000100
> > +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC      0x00000200
> > +#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(struct fastboot_ptentry *ptn);
> > +struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
> > +struct 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 do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const
> > argv[]); +
> > +#endif
> > +#endif
>
> To sum up:
>
> A lot of duplicated code - already present in part_efi.[ch] - is in
> this patch. Please rewrite it
>
> Moreover, please consider using $partitions env variable with gpt write
> command to create eMMC partitions. This code is already tested and
> validated in u-boot.
>
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
>

Thanks for the review. As an abstract patch for "oem format" by Rob Herring
is in place, stopping this submission.

Regards,
Dileep
diff mbox

Patch

diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
index b72f4f3..efdf461 100644
--- a/common/cmd_fastboot.c
+++ b/common/cmd_fastboot.c
@@ -10,12 +10,16 @@ 
 #include <common.h>
 #include <command.h>
 #include <g_dnl.h>
+#include <usb/fastboot.h>
 
 static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
 	int ret;
 
 	g_dnl_clear_detach();
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+	board_partition_init();
+#endif
 	ret = g_dnl_register("usb_dnl_fastboot");
 	if (ret)
 		return ret;
diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c
index 4e28c9d..0ce747b 100644
--- a/common/cmd_mmc.c
+++ b/common/cmd_mmc.c
@@ -809,7 +809,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/disk/Makefile b/disk/Makefile
index 6970cec..4969656 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_FASTBOOT_FLASH_MMC_DEV)	+=part_fastboot.o
diff --git a/disk/part_fastboot.c b/disk/part_fastboot.c
new file mode 100644
index 0000000..adf37af
--- /dev/null
+++ b/disk/part_fastboot.c
@@ -0,0 +1,363 @@ 
+/*
+ * Copyright (C) 2013 Texas Instruments
+ *
+ * Author : Pankaj Bharadiya <pankaj.bharadiya@ti.com>
+ *
+ * Tom Rix <Tom.Rix@windriver.com> and Sitara 2011 u-boot by
+ * Mohammed Afzal M A <afzal@ti.com>
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Copyright 2014 Linaro, Ltd.
+ * Dileep Katta <dileep.katta@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>
+#include <asm/arch/mmc_host_def.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;
+} __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;
+
+	/* Get the initial checksum by passing buf as NULL */
+	n = crc32(0, NULL, 0);
+	n = crc32(n, (void *)ptbl->entry, sizeof(ptbl->entry));
+	hdr->entries_crc32 = n;
+
+	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)
+{
+	u64 ptbl_sectors = 0;
+	int i = 0, r = 0;
+
+	struct ptable gpt[sizeof(struct ptable)];
+	struct mmc *mmc = NULL;
+
+	mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV);
+	if (mmc == NULL) {
+		printf("No MMC in slot 1\n");
+		return -1;
+	}
+
+	int gpt_size = sizeof(struct ptable);
+
+	ptbl_sectors = (u64)(gpt_size / MMCSD_SECTOR_SIZE);
+
+	r = mmc->block_dev.block_read(1, 0, ptbl_sectors, (void *)gpt);
+	if (r == -1) {
+		printf("error reading GPT\n");
+		goto fail;
+	}
+
+	if (memcmp(gpt->header.magic, "EFI PART", 8)) {
+		printf("efi partition table not found\n");
+		r = -1;
+		goto fail;
+	}
+
+	for (i = 0; i < EFI_ENTRIES; i++)
+		import_efi_partition(&gpt->entry[i]);
+
+fail:
+	return r;
+}
+
+int board_mmc_fbtptn_init(void)
+{
+	char *mmc_init[2] = {"mmc", "rescan",};
+	char dev[2];
+	char *mmc_dev[3] = {"mmc", "dev", dev};
+	unsigned fb_mmcdev = CONFIG_FASTBOOT_FLASH_MMC_DEV;
+
+	sprintf(dev, "0x%x", fb_mmcdev);
+
+	if (do_mmcops(NULL, 0, 3, mmc_dev)) {
+		printf("MMC DEV: %d selection FAILED!\n", fb_mmcdev);
+		return -1;
+	}
+
+	if (do_mmcops(NULL, 0, 2, mmc_init)) {
+			printf("FAIL:Init of MMC card\n");
+			return -1;
+	}
+
+	return load_ptbl();
+}
+
+
+static struct ptable the_ptable;
+
+int do_format(void)
+{
+	struct ptable *ptbl = &the_ptable;
+	struct mmc *mmc = NULL;
+	unsigned blocks;
+	unsigned next;
+	unsigned sz;
+	int n;
+	unsigned fb_mmcdev = CONFIG_FASTBOOT_FLASH_MMC_DEV;
+
+	/* get mmc info */
+	mmc = find_mmc_device(fb_mmcdev);
+	if (mmc == 0) {
+		printf("no mmc device at slot %d", fb_mmcdev);
+		return -1;
+	}
+
+	mmc->has_init = 0;
+	if (mmc_init(mmc)) {
+		printf("\n mmc init FAILED");
+		return -1;
+	}
+
+	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;
+
+	start_ptbl(ptbl, blocks);
+	n = 0;
+	next = 0;
+	for (n = 0, next = 0; partitions[n].name; n++) {
+		/* below line change size from KB to no of blocks */
+		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();
+
+	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", fb_mmcdev);
+
+	if (do_mmcops(NULL, 0, 3, mmc_dev)) {
+		printf("MMC DEV: %d selection FAILED!\n", 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("mbr write FAILED!\n");
+		return -1;
+	}
+
+	printf("\nnew partition table:\n");
+	load_ptbl();
+
+	return 0;
+}
diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot
index 1677609..77cce8e 100644
--- a/doc/README.android-fastboot
+++ b/doc/README.android-fastboot
@@ -6,9 +6,8 @@  Overview
 The protocol that is used over USB is described in
 README.android-fastboot-protocol in same directory.
 
-The current implementation does not yet support the erase command or the
-"oem format" command, and there is minimal support for the flash command;
-it only supports eMMC devices.
+The current implementation does not yet support the erase command, and
+there is minimal support for the flash command;it only supports eMMC devices.
 
 Client installation
 ===================
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 310175a..76ccc55 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -23,6 +23,8 @@ 
 #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
 #include <fb_mmc.h>
 #endif
+#include <usb/fastboot.h>
+#include <command.h>
 
 #define FASTBOOT_VERSION		"0.4"
 
@@ -39,6 +41,12 @@ 
 
 #define EP_BUFFER_SIZE			4096
 
+/* To support the Android-style naming of flash */
+#define MAX_PTN 16
+static struct fastboot_ptentry ptable[MAX_PTN];
+static unsigned int pcount;
+/* static int static_pcount = -1; */
+
 struct f_fastboot {
 	struct usb_function usb_function;
 
@@ -123,6 +131,33 @@  static struct usb_gadget_strings *fastboot_strings[] = {
 
 static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
 
+/* 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(struct 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++) {
+		struct 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;
@@ -312,6 +347,21 @@  static int fastboot_tx_write_str(const char *buffer)
 	return fastboot_tx_write(buffer, strlen(buffer));
 }
 
+struct 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);
@@ -513,6 +563,27 @@  static void cb_flash(struct usb_ep *ep, struct usb_request *req)
 }
 #endif
 
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+int fastboot_oem(const char *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;
+
+	int r = fastboot_oem(cmd + 4);
+	if (r < 0) {
+		fastboot_tx_write_str("FAIL");
+	} else {
+		fastboot_tx_write_str("OKAY");
+	}
+}
+#endif
+
 struct cmd_dispatch_info {
 	char *cmd;
 	void (*cb)(struct usb_ep *ep, struct usb_request *req);
@@ -541,6 +612,12 @@  static const struct cmd_dispatch_info cmd_dispatch_info[] = {
 		.cb = cb_flash,
 	},
 #endif
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+	{
+		.cmd = "oem",
+		.cb = cb_oem,
+	},
+#endif
 };
 
 static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
@@ -576,3 +653,11 @@  static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
 		usb_ep_queue(ep, req, 0);
 	}
 }
+
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+int board_partition_init(void)
+{
+	board_mmc_fbtptn_init();
+	return 1;
+}
+#endif
diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
new file mode 100644
index 0000000..8fee6fc
--- /dev/null
+++ b/include/usb/fastboot.h
@@ -0,0 +1,108 @@ 
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Copyright 2014 Linaro, Ltd.
+ * Dileep Katta <dileep.katta@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 CONFIG_CMD_FASTBOOT
+
+/* Android-style flash naming */
+
+/* flash partitions are defined in blocks (flash erase units) */
+struct fastboot_ptentry {
+	/* The logical name for this partition, null terminated */
+	char name[16];
+	/* start wrt the nand part, must be multiple of nand block size */
+	unsigned int start;
+	/* 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 is 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
+
+/*
+ * Following definitions are to set the ECC to software/Hardware
+ * before writing. HW and SW ECC should not both be set.
+ */
+
+
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC           0x00000040
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC           0x00000080
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH4_ECC      0x00000100
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC      0x00000200
+#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(struct fastboot_ptentry *ptn);
+struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
+struct 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 do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+#endif
+#endif