[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/lib/fastboot/dl_commands.c b/src/bsp/lk/lib/fastboot/dl_commands.c
new file mode 100644
index 0000000..4a9d10f
--- /dev/null
+++ b/src/bsp/lk/lib/fastboot/dl_commands.c
@@ -0,0 +1,605 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <app.h>
+#include <arch/ops.h>
+#include <ctype.h>
+#include <debug.h>
+#include <dev/timer/arm_generic.h>
+#include <dev/udc.h>
+#include <errno.h>
+#include <fit.h>
+#include <kernel/event.h>
+#include <kernel/thread.h>
+#include <lib/bio.h>
+#include <lib/dl_commands.h>
+#include <lib/fastboot.h>
+#include <lib/mempool.h>
+#include <lib/partition.h>
+#include <lib/sparse_format.h>
+#include <libfdt.h>
+#include <platform.h>
+#include <platform/mmc_rpmb.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mtk_wdt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <target.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+#define MODULE_NAME "FASTBOOT_DOWNLOAD"
+
+extern void *download_base;
+extern unsigned download_max;
+extern unsigned download_size;
+extern unsigned fastboot_state;
+
+/*LXO: !Download related command*/
+
+#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
+#define INVALID_PTN -1
+
+lk_bigtime_t start_time_ms;
+#define TIME_STAMP current_time_hires()
+#define TIME_START {start_time_ms = current_time_hires();}
+#define TIME_ELAPSE (current_time_hires() - start_time_ms)
+
+extern int usb_write(void *buf, unsigned len);
+extern int usb_read(void *buf, unsigned len);
+
+static int create_download_membdev(const char *arg, unsigned sz);
+
+extern struct fastboot_var *varlist;
+void cmd_getvar(const char *arg, void *data, unsigned sz)
+{
+    struct fastboot_var *var;
+    char response[MAX_RSP_SIZE];
+
+    if (!strcmp(arg, "all")) {
+        for (var = varlist; var; var = var->next) {
+            snprintf(response, MAX_RSP_SIZE,"\t%s: %s", var->name, var->value);
+            fastboot_info(response);
+        }
+        fastboot_okay("Done!!");
+        return;
+    }
+    for (var = varlist; var; var = var->next) {
+        if (!strcmp(var->name, arg)) {
+            fastboot_okay(var->value);
+            return;
+        }
+    }
+    fastboot_okay("");
+}
+
+void cmd_reboot(const char *arg, void *data, unsigned sz)
+{
+    dprintf(ALWAYS, "rebooting the device\n");
+    fastboot_okay("");
+    set_clr_fastboot_mode(false);
+    mtk_arch_reset(1); /* bypass pwr key when reboot */
+}
+
+void cmd_reboot_bootloader(const char *arg, void *data, unsigned sz)
+{
+    dprintf(ALWAYS, "rebooting the device to bootloader\n");
+    fastboot_okay("");
+    set_clr_fastboot_mode(true);
+    mtk_arch_reset(1); /* bypass pwr key when reboot */
+}
+
+__WEAK void set_clr_fastbootd_mode(bool flag)
+{
+    dprintf(ALWAYS, "not support rebooting the device to fastbootd\n");
+}
+
+void cmd_reboot_fastbootd(const char *arg, void *data, unsigned sz)
+{
+    dprintf(ALWAYS, "rebooting the device to fastbootd\n");
+    fastboot_okay("");
+    set_clr_fastboot_mode(false);
+    set_clr_recovery_mode(false);
+    set_clr_fastbootd_mode(true);
+    mtk_arch_reset(1); /* bypass pwr key when reboot */
+}
+
+void cmd_reboot_recovery(const char *arg, void *data, unsigned sz)
+{
+    dprintf(ALWAYS, "rebooting the device to recovery\n");
+    fastboot_okay("");
+    set_clr_recovery_mode(true);
+    mtk_arch_reset(1); /* bypass pwr key when reboot */
+}
+
+static void fastboot_fail_wrapper(const char *msg)
+{
+    fastboot_fail(msg);
+}
+
+static void fastboot_ok_wrapper(const char *msg, unsigned data_size)
+{
+    fastboot_okay("");
+}
+
+void cmd_download(const char *arg, void *data, unsigned sz)
+{
+    char *response;
+    char *endptr;
+    unsigned len = strtoul(arg, &endptr, 16);
+    int r;
+
+    download_size = 0;
+    if (len > download_max) {
+        fastboot_fail_wrapper("data is too large");
+        return;
+    }
+    response = (char *)memalign(CACHE_LINE, MAX_RSP_SIZE);
+    if (!response) {
+        fastboot_fail_wrapper("buffer allocation fail");
+        return;
+    }
+
+    snprintf(response, MAX_RSP_SIZE, "DATA%08x", len);
+    r = usb_write(response, strlen(response));
+    free(response);
+    if (r < 0) {
+        return;
+    }
+
+
+    TIME_START;
+    r = usb_read(download_base, len);
+    if ((r < 0) || ((unsigned) r != len)) {
+        fastboot_fail_wrapper("Read USB error");
+        fastboot_state = STATE_ERROR;
+        return;
+    }
+    download_size = len;
+
+    fastboot_ok_wrapper("USB Transmission OK", len);
+}
+
+void cmd_flash_img(const char *arg, void *data, unsigned sz)
+{
+    bdev_t *bdev;
+    int ret = 0;
+    off_t round_size;
+
+    if (!strncmp(arg, "download:", strlen("download:"))) {
+        if (create_download_membdev(arg, sz)) {
+            fastboot_fail_wrapper("create memdev fail.");
+            return;
+        }
+    }
+
+    bdev = bio_open_by_label(arg) ? : bio_open(arg);
+    if (!bdev) {
+        fastboot_fail_wrapper("Partition is not exist.");
+        return;
+    }
+
+    round_size = (off_t)ROUND_TO_PAGE(sz, bdev->block_size - 1);
+    LTRACEF("src size is %lld, dst size is %lld\n",
+            round_size, bdev->total_size);
+    if (bdev->total_size && (round_size > bdev->total_size)) {
+        fastboot_fail_wrapper("Image size is too large.");
+        goto closebdev;
+    }
+
+    ret = partition_update(bdev->name, 0x0, data, sz);
+    if (ret < 0) {
+        fastboot_fail_wrapper("Flash write failure.");
+        goto closebdev;
+    }
+
+    ret = partition_publish(bdev->name, 0x0);
+    if (ret > 0)
+        bio_dump_devices();
+
+    fastboot_okay("");
+
+closebdev:
+        bio_close(bdev);
+
+    return;
+}
+
+void cmd_flash_sparse_img(const char *arg, void *data, unsigned sz)
+{
+    bdev_t *bdev;
+    size_t ret = 0;
+    unsigned int chunk;
+    unsigned int chunk_data_sz;
+    uint32_t *fill_buf = NULL;
+    uint32_t fill_val, pre_fill_val, erase_val;
+    uint32_t chunk_blk_cnt = 0;
+    uint32_t i;
+    sparse_header_t *sparse_header;
+    chunk_header_t *chunk_header;
+    uint32_t total_blocks = 0;
+    unsigned long long size = 0;
+
+    bdev = bio_open_by_label(arg);
+    if (!bdev) {
+        fastboot_fail_wrapper("Partition is not exist.");
+        return;
+    }
+
+    size = bdev->total_size;
+    if (!size) {
+        fastboot_fail_wrapper("Size is uncorrect.");
+        goto closebdev;
+    }
+
+    /* Read and skip over sparse image header */
+    sparse_header = (sparse_header_t *) data;
+    dprintf(ALWAYS, "Image size span 0x%llx, partition size 0x%llx\n", (unsigned long long)sparse_header->total_blks*sparse_header->blk_sz, size);
+    if ((unsigned long long)sparse_header->total_blks*sparse_header->blk_sz > size) {
+        fastboot_fail("sparse image size span overflow.");
+        goto closebdev;
+    }
+
+    data += sparse_header->file_hdr_sz;
+    if (sparse_header->file_hdr_sz > sizeof(sparse_header_t)) {
+        /* Skip the remaining bytes in a header that is longer than
+         * we expected.
+         */
+        data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t));
+    }
+
+    /* sparse_header->blk_sz is used as denominator later, ensure it's not 0 */
+    if (sparse_header->blk_sz == 0) {
+        fastboot_fail("wrong blk_sz in sparse header.");
+        goto closebdev;
+    }
+
+    LTRACEF("=== Sparse Image Header ===\n");
+    LTRACEF("magic: 0x%x\n", sparse_header->magic);
+    LTRACEF("major_version: 0x%x\n", sparse_header->major_version);
+    LTRACEF("minor_version: 0x%x\n", sparse_header->minor_version);
+    LTRACEF("file_hdr_sz: %d\n", sparse_header->file_hdr_sz);
+    LTRACEF("chunk_hdr_sz: %d\n", sparse_header->chunk_hdr_sz);
+    LTRACEF("blk_sz: %d\n", sparse_header->blk_sz);
+    LTRACEF("total_blks: %d\n", sparse_header->total_blks);
+    LTRACEF("total_chunks: %d\n", sparse_header->total_chunks);
+
+    fill_buf = (uint32_t *)memalign(CACHE_LINE, ROUNDUP(sparse_header->blk_sz, CACHE_LINE));
+    if (!fill_buf) {
+        fastboot_fail_wrapper("Malloc failed for: CHUNK_TYPE_FILL");
+        goto closebdev;
+    }
+    erase_val = (int)bdev->erase_byte|bdev->erase_byte<<8|bdev->erase_byte<<16|bdev->erase_byte<<24;
+    pre_fill_val = erase_val;
+    LTRACEF("Init previous fill value to 0x%08x\n", pre_fill_val);
+
+    /* Start processing chunks */
+    for (chunk=0; chunk<sparse_header->total_chunks; chunk++) {
+        /* Read and skip over chunk header */
+        chunk_header = (chunk_header_t *)data;
+        data += sizeof(chunk_header_t);
+
+        LTRACEF("=== Chunk Header ===\n");
+        LTRACEF("chunk_type: 0x%x\n", chunk_header->chunk_type);
+        LTRACEF("chunk_data_sz: 0x%x\n", chunk_header->chunk_sz);
+        LTRACEF("total_size: 0x%x\n", chunk_header->total_sz);
+
+        if (sparse_header->chunk_hdr_sz > sizeof(chunk_header_t)) {
+            /* Skip the remaining bytes in a header that is longer than
+             * we expected.
+             */
+            data += (sparse_header->chunk_hdr_sz - sizeof(chunk_header_t));
+        }
+
+        chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz;
+        switch (chunk_header->chunk_type) {
+            case CHUNK_TYPE_RAW:
+                if (chunk_header->total_sz != (sparse_header->chunk_hdr_sz +
+                                               chunk_data_sz)) {
+                    fastboot_fail("Bogus chunk size for chunk type Raw");
+                    goto error;
+                }
+
+                LTRACEF("Raw: start block addr: 0x%x\n", total_blocks);
+
+                LTRACEF("addr 0x%llx, partsz 0x%x\n", ((unsigned long long)total_blocks*sparse_header->blk_sz) , chunk_data_sz);
+                ret = (size_t)bio_write(bdev, data, ((unsigned long long)total_blocks*sparse_header->blk_sz), chunk_data_sz);
+                if (ret != chunk_data_sz) {
+                    fastboot_fail_wrapper("flash write failure");
+                    goto error;
+                }
+
+                total_blocks += chunk_header->chunk_sz;
+                data += chunk_data_sz;
+                break;
+
+            case CHUNK_TYPE_DONT_CARE:
+                LTRACEF("!!Blank: start: 0x%x  offset: 0x%x\n",
+                        total_blocks, chunk_header->chunk_sz);
+                total_blocks += chunk_header->chunk_sz;
+                break;
+
+            case CHUNK_TYPE_FILL:
+                LTRACEF("CHUNK_TYPE_FILL=0x%x size=%d chunk_data_sz=%d\n",
+                        *(uint32_t *)data,
+                        ROUNDUP(sparse_header->blk_sz, CACHE_LINE),
+                        chunk_data_sz);
+                if (chunk_header->total_sz != (sparse_header->chunk_hdr_sz + sizeof(uint32_t))) {
+                    fastboot_fail_wrapper("Bogus chunk size for chunk type FILL");
+                    goto error;
+                }
+
+                fill_val = *(uint32_t *)data;
+                data = (char *) data + sizeof(uint32_t);
+                chunk_blk_cnt = chunk_data_sz / sparse_header->blk_sz;
+
+                if (fill_val != pre_fill_val) {
+                    pre_fill_val = fill_val;
+                    for (i = 0; i < (sparse_header->blk_sz / sizeof(fill_val)); i++)
+                        fill_buf[i] = fill_val;
+                }
+
+                for (i = 0; i < chunk_blk_cnt; i++) {
+                    if (fill_val == erase_val) {
+                        /* To assume partition already erased */
+                        /* skip fill value as same as erase_byte */
+                        LTRACEF("skip CHUNK_TYPE_FILL with value '%x'\n", fill_val);
+                    } else {
+                        ret = (size_t)bio_write(bdev, fill_buf, ((uint64_t)total_blocks*sparse_header->blk_sz), sparse_header->blk_sz);
+                        if (ret != sparse_header->blk_sz) {
+                            fastboot_fail_wrapper("CHUNK_TYPE_FILL flash write failure");
+                            goto error;
+                        }
+                    }
+                    total_blocks++;
+                }
+                break;
+
+            case CHUNK_TYPE_CRC:
+                if (chunk_header->total_sz != sparse_header->chunk_hdr_sz) {
+                    fastboot_fail_wrapper("Bogus chunk size for chunk type Dont Care");
+                    goto error;
+                }
+                total_blocks += chunk_header->chunk_sz;
+                data += chunk_data_sz;
+                break;
+
+            default:
+                fastboot_fail_wrapper("Unknown chunk type");
+                goto error;
+        }
+    }
+
+    dprintf(ALWAYS, "Wrote %d blocks, expected to write %d blocks\n",
+            total_blocks, sparse_header->total_blks);
+
+    if (total_blocks != sparse_header->total_blks) {
+        fastboot_fail_wrapper("sparse image write failure");
+    } else {
+        fastboot_okay("");
+    }
+
+error:
+    free(fill_buf);
+closebdev:
+    bio_close(bdev);
+
+    return;
+}
+
+void cmd_flash(const char *arg, void *data, unsigned sz)
+{
+    sparse_header_t *sparse_header;
+
+    dprintf(ALWAYS, "cmd_flash: %s, %d\n", arg, (u32)sz);
+
+    if (sz  == 0) {
+        fastboot_okay("");
+        return;
+    }
+
+    TIME_START;
+
+// security check, only unlocked device can flash partitions
+#if !(defined FORCE_DISABLE_FLASH_CHECK)
+    int ret=-1;
+    unsigned char blk[256]={0};
+
+    ret=mmc_rpmb_block_read(INDEX_RPMB_UNLOCK,&blk[0]);
+    if(ret != 0){
+        dprintf(CRITICAL, "mmc_rpmb_block_read fail %d.\n", ret);
+        return;
+    }
+
+    if(blk[0] != AVB_DEVICE_UNLOCK){
+        dprintf(ALWAYS, "Device not unlocked, cmd_flash refused \n");
+        return;
+    }
+#endif
+
+    sparse_header = (sparse_header_t *) data;
+    if (sparse_header->magic != SPARSE_HEADER_MAGIC)
+        cmd_flash_img(arg, data, sz);
+    else {
+        cmd_flash_sparse_img(arg, data, sz);
+    }
+
+    return;
+}
+
+void cmd_erase(const char *arg, void *data, unsigned sz)
+{
+#define MAX_ERASE_SIZE  (INT_MAX & ~(bdev->block_size - 1))
+    bdev_t *bdev;
+    ssize_t ret = 0, erase_len = 0;
+    char response[MAX_RSP_SIZE];
+
+    dprintf(ALWAYS, "cmd_erase\n");
+    bdev = bio_open_by_label(arg);
+    if (!bdev) {
+        bdev = bio_open(arg);
+        if (!bdev) {
+            fastboot_fail_wrapper("Partition is not exist.");
+            return;
+        }
+    }
+
+    if (!bdev->total_size) {
+        fastboot_fail_wrapper("Size is uncorrect.");
+        goto closebdev;
+    }
+
+    LTRACEF("%s %s %lld %d\n",
+            bdev->name, bdev->label, bdev->total_size, bdev->block_count);
+    if (bdev->total_size > (off_t)MAX_ERASE_SIZE) {
+        off_t offset = 0LL, size = bdev->total_size;
+        size_t len;
+        do {
+            len = (size_t)MIN(size, (off_t)MAX_ERASE_SIZE);
+            ret = bio_erase(bdev, offset, len);
+            if (ret < 0) {
+                fastboot_fail_wrapper("Erase failure.");
+                goto closebdev;
+            }
+            erase_len += ret;
+            size -= len;
+            offset += len;
+        } while (size);
+    } else {
+        ret = bio_erase(bdev, 0, bdev->total_size);
+        if (ret < 0) {
+            fastboot_fail_wrapper("Erase failure.");
+            goto closebdev;
+        }
+        erase_len = ret;
+    }
+
+    ret = partition_unpublish(bdev->name);
+    if (ret > 0)
+        bio_dump_devices();
+
+    snprintf(response, MAX_RSP_SIZE, "request sz: 0x%llx, real erase len: 0x%lx",
+             bdev->total_size, erase_len);
+    fastboot_info(response);
+
+    fastboot_okay("");
+
+closebdev:
+    bio_close(bdev);
+
+    return;
+}
+
+//to support AVB2.0 cmd: fastboot flashing [lock | unlock]
+#ifdef AVB_ENABLE_DEVICE_STATE_CHANGE
+int cmd_flash_lock_state(const char *arg)
+{
+    unsigned char blk[256]={0};
+    int ret=-1;
+
+    LTRACEF("start to flash  device state [%s] \n",arg);
+
+    if (!strcmp(arg, " lock")) {
+        blk[0]=0;
+        LTRACEF("start to flash lock state \n");
+        ret=mmc_rpmb_block_write(INDEX_RPMB_UNLOCK,&blk[0]);
+        LTRACEF("end to flash lock state %d \n",ret);
+    }
+    else if (!strcmp(arg, " unlock")){
+        blk[0]=AVB_DEVICE_UNLOCK;
+        ret=mmc_rpmb_block_write(INDEX_RPMB_UNLOCK,&blk[0]);
+        LTRACEF("end to flash unlock state %d \n",ret);
+    }
+    else{
+        dprintf(ALWAYS, "cmd %s not supported \n",arg);
+    }
+
+    dprintf(ALWAYS, "cmd %s finish %d  \n",arg,ret);
+
+    return ret;
+}
+
+void cmd_flashing(const char *arg, void *data, unsigned sz)
+{
+    char response[MAX_RSP_SIZE];
+    int ret=-1;
+
+    if(arg ==  NULL){
+        dprintf(ALWAYS, "invalid parameter \n");
+        return ;
+    }
+
+    dprintf(ALWAYS, "cmd_flashing: %s, \n", arg);
+
+    ret=cmd_flash_lock_state(arg);
+
+    snprintf(response, MAX_RSP_SIZE, "flashing state %s", (ret==0)?"sucessful":"fail");
+    fastboot_info(response);
+
+    fastboot_okay("");
+
+    return;
+}
+#endif
+
+extern unsigned fastboot_state;
+void cmd_continue_boot(const char *arg, void *data, unsigned sz)
+{
+    fastboot_okay("");
+    /* set state to leave fastboot command loop and handler */
+    fastboot_state = STATE_RETURN;
+    mtk_wdt_init();
+}
+
+static int create_download_membdev(const char *arg, unsigned sz)
+{
+    size_t membdev_size;
+    void *membdev_buf;
+    int rc;
+
+    /* destroy the membdev if previously created */
+    membdev_buf = destroy_membdev(arg);
+    if (membdev_buf) {
+        mempool_free(membdev_buf);
+        membdev_buf = NULL;
+    }
+
+    /* membdev size should be aligned to 512 bytes */
+    membdev_size = ROUNDUP(sz, 512);
+    membdev_buf = mempool_alloc(membdev_size, MEMPOOL_ANY);
+    if (membdev_buf == NULL) {
+        fastboot_fail_wrapper("size is too large");
+        return -1;
+    }
+
+    rc = create_membdev(arg, membdev_buf, membdev_size);
+    if (rc) {
+        fastboot_fail_wrapper("fail to create membdev");
+        mempool_free(membdev_buf);
+        return -1;
+    }
+    fastboot_okay("");
+
+    return 0;
+}
diff --git a/src/bsp/lk/lib/fastboot/ext_boot.c b/src/bsp/lk/lib/fastboot/ext_boot.c
new file mode 100644
index 0000000..b2b3e9e
--- /dev/null
+++ b/src/bsp/lk/lib/fastboot/ext_boot.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dev/udc.h>
+#include <lib/bio.h>
+#include <lib/dl_commands.h>
+#include <lib/fastboot.h>
+#include <lib/fastboot_oem_cmd.h>
+#include <lib/mempool.h>
+#include <platform/mtk_serial_key.h>
+#include <platform/mtk_wdt.h>
+#include <reg.h>
+#include <stdio.h>
+#include <string.h>
+#include <target/cust_usb.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#ifndef SN_BUF_LEN
+#define SN_BUF_LEN  19  /* fastboot use 13 bytes as default, max is 19 */
+#endif
+#define DEFAULT_SERIAL_NUM "0123456789ABCDEF"
+char sn_buf[SN_BUF_LEN+1] = DEFAULT_SERIAL_NUM;
+
+static struct udc_device surf_udc_device = {
+    .vendor_id  = USB_VENDORID,
+    .product_id = USB_PRODUCTID,
+    .version_id = USB_VERSIONID,
+    .manufacturer   = USB_MANUFACTURER,
+    .product    = USB_PRODUCT_NAME,
+};
+
+static void register_commands(void)
+{
+    fastboot_register("getvar:", cmd_getvar);
+    fastboot_register("download:", cmd_download);
+    fastboot_register("flash:", cmd_flash);
+    fastboot_register("erase:", cmd_erase);
+    fastboot_register("reboot", cmd_reboot);
+    fastboot_register("reboot-bootloader", cmd_reboot_bootloader);
+    fastboot_register("reboot-fastboot", cmd_reboot_fastbootd);
+    fastboot_register("oem reboot-recovery", cmd_reboot_recovery);
+    fastboot_register("oem continue", cmd_continue_boot);
+#ifdef AVB_ENABLE_DEVICE_STATE_CHANGE
+    fastboot_register("flashing", cmd_flashing);
+#endif
+}
+
+static void register_oem_fastboot_cmds(void)
+{
+    extern const struct fastboot_oem_cmd_descriptor __fb_oem_cmd_start[];
+    extern const struct fastboot_oem_cmd_descriptor __fb_oem_cmd_end[];
+
+    const struct fastboot_oem_cmd_descriptor *cmd;
+
+    for (cmd = __fb_oem_cmd_start; cmd != __fb_oem_cmd_end; cmd++) {
+        if (cmd->cmd_handler)
+            fastboot_register(cmd->cmd_str, cmd->cmd_handler);
+    }
+}
+
+static void publish_attributes(void)
+{
+    char buffer_size[11];
+    sprintf(buffer_size, "0x%x", SCRATCH_SIZE);
+    fastboot_publish("version", "0.5");
+    fastboot_publish("max-download-size", buffer_size);
+    fastboot_publish("is-userspace", "no");
+}
+
+static void storage_init(void)
+{
+    /* init storage that only use in fastboot, currently none */
+    bio_dump_devices();
+}
+
+static char udc_chr[32] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ456789"};
+static int get_serial(u64 hwkey, u32 chipid, char *ser)
+{
+    u16 hashkey[4];
+    u32 idx, ser_idx;
+
+    /* split to 4 key with 16-bit width each */
+    for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
+        hashkey[idx] = (u16)(hwkey & 0xffff);
+        hwkey >>= 16;
+    }
+
+    /* hash the key with chip id */
+    for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
+        u32 digit = (chipid % 10);
+        hashkey[idx] = (hashkey[idx] >> digit) | (hashkey[idx] << (16-digit));
+        chipid = (chipid / 10);
+    }
+
+    /* generate serail using hashkey */
+    ser_idx = 0;
+    for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
+        ser[ser_idx++] = (hashkey[idx] & 0x001f);
+        ser[ser_idx++] = (hashkey[idx] & 0x00f8) >> 3;
+        ser[ser_idx++] = (hashkey[idx] & 0x1f00) >> 8;
+        ser[ser_idx++] = (hashkey[idx] & 0xf800) >> 11;
+    }
+
+    for (idx = 0; idx < ser_idx; idx++)
+        ser[idx] = udc_chr[(int)ser[idx]];
+
+    ser[ser_idx] = 0x00;
+
+    return 0;
+}
+
+void ext_boot(void)
+{
+    void *scratch_buf;
+
+    u64 key = ((u64)readl(SERIAL_KEY_HI) << 32) | readl(SERIAL_KEY_LO);
+    if (key != 0)
+        get_serial(key, MACH_TYPE, sn_buf);
+
+    surf_udc_device.serialno = sn_buf;
+    udc_init(&surf_udc_device);
+
+    storage_init();
+    mtk_wdt_disable();
+    register_commands();
+    register_oem_fastboot_cmds();
+    publish_attributes();
+
+    scratch_buf = mempool_alloc(SCRATCH_SIZE, MEMPOOL_ANY);
+
+    if (!scratch_buf)
+        return;
+
+    fastboot_init(scratch_buf, (unsigned long long)SCRATCH_SIZE);
+    mempool_free(scratch_buf);
+}
diff --git a/src/bsp/lk/lib/fastboot/fastboot.c b/src/bsp/lk/lib/fastboot/fastboot.c
new file mode 100644
index 0000000..43ff0a5
--- /dev/null
+++ b/src/bsp/lk/lib/fastboot/fastboot.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <debug.h>
+#include <dev/udc.h>
+#include <err.h>
+#include <kernel/event.h>
+#include <kernel/thread.h>
+#include <kernel/timer.h>
+#include <lib/fastboot.h>
+#include <platform/udc-common.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+/* MAX_USBFS_BULK_SIZE: if use USB3 QMU GPD mode: cannot exceed 63 * 1024 */
+#define MAX_USBFS_BULK_SIZE (16 * 1024)
+
+static event_t usb_online;
+static event_t txn_done;
+static struct udc_endpoint *in, *out;
+static struct udc_request *req;
+int txn_status;
+
+void *download_base;
+unsigned download_max;
+unsigned download_size;
+unsigned fastboot_state = STATE_OFFLINE;
+
+struct fastboot_cmd *cmdlist;
+
+static void req_complete(struct udc_request *req, unsigned actual, int status)
+{
+    txn_status = status;
+    req->length = actual;
+    event_signal(&txn_done, 0);
+}
+
+void fastboot_register(const char *prefix,
+                       void (*handle)(const char *arg, void *data, unsigned sz))
+{
+    struct fastboot_cmd *cmd;
+
+    cmd = malloc(sizeof(*cmd));
+    if (cmd) {
+        cmd->prefix = prefix;
+        cmd->prefix_len = strlen(prefix);
+        cmd->handle = handle;
+        cmd->next = cmdlist;
+        cmdlist = cmd;
+    }
+}
+
+struct fastboot_var *varlist;
+
+void fastboot_publish(const char *name, const char *value)
+{
+    struct fastboot_var *var;
+    var = malloc(sizeof(*var));
+    if (var) {
+        var->name = name;
+        var->value = value;
+        var->next = varlist;
+        varlist = var;
+    }
+}
+
+/*
+ * Read data from USB.
+ * _buf: the buffer for reading data. Star address must be cache line aligned!
+ * len: the length for reading data. Must be cache line size aligned!
+ */
+int usb_read(void *_buf, unsigned len)
+{
+    int r;
+    unsigned xfer;
+    unsigned char *buf = _buf;
+    int count = 0;
+
+    if (fastboot_state == STATE_ERROR)
+        goto oops;
+
+    while (len > 0) {
+        xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
+        req->buffer = buf;
+        req->length = xfer;
+        req->complete = req_complete;
+        r = udc_request_queue(out, req);
+        if (r < 0) {
+            LTRACEF("usb_read() queue failed\n");
+            goto oops;
+        }
+        event_wait(&txn_done);
+
+        if (txn_status < 0) {
+            LTRACEF("usb_read() transaction failed\n");
+            goto oops;
+        }
+
+        count += req->length;
+        buf += req->length;
+        len -= req->length;
+
+        /* short transfer? */
+        if (req->length != xfer) break;
+    }
+
+    return count;
+
+oops:
+    fastboot_state = STATE_ERROR;
+    return -1;
+}
+
+/*
+ * Write data to USB.
+ * buf: the buffer for writing data. Star address must be cache line aligned!
+ * len: the length for writing data. Must be cache line size aligned!
+ */
+int usb_write(void *buf, unsigned len)
+{
+    int r;
+
+    if (fastboot_state == STATE_ERROR)
+        goto oops;
+
+    req->buffer = buf;
+    req->length = len;
+    req->complete = req_complete;
+    r = udc_request_queue(in, req);
+    if (r < 0) {
+        LTRACEF("usb_write() queue failed\n");
+        goto oops;
+    }
+    event_wait(&txn_done);
+    if (txn_status < 0) {
+        LTRACEF("usb_write() transaction failed\n");
+        goto oops;
+    }
+    return req->length;
+
+oops:
+    fastboot_state = STATE_ERROR;
+    return -1;
+}
+
+void fastboot_ack(const char *code, const char *reason)
+{
+    char *response;
+
+    if (fastboot_state != STATE_COMMAND)
+        return;
+
+    if (reason == 0)
+        reason = "";
+
+    response = (char *)memalign(CACHE_LINE, MAX_RSP_SIZE);
+    if (!response) {
+        dprintf(CRITICAL, "fastboot: can't allocate memory\n");
+        return;
+    }
+    snprintf(response, MAX_RSP_SIZE, "%s%s", code, reason);
+    fastboot_state = STATE_COMPLETE;
+
+    usb_write(response, strlen(response));
+    free(response);
+
+}
+
+void fastboot_info(const char *reason)
+{
+    char *response;
+
+    if (fastboot_state != STATE_COMMAND)
+        return;
+
+    if (reason == 0)
+        return;
+
+    response = (char *)memalign(CACHE_LINE, MAX_RSP_SIZE);
+    if (!response) {
+        dprintf(CRITICAL, "fastboot: can't allocate memory\n");
+        return;
+    }
+    snprintf(response, MAX_RSP_SIZE, "INFO%s", reason);
+
+    usb_write(response, strlen(response));
+    free(response);
+}
+
+void fastboot_fail(const char *reason)
+{
+    fastboot_ack("FAIL", reason);
+    /* add debug log */
+    dprintf(ALWAYS, "%s\n", reason);
+}
+
+void fastboot_okay(const char *info)
+{
+    fastboot_ack("OKAY", info);
+}
+
+static int fastboot_command_loop(void)
+{
+    struct fastboot_cmd *cmd;
+    int r;
+    char *buffer = (char *)memalign(CACHE_LINE, MAX_RSP_SIZE);
+
+    if (!buffer) {
+        dprintf(CRITICAL, "fastboot: can't allocate memory\n");
+        return ERR_NO_MEMORY;
+    }
+    dprintf(ALWAYS,"fastboot: processing commands\n");
+
+again:
+    while ((fastboot_state != STATE_ERROR) && (fastboot_state != STATE_RETURN)) {
+        r = usb_read(buffer, MAX_RSP_SIZE);
+        if (r < 0) break; /* no input command */
+        buffer[r] = 0;
+        dprintf(ALWAYS, "fastboot: %s[len:%d]\n", buffer, r);
+        dprintf(ALWAYS, "fastboot:[download_base:%p][download_size:0x%x]\n",download_base,(unsigned int)download_size);
+
+        /* Pick up matched command and handle it */
+        for (cmd = cmdlist; cmd; cmd = cmd->next) {
+            if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
+                continue;
+            fastboot_state = STATE_COMMAND;
+            dprintf(ALWAYS,"fastboot:[cmd:%s]-[arg:%s]\n", cmd->prefix,  buffer + cmd->prefix_len);
+            cmd->handle((const char *) buffer + cmd->prefix_len, (void *) download_base, download_size);
+            if (fastboot_state == STATE_COMMAND)
+                fastboot_fail("unknown reason");
+            goto again;
+        }
+        dprintf(ALWAYS,"[unknown command]*[%s]*\n", buffer);
+        fastboot_fail("unknown command");
+
+    }
+    if (fastboot_state != STATE_RETURN)
+        fastboot_state = STATE_OFFLINE;
+    dprintf(ALWAYS,"fastboot: oops!\n");
+    free(buffer);
+    return fastboot_state;
+}
+
+static int fastboot_handler(void *arg)
+{
+    int status = 0;
+    while (status != STATE_RETURN) {
+        event_wait(&usb_online);
+        status = fastboot_command_loop();
+    }
+    return 0;
+}
+
+static void fastboot_notify(struct udc_gadget *gadget, unsigned event)
+{
+    if (event == UDC_EVENT_ONLINE) {
+        event_signal(&usb_online, 0);
+    } else if (event == UDC_EVENT_OFFLINE) {
+        event_unsignal(&usb_online);
+    }
+}
+
+static struct udc_endpoint *fastboot_endpoints[2];
+
+static struct udc_gadget fastboot_gadget = {
+    .notify     = fastboot_notify,
+    .ifc_class  = 0xff,
+    .ifc_subclass   = 0x42,
+    .ifc_protocol   = 0x03,
+    .ifc_endpoints  = 2,
+    .ifc_string = "fastboot",
+    .ept        = fastboot_endpoints,
+};
+
+int fastboot_init(void *base, unsigned size)
+{
+    thread_t *thr;
+
+    dprintf(ALWAYS, "fastboot_init()\n");
+    download_base = base;
+    download_max = size;
+
+    event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
+    event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);
+
+    in = udc_endpoint_alloc(UDC_BULK_IN, 512);
+    if (!in)
+        goto fail_alloc_in;
+    out = udc_endpoint_alloc(UDC_BULK_OUT, 512);
+    if (!out)
+        goto fail_alloc_out;
+
+    fastboot_endpoints[0] = in;
+    fastboot_endpoints[1] = out;
+
+    req = udc_request_alloc();
+    if (!req)
+        goto fail_alloc_req;
+
+    if (udc_register_gadget(&fastboot_gadget))
+        goto fail_udc_register;
+
+    thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+    if (!thr) {
+        goto fail_alloc_in;
+    }
+    thread_resume(thr);
+
+    udc_start();
+    thread_join(thr, NULL, INFINITE_TIME);
+    udc_stop();
+
+    return 0;
+
+fail_udc_register:
+    udc_request_free(req);
+fail_alloc_req:
+    udc_endpoint_free(out);
+fail_alloc_out:
+    udc_endpoint_free(in);
+fail_alloc_in:
+    return -1;
+}
+
diff --git a/src/bsp/lk/lib/fastboot/fastboot_oem_cmd.ld b/src/bsp/lk/lib/fastboot/fastboot_oem_cmd.ld
new file mode 100644
index 0000000..211ec23
--- /dev/null
+++ b/src/bsp/lk/lib/fastboot/fastboot_oem_cmd.ld
@@ -0,0 +1,8 @@
+SECTIONS {
+    .fb_oem_cmd : {
+        __fb_oem_cmd_start = .;
+        KEEP(*(.fb_oem_cmd))
+        __fb_oem_cmd_end = .;
+    }
+}
+INSERT AFTER .rodata;
diff --git a/src/bsp/lk/lib/fastboot/include/lib/dl_commands.h b/src/bsp/lk/lib/fastboot/include/lib/dl_commands.h
new file mode 100644
index 0000000..f081ddc
--- /dev/null
+++ b/src/bsp/lk/lib/fastboot/include/lib/dl_commands.h
@@ -0,0 +1,28 @@
+#pragma once
+/* [FIXME] remove the MT2712_ANDROID option check */
+#ifdef MT2712_ANDROID
+#define AVB_ENABLE_DEVICE_STATE_CHANGE 1
+#endif
+#define FORCE_DISABLE_FLASH_CHECK 1
+#define INDEX_RPMB_UNLOCK 1
+#define AVB_DEVICE_UNLOCK 0x5a
+
+void cmd_continue_boot(const char *arg, void *data, unsigned sz);
+void cmd_download(const char *arg, void *data, unsigned sz);
+void cmd_download_boot(const char *arg, void *data, unsigned sz);
+void cmd_download_bl33(const char *arg, void *data, unsigned sz);
+void cmd_download_spmfw(const char *arg, void *data, unsigned sz);
+void cmd_download_tz(const char *arg, void *data, unsigned sz);
+void cmd_erase(const char *arg, void *data, unsigned sz);
+void cmd_flash(const char *arg, void *data, unsigned sz);
+void cmd_flash_img(const char *arg, void *data, unsigned sz);
+void cmd_flash_sparse_img(const char *arg, void *data, unsigned sz);
+void cmd_getvar(const char *arg, void *data, unsigned sz);
+void cmd_reboot(const char *arg, void *data, unsigned sz);
+void cmd_reboot_bootloader(const char *arg, void *data, unsigned sz);
+void cmd_reboot_fastbootd(const char *arg, void *data, unsigned sz);
+void cmd_reboot_recovery(const char *arg, void *data, unsigned sz);
+#ifdef AVB_ENABLE_DEVICE_STATE_CHANGE
+void cmd_flashing(const char *arg, void *data, unsigned sz);
+int cmd_flash_lock_state(const char *arg);
+#endif
diff --git a/src/bsp/lk/lib/fastboot/include/lib/fastboot.h b/src/bsp/lk/lib/fastboot/include/lib/fastboot.h
new file mode 100644
index 0000000..411c724
--- /dev/null
+++ b/src/bsp/lk/lib/fastboot/include/lib/fastboot.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#pragma once
+
+#define MAX_RSP_SIZE 64
+
+struct fastboot_cmd {
+    struct fastboot_cmd *next;
+    const char *prefix;
+    unsigned prefix_len;
+    void (*handle)(const char *arg, void *data, unsigned sz);
+};
+
+struct fastboot_var {
+    struct fastboot_var *next;
+    const char *name;
+    const char *value;
+};
+
+void fastboot_okay(const char *info);
+void fastboot_fail(const char *reason);
+void fastboot_register(const char *prefix, void (*handle)(const char *arg, void *data, unsigned sz));
+void fastboot_publish(const char *name, const char *value);
+void fastboot_info(const char *reason);
+int fastboot_init(void *base, unsigned size);
+
+#define STATE_OFFLINE   0
+#define STATE_COMMAND   1
+#define STATE_COMPLETE  2
+#define STATE_ERROR     3
+#define STATE_RETURN    4
diff --git a/src/bsp/lk/lib/fastboot/include/lib/fastboot_oem_cmd.h b/src/bsp/lk/lib/fastboot/include/lib/fastboot_oem_cmd.h
new file mode 100644
index 0000000..3ba1cfe
--- /dev/null
+++ b/src/bsp/lk/lib/fastboot/include/lib/fastboot_oem_cmd.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#pragma once
+
+#include <stddef.h>
+
+struct fastboot_oem_cmd_descriptor;
+typedef void (*oem_cmd_handler)(const char *arg, void *data, unsigned size);
+
+struct fastboot_oem_cmd_descriptor {
+    const char *cmd_str;
+    oem_cmd_handler cmd_handler;
+};
+
+#define FASTBOOT_OEM_CMD_START(cmd_name) \
+    const struct fastboot_oem_cmd_descriptor _fb_oem_##cmd_name __ALIGNED(sizeof(void *)) __SECTION(".fb_oem_cmd") = {
+
+#define FASTBOOT_OEM_CMD_END };
diff --git a/src/bsp/lk/lib/fastboot/include/lib/sparse_format.h b/src/bsp/lk/lib/fastboot/include/lib/sparse_format.h
new file mode 100644
index 0000000..3a9bab8
--- /dev/null
+++ b/src/bsp/lk/lib/fastboot/include/lib/sparse_format.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#pragma once
+typedef struct sparse_header {
+    uint32_t  magic;          /* 0xed26ff3a */
+    uint16_t  major_version;  /* (0x1) - reject images with higher major versions */
+    uint16_t  minor_version;  /* (0x0) - allow images with higer minor versions */
+    uint16_t  file_hdr_sz;    /* 28 bytes for first revision of the file format */
+    uint16_t  chunk_hdr_sz;   /* 12 bytes for first revision of the file format */
+    uint32_t  blk_sz;         /* block size in bytes, must be a multiple of 4 (4096) */
+    uint32_t  total_blks;     /* total blocks in the non-sparse output image */
+    uint32_t  total_chunks;   /* total chunks in the sparse input image */
+    uint32_t  image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
+                              /* as 0. Standard 802.3 polynomial, use a Public Domain */
+                              /* table implementation */
+} sparse_header_t;
+
+#define SPARSE_HEADER_MAGIC 0xed26ff3a
+
+#define CHUNK_TYPE_RAW      0xCAC1
+#define CHUNK_TYPE_FILL     0xCAC2
+#define CHUNK_TYPE_DONT_CARE    0xCAC3
+#define CHUNK_TYPE_CRC      0xCAC4
+
+typedef struct chunk_header {
+    uint16_t  chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
+    uint16_t  reserved1;
+    uint32_t  chunk_sz;   /* in blocks in output image */
+    uint32_t  total_sz;   /* in bytes of chunk input file including chunk header and data */
+} chunk_header_t;
+
+/* Following a Raw or Fill chunk is data.  For a Raw chunk, it's the data in chunk_sz * blk_sz.
+ * For a Fill chunk, it's 4 bytes of the fill data.
+ */
diff --git a/src/bsp/lk/lib/fastboot/rules.mk b/src/bsp/lk/lib/fastboot/rules.mk
new file mode 100644
index 0000000..edb4fc6
--- /dev/null
+++ b/src/bsp/lk/lib/fastboot/rules.mk
@@ -0,0 +1,22 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/dl_commands.c \
+    $(LOCAL_DIR)/fastboot.c \
+    $(LOCAL_DIR)/ext_boot.c \
+
+MODULE_DEPS += \
+    lib/bio \
+    lib/mempool
+
+MODULE_COMPILEFLAGS += -Wno-sign-compare
+
+ifeq ($(strip $(ANDROID_2712)),yes)
+MODULE_COMPILEFLAGS += -DMT2712_ANDROID
+endif
+
+EXTRA_LINKER_SCRIPTS += $(LOCAL_DIR)/fastboot_oem_cmd.ld
+
+include make/module.mk