[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