[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/platform/mediatek/common/arch/arm/mp.c b/src/bsp/lk/platform/mediatek/common/arch/arm/mp.c
new file mode 120000
index 0000000..a2426e7
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/arch/arm/mp.c
@@ -0,0 +1 @@
+../arm64/mp.c
\ No newline at end of file
diff --git a/src/bsp/lk/platform/mediatek/common/arch/arm64/mp.c b/src/bsp/lk/platform/mediatek/common/arch/arm64/mp.c
new file mode 100644
index 0000000..4ad7d24
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/arch/arm64/mp.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <arch/arch_ops.h>
+#include <arch/mp.h>
+#include <arch/mp_mediatek.h>
+#include <arch/ops.h>
+#include <assert.h>
+#include <compiler.h>
+#include <debug.h>
+#include <dev/interrupt/arm_gic.h>
+#include <err.h>
+#include <kernel/mp.h>
+#include <kernel/thread.h>
+#include <lk/init.h>
+#include <platform/interrupts.h>
+#include <platform/psci.h>
+#include <sys/types.h>
+#include <trace.h>
+
+#if LK_AS_BL33 == 0
+#error "MTK BL2 does not support SMP yet!"
+#endif
+
+#define LOCAL_TRACE 0
+
+/*
+ * [platform smp note]
+ * Platform should add platform specific stuff to support smp:
+ * 1. define following SMP constants in platform specific makefile,
+ *      SMP_MAX_CPUS:
+ *          Max number of cpus to be used
+ *      SMP_CPU_CLUSTER_SHIFT:
+ *          Bits to shift for cluster to form linear cpu id.
+ *          For example, if at most 4 cores in a cluster, set this to 2.
+ * 2. add "struct smp_cpu_info smp_cpu" in platform code.
+ * 3. implement void platform_quiesce(void) to call plat_mp_off().
+ * 4. optional: add PLAT_GIC_IPI_BASE to GLOBAL_DEFINES constant in makefile
+ *    if platform required IPI base other than 0.
+ */
+
+/* set PLAT_GIC_IPI_BASE to non-secure interrupt base */
+#if !defined(PLAT_GIC_IPI_BASE)
+#define PLAT_GIC_IPI_BASE   0
+#endif
+
+#define MAX_IPI_NUM 15
+enum {
+    MTK_PLAT_MP_IPI_GENERIC = MP_IPI_GENERIC,
+    MTK_PLAT_MP_IPI_RESCHEDULE = MP_IPI_RESCHEDULE,
+    MTK_PLAT_MP_IPI_CUSTOM_START,
+};
+
+STATIC_ASSERT(MTK_PLAT_MP_IPI_CUSTOM_START <= MAX_IPI_NUM);
+
+
+status_t plat_mp_send_ipi(mp_cpu_mask_t target, uint ipi)
+{
+    LTRACEF_LEVEL(2, "target 0x%x, ipi %u\n", target, ipi);
+
+    uint gic_ipi_num = ipi + PLAT_GIC_IPI_BASE;
+
+    /* filter out targets outside of the range of cpus we care about */
+    target &= ((1UL << SMP_MAX_CPUS) - 1);
+    if (target != 0) {
+        LTRACEF_LEVEL(2, "target 0x%x, gic_ipi %u\n", target, gic_ipi_num);
+        arm_gic_sgi(gic_ipi_num, ARM_GIC_SGI_FLAG_NS, target);
+    }
+
+    return NO_ERROR;
+}
+
+status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi)
+{
+    return plat_mp_send_ipi(target, ipi);
+}
+
+void arch_mp_init_percpu(void)
+{
+    extern enum handler_return arm_ipi_generic_handler(void *arg);
+    extern enum handler_return arm_ipi_reschedule_handler(void *arg);
+
+    register_int_handler(MTK_PLAT_MP_IPI_GENERIC + PLAT_GIC_IPI_BASE,
+            &arm_ipi_generic_handler, 0);
+    register_int_handler(MTK_PLAT_MP_IPI_RESCHEDULE + PLAT_GIC_IPI_BASE,
+            &arm_ipi_reschedule_handler, 0);
+
+    unmask_interrupt(MTK_PLAT_MP_IPI_GENERIC + PLAT_GIC_IPI_BASE);
+    unmask_interrupt(MTK_PLAT_MP_IPI_RESCHEDULE + PLAT_GIC_IPI_BASE);
+}
+
+static int cpu_off_thread(void *arg)
+{
+    int ret;
+
+    arch_disable_ints();
+
+    THREAD_LOCK(state);
+    mp_set_curr_cpu_active(false);
+    THREAD_UNLOCK(state);
+
+    /* executed by the to-be-off cpu */
+    ret = psci_cpu_off(); /* should never return */
+    DEBUG_ASSERT(ret && 0);
+
+    return -1;
+}
+
+__WEAK void plat_pre_cpu_on(void)
+{
+}
+
+static void plat_mp_on(uint level)
+{
+    extern struct smp_cpu_info smp_cpu;
+    int i, ret;
+    uint32_t local_cpu = arch_curr_cpu_num();
+    uint32_t cpu_on_mask = smp_cpu.cpu_on_mask & ~(1U << local_cpu);
+
+    plat_pre_cpu_on(); /* preprocess cpu if necessary */
+
+    for (i = 0; i < SMP_MAX_CPUS; i++) {
+        if (cpu_on_mask & (1 << i)) {
+            ret = psci_cpu_on(smp_cpu.id[i], MEMBASE + KERNEL_LOAD_OFFSET, 0);
+            LTRACEF("plat_mp_on cpu=0x%x, ret=%d, entry=%x\n",
+                    smp_cpu.id[i], ret, MEMBASE + KERNEL_LOAD_OFFSET);
+        }
+    }
+}
+
+void plat_mp_off(void)
+{
+    mp_cpu_mask_t target = 0;
+    uint32_t local_cpu = arch_curr_cpu_num();
+    thread_t *t;
+    uint32_t cpu;
+
+    for (cpu = 0; cpu < SMP_MAX_CPUS; cpu++) {
+        if (mp_is_cpu_active(cpu) && (cpu != local_cpu)) {
+            t = thread_create("cpu_off_thread", &cpu_off_thread, NULL,
+                              DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+            thread_set_pinned_cpu(t, cpu);
+            thread_detach_and_resume(t);
+            target |= (1 << cpu);
+        }
+    }
+
+    plat_mp_send_ipi(target, MTK_PLAT_MP_IPI_RESCHEDULE);
+}
+
+static int dummy_worker(void *arg)
+{
+    /* do nothing, just to let boot cpu go away from blxboot thread */
+    return 0;
+}
+
+void plat_mp_bootcpu_handover(uint32_t cpu)
+{
+    uint32_t curr_cpu = arch_curr_cpu_num();
+    thread_t *curr_thread;
+    thread_t *dummy_thread;
+
+    DEBUG_ASSERT(!arch_ints_disabled());
+
+    if (curr_cpu == cpu)
+        return;
+
+    if (!mp_is_cpu_active(cpu)) {
+        LTRACEF("handover cpu=%u is not active.\n", cpu);
+        return;
+    }
+
+    /* switch boot cpu to new one */
+    curr_thread = get_current_thread();
+    thread_set_pinned_cpu(curr_thread, cpu);
+    dummy_thread = thread_create("dummy_worker", &dummy_worker, NULL,
+                                 DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+    thread_detach_and_resume(dummy_thread);
+    LTRACEF("new cpu=%u\n", arch_curr_cpu_num());
+}
+
+LK_INIT_HOOK(plat_mp_on, &plat_mp_on, LK_INIT_LEVEL_THREADING);
diff --git a/src/bsp/lk/platform/mediatek/common/boot_mode.c b/src/bsp/lk/platform/mediatek/common/boot_mode.c
new file mode 100644
index 0000000..a2a3882
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/boot_mode.c
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#include <boot_mode.h>
+#include <compiler.h>
+#include <platform/debug.h>
+#include <platform/mtk_key.h>
+#include <platform/mtk_wdt.h>
+
+static bool check_uart_enter(void)
+{
+    char c;
+    if (platform_dgetc(&c, false) != 0)
+        return false;
+    return (c == 13);
+}
+
+static bool download_check(void)
+{
+    return (check_fastboot_mode() ||
+            check_download_key() ||
+            check_uart_enter());
+}
+
+/* platform specific boot mode determination */
+__WEAK uint32_t plat_get_boot_mode(void)
+{
+    return NORMAL_BOOT;
+}
+
+uint32_t get_boot_mode(void)
+{
+    uint32_t boot_mode;
+
+    if (download_check()) {
+        boot_mode = FASTBOOT_BOOT;
+        if (OPTION_CLEAR_FASTBOOT_FLAG)
+            set_clr_fastboot_mode(false);
+    } else if (check_recovery_mode()) {
+        boot_mode = RECOVERY_BOOT;
+        if (OPTION_CLEAR_RECOVERY_FLAG)
+            set_clr_recovery_mode(false);
+    } else {
+        boot_mode = plat_get_boot_mode();
+    }
+    return boot_mode;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/debug.c b/src/bsp/lk/platform/mediatek/common/debug.c
new file mode 100644
index 0000000..ae4a7a4
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/debug.c
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#include <platform/debug.h>
+#include <platform/mt_uart.h>
+
+void platform_dputc(char c)
+{
+    if (c == '\n')
+        mtk_uart_putc('\r');
+    mtk_uart_putc(c);
+}
+
+int platform_dgetc(char *c, bool wait)
+{
+    int ret = mtk_uart_getc(wait);
+    if (ret == -1)
+        return -1;
+    *c = ret;
+    return 0;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/emi/emi_info_v1.c b/src/bsp/lk/platform/mediatek/common/drivers/emi/emi_info_v1.c
new file mode 100644
index 0000000..b2cc8c5
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/emi/emi_info_v1.c
@@ -0,0 +1,134 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek Software")
+* have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+* applicable license agreements with MediaTek Inc.
+*/
+
+#include <boot_args.h>
+#include <libfdt.h>
+#include <debug.h>
+
+extern BOOT_ARGUMENT g_boot_arg;
+
+int set_fdt_emi_info(void *fdt)
+{
+	int ret = 0;
+	int offset;
+	unsigned int i;
+	unsigned int dram_type;
+	unsigned int ch_num;
+	unsigned int rk_num;
+	unsigned int rank_size[MAX_RK];
+
+	if (!fdt)
+		return -1;
+
+	offset = fdt_path_offset(fdt, "/emi");
+	if (offset < 0)
+		return offset;
+
+	dram_type = cpu_to_fdt32(g_boot_arg.emi_info.dram_type);
+	ch_num = cpu_to_fdt32(g_boot_arg.emi_info.ch_num);
+	rk_num = cpu_to_fdt32(g_boot_arg.emi_info.rk_num);
+
+	/* unit of rank size: 1Gb (128MB) */
+	for (i = 0; i < MAX_RK; i++) {
+		if (i < rk_num) {
+			rank_size[i] = (g_boot_arg.emi_info.rank_size[i] >> 27) & 0xFFFFFFFF;
+			rank_size[i] = cpu_to_fdt32(rank_size[i]);
+		} else {
+			rank_size[i] = cpu_to_fdt32(0);
+		}
+	}
+
+	/* pass parameter to kernel */
+	ret = fdt_setprop(fdt, offset, "emi_info,dram_type", &dram_type, sizeof(dram_type));
+	if (ret < 0)
+		return ret;
+
+	ret = fdt_setprop(fdt, offset, "emi_info,ch_num", &ch_num, sizeof(ch_num));
+	if (ret < 0)
+		return ret;
+
+	ret = fdt_setprop(fdt, offset, "emi_info,rk_num", &rk_num, sizeof(rk_num));
+	if (ret < 0)
+		return ret;
+
+	ret = fdt_setprop(fdt, offset, "emi_info,rank_size", rank_size, sizeof(rank_size));
+
+	return ret;
+}
+
+typedef struct {      /* RAM configuration */
+	unsigned int start_hi;
+	unsigned int start_lo;
+	unsigned int size_hi;
+	unsigned int size_lo;
+} dt_dram_info;
+
+
+__WEAK u64 get_dram_size(void)
+{
+	return -1;
+}
+
+int set_fdt_dram_size(void *fdt)
+{
+	int ret = -1;
+	int offset;
+	u64 dram_sz;
+	int lenth;
+	const unsigned int *strings;
+	dt_dram_info mem_reg_property;
+	if (!fdt)
+		return -1;
+
+	offset = fdt_path_offset(fdt, "/memory");
+	if (offset < 0)
+		return offset;
+
+	strings = fdt_getprop(fdt, offset, "reg", &lenth);
+
+	mem_reg_property.start_hi = strings[0];
+	mem_reg_property.start_lo = strings[1];
+
+	dram_sz = get_dram_size();
+	if(dram_sz < 0)
+		return -1;
+	mem_reg_property.size_hi = cpu_to_fdt32(dram_sz >> 32);
+	mem_reg_property.size_lo = cpu_to_fdt32(dram_sz);
+
+	/* pass parameter to kernel */
+	ret = fdt_setprop(fdt, offset, "reg", &mem_reg_property, sizeof(dt_dram_info));
+
+	return ret;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/mtcmos/mtcmos.c b/src/bsp/lk/platform/mediatek/common/drivers/mtcmos/mtcmos.c
new file mode 100644
index 0000000..81d6267
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/mtcmos/mtcmos.c
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#include <platform/mtcmos.h>
+#include <platform/reg_utils.h>
+#include <platform/spm.h>
+
+struct power_domain_data {
+    void *pwr_con;
+    unsigned int pwr_sta_mask;
+    unsigned int sram_pdn_mask;
+    unsigned int sram_ack_mask;
+};
+
+enum {
+    SRAM_ISOINT_B = 1U << 6,
+    SRAM_CKISO    = 1U << 5,
+    PWR_CLK_DIS   = 1U << 4,
+    PWR_ON_2ND    = 1U << 3,
+    PWR_ON        = 1U << 2,
+    PWR_ISO       = 1U << 1,
+    PWR_RST_B     = 1U << 0
+};
+
+enum {
+    DISP_PWR_STA_MASK  = 0x1 << 3,
+    AUDIO_PWR_STA_MASK = 0x1 << 24,
+};
+
+static void mtcmos_power_on(const struct power_domain_data *pd)
+{
+    writel_r(&mtk_spm->poweron_config_set,
+        (SPM_PROJECT_CODE << 16) | (1U << 0));
+
+    setbits32(pd->pwr_con, PWR_ON);
+    setbits32(pd->pwr_con, PWR_ON_2ND);
+
+    while (!(readl(&mtk_spm->pwr_status) & pd->pwr_sta_mask) ||
+           !(readl(&mtk_spm->pwr_status_2nd) & pd->pwr_sta_mask))
+        continue;
+
+    clrbits32(pd->pwr_con, PWR_CLK_DIS);
+    clrbits32(pd->pwr_con, PWR_ISO);
+    setbits32(pd->pwr_con, PWR_RST_B);
+    clrbits32(pd->pwr_con, pd->sram_pdn_mask);
+
+    while (readl(pd->pwr_con) & pd->sram_ack_mask)
+        continue;
+}
+
+void mtcmos_display_power_on(void)
+{
+    static const struct power_domain_data disp = {
+        .pwr_con = &mtk_spm->dis_pwr_con,
+        .pwr_sta_mask = DISP_PWR_STA_MASK,
+        .sram_pdn_mask = DISP_SRAM_PDN_MASK,
+        .sram_ack_mask = DISP_SRAM_ACK_MASK,
+    };
+
+    mtcmos_power_on(&disp);
+}
+
+void mtcmos_audio_power_on(void)
+{
+    static const struct power_domain_data audio = {
+        .pwr_con = &mtk_spm->audio_pwr_con,
+        .pwr_sta_mask = AUDIO_PWR_STA_MASK,
+        .sram_pdn_mask = AUDIO_SRAM_PDN_MASK,
+        .sram_ack_mask = AUDIO_SRAM_ACK_MASK,
+    };
+
+    mtcmos_power_on(&audio);
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/pll/pll.c b/src/bsp/lk/platform/mediatek/common/drivers/pll/pll.c
new file mode 100644
index 0000000..b2a68d5
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/pll/pll.c
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#include <assert.h>
+#include <platform/pll.h>
+#include <platform/reg_utils.h>
+
+#define BIT(x) (1ul << (x))
+#define GENMASK(h, l) (BIT(h + 1) - BIT(l))
+
+void mux_set_sel(const struct mux *mux, unsigned int sel)
+{
+    unsigned int mask = GENMASK(mux->mux_width - 1, 0);
+    unsigned int val = readl(mux->reg);
+
+    val &= ~(mask << mux->mux_shift);
+    val |= (sel & mask) << mux->mux_shift;
+    writel_r(mux->reg, val);
+    if (mux->upd_reg)
+        writel_r(mux->upd_reg, 1 << mux->upd_shift);
+}
+
+static void pll_calc_values(const struct pll *pll, unsigned int *pcw, unsigned int *postdiv,
+                            unsigned int freq)
+{
+    const unsigned int fin_hz = CLK26M_HZ;
+    const unsigned int *div_rate = pll->div_rate;
+    unsigned int val;
+
+    assert(freq <= div_rate[0]);
+    assert(freq >= 1 * GHz / 16);
+
+    for (val = 1; div_rate[val] != 0; val++) {
+        if (freq > div_rate[val])
+            break;
+    }
+    val--;
+    *postdiv = val;
+
+    /* _pcw = freq * 2^postdiv / fin * 2^pcwbits_fractional */
+    val += pll->pcwbits - PCW_INTEGER_BITS;
+
+    *pcw = ((u64)freq << val) / fin_hz;
+}
+
+static void pll_set_rate_regs(const struct pll *pll, unsigned int pcw, unsigned int postdiv)
+{
+    unsigned int val;
+
+    /* set postdiv */
+    val = readl(pll->div_reg);
+    val &= ~(PLL_POSTDIV_MASK << pll->div_shift);
+    val |= postdiv << pll->div_shift;
+
+    /* set postdiv and pcw at the same time if on the same register */
+    if (pll->div_reg != pll->pcw_reg) {
+        writel_r(pll->div_reg, val);
+        val = readl(pll->pcw_reg);
+    }
+
+    /* set pcw */
+    val &= ~GENMASK(pll->pcw_shift + pll->pcwbits - 1, pll->pcw_shift);
+    val |= pcw << pll->pcw_shift;
+    writel_r(pll->pcw_reg, val);
+
+    pll_set_pcw_change(pll);
+}
+
+int pll_set_rate(const struct pll *pll, unsigned int rate)
+{
+    unsigned int pcw, postdiv;
+
+    pll_calc_values(pll, &pcw, &postdiv, rate);
+    pll_set_rate_regs(pll, pcw, postdiv);
+
+    return 0;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/pmic/regulator.c b/src/bsp/lk/platform/mediatek/common/drivers/pmic/regulator.c
new file mode 100644
index 0000000..a6b9c53
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/pmic/regulator.c
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#include <platform/mt6358.h>
+#include <platform/regulator.h>
+#include <platform/regulator_core.h>
+#include <string.h>
+
+static struct mtk_regulator mtk_regulator_table[MTK_REGULATOR_MAX_NR];
+
+int mtk_regulator_get(const char *id, struct mtk_regulator *mreg)
+{
+    int i = 0;
+
+    for (i = 0; i < MTK_REGULATOR_MAX_NR; i++) {
+        if (mtk_regulator_table[i].name != 0) {
+            if (strcmp(mtk_regulator_table[i].name, id) == 0) {
+                memcpy(mreg, &mtk_regulator_table[i],
+                    sizeof(struct mtk_regulator));
+                return 0;
+            }
+        }
+    }
+    return -1;
+}
+
+int mtk_simple_regulator_register(struct mtk_regulator *mreg)
+{
+    if (mreg == 0)
+        return -1;
+    memcpy(&mtk_regulator_table[mreg->id], mreg,
+                sizeof(struct mtk_regulator));
+    return 0;
+}
+
+int mtk_regulator_enable(struct mtk_regulator *mreg, unsigned char enable)
+{
+    int ret = 0;
+
+    ret = mreg->reg_ops->enable(mreg->id, enable);
+    return ret;
+}
+
+int mtk_regulator_is_enabled(struct mtk_regulator *mreg)
+{
+    int ret = 0;
+
+    ret = mreg->reg_ops->is_enabled(mreg->id);
+    return ret;
+}
+
+int mtk_regulator_set_voltage(struct mtk_regulator *mreg, int min_uv, int max_uv)
+{
+    int ret = 0;
+
+    ret = mreg->reg_ops->set_voltage(mreg->id, min_uv, max_uv);
+    return ret;
+}
+
+int mtk_regulator_get_voltage(struct mtk_regulator *mreg)
+{
+    int ret = 0;
+
+    ret = mreg->reg_ops->get_voltage(mreg->id);
+    return ret;
+}
+
+int mtk_regulator_set_mode(struct mtk_regulator *mreg, unsigned char mode)
+{
+    int ret = 0;
+    ret = mreg->reg_ops->set_mode(mreg->id, mode);
+    return ret;
+}
+
+int mtk_regulator_get_mode(struct mtk_regulator *mreg)
+{
+    int ret = 0;
+    ret = mreg->reg_ops->get_mode(mreg->id);
+    return ret;
+}
+
+int mtk_regulator_set_votrim(struct mtk_regulator *mreg, int trim_uv)
+{
+    int ret = 0;
+    ret = mreg->reg_ops->set_votrim(mreg->id, trim_uv);
+    return ret;
+}
+
+int mtk_regulator_get_votrim(struct mtk_regulator *mreg)
+{
+    int ret = 0;
+    ret = mreg->reg_ops->get_votrim(mreg->id);
+    return ret;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/pmic_wrap/pmic_wrap_common.c b/src/bsp/lk/platform/mediatek/common/drivers/pmic_wrap/pmic_wrap_common.c
new file mode 100644
index 0000000..06ef299
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/pmic_wrap/pmic_wrap_common.c
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+#include <platform.h>
+#include <platform/pmic_wrap.h>
+#include <reg.h>
+
+u32 wait_for_state_idle(u32 timeout_us, void *wacs_register,
+			void *wacs_vldclr_register, u32 *read_reg)
+{
+	u32 reg_rdata;
+	lk_bigtime_t start = current_time_hires();
+
+	do {
+		reg_rdata = readl(wacs_register);
+		/* if last read command timeout,clear vldclr bit
+		   read command state machine:FSM_REQ-->wfdle-->WFVLDCLR;
+		   write:FSM_REQ-->idle */
+		switch (((reg_rdata >> RDATA_WACS_FSM_SHIFT) &
+			RDATA_WACS_FSM_MASK)) {
+		case WACS_FSM_WFVLDCLR:
+			writel(1, wacs_vldclr_register);
+			pwrap_err("WACS_FSM = PMIC_WRAP_WACS_VLDCLR\n");
+			break;
+		case WACS_FSM_WFDLE:
+			pwrap_err("WACS_FSM = WACS_FSM_WFDLE\n");
+			break;
+		case WACS_FSM_REQ:
+			pwrap_err("WACS_FSM = WACS_FSM_REQ\n");
+			break;
+		default:
+			break;
+		}
+
+		if ((current_time_hires() - start) > timeout_us)
+			return E_PWR_WAIT_IDLE_TIMEOUT;
+
+	} while (((reg_rdata >> RDATA_WACS_FSM_SHIFT) & RDATA_WACS_FSM_MASK) !=
+		 WACS_FSM_IDLE);  /* IDLE State */
+	if (read_reg)
+		*read_reg = reg_rdata;
+	return 0;
+}
+
+u32 wait_for_state_ready(loop_condition_fp fp, u32 timeout_us,
+			 void *wacs_register, u32 *read_reg)
+{
+	u32 reg_rdata;
+	lk_bigtime_t start = current_time_hires();
+
+	do {
+		reg_rdata = readl((wacs_register));
+		if ((current_time_hires() - start) > timeout_us)
+			return E_PWR_WAIT_IDLE_TIMEOUT;
+	} while (fp(reg_rdata));  /* IDLE State */
+	if (read_reg)
+		*read_reg = reg_rdata;
+	return 0;
+}
+
+s32 pwrap_reset_spislv(void)
+{
+	u32 ret = 0;
+
+	writel(0, &mtk_pwrap->hiprio_arb_en);
+	writel(0, &mtk_pwrap->wrap_en);
+	writel(1, &mtk_pwrap->mux_sel);
+	writel(1, &mtk_pwrap->man_en);
+	writel(0, &mtk_pwrap->dio_en);
+
+	writel((OP_WR << 13) | (OP_CSL << 8), &mtk_pwrap->man_cmd);
+	/* Reset counter */
+	writel((OP_WR << 13) | (OP_OUTS << 8), &mtk_pwrap->man_cmd);
+	writel((OP_WR << 13) | (OP_CSH << 8), &mtk_pwrap->man_cmd);
+	/*
+	 * In order to pull CSN signal to PMIC,
+	 * PMIC will count it then reset spi slave
+	 */
+	writel((OP_WR << 13) | (OP_OUTS << 8), &mtk_pwrap->man_cmd);
+	writel((OP_WR << 13) | (OP_OUTS << 8), &mtk_pwrap->man_cmd);
+	writel((OP_WR << 13) | (OP_OUTS << 8), &mtk_pwrap->man_cmd);
+	writel((OP_WR << 13) | (OP_OUTS << 8), &mtk_pwrap->man_cmd);
+
+	if (wait_for_state_ready(wait_for_sync, TIMEOUT_WAIT_IDLE_US,
+				 &mtk_pwrap->wacs2_rdata, 0))
+		ret = E_PWR_TIMEOUT;
+
+	writel(0, &mtk_pwrap->man_en);
+	writel(0, &mtk_pwrap->mux_sel);
+
+	return ret;
+}
+
+s32 pwrap_wacs2(u32 write, u16 addr, u16 wdata, u16 *rdata, u32 init_check)
+{
+	u32 reg_rdata = 0;
+	u32 wacs_write = 0;
+	u32 wacs_addr = 0;
+	u32 wacs_cmd = 0;
+	u32 wait_result = 0;
+
+	if (init_check) {
+		reg_rdata = readl(&mtk_pwrap->wacs2_rdata);
+		/* Prevent someone to use pwrap before pwrap init */
+		if (((reg_rdata >> RDATA_INIT_DONE_SHIFT) &
+		    RDATA_INIT_DONE_MASK) != WACS_INIT_DONE) {
+			pwrap_err("Pwrap initialization isn't finished\n");
+			return E_PWR_NOT_INIT_DONE;
+		}
+	}
+	reg_rdata = 0;
+	/* Check IDLE in advance */
+	wait_result = wait_for_state_idle(TIMEOUT_WAIT_IDLE_US,
+					  &mtk_pwrap->wacs2_rdata,
+					  &mtk_pwrap->wacs2_vldclr,
+					  0);
+	if (wait_result != 0) {
+		pwrap_err("wait_for_fsm_idle fail,wait_result=%d\n",
+			  wait_result);
+		return E_PWR_WAIT_IDLE_TIMEOUT;
+	}
+	wacs_write = write << 31;
+	wacs_addr = (addr >> 1) << 16;
+	wacs_cmd = wacs_write | wacs_addr | wdata;
+
+	writel(wacs_cmd, &mtk_pwrap->wacs2_cmd);
+	if (write == 0) {
+		if (rdata == NULL) {
+			pwrap_err("rdata is a NULL pointer\n");
+			return E_PWR_INVALID_ARG;
+		}
+		wait_result = wait_for_state_ready(wait_for_fsm_vldclr,
+						   TIMEOUT_READ_US,
+						   &mtk_pwrap->wacs2_rdata,
+						   &reg_rdata);
+		if (wait_result != 0) {
+			pwrap_err("wait_for_fsm_vldclr fail,wait_result=%d\n",
+				  wait_result);
+			return E_PWR_WAIT_IDLE_TIMEOUT_READ;
+		}
+		*rdata = ((reg_rdata >> RDATA_WACS_RDATA_SHIFT)
+			  & RDATA_WACS_RDATA_MASK);
+		writel(1, &mtk_pwrap->wacs2_vldclr);
+	}
+
+	return 0;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/rtc/rtc_common.c b/src/bsp/lk/platform/mediatek/common/drivers/rtc/rtc_common.c
new file mode 100644
index 0000000..ad95044
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/rtc/rtc_common.c
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+#include <platform/rtc_common.h>
+#include <platform/rtc.h>
+#include <platform/pmic_wrap.h>
+
+extern lk_time_t current_time(void);
+/* ensure rtc write success */
+int rtc_busy_wait(void)
+{
+    lk_time_t begin = current_time();
+    u16 bbpu;
+
+    do {
+        rtc_read(RTC_BBPU, &bbpu);
+        /* Time > 1sec, time out and set recovery mode enable.*/
+        if (current_time() - begin > 1000000) {
+            rtc_info("BBPU CBUSY time out !!\n");
+            return 0;
+        }
+    } while (bbpu & RTC_BBPU_CBUSY);
+
+    return 1;
+}
+
+int rtc_write_trigger(void)
+{
+    rtc_write(RTC_WRTGR, 1);
+    return rtc_busy_wait();
+}
+
+/* unlock rtc write interface */
+int rtc_writeif_unlock(void)
+{
+    rtc_write(RTC_PROT, RTC_PROT_UNLOCK1);
+    if (!rtc_write_trigger())
+        return 0;
+    rtc_write(RTC_PROT, RTC_PROT_UNLOCK2);
+    if (!rtc_write_trigger())
+        return 0;
+
+    return 1;
+}
+
+/* set rtc time */
+int rtc_set(const struct rtc_time *time)
+{
+    return -1;
+}
+
+/* get rtc time */
+int rtc_get(struct rtc_time *time)
+{
+    u16 value;
+
+    rtc_read(RTC_TC_SEC, &value);
+    time->sec = value;
+    rtc_read(RTC_TC_MIN, &value);
+    time->min = value;
+    rtc_read(RTC_TC_HOU, &value);
+    time->hour = value;
+    rtc_read(RTC_TC_DOM, &value);
+    time->mday = value;
+    rtc_read(RTC_TC_MTH, &value);
+    time->mon = value;
+    rtc_read(RTC_TC_YEA, &value);
+    time->year = (value + RTC_MIN_YEAR_OFFSET) % 100;
+
+    return 0;
+}
+
+/* set rtc xosc setting */
+int rtc_xosc_write(u16 val)
+{
+    u16 bbpu;
+
+    rtc_write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK1);
+    if (!rtc_busy_wait())
+        return 0;
+    rtc_write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK2);
+    if (!rtc_busy_wait())
+        return 0;
+
+    rtc_write(RTC_OSC32CON, val);
+    if (!rtc_busy_wait())
+        return 0;
+
+    rtc_read(RTC_BBPU, &bbpu);
+    bbpu |= RTC_BBPU_KEY | RTC_BBPU_RELOAD;
+    rtc_write(RTC_BBPU, bbpu);
+
+    return rtc_write_trigger();
+}
+
+/* initialize rtc related registers */
+int rtc_reg_init(void)
+{
+    u16 irqsta;
+
+    rtc_write(RTC_IRQ_EN, 0);
+    rtc_write(RTC_CII_EN, 0);
+    rtc_write(RTC_AL_MASK, 0);
+    rtc_write(RTC_AL_YEA, 1970 - RTC_MIN_YEAR);
+    rtc_write(RTC_AL_MTH, 1);
+    rtc_write(RTC_AL_DOM, 1);
+    rtc_write(RTC_AL_DOW, 4);
+    rtc_write(RTC_AL_HOU, 0);
+    rtc_write(RTC_AL_MIN, 0);
+    rtc_write(RTC_AL_SEC, 0);
+
+    rtc_write(RTC_DIFF, 0);
+    rtc_write(RTC_CALI, 0);
+    if (!rtc_write_trigger())
+        return 0;
+
+    rtc_read(RTC_IRQ_STA, &irqsta);  /* read clear */
+
+    /* init time counters after resetting RTC_DIFF and RTC_CALI */
+    rtc_write(RTC_TC_YEA, RTC_DEFAULT_YEA - RTC_MIN_YEAR);
+    rtc_write(RTC_TC_MTH, RTC_DEFAULT_MTH);
+    rtc_write(RTC_TC_DOM, RTC_DEFAULT_DOM);
+    rtc_write(RTC_TC_DOW, RTC_DEFAULT_DOW);
+    rtc_write(RTC_TC_HOU, 0);
+    rtc_write(RTC_TC_MIN, 0);
+    rtc_write(RTC_TC_SEC, 0);
+    if (!rtc_write_trigger())
+        return 0;
+
+    rtc_write(RTC_PDN1, 0);
+    rtc_write(RTC_PDN2, 0);
+    rtc_write(RTC_SPAR0, 0);
+    rtc_write(RTC_SPAR1, 0);
+    return rtc_write_trigger();
+}
+
+static u8 rtc_check_state(void)
+{
+    u16 con;
+    u16 pwrky1;
+    u16 pwrky2;
+
+    rtc_read(RTC_CON, &con);
+    rtc_read(RTC_POWERKEY1, &pwrky1);
+    rtc_read(RTC_POWERKEY2, &pwrky2);
+
+    rtc_info("con=%x, pwrkey1=%x, pwrkey2=%x\n", con, pwrky1, pwrky2);
+
+    if (con & RTC_CON_LPSTA_RAW)
+        return RTC_STATE_INIT;
+
+    if (!rtc_busy_wait())
+        return RTC_STATE_RECOVER;
+
+    if (!rtc_writeif_unlock())
+        return RTC_STATE_RECOVER;
+
+    if (pwrky1 != RTC_POWERKEY1_KEY || pwrky2 != RTC_POWERKEY2_KEY)
+        return RTC_STATE_INIT;
+    else
+        return RTC_STATE_REBOOT;
+}
+
+void rtc_boot_common(void)
+{
+    u16 bbpu;
+    u16 con;
+    u16 irqsta;
+
+    switch (rtc_check_state()) {
+        case RTC_STATE_REBOOT:
+            pwrap_write_field(RTC_BBPU, RTC_BBPU_KEY | RTC_BBPU_RELOAD,
+                              0xFFFF, 0);
+            rtc_write_trigger();
+            rtc_osc_init();
+            break;
+        case RTC_STATE_RECOVER:
+            rtc_init(1);
+            break;
+        case RTC_STATE_INIT:
+        default:
+            if (rtc_init(0))
+                rtc_init(1);
+            break;
+    }
+
+    rtc_read(RTC_IRQ_STA, &irqsta);  /* Read clear */
+    rtc_read(RTC_BBPU, &bbpu);
+    rtc_read(RTC_CON, &con);
+
+    rtc_info("irqsta=%x, bbpu=%x, con=%x\n", irqsta, bbpu, con);
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/smc/psci.c b/src/bsp/lk/platform/mediatek/common/drivers/smc/psci.c
new file mode 100644
index 0000000..6f6bb2f
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/smc/psci.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018 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 <platform/smc.h>
+#include <sys/types.h>
+
+#define PSCI_CPU_OFF_FUNC_ID    0x84000002
+#define PSCI_CPU_ON_FUNC_ID_32  0x84000003
+#define PSCI_CPU_ON_FUNC_ID_64  0xc4000003
+
+#if ARCH_ARM64
+#define PSCI_CPU_ON_FUNC_ID     PSCI_CPU_ON_FUNC_ID_64
+#else
+#define PSCI_CPU_ON_FUNC_ID     PSCI_CPU_ON_FUNC_ID_32
+#endif
+
+int psci_cpu_on(ulong target_cpu, ulong ep, ulong context_id)
+{
+    struct __smccc_res res;
+
+    __smc_pipe(PSCI_CPU_ON_FUNC_ID, target_cpu, ep, context_id, 0, &res);
+    return (int)res.a0;
+}
+
+int psci_cpu_off(void)
+{
+    struct __smccc_res res;
+
+    __smc_pipe(PSCI_CPU_OFF_FUNC_ID, 0, 0, 0, 0, &res);
+    return (int)res.a0;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/smc/smc.c b/src/bsp/lk/platform/mediatek/common/drivers/smc/smc.c
new file mode 100644
index 0000000..8c8b8b3
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/smc/smc.c
@@ -0,0 +1,72 @@
+/*
+ * 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.
+*/
+
+#include <platform/smc.h>
+#include <sys/types.h>
+
+void __smc_pipe(size_t smc_id, ulong arg0, ulong arg1, ulong arg2, ulong arg3,
+                struct __smccc_res *res)
+{
+    ulong ret0, ret1, ret2, ret3;
+
+#if ARCH_ARM64
+    __asm__ volatile("mov w0, %w[fid]\n\t"
+                     "mov x1, %[a0]\n\t"
+                     "mov x2, %[a1]\n\t"
+                     "mov x3, %[a2]\n\t"
+                     "mov x4, %[a3]\n\t"
+                     "smc #0       \n\t"
+                     "mov %[rt0], x0\n\t"
+                     "mov %[rt1], x1\n\t"
+                     "mov %[rt2], x2\n\t"
+                     "mov %[rt3], x3\n\t"
+                     : [rt0] "=r" (ret0), [rt1] "=r" (ret1), [rt2] "=r" (ret2),
+                       [rt3] "=r" (ret3)
+                     : [fid] "r" (smc_id), [a0] "r" (arg0), [a1] "r" (arg1),
+                       [a2] "r" (arg2), [a3] "r" (arg3)
+                     : "x0", "x1", "x2", "x3", "x4");
+#else
+    __asm__ volatile("mov r0, %[fid]\n\t"
+                     "mov r1, %[a0]\n\t"
+                     "mov r2, %[a1]\n\t"
+                     "mov r3, %[a2]\n\t"
+                     "mov r4, %[a3]\n\t"
+                     "smc #0       \n\t"
+                     "mov %[rt0], r0\n\t"
+                     "mov %[rt1], r1\n\t"
+                     "mov %[rt2], r2\n\t"
+                     "mov %[rt3], r3\n\t"
+                     : [rt0] "=r" (ret0), [rt1] "=r" (ret1), [rt2] "=r" (ret2),
+                       [rt3] "=r" (ret3)
+                     : [fid] "r" (smc_id), [a0] "r" (arg0), [a1] "r" (arg1),
+                       [a2] "r" (arg2), [a3] "r" (arg3)
+                     : "r0", "r1", "r2", "r3", "r4");
+#endif
+
+    if (res != NULL) {
+        res->a0 = ret0;
+        res->a1 = ret1;
+        res->a2 = ret2;
+        res->a3 = ret3;
+    }
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/uart/uart.c b/src/bsp/lk/platform/mediatek/common/drivers/uart/uart.c
new file mode 100644
index 0000000..7c73360
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/uart/uart.c
@@ -0,0 +1,156 @@
+/*
+ * 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.
+*/
+
+#include <debug.h>
+#include <dev/uart.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mt_uart.h>
+#include <reg.h>
+
+#define CONFIG_BAUDRATE     921600
+#define UART_BASE     (UART0_BASE)
+
+/* FCR */
+#define UART_FCR_FIFOE      (1 << 0)
+#define UART_FCR_CLRR       (1 << 1)
+#define UART_FCR_CLRT       (1 << 2)
+
+#define UART_FCR_FIFO_INIT  (UART_FCR_FIFOE|UART_FCR_CLRR|UART_FCR_CLRT)
+
+/* LCR */
+#define UART_LCR_DLAB       (1 << 7)
+
+#define UART_WLS_8      (3 << 0)
+#define UART_1_STOP     (0 << 2)
+#define UART_NONE_PARITY    (0 << 3)
+
+/* LSR */
+#define UART_LSR_DR     (1 << 0)
+#define UART_LSR_THRE       (1 << 5)
+
+#define UART_RBR      (UART_BASE+0x0)  /* Read only */
+#define UART_THR      (UART_BASE+0x0)  /* Write only */
+#define UART_FCR      (UART_BASE+0x8)  /* Write only */
+#define UART_LCR      (UART_BASE+0xc)
+#define UART_LSR      (UART_BASE+0x14)
+#define UART_DLL      (UART_BASE+0x0)  /* Only when LCR.DLAB = 1 */
+#define UART_DLH      (UART_BASE+0x4)  /* Only when LCR.DLAB = 1 */
+#define UART_HIGHSPEED    (UART_BASE+0x24)
+#define UART_SAMPLE_COUNT (UART_BASE+0x28)
+#define UART_SAMPLE_POINT (UART_BASE+0x2c)
+
+static void uart_setbrg(void)
+{
+    unsigned int byte,speed;
+    unsigned int highspeed;
+    unsigned int quot, divisor, remainder;
+    unsigned int uartclk;
+    unsigned short data, high_speed_div, sample_count, sample_point;
+    unsigned int tmp_div;
+
+    speed = CONFIG_BAUDRATE;
+    uartclk = SRC_CLOCK;
+    if (speed <= 115200 ) {
+        highspeed = 0;
+        quot = 16;
+    } else {
+        highspeed = 3;
+        quot = 1;
+    }
+
+    if (highspeed < 3) { /* 0~2 */
+        /* Set divisor DLL and DLH  */
+        divisor   =  uartclk / (quot * speed);
+        remainder =  uartclk % (quot * speed);
+
+        if (remainder >= (quot / 2) * speed)
+            divisor += 1;
+
+        writel(highspeed, UART_HIGHSPEED);
+        byte = readl(UART_LCR);   /* DLAB start */
+        writel((byte | UART_LCR_DLAB), UART_LCR);
+        writel((divisor & 0x00ff), UART_DLL);
+        writel(((divisor >> 8)&0x00ff), UART_DLH);
+        writel(byte, UART_LCR);   /* DLAB end */
+    } else {
+        data=(unsigned short)(uartclk/speed);
+        high_speed_div = (data>>8) + 1; // divided by 256
+
+        tmp_div=uartclk/(speed*high_speed_div);
+        divisor =  (unsigned short)tmp_div;
+
+        remainder = (uartclk)%(high_speed_div*speed);
+        /* get (sample_count+1) */
+        if (remainder >= ((speed)*(high_speed_div))>>1)
+            divisor =  (unsigned short)(tmp_div+1);
+        else
+            divisor =  (unsigned short)tmp_div;
+
+        sample_count=divisor-1;
+
+        /* get the sample point */
+        sample_point=(sample_count-1)>>1;
+
+        /* configure register */
+        writel(highspeed, UART_HIGHSPEED);
+
+        byte = readl(UART_LCR);    /* DLAB start */
+        writel((byte | UART_LCR_DLAB), UART_LCR);
+        writel((high_speed_div & 0x00ff), UART_DLL);
+        writel(((high_speed_div >> 8)&0x00ff), UART_DLH);
+        writel(sample_count, UART_SAMPLE_COUNT);
+        writel(sample_point, UART_SAMPLE_POINT);
+        writel(byte, UART_LCR);   /* DLAB end */
+    }
+}
+
+void uart_init_early(void)
+{
+    /* clear fifo */
+    writel(readl(UART_FCR) + UART_FCR_FIFO_INIT, UART_FCR);
+    writel(UART_NONE_PARITY | UART_WLS_8 | UART_1_STOP, UART_LCR);
+    uart_setbrg();
+}
+
+int mtk_uart_putc(char c)
+{
+    while (!(readl(UART_LSR) & UART_LSR_THRE));
+
+    if (c == '\n')
+        writel((unsigned int)'\r', UART_THR);
+
+    writel((unsigned int)c, UART_THR);
+
+    return 0;
+}
+
+int mtk_uart_getc(bool wait)
+{
+    do {
+        if (readl(UART_LSR) & UART_LSR_DR)
+            return (int)(readl(UART_RBR) & 0xFF);
+    } while (wait);
+
+    return -1; /* no data available */
+}
+
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/usb/md1122.c b/src/bsp/lk/platform/mediatek/common/drivers/usb/md1122.c
new file mode 100644
index 0000000..a9c112e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/usb/md1122.c
@@ -0,0 +1,173 @@
+/*
+ * MD1122 usb2.0 phy board for FPGA
+ *
+ * Copyright 2016 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#include <debug.h>
+#include <trace.h>
+
+#include "mtu3_hw_regs.h"
+#include "u3phy-i2c.h"
+
+#define LOCAL_TRACE 0
+
+#define MD1122_I2C_ADDR 0x60
+#define PHY_VERSION_BANK 0x20
+#define PHY_VERSION_ADDR 0xe4
+
+static void *g_ippc_port_addr;
+
+int USB_PHY_Write_Register8(unsigned char data, unsigned char addr)
+{
+    u3phy_write_reg(g_ippc_port_addr, MD1122_I2C_ADDR, addr, data);
+
+    return 0;
+}
+
+unsigned char USB_PHY_Read_Register8(unsigned char addr)
+{
+    unsigned char data;
+
+    data = u3phy_read_reg(g_ippc_port_addr, MD1122_I2C_ADDR, addr);
+
+    return data;
+}
+
+unsigned int get_phy_verison(void)
+{
+    unsigned int version = 0;
+
+    u3phy_write_reg8(g_ippc_port_addr, MD1122_I2C_ADDR, 0xff, PHY_VERSION_BANK);
+
+    version = u3phy_read_reg32(g_ippc_port_addr, MD1122_I2C_ADDR, PHY_VERSION_ADDR);
+    dprintf(ALWAYS, "ssusb phy version: %x %p\n", version, g_ippc_port_addr);
+
+    return version;
+}
+
+
+int md1122_u3phy_init(void *i2c_port_base)
+{
+    g_ippc_port_addr = i2c_port_base;
+
+    if (get_phy_verison() != 0xa60810a) {
+        dprintf(ALWAYS,"get phy version failed\n");
+        return -1;
+    }
+
+    /* usb phy initial sequence */
+    USB_PHY_Write_Register8(0x00, 0xFF);
+    LTRACEF("****************before bank 0x00*************************\n");
+    LTRACEF("0x00~0x0F 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
+            USB_PHY_Read_Register8(0x00),USB_PHY_Read_Register8(0x01),USB_PHY_Read_Register8(0x02),USB_PHY_Read_Register8(0x03),
+            USB_PHY_Read_Register8(0x04),USB_PHY_Read_Register8(0x05),USB_PHY_Read_Register8(0x06),USB_PHY_Read_Register8(0x07),
+            USB_PHY_Read_Register8(0x08),USB_PHY_Read_Register8(0x09),USB_PHY_Read_Register8(0x0A),USB_PHY_Read_Register8(0x0B),
+            USB_PHY_Read_Register8(0x0C),USB_PHY_Read_Register8(0x0D),USB_PHY_Read_Register8(0x0E),USB_PHY_Read_Register8(0x0F));
+    LTRACEF("[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    LTRACEF("[U2P]addr: 0x05, value: %x\n", USB_PHY_Read_Register8(0x05));
+    LTRACEF("[U2P]addr: 0x18, value: %x\n", USB_PHY_Read_Register8(0x18));
+    LTRACEF("*****************after **********************************\n");
+    USB_PHY_Write_Register8(0x55, 0x05);
+    USB_PHY_Write_Register8(0x84, 0x18);
+
+
+    LTRACEF("[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    LTRACEF("[U2P]addr: 0x05, value: %x\n", USB_PHY_Read_Register8(0x05));
+    LTRACEF("[U2P]addr: 0x18, value: %x\n", USB_PHY_Read_Register8(0x18));
+    LTRACEF("****************before bank 0x10*************************\n");
+    USB_PHY_Write_Register8(0x10, 0xFF);
+    LTRACEF("0x00~0x0F 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
+            USB_PHY_Read_Register8(0x00),USB_PHY_Read_Register8(0x01),USB_PHY_Read_Register8(0x02),USB_PHY_Read_Register8(0x03),
+            USB_PHY_Read_Register8(0x04),USB_PHY_Read_Register8(0x05),USB_PHY_Read_Register8(0x06),USB_PHY_Read_Register8(0x07),
+            USB_PHY_Read_Register8(0x08),USB_PHY_Read_Register8(0x09),USB_PHY_Read_Register8(0x0A),USB_PHY_Read_Register8(0x0B),
+            USB_PHY_Read_Register8(0x0C),USB_PHY_Read_Register8(0x0D),USB_PHY_Read_Register8(0x0E),USB_PHY_Read_Register8(0x0F));
+    LTRACEF("[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    LTRACEF("[U2P]addr: 0x0A, value: %x\n", USB_PHY_Read_Register8(0x0A));
+    LTRACEF("*****************after **********************************\n");
+
+    USB_PHY_Write_Register8(0x84, 0x0A);
+
+    LTRACEF("[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    LTRACEF("[U2P]addr: 0x0A, value: %x\n", USB_PHY_Read_Register8(0x0A));
+    LTRACEF("****************before bank 0x40*************************\n");
+    USB_PHY_Write_Register8(0x40, 0xFF);
+    LTRACEF("0x00~0x0F 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
+            USB_PHY_Read_Register8(0x00),USB_PHY_Read_Register8(0x01),USB_PHY_Read_Register8(0x02),USB_PHY_Read_Register8(0x03),
+            USB_PHY_Read_Register8(0x04),USB_PHY_Read_Register8(0x05),USB_PHY_Read_Register8(0x06),USB_PHY_Read_Register8(0x07),
+            USB_PHY_Read_Register8(0x08),USB_PHY_Read_Register8(0x09),USB_PHY_Read_Register8(0x0A),USB_PHY_Read_Register8(0x0B),
+            USB_PHY_Read_Register8(0x0C),USB_PHY_Read_Register8(0x0D),USB_PHY_Read_Register8(0x0E),USB_PHY_Read_Register8(0x0F));
+    LTRACEF("[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    LTRACEF("[U2P]addr: 0x38, value: %x\n", USB_PHY_Read_Register8(0x38));
+    LTRACEF("[U2P]addr: 0x42, value: %x\n", USB_PHY_Read_Register8(0x42));
+    LTRACEF("[U2P]addr: 0x08, value: %x\n", USB_PHY_Read_Register8(0x08));
+    LTRACEF("[U2P]addr: 0x09, value: %x\n", USB_PHY_Read_Register8(0x09));
+    LTRACEF("[U2P]addr: 0x0C, value: %x\n", USB_PHY_Read_Register8(0x0C));
+    LTRACEF("[U2P]addr: 0x0E, value: %x\n", USB_PHY_Read_Register8(0x0E));
+    LTRACEF("[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x10));
+    LTRACEF("[U2P]addr: 0x14, value: %x\n", USB_PHY_Read_Register8(0x14));
+    LTRACEF("*****************after **********************************\n");
+
+    USB_PHY_Write_Register8(0x46, 0x38);
+    USB_PHY_Write_Register8(0x40, 0x42);
+    USB_PHY_Write_Register8(0xAB, 0x08);
+    USB_PHY_Write_Register8(0x0C, 0x09);
+    USB_PHY_Write_Register8(0x71, 0x0C);
+    USB_PHY_Write_Register8(0x4F, 0x0E);
+    USB_PHY_Write_Register8(0xE1, 0x10);
+    USB_PHY_Write_Register8(0x5F, 0x14);
+    LTRACEF("[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    LTRACEF("[U2P]addr: 0x38, value: %x\n", USB_PHY_Read_Register8(0x38));
+    LTRACEF("[U2P]addr: 0x42, value: %x\n", USB_PHY_Read_Register8(0x42));
+    LTRACEF("[U2P]addr: 0x08, value: %x\n", USB_PHY_Read_Register8(0x08));
+    LTRACEF("[U2P]addr: 0x09, value: %x\n", USB_PHY_Read_Register8(0x09));
+    LTRACEF("[U2P]addr: 0x0C, value: %x\n", USB_PHY_Read_Register8(0x0C));
+    LTRACEF("[U2P]addr: 0x0E, value: %x\n", USB_PHY_Read_Register8(0x0E));
+    LTRACEF("[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x10));
+    LTRACEF("[U2P]addr: 0x14, value: %x\n", USB_PHY_Read_Register8(0x14));
+    LTRACEF("****************before bank 0x60*************************\n");
+    USB_PHY_Write_Register8(0x60, 0xFF);
+    LTRACEF("0x00~0x0F 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
+            USB_PHY_Read_Register8(0x00),USB_PHY_Read_Register8(0x01),USB_PHY_Read_Register8(0x02),USB_PHY_Read_Register8(0x03),
+            USB_PHY_Read_Register8(0x04),USB_PHY_Read_Register8(0x05),USB_PHY_Read_Register8(0x06),USB_PHY_Read_Register8(0x07),
+            USB_PHY_Read_Register8(0x08),USB_PHY_Read_Register8(0x09),USB_PHY_Read_Register8(0x0A),USB_PHY_Read_Register8(0x0B),
+            USB_PHY_Read_Register8(0x0C),USB_PHY_Read_Register8(0x0D),USB_PHY_Read_Register8(0x0E),USB_PHY_Read_Register8(0x0F));
+    LTRACEF("[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    LTRACEF("[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x14));
+    LTRACEF("*****************after **********************************\n");
+
+    USB_PHY_Write_Register8(0x03, 0x14);
+    LTRACEF("[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    LTRACEF("[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x14));
+    LTRACEF("****************before bank 0x00*************************\n");
+    USB_PHY_Write_Register8(0x00, 0xFF);
+    LTRACEF("[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    LTRACEF("[U2P]addr: 0x6A, value: %x\n", USB_PHY_Read_Register8(0x6A));
+    LTRACEF("[U2P]addr: 0x68, value: %x\n", USB_PHY_Read_Register8(0x68));
+    LTRACEF("[U2P]addr: 0x6C, value: %x\n", USB_PHY_Read_Register8(0x6C));
+    LTRACEF("[U2P]addr: 0x6D, value: %x\n", USB_PHY_Read_Register8(0x6D));
+    USB_PHY_Write_Register8(0x04, 0x6A);
+    USB_PHY_Write_Register8(0x08, 0x68);
+    USB_PHY_Write_Register8(0x26, 0x6C);
+    USB_PHY_Write_Register8(0x36, 0x6D);
+    LTRACEF("*****************after **********************************\n");
+    LTRACEF("[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    LTRACEF("[U2P]addr: 0x6A, value: %x\n", USB_PHY_Read_Register8(0x6A));
+    LTRACEF("[U2P]addr: 0x68, value: %x\n", USB_PHY_Read_Register8(0x68));
+    LTRACEF("[U2P]addr: 0x6C, value: %x\n", USB_PHY_Read_Register8(0x6C));
+    LTRACEF("[U2P]addr: 0x6D, value: %x\n", USB_PHY_Read_Register8(0x6D));
+
+    LTRACEF("[U2P]%s, end\n", __func__);
+    return 0;
+}
+
+void mt_usb_phy_poweron(void)
+{
+    md1122_u3phy_init((void *)U3D_SSUSB_FPGA_I2C_OUT_0P);
+}
+
+void mt_usb_phy_poweroff(void)
+{
+    return;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3.c b/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3.c
new file mode 100644
index 0000000..2aa3d9b
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3.c
@@ -0,0 +1,1845 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in
+ *  the documentation and/or other materials provided with the
+ *  distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <arch/ops.h>
+#include <debug.h>
+#include <errno.h>
+#include <lib/mempool.h>
+#include <platform.h>
+#include <platform/interrupts.h>
+#include <platform/mt_irq.h>
+#include <platform/mt_usbphy.h>
+#include <platform/reg_utils.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <trace.h>
+
+#include "mtu3.h"
+#include "mtu3_qmu.h"
+
+#define LOCAL_TRACE 0
+
+#define DBG_C(x...) dprintf(CRITICAL, "[USB] " x)
+/* use compile option DEBUG=1 to enable following logs */
+#define DBG_I(x...) LTRACEF("[USB] " x)
+#define DBG_S(x...) dprintf(SPEW, "[USB] " x)
+
+/* bits used in ep interrupts etc */
+#define EPT_RX(n) (1 << ((n) + 16))
+#define EPT_TX(n) (1 << (n))
+
+#define EP0 0
+
+/* Request types */
+#define USB_TYPE_STANDARD   (0x00 << 5)
+#define USB_TYPE_CLASS      (0x01 << 5)
+#define USB_TYPE_VENDOR     (0x02 << 5)
+#define USB_TYPE_RESERVED   (0x03 << 5)
+
+/* values used in GET_STATUS requests */
+#define USB_STAT_SELFPOWERED    0x01
+
+/* USB recipients */
+#define USB_RECIP_DEVICE    0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT  0x02
+#define USB_RECIP_OTHER     0x03
+
+/* Endpoints */
+#define USB_EP_NUM_MASK 0x0f        /* in bEndpointAddress */
+#define USB_EP_DIR_MASK 0x80
+
+#define USB_TYPE_MASK   0x60
+#define USB_RECIP_MASK  0x1f
+
+static struct mu3d g_u3d;
+
+
+static void dump_setup_packet(const char *str, struct usb_setup *sp)
+{
+    DBG_I("\n");
+    DBG_I("%s", str);
+    DBG_I("	   bmRequestType = %x\n", sp->request_type);
+    DBG_I("	   bRequest = %x\n", sp->request);
+    DBG_I("	   wValue = %x\n", sp->value);
+    DBG_I("	   wIndex = %x\n", sp->index);
+    DBG_I("	   wLength = %x\n", sp->length);
+}
+
+static void *udc_zalloc(size_t size)
+{
+    void *buf;
+
+    buf = mempool_alloc(size, MEMPOOL_ANY);
+    if (buf)
+        memset(buf, 0, size);
+
+    return buf;
+}
+
+/* descriptors APIs */
+
+static void change_eps_maxp(struct udc_descriptor *desc, u8 *buf, int len)
+{
+    struct udc_gadget *g = g_u3d.gadget;
+    int n;
+
+    /* only supports HS/FS bulk,  default maxp of all eps is 512, change it to 64 when FS; */
+    if ((g_u3d.speed == SSUSB_SPEED_FULL) &&
+            (desc->tag == ((CONFIGURATION << 8) | EP0))) {
+
+        buf += (9 + 9);  /* size of (config + interface) */
+        for (n = 0; n < g->ifc_endpoints; n++) {
+            if ((9 + 9 + 5 + (7 * n)) >= len)
+                break;
+
+            buf[4] = 0x40;  /* ept->maxpkt; 64bytes */
+            buf[5] = 0x00;  /* ept->maxpkt >> 8; 64bytes */
+            buf += 7;
+        }
+    }
+}
+
+static void copy_desc(struct udc_request *req, void *data, int length)
+{
+    memcpy(req->buffer, data, length);
+    req->length = length;
+}
+
+static struct udc_descriptor *udc_descriptor_alloc(unsigned int type,
+        unsigned int num, unsigned int len)
+{
+    struct udc_descriptor *desc;
+
+    if ((len > 255) || (len < 2) || (num > 255) || (type > 255)) {
+        DBG_C("%s invalid argument\n", __func__);
+        return NULL;
+    }
+
+    desc = udc_zalloc(sizeof(struct udc_descriptor) + len);
+    if (!desc) {
+        DBG_C("alloc desc failed (type:%d)\n", type);
+        return NULL;
+    }
+
+    desc->next = 0;
+    desc->tag = (type << 8) | num;
+    desc->len = len;
+    desc->data[0] = len;
+    desc->data[1] = type;
+
+    return desc;
+}
+
+static void udc_descriptor_register(struct udc_descriptor *desc, int dtype)
+{
+    if (dtype == DESC_TYPE_U2) {
+        desc->next = g_u3d.desc_list;
+        g_u3d.desc_list = desc;
+    } else {
+        desc->next = g_u3d.desc_list_u3;
+        g_u3d.desc_list_u3 = desc;
+    }
+}
+
+static unsigned int udc_string_desc_alloc(const char *str, int dtype)
+{
+    struct udc_descriptor *desc;
+    unsigned char *data;
+    unsigned int len;
+    unsigned int *str_id;
+
+    if (dtype == DESC_TYPE_U2)
+        str_id = &g_u3d.next_string_id;
+    else
+        str_id = &g_u3d.next_string_id_u3;
+
+    if (*str_id > 255)
+        return 0;
+
+    if (!str)
+        return 0;
+
+    len = strlen(str);
+    desc = udc_descriptor_alloc(STRING, *str_id, len * 2 + 2);
+    if (!desc)
+        return 0;
+
+    *str_id += 1;
+
+    /* expand ascii string to utf16 */
+    data = desc->data + 2;
+    while (len-- > 0) {
+        *data++ = *str++;
+        *data++ = 0;
+    }
+
+    udc_descriptor_register(desc, dtype);
+    return desc->tag & 0xff;
+}
+
+static void udc_ept_desc_fill(struct udc_endpoint *ept, unsigned char *data, int dtype)
+{
+    data[0] = 7;
+    data[1] = ENDPOINT;
+    data[2] = ept->num | (ept->in ? USB_DIR_IN : USB_DIR_OUT);
+    data[3] = 0x02;     /* bulk -- the only kind we support */
+    data[4] = 0x00;     /* ept->maxpkt; u2: 512bytes, u3: 1024 by default */
+    data[5] = (dtype == DESC_TYPE_U2) ? 0x02 : 0x04; /* ept->maxpkt >> 8; */
+    data[6] = ept->in ? 0x01 : 0x00;
+}
+
+static void udc_companion_desc_fill(uint8_t *data)
+{
+    data[0] = 6;
+    data[1] = SS_EP_COMP;
+    data[2] = 0x0f;     /* max burst: 0x0~0xf */
+    data[3] = 0x00;
+    data[4] = 0x00;
+    data[5] = 0x00;
+}
+
+static unsigned int udc_ifc_desc_size(struct udc_gadget *g, int dtype)
+{
+    int tmp = 7; /* ep desc */
+
+    tmp += ((dtype == DESC_TYPE_U2) ? 0 : 6); /* u3: add Companion desc */
+    return 9 + g->ifc_endpoints * tmp;
+}
+
+static void udc_ifc_desc_fill(struct udc_gadget *g, unsigned char *data, int dtype)
+{
+    unsigned int n;
+
+    data[0] = 0x09;
+    data[1] = INTERFACE;
+    data[2] = 0x00;     /* ifc number */
+    data[3] = 0x00;     /* alt number */
+    data[4] = g->ifc_endpoints; /* 0x02 */
+    data[5] = g->ifc_class;     /* 0xff */
+    data[6] = g->ifc_subclass;  /* 0x42 */
+    data[7] = g->ifc_protocol;  /* 0x03 */
+    data[8] = udc_string_desc_alloc(g->ifc_string, dtype);
+
+    data += 9;
+    for (n = 0; n < g->ifc_endpoints; n++) {
+        udc_ept_desc_fill(g->ept[n], data, dtype);
+        data += 7;
+        if (dtype == DESC_TYPE_U3) {
+            udc_companion_desc_fill(data);
+            data += 6;
+        }
+    }
+}
+
+/* create our device descriptor */
+static int udc_create_dev_desc(struct udc_device *udev, int dtype)
+{
+    struct udc_descriptor *desc;
+    unsigned char *data;
+
+    desc = udc_descriptor_alloc(DEVICE, EP0, 18);
+    if (!desc)
+        return -ENOMEM;
+
+    data = desc->data;
+    data[2] = 0x00;     /* usb spec minor rev */
+    data[3] = (dtype == DESC_TYPE_U2) ? 0x02 : 0x03; /* usb spec major rev */
+    data[4] = 0x00;     /* class */
+    data[5] = 0x00;     /* subclass */
+    data[6] = 0x00;     /* protocol */
+    data[7] = (dtype == DESC_TYPE_U2) ? 0x40 : 0x09; /* maxp on ept 0 */
+    memcpy(data + 8, &udev->vendor_id, sizeof(short));
+    memcpy(data + 10, &udev->product_id, sizeof(short));
+    memcpy(data + 12, &udev->version_id, sizeof(short));
+    data[14] = udc_string_desc_alloc(udev->manufacturer, dtype);
+    data[15] = udc_string_desc_alloc(udev->product, dtype);
+    data[16] = udc_string_desc_alloc(udev->serialno, dtype);
+    data[17] = 1;       /* number of configurations */
+    udc_descriptor_register(desc, dtype);
+    return 0;
+}
+
+/* create our BOS Binary Device Object descriptor - USB3 (FULL) */
+static int udc_create_u3_bos_desc(void)
+{
+    struct udc_descriptor *desc;
+    unsigned char *data;
+
+    desc = udc_descriptor_alloc(BOS, EP0, 22);
+    if (!desc)
+        return -ENOMEM;
+
+    data = desc->data;
+    data[0] = 0x05;     /* bLength of BOS Header */
+    data[2] = 0x16;     /* wTotalLength[0] */
+    data[3] = 0x00;     /* wTotalLength[1] */
+    data[4] = 0x02;     /* bNumDeviceCaps: number of separate device*/
+    /* capability descriptors in BOS */
+
+    /* BOS 1 */
+    data[5] = 0x07;     /* bLength: 7 */
+    data[6] = 0x10;     /* bDescriptorType: DEVICE CAPABILITY */
+    data[7] = 0x02;     /* bDevCapabilityType: USB 2.0 Ext Descriptor */
+    data[8] = 0x02;     /* bmAttributes[4]: LPM (SuperSpeed) */
+    data[9] = 0x00;
+    data[10] = 0x00;
+    data[11] = 0x00;
+
+    /* BOS 2 */
+    data[12] = 0x0A;        /* bLength: 10 */
+    data[13] = 0x10;        /* bDescriptorType: DEVICE CAPABILITY */
+    data[14] = 0x03;        /* bDevCapabilityType: SuperSpeed */
+    data[15] = 0x00;        /* bmAttributes: Don't support LTM */
+    data[16] = 0x0E;        /* wSpeedsSupported[0]: b'1110 */
+    data[17] = 0x00;        /* wSpeedsSupported[1] */
+    data[18] = 0x01;        /* bFunctionalitySupport */
+    data[19] = 0x0A;        /* bU1DevExitLat: Less than 10us */
+    data[20] = 0x20;        /* wU2DevExitLat[0]: 32us */
+    data[21] = 0x00;        /* wU2DevExitLat[1] */
+
+    udc_descriptor_register(desc, DESC_TYPE_U3);
+    return 0;
+}
+
+static int udc_create_config_desc(struct udc_gadget *gadget, int dtype)
+{
+    struct udc_descriptor *desc;
+    unsigned char *data;
+    unsigned int size;
+
+    /* create our configuration descriptor */
+    size = 9 + udc_ifc_desc_size(gadget, dtype);
+    desc = udc_descriptor_alloc(CONFIGURATION, EP0, size);
+    if (!desc)
+        return -ENOMEM;
+
+    data = desc->data;
+    data[0] = 0x09;
+    data[2] = size;
+    data[3] = size >> 8;
+    data[4] = 0x01;     /* number of interfaces */
+    data[5] = 0x01;     /* configuration value */
+    data[6] = 0x00;     /* configuration string */
+    data[7] = 0x80;     /* attributes */
+    /* max power u2: (250ma), u3: 400ma  */
+    data[8] = (dtype == DESC_TYPE_U2) ? 0x80 : 0x32;
+
+    udc_ifc_desc_fill(gadget, data + 9, dtype);
+    udc_descriptor_register(desc, dtype);
+    return 0;
+}
+
+static int udc_create_language_table_desc(int dtype)
+{
+    struct udc_descriptor *desc;
+
+    /* create and register a language table descriptor */
+    /* language 0x0409 is US English */
+    desc = udc_descriptor_alloc(STRING, EP0, 4);
+    if (!desc)
+        return -ENOMEM;
+
+    desc->data[2] = 0x09;
+    desc->data[3] = 0x04;
+    udc_descriptor_register(desc, dtype);
+    return 0;
+}
+
+static int udc_create_descriptors(struct udc_device *udev, struct udc_gadget *gadget)
+{
+    udc_create_dev_desc(udev, DESC_TYPE_U2);
+    udc_create_config_desc(gadget, DESC_TYPE_U2);
+    udc_create_language_table_desc(DESC_TYPE_U2);
+
+    if (g_u3d.is_u3_ip) {
+        udc_create_dev_desc(udev, DESC_TYPE_U3);
+        udc_create_u3_bos_desc();
+        udc_create_config_desc(gadget, DESC_TYPE_U3);
+        udc_create_language_table_desc(DESC_TYPE_U3);
+    }
+
+#if 0
+    {
+        struct udc_descriptor *desc;
+
+        DBG_I("%s: dump u2 desc_list\n", __func__);
+        for (desc = g_u3d.desc_list; desc; desc = desc->next) {
+            DBG_I("tag: %04x\n", desc->tag);
+            DBG_I("len: %d\n", desc->len);
+            DBG_I("data:");
+            hexdump8(desc->data, desc->len);
+        }
+
+        DBG_I("%s: dump u3 desc_list\n", __func__);
+        for (desc = g_u3d.desc_list_u3; desc; desc = desc->next) {
+            DBG_I("tag: %04x\n", desc->tag);
+            DBG_I("len: %d\n", desc->len);
+            DBG_I("data:");
+            hexdump8(desc->data, desc->len);
+        }
+    }
+#endif
+
+    return 0;
+}
+
+/* hardware access APIs */
+
+int wait_for_value(paddr_t addr, u32 msk, u32 value, int us_intvl, int count)
+{
+    int i;
+
+    for (i = 0; i < count; i++) {
+        if ((readl(addr) & msk) == value)
+            return 0;
+
+        spin(us_intvl);
+    }
+
+    return -ETIMEDOUT;
+}
+
+static inline void writel_rep(volatile void *addr, const void *buffer,
+                              unsigned int count)
+{
+    if (count) {
+        const u32 *buf = buffer;
+
+        do {
+            writel(*buf++, addr);
+        } while (--count);
+    }
+}
+
+static inline void readl_rep(const volatile void *addr, void *buffer,
+                             unsigned int count)
+{
+    if (count) {
+        u32 *buf = buffer;
+
+        do {
+            u32 x = readl(addr);
+            *buf++ = x;
+        } while (--count);
+    }
+}
+
+static int pio_read_fifo(int ep_num, u8 *dst, u16 len)
+{
+    void *fifo = (void *)(paddr_t)(USB_FIFO(ep_num));
+    u32 index = 0;
+    u32 value;
+
+    if (len >= 4) {
+        readl_rep(fifo, dst, len >> 2);
+        index = len & ~0x03;
+    }
+    if (len & 0x3) {
+        value = readl(fifo);
+        memcpy(&dst[index], &value, len & 0x3);
+    }
+
+    DBG_I("%s - ep_num: %d, len: %d, dst: %p\n",
+          __func__, ep_num, len, dst);
+
+    return len;
+}
+
+static void pio_write_fifo(int ep_num, u8 *src, u16 len)
+{
+    void *fifo = (void *)(paddr_t)(USB_FIFO(ep_num));
+    u32 index = 0;
+
+    DBG_I("%s - ep_num: %d, len: %d, src: %p\n",
+          __func__, ep_num, len, src);
+
+    if (len >= 4) {
+        writel_rep(fifo, src, len >> 2);
+        index = len & ~0x03;
+    }
+    if (len & 0x02) {
+        writew(*(u16 *)&src[index], fifo);
+        index += 2;
+    }
+    if (len & 0x01)
+        writeb(src[index], fifo);
+}
+
+static int mu3d_check_clk_sts(void)
+{
+    u32 check_val;
+    int ret = 0;
+
+    check_val = SSUSB_SYS125_RST_B_STS | SSUSB_SYSPLL_STABLE |
+                SSUSB_REF_RST_B_STS;
+    if (g_u3d.is_u3_ip)
+        check_val |= SSUSB_U3_MAC_RST_B_STS;
+
+    ret = wait_for_value(U3D_SSUSB_IP_PW_STS1, check_val, check_val, 100, 100);
+    if (ret) {
+        DBG_C("SSUSB_SYS125_RST_B_STS NG\n");
+        goto err;
+    } else {
+        DBG_I("clk sys125:OK\n");
+    }
+
+    ret = wait_for_value(U3D_SSUSB_IP_PW_STS2, SSUSB_U2_MAC_SYS_RST_B_STS,
+                         SSUSB_U2_MAC_SYS_RST_B_STS, 100, 100);
+    if (ret) {
+        DBG_C("SSUSB_U2_MAC_SYS_RST_B_STS NG\n");
+        goto err;
+    } else {
+        DBG_I("clk mac2:OK\n");
+    }
+
+    return 0;
+
+err:
+    DBG_C("Refer clocks stability check failed!\n");
+    return ret;
+}
+
+static void mu3d_ssusb_enable(void)
+{
+    clrbits32_r(SSUSB_IP_SW_RST, U3D_SSUSB_IP_PW_CTRL0);
+    clrbits32_r(SSUSB_IP_DEV_PDN, U3D_SSUSB_IP_PW_CTRL2);
+    clrbits32_r((SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN |
+                 SSUSB_U2_PORT_HOST_SEL), U3D_SSUSB_U2_CTRL_0P);
+    if (g_u3d.is_u3_ip)
+        clrbits32_r((SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN |
+                     SSUSB_U3_PORT_HOST_SEL), U3D_SSUSB_U3_CTRL_0P);
+
+    mu3d_check_clk_sts();
+}
+
+/* enable/disable U3D SS function */
+static void mu3d_ss_func_set(bool enable)
+{
+    /* If usb3_en==0, LTSSM will go to SS.Disable state */
+    if (enable)
+        setbits32_r(USB3_EN, U3D_USB3_CONFIG);
+    else
+        clrbits32_r(USB3_EN, U3D_USB3_CONFIG);
+
+    DBG_C("U3 pullup D%s\n", enable ? "+" : "-");
+}
+
+/* set/clear U3D HS device soft connect */
+static void mu3d_hs_softconn_set(bool enable)
+{
+    if (enable)
+        setbits32_r(SOFT_CONN | SUSPENDM_ENABLE, U3D_POWER_MANAGEMENT);
+    else
+        clrbits32_r(SOFT_CONN | SUSPENDM_ENABLE, U3D_POWER_MANAGEMENT);
+
+    DBG_C("U2 pullup D%s\n", enable ? "+" : "-");
+}
+
+static void mu3d_soft_connect(void)
+{
+    if (g_u3d.is_u3_ip && g_u3d.speed > SSUSB_SPEED_HIGH)
+        mu3d_ss_func_set(true);
+    else
+        mu3d_hs_softconn_set(true);
+}
+
+static void mu3d_soft_disconnect(void)
+{
+    if (g_u3d.is_u3_ip && g_u3d.speed > SSUSB_SPEED_HIGH)
+        mu3d_ss_func_set(false);
+    else
+        mu3d_hs_softconn_set(false);
+}
+
+static void mu3d_dev_reset(void)
+{
+    setbits32_r(SSUSB_DEV_SW_RST, U3D_SSUSB_DEV_RST_CTRL);
+    clrbits32_r(SSUSB_DEV_SW_RST, U3D_SSUSB_DEV_RST_CTRL);
+}
+
+static void mu3d_intr_enable(void)
+{
+    u32 value;
+
+    /* enable LV1 ISR */
+    value = BMU_INTR | QMU_INTR | MAC3_INTR | MAC2_INTR | EP_CTRL_INTR;
+    writel(value, U3D_LV1IESR);
+    /* enable U2 common interrupts */
+    value = SUSPEND_INTR | RESUME_INTR | RESET_INTR;
+    writel(value, U3D_COMMON_USB_INTR_ENABLE);
+
+    /* Enable U3 LTSSM interrupts */
+    if (g_u3d.is_u3_ip) {
+        value = HOT_RST_INTR | WARM_RST_INTR | VBUS_RISE_INTR |
+                VBUS_FALL_INTR | ENTER_U3_INTR | EXIT_U3_INTR;
+        writel(value, U3D_LTSSM_INTR_ENABLE);
+    }
+
+    /* Enable QMU interrupts. */
+    value = TXQ_CSERR_INT | TXQ_LENERR_INT | RXQ_CSERR_INT |
+            RXQ_LENERR_INT | RXQ_ZLPERR_INT;
+    writel(value, U3D_QIESR1);
+    /* Enable speed change interrupt */
+    writel(SSUSB_DEV_SPEED_CHG_INTR, U3D_DEV_LINK_INTR_ENABLE);
+}
+
+static void mu3d_intr_disable(void)
+{
+    writel(0xffffffff, U3D_EPISR);
+    writel(0xffffffff, U3D_QISAR0);
+    writel(0xffffffff, U3D_QISAR1);
+    writel(0xffffffff, U3D_TQERRIR0);
+    writel(0xffffffff, U3D_RQERRIR0);
+    writel(0xffffffff, U3D_RQERRIR1);
+    writel(0xffffffff, U3D_LV1IECR);
+    writel(0xffffffff, U3D_EPIECR);
+
+    /* clear registers */
+    writel(0xffffffff, U3D_QIECR0);
+    writel(0xffffffff, U3D_QIECR1);
+    writel(0xffffffff, U3D_TQERRIECR0);
+    writel(0xffffffff, U3D_RQERRIECR0);
+    writel(0xffffffff, U3D_RQERRIECR1);
+    writel(0xffffffff, U3D_COMMON_USB_INTR);
+}
+
+static void mu3d_reg_init(void)
+{
+    if (g_u3d.is_u3_ip) {
+        /* disable LGO_U1/U2 by default */
+        clrbits32_r(SW_U1_ACCEPT_ENABLE | SW_U2_ACCEPT_ENABLE |
+                     SW_U1_REQUEST_ENABLE | SW_U2_REQUEST_ENABLE,
+                     U3D_LINK_POWER_CONTROL);
+        /* device responses to u3_exit from host automatically */
+        clrbits32_r(SOFT_U3_EXIT_EN, U3D_LTSSM_CTRL);
+        /* automatically build U2 link when U3 detect fail */
+        setbits32_r(U2U3_AUTO_SWITCH, U3D_USB2_TEST_MODE);
+    }
+    /* delay about 0.1us from detecting reset to send chirp-K */
+    clrbits32_r(WTCHRP_MSK, U3D_LINK_RESET_INFO);
+    /* U2/U3 detected by HW */
+    writel(0, U3D_DEVICE_CONF);
+    /* enable QMU 16B checksum */
+    setbits32_r(QMU_CS16B_EN, U3D_QCR0);
+    /* vbus detected by HW */
+    clrbits32_r(VBUS_FRC_EN | VBUS_ON, U3D_MISC_CTRL);
+}
+
+static USB_SPEED mu3d_get_speed(void)
+{
+    const char *spd_str[] = {"UNKNOW", "FS", "HS", "SS", "SSP"};
+    USB_SPEED spd;
+
+    switch (SSUSB_DEV_SPEED(readl(U3D_DEVICE_CONF))) {
+        case 1:
+            spd = SSUSB_SPEED_FULL;
+            break;
+        case 3:
+            spd = SSUSB_SPEED_HIGH;
+            break;
+        case 4:
+            spd = SSUSB_SPEED_SUPER;
+            break;
+        case 5:
+            spd = SSUSB_SPEED_SUPER_PLUS;
+            break;
+        default:
+            spd = SSUSB_SPEED_UNKNOWN;
+            break;
+    }
+
+    DBG_C("%s (%d) is detected\n", spd_str[spd % ARRAY_SIZE(spd_str)], spd);
+    return spd;
+}
+
+/* SSP is not supported tmp. */
+static void mu3d_set_speed(USB_SPEED spd)
+{
+    const char *spd_str[] = {"UNKNOW", "FS", "HS", "SS", "SSP"};
+
+    switch (spd) {
+        case SSUSB_SPEED_FULL:
+            clrbits32_r(USB3_EN, U3D_USB3_CONFIG);
+            clrbits32_r(HS_ENABLE, U3D_POWER_MANAGEMENT);
+            break;
+        case SSUSB_SPEED_HIGH:
+            clrbits32_r(USB3_EN, U3D_USB3_CONFIG);
+            setbits32_r(HS_ENABLE, U3D_POWER_MANAGEMENT);
+            break;
+        case SSUSB_SPEED_SUPER:
+            /* fall through */
+        default:
+            clrbits32_r(SSUSB_U3_PORT_SSP_SPEED, U3D_SSUSB_U3_CTRL_0P);
+            break;
+    }
+    DBG_I("%s %s (%d)\n", __func__, spd_str[spd % ARRAY_SIZE(spd_str)], spd);
+}
+
+static inline void mu3d_set_address(int addr)
+{
+    writel(DEV_ADDR(addr), U3D_DEVICE_CONF);
+}
+
+struct udc_endpoint *mtu3_find_ep(int ep_num, u8 dir)
+{
+    struct udc_endpoint *ep_list = g_u3d.eps;
+    int i;
+    u8 in;
+
+    /* convert dir to in */
+    if (dir == USB_DIR_IN)
+        in = 1;
+    else
+        in = 0;
+
+    for (i = 1; i < MT_EP_NUM; i++) {
+        if ((ep_list[i].num == ep_num) && (ep_list[i].in == in))
+            return &ep_list[i];
+    }
+    return NULL;
+}
+
+static void mu3d_flush_fifo(u8 ep_num, u8 dir)
+{
+    if (ep_num == 0) {
+        setbits32_r(EP0_RST, U3D_EP_RST);
+        clrbits32_r(EP0_RST, U3D_EP_RST);
+    } else {
+        setbits32_r(EP_RST((dir == USB_DIR_IN), ep_num), U3D_EP_RST);
+        clrbits32_r(EP_RST((dir == USB_DIR_IN), ep_num), U3D_EP_RST);
+    }
+}
+
+static void ep0_stall_set(bool set, u32 pktrdy)
+{
+    u32 csr;
+
+    /* EP0_SENTSTALL is W1C */
+    csr = readl(U3D_EP0CSR) & EP0_W1C_BITS;
+    if (set)
+        csr |= EP0_SENDSTALL | pktrdy;
+    else
+        csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL;
+    writel(csr, U3D_EP0CSR);
+
+    g_u3d.ep0_state = EP0_IDLE;
+}
+
+/*
+ * Return value indicates the TxFIFO size of 2^n bytes, (ex: value 10 means 2^10 =
+ * 1024 bytes.) TXFIFOSEGSIZE should be equal or bigger than 4. The TxFIFO size of
+ * 2^n bytes also should be equal or bigger than TXMAXPKTSZ. This EndPoint occupy
+ * total memory size  (TX_SLOT + 1 )*2^TXFIFOSEGSIZE bytes.
+ */
+static u8 get_seg_size(u32 maxp)
+{
+    /* Set fifo size(double buffering is currently not enabled) */
+    switch (maxp) {
+        case 8:
+        case 16:
+            return USB_FIFOSZ_SIZE_16;
+        case 32:
+            return USB_FIFOSZ_SIZE_32;
+        case 64:
+            return USB_FIFOSZ_SIZE_64;
+        case 128:
+            return USB_FIFOSZ_SIZE_128;
+        case 256:
+            return USB_FIFOSZ_SIZE_256;
+        case 512:
+            return USB_FIFOSZ_SIZE_512;
+        case 1023:
+        case 1024:
+        case 2048:
+        case 3072:
+        case 4096:
+            return USB_FIFOSZ_SIZE_1024;
+        default:
+            DBG_I("The maxp %d is not supported\n", maxp);
+            return USB_FIFOSZ_SIZE_512;
+    }
+}
+
+static void mu3d_setup_ep(unsigned int ep_num, struct udc_endpoint *ept)
+{
+    u32 csr0, csr1, csr2;
+    u32 fifo_addr;
+    u8 seg_size;
+
+    /* Nothing needs to be done for ep0 */
+    if (ep_num == 0)
+        return;
+
+    /* In LK (FASTBOOT) will use BULK transfer only */
+    if (ept->type != USB_EP_XFER_BULK)
+        DBG_C("ep type is wrong, should be bulk,\n");
+
+    /* Set fifo address, fifo size, and fifo max packet size */
+    DBG_I("%s: %s, maxpkt: %d\n", __func__, ept->name, ept->maxpkt);
+
+    /* Set fifo size(only supports single buffering) */
+    seg_size = get_seg_size(ept->maxpkt);
+
+    if (ept->in) {  /* TX case */
+        mu3d_flush_fifo(ep_num, USB_DIR_IN);
+
+        csr0 = TX_TXMAXPKTSZ(ept->maxpkt);
+
+        /* only support BULK, set 0 for burst, slot, mult, num_pkts  */
+        csr1 = TX_TYPE(TYPE_BULK);
+
+        fifo_addr = g_u3d.tx_fifo_addr + (U3D_FIFO_SIZE_UNIT * ep_num);
+        csr2 = TX_FIFOADDR(fifo_addr >> 4);
+        csr2 |= TX_FIFOSEGSIZE(seg_size);
+
+#ifdef SUPPORT_QMU
+        csr0 |= TX_DMAREQEN;
+        /* Enable QMU Done interrupt */
+        setbits32_r(QMU_TX_DONE_INT(ep_num), U3D_QIESR0);
+#else
+        setbits32_r(EP_TXISR(ep_num), U3D_EPIECR);  /* W1C */
+        setbits32_r(EP_TXISR(ep_num), U3D_EPIESR);  /* W1S */
+#endif
+
+        writel(csr0, MU3D_EP_TXCR0(ep_num));
+        writel(csr1, MU3D_EP_TXCR1(ep_num));
+        writel(csr2, MU3D_EP_TXCR2(ep_num));
+
+    } else {    /* RX case */
+        mu3d_flush_fifo(ep_num, USB_DIR_OUT);
+
+        csr0 = RX_RXMAXPKTSZ(ept->maxpkt);
+
+        /* only support BULK, set 0 for burst, slot, mult, num_pkts  */
+        csr1 = RX_TYPE(TYPE_BULK);
+
+        fifo_addr = g_u3d.rx_fifo_addr + (U3D_FIFO_SIZE_UNIT * ep_num);
+        csr2 = RX_FIFOADDR(fifo_addr >> 4);
+        csr2 |= RX_FIFOSEGSIZE(seg_size);
+
+#ifdef SUPPORT_QMU
+        csr0 |= RX_DMAREQEN;
+        /* Enable QMU Done interrupt */
+        setbits32_r(QMU_RX_DONE_INT(ep_num), U3D_QIESR0);
+#else
+        setbits32_r(EP_RXISR(ep_num), U3D_EPIECR);  /* W1C */
+        /* enable it when queue RX request */
+        /* setbits32_r(EP_RXISR(ep_num), U3D_EPIESR);*/   /* W1S */
+#endif
+        writel(csr0, MU3D_EP_RXCR0(ep_num));
+        writel(csr1, MU3D_EP_RXCR1(ep_num));
+        writel(csr2, MU3D_EP_RXCR2(ep_num));
+    }
+
+#ifdef SUPPORT_QMU
+    mtu3_qmu_start(ept);
+#endif
+}
+
+static void mu3d_ep0en(void)
+{
+    u32 temp = 0;
+    struct udc_endpoint *ep0 = g_u3d.ep0;
+
+    sprintf(ep0->name, "ep0");
+    ep0->type = USB_EP_XFER_CTRL;
+    ep0->num = EP0;
+    if (g_u3d.speed == SSUSB_SPEED_SUPER)
+        ep0->maxpkt = EP0_MAX_PACKET_SIZE_U3;
+    else
+        ep0->maxpkt = EP0_MAX_PACKET_SIZE;
+
+    temp = readl(U3D_EP0CSR);
+    temp &= ~(EP0_MAXPKTSZ_MSK | EP0_AUTOCLEAR | EP0_AUTOSET | EP0_DMAREQEN);
+    temp |= EP0_MAXPKTSZ(ep0->maxpkt);
+    temp &= EP0_W1C_BITS;
+    writel(temp, U3D_EP0CSR);
+
+    /* enable EP0 interrupts */
+    setbits32_r(EP_EP0ISR, U3D_EPIESR);
+}
+
+static void mu3d_get_ip_vers(void)
+{
+    u32 val;
+
+    val = readl(U3D_SSUSB_IP_DEV_CAP);
+    g_u3d.is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(val);
+    DBG_C("IP version 0x%x(%s IP)\n", readl(U3D_SSUSB_HW_ID),
+          g_u3d.is_u3_ip ? "U3" : "U2");
+}
+
+static void mu3d_hw_init(void)
+{
+    mu3d_dev_reset();
+    mu3d_ssusb_enable();
+    mu3d_intr_disable();
+    mu3d_reg_init();
+    mu3d_set_speed(g_u3d.speed);
+    mu3d_intr_enable();
+    mu3d_ep0en();
+}
+
+static void mtu3_setup_eps(void)
+{
+    struct udc_endpoint *ep_list = g_u3d.eps;
+    USB_SPEED speed = g_u3d.speed;
+    int maxp = 512;
+    int i;
+
+    if (speed == SSUSB_SPEED_FULL)
+        maxp = 64;
+    else if (speed == SSUSB_SPEED_HIGH)
+        maxp = 512;
+    else if (speed == SSUSB_SPEED_SUPER)
+        maxp = 1024;
+
+    for (i = 1; i < MT_EP_NUM; i++) {
+        if (ep_list[i].num != 0) { /* allocated */
+            ep_list[i].maxpkt = maxp;
+            mu3d_setup_ep(ep_list[i].num, &ep_list[i]);
+        }
+    }
+}
+
+
+/* usb generic functions */
+
+void handle_ept_complete(struct udc_endpoint *ept, int status)
+{
+    struct udc_request *req;
+    struct mu3d_req *mreq;
+    unsigned int actual;
+
+    req = ept->req;
+    mreq = to_mu3d_req(req);
+    if (req) {
+        ept->req = NULL;
+
+        if (status)
+            DBG_C("%s: %s FAIL status: %d\n", __func__, ept->name, status);
+
+        actual = status ? 0 : mreq->actual;
+
+        DBG_I("%s: %s, req: %p: complete: %d/%d: status: %d\n",
+              __func__, ept->name, req, actual, req->length, status);
+
+        if (req->complete)
+            req->complete(req, actual, status);
+    }
+}
+
+static int mtu3_read_fifo(struct udc_endpoint *ept)
+{
+    struct udc_request *req = ept->req;
+    struct mu3d_req *mreq = to_mu3d_req(req);
+    int ep_num = ept->num;
+    u32 count = 0;
+
+    if (mreq) {
+        if (ep_num == 0)
+            count = readl(U3D_RXCOUNT0);
+        else
+            count = EP_RX_COUNT(readl(MU3D_EP_RXCR3(ep_num)));
+
+        count = MIN(req->length - mreq->actual, count);
+        pio_read_fifo(ep_num, req->buffer + mreq->actual, count);
+#if 0
+        if (ep_num != 0) {
+            DBG_I("%s: &req->buffer: %p\n", __func__, req->buffer);
+            DBG_I("dump data:\n");
+            hexdump8(req->buffer, len);
+        }
+#endif
+        mreq->actual += count;
+
+        DBG_I("%s: ep%dout, mreq: %p, buf: %p, length: %d, actual: %d\n",
+              __func__, ep_num, mreq, req->buffer, req->length, mreq->actual);
+    }
+
+    return count;
+}
+
+static int mtu3_write_fifo(struct udc_endpoint *ept)
+{
+    struct udc_request *req = ept->req;
+    struct mu3d_req *mreq = to_mu3d_req(req);
+    unsigned char *buf;
+    int ep_num = ept->num;
+    int count = 0;
+
+    if (mreq) {
+        DBG_I("%s: ep%din mreq: %p, length: %d, actual: %d, maxp: %d\n",
+              __func__, ep_num, mreq, req->length, mreq->actual, ept->maxpkt);
+
+        count = MIN(req->length - mreq->actual, ept->maxpkt);
+        buf = req->buffer + mreq->actual;
+        pio_write_fifo(ep_num, buf, count);
+        mreq->actual += count;
+    }
+
+    return count;
+}
+
+static void mtu3_ep0_write(void)
+{
+    struct udc_endpoint *ep0 = g_u3d.ep0;
+    struct udc_request *req = ep0->req;
+    struct mu3d_req *mreq = to_mu3d_req(req);
+    unsigned int count = 0;
+    u32 csr0;
+
+    csr0 = readl(U3D_EP0CSR);
+    if (csr0 & EP0_TXPKTRDY) {
+        DBG_I("%s: ep0 is not ready to be written\n", __func__);
+        return;
+    }
+
+    count = mtu3_write_fifo(ep0);
+
+    /* hardware limitiation: can't set (EP0_TXPKTRDY | EP0_DATAEND) at same time */
+    csr0 |= (EP0_TXPKTRDY);
+    writel(csr0, U3D_EP0CSR);
+
+    DBG_I("%s: length=%d, actual=%d\n", __func__, req->length, mreq->actual);
+    if ((count < ep0->maxpkt) || (req->length == mreq->actual)) {
+        /* last packet */
+        mreq->actual = 0;
+        g_u3d.ep0_state = EP0_TX_END;
+    }
+}
+
+static void mtu3_ep0_read(void)
+{
+    struct udc_endpoint *ep0 = g_u3d.ep0;
+    struct udc_request *req = ep0->req;
+    struct mu3d_req *mreq = to_mu3d_req(req);
+    unsigned int count = 0;
+    u32 csr0 = 0;
+
+    csr0 = readl(U3D_EP0CSR);
+
+    /* erroneous ep0 interrupt */
+    if (!(csr0 & EP0_RXPKTRDY))
+        return;
+
+    count = mtu3_read_fifo(ep0);
+
+    /* work around: cannot set  (EP0_RXPKTRDY | EP0_DATAEND) at same time */
+    csr0 |= (EP0_RXPKTRDY);
+    writel(csr0, U3D_EP0CSR);
+
+    if ((count < ep0->maxpkt) || (mreq->actual == req->length)) {
+        /* last packet */
+        csr0 |= EP0_DATAEND;
+        g_u3d.ep0_state = EP0_IDLE;
+    } else {
+        /* more packets are waiting to be transferred */
+        csr0 |= EP0_RXPKTRDY;
+    }
+
+    writel(csr0, U3D_EP0CSR);
+}
+
+static int std_get_descs(struct udc_request *req, struct usb_setup *setup)
+{
+    struct udc_descriptor *desc = NULL;
+
+    if (g_u3d.speed <= SSUSB_SPEED_HIGH)
+        desc = g_u3d.desc_list;
+    else
+        desc = g_u3d.desc_list_u3;
+
+    for (; desc; desc = desc->next) {
+        if (desc->tag == setup->value) {
+            unsigned int len = desc->len;
+
+            if (len > setup->length)
+                len = setup->length;
+
+            copy_desc(req, desc->data, len);
+            change_eps_maxp(desc, req->buffer, len);
+            return 0;
+        }
+    }
+    /* descriptor lookup failed */
+    return -EINVAL;
+}
+
+static void mtu3_ep_reset(int epnum, bool is_in)
+{
+    u32 rst_bit = EP_RST(is_in, epnum);
+
+    setbits32(U3D_EP_RST, rst_bit);
+    clrbits32(U3D_EP_RST, rst_bit);
+}
+
+
+static void mtu3_ep_stall_set(int index, bool set)
+{
+    bool is_in = index & USB_DIR_IN;
+    int epnum = index & 0xf;
+    u32 csr;
+
+    if (is_in) {   /* TX */
+        csr = readl(MU3D_EP_TXCR0(epnum)) & TX_W1C_BITS;
+        if (set)
+            csr |= TX_SENDSTALL;
+        else
+            csr = (csr & (~TX_SENDSTALL)) | TX_SENTSTALL;
+
+        writel(csr, MU3D_EP_TXCR0(epnum));
+    } else {    /* RX */
+        csr = readl(MU3D_EP_RXCR0(epnum)) & RX_W1C_BITS;
+        if (set)
+            csr |= RX_SENDSTALL;
+        else
+            csr = (csr & (~RX_SENDSTALL)) | RX_SENTSTALL;
+
+        writel(csr, MU3D_EP_RXCR0(epnum));
+    }
+
+    if (!set)
+        mtu3_ep_reset(epnum, is_in);
+
+    DBG_I("ep%d%s: %s STALL, with EP RESET\n", epnum, is_in ? "in" : "out",
+          set ? "SET" : "CLEAE");
+}
+
+static int ep0_standard_setup(struct usb_setup *setup)
+{
+    struct udc_gadget *gadget = g_u3d.gadget;
+    struct udc_request *req = g_u3d.ep0->req;
+    u8 *cp = req->buffer;
+
+    dump_setup_packet("Device Request\n", setup);
+
+    if ((setup->request_type & USB_TYPE_MASK) != 0)
+        return -EINVAL; /* Class-specific requests are handled elsewhere */
+
+    /* handle all requests that return data (direction bit set on bm RequestType) */
+    if ((setup->request_type & USB_EP_DIR_MASK)) {
+        /* send the descriptor */
+        g_u3d.ep0_state = EP0_TX;
+
+        switch (setup->request) {
+                /* data stage: from device to host */
+            case GET_STATUS:
+                DBG_I("GET_STATUS\n");
+                req->length = 2;
+                cp[0] = cp[1] = 0;
+
+                switch (setup->request_type & USB_RECIP_MASK) {
+                    case USB_RECIP_DEVICE:
+                        cp[0] = USB_STAT_SELFPOWERED;
+                        break;
+                    case USB_RECIP_OTHER:
+                        req->length = 0;
+                        break;
+                    default:
+                        break;
+                }
+                return 0;
+            case GET_DESCRIPTOR:
+                DBG_I("GET_DESCRIPTOR\n");
+                return std_get_descs(req, setup);
+            case GET_CONFIGURATION:
+                DBG_I("GET_CONFIGURATION\n");
+                break;
+            case GET_INTERFACE:
+                DBG_I("GET_INTERFACE\n");
+                break;
+            default:
+                DBG_C("Unsupported command with TX data stage\n");
+                break;
+        }
+    } else {
+        switch (setup->request) {
+            case SET_ADDRESS:
+                DBG_I("SET_ADDRESS\n");
+                g_u3d.address = (setup->value);
+                mu3d_set_address(g_u3d.address);
+                return 0;
+            case SET_CONFIGURATION:
+                DBG_I("SET_CONFIGURATION\n");
+                g_u3d.usb_online = setup->value ? 1 : 0;
+                if (setup->value == 1) {
+                    mtu3_setup_eps();
+                    spin(50);
+                    gadget->notify(gadget, UDC_EVENT_ONLINE);
+                } else {
+                    gadget->notify(gadget, UDC_EVENT_OFFLINE);
+                }
+                DBG_C("usb_online: %d\n", g_u3d.usb_online);
+                return 0;
+            case CLEAR_FEATURE:
+                DBG_I("CLEAR_FEATURE\n" );
+                switch(setup->request_type & 0x1f) {
+                    case RECIP_DEVICE:
+                        DBG_I("RECIP_DEVICE\n");
+                        break;
+                    case RECIP_INTERFACE:
+                        DBG_I("RECIP_INTERFACE\n");
+                        break;
+                    case RECIP_ENDPOINT:
+                        DBG_I("RECIP_ENDPOINT\n");
+                        mtu3_ep_stall_set(setup->index, false);
+                        return 0;
+                    default:
+                        DBG_I("USB_REQ_CLEAR_FEATURE - OTHER\n");
+                        break;
+                }
+
+                break;
+
+            default:
+                DBG_I("setup->request: %x, setup->value: %x\n",
+                      setup->request, setup->value);
+                DBG_C("Unsupported command with RX data stage\n");
+                break;
+        } /* switch request */
+    }
+
+    return -EINVAL;
+}
+
+static void mtu3_ep0_setup(void)
+{
+    struct usb_setup setup;
+    int stall = -ENOTSUP;
+    u32 csr0;
+    u32 len;
+
+    csr0 = readl(U3D_EP0CSR);
+    if (!(csr0 & EP0_SETUPPKTRDY))
+        return;
+
+    len = readl(U3D_RXCOUNT0);
+    if (len != 8) {
+        DBG_C("SETUP packet len %d != 8?\n", len);
+        return;
+    }
+
+    /* unload fifo */
+    pio_read_fifo(EP0, (u8 *)&setup, len);
+
+    /* decode command */
+    if (((setup.request_type) & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+        DBG_I("Standard Request\n");
+        stall = ep0_standard_setup(&setup);
+    }
+
+    /* command is not supported, inlcude  USB_TYPE_CLASS & USB_TYPE_VENDOR */
+    if (stall) {
+        dump_setup_packet("REQUEST NOT SUPPORTED\n", &setup);
+        ep0_stall_set(true, EP0_SETUPPKTRDY);
+        return;
+    }
+
+    /* handle EP0 state */
+    switch (g_u3d.ep0_state) {
+        case EP0_TX:
+            DBG_I("%s: EP0_TX\n", __func__);
+            csr0 = readl(U3D_EP0CSR);
+            csr0 |= (EP0_SETUPPKTRDY | EP0_DPHTX);
+            writel(csr0, U3D_EP0CSR);
+
+            mtu3_ep0_write();
+            break;
+        case EP0_RX:
+            DBG_I("%s: EP0_RX\n", __func__);
+            csr0 = readl(U3D_EP0CSR);
+            csr0 |= (EP0_SETUPPKTRDY);
+            writel(csr0, U3D_EP0CSR);
+            break;
+        case EP0_IDLE:
+            /* no data stage */
+            DBG_I("%s: EP0_IDLE\n", __func__);
+            csr0 = readl(U3D_EP0CSR);
+            csr0 |= (EP0_SETUPPKTRDY | EP0_DATAEND);
+            writel(csr0, U3D_EP0CSR);
+            break;
+        default:
+            break;
+    }
+}
+
+static void mtu3_ep0_isr(void)
+{
+    u32 csr0;
+
+    csr0 = readl(U3D_EP0CSR);
+
+    if (csr0 & EP0_SENTSTALL) {
+        DBG_I("USB: [EP0] SENTSTALL\n");
+        ep0_stall_set(false, 0);
+        csr0 = readl(U3D_EP0CSR);
+    }
+
+    switch (g_u3d.ep0_state) {
+        case EP0_IDLE:
+            DBG_I("%s: EP0_IDLE\n", __func__);
+            mtu3_ep0_setup();
+            break;
+        case EP0_TX:
+            DBG_I("%s: EP0_TX\n", __func__);
+            mtu3_ep0_write();
+            break;
+        case EP0_TX_END:
+            DBG_I("%s: EP0_TX_END\n", __func__);
+            csr0 |= EP0_DATAEND;
+            writel(csr0, U3D_EP0CSR);
+            g_u3d.ep0_state = EP0_IDLE;
+            break;
+        case EP0_RX:
+            DBG_I("%s: EP0_RX\n", __func__);
+            mtu3_ep0_read();
+            g_u3d.ep0_state = EP0_IDLE;
+            break;
+        default:
+            DBG_I("[ERR]: Unrecognized ep0 state %d", g_u3d.ep0_state);
+            break;
+    }
+}
+
+#ifndef SUPPORT_QMU
+/* PIO: TX packet */
+static int mtu3_epx_write(struct udc_endpoint *ept)
+{
+    int ep_num = ept->num;
+    int count;
+    u32 csr;
+
+    /* only for non-ep0 */
+    if (ep_num == 0)
+        return -EACCES;
+
+    if (!ept->in)
+        return -EINVAL;
+
+    csr = readl(MU3D_EP_TXCR0(ep_num));
+    if (csr & TX_TXPKTRDY) {
+        DBG_I("%s: ep%d is busy!\n", __func__, ep_num);
+        return -EBUSY;
+    }
+    count = mtu3_write_fifo(ept);
+
+    csr |= TX_TXPKTRDY;
+    writel(csr, MU3D_EP_TXCR0(ep_num));
+
+    return count;
+}
+
+static void mtu3_epx_isr(u8 ep_num, u8 dir)
+{
+    struct udc_endpoint *ept;
+    struct mu3d_req *mreq;
+    struct udc_request *req;
+    u32 csr;
+    u32 count;
+
+    ept = mtu3_find_ep(ep_num, dir);
+    if (!ept || !ept->req)
+        return;
+
+    DBG_I("%s Interrupt\n", ept->name);
+    req = ept->req;
+    mreq = to_mu3d_req(req);
+
+    if (dir == USB_DIR_IN) {
+        csr = readl(MU3D_EP_TXCR0(ep_num));
+        if (csr & TX_SENTSTALL) {
+            DBG_C("EP%dIN: STALL\n", ep_num);
+            handle_ept_complete(ept, -EPIPE);
+            /* exception handling: implement this!! */
+            return;
+        }
+
+        if (csr & TX_TXPKTRDY) {
+            DBG_C("%s: EP%dIN is busy\n", __func__, ep_num);
+            return;
+        }
+
+        if (req->length == mreq->actual) {
+            handle_ept_complete(ept, 0);
+            return;
+        }
+
+        count = mtu3_write_fifo(ept);
+        if (count) {
+            csr |= TX_TXPKTRDY;
+            writel(csr, MU3D_EP_TXCR0(ep_num));
+        }
+
+        DBG_I("EP%dIN, count=%d, %d/%d\n",
+              ep_num, count, mreq->actual, req->length);
+
+    } else {
+        csr = readl(MU3D_EP_RXCR0(ep_num));
+        if (csr & RX_SENTSTALL) {
+            DBG_C("EP%dOUT: STALL\n", ep_num);
+            /* exception handling: implement this!! */
+            return;
+        }
+
+        if (!(csr & RX_RXPKTRDY)) {
+            DBG_I("EP%dOUT: ERRONEOUS INTERRUPT\n", ep_num);
+            return;
+        }
+
+        count = mtu3_read_fifo(ept);
+
+        DBG_I("EP%dOUT, count = %d\n", ep_num, count);
+
+        /* write 1 to clear RXPKTRDY */
+        csr |= RX_RXPKTRDY;
+        writel(csr, MU3D_EP_RXCR0(ep_num));
+
+        if (readl(MU3D_EP_RXCR0(ep_num)) & RX_RXPKTRDY)
+            DBG_I("%s: rxpktrdy clear failed\n", __func__);
+
+        if ((req->length == mreq->actual) || (count < ept->maxpkt)) {
+            /* disable EP RX intr */
+            setbits32_r(EP_RXISR(ep_num), U3D_EPIECR);  /* W1C */
+            handle_ept_complete(ept, 0);
+        }
+    }
+}
+#endif
+
+/* handle abnormal DATA transfer if we had any, like USB unplugged */
+static void mtu3_suspend(void)
+{
+    struct udc_gadget *gadget = g_u3d.gadget;
+    struct udc_endpoint *ep_list = g_u3d.eps;
+    struct udc_endpoint *ept;
+    int i;
+
+    g_u3d.usb_online = 0;
+    gadget->notify(gadget, UDC_EVENT_OFFLINE);
+
+    /* error out any pending reqs, except ep0 */
+    for (i = 1; i < MT_EP_NUM; i++) {
+        ept = &ep_list[i];
+        /* End operation when encounter uninitialized ept */
+        if (ept->num == 0)
+            break;
+
+        DBG_I("%s: %s, req: %p\n", __func__, ept->name, ept->req);
+
+        mtu3_qmu_flush(ept);
+
+        if (ept->req)
+            handle_ept_complete(ept, -ESHUTDOWN);
+    }
+}
+
+static void mtu3_status_reset(void)
+{
+    g_u3d.ep0_state = EP0_IDLE;
+    g_u3d.address = 0;
+}
+
+static void mtu3_link_isr(void)
+{
+    u32 linkint;
+
+    linkint = readl(U3D_DEV_LINK_INTR) & readl(U3D_DEV_LINK_INTR_ENABLE);
+    writel(linkint, U3D_DEV_LINK_INTR);
+
+    if (linkint & SSUSB_DEV_SPEED_CHG_INTR) {
+        DBG_I("[INTR] Speed Change\n");
+        g_u3d.speed = mu3d_get_speed();
+        if (g_u3d.speed == SSUSB_SPEED_UNKNOWN)
+            mtu3_suspend();
+        else
+            mu3d_ep0en();
+    }
+}
+
+static void mtu3_u2_common_isr(void)
+{
+    u32 intrusb = 0;
+
+    intrusb = readl(U3D_COMMON_USB_INTR) & readl(U3D_COMMON_USB_INTR_ENABLE);
+    writel(intrusb, U3D_COMMON_USB_INTR);
+
+    if (intrusb & RESET_INTR) {
+        DBG_I("[INTR] Reset\n");
+        mtu3_status_reset();
+    }
+
+    if (intrusb & SUSPEND_INTR) {
+        DBG_I("[INTR] Suspend\n");
+        mtu3_suspend();
+    }
+
+    if (intrusb & RESUME_INTR)
+        DBG_I("[INTR] Resume\n");
+
+}
+
+static void mtu3_u3_ltssm_isr(void)
+{
+    u32 ltssm;
+
+    ltssm = readl(U3D_LTSSM_INTR) & readl(U3D_LTSSM_INTR_ENABLE);
+    writel(ltssm, U3D_LTSSM_INTR); /* W1C */
+    DBG_I("=== LTSSM[%x] ===\n", ltssm);
+
+    if (ltssm & (HOT_RST_INTR | WARM_RST_INTR))
+        mtu3_status_reset();
+
+    if (ltssm & VBUS_FALL_INTR) {
+        mu3d_ss_func_set(false);
+        mtu3_status_reset();
+    }
+
+    if (ltssm & VBUS_RISE_INTR)
+        mu3d_ss_func_set(true);
+
+    if (ltssm & ENTER_U3_INTR)
+        mtu3_suspend();
+
+    if (ltssm & EXIT_U3_INTR)
+        DBG_I("[INTR] Resume\n");
+
+}
+
+static void mtu3_bmu_isr(void)
+{
+    u32 intrep;
+
+    intrep = readl(U3D_EPISR) & readl(U3D_EPIER);
+    writel(intrep, U3D_EPISR);
+    DBG_I("[INTR] BMU[tx:%x, rx:%x] IER: %x\n",
+          intrep & 0xffff, intrep >> 16, readl(U3D_EPIER));
+
+    /* For EP0 */
+    if (intrep & 0x1) {
+        mtu3_ep0_isr();
+        intrep &= ~0x1;
+    }
+
+#ifndef SUPPORT_QMU
+    if (intrep) {
+        u32 ep_num;
+
+        for (ep_num = 1; ep_num <= (MT_EP_NUM / 2); ep_num++) {
+            if (intrep & EPT_RX(ep_num))
+                mtu3_epx_isr(ep_num, USB_DIR_OUT);
+
+            if (intrep & EPT_TX(ep_num))
+                mtu3_epx_isr(ep_num, USB_DIR_IN);
+        }
+    }
+#endif
+}
+
+static enum handler_return mtu3_isr(void *arg)
+{
+    u32 lv1_isr;
+
+    lv1_isr = readl(U3D_LV1ISR);  /* LV1ISR is RU */
+    lv1_isr &= readl(U3D_LV1IER);
+    DBG_I("[INTR] lv1_isr:0x%x\n", lv1_isr);
+
+    if (lv1_isr & EP_CTRL_INTR)
+        mtu3_link_isr();
+
+    if (lv1_isr & MAC2_INTR)
+        mtu3_u2_common_isr();
+
+    if (lv1_isr & MAC3_INTR)
+        mtu3_u3_ltssm_isr();
+
+    if (lv1_isr & BMU_INTR)
+        mtu3_bmu_isr();
+
+    if (lv1_isr & QMU_INTR)
+        mtu3_qmu_isr();
+
+    return INT_RESCHEDULE;
+}
+
+static void mu3d_isr_init(void)
+{
+    mt_irq_set_sens(SSUSB_DEV_INT_ID, LEVEL_SENSITIVE);
+    mt_irq_set_polarity(SSUSB_DEV_INT_ID, MT65xx_POLARITY_LOW);
+    register_int_handler(SSUSB_DEV_INT_ID, mtu3_isr, NULL);
+    unmask_interrupt(SSUSB_DEV_INT_ID);
+}
+
+/* gadget common APIs */
+
+static int g_u3d_init(void)
+{
+    struct mu3d_req *mreq = &g_u3d.ep0_mreq;
+    struct udc_request *req = &mreq->req;
+
+    mu3d_get_ip_vers();
+    g_u3d.ep0_state = EP0_IDLE;
+    g_u3d.address = 0;
+    if (g_u3d.is_u3_ip) {
+        g_u3d.speed = U3D_U3IP_DFT_SPEED;
+        g_u3d.tx_fifo_addr = U3IP_TX_FIFO_START_ADDR;
+        g_u3d.rx_fifo_addr = U3IP_RX_FIFO_START_ADDR;
+    } else {
+        g_u3d.speed = U3D_U2IP_DFT_SPEED;
+        g_u3d.tx_fifo_addr = U2IP_TX_FIFO_START_ADDR;
+        g_u3d.rx_fifo_addr = U2IP_RX_FIFO_START_ADDR;
+    }
+
+    g_u3d.ep0 = &g_u3d.eps[EP0];
+
+    req->buffer = udc_zalloc(512);
+    if (!req->buffer)
+        return -ENOMEM;
+
+    g_u3d.ep0->req = req;
+    g_u3d.ept_alloc_table = EPT_TX(0) | EPT_RX(0);
+    g_u3d.desc_list = NULL;
+    g_u3d.next_string_id = 1;
+    g_u3d.next_string_id_u3 = 1;
+
+    return mtu3_qmu_init();
+}
+
+int udc_init(struct udc_device *dev)
+{
+    g_u3d_init();
+    g_u3d.udev = dev;
+    return 0;
+}
+
+static struct udc_endpoint *_udc_endpoint_alloc(unsigned char num,
+        unsigned char in, unsigned short max_pkt)
+{
+    struct udc_endpoint *ep_list = g_u3d.eps;
+    struct udc_endpoint *ept;
+    int ret;
+    int i;
+
+    /* allocated and enabled by default */
+    if (num == EP0)
+        return NULL;
+
+    /*
+     * find an unused slot in ep_list from EP1 to MAX_EP
+     * for example, EP1 will use 2 eps, one for IN and the other for OUT
+     */
+    for (i = 1; i < MT_EP_NUM; i++) {
+        if (ep_list[i].num == 0) /* usable */
+            break;
+    }
+    if (i == MT_EP_NUM) /* ep has been exhausted. */
+        return NULL;
+
+    ept = &ep_list[i];
+    sprintf(ept->name, "ep%d%s", num, in ? "in" : "out");
+
+    ret = mtu3_gpd_ring_alloc(ept);
+    if (ret) {
+        DBG_C("%s gpd alloc failed\n", ept->name);
+        return NULL;
+    }
+
+    /* only supports BULK */
+    ept->type = USB_EP_XFER_BULK;
+    ept->maxpkt = max_pkt;
+    ept->num = num;
+    ept->in = in;
+    ept->req = NULL;
+
+    /* store EPT_TX/RX info */
+    if (ept->in)
+        ept->bit = EPT_TX(num);
+    else
+        ept->bit = EPT_RX(num);
+
+    /* write parameters to this ep (write to hardware) when SET_CONFIG */
+
+    DBG_I("%s @%p/%p max=%d bit=%x\n", ept->name,
+          ept, &ep_list, max_pkt, ept->bit);
+
+    return &ep_list[i];
+}
+
+struct udc_endpoint *udc_endpoint_alloc(unsigned int type, unsigned int maxpkt)
+{
+    struct udc_endpoint *ept;
+    unsigned int n;
+    unsigned int in;
+
+    DBG_I("%s\n", __func__);
+
+    if (type == UDC_BULK_IN)
+        in = 1;
+    else if (type == UDC_BULK_OUT)
+        in = 0;
+    else
+        return NULL;
+
+    /* udc_endpoint_alloc is used for EPx except EP0 */
+    for (n = 1; n < MT_EP_NUM; n++) {
+        unsigned int bit = in ? EPT_TX(n) : EPT_RX(n);
+
+        if (g_u3d.ept_alloc_table & bit)
+            continue;
+
+        ept = _udc_endpoint_alloc(n, in, maxpkt);
+        if (ept) {
+            g_u3d.ept_alloc_table |= bit;
+            return ept;
+        }
+    }
+
+    return NULL;
+}
+
+void udc_endpoint_free(struct udc_endpoint *ept)
+{
+    if (ept->num)
+        mtu3_gpd_ring_free(ept);
+}
+
+struct udc_request *udc_request_alloc(void)
+{
+    struct mu3d_req *mreq;
+
+    mreq = udc_zalloc(sizeof(*mreq));
+
+    return mreq ? &mreq->req : NULL;
+}
+
+void udc_request_free(struct udc_request *req)
+{
+    free(req);
+}
+
+int udc_request_queue(struct udc_endpoint *ept, struct udc_request *req)
+{
+    struct mu3d_req *mreq = to_mu3d_req(req);
+    int ret = 0;
+
+    DBG_I("%s: %s, req=%p, buf: %p, length=%d\n", __func__,
+          ept->name, req, req->buffer, req->length);
+
+    if (!g_u3d.usb_online)
+        return -ENXIO;
+
+    mask_interrupt(SSUSB_DEV_INT_ID);
+    ept->req = req;
+    mreq->ept = ept;
+    mreq->actual = 0;
+
+#ifdef SUPPORT_QMU
+    if (req->length > GPD_BUF_SIZE) {
+        DBG_C("req length > supported MAX:%d requested:%d\n",
+              GPD_BUF_SIZE, req->length);
+        ret = -EOPNOTSUPP;
+        goto out;
+    }
+
+    if (mtu3_prepare_transfer(ept)) {
+        ret = -EAGAIN;
+        goto out;
+    }
+
+    arch_clean_invalidate_cache_range((addr_t)req->buffer, req->length);
+    mtu3_insert_gpd(ept, mreq);
+    mtu3_qmu_resume(ept);
+#else
+
+    /*
+     * PIO mode:
+     * when class driver shares a buffer to TX and RX data,
+     * mtu3 sends a data to host, then host sends a data back immediately,
+     * cause EP TX and RX interrupts arise at the same time,
+     * but the buffer is using by the TX, so no buffer for RX to receive data.
+     * To fix the issue:
+     * disable EP RX intrrupt by default, enable it when queue RX
+     * request and disable it again when complete the request.
+     */
+    if (ept->in)
+        mtu3_epx_write(ept);
+    else
+        setbits32_r(EP_RXISR(ept->num), U3D_EPIESR);    /* W1S */
+#endif
+
+out:
+    unmask_interrupt(SSUSB_DEV_INT_ID);
+
+    return ret;
+}
+
+int udc_register_gadget(struct udc_gadget *gadget)
+{
+    if (g_u3d.gadget) {
+        DBG_C("only one gadget supported\n");
+        return -EBUSY;
+    }
+    g_u3d.gadget = gadget;
+
+    return 0;
+}
+
+int udc_start(void)
+{
+    struct udc_device *udev = g_u3d.udev;
+    struct udc_gadget *gadget = g_u3d.gadget;
+
+    if (!udev) {
+        DBG_C("udc cannot start before init\n");
+        return -ENODEV;
+    }
+    if (!gadget) {
+        DBG_C("udc has no gadget registered\n");
+        return -ENXIO;
+    }
+    DBG_I("%s\n", __func__);
+
+    udc_create_descriptors(udev, gadget);
+    mt_usb_phy_poweron();
+    mu3d_hw_init();
+    mu3d_isr_init();
+    mu3d_soft_connect();
+
+    return 0;
+}
+
+int udc_stop(void)
+{
+    mu3d_soft_disconnect();
+    mt_usb_phy_poweroff();
+
+    return 0;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3.h b/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3.h
new file mode 100644
index 0000000..272ec3c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * 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 <dev/udc.h>
+#include <hw/usb.h>
+#include <reg.h>
+
+struct udc_endpoint;
+struct mu3d_req;
+
+#include "mtu3_hw_regs.h"
+#include "mtu3_qmu.h"
+
+/* if want to use PIO mode, comment out the following macro */
+#define SUPPORT_QMU
+
+/* two bulk and ep0 */
+#define MT_EP_NUM 3
+#define MAX_EP_NUM 8
+
+#define DESC_TYPE_U2 0
+#define DESC_TYPE_U3 1
+
+/* U3 IP: EP0, TX, RX has separate SRAMs */
+#define U3IP_TX_FIFO_START_ADDR   0
+#define U3IP_RX_FIFO_START_ADDR   0
+
+/* U2 IP: EP0, TX, RX share one SRAM. 0-63 bytes are reserved for EP0 */
+#define U2IP_TX_FIFO_START_ADDR   (64)
+#define U2IP_RX_FIFO_START_ADDR   (64 + 512 * (MAX_EP_NUM))
+
+#define U3D_U3IP_DFT_SPEED SSUSB_SPEED_SUPER
+#define U3D_U2IP_DFT_SPEED SSUSB_SPEED_HIGH
+
+/*
+ * fastboot only supports BULK, alloc 1024B for each ep and offset are
+ * also fixed, such as, offset-1024 for ep1, offset-2048 for ep2;
+ * so MT_EP_NUM should not greater than 9(ep0 + 4 bulk in + 4 bulk out)
+ */
+#define U3D_FIFO_SIZE_UNIT 1024
+
+#define EP0_MAX_PACKET_SIZE 64
+#define EP0_MAX_PACKET_SIZE_U3 512
+
+#define USB_FIFOSZ_SIZE_8       (0x03)
+#define USB_FIFOSZ_SIZE_16      (0x04)
+#define USB_FIFOSZ_SIZE_32      (0x05)
+#define USB_FIFOSZ_SIZE_64      (0x06)
+#define USB_FIFOSZ_SIZE_128     (0x07)
+#define USB_FIFOSZ_SIZE_256     (0x08)
+#define USB_FIFOSZ_SIZE_512     (0x09)
+#define USB_FIFOSZ_SIZE_1024    (0x0A)
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+typedef enum {
+    EP0_IDLE = 0,
+    EP0_RX,
+    EP0_TX,
+    EP0_TX_END,
+} EP0_STATE;
+
+/* MTK USB3 ssusb defines */
+typedef enum {
+    SSUSB_SPEED_UNKNOWN = 0,
+    SSUSB_SPEED_FULL = 1,
+    SSUSB_SPEED_HIGH = 2,
+    SSUSB_SPEED_SUPER = 3,
+    SSUSB_SPEED_SUPER_PLUS = 4,
+} USB_SPEED;
+
+#define USB_EP_XFER_CTRL    0
+#define USB_EP_XFER_ISO     1
+#define USB_EP_XFER_BULK    2
+#define USB_EP_XFER_INT     3
+
+/* USB transfer directions */
+#define USB_DIR_IN  0x80
+#define USB_DIR_OUT 0x00
+
+struct udc_descriptor {
+    struct udc_descriptor *next;
+    unsigned short tag; /* ((TYPE << 8) | NUM) */
+    unsigned short len; /* total length */
+    unsigned char data[0];
+};
+
+struct mu3d_req {
+    struct udc_request req; /* should be first */
+    struct udc_endpoint *ept;
+    struct qmu_gpd *gpd;
+    unsigned int actual;    /* data already sent/rcv */
+};
+
+/* endpoint data */
+struct udc_endpoint {
+    struct udc_request *req;
+    struct mtu3_gpd_ring gpd_ring;
+    char name[12];
+    unsigned int maxpkt;
+    unsigned char num;
+    unsigned char in;
+    unsigned char type; /* Transfer type */
+    unsigned int bit;   /* EPT_TX/EPT_RX */
+};
+
+struct mu3d {
+    struct udc_device *udev;
+    struct udc_gadget *gadget;
+    EP0_STATE ep0_state;
+    USB_SPEED speed;
+    u32 tx_fifo_addr;
+    u32 rx_fifo_addr;
+
+    struct udc_endpoint eps[MT_EP_NUM]; /* index 0 is fixed as EP0 */
+    struct udc_endpoint *ep0;
+    struct mu3d_req ep0_mreq;
+    u32 ept_alloc_table;
+
+    struct udc_descriptor *desc_list;
+    unsigned int next_string_id;
+    struct udc_descriptor *desc_list_u3;
+    unsigned int next_string_id_u3;
+
+    u8 address;
+    unsigned usb_online:1;
+    unsigned is_u3_ip:1;
+};
+
+int wait_for_value(paddr_t addr, u32 msk, u32 value, int us_intvl, int count);
+struct udc_endpoint *mtu3_find_ep(int ep_num, u8 dir);
+void handle_ept_complete(struct udc_endpoint *ept, int status);
+static int pio_read_fifo(int ep_num, u8 *dst, u16 len) __attribute__((noinline));
+
+static inline struct mu3d_req *to_mu3d_req(struct udc_request *req)
+{
+    return (struct mu3d_req *)req;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3_hw_regs.h b/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3_hw_regs.h
new file mode 100644
index 0000000..cbf265c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3_hw_regs.h
@@ -0,0 +1,495 @@
+/*
+ * mtu3_hw_regs.h - MediaTek USB3 DRD register and field definitions
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * 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 <platform/mt_reg_base.h>
+
+/* segment offset of MAC register */
+#define SSUSB_DEV_BASE              (USB3_BASE + 0x1000)
+#define SSUSB_EPCTL_CSR_BASE        (USB3_BASE + 0x1800)
+#define SSUSB_USB3_MAC_CSR_BASE     (USB3_BASE + 0x2400)
+#define SSUSB_USB3_SYS_CSR_BASE     (USB3_BASE + 0x2400)
+#define SSUSB_USB2_CSR_BASE         (USB3_BASE + 0x3400)
+
+/* IPPC register in Infra */
+#define SSUSB_SIFSLV_IPPC_BASE      (USB3_IPPC_BASE)
+
+#define BITS_PER_LONG 32
+#ifndef BIT
+#define BIT(bit) (1UL << (bit))
+#endif
+#ifndef GENMASK
+#define GENMASK(h, l) \
+    ((u32)(((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))))
+#endif
+
+/* SSUSB_DEV REGISTER DEFINITION */
+#define U3D_LV1ISR      (SSUSB_DEV_BASE + 0x0000)
+#define U3D_LV1IER      (SSUSB_DEV_BASE + 0x0004)
+#define U3D_LV1IESR     (SSUSB_DEV_BASE + 0x0008)
+#define U3D_LV1IECR     (SSUSB_DEV_BASE + 0x000C)
+
+#define U3D_EPISR       (SSUSB_DEV_BASE + 0x0080)
+#define U3D_EPIER       (SSUSB_DEV_BASE + 0x0084)
+#define U3D_EPIESR      (SSUSB_DEV_BASE + 0x0088)
+#define U3D_EPIECR      (SSUSB_DEV_BASE + 0x008C)
+
+#define U3D_EP0CSR      (SSUSB_DEV_BASE + 0x0100)
+#define U3D_RXCOUNT0    (SSUSB_DEV_BASE + 0x0108)
+#define U3D_RESERVED    (SSUSB_DEV_BASE + 0x010C)
+#define U3D_TX1CSR0     (SSUSB_DEV_BASE + 0x0110)
+#define U3D_TX1CSR1     (SSUSB_DEV_BASE + 0x0114)
+#define U3D_TX1CSR2     (SSUSB_DEV_BASE + 0x0118)
+
+#define U3D_RX1CSR0     (SSUSB_DEV_BASE + 0x0210)
+#define U3D_RX1CSR1     (SSUSB_DEV_BASE + 0x0214)
+#define U3D_RX1CSR2     (SSUSB_DEV_BASE + 0x0218)
+#define U3D_RX1CSR3     (SSUSB_DEV_BASE + 0x021C)
+
+#define U3D_FIFO0       (SSUSB_DEV_BASE + 0x0300)
+
+#define U3D_QCR0        (SSUSB_DEV_BASE + 0x0400)
+#define U3D_QCR1        (SSUSB_DEV_BASE + 0x0404)
+#define U3D_QCR2        (SSUSB_DEV_BASE + 0x0408)
+#define U3D_QCR3        (SSUSB_DEV_BASE + 0x040C)
+
+#define U3D_TXQCSR1     (SSUSB_DEV_BASE + 0x0510)
+#define U3D_TXQSAR1     (SSUSB_DEV_BASE + 0x0514)
+#define U3D_TXQCPR1     (SSUSB_DEV_BASE + 0x0518)
+
+#define U3D_RXQCSR1     (SSUSB_DEV_BASE + 0x0610)
+#define U3D_RXQSAR1     (SSUSB_DEV_BASE + 0x0614)
+#define U3D_RXQCPR1     (SSUSB_DEV_BASE + 0x0618)
+#define U3D_RXQLDPR1    (SSUSB_DEV_BASE + 0x061C)
+
+#define U3D_QISAR0      (SSUSB_DEV_BASE + 0x0700)
+#define U3D_QIER0       (SSUSB_DEV_BASE + 0x0704)
+#define U3D_QIESR0      (SSUSB_DEV_BASE + 0x0708)
+#define U3D_QIECR0      (SSUSB_DEV_BASE + 0x070C)
+#define U3D_QISAR1      (SSUSB_DEV_BASE + 0x0710)
+#define U3D_QIER1       (SSUSB_DEV_BASE + 0x0714)
+#define U3D_QIESR1      (SSUSB_DEV_BASE + 0x0718)
+#define U3D_QIECR1      (SSUSB_DEV_BASE + 0x071C)
+
+#define U3D_TQERRIR0        (SSUSB_DEV_BASE + 0x0780)
+#define U3D_TQERRIER0       (SSUSB_DEV_BASE + 0x0784)
+#define U3D_TQERRIESR0      (SSUSB_DEV_BASE + 0x0788)
+#define U3D_TQERRIECR0      (SSUSB_DEV_BASE + 0x078C)
+#define U3D_RQERRIR0        (SSUSB_DEV_BASE + 0x07C0)
+#define U3D_RQERRIER0       (SSUSB_DEV_BASE + 0x07C4)
+#define U3D_RQERRIESR0      (SSUSB_DEV_BASE + 0x07C8)
+#define U3D_RQERRIECR0      (SSUSB_DEV_BASE + 0x07CC)
+#define U3D_RQERRIR1        (SSUSB_DEV_BASE + 0x07D0)
+#define U3D_RQERRIER1       (SSUSB_DEV_BASE + 0x07D4)
+#define U3D_RQERRIESR1      (SSUSB_DEV_BASE + 0x07D8)
+#define U3D_RQERRIECR1      (SSUSB_DEV_BASE + 0x07DC)
+
+#define U3D_CAP_EP0FFSZ     (SSUSB_DEV_BASE + 0x0C04)
+#define U3D_CAP_EPNTXFFSZ   (SSUSB_DEV_BASE + 0x0C08)
+#define U3D_CAP_EPNRXFFSZ   (SSUSB_DEV_BASE + 0x0C0C)
+#define U3D_CAP_EPINFO      (SSUSB_DEV_BASE + 0x0C10)
+#define U3D_MISC_CTRL       (SSUSB_DEV_BASE + 0x0C84)
+
+/* SSUSB_DEV FIELD DEFINITION */
+/* U3D_LV1ISR */
+#define EP_CTRL_INTR    BIT(5)
+#define MAC2_INTR       BIT(4)
+#define DMA_INTR        BIT(3)
+#define MAC3_INTR       BIT(2)
+#define QMU_INTR        BIT(1)
+#define BMU_INTR        BIT(0)
+
+/* U3D_LV1IECR */
+#define LV1IECR_MSK     GENMASK(31, 0)
+
+/* U3D_EPISR */
+#define EP_RXISR(x)     (BIT(16) << (x))
+#define EP_TXISR(x)     (BIT(0) << (x))
+#define EP_EP0ISR       BIT(0)
+
+/* U3D_EP0CSR */
+#define EP0_AUTOCLEAR   BIT(30)
+#define EP0_AUTOSET     BIT(29)
+#define EP0_DMAREQEN    BIT(28)
+#define EP0_SENDSTALL   BIT(25)
+#define EP0_FIFOFULL    BIT(23)
+#define EP0_SENTSTALL   BIT(22)
+#define EP0_DPHTX       BIT(20)
+#define EP0_DATAEND     BIT(19)
+#define EP0_TXPKTRDY        BIT(18)
+#define EP0_SETUPPKTRDY     BIT(17)
+#define EP0_RXPKTRDY        BIT(16)
+#define EP0_MAXPKTSZ_MSK    GENMASK(9, 0)
+#define EP0_MAXPKTSZ(x)     ((x) & EP0_MAXPKTSZ_MSK)
+#define EP0_W1C_BITS    (~(EP0_RXPKTRDY | EP0_SETUPPKTRDY | EP0_SENTSTALL))
+
+/* U3D_TX1CSR0 */
+#define TX_AUTOSET      BIT(30)
+#define TX_DMAREQEN     BIT(29)
+#define TX_FIFOFULL     BIT(25)
+#define TX_FIFOEMPTY    BIT(24)
+#define TX_SENTSTALL    BIT(22)
+#define TX_SENDSTALL    BIT(21)
+#define TX_TXPKTRDY     BIT(16)
+#define TX_TXMAXPKTSZ_MSK   GENMASK(10, 0)
+#define TX_TXMAXPKTSZ(x)    ((x) & TX_TXMAXPKTSZ_MSK)
+#define TX_W1C_BITS     (~(TX_SENTSTALL))
+
+/* U3D_TX1CSR1 */
+#define TX_MULT(x)      (((x) & 0x3) << 22)
+#define TX_MAX_PKT(x)   (((x) & 0x3f) << 16)
+#define TX_SLOT(x)      (((x) & 0x3f) << 8)
+#define TX_TYPE(x)      (((x) & 0x3) << 4)
+#define TX_SS_BURST(x)      (((x) & 0xf) << 0)
+
+/* for TX_TYPE & RX_TYPE */
+#define TYPE_BULK       (0x0)
+#define TYPE_INT        (0x1)
+#define TYPE_ISO        (0x2)
+#define TYPE_MSK        (0x3)
+
+/* U3D_TX1CSR2 */
+#define TX_BINTERVAL(x)     (((x) & 0xff) << 24)
+#define TX_FIFOSEGSIZE(x)   (((x) & 0xf) << 16)
+#define TX_FIFOADDR(x)      (((x) & 0x1fff) << 0)
+
+/* U3D_RX1CSR0 */
+#define RX_AUTOCLEAR    BIT(30)
+#define RX_DMAREQEN     BIT(29)
+#define RX_SENTSTALL    BIT(22)
+#define RX_SENDSTALL    BIT(21)
+#define RX_RXPKTRDY     BIT(16)
+#define RX_RXMAXPKTSZ_MSK   GENMASK(10, 0)
+#define RX_RXMAXPKTSZ(x)    ((x) & RX_RXMAXPKTSZ_MSK)
+#define RX_W1C_BITS     (~(RX_SENTSTALL | RX_RXPKTRDY))
+
+/* U3D_RX1CSR1 */
+#define RX_MULT(x)      (((x) & 0x3) << 22)
+#define RX_MAX_PKT(x)   (((x) & 0x3f) << 16)
+#define RX_SLOT(x)      (((x) & 0x3f) << 8)
+#define RX_TYPE(x)      (((x) & 0x3) << 4)
+#define RX_SS_BURST(x)  (((x) & 0xf) << 0)
+
+/* U3D_RX1CSR2 */
+#define RX_BINTERVAL(x)     (((x) & 0xff) << 24)
+#define RX_FIFOSEGSIZE(x)   (((x) & 0xf) << 16)
+#define RX_FIFOADDR(x)      (((x) & 0x1fff) << 0)
+
+/* U3D_RX1CSR3 */
+#define EP_RX_COUNT(x)      (((x) >> 16) & 0x7ff)
+
+/* U3D_FIFO: ep(0-15)*/
+#define U3D_FIFO(x)         (U3D_FIFO0 + ((x) * 0x10))
+#define USB_FIFO(x)         (U3D_FIFO(x))
+
+/* U3D_QCR0 */
+#define QMU_RX_CS_EN(x)     (BIT(16) << (x))
+#define QMU_TX_CS_EN(x)     (BIT(0) << (x))
+#define QMU_CS16B_EN        BIT(0)
+
+/* U3D_QCR1 */
+#define QMU_TX_ZLP(x)       (BIT(0) << (x))
+
+/* U3D_QCR3 */
+#define QMU_RX_COZ(x)       (BIT(16) << (x))
+#define QMU_RX_ZLP(x)       (BIT(0) << (x))
+
+/* U3D_TXQCSR1 */
+/* U3D_RXQCSR1 */
+#define QMU_Q_ACTIVE    BIT(15)
+#define QMU_Q_STOP      BIT(2)
+#define QMU_Q_RESUME    BIT(1)
+#define QMU_Q_START     BIT(0)
+
+/* U3D_QISAR0, U3D_QIER0, U3D_QIESR0, U3D_QIECR0 */
+#define QMU_RX_DONE_INT(x)  (BIT(16) << (x))
+#define QMU_TX_DONE_INT(x)  (BIT(0) << (x))
+
+/* U3D_QISAR1, U3D_QIER1, U3D_QIESR1, U3D_QIECR1 */
+#define RXQ_ZLPERR_INT      BIT(20)
+#define RXQ_LENERR_INT      BIT(18)
+#define RXQ_CSERR_INT       BIT(17)
+#define RXQ_EMPTY_INT       BIT(16)
+#define TXQ_LENERR_INT      BIT(2)
+#define TXQ_CSERR_INT       BIT(1)
+#define TXQ_EMPTY_INT       BIT(0)
+
+/* U3D_TQERRIR0, U3D_TQERRIER0, U3D_TQERRIESR0, U3D_TQERRIECR0 */
+#define QMU_TX_LEN_ERR(x)   (BIT(16) << (x))
+#define QMU_TX_CS_ERR(x)    (BIT(0) << (x))
+
+/* U3D_RQERRIR0, U3D_RQERRIER0, U3D_RQERRIESR0, U3D_RQERRIECR0 */
+#define QMU_RX_LEN_ERR(x)   (BIT(16) << (x))
+#define QMU_RX_CS_ERR(x)    (BIT(0) << (x))
+
+/* U3D_RQERRIR1, U3D_RQERRIER1, U3D_RQERRIESR1, U3D_RQERRIECR1 */
+#define QMU_RX_ZLP_ERR(n)   (BIT(16) << (n))
+
+/* U3D_CAP_EPINFO */
+#define CAP_RX_EP_NUM(x)    (((x) >> 8) & 0x1f)
+#define CAP_TX_EP_NUM(x)    ((x) & 0x1f)
+
+/* U3D_MISC_CTRL */
+#define VBUS_ON         BIT(1)
+#define VBUS_FRC_EN     BIT(0)
+
+
+/* SSUSB_EPCTL_CSR REGISTER DEFINITION */
+#define U3D_DEVICE_CONF     (SSUSB_EPCTL_CSR_BASE + 0x0000)
+#define U3D_EP_RST          (SSUSB_EPCTL_CSR_BASE + 0x0004)
+
+#define U3D_DEV_LINK_INTR_ENABLE    (SSUSB_EPCTL_CSR_BASE + 0x0050)
+#define U3D_DEV_LINK_INTR       (SSUSB_EPCTL_CSR_BASE + 0x0054)
+
+/* SSUSB_EPCTL_CSR FIELD DEFINITION */
+/* U3D_DEVICE_CONF */
+#define DEV_ADDR_MSK    GENMASK(30, 24)
+#define DEV_ADDR(x)     ((0x7f & (x)) << 24)
+#define HW_USB2_3_SEL       BIT(18)
+#define SW_USB2_3_SEL_EN    BIT(17)
+#define SW_USB2_3_SEL       BIT(16)
+#define SSUSB_DEV_SPEED(x)  ((x) & 0x7)
+
+/* U3D_EP_RST */
+#define EP1_IN_RST      BIT(17)
+#define EP1_OUT_RST     BIT(1)
+#define EP_RST(is_in, epnum)    (((is_in) ? BIT(16) : BIT(0)) << (epnum))
+#define EP0_RST         BIT(0)
+
+/* U3D_DEV_LINK_INTR_ENABLE */
+/* U3D_DEV_LINK_INTR */
+#define SSUSB_DEV_SPEED_CHG_INTR    BIT(0)
+
+
+/* SSUSB_USB3_MAC_CSR REGISTER DEFINITION */
+#define U3D_LTSSM_CTRL      (SSUSB_USB3_MAC_CSR_BASE + 0x0010)
+#define U3D_USB3_CONFIG     (SSUSB_USB3_MAC_CSR_BASE + 0x001C)
+
+#define U3D_LTSSM_INTR_ENABLE   (SSUSB_USB3_MAC_CSR_BASE + 0x013C)
+#define U3D_LTSSM_INTR      (SSUSB_USB3_MAC_CSR_BASE + 0x0140)
+
+/* SSUSB_USB3_MAC_CSR FIELD DEFINITION */
+/* U3D_LTSSM_CTRL */
+#define FORCE_POLLING_FAIL  BIT(4)
+#define FORCE_RXDETECT_FAIL BIT(3)
+#define SOFT_U3_EXIT_EN     BIT(2)
+#define COMPLIANCE_EN       BIT(1)
+#define U1_GO_U2_EN     BIT(0)
+
+/* U3D_USB3_CONFIG */
+#define USB3_EN         BIT(0)
+
+/* U3D_LTSSM_INTR_ENABLE */
+/* U3D_LTSSM_INTR */
+#define U3_RESUME_INTR      BIT(18)
+#define U3_LFPS_TMOUT_INTR  BIT(17)
+#define VBUS_FALL_INTR      BIT(16)
+#define VBUS_RISE_INTR      BIT(15)
+#define RXDET_SUCCESS_INTR  BIT(14)
+#define EXIT_U3_INTR        BIT(13)
+#define EXIT_U2_INTR        BIT(12)
+#define EXIT_U1_INTR        BIT(11)
+#define ENTER_U3_INTR       BIT(10)
+#define ENTER_U2_INTR       BIT(9)
+#define ENTER_U1_INTR       BIT(8)
+#define ENTER_U0_INTR       BIT(7)
+#define RECOVERY_INTR       BIT(6)
+#define WARM_RST_INTR       BIT(5)
+#define HOT_RST_INTR        BIT(4)
+#define LOOPBACK_INTR       BIT(3)
+#define COMPLIANCE_INTR     BIT(2)
+#define SS_DISABLE_INTR     BIT(1)
+#define SS_INACTIVE_INTR    BIT(0)
+
+/* SSUSB_USB3_SYS_CSR REGISTER DEFINITION */
+#define U3D_LINK_UX_INACT_TIMER (SSUSB_USB3_SYS_CSR_BASE + 0x020C)
+#define U3D_LINK_POWER_CONTROL  (SSUSB_USB3_SYS_CSR_BASE + 0x0210)
+#define U3D_LINK_ERR_COUNT      (SSUSB_USB3_SYS_CSR_BASE + 0x0214)
+
+/* SSUSB_USB3_SYS_CSR FIELD DEFINITION */
+/* U3D_LINK_UX_INACT_TIMER */
+#define DEV_U2_INACT_TIMEOUT_MSK    GENMASK(23, 16)
+#define DEV_U2_INACT_TIMEOUT_VALUE(x)   (((x) & 0xff) << 16)
+#define U2_INACT_TIMEOUT_MSK        GENMASK(15, 8)
+#define U1_INACT_TIMEOUT_MSK        GENMASK(7, 0)
+#define U1_INACT_TIMEOUT_VALUE(x)   ((x) & 0xff)
+
+/* U3D_LINK_POWER_CONTROL */
+#define SW_U2_ACCEPT_ENABLE     BIT(9)
+#define SW_U1_ACCEPT_ENABLE     BIT(8)
+#define UX_EXIT         BIT(5)
+#define LGO_U3          BIT(4)
+#define LGO_U2          BIT(3)
+#define LGO_U1          BIT(2)
+#define SW_U2_REQUEST_ENABLE    BIT(1)
+#define SW_U1_REQUEST_ENABLE    BIT(0)
+
+/* U3D_LINK_ERR_COUNT */
+#define CLR_LINK_ERR_CNT    BIT(16)
+#define LINK_ERROR_COUNT    GENMASK(15, 0)
+
+/* SSUSB_USB2_CSR REGISTER DEFINITION */
+#define U3D_POWER_MANAGEMENT        (SSUSB_USB2_CSR_BASE + 0x0004)
+#define U3D_DEVICE_CONTROL          (SSUSB_USB2_CSR_BASE + 0x000C)
+#define U3D_USB2_TEST_MODE          (SSUSB_USB2_CSR_BASE + 0x0014)
+#define U3D_COMMON_USB_INTR_ENABLE  (SSUSB_USB2_CSR_BASE + 0x0018)
+#define U3D_COMMON_USB_INTR         (SSUSB_USB2_CSR_BASE + 0x001C)
+#define U3D_LINK_RESET_INFO         (SSUSB_USB2_CSR_BASE + 0x0024)
+#define U3D_USB20_FRAME_NUM         (SSUSB_USB2_CSR_BASE + 0x003C)
+#define U3D_USB20_LPM_PARAMETER     (SSUSB_USB2_CSR_BASE + 0x0044)
+#define U3D_USB20_MISC_CONTROL      (SSUSB_USB2_CSR_BASE + 0x004C)
+
+/* SSUSB_USB2_CSR FIELD DEFINITION */
+/* U3D_POWER_MANAGEMENT */
+#define LPM_BESL_STALL      BIT(14)
+#define LPM_BESLD_STALL     BIT(13)
+#define LPM_RWP         BIT(11)
+#define LPM_HRWE        BIT(10)
+#define LPM_MODE(x)     (((x) & 0x3) << 8)
+#define ISO_UPDATE      BIT(7)
+#define SOFT_CONN       BIT(6)
+#define HS_ENABLE       BIT(5)
+#define RESUME          BIT(2)
+#define SUSPENDM_ENABLE     BIT(0)
+
+/* U3D_DEVICE_CONTROL */
+#define DC_HOSTREQ      BIT(1)
+#define DC_SESSION      BIT(0)
+
+/* U3D_USB2_TEST_MODE */
+#define U2U3_AUTO_SWITCH    BIT(10)
+#define LPM_FORCE_STALL     BIT(8)
+#define FIFO_ACCESS         BIT(6)
+#define FORCE_FS            BIT(5)
+#define FORCE_HS            BIT(4)
+#define TEST_PACKET_MODE    BIT(3)
+#define TEST_K_MODE         BIT(2)
+#define TEST_J_MODE         BIT(1)
+#define TEST_SE0_NAK_MODE   BIT(0)
+
+/* U3D_COMMON_USB_INTR_ENABLE */
+/* U3D_COMMON_USB_INTR */
+#define LPM_RESUME_INTR BIT(9)
+#define LPM_INTR        BIT(8)
+#define DISCONN_INTR    BIT(5)
+#define CONN_INTR       BIT(4)
+#define SOF_INTR        BIT(3)
+#define RESET_INTR      BIT(2)
+#define RESUME_INTR     BIT(1)
+#define SUSPEND_INTR    BIT(0)
+
+/* U3D_LINK_RESET_INFO */
+#define WTCHRP_MSK      GENMASK(19, 16)
+
+/* U3D_USB20_LPM_PARAMETER */
+#define LPM_BESLCK_U3(x)    (((x) & 0xf) << 12)
+#define LPM_BESLCK(x)       (((x) & 0xf) << 8)
+#define LPM_BESLDCK(x)      (((x) & 0xf) << 4)
+#define LPM_BESL            GENMASK(3, 0)
+
+/* U3D_USB20_MISC_CONTROL */
+#define LPM_U3_ACK_EN       BIT(0)
+
+/* SSUSB_SIFSLV_IPPC REGISTER DEFINITION */
+#define U3D_SSUSB_IP_PW_CTRL0   (SSUSB_SIFSLV_IPPC_BASE + 0x0000)
+#define U3D_SSUSB_IP_PW_CTRL1   (SSUSB_SIFSLV_IPPC_BASE + 0x0004)
+#define U3D_SSUSB_IP_PW_CTRL2   (SSUSB_SIFSLV_IPPC_BASE + 0x0008)
+#define U3D_SSUSB_IP_PW_CTRL3   (SSUSB_SIFSLV_IPPC_BASE + 0x000C)
+#define U3D_SSUSB_IP_PW_STS1    (SSUSB_SIFSLV_IPPC_BASE + 0x0010)
+#define U3D_SSUSB_IP_PW_STS2    (SSUSB_SIFSLV_IPPC_BASE + 0x0014)
+#define U3D_SSUSB_OTG_STS       (SSUSB_SIFSLV_IPPC_BASE + 0x0018)
+#define U3D_SSUSB_OTG_STS_CLR   (SSUSB_SIFSLV_IPPC_BASE + 0x001C)
+#define U3D_SSUSB_IP_XHCI_CAP   (SSUSB_SIFSLV_IPPC_BASE + 0x0024)
+#define U3D_SSUSB_IP_DEV_CAP    (SSUSB_SIFSLV_IPPC_BASE + 0x0028)
+#define U3D_SSUSB_OTG_INT_EN    (SSUSB_SIFSLV_IPPC_BASE + 0x002C)
+#define U3D_SSUSB_U3_CTRL_0P    (SSUSB_SIFSLV_IPPC_BASE + 0x0030)
+#define U3D_SSUSB_U2_CTRL_0P    (SSUSB_SIFSLV_IPPC_BASE + 0x0050)
+#define U3D_SSUSB_REF_CK_CTRL   (SSUSB_SIFSLV_IPPC_BASE + 0x008C)
+#define U3D_SSUSB_DEV_RST_CTRL  (SSUSB_SIFSLV_IPPC_BASE + 0x0098)
+#define U3D_SSUSB_HW_ID         (SSUSB_SIFSLV_IPPC_BASE + 0x00A0)
+#define U3D_SSUSB_HW_SUB_ID     (SSUSB_SIFSLV_IPPC_BASE + 0x00A4)
+#define U3D_SSUSB_IP_SPARE0     (SSUSB_SIFSLV_IPPC_BASE + 0x00C8)
+#define U3D_SSUSB_FPGA_I2C_OUT_0P       (SSUSB_SIFSLV_IPPC_BASE+0x00A8)
+#define U3D_SSUSB_FPGA_I2C_IN_0P        (SSUSB_SIFSLV_IPPC_BASE+0x00AC)
+
+/* SSUSB_SIFSLV_IPPC FIELD DEFINITION */
+/* U3D_SSUSB_IP_PW_CTRL0 */
+#define SSUSB_IP_SW_RST         BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL1 */
+#define SSUSB_IP_HOST_PDN       BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL2 */
+#define SSUSB_IP_DEV_PDN        BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL3 */
+#define SSUSB_IP_PCIE_PDN       BIT(0)
+
+/* U3D_SSUSB_IP_PW_STS1 */
+#define SSUSB_IP_SLEEP_STS      BIT(30)
+#define SSUSB_U3_MAC_RST_B_STS  BIT(16)
+#define SSUSB_XHCI_RST_B_STS    BIT(11)
+#define SSUSB_SYS125_RST_B_STS  BIT(10)
+#define SSUSB_REF_RST_B_STS     BIT(8)
+#define SSUSB_SYSPLL_STABLE     BIT(0)
+
+/* U3D_SSUSB_IP_PW_STS2 */
+#define SSUSB_U2_MAC_SYS_RST_B_STS  BIT(0)
+
+/* U3D_SSUSB_OTG_STS */
+#define SSUSB_VBUS_VALID        BIT(9)
+
+/* U3D_SSUSB_OTG_STS_CLR */
+#define SSUSB_VBUS_INTR_CLR     BIT(6)
+
+/* U3D_SSUSB_IP_XHCI_CAP */
+#define SSUSB_IP_XHCI_U2_PORT_NUM(x)    (((x) >> 8) & 0xff)
+#define SSUSB_IP_XHCI_U3_PORT_NUM(x)    ((x) & 0xff)
+
+/* U3D_SSUSB_IP_DEV_CAP */
+#define SSUSB_IP_DEV_U3_PORT_NUM(x) ((x) & 0xff)
+
+/* U3D_SSUSB_OTG_INT_EN */
+#define SSUSB_VBUS_CHG_INT_A_EN     BIT(7)
+#define SSUSB_VBUS_CHG_INT_B_EN     BIT(6)
+
+/* U3D_SSUSB_U3_CTRL_0P */
+#define SSUSB_U3_PORT_SSP_SPEED BIT(9)
+#define SSUSB_U3_PORT_HOST_SEL  BIT(2)
+#define SSUSB_U3_PORT_PDN       BIT(1)
+#define SSUSB_U3_PORT_DIS       BIT(0)
+
+/* U3D_SSUSB_U2_CTRL_0P */
+#define SSUSB_U2_PORT_OTG_SEL   BIT(7)
+#define SSUSB_U2_PORT_HOST_SEL  BIT(2)
+#define SSUSB_U2_PORT_PDN       BIT(1)
+#define SSUSB_U2_PORT_DIS       BIT(0)
+
+/* U3D_SSUSB_DEV_RST_CTRL */
+#define SSUSB_DEV_SW_RST        BIT(0)
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3_qmu.c b/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3_qmu.c
new file mode 100644
index 0000000..8b5e763
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3_qmu.c
@@ -0,0 +1,554 @@
+/*
+ * mtu3_qmu.c - Queue Management Unit driver for device controller
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Queue Management Unit (QMU) is designed to unload SW effort
+ * to serve DMA interrupts.
+ * By preparing General Purpose Descriptor (GPD) and Buffer Descriptor (BD),
+ * SW links data buffers and triggers QMU to send / receive data to
+ * host / from device at a time.
+ * And now only GPD is supported.
+ *
+ * For more detailed information, please refer to QMU Programming Guide
+ */
+
+#include <arch/ops.h>
+#include <debug.h>
+#include <errno.h>
+#include <kernel/vm.h>
+#include <lib/mempool.h>
+#include <platform/reg_utils.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <trace.h>
+
+#include "mtu3.h"
+#include "mtu3_hw_regs.h"
+#include "mtu3_qmu.h"
+
+#define LOCAL_TRACE 0
+
+#define QMU_CHECKSUM_LEN    16
+
+#define GPD_FLAGS_HWO   BIT(0)
+#define GPD_FLAGS_BDP   BIT(1)
+#define GPD_FLAGS_BPS   BIT(2)
+#define GPD_FLAGS_IOC   BIT(7)
+
+#define GPD_EXT_FLAG_ZLP    BIT(5)
+
+#define DBG_C(x...) dprintf(CRITICAL, "[USB][QMU] " x)
+#define DBG_I(x...) LTRACEF("[USB][QMU] " x)
+#define DBG_S(x...) dprintf(SPEW, "[USB][QMU] " x)
+
+#ifdef SUPPORT_QMU
+
+static paddr_t va_to_pa(void *vaddr)
+{
+#if WITH_KERNEL_VM
+    return kvaddr_to_paddr(vaddr);
+#else
+    return (paddr_t)vaddr;
+#endif
+}
+
+static void *pa_to_va(paddr_t paddr)
+{
+#if WITH_KERNEL_VM
+    return paddr_to_kvaddr(paddr);
+#else
+    return (void *)paddr;
+#endif
+}
+
+static struct qmu_gpd *gpd_dma_to_virt(struct mtu3_gpd_ring *ring,
+                                       paddr_t dma_addr)
+{
+    paddr_t dma_base = ring->dma;
+    struct qmu_gpd *gpd_head = ring->start;
+    u32 offset = (dma_addr - dma_base) / sizeof(*gpd_head);
+
+    if (offset >= MAX_GPD_NUM)
+        return NULL;
+
+    return gpd_head + offset;
+}
+
+static paddr_t gpd_virt_to_dma(struct mtu3_gpd_ring *ring,
+                               struct qmu_gpd *gpd)
+{
+    paddr_t dma_base = ring->dma;
+    struct qmu_gpd *gpd_head = ring->start;
+    u32 offset;
+
+    offset = gpd - gpd_head;
+    if (offset >= MAX_GPD_NUM)
+        return 0;
+
+    return dma_base + (offset * sizeof(*gpd));
+}
+
+static void gpd_ring_init(struct mtu3_gpd_ring *ring, struct qmu_gpd *gpd)
+{
+    ring->start = gpd;
+    ring->enqueue = gpd;
+    ring->dequeue = gpd;
+    ring->end = gpd + MAX_GPD_NUM - 1;
+}
+
+static void reset_gpd_list(struct udc_endpoint *mep)
+{
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    struct qmu_gpd *gpd = ring->start;
+
+    if (gpd) {
+        gpd->flag &= ~GPD_FLAGS_HWO;
+        gpd_ring_init(ring, gpd);
+    }
+}
+
+int mtu3_gpd_ring_alloc(struct udc_endpoint *mep)
+{
+    struct qmu_gpd *gpd;
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    u32 size;
+
+    /* software own all gpds as default */
+    size = sizeof(struct qmu_gpd) * MAX_GPD_NUM;
+    gpd = (struct qmu_gpd *)mempool_alloc(size, MEMPOOL_UNCACHE);
+    if (gpd == NULL)
+        return -ENOMEM;
+
+    memset(gpd, 0, size);
+    ring->dma = va_to_pa(gpd);
+    gpd_ring_init(ring, gpd);
+    return 0;
+}
+
+void mtu3_gpd_ring_free(struct udc_endpoint *mep)
+{
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+
+    mempool_free(ring->start);
+    memset(ring, 0, sizeof(*ring));
+}
+
+/*
+ * calculate check sum of a gpd or bd
+ * add "noinline" and "mb" to prevent wrong calculation
+ */
+static u8 qmu_calc_checksum(u8 *data)
+{
+    u8 chksum = 0;
+    int i;
+
+    data[1] = 0x0;  /* set checksum to 0 */
+
+    mb();   /* ensure the gpd/bd is really up-to-date */
+    for (i = 0; i < QMU_CHECKSUM_LEN; i++)
+        chksum += data[i];
+
+    /* Default: HWO=1, @flag[bit0] */
+    chksum += 1;
+
+    return 0xFF - chksum;
+}
+
+void mtu3_qmu_resume(struct udc_endpoint *mep)
+{
+    int epnum = mep->num;
+    paddr_t qcsr;
+
+    qcsr = mep->in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
+
+    writel(QMU_Q_RESUME, qcsr);
+    if (!(readl(qcsr) & QMU_Q_ACTIVE))
+        writel(QMU_Q_RESUME, qcsr);
+}
+
+static struct qmu_gpd *advance_enq_gpd(struct mtu3_gpd_ring *ring)
+{
+    if (ring->enqueue < ring->end)
+        ring->enqueue++;
+    else
+        ring->enqueue = ring->start;
+
+    return ring->enqueue;
+}
+
+static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring)
+{
+    if (ring->dequeue < ring->end)
+        ring->dequeue++;
+    else
+        ring->dequeue = ring->start;
+
+    return ring->dequeue;
+}
+
+/* check if a ring is emtpy */
+static int gpd_ring_empty(struct mtu3_gpd_ring *ring)
+{
+    struct qmu_gpd *enq = ring->enqueue;
+    struct qmu_gpd *next;
+
+    if (ring->enqueue < ring->end)
+        next = enq + 1;
+    else
+        next = ring->start;
+
+    /* one gpd is reserved to simplify gpd preparation */
+    return next == ring->dequeue;
+}
+
+int mtu3_prepare_transfer(struct udc_endpoint *mep)
+{
+    return gpd_ring_empty(&mep->gpd_ring);
+}
+
+static int mtu3_prepare_tx_gpd(struct udc_endpoint *mep, struct mu3d_req *mreq)
+{
+    struct qmu_gpd *enq;
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    struct qmu_gpd *gpd = ring->enqueue;
+    struct udc_request *req = &mreq->req;
+
+    /* set all fields to zero as default value */
+    memset(gpd, 0, sizeof(*gpd));
+
+    gpd->buffer = (u32)va_to_pa(req->buffer);
+    gpd->buf_len = (req->length);
+    gpd->flag |= GPD_FLAGS_IOC;
+
+    /* get the next GPD */
+    enq = advance_enq_gpd(ring);
+    DBG_I("TX %s queue gpd=%p, enq=%p\n", mep->name, gpd, enq);
+
+    enq->flag &= ~GPD_FLAGS_HWO;
+    gpd->next_gpd = (u32)gpd_virt_to_dma(ring, enq);
+
+    if (mep->type != USB_EP_XFER_ISO)
+        gpd->ext_flag |= GPD_EXT_FLAG_ZLP;
+
+    gpd->chksum = qmu_calc_checksum((u8 *)gpd);
+    gpd->flag |= GPD_FLAGS_HWO;
+
+    mreq->gpd = gpd;
+
+    return 0;
+}
+
+static int mtu3_prepare_rx_gpd(struct udc_endpoint *mep, struct mu3d_req *mreq)
+{
+    struct qmu_gpd *enq;
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    struct qmu_gpd *gpd = ring->enqueue;
+    struct udc_request *req = &mreq->req;
+
+    /* set all fields to zero as default value */
+    memset(gpd, 0, sizeof(*gpd));
+
+    gpd->buffer = (u32)va_to_pa(req->buffer);
+    gpd->data_buf_len = req->length;
+    gpd->flag |= GPD_FLAGS_IOC;
+
+    /* get the next GPD */
+    enq = advance_enq_gpd(ring);
+    DBG_I("RX %s queue gpd=%p, enq=%p\n", mep->name, gpd, enq);
+
+    enq->flag &= ~GPD_FLAGS_HWO;
+    gpd->next_gpd = (u32)gpd_virt_to_dma(ring, enq);
+    gpd->chksum = qmu_calc_checksum((u8 *)gpd);
+    gpd->flag |= GPD_FLAGS_HWO;
+
+    mreq->gpd = gpd;
+
+    return 0;
+}
+
+void mtu3_insert_gpd(struct udc_endpoint *mep, struct mu3d_req *mreq)
+{
+    if (mep->in)
+        mtu3_prepare_tx_gpd(mep, mreq);
+    else
+        mtu3_prepare_rx_gpd(mep, mreq);
+}
+
+int mtu3_qmu_start(struct udc_endpoint *mep)
+{
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    u8 epnum = mep->num;
+
+    if (mep->in) {
+        /* set QMU start address */
+        writel(ring->dma, USB_QMU_TQSAR(mep->num));
+        setbits32_r(TX_DMAREQEN, MU3D_EP_TXCR0(mep->num));
+        setbits32_r(QMU_TX_CS_EN(epnum), U3D_QCR0);
+        /* send zero length packet according to ZLP flag in GPD */
+        setbits32_r(QMU_TX_ZLP(epnum), U3D_QCR1);
+        writel(QMU_TX_LEN_ERR(epnum) | QMU_TX_CS_ERR(epnum), U3D_TQERRIESR0);
+
+        if (readl(USB_QMU_TQCSR(epnum)) & QMU_Q_ACTIVE) {
+            DBG_C("%s Active Now!\n", mep->name);
+            return 0;
+        }
+        writel(QMU_Q_START, USB_QMU_TQCSR(epnum));
+
+    } else {
+        writel(ring->dma, USB_QMU_RQSAR(mep->num));
+        setbits32_r(RX_DMAREQEN, MU3D_EP_RXCR0(mep->num));
+        setbits32_r(QMU_RX_CS_EN(epnum), U3D_QCR0);
+        /* don't expect ZLP */
+        clrbits32_r(QMU_RX_ZLP(epnum), U3D_QCR3);
+        /* move to next GPD when receive ZLP */
+        setbits32_r(QMU_RX_COZ(epnum), U3D_QCR3);
+        writel(QMU_RX_LEN_ERR(epnum) | QMU_RX_CS_ERR(epnum), U3D_RQERRIESR0);
+        writel(QMU_RX_ZLP_ERR(epnum), U3D_RQERRIESR1);
+
+        if (readl(USB_QMU_RQCSR(epnum)) & QMU_Q_ACTIVE) {
+            DBG_C("%s Active Now!\n", mep->name);
+            return 0;
+        }
+        writel(QMU_Q_START, USB_QMU_RQCSR(epnum));
+    }
+    DBG_I("%s's qmu start now!\n", mep->name);
+
+    return 0;
+}
+
+/* may called in atomic context */
+static void mtu3_qmu_stop(struct udc_endpoint *mep)
+{
+    int epnum = mep->num;
+    paddr_t qcsr;
+    int ret;
+
+    qcsr = mep->in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
+
+    if (!(readl(qcsr) & QMU_Q_ACTIVE)) {
+        DBG_C("%s's qmu is inactive now!\n", mep->name);
+        return;
+    }
+    writel(QMU_Q_STOP, qcsr);
+
+    ret = wait_for_value(qcsr, QMU_Q_ACTIVE, 0, 10, 100);
+    if (ret) {
+        DBG_C("stop %s's qmu failed\n", mep->name);
+        return;
+    }
+
+    DBG_I("%s's qmu stop now!\n", mep->name);
+}
+
+void mtu3_qmu_flush(struct udc_endpoint *mep)
+{
+    DBG_I("%s flush QMU %s\n", __func__, mep->name);
+
+    /*Stop QMU */
+    mtu3_qmu_stop(mep);
+    reset_gpd_list(mep);
+}
+
+static void qmu_done_tx(u8 epnum)
+{
+    struct udc_endpoint *mep = mtu3_find_ep(epnum, USB_DIR_IN);
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    struct qmu_gpd *gpd = ring->dequeue;
+    struct qmu_gpd *gpd_current = NULL;
+    struct udc_request *request = NULL;
+    struct mu3d_req *mreq;
+    paddr_t gpd_dma;
+
+    gpd_dma = readl(USB_QMU_TQCPR(epnum));
+    /*transfer phy address got from QMU register to virtual address */
+    gpd_current = gpd_dma_to_virt(ring, gpd_dma);
+
+    DBG_I("%s %s, last=%p, current=%p, enq=%p\n",
+          __func__, mep->name, gpd, gpd_current, ring->enqueue);
+
+    while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+
+        request = mep->req;
+        mreq = to_mu3d_req(request);
+        if (mreq == NULL || mreq->gpd != gpd) {
+            DBG_C("no correct TX req is found\n");
+            break;
+        }
+
+        mreq->actual = gpd->buf_len;
+        handle_ept_complete(mep, 0);
+        gpd = advance_deq_gpd(ring);
+    }
+
+    DBG_I("%s EP%dIN, deq=%p, enq=%p, complete\n",
+          __func__, epnum, ring->dequeue, ring->enqueue);
+}
+
+static void qmu_done_rx(u8 epnum)
+{
+    struct udc_endpoint *mep = mtu3_find_ep(epnum, USB_DIR_OUT);
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    struct qmu_gpd *gpd = ring->dequeue;
+    struct qmu_gpd *gpd_current = NULL;
+    struct udc_request *request = NULL;
+    struct mu3d_req *mreq;
+    paddr_t gpd_dma;
+
+    gpd_dma = readl(USB_QMU_RQCPR(epnum));
+    gpd_current = gpd_dma_to_virt(ring, gpd_dma);
+
+    DBG_I("%s %s, last=%p, current=%p, enq=%p\n",
+          __func__, mep->name, gpd, gpd_current, ring->enqueue);
+
+    while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+
+        request = mep->req;
+        mreq = to_mu3d_req(request);
+        if (mreq == NULL || mreq->gpd != gpd) {
+            DBG_C("no correct RX req is found\n");
+            break;
+        }
+        mreq->actual = gpd->buf_len;
+        handle_ept_complete(mep, 0);
+        gpd = advance_deq_gpd(ring);
+    }
+
+    DBG_I("%s EP%dOUT, deq=%p, enq=%p, complete\n",
+          __func__, epnum, ring->dequeue, ring->enqueue);
+}
+
+static void qmu_done_isr(u32 done_status)
+{
+    int i;
+
+    for (i = 1; i <= (MT_EP_NUM / 2); i++) {
+        if (done_status & QMU_RX_DONE_INT(i))
+            qmu_done_rx(i);
+        if (done_status & QMU_TX_DONE_INT(i))
+            qmu_done_tx(i);
+    }
+}
+
+static void qmu_exception_isr(u32 qmu_status)
+{
+    u32 errval;
+    int i;
+
+    if ((qmu_status & RXQ_CSERR_INT) || (qmu_status & RXQ_LENERR_INT)) {
+        errval = readl(U3D_RQERRIR0);
+        for (i = 1; i <= (MT_EP_NUM / 2); i++) {
+            if (errval & QMU_RX_CS_ERR(i))
+                DBG_C("Rx EP%d CS error!\n", i);
+
+            if (errval & QMU_RX_LEN_ERR(i))
+                DBG_C("RX EP%d Length error\n", i);
+        }
+        writel(errval, U3D_RQERRIR0);
+    }
+
+    if (qmu_status & RXQ_ZLPERR_INT) {
+        errval = readl(U3D_RQERRIR1);
+        for (i = 1; i <= (MT_EP_NUM / 2); i++) {
+            if (errval & QMU_RX_ZLP_ERR(i))
+                DBG_I("RX EP%d Recv ZLP\n", i);
+        }
+        writel(errval, U3D_RQERRIR1);
+    }
+
+    if ((qmu_status & TXQ_CSERR_INT) || (qmu_status & TXQ_LENERR_INT)) {
+        errval = readl(U3D_TQERRIR0);
+        for (i = 1; i <= (MT_EP_NUM / 2); i++) {
+            if (errval & QMU_TX_CS_ERR(i))
+                DBG_C("Tx EP%d checksum error!\n", i);
+
+            if (errval & QMU_TX_LEN_ERR(i))
+                DBG_I("Tx EP%d send ZLP failed\n", i);
+        }
+        writel(errval, U3D_TQERRIR0);
+    }
+}
+
+enum handler_return mtu3_qmu_isr(void)
+{
+    u32 qmu_status;
+    u32 qmu_done_status;
+
+    /* U3D_QISAR1 is read update */
+    qmu_status = readl(U3D_QISAR1);
+    qmu_status &= readl(U3D_QIER1);
+
+    qmu_done_status = readl(U3D_QISAR0);
+    qmu_done_status &= readl(U3D_QIER0);
+    writel(qmu_done_status, U3D_QISAR0); /* W1C */
+    DBG_I("[INTR] QMUdone[TX=%x, RX=%x] QMUexp[%x]\n",
+          (qmu_done_status & 0xFFFF), qmu_done_status >> 16,
+          qmu_status);
+
+    if (qmu_done_status)
+        qmu_done_isr(qmu_done_status);
+
+    if (qmu_status)
+        qmu_exception_isr(qmu_status);
+
+    return INT_RESCHEDULE;
+}
+
+int mtu3_qmu_init(void)
+{
+    if (QMU_GPD_SIZE != 16) {
+        DBG_C("QMU_GPD size SHOULD be 16 Bytes");
+        return -EFAULT;
+    }
+    return 0;
+}
+
+#else   /* PIO mode */
+
+void mtu3_qmu_flush(struct udc_endpoint *mep)
+{}
+
+int mtu3_gpd_ring_alloc(struct udc_endpoint *mep)
+{
+    return 0;
+}
+
+void mtu3_gpd_ring_free(struct udc_endpoint *mep)
+{}
+
+enum handler_return mtu3_qmu_isr(void)
+{
+    return INT_NO_RESCHEDULE;
+}
+
+int mtu3_qmu_init(void)
+{
+    return 0;
+}
+
+#endif  /* SUPPORT_QMU */
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3_qmu.h b/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3_qmu.h
new file mode 100644
index 0000000..9dfaa89
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/usb/mtu3_qmu.h
@@ -0,0 +1,113 @@
+/*
+ * mtu3_qmu.h - Queue Management Unit driver header
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * 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 "mtu3.h"
+
+struct qmu_gpd;
+
+#define MAX_GPD_NUM         4
+#define QMU_GPD_SIZE        (sizeof(struct qmu_gpd))
+#define QMU_GPD_RING_SIZE   ((MAX_GPD_NUM) * (QMU_GPD_SIZE))
+
+#define GPD_BUF_SIZE        65532
+
+#define MU3D_EP_TXCR0(epnum)    (U3D_TX1CSR0 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_TXCR1(epnum)    (U3D_TX1CSR1 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_TXCR2(epnum)    (U3D_TX1CSR2 + (((epnum) - 1) * 0x10))
+
+#define MU3D_EP_RXCR0(epnum)    (U3D_RX1CSR0 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_RXCR1(epnum)    (U3D_RX1CSR1 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_RXCR2(epnum)    (U3D_RX1CSR2 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_RXCR3(epnum)    (U3D_RX1CSR3 + (((epnum) - 1) * 0x10))
+
+#define USB_QMU_RQCSR(epnum)    (U3D_RXQCSR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_RQSAR(epnum)    (U3D_RXQSAR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_RQCPR(epnum)    (U3D_RXQCPR1 + (((epnum) - 1) * 0x10))
+
+#define USB_QMU_TQCSR(epnum)    (U3D_TXQCSR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_TQSAR(epnum)    (U3D_TXQSAR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_TQCPR(epnum)    (U3D_TXQCPR1 + (((epnum) - 1) * 0x10))
+
+
+/* U3D_QCR0 */
+#define QMU_RX_CS_EN(x)     (BIT(16) << (x))
+#define QMU_TX_CS_EN(x)     (BIT(0) << (x))
+#define QMU_CS16B_EN        BIT(0)
+
+/* U3D_QCR1 */
+#define QMU_TX_ZLP(x)       (BIT(0) << (x))
+
+/* U3D_QCR3 */
+#define QMU_RX_COZ(x)       (BIT(16) << (x))
+#define QMU_RX_ZLP(x)       (BIT(0) << (x))
+
+/* U3D_TXQCSR1 */
+/* U3D_RXQCSR1 */
+#define QMU_Q_ACTIVE    BIT(15)
+#define QMU_Q_STOP      BIT(2)
+#define QMU_Q_RESUME    BIT(1)
+#define QMU_Q_START     BIT(0)
+
+/* U3D_QISAR0, U3D_QIER0, U3D_QIESR0, U3D_QIECR0 */
+#define QMU_RX_DONE_INT(x)  (BIT(16) << (x))
+#define QMU_TX_DONE_INT(x)  (BIT(0) << (x))
+
+
+struct qmu_gpd {
+    u8 flag;
+    u8 chksum;
+    u16 data_buf_len;
+    u32 next_gpd;
+    u32 buffer;
+    u16 buf_len;
+    u8 ext_len;
+    u8 ext_flag;
+} __attribute__((packed));
+
+struct mtu3_gpd_ring {
+    paddr_t dma;
+    struct qmu_gpd *start;
+    struct qmu_gpd *end;
+    struct qmu_gpd *enqueue;
+    struct qmu_gpd *dequeue;
+};
+
+int mtu3_qmu_start(struct udc_endpoint *mep);
+void mtu3_qmu_resume(struct udc_endpoint *mep);
+void mtu3_qmu_flush(struct udc_endpoint *mep);
+
+void mtu3_insert_gpd(struct udc_endpoint *mep, struct mu3d_req *mreq);
+int mtu3_prepare_transfer(struct udc_endpoint *mep);
+
+int mtu3_gpd_ring_alloc(struct udc_endpoint *mep);
+void mtu3_gpd_ring_free(struct udc_endpoint *mep);
+
+enum handler_return mtu3_qmu_isr(void);
+int mtu3_qmu_init(void);
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/usb/u3phy-i2c.c b/src/bsp/lk/platform/mediatek/common/drivers/usb/u3phy-i2c.c
new file mode 100644
index 0000000..4f0378a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/usb/u3phy-i2c.c
@@ -0,0 +1,352 @@
+#include <debug.h>
+#include <reg.h>
+
+#define PHY_TRUE 1
+#define PHY_FALSE 0
+
+#define SDA 0
+#define SCL 1
+
+#define INPUT 0
+#define OUTPUT 1
+
+#define SSUSB_FPGA_I2C_OUT_OFFSET 0
+#define SSUSB_FPGA_I2C_IN_OFFSET  0x04
+
+#define SSUSB_FPGA_I2C_SDA_OUT (1<<0)
+#define SSUSB_FPGA_I2C_SDA_OEN (1<<1)
+#define SSUSB_FPGA_I2C_SCL_OUT (1<<2)
+#define SSUSB_FPGA_I2C_SCL_OEN (1<<3)
+
+#define SSUSB_FPGA_I2C_SDA_IN_OFFSET 0
+#define SSUSB_FPGA_I2C_SCL_IN_OFFSET 1
+
+#define I2C_DELAY 10
+
+typedef unsigned char u8;
+typedef unsigned int u32;
+
+static void i2c_dummy_delay(volatile unsigned int count)
+{
+    do {
+        count--;
+    } while (count>0);
+}
+
+void gpio_set_direction(void *i2c_port_base, unsigned char gpio_dir, unsigned char gpio_pin)
+{
+    unsigned int temp;
+    void *addr;
+
+    addr = i2c_port_base + SSUSB_FPGA_I2C_OUT_OFFSET;
+
+    temp = readl(addr);
+
+    if (gpio_pin == SDA) {
+        if (gpio_dir==OUTPUT) {
+            temp |= SSUSB_FPGA_I2C_SDA_OEN;
+            writel(temp, addr);
+        } else {
+            temp &= ~SSUSB_FPGA_I2C_SDA_OEN;
+            writel(temp, addr);
+        }
+    } else {
+        if (gpio_dir==OUTPUT) {
+            temp |= SSUSB_FPGA_I2C_SCL_OEN;
+            writel(temp, addr);
+        } else {
+            temp &= ~SSUSB_FPGA_I2C_SCL_OEN;
+            writel(temp, addr);
+        }
+    }
+}
+
+void gpio_set_value(void *i2c_port_base, unsigned char value, unsigned char gpio_pin)
+{
+    unsigned int temp;
+    void *addr;
+
+    addr = i2c_port_base + SSUSB_FPGA_I2C_OUT_OFFSET;
+
+    temp = readl(addr);
+
+    if (gpio_pin == SDA) {
+        if (value == 1) {
+            temp |= SSUSB_FPGA_I2C_SDA_OUT;
+            writel(temp, addr);
+        } else {
+            temp &= ~SSUSB_FPGA_I2C_SDA_OUT;
+            writel(temp, addr);
+        }
+    } else {
+        if (value == 1) {
+            temp |= SSUSB_FPGA_I2C_SCL_OUT;
+            writel(temp, addr);
+        } else {
+            temp &= ~SSUSB_FPGA_I2C_SCL_OUT;
+            writel(temp, addr);
+        }
+    }
+}
+
+unsigned char gpio_get_value(void *i2c_port_base, unsigned char gpio_pin)
+{
+    unsigned char temp;
+    void *addr;
+
+    addr = i2c_port_base + SSUSB_FPGA_I2C_IN_OFFSET;
+
+    temp = readl(addr);
+
+    if (gpio_pin == SDA)
+        temp = (temp >> SSUSB_FPGA_I2C_SDA_IN_OFFSET) & 0x01;
+    else
+        temp = (temp >> SSUSB_FPGA_I2C_SCL_IN_OFFSET) & 0x01;
+
+    return temp;
+}
+
+void i2c_stop(void *i2c_port_base)
+{
+    gpio_set_direction(i2c_port_base, OUTPUT, SDA);
+    gpio_set_value(i2c_port_base, 0, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 0, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 1, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 1, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_direction(i2c_port_base, INPUT, SCL);
+    gpio_set_direction(i2c_port_base, INPUT, SDA);
+}
+
+void i2c_start(void *i2c_port_base) /* Prepare the SDA and SCL for sending/receiving */
+{
+    gpio_set_direction(i2c_port_base, OUTPUT, SCL);
+    gpio_set_direction(i2c_port_base, OUTPUT, SDA);
+    gpio_set_value(i2c_port_base, 1, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 1, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 0, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 0, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+}
+
+u32 i2c_send_byte(void *i2c_port_base, u8 data) /* return 0 --> ack */
+{
+    int i, ack;
+
+    gpio_set_direction(i2c_port_base, OUTPUT, SDA);
+
+    for (i=8; --i>0;) {
+        gpio_set_value(i2c_port_base, (data>>i)&0x01, SDA);
+        i2c_dummy_delay(I2C_DELAY);
+        gpio_set_value(i2c_port_base,  1, SCL); /* high */
+        i2c_dummy_delay(I2C_DELAY);
+        gpio_set_value(i2c_port_base,  0, SCL); /* low */
+        i2c_dummy_delay(I2C_DELAY);
+    }
+    gpio_set_value(i2c_port_base, (data>>i)&0x01, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base,  1, SCL); /* high */
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base,  0, SCL); /* low */
+    i2c_dummy_delay(I2C_DELAY);
+
+    gpio_set_value(i2c_port_base, 0, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_direction(i2c_port_base, INPUT, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 1, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    ack = gpio_get_value(i2c_port_base,SDA); /* ack 1: error , 0:ok */
+    gpio_set_value(i2c_port_base, 0, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+
+    if (ack==1)
+        return PHY_FALSE;
+    else
+        return PHY_TRUE;
+}
+
+void i2c_receive_byte(void *i2c_port_base, u8 *data, u8 ack)
+{
+    int i;
+    u32 dataCache;
+
+    dataCache = 0;
+    gpio_set_direction(i2c_port_base, INPUT, SDA);
+
+    for (i=8; --i>=0;) {
+        dataCache <<= 1;
+        i2c_dummy_delay(I2C_DELAY);
+        gpio_set_value(i2c_port_base, 1, SCL);
+        i2c_dummy_delay(I2C_DELAY);
+        dataCache |= gpio_get_value(i2c_port_base,SDA);
+        gpio_set_value(i2c_port_base, 0, SCL);
+        i2c_dummy_delay(I2C_DELAY);
+    }
+
+    gpio_set_direction(i2c_port_base, OUTPUT, SDA);
+    gpio_set_value(i2c_port_base, ack, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 1, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 0, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    *data = (u8)dataCache;
+}
+
+
+int i2c_write_reg(void *i2c_port_base, u8 dev_id, u8 addr, u8 data)
+{
+    int acknowledge=0;
+
+    i2c_start(i2c_port_base);
+
+    acknowledge=i2c_send_byte(i2c_port_base,(dev_id<<1) & 0xff);
+    if (acknowledge)
+        acknowledge=i2c_send_byte(i2c_port_base,addr);
+    else
+        return PHY_FALSE;
+
+    acknowledge=i2c_send_byte(i2c_port_base,data);
+    if (acknowledge) {
+        i2c_stop(i2c_port_base);
+        return PHY_TRUE;
+    } else {
+        return PHY_FALSE;
+    }
+}
+
+int i2c_read_reg(void *i2c_port_base, u8 dev_id, u8 addr, u8 *data)
+{
+    int acknowledge=0;
+
+    i2c_start(i2c_port_base);
+
+    acknowledge=i2c_send_byte(i2c_port_base,(dev_id<<1) & 0xff);
+    if (acknowledge)
+        acknowledge=i2c_send_byte(i2c_port_base,addr);
+    else
+        return PHY_FALSE;
+
+    i2c_start(i2c_port_base);
+
+    acknowledge=i2c_send_byte(i2c_port_base,((dev_id<<1) & 0xff) | 0x01);
+    if (acknowledge)
+        i2c_receive_byte(i2c_port_base,data, 1);  /* ack 0: ok , 1 error */
+    else
+        return PHY_FALSE;
+
+    i2c_stop(i2c_port_base);
+
+    return acknowledge;
+}
+
+int u3phy_write_reg(void *i2c_port_base, u8 dev_id, u8 address, int value)
+{
+    int ret;
+
+    ret = i2c_write_reg(i2c_port_base, dev_id, address, value);
+    if (ret == PHY_FALSE) {
+        dprintf(ALWAYS, "Write failed(dev_id: %x, addr: 0x%x, val: 0x%x)\n", dev_id, address, value);
+        return PHY_FALSE;
+    }
+
+    return PHY_TRUE;
+}
+
+unsigned char u3phy_read_reg(void *i2c_port_base, u8 dev_id,  u8 address)
+{
+    u8 buf;
+    int ret;
+
+    /* buf = (char *)kmalloc(1, GFP_NOIO); */
+    ret = i2c_read_reg(i2c_port_base, dev_id, address, &buf);
+    if (ret == PHY_FALSE) {
+        dprintf(ALWAYS, "Read failed(dev_id: %x, addr: 0x%x)\n", dev_id, address);
+        return PHY_FALSE;
+    }
+    ret = buf;
+
+    return ret;
+
+}
+
+int u3phy_write_reg32(void *i2c_port_base, u8 dev_id, u32 addr, u32 data)
+{
+    u8 addr8;
+    u8 data_0, data_1, data_2, data_3;
+
+    addr8 = addr & 0xff;
+    data_0 = data & 0xff;
+    data_1 = (data>>8) & 0xff;
+    data_2 = (data>>16) & 0xff;
+    data_3 = (data>>24) & 0xff;
+
+    u3phy_write_reg(i2c_port_base, dev_id, addr8, data_0);
+    u3phy_write_reg(i2c_port_base, dev_id, addr8+1, data_1);
+    u3phy_write_reg(i2c_port_base, dev_id, addr8+2, data_2);
+    u3phy_write_reg(i2c_port_base, dev_id, addr8+3, data_3);
+
+    return 0;
+}
+
+unsigned int u3phy_read_reg32(void *i2c_port_base, u8 dev_id, u32 addr)
+{
+    u8 addr8;
+    u32 data;
+
+    addr8 = addr & 0xff;
+
+    data = u3phy_read_reg(i2c_port_base, dev_id, addr8);
+    data |= (u3phy_read_reg(i2c_port_base, dev_id, addr8+1) << 8);
+    data |= (u3phy_read_reg(i2c_port_base, dev_id, addr8+2) << 16);
+    data |= (u3phy_read_reg(i2c_port_base, dev_id, addr8+3) << 24);
+
+    return data;
+}
+
+
+int u3phy_write_reg8(void *i2c_port_base, u8 dev_id, u32 addr, u8 data)
+{
+    u8 addr8;
+
+    addr8 = addr & 0xff;
+    u3phy_write_reg(i2c_port_base, dev_id, addr8, data);
+
+    return PHY_TRUE;
+}
+
+unsigned char u3phy_read_reg8(void *i2c_port_base, u8 dev_id, u32 addr)
+{
+    u8 addr8;
+    u32 data;
+
+    addr8 = addr & 0xff;
+    data = u3phy_read_reg(i2c_port_base, dev_id, addr8);
+
+    return data;
+}
+
+
+unsigned int u3phy_readlmsk(void *i2c_port_base, unsigned char i2c_addr, unsigned int reg_addr32, unsigned int offset, unsigned int mask)
+{
+    return  ((u3phy_read_reg32(i2c_port_base, i2c_addr, reg_addr32) & mask) >> offset);
+}
+
+int u3phy_writelmsk(void *i2c_port_base, unsigned char i2c_addr, unsigned int reg_addr32, unsigned int offset, unsigned int mask, unsigned int data)
+{
+    unsigned int cur_value;
+    unsigned int new_value;
+
+    cur_value = u3phy_read_reg32(i2c_port_base, i2c_addr, reg_addr32);
+    new_value = (cur_value & (~mask)) | ((data << offset) & mask);
+    u3phy_write_reg32(i2c_port_base, i2c_addr, reg_addr32, new_value);
+
+    return 0;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/usb/u3phy-i2c.h b/src/bsp/lk/platform/mediatek/common/drivers/usb/u3phy-i2c.h
new file mode 100644
index 0000000..fc347e3
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/usb/u3phy-i2c.h
@@ -0,0 +1,9 @@
+int u3phy_write_reg(void *i2c_port_base, unsigned char dev_id, unsigned char address, int value);

+unsigned char u3phy_read_reg(void *i2c_port_base, unsigned char dev_id,  unsigned char address);

+int u3phy_write_reg32(void *i2c_port_base, unsigned char dev_id, unsigned int addr, unsigned int data);

+unsigned int u3phy_read_reg32(void *i2c_port_base, unsigned char dev_id, unsigned int addr);

+unsigned int u3phy_read_reg32(void *i2c_port_base, unsigned char dev_id, unsigned int addr);

+int u3phy_write_reg8(void *i2c_port_base, unsigned char dev_id, unsigned int addr, unsigned char data);

+unsigned char u3phy_read_reg8(void *i2c_port_base, unsigned char dev_id, unsigned int addr);

+unsigned int u3phy_readlmsk(void *i2c_port_base, unsigned char i2c_addr, unsigned int reg_addr32, unsigned int offset, unsigned int mask);

+int u3phy_writelmsk(void *i2c_port_base, unsigned char i2c_addr, unsigned int reg_addr32, unsigned int offset, unsigned int mask, unsigned int data);
\ No newline at end of file
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/usb/usbphy.c b/src/bsp/lk/platform/mediatek/common/drivers/usb/usbphy.c
new file mode 100644
index 0000000..04d9b81
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/usb/usbphy.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in
+ *  the documentation and/or other materials provided with the
+ *  distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <platform/mt_reg_base.h>
+#include <platform/reg_utils.h>
+
+#include "usbphy.h"
+
+#ifdef DBG_USB_PHY
+#define PHY_LOG(x...) dprintf(INFO, "[USB][PHY] " x)
+#else
+#define PHY_LOG(x...) do{} while(0)
+#endif
+
+/* 2712E1 can't set RG_AVALID */
+#define U3D_U2PHYDEV_MASK   (E60802_RG_IDDIG | /*E60802_RG_AVALID |*/ \
+    E60802_RG_BVALID | E60802_RG_VBUSVALID)
+
+#define U3D_U2PHYFRCDEV_MASK (E60802_FORCE_IDDIG | /*E60802_FORCE_AVALID |*/ \
+    E60802_FORCE_BVALID | E60802_FORCE_SESSEND | E60802_FORCE_VBUSVALID)
+
+void mt_usb_phy_poweron(void)
+{
+    PHY_LOG("%s\n", __func__);
+
+    /* switch to USB function */
+    clrbits32_r(E60802_FORCE_UART_EN, U3D_U2PHYDTM0);
+    clrbits32_r(E60802_RG_UART_EN, U3D_U2PHYDTM1);
+    clrbits32_r(E60802_RG_USB20_GPIO_CTL, U3D_U2PHYACR4);
+    clrbits32_r(E60802_USB20_GPIO_MODE, U3D_U2PHYACR4);
+    /* DP/DM BC1.1 path Disable */
+    clrbits32_r(E60802_RG_USB20_BC11_SW_EN, U3D_USBPHYACR6);
+    /* Internal R bias enable */
+    setbits32_r(E60802_RG_USB20_INTR_EN, U3D_USBPHYACR0);
+    /* 100U from u2 */
+    clrbits32_r(E60802_RG_USB20_HS_100U_U3_EN, U3D_USBPHYACR5);
+    /* let suspendm=1, enable usb 480MHz pll */
+    setbits32_r(E60802_RG_SUSPENDM, U3D_U2PHYDTM0);
+    /* force_suspendm=1 */
+    setbits32_r(E60802_FORCE_SUSPENDM, U3D_U2PHYDTM0);
+    /* wait 2 ms for USBPLL stable */
+    spin(2000);
+    /* power on device mode */
+    clrbits32_r(E60802_RG_SESSEND, U3D_U2PHYDTM1);
+    /* NOTE: mt2712E1 can't set RG_AVALID */
+    setbits32_r(U3D_U2PHYDEV_MASK, U3D_U2PHYDTM1);
+    /* enable force into device mode */
+    setbits32_r(U3D_U2PHYFRCDEV_MASK, U3D_U2PHYDTM1);
+    /* wait mac ready */
+    spin(2000);
+    /* apply MAC clock related setting after phy init */
+}
+
+void mt_usb_phy_poweroff(void)
+{
+    /* power down device mode */
+    clrbits32_r(E60802_RG_VBUSVALID | E60802_RG_BVALID | E60802_RG_AVALID, U3D_U2PHYDTM1);
+    setbits32_r(E60802_RG_IDDIG | E60802_RG_SESSEND, U3D_U2PHYDTM1);
+
+    /* cleaer device force mode */
+    clrbits32_r(U3D_U2PHYFRCDEV_MASK, U3D_U2PHYDTM1);
+
+    clrbits32_r(E60802_RG_SUSPENDM, U3D_U2PHYDTM0);
+    setbits32_r(E60802_FORCE_SUSPENDM, U3D_U2PHYDTM0);
+    spin(2000);
+    PHY_LOG("%s\n", __func__);
+}
diff --git a/src/bsp/lk/platform/mediatek/common/drivers/usb/usbphy.h b/src/bsp/lk/platform/mediatek/common/drivers/usb/usbphy.h
new file mode 100644
index 0000000..aded24e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/drivers/usb/usbphy.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright(c) 2013 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
+
+/* APB Module ssusb_top_sif - USB3_SIF2_BASE */
+#define SSUSB_SIFSLV_U2PHY_COM_BASE     (USB3_SIF2_BASE + 0x300)
+#define SSUSB_SIFSLV_SPLLC_BASE         (USB3_SIF2_BASE + 0x700)
+#define SSUSB_SIFSLV_U3PHYD_BASE        (USB3_SIF2_BASE + 0x900)
+#define SSUSB_SIFSLV_U3PHYA_BASE        (USB3_SIF2_BASE + 0xB00)
+#define SSUSB_SIFSLV_U3PHYA_DA_BASE     (USB3_SIF2_BASE + 0xC00)
+
+/* referenecd from ssusb_USB20_PHY_regmap_com_T28.xls */
+#define U3D_USBPHYACR0              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0000) /* bit 2~bit 30 */
+#define U3D_USBPHYACR1              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0004)
+#define U3D_USBPHYACR2              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0008) /* bit 0~ bit15 */
+#define U3D_USBPHYACR4              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0010)
+#define U3D_USBPHYACR5              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0014)
+#define U3D_USBPHYACR6              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0018)
+#define U3D_U2PHYACR3               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x001c)
+#define U3D_U2PHYACR4               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0020) /* bit8~ bit18 */
+#define U3D_U2PHYAMON0              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0024)
+#define U3D_U2PHYDCR0               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0060)
+#define U3D_U2PHYDCR1               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0064)
+#define U3D_U2PHYDTM0               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0068)
+#define U3D_U2PHYDTM1               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x006C)
+#define U3D_U2PHYDMON0              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0070)
+#define U3D_U2PHYDMON1              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0074)
+#define U3D_U2PHYDMON2              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0078)
+#define U3D_U2PHYDMON3              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x007C)
+#define U3D_U2PHYBC12C              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0080)
+#define U3D_U2PHYBC12C1             (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0084)
+#define U3D_U2PHYREGFPPC            (SSUSB_SIFSLV_U2PHY_COM_BASE+0x00e0)
+#define U3D_U2PHYVERSIONC           (SSUSB_SIFSLV_U2PHY_COM_BASE+0x00f0)
+#define U3D_U2PHYREGFCOM            (SSUSB_SIFSLV_U2PHY_COM_BASE+0x00fc)
+
+/* U3D_USBPHYACR0 */
+#define E60802_RG_USB20_MPX_OUT_SEL               (0x7<<28) /* 30:28 */
+#define E60802_RG_USB20_TX_PH_ROT_SEL             (0x7<<24) /* 26:24 */
+#define E60802_RG_USB20_PLL_DIVEN                 (0x7<<20) /* 22:20 */
+#define E60802_RG_USB20_PLL_BR                    (0x1<<18) /* 18:18 */
+#define E60802_RG_USB20_PLL_BP                    (0x1<<17) /* 17:17 */
+#define E60802_RG_USB20_PLL_BLP                   (0x1<<16) /* 16:16 */
+#define E60802_RG_USB20_USBPLL_FORCE_ON           (0x1<<15) /* 15:15 */
+#define E60802_RG_USB20_PLL_FBDIV                 (0x7f<<8) /* 14:8 */
+#define E60802_RG_USB20_PLL_PREDIV                (0x3<<6) /* 7:6 */
+#define E60802_RG_USB20_INTR_EN                   (0x1<<5) /* 5:5 */
+#define E60802_RG_USB20_REF_EN                    (0x1<<4) /* 4:4 */
+#define E60802_RG_USB20_BGR_DIV                   (0x3<<2) /* 3:2 */
+#define E60802_RG_SIFSLV_CHP_EN                   (0x1<<1) /* 1:1 */
+#define E60802_RG_SIFSLV_BGR_EN                   (0x1<<0) /* 0:0 */
+
+/* U3D_USBPHYACR1 */
+#define E60802_RG_USB20_INTR_CAL                  (0x1f<<19) /* 23:19 */
+#define E60802_RG_USB20_OTG_VBUSTH                (0x7<<16) /* 18:16 */
+#define E60802_RG_USB20_VRT_VREF_SEL              (0x7<<12) /* 14:12 */
+#define E60802_RG_USB20_TERM_VREF_SEL             (0x7<<8) /* 10:8 */
+#define E60802_RG_USB20_MPX_SEL                   (0xff<<0) /* 7:0 */
+
+/* U3D_USBPHYACR2 */
+#define E60802_RG_SIFSLV_MAC_BANDGAP_EN           (0x1<<17) /* 17:17 */
+#define E60802_RG_SIFSLV_MAC_CHOPPER_EN           (0x1<<16) /* 16:16 */
+#define E60802_RG_USB20_CLKREF_REV                (0xffff<<0) /* 15:0 */
+
+/* U3D_USBPHYACR4 */
+#define E60802_RG_USB20_DP_ABIST_SOURCE_EN        (0x1<<31) /* 31:31 */
+#define E60802_RG_USB20_DP_ABIST_SELE             (0xf<<24) /* 27:24 */
+#define E60802_RG_USB20_ICUSB_EN                  (0x1<<16) /* 16:16 */
+#define E60802_RG_USB20_LS_CR                     (0x7<<12) /* 14:12 */
+#define E60802_RG_USB20_FS_CR                     (0x7<<8) /* 10:8 */
+#define E60802_RG_USB20_LS_SR                     (0x7<<4) /* 6:4 */
+#define E60802_RG_USB20_FS_SR                     (0x7<<0) /* 2:0 */
+
+/* U3D_USBPHYACR5 */
+#define E60802_RG_USB20_DISC_FIT_EN               (0x1<<28) /* 28:28 */
+#define E60802_RG_USB20_INIT_SQ_EN_DG             (0x3<<26) /* 27:26 */
+#define E60802_RG_USB20_HSTX_TMODE_SEL            (0x3<<24) /* 25:24 */
+#define E60802_RG_USB20_SQD                       (0x3<<22) /* 23:22 */
+#define E60802_RG_USB20_DISCD                     (0x3<<20) /* 21:20 */
+#define E60802_RG_USB20_HSTX_TMODE_EN             (0x1<<19) /* 19:19 */
+#define E60802_RG_USB20_PHYD_MONEN                (0x1<<18) /* 18:18 */
+#define E60802_RG_USB20_INLPBK_EN                 (0x1<<17) /* 17:17 */
+#define E60802_RG_USB20_CHIRP_EN                  (0x1<<16) /* 16:16 */
+#define E60802_RG_USB20_HSTX_SRCAL_EN             (0x1<<15) /* 15:15 */
+#define E60802_RG_USB20_HSTX_SRCTRL               (0x7<<12) /* 14:12 */
+#define E60802_RG_USB20_HS_100U_U3_EN             (0x1<<11) /* 11:11 */
+#define E60802_RG_USB20_GBIAS_ENB                 (0x1<<10) /* 10:10 */
+#define E60802_RG_USB20_DM_ABIST_SOURCE_EN        (0x1<<7) /* 7:7 */
+#define E60802_RG_USB20_DM_ABIST_SELE             (0xf<<0) /* 3:0 */
+
+/* U3D_USBPHYACR6 */
+#define E60802_RG_USB20_ISO_EN                    (0x1<<31) /* 31:31 */
+#define E60802_RG_USB20_PHY_REV                   (0xef<<24) /* 31:24 */
+#define E60802_RG_USB20_BC11_SW_EN                (0x1<<23) /* 23:23 */
+#define E60802_RG_USB20_SR_CLK_SEL                (0x1<<22) /* 22:22 */
+#define E60802_RG_USB20_OTG_VBUSCMP_EN            (0x1<<20) /* 20:20 */
+#define E60802_RG_USB20_OTG_ABIST_EN              (0x1<<19) /* 19:19 */
+#define E60802_RG_USB20_OTG_ABIST_SELE            (0x7<<16) /* 18:16 */
+#define E60802_RG_USB20_HSRX_MMODE_SELE           (0x3<<12) /* 13:12 */
+#define E60802_RG_USB20_HSRX_BIAS_EN_SEL          (0x3<<9) /* 10:9 */
+#define E60802_RG_USB20_HSRX_TMODE_EN             (0x1<<8) /* 8:8 */
+#define E60802_RG_USB20_DISCTH                    (0xf<<4) /* 7:4 */
+#define E60802_RG_USB20_SQTH                      (0xf<<0) /* 3:0 */
+
+/* U3D_U2PHYACR3 */
+#define E60802_RG_USB20_HSTX_DBIST                (0xf<<28) /* 31:28 */
+#define E60802_RG_USB20_HSTX_BIST_EN              (0x1<<26) /* 26:26 */
+#define E60802_RG_USB20_HSTX_I_EN_MODE            (0x3<<24) /* 25:24 */
+#define E60802_RG_USB20_USB11_TMODE_EN            (0x1<<19) /* 19:19 */
+#define E60802_RG_USB20_TMODE_FS_LS_TX_EN         (0x1<<18) /* 18:18 */
+#define E60802_RG_USB20_TMODE_FS_LS_RCV_EN        (0x1<<17) /* 17:17 */
+#define E60802_RG_USB20_TMODE_FS_LS_MODE          (0x1<<16) /* 16:16 */
+#define E60802_RG_USB20_HS_TERM_EN_MODE           (0x3<<13) /* 14:13 */
+#define E60802_RG_USB20_PUPD_BIST_EN              (0x1<<12) /* 12:12 */
+#define E60802_RG_USB20_EN_PU_DM                  (0x1<<11) /* 11:11 */
+#define E60802_RG_USB20_EN_PD_DM                  (0x1<<10) /* 10:10 */
+#define E60802_RG_USB20_EN_PU_DP                  (0x1<<9) /* 9:9 */
+#define E60802_RG_USB20_EN_PD_DP                  (0x1<<8) /* 8:8 */
+
+/* U3D_U2PHYACR4 */
+#define E60802_RG_USB20_DP_100K_MODE              (0x1<<18) /* 18:18 */
+#define E60802_RG_USB20_DM_100K_EN                (0x1<<17) /* 17:17 */
+#define E60802_USB20_DP_100K_EN                   (0x1<<16) /* 16:16 */
+#define E60802_USB20_GPIO_DM_I                    (0x1<<15) /* 15:15 */
+#define E60802_USB20_GPIO_DP_I                    (0x1<<14) /* 14:14 */
+#define E60802_USB20_GPIO_DM_OE                   (0x1<<13) /* 13:13 */
+#define E60802_USB20_GPIO_DP_OE                   (0x1<<12) /* 12:12 */
+#define E60802_RG_USB20_GPIO_CTL                  (0x1<<9) /* 9:9 */
+#define E60802_USB20_GPIO_MODE                    (0x1<<8) /* 8:8 */
+#define E60802_RG_USB20_TX_BIAS_EN                (0x1<<5) /* 5:5 */
+#define E60802_RG_USB20_TX_VCMPDN_EN              (0x1<<4) /* 4:4 */
+#define E60802_RG_USB20_HS_SQ_EN_MODE             (0x3<<2) /* 3:2 */
+#define E60802_RG_USB20_HS_RCV_EN_MODE            (0x3<<0) /* 1:0 */
+
+/* U3D_U2PHYAMON0 */
+#define E60802_RGO_USB20_GPIO_DM_O                (0x1<<1) /* 1:1 */
+#define E60802_RGO_USB20_GPIO_DP_O                (0x1<<0) /* 0:0 */
+
+/* U3D_U2PHYDCR0 */
+#define E60802_RG_USB20_CDR_TST                   (0x3<<30) /* 31:30 */
+#define E60802_RG_USB20_GATED_ENB                 (0x1<<29) /* 29:29 */
+#define E60802_RG_USB20_TESTMODE                  (0x3<<26) /* 27:26 */
+#define E60802_RG_SIFSLV_USB20_PLL_STABLE         (0x1<<25) /* 25:25 */
+#define E60802_RG_SIFSLV_USB20_PLL_FORCE_ON       (0x1<<24) /* 24:24 */
+#define E60802_RG_USB20_PHYD_RESERVE              (0xffff<<8) /* 23:8 */
+#define E60802_RG_USB20_EBTHRLD                   (0x1<<7) /* 7:7 */
+#define E60802_RG_USB20_EARLY_HSTX_I              (0x1<<6) /* 6:6 */
+#define E60802_RG_USB20_TX_TST                    (0x1<<5) /* 5:5 */
+#define E60802_RG_USB20_NEGEDGE_ENB               (0x1<<4) /* 4:4 */
+#define E60802_RG_USB20_CDR_FILT                  (0xf<<0) /* 3:0 */
+
+/* U3D_U2PHYDCR1 */
+#define E60802_RG_USB20_PROBE_SEL                 (0xff<<24) /* 31:24 */
+#define E60802_RG_USB20_DRVVBUS                   (0x1<<23) /* 23:23 */
+#define E60802_RG_DEBUG_EN                        (0x1<<22) /* 22:22 */
+#define E60802_RG_USB20_OTG_PROBE                 (0x3<<20) /* 21:20 */
+#define E60802_RG_USB20_SW_PLLMODE                (0x3<<18) /* 19:18 */
+#define E60802_RG_USB20_BERTH                     (0x3<<16) /* 17:16 */
+#define E60802_RG_USB20_LBMODE                    (0x3<<13) /* 14:13 */
+#define E60802_RG_USB20_FORCE_TAP                 (0x1<<12) /* 12:12 */
+#define E60802_RG_USB20_TAPSEL                    (0xfff<<0) /* 11:0 */
+
+/* U3D_U2PHYDTM0 */
+#define E60802_RG_UART_MODE                       (0x3<<30) /* 31:30 */
+#define E60802_FORCE_UART_I                       (0x1<<29) /* 29:29 */
+#define E60802_FORCE_UART_BIAS_EN                 (0x1<<28) /* 28:28 */
+#define E60802_FORCE_UART_TX_OE                   (0x1<<27) /* 27:27 */
+#define E60802_FORCE_UART_EN                      (0x1<<26) /* 26:26 */
+#define E60802_FORCE_USB_CLKEN                    (0x1<<25) /* 25:25 */
+#define E60802_FORCE_DRVVBUS                      (0x1<<24) /* 24:24 */
+#define E60802_FORCE_DATAIN                       (0x1<<23) /* 23:23 */
+#define E60802_FORCE_TXVALID                      (0x1<<22) /* 22:22 */
+#define E60802_FORCE_DM_PULLDOWN                  (0x1<<21) /* 21:21 */
+#define E60802_FORCE_DP_PULLDOWN                  (0x1<<20) /* 20:20 */
+#define E60802_FORCE_XCVRSEL                      (0x1<<19) /* 19:19 */
+#define E60802_FORCE_SUSPENDM                     (0x1<<18) /* 18:18 */
+#define E60802_FORCE_TERMSEL                      (0x1<<17) /* 17:17 */
+#define E60802_FORCE_OPMODE                       (0x1<<16) /* 16:16 */
+#define E60802_UTMI_MUXSEL                        (0x1<<15) /* 15:15 */
+#define E60802_RG_RESET                           (0x1<<14) /* 14:14 */
+#define E60802_RG_DATAIN                          (0xf<<10) /* 13:10 */
+#define E60802_RG_TXVALIDH                        (0x1<<9) /* 9:9 */
+#define E60802_RG_TXVALID                         (0x1<<8) /* 8:8 */
+#define E60802_RG_DMPULLDOWN                      (0x1<<7) /* 7:7 */
+#define E60802_RG_DPPULLDOWN                      (0x1<<6) /* 6:6 */
+#define E60802_RG_XCVRSEL                         (0x3<<4) /* 5:4 */
+#define E60802_RG_SUSPENDM                        (0x1<<3) /* 3:3 */
+#define E60802_RG_TERMSEL                         (0x1<<2) /* 2:2 */
+#define E60802_RG_OPMODE                          (0x3<<0) /* 1:0 */
+
+/* U3D_U2PHYDTM1 */
+#define E60802_RG_USB20_PRBS7_EN                  (0x1<<31) /* 31:31 */
+#define E60802_RG_USB20_PRBS7_BITCNT              (0x3f<<24) /* 29:24 */
+#define E60802_RG_USB20_CLK48M_EN                 (0x1<<23) /* 23:23 */
+#define E60802_RG_USB20_CLK60M_EN                 (0x1<<22) /* 22:22 */
+#define E60802_RG_UART_I                          (0x1<<19) /* 19:19 */
+#define E60802_RG_UART_BIAS_EN                    (0x1<<18) /* 18:18 */
+#define E60802_RG_UART_TX_OE                      (0x1<<17) /* 17:17 */
+#define E60802_RG_UART_EN                         (0x1<<16) /* 16:16 */
+#define E60802_RG_IP_U2_PORT_POWER                (0x1<<15) /* 15:15 */
+#define E60802_FORCE_IP_U2_PORT_POWER             (0x1<<14) /* 14:14 */
+#define E60802_FORCE_VBUSVALID                    (0x1<<13) /* 13:13 */
+#define E60802_FORCE_SESSEND                      (0x1<<12) /* 12:12 */
+#define E60802_FORCE_BVALID                       (0x1<<11) /* 11:11 */
+#define E60802_FORCE_AVALID                       (0x1<<10) /* 10:10 */
+#define E60802_FORCE_IDDIG                        (0x1<<9) /* 9:9 */
+#define E60802_FORCE_IDPULLUP                     (0x1<<8) /* 8:8 */
+#define E60802_RG_VBUSVALID                       (0x1<<5) /* 5:5 */
+#define E60802_RG_SESSEND                         (0x1<<4) /* 4:4 */
+#define E60802_RG_BVALID                          (0x1<<3) /* 3:3 */
+#define E60802_RG_AVALID                          (0x1<<2) /* 2:2 */
+#define E60802_RG_IDDIG                           (0x1<<1) /* 1:1 */
+#define E60802_RG_IDPULLUP                        (0x1<<0) /* 0:0 */
+
+/* U3D_U2PHYDMON0 */
+#define E60802_RG_USB20_PRBS7_BERTH               (0xff<<0) /* 7:0 */
+
+/* U3D_U2PHYDMON1 */
+#define E60802_USB20_UART_O                       (0x1<<31) /* 31:31 */
+#define E60802_RGO_USB20_LB_PASS                  (0x1<<30) /* 30:30 */
+#define E60802_RGO_USB20_LB_DONE                  (0x1<<29) /* 29:29 */
+#define E60802_AD_USB20_BVALID                    (0x1<<28) /* 28:28 */
+#define E60802_USB20_IDDIG                        (0x1<<27) /* 27:27 */
+#define E60802_AD_USB20_VBUSVALID                 (0x1<<26) /* 26:26 */
+#define E60802_AD_USB20_SESSEND                   (0x1<<25) /* 25:25 */
+#define E60802_AD_USB20_AVALID                    (0x1<<24) /* 24:24 */
+#define E60802_USB20_LINE_STATE                   (0x3<<22) /* 23:22 */
+#define E60802_USB20_HST_DISCON                   (0x1<<21) /* 21:21 */
+#define E60802_USB20_TX_READY                     (0x1<<20) /* 20:20 */
+#define E60802_USB20_RX_ERROR                     (0x1<<19) /* 19:19 */
+#define E60802_USB20_RX_ACTIVE                    (0x1<<18) /* 18:18 */
+#define E60802_USB20_RX_VALIDH                    (0x1<<17) /* 17:17 */
+#define E60802_USB20_RX_VALID                     (0x1<<16) /* 16:16 */
+#define E60802_USB20_DATA_OUT                     (0xffff<<0) /* 15:0 */
+
+/* U3D_U2PHYDMON2 */
+#define E60802_RGO_TXVALID_CNT                    (0xff<<24) /* 31:24 */
+#define E60802_RGO_RXACTIVE_CNT                   (0xff<<16) /* 23:16 */
+#define E60802_RGO_USB20_LB_BERCNT                (0xff<<8) /* 15:8 */
+#define E60802_USB20_PROBE_OUT                    (0xff<<0) /* 7:0 */
+
+/* U3D_U2PHYDMON3 */
+#define E60802_RGO_USB20_PRBS7_ERRCNT             (0xffff<<16) /* 31:16 */
+#define E60802_RGO_USB20_PRBS7_DONE               (0x1<<3) /* 3:3 */
+#define E60802_RGO_USB20_PRBS7_LOCK               (0x1<<2) /* 2:2 */
+#define E60802_RGO_USB20_PRBS7_PASS               (0x1<<1) /* 1:1 */
+#define E60802_RGO_USB20_PRBS7_PASSTH             (0x1<<0) /* 0:0 */
+
+/* U3D_U2PHYBC12C */
+#define E60802_RG_SIFSLV_CHGDT_DEGLCH_CNT         (0xf<<28) /* 31:28 */
+#define E60802_RG_SIFSLV_CHGDT_CTRL_CNT           (0xf<<24) /* 27:24 */
+#define E60802_RG_SIFSLV_CHGDT_FORCE_MODE         (0x1<<16) /* 16:16 */
+#define E60802_RG_CHGDT_ISRC_LEV                  (0x3<<14) /* 15:14 */
+#define E60802_RG_CHGDT_VDATSRC                   (0x1<<13) /* 13:13 */
+#define E60802_RG_CHGDT_BGVREF_SEL                (0x7<<10) /* 12:10 */
+#define E60802_RG_CHGDT_RDVREF_SEL                (0x3<<8) /* 9:8 */
+#define E60802_RG_CHGDT_ISRC_DP                   (0x1<<7) /* 7:7 */
+#define E60802_RG_SIFSLV_CHGDT_OPOUT_DM           (0x1<<6) /* 6:6 */
+#define E60802_RG_CHGDT_VDAT_DM                   (0x1<<5) /* 5:5 */
+#define E60802_RG_CHGDT_OPOUT_DP                  (0x1<<4) /* 4:4 */
+#define E60802_RG_SIFSLV_CHGDT_VDAT_DP            (0x1<<3) /* 3:3 */
+#define E60802_RG_SIFSLV_CHGDT_COMP_EN            (0x1<<2) /* 2:2 */
+#define E60802_RG_SIFSLV_CHGDT_OPDRV_EN           (0x1<<1) /* 1:1 */
+#define E60802_RG_CHGDT_EN                        (0x1<<0) /* 0:0 */
+
+/* U3D_U2PHYBC12C1 */
+#define E60802_RG_CHGDT_REV                       (0xff<<0) /* 7:0 */
+
+/* U3D_REGFPPC */
+#define E60802_USB11_OTG_REG                      (0x1<<4) /* 4:4 */
+#define E60802_USB20_OTG_REG                      (0x1<<3) /* 3:3 */
+#define E60802_CHGDT_REG                          (0x1<<2) /* 2:2 */
+#define E60802_USB11_REG                          (0x1<<1) /* 1:1 */
+#define E60802_USB20_REG                          (0x1<<0) /* 0:0 */
+
+/* U3D_VERSIONC */
+#define E60802_VERSION_CODE_REGFILE               (0xff<<24) /* 31:24 */
+#define E60802_USB11_VERSION_CODE                 (0xff<<16) /* 23:16 */
+#define E60802_VERSION_CODE_ANA                   (0xff<<8) /* 15:8 */
+#define E60802_VERSION_CODE_DIG                   (0xff<<0) /* 7:0 */
+
+/* U3D_REGFCOM */
+#define E60802_RG_PAGE                            (0xff<<24) /* 31:24 */
+#define E60802_I2C_MODE                           (0x1<<16) /* 16:16 */
diff --git a/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_ab_cmd.c b/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_ab_cmd.c
new file mode 100644
index 0000000..08cae76
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_ab_cmd.c
@@ -0,0 +1,94 @@
+/*
+ * 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.
+*/
+
+#include <compiler.h>
+#include <debug.h>
+#include <errno.h>
+#include <lib/fastboot.h>
+#include <lib/fastboot_oem_cmd.h>
+
+/*
+ * cmd_ab_set_active(): set active slot for a/b update flow
+ *
+ * This command provides the set_active command for both ab and non-ab case.
+ * For ab case,
+ *     oem set_active [a|b] - set active slot to a or b slot
+ *  For non-ab case,
+ *     oem set_active [0|1] - set device active boot partition,
+ *         emmc: 0 for boot partition 0, 1 for boot partition 1
+ *         other devices: not supported
+ * depends: lib/fastboot, lib/booctrl
+ *          - ab_metadata_init(): should be override if ab set_active required
+ *          - plat_ab_set_active_bootdev(): should be override if set_active
+ *            required
+ */
+extern __WEAK int ab_metadata_init(int slot);
+extern __WEAK int plat_ab_set_active_bootdev(int slot);
+static void cmd_oem_ab_set_active(const char *arg, void *data, unsigned size)
+{
+    int rc;
+    int slot;
+    bool is_ab_cmd;
+
+    /* the pass in oem command arg contains a leading space, skip it */
+    switch (arg[1]) {
+        case '0':
+        case '1':
+            slot = (int)(arg[1] - '0');
+            is_ab_cmd = false;
+            break;
+        case 'a':
+        case 'b':
+            slot = (int)(arg[1] - 'a');
+            is_ab_cmd = true;
+            break;
+        default:
+            fastboot_fail("invalid param\n");
+            return;
+    }
+
+    rc = 0;
+    if (is_ab_cmd)
+        rc = ab_metadata_init(slot);
+
+    if (rc == 0) {
+        rc = plat_ab_set_active_bootdev(slot);
+        /* allow platform not support 'set active bootdev' when ab enabled */
+        if (is_ab_cmd && rc == -ENOTSUP) {
+            dprintf(ALWAYS, "\"set active bootdev\" is not supported.\n");
+            rc = 0;
+        }
+    }
+
+    if (rc == 0) {
+        fastboot_okay("");
+        dprintf(ALWAYS, "set active slot ok\n");
+    } else {
+        fastboot_fail("set active slot failed\n");
+    }
+}
+
+FASTBOOT_OEM_CMD_START(cmd_oem_ab_set_active)
+    .cmd_str = "oem set_active",
+    .cmd_handler = cmd_oem_ab_set_active,
+FASTBOOT_OEM_CMD_END
diff --git a/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_efuse_cmd.c b/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_efuse_cmd.c
new file mode 100644
index 0000000..99120b5
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_efuse_cmd.c
@@ -0,0 +1,215 @@
+/*
+ * 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.
+*/
+
+#include <ctype.h>
+#include <lib/fastboot.h>
+#include <lib/fastboot_oem_cmd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+extern void enable_vefuse(void);
+extern void disable_vefuse(void);
+
+__WEAK int read_efuse(unsigned int index, unsigned char *data, unsigned int len)
+{
+    fastboot_fail("Can not find libefuse, efuse write is not supported");
+    return -1;
+}
+
+__WEAK int write_efuse(unsigned int index, const unsigned char *data, unsigned int len)
+{
+    fastboot_fail("Can not find libefuse, efuse read is not supported");
+    return -1;
+}
+
+__WEAK void set_op_vefuse(int vefuse_op, int vcore_op)
+{
+    fastboot_fail("Can not find libefuse, efuse set op is not supported");
+}
+
+__WEAK void get_op_vefuse(int *vefuse_op, int *vcore_op)
+{
+    fastboot_fail("Can not find libefuse, efuse get op is not supported");
+}
+
+static int split(char *buf, char *argv[], int num)
+{
+    int i = 0;
+    char *pch;
+    pch = strtok(buf, " ");
+    while(pch != NULL && i < num) {
+        argv[i++] = pch;
+        pch = strtok(NULL, " ");
+    }
+    return i;
+}
+
+void cmd_oem_efuse_write(const char *arg, void *data, unsigned sz)
+{
+#define EFUSE_WIRTE_ARGV_NUM 3
+#define EFUSE_WRITE_BUF_SIZE 32
+    char buf[MAX_RSP_SIZE];
+    char *argv[MAX_RSP_SIZE];
+    int argc, ret = 0;
+    char res[MAX_RSP_SIZE];
+    char write[EFUSE_WRITE_BUF_SIZE];
+    unsigned long write_val;
+    char *endptr;
+
+    strlcpy(buf, arg, sizeof(buf));
+    argc = split(buf, argv, EFUSE_WIRTE_ARGV_NUM);
+
+    if (argc != EFUSE_WIRTE_ARGV_NUM) {
+        fastboot_fail("number of arguments should be three");
+        return;
+    }
+
+    if (!(isdigit(argv[0][0]) && isdigit(argv[2][0]))) {
+        fastboot_fail("idx and len should be digit");
+        return;
+    }
+
+    if ((long)strlen(argv[1]) != (atol(argv[2]) * 2)) {
+        fastboot_fail("data len is not equal to byte len");
+        return;
+    }
+
+    write_val = strtoul(argv[1], &endptr, 16);
+    if (*endptr != '\0') {
+        fastboot_fail("data should be hex");
+        return;
+    }
+
+    memcpy(write, &write_val, sizeof(write_val));
+
+    LTRACEF("idx %u, data %s(0x%lx), len %u\n",
+            atoui(argv[0]), argv[1], write_val, atoui(argv[2]));
+
+    enable_vefuse();
+
+    ret = write_efuse(atoui(argv[0]), (const unsigned char *)write, atoui(argv[2]));
+
+    disable_vefuse();
+
+    if (!ret) {
+        snprintf(res, MAX_RSP_SIZE, "efuse write ok 0x%lx", write_val);
+        fastboot_info(res);
+        fastboot_okay("");
+    } else {
+        snprintf(res, MAX_RSP_SIZE, "efuse write fail %d", ret);
+        fastboot_fail(res);
+    }
+}
+
+void cmd_oem_efuse_read(const char *arg, void *data, unsigned sz)
+{
+#define EFUSE_READ_ARGV_NUM 2
+#define EFUSE_READ_BUF_SIZE 32
+    char read_data[EFUSE_READ_BUF_SIZE];
+    char buf[MAX_RSP_SIZE];
+    char *argv[MAX_RSP_SIZE];
+    int argc, ret = 0;
+    unsigned int i;
+    char res[MAX_RSP_SIZE];
+    unsigned long read_val = 0;
+
+    strlcpy(buf, arg, sizeof(buf));
+    argc = split(buf, argv, EFUSE_READ_ARGV_NUM);
+
+    if (argc != EFUSE_READ_ARGV_NUM) {
+        fastboot_fail("number of arguments should be two");
+        return;
+    }
+
+    if (!(isdigit(argv[0][0]) && isdigit(argv[1][0]))) {
+        fastboot_fail("arguments should be digit");
+        return;
+    }
+
+    LTRACEF("idx %u, len %u\n", atoui(argv[0]), atoui(argv[1]));
+
+    ret = read_efuse(atoui(argv[0]), (unsigned char *)read_data, atoui(argv[1]));
+
+    if (!ret) {
+        for (i = 0; i < atoui(argv[1]);i++) {
+            read_val |= (*(read_data + i) << (i * 8)) ;
+        }
+        snprintf(res, MAX_RSP_SIZE, "efuse read ok 0x%lx", read_val);
+        fastboot_info(res);
+        fastboot_okay("");
+    } else {
+        snprintf(res, MAX_RSP_SIZE, "efuse read fail %d", ret);
+        fastboot_fail(res);
+    }
+}
+
+void cmd_oem_efuse_set_op(const char *arg, void *data, unsigned sz)
+{
+#define EFUSE_SET_OP_ARGV_NUM 2
+    char buf[MAX_RSP_SIZE];
+    char *argv[MAX_RSP_SIZE];
+    int argc;
+    char res[MAX_RSP_SIZE];
+    int vefuse, vcore;
+
+    strlcpy(buf, arg, sizeof(buf));
+    argc = split(buf, argv, EFUSE_SET_OP_ARGV_NUM);
+
+    if (argc != EFUSE_SET_OP_ARGV_NUM) {
+        fastboot_fail("number of arguments should be 2");
+        return;
+    }
+
+    if (!(isdigit(argv[0][0]) && isdigit(argv[1][0]))) {
+        fastboot_fail("arguments should be digit");
+        return;
+    }
+
+    LTRACEF("vefuse op %u, vcore op %u\n", atoui(argv[0]), atoui(argv[1]));
+
+    set_op_vefuse(atoui(argv[0]), atoui(argv[1]));
+    get_op_vefuse(&vefuse, &vcore);
+
+    snprintf(res, MAX_RSP_SIZE, "efuse set op ok, vefuse=%dmV, vcore=%dmV", vefuse, vcore);
+    fastboot_info(res);
+    fastboot_okay("");
+}
+
+/* fastboot oem writeefuse/readefuse/setopefuse commands registeration */
+FASTBOOT_OEM_CMD_START(cmd_oem_efuse_write)
+    .cmd_str = "oem writeefuse",
+    .cmd_handler = cmd_oem_efuse_write,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_efuse_read)
+    .cmd_str = "oem readefuse",
+    .cmd_handler = cmd_oem_efuse_read,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_efuse_set_op)
+    .cmd_str = "oem setopefuse",
+    .cmd_handler = cmd_oem_efuse_set_op,
+FASTBOOT_OEM_CMD_END
diff --git a/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_mac_cmd.c b/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_mac_cmd.c
new file mode 100644
index 0000000..3392c11
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_mac_cmd.c
@@ -0,0 +1,427 @@
+/*
+ * 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.
+*/
+
+#include <compiler.h>
+#include <debug.h>
+#include <fit.h>
+#include <lib/bio.h>
+#include <lib/fastboot.h>
+#include <lib/fastboot_oem_cmd.h>
+#include <lib/mempool.h>
+#include <libfdt.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MAC_ADDRESS_STR_LEN       12
+#define MAC_ADDRESS_BYTE_LEN      6
+#define WIFIMAC_OVERLAY_PROP_NAME "aucMacAddress"
+#define BTMAC_OVERLAY_PROP_NAME "btAddr"
+#define ETHMAC_OVERLAY_PROP_NAME "mac-address"
+
+struct dto_partition {
+    const char *part;
+    bool hasAB;
+};
+
+#if !defined(VPD_PART_NAME)
+#define VPD_PART_NAME NULL
+#endif
+#if !defined(DTBO_PART_NAME)
+#define DTBO_PART_NAME NULL
+#endif
+#if !defined(VPD_HAS_SLOT)
+#define VPD_HAS_SLOT 0
+#endif
+#if !defined(DTBO_HAS_SLOT)
+#define DTBO_HAS_SLOT 0
+#endif
+struct dto_partition dto_part[] = {
+    {
+        .part = VPD_PART_NAME,
+        .hasAB = (VPD_HAS_SLOT != 0)
+    },
+    {
+        .part = DTBO_PART_NAME,
+        .hasAB = (DTBO_HAS_SLOT != 0)
+    }
+};
+
+#define NUM_OF_DTO_PARTITIONS   (sizeof(dto_part)/sizeof(struct dto_partition))
+
+struct mac_dtoverlay {
+    const char *tag;
+    const char *node_path;
+    const char *prop_name;
+    int node_offset;
+};
+
+static int mac_str_to_ull(const char *macstr, uint64_t *hexp)
+{
+    uint64_t _hex;
+    char *ep;
+
+    if (!macstr || !hexp)
+        return -1;
+
+    if (strlen(macstr) != MAC_ADDRESS_STR_LEN)
+        return -1;
+
+    _hex = (uint64_t)strtoll(macstr, &ep, 16);
+    if (*ep != '\0')
+        return -1;
+
+    *hexp = cpu_to_fdt64(_hex) >> 16;
+
+    return 0;
+}
+
+static char *get_dto_part_name(int index)
+{
+    extern __WEAK const char *get_suffix(void);
+    const char *base_name;
+    const char *suffix = "";
+    char *full_name;
+    size_t name_len;
+
+    base_name = dto_part[index].part;
+
+    if (dto_part[index].hasAB == false)
+        return strdup(base_name);
+
+    if (get_suffix)
+        suffix = get_suffix();
+
+    name_len = strlen(base_name) + strlen(suffix) + 1;
+    full_name = (char *)malloc(name_len);
+    if (full_name)
+        snprintf(full_name, name_len, "%s%s", base_name, suffix);
+
+    return full_name;
+}
+
+static int get_overlay_symbols_path(void *dtbo, struct mac_dtoverlay *mac_overlay) {
+    int noffset;
+
+    noffset = fdt_path_offset(dtbo, "/__symbols__");
+    if (noffset < 0) {
+        dprintf(CRITICAL, "Can't find symbols\n");
+        goto err;
+    }
+
+    if (strcmp(mac_overlay->tag, "wifi") == 0) {
+        mac_overlay->node_path = fdt_getprop(dtbo, noffset, "combo", NULL);
+        if (mac_overlay->node_path == NULL)
+            goto err;
+
+        mac_overlay->node_offset = fdt_path_offset(dtbo, mac_overlay->node_path);
+        mac_overlay->prop_name = WIFIMAC_OVERLAY_PROP_NAME;
+
+    } else if (strcmp(mac_overlay->tag, "bt") == 0) {
+        mac_overlay->node_path = fdt_getprop(dtbo, noffset, "combo", NULL);
+        if (mac_overlay->node_path == NULL)
+            goto err;
+
+        mac_overlay->node_offset = fdt_path_offset(dtbo, mac_overlay->node_path);
+        mac_overlay->prop_name = BTMAC_OVERLAY_PROP_NAME;
+
+    } else if (strcmp(mac_overlay->tag, "ethernet") == 0) {
+        mac_overlay->node_path = fdt_getprop(dtbo, noffset, "eth", NULL);
+        if (mac_overlay->node_path == NULL)
+            goto err;
+
+        mac_overlay->node_offset = fdt_path_offset(dtbo, mac_overlay->node_path);
+        mac_overlay->prop_name = ETHMAC_OVERLAY_PROP_NAME;
+    } else {
+        dprintf(CRITICAL, "tag not found\n");
+        goto err;
+    }
+
+    return mac_overlay->node_offset;
+
+err:
+    return -1;
+}
+
+static int find_mac_overlay_node_offset(struct mac_dtoverlay *pmac_overlay,
+                                        char **part_name, void **dtbo)
+{
+    unsigned long i;
+    int noffset;
+    char *part;
+    void *buf;
+
+    for (i = 0; i < NUM_OF_DTO_PARTITIONS; i++) {
+        part = get_dto_part_name(i);
+        if (part == NULL)
+            continue;
+
+        buf = NULL;
+        if (fit_get_image(part, &buf) != 0)
+            goto rel_mem_continue;
+
+        noffset = get_overlay_symbols_path(buf, pmac_overlay);
+        if (noffset < 0)
+            goto rel_mem_continue;
+
+        if (part_name)
+            *part_name = part;
+        if (dtbo)
+            *dtbo = buf;
+        pmac_overlay->node_offset = noffset;
+        break;
+
+rel_mem_continue:
+        free(part);
+        if (buf)
+            mempool_free(buf);
+    }
+
+    return (i < NUM_OF_DTO_PARTITIONS) ? 0 : -1;
+}
+
+static int update_mac_overlay_prop(struct mac_dtoverlay *pmac_overlay,
+                                   uint64_t mac_address,
+                                   char *part_name, void *dtbo)
+{
+    int ret;
+    bdev_t *bdev;
+    size_t totalsize;
+    ssize_t nbytes_written;
+
+    bdev = bio_open_by_label(part_name);
+    if (!bdev)
+        return -1;
+
+    /* update overlay prop */
+    ret = fdt_open_into(dtbo, dtbo, MAX_DTB_SIZE);
+    if (ret < 0)
+        return -1;
+
+    ret = fdt_setprop(dtbo, pmac_overlay->node_offset, pmac_overlay->prop_name,
+                      (const void *)&mac_address, MAC_ADDRESS_BYTE_LEN);
+    if (ret < 0)
+        return -1;
+
+    if (fdt_pack(dtbo) < 0)
+        return -1;
+
+    /* write to partition */
+    ret = bio_erase(bdev, 0, bdev->total_size);
+    if (ret < 0) {
+        dprintf(CRITICAL, "[%s] erase failed\n", part_name);
+        return -1;
+    }
+
+    totalsize = fdt_totalsize(dtbo);
+    nbytes_written = bio_write(bdev, dtbo, 0, totalsize);
+    if ((nbytes_written < 0) || ((size_t)nbytes_written != totalsize))
+        return -1;
+
+    return 0;
+}
+
+static void mac_write(const char *arg, struct mac_dtoverlay *pmac_overlay)
+{
+    int ret;
+    uint64_t mac_address; /* lower 48bits */
+    char *part_name;
+    char res[MAX_RSP_SIZE];
+    const char *macp = arg + 1; /* skip leading space */
+    void *dtbo;
+
+    if (mac_str_to_ull(macp, &mac_address) != 0) {
+        fastboot_fail("Inut mac address: 12 chars of 0-9a-fA-F");
+        return;
+    }
+
+    ret = find_mac_overlay_node_offset(pmac_overlay, &part_name, &dtbo);
+    if (ret < 0) {
+        snprintf(res, MAX_RSP_SIZE, "can't find %s mac node in dtbo",
+                 pmac_overlay->tag);
+        fastboot_fail(res);
+        return;
+    }
+
+    ret = update_mac_overlay_prop(pmac_overlay, mac_address, part_name, dtbo);
+    if (ret) {
+        snprintf(res, MAX_RSP_SIZE, "write %s mac address failed",
+                 pmac_overlay->tag);
+        fastboot_fail(res);
+        goto err;
+    }
+
+    snprintf(res, MAX_RSP_SIZE, "%s mac write ok 0x%012llx",
+             pmac_overlay->tag, (fdt64_to_cpu(mac_address) >> 16));
+    fastboot_info(res);
+    fastboot_okay("");
+err:
+    free(part_name);
+    mempool_free(dtbo);
+}
+
+static void mac_read(struct mac_dtoverlay *pmac_overlay)
+{
+    int ret;
+    int len;
+    void *dtbo;
+    const unsigned char *pmac;
+    char res[MAX_RSP_SIZE];
+
+    ret = find_mac_overlay_node_offset(pmac_overlay, NULL, &dtbo);
+    if (ret < 0) {
+        snprintf(res, MAX_RSP_SIZE, "can't find %s mac node in dtbo",
+                pmac_overlay->tag);
+        fastboot_fail(res);
+        return;
+    }
+
+    pmac = fdt_getprop(dtbo, pmac_overlay->node_offset,
+                       pmac_overlay->prop_name, &len);
+    if ((pmac == NULL) || (len != MAC_ADDRESS_BYTE_LEN)) {
+        snprintf(res, MAX_RSP_SIZE, "read %s mac addr failed in dtbo",
+                pmac_overlay->tag);
+        fastboot_fail(res);
+        goto err;
+    }
+
+    snprintf(res, MAX_RSP_SIZE, "%s mac read ok 0x%02x%02x%02x%02x%02x%02x",
+            pmac_overlay->tag,
+            pmac[0], pmac[1], pmac[2], pmac[3], pmac[4], pmac[5]);
+    fastboot_info(res);
+    fastboot_okay("");
+
+err:
+    mempool_free(dtbo);
+}
+
+/*
+ * cmd_oem_wifimac_write(): update wifi mac address in wifi mac overlay node
+ * cmd_oem_wifimac_read():  read wifi mac address from wifi mac overlay node
+ * cmd_oem_btmac_write():   update bt mac address in bt mac overlay node
+ * cmd_oem_btmac_read():    read bt mac address from bt mac overlay node
+ * cmd_oem_ethmac_write():  update eth mac address in eth mac overlay node
+ * cmd_oem_ethmac_read():   read eth mac address from eth mac overlay node
+ *
+ * This command looks for the [wifi|bt|eth] overlay node in dto partitions
+ * (vpd or dtbo), and
+ *   *_write(): update the specified mac address to the image, and write back
+ *              to the partition.
+ *   *_read():  get the mac address from the overlay node and respond to the
+ *              host fastboot program.
+ * depends: lib/bio
+ *          lib/bootctrl
+ *          lib/fastboot
+ *          lib/fdt
+ *          lib/fit
+ *          lib/mempool
+ */
+static void cmd_oem_wifimac_write(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "wifi";
+
+    mac_write(arg, &mac_overlay);
+}
+
+static void cmd_oem_wifimac_read(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "wifi";
+
+    mac_read(&mac_overlay);
+}
+
+static void cmd_oem_btmac_write(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "bt";
+
+    mac_write(arg, &mac_overlay);
+}
+
+static void cmd_oem_btmac_read(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "bt";
+
+    mac_read(&mac_overlay);
+}
+
+static void cmd_oem_ethmac_write(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "ethernet";
+
+    mac_write(arg, &mac_overlay);
+}
+
+static void cmd_oem_ethmac_read(const char *arg, void *data, unsigned sz)
+{
+    struct mac_dtoverlay mac_overlay;
+
+    memset(&mac_overlay, 0, sizeof(struct mac_dtoverlay));
+    mac_overlay.tag = "ethernet";
+
+    mac_read(&mac_overlay);
+}
+
+/* fastboot oem mac read/write commands registeration */
+FASTBOOT_OEM_CMD_START(cmd_oem_wifimac_write)
+    .cmd_str = "oem writewifimac",
+    .cmd_handler = cmd_oem_wifimac_write,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_wifimac_read)
+    .cmd_str = "oem readwifimac",
+    .cmd_handler = cmd_oem_wifimac_read,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_btmac_write)
+    .cmd_str = "oem writebtmac",
+    .cmd_handler = cmd_oem_btmac_write,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_btmac_read)
+    .cmd_str = "oem readbtmac",
+    .cmd_handler = cmd_oem_btmac_read,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_ethmac_write)
+    .cmd_str = "oem writeethmac",
+    .cmd_handler = cmd_oem_ethmac_write,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_oem_ethmac_read)
+    .cmd_str = "oem readethmac",
+    .cmd_handler = cmd_oem_ethmac_read,
+FASTBOOT_OEM_CMD_END
diff --git a/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_nand_cmd.c b/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_nand_cmd.c
new file mode 100644
index 0000000..b90d145
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/fastboot_oem_cmd/oem_nand_cmd.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <compiler.h>
+#include <debug.h>
+#include <errno.h>
+#include <lib/fastboot.h>
+#include <lib/fastboot_oem_cmd.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+extern void nand_show_bad(void);
+static void cmd_nand_show_bad(const char *arg, void *data, unsigned sz)
+{
+    LTRACE;
+    nand_show_bad();
+    fastboot_okay("");
+}
+
+extern void nand_erase_block(const char *arg, void *data, unsigned sz);
+static void cmd_nand_erase_block(const char *arg, void *data, unsigned sz)
+{
+    LTRACE;
+    nand_erase_block(arg, data, sz);
+    fastboot_okay("");
+}
+
+extern void nand_read_page(const char *arg, void *data, unsigned sz);
+static void cmd_nand_read_page(const char *arg, void *data, unsigned sz)
+{
+    LTRACE;
+    nand_read_page(arg, data, sz);
+    fastboot_okay("");
+}
+
+extern void nand_write_page(const char *arg, void *data, unsigned sz);
+static void cmd_nand_write_page(const char *arg, void *data, unsigned sz)
+{
+    LTRACE;
+    nand_write_page(arg, data, sz);
+    fastboot_okay("");
+}
+extern void nand_stress_test(void);
+static void cmd_nand_stress_test(const char *arg, void *data, unsigned sz)
+{
+    LTRACE;
+    nand_stress_test();
+    fastboot_okay("");
+}
+
+extern void nand_mark_block(const char *arg, void *data, unsigned sz);
+static void cmd_nand_mark_block(const char *arg, void *data, unsigned sz)
+{
+    LTRACE;
+    nand_mark_block(arg, data, sz);
+    fastboot_okay("");
+}
+
+FASTBOOT_OEM_CMD_START(cmd_nand_show_bad)
+    .cmd_str = "oem nandshowbad",
+    .cmd_handler = cmd_nand_show_bad,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_nand_erase_block)
+    .cmd_str = "oem nanderaseblock",
+    .cmd_handler = cmd_nand_erase_block,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_nand_read_page)
+    .cmd_str = "oem nandreadpage",
+    .cmd_handler = cmd_nand_read_page,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_nand_write_page)
+    .cmd_str = "oem nandwritepage",
+    .cmd_handler = cmd_nand_write_page,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_nand_stress_test)
+    .cmd_str = "oem nandstresstest",
+    .cmd_handler = cmd_nand_stress_test,
+FASTBOOT_OEM_CMD_END
+
+FASTBOOT_OEM_CMD_START(cmd_nand_mark_block)
+    .cmd_str = "oem nandmarkblock",
+    .cmd_handler = cmd_nand_mark_block,
+FASTBOOT_OEM_CMD_END
diff --git a/src/bsp/lk/platform/mediatek/common/include/arch/mp_mediatek.h b/src/bsp/lk/platform/mediatek/common/include/arch/mp_mediatek.h
new file mode 100644
index 0000000..449cdc5
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/arch/mp_mediatek.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+#pragma once
+
+#include <sys/types.h>
+
+#if WITH_SMP
+
+struct smp_cpu_info {
+    uint id[SMP_MAX_CPUS];  /* Bit[0:23] of mpidr for each core */
+    uint cpu_on_mask;       /* Cpu mask to indicate which cpu to be on.
+                               Bit 0: don't care.
+                               For example: 0x11 (or 0x10) to bring up cpu 4. */
+};
+
+/* power off non boot cpus */
+void plat_mp_off(void);
+
+/* handover bootcpu to cpu */
+void plat_mp_bootcpu_handover(uint32_t cpu);
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/emi_info_v1.h b/src/bsp/lk/platform/mediatek/common/include/platform/emi_info_v1.h
new file mode 100644
index 0000000..04d55d9
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/emi_info_v1.h
@@ -0,0 +1,53 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek Software")
+* have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+* applicable license agreements with MediaTek Inc.
+*/
+
+#ifndef __EMI_INFO_H__
+#define __EMI_INFO_H__
+
+#define MAX_CH	2
+#define MAX_RK	2
+
+typedef struct {
+	unsigned int dram_type;
+	unsigned int ch_num;
+	unsigned int rk_num;
+	unsigned long long rank_size[MAX_RK];
+} emi_info_t;
+
+int set_fdt_emi_info(void *fdt);
+
+int set_fdt_dram_size(void *fdt);
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/emi_mpu_v1.h b/src/bsp/lk/platform/mediatek/common/include/platform/emi_mpu_v1.h
new file mode 100644
index 0000000..54a56de
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/emi_mpu_v1.h
@@ -0,0 +1,48 @@
+#ifndef __EMI_MPU_H__
+#define __EMI_MPU_H__
+
+
+#define NO_PROTECTION       0
+#define SEC_RW              1
+#define SEC_RW_NSEC_R       2
+#define SEC_RW_NSEC_W       3
+#define SEC_R_NSEC_R        4
+#define FORBIDDEN           5
+#define SEC_R_NSEC_RW       6
+
+#define LOCK                1
+#define UNLOCK              0
+
+#define EMI_MPU_DGROUP_NUM	(EMI_MPU_DOMAIN_NUM / 8)
+#if (EMI_MPU_DGROUP_NUM == 1)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+	apc_ary[0] = \
+		(((unsigned int)  d7) << 21) | (((unsigned int)  d6) << 18) | (((unsigned int)  d5) << 15) | \
+		(((unsigned int)  d4) << 12) | (((unsigned int)  d3) <<  9) | (((unsigned int)  d2) <<  6) | \
+		(((unsigned int)  d1) <<  3) |  ((unsigned int)  d0) | ((unsigned int) lock << 31); \
+} while (0)
+#elif (EMI_MPU_DGROUP_NUM == 2)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d15, d14, d13, d12, d11, d10, d9, d8, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+	apc_ary[1] = \
+		(((unsigned int) d15) << 21) | (((unsigned int) d14) << 18) | (((unsigned int) d13) << 15) | \
+		(((unsigned int) d12) << 12) | (((unsigned int) d11) <<  9) | (((unsigned int) d10) <<  6) | \
+		(((unsigned int)  d9) <<  3) |  ((unsigned int)  d8); \
+	apc_ary[0] = \
+		(((unsigned int)  d7) << 21) | (((unsigned int)  d6) << 18) | (((unsigned int)  d5) << 15) | \
+		(((unsigned int)  d4) << 12) | (((unsigned int)  d3) <<  9) | (((unsigned int)  d2) <<  6) | \
+		(((unsigned int)  d1) <<  3) |  ((unsigned int)  d0) | ((unsigned int) lock << 31); \
+} while (0)
+#endif
+
+struct emi_region_info_t {
+	unsigned long long start;
+	unsigned long long end;
+	unsigned int region;
+	unsigned int apc[EMI_MPU_DGROUP_NUM];
+};
+
+extern int emi_mpu_set_protection(struct emi_region_info_t *region_info);
+
+#endif /* __EMI_MPU_H__ */
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/mt_uart.h b/src/bsp/lk/platform/mediatek/common/include/platform/mt_uart.h
new file mode 100644
index 0000000..f2e5560
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/mt_uart.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+*/
+#ifndef __MT_UART_H
+#define __MT_UART_H
+
+int mtk_uart_putc(char c);
+int mtk_uart_getc(bool wait);
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/mt_usbphy.h b/src/bsp/lk/platform/mediatek/common/include/platform/mt_usbphy.h
new file mode 100644
index 0000000..507bb3f
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/mt_usbphy.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012 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
+
+void mt_usb_phy_poweron(void);
+void mt_usb_phy_poweroff(void);
+
+void charger_detect_init(void);
+void charger_detect_release(void);
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/mtcmos.h b/src/bsp/lk/platform/mediatek/common/include/platform/mtcmos.h
new file mode 100644
index 0000000..dba3028
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/mtcmos.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef __SOC_MEDIATEK_COMMON_MTCMOS_H__
+#define __SOC_MEDIATEK_COMMON_MTCMOS_H__
+
+void mtcmos_audio_power_on(void);
+void mtcmos_display_power_on(void);
+
+void mtcmos_protect_display_bus(void);
+
+#endif /* __SOC_MEDIATEK_COMMON_MTCMOS_H__ */
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/mtk_bio_ioctl.h b/src/bsp/lk/platform/mediatek/common/include/platform/mtk_bio_ioctl.h
new file mode 100644
index 0000000..860eb51
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/mtk_bio_ioctl.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+*/
+
+#ifndef __MTK_BIO_IOCTL_H__
+#define __MTK_BIO_IOCTL_H__
+
+#include <lib/bio.h>
+
+enum bio_ioctl_custom_num {
+    /* common ioctl cmds */
+    /* query the capability of directly write without erase */
+    BIO_IOCTL_QUERY_CAP_REWRITABLE = BIO_IOCTL_CUSTOM_START + 1,
+
+    /* mmc specific cmds */
+    BIO_IOCTL_MMC_IOC_CMD,
+    BIO_IOCTL_MMC_IOC_MULTI_CMD,
+    BIO_IOCTL_MMC_SET_BOOT,
+    BIO_IOCTL_MMC_GET_BOOT,
+};
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/mtk_key.h b/src/bsp/lk/platform/mediatek/common/include/platform/mtk_key.h
new file mode 100644
index 0000000..ab957d0
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/mtk_key.h
@@ -0,0 +1,26 @@
+/*
+ * 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
+
+bool check_download_key(void);
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/pll_common.h b/src/bsp/lk/platform/mediatek/common/include/platform/pll_common.h
new file mode 100644
index 0000000..94b587c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/pll_common.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef SOC_MEDIATEK_PLL_COMMON_H
+#define SOC_MEDIATEK_PLL_COMMON_H
+
+#include <platform/mt_reg_base.h>
+
+#define KHz (1000)
+#define MHz (1000*KHz)
+#define GHz (1000*MHz)
+
+/* These need to be macros for use in static initializers. */
+#define mtk_topckgen ((struct mtk_topckgen_regs *)CKSYS_BASE)
+#define mtk_apmixed  ((struct mtk_apmixed_regs *)APMIXED_BASE)
+
+#define PLL_PWR_ON       (1 << 0)
+#define PLL_EN           (1 << 0)
+#define PLL_ISO          (1 << 1)
+#define PLL_RSTB_SHIFT   (24)
+#define NO_RSTB_SHIFT    (255)
+#define PLL_PCW_CHG      (1 << 31)
+#define PLL_POSTDIV_MASK 0x7
+
+struct mux {
+    void *reg;
+    void *upd_reg;
+    unsigned char mux_shift;
+    unsigned char mux_width;
+    unsigned char upd_shift;
+};
+
+struct pll {
+    void *reg;
+    void *pwr_reg;
+    void *div_reg;
+    void *pcw_reg;
+    const unsigned int *div_rate;
+    unsigned char rstb_shift;
+    unsigned char pcwbits;
+    unsigned char div_shift;
+    unsigned char pcw_shift;
+};
+
+#define PLL(_id, _reg, _pwr_reg, _rstb, _pcwbits, _div_reg, _div_shift, \
+            _pcw_reg, _pcw_shift, _div_rate)                            \
+    [_id] = {                                                           \
+        .reg = &mtk_apmixed->_reg,                                      \
+        .pwr_reg = &mtk_apmixed->_pwr_reg,                              \
+        .rstb_shift = _rstb,                                            \
+        .pcwbits = _pcwbits,                                            \
+        .div_reg = &mtk_apmixed->_div_reg,                              \
+        .div_shift = _div_shift,                                        \
+        .pcw_reg = &mtk_apmixed->_pcw_reg,                              \
+        .pcw_shift = _pcw_shift,                                        \
+        .div_rate = _div_rate,                                          \
+    }
+
+void pll_set_pcw_change(const struct pll *pll);
+void mux_set_sel(const struct mux *mux, unsigned int sel);
+int pll_set_rate(const struct pll *pll, unsigned int rate);
+void mt_pll_init(void);
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/pmic_wrap_common.h b/src/bsp/lk/platform/mediatek/common/include/platform/pmic_wrap_common.h
new file mode 100644
index 0000000..76973ac
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/pmic_wrap_common.h
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+
+#ifndef __PMIC_WRAP_COMMON_H
+#define __PMIC_WRAP_COMMON_H
+
+#include <debug.h>
+
+#define PWRAPTAG                "[PWRAP] "
+#define pwrap_err(fmt, arg ...) dprintf(CRITICAL, PWRAPTAG "ERROR,line=%d" fmt, \
+				       __LINE__, ## arg)
+
+/* external API */
+s32 pwrap_wacs2(u32 write, u16 adr, u16 wdata, u16 *rdata, u32 init_check);
+s32 pwrap_init(void);
+static inline s32 pwrap_read(u16 addr, u16 *rdata)
+{
+	return pwrap_wacs2(0, addr, 0, rdata, 1);
+}
+
+static inline s32 pwrap_write(u16 addr, u16 wdata)
+{
+	return pwrap_wacs2(1, addr, wdata, 0, 1);
+}
+
+static inline u16 pwrap_read_field(u16 reg, u16 mask, u16 shift)
+{
+	u16 rdata;
+
+	pwrap_read(reg, &rdata);
+	rdata &= (mask << shift);
+	rdata = (rdata >> shift);
+
+	return rdata;
+}
+
+static inline void pwrap_write_field(u16 reg, u16 val, u16 mask, u16 shift)
+{
+	u16 old, new;
+
+	pwrap_read(reg, &old);
+	new = old & ~(mask << shift);
+	new |= (val << shift);
+	pwrap_write(reg, new);
+}
+
+/* internal API */
+s32 pwrap_reset_spislv(void);
+
+static inline s32 pwrap_read_nochk(u16 addr, u16 *rdata)
+{
+	return pwrap_wacs2(0, addr, 0, rdata, 0);
+}
+
+static inline s32 pwrap_write_nochk(u16 addr, u16 wdata)
+{
+	return pwrap_wacs2(1, addr, wdata, 0, 0);
+}
+
+/* dewrapper defaule value */
+enum {
+	DEFAULT_VALUE_READ_TEST  = 0x5aa5,
+	WRITE_TEST_VALUE         = 0xa55a
+};
+
+/* timeout setting */
+enum {
+	TIMEOUT_READ_US        = 255,
+	TIMEOUT_WAIT_IDLE_US   = 255
+};
+
+/* manual commnd */
+enum {
+	OP_WR    = 0x1,
+	OP_CSH   = 0x0,
+	OP_CSL   = 0x1,
+	OP_OUTS  = 0x8,
+};
+
+enum {
+	RDATA_WACS_RDATA_SHIFT = 0,
+	RDATA_WACS_FSM_SHIFT   = 16,
+	RDATA_WACS_REQ_SHIFT   = 19,
+	RDATA_SYNC_IDLE_SHIFT,
+	RDATA_INIT_DONE_SHIFT,
+	RDATA_SYS_IDLE_SHIFT,
+};
+
+enum {
+	RDATA_WACS_RDATA_MASK = 0xffff,
+	RDATA_WACS_FSM_MASK   = 0x7,
+	RDATA_WACS_REQ_MASK   = 0x1,
+	RDATA_SYNC_IDLE_MASK  = 0x1,
+	RDATA_INIT_DONE_MASK  = 0x1,
+	RDATA_SYS_IDLE_MASK   = 0x1,
+};
+
+/* WACS_FSM */
+enum {
+	WACS_FSM_IDLE     = 0x00,
+	WACS_FSM_REQ      = 0x02,
+	WACS_FSM_WFDLE    = 0x04, /* wait for dle, wait for read data done */
+	WACS_FSM_WFVLDCLR = 0x06, /* finish read data, wait for valid flag
+				   * clearing */
+	WACS_INIT_DONE    = 0x01,
+	WACS_SYNC_IDLE    = 0x01,
+	WACS_SYNC_BUSY    = 0x00
+};
+
+enum {
+	RDATA_WRAP_CH_DLE_RESTCNT_SHIFT = 0,
+	RDATA_WRAP_FSM_SHIFT            = 11,
+};
+
+enum {
+	RDATA_WRAP_CH_DLE_RESTCNT_MASK = 0x7,
+	RDATA_WRAP_FSM_MASK            = 0xf,
+};
+
+enum {
+	WRAP_IDLE = 0x0,
+};
+
+/* error information flag */
+enum {
+	E_PWR_INVALID_ARG             = 1,
+	E_PWR_INVALID_RW              = 2,
+	E_PWR_INVALID_ADDR            = 3,
+	E_PWR_INVALID_WDAT            = 4,
+	E_PWR_INVALID_OP_MANUAL       = 5,
+	E_PWR_NOT_IDLE_STATE          = 6,
+	E_PWR_NOT_INIT_DONE           = 7,
+	E_PWR_NOT_INIT_DONE_READ      = 8,
+	E_PWR_WAIT_IDLE_TIMEOUT       = 9,
+	E_PWR_WAIT_IDLE_TIMEOUT_READ  = 10,
+	E_PWR_INIT_SIDLY_FAIL         = 11,
+	E_PWR_RESET_TIMEOUT           = 12,
+	E_PWR_TIMEOUT                 = 13,
+	E_PWR_INIT_RESET_SPI          = 20,
+	E_PWR_INIT_SIDLY              = 21,
+	E_PWR_INIT_REG_CLOCK          = 22,
+	E_PWR_INIT_ENABLE_PMIC        = 23,
+	E_PWR_INIT_DIO                = 24,
+	E_PWR_INIT_CIPHER             = 25,
+	E_PWR_INIT_WRITE_TEST         = 26,
+	E_PWR_INIT_ENABLE_CRC         = 27,
+	E_PWR_INIT_ENABLE_DEWRAP      = 28,
+	E_PWR_INIT_ENABLE_EVENT       = 29,
+	E_PWR_READ_TEST_FAIL          = 30,
+	E_PWR_WRITE_TEST_FAIL         = 31,
+	E_PWR_SWITCH_DIO              = 32
+};
+
+typedef u32 (*loop_condition_fp)(u32);
+
+static inline u32 wait_for_fsm_vldclr(u32 x)
+{
+	return ((x >> RDATA_WACS_FSM_SHIFT) & RDATA_WACS_FSM_MASK) !=
+		WACS_FSM_WFVLDCLR;
+}
+
+static inline u32 wait_for_sync(u32 x)
+{
+	return ((x >> RDATA_SYNC_IDLE_SHIFT) & RDATA_SYNC_IDLE_MASK) !=
+		WACS_SYNC_IDLE;
+}
+
+static inline u32 wait_for_idle_and_sync(u32 x)
+{
+	return ((((x >> RDATA_WACS_FSM_SHIFT) & RDATA_WACS_FSM_MASK) !=
+		WACS_FSM_IDLE) || (((x >> RDATA_SYNC_IDLE_SHIFT) &
+		RDATA_SYNC_IDLE_MASK) != WACS_SYNC_IDLE));
+}
+
+static inline u32 wait_for_wrap_idle(u32 x)
+{
+	return ((((x >> RDATA_WRAP_FSM_SHIFT) & RDATA_WRAP_FSM_MASK) !=
+		WRAP_IDLE) || (((x >> RDATA_WRAP_CH_DLE_RESTCNT_SHIFT) &
+		RDATA_WRAP_CH_DLE_RESTCNT_MASK) != WRAP_IDLE));
+}
+
+static inline u32 wait_for_cipher_ready(u32 x)
+{
+	return x != 3;
+}
+
+u32 wait_for_state_idle(u32 timeout_us, void *wacs_register,
+			void *wacs_vldclr_register, u32 *read_reg);
+
+u32 wait_for_state_ready(loop_condition_fp fp, u32 timeout_us,
+			 void *wacs_register, u32 *read_reg);
+
+#endif /* __PMIC_WRAP_COMMON_H */
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/psci.h b/src/bsp/lk/platform/mediatek/common/include/platform/psci.h
new file mode 100644
index 0000000..380305d
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/psci.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 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 <sys/types.h>
+
+/* PSCI v1.0 error code from section 5.2.2 */
+enum {
+    E_PSCI_SUCCESS              = 0,
+    E_PSCI_NOT_SUPPORTED        = -1,
+    E_PSCI_INVALID_PARAMETERS   = -2,
+    E_PSCI_DENIED               = -3,
+    E_PSCI_ALREADY_ON           = -4,
+    E_PSCI_ON_PENDING           = -5,
+    E_PSCI_INTERNAL_FAILURE     = -6,
+    E_PSCI_NOT_PRESENT          = -7,
+    E_PSCI_DISABLED             = -8,
+    E_PSCI_INVALID_ADDRESS      = -9,
+};
+
+/*
+ * power on target cpu
+ *
+ * param
+ *      - target_cpu: the cpu to be powered on
+ *      - ep: entrypoint of the target_cpu
+ *      - context_id: 32 bits for SMC32 and 64 bits for SMC64. When the
+ *                    target_cpu first enters the return non-secure exception
+ *                    level, this value must be presented in X0 or R0.
+ * return
+ *      - E_PSCI_SUCCESS on sucess,
+ *      - other error code on failure
+ */
+int psci_cpu_on(ulong target_cpu, ulong ep, ulong context_id);
+
+/*
+ * power down the calling cpu
+ *
+ * return
+ *      - doesn't return on success,
+ *      - E_PSCI_DENIED on failure
+ */
+int psci_cpu_off(void);
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/reg_utils.h b/src/bsp/lk/platform/mediatek/common/include/platform/reg_utils.h
new file mode 100644
index 0000000..8067854
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/reg_utils.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 <reg.h>
+
+#define clrbits32(addr, clr_bits)   writel(readl(addr) & (~clr_bits), (addr))
+#define setbits32(addr, set_bits)   writel(readl(addr) | (set_bits), (addr))
+#define clrsetbits32(addr, clr_bits, set_bits) \
+    writel((readl(addr) & (~clr_bits)) | (set_bits), (addr))
+
+/* value first style for backward compatibility */
+#define clrbits32_r(clr_bits, addr) clrbits32(addr, clr_bits)
+#define setbits32_r(set_bits, addr) setbits32(addr, set_bits)
+
+#define writel_r(a, v) writel(v, a)
+
+#define writew(v, a)    (*REG16(a) = (v))
+#define readw(a)        (*REG16(a))
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/regulator.h b/src/bsp/lk/platform/mediatek/common/include/platform/regulator.h
new file mode 100644
index 0000000..3fded8e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/regulator.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#ifndef __REGULATOR_H
+#define __REGULATOR_H
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+struct mtk_regulator {
+    const char *name;
+    unsigned char id;
+    struct regulator_ctrl *reg_ops;
+};
+
+enum {
+    REGULATOR_MODE_FAST,
+    REGULATOR_MODE_NORMAL,
+};
+
+enum {
+    EPERM = 1,    /* Operation not permitted */
+    EIO = 5,      /* I/O error */
+    ENXIO = 6,    /* No such device or address */
+    ENOMEM = 12,  /* Out of memory */
+    EBUSY = 16,   /* Device or resource busy */
+    ENODEV = 19,  /* No such device */
+    EINVAL = 22,  /* Invalid argument */
+};
+
+typedef enum {
+	VOLTOSEL,
+	SELTOVOL,
+} volseltran;
+
+typedef enum {
+	TRIMTOSEL,
+	SELTOTRIM,
+} trimseltran;
+
+typedef enum {
+	NON_REGULAR_VOLTAGE,
+	FIXED_REGULAR_VOLTAGE,
+	REGULAR_VOLTAGE,
+} regulator_type;
+
+struct mt6358_ldo_trim_info {
+	unsigned short trim_reg;
+	unsigned short trim_mask;
+	unsigned short trim_shift;
+	const void *trim_voltages;
+	unsigned int trim_size;
+};
+
+struct mt6358_ldo_info {
+	const void *pvoltages;
+	const void *idxs;
+	unsigned int n_size;
+};
+
+struct mt6358_regulator_info {
+	unsigned int min_uV;
+	unsigned int max_uV;
+	unsigned short vol_reg;
+	unsigned short vol_mask;
+	unsigned short vol_shift;
+	unsigned short da_vol_reg;
+	unsigned short da_vol_mask;
+	unsigned short da_vol_shift;
+	unsigned short enable_reg;
+	unsigned short enable_shift;
+	unsigned short mode_reg;
+	unsigned short mode_shift;
+	struct mt6358_ldo_info *extinfo;
+	struct mt6358_ldo_trim_info *triminfo;
+	unsigned short step_uV;
+	regulator_type rtype;
+};
+
+extern int mtk_regulator_get(const char *id, struct mtk_regulator *mreg);
+extern int mtk_regulator_enable(struct mtk_regulator *mreg, unsigned char enable);
+extern int mtk_regulator_is_enabled(struct mtk_regulator *mreg);
+extern int mtk_regulator_set_voltage(struct mtk_regulator *mreg, int min_uv, int max_uv);
+extern int mtk_regulator_get_voltage(struct mtk_regulator *mreg);
+extern int mtk_regulator_set_mode(struct mtk_regulator *mreg, unsigned char mode);
+extern int mtk_regulator_get_mode(struct mtk_regulator *mreg);
+extern int mtk_regulator_set_votrim(struct mtk_regulator *mreg, int trim_uv);
+extern int mtk_regulator_get_votrim(struct mtk_regulator *mreg);
+
+#endif /* __REGULATOR_H */
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/rtc_common.h b/src/bsp/lk/platform/mediatek/common/include/platform/rtc_common.h
new file mode 100644
index 0000000..310b943
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/rtc_common.h
@@ -0,0 +1,155 @@
+/*
+ * 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 <debug.h>
+#include <platform/pmic_wrap_common.h>
+
+#define RTCTAG          "[RTC] "
+#define rtc_info(fmt, arg ...) dprintf(CRITICAL, RTCTAG "%s,%d: " fmt, \
+                 __func__, __LINE__, ## arg)
+
+#define udelay(x) spin(x)
+#define mdelay(x) udelay((x) * 1000)
+
+struct rtc_time {
+    int sec;
+    int min;
+    int hour;
+    int mday;
+    int mon;
+    int year;
+    int wday;
+};
+
+/*
+ * Default values for RTC initialization
+ * Year (YEA)        : 1970 ~ 2037
+ * Month (MTH)       : 1 ~ 12
+ * Day of Month (DOM): 1 ~ 31
+ */
+
+enum {
+    RTC_DEFAULT_YEA = 2010,
+    RTC_DEFAULT_MTH = 1,
+    RTC_DEFAULT_DOM = 1,
+    RTC_DEFAULT_DOW = 5
+};
+
+enum {
+    RTC_2SEC_REBOOT_ENABLE  = 1,
+    RTC_2SEC_MODE   = 2
+};
+
+enum {
+    RTC_OSC32CON_UNLOCK1 = 0x1A57,
+    RTC_OSC32CON_UNLOCK2 = 0x2B68
+};
+
+enum {
+    RTC_PROT_UNLOCK1 = 0x586A,
+    RTC_PROT_UNLOCK2 = 0x9136
+};
+
+enum {
+    RTC_BBPU_KEY    = 0x43 << 8
+};
+
+enum {
+    RTC_IRQ_STA_AL  = 1U << 0,
+    RTC_IRQ_STA_TC  = 1U << 1,
+    RTC_IRQ_STA_LP  = 1U << 3
+};
+
+enum {
+    RTC_IRQ_EN_AL       = 1U << 0,
+    RTC_IRQ_EN_TC       = 1U << 1,
+    RTC_IRQ_EN_ONESHOT  = 1U << 2,
+    RTC_IRQ_EN_LP       = 1U << 3,
+    RTC_IRQ_EN_ONESHOT_AL   = RTC_IRQ_EN_ONESHOT | RTC_IRQ_EN_AL
+};
+
+enum {
+    RTC_POWERKEY1_KEY   = 0xA357,
+    RTC_POWERKEY2_KEY   = 0x67D2
+};
+
+enum {
+    RTC_SPAR0_32K_LESS  = 1U << 6
+};
+
+enum {
+    RTC_MIN_YEAR    = 1968,
+    RTC_BASE_YEAR   = 1900,
+    RTC_MIN_YEAR_OFFSET = RTC_MIN_YEAR - RTC_BASE_YEAR,
+
+    RTC_NUM_YEARS   = 128
+};
+
+enum {
+    RTC_STATE_REBOOT    = 0,
+    RTC_STATE_RECOVER   = 1,
+    RTC_STATE_INIT      = 2
+};
+
+/* RTC error code */
+enum {
+    RTC_STATUS_OK   = 0,
+    RTC_STATUS_POWERKEY_INIT_FAIL,
+    RTC_STATUS_WRITEIF_UNLOCK_FAIL,
+    RTC_STATUS_OSC_SETTING_FAIL,
+    RTC_STATUS_GPIO_INIT_FAIL,
+    RTC_STATUS_HW_INIT_FAIL,
+    RTC_STATUS_REG_INIT_FAIL,
+    RTC_STATUS_LPD_INIT_FAIL
+};
+
+/* external API */
+int rtc_busy_wait(void);
+int rtc_write_trigger(void);
+int rtc_writeif_unlock(void);
+int rtc_xosc_write(u16 val);
+int rtc_reg_init(void);
+void rtc_boot_common(void);
+
+static inline s32 rtc_read(u16 addr, u16 *rdata)
+{
+    s32 ret;
+
+    ret = pwrap_read(addr, rdata);
+    if (ret < 0)
+        rtc_info("pwrap_read fail: ret=%d\n", ret);
+
+    return ret;
+}
+
+static inline s32 rtc_write(u16 addr, u16 wdata)
+{
+    s32 ret;
+
+    ret = pwrap_write(addr, wdata);
+    if (ret < 0)
+        rtc_info("pwrap_write fail: ret=%d\n", ret);
+
+    return ret;
+}
diff --git a/src/bsp/lk/platform/mediatek/common/include/platform/smc.h b/src/bsp/lk/platform/mediatek/common/include/platform/smc.h
new file mode 100644
index 0000000..22bc9e1
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/platform/smc.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 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 <sys/types.h>
+
+struct __smccc_res {
+    ulong a0;
+    ulong a1;
+    ulong a2;
+    ulong a3;
+};
+
+void __smc_pipe(size_t smc_id, ulong arg0, ulong arg1, ulong arg2, ulong arg3,
+                struct __smccc_res *res);
diff --git a/src/bsp/lk/platform/mediatek/common/include/profiling.h b/src/bsp/lk/platform/mediatek/common/include/profiling.h
new file mode 100644
index 0000000..1fa4c3c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/include/profiling.h
@@ -0,0 +1,19 @@
+/*

+ * Copyright (c) 2020 MediaTek Inc.

+ *

+ * Use of this source code is governed by a MIT-style

+ * license that can be found in the LICENSE file or at

+ * https://opensource.org/licenses/MIT

+ */

+

+#include <platform.h>

+#include <stdio.h>

+#include <stdlib.h>

+

+#define PROFILING(func) do { \

+        lk_bigtime_t __timer; \

+        __timer = current_time_hires(); \

+        func; \

+        __timer = current_time_hires() - __timer; \

+        dprintf(ALWAYS,"%s execution time: %llu (us). \n", #func, __timer); \

+} while(0)

diff --git a/src/bsp/lk/platform/mediatek/common/interrupts.c b/src/bsp/lk/platform/mediatek/common/interrupts.c
new file mode 100644
index 0000000..e0cd297
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/common/interrupts.c
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include <debug.h>
+#include <kernel/thread.h>
+#include <platform/interrupts.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mt_irq.h>
+#include <platform/reg_utils.h>
+
+/* set for mt_gic */
+void mt_irq_set_polarity(unsigned int irq, unsigned int polarity)
+{
+    unsigned int offset;
+    unsigned int reg_index;
+    unsigned int value;
+
+    /* peripheral device's IRQ line is using GIC's SPI, and line ID >= GIC_PRIVATE_SIGNALS */
+    if (irq < GIC_PRIVATE_SIGNALS) {
+        dprintf(SPEW, "The Interrupt ID < 32, please check!\n");
+        return;
+    }
+
+    offset = (irq - GIC_PRIVATE_SIGNALS) & 0x1F;
+    reg_index = (irq - GIC_PRIVATE_SIGNALS) >> 5;
+    if (polarity == 0) {
+        value = readl(INT_POL_CTL0 + (reg_index * 4));
+        value |= (1 << offset); /* always invert the incoming IRQ's polarity */
+        writel_r((INT_POL_CTL0 + (reg_index * 4)), value);
+    } else {
+        value = readl(INT_POL_CTL0 + (reg_index * 4));
+        value &= ~(0x1 << offset);
+        writel_r(INT_POL_CTL0 + (reg_index * 4), value);
+    }
+}
+
+/* set for arm gic */
+void mt_irq_set_sens(unsigned int irq, unsigned int sens)
+{
+    unsigned int config;
+
+    if (sens == EDGE_SENSITIVE) {
+        config = readl(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
+        config |= (0x2 << (irq % 16) * 2);
+        writel_r(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4, config);
+    } else {
+        config = readl(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
+        config &= ~(0x2 << (irq % 16) * 2);
+        writel_r( GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4, config);
+    }
+    DSB;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/bl2_bl33_options.mk b/src/bsp/lk/platform/mediatek/mt2712/bl2_bl33_options.mk
new file mode 100644
index 0000000..dac1fe8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/bl2_bl33_options.mk
@@ -0,0 +1,103 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+# SCP config
+ENABLE_SCP_LOAD ?= 0
+ENABLE_SCP_AUX_LOAD ?= 0
+
+ifeq ($(MTK_TINYSYS_SCP_SUPPORT),1)
+ENABLE_SCP_LOAD := 1
+ENABLE_SCP_AUX_LOAD := 1
+endif
+
+ifeq ($(MTK_TINYSYS_SCP_FUNCTION_SAFETY),1)
+ENABLE_SCP_LOAD := 1
+endif
+
+ifeq ($(LK_AS_BL33),1)
+# LK build as BL33
+
+# memory setting
+MEMBASE ?= 0x73500000
+KERNEL_LOAD_OFFSET ?= 0x0
+MEMSIZE ?= 0x100000 # 1MB
+
+ifeq ($(WITH_KERNEL_VM),1)
+KERNEL_BASE ?= 0xfffffff073500000   # KERNEL_ASPACE_BASE + MEMBASE
+else
+KERNEL_BASE ?= 0x73500000
+endif
+
+# image load options
+ENABLE_TZ_LOAD := 0                 # bl33 doesnt' load tz
+ENABLE_BL33_LOAD := 0               # bl33 doesn't load itself
+ENABLE_KERNEL_LOAD := 1             # bl33 loads kernel and dtbo
+ENABLE_SLAVE_CPU_LOAD ?= 0          # bl33 doesn't load slave cpu by default
+
+# bl33 boot options
+BL33_BOOT_NEXT_64BITS ?= 1          # boot stage after bl33 is 64 bits
+
+# fastboot mode option
+OPTION_CLEAR_FASTBOOT_FLAG ?= 1
+
+# recovery mode option
+OPTION_CLEAR_RECOVERY_FLAG ?= 1
+
+MODULE_SRCS += $(LOCAL_DIR)/platform_bl33.c
+
+GLOBAL_DEFINES += \
+    BL33_BOOT_NEXT_64BITS=$(BL33_BOOT_NEXT_64BITS)
+
+else
+
+# LK build as BL2
+
+# memory setting
+MEMBASE ?= 0x200000
+KERNEL_LOAD_OFFSET ?= 0x1000
+MEMSIZE ?= 0x40000 # 256KB
+
+ifeq ($(WITH_KERNEL_VM),1)
+KERNEL_BASE ?= 0xfffffff000200000   # KERNEL_ASPACE_BASE + MEMBASE
+else
+KERNEL_BASE ?= 0x200000             # KERNEL_ASPACE_BASE + MEMBASE
+endif
+
+# dram calibration setting
+DRAM_SZ ?= DRAM_SZ_AUTO             # DRAM_SZ_2G, DRAM_SZ_3G, DRAM_SZ_AUTO
+DRAM_BW ?= DRAM_BW_AUTO             # DRAM_BW_32BIT, DRAM_BW_64BIT, DRAM_BW_AUTO
+
+# image load options
+ENABLE_TZ_LOAD := 1                 # loads tz
+ENABLE_BL33_LOAD := 1
+ENABLE_BUILTIN_BL33 ?= 1            # default use builtin 'do-nothing-but-jump' bl33
+ifeq ($(ENABLE_BUILTIN_BL33),1)
+ENABLE_KERNEL_LOAD := 1             # if builtin bl33, bl2 also loads kernel (& dtbo)
+OPTION_CLEAR_FASTBOOT_FLAG ?= 1
+OPTION_CLEAR_RECOVERY_FLAG ?= 1
+else
+ENABLE_KERNEL_LOAD := 0
+OPTION_CLEAR_FASTBOOT_FLAG ?= 0
+OPTION_CLEAR_RECOVERY_FLAG ?= 0
+endif
+ENABLE_SLAVE_CPU_LOAD ?= 0          # bl2 doesn't load slave cpu image
+
+MODULE_SRCS += $(LOCAL_DIR)/platform_bl2.c
+
+GLOBAL_DEFINES += \
+    $(DRAM_SZ) \
+    $(DRAM_BW) \
+    ENABLE_BUILTIN_BL33=$(ENABLE_BUILTIN_BL33)
+
+endif
+
+GLOBAL_DEFINES += \
+    MEMBASE=$(MEMBASE) \
+    MEMSIZE=$(MEMSIZE) \
+    ENABLE_TZ_LOAD=$(ENABLE_TZ_LOAD) \
+    ENABLE_BL33_LOAD=$(ENABLE_BL33_LOAD) \
+    ENABLE_KERNEL_LOAD=$(ENABLE_KERNEL_LOAD) \
+    OPTION_CLEAR_FASTBOOT_FLAG=$(OPTION_CLEAR_FASTBOOT_FLAG) \
+    OPTION_CLEAR_RECOVERY_FLAG=$(OPTION_CLEAR_RECOVERY_FLAG) \
+    ENABLE_SLAVE_CPU_LOAD=$(ENABLE_SLAVE_CPU_LOAD) \
+    ENABLE_SCP_LOAD=$(ENABLE_SCP_LOAD) \
+    ENABLE_SCP_AUX_LOAD=$(ENABLE_SCP_AUX_LOAD)
diff --git a/src/bsp/lk/platform/mediatek/mt2712/boot_mode.c b/src/bsp/lk/platform/mediatek/mt2712/boot_mode.c
new file mode 100644
index 0000000..ad8731a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/boot_mode.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+#if BCB_RECOVERY_SUPPORT
+#include <boot_mode.h>
+#include <lib/bio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <platform/mtk_wdt.h>
+
+/*
+ * BCB = bootloader control block
+ * Offset 0 ~ 2KB of BCB_PARTITION stored the BCB message struct
+ */
+#define BCB_PARTITION   "misc"
+
+struct bcb_msg {
+    char command[32];
+    char status[32];
+    char recovery[1024];
+    char reserved[960];
+};
+
+static const char cmd_recovery[] = "boot-recovery";
+static const char cmd_fastboot[] = "boot-fastboot";
+
+static bool check_bcb_recovery_mode(void)
+{
+    bdev_t *dev;
+    ssize_t bytes_read;
+    struct bcb_msg *msg;
+    bool ret = false;
+
+    dev = bio_open_by_label(BCB_PARTITION);
+    if (!dev)
+        goto err_exit;
+
+    msg = (struct bcb_msg *)malloc(sizeof(struct bcb_msg));
+    if (!msg)
+        goto err_close_dev;
+
+    bytes_read = bio_read(dev, msg, 0, sizeof(struct bcb_msg));
+    if ((size_t)bytes_read < sizeof(struct bcb_msg))
+        goto err_free_mem;
+
+    if ((strncmp(msg->command, cmd_recovery, strlen(cmd_recovery)) == 0) ||
+        (strncmp(msg->command, cmd_fastboot, strlen(cmd_fastboot)) == 0))
+        ret = true;
+
+err_free_mem:
+    free(msg);
+    msg = NULL;
+
+err_close_dev:
+    bio_close(dev);
+
+err_exit:
+    return ret;
+}
+
+static bool write_bcb_fastbootd_mode(void)
+{
+    bdev_t *dev;
+    ssize_t bytes_read;
+    ssize_t bytes_write;
+    ssize_t erase_size;
+    struct bcb_msg *msg;
+    bool ret = false;
+    int ret_erase;
+
+    dev = bio_open_by_label(BCB_PARTITION);
+    if (!dev)
+        goto err_exit;
+
+    ASSERT(dev->geometry != NULL);
+    erase_size = (size_t)dev->geometry->erase_size;
+
+    msg = (struct bcb_msg *)malloc(erase_size);
+    if (!msg)
+        goto err_close_dev;
+
+    bytes_read = bio_read(dev, msg, 0, erase_size);
+    if ((size_t)bytes_read < erase_size)
+        goto err_free_mem;
+
+    memset(msg->command, 0, strlen(cmd_fastboot) + 1);
+    strncpy(msg->command, cmd_fastboot, strlen(cmd_fastboot));
+
+    ret_erase = bio_erase(dev, 0, erase_size);
+    if (ret_erase < 0)
+        goto err_free_mem;
+
+    bytes_write = bio_write(dev, msg, 0, erase_size);
+    if ((size_t)bytes_write < erase_size)
+        goto err_free_mem;
+    ret = true;
+
+err_free_mem:
+    free(msg);
+    msg = NULL;
+
+err_close_dev:
+    bio_close(dev);
+
+err_exit:
+    return ret;
+}
+
+uint32_t plat_get_boot_mode(void)
+{
+    if (check_fastbootd_mode())
+    {
+        set_clr_fastbootd_mode(false);
+        write_bcb_fastbootd_mode();
+    }
+    return check_bcb_recovery_mode() ? RECOVERY_BOOT : NORMAL_BOOT;
+}
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/audio/audio_clk_enable.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/audio/audio_clk_enable.c
new file mode 100644
index 0000000..6634bdd
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/audio/audio_clk_enable.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2018 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 <reg.h>
+#include <platform/audio_clk_enable.h>
+#include <platform/pll.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+#ifndef LK_ENABLE_AUDIO_CLK
+
+void mt_audio_clk_enable(void)
+{
+    return;
+}
+
+#else
+
+static uintptr_t g_afe_enable_reg[] = {
+    ASYS_TOP_CON,
+    AFE_DAC_CON0
+};
+
+static uint32_t g_afe_enable_val[] = {
+    0x00000003U,
+    0x00000001U,
+};
+
+static uintptr_t g_clk_enable_reg[] = {
+    AUDIO_TOP_CON4,
+};
+
+static uint32_t g_clk_enable_val[] = {
+#if LK_ENABLE_I2S_SEP_CLK
+    0xff1fffbfU,
+#elif LK_ENABLE_I2S_COCLK
+    0xff1fffbeU,
+#else
+    0xff1fffffU,
+#endif
+};
+
+#if ENABLE_TDM_CLK
+#if LK_ENABLE_TDM_SEP_CLK
+static uintptr_t g_tdm_enable_reg[] = {
+    AUDIO_TOP_CON1,
+    AUDIO_TOP_CON2,
+    AFE_TDM_G1_CON1,
+    AFE_TDM_G1_CON2,
+    AFE_TDM_G1_CON1
+};
+static uint32_t g_tdm_enable_val[] = {
+    0x0f000000U,
+    0x00000f02U,
+    0x0fbfab1aU,
+    0xa500ff40U,
+    0x0fbfab1bU
+};
+#elif LK_ENABLE_TDM_COCLK
+static uintptr_t g_tdm_enable_reg[] = {
+    AUDIO_TOP_CON1,
+    AUDIO_TOP_CON2,
+    AFE_TDM_G1_CON1,
+    AFE_TDM_G1_CON2,
+    AFE_TDM_IN_CON1,
+    AFE_TDM_IN_CON2,
+    AFE_TDM_G1_CON1,
+    AFE_TDM_IN_CON1
+};
+static uint32_t g_tdm_enable_val[] = {
+    0x0f000000U,
+    0x00000f02U,
+    0x0fbfab0aU,
+    0xa500ff40U,
+    0x0fa6230aU,
+    0x00000000U,
+    0x0fbfab0bU,
+    0x0fa6230bU
+};
+#endif
+#endif
+
+#if ENABLE_I2S_CLK
+#if LK_ENABLE_I2S_SEP_CLK
+static uintptr_t g_i2s_enable_reg[] = {
+    ASYS_I2SO1_CON,
+    ASMO_TIMING_CON1,
+    ASYS_I2SO1_CON
+};
+
+static uint32_t g_i2s_enable_val[] = {
+    0x0000050aU,
+    0x00000005U,
+    0x0000050bU
+};
+#elif LK_ENABLE_I2S_COCLK
+static uintptr_t g_i2s_enable_reg[] = {
+    ASYS_I2SO1_CON,
+    ASMO_TIMING_CON1,
+    ASYS_I2SIN1_CON,
+    ASMI_TIMING_CON1,
+    ASYS_I2SO1_CON,
+    ASYS_I2SIN1_CON
+};
+
+static uint32_t g_i2s_enable_val[] = {
+    0x0000050aU,
+    0x00000005U,
+    0x8000850aU,
+    0x00000005U,
+    0x0000050bU,
+    0x8000850bU,
+};
+#endif
+#endif
+
+#ifdef LK_AUDIO_USE_EXT_CLK
+static uintptr_t g_set_apll_src_reg[] = {
+    PLL_TEST_CON0,
+    AP_PLL_CON5,
+    APLL1_CON0,
+    APLL1_CON1,
+    APLL1_CON2,
+    APLL1_CON1,
+    APLL2_CON0,
+    APLL2_CON1,
+    APLL2_CON2,
+    APLL2_CON1,
+    AP_PLL_CON5,
+};
+
+static uint32_t g_set_apll_src_val[] = {
+    0x00060000U,
+    0x00000000U,
+    0x00000030U,
+    0x40000000U,
+    0x40000001U,
+    0x80000000U,
+    0x00000030U,
+    0x3ACCCCCCU,
+    0x3ACCCCCDU,
+    0x80000000U,
+    0x00000003U,
+};
+
+static uint32_t g_set_apll_src_mask[] = {
+    0x00060000U,
+    0x00000003U,
+    0x00000070U,
+    0xFFFFFFFFU,
+    0xFFFFFFFFU,
+    0x80000000U,
+    0x00000070U,
+    0xFFFFFFFFU,
+    0xFFFFFFFFU,
+    0x80000000U,
+    0x00000003U,
+};
+#endif
+
+void audio_set_reg_addr_val_mask(uintptr_t addr, uint32_t val, uint32_t mask)
+{
+    volatile uint32_t val_orig = audio_get_reg(addr);
+    volatile uint32_t val_to_write = (val_orig & (~mask)) | (val & mask);
+
+    audio_set_reg_addr_val(addr, val_to_write);
+}
+
+void write_reg_seq(uintptr_t *reg_arr, uint32_t *val_arr, size_t size)
+{
+    size_t i;
+    for (i=0; i<size; ++i) {
+        audio_set_reg_addr_val(reg_arr[i], val_arr[i]);
+    }
+}
+
+void write_reg_seq_with_mask(uintptr_t *reg_arr, uint32_t *val_arr,
+                             uint32_t *mask_arr, size_t size)
+{
+    size_t i;
+    for (i=0; i<size; ++i) {
+        audio_set_reg_addr_val_mask(reg_arr[i], val_arr[i], mask_arr[i]);
+    }
+}
+
+void mt_audio_clk_enable(void)
+{
+
+    LTRACEF("open clk start time tag %u\n",
+            audio_get_reg(IO_PHYS + 0x0000c008));
+
+#ifdef LK_AUDIO_USE_EXT_CLK
+    /* Set gpio here (GPIO186 set to mode 1) for EXT_CLK 1  */
+    LTRACEF("Set gpio (GPIO186 set to mode 1) for EXT_CLK 1\n");
+    audio_set_reg_addr_val_mask(IO_PHYS + 0x00005750, 0x00000008, 0x00000038);
+
+    /* Set rate & external source for apll1/apll2 */
+    write_reg_seq_with_mask(g_set_apll_src_reg,
+        g_set_apll_src_val, g_set_apll_src_mask,
+        sizeof(g_set_apll_src_reg) / sizeof(g_set_apll_src_reg[0]));
+
+#endif
+
+    /* set ccf clk to right value which is not the same with default */
+    audio_set_reg_addr_val_mask(CLK_CFG_12, 0x01000001, 0x03000003);
+    audio_set_reg_addr_val_mask(CLK_AUDDIV_1, 0x0F00003F, 0xFF0000FF);
+    audio_set_reg_addr_val_mask(CLK_CFG_10, 0x03000000, 0x07000000);
+    audio_set_reg_addr_val_mask(CLK_CFG_11, 0x00000003, 0x00000007);
+
+    /* enable clks in ccf */
+    audio_set_reg_addr_val_mask(CLK_CFG_12, 0x0, 0x80000008);
+    audio_set_reg_addr_val_mask(CLK_CFG_10, 0x0, 0x80808000);
+    audio_set_reg_addr_val_mask(CLK_CFG_11, 0x0, 0x00000080);
+    audio_set_reg_addr_val_mask(CLK_CFG_4, 0x0, 0x80000000);
+
+#if ENABLE_TDM_CLK
+    /* Set gpio here (GPIO200~GPIO203 set to mode 1) for TDM out */
+    LTRACEF("Set gpio (GPIO200~GPIO203 set to mode 1) for TDM out\n");
+    audio_set_reg_addr_val_mask(IO_PHYS + 0x00005780, 0x00000249, 0x00000FFF);
+#endif
+
+#if ENABLE_I2S_CLK
+    /* Set gpio here (GPIO192~GPIO195 set to mode 1) for I2S out */
+    LTRACEF("Set gpio (GPIO192~GPIO195 set to mode 1) for I2S out\n");
+    audio_set_reg_addr_val_mask(IO_PHYS + 0x00005760, 0x00001240, 0x00007FC0);
+    audio_set_reg_addr_val_mask(IO_PHYS + 0x00005770, 0x00000001, 0x00000007);
+#endif
+
+    write_reg_seq(g_afe_enable_reg, g_afe_enable_val,
+                  sizeof(g_afe_enable_reg) / sizeof(g_afe_enable_reg[0]));
+    write_reg_seq(g_clk_enable_reg, g_clk_enable_val,
+                  sizeof(g_clk_enable_reg) / sizeof(g_clk_enable_reg[0]));
+#if ENABLE_TDM_CLK
+    write_reg_seq(g_tdm_enable_reg, g_tdm_enable_val,
+                  sizeof(g_tdm_enable_reg) / sizeof(g_tdm_enable_reg[0]));
+#endif
+
+#if ENABLE_I2S_CLK
+    write_reg_seq(g_i2s_enable_reg, g_i2s_enable_val,
+                  sizeof(g_i2s_enable_reg) / sizeof(g_i2s_enable_reg[0]));
+#endif
+    LTRACEF("open clk end time tag %u\n",
+            audio_get_reg(IO_PHYS + 0x0000c008));
+}
+
+#endif //LK_ENABLE_AUDIO_CLK
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/audio/include/platform/audio_clk_enable.h b/src/bsp/lk/platform/mediatek/mt2712/drivers/audio/include/platform/audio_clk_enable.h
new file mode 100644
index 0000000..27b3ab8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/audio/include/platform/audio_clk_enable.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 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 <platform/mt_reg_base.h>
+#define AFE_REG_BASE (IO_PHYS + 0x01220000)
+
+#define AUDIO_TOP_CON0 (AFE_REG_BASE + 0x0000U)
+#define AUDIO_TOP_CON1 (AFE_REG_BASE + 0x0004U)
+#define AUDIO_TOP_CON2 (AFE_REG_BASE + 0x0008U)
+#define AUDIO_TOP_CON4 (AFE_REG_BASE + 0x0010U)
+#define ASMI_TIMING_CON1 (AFE_REG_BASE + 0x0100U)
+#define ASMO_TIMING_CON1 (AFE_REG_BASE + 0x0104U)
+#define AFE_TDM_G1_CON1 (AFE_REG_BASE + 0x0290U)
+#define AFE_TDM_G1_CON2 (AFE_REG_BASE + 0x0294U)
+#define AFE_TDM_G2_CON1 (AFE_REG_BASE + 0x02a0U)
+#define AFE_TDM_G2_CON2 (AFE_REG_BASE + 0x02a4U)
+#define AFE_TDM_IN_CON1 (AFE_REG_BASE + 0x02b8U)
+#define AFE_TDM_IN_CON2 (AFE_REG_BASE + 0x02bcU)
+#define ASYS_TOP_CON (AFE_REG_BASE + 0x0600U)
+#define ASYS_I2SIN1_CON (AFE_REG_BASE + 0x0604U)
+#define ASYS_I2SO1_CON (AFE_REG_BASE + 0x061cU)
+#define AFE_DAC_CON0 (AFE_REG_BASE + 0x1200U)
+
+#define AFE_SGEN_CON0 (AFE_REG_BASE + 0x01f0U)
+
+#define audio_get_reg(addr) readl(addr)
+#define audio_set_reg_addr_val(addr, val) writel(val, addr)
+
+#define ENABLE_TDM_CLK (LK_ENABLE_TDM_SEP_CLK || LK_ENABLE_TDM_COCLK)
+#define ENABLE_I2S_CLK (LK_ENABLE_I2S_SEP_CLK || LK_ENABLE_I2S_COCLK)
+
+void mt_audio_clk_enable(void);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/audio/rules.mk b/src/bsp/lk/platform/mediatek/mt2712/drivers/audio/rules.mk
new file mode 100644
index 0000000..1b915ea
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/audio/rules.mk
@@ -0,0 +1,43 @@
+# define build parameters to enable "lk open clock feature"
+# you may define the parameters in project/XXX.mk for XXX project
+# ENABLE_AUDIO_CLK := 1 -> enable the feature
+# AUDIO_USE_EXT_CLK := 1 -> apll1/apll2 use external clk
+# ENABLE_TDM_CLK_MODE := 1 -> enable the TDM out 0 with non-coclk setting
+# ENABLE_TDM_CLK_MODE := 2 -> enable the TDM out 0 with coclk setting
+# ENABLE_I2S_CLK_MODE := 1 -> enable the I2S out 0 with non-coclk setting
+# ENABLE_I2S_CLK_MODE := 2 -> enable the I2S out 0 with coclk setting
+#
+# Note: The TDM/I2S out format will be fixed once you enable the feature.
+# If you want to change the setting there is some parameter you need to change:
+#    TDM Sample rate: AUDIO_TOP_CON1 bit 31:24, AUDIO_TOP_CON2 bit 15:8
+#    TDM data/clk format: AFE_TDM_G1_CON1, AFE_TDM_IN_CON1
+#    I2S Sample rate: ASMO_TIMING_CON1, ASMI_TIMING_CON1
+#    I2S format: ASYS_I2SO1_CON, ASYS_I2SIN1_CON
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+ifeq ($(strip $(ENABLE_AUDIO_CLK)),1)
+MODULE_DEFINES += LK_ENABLE_AUDIO_CLK
+
+ifeq ($(strip $(AUDIO_USE_EXT_CLK)),1)
+MODULE_DEFINES += LK_AUDIO_USE_EXT_CLK
+endif
+
+ifeq ($(strip $(ENABLE_TDM_CLK_MODE)),1)
+MODULE_DEFINES += LK_ENABLE_TDM_SEP_CLK=1
+else ifeq ($(strip $(ENABLE_TDM_CLK_MODE)),2)
+MODULE_DEFINES += LK_ENABLE_TDM_COCLK=1
+endif
+
+ifeq ($(strip $(ENABLE_I2S_CLK_MODE)),1)
+MODULE_DEFINES += LK_ENABLE_I2S_SEP_CLK=1
+else ifeq ($(strip $(ENABLE_I2S_CLK_MODE)),2)
+MODULE_DEFINES += LK_ENABLE_I2S_COCLK=1
+endif
+
+endif
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/audio_clk_enable.c \
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/dcm/dcm.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/dcm/dcm.c
new file mode 100644
index 0000000..c5d3b97
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/dcm/dcm.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017 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 <platform/dcm.h>
+#include <platform/mt_reg_base.h>
+#include <platform/reg_utils.h>
+
+#define BIT(bit) (1UL << (bit))
+
+#define INFRA_TOPCKGEN_DCMCTL	(INFRACFG_BASE	+ 0x0010)
+#define INFRA_TOPCKGEN_DCMDBC	(INFRACFG_BASE	+ 0x0014)
+#define INFRA_GLOBALCON_DCMCTL	(INFRACFG_BASE	+ 0x0050)
+#define INFRA_GLOBALCON_DCMDBC	(INFRACFG_BASE	+ 0x0054)
+#define INFRA_GLOBALCON_DCMFSEL	(INFRACFG_BASE	+ 0x0058)
+
+#define PERI_GLOBALCON_DCMCTL	(PERICFG_BASE	+ 0x0050)
+#define PERI_GLOBALCON_DCMDBC	(PERICFG_BASE	+ 0x0054)
+
+#define PERI_REV_REG            (PERICFG_BASE   + 0x0800)
+
+#define E1_WORKAROUND		1
+
+void mt_dcm_init(void)
+{
+	/* INFRA DCM */
+	setbits32(INFRA_TOPCKGEN_DCMCTL, BIT(0));
+
+#if E1_WORKAROUND
+	setbits32(INFRA_GLOBALCON_DCMCTL, BIT(0) | BIT(1) | BIT(9));
+	clrbits32(INFRA_GLOBALCON_DCMCTL, BIT(8));
+#else
+	setbits32(INFRA_GLOBALCON_DCMCTL, BIT(0) | BIT(1) | BIT(8) | BIT(9));
+#endif
+
+	setbits32(INFRA_GLOBALCON_DCMDBC, BIT(8) | BIT(24));
+
+	/* PERISYS GLOBALCON DCM */
+	setbits32(PERI_GLOBALCON_DCMCTL, BIT(0)| BIT(1));
+
+	/* PREVENT I2C TRANSFER RATE MAY SLOW DOWN
+         * DUE TO BUS CLOCK DCM FUNCTION*/
+	setbits32(PERI_REV_REG, BIT(8));
+
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/efuse/mtk_devinfo.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/efuse/mtk_devinfo.c
new file mode 100644
index 0000000..5299e57
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/efuse/mtk_devinfo.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <platform/mtk_devinfo.h>
+
+int det_ca35_freq(void)
+{
+    int ca35_freq;
+
+    ca35_freq = get_ca35_freq();
+
+    if (ca35_freq == CA35_SPD_FREE) {
+#if defined(CA35_FREQ_806MHZ)
+        ca35_freq = CA35_SPD_806MHZ;
+#elif defined(CA35_FREQ_1001MHZ)
+        ca35_freq = CA35_SPD_1001MHZ;
+#else
+        ca35_freq = CA35_SPD_1196MHZ;
+#endif
+    }
+    return ca35_freq;
+}
+
+int det_ca72_freq(void)
+{
+    int ca72_freq;
+
+    ca72_freq = get_ca72_freq();
+
+    if (ca72_freq == CA72_SPD_FREE) {
+#if defined(CA72_FREQ_1001MHZ)
+        ca72_freq = CA72_SPD_1001MHZ;
+#elif defined(CA72_FREQ_1196MHZ)
+        ca72_freq = CA72_SPD_1196MHZ;
+#elif defined(CA72_FREQ_1391MHZ)
+        ca72_freq = CA72_SPD_1391MHZ;
+#elif defined(CA72_FREQ_1495MHZ)
+        ca72_freq = CA72_SPD_1495MHZ;
+#else
+        ca72_freq = CA72_SPD_1599MHZ;
+#endif
+    }
+    return ca72_freq;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/efuse/mtk_efuse.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/efuse/mtk_efuse.c
new file mode 100644
index 0000000..dc89b83
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/efuse/mtk_efuse.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017 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 <mtk_i2c.h>
+#include <reg.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+static int enable_efuse_i2c(uint8_t benable)
+{
+    int ret = 0;
+    uint8_t rw_buffer[2];
+
+    /* set voltage to 2.0V */
+    rw_buffer[0] = 0x3;
+    ret = i2c_cust_write(0, 0x3F, 100, rw_buffer, 1);
+    if (ret)
+        return ret;
+    ret = i2c_cust_read(0, 0x3F, 100, &rw_buffer[1], 1);
+    if (ret)
+        return ret;
+    rw_buffer[1] |= (0x1A << 2);
+    LTRACEF("[enable_efuse]write: 0x%x: 0x%x\r\n", rw_buffer[0], rw_buffer[1]);
+    ret = i2c_cust_write(0, 0x3F, 100, rw_buffer, 2);
+    if (ret)
+        return ret;
+
+    /* enable/disable power */
+    rw_buffer[0] = 0x12;
+    ret = i2c_cust_write(0, 0x3F, 100, rw_buffer, 1);
+    if (ret)
+        return ret;
+    ret = i2c_cust_read(0, 0x3F, 100, &rw_buffer[1], 1);
+    if (ret)
+        return ret;
+    if (benable)
+        rw_buffer[1] |= (0x1 << 2);
+    else
+        rw_buffer[1] &= ~(0x1 << 2);
+
+    LTRACEF("[enable_efuse]write: 0x%x: 0x%x\r\n", rw_buffer[0], rw_buffer[1]);
+    ret = i2c_cust_write(0, 0x3F, 100, rw_buffer, 2);
+    if (ret)
+        return ret;
+    return ret;
+}
+
+void enable_vefuse(void)
+{
+    enable_efuse_i2c(1);
+    spin(10000);
+}
+
+void disable_vefuse(void)
+{
+    enable_efuse_i2c(0);
+    spin(10000);
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/gpio/mt_gpio.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/gpio/mt_gpio.c
new file mode 100644
index 0000000..b8eea91
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/gpio/mt_gpio.c
@@ -0,0 +1,111 @@
+/*
+ * 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 <platform/mt_gpio.h>
+#include <platform/mt_reg_base.h>
+#include <reg.h>
+#include <string.h>
+#include <target/io_pwr.h>
+
+enum gpio_rdsel_type {
+    GPIO,   /* VCC3IO_GPIO */
+    GBE,    /* VCC3IO_GBE */
+    NOR,    /* VCC3IO_NOR */
+    MSDC1,  /* VCC3IO_MSDC1 */
+    MSDC2,  /* VCC3IO_MSDC2 */
+    UART4B, /* VCC3IO_UART4B */
+    SPICTP, /* VCC3IO_SPICTP */
+    SPIMCU, /* VCC3IO_SPIMCU */
+    I2S102, /* VCC3IO_I2S102 */
+    I2SIO1, /* VCC3IO_I2SIO1 */
+    I2SO02, /* VCC3IO_I2SO02 */
+    TDMO,   /* VCC3IO_TDMO */
+};
+
+int gpio_type[] = {
+    [GPIO] = VCC3IO_GPIO,
+    [GBE] = VCC3IO_GBE,
+    [NOR] = VCC3IO_NOR,
+    [MSDC1] = VCC3IO_MSDC1,
+    [MSDC2] = VCC3IO_MSDC2,
+    [UART4B] = VCC3IO_UART4B,
+    [SPICTP] = VCC3IO_SPICTP,
+    [SPIMCU] = VCC3IO_SPIMCU,
+    [I2S102] = VCC3IO_I2S102,
+    [I2SIO1] = VCC3IO_I2SIO1,
+    [I2SO02] = VCC3IO_I2SO02,
+    [TDMO] = VCC3IO_TDMO
+};
+
+static inline void gpio_set_rdsel(enum gpio_rdsel_type type, addr_t reg, int start_pos)
+{
+    u32 val = 0;
+
+    if (gpio_type[type] == 1) {
+        val |= 0x0c << start_pos;
+    }
+    writel((readl(reg) & (~(0x3f << start_pos))) | val, reg);
+}
+
+void mt_gpio_init(void)
+{
+    gpio_set_rdsel(GPIO, GPIO_RDSEL11_EN, 0);
+    gpio_set_rdsel(GPIO, GPIO_RDSEL11_EN, 6);
+    gpio_set_rdsel(GPIO, GPIO_EXMD_CTRL0, 4);
+    gpio_set_rdsel(GPIO, GPIO_RDSEL10_EN, 0);
+    gpio_set_rdsel(GPIO, GPIO_RDSEL10_EN, 6);
+    gpio_set_rdsel(GPIO, GPIO_RDSEL2_EN, 0);
+    gpio_set_rdsel(GPIO, GPIO_RDSEL2_EN, 6);
+    gpio_set_rdsel(GBE, GPIO_RDSEL3_EN, 0);
+    gpio_set_rdsel(GBE, GPIO_RDSEL3_EN, 6);
+    gpio_set_rdsel(GBE, GPIO_RDSEL2_EN, 0);
+    gpio_set_rdsel(GBE, GPIO_RDSEL2_EN, 6);
+    gpio_set_rdsel(GBE, GPIO_RDSEL4_EN, 0);
+    gpio_set_rdsel(NOR, GPIO_RDSEL1_EN, 6);
+    gpio_set_rdsel(MSDC1, GPIO_MSDC1_CTRL5, 4);
+    gpio_set_rdsel(MSDC2, GPIO_MSDC2_CTRL5, 4);
+    gpio_set_rdsel(UART4B, GPIO_RDSEL4_EN, 6);
+    gpio_set_rdsel(UART4B, GPIO_RDSEL5_EN, 0);
+    gpio_set_rdsel(SPICTP, GPIO_RDSEL6_EN, 0);
+    gpio_set_rdsel(SPICTP, GPIO_RDSEL6_EN, 6);
+    gpio_set_rdsel(SPIMCU, GPIO_RDSEL7_EN, 0);
+    gpio_set_rdsel(SPIMCU, GPIO_RDSEL7_EN, 6);
+    gpio_set_rdsel(I2S102, GPIO_RDSEL8_EN, 0);
+    gpio_set_rdsel(I2S102, GPIO_RDSEL8_EN, 6);
+    gpio_set_rdsel(I2S102, GPIO_RDSEL9_EN, 0);
+    gpio_set_rdsel(I2S102, GPIO_RDSEL9_EN, 6);
+    gpio_set_rdsel(I2SIO1, GPIO_RDSELA_EN, 0);
+    gpio_set_rdsel(I2SIO1, GPIO_RDSELA_EN, 6);
+    gpio_set_rdsel(I2SIO1, GPIO_RDSELB_EN, 0);
+    gpio_set_rdsel(I2SIO1, GPIO_RDSELB_EN, 6);
+    gpio_set_rdsel(I2SO02, GPIO_RDSELC_EN, 0);
+    gpio_set_rdsel(I2SO02, GPIO_RDSELC_EN, 6);
+    gpio_set_rdsel(I2SO02, GPIO_RDSELD_EN, 0);
+    gpio_set_rdsel(I2SO02, GPIO_RDSELD_EN, 6);
+    gpio_set_rdsel(I2SO02, GPIO_RDSELE_EN, 0);
+    gpio_set_rdsel(I2SO02, GPIO_RDSELE_EN, 6);
+    gpio_set_rdsel(TDMO, GPIO_RDSELF_EN, 0);
+    gpio_set_rdsel(TDMO, GPIO_RDSELF_EN, 6);
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/key/mtk_key.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/key/mtk_key.c
new file mode 100644
index 0000000..9f7e6a6
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/key/mtk_key.c
@@ -0,0 +1,37 @@
+/*
+ * 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 <platform/mt_reg_base.h>
+#include <reg.h>
+
+#define GPIO_DIN2          (GPIO_BASE + 0x410)
+
+bool check_download_key(void)
+{
+#if !(CFG_FPGA_PLATFORM)
+    return (readl(GPIO_DIN2) & (1U << 3)) == 0;
+#else
+    return false;
+#endif
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/mmc_core.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/mmc_core.c
new file mode 100644
index 0000000..23d3ace
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/mmc_core.c
@@ -0,0 +1,2084 @@
+/*
+ * 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.
+ */
+
+/*=======================================================================*/
+/* HEADER FILES                                                          */
+/*=======================================================================*/
+#include <config.h>
+#include <platform/msdc.h>
+#include <platform/mmc_core.h>
+#include <platform/mmc_rpmb.h>
+#include <platform/mmc_ioctl.h>
+#include <platform/mtk_bio_ioctl.h>
+#include <platform/trapping.h>
+#include <lib/bio.h>
+#include <lib/heap.h>
+#include <lib/partition.h>
+#include <pow2.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+#include <kernel/mutex.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+#define CMD_RETRIES        (5)
+#define CMD_TIMEOUT        (100)    /* 100ms */
+#define PAD_DELAY_MAX 32
+
+static int mmc_set_ext_csd(struct mmc_card *card, u8 addr, u8 value);
+/* before DRAM k, malloc() is not ready, so define it globally */
+struct mmc_host msdc_host0;
+struct mmc_card emmc_card;
+
+typedef struct {
+    bdev_t bdev;
+    u32 part_id;
+    struct mmc_host *host;
+    struct mmc_card *card;
+} mmc_dev_t;
+
+struct msdc_delay_phase {
+    u8 maxlen;
+    u8 start;
+    u8 final_phase;
+};
+
+static const unsigned int tran_exp[] = {
+    10000,      100000,     1000000,    10000000,
+    0,      0,      0,      0
+};
+
+static const unsigned char tran_mant[] = {
+    0,  10, 12, 13, 15, 20, 25, 30,
+    35, 40, 45, 50, 55, 60, 70, 80,
+};
+
+static const unsigned char mmc_tran_mant[] = {
+    0,  10, 12, 13, 15, 20, 26, 30,
+    35, 40, 45, 52, 55, 60, 70, 80,
+};
+
+static u32 unstuff_bits(u32 *resp, u32 start, u32 size)
+{
+    const u32 __mask = (1 << (size)) - 1;
+    const int __off = 3 - ((start) / 32);
+    const int __shft = (start) & 31;
+    u32 __res;
+
+    __res = resp[__off] >> __shft;
+    if ((size) + __shft >= 32)
+        __res |= resp[__off-1] << (32 - __shft);
+    return __res & __mask;
+}
+
+#define UNSTUFF_BITS(r,s,sz)    unstuff_bits(r,s,sz)
+
+static int mmc_switch_part(mmc_dev_t *dev)
+{
+    int err = MMC_ERR_NONE;
+    struct mmc_card *card;
+    struct mmc_host *host;
+    u8 cfg;
+
+    host = dev->host;
+    if (host->curr_part == dev->part_id)
+        /* already set to specific partition */
+        return MMC_ERR_NONE;
+
+    if (dev->part_id > EXT_CSD_PART_CFG_GP_PART_4) {
+        dprintf(CRITICAL, "[MSDC] Unsupported partid: %u\n", dev->part_id);
+        return MMC_ERR_INVALID;
+    }
+
+    card = dev->card;
+    ASSERT(card);
+
+    cfg = card->ext_csd.part_cfg;
+    cfg = (cfg & ~0x7) | dev->part_id;
+    err = mmc_set_ext_csd(card, EXT_CSD_PART_CFG, cfg);
+    if (err)
+        dprintf(CRITICAL, "[MSDC] switch to part %u failed!\n", dev->part_id);
+    else
+        card->ext_csd.part_cfg = cfg;
+
+    return err;
+}
+
+static int mmc_cmd(struct mmc_host *host, struct mmc_command *cmd)
+{
+    int err;
+    int retry = cmd->retries;
+
+    do {
+        err = msdc_cmd(host, cmd);
+        /* do not retry CMD21 */
+        if (err == MMC_ERR_NONE || cmd->opcode == MMC_CMD21)
+            break;
+    } while (retry--);
+
+    return err;
+}
+
+static int mmc_app_cmd(struct mmc_host *host, struct mmc_command *cmd,
+                       u32 rca, int retries)
+{
+    int err = MMC_ERR_FAILED;
+    struct mmc_command appcmd;
+
+    appcmd.opcode  = MMC_CMD_APP_CMD;
+    appcmd.arg     = rca << 16;
+    appcmd.rsptyp  = RESP_R1;
+    appcmd.retries = CMD_RETRIES;
+    appcmd.timeout = CMD_TIMEOUT;
+
+    do {
+        err = mmc_cmd(host, &appcmd);
+
+        if (err == MMC_ERR_NONE)
+            err = mmc_cmd(host, cmd);
+        if (err == MMC_ERR_NONE)
+            break;
+    } while (retries--);
+
+    return err;
+}
+
+static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
+{
+    int bit;
+
+    ocr &= host->ocr_avail;
+
+    bit = __builtin_ffs(ocr);
+    if (bit) {
+        bit -= 1;
+        ocr &= 3 << bit;
+    } else {
+        ocr = 0;
+    }
+    return ocr;
+}
+
+static inline int mmc_go_idle(struct mmc_host *host)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_GO_IDLE_STATE, 0, RESP_NONE, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+    return mmc_cmd(host, &cmd);
+}
+
+static int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
+{
+    struct mmc_command cmd;
+    int err;
+    static const u8 test_pattern = 0xAA;
+    u8 result_pattern;
+
+    /*
+     * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+     * before SD_APP_OP_COND. This command will harmlessly fail for
+     * SD 1.0 cards.
+     */
+
+    cmd.opcode  = SD_CMD_SEND_IF_COND;
+    cmd.arg     = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+    cmd.rsptyp  = RESP_R1;
+    cmd.retries = 0;
+    cmd.timeout = CMD_TIMEOUT;
+
+    err = mmc_cmd(host, &cmd);
+
+    if (err != MMC_ERR_NONE)
+        return err;
+
+    result_pattern = cmd.resp[0] & 0xFF;
+
+    if (result_pattern != test_pattern)
+        return MMC_ERR_INVALID;
+
+    return MMC_ERR_NONE;
+}
+
+/*
+ * return MMC_ERR_RETRY means that need re-send CMD1 in stage 2
+ */
+static int mmc_send_op_cond_once(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+    int i, err = 0;
+    struct mmc_command cmd = {
+        MMC_CMD_SEND_OP_COND, 0, RESP_R3, {0}, CMD_TIMEOUT, 0, 0
+    };
+
+    cmd.arg = ocr;
+
+    for (i = 1; i; i--) {
+        err = mmc_cmd(host, &cmd);
+        if (err)
+            break;
+
+        /* if we're just probing, do a single pass */
+        if (ocr == 0)
+            break;
+
+        if (cmd.resp[0] & MMC_CARD_BUSY)
+            break;
+
+        err = MMC_ERR_RETRY;
+    }
+
+    if (!err && rocr)
+        *rocr = cmd.resp[0];
+
+    return err;
+}
+
+static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+    int i, err = 0;
+    struct mmc_command cmd = {
+        MMC_CMD_SEND_OP_COND, 0, RESP_R3, {0}, CMD_TIMEOUT, 0, 0
+    };
+
+    cmd.arg = ocr;
+
+    for (i = 100; i; i--) {
+        err = mmc_cmd(host, &cmd);
+        if (err)
+            break;
+
+        /* if we're just probing, do a single pass */
+        if (ocr == 0)
+            break;
+
+        if (cmd.resp[0] & MMC_CARD_BUSY)
+            break;
+
+        err = MMC_ERR_TIMEOUT;
+
+        spin(10000);
+
+    }
+
+    if (!err && rocr)
+        *rocr = cmd.resp[0];
+
+    return err;
+}
+
+static int mmc_send_app_op_cond_once(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+    struct mmc_command cmd;
+    int i, err = 0;
+
+    cmd.opcode  = SD_ACMD_SEND_OP_COND;
+    cmd.arg     = ocr;
+    cmd.rsptyp  = RESP_R3;
+    cmd.retries = CMD_RETRIES;
+    cmd.timeout = CMD_TIMEOUT;
+
+    for (i = 1; i; i--) {
+        err = mmc_app_cmd(host, &cmd, 0, CMD_RETRIES);
+        if (err != MMC_ERR_NONE)
+            break;
+
+        if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+            break;
+
+        err = MMC_ERR_RETRY;
+    }
+
+    if (rocr)
+        *rocr = cmd.resp[0];
+
+    return err;
+}
+
+static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+    struct mmc_command cmd;
+    int i, err = 0;
+
+    cmd.opcode  = SD_ACMD_SEND_OP_COND;
+    cmd.arg     = ocr;
+    cmd.rsptyp  = RESP_R3;
+    cmd.retries = CMD_RETRIES;
+    cmd.timeout = CMD_TIMEOUT;
+
+    for (i = 100; i; i--) {
+        err = mmc_app_cmd(host, &cmd, 0, CMD_RETRIES);
+        if (err != MMC_ERR_NONE)
+            break;
+
+        if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+            break;
+
+        err = MMC_ERR_TIMEOUT;
+
+        spin(10000);
+    }
+
+    if (rocr)
+        *rocr = cmd.resp[0];
+
+    return err;
+}
+
+static int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
+{
+    int ret;
+    struct mmc_command cmd = {
+        MMC_CMD_ALL_SEND_CID, 0, RESP_R2, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+    ret = mmc_cmd(host, &cmd);
+    if (ret == MMC_ERR_NONE) {
+        memcpy(cid, &cmd.resp[0], sizeof(u32) * 4);
+        LTRACEF("eMMC CID: %08x%08x%08x%08x\n",
+                cid[0], cid[1], cid[2], cid[3]);
+    }
+
+    return ret;
+}
+
+static int mmc_send_relative_addr(struct mmc_host *host,
+                                  struct mmc_card *card, unsigned int *rca)
+{
+    int err;
+    struct mmc_command cmd;
+
+    memset(&cmd, 0, sizeof(struct mmc_command));
+
+    if (mmc_card_mmc(card)) { /* set rca */
+        cmd.opcode  = MMC_CMD_SET_RELATIVE_ADDR;
+        cmd.arg     = *rca << 16;
+        cmd.rsptyp  = RESP_R1;
+        cmd.retries = CMD_RETRIES;
+        cmd.timeout = CMD_TIMEOUT;
+    } else {  /* send rca */
+        cmd.opcode  = SD_CMD_SEND_RELATIVE_ADDR;
+        cmd.arg     = 0;
+        cmd.rsptyp  = RESP_R6;
+        cmd.retries = CMD_RETRIES;
+        cmd.timeout = CMD_TIMEOUT;
+    }
+    err = mmc_cmd(host, &cmd);
+    if ((err == MMC_ERR_NONE) && !mmc_card_mmc(card))
+        *rca = cmd.resp[0] >> 16;
+
+    return err;
+}
+
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_SELECT_CARD, 0, RESP_R1B, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+    cmd.arg = card->rca << 16;
+    return mmc_cmd(host, &cmd);
+}
+
+static int mmc_deselect_card(struct mmc_host *host, struct mmc_card *card)
+{
+    /* deslect cmd has no response */
+    struct mmc_command cmd = {
+        MMC_CMD_SELECT_CARD, 0, RESP_NONE, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+    return mmc_cmd(host, &cmd);
+}
+
+static int mmc_send_status(struct mmc_host *host, struct mmc_card *card,
+                           u32 *status)
+{
+    int err;
+    struct mmc_command cmd = {
+        MMC_CMD_SEND_STATUS, 0, RESP_R1, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+    cmd.arg = card->rca << 16;
+
+    err = mmc_cmd(host, &cmd);
+    if (err == MMC_ERR_NONE)
+        *status = cmd.resp[0];
+    return err;
+}
+
+static int mmc_switch(struct mmc_host *host, struct mmc_card *card,
+                      u8 set, u8 index, u8 value)
+{
+    int err;
+    u32 status = 0, count = 0;
+    struct mmc_command cmd = {
+        MMC_CMD_SWITCH, 0, RESP_R1B, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+
+    cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) |
+              (value << 8) | set;
+
+    err = mmc_cmd(host, &cmd);
+    if (err != MMC_ERR_NONE)
+        return err;
+
+    do {
+        err = mmc_send_status(host, card, &status);
+        if (err) {
+            dprintf(CRITICAL, "[eMMC] Fail to send status %d\n", err);
+            break;
+        }
+        if (status & R1_SWITCH_ERROR) {
+            dprintf(CRITICAL, "[eMMC] switch error. arg(0x%x)\n", cmd.arg);
+            return MMC_ERR_FAILED;
+        }
+        if (count++ >= 600000) {
+            dprintf(CRITICAL, "[%s]: timeout happend, count=%d, status=0x%x\n",
+                    __func__, count, status);
+            break;
+        }
+    } while (!(status & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(status) == 7));
+
+    if (!err && (index == EXT_CSD_PART_CFG))
+        host->curr_part = value & 0x7;
+
+    return err;
+}
+
+static int mmc_read_csds(struct mmc_host *host, struct mmc_card *card)
+{
+    int err;
+    struct mmc_command cmd = {
+        MMC_CMD_SEND_CSD, 0, RESP_R2, {0}, CMD_TIMEOUT * 100, CMD_RETRIES, 0
+    };
+
+    cmd.arg = card->rca << 16;
+
+    err = mmc_cmd(host, &cmd);
+    if (err == MMC_ERR_NONE) {
+        unsigned int e, m;
+        card->csd.mmca_vsn = UNSTUFF_BITS(&cmd.resp[0], 122, 4);
+        m = UNSTUFF_BITS(&cmd.resp[0], 99, 4);
+        e = UNSTUFF_BITS(&cmd.resp[0], 96, 3);
+        card->csd.max_dtr = tran_exp[e] * mmc_tran_mant[m];
+        e = UNSTUFF_BITS(&cmd.resp[0], 47, 3);
+        m = UNSTUFF_BITS(&cmd.resp[0], 62, 12);
+        card->csd.capacity = (1 + m) << (e + 2);
+        card->csd.read_blkbits = UNSTUFF_BITS(&cmd.resp[0], 80, 4);
+        memcpy(&card->raw_csd, &cmd.resp[0], sizeof(u32) * 4);
+    }
+
+    return err;
+}
+
+static int mmc_decode_csd(struct mmc_card *card)
+{
+    struct mmc_csd *csd = &card->csd;
+    unsigned int e, m, csd_struct;
+    u32 *resp = card->raw_csd;
+
+    /* common part; some part are updated later according to spec. */
+    csd_struct = unstuff_bits(resp, 126, 2);
+    csd->csd_struct = csd_struct;
+
+    /* For MMC
+     * We only understand CSD structure v1.1 and v1.2.
+     * v1.2 has extra information in bits 15, 11 and 10.
+     */
+    if ( ( mmc_card_mmc(card) &&
+            ( csd_struct != CSD_STRUCT_VER_1_0 && csd_struct != CSD_STRUCT_VER_1_1
+              && csd_struct != CSD_STRUCT_VER_1_2 && csd_struct != CSD_STRUCT_EXT_CSD )
+         ) ||
+            ( mmc_card_sd(card) && ( csd_struct != 0 && csd_struct!=1 ) )
+       ) {
+        dprintf(ALWAYS, "Unknown CSD ver %d\n", csd_struct);
+        return MMC_ERR_INVALID;
+    }
+
+    m = unstuff_bits(resp, 99, 4);
+    e = unstuff_bits(resp, 96, 3);
+    csd->max_dtr      = tran_exp[e] * tran_mant[m];
+
+    /* update later according to spec. */
+    csd->read_blkbits = unstuff_bits(resp, 80, 4);
+
+    e = unstuff_bits(resp, 47, 3);
+    m = unstuff_bits(resp, 62, 12);
+    csd->capacity     = (1 + m) << (e + 2);
+
+    //Specific part
+    if (mmc_card_sd(card)) {
+        switch (csd_struct) {
+            case 0:
+                break;
+            case 1:
+                /*
+                 * This is a block-addressed SDHC card. Most
+                 * interesting fields are unused and have fixed
+                 * values. To avoid getting tripped by buggy cards,
+                 * we assume those fixed values ourselves.
+                 */
+                mmc_card_set_blockaddr(card);
+
+                m = unstuff_bits(resp, 48, 22);
+                csd->capacity     = (1 + m) << 10;
+
+                csd->read_blkbits = 9;
+                break;
+        }
+    } else {
+        csd->mmca_vsn    = unstuff_bits(resp, 122, 4);
+    }
+
+    return 0;
+}
+
+static void mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+    u32 caps = card->host->caps;
+    u8 card_type = ext_csd[EXT_CSD_CARD_TYPE];
+
+    card->ext_csd.sectors =
+        ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+        ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+        ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+        ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+
+    card->ext_csd.rev = ext_csd[EXT_CSD_REV];
+    card->ext_csd.boot_info   = ext_csd[EXT_CSD_BOOT_INFO];
+    card->ext_csd.boot_part_sz = ext_csd[EXT_CSD_BOOT_SIZE_MULT] * 128 * 1024;
+    card->ext_csd.rpmb_sz = ext_csd[EXT_CSD_RPMB_SIZE_MULT] * 128 * 1024;
+
+    if (card->ext_csd.sectors)
+        mmc_card_set_blockaddr(card);
+
+    if (caps & MMC_CAP_EMMC_HS400 &&
+            card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+        card->ext_csd.hs400_support = 1;
+        card->ext_csd.hs_max_dtr = 200000000;
+    } else if (caps & MMC_CAP_EMMC_HS200 &&
+               card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
+        card->ext_csd.hs_max_dtr = 200000000;
+    } else if (caps & MMC_CAP_DDR &&
+               card_type & EXT_CSD_CARD_TYPE_DDR_52) {
+        card->ext_csd.ddr_support = 1;
+        card->ext_csd.hs_max_dtr = 52000000;
+    } else if (caps & MMC_CAP_MMC_HIGHSPEED &&
+               card_type & EXT_CSD_CARD_TYPE_52) {
+        card->ext_csd.hs_max_dtr = 52000000;
+    } else if (card_type & EXT_CSD_CARD_TYPE_26) {
+        card->ext_csd.hs_max_dtr = 26000000;
+    } else {
+        /* MMC v4 spec says this cannot happen */
+        dprintf(CRITICAL, "[eMMC] MMCv4 but HS unsupported\n");
+    }
+
+    card->ext_csd.part_cfg = ext_csd[EXT_CSD_PART_CFG];
+    card->ext_csd.sec_support = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
+    card->ext_csd.reset_en = ext_csd[EXT_CSD_RST_N_FUNC];
+    card->ext_csd.hs_timing = ext_csd[EXT_CSD_HS_TIMING];
+
+    return;
+}
+
+/* Read and decode extended CSD. */
+static int mmc_read_ext_csd(struct mmc_host *host, struct mmc_card *card)
+{
+    int err = MMC_ERR_NONE;
+    u8 *ext_csd;
+    int result = MMC_ERR_NONE;
+    struct mmc_data data;
+    addr_t base = host->base;
+    struct mmc_command cmd = {
+        MMC_CMD_SEND_EXT_CSD, 0, RESP_R1, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+
+    if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
+        dprintf(CRITICAL, "[eMMC] MMCA_VSN: %d. Skip EXT_CSD\n",
+                card->csd.mmca_vsn);
+        return MMC_ERR_NONE;
+    }
+
+    /*
+     * As the ext_csd is so large and mostly unused, we don't store the
+     * raw block in mmc_card.
+     */
+    ext_csd = malloc(512);
+    ASSERT(ext_csd);
+    memset(ext_csd, 0, 512);
+
+    msdc_reset_tune_counter(host);
+
+    do {
+        MSDC_DMA_ON;
+        MSDC_CLR_FIFO();
+        MSDC_WRITE32(SDC_BLK_NUM, 1);
+        host->blklen = 512;
+        msdc_set_timeout(host, 100000000, 0);
+        err = mmc_cmd(host, &cmd);
+        if (err != MMC_ERR_NONE)
+            goto out;
+
+        data.cmd = &cmd;
+        data.blks = 1;
+        data.buf = ext_csd;
+        data.timeout = 100;
+        err = msdc_dma_transfer(host, &data);
+        MSDC_DMA_OFF;
+        if (err != MMC_ERR_NONE) {
+            if (msdc_abort_handler(host, 1))
+                dprintf(CRITICAL, "[eMMC] data abort failed\n");
+            result = msdc_tune_read(host);
+        }
+    } while (err && result != MMC_ERR_READTUNEFAIL);
+    msdc_reset_tune_counter(host);
+    mmc_decode_ext_csd(card, ext_csd);
+
+out:
+    free(ext_csd);
+    return err;
+}
+
+static void mmc_set_clock(struct mmc_host *host, int state, unsigned int hz)
+{
+    if (hz >= host->f_max) {
+        hz = host->f_max;
+    } else if (hz < host->f_min) {
+        hz = host->f_min;
+    }
+    msdc_config_clock(host, state, hz);
+}
+
+static int mmc_set_bus_width(struct mmc_host *host, struct mmc_card *card, int width)
+{
+    int err = MMC_ERR_NONE;
+    u32 arg = 0;
+    struct mmc_command cmd;
+
+    if (mmc_card_sd(card)) {
+        if (width == HOST_BUS_WIDTH_8) {
+            arg = SD_BUS_WIDTH_4;
+            width = HOST_BUS_WIDTH_4;
+        }
+
+        if ((width == HOST_BUS_WIDTH_4) && (host->caps & MMC_CAP_4_BIT_DATA)) {
+            arg = SD_BUS_WIDTH_4;
+        } else {
+            arg = SD_BUS_WIDTH_1;
+            width = HOST_BUS_WIDTH_1;
+        }
+
+        cmd.opcode  = SD_ACMD_SET_BUSWIDTH;
+        cmd.arg     = arg;
+        cmd.rsptyp  = RESP_R1;
+        cmd.retries = CMD_RETRIES;
+        cmd.timeout = CMD_TIMEOUT;
+
+        err = mmc_app_cmd(host, &cmd, card->rca, 0);
+        if (err != MMC_ERR_NONE)
+            goto out;
+
+        msdc_config_bus(host, width);
+    } else if (mmc_card_mmc(card)) {
+
+        if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+            goto out;
+
+        if (width == HOST_BUS_WIDTH_8) {
+            if (host->caps & MMC_CAP_8_BIT_DATA) {
+                arg = EXT_CSD_BUS_WIDTH_8;
+            } else {
+                width = HOST_BUS_WIDTH_4;
+            }
+        }
+        if (width == HOST_BUS_WIDTH_4) {
+            if (host->caps & MMC_CAP_4_BIT_DATA) {
+                arg = EXT_CSD_BUS_WIDTH_4;
+            } else {
+                width = HOST_BUS_WIDTH_1;
+            }
+        }
+        if (width == HOST_BUS_WIDTH_1)
+            arg = EXT_CSD_BUS_WIDTH_1;
+
+        err = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, arg);
+        if (err != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "[eMMC] Switch to bus width(%d) failed\n", arg);
+            goto out;
+        }
+        mmc_card_clr_ddr(card);
+
+        msdc_config_bus(host, width);
+    }
+
+out:
+    return err;
+}
+
+static u32 test_delay_bit(u32 delay, u32 bit)
+{
+    bit %= PAD_DELAY_MAX;
+    return delay & (1 << bit);
+}
+
+static int get_delay_len(u32 delay, u32 start_bit)
+{
+    u32 i;
+
+    for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) {
+        if (test_delay_bit(delay, start_bit + i) == 0)
+            return i;
+    }
+    return PAD_DELAY_MAX - start_bit;
+}
+
+static struct msdc_delay_phase get_best_delay(u32 delay)
+{
+    int start = 0, len = 0;
+    int start_final = 0, len_final = 0;
+    u8 final_phase = 0xff;
+    struct msdc_delay_phase delay_phase = { .start = 0 };
+
+    if (delay == 0) {
+        dprintf(CRITICAL, "phase error: [map:%x]\n", delay);
+        delay_phase.final_phase = final_phase;
+        return delay_phase;
+    }
+
+    while (start < PAD_DELAY_MAX) {
+        len = get_delay_len(delay, start);
+        if (len_final < len) {
+            start_final = start;
+            len_final = len;
+        }
+        start += len ? len : 1;
+        if (len >= 12 && start_final < 4)
+            break;
+    }
+
+    /* The rule is that to find the smallest delay cell */
+    if (start_final == 0)
+        final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX;
+    else
+        final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX;
+    dprintf(ALWAYS, "phase: [map:%x] [maxlen:%d] [final:%d]\n",
+            delay, len_final, final_phase);
+
+    delay_phase.maxlen = len_final;
+    delay_phase.start = start_final;
+    delay_phase.final_phase = final_phase;
+    return delay_phase;
+}
+
+static int mmc_hs200_tune_cmd(struct mmc_host *host, int *cmd_error)
+{
+    int err = MMC_ERR_NONE;
+    u8 *tune_data;
+    u16 data_len = host->caps &  MMC_CAP_8_BIT_DATA ? 128: 64;
+    struct mmc_data data;
+    addr_t base = host->base;
+    struct mmc_command cmd = {
+        MMC_CMD21, 0, RESP_R1, {0}, CMD_TIMEOUT, 0, 0
+    };
+
+    tune_data = malloc(data_len);
+    ASSERT(tune_data);
+    memset(tune_data, 0, data_len);
+    *cmd_error = MMC_ERR_NONE;
+
+    msdc_reset_tune_counter(host);
+
+    MSDC_DMA_ON;
+    MSDC_CLR_FIFO();
+    MSDC_WRITE32(SDC_BLK_NUM, 1);
+    host->blklen = data_len;
+    msdc_set_timeout(host, 100000000, 0);
+    err = mmc_cmd(host, &cmd);
+    if (err != MMC_ERR_NONE)
+        *cmd_error = err; /* still need receive data, or will impact the next cmd21 */
+
+    data.cmd = &cmd;
+    data.blks = 1;
+    data.buf = tune_data;
+    data.timeout = 100;
+    err = msdc_dma_transfer(host, &data);
+    MSDC_DMA_OFF;
+    msdc_reset_tune_counter(host);
+
+out:
+    free(tune_data);
+    return err;
+}
+
+static int msdc_tune_together(struct mmc_host *mmc)
+{
+    addr_t base = mmc->base;
+    u32 rise_delay = 0, fall_delay = 0;
+    struct msdc_delay_phase final_rise_delay,
+            final_fall_delay = { .start = 0 };
+    u8 final_delay, final_maxlen;
+    int cmd_err;
+    int i;
+    int ret;
+
+    MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+    MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_D_SMPL);
+    for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+        MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY, i);
+        MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATRRDLY, i);
+        ret = mmc_hs200_tune_cmd(mmc, &cmd_err);
+        if (!ret && !cmd_err)
+            rise_delay |= (1 << i);
+    }
+    final_rise_delay = get_best_delay(rise_delay);
+    /* if rising edge has enough margin, then do not scan falling edge */
+    if (final_rise_delay.maxlen >= 12 ||
+            (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
+        goto skip_fall;
+
+    MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+    MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_D_SMPL);
+    for (i = 0; i < PAD_DELAY_MAX; i++) {
+        MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY, i);
+        MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATRRDLY, i);
+        ret = mmc_hs200_tune_cmd(mmc, &cmd_err);
+        if (!ret && !cmd_err)
+            fall_delay |= (1 << i);
+    }
+    final_fall_delay = get_best_delay(fall_delay);
+
+skip_fall:
+    final_maxlen = MAX(final_rise_delay.maxlen, final_fall_delay.maxlen);
+    if (final_maxlen == final_rise_delay.maxlen) {
+        MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+        MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_D_SMPL);
+        MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+                       final_rise_delay.final_phase);
+        MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATRRDLY,
+                       final_rise_delay.final_phase);
+        final_delay = final_rise_delay.final_phase;
+    } else {
+        MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+        MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_D_SMPL);
+        MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+                       final_fall_delay.final_phase);
+        MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATRRDLY,
+                       final_fall_delay.final_phase);
+        final_delay = final_fall_delay.final_phase;
+    }
+
+    dprintf(ALWAYS, "Final cmd/data pad delay: %x\n", final_delay);
+    return final_delay == 0xff ? -EIO : 0;
+}
+
+static int mmc_select_hs200(struct mmc_card *card)
+{
+    struct mmc_host *host = card->host;
+    int ret;
+
+    ret = mmc_set_bus_width(host, card, HOST_BUS_WIDTH_8);
+    if (ret != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "failed to set bus width!\n");
+        return ret;
+    }
+
+    ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+                     EXT_CSD_HS_TIMEING_HS200);
+    if (ret != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "failed to switch to hs200 mode!\n");
+        return ret;
+    }
+
+    mmc_card_set_hs200(card);
+    mmc_set_clock(host, card->state, card->ext_csd.hs_max_dtr);
+
+    return 0;
+}
+
+static int mmc_select_hs400(struct mmc_card *card)
+{
+    struct mmc_host *host = card->host;
+    addr_t base = host->base;
+    int ret;
+
+    mmc_set_clock(host, card->state, 50000000);
+    ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+                     EXT_CSD_HS_TIMEING_HS);
+    if (ret != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "switch to high-speed from hs200 failed, err:%d\n", ret);
+        return ret;
+    }
+
+    ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8_DDR);
+    if (ret != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "switch to bus width for hs400 failed, err:%d\n", ret);
+        return ret;
+    }
+
+    ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+                     EXT_CSD_HS_TIMEING_HS400);
+    if (ret != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "switch to hs400 failed, err:%d\n", ret);
+        return ret;
+    }
+    mmc_card_set_hs400(card);
+    mmc_set_clock(host, card->state, card->ext_csd.hs_max_dtr);
+
+    /*
+     * Apply hs400 settings:
+     * set data tune to default value and apply ds delay setting
+     */
+
+    MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_D_SMPL);
+    MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATRRDLY, 0);
+    MSDC_WRITE32(EMMC50_PAD_DS_TUNE, 0x14029);
+
+    return ret;
+}
+
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+    struct mmc_host *host = card->host;
+    int ret;
+
+    ret = msdc_tune_together(host);
+    if (ret == -EIO) {
+        dprintf(CRITICAL, "hs200 tuning cmd/data error!\n");
+        return ret;
+    }
+
+    return MMC_ERR_NONE;
+}
+
+static int mmc_erase_start(struct mmc_card *card, u32 blknr)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_ERASE_GROUP_START, 0, RESP_R1, {0}, CMD_TIMEOUT, 3, 0
+    };
+    if (mmc_card_sd(card))
+        cmd.opcode = MMC_CMD_ERASE_WR_BLK_START;
+    cmd.arg = blknr;
+    return mmc_cmd(card->host, &cmd);
+}
+
+static int mmc_erase_end(struct mmc_card *card, u32 blknr)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_ERASE_GROUP_END, 0, RESP_R1, {0}, CMD_TIMEOUT, 3, 0
+    };
+    if (mmc_card_sd(card))
+        cmd.opcode = MMC_CMD_ERASE_WR_BLK_END;
+    cmd.arg = blknr;
+    return mmc_cmd(card->host, &cmd);
+}
+
+static int mmc_erase(struct mmc_card *card, u32 arg)
+{
+    int err;
+    u32 status;
+    struct mmc_command cmd = {
+        MMC_CMD_ERASE, 0, RESP_R1B, {0}, CMD_TIMEOUT, 3, 0
+    };
+    if (mmc_card_sd(card))
+        arg = 0;
+    cmd.arg = arg;
+
+    if (arg & MMC_ERASE_SECURE_REQ) {
+        if (!(card->ext_csd.sec_support & EXT_CSD_SEC_FEATURE_ER_EN))
+            return MMC_ERR_INVALID;
+    }
+    if ((arg & MMC_ERASE_GC_REQ) || (arg & MMC_ERASE_TRIM)) {
+        if (!(card->ext_csd.sec_support & EXT_CSD_SEC_FEATURE_GB_CL_EN))
+            return MMC_ERR_INVALID;
+    }
+
+    err = mmc_cmd(card->host, &cmd);
+    if (err)
+        return err;
+
+    do {
+        err = mmc_send_status(card->host, card, &status);
+        if (err)
+            break;
+        if (R1_STATUS(status) != 0)
+            break;
+    } while (R1_CURRENT_STATE(status) == 7);
+
+    return err;
+}
+
+static int mmc_do_trim(struct mmc_card *card, off_t start_addr, size_t len)
+{
+    int err = MMC_ERR_NONE;
+    off_t end_addr;
+
+    if (len < card->blklen) {
+        dprintf(CRITICAL, "%s: invalid len: %ld\n", __func__, len);
+        return MMC_ERR_INVALID;
+    }
+
+    end_addr =((start_addr + len) / card->blklen - 1) * card->blklen;
+
+    if (mmc_card_highcaps(card)) {
+        start_addr >>= MMC_BLOCK_BITS_SHFT;
+        end_addr >>= MMC_BLOCK_BITS_SHFT;
+    }
+
+    err = mmc_erase_start(card, start_addr);
+    if (err)
+        goto error;
+
+    err = mmc_erase_end(card, end_addr);
+    if (err)
+        goto error;
+
+    err = mmc_erase(card, MMC_ERASE_TRIM);
+
+error:
+    if (err)
+        dprintf(CRITICAL, "%s: erase range (0x%llx~0x%llx) failed,Err<%d>\n",
+                __func__, start_addr, end_addr, err);
+
+    return err;
+}
+
+static int mmc_set_ext_csd(struct mmc_card *card, u8 addr, u8 value)
+{
+    int err;
+
+    /* can't write */
+    if (192 <= addr || !card)
+        return MMC_ERR_INVALID;
+
+    err = mmc_switch(card->host, card, EXT_CSD_CMD_SET_NORMAL, addr, value);
+
+    if (err == MMC_ERR_NONE)
+        err = mmc_read_ext_csd(card->host, card);
+
+    return err;
+}
+
+static int mmc_set_reset_func(struct mmc_card *card, u8 enable)
+{
+    int err = MMC_ERR_FAILED;
+
+    if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+        goto out;
+
+    if (card->ext_csd.reset_en == 0) {
+        err = mmc_set_ext_csd(card, EXT_CSD_RST_N_FUNC, enable);
+        if (err == MMC_ERR_NONE)
+            card->ext_csd.reset_en = enable;
+    } else {
+        /* no need set */
+        return MMC_ERR_NONE;
+    }
+out:
+    return err;
+}
+
+static int mmc_set_boot_bus(struct mmc_card *card, u8 rst_bwidth, u8 mode, u8 bwidth)
+{
+    int err = MMC_ERR_FAILED;
+    u8 arg;
+
+    if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+        goto out;
+
+    arg = mode | rst_bwidth | bwidth;
+
+    err = mmc_set_ext_csd(card, EXT_CSD_BOOT_BUS_WIDTH, arg);
+out:
+    return err;
+}
+
+int mmc_get_boot_part(u32 *bootpart)
+{
+    struct mmc_host *host;
+    struct mmc_card *card;
+    int err = MMC_ERR_NONE;
+    u8 part_config;
+
+    host = &msdc_host0;
+    card = &emmc_card;
+
+    if (!bootpart)
+        return -1;
+
+    if (!card || !host)
+        return -1;
+    err = mmc_read_ext_csd(host, card);
+
+    if (err == MMC_ERR_NONE) {
+        part_config = (card->ext_csd.part_cfg >> 3) & 0x07;
+        if (part_config == 1) {
+            *bootpart = EMMC_PART_BOOT1;
+        } else if (part_config == 2) {
+            *bootpart = EMMC_PART_BOOT2;
+        } else if (part_config == 7) {
+            *bootpart = EMMC_PART_USER;
+        } else {
+            dprintf(CRITICAL, "[eMMC] Fail to get boot part\n");
+            return -1;
+        }
+    }
+
+    return err;
+}
+
+int mmc_set_boot_part(u32 bootpart)
+{
+    struct mmc_host *host;
+    struct mmc_card *card;
+    int err = MMC_ERR_NONE;
+    u8 part_config;
+    u8 cur_bootpart;
+
+    host = &msdc_host0;
+    card = &emmc_card;
+
+    if (bootpart !=  EMMC_PART_BOOT1
+            && bootpart !=  EMMC_PART_BOOT2
+            && bootpart !=  EMMC_PART_USER)
+        return -1;
+
+    if (!card || !host)
+        return -1;
+
+    err = mmc_read_ext_csd(host, card);
+    if (err != MMC_ERR_NONE)
+        goto out;
+
+    part_config = card->ext_csd.part_cfg;
+    cur_bootpart = (card->ext_csd.part_cfg >> 3) & 0x07;
+
+    if (((u32)cur_bootpart) == bootpart)
+        goto out;
+    LTRACEF("[SD0] Current boot part is %d\n", cur_bootpart);
+
+    part_config = (part_config & (~(0x7 << 3))) | (bootpart << 3);
+    LTRACEF("[SD0] Set boot part as %d\n", bootpart);
+    err = mmc_switch(host, card,
+                     EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CFG, part_config);
+
+out:
+    return err;
+}
+
+static int mmc_set_part_config(struct mmc_card *card, u8 cfg)
+{
+    int err = MMC_ERR_FAILED;
+
+    if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+        goto out;
+
+    err = mmc_set_ext_csd(card, EXT_CSD_PART_CFG, cfg);
+out:
+    return err;
+}
+
+static int mmc_boot_config(struct mmc_card *card, u8 acken, u8 enpart, u8 buswidth, u8 busmode)
+{
+    int err = MMC_ERR_FAILED;
+    u8 val;
+    u8 rst_bwidth = 0;
+    u8 cfg;
+
+    if (card->csd.mmca_vsn < CSD_SPEC_VER_4 ||
+            !card->ext_csd.boot_info || card->ext_csd.rev < 3)
+        goto out;
+
+    cfg = card->ext_csd.part_cfg;
+    /* configure boot partition */
+    val = acken | (cfg & 0x3F);
+    err = mmc_set_part_config(card, val);
+    if (err != MMC_ERR_NONE)
+        goto out;
+    else
+        card->ext_csd.part_cfg = val;
+
+    /* configure boot bus mode and width */
+    rst_bwidth = (buswidth != EXT_CSD_BOOT_BUS_WIDTH_1 ? 1 : 0) << 2;
+    LTRACEF(" =====Set boot Bus Width<%d>=======\n", buswidth);
+    LTRACEF(" =====Set boot Bus mode<%d>=======\n", busmode);
+    err = mmc_set_boot_bus(card, rst_bwidth, busmode, buswidth);
+out:
+
+    return err;
+}
+
+static int emmc_boot_prepare(struct mmc_card *card)
+{
+    int err = MMC_ERR_NONE;
+    u8 buswidth = EXT_CSD_BOOT_BUS_WIDTH_1;
+
+    if (TRAPPING_IS_EMMC_BOOT_BUS_WIDTH_8BIT())
+        buswidth = EXT_CSD_BOOT_BUS_WIDTH_8;
+
+    err = mmc_boot_config(card, EXT_CSD_PART_CFG_EN_ACK,
+                          EXT_CSD_PART_CFG_EN_BOOT_PART_1,
+                          buswidth, EXT_CSD_BOOT_BUS_MODE_DEFT);
+    if (err)
+        goto exit;
+
+    err = mmc_set_reset_func(card, 1);
+exit:
+    return err;
+}
+
+static int mmc_dev_bread(struct mmc_card *card, unsigned long blknr, u32 blkcnt, u8 *dst)
+{
+    struct mmc_host *host = card->host;
+    u32 blksz = host->blklen;
+    int tune = 0;
+    int retry = 3;
+    int err;
+    unsigned long src;
+
+    src = mmc_card_highcaps(card) ? blknr : blknr * blksz;
+
+    do {
+        if (!tune) {
+            err = host->blk_read(host, (uchar *)dst, src, blkcnt);
+        } else {
+#ifdef FEATURE_MMC_RD_TUNING
+            err = msdc_tune_bread(host, (uchar *)dst, src, blkcnt);
+#endif
+            if (err && (host->sclk > (host->f_max >> 4)))
+                mmc_set_clock(host, card->state, host->sclk >> 1);
+        }
+        if (err == MMC_ERR_NONE) {
+            break;
+        }
+
+        if (err == MMC_ERR_BADCRC || err == MMC_ERR_ACMD_RSPCRC || err == MMC_ERR_CMD_RSPCRC) {
+            tune = 1;
+            retry++;
+        } else if (err == MMC_ERR_READTUNEFAIL || err == MMC_ERR_CMDTUNEFAIL) {
+            dprintf(CRITICAL, "[eMMC] Fail to tuning,%s",
+                    (err == MMC_ERR_CMDTUNEFAIL) ?
+                    "cmd tune failed!\n" : "read tune failed!\n");
+            break;
+        }
+    } while (retry--);
+
+    return err;
+}
+
+static int mmc_dev_bwrite(struct mmc_card *card, unsigned long blknr,
+                          u32 blkcnt, const u8 *src)
+{
+    struct mmc_host *host = card->host;
+    u32 blksz = host->blklen;
+    u32 status;
+    int tune = 0;
+    int retry = 3;
+    int err;
+    unsigned long dst;
+
+    dst = mmc_card_highcaps(card) ? blknr : blknr * blksz;
+
+    do {
+        if (!tune) {
+            err = host->blk_write(host, dst, (uchar *)src, blkcnt);
+        } else {
+#ifdef FEATURE_MMC_WR_TUNING
+            err = msdc_tune_bwrite(host, dst, (uchar *)src, blkcnt);
+#endif
+            if (err && (host->sclk > (host->f_max >> 4)))
+                mmc_set_clock(host, card->state, host->sclk >> 1);
+        }
+        if (err == MMC_ERR_NONE) {
+            do {
+                err = mmc_send_status(host, card, &status);
+                if (err) {
+                    dprintf(CRITICAL, "[eMMC] Fail to send status %d\n", err);
+                    break;
+                }
+            } while (!(status & R1_READY_FOR_DATA) ||
+                     (R1_CURRENT_STATE(status) == 7));
+            LTRACEF("[eMMC] Write %d bytes (DONE)\n", blkcnt * blksz);
+            break;
+        }
+
+        if (err == MMC_ERR_BADCRC || err == MMC_ERR_ACMD_RSPCRC || err == MMC_ERR_CMD_RSPCRC) {
+            tune = 1;
+            retry++;
+        } else if (err == MMC_ERR_WRITETUNEFAIL || err == MMC_ERR_CMDTUNEFAIL) {
+            dprintf(CRITICAL, "[eMMC] Fail to tuning,%s",
+                    (err == MMC_ERR_CMDTUNEFAIL) ?
+                    "cmd tune failed!\n" : "write tune failed!\n");
+            break;
+        }
+    } while (retry--);
+
+    return err;
+}
+
+static ssize_t mmc_block_read(struct bdev *dev, void *buf, bnum_t block,
+                              uint count)
+{
+    mmc_dev_t *__dev = (mmc_dev_t *)dev;
+    struct mmc_host *host = __dev->host;
+    struct mmc_card *card = __dev->card;
+    u32 maxblks = host->max_phys_segs;
+    u32 leftblks, totalblks = count;
+    ssize_t ret = 0;
+
+    mutex_acquire(&host->lock);
+    if (mmc_switch_part(__dev)) {
+        ret = ERR_IO;
+        goto done;
+    }
+
+    do {
+        leftblks = ((count > maxblks) ? maxblks : count);
+        if (mmc_dev_bread(card, (unsigned long)block, leftblks, buf)) {
+            ret = ERR_IO;
+            goto done;
+        }
+        block += leftblks;
+        buf += maxblks * dev->block_size;
+        count -= leftblks;
+    } while (count);
+
+    if (dev->block_size * totalblks > 0x7fffffffU)
+        /* ssize_t is defined as signed, should take a look here */
+        dprintf(CRITICAL, "[MSDC] %s: WARN! The return size is overflow! 0x%lx\n",
+                __func__, dev->block_size * totalblks);
+
+done:
+    mutex_release(&host->lock);
+    return ret ? ret : (ssize_t)dev->block_size * totalblks;
+}
+
+static ssize_t mmc_block_write(struct bdev *dev, const void *buf, bnum_t block,
+                               uint count)
+{
+    mmc_dev_t *__dev = (mmc_dev_t *)dev;
+    struct mmc_host *host = __dev->host;
+    struct mmc_card *card = __dev->card;
+    u32 maxblks = host->max_phys_segs;
+    u32 leftblks, totalblks = count;
+    ssize_t ret = 0;
+
+    mutex_acquire(&host->lock);
+    if (mmc_switch_part(__dev)) {
+        ret = ERR_IO;
+        goto done;
+    }
+
+    do {
+        leftblks = ((count > maxblks) ? maxblks : count);
+        if (mmc_dev_bwrite(card, (unsigned long)block, leftblks, buf)) {
+            ret = ERR_IO;
+            goto done;
+        }
+        block += leftblks;
+        buf = (u8 *)buf + maxblks * dev->block_size;
+        count -= leftblks;
+    } while (count);
+
+    if (dev->block_size * totalblks > 0x7fffffffU)
+        /* ssize_t is defined as signed, should take a look here */
+        dprintf(CRITICAL, "[MSDC] %s: WARN! The return size is overflow! 0x%lx\n",
+                __func__, dev->block_size * totalblks);
+
+done:
+    mutex_release(&host->lock);
+    return ret ? ret: (ssize_t)dev->block_size * totalblks;
+}
+
+static ssize_t mmc_wrap_erase(struct bdev *bdev, off_t offset, size_t len)
+{
+    mmc_dev_t *dev = (mmc_dev_t *)bdev;
+    struct mmc_host *host = dev->host;
+    ssize_t ret = 0;
+
+    mutex_acquire(&host->lock);
+    if (mmc_switch_part(dev)) {
+        ret = ERR_IO;
+        goto done;
+    }
+
+    /* ATTENTION:
+     * We use TRIM here, which is block-based(512B) wipping,
+     * If using ERASE here, please ensure the offset & size are
+     * erase-group aligned,
+     * OTHERWISE, some valid data may be wiped. refer to JEDEC spec:
+     * The Device will ignore all LSB's below the Erase Group size,
+     * effectively ROUNDING the address DOWN to the Erase Group boundary. */
+    ASSERT(dev && len);
+    if ((offset % MMC_BLOCK_SIZE) || (len % MMC_BLOCK_SIZE)) {
+        dprintf(CRITICAL, "%s: offset(0x%llx)/len(%lu) is not block-aligned!\n",
+                __func__, offset, len);
+        ret = ERR_IO;
+        goto done;
+    }
+
+    ASSERT(dev->card);
+    if (mmc_do_trim(dev->card, offset, len)) {
+        ret = ERR_IO;
+        goto done;
+    }
+
+done:
+    mutex_release(&host->lock);
+    return ret ? ret: (ssize_t)len;
+}
+
+static ssize_t mmc_rpmb_dummy_read(struct bdev *dev, void *buf, bnum_t block,
+                                   uint count)
+{
+    return 0;
+}
+
+static ssize_t mmc_rpmb_dummy_write(struct bdev *dev, const void *buf, bnum_t block,
+                                    uint count)
+{
+    return 0;
+}
+
+static ssize_t mmc_rpmb_dummy_erase(struct bdev *bdev, off_t offset, size_t len)
+{
+    return 0;
+}
+
+static int mmc_set_block_count(struct mmc_host *host, unsigned int blockcount,
+                               bool is_rel_write)
+{
+    struct mmc_command cmd = { .opcode = 0 };
+
+    cmd.opcode = MMC_CMD_SET_BLOCK_COUNT;
+    cmd.arg = blockcount & 0x0000FFFF;
+    if (is_rel_write)
+        cmd.arg |= 1 << 31;
+    cmd.rsptyp = RESP_R1;
+
+    return mmc_cmd(host, &cmd);
+}
+
+static int mmc_rpmb_ioctl_cmd(struct bdev *dev, struct mmc_ioc_cmd *arg)
+{
+    mmc_dev_t *__dev = (mmc_dev_t *)dev;
+    struct mmc_host *host = __dev->host;
+    //struct mmc_card *card = __dev->card;
+    struct mmc_command cmd = { .opcode = 0 };
+    struct mmc_data data = { .buf = NULL };
+    addr_t base = host->base;
+    int ret = 0;
+    u32 status;
+    int old_autocmd = msdc_get_autocmd(host);
+
+    msdc_set_autocmd(host, 0);
+    cmd.opcode = arg->opcode;
+    cmd.arg = arg->arg;
+    cmd.rsptyp = arg->flags; /* arg->flags must be type of enum of RESP_NONE ~ RESP_R1B */
+
+    if (arg->blocks) {
+        ret = mmc_set_block_count(host, arg->blocks,
+                                  arg->write_flag & (1 << 31));
+        if (ret != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "mmc cmd23 failed!\n");
+            goto out;
+        }
+    }
+
+    if (arg->blocks) {
+        MSDC_DMA_ON;
+        MSDC_CLR_FIFO();
+        MSDC_WRITE32(SDC_BLK_NUM, arg->blocks);
+        host->blklen = 512;
+        msdc_set_timeout(host, 100000000, 0);
+        ret = mmc_cmd(host, &cmd);
+        if (ret != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "mmc cmd failed\n");
+            goto out;
+        }
+
+        data.cmd = &cmd;
+        data.blks = arg->blocks;
+        data.buf = (uchar *)arg->data_ptr;
+        data.timeout = 100;
+        ret = msdc_dma_transfer(host, &data);
+        MSDC_DMA_OFF;
+
+    } else {
+        ret = mmc_cmd(host, &cmd);
+    }
+
+    if (ret == MMC_ERR_NONE && arg->write_flag & (1 << 31)) {
+        /* should use CMD13 to polling busy status */
+        do {
+            ret = mmc_send_status(host, host->card, &status);
+            if (ret) {
+                dprintf(CRITICAL, "error %d sending CMD13!\n", ret);
+                break;
+            }
+        } while (R1_CURRENT_STATE(status) == 7);
+    }
+out:
+    msdc_set_autocmd(host, old_autocmd);
+    return ret;
+}
+
+static int mmc_rpmb_ioctl(struct bdev *dev, int request, void *argp)
+{
+    mmc_dev_t *__dev = (mmc_dev_t *)dev;
+    struct mmc_host *host = __dev->host;
+    int ret = 0;
+
+    mutex_acquire(&host->lock);
+    if (mmc_switch_part(__dev)) {
+        ret = ERR_IO;
+        goto done;
+    }
+
+    switch ((unsigned int)request) {
+        case BIO_IOCTL_MMC_IOC_CMD:
+            ret = mmc_rpmb_ioctl_cmd(dev, (struct mmc_ioc_cmd *)argp);
+            break;
+        default:
+            ret = ERR_INVALID_ARGS;
+            break;
+    }
+
+done:
+    mutex_release(&host->lock);
+    return ret;
+}
+
+static int mmc_ioctl(struct bdev *dev, int request, void *argp)
+{
+    mmc_dev_t *__dev = (mmc_dev_t *)dev;
+    struct mmc_host *host = __dev->host;
+    int ret = 0;
+
+    mutex_acquire(&host->lock);
+    if (mmc_switch_part(__dev)) {
+        ret = ERR_IO;
+        goto done;
+    }
+
+    switch (request) {
+        case BIO_IOCTL_MMC_SET_BOOT:
+            ret = mmc_set_boot_part(*(u32 *)argp);
+            break;
+        case BIO_IOCTL_MMC_GET_BOOT:
+            ret = mmc_get_boot_part((u32 *)argp);
+            break;
+        case BIO_IOCTL_QUERY_CAP_REWRITABLE:
+            *(bool *)argp = true;
+            ret = NO_ERROR;
+            break;
+        default:
+            ret = ERR_INVALID_ARGS;
+            break;
+    }
+
+done:
+    mutex_release(&host->lock);
+    return ret;
+}
+
+static int mmc_init_mem_card_stage1(struct mmc_host *host,
+                                    struct mmc_card *card, u32 ocr)
+{
+    int err;
+
+    /*
+     * Sanity check the voltages that the card claims to
+     * support.
+     */
+    if (ocr & 0x7F)
+        ocr &= ~0x7F;
+
+    ocr = host->ocr = mmc_select_voltage(host, ocr);
+
+    /*
+     * Can we support the voltage(s) of the card(s)?
+     */
+    if (!host->ocr) {
+        err = MMC_ERR_FAILED;
+        goto out;
+    }
+
+    err = mmc_go_idle(host);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in GO_IDLE_STATE cmd\n");
+        goto out;
+    }
+
+    /* send interface condition */
+    if (mmc_card_sd(card))
+        err = mmc_send_if_cond(host, ocr);
+
+    /* host support HCS[30] */
+    ocr |= (1 << 30);
+
+    /* send operation condition */
+    if (mmc_card_sd(card)) {
+        err = mmc_send_app_op_cond_once(host, ocr, &card->ocr);
+    } else {
+        /* The extra bit indicates that we support high capacity */
+        err = mmc_send_op_cond_once(host, ocr, &card->ocr);
+    }
+
+out:
+    /* MMC_ERR_RETRY is not error */
+    return err;
+}
+
+static int mmc_init_mem_card_stage2(struct mmc_host *host,
+                                    struct mmc_card *card, bool retry_opcond)
+{
+    int err = MMC_ERR_NONE;
+    u32 ocr = host->ocr;
+
+    /* Since do not send CMD1 in BL33 stage, so just assume card capacity > 2GB */
+    if (host->skip_reinit) {
+        card->state |= MMC_STATE_HIGHCAPS;
+        card->rca = 0x1;
+        goto deselect_card;
+    }
+    /* host support HCS[30] */
+    ocr |= (1 << 30);
+
+    if (retry_opcond) {
+        /* send operation condition */
+        if (mmc_card_sd(card)) {
+            err = mmc_send_app_op_cond(host, ocr, &card->ocr);
+        } else {
+            /* The extra bit indicates that we support high capacity */
+            err = mmc_send_op_cond(host, ocr, &card->ocr);
+        }
+    }
+
+    if (err != MMC_ERR_NONE) {
+        LTRACEF("Fail in SEND_OP_COND cmd\n");
+        goto out;
+    }
+
+    /* set hcs bit if a high-capacity card */
+    card->state |= ((card->ocr >> 30) & 0x1) ? MMC_STATE_HIGHCAPS : 0;
+    /* send cid */
+    err = mmc_all_send_cid(host, card->raw_cid);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in SEND_CID cmd\n");
+        goto out;
+    }
+
+    /* assign a rca */
+    card->rca = 0x1;
+
+    /* set/send rca */
+    err = mmc_send_relative_addr(host, card, &card->rca);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in SEND_RCA cmd\n");
+        goto out;
+    }
+
+deselect_card:
+    /* de-select card for re-send CMD9 */
+    if (host->skip_reinit) {
+        err = mmc_deselect_card(host, card);
+        if (err) {
+            /* should not have error, since deselect cmd has no response */
+            dprintf(CRITICAL, "BL33 stage, failed to deselect card!\n");
+            goto out;
+        }
+    }
+    /* send csd */
+    err = mmc_read_csds(host, card);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in SEND_CSD cmd\n");
+        goto out;
+    }
+    mmc_decode_csd(card);
+
+    /* select this card */
+    err = mmc_select_card(host, card);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in select card cmd\n");
+        goto out;
+    }
+
+    if (mmc_card_sd(card)) {
+        /* set bus width */
+        mmc_set_bus_width(host, card, HOST_BUS_WIDTH_4);
+        /* compute bus speed.  usd defalut speed */
+        card->maxhz = 26000000;
+        mmc_set_clock(host, card->state, card->maxhz);
+    } else {
+
+        /* send ext csd */
+        err = mmc_read_ext_csd(host, card);
+        if (err != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "[eMMC] Fail in SEND_EXT_CSD cmd\n");
+            goto out;
+        }
+
+        /*
+         * if eMMC has alreay in HS400 mode, will fail when set bus-width
+         */
+        if (host->skip_reinit && (card->ext_csd.hs_timing == 0x03)) {
+            LTRACEF("already in hs400 mode, skip tuning!\n");
+            mmc_card_set_hs200(card);
+            mmc_card_set_hs400(card);
+            mmc_set_clock(host, card->state, card->ext_csd.hs_max_dtr);
+            msdc_set_timeout(host, 100000000, 0);
+            goto card_init_done;
+        }
+
+        if (host->caps & MMC_CAP_EMMC_HS200 && host->caps & MMC_CAP_EMMC_HS400) {
+            if (card->ext_csd.hs400_support) {
+                err = mmc_select_hs200(card);
+                if (err != MMC_ERR_NONE)
+                    goto select_hs;
+                err = mmc_hs200_tuning(card);
+                if (err != MMC_ERR_NONE)
+                    goto select_hs;
+                err = mmc_select_hs400(card);
+                if (err != MMC_ERR_NONE)
+                    goto select_hs;
+                else
+                    goto card_init_done;
+            }
+        }
+
+select_hs:
+        /* activate high speed (if supported) */
+        if ((card->ext_csd.hs_max_dtr != 0) && (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
+            mmc_set_clock(host, 0, host->f_min);
+            err = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
+            if (err == MMC_ERR_NONE) {
+                LTRACEF("[eMMC] Switched to High-Speed mode!\n");
+                mmc_card_clear_hs200(card);
+                mmc_card_clear_hs400(card);
+                mmc_card_clear_ddr(card);
+                mmc_card_set_highspeed(card);
+                mmc_set_clock(host, card->state, 50000000);
+                /* set bus width */
+                mmc_set_bus_width(host, card, HOST_BUS_WIDTH_8);
+            }
+        }
+
+card_init_done:
+        /* compute bus speed. */
+        card->maxhz = (unsigned int)-1;
+
+        if (mmc_card_highspeed(card) || mmc_card_hs400(card)) {
+            if (card->maxhz > card->ext_csd.hs_max_dtr)
+                card->maxhz = card->ext_csd.hs_max_dtr;
+        } else if (card->maxhz > card->csd.max_dtr) {
+            card->maxhz = card->csd.max_dtr;
+        }
+    }
+
+    if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
+        /* The EXT_CSD sector count is in number or 512 byte sectors. */
+        card->blklen = MMC_BLOCK_SIZE;
+        card->nblks  = card->ext_csd.sectors;
+    } else {
+        /* The CSD capacity field is in units of read_blkbits.
+         * set_capacity takes units of 512 bytes.
+         */
+        card->blklen = MMC_BLOCK_SIZE;
+        host->blklen = MMC_BLOCK_SIZE;
+        card->nblks  = card->csd.capacity << (card->csd.read_blkbits - 9);
+    }
+
+    dprintf(CRITICAL,"[eMMC/SD] Size: %d MB, Max.Speed: %d kHz, blklen(%d), nblks(%d), ro(%d)\n",
+            ((card->nblks / 1024) * card->blklen) / 1024 , card->maxhz / 1000,
+            card->blklen, card->nblks, mmc_card_readonly(card));
+
+    card->ready = 1;
+
+    LTRACEF("[eMMC/SD] Initialized\n");
+out:
+    return err;
+}
+
+static int mmc_init_card_stage1(struct mmc_host *host, struct mmc_card *card)
+{
+    int err = 0;
+    u32 ocr;
+
+    LTRACEF("[%s]: start\n", __func__);
+    memset(card, 0, sizeof(struct mmc_card));
+
+    mmc_card_set_present(card);
+    mmc_card_set_host(card, host);
+    mmc_card_set_unknown(card);
+
+    /* only consider of eMMC, don't care SD */
+    if (host->skip_reinit)
+        goto skip_reinit;
+
+    err = mmc_go_idle(host);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in GO_IDLE_STATE cmd\n");
+        goto out;
+    }
+
+    /* send interface condition */
+    if (host->host_id)
+        mmc_send_if_cond(host, host->ocr_avail);
+
+    /* query operation condition */
+
+    if (host->host_id) {
+        err = mmc_send_app_op_cond(host, 0, &ocr);
+        if (err != MMC_ERR_NONE) {
+            err = mmc_send_op_cond(host, 0, &ocr);
+            if (err != MMC_ERR_NONE) {
+                LTRACEF("Fail in MMC_CMD_SEND_OP_COND/SD_ACMD_SEND_OP_COND cmd\n");
+                goto out;
+            }
+            mmc_card_set_mmc(card);
+        } else {
+            mmc_card_set_sd(card);
+        }
+    } else {
+        err = mmc_send_op_cond(host, 0, &ocr);
+        if (err != MMC_ERR_NONE) {
+            LTRACEF("Fail in MMC_CMD_SEND_OP_COND/SD_ACMD_SEND_OP_COND cmd\n");
+            goto out;
+        }
+        mmc_card_set_mmc(card);
+    }
+
+    host->card = card;
+
+skip_reinit:
+    if (host->skip_reinit)
+        mmc_card_set_mmc(card);
+    else
+        err = mmc_init_mem_card_stage1(host, card, ocr);
+
+out:
+    return err;
+}
+
+static int mmc_init_card_stage2(struct mmc_host *host, struct mmc_card *card,
+                                bool retry_opcond)
+{
+    int err;
+
+    err = mmc_init_mem_card_stage2(host, card, retry_opcond);
+    if (err) {
+        dprintf(CRITICAL, "[%s]: failed, err=%d\n", __func__, err);
+        return err;
+    }
+    host->card = card;
+    LTRACEF("[%s]: finish successfully\n",__func__);
+    return 0;
+}
+
+static inline int mmc_init_host(struct mmc_host *host)
+{
+    mutex_init(&host->lock);
+    return msdc_init(host);
+}
+
+static int mmc_bio_ops(const void *name, const int part_id, const int nblks,
+                        struct mmc_host *host, struct mmc_card *card)
+{
+    mmc_dev_t *dev;
+    bio_erase_geometry_info_t *geometry;
+
+    dev = malloc(sizeof(mmc_dev_t));
+    /* malloc fail */
+    ASSERT(dev);
+    /* construct the block device */
+    memset(dev, 0, sizeof(mmc_dev_t));
+
+    geometry = (bio_erase_geometry_info_t *)malloc(sizeof(bio_erase_geometry_info_t));
+    if (!geometry) {
+        dprintf(CRITICAL, "%s: no enough memory for geometry\n", __func__);
+        free(dev);
+        return -1;
+    }
+
+    /* setup partition id*/
+    dev->part_id = part_id;
+    /* setup host */
+    dev->host = host;
+    /* setup card */
+    dev->card = card;
+
+    geometry->start = 0;
+    geometry->size = card->nblks * card->blklen;
+    geometry->erase_size = 512;
+    geometry->erase_shift = log2_uint(geometry->erase_size);
+    /* bio block device register */
+    bio_initialize_bdev(&dev->bdev, name,
+                        card->blklen, nblks,
+                        1, geometry, BIO_FLAGS_NONE);
+    /* override our block device hooks */
+    if (part_id == EXT_CSD_PART_CFG_RPMB_PART) {
+        dev->bdev.read_block = mmc_rpmb_dummy_read;
+        dev->bdev.write_block = mmc_rpmb_dummy_write;
+        dev->bdev.erase = mmc_rpmb_dummy_erase;
+        dev->bdev.ioctl = mmc_rpmb_ioctl;
+    } else {
+        dev->bdev.read_block = mmc_block_read;
+        dev->bdev.write_block = mmc_block_write;
+        dev->bdev.erase = mmc_wrap_erase;
+        if (part_id == EXT_CSD_PART_CFG_DEFT_PART)
+            dev->bdev.ioctl = mmc_ioctl;
+    }
+    bio_register_device(&dev->bdev);
+    return (partition_publish(dev->bdev.name, 0x0) < 0) ? -1 : 0;
+}
+
+struct mmc_card *emmc_init_stage1(bool *retry_opcond, bool skip_reinit)
+{
+    int err = MMC_ERR_NONE;
+    struct mmc_host *host;
+    struct mmc_card *card;
+
+    host = &msdc_host0;
+    /* construct the block device */
+    memset(host, 0, sizeof(struct mmc_host));
+    host->host_id = 0;
+
+    host->skip_reinit = skip_reinit;
+
+    card = &emmc_card;
+    /* construct the block device */
+    memset(card, 0, sizeof(struct mmc_card));
+
+    err = mmc_init_host(host);
+
+    if (err == MMC_ERR_NONE)
+        err = mmc_init_card_stage1(host, card);
+
+    if (err && err != MMC_ERR_RETRY) {
+        dprintf(CRITICAL, "failed in %s \n", __func__);
+        return NULL;
+    } else if (err == MMC_ERR_RETRY) {
+        *retry_opcond = true;
+    } else {
+        *retry_opcond = false;
+    }
+
+    return card;
+}
+
+int emmc_init_stage2(struct mmc_card *card, bool retry_opcond, bool skip_reinit)
+{
+    int err = MMC_ERR_NONE;
+    struct mmc_host *host;
+    int boot_part_nblks = 0;
+    int rpmb_part_nblks = 0;
+
+    host = card->host;
+
+    host->skip_reinit = skip_reinit;
+
+    err = mmc_init_card_stage2(host, card, retry_opcond);
+    /* mmc init fail */
+    ASSERT(err == MMC_ERR_NONE);
+
+    err = emmc_boot_prepare(card);
+    ASSERT(err == MMC_ERR_NONE);
+
+    err = mmc_bio_ops("mmc0", EXT_CSD_PART_CFG_DEFT_PART, card->nblks, host, card);
+    if (err)
+        goto error;
+    boot_part_nblks = card->ext_csd.boot_part_sz/card->blklen;
+    err = mmc_bio_ops("mmc0boot0", EXT_CSD_PART_CFG_BOOT_PART_1, boot_part_nblks,
+                host, card);
+    if (err)
+        goto error;
+    err = mmc_bio_ops("mmc0boot1", EXT_CSD_PART_CFG_BOOT_PART_2, boot_part_nblks,
+                host, card);
+    if (err)
+        goto error;
+    rpmb_part_nblks = card->ext_csd.rpmb_sz/card->blklen;
+    err = mmc_bio_ops("mmc0rpmb", EXT_CSD_PART_CFG_RPMB_PART, rpmb_part_nblks,
+                host, card);
+
+error:
+    return err;
+}
+
+int sdmmc_init(u8 host_id, bool skip_reinit)
+{
+    int err = MMC_ERR_NONE;
+    struct mmc_host *host;
+    struct mmc_card *card;
+    bool retry_opcond;
+
+    printf("%s enter\n", __func__);
+
+    host = malloc(sizeof(struct mmc_host));
+    /* malloc fail */
+    if (!host) {
+        LTRACEF("Failed to malloc host!\n");
+        err = -ENOMEM;
+        goto end;
+    }
+    /* construct the block device */
+    memset(host, 0, sizeof(struct mmc_host));
+    host->host_id = host_id;
+
+    host->skip_reinit = skip_reinit;
+
+    card = malloc(sizeof(struct mmc_card));
+    /* malloc fail */
+    if (!card) {
+        LTRACEF("Failed to malloc card!\n");
+        free(host);
+        err = -ENOMEM;
+        goto end;
+    }
+    /* construct the block device */
+    memset(card, 0, sizeof(struct mmc_card));
+
+    err = mmc_init_host(host);
+
+    if (err == MMC_ERR_NONE)
+        err = mmc_init_card_stage1(host, card);
+    /* mmc init fail */
+    if (err && err != MMC_ERR_RETRY) {
+        LTRACEF("mmc_init_card fail!\n");
+        free(host);
+        free(card);
+        goto end;
+    } else if (err == MMC_ERR_RETRY) {
+        retry_opcond = true;
+    } else {
+        retry_opcond = false;
+    }
+
+    err = mmc_init_card_stage2(host, card, retry_opcond);
+    if (err != MMC_ERR_NONE) {
+        LTRACEF("mmc_init_card fail!\n");
+        free(host);
+        free(card);
+        goto end;
+    }
+    err = mmc_bio_ops("sdmmc1", EXT_CSD_PART_CFG_DEFT_PART, card->nblks, host, card);
+
+end:
+    return err;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/mmc_rpmb.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/mmc_rpmb.c
new file mode 100644
index 0000000..1608510
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/mmc_rpmb.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2017 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 <stdlib.h>
+#include <string.h>
+#include <lib/bio.h>
+#include <platform/mmc_ioctl.h>
+#include <platform/mmc_rpmb.h>
+#include <platform/mtk_bio_ioctl.h>
+#include <platform/mtk_trng.h>
+#include <rpmb_mac.h>
+#include <debug.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+static void reverse_endian(void *data, size_t size)
+{
+    unsigned int i;
+    char tmp;
+    char *swp = (char *)data;
+
+    for (i = 0 ; i< (size/2); ++i) {
+        tmp = swp[i];
+        swp[i] = swp[size-1-i];
+        swp[size-1-i] = tmp;
+    }
+}
+
+int mmc_rpmb_set_key(u8 *key)
+{
+    int ret;
+    bdev_t *rpdev;
+    struct mmc_ioc_cmd *idata;
+    unsigned char *rpmb_pkt;
+    unsigned char nonce[RPMB_SZ_NONCE];
+    unsigned char back_nonce[RPMB_SZ_NONCE];
+    unsigned int i;
+
+    idata = malloc(sizeof(struct mmc_ioc_cmd));
+    if (idata == NULL) {
+        return -2;
+    }
+    rpmb_pkt = malloc(512);
+    if (rpmb_pkt == NULL) {
+        free(idata);
+        return -2;
+    }
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+
+    rpdev = bio_open("mmc0rpmb");
+    if (rpdev == NULL) {
+        free(rpmb_pkt);
+        free(idata);
+        return -3;
+    }
+
+    /* get wc for status */
+    rpmb_pkt[0] = 2;
+    if (trng_drv_get_random_data(nonce, RPMB_SZ_NONCE) != RPMB_SZ_NONCE)
+        return -4;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1;
+    reverse_endian(rpmb_pkt, 512);
+    memcpy(rpmb_pkt + RPMB_NONCE_BEG, nonce, RPMB_SZ_NONCE);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_READ_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 0;
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    memcpy(back_nonce, &rpmb_pkt[RPMB_NONCE_BEG], RPMB_SZ_NONCE);
+
+    reverse_endian(rpmb_pkt, 512);
+    /* check result */
+    ret = *(unsigned short *)&rpmb_pkt[2];
+    if (ret != 7) { /* 7 means not programmed yet */
+        for (i = 0; i < RPMB_SZ_NONCE; i++) {
+            if (nonce[i] ^ back_nonce[i]) {
+                dprintf(CRITICAL, "nonce mismatch!\n");
+                ret = -5;
+                goto rpmb_end;
+            }
+        }
+        /* key has already programmed */
+        LTRACEF("ret=%d, rpmb key has already programmed.\n", ret);
+        goto rpmb_end;
+    }
+    LTRACEF("ret=%d, key not programmed yet\n", ret);
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+
+    rpmb_pkt[0] = 1;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1 << 31;
+    reverse_endian(rpmb_pkt, 512);
+    memcpy(&rpmb_pkt[RPMB_MAC_BEG], key, 32);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+
+    rpmb_pkt[0] = 5;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1;
+    reverse_endian(rpmb_pkt, 512);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_READ_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 0;
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    reverse_endian(rpmb_pkt, 512);
+
+    ret = ((unsigned short *)&rpmb_pkt)[2];
+
+rpmb_end:
+    free(rpmb_pkt);
+    free(idata);
+    bio_close(rpdev);
+    return ret;
+}
+
+int mmc_rpmb_block_read(int blknr, unsigned char blk[256])
+{
+    int ret;
+    bdev_t *rpdev;
+    struct mmc_ioc_cmd *idata;
+    unsigned char *rpmb_pkt;
+    unsigned char mac[RPMB_SZ_MAC];
+    unsigned char nonce[RPMB_SZ_NONCE];
+    unsigned int mac_sz = RPMB_SZ_MAC;
+    int i;
+
+    idata = malloc(sizeof(struct mmc_ioc_cmd));
+    if (idata == NULL)
+        return -2;
+    rpmb_pkt = malloc(512);
+    if (rpmb_pkt == NULL) {
+        free(idata);
+        return -2;
+    }
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+
+    rpdev = bio_open("mmc0rpmb");
+    if (rpdev == NULL) {
+        free(rpmb_pkt);
+        free(idata);
+        return -3;
+    }
+
+    /* read */
+    rpmb_pkt[0] = 4;
+    rpmb_pkt[6] = blknr;
+    if (trng_drv_get_random_data(nonce, RPMB_SZ_NONCE) != RPMB_SZ_NONCE)
+        return -4;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1;
+    reverse_endian(rpmb_pkt, 512);
+    memcpy(rpmb_pkt + RPMB_NONCE_BEG, nonce, RPMB_SZ_NONCE);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+    spin(1000);
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_READ_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 0;
+    reverse_endian(rpmb_pkt, 512);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    ret = *(unsigned short *)&rpmb_pkt[RPMB_RES_BEG];
+    reverse_endian(&ret, sizeof(short));
+    if (ret != 0)
+        goto rpmb_end;
+
+    rpmb_hmac_init(rpmb_pkt + RPMB_DATA_BEG, 512 - RPMB_DATA_BEG);
+    rpmb_hmac_done(mac, &mac_sz);
+    ret = 0;
+    for (i = 0; i < RPMB_SZ_NONCE; i++)
+        ret |= nonce[i] ^ rpmb_pkt[RPMB_NONCE_BEG + i];
+
+    if (ret != 0) {
+        ret = -5;
+        goto rpmb_end;
+    }
+    for (i = 0; i < RPMB_SZ_MAC; i++)
+        ret |= mac[i] ^ rpmb_pkt[RPMB_MAC_BEG + i];
+
+    if (ret != 0) {
+        ret = -1;
+        goto rpmb_end;
+    }
+    memcpy(blk, rpmb_pkt + RPMB_DATA_BEG, RPMB_SZ_DATA);
+    reverse_endian(blk, RPMB_SZ_DATA);
+
+rpmb_end:
+    free(rpmb_pkt);
+    free(idata);
+    bio_close(rpdev);
+    return ret;
+}
+
+int mmc_rpmb_block_write(int blknr, unsigned char blk[256])
+{
+    int ret;
+    bdev_t *rpdev;
+    struct mmc_ioc_cmd *idata;
+    unsigned char *rpmb_pkt;
+    unsigned int wc, mac_sz = RPMB_SZ_MAC;
+    unsigned char nonce[RPMB_SZ_NONCE];
+    unsigned int i;
+
+    idata = malloc(sizeof(struct mmc_ioc_cmd));
+    if (idata == NULL) {
+        return -2;
+    }
+    rpmb_pkt = malloc(512);
+    if (rpmb_pkt == NULL) {
+        free(idata);
+        return -2;
+    }
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+
+    rpdev = bio_open("mmc0rpmb");
+    if (rpdev == NULL) {
+        free(rpmb_pkt);
+        free(idata);
+        return -3;
+    }
+
+    /* get wc */
+    rpmb_pkt[0] = 2;
+    if (trng_drv_get_random_data(nonce, RPMB_SZ_NONCE) != RPMB_SZ_NONCE)
+        return -4;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1;
+    reverse_endian(rpmb_pkt, 512);
+    memcpy(rpmb_pkt + RPMB_NONCE_BEG, nonce, RPMB_SZ_NONCE);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_READ_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 0;
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    ret = 0;
+    for (i = 0; i < RPMB_SZ_NONCE; i++)
+        ret |= nonce[i] ^ rpmb_pkt[RPMB_NONCE_BEG + i];
+
+    if (ret != 0) {
+        ret = -5;
+        goto rpmb_end;
+    }
+    reverse_endian(rpmb_pkt, 512);
+    /* check result */
+    ret = *(unsigned short *)&rpmb_pkt[2];
+    if (ret != 0) /* get success */
+        goto rpmb_end;
+    wc = *(unsigned int *)&rpmb_pkt[8];
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+    /* do write */
+    rpmb_pkt[0] = 0x3;
+    rpmb_pkt[4] = 1;
+    rpmb_pkt[6] = blknr;
+    *(unsigned int *)&rpmb_pkt[8] = wc;
+    memcpy(rpmb_pkt + 28, blk, RPMB_SZ_DATA);
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1<<31;
+    reverse_endian(rpmb_pkt, 512);
+    rpmb_hmac_init(rpmb_pkt + RPMB_DATA_BEG, 512 - RPMB_DATA_BEG);
+    rpmb_hmac_done(rpmb_pkt + RPMB_MAC_BEG, &mac_sz);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+    spin(1000);
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+    /* request to read result back */
+    rpmb_pkt[0] = 0x5;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1;
+    reverse_endian(rpmb_pkt, 512);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    spin(1000);
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+    /* read result back */
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_READ_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 0;
+    reverse_endian(rpmb_pkt, 512);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, BIO_IOCTL_MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    reverse_endian(rpmb_pkt, 512);
+    /* get result */
+    ret = *(unsigned short *)&rpmb_pkt[2];
+
+rpmb_end:
+    free(rpmb_pkt);
+    free(idata);
+    bio_close(rpdev);
+    return ret;
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/msdc.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/msdc.c
new file mode 100644
index 0000000..1618abe
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/msdc.c
@@ -0,0 +1,2096 @@
+/*
+ * 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.
+ */
+#define MSDC_DEBUG_KICKOFF
+
+#include <platform/msdc.h>
+#include <platform/pll.h>
+#include <platform/mmc_core.h>
+#include <kernel/event.h>
+#include <kernel/vm.h>
+#include <platform/interrupts.h>
+#include <platform/mt_irq.h>
+#include <string.h>
+#include <assert.h>
+#include <trace.h>
+
+#define LOCAL_TRACE        0
+
+#define CMD_RETRIES        (5)
+#define CMD_TIMEOUT        (100) /* 100ms */
+
+#define PERI_MSDC_SRCSEL   (0xc100000c)
+
+/* Tuning Parameter */
+#define DEFAULT_DEBOUNCE   (8)  /* 8 cycles */
+#define DEFAULT_DTOC       (40) /* data timeout counter. 65536x40 sclk. */
+#define DEFAULT_WDOD       (0)  /* write data output delay. no delay. */
+#define DEFAULT_BSYDLY     (8)  /* card busy delay. 8 extend sclk */
+
+#define MSDC_USE_PATCH_BIT2_TURNING_WITH_ASYNC 1
+/* Declarations */
+static int msdc_send_cmd(struct mmc_host *host, struct mmc_command *cmd);
+static int msdc_wait_cmd_done(struct mmc_host *host, struct mmc_command *cmd);
+static int msdc_tune_cmdrsp(struct mmc_host *host, struct mmc_command *cmd);
+
+typedef struct {
+    int    autocmd;
+    int    rdsmpl;
+    int    wdsmpl;
+    int    rsmpl;
+    int    start_bit;
+} msdc_priv_t;
+
+static int msdc_rsp[] = {
+    0,  /* RESP_NONE */
+    1,  /* RESP_R1 */
+    2,  /* RESP_R2 */
+    3,  /* RESP_R3 */
+    4,  /* RESP_R4 */
+    1,  /* RESP_R5 */
+    1,  /* RESP_R6 */
+    1,  /* RESP_R7 */
+    7,  /* RESP_R1b */
+};
+
+struct msdc_cust {
+    unsigned char  clk_src;           /* host clock source             */
+    unsigned char  hclk_src;           /* host clock source             */
+    unsigned char  cmd_edge;          /* command latch edge            */
+    unsigned char  data_edge;         /* data latch edge               */
+#define MSDC_SMPL_RISING        (0)
+#define MSDC_SMPL_FALLING       (1)
+#define MSDC_SMPL_SEPERATE      (2)
+    unsigned char  clk_drv;           /* clock pad driving             */
+    unsigned char  cmd_drv;           /* command pad driving           */
+    unsigned char  dat_drv;           /* data pad driving              */
+    unsigned char  rst_drv;           /* reset pin pad driving         */
+    unsigned char  ds_drv;            /* ds pad driving                */
+    unsigned char  data_pins;         /* data pins                     */
+    unsigned int   data_offset;       /* data address offset           */
+    unsigned int   flags;             /* hardware capability flags     */
+#define MSDC_CD_PIN_EN      (1 << 0)  /* card detection pin is wired   */
+#define MSDC_WP_PIN_EN      (1 << 1)  /* write protection pin is wired */
+#define MSDC_RST_PIN_EN     (1 << 2)  /* emmc reset pin is wired       */
+#define MSDC_SDIO_IRQ       (1 << 3)  /* use internal sdio irq (bus)   */
+#define MSDC_EXT_SDIO_IRQ   (1 << 4)  /* use external sdio irq         */
+#define MSDC_REMOVABLE      (1 << 5)  /* removable slot                */
+#define MSDC_SYS_SUSPEND    (1 << 6)  /* suspended by system           */
+#define MSDC_HIGHSPEED      (1 << 7)  /* high-speed mode support       */
+#define MSDC_UHS1           (1 << 8)  /* uhs-1 mode support            */
+#define MSDC_DDR            (1 << 9)  /* ddr mode support              */
+#define MSDC_HS200          (1 << 10) /* hs200 mode support(eMMC4.5)   */
+#define MSDC_HS400          (1 << 11) /* hs200 mode support(eMMC5.0)   */
+} msdc_cap[2] = {
+    {
+        MSDC50_CLKSRC_DEFAULT, /* host clock source          */
+        MSDC50_CLKSRC4HCLK_273MHZ, /* host clock source          */
+        MSDC_SMPL_RISING,   /* command latch edge            */
+        MSDC_SMPL_RISING,   /* data latch edge               */
+        MSDC_DRVN_GEAR2,    /* clock pad driving             */
+        MSDC_DRVN_GEAR2,    /* command pad driving           */
+        MSDC_DRVN_GEAR2,    /* data pad driving              */
+        MSDC_DRVN_GEAR2,    /* rst pad driving               */
+        MSDC_DRVN_GEAR2,    /* ds pad driving                */
+        8,                  /* data pins                     */
+        0,                  /* data address offset           */
+        MSDC_HIGHSPEED | MSDC_HS200 | MSDC_HS400
+    },
+
+    {
+        MSDC50_CLKSRC_DEFAULT, /* host clock source          */
+        MSDC50_CLKSRC4HCLK_273MHZ, /* host clock source          */
+        MSDC_SMPL_RISING,   /* command latch edge            */
+        MSDC_SMPL_RISING,   /* data latch edge               */
+        MSDC_DRVN_GEAR2,    /* clock pad driving             */
+        MSDC_DRVN_GEAR2,    /* command pad driving           */
+        MSDC_DRVN_GEAR2,    /* data pad driving              */
+        MSDC_DRVN_GEAR2,    /* rst pad driving               */
+        MSDC_DRVN_GEAR2,    /* ds pad driving                */
+        4,                  /* data pins                     */
+        0,                  /* data address offset           */
+        MSDC_HIGHSPEED
+    },
+};
+
+static event_t msdc_int_event;
+static u32 g_int_status = 0;
+static msdc_priv_t msdc_priv;
+static u32 hclks_msdc30[] = { 26000000, 208000000, 200000000, 156000000,
+                              182000000, 156000000, 178280000
+                            };
+
+/* add function for MSDC_PAD_CTL handle */
+#ifndef FPGA_PLATFORM
+static void msdc_set_smt(struct mmc_host *host, int smt)
+{
+    MSDC_SET_FIELD(MSDC_CTRL0, MSDC0_CLK_SMT, smt);
+    MSDC_SET_FIELD(MSDC_CTRL4, MSDC0_DS_SMT, smt);
+    MSDC_SET_FIELD(MSDC_CTRL1, MSDC0_CMD_SMT, smt);
+    MSDC_SET_FIELD(MSDC_CTRL2, MSDC0_DAT_SMT, smt);
+}
+
+/* pull up means that host driver the line to HIGH
+ * pull down means that host driver the line to LOW */
+static void msdc_pin_set(struct mmc_host *host, bool pull_down, MSDC_PIN_STATE mode)
+{
+    /* driver CLK/DAT pin */
+    ASSERT(host);
+    ASSERT(mode < MSDC_PST_MAX);
+
+    MSDC_SET_FIELD(MSDC_CTRL0, MSDC0_CLK_PUPD, 1); /* clock is pull-down */
+    MSDC_SET_FIELD(MSDC_CTRL0, MSDC0_CLK_R1R0, 2); /* clock is pull-down 50K */
+
+    MSDC_SET_FIELD(MSDC_CTRL4, MSDC0_DS_PUPD, 1); /* DS is pull-down */
+    MSDC_SET_FIELD(MSDC_CTRL4, MSDC0_DS_R1R0, 2); /* DS is pull-down 50K */
+
+    MSDC_SET_FIELD(MSDC_CTRL1, MSDC0_CMD_PUPD, pull_down);
+    MSDC_SET_FIELD(MSDC_CTRL1, MSDC0_CMD_R1R0, mode);
+
+    MSDC_SET_FIELD(MSDC_CTRL2, MSDC0_DAT_PUPD, pull_down);
+    MSDC_SET_FIELD(MSDC_CTRL2, MSDC0_DAT_R1R0, mode);
+}
+
+/* host can modify from 0-7 */
+static void msdc_set_driving(struct mmc_host *host, struct msdc_cust *msdc_cap)
+{
+    ASSERT(host);
+    ASSERT(msdc_cap);
+
+    if (host && msdc_cap) {
+        MSDC_SET_FIELD(MSDC_CTRL0, MSDC0_DRV_CLK_MASK, msdc_cap->clk_drv);
+        MSDC_SET_FIELD(MSDC_CTRL1, MSDC0_DRV_CMD_MASK, msdc_cap->cmd_drv);
+        MSDC_SET_FIELD(MSDC_CTRL2, MSDC0_DRV_DAT_MASK, msdc_cap->dat_drv);
+        MSDC_SET_FIELD(MSDC_CTRL4, MSDC0_DRV_DS_MASK, msdc_cap->ds_drv);
+    }
+}
+#endif
+
+#ifndef FPGA_PLATFORM /* don't power on/off device and use power-on default volt */
+/* MT2712EVB, GPIO67 to control SD VCCQ, output H --> 3.3V, output L --> 1.8V */
+/* set to 3.3V */
+static void sd_card_vccq_on(void)
+{
+    MSDC_SET_FIELD(GPIO_MODE14, 0x7 << 6, 0);
+    MSDC_SET_BIT32(GPIO_DIR5, 0x1 << 3);
+    MSDC_SET_BIT32(GPIO_DOUT5, 0x1 << 3);
+}
+
+static int pmic_config_interface(int a, int b, int c, int d)
+{
+    return 0;
+}
+
+static void msdc_set_card_pwr(struct mmc_host *host, int on)
+{
+    unsigned int ret;
+
+    ret = pmic_config_interface(0xAB,0x7,0x7,4); /* VMCH=3.3V */
+
+    if (ret == 0) {
+        if (on) {
+            ret = pmic_config_interface(0xAB,0x1,0x1,0); /* VMCH_EN=1 */
+        } else {
+            ret = pmic_config_interface(0xAB,0x0,0x1,0); /* VMCH_EN=0 */
+        }
+    }
+
+    if (ret != 0) {
+        dprintf(CRITICAL, "PMIC: Set MSDC Host Power Fail\n");
+    } else {
+        spin(3000);
+    }
+}
+
+static void msdc_set_host_pwr(struct mmc_host *host, int on)
+{
+    unsigned int ret;
+
+    ret = pmic_config_interface(0xA7,0x7,0x7,4); /* VMC=3.3V */
+
+    if (ret == 0) {
+        if (on) {
+            ret = pmic_config_interface(0xA7,0x1,0x1,0); /* VMC_EN=1 */
+        } else {
+            ret = pmic_config_interface(0xA7,0x0,0x1,0); /* VMC_EN=0 */
+        }
+    }
+
+    if (ret != 0) {
+        dprintf(CRITICAL, "PMIC: Set MSDC Card Power Fail\n");
+    }
+}
+#else
+#define PWR_GPIO            (0x10001E84)
+#define PWR_GPIO_EO         (0x10001E88)
+
+#define PWR_MASK_EN         (0x1 << 8)
+#define PWR_MASK_VOL_18     (0x1 << 9)
+#define PWR_MASK_VOL_33     (0x1 << 10)
+#define PWR_MASK_L4         (0x1 << 11)
+#define PWR_MSDC_DIR        (PWR_MASK_EN | PWR_MASK_VOL_18 | PWR_MASK_VOL_33 | PWR_MASK_L4)
+
+#define MSDC0_PWR_MASK_EN         (0x1 << 12)
+#define MSDC0_PWR_MASK_VOL_18     (0x1 << 13)
+#define MSDC0_PWR_MASK_VOL_33     (0x1 << 14)
+#define MSDC0_PWR_MASK_L4         (0x1 << 15)
+#define MSDC0_PWR_MSDC_DIR        (MSDC0_PWR_MASK_EN | MSDC0_PWR_MASK_VOL_18 | MSDC0_PWR_MASK_VOL_33 | MSDC0_PWR_MASK_L4)
+
+static void msdc_clr_gpio(u32 bits)
+{
+    u32 l_val = 0;
+
+    switch (bits) {
+        case MSDC0_PWR_MASK_EN:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_EN),0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_EN),0);
+            break;
+        case MSDC0_PWR_MASK_VOL_18:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+            break;
+        case MSDC0_PWR_MASK_VOL_33:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+            break;
+        case MSDC0_PWR_MASK_L4:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    MSDC0_PWR_MASK_L4, 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, MSDC0_PWR_MASK_L4, 0);
+            break;
+        case PWR_MASK_EN:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_EN,0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_EN,0);
+            break;
+        case PWR_MASK_VOL_18:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+            break;
+        case PWR_MASK_VOL_33:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+            break;
+        case PWR_MASK_L4:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_L4, 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_L4, 0);
+            break;
+        default:
+            dprintf(CRITICAL, "[%s:%d]invalid value: 0x%x\n", __FILE__, __func__, bits);
+            break;
+    }
+}
+
+static void msdc_set_gpio(u32 bits)
+{
+    u32 l_val = 0;
+
+    switch (bits) {
+        case MSDC0_PWR_MASK_EN:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    MSDC0_PWR_MASK_EN,1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, MSDC0_PWR_MASK_EN,1);
+            break;
+        case MSDC0_PWR_MASK_VOL_18:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 1);
+            break;
+        case MSDC0_PWR_MASK_VOL_33:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 2);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 2);
+            break;
+        case MSDC0_PWR_MASK_L4:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    MSDC0_PWR_MASK_L4, 1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, MSDC0_PWR_MASK_L4, 1);
+            break;
+        case PWR_MASK_EN:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_EN,1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_EN,1);
+            break;
+        case PWR_MASK_VOL_18:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 1);
+            break;
+        case PWR_MASK_VOL_33:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 2);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 2);
+            break;
+        case PWR_MASK_L4:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_L4, 1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_L4, 1);
+            break;
+        default:
+            dprintf(CRITICAL, "[%s:%s]invalid value: 0x%x\n", __FILE__, __func__, bits);
+            break;
+    }
+}
+
+static void msdc_set_card_pwr(struct mmc_host *host, int on)
+{
+    if (on) {
+        msdc_set_gpio(MSDC0_PWR_MASK_VOL_18);
+        msdc_set_gpio(MSDC0_PWR_MASK_L4);
+        msdc_set_gpio(MSDC0_PWR_MASK_EN);
+    } else {
+        msdc_clr_gpio(MSDC0_PWR_MASK_EN);
+        msdc_clr_gpio(MSDC0_PWR_MASK_VOL_18);
+        msdc_clr_gpio(MSDC0_PWR_MASK_L4);
+    }
+    spin(10000);
+}
+
+static void msdc_set_host_level_pwr(struct mmc_host *host, u32 level)
+{
+    msdc_clr_gpio(PWR_MASK_VOL_18);
+    msdc_clr_gpio(PWR_MASK_VOL_33);
+
+    if (level) {
+        msdc_set_gpio(PWR_MASK_VOL_18);
+    } else {
+        msdc_set_gpio(PWR_MASK_VOL_33);
+    }
+    msdc_set_gpio(PWR_MASK_L4);
+}
+
+static void msdc_set_host_pwr(struct mmc_host *host, int on)
+{
+    msdc_set_host_level_pwr(host, 0);
+}
+#endif
+
+static void msdc_set_startbit(struct mmc_host *host, u8 start_bit)
+{
+    addr_t base = host->base;
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+
+    /* set start bit */
+    MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_START_BIT, start_bit);
+    priv->start_bit = start_bit;
+    LTRACEF("start bit = %d, MSDC_CFG[0x%x]\n", start_bit, MSDC_READ32(MSDC_CFG));
+}
+
+#define TYPE_CMD_RESP_EDGE      (0)
+#define TYPE_WRITE_CRC_EDGE     (1)
+#define TYPE_READ_DATA_EDGE     (2)
+#define TYPE_WRITE_DATA_EDGE    (3)
+
+static void msdc_set_smpl(struct mmc_host *host, u8 HS400, u8 mode, u8 type)
+{
+    addr_t base = host->base;
+    int i=0;
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+    static u8 read_data_edge[8] = {MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING,
+                                   MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING
+                                  };
+    static u8 write_data_edge[4] = {MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING};
+
+    switch (type) {
+        case TYPE_CMD_RESP_EDGE:
+            if (HS400) {
+                // eMMC5.0 only output resp at CLK pin, so no need to select DS pin
+                MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_PADCMD_LATCHCK, 0); //latch cmd resp at CLK pin
+                MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CMD_RESP_SEL, 0);//latch cmd resp at CLK pin
+            }
+
+            if (mode == MSDC_SMPL_RISING || mode == MSDC_SMPL_FALLING) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, mode);
+                priv->rsmpl = mode;
+            } else {
+                dprintf(CRITICAL, "[%s]: invalid resp parameter: HS400=%d, type=%d, mode=%d\n", __func__, HS400, type, mode);
+            }
+            break;
+
+        case TYPE_WRITE_CRC_EDGE:
+            if (HS400) {
+                MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_SEL, 1);//latch write crc status at DS pin
+            } else {
+                MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_SEL, 0);//latch write crc status at CLK pin
+            }
+
+            if (mode == MSDC_SMPL_RISING || mode == MSDC_SMPL_FALLING) {
+                if (HS400) {
+                    MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_EDGE, mode);
+                } else {
+                    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL_SEL, 0);
+                    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL, mode);
+                }
+                priv->wdsmpl = mode;
+            } else if (mode == MSDC_SMPL_SEPERATE && !HS400) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D0SPL, write_data_edge[0]); //only dat0 is for write crc status.
+                priv->wdsmpl = mode;
+            } else {
+                dprintf(CRITICAL, "[%s]: invalid crc parameter: HS400=%d, type=%d, mode=%d\n", __func__, HS400, type, mode);
+            }
+            break;
+
+        case TYPE_READ_DATA_EDGE:
+            if (HS400) {
+                msdc_set_startbit(host, START_AT_RISING_AND_FALLING); //for HS400, start bit is output both on rising and falling edge
+                priv->start_bit = START_AT_RISING_AND_FALLING;
+            } else {
+                msdc_set_startbit(host, START_AT_RISING); //for the other mode, start bit is only output on rising edge. but DDR50 can try falling edge if error casued by pad delay
+                priv->start_bit = START_AT_RISING;
+            }
+            if (mode == MSDC_SMPL_RISING || mode == MSDC_SMPL_FALLING) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL_SEL, 0);
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL, mode);
+                priv->rdsmpl = mode;
+            } else if (mode == MSDC_SMPL_SEPERATE) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL_SEL, 1);
+                for (i=0; i<8; i++) {
+                    MSDC_SET_FIELD(MSDC_IOCON, (MSDC_IOCON_R_D0SPL << i), read_data_edge[i]);
+                }
+                priv->rdsmpl = mode;
+            } else {
+                dprintf(CRITICAL, "[%s]: invalid read parameter: HS400=%d, type=%d, mode=%d\n", __func__, HS400, type, mode);
+            }
+            break;
+
+        case TYPE_WRITE_DATA_EDGE:
+            MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_SEL, 0);//latch write crc status at CLK pin
+
+            if (mode == MSDC_SMPL_RISING|| mode == MSDC_SMPL_FALLING) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL_SEL, 0);
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL, mode);
+                priv->wdsmpl = mode;
+            } else if (mode == MSDC_SMPL_SEPERATE) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL_SEL, 1);
+                for (i=0; i<4; i++) {
+                    MSDC_SET_FIELD(MSDC_IOCON, (MSDC_IOCON_W_D0SPL << i), write_data_edge[i]);//dat0~4 is for SDIO card.
+                }
+                priv->wdsmpl = mode;
+            } else {
+                dprintf(CRITICAL, "[%s]: invalid write parameter: HS400=%d, type=%d, mode=%d\n", __func__, HS400, type, mode);
+            }
+            break;
+
+        default:
+            dprintf(CRITICAL, "[%s]: invalid parameter: HS400=%d, type=%d, mode=%d\n", __func__, HS400, type, mode);
+            break;
+    }
+}
+
+void msdc_set_timeout(struct mmc_host *host, u32 ns, u32 clks)
+{
+    addr_t base = host->base;
+    u32 timeout, clk_ns;
+    u32 mode = 0;
+
+    if (host->sclk == 0) {
+        timeout = 0;
+    } else {
+        clk_ns  = 1000000000UL / host->sclk;
+        timeout = (ns + clk_ns - 1) / clk_ns + clks;
+        timeout = (timeout + (1 << 20) - 1) >> 20; /* in 1048576 sclk cycle unit */
+        MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, mode);
+        timeout = mode >= 2 ? timeout * 2 : timeout; //DDR mode will double the clk cycles for data timeout
+        timeout = timeout > 1 ? timeout - 1 : 0;
+        timeout = timeout > 255 ? 255 : timeout;
+    }
+    MSDC_SET_FIELD(SDC_CFG, SDC_CFG_DTOC, timeout);
+    LTRACEF("[MSDC] Set read data timeout: %dns %dclks -> %d (65536 sclk cycles)\n",
+            ns, clks, timeout + 1);
+}
+
+void msdc_set_autocmd(struct mmc_host *host, int cmd)
+{
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+
+    priv->autocmd = cmd;
+}
+
+int msdc_get_autocmd(struct mmc_host *host)
+{
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+
+    return priv->autocmd;
+}
+
+static void msdc_abort(struct mmc_host *host)
+{
+    addr_t base = host->base;
+
+    dprintf(CRITICAL, "[MSDC] Abort: MSDC_FIFOCS=%xh MSDC_PS=%xh SDC_STS=%xh\n",
+            MSDC_READ32(MSDC_FIFOCS), MSDC_READ32(MSDC_PS), MSDC_READ32(SDC_STS));
+    /* reset controller */
+    MSDC_RESET();
+
+    /* clear fifo */
+    MSDC_CLR_FIFO();
+
+    /* make sure txfifo and rxfifo are empty */
+    if (MSDC_TXFIFOCNT() != 0 || MSDC_RXFIFOCNT() != 0) {
+        LTRACEF("[MSDC] Abort: TXFIFO(%d), RXFIFO(%d) != 0\n",
+                MSDC_TXFIFOCNT(), MSDC_RXFIFOCNT());
+    }
+
+    /* clear all interrupts */
+    MSDC_CLR_INT();
+}
+
+static int msdc_get_card_status(struct mmc_host *host, u32 *status)
+{
+    int err;
+    struct mmc_command cmd;
+
+    cmd.opcode  = MMC_CMD_SEND_STATUS;
+    cmd.arg     = host->card->rca << 16;
+    cmd.rsptyp  = RESP_R1;
+    cmd.retries = CMD_RETRIES;
+    cmd.timeout = CMD_TIMEOUT;
+
+    err = msdc_send_cmd(host, &cmd);
+    if (!err)
+        err = msdc_wait_cmd_done(host, &cmd);
+
+    if (err == MMC_ERR_NONE)
+        *status = cmd.resp[0];
+
+    return err;
+}
+
+int msdc_abort_handler(struct mmc_host *host, int abort_card)
+{
+    struct mmc_command stop;
+    u32 status = 0;
+    u32 state = 0;
+
+    while (state != 4) { // until status to "tran"
+        msdc_abort(host);
+        if (msdc_get_card_status(host, &status)) {
+            dprintf(CRITICAL, "Get card status failed\n");
+            return 1;
+        }
+        state = R1_CURRENT_STATE(status);
+        LTRACEF("check card state<%d>\n", state);
+        if (state == 5 || state == 6) {
+            LTRACEF("state<%d> need cmd12 to stop\n", state);
+            if (abort_card) {
+                stop.opcode  = MMC_CMD_STOP_TRANSMISSION;
+                stop.rsptyp  = RESP_R1B;
+                stop.arg     = 0;
+                stop.retries = CMD_RETRIES;
+                stop.timeout = CMD_TIMEOUT;
+                msdc_send_cmd(host, &stop);
+                msdc_wait_cmd_done(host, &stop); // don't tuning
+            } else if (state == 7) {  // busy in programing
+                LTRACEF("state<%d> card is busy\n", state);
+                spin(100000);
+            } else if (state != 4) {
+                LTRACEF("state<%d> ??? \n", state);
+                return 1;
+            }
+        }
+    }
+    msdc_abort(host);
+    return 0;
+}
+
+static u32 msdc_intr_wait(struct mmc_host *host, u32 intrs)
+{
+    u32 sts = 0;
+    u32 tmo = UINT_MAX;
+    int ret = 0;
+
+    /* warning that interrupts are not enabled */
+    ret = event_wait_timeout(&msdc_int_event, tmo);
+    if (ret != 0) {
+        addr_t base = host->base;
+        dprintf(CRITICAL, "[%s]: failed to get event INT=0x%x\n",
+                __func__, MSDC_READ32(MSDC_INT));
+        g_int_status = 0;
+        return 0;
+    }
+
+    sts = g_int_status;
+    g_int_status = 0;
+
+    if (~intrs & sts)
+        dprintf(CRITICAL, "[MSDC]<CHECKME> Unexpected INT(0x%x)\n", ~intrs & sts);
+
+    return sts;
+}
+
+static enum handler_return msdc_interrupt_handler(void *arg)
+{
+    struct mmc_host *host = arg;
+    addr_t base = host->base;
+
+    /* Save & Clear the interrupt */
+    g_int_status = MSDC_READ32(MSDC_INT);
+    MSDC_WRITE32(MSDC_INT, g_int_status & host->intr_mask);
+    MSDC_WRITE32(MSDC_INTEN, 0);
+    host->intr_mask = 0;
+
+    /* MUST BE *false*! otherwise, schedule in interrupt */
+    event_signal(&msdc_int_event, false);
+
+    return INT_RESCHEDULE;
+}
+
+static int msdc_send_cmd(struct mmc_host *host, struct mmc_command *cmd)
+{
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+    addr_t base   = host->base;
+    u32 opcode = cmd->opcode;
+    u32 rsptyp = cmd->rsptyp;
+    u32 rawcmd;
+    u32 error = MMC_ERR_NONE;
+
+    /* rawcmd :
+     * vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 |
+     * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode
+     */
+    rawcmd = (opcode & ~(SD_CMD_BIT | SD_CMD_APP_BIT)) |
+             msdc_rsp[rsptyp] << 7 | host->blklen << 16;
+
+    if (opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
+        rawcmd |= ((2 << 11) | (1 << 13));
+        if (priv->autocmd & MSDC_AUTOCMD12) {
+            rawcmd |= (1 << 28);
+        } else if (priv->autocmd & MSDC_AUTOCMD23) {
+            rawcmd |= (2 << 28);
+        }
+    } else if (opcode == MMC_CMD_WRITE_BLOCK || opcode == MMC_CMD50) {
+        rawcmd |= ((1 << 11) | (1 << 13));
+    } else if (opcode == MMC_CMD_READ_MULTIPLE_BLOCK) {
+        rawcmd |= (2 << 11);
+        if (priv->autocmd & MSDC_AUTOCMD12) {
+            rawcmd |= (1 << 28);
+        } else if (priv->autocmd & MSDC_AUTOCMD23) {
+            rawcmd |= (2 << 28);
+        }
+    } else if (opcode == MMC_CMD_READ_SINGLE_BLOCK ||
+               opcode == SD_ACMD_SEND_SCR ||
+               opcode == SD_CMD_SWITCH ||
+               opcode == MMC_CMD_SEND_EXT_CSD ||
+               opcode == MMC_CMD_SEND_WRITE_PROT ||
+               opcode == MMC_CMD_SEND_WRITE_PROT_TYPE ||
+               opcode == MMC_CMD21) {
+        rawcmd |= (1 << 11);
+    } else if (opcode == MMC_CMD_STOP_TRANSMISSION) {
+        rawcmd |= (1 << 14);
+        rawcmd &= ~(0x0FFF << 16);
+    } else if (opcode == SD_IO_RW_EXTENDED) {
+        if (cmd->arg & 0x80000000)  /* R/W flag */
+            rawcmd |= (1 << 13);
+        if ((cmd->arg & 0x08000000) && ((cmd->arg & 0x1FF) > 1))
+            rawcmd |= (2 << 11); /* multiple block mode */
+        else
+            rawcmd |= (1 << 11);
+    } else if (opcode == SD_IO_RW_DIRECT) {
+        if ((cmd->arg & 0x80000000) && ((cmd->arg >> 9) & 0x1FFFF))/* I/O abt */
+            rawcmd |= (1 << 14);
+    } else if (opcode == SD_CMD_VOL_SWITCH) {
+        rawcmd |= (1 << 30);
+    } else if (opcode == SD_CMD_SEND_TUNING_BLOCK) {
+        rawcmd |= (1 << 11); /* CHECKME */
+        if (priv->autocmd & MSDC_AUTOCMD19)
+            rawcmd |= (3 << 28);
+    } else if (opcode == MMC_CMD_GO_IRQ_STATE) {
+        rawcmd |= (1 << 15);
+    } else if (opcode == MMC_CMD_WRITE_DAT_UNTIL_STOP) {
+        rawcmd |= ((1<< 13) | (3 << 11));
+    } else if (opcode == MMC_CMD_READ_DAT_UNTIL_STOP) {
+        rawcmd |= (3 << 11);
+    }
+
+    LTRACEF("+[MSDC%d] CMD(%d): ARG(0x%x), RAW(0x%x), BLK_NUM(0x%x) RSP(%d)\n",host->host_id,
+            (opcode & ~(SD_CMD_BIT | SD_CMD_APP_BIT)), cmd->arg, rawcmd,
+            MSDC_READ32(SDC_BLK_NUM), rsptyp);
+
+    while (SDC_IS_CMD_BUSY());
+    if ((rsptyp == RESP_R1B) || (opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK) ||
+            opcode == MMC_CMD_WRITE_BLOCK || opcode == MMC_CMD_READ_MULTIPLE_BLOCK ||
+            opcode == MMC_CMD_READ_SINGLE_BLOCK)
+        while (SDC_IS_BUSY());
+
+    SDC_SEND_CMD(rawcmd, cmd->arg);
+
+end:
+    cmd->error = error;
+
+    return error;
+}
+
+static int msdc_wait_cmd_done(struct mmc_host *host, struct mmc_command *cmd)
+{
+    addr_t base   = host->base;
+    u32 rsptyp = cmd->rsptyp;
+    u32 status;
+    u32 opcode = (cmd->opcode & ~(SD_CMD_BIT | SD_CMD_APP_BIT));
+    u32 error = MMC_ERR_NONE;
+    u32 wints = MSDC_INT_CMDTMO | MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR |
+                MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO;
+    u32 *resp = &cmd->resp[0];
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+
+    while (1) {
+        /* Wait for interrupt coming */
+        while (((status = MSDC_READ32(MSDC_INT)) & wints) == 0);
+        MSDC_WRITE32(MSDC_INT, (status & wints));
+        if (~wints & status)
+            dprintf(CRITICAL, "[MSDC]<CHECKME> Unexpected INT(0x%x)\n",
+                    ~wints & status);
+
+        if (status & MSDC_INT_CMDRDY)
+            break;
+        else if (status & MSDC_INT_RSPCRCERR) {
+            if (opcode != MMC_CMD21)
+                dprintf(CRITICAL, "[MSDC] cmd%d CRCERR! (0x%x)\n", opcode, status);
+            error = MMC_ERR_BADCRC;
+            goto err;
+        } else if (status & MSDC_INT_CMDTMO) {
+            dprintf(CRITICAL, "[MSDC] cmd%d TMO! (0x%x)\n", opcode, status);
+            error = MMC_ERR_TIMEOUT;
+            goto err;
+        } else if (priv->autocmd & MSDC_AUTOCMD23) {
+            if (status & MSDC_INT_ACMDRDY)
+                /* Autocmd rdy is set prior to cmd rdy */
+                continue;
+            else if (status & MSDC_INT_ACMDCRCERR) {
+                dprintf(CRITICAL, "[MSDC] autocmd23 CRCERR! (0x%x)\n", status);
+                error = MMC_ERR_ACMD_RSPCRC;
+                goto err;
+            } else if (status & MSDC_INT_ACMDTMO) {
+                dprintf(CRITICAL, "[MSDC] autocmd23 TMO! (0x%x)\n", status);
+                error = MMC_ERR_ACMD_TIMEOUT;
+                goto err;
+            }
+        } else {
+            dprintf(CRITICAL, "[MSDC] cmd%d UNEXPECT status! (0x%x)\n",
+                    opcode, status);
+            error = MMC_ERR_UNEXPECT;
+            goto err;
+        }
+    }
+
+    switch (rsptyp) {
+        case RESP_NONE:
+            LTRACEF("-[MSDC] CMD(%d): RSP(%d)\n",
+                    opcode, rsptyp);
+            break;
+        case RESP_R2:
+            *resp++ = MSDC_READ32(SDC_RESP3);
+            *resp++ = MSDC_READ32(SDC_RESP2);
+            *resp++ = MSDC_READ32(SDC_RESP1);
+            *resp++ = MSDC_READ32(SDC_RESP0);
+            LTRACEF("-[MSDC] CMD(%d): RSP(%d) = 0x%x 0x%x 0x%x 0x%x\n",
+                    opcode, cmd->rsptyp, cmd->resp[0], cmd->resp[1],
+                    cmd->resp[2], cmd->resp[3]);
+            break;
+        default: /* Response types 1, 3, 4, 5, 6, 7(1b) */
+            cmd->resp[0] = MSDC_READ32(SDC_RESP0);
+            LTRACEF("-[MSDC] CMD(%d): RSP(%d) = 0x%x\n",
+                    opcode, cmd->rsptyp, cmd->resp[0]);
+            break;
+    }
+
+err:
+    if (rsptyp == RESP_R1B)
+        while ((MSDC_READ32(MSDC_PS) & MSDC_PS_DAT0) != MSDC_PS_DAT0);
+
+    cmd->error = error;
+
+    return error;
+}
+
+int msdc_cmd(struct mmc_host *host, struct mmc_command *cmd)
+{
+    int err;
+
+    err = msdc_send_cmd(host, cmd);
+    if (err != MMC_ERR_NONE)
+        return err;
+
+    err = msdc_wait_cmd_done(host, cmd);
+
+    /*
+     * For CMD21 resp CRC error, sitll need receive data, so MUST not
+     * clear fifo or do host reset
+     */
+    if (err && cmd->opcode != MMC_CMD21) {
+        addr_t base = host->base;
+        u32 tmp = MSDC_READ32(SDC_CMD);
+
+        /* check if data is used by the command or not */
+        if (tmp & SDC_CMD_DTYP) {
+            if (msdc_abort_handler(host, 1)) {
+                dprintf(CRITICAL, "[MSDC] abort failed\n");
+            }
+        }
+
+        if (cmd->opcode == MMC_CMD_APP_CMD ||
+                cmd->opcode == SD_CMD_SEND_IF_COND) {
+            if (err ==  MMC_ERR_TIMEOUT)
+                return err;
+        }
+
+        err = msdc_tune_cmdrsp(host, cmd);
+    }
+
+    return err;
+}
+
+#ifdef MSDC_USE_DMA_MODE
+static void msdc_flush_membuf(void *buf, u32 len)
+{
+    arch_clean_invalidate_cache_range((addr_t)buf,len);
+}
+
+static int msdc_dma_wait_done(struct mmc_host *host, struct mmc_command *cmd)
+{
+    addr_t base = host->base;
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+    u32 status;
+    u32 error = MMC_ERR_NONE;
+    u32 wints = MSDC_INT_XFER_COMPL | MSDC_INT_DATTMO | MSDC_INT_DATCRCERR |
+                MSDC_INT_DXFER_DONE | MSDC_INT_DMAQ_EMPTY |
+                MSDC_INT_ACMDRDY | MSDC_INT_ACMDTMO | MSDC_INT_ACMDCRCERR |
+                MSDC_INT_CMDRDY | MSDC_INT_CMDTMO | MSDC_INT_RSPCRCERR;
+
+    /* Deliver it to irq handler */
+    host->intr_mask = wints;
+
+    do {
+        status = msdc_intr_wait(host, wints);
+
+        if (status & MSDC_INT_XFER_COMPL) {
+            if (mmc_op_multi(cmd->opcode) && (priv->autocmd & MSDC_AUTOCMD12)) {
+                /* acmd rdy should be checked after xfer_done been held */
+                if (status & MSDC_INT_ACMDRDY) {
+                    break;
+                } else if (status & MSDC_INT_ACMDTMO) {
+                    dprintf(CRITICAL, "[MSDC] ACMD12 timeout(%xh)\n", status);
+                    error = MMC_ERR_ACMD_TIMEOUT;
+                    goto end;
+                } else if (status & MSDC_INT_ACMDCRCERR) {
+                    dprintf(CRITICAL, "[MSDC] ACMD12 CRC error(%xh)\n", status);
+                    error = MMC_ERR_ACMD_RSPCRC;
+                    goto end;
+                }
+            } else
+                break;
+        }
+
+        if (status == 0 || status & MSDC_INT_DATTMO) {
+            dprintf(CRITICAL, "[MSDC] DMA DAT timeout(%xh)\n", status);
+            error = MMC_ERR_TIMEOUT;
+            goto end;
+        } else if (status & MSDC_INT_DATCRCERR) {
+		if (cmd->opcode != MMC_CMD21)
+			dprintf(CRITICAL, "[MSDC] DMA DAT CRC error(%xh)\n", status);
+            error = MMC_ERR_BADCRC;
+            goto end;
+        } else {
+            dprintf(CRITICAL, "[MSDC] Unexpect status(0x%x)\n", status);
+            error = MMC_ERR_UNEXPECT;
+            goto end;
+        }
+    } while (1);
+
+end:
+    if (error)
+        MSDC_RESET();
+
+    return error;
+}
+
+int msdc_dma_transfer(struct mmc_host *host, struct mmc_data *data)
+{
+    addr_t base = host->base;
+    int err;
+    paddr_t pa;
+
+    /* Set dma timeout */
+    msdc_set_timeout(host, data->timeout * 1000000, 0);
+    /* DRAM address */
+#if WITH_KERNEL_VM
+    pa = kvaddr_to_paddr(data->buf);
+#else
+    pa = (paddr_t)(data->buf);
+#endif
+    if (sizeof(pa) > 4)
+        LTRACEF("[MSDC] WARN: 64bit physical address!\n");
+    MSDC_WRITE32(MSDC_DMA_SA, (u32)pa);
+    MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_BURSTSZ, MSDC_DMA_BURST_64B);
+    /* BASIC_DMA mode */
+    MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 0);
+    /* This is the last buffer */
+    MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_LASTBUF, 1);
+    /* Total transfer size */
+    MSDC_WRITE32(MSDC_DMA_LEN, data->blks * host->blklen);
+    /* Set interrupts bit */
+    MSDC_SET_BIT32(MSDC_INTEN,
+                   MSDC_INT_XFER_COMPL | MSDC_INT_DATTMO | MSDC_INT_DATCRCERR);
+    /* Clean & Invalidate cache */
+    msdc_flush_membuf(data->buf, data->blks * host->blklen);
+    /* Trigger DMA start */
+    MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1);
+    /* wait DMA transferring done */
+    err = msdc_dma_wait_done(host, data->cmd);
+    msdc_flush_membuf(data->buf, data->blks * host->blklen);
+    if (err) {
+	    /*
+	     * We do not want print out error logs of CMD21, As it may
+	     * let user confused.
+	     */
+	    if (data->cmd->opcode == MMC_CMD21) {
+		    /* reset controller */
+		    MSDC_RESET();
+
+		    /* clear fifo */
+		    MSDC_CLR_FIFO();
+
+		    /* make sure txfifo and rxfifo are empty */
+		    if (MSDC_TXFIFOCNT() != 0 || MSDC_RXFIFOCNT() != 0) {
+			    LTRACEF("[MSDC] Abort: TXFIFO(%d), RXFIFO(%d) != 0\n",
+					    MSDC_TXFIFOCNT(), MSDC_RXFIFOCNT());
+		    }
+
+		    /* clear all interrupts */
+		    MSDC_CLR_INT();
+
+	    } else {
+		    dprintf(CRITICAL, "[MSDC] DMA failed! err(%d)\n", err);
+		    if (msdc_abort_handler(host, 1)) {
+			    dprintf(CRITICAL, "[MSDC] eMMC cannot back to TRANS mode!\n");
+			    return MMC_ERR_FAILED;
+		    }
+	    }
+    }
+
+    /* Check DMA status and stop DMA transfer */
+    MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 1);
+    while (MSDC_READ32(MSDC_DMA_CFG) & MSDC_DMA_CFG_STS);
+
+    return err;
+}
+
+static int msdc_dma_rw(struct mmc_host *host, u8 *buf, u32 blkaddr, u32 nblks, bool rd)
+{
+    int multi, err;
+    struct mmc_command cmd;
+    struct mmc_data data;
+    addr_t base = host->base;
+
+    ASSERT(nblks <= host->max_phys_segs);
+
+    LTRACEF("[MSDC] %s data %d blks %s 0x%x\n",
+            rd ? "Read" : "Write", nblks, rd ? "from" : "to", blkaddr);
+
+    multi = nblks > 1 ? 1 : 0;
+    /* DMA and block number _MUST_BE_ set prior to issuing command */
+    MSDC_DMA_ON;
+    MSDC_WRITE32(SDC_BLK_NUM, nblks);
+
+    /* send read command */
+    if (rd)
+        cmd.opcode =
+            multi ? MMC_CMD_READ_MULTIPLE_BLOCK : MMC_CMD_READ_SINGLE_BLOCK;
+    else
+        cmd.opcode = multi ? MMC_CMD_WRITE_MULTIPLE_BLOCK : MMC_CMD_WRITE_BLOCK;
+    cmd.arg = blkaddr;
+    cmd.rsptyp  = RESP_R1;
+    cmd.retries = 0;
+    cmd.timeout = CMD_TIMEOUT;
+
+    err = msdc_cmd(host, &cmd);
+    if (err != MMC_ERR_NONE)
+        return err;
+
+    data.cmd = &cmd;
+    data.blks = nblks;
+    data.buf = buf;
+    if (rd)
+        data.timeout = 100;
+    else
+        data.timeout = 250;
+
+    err = msdc_dma_transfer(host, &data);
+    MSDC_DMA_OFF;
+
+    return err;
+}
+
+static int msdc_dma_bread(struct mmc_host *host, u8 *dst, u32 src, u32 nblks)
+{
+    return msdc_dma_rw(host, dst, src, nblks, true);
+}
+
+static int msdc_dma_bwrite(struct mmc_host *host, u32 dst, u8 *src, u32 nblks)
+{
+    return msdc_dma_rw(host, src, dst, nblks, false);
+}
+#else
+static int msdc_pio_read_word(struct mmc_host *host, u32 *ptr, u32 size)
+{
+    int err = MMC_ERR_NONE;
+    addr_t base = host->base;
+    u32 ints = MSDC_INT_DATCRCERR | MSDC_INT_DATTMO | MSDC_INT_XFER_COMPL;
+    //u32 timeout = 100000;
+    u32 status;
+    u32 totalsz = size;
+    u8  done = 0;
+    u8 *u8ptr;
+    u32 dcrc=0;
+
+    while (1) {
+        status = MSDC_READ32(MSDC_INT);
+        MSDC_WRITE32(MSDC_INT, status);
+        if (status & ~ints)
+            dprintf(CRITICAL, "[MSDC]<CHECKME> Unexpected INT(0x%x)\n", status);
+        if (status & MSDC_INT_DATCRCERR) {
+            MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+            dprintf(CRITICAL, "[MSDC] DAT CRC error (0x%x), Left:%d/%d bytes, RXFIFO:%d,dcrc:0x%x\n",
+                    status, size, totalsz, MSDC_RXFIFOCNT(),dcrc);
+            err = MMC_ERR_BADCRC;
+            break;
+        } else if (status & MSDC_INT_DATTMO) {
+            dprintf(CRITICAL, "[MSDC] DAT TMO error (0x%x), Left: %d/%d bytes, RXFIFO:%d\n",
+                    status, size, totalsz, MSDC_RXFIFOCNT());
+            err = MMC_ERR_TIMEOUT;
+            break;
+        } else if (status & MSDC_INT_ACMDCRCERR) {
+            MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+            dprintf(CRITICAL, "[MSDC] AUTOCMD CRC error (0x%x), Left:%d/%d bytes, RXFIFO:%d,dcrc:0x%x\n",
+                    status, size, totalsz, MSDC_RXFIFOCNT(),dcrc);
+            err = MMC_ERR_ACMD_RSPCRC;
+            break;
+        } else if (status & MSDC_INT_XFER_COMPL) {
+            done = 1;
+        }
+
+        if (size == 0 && done)
+            break;
+
+        /* Note. RXFIFO count would be aligned to 4-bytes alignment size */
+        if ((size >=  MSDC_FIFO_THD) && (MSDC_RXFIFOCNT() >= MSDC_FIFO_THD)) {
+            int left = MSDC_FIFO_THD >> 2;
+            do {
+                *ptr++ = MSDC_FIFO_READ32();
+            } while (--left);
+            size -= MSDC_FIFO_THD;
+            LTRACEF("[MSDC] Read %d bytes, RXFIFOCNT: %d,  Left: %d/%d\n",
+                    MSDC_FIFO_THD, MSDC_RXFIFOCNT(), size, totalsz);
+        } else if ((size < MSDC_FIFO_THD) && MSDC_RXFIFOCNT() >= size) {
+            while (size) {
+                if (size > 3) {
+                    *ptr++ = MSDC_FIFO_READ32();
+                } else {
+                    u8ptr = (u8 *)ptr;
+                    while (size --)
+                        *u8ptr++ = MSDC_FIFO_READ8();
+                }
+            }
+            LTRACEF("[MSDC] Read left bytes, RXFIFOCNT: %d, Left: %d/%d\n",
+                    MSDC_RXFIFOCNT(), size, totalsz);
+        }
+    }
+
+    return err;
+}
+
+static int msdc_pio_read(struct mmc_host *host, u32 *ptr, u32 size)
+{
+    int err = msdc_pio_read_word(host, (u32 *)ptr, size);
+
+    if (err != MMC_ERR_NONE) {
+        msdc_abort(host); /* reset internal fifo and state machine */
+        dprintf(CRITICAL, "[MSDC] %d-bit PIO Read Error (%d)\n", 32, err);
+    }
+
+    return err;
+}
+
+static int msdc_pio_write_word(struct mmc_host *host, u32 *ptr, u32 size)
+{
+    int err = MMC_ERR_NONE;
+    addr_t base = host->base;
+    u32 ints = MSDC_INT_DATCRCERR | MSDC_INT_DATTMO | MSDC_INT_XFER_COMPL;
+    //u32 timeout = 250000;
+    u32 status;
+    u8 *u8ptr;
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+
+    while (1) {
+        status = MSDC_READ32(MSDC_INT);
+        MSDC_WRITE32(MSDC_INT, status);
+        if (status & ~ints) {
+            dprintf(CRITICAL, "[MSDC]<CHECKME> Unexpected INT(0x%x)\n", status);
+        }
+        if (status & MSDC_INT_DATCRCERR) {
+            dprintf(CRITICAL, "[MSDC] DAT CRC error (0x%x), Left DAT: %d bytes\n",
+                    status, size);
+            err = MMC_ERR_BADCRC;
+            break;
+        } else if (status & MSDC_INT_DATTMO) {
+            dprintf(CRITICAL, "[MSDC] DAT TMO error (0x%x), Left DAT: %d bytes, MSDC_FIFOCS=%xh\n",
+                    status, size, MSDC_READ32(MSDC_FIFOCS));
+            err = MMC_ERR_TIMEOUT;
+            break;
+        } else if (status & MSDC_INT_ACMDCRCERR) {
+            dprintf(CRITICAL, "[MSDC] AUTO CMD CRC error (0x%x), Left DAT: %d bytes\n",
+                    status, size);
+            err = MMC_ERR_ACMD_RSPCRC;
+            break;
+        } else if (status & MSDC_INT_XFER_COMPL) {
+            if (size == 0) {
+                LTRACEF("[MSDC] all data flushed to card\n");
+                break;
+            } else
+                LTRACEF("[MSDC]<CHECKME> XFER_COMPL before all data written\n");
+        }
+
+        if (size == 0)
+            continue;
+
+        if (size >= MSDC_FIFO_SZ) {
+            if (MSDC_TXFIFOCNT() == 0) {
+                int left = MSDC_FIFO_SZ >> 2;
+                do {
+                    MSDC_FIFO_WRITE32(*ptr);
+                    ptr++;
+                } while (--left);
+                size -= MSDC_FIFO_SZ;
+            }
+        } else if (size < MSDC_FIFO_SZ && MSDC_TXFIFOCNT() == 0) {
+            while (size ) {
+                if (size > 3) {
+                    MSDC_FIFO_WRITE32(*ptr);
+                    ptr++;
+                    size -= 4;
+                } else {
+                    u8ptr = (u8 *)ptr;
+                    while (size --) {
+                        MSDC_FIFO_WRITE8(*u8ptr);
+                        u8ptr++;
+                    }
+                }
+            }
+        }
+    }
+
+    return err;
+}
+
+static int msdc_pio_write(struct mmc_host *host, u32 *ptr, u32 size)
+{
+    int err = msdc_pio_write_word(host, (u32 *)ptr, size);
+
+    if (err != MMC_ERR_NONE) {
+        msdc_abort(host); /* reset internal fifo and state machine */
+        dprintf(CRITICAL, "[MSDC] PIO Write Error (%d)\n", err);
+    }
+
+    return err;
+}
+
+static int msdc_pio_bread(struct mmc_host *host, u8 *dst, u32 src, u32 nblks)
+{
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+    addr_t base = host->base;
+    u32 blksz = host->blklen;
+    int err = MMC_ERR_NONE, derr = MMC_ERR_NONE;
+    int multi;
+    struct mmc_command cmd;
+    struct mmc_command stop;
+    u32 *ptr = (u32 *)dst;
+
+    LTRACEF("[MSDC] Read data %d bytes from 0x%x\n", nblks * blksz, src);
+
+    multi = nblks > 1 ? 1 : 0;
+
+    MSDC_CLR_FIFO();
+    MSDC_WRITE32(SDC_BLK_NUM, nblks);
+    msdc_set_timeout(host, 100000000, 0);
+
+    /* send read command */
+    cmd.opcode  = multi ? MMC_CMD_READ_MULTIPLE_BLOCK : MMC_CMD_READ_SINGLE_BLOCK;
+    cmd.rsptyp  = RESP_R1;
+    cmd.arg     = src;
+    cmd.retries = 0;
+    cmd.timeout = CMD_TIMEOUT;
+    err = msdc_cmd(host, &cmd);
+
+    if (err != MMC_ERR_NONE)
+        goto done;
+
+    err = derr = msdc_pio_read(host, (u32 *)ptr, nblks * blksz);
+
+done:
+    if (err != MMC_ERR_NONE) {
+        if (derr != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "[MSDC] Read data error (%d)\n", derr);
+            if (msdc_abort_handler(host, 1))
+                dprintf(CRITICAL, "[MSDC] abort failed\n");
+        } else {
+            dprintf(CRITICAL, "[MSDC] Read error (%d)\n", err);
+        }
+    }
+    return (derr == MMC_ERR_NONE) ? err : derr;
+}
+
+static int msdc_pio_bwrite(struct mmc_host *host, u32 dst, u8 *src, u32 nblks)
+{
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+    addr_t base = host->base;
+    int err = MMC_ERR_NONE, derr = MMC_ERR_NONE;
+    int multi;
+    u32 blksz = host->blklen;
+    struct mmc_command cmd;
+    struct mmc_command stop;
+    u32 *ptr = (u32 *)src;
+
+    dprintf(CRITICAL, "[MSDC] Write data %d bytes to 0x%x\n", nblks * blksz, dst);
+
+    multi = nblks > 1 ? 1 : 0;
+
+    MSDC_CLR_FIFO();
+    MSDC_WRITE32(SDC_BLK_NUM, nblks);
+
+    /* No need since MSDC always waits 8 cycles for write data timeout */
+
+    /* send write command */
+    cmd.opcode  = multi ? MMC_CMD_WRITE_MULTIPLE_BLOCK : MMC_CMD_WRITE_BLOCK;
+    cmd.rsptyp  = RESP_R1;
+    cmd.arg     = dst;
+    cmd.retries = 0;
+    cmd.timeout = CMD_TIMEOUT;
+    err = msdc_cmd(host, &cmd);
+
+    if (err != MMC_ERR_NONE)
+        goto done;
+
+    err = derr = msdc_pio_write(host, (u32 *)ptr, nblks * blksz);
+
+done:
+    if (err != MMC_ERR_NONE) {
+        if (derr != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "[MSDC] Write data error (%d)\n", derr);
+            if (msdc_abort_handler(host, 1))
+                dprintf(CRITICAL, "[MSDC] abort failed\n");
+        } else {
+            dprintf(CRITICAL, "[MSDC] Write error (%d)\n", err);
+        }
+    }
+    return (derr == MMC_ERR_NONE) ? err : derr;
+}
+#endif
+
+
+static void msdc_config_clksrc(struct mmc_host *host, u32 clksrc, u32 hclksrc)
+{
+    // modify the clock
+    ASSERT(host);
+    /*
+     * For MT2712, MSDC0 use 400Mhz(MSDCPLL) source clock
+     */
+    host->clksrc  = clksrc;
+    host->hclksrc = hclksrc;
+#ifndef FPGA_PLATFORM
+    if (host->host_id == 0)
+        host->clk     = 400 * 1000 * 1000;
+    else
+        host->clk     = 200 * 1000 * 1000;
+#else
+    host->clk = MSDC_OP_SCLK;
+#endif
+
+    /* Chaotian, may need update this part of code */
+    LTRACEF("[info][%s] pll_clk %u (%uMHz), pll_hclk %u\n",
+            __func__, host->clksrc, host->clk/1000000, host->hclksrc);
+}
+
+void msdc_config_clock(struct mmc_host *host, int state, u32 hz)
+{
+    addr_t base = host->base;
+    u32 mode = 0;
+    u32 div;
+    u32 sclk;
+    u32 u4buswidth=0;
+
+    if (hz >= host->f_max) {
+        hz = host->f_max;
+    } else if (hz < host->f_min) {
+        hz = host->f_min;
+    }
+
+    msdc_config_clksrc(host, host->clksrc, host->hclksrc);
+    MSDC_CLR_BIT32(MSDC_CFG, MSDC_CFG_CKMOD_HS400);
+    MSDC_SET_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS);
+
+    if (state & MMC_STATE_HS400) {
+        mode = 0x3;
+        div = 0; /* we let hs400 mode fixed at 200Mhz */
+        sclk = host->clk >> 1;
+        MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_CKMOD_HS400);
+        MSDC_CLR_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS);
+    } else if (state&MMC_STATE_DDR) {
+        mode = 0x2; /* ddr mode and use divisor */
+        if (hz >= (host->clk >> 2)) {
+            div  = 0;              /* mean div = 1/2 */
+            sclk = host->clk >> 2; /* sclk = clk/div/2. 2: internal divisor */
+        } else {
+            div  = (host->clk + ((hz << 2) - 1)) / (hz << 2);
+            sclk = (host->clk >> 2) / div;
+            div  = (div >> 1);     /* since there is 1/2 internal divisor */
+        }
+    } else if (hz >= host->clk) {
+        mode = 0x1; /* no divisor and divisor is ignored */
+        div  = 0;
+        sclk = host->clk;
+    } else {
+        mode = 0x0; /* use divisor */
+        if (hz >= (host->clk >> 1)) {
+            div  = 0;              /* mean div = 1/2 */
+            sclk = host->clk >> 1; /* sclk = clk / 2 */
+        } else {
+            div  = (host->clk + ((hz << 2) - 1)) / (hz << 2);
+            sclk = (host->clk >> 2) / div;
+        }
+    }
+    host->sclk = sclk;
+
+    MSDC_CLR_BIT32(PERI_MSDC_CLK_EN, (0x1 << 0));
+    /* set clock mode and divisor */
+    MSDC_SET_FIELD(MSDC_CFG, (MSDC_CFG_CKMOD |MSDC_CFG_CKDIV),\
+                   (mode << 12) | div);
+    MSDC_SET_BIT32(PERI_MSDC_CLK_EN, (0x1 << 0));
+    /* wait clock stable */
+    while (!(MSDC_READ32(MSDC_CFG) & MSDC_CFG_CKSTB));
+
+    MSDC_GET_FIELD(SDC_CFG,SDC_CFG_BUSWIDTH,u4buswidth);
+
+    LTRACEF(
+            "[MSDC] SET_CLK(%dkHz): SCLK(%dkHz) MODE(%d) DIV(%d) DS(%d) RS(%d) buswidth(%s)\n",
+            hz/1000, sclk/1000, mode, div, msdc_cap[host->host_id].data_edge,
+            msdc_cap[host->host_id].cmd_edge,
+            (u4buswidth == 0) ?
+            "1-bit" : (u4buswidth == 1) ?
+            "4-bits" : (u4buswidth == 2) ?
+            "8-bits" : "undefined");
+}
+
+void msdc_config_bus(struct mmc_host *host, u32 width)
+{
+    u32 val,mode, div;
+    addr_t base = host->base;
+
+    val = (width == HOST_BUS_WIDTH_8) ? 2 :
+          (width == HOST_BUS_WIDTH_4) ? 1 : 0;
+
+    MSDC_SET_FIELD(SDC_CFG, SDC_CFG_BUSWIDTH, val);
+    MSDC_GET_FIELD(MSDC_CFG,MSDC_CFG_CKMOD,mode);
+    MSDC_GET_FIELD(MSDC_CFG,MSDC_CFG_CKDIV,div);
+
+    LTRACEF("CLK (%dMHz), SCLK(%dkHz) MODE(%d) DIV(%d) buswidth(%u-bits)\n",
+            host->clk/1000000, host->sclk/1000, mode, div, width);
+}
+
+static void msdc_config_pin(struct mmc_host *host, int mode)
+{
+    LTRACEF("[MSDC] Pins mode(%d), none(0), down(1), up(2), keep(3)\n", mode);
+
+    switch (mode) {
+        case MSDC_PIN_PULL_UP:
+            msdc_pin_set(host, 0, MSDC_10KOHM);
+            break;
+        case MSDC_PIN_PULL_DOWN:
+            msdc_pin_set(host, 1, MSDC_50KOHM);
+            break;
+        case MSDC_PIN_PULL_NONE:
+        default:
+            msdc_pin_set(host, 1, MSDC_50KOHM);
+            break;
+    }
+}
+
+void msdc_clock(struct mmc_host *host, int on)
+{
+    /* Chaotian, may need update this part of code */
+    LTRACEF("[MSDC] Turn %s %s clock \n", on ? "on" : "off", "host");
+}
+
+static void msdc_host_power(struct mmc_host *host, int on)
+{
+    LTRACEF("[MSDC] Turn %s %s power \n", on ? "on" : "off", "host");
+    return; /* power always on, return directly */
+
+    if (on) {
+        msdc_config_pin(host, MSDC_PIN_PULL_UP);
+        msdc_set_host_pwr(host, 1);
+        msdc_clock(host, 1);
+    } else {
+        msdc_clock(host, 0);
+        msdc_set_host_pwr(host, 0);
+        msdc_config_pin(host, MSDC_PIN_PULL_DOWN);
+    }
+}
+
+static void msdc_card_power(struct mmc_host *host, int on)
+{
+    LTRACEF("[MSDC] Turn %s %s power \n", on ? "on" : "off", "card");
+    return; /* power always on, return directly */
+
+    if (on) {
+        msdc_set_card_pwr(host, 1);
+    } else {
+        msdc_set_card_pwr(host, 0);
+    }
+}
+
+void msdc_power(struct mmc_host *host, u8 mode)
+{
+    if (mode == MMC_POWER_ON || mode == MMC_POWER_UP) {
+        msdc_host_power(host, 1);
+        msdc_card_power(host, 1);
+    } else {
+        msdc_card_power(host, 0);
+        msdc_host_power(host, 0);
+    }
+}
+
+void msdc_reset_tune_counter(struct mmc_host *host)
+{
+    host->time_read = 0;
+}
+
+#ifdef FEATURE_MMC_CM_TUNING
+static int msdc_tune_cmdrsp(struct mmc_host *host, struct mmc_command *cmd)
+{
+    addr_t base = host->base;
+    u32 sel = 0;
+    u32 rsmpl,cur_rsmpl, orig_rsmpl;
+    u32 rrdly,cur_rrdly, orig_rrdly;
+    u32 cntr,cur_cntr,orig_cmdrtc;
+    u32 dl_cksel, cur_dl_cksel, orig_dl_cksel;
+    u32 times = 0;
+    int result = MMC_ERR_CMDTUNEFAIL;
+    u32 tmp = 0;
+
+    if (host->sclk > 100000000) {
+        sel = 1;
+        //MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_RX_SDCLKO_SEL,0);
+    }
+
+    MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, orig_rsmpl);
+    MSDC_GET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY, orig_rrdly);
+    MSDC_GET_FIELD(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_CMD_RSP, orig_cmdrtc);
+    MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, orig_dl_cksel);
+
+    dl_cksel = 0;
+    do {
+        cntr = 0;
+        do {
+            rrdly = 0;
+            do {
+                for (rsmpl = 0; rsmpl < 2; rsmpl++) {
+                    cur_rsmpl = (orig_rsmpl + rsmpl) % 2;
+                    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, cur_rsmpl);
+                    if (host->sclk <= 400000) { //In sd/emmc init flow, fix rising edge for latching cmd response
+                        MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, 0);
+                    }
+                    if (cmd->opcode != MMC_CMD_STOP_TRANSMISSION) {
+                        result = msdc_send_cmd(host, cmd);
+                        if (result == MMC_ERR_TIMEOUT)
+                            rsmpl--;
+                        if (result != MMC_ERR_NONE && cmd->opcode != MMC_CMD_STOP_TRANSMISSION) {
+                            if (cmd->opcode == MMC_CMD_READ_MULTIPLE_BLOCK || cmd->opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK || cmd->opcode == MMC_CMD_READ_SINGLE_BLOCK ||cmd->opcode == MMC_CMD_WRITE_BLOCK)
+                                msdc_abort_handler(host,1);
+                            continue;
+                        }
+                        result = msdc_wait_cmd_done(host, cmd);
+                    } else if (cmd->opcode == MMC_CMD_STOP_TRANSMISSION) {
+                        result = MMC_ERR_NONE;
+                        goto done;
+                    } else
+                        result = MMC_ERR_BADCRC;
+
+                    times++;
+                    if (result == MMC_ERR_NONE)
+                        goto done;
+                    tmp = MSDC_READ32(SDC_CMD);
+                    /* check if data is used by the command or not */
+                    if (tmp & 0x1800) {
+                        if (msdc_abort_handler(host, 1))
+                            dprintf(CRITICAL, "[MSDC] abort failed\n");
+                    }
+                }
+                cur_rrdly = (orig_rrdly + rrdly + 1) % 32;
+                MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY, cur_rrdly);
+            } while (++rrdly < 32);
+            if (!sel)
+                break;
+            cur_cntr = (orig_cmdrtc + cntr + 1) % 8;
+            MSDC_SET_FIELD(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_CMD_RSP, cur_cntr);
+        } while (++cntr < 8);
+        /* no need to update data ck sel */
+        if (!sel)
+            break;
+        cur_dl_cksel = (orig_dl_cksel +dl_cksel+1) % 8;
+        MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, cur_dl_cksel);
+        dl_cksel++;
+    } while (dl_cksel < 8);
+    /* no need to update ck sel */
+    if (result != MMC_ERR_NONE)
+        result = MMC_ERR_CMDTUNEFAIL;
+done:
+
+    dprintf(ALWAYS, "[MSDC] <TUNE_CMD><%d><%s>\n", times, (result == MMC_ERR_NONE) ?"PASS" : "FAIL");
+    return result;
+}
+#endif
+
+#ifdef FEATURE_MMC_RD_TUNING
+int msdc_tune_bread(struct mmc_host *host, u8 *dst, u32 src, u32 nblks)
+{
+    addr_t base = host->base;
+    u32 dcrc = 1, ddr = 0, sel = 0;
+    u32 cur_rxdly0, cur_rxdly1;
+    u32 dsmpl, cur_dsmpl, orig_dsmpl;
+    u32 dsel,cur_dsel,orig_dsel;
+    u32 dl_cksel,cur_dl_cksel,orig_dl_cksel;
+    u32 rxdly;
+    u32 cur_dat0, cur_dat1, cur_dat2, cur_dat3, cur_dat4, cur_dat5,
+        cur_dat6, cur_dat7;
+    u32 orig_dat0, orig_dat1, orig_dat2, orig_dat3, orig_dat4, orig_dat5,
+        orig_dat6, orig_dat7;
+    u32 orig_clkmode;
+    u32 times = 0;
+    int result = MMC_ERR_READTUNEFAIL;
+
+    if (host->sclk > 100000000)
+        sel = 1;
+    if (host->card)
+        ddr = mmc_card_ddr(host->card);
+    MSDC_GET_FIELD(MSDC_CFG,MSDC_CFG_CKMOD,orig_clkmode);
+    MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, orig_dsel);
+    MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, orig_dl_cksel);
+    MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_DSPL, orig_dsmpl);
+
+    /* Tune Method 2. delay each data line */
+    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1);
+
+    dl_cksel = 0;
+    do {
+        dsel = 0;
+        do {
+            rxdly = 0;
+            do {
+                for (dsmpl = 0; dsmpl < 2; dsmpl++) {
+                    cur_dsmpl = (orig_dsmpl + dsmpl) % 2;
+                    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_DSPL, cur_dsmpl);
+                    result = host->blk_read(host, dst, src, nblks);
+                    if (result == MMC_ERR_CMDTUNEFAIL || result == MMC_ERR_CMD_RSPCRC || result == MMC_ERR_ACMD_RSPCRC)
+                        goto done;
+                    MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+
+                    if (!ddr)
+                        dcrc &= ~SDC_DCRC_STS_NEG;
+
+                    /* for debugging */
+                    times++;
+                    /* no cre error in this data line */
+                    if (result == MMC_ERR_NONE && dcrc == 0) {
+                        goto done;
+                    } else {
+                        result = MMC_ERR_BADCRC;
+                    }
+                }
+                cur_rxdly0 = MSDC_READ32(MSDC_DAT_RDDLY0);
+                cur_rxdly1 = MSDC_READ32(MSDC_DAT_RDDLY1);
+
+
+                orig_dat0 = (cur_rxdly0 >> 24) & 0x1F;
+                orig_dat1 = (cur_rxdly0 >> 16) & 0x1F;
+                orig_dat2 = (cur_rxdly0 >> 8) & 0x1F;
+                orig_dat3 = (cur_rxdly0 >> 0) & 0x1F;
+                orig_dat4 = (cur_rxdly1 >> 24) & 0x1F;
+                orig_dat5 = (cur_rxdly1 >> 16) & 0x1F;
+                orig_dat6 = (cur_rxdly1 >> 8) & 0x1F;
+                orig_dat7 = (cur_rxdly1 >> 0) & 0x1F;
+
+                if (ddr) {
+                    cur_dat0 = (dcrc & (1 << 0) || dcrc & (1 <<  8)) ? ((orig_dat0 + 1) % 32) : orig_dat0;
+                    cur_dat1 = (dcrc & (1 << 1) || dcrc & (1 <<  9)) ? ((orig_dat1 + 1) % 32) : orig_dat1;
+                    cur_dat2 = (dcrc & (1 << 2) || dcrc & (1 << 10)) ? ((orig_dat2 + 1) % 32) : orig_dat2;
+                    cur_dat3 = (dcrc & (1 << 3) || dcrc & (1 << 11)) ? ((orig_dat3 + 1) % 32) : orig_dat3;
+                    cur_dat4 = (dcrc & (1 << 4) || dcrc & (1 << 12)) ? ((orig_dat4 + 1) % 32) : orig_dat4;
+                    cur_dat5 = (dcrc & (1 << 5) || dcrc & (1 << 13)) ? ((orig_dat5 + 1) % 32) : orig_dat5;
+                    cur_dat6 = (dcrc & (1 << 6) || dcrc & (1 << 14)) ? ((orig_dat6 + 1) % 32) : orig_dat6;
+                    cur_dat7 = (dcrc & (1 << 7) || dcrc & (1 << 15)) ? ((orig_dat7 + 1) % 32) : orig_dat7;
+                } else {
+                    cur_dat0 = (dcrc & (1 << 0)) ? ((orig_dat0 + 1) % 32) : orig_dat0;
+                    cur_dat1 = (dcrc & (1 << 1)) ? ((orig_dat1 + 1) % 32) : orig_dat1;
+                    cur_dat2 = (dcrc & (1 << 2)) ? ((orig_dat2 + 1) % 32) : orig_dat2;
+                    cur_dat3 = (dcrc & (1 << 3)) ? ((orig_dat3 + 1) % 32) : orig_dat3;
+                    cur_dat4 = (dcrc & (1 << 4)) ? ((orig_dat4 + 1) % 32) : orig_dat4;
+                    cur_dat5 = (dcrc & (1 << 5)) ? ((orig_dat5 + 1) % 32) : orig_dat5;
+                    cur_dat6 = (dcrc & (1 << 6)) ? ((orig_dat6 + 1) % 32) : orig_dat6;
+                    cur_dat7 = (dcrc & (1 << 7)) ? ((orig_dat7 + 1) % 32) : orig_dat7;
+                }
+
+                cur_rxdly0 = ((cur_dat0 & 0x1F) << 24) | ((cur_dat1 & 0x1F) << 16) |
+                             ((cur_dat2 & 0x1F)<< 8) | ((cur_dat3 & 0x1F) << 0);
+                cur_rxdly1 = ((cur_dat4 & 0x1F) << 24) | ((cur_dat5 & 0x1F) << 16) |
+                             ((cur_dat6 & 0x1F) << 8) | ((cur_dat7 & 0x1F) << 0);
+
+                MSDC_WRITE32(MSDC_DAT_RDDLY0, cur_rxdly0);
+                MSDC_WRITE32(MSDC_DAT_RDDLY1, cur_rxdly1);
+            } while (++rxdly < 32);
+            if (!sel)
+                break;
+            cur_dsel = (orig_dsel + dsel + 1) % 32;
+            MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, cur_dsel);
+        } while (++dsel < 32);
+        /* no need to update data ck sel */
+        if (orig_clkmode != 1)
+            break;
+
+        cur_dl_cksel = (orig_dl_cksel + dl_cksel + 1)% 8;
+        MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, cur_dl_cksel);
+        dl_cksel++;
+    } while (dl_cksel < 8);
+done:
+    dprintf(ALWAYS, "[MSDC] <msdc_tune_bread<%d><%s><cmd%d>@msdc_tune_bread\n",
+            times, (result == MMC_ERR_NONE && dcrc == 0) ? "PASS" : "FAIL",
+            (nblks == 1 ? 17 : 18));
+
+    return result;
+}
+#define READ_TUNING_MAX_HS (2 * 32)
+#define READ_TUNING_MAX_UHS (2 * 32 * 32)
+#define READ_TUNING_MAX_UHS_CLKMOD1 (2 * 32 * 32 *8)
+
+int msdc_tune_read(struct mmc_host *host)
+{
+    return 0;
+#if 0
+    addr_t base = host->base;
+    u32 dcrc, ddr = 0, sel = 0;
+    u32 cur_rxdly0 = 0 , cur_rxdly1 = 0;
+    u32 cur_dsmpl = 0, orig_dsmpl;
+    u32 cur_dsel = 0,orig_dsel;
+    u32 cur_dl_cksel = 0,orig_dl_cksel;
+    u32 cur_dat0 = 0, cur_dat1 = 0, cur_dat2 = 0, cur_dat3 = 0, cur_dat4 = 0, cur_dat5 = 0,
+        cur_dat6 = 0, cur_dat7 = 0;
+    u32 orig_dat0, orig_dat1, orig_dat2, orig_dat3, orig_dat4, orig_dat5,
+        orig_dat6, orig_dat7;
+    u32 orig_clkmode;
+    u32 times = 0;
+    int result = MMC_ERR_NONE;
+
+    if (host->sclk > 100000000)
+        sel = 1;
+    if (host->card)
+        ddr = mmc_card_ddr(host->card);
+    MSDC_GET_FIELD(MSDC_CFG,MSDC_CFG_CKMOD,orig_clkmode);
+    //if(orig_clkmode == 1)
+    //MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_RX_SDCLKO_SEL, 0);
+
+    MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, orig_dsel);
+    MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, orig_dl_cksel);
+    MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_DSPL, orig_dsmpl);
+
+    /* Tune Method 2. delay each data line */
+    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1);
+
+
+    cur_dsmpl = (orig_dsmpl + 1) ;
+    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_DSPL, cur_dsmpl % 2);
+    if (cur_dsmpl >= 2) {
+        MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+        if (!ddr) dcrc &= ~SDC_DCRC_STS_NEG;
+
+        cur_rxdly0 = MSDC_READ32(MSDC_DAT_RDDLY0);
+        cur_rxdly1 = MSDC_READ32(MSDC_DAT_RDDLY1);
+
+        orig_dat0 = (cur_rxdly0 >> 24) & 0x1F;
+        orig_dat1 = (cur_rxdly0 >> 16) & 0x1F;
+        orig_dat2 = (cur_rxdly0 >> 8) & 0x1F;
+        orig_dat3 = (cur_rxdly0 >> 0) & 0x1F;
+        orig_dat4 = (cur_rxdly1 >> 24) & 0x1F;
+        orig_dat5 = (cur_rxdly1 >> 16) & 0x1F;
+        orig_dat6 = (cur_rxdly1 >> 8) & 0x1F;
+        orig_dat7 = (cur_rxdly1 >> 0) & 0x1F;
+
+        if (ddr) {
+            cur_dat0 = (dcrc & (1 << 0) || dcrc & (1 <<  8)) ? (orig_dat0 + 1) : orig_dat0;
+            cur_dat1 = (dcrc & (1 << 1) || dcrc & (1 <<  9)) ? (orig_dat1 + 1) : orig_dat1;
+            cur_dat2 = (dcrc & (1 << 2) || dcrc & (1 << 10)) ? (orig_dat2 + 1) : orig_dat2;
+            cur_dat3 = (dcrc & (1 << 3) || dcrc & (1 << 11)) ? (orig_dat3 + 1) : orig_dat3;
+            cur_dat4 = (dcrc & (1 << 4) || dcrc & (1 << 12)) ? (orig_dat4 + 1) : orig_dat4;
+            cur_dat5 = (dcrc & (1 << 5) || dcrc & (1 << 13)) ? (orig_dat5 + 1) : orig_dat5;
+            cur_dat6 = (dcrc & (1 << 6) || dcrc & (1 << 14)) ? (orig_dat6 + 1) : orig_dat6;
+            cur_dat7 = (dcrc & (1 << 7) || dcrc & (1 << 15)) ? (orig_dat7 + 1) : orig_dat7;
+        } else {
+            cur_dat0 = (dcrc & (1 << 0)) ? (orig_dat0 + 1) : orig_dat0;
+            cur_dat1 = (dcrc & (1 << 1)) ? (orig_dat1 + 1) : orig_dat1;
+            cur_dat2 = (dcrc & (1 << 2)) ? (orig_dat2 + 1) : orig_dat2;
+            cur_dat3 = (dcrc & (1 << 3)) ? (orig_dat3 + 1) : orig_dat3;
+            cur_dat4 = (dcrc & (1 << 4)) ? (orig_dat4 + 1) : orig_dat4;
+            cur_dat5 = (dcrc & (1 << 5)) ? (orig_dat5 + 1) : orig_dat5;
+            cur_dat6 = (dcrc & (1 << 6)) ? (orig_dat6 + 1) : orig_dat6;
+            cur_dat7 = (dcrc & (1 << 7)) ? (orig_dat7 + 1) : orig_dat7;
+        }
+
+        cur_rxdly0 = ((cur_dat0 & 0x1F) << 24) | ((cur_dat1 & 0x1F) << 16) |
+                     ((cur_dat2 & 0x1F) << 8) | ((cur_dat3 & 0x1F) << 0);
+        cur_rxdly1 = ((cur_dat4 & 0x1F) << 24) | ((cur_dat5 & 0x1F)<< 16) |
+                     ((cur_dat6 & 0x1F) << 8) | ((cur_dat7 & 0x1F) << 0);
+
+        MSDC_WRITE32(MSDC_DAT_RDDLY0, cur_rxdly0);
+        MSDC_WRITE32(MSDC_DAT_RDDLY1, cur_rxdly1);
+    }
+    if (cur_dat0 >= 32 || cur_dat1 >= 32 || cur_dat2 >= 32 || cur_dat3 >= 32 ||
+            cur_dat4 >= 32 || cur_dat5 >= 32 || cur_dat6 >= 32 || cur_dat7 >= 32) {
+        if (sel) {
+
+            cur_dsel = (orig_dsel + 1);
+            MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_DLY_SEL, cur_dsel % 32);
+
+        }
+    }
+    if (cur_dsel >= 32) {
+        if (orig_clkmode == 1 && sel) {
+
+            cur_dl_cksel = (orig_dl_cksel + 1);
+            MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_INT_DAT_LATCH_CK_SEL, cur_dl_cksel % 8);
+        }
+    }
+    ++(host->time_read);
+    if ((sel == 1 && orig_clkmode == 1 && host->time_read == READ_TUNING_MAX_UHS_CLKMOD1)||
+            (sel == 1 && orig_clkmode != 1 && host->time_read == READ_TUNING_MAX_UHS)||
+            (sel == 0 && orig_clkmode != 1 && host->time_read == READ_TUNING_MAX_HS)) {
+
+        result = MMC_ERR_READTUNEFAIL;
+    }
+
+    return result;
+#endif
+}
+#endif
+
+#ifdef FEATURE_MMC_WR_TUNING
+int msdc_tune_bwrite(struct mmc_host *host, u32 dst, u8 *src, u32 nblks)
+{
+    addr_t base = host->base;
+    u32 sel = 0;
+    u32 wrrdly, cur_wrrdly, orig_wrrdly;
+    u32 dsmpl, cur_dsmpl, orig_dsmpl;
+    u32 d_cntr,orig_d_cntr,cur_d_cntr;
+    u32 rxdly, cur_rxdly0;
+    u32 orig_dat0, orig_dat1, orig_dat2, orig_dat3;
+    u32 cur_dat0, cur_dat1, cur_dat2, cur_dat3;
+    u32 times = 0;
+    int result = MMC_ERR_WRITETUNEFAIL;
+
+    if (host->sclk > 100000000)
+        sel = 1;
+
+    MSDC_GET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, orig_wrrdly);
+    MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL, orig_dsmpl);
+    MSDC_GET_FIELD(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_WRDAT_CRCS, orig_d_cntr);
+
+    /* Tune Method 2. delay data0 line */
+    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1);
+
+    cur_rxdly0 = MSDC_READ32(MSDC_DAT_RDDLY0);
+
+    orig_dat0 = (cur_rxdly0 >> 24) & 0x1F;
+    orig_dat1 = (cur_rxdly0 >> 16) & 0x1F;
+    orig_dat2 = (cur_rxdly0 >> 8) & 0x1F;
+    orig_dat3 = (cur_rxdly0 >> 0) & 0x1F;
+
+    d_cntr = 0;
+    do {
+        rxdly = 0;
+        do {
+            wrrdly = 0;
+            do {
+                for (dsmpl = 0; dsmpl < 2; dsmpl++) {
+                    cur_dsmpl = (orig_dsmpl + dsmpl) % 2;
+                    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL, cur_dsmpl);
+                    result = host->blk_write(host, dst, src, nblks);
+                    if (result == MMC_ERR_CMDTUNEFAIL || result == MMC_ERR_CMD_RSPCRC || result == MMC_ERR_ACMD_RSPCRC)
+                        goto done;
+
+                    times++;
+                    if (result == MMC_ERR_NONE) {
+                        goto done;
+                    }
+                }
+                cur_wrrdly = ++orig_wrrdly % 32;
+                MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, cur_wrrdly);
+            } while (++wrrdly < 32);
+
+            cur_dat0 = ++orig_dat0 % 32; /* only adjust bit-1 for crc */
+            cur_dat1 = orig_dat1;
+            cur_dat2 = orig_dat2;
+            cur_dat3 = orig_dat3;
+
+            cur_rxdly0 = (cur_dat0 << 24) | (cur_dat1 << 16) |
+                         (cur_dat2 << 8) | (cur_dat3 << 0);
+
+            MSDC_WRITE32(MSDC_DAT_RDDLY0, cur_rxdly0);
+        } while (++rxdly < 32);
+
+        /* no need to update data ck sel */
+        if (!sel)
+            break;
+
+        cur_d_cntr= (orig_d_cntr + d_cntr +1 )% 8;
+        MSDC_SET_FIELD(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_WRDAT_CRCS, cur_d_cntr);
+        d_cntr++;
+    } while (d_cntr < 8);
+done:
+    dprintf(ALWAYS, "[MSDC] <TUNE_BWRITE_%d><%s>\n", times, result == MMC_ERR_NONE ? "PASS" : "FAIL");
+
+    return result;
+}
+#endif
+
+void msdc_emmc_boot_stop(struct mmc_host *host)
+{
+    addr_t base = host->base;
+    u32 count = 0;
+
+    /* Step5. stop the boot mode */
+    MSDC_WRITE32(SDC_ARG, 0x00000000);
+    MSDC_WRITE32(SDC_CMD, 0x00001000);
+
+    MSDC_SET_FIELD(EMMC_CFG0, EMMC_CFG0_BOOTWDLY, 2);
+    MSDC_SET_BIT32(EMMC_CFG0, EMMC_CFG0_BOOTSTOP);
+    while (MSDC_READ32(EMMC_STS) & EMMC_STS_BOOTUPSTATE) {
+        spin(1000);
+        count++;
+        if (count >= 1000) {
+            dprintf(ALWAYS, "Timeout to wait EMMC to leave boot state!\n");
+            break;
+        }
+    }
+
+    /* Step6. */
+    MSDC_CLR_BIT32(EMMC_CFG0, EMMC_CFG0_BOOTSUPP);
+
+    /* Step7. clear EMMC_STS bits */
+    MSDC_WRITE32(EMMC_STS, MSDC_READ32(EMMC_STS));
+}
+
+int msdc_init(struct mmc_host *host)
+{
+    addr_t base = host->host_id ? MSDC1_BASE: MSDC0_BASE; /* only support MSDC0, MSDC1 */
+    msdc_priv_t *priv;
+
+    LTRACEF("[%s]: Host controller intialization start \n", __func__);
+
+    priv = &msdc_priv;
+    memset(priv, 0, sizeof(msdc_priv_t));
+
+    host->base   = base;
+    host->clksrc = msdc_cap[host->host_id].clk_src;
+    host->hclksrc= msdc_cap[host->host_id].hclk_src;
+#ifndef FPGA_PLATFORM
+    host->f_max  = hclks_msdc30[host->clksrc];
+#else
+    host->f_max  = MSDC_MAX_SCLK;
+#endif
+
+    host->f_min  = MSDC_MIN_SCLK;
+    host->blklen = 0;
+    host->priv   = (void *)priv;
+    host->caps   = MMC_CAP_MULTIWRITE;
+
+    if (msdc_cap[host->host_id].flags & MSDC_HIGHSPEED)
+        host->caps |= (MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED);
+    if (msdc_cap[host->host_id].flags & MSDC_DDR)
+        host->caps |= MMC_CAP_DDR;
+    if (msdc_cap[host->host_id].data_pins == 4)
+        host->caps |= MMC_CAP_4_BIT_DATA;
+    if (msdc_cap[host->host_id].data_pins == 8)
+        host->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
+    if (msdc_cap[host->host_id].flags & MSDC_HS200)
+        host->caps |= MMC_CAP_EMMC_HS200;
+    if (msdc_cap[host->host_id].flags & MSDC_HS400)
+        host->caps |= MMC_CAP_EMMC_HS400;
+
+    host->ocr_avail = MMC_VDD_32_33;  /* TODO: To be customized */
+
+    /* Configure BASIC_DMA + AUTOCMD12 for better R/W performance
+     * NOTE: ACMD23 only support transferring size of up to 32M */
+    priv->autocmd = MSDC_AUTOCMD12;
+    if (priv->autocmd == MSDC_AUTOCMD23)
+        /* The maximal transferring size is size of *[15:0] number of blocks* */
+        host->max_phys_segs = 0xffff;
+    else
+        /* The maximal transferring size is size of DMA_LENGTH */
+        host->max_phys_segs = (UINT_MAX & ~511) >> MMC_BLOCK_BITS_SHFT;
+
+    priv->rdsmpl       = msdc_cap[host->host_id].data_edge;
+    priv->wdsmpl       = msdc_cap[host->host_id].data_edge;
+    priv->rsmpl       = msdc_cap[host->host_id].cmd_edge;
+
+#ifdef MSDC_USE_DMA_MODE
+    host->blk_read  = msdc_dma_bread;
+    host->blk_write = msdc_dma_bwrite;
+    LTRACEF("Transfer method: DMA\n");
+#else
+    host->blk_read  = msdc_pio_bread;
+    host->blk_write = msdc_pio_bwrite;
+    LTRACEF("Transfer method: PIO\n");
+#endif
+
+    priv->rdsmpl       = msdc_cap[host->host_id].data_edge;
+    priv->rsmpl       = msdc_cap[host->host_id].cmd_edge;
+
+    if (host->skip_reinit)
+        goto skip_host_init;
+    /* disable EMMC boot mode */
+    msdc_emmc_boot_stop(host);
+
+    msdc_power(host, MMC_POWER_OFF);
+    msdc_power(host, MMC_POWER_ON);
+
+    if (host->host_id == 1)
+        sd_card_vccq_on();
+
+    /* set to SD/MMC mode */
+    MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_MODE, MSDC_SDMMC);
+    MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_PIO);
+    MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_CKPDN);
+
+    MSDC_RESET();
+    MSDC_CLR_FIFO();
+    MSDC_CLR_INT();
+
+    /* reset tuning parameter */
+    //MSDC_WRITE32(MSDC_PAD_CTL0, 0x0098000);
+    //MSDC_WRITE32(MSDC_PAD_CTL1, 0x00A0000);
+    //MSDC_WRITE32(MSDC_PAD_CTL2, 0x00A0000);
+    MSDC_WRITE32(MSDC_PAD_TUNE, 0x0000000);
+    MSDC_WRITE32(MSDC_DAT_RDDLY0, 0x00000000);
+    MSDC_WRITE32(MSDC_DAT_RDDLY1, 0x00000000);
+    MSDC_WRITE32(MSDC_IOCON, 0x00000000);
+
+    MSDC_SET_BIT32(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATRRDLYSEL);
+    MSDC_SET_BIT32(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLYSEL);
+    MSDC_WRITE32(MSDC_PATCH_BIT0, 0x403c0046);
+    MSDC_WRITE32(MSDC_PATCH_BIT1, 0xFFFF4309);//High 16 bit = 0 mean Power KPI is on, enable ECO for write timeout issue
+    MSDC_SET_BIT32(EMMC50_CFG0, MSDC_EMMC50_CFG_CRCSTS_SEL);
+    MSDC_CLR_BIT32(SDC_FIFO_CFG, SDC_FIFO_CFG_WRVALIDSEL);
+    MSDC_CLR_BIT32(SDC_FIFO_CFG, SDC_FIFO_CFG_RDVALIDSEL);
+    MSDC_SET_BIT32(SDC_AVG_CFG0, SDC_RX_ENHANCE_EN);
+    MSDC_SET_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS);
+    MSDC_CLR_BIT32(MSDC_PATCH_BIT1, MSDC_BUSY_CHECK_SEL); /* disable busy check */
+    //MSDC_PATCH_BIT1YD:WRDAT_CRCS_TA_CNTR need fix to 3'001 by default,(<50MHz) (>=50MHz set 3'001 as initial value is OK for tunning)
+    //YD:CMD_RSP_TA_CNTR need fix to 3'001 by default(<50MHz)(>=50MHz set 3'001as initial value is OK for tunning)
+    /* 2012-01-07 using internal clock instead of feedback clock */
+    //MSDC_SET_BIT32(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_CK_SEL);
+
+#ifdef MSDC_USE_PATCH_BIT2_TURNING_WITH_ASYNC
+    MSDC_SET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS,1);
+    MSDC_SET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_CFGRESP,0);
+#else
+    MSDC_SET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS,0);
+    MSDC_SET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_CFGRESP,1);
+#endif
+
+    /* enable wake up events */
+    //MSDC_SET_BIT32(SDC_CFG, SDC_CFG_INSWKUP);
+
+    /* eneable SMT for glitch filter */
+#ifdef FPGA_PLATFORM
+#if 0
+    MSDC_SET_BIT32(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKSMT);
+    MSDC_SET_BIT32(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDSMT);
+    MSDC_SET_BIT32(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATSMT);
+#endif
+#else
+    msdc_set_smt(host,1);
+#endif
+    /* set clk, cmd, dat pad driving */
+    msdc_set_driving(host, &msdc_cap[host->host_id]);
+
+    /* set sampling edge */
+    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, msdc_cap[host->host_id].cmd_edge);
+    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_DSPL, msdc_cap[host->host_id].data_edge);
+
+    /* write crc timeout detection */
+    MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_PB0_DETWR_CRCTMO, 1);
+
+    msdc_set_startbit(host, START_AT_RISING);
+
+    msdc_config_bus(host, HOST_BUS_WIDTH_1);
+    msdc_config_clock(host, 0, MSDC_MIN_SCLK);
+    msdc_set_timeout(host, 100000000, 0);
+
+    /* disable SDIO func */
+    MSDC_SET_FIELD(SDC_CFG, SDC_CFG_SDIO, 0);
+    MSDC_SET_FIELD(SDC_CFG, SDC_CFG_SDIOIDE, 0);
+    MSDC_SET_FIELD(SDC_CFG, SDC_CFG_INSWKUP, 0);
+
+    /* Clear all interrupts first */
+    MSDC_CLR_INT();
+    MSDC_WRITE32(MSDC_INTEN, 0);
+
+    if (host->host_id == 0) {
+	/*
+	 * some Samsung eMMC will occur CMD8 data CRC error
+	 * because eMMC card still in boot mode, even send CMD0
+	 * to eMMC. so add HW reset before CMD0.
+	 */
+	MSDC_SET_BIT32(EMMC_IOCON, EMMC_IOCON_BOOTRST);
+	spin(10);
+	MSDC_CLR_BIT32(EMMC_IOCON, EMMC_IOCON_BOOTRST);
+    }
+
+skip_host_init:
+    /* set clk, cmd, dat pad driving */
+    if (host->skip_reinit)
+        msdc_set_driving(host, &msdc_cap[host->host_id]);
+#ifdef MSDC_USE_DMA_MODE
+    /* Register msdc irq */
+    mt_irq_set_sens(MSDC0_IRQ_BIT_ID + host->host_id, LEVEL_SENSITIVE);
+    mt_irq_set_polarity(MSDC0_IRQ_BIT_ID + host->host_id, MT65xx_POLARITY_LOW);
+    event_init(&msdc_int_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+    register_int_handler(MSDC0_IRQ_BIT_ID + host->host_id, msdc_interrupt_handler, host);
+    unmask_interrupt(MSDC0_IRQ_BIT_ID + host->host_id);
+#endif
+
+    LTRACEF("[%s]: Host controller intialization done\n", __func__);
+    return 0;
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/rules.mk b/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/rules.mk
new file mode 100644
index 0000000..44a804b
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/mmc/rules.mk
@@ -0,0 +1,14 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/msdc.c \
+    $(LOCAL_DIR)/mmc_core.c \
+    $(LOCAL_DIR)/mmc_rpmb.c \
+
+MODULE_DEPS += \
+    lib/bio \
+    lib/partition \
+    lib/rpmb \
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_ecc_hal.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_ecc_hal.c
new file mode 100644
index 0000000..b465e60
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_ecc_hal.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2017 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 <arch/ops.h>
+#include <errno.h>
+#include <kernel/event.h>
+#include <kernel/mutex.h>
+#include <kernel/vm.h>
+#include <malloc.h>
+#include <platform/interrupts.h>
+#include <platform/mt_irq.h>
+#include <platform/mt_reg_base.h>
+#include <platform/nand/mtk_ecc_hal.h>
+#include <platform/nand/mtk_nand_common.h>
+#include <reg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+static inline void mtk_ecc_wait_ioready(struct mtk_ecc *ecc)
+{
+    if (!check_with_timeout((readl(ecc->regs +  ECC_PIO_DIRDY) & PIO_DI_RDY), ECC_TIMEOUT))
+        dprintf(CRITICAL, "ecc io not ready\n");
+
+    return;
+}
+
+static void mtk_ecc_runtime_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+{
+    u32 ecc_bit = ECC_CNFG_4BIT, dec_sz, enc_sz;
+    u32 reg;
+
+    switch (config->strength) {
+        case 4:
+            ecc_bit = ECC_CNFG_4BIT;
+            break;
+        case 6:
+            ecc_bit = ECC_CNFG_6BIT;
+            break;
+        case 8:
+            ecc_bit = ECC_CNFG_8BIT;
+            break;
+        case 10:
+            ecc_bit = ECC_CNFG_10BIT;
+            break;
+        case 12:
+            ecc_bit = ECC_CNFG_12BIT;
+            break;
+        case 14:
+            ecc_bit = ECC_CNFG_14BIT;
+            break;
+        case 16:
+            ecc_bit = ECC_CNFG_16BIT;
+            break;
+        case 18:
+            ecc_bit = ECC_CNFG_18BIT;
+            break;
+        case 20:
+            ecc_bit = ECC_CNFG_20BIT;
+            break;
+        case 22:
+            ecc_bit = ECC_CNFG_22BIT;
+            break;
+        case 24:
+            ecc_bit = ECC_CNFG_24BIT;
+            break;
+        case 28:
+            ecc_bit = ECC_CNFG_28BIT;
+            break;
+        case 32:
+            ecc_bit = ECC_CNFG_32BIT;
+            break;
+        case 36:
+            ecc_bit = ECC_CNFG_36BIT;
+            break;
+        case 40:
+            ecc_bit = ECC_CNFG_40BIT;
+            break;
+        case 44:
+            ecc_bit = ECC_CNFG_44BIT;
+            break;
+        case 48:
+            ecc_bit = ECC_CNFG_48BIT;
+            break;
+        case 52:
+            ecc_bit = ECC_CNFG_52BIT;
+            break;
+        case 56:
+            ecc_bit = ECC_CNFG_56BIT;
+            break;
+        case 60:
+            ecc_bit = ECC_CNFG_60BIT;
+            break;
+        case 68:
+            ecc_bit = ECC_CNFG_68BIT;
+            break;
+        case 72:
+            ecc_bit = ECC_CNFG_72BIT;
+            break;
+        case 80:
+            ecc_bit = ECC_CNFG_80BIT;
+            break;
+        default:
+            dprintf(CRITICAL, "invalid strength %d, default to 4 bits\n",
+                    config->strength);
+            break;
+    }
+
+    if (config->op == ECC_ENCODE) {
+        /* configure ECC encoder (in bits) */
+        enc_sz = config->len << 3;
+
+        reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
+        reg |= (enc_sz << ECC_MS_SHIFT);
+        writel(reg, ecc->regs + ECC_ENCCNFG);
+
+        if (config->mode == ECC_DMA_MODE) {
+            if (config->addr & 0x3)
+                dprintf(CRITICAL, "ecc encode address(0x%x) is not 4B aligned !!\n", config->addr);
+            writel(config->addr, ecc->regs + ECC_ENCDIADDR);
+        }
+
+    } else {
+        /* configure ECC decoder (in bits) */
+        dec_sz = (config->len << 3) + config->strength * ECC_PARITY_BITS;
+
+        reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
+        reg |= (dec_sz << ECC_MS_SHIFT) | (config->deccon << DEC_CON_SHIFT);
+        reg |= DEC_EMPTY_EN;
+        writel(reg, ecc->regs + ECC_DECCNFG);
+
+        if (config->mode == ECC_DMA_MODE) {
+            if (config->addr & 0x3)
+                dprintf(CRITICAL, "ecc decode address(0x%x) is not 4B aligned !!\n", config->addr);
+            writel(config->addr, ecc->regs + ECC_DECDIADDR);
+        }
+
+        if (config->sectors)
+            ecc->sectors = 1 << (config->sectors - 1);
+    }
+
+    return;
+}
+
+static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
+                                     enum mtk_ecc_operation op)
+{
+    if (!check_with_timeout(readl(ecc->regs + ECC_IDLE_REG(op)) & ECC_IDLE_MASK, ECC_TIMEOUT))
+        dprintf(CRITICAL, "%s NOT idle\n", op == ECC_ENCODE ? "encoder" : "decoder");
+
+    return;
+}
+
+static int mtk_ecc_irq_wait(struct mtk_ecc *ecc, lk_time_t timeout)
+{
+    int ret;
+
+    ret = event_wait_timeout(&ecc->irq_event, timeout);
+    if (ret != 0) {
+        dprintf(CRITICAL, "[%s]: failed to get event\n", __func__);
+        return ret;
+    }
+
+    return 0;
+}
+
+static enum handler_return mtk_ecc_interrupt_handler(void *arg)
+{
+    struct mtk_ecc *ecc = arg;
+    enum mtk_ecc_operation op;
+    u32 dec, enc;
+
+    dec = readw(ecc->regs + ECC_DECIRQ_STA) & ECC_IRQ_EN;
+    if (dec) {
+        op = ECC_DECODE;
+        dec = readw(ecc->regs + ECC_DECDONE);
+        if (dec & ecc->sectors) {
+            ecc->sectors = 0;
+            event_signal(&ecc->irq_event, false);
+        } else {
+            return INT_NO_RESCHEDULE;
+        }
+    } else {
+        enc = readl(ecc->regs + ECC_ENCIRQ_STA) & ECC_IRQ_EN;
+        if (enc) {
+            op = ECC_ENCODE;
+            event_signal(&ecc->irq_event, false);
+        } else {
+            return INT_NO_RESCHEDULE;
+        }
+    }
+
+    writel(0, ecc->regs + ECC_IRQ_REG(op));
+
+    return INT_RESCHEDULE;
+}
+
+static int mtk_ecc_request_irq(struct mtk_ecc *ecc)
+{
+    mt_irq_set_sens(NFIECC_IRQ_BIT_ID, LEVEL_SENSITIVE);
+    mt_irq_set_polarity(NFIECC_IRQ_BIT_ID, MT65xx_POLARITY_LOW);
+    event_init(&ecc->irq_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+    register_int_handler(NFIECC_IRQ_BIT_ID, mtk_ecc_interrupt_handler, ecc);
+    unmask_interrupt(NFIECC_IRQ_BIT_ID);
+
+    return 0;
+}
+
+int mtk_ecc_hw_init(struct mtk_ecc **ext_ecc)
+{
+    struct mtk_ecc *ecc;
+
+    ecc = (struct mtk_ecc *)malloc(sizeof(*ecc));
+    if (!ecc)
+        return -ENOMEM;
+
+    memset(ecc, 0, sizeof(*ecc));
+
+    *ext_ecc = ecc;
+
+    ecc->regs = NFIECC_BASE;
+
+    mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+    writew(ECC_OP_DISABLE, ecc->regs + ECC_ENCCON);
+
+    mtk_ecc_wait_idle(ecc, ECC_DECODE);
+    writel(ECC_OP_DISABLE, ecc->regs + ECC_DECCON);
+
+    mutex_init(&ecc->lock);
+
+    /* register interrupt handler */
+    mtk_ecc_request_irq(ecc);
+
+    return 0;
+}
+
+
+int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config, int polling)
+{
+    enum mtk_ecc_operation op = config->op;
+
+    mutex_acquire(&ecc->lock);
+
+    mtk_ecc_wait_idle(ecc, op);
+    mtk_ecc_runtime_config(ecc, config);
+
+    if (!polling) {
+        writew(ECC_IRQ_EN, ecc->regs + ECC_IRQ_REG(op));
+    }
+
+    writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
+
+    return 0;
+}
+
+void mtk_ecc_disable(struct mtk_ecc *ecc)
+{
+    enum mtk_ecc_operation op = ECC_ENCODE;
+
+    /* find out the running operation */
+    if (readw(ecc->regs + ECC_CTL_REG(op)) != ECC_OP_ENABLE)
+        op = ECC_DECODE;
+
+    /* disable it */
+    mtk_ecc_wait_idle(ecc, op);
+    writew(0, ecc->regs + ECC_IRQ_REG(op));
+    writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op));
+
+    mutex_release(&ecc->lock);
+
+    return;
+}
+
+void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
+                       u32 sectors)
+{
+    u32 offset, i, err;
+    u32 bitflips = 0;
+
+    stats->corrected = 0;
+    stats->failed = 0;
+
+    for (i = 0; i < sectors; i++) {
+        offset = (i >> 2);
+        err = readl(ecc->regs + ECC_DECENUM(offset));
+        err = err >> ((i % 4) * 8);
+        err &= ERR_MASK;
+        if (err == ERR_MASK) {
+            /* uncorrectable errors */
+            stats->failed++;
+            dprintf(ALWAYS, "sector %d is uncorrect\n", i);
+            continue;
+        }
+
+        stats->corrected += err;
+        bitflips = MAX(bitflips, err);
+    }
+
+    stats->bitflips = bitflips;
+
+    return;
+}
+
+int mtk_ecc_wait_done(struct mtk_ecc *ecc, enum mtk_ecc_operation op, int polling)
+{
+    int ret = 0;
+
+    if (!polling) {
+        ret = mtk_ecc_irq_wait(ecc, ECC_TIMEOUT);
+        if (!ret) {
+            dprintf(CRITICAL, "mtk_ecc_wait_done timeout\n");
+            return -ETIMEDOUT;
+        }
+    } else {
+        if (op == ECC_ENCODE) {
+            if (!check_with_timeout((readl(ecc->regs + ECC_ENCSTA) & ENC_IDLE), ECC_TIMEOUT)) {
+                dprintf(CRITICAL, "encoder timeout\n");
+                return -ETIMEDOUT;
+            }
+        } else {
+            if (!check_with_timeout((readw(ecc->regs + ECC_DECDONE) & ecc->sectors), ECC_TIMEOUT)) {
+                dprintf(CRITICAL, "decoder timeout\n");
+                return -ETIMEDOUT;
+            }
+        }
+    }
+
+    return 0;
+}
+
+int mtk_ecc_wait_decode_fsm_idle(struct mtk_ecc *ecc)
+{
+    /* decode done does not stands for ecc all work done.
+     * we need check syn, bma, chien, autoc all idle.
+     * just check it when ECC_DECCNFG[13:12] is 3, which means auto correct.*/
+    if (!check_with_timeout(((readl(ecc->regs + ECC_DECFSM) & FSM_MASK) == FSM_IDLE), ECC_TIMEOUT)) {
+        dprintf(CRITICAL, "decode fsm(0x%x) is not idle\n", readl(ecc->regs + ECC_DECFSM));
+        return -ETIMEDOUT;
+    }
+
+    return 0;
+}
+
+int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+                   u8 *data, u32 bytes, int polling)
+{
+    uintptr_t addr;
+    u8 *p;
+    u8 *buf = data;
+    u32 len, i, val = 0;
+    int ret = 0;
+
+    /* encoder memory address should be 4B aligned */
+    if ((config->mode == ECC_DMA_MODE) && ((uintptr_t)buf & 0x3)) {
+        buf = memalign(4, bytes);
+        if (!buf)
+            return -ENOMEM;
+        memcpy(buf, data, bytes);
+    }
+#ifdef WITH_KERNEL_VM
+    addr = (uintptr_t)kvaddr_to_paddr(buf);
+#else
+    addr = (uintptr_t)buf;
+#endif
+    if (config->mode == ECC_DMA_MODE)
+        arch_clean_cache_range((addr_t)buf, (size_t)bytes);
+
+    config->op = ECC_ENCODE;
+    config->addr = (u32)addr;
+    config->len = bytes;
+
+    ret = mtk_ecc_enable(ecc, config, polling);
+    if (ret)
+        goto freebuf;
+
+    if (config->mode == ECC_PIO_MODE) {
+        for (i = 0; i < ((config->len + 3) >> 2); i++) {
+            mtk_ecc_wait_ioready(ecc);
+            writel(*((u32 *)data + i), ecc->regs + ECC_PIO_DI);
+        }
+    }
+
+    ret = mtk_ecc_wait_done(ecc, ECC_ENCODE, polling);
+    if (ret)
+        goto timeout;
+
+    mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+
+    /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
+    len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
+    p = data + bytes;
+
+    /* write the parity bytes generated by the ECC back to the OOB region */
+    for (i = 0; i < len; i++) {
+        if ((i % 4) == 0)
+            val = readl(ecc->regs + ECC_ENCPAR(i / 4));
+        p[i] = (val >> ((i % 4) * 8)) & 0xff;
+    }
+
+timeout:
+    mtk_ecc_disable(ecc);
+freebuf:
+    if (config->mode == ECC_DMA_MODE)
+        arch_invalidate_cache_range((addr_t)buf, (size_t)bytes);
+    if (buf != data)
+        free(buf);
+    return ret;
+}
+
+int mtk_ecc_decode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+                   u8 *data, u32 len, int polling)
+{
+    struct mtk_ecc_stats stats;
+    u8 *buf = data;
+    uintptr_t addr;
+    u32 decodesize, i;
+    int ret;
+
+    decodesize = len + ((config->strength * ECC_PARITY_BITS + 7) >> 3);
+    if ((decodesize & 0x3)
+            || ((config->mode == ECC_DMA_MODE) && ((uintptr_t)buf & 0x3))) {
+        decodesize += 4 - (decodesize & 0x3);
+        buf = memalign(4, decodesize);
+        if (!buf)
+            return -ENOMEM;
+    }
+    if (config->mode == ECC_DMA_MODE)
+        arch_invalidate_cache_range((addr_t)buf, (size_t)decodesize);
+#ifdef WITH_KERNEL_VM
+    addr = (uintptr_t)kvaddr_to_paddr(buf);
+#else
+    addr = (uintptr_t)buf;
+#endif
+    config->op = ECC_DECODE;
+    config->addr = (u32)addr;
+    config->len = len;
+    ret = mtk_ecc_enable(ecc, config, polling);
+    if (ret)
+        goto freebuf;
+
+    if (config->mode == ECC_PIO_MODE) {
+        for (i = 0; i < (decodesize >> 2); i++) {
+            mtk_ecc_wait_ioready(ecc);
+            writel(*((u32 *)buf + i), ecc->regs + ECC_PIO_DI);
+        }
+    }
+
+    stats.bitflips = 0;
+    ret = mtk_ecc_cpu_correct(ecc, &stats, buf, 0, polling);
+    if (ret)
+        goto disecc;
+
+    if (config->mode == ECC_DMA_MODE)
+        arch_invalidate_cache_range((addr_t)buf, (size_t)decodesize);
+    if (buf != data)
+        memcpy(data, buf, len);
+
+disecc:
+    mtk_ecc_disable(ecc);
+
+freebuf:
+    if (buf != data)
+        free(buf);
+
+    return ret;
+}
+
+int mtk_ecc_cpu_correct(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats, u8 *data, u32 sector, int polling)
+{
+    u32 err, offset, i;
+    u32 loc, byteloc, bitloc;
+    int ret;
+
+    ecc->sectors = 1 << sector;
+    ret = mtk_ecc_wait_done(ecc, ECC_DECODE, polling);
+    if (ret)
+        return ret;
+
+    stats->corrected = 0;
+    stats->failed = 0;
+
+    offset = (sector >> 2);
+    err = readl(ecc->regs + ECC_DECENUM(offset));
+    err = err >> ((sector % 4) * 8);
+    err &= ERR_MASK;
+    if (err == ERR_MASK) {
+        /* uncorrectable errors */
+        stats->failed++;
+        return 0;
+    }
+
+    stats->corrected += err;
+    stats->bitflips = MAX(stats->bitflips, err);
+
+    for (i = 0; i < err; i++) {
+        loc = readl(ecc->regs + ECC_DECEL(i >> 1));
+        loc >>= ((i & 0x1) << 4);
+        loc &= DECEL_MASK;
+        byteloc = loc >> 3;
+        bitloc = loc & 0x7;
+        data[byteloc] ^= (1 << bitloc);
+    }
+
+    return 0;
+}
+
+void mtk_ecc_adjust_strength(u32 *p)
+{
+    u32 ecc[] = {4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
+                 40, 44, 48, 52, 56, 60, 68, 72, 80
+                };
+    u32 i;
+
+    for (i = 0; i < sizeof(ecc) / sizeof(u32); i++) {
+        if (*p <= ecc[i]) {
+            if (!i)
+                *p = ecc[i];
+            else if (*p != ecc[i])
+                *p = ecc[i - 1];
+            return;
+        }
+    }
+
+    *p = ecc[sizeof(ecc) / sizeof(u32) - 1];
+
+    return;
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_bbt.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_bbt.c
new file mode 100644
index 0000000..91a89e8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_bbt.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2017 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 <errno.h>
+#include <malloc.h>
+#include <platform/nand/mtk_nand_nal.h>
+#include <platform/nand/mtk_nand_bbt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BBT_BLOCK_GOOD          0x03
+#define BBT_BLOCK_WORN          0x02
+#define BBT_BLOCK_RESERVED      0x01
+#define BBT_BLOCK_FACTORY_BAD   0x00
+
+#define BBT_ENTRY_MASK          0x03
+#define BBT_ENTRY_SHIFT         2
+
+#define BBT_PATTERN_LEN         4
+#define BBT_VERSION_LEN         1
+
+static int check_pattern(u8 *buf)
+{
+    uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
+    uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+    if (!memcmp(buf, bbt_pattern, BBT_PATTERN_LEN))
+        return 0;
+    if (!memcmp(buf, mirror_pattern, BBT_PATTERN_LEN))
+        return 0;
+
+    return 1;
+}
+
+static void bbt_mark_entry(struct mtk_nand_chip *chip, int block, u8 mask)
+{
+    u32 offset = BBT_PATTERN_LEN + BBT_VERSION_LEN;
+
+    mask = (mask & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
+    offset += block >> BBT_ENTRY_SHIFT;
+
+    chip->bbt[offset] &= ~(BBT_ENTRY_MASK << ((block & BBT_ENTRY_MASK) * 2));
+    chip->bbt[offset] |= mask;
+}
+
+static u8 bbt_get_entry(struct mtk_nand_chip *chip, int block)
+{
+    u32 offset = BBT_PATTERN_LEN + BBT_VERSION_LEN;
+    u8 entry;
+
+    offset += block >> BBT_ENTRY_SHIFT;
+    entry = chip->bbt[offset];
+    entry >>= (block & BBT_ENTRY_MASK) * 2;
+
+    return entry & BBT_ENTRY_MASK;
+}
+
+static int search_bbt(struct mtk_nand_chip *chip, int bbt_len)
+{
+    int block, i;
+    struct mtk_nand_ops ops;
+
+    memset(&ops, 0, sizeof(ops));
+
+    block = chip->totalsize / chip->blocksize;
+    block -= 1;
+
+    for (i = 0; i < SCAN_BBT_MAXBLOCKS; i++, block--) {
+        ops.mode = NAND_OPS_ECC_DMA_POLL;
+        ops.offset = (u64)block * chip->blocksize;
+        ops.len = (u64)bbt_len;
+        ops.readbuf = chip->bbt;
+        mtk_nand_read(chip, &ops);
+        if (!check_pattern(chip->bbt)) {
+            chip->bbt_block = block;
+            dprintf(CRITICAL, "found bbt at block %d, version 0x%02X\n",
+                    block, chip->bbt[BBT_PATTERN_LEN]);
+            return 0;
+        }
+    }
+
+    dprintf(CRITICAL, "failed to find bbt!\n");
+    return -1;
+}
+
+static int create_bbt(struct mtk_nand_chip *chip, int bbt_len)
+{
+    int i, blocks = chip->totalsize / chip->blocksize;
+
+    memset(chip->bbt, 0xff, bbt_len);
+
+    for (i = 0; i < blocks; i++) {
+        if (mtk_nand_block_checkbad(chip, i * chip->page_per_block)) {
+            bbt_mark_entry(chip, i, BBT_BLOCK_FACTORY_BAD);
+            dprintf(CRITICAL, "block %d is bad\n", i);
+        }
+    }
+
+    dprintf(ALWAYS, "create bbt done!\n");
+
+    return 0;
+}
+
+int mtk_nand_scan_bbt(struct mtk_nand_chip *chip)
+{
+    int len;
+    int ret = 0;
+
+    len = (chip->totalsize / chip->blocksize + 3) >> 2;
+    len += BBT_PATTERN_LEN + BBT_VERSION_LEN;
+    /* allocate bbt memory */
+    chip->bbt = malloc(len);
+    if (!chip->bbt)
+        return -ENOMEM;
+    memset(chip->bbt, 0xff, len);
+    chip->bbt_block = -1;
+
+    if (search_bbt(chip, len)) {
+        ret = create_bbt(chip, len);
+    }
+
+    return ret;
+}
+
+int mtk_nand_isbad_bbt(struct mtk_nand_chip *chip, u32 page)
+{
+    int block = page / chip->page_per_block;
+    u8 mask;
+
+    mask = bbt_get_entry(chip, block);
+
+    return mask != BBT_BLOCK_GOOD;
+}
+
+int mtk_nand_markbad_bbt(struct mtk_nand_chip *chip, u32 page)
+{
+    struct mtk_nand_ops ops;
+    int len, write_len;
+    int ret = 0, block = page / chip->page_per_block;
+
+    bbt_mark_entry(chip, block, BBT_BLOCK_WORN);
+
+    if (chip->bbt_block > 0) {
+        memset(&ops, 0, sizeof(struct mtk_nand_ops));
+        ops.mode = NAND_OPS_ERASE_POLL;
+        ops.offset = (u64)chip->bbt_block * chip->blocksize;
+        ops.len = chip->blocksize;
+        ret = mtk_nand_erase(chip, &ops);
+        if (ret)
+            goto err;
+
+        /* increase bbt version */
+        chip->bbt[BBT_PATTERN_LEN]++;
+
+        len = (chip->totalsize / chip->blocksize + 3) >> 2;
+        len += BBT_PATTERN_LEN + BBT_VERSION_LEN;
+        ops.mode = NAND_OPS_ECC_DMA_POLL;
+        ops.len = chip->pagesize;
+        ops.writebuf = chip->databuf;
+        while (len) {
+            write_len = MIN((u32)len, chip->pagesize);
+            memset(chip->databuf, 0, chip->pagesize);
+            memcpy(chip->databuf, chip->bbt, write_len);
+            ret = mtk_nand_write(chip, &ops);
+            if (ret)
+                goto err;
+            len -= write_len;
+            ops.offset += chip->pagesize;
+        }
+    }
+
+err:
+    return ret;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_device.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_device.c
new file mode 100644
index 0000000..f0cccd7
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_device.c
@@ -0,0 +1,33 @@
+/*
+* Copyright (c) 2017 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 <platform/nand/mtk_nand_common.h>
+#include <platform/nand/mtk_nand_nal.h>
+
+#define NAND_OPTIONS_NONE   (0)
+
+struct mtk_nand_flash_dev nand_flash_devs[] = {
+    {"F59D4G81A-45TG-18V", {0xc8, 0xac, 0x90, 0x15, 0x54, 0, 0, 0}, 5, KB(512), KB(128), 2048, 64, 1, 1, 0x10804011, 1024, 4, NAND_OPTIONS_NONE, NAND_OPTIONS_NONE},
+    {"MT29F16G08ADBCA", {0x2c, 0xa5, 0xd1, 0x26, 0x68, 0, 0, 0}, 5, KB(2048), KB(256), 4096, 224, 1, 1, 0x10404011, 1024, 24, NAND_OPTIONS_NONE, NAND_CACHEREAD | NAND_CACHEPRG},
+    {NULL}
+};
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_nal.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_nal.c
new file mode 100644
index 0000000..bff973c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_nal.c
@@ -0,0 +1,875 @@
+/*
+ * Copyright (c) 2017 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 <errno.h>
+#include <kernel/mutex.h>
+#include <malloc.h>
+#include <platform/nand/mtk_nand_bbt.h>
+#include <platform/nand/mtk_nand_common.h>
+#include <platform/nand/mtk_nand_nal.h>
+#include <platform/nand/mtk_nfi_hal.h>
+#include <stdlib.h>
+#include <string.h>
+
+static struct mtk_nand_chip *nandchip;
+
+static int mtk_nand_do_read_ops(struct mtk_nand_chip *chip,
+                                struct mtk_nand_ops *ops);
+static int mtk_nand_do_erase_ops(struct mtk_nand_chip *chip,
+                                 struct mtk_nand_ops *ops);
+static int mtk_nand_do_write_ops(struct mtk_nand_chip *chip,
+                                 struct mtk_nand_ops *ops);
+
+static int mtk_nand_get_controller(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mutex_acquire(&nfc->lock);
+
+    return 0;
+}
+
+static int mtk_nand_release_controller(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mutex_release(&nfc->lock);
+
+    return 0;
+}
+
+static int mtk_nand_wait_func(struct mtk_nand_chip *chip, int polling)
+{
+    int status;
+    unsigned long timeo = 1000000;
+
+    chip->cmdfunc(chip, NAND_CMD_STATUS, -1, -1);
+
+    if (!polling) {
+        if (chip->wait_busy_irq(chip))
+            dprintf(CRITICAL, "nand dev ready timeout\n");
+    } else {
+        if (!check_with_timeout(chip->dev_ready(chip), timeo))
+            dprintf(CRITICAL, "nand dev ready timeout\n");
+    }
+
+    status = (int)chip->read_byte(chip);
+
+    return status;
+}
+
+void mtk_nand_wait_ready(struct mtk_nand_chip *chip)
+{
+    unsigned long timeo = 1000000;
+
+    if (!check_with_timeout(chip->dev_ready(chip), timeo))
+        dprintf(CRITICAL, "nand dev ready timeout\n");
+
+    return;
+}
+
+static int mtk_nand_check_wp(struct mtk_nand_chip *chip)
+{
+    /* Check the WP bit */
+    chip->cmdfunc(chip, NAND_CMD_STATUS, -1, -1);
+    return (chip->read_byte(chip) & NAND_STATUS_WP) ? 0 : 1;
+}
+
+static int mtk_nand_block_bad(struct mtk_nand_chip *chip, u64 ofs)
+{
+    int page, res = 0, i = 0;
+    u16 bad;
+
+    if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+        ofs += chip->blocksize - chip->pagesize;
+
+    page = (int)(ofs / chip->pagesize) % chip->page_per_chip;
+
+    do {
+        chip->cmdfunc(chip, NAND_CMD_READOOB, chip->badblockpos, page);
+        bad = chip->read_byte(chip);
+
+        if (chip->badblockbits == 8)
+            res = bad != 0xFF;
+
+        ofs += chip->pagesize;
+        page = (int)(ofs / chip->pagesize) % chip->page_per_chip;
+        i++;
+    } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
+
+    return res;
+}
+
+int mtk_nand_block_checkbad(struct mtk_nand_chip *chip, u32 page)
+{
+    struct mtk_nand_ops ops;
+    int ret;
+
+    /* block align */
+    page = page / chip->page_per_block * chip->page_per_block;
+
+    if (!(chip->options & NAND_NEED_SCRAMBLING)) {
+        ret = chip->block_bad(chip, (u64)page * chip->pagesize);
+    } else {
+        /*
+         * The output data is randomized if randomizer is on,
+         * we will get a wrong result if just read one byte data.
+         * So, should read page directly.
+         */
+        memset(&ops, 0, sizeof(ops));
+        ops.mode = NAND_OPS_ECC_DMA_POLL;
+        ops.offset = (u64)page * chip->pagesize;
+        ops.len = chip->pagesize;
+        ops.readbuf = chip->databuf;
+        ret = mtk_nand_do_read_ops(chip, &ops);
+        if (ret < 0)
+            ret = 1;
+        else
+            ret = chip->oob_poi[chip->badblockpos] != 0xFF;
+    }
+
+    return ret;
+}
+
+static int mtk_nand_block_isbad_lowlevel(struct mtk_nand_chip *chip, u32 page)
+{
+    if (chip->bbt)
+        return mtk_nand_isbad_bbt(chip, page);
+    else
+        return mtk_nand_block_checkbad(chip, page);
+}
+
+int mtk_nand_block_isbad(struct mtk_nand_chip *chip, u32 page)
+{
+    int ret;
+
+    mtk_nand_get_controller(chip);
+    ret = mtk_nand_block_isbad_lowlevel(chip, page);
+    mtk_nand_release_controller(chip);
+
+    return ret;
+}
+
+int mtk_nand_block_markbad(struct mtk_nand_chip *chip, u32 page)
+{
+    struct mtk_nand_ops ops;
+    u32 i = 0;
+    int ret = 0;
+
+    mtk_nand_get_controller(chip);
+    /* block align */
+    page = page / chip->page_per_block * chip->page_per_block;
+
+    ops.mode = NAND_OPS_ERASE_POLL;
+    ops.offset = (u64)page * chip->pagesize;
+    ops.len = chip->blocksize;
+    mtk_nand_do_erase_ops(chip, &ops);
+
+    if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+        ops.offset += chip->blocksize - chip->pagesize;
+    ops.mode = NAND_OPS_ECC_DMA_POLL;
+    ops.writebuf = chip->databuf;
+    ops.len = chip->pagesize;
+    ops.oobeccbuf = &chip->oob_poi[chip->oob_free_ecc_size
+                                   + chip->oob_free_raw_size];
+    ops.oobecclen = chip->ecc_steps * chip->fdm_ecc_size;
+    ops.oobeccoffs = 0;
+    ops.oobrawbuf = NULL;
+    memset(chip->databuf, 0, chip->pagesize);
+    memset(ops.oobeccbuf, 0, ops.oobecclen);
+    do {
+        ops.offset += chip->pagesize;
+        mtk_nand_do_write_ops(chip, &ops);
+        i++;
+    } while (i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
+
+    mtk_nand_release_controller(chip);
+
+    if (chip->bbt)
+        ret = mtk_nand_markbad_bbt(chip, page);
+
+    return ret;
+}
+
+int nand_reset(struct mtk_nand_chip *chip, int chipnr)
+{
+    /* power on sequence delay */
+    spin(300);
+
+    /*
+     * The CS line has to be released before we can apply the new NAND
+     * interface settings, hence this weird ->select_chip() dance.
+     */
+    chip->select_chip(chip, chipnr);
+    chip->cmdfunc(chip, NAND_CMD_RESET, -1, -1);
+    chip->select_chip(chip, -1);
+
+    return 0;
+}
+
+static inline int mtk_nand_opcode_8bits(unsigned int command)
+{
+    switch (command) {
+        case NAND_CMD_READID:
+        case NAND_CMD_PARAM:
+        case NAND_CMD_GET_FEATURES:
+        case NAND_CMD_SET_FEATURES:
+            return 1;
+        default:
+            break;
+    }
+    return 0;
+}
+
+static void mtk_nand_command_lp(struct mtk_nand_chip *chip, unsigned int command,
+                                int column, int page_addr)
+{
+    /* Emulate NAND_CMD_READOOB */
+    if (command == NAND_CMD_READOOB) {
+        column += chip->pagesize;
+        command = NAND_CMD_READ0;
+    }
+
+    /* Command latch cycle */
+    chip->cmd_ctrl(chip, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+
+    if (column != -1 || page_addr != -1) {
+        int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
+
+        /* Serially input address */
+        if (column != -1) {
+            chip->cmd_ctrl(chip, column, ctrl);
+            ctrl &= ~NAND_CTRL_CHANGE;
+
+            /* Only output a single addr cycle for 8bits opcodes. */
+            if (!mtk_nand_opcode_8bits(command))
+                chip->cmd_ctrl(chip, column >> 8, ctrl);
+        }
+        if (page_addr != -1) {
+            chip->cmd_ctrl(chip, page_addr, ctrl);
+            chip->cmd_ctrl(chip, page_addr >> 8, NAND_NCE | NAND_ALE);
+            /* One more address cycle for devices > 128MiB */
+            if (chip->chipsize > (128 << 20))
+                chip->cmd_ctrl(chip, page_addr >> 16, NAND_NCE | NAND_ALE);
+        }
+    }
+    chip->cmd_ctrl(chip, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+    /*
+     * Program and erase have their own busy handlers status, sequential
+     * in and status need no delay.
+     */
+    switch (command) {
+        case NAND_CMD_CACHEDPROG:
+        case NAND_CMD_PAGEPROG:
+        case NAND_CMD_ERASE1:
+        case NAND_CMD_ERASE2:
+        case NAND_CMD_SEQIN:
+        case NAND_CMD_STATUS:
+            return;
+
+        case NAND_CMD_RNDOUT:
+            /* No ready / busy check necessary */
+            chip->cmd_ctrl(chip, NAND_CMD_RNDOUTSTART, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+            chip->cmd_ctrl(chip, NAND_CMD_NONE,
+                           NAND_NCE | NAND_CTRL_CHANGE);
+            return;
+
+        case NAND_CMD_READ0:
+            chip->cmd_ctrl(chip, NAND_CMD_READSTART, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+            chip->cmd_ctrl(chip, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+        /* This applies to read commands */
+        default:
+            break;
+    }
+
+    mtk_nand_wait_ready(chip);
+
+    return;
+}
+
+static void mtk_nand_set_defaults(struct mtk_nand_chip *chip)
+{
+    /* chip_delay setup set 20us if not */
+    chip->chip_delay = 20;
+
+    /* command function*/
+    chip->cmdfunc = mtk_nand_command_lp;
+
+    /* wait function */
+    chip->waitfunc = mtk_nand_wait_func;
+
+    /* bad block check */
+    chip->block_bad = mtk_nand_block_bad;
+
+    /* variable defalut value */
+    chip->badblockbits = 8;
+    chip->badblockpos = 0;
+
+    chip->activechip = -1;
+
+    return;
+}
+
+int mtk_nand_flash_get(struct mtk_nand_chip *chip, int maxchips)
+{
+    int i;
+    u8 id_data[8];
+    struct mtk_nand_flash_dev *type = nand_flash_devs;
+
+    nand_reset(chip, 0);
+
+    /* Select the device */
+    chip->select_chip(chip, 0);
+
+    /* Send the command for reading device ID */
+    chip->cmdfunc(chip, NAND_CMD_READID, 0x00, -1);
+
+    /* Read entire ID string */
+    for (i = 0; i < 8; i++) {
+        id_data[i] = chip->read_byte(chip);
+        LTRACEF("nand id[%d] [%x] \n", i, id_data[i]);
+    }
+
+    for (; type->name != NULL; type++) {
+        if (!strncmp((char const*)type->id, (char const*)id_data, type->id_len)) {
+            dprintf(ALWAYS, "nand found [%s] \n", type->name);
+            break;
+        }
+    }
+
+    chip->select_chip(chip, -1);
+    if (!type->name) {
+        return -ENODEV;
+    }
+
+    chip->numchips = 1;
+
+    /* Check for a chip array */
+    for (i = 1; i < maxchips; i++) {
+        /* See comment in nand_get_flash_type for reset */
+        nand_reset(chip, i);
+
+        chip->select_chip(chip, i);
+        /* Send the command for reading device ID */
+        chip->cmdfunc(chip, NAND_CMD_READID, 0x00, -1);
+        /* Read manufacturer and device IDs */
+        if (id_data[0] != chip->read_byte(chip) ||
+                id_data[1] != chip->read_byte(chip)) {
+            chip->select_chip(chip, -1);
+            break;
+        }
+        dprintf(ALWAYS, "chip %d is found\n", i);
+        chip->select_chip(chip, -1);
+        chip->numchips++;
+    }
+
+    /* set nand chip parameters */
+    chip->pagesize = type->pagesize;
+    chip->oobsize = type->oobsize;
+    chip->bits_per_cell = type->bits_per_cell;
+    /* KB to B */
+    chip->chipsize = ((u64)type->chipsize) << 10;
+    chip->blocksize = type->erasesize;
+    chip->bbt_options |= type->bbt_options;
+    chip->options |= type->options;
+    chip->ecc_size = type->ecc_size;
+    chip->ecc_strength = type->ecc_strength;
+    chip->fdm_ecc_size = type->fdmeccsize;
+
+    chip->totalsize = i * chip->chipsize;
+
+    chip->ecc_steps = chip->pagesize / chip->ecc_size;
+    if (nand_is_slc(chip)) {
+        if (chip->ecc_steps == 2)
+            chip->subpagesize = chip->pagesize / 2;
+        else if (chip->ecc_steps > 2)
+            chip->subpagesize = chip->pagesize / 4;
+        else
+            chip->subpagesize = chip->pagesize;
+    }
+    chip->page_per_block = chip->blocksize / chip->pagesize;
+    chip->page_per_chip = chip->chipsize / chip->pagesize;
+
+    chip->databuf = (u8 *)memalign(16, chip->pagesize + chip->oobsize);
+    if (!chip->databuf)
+        return -ENOMEM;
+    chip->oob_poi = chip->databuf + chip->pagesize;
+
+    return 0;
+}
+
+int mtk_nand_scan(struct mtk_nand_chip *chip, int maxchips)
+{
+    int ret;
+
+    /* Set the defaults */
+    mtk_nand_set_defaults(chip);
+
+    ret = mtk_nand_flash_get(chip, maxchips);
+    if (ret) {
+        dprintf(CRITICAL, "no nand device found\n");
+        return ret;
+    }
+
+    return 0;
+}
+
+int mtk_nand_scan_tail(struct mtk_nand_chip *chip)
+{
+    int ret;
+
+    /* scan bad block table */
+    ret = mtk_nand_scan_bbt(chip);
+
+    return ret;
+}
+
+static int mtk_nand_transfer_oob(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int ret = 0;
+    u32 parity_size;
+
+    parity_size = chip->oobsize - chip->oob_free_raw_size
+                  - chip->oob_free_ecc_size;
+
+    if (ops->oobeccbuf && chip->transfer_oob_ecc) {
+        if (ops->oobeccoffs >= chip->oob_free_ecc_size
+            || ops->oobecclen > chip->oob_free_ecc_size - ops->oobeccoffs)
+            return -EINVAL;
+        ret = chip->transfer_oob_ecc(chip, ops->oobeccbuf, ops->oobeccoffs,
+                                     ops->oobecclen);
+        if (ret)
+            return ret;
+    }
+
+    if (ops->oobrawbuf && chip->transfer_oob_raw) {
+        if (ops->oobrawoffs >= chip->oob_free_raw_size
+            || ops->oobrawlen > chip->oob_free_raw_size - ops->oobrawoffs)
+            return -EINVAL;
+        ret = chip->transfer_oob_raw(chip, ops->oobrawbuf, ops->oobrawoffs,
+                                     ops->oobrawlen);
+    }
+
+    if (ops->oobparitybuf && chip->transfer_oob_parity) {
+        if (ops->oobparityoffs >= parity_size
+            || ops->oobparitylen > parity_size - ops->oobparityoffs)
+            return -EINVAL;
+        ret = chip->transfer_oob_parity(chip, ops->oobparitybuf, ops->oobparityoffs,
+                                        ops->oobparitylen);
+    }
+
+    return ret;
+}
+
+static int mtk_nand_do_read_ops(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int chipnr, page, realpage, col, aligned;
+    u8 *buf, *bufpoi;
+    u64 readlen = ops->len, from = ops->offset;
+    u32 bytes, ecc_failures = chip->stats.failed;
+    int ret = 0, ecc_fail = 0, max_bitflips = 0;
+    bool enable_cache = false;
+
+    chipnr = (int)(from / chip->chipsize);
+    chip->select_chip(chip, chipnr);
+
+    realpage = (int)(from / chip->pagesize);
+    page = realpage % chip->page_per_chip;
+    if (readlen == 0)
+        return 0;
+    if (NAND_HAS_CACHEREAD(chip) && (int)((from + readlen - 1) / chip->pagesize) > realpage)
+        enable_cache = true;
+
+    col = (int)(from & (chip->pagesize - 1));
+
+    buf = ops->readbuf;
+
+    while (1) {
+        bytes = MIN(chip->pagesize - col, readlen);
+        aligned = (bytes == chip->pagesize);
+        bufpoi = aligned ? buf : chip->databuf;
+
+        memset(chip->oob_poi, 0xff, chip->oobsize);
+
+        /* send read page command */
+        LTRACEF("[nand] read page %d chip %d\n", page, chipnr);
+        chip->enable_randomizer(chip, page, RAND_DECODE, 0);
+
+        if (!enable_cache || realpage == (int)(from / chip->pagesize))
+            chip->cmdfunc(chip, NAND_CMD_READ0, 0x00, page);
+
+        if (enable_cache) {
+            if ((readlen - bytes) == 0)
+                chip->cmdfunc(chip, NAND_CMD_READCACHELAST, -1, -1);
+            else
+                chip->cmdfunc(chip, NAND_CMD_READCACHESEQ, -1, -1);
+        }
+
+        if (!aligned) {
+            if (ops->mode == NAND_OPS_ECC_DMA_IRQ)
+                ret = chip->read_subpage_ecc_dma_irq(chip, col, bytes, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_DMA_POLL)
+                ret = chip->read_subpage_ecc_dma_polling(chip, col, bytes, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_IRQ)
+                ret = chip->read_subpage_ecc_pio_irq(chip, col, bytes, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_POLL)
+                ret = chip->read_subpage_ecc_pio_polling(chip, col, bytes, bufpoi, page);
+        } else {
+            if (ops->mode == NAND_OPS_RAW_DMA_IRQ)
+                ret = chip->read_page_raw_dma_irq(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_RAW_DMA_POLL)
+                ret = chip->read_page_raw_dma_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_RAW_PIO_IRQ)
+                ret = chip->read_page_raw_pio_irq(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_RAW_PIO_POLL)
+                ret = chip->read_page_raw_pio_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_DMA_IRQ)
+                ret = chip->read_page_ecc_dma_irq(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_DMA_POLL)
+                ret = chip->read_page_ecc_dma_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_IRQ)
+                ret = chip->read_page_ecc_pio_irq(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_POLL)
+                ret = chip->read_page_ecc_pio_polling(chip, bufpoi, page);
+        }
+        chip->disable_randomizer(chip);
+        if (ret < 0)
+            break;
+
+        max_bitflips = MAX(max_bitflips, ret);
+
+        ret = mtk_nand_transfer_oob(chip, ops);
+        if (ret) {
+            max_bitflips = ret;
+            break;
+        }
+
+        if (chip->stats.failed - ecc_failures) {
+            ecc_fail = 1;
+            break;
+        }
+
+        if (!aligned)
+            memcpy(buf, chip->databuf + col, bytes);
+
+        readlen -= bytes;
+        buf += bytes;
+
+        if (!readlen)
+            break;
+
+        /* For subsequent reads align to page boundary */
+        col = 0;
+        /* Increment page address */
+        realpage++;
+
+        page = realpage % chip->page_per_chip;
+        /* Check, if we cross a chip boundary */
+        if (!page) {
+            chipnr++;
+            chip->select_chip(chip, -1);
+            chip->select_chip(chip, chipnr);
+        }
+    }
+    chip->select_chip(chip, -1);
+
+    if (ecc_fail)
+        return -EBADMSG;
+
+    return max_bitflips;
+}
+
+int mtk_nand_read(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int ret;
+
+    mtk_nand_get_controller(chip);
+    ret = mtk_nand_do_read_ops(chip, ops);
+    mtk_nand_release_controller(chip);
+
+    return ret;
+}
+
+static int mtk_nand_fill_oob(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int ret = 0;
+    u32 parity_size;
+
+    parity_size = chip->oobsize - chip->oob_free_raw_size
+                  - chip->oob_free_ecc_size;
+
+    memset(chip->oob_poi, 0xff, chip->oobsize);
+
+    if (ops->oobeccbuf && chip->fill_oob_ecc) {
+        if (ops->oobeccoffs >= chip->oob_free_ecc_size
+            || ops->oobecclen > chip->oob_free_ecc_size - ops->oobeccoffs)
+            return -EINVAL;
+        ret = chip->fill_oob_ecc(chip, ops->oobeccbuf, ops->oobeccoffs,
+                                 ops->oobecclen);
+        if (ret)
+            return ret;
+    }
+
+    if (ops->oobrawbuf && chip->fill_oob_raw) {
+        if (ops->oobrawoffs >= chip->oob_free_raw_size
+            || ops->oobrawlen > chip->oob_free_raw_size - ops->oobrawoffs)
+            return -EINVAL;
+        ret = chip->fill_oob_raw(chip, ops->oobrawbuf, ops->oobrawoffs,
+                                 ops->oobrawlen);
+    }
+
+    if (ops->oobparitybuf && chip->fill_oob_parity) {
+        if (ops->oobparityoffs >= parity_size
+            || ops->oobparitylen > parity_size - ops->oobparityoffs)
+            return -EINVAL;
+        ret = chip->fill_oob_parity(chip, ops->oobparitybuf, ops->oobparityoffs,
+                                    ops->oobparitylen);
+    }
+
+    return ret;
+}
+
+static int mtk_nand_do_write_ops(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int chipnr, realpage, page, col, aligned;
+    u32 bytes, writelen = ops->len;
+    u64 to = ops->offset;
+    const u8 *buf = ops->writebuf;
+    const u8 *bufpoi;
+    int ret = 0, status, polling_wait = 1;
+    bool enable_cache = false;
+
+    /* Reject writes, which are not subpage aligned */
+    if (!IS_ALIGNED(to, chip->subpagesize) || !IS_ALIGNED(ops->len, chip->subpagesize)) {
+        dprintf(CRITICAL, "attempt to write non page aligned data (offset 0x%llx, len 0x%llx)\n", to, ops->len);
+        return -EINVAL;
+    }
+
+    col = to & (chip->pagesize - 1);
+    chipnr = (int)(to / chip->chipsize);
+    chip->select_chip(chip, chipnr);
+
+    /* Check, if it is write protected */
+    if (mtk_nand_check_wp(chip)) {
+        ret = -EIO;
+        dprintf(CRITICAL, "write protected!\n");
+        goto err_out;
+    }
+
+    realpage = (int)(to / chip->pagesize);
+    page = realpage % chip->page_per_chip;
+    if (NAND_HAS_CACHEPROG(chip) && (int)((to + writelen) / chip->pagesize) > realpage)
+        enable_cache = true;
+
+    while (1) {
+        bytes = MIN(chip->pagesize - col, writelen);
+        aligned = (bytes == chip->pagesize);
+        bufpoi = aligned ? buf : chip->databuf;
+
+        if (!aligned) {
+            memset(chip->databuf, 0xff, chip->pagesize);
+            memcpy(chip->databuf + col, buf, bytes);
+        }
+
+        ret = mtk_nand_fill_oob(chip, ops);
+        if (ret)
+            break;
+
+        LTRACEF("[nand] write page %d chip %d\n", page, chipnr);
+        chip->enable_randomizer(chip, page, RAND_ENCODE, 0);
+        chip->cmdfunc(chip, NAND_CMD_SEQIN, 0x00, page);
+
+        if (!aligned) {
+            if (ops->mode == NAND_OPS_ECC_DMA_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_subpage_ecc_dma_irq(chip, col, bytes, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_ECC_DMA_POLL)
+                ret = chip->write_subpage_ecc_dma_polling(chip, col, bytes, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_subpage_ecc_pio_irq(chip, col, bytes, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_ECC_PIO_POLL)
+                ret = chip->write_subpage_ecc_pio_polling(chip, col, bytes, bufpoi, page);
+        }
+        else {
+            if (ops->mode == NAND_OPS_RAW_DMA_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_page_raw_dma_irq(chip, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_RAW_DMA_POLL)
+                ret = chip->write_page_raw_dma_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_RAW_PIO_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_page_raw_pio_irq(chip, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_RAW_PIO_POLL)
+                ret = chip->write_page_raw_pio_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_DMA_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_page_ecc_dma_irq(chip, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_ECC_DMA_POLL)
+                ret = chip->write_page_ecc_dma_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_page_ecc_pio_irq(chip, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_ECC_PIO_POLL)
+                ret = chip->write_page_ecc_pio_polling(chip, bufpoi, page);
+        }
+        chip->disable_randomizer(chip);
+        if (ret < 0)
+            break;
+
+        if (!enable_cache || (writelen - bytes) == 0)
+            chip->cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
+        else
+            chip->cmdfunc(chip, NAND_CMD_CACHEDPROG, -1, -1);
+        status = chip->waitfunc(chip, polling_wait);
+        if (status & NAND_STATUS_FAIL) {
+            ret = -EIO;
+            dprintf(CRITICAL, "write failed at page 0x%x\n", realpage);
+            goto err_out;
+        }
+
+        writelen -= bytes;
+        if (!writelen)
+            break;
+
+        col = 0;
+        buf += bytes;
+        realpage++;
+
+        page = realpage % chip->page_per_chip;
+        /* Check, if we cross a chip boundary */
+        if (!page) {
+            chipnr++;
+            chip->select_chip(chip, -1);
+            chip->select_chip(chip, chipnr);
+        }
+    }
+
+err_out:
+    chip->select_chip(chip, -1);
+
+    return ret;
+}
+
+int mtk_nand_write(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int ret;
+
+    mtk_nand_get_controller(chip);
+    ret = mtk_nand_do_write_ops(chip, ops);
+    mtk_nand_release_controller(chip);
+
+    return ret;
+}
+
+static int mtk_nand_do_erase_ops(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    u64 offset = ops->offset;
+    u64 eraselen = ops->len;
+    int page, status, ret = 0, chipnr, polling_wait = 0;
+
+    if ((offset % chip->blocksize) || (eraselen % chip->blocksize)) {
+        dprintf(CRITICAL, "erase is not aligned (off 0x%llx, len 0x%llx)\n", offset, eraselen);
+        return -EINVAL;
+    }
+
+    page = (int)(offset / chip->pagesize);
+    chipnr = (int)(offset / chip->chipsize);
+
+    chip->select_chip(chip, chipnr);
+
+    /* Check, if it is write protected */
+    if (mtk_nand_check_wp(chip)) {
+        ret = -EIO;
+        dprintf(CRITICAL, "write protected!\n");
+        goto err_out;
+    }
+
+    while (1) {
+        if (mtk_nand_block_isbad_lowlevel(chip, page)) {
+            ret = -EIO;
+            dprintf(CRITICAL, "attempt to erase bad block at page 0x%x\n",
+                    page);
+            goto err_out;
+        }
+
+        LTRACEF("[nand] erase page %d chip %d\n", page, chipnr);
+        chip->cmdfunc(chip, NAND_CMD_ERASE1, -1, (page % chip->page_per_chip));
+        chip->cmdfunc(chip, NAND_CMD_ERASE2, -1, -1);
+        if (ops->mode == NAND_OPS_ERASE_IRQ)
+            polling_wait = 0;
+        else if (ops->mode == NAND_OPS_ERASE_POLL)
+            polling_wait = 1;
+        status = chip->waitfunc(chip, polling_wait);
+
+        if (status & NAND_STATUS_FAIL) {
+            ret = -EIO;
+            dprintf(CRITICAL, "erase failed at page 0x%x\n", page);
+            goto err_out;
+        }
+
+        eraselen -= chip->blocksize;
+        if (!eraselen)
+            break;
+        page += chip->page_per_block;
+
+        if (eraselen && !(page % chip->page_per_chip)) {
+            chipnr++;
+            chip->select_chip(chip, -1);
+            chip->select_chip(chip, chipnr);
+        }
+    }
+err_out:
+    chip->select_chip(chip, -1);
+
+    return ret;
+}
+
+int mtk_nand_erase(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int ret;
+
+    mtk_nand_get_controller(chip);
+    ret = mtk_nand_do_erase_ops(chip, ops);
+    mtk_nand_release_controller(chip);
+
+    return ret;
+}
+
+int mtk_nand_init(void)
+{
+    return mtk_nfc_nand_chip_init(&nandchip);
+}
+
+struct mtk_nand_chip *mtk_get_nand_chip(void)
+{
+    return nandchip;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_nftl.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_nftl.c
new file mode 100644
index 0000000..3abc464
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_nftl.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2018 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 <err.h>
+#include <errno.h>
+#include <lib/nftl.h>
+#include <malloc.h>
+#include <platform/mtk_bio_ioctl.h>
+#include <platform/nand/mtk_nand_nal.h>
+#include <pow2.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+struct mtk_nand_chip *chip;
+
+static ssize_t nand_write(struct nftl_info *info, const void *buf, off_t offset,
+                          ssize_t len)
+{
+    struct mtk_nand_ops ops;
+    int ret;
+
+    memset(&ops, 0, sizeof(ops));
+    ops.mode = NAND_OPS_ECC_DMA_POLL;
+    ops.offset = (u64)offset;
+    ops.len = (u64)len;
+    ops.writebuf = buf;
+
+    ret = mtk_nand_write(chip, &ops);
+
+    return (ret < 0) ? ret : len;
+}
+
+static ssize_t nand_read(struct nftl_info *info, void *buf, off_t offset,
+                         ssize_t len)
+{
+    struct mtk_nand_ops ops;
+    int ret;
+
+    memset(&ops, 0, sizeof(ops));
+    ops.mode = NAND_OPS_ECC_DMA_POLL;
+    ops.offset = (u64)offset;
+    ops.len = (u64)len;
+    ops.readbuf = buf;
+
+    ret = mtk_nand_read(chip, &ops);
+
+    return (ret < 0) ? ret : len;
+}
+
+static ssize_t nand_erase(struct nftl_info *info, off_t offset, ssize_t len)
+{
+    struct mtk_nand_ops ops;
+    int ret;
+
+    memset(&ops, 0, sizeof(ops));
+    ops.mode = NAND_OPS_ERASE_POLL;
+    ops.offset = (u64)offset;
+    ops.len = (u64)len;
+
+    ret = (ssize_t)mtk_nand_erase(chip, &ops);
+
+    return (ret < 0) ? ret : len;
+}
+
+static int nand_block_isbad(struct nftl_info *info, u32 page)
+{
+    return mtk_nand_block_isbad(chip, page);
+}
+
+static int nand_ioctl(struct nftl_info *info, int request, void *argp)
+{
+    int ret = NO_ERROR;
+
+    switch (request) {
+        case BIO_IOCTL_QUERY_CAP_REWRITABLE:
+            *(bool *)argp = false;
+            break;
+        default:
+            ret = ERR_INVALID_ARGS;
+            break;
+    }
+
+    return ret;
+}
+
+int nand_init_device(void)
+{
+    struct nftl_info *info;
+    int ret;
+
+    ret = mtk_nand_init();
+    if (ret) {
+        dprintf(CRITICAL, "nand device init error (%d)!\n", ret);
+        return ret;
+    }
+
+    chip = mtk_get_nand_chip();
+
+    info = nftl_add_master("nand0");
+    if (!info)
+        return ERR_NO_MEMORY;
+
+    info->erase_size = chip->blocksize;
+    info->write_size = chip->pagesize;
+    info->total_size = chip->totalsize;
+    info->block_isbad = nand_block_isbad;
+    info->read = nand_read;
+    info->write = nand_write;
+    info->erase = nand_erase;
+    info->ioctl = nand_ioctl;
+
+    ret = nftl_mount_bdev(info);
+
+    return ret;
+}
+
+void nand_dump_device_info(void)
+{
+    dprintf(ALWAYS, "chip size: %#llx B\n", chip->chipsize);
+    dprintf(ALWAYS, "block size: %u B\n", chip->blocksize);
+    dprintf(ALWAYS, "page size: %u B\n", chip->pagesize);
+    dprintf(ALWAYS, "oob size: %u B\n", chip->oobsize);
+    dprintf(ALWAYS, "bits per cell: %d\n", chip->bits_per_cell);
+    dprintf(ALWAYS, "ecc size: %d\n", chip->ecc_size);
+    dprintf(ALWAYS, "ecc strength: %d\n", chip->ecc_strength);
+    dprintf(ALWAYS, "all fdm ecc size: %d\n", chip->oob_free_ecc_size);
+    dprintf(ALWAYS, "all fdm raw size: %d\n", chip->oob_free_raw_size);
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_test.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_test.c
new file mode 100644
index 0000000..3eefdab
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nand_test.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2018 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.
+ */
+#if WITH_LIB_CONSOLE
+
+#include <debug.h>
+#include <err.h>
+#include <lib/bio.h>
+#include <lib/console.h>
+#include <lib/mempool.h>
+#include <platform.h>
+#include <platform/nand/mtk_nand_nal.h>
+#include <platform/nand/mtk_nand_bbt.h>
+#include <platform/nand/nand.h>
+#include <rand.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define TEST_BUFFER_SIZE (0x80000)
+
+static void gen_rand_data(u8 *buf, size_t len)
+{
+    u32 i;
+
+    for (i = 0; i < len; i++)
+        buf[i] = (u8)rand();
+}
+
+static int compare_data(u8 *src, u8 *dest, size_t len)
+{
+    u32 i;
+
+    for (i = 0; i < len; i++) {
+        if (src[i] != dest[i]) {
+            printf("ERROR at %d: should be 0x%x, is 0x%x\n", i, src[i], dest[i]);
+            return ERR_IO;
+        }
+    }
+
+    return 0;
+}
+
+static int nand_speed_test(const char *device)
+{
+    int ret = 0;
+    u8 *wbuf, *rbuf;
+    bdev_t *dev;
+    ssize_t valid_total_size, left, test_size;
+    lk_bigtime_t delta_time, start_time;
+
+    dev = bio_open(device);
+    if (!dev) {
+        dev = bio_open_by_label(device);
+        if (!dev) {
+            printf("error opening block device: %s\n", device);
+            return ERR_NOT_FOUND;
+        }
+    }
+
+    wbuf = mempool_alloc(TEST_BUFFER_SIZE, MEMPOOL_ANY);
+    if (wbuf == NULL) {
+        ret = ERR_NO_MEMORY;
+        goto closedev;
+    }
+
+    rbuf = mempool_alloc(TEST_BUFFER_SIZE, MEMPOOL_ANY);
+    if (rbuf == NULL) {
+        ret = ERR_NO_MEMORY;
+        goto freewbuf;
+    }
+
+    gen_rand_data(wbuf, TEST_BUFFER_SIZE);
+
+    printf("begin erase test!\n");
+    delta_time = current_time_hires();
+    valid_total_size = bio_erase(dev, 0, dev->total_size);
+    delta_time = current_time_hires() - delta_time;
+    printf("erase speed is: %llu KB/s\n", (valid_total_size * 1000000) / (delta_time * 1024));
+
+    printf("begin write test!\n");
+    left = valid_total_size;
+    delta_time = current_time_hires();
+    while (left) {
+        test_size = MIN(TEST_BUFFER_SIZE, left);
+        ret = bio_write(dev, wbuf, valid_total_size - left, test_size);
+        if (ret < 0)
+            goto freerbuf;
+        left -= test_size;
+    };
+    delta_time = current_time_hires() - delta_time;
+    printf("write speed is: %llu KB/s\n", (valid_total_size * 1000000) / (delta_time * 1024));
+
+    printf("begin read test!\n");
+    left = valid_total_size;
+    delta_time = 0;
+    while (left) {
+        start_time = current_time_hires();
+        test_size = MIN(TEST_BUFFER_SIZE, left);
+        ret = bio_read(dev, rbuf, valid_total_size - left, test_size);
+        if (ret < 0)
+            goto freerbuf;
+        delta_time += current_time_hires() - start_time;
+        ret = compare_data(wbuf, rbuf, test_size);
+        if (ret < 0)
+            goto freerbuf;
+        left -= test_size;
+    }
+    printf("read speed is: %llu KB/s\n", (valid_total_size * 1000000) / (delta_time * 1024));
+
+freerbuf:
+    mempool_free(rbuf);
+freewbuf:
+    mempool_free(wbuf);
+closedev:
+    bio_close(dev);
+
+    return ret;
+}
+
+#define CBIT(v, n) ((v) & (1 << (n)))
+#define BCLR(v, n) ((v) = (v) & ~(1 << (n)))
+static u32 insert_biterrors(u32 byte, u32 boundary, u32 errors, u8 *buf)
+{
+    int bit;
+
+    while (byte < boundary && errors) {
+        for (bit = 7; bit >= 0; bit--) {
+            if (CBIT(buf[byte], bit)) {
+                BCLR(buf[byte], bit);
+                printf("%s: Inserted biterror @ %u/%u\n", __func__, byte, bit);
+                if (--errors == 0)
+                    break;
+            }
+        }
+        byte++;
+    }
+
+    return errors;
+}
+
+static int nand_bit_errors_test(u32 page, u32 error_num)
+{
+    struct mtk_nand_chip *chip = mtk_get_nand_chip();
+    struct mtk_nand_ops ops;
+    u8 *rbuf, *wbuf;
+    u32 buf_size, i, byte, parity_per_sector;
+    u32 parity_bytes = chip->ecc_strength * ECC_PARITY_BITS / 8 - 1;
+    u32 errs;
+    int ret;
+
+    /* error num 0 means full ecc strength */
+    if (error_num == 0)
+        error_num = chip->ecc_strength;
+    errs = error_num;
+
+    buf_size = chip->pagesize + chip->oobsize;
+
+    rbuf = mempool_alloc(buf_size, MEMPOOL_ANY);
+    if (rbuf == NULL)
+        return ERR_NO_MEMORY;
+    memset(rbuf, 0xff, buf_size);
+
+    wbuf = mempool_alloc(buf_size, MEMPOOL_ANY);
+    if (wbuf == NULL) {
+        ret = ERR_NO_MEMORY;
+        goto freerbuf;
+    }
+    memset(wbuf, 0xff, buf_size);
+
+    if (mtk_nand_block_isbad(chip, page)) {
+        printf("%s: page %u is bad!\n", __func__, page);
+        ret = ERR_FAULT;
+        goto freewbuf;
+    }
+
+    memset(&ops, 0, sizeof(ops));
+
+    ops.mode = NAND_OPS_ECC_DMA_POLL;
+    ops.offset = (u64)page * chip->pagesize;
+    ops.len = (u64)chip->pagesize;
+    ops.readbuf = rbuf;
+    ret = mtk_nand_read(chip, &ops);
+    if (ret < 0)
+        goto freewbuf;
+    printf("%s: max bit errors before rewrite: %d\n", __func__, ret);
+
+    memset(rbuf, 0xff, buf_size);
+    ops.mode = NAND_OPS_RAW_DMA_POLL;
+    ops.oobeccbuf = ops.readbuf + chip->pagesize;
+    ops.oobeccoffs = 0;
+    ops.oobecclen = chip->oob_free_ecc_size;
+    ops.oobrawbuf = ops.oobeccbuf + chip->oob_free_ecc_size;
+    ops.oobrawoffs = 0;
+    ops.oobrawlen = chip->oob_free_raw_size;
+    ops.oobparitybuf = ops.oobrawbuf + chip->oob_free_raw_size;
+    ops.oobparityoffs = 0;
+    ops.oobparitylen = chip->oobsize - chip->oob_free_ecc_size
+                       - chip->oob_free_raw_size;
+    parity_per_sector = ops.oobparitylen / chip->ecc_steps;
+    ret = mtk_nand_read(chip, &ops);
+    if (ret < 0)
+        goto freewbuf;
+    memcpy(wbuf, rbuf, chip->pagesize + chip->oobsize);
+
+    /* introduce deliberate bit errors */
+    for (i = 0; i < chip->ecc_steps; i++) {
+        errs = error_num;
+
+        /* one bit error in fdm data area */
+        printf("%s: sector %u insert fdm data area error\n", __func__, i);
+        byte = (u32)rand() % chip->fdm_ecc_size;
+        byte += i * chip->fdm_ecc_size;
+        ret = insert_biterrors(byte, (i + 1) * chip->fdm_ecc_size, 1,
+                               ops.oobeccbuf);
+        errs -= (1 - ret);
+
+        if (errs == 0)
+            continue;
+
+        /* one bit error in parity data area */
+        printf("%s: sector %u insert parity data area error\n", __func__, i);
+        byte = (u32)rand() % parity_bytes;
+        byte += i * parity_per_sector;
+        ret = insert_biterrors(byte, (i + 1) * parity_per_sector, 1,
+                               ops.oobparitybuf);
+
+        errs -= (1 - ret);
+
+        if (errs == 0)
+            continue;
+
+        /* error in main data area */
+        printf("%s: sector %u insert main data area error\n", __func__, i);
+        byte = (u32)rand() % chip->ecc_size;
+        byte += i * chip->ecc_size;
+        ret = insert_biterrors(byte, (i + 1) * chip->ecc_size, errs,
+                               ops.readbuf);
+        errs -= (errs - ret);
+
+        if (errs)
+            printf("%s: sector %d insert errors not enough, left %u\n",
+                   __func__, i, errs);
+    }
+
+    ops.writebuf = rbuf;
+    ret = mtk_nand_write(chip, &ops);
+    if (ret < 0)
+        goto freewbuf;
+
+    /* readback */
+    memset(rbuf, 0xff, chip->pagesize + chip->oobsize);
+    ops.mode = NAND_OPS_ECC_DMA_POLL;
+    ops.oobrawbuf = NULL;
+    ops.oobparitybuf = NULL;
+    ret = mtk_nand_read(chip, &ops);
+    if (ret < 0)
+        goto freewbuf;
+    else
+        printf("%s: max bit errors after rewrite: %d\n", __func__, ret);
+
+    /* verify data */
+    for (i = 0; i < chip->pagesize + chip->oob_free_ecc_size; i++) {
+        if (wbuf[i] != rbuf[i]) {
+            printf("%s: byte %d is different: 0x%x != 0x%x, %p %p\n",
+                   __func__, i, wbuf[i], rbuf[i], &wbuf[i], &rbuf[i]);
+            hexdump(rbuf, chip->pagesize + chip->oobsize);
+            ret = ERR_IO;
+            goto freewbuf;
+        }
+    }
+
+freewbuf:
+    mempool_free(wbuf);
+freerbuf:
+    mempool_free(rbuf);
+
+    printf("%s: %u bit errors test %s\n", __func__, error_num,
+           ret < 0 ? "Failed" : "OK");
+
+    return ret;
+}
+
+static int nand_create_bbt(void)
+{
+    struct mtk_nand_chip *chip = mtk_get_nand_chip();
+    struct mtk_nand_ops ops;
+    u32 i, page;
+    int ret;
+
+    /* Free BBT */
+    free(chip->bbt);
+    chip->bbt = NULL;
+    chip->bbt_block = -1;
+
+    /* Erase BBT area */
+    for (i = 1; i <= SCAN_BBT_MAXBLOCKS; i++) {
+        page = chip->totalsize - chip->blocksize * i;
+        page /= chip->pagesize;
+        if (mtk_nand_block_isbad(chip, page))
+            continue;
+        memset(&ops, 0, sizeof(ops));
+        ops.mode = NAND_OPS_ERASE_POLL;
+        ops.offset = (u64)page * chip->pagesize;
+        ops.len = chip->blocksize;
+        mtk_nand_erase(chip, &ops);
+    }
+
+    ret = mtk_nand_scan_bbt(chip);
+
+    return ret;
+}
+
+static int cmd_nand(int argc, const cmd_args *argv)
+{
+    int ret = 0;
+
+    if (argc < 2) {
+notenoughargs:
+        printf("not enough arguments:\n");
+usage:
+        printf("%s info\n", argv[0].str);
+        printf("%s list\n", argv[0].str);
+        printf("%s speedtest <device>\n", argv[0].str);
+        printf("%s biterrstest <page> <error num>\n", argv[0].str);
+        printf("%s createbbt\n", argv[0].str);
+        return -1;
+    }
+
+    if (!strcmp(argv[1].str, "info")) {
+        nand_dump_device_info();
+    } else if (!strcmp(argv[1].str, "list")) {
+        bio_dump_devices();
+    } else if (!strcmp(argv[1].str, "speedtest")) {
+        if (argc < 3) goto notenoughargs;
+
+        ret = nand_speed_test(argv[2].str);
+    } else if (!strcmp(argv[1].str, "biterrstest")) {
+        if (argc < 4) goto notenoughargs;
+
+        ret = nand_bit_errors_test(argv[2].u, argv[3].u);
+    } else if (!strcmp(argv[1].str, "createbbt")) {
+        ret = nand_create_bbt();
+    } else {
+        printf("error: command %s not support\n", argv[1].str);
+        goto usage;
+    }
+
+    return ret;
+}
+
+STATIC_COMMAND_START
+STATIC_COMMAND("nand", "nand driver test & debug commands", &cmd_nand)
+STATIC_COMMAND_END(nand);
+
+#endif /* WITH_LIB_CONSOLE */
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nfi_hal.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nfi_hal.c
new file mode 100644
index 0000000..f611781
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/mtk_nfi_hal.c
@@ -0,0 +1,1772 @@
+/*
+ * Copyright (c) 2017 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 <arch/ops.h>
+#include <errno.h>
+#include <kernel/event.h>
+#include <kernel/mutex.h>
+#include <kernel/vm.h>
+#include <malloc.h>
+#include <platform/interrupts.h>
+#include <platform/mt_irq.h>
+#include <platform/mt_reg_base.h>
+#include <platform/nand/mtk_ecc_hal.h>
+#include <platform/nand/mtk_nand_common.h>
+#include <platform/nand/mtk_nand_nal.h>
+#include <platform/nand/mtk_nfi_hal.h>
+#include <reg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct mtk_nand_chip *chip)
+{
+    return containerof(chip, struct mtk_nfc_nand_chip, chip);
+}
+
+static inline u8 *data_ptr(struct mtk_nand_chip *chip, const u8 *p, int i)
+{
+    return (u8 *)p + i * chip->ecc_size;
+}
+
+static inline int mtk_data_len(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+
+    return chip->ecc_size + mtk_nand->spare_per_sector;
+}
+
+static inline u8 *mtk_data_ptr(struct mtk_nand_chip *chip,  int i)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    return nfc->buffer + i * mtk_data_len(chip);
+}
+
+static inline u8 *oob_ptr(struct mtk_nand_chip *chip, u32 i)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    u8 *poi;
+
+    /* map the sector's FDM data to free oob:
+     * the beginning of the oob area stores the FDM data of bad mark sectors
+     */
+    if (i < mtk_nand->bad_mark.sec)
+        poi = chip->oob_poi + (i + 1) * mtk_nand->fdm.reg_size;
+    else if (i == mtk_nand->bad_mark.sec)
+        poi = chip->oob_poi;
+    else
+        poi = chip->oob_poi + i * mtk_nand->fdm.reg_size;
+
+    return poi;
+}
+
+static inline u8 *oob_parity_ptr(struct mtk_nand_chip *chip, u32 i)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    u32 parity_size = mtk_nand->spare_per_sector - mtk_nand->fdm.reg_size;
+    u32 fdm_total_size = mtk_nand->fdm.reg_size * chip->ecc_steps;
+    u8 *poi;
+
+    poi = chip->oob_poi + fdm_total_size;
+
+    if (i < mtk_nand->bad_mark.sec)
+        poi += (i + 1) * parity_size;
+    else if (i > mtk_nand->bad_mark.sec)
+        poi += i * parity_size;
+
+    return poi;
+}
+
+static inline u8 *mtk_oob_ptr(struct mtk_nand_chip *chip, int i)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    return nfc->buffer + i * mtk_data_len(chip) + chip->ecc_size;
+}
+
+static inline u8 *mtk_oob_parity_ptr(struct mtk_nand_chip *chip, int i)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+
+    return mtk_oob_ptr(chip, i) + mtk_nand->fdm.reg_size; 
+}
+
+static inline void nfi_writel(struct mtk_nfc *nfc, u32 val, u32 reg)
+{
+    writel(val, nfc->regs + reg);
+
+    return;
+}
+
+static inline void nfi_writew(struct mtk_nfc *nfc, u16 val, u32 reg)
+{
+    (*REG16(nfc->regs + reg) = (val));
+
+    return;
+}
+
+static inline void nfi_writeb(struct mtk_nfc *nfc, u8 val, u32 reg)
+{
+    writeb(val, nfc->regs + reg);
+
+    return;
+}
+
+static inline u32 nfi_readl(struct mtk_nfc *nfc, u32 reg)
+{
+    return readl(nfc->regs + reg);
+}
+
+static inline u16 nfi_readw(struct mtk_nfc *nfc, u32 reg)
+{
+    return *REG16(nfc->regs + reg);
+}
+
+static inline u8 nfi_readb(struct mtk_nfc *nfc, u32 reg)
+{
+    return readb(nfc->regs + reg);
+}
+
+static void mtk_nfc_hw_reset(struct mtk_nfc *nfc)
+{
+    /* reset all registers and force the NFI master to terminate */
+    nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
+
+    /* wait for the master to finish the last transaction */
+    if (!check_with_timeout(!(nfi_readl(nfc, NFI_MASTER_STA) & MASTER_STA_MASK),
+                            MTK_RESET_TIMEOUT))
+        dprintf(CRITICAL, "NFI HW reset timeout!\n");
+
+    /* ensure any status register affected by the NFI master is reset */
+    nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
+    nfi_writew(nfc, STAR_DE, NFI_STRDATA);
+
+    return;
+}
+
+static int mtk_nfc_send_command(struct mtk_nfc *nfc, u8 command)
+{
+    nfi_writel(nfc, command, NFI_CMD);
+
+    if (!check_with_timeout(!(nfi_readl(nfc, NFI_STA) & STA_CMD), MTK_TIMEOUT))
+        dprintf(CRITICAL, "send cmd 0x%x timeout\n", command);
+
+    return 0;
+}
+
+static int mtk_nfc_send_address(struct mtk_nfc *nfc, int addr)
+{
+    nfi_writel(nfc, addr, NFI_COLADDR);
+    nfi_writel(nfc, 0, NFI_ROWADDR);
+    nfi_writew(nfc, 1, NFI_ADDRNOB);
+
+    if (!check_with_timeout(!(nfi_readl(nfc, NFI_STA) & STA_ADDR), MTK_TIMEOUT))
+        dprintf(CRITICAL, "send cmd 0x%x timeout\n", addr);
+
+    return 0;
+}
+
+static int mtk_nfc_irq_wait(struct mtk_nfc *nfc, lk_time_t timeout)
+{
+    int ret;
+
+    ret = event_wait_timeout(&nfc->irq_event, timeout);
+    if (ret != 0) {
+        dprintf(CRITICAL, "[%s]: failed to get event INT=0x%x\n",
+                __func__, nfi_readw(nfc, NFI_INTR_EN));
+        return ret;
+    }
+
+    return 0;
+}
+
+static enum handler_return mtk_nfc_interrupt_handler(void *arg)
+{
+    struct mtk_nfc *nfc = arg;
+    u16 sta, ien;
+
+    sta = nfi_readw(nfc, NFI_INTR_STA);
+    ien = nfi_readw(nfc, NFI_INTR_EN);
+    if (!(sta & ien))
+        return INT_NO_RESCHEDULE;
+
+    nfi_writew(nfc, ~sta & ien, NFI_INTR_EN);
+
+    /* MUST BE *false*! otherwise, schedule in interrupt */
+    event_signal(&nfc->irq_event, false);
+
+    return INT_RESCHEDULE;
+}
+
+static int mtk_nfc_request_irq(struct mtk_nfc *nfc)
+{
+    mt_irq_set_sens(NFI_IRQ_BIT_ID, LEVEL_SENSITIVE);
+    mt_irq_set_polarity(NFI_IRQ_BIT_ID, MT65xx_POLARITY_LOW);
+    event_init(&nfc->irq_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+    register_int_handler(NFI_IRQ_BIT_ID, mtk_nfc_interrupt_handler, nfc);
+    unmask_interrupt(NFI_IRQ_BIT_ID);
+
+    return 0;
+}
+
+static int mtk_nfc_hw_runtime_config(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    u32 fmt, spare;
+
+    if (!chip->pagesize)
+        return -EINVAL;
+
+    spare = mtk_nand->spare_per_sector;
+
+    switch (chip->pagesize) {
+        case 512:
+            fmt = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512;
+            break;
+        case KB(2):
+            if (chip->ecc_size == 512)
+                fmt = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512;
+            else
+                fmt = PAGEFMT_512_2K;
+            break;
+        case KB(4):
+            if (chip->ecc_size == 512)
+                fmt = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512;
+            else
+                fmt = PAGEFMT_2K_4K;
+            break;
+        case KB(8):
+            if (chip->ecc_size == 512)
+                fmt = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512;
+            else
+                fmt = PAGEFMT_4K_8K;
+            break;
+        case KB(16):
+            fmt = PAGEFMT_8K_16K;
+            break;
+        default:
+            dprintf(CRITICAL, "invalid page len: %d\n", chip->pagesize);
+            return -EINVAL;
+    }
+
+    /*
+     * the hardware will double the value for this eccsize, so we need to
+     * halve it
+     */
+    if (chip->ecc_size == 1024)
+        spare >>= 1;
+
+    switch (spare) {
+        case 16:
+            fmt |= (PAGEFMT_SPARE_16 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 26:
+            fmt |= (PAGEFMT_SPARE_26 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 27:
+            fmt |= (PAGEFMT_SPARE_27 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 28:
+            fmt |= (PAGEFMT_SPARE_28 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 32:
+            fmt |= (PAGEFMT_SPARE_32 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 36:
+            fmt |= (PAGEFMT_SPARE_36 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 40:
+            fmt |= (PAGEFMT_SPARE_40 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 44:
+            fmt |= (PAGEFMT_SPARE_44 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 48:
+            fmt |= (PAGEFMT_SPARE_48 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 49:
+            fmt |= (PAGEFMT_SPARE_49 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 50:
+            fmt |= (PAGEFMT_SPARE_50 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 51:
+            fmt |= (PAGEFMT_SPARE_51 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 52:
+            fmt |= (PAGEFMT_SPARE_52 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 62:
+            fmt |= (PAGEFMT_SPARE_62 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 63:
+            fmt |= (PAGEFMT_SPARE_63 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 64:
+            fmt |= (PAGEFMT_SPARE_64 << PAGEFMT_SPARE_SHIFT);
+            break;
+        default:
+            dprintf(CRITICAL, "invalid spare per sector %d\n", spare);
+            return -EINVAL;
+    }
+
+    fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
+    fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_SHIFT;
+    nfi_writel(nfc, fmt, NFI_PAGEFMT);
+
+    nfc->ecc_cfg.strength = chip->ecc_strength;
+    nfc->ecc_cfg.len = chip->ecc_size + mtk_nand->fdm.ecc_size;
+
+    return 0;
+}
+
+static void mtk_nfc_select_chip(struct mtk_nand_chip *chip, int chip_num)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    if ((chip_num < 0) || (chip_num == chip->activechip))
+        return;
+
+    if (!mtk_nfc_hw_runtime_config(chip)) {
+        chip->activechip = chip_num;
+    }
+
+    nfi_writel(nfc, chip_num, NFI_CSEL);
+
+    return;
+}
+
+static int mtk_nfc_dev_ready(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
+        return 0;
+
+    return 1;
+}
+
+static int mtk_nfc_wait_busy_irq(struct mtk_nand_chip *chip)
+{
+    int ret;
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    /* set wait busy interrupt */
+    nfi_writew(nfc, INTR_BUSY_RETURN_EN, NFI_INTR_EN);
+
+    /* wait interrupt */
+    ret = mtk_nfc_irq_wait(nfc, MTK_TIMEOUT);
+    if (!ret) {
+        dprintf(CRITICAL, "wait busy interrupt timeout\n");
+        nfi_writew(nfc, 0, NFI_INTR_EN);
+        return -ETIMEDOUT;
+    }
+
+    return 0;
+}
+
+static void mtk_nfc_cmd_ctrl(struct mtk_nand_chip *chip, int dat, unsigned int ctrl)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    u16 reg;
+
+    if (ctrl & NAND_ALE) {
+        mtk_nfc_send_address(nfc, dat);
+    } else if (ctrl & NAND_CLE) {
+        mtk_nfc_hw_reset(nfc);
+
+        reg = nfi_readw(nfc, NFI_CNFG);
+        reg &= CNFG_RAND_MASK;
+        reg |= CNFG_OP_CUST;
+        nfi_writew(nfc, reg, NFI_CNFG);
+        mtk_nfc_send_command(nfc, dat);
+    }
+
+    return;
+}
+
+static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
+{
+    if (!check_with_timeout((nfi_readl(nfc, NFI_PIO_DIRDY) & PIO_DI_RDY), MTK_TIMEOUT)) {
+        dprintf(CRITICAL, "data not ready\n");
+        dprintf(CRITICAL, "cntr 0x%x cnfg 0x%x fmt 0x%x con 0x%x\n", nfi_readl(nfc, NFI_BYTELEN),
+                nfi_readl(nfc, NFI_CNFG), nfi_readl(nfc, NFI_PAGEFMT), nfi_readl(nfc, NFI_CON));
+    }
+
+    return;
+}
+
+static inline u8 mtk_nfc_read_byte(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    u32 reg;
+
+    /* after each byte read, the NFI_STA reg is reset by the hardware */
+    reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
+    if (reg != NFI_FSM_CUSTDATA) {
+        reg = nfi_readw(nfc, NFI_CNFG);
+        reg |= CNFG_BYTE_RW | CNFG_READ_EN;
+        nfi_writew(nfc, reg, NFI_CNFG);
+
+        /*
+         * set to max sector to allow the HW to continue reading over
+         * unaligned accesses
+         */
+        reg = (MTK_MAX_SECTOR << CON_SEC_SHIFT) | CON_BRD;
+        nfi_writel(nfc, reg, NFI_CON);
+
+        /* trigger to fetch data */
+        nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+    }
+
+    mtk_nfc_wait_ioready(nfc);
+
+    return nfi_readb(nfc, NFI_DATAR);
+}
+
+static void mtk_nfc_read_buf(struct mtk_nand_chip *chip, u8 *buf, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        buf[i] = mtk_nfc_read_byte(chip);
+
+    return;
+}
+
+static void mtk_nfc_write_byte(struct mtk_nand_chip *chip, u8 byte)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    u32 reg;
+
+    reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
+
+    if (reg != NFI_FSM_CUSTDATA) {
+        reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
+        nfi_writew(nfc, reg, NFI_CNFG);
+
+        reg = MTK_MAX_SECTOR << CON_SEC_SHIFT | CON_BWR;
+        nfi_writel(nfc, reg, NFI_CON);
+
+        nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+    }
+
+    mtk_nfc_wait_ioready(nfc);
+    nfi_writeb(nfc, byte, NFI_DATAW);
+
+    return;
+}
+
+static void mtk_nfc_write_buf(struct mtk_nand_chip *chip, const u8 *buf, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        mtk_nfc_write_byte(chip, buf[i]);
+
+    return;
+}
+
+static int mtk_nfc_sector_encode(struct mtk_nand_chip *chip, u8 *data, int dma, int polling)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    int size = chip->ecc_size + mtk_nand->fdm.reg_size;
+
+    if (dma)
+        nfc->ecc_cfg.mode = ECC_DMA_MODE;
+    else
+        nfc->ecc_cfg.mode = ECC_PIO_MODE;
+    nfc->ecc_cfg.op = ECC_ENCODE;
+
+    return mtk_ecc_encode(nfc->ecc, &nfc->ecc_cfg, data, size, polling);
+}
+
+static void mtk_nfc_no_bad_mark_swap(struct mtk_nand_chip *a, u8 *b, int c)
+{
+    /* nop */
+    return;
+}
+
+static void mtk_nfc_bad_mark_swap(struct mtk_nand_chip *chip, u8 *buf, int raw)
+{
+    struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
+    u32 bad_pos = nand->bad_mark.pos;
+
+    if (raw)
+        bad_pos += nand->bad_mark.sec * mtk_data_len(chip);
+    else
+        bad_pos += nand->bad_mark.sec * chip->ecc_size;
+
+    swap(chip->oob_poi[0], buf[bad_pos]);
+
+    return;
+}
+
+static int mtk_nfc_format_subpage(struct mtk_nand_chip *chip, u32 offset,
+                                  u32 len, const u8 *buf, int dma, int polling)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 start, end, i;
+    int ret;
+
+    start = offset / chip->ecc_size;
+    end = DIV_ROUND_UP(offset + len, chip->ecc_size);
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i), chip->ecc_size);
+
+        if (start > i || i >= end)
+            continue;
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
+
+        /* program the CRC back to the OOB */
+        ret = mtk_nfc_sector_encode(chip, mtk_data_ptr(chip, i), dma, polling);
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+static void mtk_nfc_format_page(struct mtk_nand_chip *chip, const u8 *buf)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 parity_size = mtk_nand->spare_per_sector - fdm->reg_size;
+    u32 i;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    for (i = 0; i < chip->ecc_steps; i++) {
+        if (buf)
+            memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
+                   chip->ecc_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
+        memcpy(mtk_oob_parity_ptr(chip, i), oob_parity_ptr(chip, i),
+               parity_size);
+    }
+
+    return;
+}
+
+static inline void mtk_nfc_read_fdm(struct mtk_nand_chip *chip, u32 start,
+                                    u32 sectors)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 vall, valm, i, j;
+    u8 *oobptr;
+
+    for (i = 0; i < sectors; i++) {
+        oobptr = oob_ptr(chip, start + i);
+        vall = nfi_readl(nfc, NFI_FDML(i));
+        valm = nfi_readl(nfc, NFI_FDMM(i));
+
+        for (j = 0; j < fdm->reg_size; j++)
+            oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8);
+    }
+
+    return;
+}
+
+static inline void mtk_nfc_write_fdm(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 vall, valm, i, j;
+    u8 *oobptr;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        oobptr = oob_ptr(chip, i);
+        vall = 0;
+        valm = 0;
+        for (j = 0; j < 8; j++) {
+            if (j < 4)
+                vall |= (j < fdm->reg_size ? oobptr[j] : 0xff)
+                        << (j * 8);
+            else
+                valm |= (j < fdm->reg_size ? oobptr[j] : 0xff)
+                        << ((j - 4) * 8);
+        }
+        nfi_writel(nfc, vall, NFI_FDML(i));
+        nfi_writel(nfc, valm, NFI_FDMM(i));
+    }
+
+    return;
+}
+
+static int mtk_nfc_do_write_page(struct mtk_nand_chip *chip,
+                                 const u8 *buf, int page, int len, int raw, int dma, int polling)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    u32 *buf32 = (u32 *)buf;
+    uintptr_t addr;
+    u32 reg, i;
+    u32 data_len = chip->ecc_size;
+    int ret = 0, byterw;
+
+#ifdef WITH_KERNEL_VM
+    addr = (uintptr_t)kvaddr_to_paddr((void *)buf);
+#else
+    addr = (uintptr_t)buf;
+#endif
+
+    if (dma) {
+        reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AHB | CNFG_DMA_BURST_EN;
+        nfi_writew(nfc, reg, NFI_CNFG);
+        arch_clean_cache_range((addr_t)buf, (size_t)len);
+    }
+    nfi_writel(nfc, chip->ecc_steps << CON_SEC_SHIFT, NFI_CON);
+    nfi_writel(nfc, (u32)addr, NFI_STRADDR);
+
+    if (dma && (!polling)) {
+        nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
+    }
+
+    reg = nfi_readl(nfc, NFI_CON) | CON_BWR;
+    nfi_writel(nfc, reg, NFI_CON);
+    nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+
+    if (!dma) {
+        if (raw)
+            data_len = mtk_data_len(chip);
+        data_len *= chip->ecc_steps;
+
+        if (data_len & 0x3) {
+            reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
+            nfi_writew(nfc, reg, NFI_CNFG);
+            byterw = 1;
+        } else {
+            data_len >>= 2;
+            byterw = 0;
+        }
+
+        for (i = 0; i < data_len; i++) {
+            mtk_nfc_wait_ioready(nfc);
+            if (!byterw)
+                nfi_writel(nfc, buf32[i],NFI_DATAW);
+            else
+                nfi_writeb(nfc, buf[i], NFI_DATAW);
+        }
+    }
+
+    if (dma && (!polling)) {
+        ret = mtk_nfc_irq_wait(nfc, MTK_TIMEOUT);
+        if (!ret) {
+            dprintf(CRITICAL, "program ahb done timeout\n");
+            nfi_writew(nfc, 0, NFI_INTR_EN);
+            ret = -ETIMEDOUT;
+            goto timeout;
+        }
+    }
+
+    if (!check_with_timeout(ADDRCNTR_SEC(nfi_readl(nfc, NFI_ADDRCNTR)) >= chip->ecc_steps, MTK_TIMEOUT))
+        dprintf(CRITICAL, "do page write timeout\n");
+
+timeout:
+    if (dma)
+        arch_invalidate_cache_range((addr_t)buf, (size_t)len);
+
+    nfi_writel(nfc, 0, NFI_CON);
+
+    return ret;
+}
+
+static int mtk_nfc_write_page(struct mtk_nand_chip *chip,
+                              const u8 *buf, int page, int raw, int dma, int polling)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    u32 len;
+    const u8 *bufpoi;
+    u32 reg;
+    int ret;
+
+    if (!raw) {
+        /* OOB => FDM: from register,  ECC: from HW */
+        reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AUTO_FMT_EN;
+        nfi_writew(nfc, reg | CNFG_HW_ECC_EN, NFI_CNFG);
+
+        nfc->ecc_cfg.op = ECC_ENCODE;
+        nfc->ecc_cfg.mode = ECC_NFI_MODE;
+        ret = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg, polling);
+        if (ret) {
+            /* clear NFI config */
+            reg = nfi_readw(nfc, NFI_CNFG);
+            reg &= ~(CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
+            nfi_writew(nfc, reg, NFI_CNFG);
+
+            return ret;
+        }
+
+        memcpy(nfc->buffer, buf, chip->pagesize);
+        mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, raw);
+        bufpoi = nfc->buffer;
+
+        /* write OOB into the FDM registers (OOB area in MTK NAND) */
+        mtk_nfc_write_fdm(chip);
+    } else {
+        bufpoi = buf;
+    }
+
+    len = chip->pagesize + (raw ? chip->oobsize : 0);
+    ret = mtk_nfc_do_write_page(chip, bufpoi, page, len, raw, dma, polling);
+
+    if (!raw)
+        mtk_ecc_disable(nfc->ecc);
+
+    return ret;
+}
+
+static int mtk_nfc_write_page_ecc_dma_polling(struct mtk_nand_chip *chip, const u8 *buf,
+        int page)
+{
+    return mtk_nfc_write_page(chip, buf, page, 0, 1, 1);
+}
+
+static int mtk_nfc_write_page_ecc_dma_irq(struct mtk_nand_chip *chip, const u8 *buf,
+        int page)
+{
+    return mtk_nfc_write_page(chip, buf, page, 0, 1, 0);
+}
+
+static int mtk_nfc_write_page_ecc_pio_polling(struct mtk_nand_chip *chip, const u8 *buf,
+        int page)
+{
+    return mtk_nfc_write_page(chip, buf, page, 0, 0, 1);
+}
+
+static int mtk_nfc_write_page_ecc_pio_irq(struct mtk_nand_chip *chip, const u8 *buf,
+        int page)
+{
+    return mtk_nfc_write_page(chip, buf, page, 0, 0, 0);
+}
+
+static int mtk_nfc_write_page_raw_dma_polling(struct mtk_nand_chip *chip,
+        const u8 *buf, int pg)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mtk_nfc_format_page(chip, buf);
+    return mtk_nfc_write_page(chip, nfc->buffer, pg, 1, 1, 1);
+}
+
+static int mtk_nfc_write_page_raw_dma_irq(struct mtk_nand_chip *chip,
+        const u8 *buf, int pg)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mtk_nfc_format_page(chip, buf);
+    return mtk_nfc_write_page(chip, nfc->buffer, pg, 1, 1, 0);
+}
+
+static int mtk_nfc_write_page_raw_pio_polling(struct mtk_nand_chip *chip,
+        const u8 *buf, int pg)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mtk_nfc_format_page(chip, buf);
+    return mtk_nfc_write_page(chip, nfc->buffer, pg, 1, 0, 1);
+}
+
+static int mtk_nfc_write_page_raw_pio_irq(struct mtk_nand_chip *chip,
+        const u8 *buf, int pg)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mtk_nfc_format_page(chip, buf);
+    return mtk_nfc_write_page(chip, nfc->buffer, pg, 1, 0, 0);
+}
+
+static int mtk_nfc_write_subpage_ecc_dma_polling(struct mtk_nand_chip *chip, u32 offset,
+        u32 data_len, const u8 *buf, int page)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    int ret;
+
+    ret = mtk_nfc_format_subpage(chip, offset, data_len, buf, 1, 1);
+    if (ret < 0)
+        return ret;
+
+    /* use the data in the private buffer (now with FDM and CRC) */
+    return mtk_nfc_write_page(chip, nfc->buffer, page, 1, 1, 1);
+}
+
+static int mtk_nfc_write_subpage_ecc_dma_irq(struct mtk_nand_chip *chip, u32 offset,
+        u32 data_len, const u8 *buf, int page)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    int ret;
+
+    ret = mtk_nfc_format_subpage(chip, offset, data_len, buf, 1, 0);
+    if (ret < 0)
+        return ret;
+
+    /* use the data in the private buffer (now with FDM and CRC) */
+    return mtk_nfc_write_page(chip, nfc->buffer, page, 1, 1, 0);
+}
+
+static int mtk_nfc_write_subpage_ecc_pio_polling(struct mtk_nand_chip *chip, u32 offset,
+        u32 data_len, const u8 *buf, int page)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    int ret;
+
+    ret = mtk_nfc_format_subpage(chip, offset, data_len, buf, 0, 1);
+    if (ret < 0)
+        return ret;
+
+    /* use the data in the private buffer (now with FDM and CRC) */
+    return mtk_nfc_write_page(chip, nfc->buffer, page, 1, 0, 1);
+}
+
+static int mtk_nfc_write_subpage_ecc_pio_irq(struct mtk_nand_chip *chip, u32 offset,
+        u32 data_len, const u8 *buf, int page)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    int ret;
+
+    ret = mtk_nfc_format_subpage(chip, offset, data_len, buf, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    /* use the data in the private buffer (now with FDM and CRC) */
+    return mtk_nfc_write_page(chip, nfc->buffer, page, 1, 0, 0);
+}
+
+static int mtk_nfc_update_ecc_stats(struct mtk_nand_chip *chip, u8 *buf, u32 sectors)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_ecc_stats stats;
+    u32 rc, i;
+
+    rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
+    if (rc) {
+        memset(buf, 0xff, sectors * chip->ecc_size);
+        for (i = 0; i < sectors; i++)
+            memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size);
+        return 0;
+    }
+
+    mtk_ecc_get_stats(nfc->ecc, &stats, sectors);
+    chip->stats.corrected += stats.corrected;
+    chip->stats.failed += stats.failed;
+
+    return stats.bitflips;
+}
+
+static int mtk_nfc_read_subpage(struct mtk_nand_chip *chip,
+                                u32 data_offs, u32 readlen,
+                                u8 *bufpoi, int page, int raw, int dma, int polling)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_ecc_stats stats;
+    u32 spare = mtk_nand->spare_per_sector;
+    u32 column, sectors, start, end, reg;
+    uintptr_t addr;
+    u32 i, j;
+    int bitflips = 0;
+    u32 len, correct = 0, fail = 0;
+    u8 *buf;
+    u32 *buf32;
+    u32 data_len = chip->ecc_size;
+    int rc, byterw;
+
+    start = data_offs / chip->ecc_size;
+    end = DIV_ROUND_UP(data_offs + readlen, chip->ecc_size);
+
+    sectors = end - start;
+    column = start * (chip->ecc_size + spare);
+
+    len = sectors * chip->ecc_size + ((raw || !dma) ? sectors * spare : 0);
+    buf = bufpoi + start * (chip->ecc_size + ((raw || !dma) ? sectors * spare : 0));
+    buf32 = (u32 *)buf;
+
+    if (column != 0)
+        chip->cmdfunc(chip, NAND_CMD_RNDOUT, column, -1);
+
+#ifdef WITH_KERNEL_VM
+    addr = (uintptr_t)kvaddr_to_paddr(buf);
+#else
+    addr = (uintptr_t)buf;
+#endif
+
+    reg = nfi_readw(nfc, NFI_CNFG);
+    reg |= CNFG_READ_EN;
+    if (dma)
+        reg |= CNFG_DMA_BURST_EN | CNFG_AHB;
+    if (!raw) {
+        reg |= CNFG_HW_ECC_EN;
+        if (dma)
+            reg |= CNFG_AUTO_FMT_EN;
+        nfi_writew(nfc, reg, NFI_CNFG);
+
+        nfc->ecc_cfg.mode = ECC_NFI_MODE;
+        nfc->ecc_cfg.sectors = sectors;
+        nfc->ecc_cfg.op = ECC_DECODE;
+        if (dma) {
+            nfc->ecc_cfg.deccon = ECC_DEC_CORRECT;
+        } else {
+            nfc->ecc_cfg.deccon = ECC_DEC_LOCATE;
+        }
+        rc = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg, polling);
+        if (rc) {
+            dprintf(CRITICAL, "ecc enable failed\n");
+            /* clear NFI_CNFG */
+            reg &= ~(CNFG_DMA_BURST_EN | CNFG_AHB | CNFG_READ_EN |
+                     CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
+            nfi_writew(nfc, reg, NFI_CNFG);
+
+            return rc;
+        }
+    } else {
+        nfi_writew(nfc, reg, NFI_CNFG);
+    }
+
+    if (dma)
+        arch_invalidate_cache_range((addr_t)buf, (size_t)len);
+    nfi_writel(nfc, sectors << CON_SEC_SHIFT, NFI_CON);
+    nfi_writel(nfc, (u32)addr, NFI_STRADDR);
+
+    if (dma && (!polling)) {
+        nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
+    }
+    reg = nfi_readl(nfc, NFI_CON) | CON_BRD;
+    nfi_writel(nfc, reg, NFI_CON);
+    nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+
+    if (!dma) {
+        data_len = mtk_data_len(chip);
+
+        if (data_len & 0x3) {
+            reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
+            nfi_writew(nfc, reg, NFI_CNFG);
+            byterw = 1;
+        } else {
+            data_len >>= 2;
+            byterw = 0;
+        }
+        if (!raw) {
+            stats.bitflips = 0;
+            correct = chip->stats.corrected;
+            fail = chip->stats.failed;
+        }
+        for (i = 0; i < sectors; i++) {
+            for (j = 0; j < data_len; j++) {
+                mtk_nfc_wait_ioready(nfc);
+                if (!byterw)
+                    *(buf32 + (i * data_len) + j) = nfi_readl(nfc, NFI_DATAR);
+                else
+                    *(buf + (i * data_len) + j) = nfi_readb(nfc, NFI_DATAR);
+            }
+            if (!raw) {
+                rc = mtk_ecc_cpu_correct(nfc->ecc, &stats, buf + (i * (byterw ? data_len : (data_len << 2))), i, polling);
+                if (rc < 0)
+                    goto disecc;
+                chip->stats.corrected += stats.corrected;
+                chip->stats.failed += stats.failed;
+                if (stats.failed)
+                    dprintf(ALWAYS, "sectoer %d uncorrect\n", i);
+            }
+        }
+        if (!raw) {
+            bitflips = stats.bitflips;
+            rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
+            if (rc) {
+                LTRACEF("page is empty\n");
+                memset(buf, 0xff, sectors * mtk_data_len(chip));
+                bitflips = 0;
+                chip->stats.corrected = correct;
+                chip->stats.failed = fail;
+            }
+        }
+    }
+
+    if (dma && (!polling)) {
+        rc = mtk_nfc_irq_wait(nfc, MTK_TIMEOUT);
+        if (!rc) {
+            dprintf(CRITICAL, "read ahb/dma done timeout\n");
+            nfi_writew(nfc, 0, NFI_INTR_EN);
+        }
+    }
+
+    rc = check_with_timeout(ADDRCNTR_SEC(nfi_readl(nfc, NFI_BYTELEN)) >= sectors, MTK_TIMEOUT);
+    if (rc && polling)
+        rc = check_with_timeout((nfi_readl(nfc, NFI_MASTER_STA) & MASTER_BUS_BUSY) == 0, MTK_TIMEOUT);
+    if (!rc) {
+        dprintf(CRITICAL, "subpage done timeout %d\n", nfi_readl(nfc, NFI_BYTELEN));
+        dprintf(CRITICAL, "cnfg 0x%x fmt 0x%x con 0x%x master_sta 0x%x\n",
+                nfi_readl(nfc, NFI_CNFG), nfi_readl(nfc, NFI_PAGEFMT), nfi_readl(nfc, NFI_CON),
+                nfi_readl(nfc, NFI_MASTER_STA));
+        bitflips = -EIO;
+    } else {
+        if ((!raw) && dma) {
+            bitflips = 0;
+            rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE, polling);
+            if (!rc)
+                rc = mtk_ecc_wait_decode_fsm_idle(nfc->ecc);
+            arch_invalidate_cache_range((addr_t)buf, (size_t)len);
+            mtk_nfc_read_fdm(chip, start, sectors);
+            bitflips = rc < 0 ? -ETIMEDOUT :
+                       mtk_nfc_update_ecc_stats(chip, buf, sectors);
+        }
+    }
+
+    if (raw)
+        goto done;
+
+disecc:
+    mtk_ecc_disable(nfc->ecc);
+
+    if (!dma)
+        goto done;
+
+    if (clamp(mtk_nand->bad_mark.sec, start, end) == mtk_nand->bad_mark.sec)
+        mtk_nand->bad_mark.bm_swap(chip, bufpoi, raw);
+done:
+    nfi_writel(nfc, 0, NFI_CON);
+
+    return bitflips;
+}
+
+static int mtk_nfc_read_subpage_ecc_dma_polling(struct mtk_nand_chip *chip, u32 off,
+        u32 len, u8 *p, int pg)
+{
+    return mtk_nfc_read_subpage(chip, off, len, p, pg, 0, 1, 1);
+}
+
+static int mtk_nfc_read_subpage_ecc_dma_irq(struct mtk_nand_chip *chip, u32 off,
+        u32 len, u8 *p, int pg)
+{
+    return mtk_nfc_read_subpage(chip, off, len, p, pg, 0, 1, 0);
+}
+
+static int mtk_nfc_read_subpage_ecc_pio_polling(struct mtk_nand_chip *chip, u32 off,
+        u32 len, u8 *p, int pg)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 start, end, i;
+    int ret;
+
+    start = off / chip->ecc_size;
+    end = DIV_ROUND_UP(off + len, chip->ecc_size);
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, off, len, nfc->buffer, pg, 0, 0, 1);
+    if (ret < 0)
+        return ret;
+
+    for (i = start; i < end; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (p)
+            memcpy(data_ptr(chip, p, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_subpage_ecc_pio_irq(struct mtk_nand_chip *chip, u32 off,
+        u32 len, u8 *p, int pg)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 start, end, i;
+    int ret;
+
+    start = off / chip->ecc_size;
+    end = DIV_ROUND_UP(off + len, chip->ecc_size);
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, off, len, nfc->buffer, pg, 0, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    for (i = start; i < end; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (p)
+            memcpy(data_ptr(chip, p, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_ecc_dma_polling(struct mtk_nand_chip *chip, u8 *p,
+        int pg)
+{
+    return mtk_nfc_read_subpage(chip, 0, chip->pagesize, p, pg, 0, 1, 1);
+}
+
+static int mtk_nfc_read_page_ecc_dma_irq(struct mtk_nand_chip *chip, u8 *p,
+        int pg)
+{
+    return mtk_nfc_read_subpage(chip, 0, chip->pagesize, p, pg, 0, 1, 0);
+}
+
+static int mtk_nfc_read_page_ecc_pio_polling(struct mtk_nand_chip *chip, u8 *p,
+        int pg)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 i;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer, pg, 0, 0, 1);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (p)
+            memcpy(data_ptr(chip, p, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_ecc_pio_irq(struct mtk_nand_chip *chip, u8 *p,
+        int pg)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 i;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer, pg, 0, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (p)
+            memcpy(data_ptr(chip, p, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_raw_dma_polling(struct mtk_nand_chip *chip,
+        u8 *buf, int page)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 i;
+    u32 parity_size = mtk_nand->spare_per_sector - fdm->reg_size;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer,
+                               page, 1, 1, 1);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+        memcpy(oob_parity_ptr(chip, i), mtk_oob_parity_ptr(chip, i),
+               parity_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (buf)
+            memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_raw_dma_irq(struct mtk_nand_chip *chip,
+        u8 *buf, int page)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 i;
+    u32 parity_size = mtk_nand->spare_per_sector - fdm->reg_size;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer,
+                               page, 1, 1, 0);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+        memcpy(oob_parity_ptr(chip, i), mtk_oob_parity_ptr(chip, i),
+               parity_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (buf)
+            memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_raw_pio_polling(struct mtk_nand_chip *chip,
+        u8 *buf, int page)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 i;
+    u32 parity_size = mtk_nand->spare_per_sector - fdm->reg_size;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer,
+                               page, 1, 0, 1);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+        memcpy(oob_parity_ptr(chip, i), mtk_oob_parity_ptr(chip, i),
+               parity_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (buf)
+            memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_raw_pio_irq(struct mtk_nand_chip *chip,
+        u8 *buf, int page)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 parity_size = mtk_nand->spare_per_sector - fdm->reg_size;
+    u32 i;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer,
+                               page, 1, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+        memcpy(oob_parity_ptr(chip, i), mtk_oob_parity_ptr(chip, i),
+               parity_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (buf)
+            memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_gpio_init(void)
+{
+#define GPIO_MODE7  (GPIO_BASE + 0x560)
+#define GPIO_MODE8  (GPIO_BASE + 0x570)
+#define GPIO_MODE9  (GPIO_BASE + 0x580)
+#define GPIO_MODE10 (GPIO_BASE + 0x590)
+
+    writel(0x1249, GPIO_MODE7);
+    writel(0x2489, GPIO_MODE8);
+    writel(0x2492, GPIO_MODE9);
+    writel(0x12, GPIO_MODE10);
+
+    return 0;
+}
+
+#define SS_SEED_NUM 128
+static u16 ss_randomizer_seed[SS_SEED_NUM] = {
+    0x576A, 0x05E8, 0x629D, 0x45A3, 0x649C, 0x4BF0, 0x2342, 0x272E,
+    0x7358, 0x4FF3, 0x73EC, 0x5F70, 0x7A60, 0x1AD8, 0x3472, 0x3612,
+    0x224F, 0x0454, 0x030E, 0x70A5, 0x7809, 0x2521, 0x48F4, 0x5A2D,
+    0x492A, 0x043D, 0x7F61, 0x3969, 0x517A, 0x3B42, 0x769D, 0x0647,
+    0x7E2A, 0x1383, 0x49D9, 0x07B8, 0x2578, 0x4EEC, 0x4423, 0x352F,
+    0x5B22, 0x72B9, 0x367B, 0x24B6, 0x7E8E, 0x2318, 0x6BD0, 0x5519,
+    0x1783, 0x18A7, 0x7B6E, 0x7602, 0x4B7F, 0x3648, 0x2C53, 0x6B99,
+    0x0C23, 0x67CF, 0x7E0E, 0x4D8C, 0x5079, 0x209D, 0x244A, 0x747B,
+    0x350B, 0x0E4D, 0x7004, 0x6AC3, 0x7F3E, 0x21F5, 0x7A15, 0x2379,
+    0x1517, 0x1ABA, 0x4E77, 0x15A1, 0x04FA, 0x2D61, 0x253A, 0x1302,
+    0x1F63, 0x5AB3, 0x049A, 0x5AE8, 0x1CD7, 0x4A00, 0x30C8, 0x3247,
+    0x729C, 0x5034, 0x2B0E, 0x57F2, 0x00E4, 0x575B, 0x6192, 0x38F8,
+    0x2F6A, 0x0C14, 0x45FC, 0x41DF, 0x38DA, 0x7AE1, 0x7322, 0x62DF,
+    0x5E39, 0x0E64, 0x6D85, 0x5951, 0x5937, 0x6281, 0x33A1, 0x6A32,
+    0x3A5A, 0x2BAC, 0x743A, 0x5E74, 0x3B2E, 0x7EC7, 0x4FD2, 0x5D28,
+    0x751F, 0x3EF8, 0x39B1, 0x4E49, 0x746B, 0x6EF6, 0x44BE, 0x6DB7
+};
+
+static void mtk_nfc_randomizer_init(struct mtk_nand_chip *chip)
+{
+#define TRAP_RANDOM_CFG    (IO_PHYS + 0x434)
+#define TRAR_RANDOM_ENABLE (NAND_BIT(2))
+    if (readl(TRAP_RANDOM_CFG) & TRAR_RANDOM_ENABLE) {
+        chip->options |= NAND_NEED_SCRAMBLING;
+        dprintf(ALWAYS, "nand randomizer trapping on!\n");
+    } else {
+        dprintf(ALWAYS, "nand randomizer trapping off!\n");
+    };
+}
+
+static void mtk_nfc_randomizer_enable(struct mtk_nand_chip *chip, int page,
+                               enum mtk_randomizer_operation rand, int repage)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    u32 reg = 0, index;
+
+    if (!(chip->options & NAND_NEED_SCRAMBLING))
+        return;
+
+    /* randomizer type and reseed type setup */
+    reg = nfi_readl(nfc, NFI_CNFG) | CNFG_RAND_SEL;
+    if (repage)
+        reg &= ~CNFG_RESEED_SEC_EN;
+    else
+        reg |= CNFG_RESEED_SEC_EN;
+    nfi_writel(nfc, reg, NFI_CNFG);
+
+    /* randomizer seed and type setup */
+    index = page % chip->page_per_block;
+    index &= SS_SEED_NUM - 1;
+    reg = (ss_randomizer_seed[index] & RAN_SEED_MASK) << RAND_SEED_SHIFT(rand);
+    reg |= RAND_EN(rand);
+
+    nfi_writel(nfc, reg, NFI_RANDOM_CNFG);
+}
+
+static void mtk_nfc_randomizer_disable(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    if (!(chip->options & NAND_NEED_SCRAMBLING))
+        return;
+
+    nfi_writel(nfc, 0, NFI_RANDOM_CNFG);
+}
+
+static inline void mtk_nfc_hw_init(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    /*
+     * ACCON: access timing control register
+     * -------------------------------------
+     * 31:28: minimum required time for CS post pulling down after accessing
+     *  the device
+     * 27:22: minimum required time for CS pre pulling down before accessing
+     *  the device
+     * 21:16: minimum required time from NCEB low to NREB low
+     * 15:12: minimum required time from NWEB high to NREB low.
+     * 11:08: write enable hold time
+     * 07:04: write wait states
+     * 03:00: read wait states
+     */
+    if (!mtk_nand->acctiming)
+        nfi_writel(nfc, mtk_nand->acctiming, NFI_ACCCON);
+    else
+        nfi_writel(nfc, 0x10404011, NFI_ACCCON);
+
+    /*
+     * CNRNB: nand ready/busy register
+     * -------------------------------
+     * 7:4: timeout register for polling the NAND busy/ready signal
+     * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
+     */
+    nfi_writew(nfc, 0xf1, NFI_CNRNB);
+    nfi_writew(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
+
+    mtk_nfc_hw_reset(nfc);
+
+    nfi_readl(nfc, NFI_INTR_STA);
+    nfi_writel(nfc, 0, NFI_INTR_EN);
+
+    return;
+}
+
+static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtk_nand_chip *nand)
+{
+    struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
+    u32 ecc_bytes;
+
+    ecc_bytes = DIV_ROUND_UP(nand->ecc_strength * ECC_PARITY_BITS, 8);
+
+    fdm->reg_size = chip->spare_per_sector - ecc_bytes;
+    if (fdm->reg_size > NFI_FDM_MAX_SIZE)
+        fdm->reg_size = NFI_FDM_MAX_SIZE;
+
+    /* bad block mark storage */
+    fdm->ecc_size = nand->fdm_ecc_size > NFI_FDM_MAX_SIZE ? NFI_FDM_MAX_SIZE : nand->fdm_ecc_size;
+
+    nand->fdm_ecc_size = fdm->ecc_size;
+    nand->oob_free_ecc_size = nand->fdm_ecc_size * nand->ecc_steps;
+    nand->oob_free_raw_size = (fdm->reg_size - fdm->ecc_size) * nand->ecc_steps;
+
+    return;
+}
+
+static int mtk_nfc_deal_oob_ecc(struct mtk_nand_chip *nand, u8 *buf, u32 offset,
+                                u32 len, bool fill_oob)
+{
+    struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
+    struct mtk_nfc_fdm *fdm = &chip->fdm;
+    u32 copy_len, done = 0, sector = offset / fdm->ecc_size;
+    u8 *to, *from;
+
+    while (len) {
+        offset %= fdm->ecc_size;
+        copy_len = MIN(len, fdm->ecc_size - offset);
+        if (fill_oob) {
+            to = oob_ptr(nand, sector) + offset;
+            from = buf + done;
+        } else {
+            to = buf + done;
+            from = oob_ptr(nand, sector) + offset;
+        }
+        memcpy(to, from, copy_len);
+        done += copy_len;
+        len -= copy_len;
+        sector++;
+        offset += copy_len;
+    };
+
+    return 0;
+}
+
+static int mtk_nfc_deal_oob_raw(struct mtk_nand_chip *nand, u8 *buf, u32 offset,
+                                u32 len, bool fill_oob)
+{
+    struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
+    struct mtk_nfc_fdm *fdm = &chip->fdm;
+    u32 copy_len, done = 0, sector;
+    u32 fdm_raw_size = fdm->reg_size - fdm->ecc_size;
+    u8 *to, *from;
+
+    sector = offset / fdm_raw_size;
+    while (len) {
+        offset %= fdm_raw_size;
+        copy_len = MIN(len, fdm_raw_size - offset);
+        if (fill_oob) {
+            to = oob_ptr(nand, sector) + fdm->ecc_size + offset;
+            from = buf + done;
+        } else {
+            to = buf + done;
+            from = oob_ptr(nand, sector) + fdm->ecc_size + offset;
+        }
+        memcpy(to, from, copy_len);
+        done += copy_len;
+        len -= copy_len;
+        sector++;
+        offset += copy_len;
+    };
+
+    return 0;
+}
+
+static int mtk_nfc_deal_oob_parity(struct mtk_nand_chip *nand, u8 *buf,
+                                   u32 offset, u32 len, bool fill_oob)
+{
+    struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
+    struct mtk_nfc_fdm *fdm = &chip->fdm;
+    u32 copy_len, done = 0, sector;
+    u32 parity_size = chip->spare_per_sector - fdm->reg_size;
+    u8 *to, *from;
+
+    sector = offset / parity_size;
+    while (len) {
+        offset %= parity_size;
+        copy_len = MIN(len, parity_size - offset);
+        if (fill_oob) {
+            to = oob_parity_ptr(nand, sector) + offset;
+            from = buf + done;
+        } else {
+            to = buf + done;
+            from = oob_parity_ptr(nand, sector) + offset;
+        }
+        memcpy(to, from, copy_len);
+        done += copy_len;
+        len -= copy_len;
+        sector++;
+        offset += copy_len;
+    };
+
+    return 0;
+}
+
+static int mtk_nfc_transfer_oob_ecc(struct mtk_nand_chip *nand, u8 *buf,
+                                    u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_ecc(nand, buf, offset, len, false);
+}
+
+static int mtk_nfc_transfer_oob_raw(struct mtk_nand_chip *nand, u8 *buf,
+                                    u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_raw(nand, buf, offset, len, false);
+}
+
+static int mtk_nfc_transfer_oob_parity(struct mtk_nand_chip *nand, u8 *buf,
+                                       u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_parity(nand, buf, offset, len, false);
+}
+
+static int mtk_nfc_fill_oob_ecc(struct mtk_nand_chip *nand, u8 *buf,
+                                u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_ecc(nand, buf, offset, len, true);
+}
+
+static int mtk_nfc_fill_oob_raw(struct mtk_nand_chip *nand, u8 *buf,
+                                u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_raw(nand, buf, offset, len, true);
+}
+
+static int mtk_nfc_fill_oob_parity(struct mtk_nand_chip *nand, u8 *buf,
+                                   u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_parity(nand, buf, offset, len, true);
+}
+
+static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
+                                     struct mtk_nand_chip *nand)
+{
+    if (nand->pagesize == 512) {
+        bm_ctl->bm_swap = mtk_nfc_no_bad_mark_swap;
+    } else {
+        bm_ctl->bm_swap = mtk_nfc_bad_mark_swap;
+        bm_ctl->sec = nand->pagesize / mtk_data_len(nand);
+        bm_ctl->pos = nand->pagesize % mtk_data_len(nand);
+    }
+
+    return;
+}
+
+static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtk_nand_chip *nand)
+{
+    u32 spare[] = {16, 26, 27, 28, 32, 36, 40, 44,
+                   48, 49, 50, 51, 52, 62, 63, 64
+                  };
+    u32 eccsteps, i;
+
+    eccsteps = nand->pagesize / nand->ecc_size;
+    *sps = nand->oobsize / eccsteps;
+
+    if (nand->ecc_size == 1024)
+        *sps >>= 1;
+
+    for (i = 0; i < sizeof(spare) / sizeof(u32); i++) {
+        if (*sps <= spare[i]) {
+            if (*sps == spare[i])
+                *sps = spare[i];
+            else if (i != 0)
+                *sps = spare[i - 1];
+            break;
+        }
+    }
+
+    if (i >= sizeof(spare) / sizeof(u32))
+        *sps = spare[sizeof(spare) / sizeof(u32) - 1];
+
+    if (nand->ecc_size == 1024)
+        *sps <<= 1;
+
+    return;
+}
+
+int mtk_nfc_nand_chip_init(struct mtk_nand_chip **ext_nand)
+{
+    struct mtk_nfc *nfc;
+    struct mtk_nfc_nand_chip *chip;
+    struct mtk_nand_chip *nand;
+    int ret = 0;
+
+    nfc = (struct mtk_nfc *)malloc(sizeof(*nfc));
+    if (!nfc)
+        return -ENOMEM;
+    memset(nfc, 0, sizeof(*nfc));
+    nfc->regs = NFI_BASE;
+
+    chip = (struct mtk_nfc_nand_chip *)malloc(sizeof(*chip));
+    if (!chip) {
+        goto free_nfc;
+        ret = -ENOMEM;
+    }
+    memset(chip, 0, sizeof(*chip));
+
+    /* register interrupt handler */
+    mtk_nfc_request_irq(nfc);
+
+    nand = &chip->chip;
+    *ext_nand = nand;
+
+    nand_set_controller_data(nand, nfc);
+
+    nand->dev_ready = mtk_nfc_dev_ready;
+    nand->wait_busy_irq = mtk_nfc_wait_busy_irq;
+    nand->select_chip = mtk_nfc_select_chip;
+    nand->write_byte = mtk_nfc_write_byte;
+    nand->write_buf = mtk_nfc_write_buf;
+    nand->read_byte = mtk_nfc_read_byte;
+    nand->read_buf = mtk_nfc_read_buf;
+    nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
+
+    nand->write_page_ecc_dma_irq = mtk_nfc_write_page_ecc_dma_irq;
+    nand->write_page_ecc_dma_polling = mtk_nfc_write_page_ecc_dma_polling;
+    nand->write_page_ecc_pio_irq = mtk_nfc_write_page_ecc_pio_irq;
+    nand->write_page_ecc_pio_polling = mtk_nfc_write_page_ecc_pio_polling;
+    nand->write_page_raw_dma_irq = mtk_nfc_write_page_raw_dma_irq;
+    nand->write_page_raw_dma_polling = mtk_nfc_write_page_raw_dma_polling;
+    nand->write_page_raw_pio_irq = mtk_nfc_write_page_raw_pio_irq;
+    nand->write_page_raw_pio_polling = mtk_nfc_write_page_raw_pio_polling;
+    nand->write_subpage_ecc_dma_irq = mtk_nfc_write_subpage_ecc_dma_irq;
+    nand->write_subpage_ecc_dma_polling = mtk_nfc_write_subpage_ecc_dma_polling;
+    nand->write_subpage_ecc_pio_irq = mtk_nfc_write_subpage_ecc_pio_irq;
+    nand->write_subpage_ecc_pio_polling = mtk_nfc_write_subpage_ecc_pio_polling;
+
+    nand->read_subpage_ecc_dma_irq = mtk_nfc_read_subpage_ecc_dma_irq;
+    nand->read_subpage_ecc_dma_polling = mtk_nfc_read_subpage_ecc_dma_polling;
+    nand->read_subpage_ecc_pio_irq = mtk_nfc_read_subpage_ecc_pio_irq;
+    nand->read_subpage_ecc_pio_polling = mtk_nfc_read_subpage_ecc_pio_polling;
+    nand->read_page_ecc_dma_irq = mtk_nfc_read_page_ecc_dma_irq;
+    nand->read_page_ecc_dma_polling = mtk_nfc_read_page_ecc_dma_polling;
+    nand->read_page_ecc_pio_irq = mtk_nfc_read_page_ecc_pio_irq;
+    nand->read_page_ecc_pio_polling = mtk_nfc_read_page_ecc_pio_polling;
+    nand->read_page_raw_dma_irq = mtk_nfc_read_page_raw_dma_irq;
+    nand->read_page_raw_dma_polling = mtk_nfc_read_page_raw_dma_polling;
+    nand->read_page_raw_pio_irq = mtk_nfc_read_page_raw_pio_irq;
+    nand->read_page_raw_pio_polling = mtk_nfc_read_page_raw_pio_polling;
+
+    nand->enable_randomizer = mtk_nfc_randomizer_enable;
+    nand->disable_randomizer = mtk_nfc_randomizer_disable;
+
+    nand->fill_oob_ecc = mtk_nfc_fill_oob_ecc;
+    nand->fill_oob_raw = mtk_nfc_fill_oob_raw;
+    nand->fill_oob_parity = mtk_nfc_fill_oob_parity;
+    nand->transfer_oob_ecc = mtk_nfc_transfer_oob_ecc;
+    nand->transfer_oob_raw = mtk_nfc_transfer_oob_raw;
+    nand->transfer_oob_parity = mtk_nfc_transfer_oob_parity;
+
+    /* default acc timing */
+    chip->acctiming = 0x10404011;
+    mtk_nfc_gpio_init();
+    mtk_nfc_randomizer_init(nand);
+    mtk_nfc_hw_init(nand);
+
+    ret = mtk_ecc_hw_init(&nfc->ecc);
+    if (ret)
+        goto free_chip;
+
+    ret = mtk_nand_scan(nand, 1 /*MTK_NAND_MAX_NSELS*/);
+    if (ret)
+        goto free_ecc;
+
+    mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, nand);
+    mtk_nfc_set_fdm(&chip->fdm, nand);
+    mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, nand);
+
+    nfc->buffer = (u8 *)memalign(16, nand->pagesize + nand->oobsize);
+    if (!nfc->buffer) {
+        ret = -ENOMEM;
+        goto free_databuf;
+    }
+
+    mutex_init(&nfc->lock);
+
+    ret = mtk_nand_scan_tail(nand);
+    if (ret)
+        goto free_buffer;
+
+    LTRACEF("nand chip init done\n");
+    return 0;
+
+free_buffer:
+    free(nfc->buffer);
+free_databuf:
+    free(nand->databuf);
+free_ecc:
+    free(nfc->ecc);
+free_chip:
+    free(chip);
+free_nfc:
+    free(nfc);
+
+    return ret;
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/rules.mk b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/rules.mk
new file mode 100644
index 0000000..161e76c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/nand/rules.mk
@@ -0,0 +1,18 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/mtk_ecc_hal.c \
+    $(LOCAL_DIR)/mtk_nfi_hal.c \
+    $(LOCAL_DIR)/mtk_nand_bbt.c \
+    $(LOCAL_DIR)/mtk_nand_device.c \
+    $(LOCAL_DIR)/mtk_nand_nal.c \
+    $(LOCAL_DIR)/mtk_nand_nftl.c \
+    $(LOCAL_DIR)/mtk_nand_test.c \
+
+MODULE_DEPS += \
+    lib/bio \
+    lib/nftl \
+    lib/partition \
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/nor/mtk_nor.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/nor/mtk_nor.c
new file mode 100644
index 0000000..f81c87c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/nor/mtk_nor.c
@@ -0,0 +1,800 @@
+/*
+ * 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 <arch/ops.h>
+#include <errno.h>
+#include <kernel/vm.h>
+#include <lib/bio.h>
+#include <lib/partition.h>
+#include <kernel/event.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mtk_nor.h>
+#include <platform/interrupts.h>
+#include <string.h>
+#include <sys/types.h>
+#include <platform/mt_irq.h>
+#include <reg.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+/* nor register offset */
+#define SFLASH_MEM_BASE         ((u32)0x30000000)//mmu on
+#define SFLASH_CMD_REG          ((u32)0x00)
+#define SFLASH_CNT_REG          ((u32)0x04)
+#define SFLASH_RDSR_REG         ((u32)0x08)
+#define SFLASH_RDATA_REG        ((u32)0x0C)
+#define SFLASH_RADR0_REG        ((u32)0x10)
+#define SFLASH_RADR1_REG        ((u32)0x14)
+#define SFLASH_RADR2_REG        ((u32)0x18)
+#define SFLASH_WDATA_REG        ((u32)0x1C)
+#define SFLASH_PRGDATA0_REG     ((u32)0x20)
+#define SFLASH_PRGDATA1_REG     ((u32)0x24)
+#define SFLASH_PRGDATA2_REG     ((u32)0x28)
+#define SFLASH_PRGDATA3_REG     ((u32)0x2C)
+#define SFLASH_PRGDATA4_REG     ((u32)0x30)
+#define SFLASH_PRGDATA5_REG     ((u32)0x34)
+#define SFLASH_SHREG0_REG       ((u32)0x38)
+#define SFLASH_SHREG1_REG       ((u32)0x3C)
+#define SFLASH_SHREG2_REG       ((u32)0x40)
+#define SFLASH_SHREG3_REG       ((u32)0x44)
+#define SFLASH_SHREG4_REG       ((u32)0x48)
+#define SFLASH_SHREG5_REG       ((u32)0x4C)
+#define SFLASH_SHREG6_REG       ((u32)0x50)
+#define SFLASH_SHREG7_REG       ((u32)0x54)
+#define SFLASH_SHREG8_REG       ((u32)0x58)
+#define SFLASH_SHREG9_REG       ((u32)0x5C)
+#define SFLASH_FLHCFG_REG       ((u32)0x84)
+#define SFLASH_PP_DATA_REG      ((u32)0x98)
+#define SFLASH_PREBUF_STUS_REG  ((u32)0x9C)
+#define SFLASH_SF_INTRSTUS_REG  ((u32)0xA8)
+#define SFLASH_SF_INTREN_REG    ((u32)0xAC)
+#define SFLASH_SF_TIME_REG      ((u32)0x94)
+#define SFLASH_CHKSUM_CTL_REG   ((u32)0xB8)
+#define SFLASH_CHECKSUM_REG     ((u32)0xBC)
+#define SFLASH_CMD2_REG         ((u32)0xC0)
+#define SFLASH_WRPROT_REG       ((u32)0xC4)
+#define SFLASH_RADR3_REG        ((u32)0xC8)
+#define SFLASH_READ_DUAL_REG    ((u32)0xCC)
+#define SFLASH_DELSEL0_REG      ((u32)0xA0)
+#define SFLASH_DELSEL1_REG      ((u32)0xA4)
+#define SFLASH_DELSEL2_REG      ((u32)0xD0)
+#define SFLASH_DELSEL3_REG      ((u32)0xD4)
+#define SFLASH_DELSEL4_REG      ((u32)0xD8)
+
+#define SFLASH_CFG1_REG         ((u32)0x60)
+#define SFLASH_CFG2_REG         ((u32)0x64)
+#define SFLASH_CFG3_REG         ((u32)0x68)
+#define SFLASH_STATUS0_REG      ((u32)0x70)
+#define SFLASH_STATUS1_REG      ((u32)0x74)
+#define SFLASH_STATUS2_REG      ((u32)0x78)
+#define SFLASH_STATUS3_REG      ((u32)0x7C)
+
+#define SFLASH_WRBUF_SIZE           128
+#define SFLASH_POLLINGREG_COUNT     500000
+#define SFLASH_WRITEBUSY_TIMEOUT    500000
+#define SFLASH_ERASESECTOR_TIMEOUT  500000
+#define SFLASH_HW_ALIGNMENT         4
+
+/* nor register read/write */
+#define IO_READ32(base, offset)           readl(base + offset)
+#define IO_WRITE32(offset, value)         writel(value, offset)
+
+#define SFLASH_WREG8(offset, value)       writeb(value, NOR_BASE + offset)
+#define SFLASH_RREG8(offset)              readb(NOR_BASE + offset)
+#define SFLASH_WREG32(offset, value)      writel(value, NOR_BASE + offset)
+#define SFLASH_RREG32(offset)             readl(NOR_BASE + offset)
+
+#define SFLASH_DMA_REG_BASE         (NOR_BASE + 0x718)
+#define SFLASH_DMA_WREG32(offset, value) \
+    (*(volatile unsigned int *)(SFLASH_DMA_REG_BASE + offset)) = (value)
+#define SFLASH_DMA_RREG32(offset) \
+    (*(volatile unsigned int *)(SFLASH_DMA_REG_BASE + offset))
+#define SFLASH_DMA_ALIGN    0x10U
+
+#define LoWord(d)     ((uint16_t)(d & 0x0000ffffL))
+#define HiWord(d)     ((uint16_t)((d >> 16) & 0x0000ffffL))
+#define LoByte(w)     ((uint8_t)(w & 0x00ff))
+#define HiByte(w)     ((uint8_t)((w >> 8) & 0x00ff))
+
+#define NOR_TEST      0
+#define CMD_4KB       0x20
+#define CMD_64KB      0xD8
+#define BLK_SIZE      512
+
+typedef struct {
+    u8   u1MenuID;
+    u8   u1DevID1;
+    u8   u1DevID2;
+    u32  u4ChipSize;
+    u32  u4SecSize;
+    u8   u1WRENCmd;
+} SFLASHHW_VENDOR_T;
+
+static SFLASHHW_VENDOR_T *flash_desc;
+static SFLASHHW_VENDOR_T vendor_desc[] = {
+    {0x20, 0xBA, 0x19, 0x02000000, 0x10000, 0x06}, /* ST(M25Q256) */
+    {0xC2, 0x20, 0x13, 0x00080000, 0x10000, 0x06}, /* MXIC(25L400) */
+    {0xC2, 0x20, 0x14, 0x00100000, 0x10000, 0x06}, /* MXIC(25L80) */
+    {0xC2, 0x20, 0x15, 0x00200000, 0x10000, 0x06}, /* MXIC(25L160) */
+    {0xC2, 0x24, 0x15, 0x00200000, 0x10000, 0x06}, /* MXIC(25L1635D) */
+    {0xC2, 0x20, 0x16, 0x00400000, 0x10000, 0x06}, /* MXIC(25L320) */
+    {0xC2, 0x20, 0x17, 0x00800000, 0x10000, 0x06}, /* MXIC(25L640) */
+    {0xC2, 0x20, 0x18, 0x01000000, 0x10000, 0x06}, /* MXIC(25L1280) */
+    {0xC2, 0x5E, 0x16, 0x00400000, 0x10000, 0x06}, /* MXIC(25L3235D) */
+    {0xC2, 0x20, 0x19, 0x02000000, 0x10000, 0x06}, /* MXIC(25L256) */
+    {0xC2, 0x20, 0x1A, 0x02000000, 0x10000, 0x06}, /* MXIC(25L512) */
+    {0xC2, 0x25, 0x39, 0x02000000, 0x10000, 0x06}, /* MXIC(25U256) */
+    {0xEF, 0x30, 0x13, 0x00080000, 0x10000, 0x06}, /* WINBOND(W25X40) */
+    {0xEF, 0x30, 0x14, 0x00100000, 0x10000, 0x06}, /* WINBOND(W25X80) */
+    {0xEF, 0x30, 0x15, 0x00200000, 0x10000, 0x06}, /* WINBOND(W25X16) */
+    {0xEF, 0x30, 0x16, 0x00400000, 0x10000, 0x06}, /* WINBOND(W25X32) */
+    {0xEF, 0x60, 0x16, 0x00400000, 0x10000, 0x06}, /* WINBOND(W25X32) */
+    {0xEF, 0x30, 0x17, 0x00800000, 0x10000, 0x06}, /* WINBOND(W25X64) */
+    {0xEF, 0x40, 0x19, 0x02000000, 0x10000, 0x06}, /* WINBOND(W25Q256FV) */
+    {0xEF, 0x40, 0x15, 0x00200000, 0x10000, 0x06}, /* WINBOND(W25Q16CV) */
+    {0xEF, 0x40, 0x16, 0x00400000, 0x10000, 0x06}, /* WINBOND(W25Q32BV) */
+    {0xEF, 0x40, 0x17, 0x00800000, 0x10000, 0x06}, /* WINBOND(W25Q64BV) */
+    {0xEF, 0x40, 0x18, 0x01000000, 0x10000, 0x06}, /* WINBOND(W25Q128BV) */
+    {0x00, 0x00, 0x00, 0x00000000, 0x00000, 0x00}, /* NULL Device */
+};
+static event_t nor_int_event;
+
+static void SF_NOR_GPIO_INIT(void)
+{
+    /* use pinmux default state. */
+}
+
+static int _PollingReg(u8 u1RegOffset, u8 u8Compare)
+{
+    u32 u4Polling;
+    u8 u1Reg;
+
+    u4Polling = 0;
+    while (1) {
+        u1Reg = SFLASH_RREG8(u1RegOffset);
+        if (0x00 == (u1Reg & u8Compare))
+            break;
+
+        u4Polling++;
+        if (u4Polling > SFLASH_POLLINGREG_COUNT)
+            return 1;
+    }
+    return 0;
+}
+
+static int SFLASH_UnLock(void)
+{
+    SFLASH_WREG32(SFLASH_WRPROT_REG, 0x30);
+    return SFLASH_RREG32(SFLASH_WRPROT_REG);
+}
+
+static inline void _SendFlashCommand(u8 u1Val)
+{
+    SFLASH_WREG8(SFLASH_CMD_REG, u1Val);
+}
+
+static int _SetFlashWriteEnable(void)
+{
+    SFLASH_WREG8(SFLASH_PRGDATA5_REG, flash_desc->u1WRENCmd);
+    SFLASH_WREG8(SFLASH_CNT_REG,8);
+
+    _SendFlashCommand(0x4);
+
+    return _PollingReg(SFLASH_CMD_REG, 0x04);
+}
+
+static int SFLASHHW_ReadFlashStatus(u8 *pu1Val)
+{
+    if (pu1Val == NULL)
+        return 1;
+
+    _SendFlashCommand(0x2);
+
+    if (_PollingReg(SFLASH_CMD_REG, 0x2) != 0)
+        return 1;
+
+    *pu1Val = SFLASH_RREG8(SFLASH_RDSR_REG);
+    return 0;
+}
+
+static int _WaitForWriteBusy(u32 u4Timeout)
+{
+    u32 u4Count;
+    u8 u1Reg;
+
+    u4Count = 0;
+    while (1) {
+        if (SFLASHHW_ReadFlashStatus(&u1Reg) != 0)
+            return 1;
+
+        if (0 == (u1Reg & 0x1))
+            break;
+
+        u4Count++;
+        if (u4Count > u4Timeout)
+            return 1;
+    }
+    return 0;
+}
+
+static int _WBEnable(void)
+{
+    u32 u4Polling;
+    u8 u1Reg;
+    u8 u1Tmp = 0x01;
+
+    SFLASH_WREG8(SFLASH_CFG2_REG, u1Tmp);
+
+    u4Polling = 0;
+    while (1) {
+        u1Reg = SFLASH_RREG8(SFLASH_CFG2_REG);
+        if (0x01 == (u1Reg & 0x1))
+            break;
+
+        u4Polling++;
+        if (u4Polling > SFLASH_POLLINGREG_COUNT)
+            return 1;
+    }
+    return 0;
+}
+
+static int _WBDisable(void)
+{
+    u32 u4Polling;
+    u8 u1Reg;
+    u8 u1Tmp = 0x00;
+
+    SFLASH_WREG8(SFLASH_CFG2_REG, u1Tmp);
+    u4Polling = 0;
+    while (1) {
+        u1Reg = SFLASH_RREG8(SFLASH_CFG2_REG);
+        if (u1Tmp == (u1Reg & 0xF))
+            break;
+
+        u4Polling++;
+        if (u4Polling > SFLASH_POLLINGREG_COUNT)
+            return 1;
+    }
+    return 0;
+}
+
+static int _ExecuteWriteCmd(void)
+{
+    u8 u1Reg;
+
+    _SendFlashCommand(0x10);
+    while (1) {
+        u1Reg = SFLASH_RREG8(SFLASH_CMD_REG);
+        if (0x0 == (u1Reg & 0x10))
+            break;
+    }
+    return 0;
+}
+
+static int SFLASHHW_WriteProtect(bool fgEnable)
+{
+    if (_WaitForWriteBusy(SFLASH_WRITEBUSY_TIMEOUT) != 0)
+        return -1;
+
+    if (_SetFlashWriteEnable() != 0)
+        return -1;
+    if (fgEnable)
+        SFLASH_WREG8(SFLASH_PRGDATA5_REG, 0x0);
+    else
+        SFLASH_WREG32(SFLASH_PRGDATA5_REG, 0x0);
+
+    SFLASH_WREG8(SFLASH_CNT_REG,8);
+    _SendFlashCommand(0x20);
+
+    if (_PollingReg(SFLASH_CMD_REG, 0x20) != 0)
+        return -1;
+    return _WaitForWriteBusy(SFLASH_WRITEBUSY_TIMEOUT);
+}
+
+static int enter_4byte(void)
+{
+    u8 val;
+
+    if (_SetFlashWriteEnable() != 0) {
+        LTRACEF("_SetFlashWriteEnable fail!\n");
+        return 1;
+    }
+
+    SFLASH_WREG8(SFLASH_PRGDATA5_REG, 0xb7);
+    SFLASH_WREG8(SFLASH_CNT_REG, 8);
+    _SendFlashCommand(0x4);
+    if (_PollingReg(SFLASH_CMD_REG, 0x4) != 0)
+        return -1;
+
+    if (_WaitForWriteBusy(SFLASH_WRITEBUSY_TIMEOUT))
+        return -1;
+
+    val = SFLASH_RREG8(SFLASH_READ_DUAL_REG);
+    SFLASH_WREG8(SFLASH_READ_DUAL_REG, val | 0x10);
+
+    return 0;
+}
+
+static int SFLASHHW_GetID(u8 *pu1MenuID, u8 *pu1DevID1, u8 *pu1DevID2)
+{
+    SFLASH_WREG8(SFLASH_PRGDATA5_REG, 0x9F);
+    SFLASH_WREG8(SFLASH_PRGDATA4_REG, 0x00);
+    SFLASH_WREG8(SFLASH_PRGDATA3_REG, 0x00);
+    SFLASH_WREG8(SFLASH_PRGDATA2_REG, 0x00);
+    SFLASH_WREG8(SFLASH_CNT_REG, 32);
+
+    _SendFlashCommand(0x4);
+
+    if ( _PollingReg(SFLASH_CMD_REG, 0x04) !=0)
+        return 1;
+
+    *pu1DevID2 = SFLASH_RREG8(SFLASH_SHREG0_REG);
+    *pu1DevID1 = SFLASH_RREG8(SFLASH_SHREG1_REG);
+    *pu1MenuID = SFLASH_RREG8(SFLASH_SHREG2_REG);
+
+    _SendFlashCommand(0x0);
+    if ((pu1MenuID != NULL) && (pu1DevID1 != NULL)) {
+        if ((*pu1MenuID == 0xFF) || (*pu1DevID1 == 0x00))
+            return 1;
+    }
+    return 0;
+}
+
+static int _DoIdentify(u32 *pu4Vendor)
+{
+    u32 i;
+    u8 menuID, devID1, devID2;
+
+    if (pu4Vendor == NULL)
+        return 1;
+    *pu4Vendor = 0xFFFFFFFF;
+    if (SFLASHHW_GetID(&menuID, &devID1, &devID2) != 0)
+        return 1;
+
+    dprintf(CRITICAL,"MenuID: 0x%X, DeviceID1: 0x%X, DeviceID2: 0x%X\n",
+            menuID, devID1, devID2);
+    i = 0;
+
+    while (vendor_desc[i].u1MenuID != (u8)0x0) {
+        if ( (vendor_desc[i].u1MenuID == menuID) &&
+                (vendor_desc[i].u1DevID1 == devID1) &&
+                (vendor_desc[i].u1DevID2 == devID2)) {
+            *pu4Vendor = i;
+            flash_desc = &vendor_desc[i];
+            return 0;
+        }
+        i++;
+    }
+    return 1;
+}
+
+static int SFLASHHW_Init(void)
+{
+    u32 u4VendorIdx;
+    u32 _u4ChipCount = 0;
+
+    SFLASH_WREG32(SFLASH_WRPROT_REG, 0x30);
+    SF_NOR_GPIO_INIT();
+
+    if (_DoIdentify(&u4VendorIdx) != 0)
+        return 1;
+
+    dprintf(CRITICAL, "Detect flash #%d\n", u4VendorIdx);
+    _u4ChipCount++;
+
+    if (_u4ChipCount == 0) {
+        dprintf(CRITICAL, "There is no flash!\n");
+        return 1;
+    }
+
+    SFLASH_WREG8(SFLASH_READ_DUAL_REG, 0);
+    /* Clear interrupts */
+    SFLASH_WREG8(SFLASH_SF_INTREN_REG, 0x0);
+    SFLASH_WREG8(SFLASH_SF_INTRSTUS_REG, 0xff);
+
+    /* chipsize > 16MB, enter 4Byte address mode. */
+    if (flash_desc->u4ChipSize > 0x1000000) {
+        if (enter_4byte())
+            return 1;
+    }
+
+    return 0;
+}
+
+static enum handler_return nor_interrupt_handler(void *arg)
+{
+    /* Clear event bits */
+    SFLASH_WREG8(SFLASH_SF_INTREN_REG, 0x0);
+    SFLASH_WREG8(SFLASH_SF_INTRSTUS_REG, SFLASH_RREG8(SFLASH_SF_INTRSTUS_REG));
+    /* MUST BE *false*! otherwise, schedule in intr routine */
+    event_signal(&nor_int_event, false);
+
+    return INT_RESCHEDULE;
+}
+
+static int NOR_Init(void)
+{
+    SFLASH_UnLock();
+    if (SFLASHHW_Init() != 0)
+        return -1;
+
+    /* Register msdc irq */
+    mt_irq_set_sens(MT_NOR_IRQ_ID, LEVEL_SENSITIVE);
+    mt_irq_set_polarity(MT_NOR_IRQ_ID, MT65xx_POLARITY_LOW);
+    event_init(&nor_int_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+    register_int_handler(MT_NOR_IRQ_ID, nor_interrupt_handler, NULL);
+    unmask_interrupt(MT_NOR_IRQ_ID);
+
+    return 0;
+}
+
+static int _WriteBuffer(u32 u4Addr, u32 u4Len, const u8 *pu1Buf)
+{
+    u32 i, j, u4BufIdx, u4Data;
+
+    if (pu1Buf == NULL)
+        return 1;
+
+    ASSERT(u4Len <= SFLASH_WRBUF_SIZE);
+    ASSERT((u4Addr%SFLASH_HW_ALIGNMENT) == 0);
+    ASSERT((u4Len%SFLASH_HW_ALIGNMENT) == 0);
+
+    SFLASH_WREG8(SFLASH_RADR3_REG, HiByte(HiWord(u4Addr)));
+    SFLASH_WREG8(SFLASH_RADR2_REG, LoByte(HiWord(u4Addr)));
+    SFLASH_WREG8(SFLASH_RADR1_REG, HiByte(LoWord(u4Addr)));
+    SFLASH_WREG8(SFLASH_RADR0_REG, LoByte(LoWord(u4Addr)));
+
+    u4BufIdx = 0;
+    for (i=0; i<u4Len; i+=4) {
+        for (j=0; j<4; j++) {
+            (*((u8 *)&u4Data + j)) = pu1Buf[u4BufIdx];
+            u4BufIdx++;
+        }
+        SFLASH_WREG32(SFLASH_PP_DATA_REG, u4Data);
+    }
+
+    if (_ExecuteWriteCmd() != 0)
+        return 1;
+
+    if (_WaitForWriteBusy(SFLASH_WRITEBUSY_TIMEOUT) != 0)
+        return 1;
+    return 0;
+}
+
+static int SFLASHHW_WriteSector(u32 u4Addr, u32 u4Len, const u8 *pu1Buf)
+{
+    u32 u4Count;
+
+    if (_SetFlashWriteEnable() != 0)
+        return -EIO;
+
+    if (_WBEnable() != 0)
+        return -EIO;
+
+    while ((int)u4Len > 0) {
+        if (u4Len >= SFLASH_WRBUF_SIZE)
+            u4Count = SFLASH_WRBUF_SIZE;
+        else
+            break;
+
+        if (_WriteBuffer(u4Addr, u4Count, pu1Buf) != 0) {
+            dprintf(CRITICAL, "Write err! addr: 0x%x\n", u4Addr);
+            if (_WBDisable() != 0)
+                return -EIO;
+            return -EIO;
+        }
+        u4Len -= u4Count;
+        u4Addr += u4Count;
+        pu1Buf += u4Count;
+    }
+    if (_WBDisable() != 0)
+        return -EIO;
+
+    return 0;
+}
+
+static ssize_t dma_read(uint32_t u4SrcAddr, unsigned long u4DestAddr, uint32_t u4Size)
+{
+    int ret;
+    uint32_t dmaAddr;
+
+#if WITH_KERNEL_VM
+    dmaAddr = (uint32_t)kvaddr_to_paddr((void *)u4DestAddr);
+#else
+    dmaAddr = (uint32_t)u4DestAddr;
+#endif
+
+    arch_clean_invalidate_cache_range(u4DestAddr, u4Size);
+
+    SFLASH_WREG8(SFLASH_SF_INTREN_REG, 0x80);
+    SFLASH_WREG8(SFLASH_SF_INTRSTUS_REG, 0xff);
+
+    /* Do reset */
+    SFLASH_DMA_WREG32(0x0, 0x0);
+    SFLASH_DMA_WREG32(0x0, 0x2);
+    SFLASH_DMA_WREG32(0x0, 0x4);
+
+    /* Flash source address and DRAM destination address */
+    SFLASH_DMA_WREG32(0x4, u4SrcAddr);
+    SFLASH_DMA_WREG32(0x8, dmaAddr);
+    SFLASH_DMA_WREG32(0xC, dmaAddr + u4Size);
+
+    /* Trigger DMA */
+    SFLASH_DMA_WREG32(0x0, 0x5);
+
+    /* Wait for interrupt */
+    ret = event_wait_timeout(&nor_int_event, 10000);
+    if (ret != 0) {
+        dprintf(CRITICAL, "%s -> wait interrupt timeout\n", __func__);
+        /* Clear IntrEn */
+        SFLASH_WREG8(SFLASH_SF_INTREN_REG, 0x0);
+        return ret;
+    }
+
+    return u4Size;
+}
+
+static int SFLASHHW_EraseSector(u32 u4Addr, u32 command)
+{
+    u32 u4Polling;
+    u8 u1Reg;
+
+    if (SFLASHHW_WriteProtect(false) != 0) {
+        LTRACEF("Disable Flash write protect fail!\n");
+        return -1;
+    }
+    if (_WaitForWriteBusy(SFLASH_WRITEBUSY_TIMEOUT) != 0) {
+        return 1;
+        LTRACEF("_WaitForWriteBusy fail!\n");
+    }
+
+    if (_SetFlashWriteEnable() != 0) {
+        LTRACEF("_SetFlashWriteEnable fail!\n");
+        return 1;
+    }
+    /* Execute sector erase command */
+    SFLASH_WREG8(SFLASH_PRGDATA5_REG, command);
+    if (SFLASH_RREG8(SFLASH_READ_DUAL_REG) & 0x10) {
+        SFLASH_WREG8(SFLASH_PRGDATA4_REG, HiByte(HiWord(u4Addr)));
+        SFLASH_WREG8(SFLASH_PRGDATA3_REG, LoByte(HiWord(u4Addr)));
+        SFLASH_WREG8(SFLASH_PRGDATA2_REG, HiByte(LoWord(u4Addr)));
+        SFLASH_WREG8(SFLASH_PRGDATA1_REG, LoByte(LoWord(u4Addr)));
+        SFLASH_WREG8(SFLASH_CNT_REG, 40);
+    } else {
+        SFLASH_WREG8(SFLASH_PRGDATA4_REG, LoByte(HiWord(u4Addr)));
+        SFLASH_WREG8(SFLASH_PRGDATA3_REG, HiByte(LoWord(u4Addr)));
+        SFLASH_WREG8(SFLASH_PRGDATA2_REG, LoByte(LoWord(u4Addr)));
+        SFLASH_WREG8(SFLASH_CNT_REG, 32);
+    }
+
+    _SendFlashCommand(0x4);
+    u4Polling = 0;
+    while (1) {
+        if (SFLASHHW_ReadFlashStatus(&u1Reg) != 0) {
+            LTRACEF("SFLASHHW_ReadFlashStatus fail!\n");
+            return 1;
+        }
+
+        if (0 == (u1Reg & 0x1))
+            break;
+
+        u4Polling++;
+        if (u4Polling > SFLASH_ERASESECTOR_TIMEOUT) {
+            LTRACEF("SFLASH_ERASESECTOR_TIMEOUT timeout!\n");
+            return 1;
+        }
+    }
+    if (SFLASHHW_WriteProtect(true) != 0) {
+        LTRACEF("Disable Flash write protect fail!\n");
+        return -1;
+    }
+    return 0;
+}
+
+static ssize_t nor_erase(struct bdev *bdev, off_t offset, size_t len)
+{
+    u32 i = 0;
+    u32 block_number = 0;
+    u32 addr = (u32)offset;
+    u32 block_size = 0;
+    u32 command = 0;
+
+    LTRACEF("addr %d, blksz %u\n", addr, flash_desc->u4SecSize);
+    if (!addr || addr > flash_desc->u4SecSize) {
+        block_size = flash_desc->u4SecSize;
+        command = CMD_64KB;
+    } else {
+        block_size = 4*1024;
+        command = CMD_4KB;
+    }
+
+    LTRACEF("nor erase block size %d\n", block_size);
+    if ((len % bdev->block_size) != 0) {
+        dprintf(ALWAYS,"nor erase fail: length must align block size!\n");
+        return -1;
+    }
+
+    block_number = len / block_size;
+    for (i = 0; i < block_number; i++) {
+        LTRACEF("erase offset from %d to %d\n", addr + i * block_size,
+                addr + (i + 1) * block_size);
+        if (SFLASHHW_EraseSector(addr + i * block_size, command))
+            return -1;
+    }
+
+    /* erase redundant block */
+    LTRACEF("erase redundant from %lu to %lu\n", addr + len - block_size,
+            addr + len);
+    if (SFLASHHW_EraseSector(addr + len - block_size, command))
+        return -1;
+
+    return len;
+}
+
+static ssize_t nor_read_block(struct bdev *bdev, void *buf, bnum_t blknr, uint blks)
+{
+    u32 offset, len;
+
+    if (((unsigned long)buf & (SFLASH_DMA_ALIGN - 1))!=0) {
+        dprintf(ALWAYS, "Address or size is not 16-byte alignment!\n");
+        return -EINVAL;
+    }
+
+    offset = blknr * bdev->block_size;
+    len = (u32)blks * bdev->block_size;
+
+    return dma_read(offset, (unsigned long)buf, len);
+}
+
+static ssize_t nor_write_block(struct bdev *bdev, const void *buf, bnum_t blknr, uint blks)
+{
+    int ret;
+    u32 addr, len;
+
+    ret = SFLASHHW_WriteProtect(false);
+    if (ret != 0) {
+        dprintf(CRITICAL, "Disable Flash write protect fail!\n");
+        return -EIO;
+    }
+
+    addr = blknr * bdev->block_size;
+    len = (u32)blks * bdev->block_size;
+
+    LTRACEF("nor write from %d to %d\n", addr, addr + len);
+    ret = SFLASHHW_WriteSector(addr, len, buf);
+    if (ret) {
+        dprintf(CRITICAL, "Write flash error ! (%d)\n", ret);
+        SFLASHHW_WriteProtect(true);
+        return ret;
+    }
+
+    ret = SFLASHHW_WriteProtect(true);
+    if (ret != 0) {
+        dprintf(CRITICAL, "Enable flash write protect fail!\n");
+        return -EIO;
+    }
+
+    return len;
+}
+
+#if NOR_TEST
+#define NOR_WRITE_OFFSET 0x700000
+#define NOR_TEST_SIZE 4096
+static void nor_test(struct bdev *dev)
+{
+    int i, ret, check_flag = 0;
+    u8 *w_buf = malloc(NOR_TEST_SIZE);
+
+    /* erase test */
+    dprintf(ALWAYS, "nor driver ut test START\n");
+    if (!SFLASHHW_EraseSector(NOR_WRITE_OFFSET, CMD_64KB))
+        dprintf(ALWAYS, "nor erase success\n");
+    else
+        dprintf(ALWAYS, "nor erase failed\n");
+
+    spin(100000);
+
+    memset(w_buf, 0x0, NOR_TEST_SIZE);
+    ret = bio_read(dev, (void *)w_buf, (off_t)NOR_WRITE_OFFSET, NOR_TEST_SIZE);
+    if (ret == NOR_TEST_SIZE)
+        dprintf(ALWAYS, "nor read success after erase\n");
+    else
+        dprintf(ALWAYS, "nor read failed after erase with ret: %d @line: %d\n",
+                ret, __LINE__);
+
+    for (i = 0; i < NOR_TEST_SIZE; i++) {
+        if (w_buf[i] != 0xff)
+            check_flag = 1;
+        dprintf(ALWAYS, " 0x%x",w_buf[i]);
+    }
+    LTRACEF("\n");
+    if (check_flag == 1) {
+        dprintf(ALWAYS, "ERROR... data not expected, fail @line: %d\n",
+                __LINE__);
+        check_flag = 0;
+    }
+
+    /* write test */
+    for (i = 0; i < NOR_TEST_SIZE; i++)
+        w_buf[i] = i & 0xFF;
+
+    ret = bio_write(dev, (void *)w_buf, (off_t)NOR_WRITE_OFFSET, NOR_TEST_SIZE);
+    if (ret == NOR_TEST_SIZE)
+        dprintf(ALWAYS, "nor write success\n");
+    else
+        dprintf(ALWAYS, "nor write failed with ret: %d @line: %d\n",
+                ret, __LINE__);
+
+    memset(w_buf, 0x0, NOR_TEST_SIZE);
+    ret = bio_read(dev, (void *)w_buf, (off_t)NOR_WRITE_OFFSET, NOR_TEST_SIZE);
+    if (ret == NOR_TEST_SIZE)
+        dprintf(ALWAYS, "nor read success after write\n");
+    else
+        dprintf(ALWAYS, "nor read failed after write with ret: %d @line: %d\n",
+                ret, __LINE__);
+
+    for (i = 0; i < NOR_TEST_SIZE; i++) {
+        if ((i & 0xFF) != w_buf[i])
+            check_flag =1;
+        dprintf(ALWAYS, " 0x%x", w_buf[i]);
+    }
+    LTRACEF("\n");
+    if (check_flag == 1)
+        dprintf(ALWAYS, "ERROR... data not expected, fail @line: %d\n",
+                __LINE__);
+
+    dprintf(ALWAYS, "nor driver ut test DONE.\n");
+    free(w_buf);
+}
+#endif
+
+void nor_init_device(void)
+{
+    struct bdev *dev;
+
+    if (NOR_Init())
+        ASSERT(0);
+
+    dev = malloc(sizeof(struct bdev));
+    ASSERT(dev);
+    memset(dev, 0, sizeof(struct bdev));
+
+    /* construct the block device */
+    bio_initialize_bdev(dev, "nor0",
+                        BLK_SIZE, flash_desc->u4ChipSize / BLK_SIZE, 0, NULL,
+                        (BIO_FLAG_CACHE_ALIGNED_READS));
+
+    /* override our block device hooks */
+    dev->read_block = nor_read_block;
+    dev->write_block = nor_write_block;
+    dev->erase = nor_erase;
+
+    bio_register_device(dev);
+    partition_publish(dev->name, 0x0);
+
+#if NOR_TEST
+    nor_test(dev);
+#endif
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/pll/pll.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/pll/pll.c
new file mode 100644
index 0000000..3f84517
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/pll/pll.c
@@ -0,0 +1,696 @@
+/*
+ * 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.
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <platform/mtk_devinfo.h>
+#include <platform/pll.h>
+#include <platform/reg_utils.h>
+#include <platform/spm_mtcmos.h>
+
+#define ALL_CLK_ON  1
+#define FMETER_EN   0
+
+#define udelay(x)       spin(x)
+#define mdelay(x)       udelay((x) * 1000)
+
+#define ARRAY_SIZE(a)       (sizeof(a) / sizeof(a[0]))
+
+#if FMETER_EN
+static u32 mt_fmeter_abist(u32 id, u32 arm_k1, u32 abist_k1)
+{
+    int output = 0;
+    int i = 0;
+    u32 temp, clk26cali_0, clk_cfg_m0, clk_misc_cfg_1;
+
+    /* use AD_PLLGP_TST_CK_CKSYS to measure CVBSPLL */
+    if (id == 43) {
+        setbits32(PLL_TEST_CON0, 0x30F); /* [9:8]:TST_SEL, [3:0]:TSTOD_EN, A2DCK_EN, TSTCK_EN, TST_EN */
+        setbits32(CVBSREFPLL_CON1, 0x11); /* [4]:CVBS_MONCK_EN, [3:0]:CVBSREFPLL_TESTMUX */
+        setbits32(CVBSPLL_CON1, 0x20); /* [5]: CVBSPLL_MONCK_EN */
+    }
+
+    clk26cali_0 = readl(CLK26CALI_0);
+    writel_r(CLK26CALI_0, clk26cali_0 | 0x80); /* enable fmeter_en */
+
+    clk_misc_cfg_1 = readl(CLK_MISC_CFG_1);
+    writel_r(CLK_MISC_CFG_1, 0xFFFF0000 | (arm_k1 << 8) | abist_k1);
+    /* select divider */
+
+    clk_cfg_m0 = readl(CLK_CFG_M0);
+    writel_r(CLK_CFG_M0, (id << 8)); /* select abist_cksw */
+
+    setbits32(CLK26CALI_0, 0x1); /* start fmeter */
+
+    /* wait frequency meter finish */
+    while ((readl(CLK26CALI_0) & 0x1) && (++i <= 10))
+        udelay(50);
+
+    temp = readl(CLK26CALI_1) & 0xFFFF;
+
+    output = (temp * 26000) * (abist_k1 + 1) * (arm_k1 + 1) / 1024;
+
+    writel_r(CLK_CFG_M0, clk_cfg_m0);
+    writel_r(CLK_MISC_CFG_1, clk_misc_cfg_1);
+    writel_r(CLK26CALI_0, clk26cali_0);
+
+    if (id == 43) {
+        clrbits32(PLL_TEST_CON0, 0x30F);
+        clrbits32(CVBSREFPLL_CON1, 0x11);
+        clrbits32(CVBSPLL_CON1, 0x20);
+    }
+
+    if (i > 10)
+        return 0;
+    else
+        return output;
+}
+
+static u32 mt_fmeter_ckgen(u32 id, u32 ckgen_k1)
+{
+    int output = 0;
+    int i = 0;
+    u32 temp, clk26cali_0, clk_cfg_m1, clk_misc_cfg_1;
+
+    clk26cali_0 = readl(CLK26CALI_0);
+    writel_r(CLK26CALI_0, clk26cali_0 | 0x80); /* enable fmeter_en */
+
+    clk_misc_cfg_1 = readl(CLK_MISC_CFG_1);
+    writel_r(CLK_MISC_CFG_1, 0x00FFFFFF | ckgen_k1 << 24);
+    /* select divider */
+
+    clk_cfg_m1 = readl(CLK_CFG_M1);
+    writel_r(CLK_CFG_M1, (id << 16)); /* select ckgen_cksw */
+
+    setbits32(CLK26CALI_0, 0x10); /* start fmeter */
+
+    /* wait frequency meter finish */
+    while ((readl(CLK26CALI_0) & 0x10) && (++i <= 10))
+        udelay(50);
+
+    temp = readl(CLK26CALI_2) & 0xFFFF;
+
+    output = (temp * 26000) * (ckgen_k1 + 1) / 1024;
+
+    writel_r(CLK_CFG_M1, clk_cfg_m1);
+    writel_r(CLK_MISC_CFG_1, clk_misc_cfg_1);
+    writel_r(CLK26CALI_0, clk26cali_0);
+
+    if (i > 10)
+        return 0;
+    else
+        return output;
+}
+
+static u32 mt_get_cpu_freq(void)
+{
+    return mt_fmeter_abist(59, 0, 0);
+}
+
+static u32 mt_get_bus_freq(void)
+{
+    return mt_fmeter_ckgen(1, 0);
+}
+
+static const char *abist_clk[] = {
+    //[1] = "AD_MEMPLL2_CKOUT0_PRE_ISO(0)",
+    [2] =   "AD_ARMCA35PLL_600M_CORE_CK",
+    [3] =   "AD_ARMCA35PLL_400M_CORE_CK",
+    [4] =   "AD_MAIN_H546M_CK",
+    [5] =   "AD_MAIN_H364M_CK",
+    [6] =   "AD_MAIN_H218P4M_CK",
+    [7] =   "AD_MAIN_H156M_CK",
+    [8] =   "AD_UNIV_178P3M_CK",
+    [9] =   "AD_UNIVPLL_UNIV_48M_CK",
+    [10] =  "AD_UNIV_624M_CK",
+    [11] =  "AD_UNIV_416M_CK",
+    [12] =  "AD_UNIV_249P6M_CK",
+    [13] =  "AD_APLL1_CK",
+    [14] =  "AD_APLL2_CK",
+    [15] =  "AD_LTEPLL_FS26M_CK",
+    [16] =  "rtc32k_ck_i",
+    [17] =  "AD_MMPLL_500M_CK",
+    [18] =  "AD_VENCPLL_380M_CK",
+    [19] =  "AD_VCODEPLL_442M_CK",
+    [20] =  "AD_TVDPLL_572M_CK",
+    [21] =  "AD_LVDSPLL_150M_CK",
+    [22] =  "AD_MSDCPLL_400M_CK",
+    [23] =  "AD_ETHERPLL_50M_CK",
+    [24] =  "clkph_MCK_o",
+    [25] =  "AD_USB_48M_CK",
+    [26] =  "AD_MSDCPLL2_400M_CK",
+    [27] =  "AD_CVBSADC_CKOUTA",
+    //[28] =    "NA",
+    //[29] =    "NA",
+    [30] =  "AD_TVDPLL_429M_CK",
+    //[31] =    "soc_rosc(0)",
+    //[32] =    "soc_rosc1(0)",
+    [33] =  "AD_LVDSPLL2_150M_CK",
+    [34] =  "AD_ETHERPLL_125M_CK",
+    [35] =  "AD_MIPI_26M_CK_CKSYS",
+    [36] =  "AD_LTEPLL_ARMPLL26M_CK_CKSYS",
+    [37] =  "AD_LETPLL_SSUSB26M_CK_CKSYS",
+    [38] =  "AD_DSI2_LNTC_DSICLK_CKSYS",
+    [39] =  "AD_DSI3_LNTC_DSICLK_CKSYS",
+    [40] =  "AD_DSI2_MPPLL_TST_CK_CKSYS",
+    [41] =  "AD_DSI3_MPPLL_TST_CK_CKSYS",
+    [42] =  "AD_LVDSTX3_MONCLK",
+    [43] =  "AD_PLLGP_TST_CK_CKSYS",
+    [44] =  "AD_SSUSB_48M_CK_CKSYS",
+    [45] =  "AD_MONREF3_CK",
+    [46] =  "AD_MONFBK3_CK",
+    [47] =  "big_clkmon_o",
+    [48] =  "DA_ARMCPU_MON_CK",
+    [49] =  "AD_CSI0_LNRC_BYTE_CLK",
+    [50] =  "AD_CSI1_LNRC_BYTE_CLK",
+    [51] =  "AD_CSI0_LNRC_4X_CLK",
+    [52] =  "AD_CSI1_LNRC_4X_CLK",
+    [53] =  "AD_CSI0_CAL_CLK",
+    [54] =  "AD_CSI1_CAL_CLK",
+    [55] =  "AD_UNIVPL_1248M_CK",
+    [56] =  "AD_MAINPLL_1092_CORE_CK",
+    [57] =  "AD_ARMCA15PLL_2002M_CORE_CK",
+    [58] =  "mcusys_arm_clk_out_all",
+    [59] =  "AD_ARMCA7PLL_1508M_CORE_CK",
+    //[60] =    "abist_clk26(0)",
+    [61] =  "AD_UNIVPLL_USB20_48M_CK",
+    [62] =  "AD_UNIVPLL_USB20_48M_CK1",
+    [63] =  "AD_UNIVPLL_USB20_48M_CK2",
+    //[64] =    "RESERVE",
+    [65] =  "AD_UNIVPLL_USB20_48M_CK3",
+    //[66] =    "abist_clk31(0)",
+    //[67] =    "abist_clk32(0)",
+    //[68] =    "abist_clk33(0)",
+    //[69] =    "abist_clk34(0)",
+    //[70] =    "abist_clk35(0)",
+    //[71] =    "abist_clk36(0)",
+    //[72] =    "abist_clk37(0)",
+    //[73] =    "abist_clk38(0)",
+    //[74] =    "abist_clk39(0)",
+    //[75] =    "abist_clk40(0)",
+    //[76] =    "abist_clk41(0)",
+    [77] =  "AD_LVDSTX1_MONCLK",
+    [78] =  "AD_MONREF1_CK",
+    [79] =  "AD_MONFBK1_CK",
+    //[80] =    "abist_clk45(0)",
+    //[81] =    "abist_clk46(0)",
+    //[82] =    "abist_clk47(0)",
+    //[83] =    "abist_clk48(0)",
+    //[84] =    "abist_clk49(0)",
+    [85] =  "trng_freq_debug_out0",
+    [86] =  "trng_freq_debug_out1",
+    [87] =  "AD_DSI0_LNTC_DSICLK_CKSYS",
+    [88] =  "AD_DSI0_MPLL_TST_CK_CKSYS",
+    [89] =  "AD_DSI1_LNTC_DSICLK_CKSYS",
+    [90] =  "AD_DSI1_MPLL_TST_CK_CKSYS",
+    [91] =  "ddr_clk_freq_meter[0]",
+    [92] =  "ddr_clk_freq_meter[1]",
+    [93] =  "ddr_clk_freq_meter[2]",
+    [94] =  "ddr_clk_freq_meter[3]",
+    [95] =  "ddr_clk_freq_meter[4]",
+    [96] =  "ddr_clk_freq_meter[5]",
+    [97] =  "ddr_clk_freq_meter[6]",
+    [98] =  "ddr_clk_freq_meter[7]",
+    [99] =  "ddr_clk_freq_meter[8]",
+    [100] = "ddr_clk_freq_meter[9]",
+    [101] = "ddr_clk_freq_meter[10]",
+    [102] = "ddr_clk_freq_meter[11]",
+    [103] = "ddr_clk_freq_meter[12]",
+    [104] = "ddr_clk_freq_meter[13]",
+    [105] = "ddr_clk_freq_meter[14]",
+    [106] = "ddr_clk_freq_meter[15]",
+    [107] = "ddr_clk_freq_meter[16]",
+    [108] = "ddr_clk_freq_meter[17]",
+    [109] = "ddr_clk_freq_meter[18]",
+    [110] = "ddr_clk_freq_meter[19]",
+    [111] = "ddr_clk_freq_meter[20]",
+    [112] = "ddr_clk_freq_meter[21]",
+    [113] = "ddr_clk_freq_meter[22]",
+    [114] = "ddr_clk_freq_meter[23]",
+    [115] = "ddr_clk_freq_meter[24]",
+    [116] = "ddr_clk_freq_meter[25]",
+    [117] = "ddr_clk_freq_meter[26]",
+    [118] = "ddr_clk_freq_meter[27]",
+    [119] = "ddr_clk_freq_meter[28]",
+    [120] = "ddr_clk_freq_meter[29]",
+    [121] = "ddr_clk_freq_meter[30]",
+    [122] = "ddr_clk_freq_meter[31]",
+    [123] = "ddr_clk_freq_meter[32]",
+    [124] = "ddr_clk_freq_meter[33]",
+    [125] = "ddr_clk_freq_meter[34]",
+    //[126] = "abist_clk91(0)",
+    //[127] = "abist_clk92(0)",
+};
+
+static const char *ckgen_clk[] = {
+    [1] =  "hf_faxi_ck",
+    [2] =  "hd_faxi_ck",
+    [3] =  "hf_fscam_ck",
+    [4] =  "hf_fddrphycfg_ck",
+    [5] =  "hf_fmm_ck",
+    [6] =  "f_fpwm_ck",
+    [7] =  "hf_fvdec_ck",
+    [8] =  "hf_fvenc_ck",
+    [9] =  "hf_fmfg_ck",
+    [10] = "hf_fcamtg_ck",
+    [11] = "f_fuart_ck",
+    [12] = "hf_fspi_ck",
+    [13] = "f_fusb20_ck",
+    [14] = "f_fusb30_ck",
+    [15] = "hf_fmsdc50_0_hclk_ck",
+    [16] = "hf_fmsdc50_0_ck",
+    [17] = "hf_fmsdc30_1_ck",
+    [18] = "hf_fmsdc30_2_ck",
+    [19] = "hf_fmsdc30_3_ck",
+    [20] = "hf_faudio_ck",
+    [21] = "hf_faud_intbus_ck",
+    [22] = "hf_fpmicspi_ck",
+    [23] = "hf_fdpilvds1_ck",
+    [24] = "hf_fatb_ck",
+    [25] = "hf_fnr_ck",
+    [26] = "hf_firda_ck",
+    [27] = "hf_fcci400_ck",
+    [28] = "hf_faud_1_ck",
+    [29] = "hf_faud_2_ck",
+    [30] = "hf_fmem_mfg_in_as_ck",
+    [31] = "hf_faxi_mfg_in_as_ck",
+    [32] = "f_frtc_ck",
+    [33] = "f_f26m_ck",
+    [34] = "f_f32k_md1_ck",
+    [35] = "f_frtc_conn_ck",
+    [36] = "hg_fmipicfg_ck",
+    [37] = "hd_haxi_nli_ck",
+    [38] = "hd_qaxidcm_ck",
+    [39] = "f_ffpc_ck",
+    [40] = "f_fckbus_ck_scan",
+    [41] = "f_fckrtc_ck_scan",
+    [42] = "hf_flvds_pxl_ck",
+    [43] = "hf_flvds_cts_ck",
+    [44] = "hf_fdpilvds_ck",
+    [45] = "hf_flvds1_pxl_ck",
+    [46] = "hf_flvds1_cts_ck",
+    [47] = "hf_fhdcp_ck",
+    [48] = "hf_fmsdc50_3_hclk_ck",
+    [49] = "hf_fhdcp_24m_ck",
+    [50] = "hf_fmsdc0p_aes_ck",
+    [51] = "hf_fgcpu_ck",
+    [52] = "hf_fmem_ck",
+    [53] = "hf_fi2so1_mck",
+    [54] = "hf_fcam2tg_ck",
+    [55] = "hf_fether_125m_ck",
+    [56] = "hf_fapll2_ck",
+    [57] = "hf_fa2sys_hp_ck",
+    [58] = "hf_fasm_l_ck",
+    [59] = "hf_fspislv_ck",
+    [60] = "hf_ftdmo1_mck",
+    [61] = "hf_fasm_h_ck",
+    [62] = "hf_ftdmo0_mck",
+    [63] = "hf_fa1sys_hp_ck",
+    //[64] = "Reserved",
+    [65] = "hf_fasm_m_ck",
+    [66] = "hf_fapll_ck",
+    [67] = "hf_fspinor_ck",
+    [68] = "hf_fpe2_mac_p0_ck",
+    [69] = "hf_fjpgdec_ck",
+    [70] = "hf_fpwm_infra_ck",
+    [71] = "hf_fnfiecc_ck",
+    [72] = "hf_fether_50m_rmii_ck",
+    [73] = "hf_fi2c_ck",
+    [74] = "hf_fcmsys_ck",
+    [75] = "hf_fpe2_mac_p1_ck",
+    [76] = "hf_fdi_ck",
+    [77] = "hf_fi2si3_mck",
+    [78] = "hf_fether_50m_ck",
+    [79] = "hf_fi2si2_mck",
+    [80] = "hf_fi2so3_mck",
+    [81] = "hf_ftvd_ck",
+    [82] = "hf_fnfi2x_ck",
+    [83] = "hf_fi2si1_mck",
+    [84] = "hf_fi2so2_mck",
+};
+#endif /* FMETER_EN */
+
+/* after pmic_init */
+void mt_pll_post_init(void)
+{
+#if FMETER_EN
+    unsigned int temp;
+#endif
+
+    setbits32(INFRA_APB_ASYNC_STA, (0x1 << 19));
+
+    /* MTCMOS */
+    spm_mtcmos_poweron_config_enable();
+#if ALL_CLK_ON
+    spm_mtcmos_display_power_on();
+    spm_mtcmos_mfg_power_on();
+    spm_mtcmos_protect_mfg_bus();
+    spm_mtcmos_mfg_sc1_power_on();
+    spm_mtcmos_mfg_sc2_power_on();
+    spm_mtcmos_mfg_sc3_power_on();
+    spm_mtcmos_isp_power_on();
+    spm_mtcmos_vdec_power_on();
+    spm_mtcmos_usb2_power_on();
+    spm_mtcmos_venc_power_on();
+    spm_mtcmos_audio_power_on();
+    spm_mtcmos_usb_power_on();
+#endif /* ALL_CLK_ON */
+
+    /* SUBSYS_CG */
+#if ALL_CLK_ON
+    clrbits32(CLK_AUDDIV_0, 0x000000ff);
+
+    setbits32(CLK_CG_EN_CFG, 0x00000007);
+
+    writel_r(INFRA_PDN_CLR, 0x07050141);
+
+    writel_r(PERI_GLOBALCON_PDN0_CLR, 0x7ff7e7ff);
+
+    writel_r(PERI_GLOBALCON_PDN1_CLR, 0x0001dffa);
+
+    setbits32(PERI_MSDC_CLK_EN, 0x000000ff);
+
+    writel_r(MFG_CG_CLR, 0x00000001);
+
+    writel_r(MMSYS_CG0_CLR, 0xffffffff);
+
+    writel_r(MMSYS_CG1_CLR, 0xffe70fff);
+
+    writel_r(MMSYS_CG2_CLR, 0x0000007f);
+
+    clrbits32(IMG_CG, 0x00000f6f);
+
+    clrbits32(BDP_DISPSYS_CG_CON0, 0x7ffffe3f);
+
+    writel_r(VDEC_CKEN_SET, 0x00000001);
+
+    writel_r(VDEC_LARB1_CKEN_SET, 0x00000003);
+
+    writel_r(VENC_CG_SET, 0x00001011);
+
+    writel_r(JPGDEC_CG_SET, 0x00000011);
+#endif /* ALL_CLK_ON */
+
+    /* only trun off those clocks not modeled in CCF */
+    writel_r(INFRA_PDN_SET, 0x00040000);
+    writel_r(DEVAPC_PDN_SET, 0x00000001);
+    writel_r(TRNG_PDN_SET, 0x00000001);
+    writel_r(PERI_GLOBALCON_PDN0_SET, 0x00040000);
+    writel_r(PERI_GLOBALCON_PDN1_SET, 0x00000490);
+    writel_r(MMSYS_CG0_SET, 0x60000000);
+    setbits32(IMG_CG, 0x00000066);
+
+    setbits32(CLK_SCP_CFG_0, 0x205);    /* enable scpsys clock off control */
+    setbits32(CLK_SCP_CFG_1, 0x15);     /* enable scpsys clock dcm, clock sel control */
+
+    clrbits32(AP_PLL_CON3, 0x77773);    /* set Univ, Main, ARMCA35 PLL PLLs HW control */
+
+    clrbits32(AP_PLL_CON4, 0x7);    /* set Univ, Main, ARMCA35 PLL PLLs HW control */
+
+#if FMETER_EN
+    dprintf(CRITICAL, "mt_get_cpu_freq(): %d KHz\n", mt_get_cpu_freq());
+    dprintf(CRITICAL, "mt_get_bus_freq(): %d KHz\n", mt_get_bus_freq());
+
+    dprintf(CRITICAL, "abist:\n");
+
+    for (temp = 0; temp < ARRAY_SIZE(abist_clk); temp++) {
+        if (!abist_clk[temp])
+            continue;
+
+        dprintf(CRITICAL, "%2u: %s: %d KHz\n", temp, abist_clk[temp],
+                mt_fmeter_abist(temp, 0, 0));
+    }
+
+    dprintf(CRITICAL, "ckegen:\n");
+
+    for (temp = 0; temp < ARRAY_SIZE(ckgen_clk); temp++) {
+        if (!ckgen_clk[temp])
+            continue;
+
+        dprintf(CRITICAL, "%2u: %s: %d KHz\n", temp, ckgen_clk[temp],
+                mt_fmeter_ckgen(temp, 0));
+    }
+#endif /* FMETER_EN */
+}
+
+void mt_pll_init(void)
+{
+    int ca35_freq, ca72_freq;
+
+    /* AP_PLL_CON0, CLKSQ_STB_CON0, PLL_ISO_CON0 use default */
+
+    writel_r(AP_PLL_CON6, 0x00000000);   /* ISO, PWR delay mode */
+
+    /* xPLL PWR ON */
+
+    setbits32(ARMCA35PLL_PWR_CON0, 0x1);
+
+    setbits32(ARMCA72PLL_PWR_CON0, 0x1);
+
+    setbits32(MAINPLL_PWR_CON0, 0x1);
+
+    setbits32(UNIVPLL_PWR_CON0, 0x1);
+
+    setbits32(MMPLL_PWR_CON0, 0x1);
+
+    setbits32(MSDCPLL_PWR_CON0, 0x1);
+
+    setbits32(VENCPLL_PWR_CON0, 0x1);
+
+    setbits32(TVDPLL_PWR_CON0, 0x1);
+
+    setbits32(ETHERPLL_PWR_CON0, 0x1);
+
+    setbits32(VCODECPLL_PWR_CON0, 0x1);
+
+    setbits32(APLL1_PWR_CON0, 0x1);
+
+    setbits32(APLL2_PWR_CON0, 0x1);
+
+    setbits32(LVDSPLL_PWR_CON0, 0x1);
+
+    setbits32(LVDSPLL2_PWR_CON0, 0x1);
+
+    setbits32(MSDCPLL2_PWR_CON0, 0x1);
+
+    udelay(5);  /* wait for xPLL_PWR_ON ready (min delay is 0.1us) */
+
+    /* xPLL ISO Disable */
+
+    clrbits32(ARMCA35PLL_PWR_CON0, 0x2);
+
+    clrbits32(ARMCA72PLL_PWR_CON0, 0x2);
+
+    clrbits32(MAINPLL_PWR_CON0, 0x2);
+
+    clrbits32(UNIVPLL_PWR_CON0, 0x2);
+
+    clrbits32(MMPLL_PWR_CON0, 0x2);
+
+    clrbits32(MSDCPLL_PWR_CON0, 0x2);
+
+    clrbits32(VENCPLL_PWR_CON0, 0x2);
+
+    clrbits32(TVDPLL_PWR_CON0, 0x2);
+
+    clrbits32(ETHERPLL_PWR_CON0, 0x2);
+
+    clrbits32(VCODECPLL_PWR_CON0, 0x2);
+
+    clrbits32(APLL1_PWR_CON0, 0x2);
+
+    clrbits32(APLL2_PWR_CON0, 0x2);
+
+    clrbits32(LVDSPLL_PWR_CON0, 0x2);
+
+    clrbits32(LVDSPLL2_PWR_CON0, 0x2);
+
+    clrbits32(MSDCPLL2_PWR_CON0, 0x2);
+
+    /* xPLL Frequency Set */
+    ca35_freq = det_ca35_freq();
+    switch (ca35_freq) {
+        case CA35_SPD_806MHZ:
+            writel_r(ARMCA35PLL_CON1, 0xBE000000);   /* 806MHz */
+            break;
+        case CA35_SPD_1001MHZ:
+            writel_r(ARMCA35PLL_CON1, 0xCD000000);   /* 1001Mhz */
+            break;
+        case CA35_SPD_1196MHZ:
+            writel_r(ARMCA35PLL_CON1, 0xDC000000);   /* 1196MHz */
+            break;
+        default:
+            assert(false);
+    }
+
+    ca72_freq = det_ca72_freq();
+    switch (ca72_freq) {
+        case CA72_SPD_1001MHZ:
+            writel_r(ARMCA72PLL_CON1, 0xA6800000);   /* 1001MHz */
+            break;
+        case CA72_SPD_1105MHZ:
+            writel_r(ARMCA72PLL_CON1, 0xAA800000);   /* 1105MHz */
+            break;
+        case CA72_SPD_1196MHZ:
+            writel_r(ARMCA72PLL_CON1, 0xAE000000);   /* 1196MHz */
+            break;
+        case CA72_SPD_1391MHZ:
+            writel_r(ARMCA72PLL_CON1, 0xB5800000);   /* 1391MHz */
+            break;
+        case CA72_SPD_1495MHZ:
+            writel_r(ARMCA72PLL_CON1, 0xB9800000);   /* 1495MHz */
+            break;
+        case CA72_SPD_1599MHZ:
+            writel_r(ARMCA72PLL_CON1, 0xBD800000);   /* 1599MHz */
+            break;
+        default:
+            assert(false);
+    }
+
+    writel_r(MAINPLL_CON1, 0xD4000000);  /* 1092MHz */
+
+    writel_r(UNIVPLL_CON1, 0xE0000000);  /* 1248MHz */
+
+    writel_r(MMPLL_CON1, 0xCD000000);    /* 500.5MHz */
+
+    writel_r(MSDCPLL_CON1, 0xBD89D89D);  /* 400MHz */
+
+    writel_r(VENCPLL_CON1, 0xBA762762);  /* 380 MHz */
+
+    writel_r(TVDPLL_CON1, 0xC2000000);   /* 429MHz */
+
+    writel_r(ETHERPLL_CON1, 0xCCEC4EC4); /* 50MHz */
+
+    writel_r(VCODECPLL_CON1, 0xC4000000);    /* 442 MHz */
+
+    writel_r(APLL1_CON1, 0xBC7EA932);    /* 196.608MHz */
+
+    writel_r(APLL2_CON1, 0xB7945EA6);    /* 180.6336MHz */
+
+    writel_r(LVDSPLL_CON1, 0xAE276276);  /* 150MHz */
+
+    writel_r(LVDSPLL2_CON1, 0xAE276276); /* 150MHz */
+
+    writel_r(MSDCPLL2_CON1, 0xBD89D89D); /* 400MHz */
+
+    /* xPLL Frequency Enable */
+
+    setbits32(ARMCA35PLL_CON0, 0x1);
+
+    setbits32(ARMCA72PLL_CON0, 0x1);
+
+    setbits32(MAINPLL_CON0, 0x1);
+
+    clrsetbits32(UNIVPLL_CON0, 0x100, 0x1); /* Integer Mode */
+
+    setbits32(MMPLL_CON0, 0x1);
+
+    setbits32(MSDCPLL_CON0, 0x1);
+
+    setbits32(VENCPLL_CON0, 0x1);
+
+    setbits32(TVDPLL_CON0, 0x1);
+
+    setbits32(ETHERPLL_CON0, 0x1);
+
+    setbits32(VCODECPLL_CON0, 0x1);
+
+    setbits32(APLL1_CON0, 0x1);
+
+    setbits32(APLL2_CON0, 0x1);
+
+    setbits32(LVDSPLL_CON0, 0x1);
+
+    setbits32(LVDSPLL2_CON0, 0x1);
+
+    setbits32(MSDCPLL2_CON0, 0x1);
+
+    udelay(40); /* wait for PLL stable (min delay is 20us) */
+
+    /* xPLL DIV RSTB */
+
+    setbits32(ARMCA35PLL_CON0, 0x01000000);
+
+    setbits32(MAINPLL_CON0, 0x01000000);
+
+    setbits32(UNIVPLL_CON0, 0x01000000);
+
+    /* MCUCFG CLKMUX */
+
+    clrsetbits32(mp0_pll_divider_cfg, 0x00000600, 0x00000200);
+
+    clrsetbits32(mp2_pll_divider_cfg, 0x00000600, 0x00000200);
+
+    clrsetbits32(bus_pll_divider_cfg, 0x00000600, 0x00000200);
+
+    setbits32(TOP_DCMCTL, 0x1); /* enable infrasys clock div */
+
+    setbits32(DCM_CFG, 0x80);   /* enable AXI bus clock DCM */
+
+    writel_r(MBIST_CFG_2, 0x67D2A357); /* enable reset deglitch */
+
+    setbits32(CLK_MODE, 0x1);
+    clrbits32(CLK_MODE, 0x1);   /* enable TOPCKGEN */
+
+    /* TOP CLKMUX */
+
+    clrsetbits32(CLK_CFG_0, 0x07000107, 0x01000101);
+
+    clrsetbits32(CLK_CFG_1, 0x0f0f0f03, 0x01010101);
+
+    clrsetbits32(CLK_CFG_2, 0x0307010f, 0x0101000a);
+
+    clrsetbits32(CLK_CFG_3, 0x070f0703, 0x02010101);
+
+    clrsetbits32(CLK_CFG_4, 0x07030f07, 0x01000202);
+
+    clrsetbits32(CLK_CFG_5, 0x07030707, 0x01010101);
+
+    clrsetbits32(CLK_CFG_6, 0x0307030f, 0x01040107);
+
+    clrsetbits32(CLK_CFG_7, 0x03030303, 0x01010101);
+
+    clrsetbits32(CLK_CFG_8, 0x07070707, 0x01050506);
+
+#if MTK_CLK32K_EXT_REMOVAL_SUPPORT
+    clrsetbits32(CLK_CFG_9, 0x03030307, 0x00030302);
+#else
+    clrsetbits32(CLK_CFG_9, 0x03030307, 0x01030302);
+#endif
+
+    clrsetbits32(CLK_CFG_10, 0x070f0f0f, 0x02060103);
+
+    clrsetbits32(CLK_CFG_11, 0x03030307, 0x03030302);
+
+    clrsetbits32(CLK_CFG_12, 0x03030303, 0x02020202);
+
+    clrsetbits32(CLK_CFG_13, 0x03030303, 0x02020202);
+
+    clrsetbits32(CLK_CFG_14, 0x070f0303, 0x06030101);
+
+    clrsetbits32(CLK_CFG_15, 0x03070f03, 0x01010a01);
+
+    clrsetbits32(CLK_CFG_16, 0x07030307, 0x01010104);
+
+    clrsetbits32(CLK_CFG_17, 0x00000007, 0x00000001);
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/pmic/pmic.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/pmic/pmic.c
new file mode 100644
index 0000000..98375e7
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/pmic/pmic.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include "mtk_i2c.h"
+
+#define CORE_BUS_NUM 0
+#define CPU_BUS_NUM 1
+#define DEV_ADDR 0x18
+#define SPEED 1000
+
+int rtq2134_set_bcpu_voltage(int target_vol)
+{
+    int read_vol;
+    uint8_t rw_buffer[2];
+
+    rw_buffer[0] = 0x48;
+    rw_buffer[1] = (target_vol - 300) / 5;
+    dprintf(CRITICAL, "[%s]Target Vol: %d(0x%x)\n", __func__, target_vol, rw_buffer[1]);
+    i2c_cust_write(CPU_BUS_NUM, DEV_ADDR, SPEED, rw_buffer, 2);
+    i2c_cust_write(CPU_BUS_NUM, DEV_ADDR, SPEED, rw_buffer, 1);
+    i2c_cust_read(CPU_BUS_NUM, DEV_ADDR, SPEED, &rw_buffer[1], 1);
+    read_vol =  rw_buffer[1] * 5 + 300;
+    dprintf(CRITICAL, "[%s]Current Vol: %d(0x%x)\n", __func__, read_vol, rw_buffer[1]);
+
+    return read_vol;
+}
+
+int rtq2134_set_lcpu_voltage(int target_vol)
+{
+    int read_vol;
+    uint8_t rw_buffer[2];
+
+    rw_buffer[0] = 0x62;
+    rw_buffer[1] = (target_vol - 300) / 5;
+    dprintf(CRITICAL, "[%s]Target Vol: %d(0x%x)\n", __func__, target_vol, rw_buffer[1]);
+    i2c_cust_write(CPU_BUS_NUM, DEV_ADDR, SPEED, rw_buffer, 2);
+    i2c_cust_write(CPU_BUS_NUM, DEV_ADDR, SPEED, rw_buffer, 1);
+    i2c_cust_read(CPU_BUS_NUM, DEV_ADDR, SPEED, &rw_buffer[1], 1);
+    read_vol =  rw_buffer[1] * 5 + 300;
+    dprintf(CRITICAL, "[%s]Current Vol: %d(0x%x)\n", __func__, read_vol, rw_buffer[1]);
+
+    return read_vol;
+}
+
+int rtq2134_set_core_voltage(int target_vol)
+{
+    int read_vol;
+    uint8_t rw_buffer[2];
+
+    rw_buffer[0] = 0x48;
+    rw_buffer[1] = (target_vol - 300) / 5;
+    dprintf(CRITICAL, "[%s]Target Vol: %d(0x%x)\n", __func__, target_vol, rw_buffer[1]);
+    i2c_cust_write(CORE_BUS_NUM, DEV_ADDR, SPEED, rw_buffer, 2);
+    i2c_cust_write(CORE_BUS_NUM, DEV_ADDR, SPEED, rw_buffer, 1);
+    i2c_cust_read(CORE_BUS_NUM, DEV_ADDR, SPEED, &rw_buffer[1], 1);
+    read_vol =  rw_buffer[1] * 5 + 300;
+    dprintf(CRITICAL, "[%s]Current Vol: %d(0x%x)\n", __func__, read_vol, rw_buffer[1]);
+
+    return read_vol;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/rules.mk b/src/bsp/lk/platform/mediatek/mt2712/drivers/rules.mk
new file mode 100644
index 0000000..2c3c64b
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/rules.mk
@@ -0,0 +1,48 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+    $(COMMON_PLAT)/drivers/uart/uart.c \
+    $(COMMON_PLAT)/drivers/usb/mtu3.c \
+    $(COMMON_PLAT)/drivers/usb/mtu3_qmu.c \
+    $(COMMON_PLAT)/drivers/usb/usbphy.c \
+    $(LOCAL_DIR)/dcm/dcm.c \
+    $(LOCAL_DIR)/efuse/mtk_devinfo.c \
+    $(LOCAL_DIR)/gpio/mt_gpio.c \
+    $(LOCAL_DIR)/key/mtk_key.c \
+    $(LOCAL_DIR)/nor/mtk_nor.c \
+    $(LOCAL_DIR)/pll/pll.c \
+    $(LOCAL_DIR)/spm/spm_mtcmos.c \
+    $(LOCAL_DIR)/trng/mtk_trng.c \
+    $(LOCAL_DIR)/wdt/mtk_wdt.c \
+
+MODULE_DEPS += \
+    lib/bio \
+    lib/cksum \
+    lib/fdt \
+    lib/mempool \
+    lib/partition \
+    lib/wrapper \
+
+ifeq ($(ENABLE_SCP_LOAD),1)
+MODULE_DEPS += $(LOCAL_DIR)/scp
+endif
+
+ifeq ($(LK_AS_BL33),0)
+MODULE_DEPS += \
+    $(LOCAL_DIR)/../../../../../dramk_2712/$(DRAM_TYPE)
+endif
+
+ifeq ($(LK_AS_BL33),1)
+MODULE_SRCS += \
+    $(LOCAL_DIR)/efuse/mtk_efuse.c \
+    $(LOCAL_DIR)/pmic/pmic.c \
+
+MODULE_EXTRA_OBJS += $(LOCAL_DIR)/../../../../../lk_ext_mod/platform/mt2712/drivers/efuse/$(ARCH)/VM/libefuse.o
+endif
+
+EXTRA_OBJS += $(LOCAL_DIR)/security/libsec.a
+MODULE_EXTRA_OBJS += $(LOCAL_DIR)/../../../../../lk_ext_mod/platform/mt2712/drivers/devinfo/libdevinfo.o
+
+include make/module.mk
+include $(LOCAL_DIR)/audio/rules.mk
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/scp/mt_scp.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/scp/mt_scp.c
new file mode 100644
index 0000000..40bde43
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/scp/mt_scp.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018 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 <arch/arm64.h>
+#include <platform/mt2712.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mt_scp.h>
+#include <reg.h>
+#include <sys/types.h>
+
+#define BIT(bit) (1UL << (bit))
+
+/* scp control */
+#define CMSYS_RESET_CTL     0x0
+#define CPU_RST_SW          BIT(0)
+#define BUS_RST_SW	    BIT(1)
+#define HBUS_RST_SW	    BIT(2)
+
+#define CMSYS_CLKGAT_CTL    0x8
+#define CPUCK_EN            0x1
+
+void start_scpsys(void)
+{
+    u32 reg;
+
+    /*
+     * These buses should be reset before the CM4 start running,
+     * in case some bus issues will be happened when system reboot
+     */
+    reg = readl(SCP_BASE_CFG + CMSYS_RESET_CTL);
+    reg &= ~(BUS_RST_SW | HBUS_RST_SW);
+    writel(reg, SCP_BASE_CFG + CMSYS_RESET_CTL);
+    DSB;
+
+    reg = readl(SCP_BASE_CFG + CMSYS_RESET_CTL);
+    reg |= BUS_RST_SW | HBUS_RST_SW;
+    writel(reg, SCP_BASE_CFG + CMSYS_RESET_CTL);
+
+    reg = readl(SCP_BASE_CFG + CMSYS_CLKGAT_CTL);
+    reg |= CPUCK_EN;
+    writel(reg, SCP_BASE_CFG + CMSYS_CLKGAT_CTL);
+
+    reg = readl(SCP_BASE_CFG + CMSYS_RESET_CTL);
+    reg |= CPU_RST_SW;
+    writel(reg, SCP_BASE_CFG + CMSYS_RESET_CTL);
+    DSB;
+}
+
+void stop_scpsys(void)
+{
+    u32 reg;
+
+    reg = readl(SCP_BASE_CFG + CMSYS_RESET_CTL);
+    reg &= ~CPU_RST_SW;
+    writel(reg, SCP_BASE_CFG + CMSYS_RESET_CTL);
+
+    reg = readl(SCP_BASE_CFG + CMSYS_CLKGAT_CTL);
+    reg &= ~CPUCK_EN;
+    writel(reg, SCP_BASE_CFG + CMSYS_CLKGAT_CTL);
+    DSB;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/scp/rules.mk b/src/bsp/lk/platform/mediatek/mt2712/drivers/scp/rules.mk
new file mode 100644
index 0000000..97bb27d
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/scp/rules.mk
@@ -0,0 +1,7 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/mt_scp.c
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/security/libsec.a b/src/bsp/lk/platform/mediatek/mt2712/drivers/security/libsec.a
new file mode 100644
index 0000000..41b5167
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/security/libsec.a
Binary files differ
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/spm/spm_mtcmos.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/spm/spm_mtcmos.c
new file mode 100644
index 0000000..665835b
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/spm/spm_mtcmos.c
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+#include <platform/mt_infracfg.h>
+#include <platform/reg_utils.h>
+
+#include "spm_mtcmos_internal.h"
+
+struct power_domain_data {
+    void *pwr_con;
+    unsigned int pwr_sta_mask;
+    unsigned int sram_pdn_mask;
+    unsigned int sram_ack_mask;
+};
+
+static void mtcmos_power_on(const struct power_domain_data *pd)
+{
+    setbits32(pd->pwr_con, PWR_ON);
+    setbits32(pd->pwr_con, PWR_ON_2ND);
+
+    while (!(readl(&mtk_spm->pwr_status) & pd->pwr_sta_mask) ||
+           !(readl(&mtk_spm->pwr_status_2nd) & pd->pwr_sta_mask))
+        continue;
+
+    clrbits32(pd->pwr_con, PWR_CLK_DIS);
+    clrbits32(pd->pwr_con, PWR_ISO);
+    setbits32(pd->pwr_con, PWR_RST_B);
+    clrbits32(pd->pwr_con, pd->sram_pdn_mask);
+
+    while (readl(pd->pwr_con) & pd->sram_ack_mask)
+        continue;
+}
+
+void spm_mtcmos_poweron_config_enable(void)
+{
+    writel((SPM_REGWR_CFG_KEY | SPM_REGWR_EN), &mtk_spm->poweron_config_set);
+}
+
+void spm_mtcmos_protect_mfg_bus(void)
+{
+    writel(MFG_PROT_MASK, TOPAXI_PROT_EN_CLR);
+    while (readl(TOPAXI_PROT_STA1) & MFG_PROT_MASK)
+        continue;
+}
+
+void spm_mtcmos_display_power_on(void)
+{
+    static const struct power_domain_data disp = {
+        .pwr_con = &mtk_spm->dis_pwr_con,
+        .pwr_sta_mask = DIS_PWR_STA_MASK,
+        .sram_pdn_mask = DIS_SRAM_PDN,
+        .sram_ack_mask = DIS_SRAM_ACK,
+    };
+
+    mtcmos_power_on(&disp);
+}
+
+void spm_mtcmos_audio_power_on(void)
+{
+    static const struct power_domain_data audio = {
+        .pwr_con = &mtk_spm->audio_pwr_con,
+        .pwr_sta_mask = AUD_PWR_STA_MASK,
+        .sram_pdn_mask = AUD_SRAM_PDN,
+        .sram_ack_mask = AUD_SRAM_ACK,
+    };
+
+    mtcmos_power_on(&audio);
+}
+
+void spm_mtcmos_mfg_power_on(void)
+{
+    static const struct power_domain_data mfg = {
+        .pwr_con = &mtk_spm->mfg_pwr_con,
+        .pwr_sta_mask = MFG_PWR_STA_MASK,
+        .sram_pdn_mask = MFG_SRAM_PDN,
+        .sram_ack_mask = MFG_SRAM_ACK,
+    };
+
+    mtcmos_power_on(&mfg);
+}
+
+void spm_mtcmos_mfg_sc1_power_on(void)
+{
+    static const struct power_domain_data mfg_sc1 = {
+        .pwr_con = &mtk_spm->mfg_sc1_pwr_con,
+        .pwr_sta_mask = MFG_SC1_PWR_STA_MASK,
+        .sram_pdn_mask = MFG_SRAM_PDN,
+        .sram_ack_mask = MFG_SRAM_ACK,
+    };
+
+    mtcmos_power_on(&mfg_sc1);
+}
+
+void spm_mtcmos_mfg_sc2_power_on(void)
+{
+    static const struct power_domain_data mfg_sc2 = {
+        .pwr_con = &mtk_spm->mfg_sc2_pwr_con,
+        .pwr_sta_mask = MFG_SC2_PWR_STA_MASK,
+        .sram_pdn_mask = MFG_SRAM_PDN,
+        .sram_ack_mask = MFG_SRAM_ACK,
+    };
+
+    mtcmos_power_on(&mfg_sc2);
+}
+
+void spm_mtcmos_mfg_sc3_power_on(void)
+{
+    static const struct power_domain_data mfg_sc3 = {
+        .pwr_con = &mtk_spm->mfg_sc3_pwr_con,
+        .pwr_sta_mask = MFG_SC3_PWR_STA_MASK,
+        .sram_pdn_mask = MFG_SRAM_PDN,
+        .sram_ack_mask = MFG_SRAM_ACK,
+    };
+
+    mtcmos_power_on(&mfg_sc3);
+}
+
+void spm_mtcmos_isp_power_on(void)
+{
+    static const struct power_domain_data isp = {
+        .pwr_con = &mtk_spm->isp_pwr_con,
+        .pwr_sta_mask = ISP_PWR_STA_MASK,
+        .sram_pdn_mask = ISP_SRAM_PDN,
+        .sram_ack_mask = ISP_SRAM_ACK,
+    };
+
+    mtcmos_power_on(&isp);
+}
+
+void spm_mtcmos_vdec_power_on(void)
+{
+    static const struct power_domain_data vdec = {
+        .pwr_con = &mtk_spm->vdec_pwr_con,
+        .pwr_sta_mask = VDE_PWR_STA_MASK,
+        .sram_pdn_mask = VDE_SRAM_PDN,
+        .sram_ack_mask = VDE_SRAM_ACK,
+    };
+
+    mtcmos_power_on(&vdec);
+}
+
+void spm_mtcmos_venc_power_on(void)
+{
+    static const struct power_domain_data venc = {
+        .pwr_con = &mtk_spm->ven_pwr_con,
+        .pwr_sta_mask = VEN_PWR_STA_MASK,
+        .sram_pdn_mask = VEN_SRAM_PDN,
+        .sram_ack_mask = VEN_SRAM_ACK,
+    };
+
+    mtcmos_power_on(&venc);
+}
+
+void spm_mtcmos_usb_power_on(void)
+{
+    static const struct power_domain_data usb = {
+        .pwr_con = &mtk_spm->usb_pwr_con,
+        .pwr_sta_mask = USB_PWR_STA_MASK,
+        .sram_pdn_mask = USB_SRAM_PDN,
+        .sram_ack_mask = USB_SRAM_ACK,
+    };
+
+    mtcmos_power_on(&usb);
+}
+
+void spm_mtcmos_usb2_power_on(void)
+{
+    static const struct power_domain_data usb2 = {
+        .pwr_con = &mtk_spm->usb2_pwr_con,
+        .pwr_sta_mask = USB2_PWR_STA_MASK,
+        .sram_pdn_mask = USB2_SRAM_PDN,
+        .sram_ack_mask = USB2_SRAM_ACK,
+    };
+
+    mtcmos_power_on(&usb2);
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/spm/spm_mtcmos_internal.h b/src/bsp/lk/platform/mediatek/mt2712/drivers/spm/spm_mtcmos_internal.h
new file mode 100644
index 0000000..dcafd6a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/spm/spm_mtcmos_internal.h
@@ -0,0 +1,286 @@
+/*
+ * 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 <platform/mt_reg_base.h>
+
+enum {
+    SPM_PROJECT_CODE    = 0xb16,
+    SPM_REGWR_CFG_KEY   = (SPM_PROJECT_CODE << 16),
+    SPM_REGWR_EN        = (1U << 0),
+};
+
+enum {
+    DIS_PWR_STA_MASK        = 0x1 << 3,
+    MFG_PWR_STA_MASK        = 0x1 << 4,
+    ISP_PWR_STA_MASK        = 0x1 << 5,
+    VDE_PWR_STA_MASK        = 0x1 << 7,
+    USB2_PWR_STA_MASK       = 0x1 << 19,
+    VEN_PWR_STA_MASK        = 0x1 << 21,
+    MFG_SC1_PWR_STA_MASK    = 0x1 << 22,
+    MFG_SC2_PWR_STA_MASK    = 0x1 << 23,
+    AUD_PWR_STA_MASK        = 0x1 << 24,
+    USB_PWR_STA_MASK        = 0x1 << 25,
+    MFG_SC3_PWR_STA_MASK    = 0x1 << 30,
+};
+
+enum {
+    DIS_SRAM_PDN    = 0x1 << 8,
+    DIS_SRAM_ACK    = 0x1 << 12,
+    MFG_SRAM_PDN    = 0x1 << 8,
+    MFG_SRAM_ACK    = 0x1 << 16,
+    ISP_SRAM_PDN    = 0xf << 8,
+    ISP_SRAM_ACK    = 0x3 << 12,
+    VDE_SRAM_PDN    = 0x1 << 8,
+    VDE_SRAM_ACK    = 0x1 << 12,
+    USB2_SRAM_PDN   = 0x7 << 8,
+    USB2_SRAM_ACK   = 0x7 << 12,
+    VEN_SRAM_PDN    = 0xf << 8,
+    VEN_SRAM_ACK    = 0xf << 12,
+    AUD_SRAM_PDN    = 0xf << 8,
+    AUD_SRAM_ACK    = 0xf << 12,
+    USB_SRAM_PDN    = 0x7 << 8,
+    USB_SRAM_ACK    = 0x7 << 12,
+};
+
+enum {
+    SRAM_ISOINT_B = 1U << 6,
+    SRAM_CKISO    = 1U << 5,
+    PWR_CLK_DIS   = 1U << 4,
+    PWR_ON_2ND    = 1U << 3,
+    PWR_ON        = 1U << 2,
+    PWR_ISO       = 1U << 1,
+    PWR_RST_B     = 1U << 0
+};
+
+struct mtk_2712_spm_regs {
+    unsigned int poweron_config_set;
+    unsigned int reserved_00[3];
+    unsigned int power_on_val0;     /* 0x10 */
+    unsigned int power_on_val1;
+    unsigned int reserved_10[58];
+    unsigned int clk_settle;        /* 0x100 */
+    unsigned int reserved_20[61];
+    unsigned int mfg_sc3_pwr_con;   /* 0x1f8 */
+    unsigned int reserved_21[1];
+    unsigned int mp0_cpu0_pwr_con;  /* 0x200 */
+    unsigned int mp0_dbg_pwr_con;
+    unsigned int mp0_cputop_pwr_con;
+    unsigned int reserved_30[1];
+    unsigned int vdec_pwr_con;      /* 0x210 */
+    unsigned int mfg_pwr_con;
+    unsigned int mp0_cpu1_pwr_con;
+    unsigned int mp0_cpu2_pwr_con;
+    unsigned int mp0_cpu3_pwr_con;
+    unsigned int reserved_40[3];
+    unsigned int ven_pwr_con;       /* 0x230 */
+    unsigned int ifr_pwr_con;
+    unsigned int isp_pwr_con;
+    unsigned int dis_pwr_con;
+    unsigned int dpy_pwr_con;
+    unsigned int mp0_cputop_l2_pdn;
+    unsigned int mp0_cputop_l2_sleep;
+    unsigned int reserved_50[4];
+    unsigned int mp0_cpu0_l1_pdn;   /* 0x25c */
+    unsigned int reserved_51;
+    unsigned int mp0_cpu1_l1_pdn;
+    unsigned int reserved_52;
+    unsigned int mp0_cpu2_l1_pdn;
+    unsigned int reserved_53;
+    unsigned int mp0_cpu3_l1_pdn;
+    unsigned int reserved_54;
+    unsigned int fhc_sram_con;
+    unsigned int conn_pwr_con;
+    unsigned int md_pwr_con;
+    unsigned int reserved_60[2];
+    unsigned int mcu_pwr_con;       /* 0x290 */
+    unsigned int ifr_sramrom_con;
+    unsigned int ven2_pwr_con;
+    unsigned int audio_pwr_con;
+    unsigned int reserved_70[8];
+    unsigned int mfg_sc1_pwr_con;   /* 0x2c0 */
+    unsigned int mfg_sc2_pwr_con;
+    unsigned int md32_sram_pwr_con;
+    unsigned int usb_pwr_con;
+    unsigned int reserved_80[1];
+    unsigned int usb2_pwr_con;
+    unsigned int reserved_81[1];
+    unsigned int cpu_ext_iso;
+    unsigned int reserved_85[5];
+    unsigned int mp_pwr_con;        /* 0x2f4 */
+    unsigned int reserved_90[6];
+    unsigned int pcm_con0;          /* 0x310 */
+    unsigned int pcm_con1;
+    unsigned int pcm_im_ptr;
+    unsigned int pcm_im_len;
+    unsigned int pcm_reg_data_ini;
+    unsigned int reserved_100[7];
+    unsigned int pcm_event_vector0; /* 0x340 */
+    unsigned int pcm_event_vector1;
+    unsigned int pcm_event_vector2;
+    unsigned int pcm_event_vector3;
+    unsigned int reserved_110[1];
+    unsigned int pcm_mas_pause_mask;
+    unsigned int pcm_pwr_io_en;
+    unsigned int pcm_timer_val;
+    unsigned int pcm_timer_out;
+    unsigned int reserved_120[7];
+    unsigned int pcm_reg0_data;     /* 0x380 */
+    unsigned int pcm_reg1_data;
+    unsigned int pcm_reg2_data;
+    unsigned int pcm_reg3_data;
+    unsigned int pcm_reg4_data;
+    unsigned int pcm_reg5_data;
+    unsigned int pcm_reg6_data;
+    unsigned int pcm_reg7_data;
+    unsigned int pcm_reg8_data;
+    unsigned int pcm_reg9_data;
+    unsigned int pcm_reg10_data;
+    unsigned int pcm_reg11_data;
+    unsigned int pcm_reg12_data;
+    unsigned int pcm_reg13_data;
+    unsigned int pcm_reg14_data;
+    unsigned int pcm_reg15_data;
+    unsigned int pcm_event_reg_sta;
+    unsigned int pcm_fsm_sta;
+    unsigned int pcm_im_host_rw_ptr;
+    unsigned int pcm_im_host_rw_dat;
+    unsigned int pcm_event_vector4;
+    unsigned int pcm_event_vector5;
+    unsigned int pcm_event_vector6;
+    unsigned int pcm_event_vector7;
+    unsigned int pcm_sw_int_set;
+    unsigned int pcm_sw_int_clear;
+    unsigned int pcm_regc_wakeup_mask;
+    unsigned int reserved_130[3];
+    unsigned int pcm_mas_pause_mask2;       /* 0x3f8 */
+    unsigned int reserved_132[1];
+    unsigned int clk_con;
+    unsigned int reserved_140[127];
+    unsigned int apmcu_pwrctl;              /* 0x600 */
+    unsigned int ap_dvfs_con_set;
+    unsigned int sleep_stnby_con;
+    unsigned int pwr_status;
+    unsigned int pwr_status_2nd;
+    unsigned int sleep_mdbsi_con;
+    unsigned int reserved_150[2];
+    unsigned int rf_clk_cfg;                /* 0x620 */
+    unsigned int rf_clk_cfg_set;
+    unsigned int rf_clk_cfg_clr;
+    unsigned int reserved_160[3];
+    unsigned int spm_ap_sema;               /* 0x638 */
+    unsigned int spm_spm_sema;
+    unsigned int reserved_170[56];
+    unsigned int sleep_timer_sta;           /* 0x720 */
+    unsigned int reserved_180[15];
+    unsigned int sleep_twam_con;            /* 0x760 */
+    unsigned int sleep_twam_last_status0;
+    unsigned int sleep_twam_last_status1;
+    unsigned int sleep_twam_last_status2;
+    unsigned int sleep_twam_last_status3;
+    unsigned int sleep_twam_curr_status0;
+    unsigned int sleep_twam_curr_status1;
+    unsigned int sleep_twam_curr_status2;
+    unsigned int sleep_twam_curr_status3;
+    unsigned int sleep_twam_timer_out;
+    unsigned int sleep_twam_window_len;
+    unsigned int reserved_190[33];
+    unsigned int sleep_wakeup_event_mask;   /* 0x810 */
+    unsigned int sleep_cpu_wakeup_event;
+    unsigned int reserved_200[3];
+    unsigned int pcm_wdt_timer_val;
+    unsigned int pcm_wdt_timer_out;
+    unsigned int reserved_210[53];
+    unsigned int sleep_isr_mask;            /* 0x900 */
+    unsigned int sleep_isr_status;
+    unsigned int reserved_220[2];
+    unsigned int sleep_isr_raw_sta;         /* 0x910 */
+    unsigned int reserved_230[1];
+    unsigned int sleep_wakeup_misc;
+    unsigned int sleep_bus_protect_rdy;
+    unsigned int sleep_subsys_idle_sta;
+    unsigned int reserved_240[119];
+    unsigned int pcm_reserve;               /* 0xb00 */
+    unsigned int pcm_reserve2;
+    unsigned int pcm_flags;
+    unsigned int pcm_src_req;
+    unsigned int reserved_250;
+    unsigned int pcm_reserve3;
+    unsigned int pcm_reserve4;
+    unsigned int pcm_mmddr_mask;
+    unsigned int pcm_debug_con;
+    unsigned int pcm_wdt_latch;
+    unsigned int reserved_260[2];
+    unsigned int mp0_cpu0_irq_mask;         /* 0xb30 */
+    unsigned int mp0_cpu1_irq_mask;
+    unsigned int mp0_cpu2_irq_mask;
+    unsigned int mp0_cpu3_irq_mask;
+    unsigned int reserved_270[8];
+    unsigned int pcm_pasr_dpd_0;            /* 0xb60 */
+    unsigned int pcm_pasr_dpd_1;
+    unsigned int pcm_pasr_dpd_2;
+    unsigned int pcm_pasr_dpd_3;
+    unsigned int reserved_280[36];
+    unsigned int pcm_event_vector_en;       /* 0xc00 */
+    unsigned int pcm_event_vector8;
+    unsigned int pcm_event_vector9;
+    unsigned int pcm_event_vectora;
+    unsigned int pcm_event_vectorb;
+    unsigned int pcm_event_vectorc;
+    unsigned int pcm_event_vectord;
+    unsigned int pcm_event_vectore;
+    unsigned int pcm_event_vectorf;
+    unsigned int pcm_reserve5;
+    unsigned int pcm_reserve6;
+    unsigned int pcm_reserve7;
+    unsigned int pcm_reserve8;
+    unsigned int reserved_290[3];
+    unsigned int spmc_mp0_cpu0_con;         /* 0xc40 */
+    unsigned int spmc_mp0_cpu1_con;
+    unsigned int spmc_mp0_cpu2_con;
+    unsigned int spmc_mp0_cpu3_con;
+    unsigned int spmc_mp0_con;
+    unsigned int spmc_mp0_srm_slp;
+    unsigned int spmc_mp0_clk_dis;
+    unsigned int reserved_300[1];
+    unsigned int spmc_mp1_cpu0_con;
+    unsigned int spmc_mp1_cpu1_con;
+    unsigned int reserved_310[2];
+    unsigned int spmc_mp1_con;              /* 0xc70 */
+    unsigned int spmc_mp1_srm_slp;
+    unsigned int spmc_mp1_clk_dis;
+    unsigned int spmc_mp1_l2_flush;
+    unsigned int reserved_320[160];
+    unsigned int sleep_mp0_wfi0_en;         /* 0xf00 */
+    unsigned int sleep_mp0_wfi1_en;
+    unsigned int sleep_mp0_wfi2_en;
+    unsigned int sleep_mp0_wfi3_en;
+    unsigned int sleep_mp1_wfi0_en;
+    unsigned int sleep_mp1_wfi1_en;         /* 0xf14 */
+};
+
+_Static_assert(offsetof(struct mtk_2712_spm_regs, sleep_mp1_wfi1_en) == 0xf14,
+        "sleep_mp1_wfi1_en offset shift");
+
+static struct mtk_2712_spm_regs *const mtk_spm = (void *)SPM_BASE;
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/trng/mtk_trng.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/trng/mtk_trng.c
new file mode 100644
index 0000000..f5ca1f4
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/trng/mtk_trng.c
@@ -0,0 +1,61 @@
+#include <debug.h>
+#include <reg.h>
+#include <platform/mt_reg_base.h>
+#include <platform/pll.h>
+#include <string.h>
+
+#define TRNG_CTRL_REG            (TRNG_BASE+0x00)
+#define TRNG_DATA_REG            (TRNG_BASE+0x08)
+#define TRNG_CONF_REG            (TRNG_BASE+0x0C)
+
+#define TRNG_PDN_VALUE          0x1
+
+/* TRNG_CTRL_REG */
+#define TRNG_RDY         (0x80000000)
+#define TRNG_START       (0x00000001)
+
+/* Assume clock setting for trng is on */
+s32 trng_drv_get_random_data(u8 *buf, u32 len)
+{
+    s32 retval = 0;
+
+    if (0 == len)
+        return 0;
+
+    if (NULL == buf) {
+        dprintf(CRITICAL, "[TRNG] Error: input buffer is NULL\n");
+        return -1;
+    }
+
+    if (readl(TRNG_PDN_STATUS) & TRNG_PDN_VALUE) //TRNG clock is off
+        writel(TRNG_PDN_VALUE, TRNG_PDN_CLR);  //ungate TRNG clock
+
+    if (TRNG_START != (readl(TRNG_CTRL_REG) & TRNG_START)) {
+        writel(TRNG_START, TRNG_CTRL_REG); //start TRNG
+        if (TRNG_START != (readl(TRNG_CTRL_REG) & TRNG_START)) {
+            dprintf(CRITICAL, "[TRNG] Error: fail to start TRNG because clock is disabled\n");
+            return -2;
+        }
+    }
+
+    /* clear output buffer */
+    memset(buf, 0, len);
+
+    /* generate random data with default rings */
+    while (len >= sizeof(u32)) {
+        if(TRNG_RDY != (readl(TRNG_CTRL_REG) & TRNG_RDY)) {
+            spin(1);
+            continue;
+        }
+
+        *(u32 *)buf = readl(TRNG_DATA_REG);
+        retval += sizeof(u32);
+        buf += sizeof(u32);
+        len -= sizeof(u32);
+    }
+
+    writel(0x0, TRNG_CTRL_REG);     //stop TRNG
+    writel(TRNG_PDN_VALUE, TRNG_PDN_SET); //gate TRNG clock
+
+    return retval;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/drivers/wdt/mtk_wdt.c b/src/bsp/lk/platform/mediatek/mt2712/drivers/wdt/mtk_wdt.c
new file mode 100644
index 0000000..f71c6d3
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/drivers/wdt/mtk_wdt.c
@@ -0,0 +1,469 @@
+#include <debug.h>
+#include <platform/mtk_wdt.h>
+#include <reg.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+#if ENABLE_WDT_MODULE
+
+static bool mtk_wd_CheckNonResetReg2(unsigned int status)
+{
+    u32 reg;
+
+    reg = readl(MTK_WDT_NONRST_REG2) & MTK_WDT_NONRST2_BOOT_MASK;
+    if (reg == status)
+        return true;
+    else
+        return false;
+}
+
+static void mtk_wd_SetNonResetReg2(unsigned int status, bool flag)
+{
+    u32 reg;
+
+    reg = readl(MTK_WDT_NONRST_REG2);
+    if (flag)
+        reg |= status;
+    else
+        reg &= ~status;
+
+    writel(reg, MTK_WDT_NONRST_REG2);
+}
+
+void set_clr_fastboot_mode(bool flag)
+{
+    mtk_wd_SetNonResetReg2(MTK_WDT_NONRST2_BOOT_BOOTLOADER, flag);
+
+    LTRACEF("set_clr_fastboot_mode\n");
+}
+
+void set_clr_fastbootd_mode(bool flag)
+{
+    mtk_wd_SetNonResetReg2(MTK_WDT_NONRST2_BOOT_FASTBOOTD, flag);
+
+    LTRACEF("set_clr_fastbootd_mode\n");
+}
+
+void set_clr_recovery_mode(bool flag)
+{
+    mtk_wd_SetNonResetReg2(MTK_WDT_NONRST2_BOOT_RECOVERY, flag);
+
+    LTRACEF("set_clr_recovery_mode\n");
+}
+
+void clr_cm4_resume_mode(void)
+{
+    /* clear cm4 resume (bit 21) and show logo (bit 22) flags */
+    mtk_wd_SetNonResetReg2((1U << MTK_WDT_NONRST2_CM4_RESUME), false);
+    mtk_wd_SetNonResetReg2((1U << MTK_WDT_NONRST2_SHOW_LOGO), false);
+}
+
+bool check_fastboot_mode(void)
+{
+    return mtk_wd_CheckNonResetReg2(MTK_WDT_NONRST2_BOOT_BOOTLOADER);
+}
+
+bool check_fastbootd_mode(void)
+{
+    return mtk_wd_CheckNonResetReg2(MTK_WDT_NONRST2_BOOT_FASTBOOTD);
+}
+
+bool check_recovery_mode(void)
+{
+    return mtk_wd_CheckNonResetReg2(MTK_WDT_NONRST2_BOOT_RECOVERY);
+}
+
+void mtk_wdt_disable(void)
+{
+    u32 tmp;
+
+    tmp = readl(MTK_WDT_MODE);
+    tmp &= ~MTK_WDT_MODE_ENABLE;       /* disable watchdog */
+    tmp |= (MTK_WDT_MODE_KEY);         /* need key then write is allowed */
+    writel(tmp, MTK_WDT_MODE);
+}
+
+static void mtk_wdt_reset(char mode)
+{
+    /* Watchdog Rest */
+    unsigned int wdt_mode_val;
+    writel(MTK_WDT_RESTART_KEY, MTK_WDT_RESTART);
+
+    wdt_mode_val = readl(MTK_WDT_MODE);
+    /* clear autorestart bit:
+     * autoretart: 1, bypass power key, 0: not bypass power key */
+    wdt_mode_val &=(~MTK_WDT_MODE_AUTO_RESTART);
+    /* make sure WDT mode is hw reboot mode, can not config isr mode  */
+    wdt_mode_val &= \
+        ~(MTK_WDT_MODE_IRQ | MTK_WDT_MODE_ENABLE | MTK_WDT_MODE_DUAL_MODE);
+
+    wdt_mode_val |= (MTK_WDT_MODE_KEY | MTK_WDT_MODE_EXTEN);
+
+    /* mode != 0 means by pass power key reboot,
+     * We using auto_restart bit as by pass power key flag */
+    if (mode)
+        wdt_mode_val |= MTK_WDT_MODE_AUTO_RESTART;
+
+    writel(wdt_mode_val, MTK_WDT_MODE);
+
+    spin(100);
+    writel(MTK_WDT_SWRST_KEY, MTK_WDT_SWRST);
+}
+
+unsigned int mtk_wdt_check_status(void)
+{
+    static unsigned int status = 0;
+
+    /*
+     * Because WDT_STA register will be cleared after writing WDT_MODE,
+     * we use a static variable to store WDT_STA.
+     * After reset, static varialbe will always be clear to 0,
+     * so only read WDT_STA when static variable is 0 is OK
+     */
+    if (0 == status)
+        status = readl(MTK_WDT_STATUS);
+
+    return status;
+}
+
+static void mtk_wdt_mode_config(bool dual_mode_en,
+                                bool irq,
+                                bool ext_en,
+                                bool ext_pol,
+                                bool wdt_en)
+{
+    unsigned int tmp;
+
+    tmp = readl(MTK_WDT_MODE);
+    tmp |= MTK_WDT_MODE_KEY;
+
+    // Bit 0 : Whether enable watchdog or not
+    if (wdt_en == true)
+        tmp |= MTK_WDT_MODE_ENABLE;
+    else
+        tmp &= ~MTK_WDT_MODE_ENABLE;
+
+    // Bit 1 : Configure extern reset signal polarity.
+    if (ext_pol == true)
+        tmp |= MTK_WDT_MODE_EXT_POL;
+    else
+        tmp &= ~MTK_WDT_MODE_EXT_POL;
+
+    // Bit 2 : Whether enable external reset signal
+    if (ext_en == true)
+        tmp |= MTK_WDT_MODE_EXTEN;
+    else
+        tmp &= ~MTK_WDT_MODE_EXTEN;
+
+    // Bit 3 : Whether generating interrupt instead of reset signal
+    if (irq == true)
+        tmp |= MTK_WDT_MODE_IRQ;
+    else
+        tmp &= ~MTK_WDT_MODE_IRQ;
+
+    // Bit 6 : Whether enable debug module reset
+    if (dual_mode_en == true)
+        tmp |= MTK_WDT_MODE_DUAL_MODE;
+    else
+        tmp &= ~MTK_WDT_MODE_DUAL_MODE;
+
+    /*  Bit 4: WDT_Auto_restart, this is a reserved bit,
+     *  we use it as bypass powerkey flag.
+     *  Because HW reboot always need reboot to kernel, we set it always.
+     */
+    tmp |= MTK_WDT_MODE_AUTO_RESTART;
+
+    writel(tmp, MTK_WDT_MODE);
+    //dual_mode(1); //always dual mode
+    //mdelay(100);
+    LTRACEF("mtk_wdt_mode_config LK mode value=%x", readl(MTK_WDT_MODE));
+}
+
+static void mtk_wdt_set_time_out_value(uint32_t value)
+{
+    static unsigned int timeout;
+
+
+    /* TimeOut = BitField 15:5
+     * Key     = BitField  4:0 = 0x08
+     */
+
+    // sec * 32768 / 512 = sec * 64 = sec * 1 << 6
+    timeout = (unsigned int)(value * ( 1 << 6) );
+    timeout = timeout << 5;
+    writel((timeout | MTK_WDT_LENGTH_KEY), MTK_WDT_LENGTH);
+}
+
+void mtk_wdt_restart(void)
+{
+    // Reset WatchDogTimer's counting value to time out value
+    // ie., keepalive()
+    writel(MTK_WDT_RESTART_KEY, MTK_WDT_RESTART);
+}
+
+static void mtk_wdt_sw_reset(void)
+{
+    printf ("UB WDT SW RESET\n");
+    mtk_wdt_reset(1); /* NOTE here, this reset will cause by pass power key */
+
+    while (1) {
+        printf ("UB SW reset fail ... \n");
+    }
+}
+
+static void mtk_wdt_hw_reset(void)
+{
+    LTRACEF("UB WDT_HW_Reset\n");
+
+    // 1. set WDT timeout 1 secs, 1*64*512/32768 = 1sec
+    mtk_wdt_set_time_out_value(1);
+
+    // 2. enable WDT debug reset enable, generating irq disable,
+    //    ext reset disable, ext reset signal low, wdt enalbe
+    mtk_wdt_mode_config(true, false, false, false, true);
+
+    // 3. reset the watch dog timer to the value set in WDT_LENGTH register
+    mtk_wdt_restart();
+
+    // 4. system will reset
+    while (1);
+}
+
+static const char* parsing_reset_reason(unsigned int wdt_status)
+{
+	const char *rst_reason="normal";
+	switch(wdt_status)
+	{
+		case MTK_WDT_STATUS_HWWDT_RST_WITH_IRQ:
+			rst_reason="hw_rst_with_irq";
+			break;
+
+		case MTK_WDT_STATUS_HWWDT_RST:
+			rst_reason="hw_rst";
+			break;
+
+		case MTK_WDT_STATUS_SWWDT_RST:
+			rst_reason="sw_rst";
+			break;
+
+		case MTK_WDT_STATUS_IRQWDT_RST:
+			rst_reason="irq_rst";
+			break;
+
+		case MTK_WDT_STATUS_SECURITY_RST:
+			rst_reason="security_rst";
+			break;
+
+		case MTK_WDT_STATUS_DEBUGWDT_RST:
+			rst_reason="debug_rst";
+			break;
+
+		case MTK_WDT_STATUS_THERMAL_CTL_RST:
+			rst_reason="thermal_ctl_rst";
+			break;
+
+		case MTK_WDT_STATUS_SPMWDT_RST:
+			rst_reason="spm_rst";
+			break;
+
+		case MTK_WDT_STATUS_SPM_THERMAL_RST:
+			rst_reason="spm_thermal_rst";
+			break;
+
+		default:
+			break;
+	}
+
+	return rst_reason;
+}
+
+void mtk_wdt_init(void)
+{
+    /* This function will store the reset reason: Time out/ SW trigger */
+    dprintf(ALWAYS, "Watchdog Status: %x , boot from %s\n",
+            mtk_wdt_check_status(),
+            parsing_reset_reason(mtk_wdt_check_status()));
+
+    mtk_wdt_mode_config(false, false, false, false, false);
+
+#if (!LK_WDT_DISABLE)
+    mtk_wdt_set_time_out_value(10);
+    mtk_wdt_mode_config(true, true, true, false, true);
+    mtk_wdt_restart();
+#endif
+}
+
+static bool mtk_is_rgu_trigger_reset(void)
+{
+    if (mtk_wdt_check_status())
+        return true;
+    return false;
+}
+
+void mtk_arch_reset(char mode)
+{
+    LTRACEF("UB mtk_arch_reset\n");
+
+    mtk_wdt_reset(mode);
+
+    while (1);
+}
+
+static void rgu_swsys_reset(WD_SYS_RST_TYPE reset_type)
+{
+    if (WD_MD_RST == reset_type) {
+        unsigned int wdt_dbg_ctrl;
+        wdt_dbg_ctrl = readl(MTK_WDT_SWSYSRST);
+        wdt_dbg_ctrl |= MTK_WDT_SWSYS_RST_KEY;
+        wdt_dbg_ctrl |= 0x80;// 1<<7
+        writel(wdt_dbg_ctrl, MTK_WDT_SWSYSRST);
+        spin(1000);
+        wdt_dbg_ctrl = readl(MTK_WDT_SWSYSRST);
+        wdt_dbg_ctrl |= MTK_WDT_SWSYS_RST_KEY;
+        wdt_dbg_ctrl &= (~0x80);// ~(1<<7)
+        writel(wdt_dbg_ctrl, MTK_WDT_SWSYSRST);
+        LTRACEF("rgu pl md reset\n");
+    }
+}
+
+void rgu_dram_reserved(bool enable)
+{
+    volatile unsigned int tmp;
+
+    if (enable) {
+        /* enable ddr reserved mode */
+        tmp = readl(MTK_WDT_MODE);
+        tmp |= (MTK_WDT_MODE_DDR_RESERVE|MTK_WDT_MODE_KEY);
+        writel(tmp, MTK_WDT_MODE);
+    } else {
+        /* disable ddr reserved mode, set reset mode,
+         * disable watchdog output reset signal
+         */
+        tmp = readl(MTK_WDT_MODE);
+        tmp &= (~MTK_WDT_MODE_DDR_RESERVE);
+        tmp |= MTK_WDT_MODE_KEY;
+        writel(tmp, MTK_WDT_MODE);
+    }
+
+    dprintf(CRITICAL,"RGU %s:MTK_WDT_MODE(%x)\n", __func__, tmp);
+}
+
+int rgu_is_reserve_ddr_enabled(void)
+{
+  unsigned int wdt_mode;
+  wdt_mode = readl(MTK_WDT_MODE);
+  if(wdt_mode & MTK_WDT_MODE_DDR_RESERVE)
+  {
+    return 1;
+  }
+  else
+  {
+    return 0;
+  }
+}
+
+int rgu_is_dram_slf(void)
+{
+  unsigned int wdt_dbg_ctrl;
+  wdt_dbg_ctrl = readl(MTK_WDT_DRAMC_CTL);
+  dprintf(CRITICAL,"DDR is in self-refresh. %x\n", wdt_dbg_ctrl);
+  if(wdt_dbg_ctrl & MTK_DDR_SREF_STA)
+  {
+    //dprintf(CRITICAL,"DDR is in self-refresh. %x\n", wdt_dbg_ctrl);
+    return 1;
+  }
+  else
+  {
+    //dprintf(CRITICAL,"DDR is not in self-refresh. %x\n", wdt_dbg_ctrl);
+    return 0;
+  }
+}
+
+void rgu_release_rg_dramc_conf_iso(void)
+{
+  unsigned int wdt_dbg_ctrl;
+  wdt_dbg_ctrl = readl(MTK_WDT_DRAMC_CTL);
+  wdt_dbg_ctrl &= (~MTK_RG_CONF_ISO);
+  wdt_dbg_ctrl |= MTK_DEBUG_CTL_KEY;
+  writel(wdt_dbg_ctrl, MTK_WDT_DRAMC_CTL);
+  dprintf(CRITICAL,"RGU %s:MTK_WDT_DRAMC_CTL(%x)\n", __func__,wdt_dbg_ctrl);
+}
+
+void rgu_release_rg_dramc_iso(void)
+{
+  unsigned int wdt_dbg_ctrl;
+  wdt_dbg_ctrl = readl(MTK_WDT_DRAMC_CTL);
+  wdt_dbg_ctrl &= (~MTK_RG_DRAMC_ISO);
+  wdt_dbg_ctrl |= MTK_DEBUG_CTL_KEY;
+  writel(wdt_dbg_ctrl, MTK_WDT_DRAMC_CTL);
+  dprintf(CRITICAL,"RGU %s:MTK_WDT_DRAMC_CTL(%x)\n", __func__,wdt_dbg_ctrl);
+}
+
+void rgu_release_rg_dramc_sref(void)
+{
+  unsigned int wdt_dbg_ctrl;
+  wdt_dbg_ctrl = readl(MTK_WDT_DRAMC_CTL);
+  wdt_dbg_ctrl &= (~MTK_RG_DRAMC_SREF);
+  wdt_dbg_ctrl |= MTK_DEBUG_CTL_KEY;
+  writel(wdt_dbg_ctrl, MTK_WDT_DRAMC_CTL);
+  dprintf(CRITICAL,"RGU %s:MTK_WDT_DRAMC_CTL(%x)\n", __func__,wdt_dbg_ctrl);
+}
+int rgu_is_reserve_ddr_mode_success(void)
+{
+  unsigned int wdt_dbg_ctrl;
+  wdt_dbg_ctrl = readl(MTK_WDT_DRAMC_CTL);
+  if(wdt_dbg_ctrl & MTK_DDR_RESERVE_RTA)
+  {
+    dprintf(CRITICAL,"WDT DDR reserve mode success! %x\n",wdt_dbg_ctrl);
+    return 1;
+  }
+  else
+  {
+    dprintf(CRITICAL,"WDT DDR reserve mode FAIL! %x\n",wdt_dbg_ctrl);
+    return 0;
+  }
+}
+
+#else
+
+void mtk_wdt_init(void)
+{
+    LTRACEF("UB WDT Dummy init called\n");
+}
+
+static bool mtk_is_rgu_trigger_reset()
+{
+    LTRACEF("UB Dummy mtk_is_rgu_trigger_reset called\n");
+    return FALSE;
+}
+
+void mtk_arch_reset(char mode)
+{
+    LTRACEF("UB WDT Dummy arch reset called\n");
+}
+
+void mtk_wdt_disable(void)
+{
+    LTRACEF("UB WDT Dummy mtk_wdt_disable called\n");
+}
+
+static void mtk_wdt_restart(void)
+{
+    LTRACEF("UB WDT Dummy mtk_wdt_restart called\n");
+}
+static void mtk_wdt_sw_reset(void)
+{
+    LTRACEF("UB WDT Dummy mtk_wdt_sw_reset called\n");
+}
+
+static void mtk_wdt_hw_reset(void)
+{
+    LTRACEF("UB WDT Dummy mtk_wdt_hw_reset called\n");
+}
+
+static void rgu_swsys_reset(WD_SYS_RST_TYPE reset_type)
+{
+    LTRACEF("UB WDT Dummy rgu_swsys_reset called\n");
+}
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt2712/fixup/android_fixup.c b/src/bsp/lk/platform/mediatek/mt2712/fixup/android_fixup.c
new file mode 100644
index 0000000..7fed149
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/fixup/android_fixup.c
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#include <boot_mode.h>
+#include <lib/bio.h>
+#include <lib/kcmdline.h>
+#include <malloc.h>
+#include <string.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+static void normal_mode_fixup(const char *ab_suffix)
+{
+
+#if defined(AB_OTA_UPDATER)
+     kcmdline_append("androidboot.force_normal_boot=1");
+#endif
+
+#if !defined(AVB_VERIFY_KERNEL)
+    bdev_t *bdev;
+    char *part_name;
+    char *part_uuid;
+    const char *suffix = ab_suffix ? : "";
+
+    part_name = (char *)malloc(strlen(ROOTFS_PART_NAME) +
+                               strlen(suffix) + 1);
+    if (!part_name) {
+        LTRACEF("Not enough memory for part_name\n");
+        return;
+    }
+
+    sprintf(part_name, "%s%s", ROOTFS_PART_NAME, suffix);
+
+    bdev = bio_open_by_label(part_name);
+    if (!bdev) {
+        LTRACEF("Partition not exist: %s\n", part_name);
+        goto err;
+    }
+
+    part_uuid = (char *)malloc(strlen("root=PARTUUID=") +
+                               strlen(bdev->unique_uuid) + 1);
+    if (!part_uuid) {
+        LTRACEF("Not enough memory for part_uuid\n");
+        goto err;
+    }
+
+    sprintf(part_uuid, "root=PARTUUID=%s", bdev->unique_uuid);
+    kcmdline_append(part_uuid);
+
+    free(part_uuid);
+err:
+    free(part_name);
+#endif
+}
+
+static void recovery_mode_fixup(void)
+{
+#if defined(AVB_VERIFY_KERNEL)
+    kcmdline_subst("root=/dev/dm-0", "root=/dev/ram");
+#else
+    kcmdline_append("root=/dev/ram");
+#endif
+}
+
+/* android specfic fixup hook function */
+void project_fixup_hook(uint32_t boot_mode, const char *ab_suffix)
+{
+    if ((boot_mode == NORMAL_BOOT) || (boot_mode == FASTBOOT_BOOT))
+        normal_mode_fixup(ab_suffix);
+    else /* RECOVERY_BOOT */
+        recovery_mode_fixup();
+
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/fixup/plat_fixup.c b/src/bsp/lk/platform/mediatek/mt2712/fixup/plat_fixup.c
new file mode 100644
index 0000000..c83c573
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/fixup/plat_fixup.c
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+#include <assert.h>
+#include <compiler.h>
+#include <err.h>
+#include <lib/kcmdline.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trace.h>
+
+#if WITH_SMP
+#include <arch/mp_mediatek.h>
+#endif
+
+#if LOG_STORE_SUPPORT
+#include <lib/log_store.h>
+#endif
+
+#define LOCAL_TRACE 0
+
+extern __WEAK void mrdump_append_cmdline(void);
+
+extern void project_fixup_hook(uint32_t boot_mode, const char *ab_suffix);
+
+#if defined(AB_OTA_UPDATER)
+static void ab_fixup(const char *ab_suffix)
+{
+    int rc __UNUSED;
+    char *suffix_arg;
+
+    if (!ab_suffix)
+        return;
+
+    suffix_arg = (char *)malloc(strlen("androidboot.slot_suffix=") +
+                                strlen(ab_suffix) + 1);
+    if (!suffix_arg) {
+        LTRACEF("Not enough memory for suffix cmdline\n");
+        return;
+    }
+
+    sprintf(suffix_arg, "androidboot.slot_suffix=%s", ab_suffix);
+    rc = kcmdline_append(suffix_arg);
+    assert(rc == NO_ERROR);
+    free(suffix_arg);
+}
+#endif
+
+/* need to do fixup when bl2 or bl33 lk will load kernel image */
+#if (defined(ENABLE_BUILTIN_BL33) && (ENABLE_BUILTIN_BL33 == 1)) || \
+    (defined(LK_AS_BL33) && (LK_AS_BL33 == 1))
+int plat_fixup_init(void)
+{
+#if WITH_SMP
+    /* cpu 4 (0x200) as new boot cpu */
+    plat_mp_bootcpu_handover(4);
+#endif
+
+    return kcmdline_init();
+}
+
+void plat_fixup_append(char *append_str)
+{
+    if (kcmdline_append(append_str) != NO_ERROR) {
+        LTRACEF("append str failed: %s\n", append_str);
+    }
+}
+
+void plat_fixup_hook(uint32_t boot_mode, const char *ab_suffix,
+                     void *dtb, size_t dtb_size)
+{
+    /* feature related fixup */
+#if defined(AB_OTA_UPDATER)
+    ab_fixup(ab_suffix);
+#endif
+
+#if (LOG_STORE_SUPPORT == 1)
+    log_store_append_cmdline();
+#endif
+
+    if (mrdump_append_cmdline)
+        mrdump_append_cmdline();
+
+    /* android or yocto project specific fixup */
+    project_fixup_hook(boot_mode, ab_suffix);
+
+    /* finalized fixup */
+    if (kcmdline_finalized(dtb, dtb_size)) {
+        LTRACEF("kcmdline finalized failed.\n");
+    }
+
+#if WITH_SMP
+    /* [TODO] When kernel supports big core booting, remove this to
+     * boot kernel by big core to reduce boot time */
+    plat_mp_bootcpu_handover(0);
+#endif
+}
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt2712/fixup/yocto_fixup.c b/src/bsp/lk/platform/mediatek/mt2712/fixup/yocto_fixup.c
new file mode 100644
index 0000000..bb02a18
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/fixup/yocto_fixup.c
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#include <boot_mode.h>
+#include <sys/types.h>
+
+void project_fixup_hook(uint32_t boot_mode, const char *ab_suffix)
+{
+    /* add yocto specific fixup imp. here */
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/dcm.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/dcm.h
new file mode 100644
index 0000000..b6262e7
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/dcm.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017 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.
+*/
+
+#ifndef DCM_H
+#define DCM_H
+
+void mt_dcm_init(void);
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/generic_ioctl.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/generic_ioctl.h
new file mode 100644
index 0000000..84c2ec8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/generic_ioctl.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_ASM_GENERIC_IOCTL_H
+#define _UAPI_ASM_GENERIC_IOCTL_H
+#define _IOC_NRBITS 8
+#define _IOC_TYPEBITS 8
+#ifndef _IOC_SIZEBITS
+#define _IOC_SIZEBITS 14
+#endif
+#ifndef _IOC_DIRBITS
+#define _IOC_DIRBITS 2
+#endif
+#define _IOC_NRMASK ((1 << _IOC_NRBITS) - 1)
+#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS) - 1)
+#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS) - 1)
+#define _IOC_DIRMASK ((1 << _IOC_DIRBITS) - 1)
+#define _IOC_NRSHIFT 0
+#define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS)
+#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS)
+#define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS)
+#ifndef _IOC_NONE
+#define _IOC_NONE 0U
+#endif
+#ifndef _IOC_WRITE
+#define _IOC_WRITE 1U
+#endif
+#ifndef _IOC_READ
+#define _IOC_READ 2U
+#endif
+#define _IOC(dir,type,nr,size) (((dir) << _IOC_DIRSHIFT) | ((type) << _IOC_TYPESHIFT) | ((nr) << _IOC_NRSHIFT) | ((size) << _IOC_SIZESHIFT))
+#define _IOC_TYPECHECK(t) (sizeof(t))
+#define _IO(type,nr) _IOC(_IOC_NONE, (type), (nr), 0)
+#define _IOR(type,nr,size) _IOC(_IOC_READ, (type), (nr), (_IOC_TYPECHECK(size)))
+#define _IOW(type,nr,size) _IOC(_IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size)))
+#define _IOWR(type,nr,size) _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size)))
+#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ, (type), (nr), sizeof(size))
+#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE, (type), (nr), sizeof(size))
+#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), sizeof(size))
+#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT ((_IOC_WRITE | _IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/gic.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/gic.h
new file mode 100644
index 0000000..133024e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/gic.h
@@ -0,0 +1,29 @@
+/*
+ * 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
+
+#include <platform/mt2712.h>
+
+#define GICBASE(n)  (PERIPHERAL_BASE_VIRT + 0x510000)
+#define GICD_OFFSET (0x0)
+#define GICC_OFFSET (0x10000)
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mmc_core.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mmc_core.h
new file mode 100644
index 0000000..550f428
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mmc_core.h
@@ -0,0 +1,666 @@
+/*
+ * 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
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <kernel/mutex.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MMC_BLOCK_BITS_SHFT             (9)
+#define MMC_BLOCK_SIZE                  (1 << MMC_BLOCK_BITS_SHFT)
+#define MMC_MAX_BLOCK_SIZE              (1 << MMC_BLOCK_BITS_SHFT)
+
+#define SDIO_MAX_FUNCS                  (7)
+
+#define SD_CMD_BIT                      (1 << 7)
+#define SD_CMD_APP_BIT                  (1 << 8)
+#define SD_CMD_AUTO_BIT                 (1 << 9)
+
+/* MMC command numbers */
+#define MMC_CMD_GO_IDLE_STATE           (0)              /* bc.   no response */
+#define MMC_CMD_SEND_OP_COND            (1)              /* bcr.  R3          */
+#define MMC_CMD_ALL_SEND_CID            (2)              /* bcr.  R2          */
+#define MMC_CMD_SET_RELATIVE_ADDR       (3)              /* ac.   R1          */
+#define MMC_CMD_SET_DSR                 (4)              /* bc.   no response */
+#define MMC_CMD_SLEEP_AWAKE             (5)              /* ac.   R1b         */
+#define MMC_CMD_SWITCH                  (6)              /* ac.   R1b         */
+#define MMC_CMD_SELECT_CARD             (7)              /* ac.   R1/R1b      */
+#define MMC_CMD_SEND_EXT_CSD            (8)              /* adtc. R1          */
+#define MMC_CMD_SEND_CSD                (9)              /* ac.   R2          */
+#define MMC_CMD_SEND_CID                (10)             /* ac.   R2          */
+#define MMC_CMD_READ_DAT_UNTIL_STOP     (11)             /* adtc. R1          */
+#define MMC_CMD_STOP_TRANSMISSION       (12)             /* ac.   R1/R1b      */
+#define MMC_CMD_SEND_STATUS             (13)             /* ac.   R1          */
+#define MMC_CMD_BUSTEST_R               (14)             /* adtc. R1          */
+#define MMC_CMD_GO_INACTIVE_STATE       (15)             /* ac.   no response */
+#define MMC_CMD_SET_BLOCKLEN            (16)             /* ac.   R1          */
+#define MMC_CMD_READ_SINGLE_BLOCK       (17)             /* adtc. R1          */
+#define MMC_CMD_READ_MULTIPLE_BLOCK     (18)             /* adtc. R1          */
+#define MMC_CMD_BUSTEST_W               (19)             /* adtc. R1          */
+#define MMC_CMD_WRITE_DAT_UNTIL_STOP    (20)             /* adtc. R1          */
+#define MMC_CMD21                       (21)             /* adtc. R1  Sandisk  */
+#define MMC_CMD_SET_BLOCK_COUNT         (23)             /* ac.   R1          */
+#define MMC_CMD_WRITE_BLOCK             (24)             /* adtc. R1          */
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK    (25)             /* adtc. R1          */
+#define MMC_CMD_PROGRAM_CID             (26)             /* adtc. R1          */
+#define MMC_CMD_PROGRAM_CSD             (27)             /* adtc. R1          */
+
+#define MMC_CMD_SET_WRITE_PROT          (28)             /* ac.   R1b         */
+#define MMC_CMD_CLR_WRITE_PROT          (29)             /* ac.   R1b         */
+#define MMC_CMD_SEND_WRITE_PROT         (30)             /* adtc. R1          */
+#define MMC_CMD_SEND_WRITE_PROT_TYPE    (31)             /* adtc. R1          */
+#define MMC_CMD_ERASE_WR_BLK_START      (32)
+#define MMC_CMD_ERASE_WR_BLK_END        (33)
+#define MMC_CMD_ERASE_GROUP_START       (35)             /* ac.   R1          */
+#define MMC_CMD_ERASE_GROUP_END         (36)             /* ac.   R1          */
+#define MMC_CMD_ERASE                   (38)             /* ac.   R1b         */
+#define MMC_CMD_FAST_IO                 (39)             /* ac.   R4          */
+#define MMC_CMD_GO_IRQ_STATE            (40)             /* bcr.  R5          */
+#define MMC_CMD_LOCK_UNLOCK             (42)             /* adtc. R1          */
+#define MMC_CMD50                       (50)             /* adtc. R1 Sandisk */
+#define MMC_CMD_APP_CMD                 (55)             /* ac.   R1          */
+#define MMC_CMD_GEN_CMD                 (56)             /* adtc. R1          */
+
+/* SD Card command numbers */
+#define SD_CMD_SEND_RELATIVE_ADDR       (3 | SD_CMD_BIT)
+#define SD_CMD_SWITCH                   (6 | SD_CMD_BIT)
+#define SD_CMD_SEND_IF_COND             (8 | SD_CMD_BIT)
+#define SD_CMD_VOL_SWITCH               (11 | SD_CMD_BIT)
+#define SD_CMD_SEND_TUNING_BLOCK        (19 | SD_CMD_BIT)
+#define SD_CMD_SPEED_CLASS_CTRL         (20 | SD_CMD_BIT)
+
+#define SD_ACMD_SET_BUSWIDTH            (6  | SD_CMD_APP_BIT)
+#define SD_ACMD_SD_STATUS               (13 | SD_CMD_APP_BIT)
+#define SD_ACMD_SEND_NR_WR_BLOCKS       (22 | SD_CMD_APP_BIT)
+#define SD_ACMD_SET_WR_ERASE_CNT        (23 | SD_CMD_APP_BIT)
+#define SD_ACMD_SEND_OP_COND            (41 | SD_CMD_APP_BIT)
+#define SD_ACMD_SET_CLR_CD              (42 | SD_CMD_APP_BIT)
+#define SD_ACMD_SEND_SCR                (51 | SD_CMD_APP_BIT)
+
+/* SDIO Card command numbers */
+#define SD_IO_SEND_OP_COND              (5 | SD_CMD_BIT) /* bcr. R4           */
+#define SD_IO_RW_DIRECT                 (52 | SD_CMD_BIT)/* ac.  R5           */
+#define SD_IO_RW_EXTENDED               (53 | SD_CMD_BIT)/* adtc. R5          */
+
+/* platform dependent command */
+#define SD_ATOCMD_STOP_TRANSMISSION     (12 | SD_CMD_AUTO_BIT)
+#define SD_ATOCMD_SET_BLOCK_COUNT       (23 | SD_CMD_AUTO_BIT)
+
+#define MMC_VDD_145_150 0x00000001  /* VDD voltage 1.45 - 1.50 */
+#define MMC_VDD_150_155 0x00000002  /* VDD voltage 1.50 - 1.55 */
+#define MMC_VDD_155_160 0x00000004  /* VDD voltage 1.55 - 1.60 */
+#define MMC_VDD_160_165 0x00000008  /* VDD voltage 1.60 - 1.65 */
+#define MMC_VDD_165_170 0x00000010  /* VDD voltage 1.65 - 1.70 */
+#define MMC_VDD_17_18   0x00000020  /* VDD voltage 1.7 - 1.8 */
+#define MMC_VDD_18_19   0x00000040  /* VDD voltage 1.8 - 1.9 */
+#define MMC_VDD_19_20   0x00000080  /* VDD voltage 1.9 - 2.0 */
+#define MMC_VDD_20_21   0x00000100  /* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22   0x00000200  /* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23   0x00000400  /* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24   0x00000800  /* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25   0x00001000  /* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26   0x00002000  /* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27   0x00004000  /* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28   0x00008000  /* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29   0x00010000  /* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30   0x00020000  /* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31   0x00040000  /* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32   0x00080000  /* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33   0x00100000  /* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34   0x00200000  /* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35   0x00400000  /* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36   0x00800000  /* VDD voltage 3.5 ~ 3.6 */
+#define MMC_CARD_BUSY   0x80000000  /* Card Power up status bit */
+#define MMC_VDD_165_195     0x00000080  /* VDD voltage 1.65 - 1.95 */ //Add this line by reference to include/linux/mmc/host.h in linux kernel
+#define MMC_VDD_27_36       0x00FF8000
+
+#define EMMC_VER_50   (50)
+#define EMMC_VER_45   (45)
+#define EMMC_VER_44   (44)
+#define EMMC_VER_43   (43)
+#define EMMC_VER_42   (42)
+#define SD_VER_10     (10)
+#define SD_VER_20     (20)
+#define SD_VER_30     (30)
+
+#define MMC_ERR_NONE          0
+#define MMC_ERR_TIMEOUT       1
+#define MMC_ERR_BADCRC        2
+#define MMC_ERR_FIFO          3
+#define MMC_ERR_FAILED        4
+#define MMC_ERR_INVALID       5
+#define MMC_ERR_CMDTUNEFAIL   6
+#define MMC_ERR_READTUNEFAIL  7
+#define MMC_ERR_WRITETUNEFAIL 8
+#define MMC_ERR_CMD_TIMEOUT   9
+#define MMC_ERR_CMD_RSPCRC    10
+#define MMC_ERR_ACMD_TIMEOUT  11
+#define MMC_ERR_ACMD_RSPCRC   12
+#define MMC_ERR_AXI_RSPCRC    13
+#define MMC_ERR_UNEXPECT      14
+#define MMC_ERR_RETRY         15
+
+#define MMC_POWER_OFF       0
+#define MMC_POWER_UP        1
+#define MMC_POWER_ON        2
+
+#define MMC_BUS_WIDTH_1     0
+#define MMC_BUS_WIDTH_4     2
+
+#define SD_BUS_WIDTH_1      0
+#define SD_BUS_WIDTH_4      2
+
+#define MMC_STATE_PRESENT       (1<<0)      /* present in sysfs */
+#define MMC_STATE_READONLY      (1<<1)      /* card is read-only */
+#define MMC_STATE_HIGHSPEED     (1<<2)      /* card is in high speed mode */
+#define MMC_STATE_BLOCKADDR     (1<<3)      /* card uses block-addressing */
+#define MMC_STATE_HIGHCAPS      (1<<4)
+#define MMC_STATE_UHS1          (1<<5)      /* card is in ultra high speed mode */
+#define MMC_STATE_DDR           (1<<6)      /* card is in ddr mode */
+#define MMC_STATE_HS200         (1<<7)
+#define MMC_STATE_HS400         (1<<8)
+#define MMC_STATE_BACKYARD      (1<<9)
+
+#define R1_OUT_OF_RANGE         (1UL << 31) /* er, c */
+#define R1_ADDRESS_ERROR        (1 << 30)   /* erx, c */
+#define R1_BLOCK_LEN_ERROR      (1 << 29)   /* er, c */
+#define R1_ERASE_SEQ_ERROR      (1 << 28)   /* er, c */
+#define R1_ERASE_PARAM          (1 << 27)   /* ex, c */
+#define R1_WP_VIOLATION         (1 << 26)   /* erx, c */
+#define R1_CARD_IS_LOCKED       (1 << 25)   /* sx, a */
+#define R1_LOCK_UNLOCK_FAILED   (1 << 24)   /* erx, c */
+#define R1_COM_CRC_ERROR        (1 << 23)   /* er, b */
+#define R1_ILLEGAL_COMMAND      (1 << 22)   /* er, b */
+#define R1_CARD_ECC_FAILED      (1 << 21)   /* ex, c */
+#define R1_CC_ERROR             (1 << 20)   /* erx, c */
+#define R1_ERROR                (1 << 19)   /* erx, c */
+#define R1_UNDERRUN             (1 << 18)   /* ex, c */
+#define R1_OVERRUN              (1 << 17)   /* ex, c */
+#define R1_CID_CSD_OVERWRITE    (1 << 16)   /* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP        (1 << 15)   /* sx, c */
+#define R1_CARD_ECC_DISABLED    (1 << 14)   /* sx, a */
+#define R1_ERASE_RESET          (1 << 13)   /* sr, c */
+#define R1_STATUS(x)            (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x)     ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
+#define R1_READY_FOR_DATA       (1 << 8)    /* sx, a */
+#define R1_SWITCH_ERROR         (1 << 7)    /* ex, b */
+#define R1_URGENT_BKOPS         (1 << 6)    /* sr, a */
+#define R1_APP_CMD              (1 << 5)    /* sr, c */
+
+/*
+ * Card Command Classes (CCC)
+ */
+#define CCC_BASIC               (1<<0)  /* (0) Basic protocol functions */
+/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
+#define CCC_STREAM_READ         (1<<1)  /* (1) Stream read commands */
+/* (CMD11) */
+#define CCC_BLOCK_READ          (1<<2)  /* (2) Block read commands */
+/* (CMD16,17,18) */
+#define CCC_STREAM_WRITE        (1<<3)  /* (3) Stream write commands */
+/* (CMD20) */
+#define CCC_BLOCK_WRITE         (1<<4)  /* (4) Block write commands */
+/* (CMD16,24,25,26,27) */
+#define CCC_ERASE               (1<<5)  /* (5) Ability to erase blocks */
+/* (CMD32,33,34,35,36,37,38,39) */
+#define CCC_WRITE_PROT          (1<<6)  /* (6) Able to write protect blocks */
+/* (CMD28,29,30) */
+#define CCC_LOCK_CARD           (1<<7)  /* (7) Able to lock down card */
+/* (CMD16,CMD42) */
+#define CCC_APP_SPEC            (1<<8)  /* (8) Application specific */
+/* (CMD55,56,57,ACMD*) */
+#define CCC_IO_MODE             (1<<9)  /* (9) I/O mode */
+/* (CMD5,39,40,52,53) */
+#define CCC_SWITCH              (1<<10) /* (10) High speed switch */
+/* (CMD6,34,35,36,37,50) */
+/* (11) Reserved */
+/* (CMD?) */
+
+/*
+ * CSD field definitions
+ */
+
+#define CSD_STRUCT_VER_1_0  0   /* Valid for system specification 1.0 - 1.2 */
+#define CSD_STRUCT_VER_1_1  1   /* Valid for system specification 1.4 - 2.2 */
+#define CSD_STRUCT_VER_1_2  2   /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
+#define CSD_STRUCT_EXT_CSD  3   /* Version is coded in CSD_STRUCTURE in EXT_CSD */
+
+#define CSD_SPEC_VER_0      0   /* Implements system specification 1.0 - 1.2 */
+#define CSD_SPEC_VER_1      1   /* Implements system specification 1.4 */
+#define CSD_SPEC_VER_2      2   /* Implements system specification 2.0 - 2.2 */
+#define CSD_SPEC_VER_3      3   /* Implements system specification 3.1 - 3.2 - 3.31 */
+#define CSD_SPEC_VER_4      4   /* Implements system specification 4.0 - 4.1 */
+
+/*
+ * EXT_CSD fields
+ */
+
+#define EXT_CSD_BADBLK_MGMT             134 /* R/W */
+#define EXT_CSD_ENH_START_ADDR          136 /* R/W 4 bytes */
+#define EXT_CSD_ENH_SIZE_MULT           140 /* R/W 3 bytes */
+#define EXT_CSD_GP1_SIZE_MULT           143 /* R/W 3 bytes */
+#define EXT_CSD_GP2_SIZE_MULT           146 /* R/W 3 bytes */
+#define EXT_CSD_GP3_SIZE_MULT           149 /* R/W 3 bytes */
+#define EXT_CSD_GP4_SIZE_MULT           152 /* R/W 3 bytes */
+#define EXT_CSD_PART_SET_COMPL          155 /* R/W */
+#define EXT_CSD_PART_ATTR               156 /* R/W 3 bytes */
+#define EXT_CSD_MAX_ENH_SIZE_MULT       157 /* R/W 3 bytes */
+#define EXT_CSD_PART_SUPPORT            160 /* R */
+#define EXT_CSD_HPI_MGMT                161 /* R/W/E_P (4.41) */
+#define EXT_CSD_RST_N_FUNC              162 /* R/W */
+#define EXT_CSD_BKOPS_EN                163 /* R/W (4.41) */
+#define EXT_CSD_BKOPS_START             164 /* W/E_P (4.41) */
+#define EXT_CSD_WR_REL_PARAM            166 /* R (4.41) */
+#define EXT_CSD_WR_REL_SET              167 /* R/W (4.41) */
+#define EXT_CSD_RPMB_SIZE_MULT          168 /* R */
+#define EXT_CSD_FW_CONFIG               169 /* R/W */
+#define EXT_CSD_USR_WP                  171 /* R/W, R/W/C_P & R/W/E_P */
+#define EXT_CSD_BOOT_WP                 173 /* R/W, R/W/C_P */
+#define EXT_CSD_ERASE_GRP_DEF           175 /* R/W/E */
+#define EXT_CSD_BOOT_BUS_WIDTH          177 /* R/W/E */
+#define EXT_CSD_BOOT_CONFIG_PROT        178 /* R/W & R/W/C_P */
+#define EXT_CSD_PART_CFG                179 /* R/W/E & R/W/E_P */
+#define EXT_CSD_ERASED_MEM_CONT         181 /* R */
+#define EXT_CSD_BUS_WIDTH               183 /* R/W */
+#define EXT_CSD_HS_TIMING               185 /* R/W */
+#define EXT_CSD_PWR_CLASS               187 /* R/W/E_P */
+#define EXT_CSD_CMD_SET_REV             189 /* R */
+#define EXT_CSD_CMD_SET                 191 /* R/W/E_P */
+#define EXT_CSD_REV                     192 /* R */
+#define EXT_CSD_STRUCT                  194 /* R */
+#define EXT_CSD_CARD_TYPE               196 /* RO */
+#define EXT_CSD_OUT_OF_INTR_TIME        198 /* R (4.41) */
+#define EXT_CSD_PART_SWITCH_TIME        199 /* R (4.41) */
+#define EXT_CSD_PWR_CL_52_195           200 /* R */
+#define EXT_CSD_PWR_CL_26_195           201 /* R */
+#define EXT_CSD_PWR_CL_52_360           202 /* R */
+#define EXT_CSD_PWR_CL_26_360           203 /* R */
+#define EXT_CSD_MIN_PERF_R_4_26         205 /* R */
+#define EXT_CSD_MIN_PERF_W_4_26         206 /* R */
+#define EXT_CSD_MIN_PERF_R_8_26_4_25    207 /* R */
+#define EXT_CSD_MIN_PERF_W_8_26_4_25    208 /* R */
+#define EXT_CSD_MIN_PERF_R_8_52         209 /* R */
+#define EXT_CSD_MIN_PERF_W_8_52         210 /* R */
+#define EXT_CSD_SEC_CNT                 212 /* RO, 4 bytes */
+#define EXT_CSD_S_A_TIMEOUT             217 /* R */
+#define EXT_CSD_S_C_VCCQ                219 /* R */
+#define EXT_CSD_S_C_VCC                 220 /* R */
+#define EXT_CSD_HC_WP_GPR_SIZE          221 /* R */
+#define EXT_CSD_REL_WR_SEC_C            222 /* R */
+#define EXT_CSD_ERASE_TIMEOUT_MULT      223 /* R */
+#define EXT_CSD_HC_ERASE_GRP_SIZE       224 /* R */
+#define EXT_CSD_ACC_SIZE                225 /* R */
+#define EXT_CSD_BOOT_SIZE_MULT          226 /* R */
+#define EXT_CSD_BOOT_INFO               228 /* R */
+#define EXT_CSD_SEC_TRIM_MULT           229 /* R */
+#define EXT_CSD_SEC_ERASE_MULT          230 /* R */
+#define EXT_CSD_SEC_FEATURE_SUPPORT     231 /* R */
+#define EXT_CSD_TRIM_MULT               232 /* R */
+#define EXT_CSD_MIN_PERF_DDR_R_8_52     234 /* R */
+#define EXT_CSD_MIN_PERF_DDR_W_8_52     235 /* R */
+#define EXT_CSD_PWR_CL_DDR_52_195       238 /* R */
+#define EXT_CSD_PWR_CL_DDR_52_360       239 /* R */
+#define EXT_CSD_INI_TIMEOUT_AP          241 /* R */
+#define EXT_CSD_CORRECT_PRG_SECTS_NUM   242 /* R, 4 bytes (4.41) */
+#define EXT_CSD_BKOPS_STATUS            246 /* R (4.41) */
+#define EXT_CSD_BKOPS_SUPP              502 /* R (4.41) */
+#define EXT_CSD_HPI_FEATURE             503 /* R (4.41) */
+#define EXT_CSD_S_CMD_SET               504 /* R */
+
+/*
+ * EXT_CSD field definitions
+ */
+
+/* SEC_FEATURE_SUPPORT[231] */
+#define EXT_CSD_SEC_FEATURE_ER_EN       (1<<0)
+#define EXT_CSD_SEC_FEATURE_BD_BLK_EN   (1<<2)
+#define EXT_CSD_SEC_FEATURE_GB_CL_EN    (1<<4)
+
+/* BOOT_INFO[228] */
+#define EXT_CSD_BOOT_INFO_ALT_BOOT      (1<<0)
+#define EXT_CSD_BOOT_INFO_DDR_BOOT      (1<<1)
+#define EXT_CSD_BOOT_INFO_HS_BOOT       (1<<2)
+
+#define EXT_CSD_CMD_SET_NORMAL          (1<<0)
+#define EXT_CSD_CMD_SET_SECURE          (1<<1)
+#define EXT_CSD_CMD_SET_CPSECURE        (1<<2)
+
+#define EXT_CSD_CARD_TYPE_26            (1<<0)  /* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_52            (1<<1)  /* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_DDR_52        (1<<2)  /* Card can run at DDR 52MHz@1.8V or 3V */
+#define EXT_CSD_CARD_TYPE_DDR_52_1_2V   (1<<3)  /* Card can run at DDR 52MHz@1.2V */
+#define EXT_CSD_CARD_TYPE_HS200_1_8V    (1<<4)  /* Card can run at 200MHz@ 1.8V*/
+#define EXT_CSD_CARD_TYPE_HS200_1_2V    (1<<5)  /* Card can run at 200MHz@ 1.2V*/
+#define EXT_CSD_CARD_TYPE_HS400_1_8V    (1<<6)  /* Card can run at 200MHz@ 1.8V*/
+#define EXT_CSD_CARD_TYPE_HS400_1_2V    (1<<7)  /* Card can run at 200MHz@ 1.2V*/
+
+/* BUS_WIDTH[183] */
+#define EXT_CSD_BUS_WIDTH_1             (0) /* Card is in 1 bit mode */
+#define EXT_CSD_BUS_WIDTH_4             (1) /* Card is in 4 bit mode */
+#define EXT_CSD_BUS_WIDTH_8             (2) /* Card is in 8 bit mode */
+#define EXT_CSD_BUS_WIDTH_4_DDR         (5) /* Card is in 4 bit mode + DDR */
+#define EXT_CSD_BUS_WIDTH_8_DDR         (6) /* Card is in 8 bit mode + DDR */
+
+/* high speed timing */
+#define EXT_CSD_HS_TIMEING_BACKWARDS    (0) /* selecting backwards compatibility interface timing */
+#define EXT_CSD_HS_TIMEING_HS           (1) /* selecting high speed  interface timing */
+#define EXT_CSD_HS_TIMEING_HS200        (2) /* selecting hs200 interface timing */
+#define EXT_CSD_HS_TIMEING_HS400        (3) /* selecting hs400 interface timing */
+
+/* ERASED_MEM_CONT[181] */
+#define EXT_CSD_ERASED_MEM_CONT_0       (0)
+#define EXT_CSD_ERASED_MEM_CONT_1       (1)
+
+/* PARTITION CONFIG[179] */
+#define EXT_CSD_PART_CFG_DEFT_PART      (0)
+#define EXT_CSD_PART_CFG_BOOT_PART_1    (1)
+#define EXT_CSD_PART_CFG_BOOT_PART_2    (2)
+#define EXT_CSD_PART_CFG_RPMB_PART      (3)
+#define EXT_CSD_PART_CFG_GP_PART_1      (4)
+#define EXT_CSD_PART_CFG_GP_PART_2      (5)
+#define EXT_CSD_PART_CFG_GP_PART_3      (6)
+#define EXT_CSD_PART_CFG_GP_PART_4      (7)
+#define EXT_CSD_PART_CFG_EN_NO_BOOT     (0 << 3)
+#define EXT_CSD_PART_CFG_EN_BOOT_PART_1 (1 << 3)
+#define EXT_CSD_PART_CFG_EN_BOOT_PART_2 (2 << 3)
+#define EXT_CSD_PART_CFG_EN_USER_AREA   (7 << 3)
+#define EXT_CSD_PART_CFG_EN_NO_ACK      (0 << 6)
+#define EXT_CSD_PART_CFG_EN_ACK         (1 << 6)
+
+/* BOOT_CONFIG_PROT[178] */
+#define EXT_CSD_EN_PWR_BOOT_CFG_PROT    (1)
+#define EXT_CSD_EN_PERM_BOOT_CFG_PROT   (1<<4)  /* Carefully */
+
+/* BOOT_BUS_WIDTH[177] */
+#define EXT_CSD_BOOT_BUS_WIDTH_1        (0)
+#define EXT_CSD_BOOT_BUS_WIDTH_4        (1)
+#define EXT_CSD_BOOT_BUS_WIDTH_8        (2)
+#define EXT_CSD_BOOT_BUS_RESET          (1 << 2)
+
+#define EXT_CSD_BOOT_BUS_MODE_DEFT      (0 << 3)
+#define EXT_CSD_BOOT_BUS_MODE_HS        (1 << 3)
+#define EXT_CSD_BOOT_BUS_MODE_DDR       (2 << 3)
+
+/* ERASE_GROUP_DEF[175] */
+#define EXT_CSD_ERASE_GRP_DEF_EN        (1)
+
+/* BOOT_WP[173] */
+#define EXT_CSD_BOOT_WP_EN_PWR_WP       (1)
+#define EXT_CSD_BOOT_WP_EN_PERM_WP      (1 << 2)
+#define EXT_CSD_BOOT_WP_DIS_PERM_WP     (1 << 4)
+#define EXT_CSD_BOOT_WP_DIS_PWR_WP      (1 << 6)
+
+/* USER_WP[171] */
+#define EXT_CSD_USR_WP_EN_PWR_WP        (1)
+#define EXT_CSD_USR_WP_EN_PERM_WP       (1<<2)
+#define EXT_CSD_USR_WP_DIS_PWR_WP       (1<<3)
+#define EXT_CSD_USR_WP_DIS_PERM_WP      (1<<4)
+#define EXT_CSD_USR_WP_DIS_CD_PERM_WP   (1<<6)
+#define EXT_CSD_USR_WP_DIS_PERM_PWD     (1<<7)
+
+/* RST_n_FUNCTION[162] */
+#define EXT_CSD_RST_N_TEMP_DIS          (0)
+#define EXT_CSD_RST_N_PERM_EN           (1) /* carefully */
+#define EXT_CSD_RST_N_PERM_DIS          (2) /* carefully */
+
+/* PARTITIONING_SUPPORT[160] */
+#define EXT_CSD_PART_SUPPORT_PART_EN     (1)
+#define EXT_CSD_PART_SUPPORT_ENH_ATTR_EN (1<<1)
+
+/* PARTITIONS_ATTRIBUTE[156] */
+#define EXT_CSD_PART_ATTR_ENH_USR       (1<<0)
+#define EXT_CSD_PART_ATTR_ENH_1         (1<<1)
+#define EXT_CSD_PART_ATTR_ENH_2         (1<<2)
+#define EXT_CSD_PART_ATTR_ENH_3         (1<<3)
+#define EXT_CSD_PART_ATTR_ENH_4         (1<<4)
+
+/* PARTITION_SETTING_COMPLETED[156] */
+#define EXT_CSD_PART_SET_COMPL_BIT      (1<<0)
+
+/*
+ * MMC_SWITCH access modes
+ */
+
+#define MMC_SWITCH_MODE_CMD_SET     0x00    /* Change the command set */
+#define MMC_SWITCH_MODE_SET_BITS    0x01    /* Set bits which are 1 in value */
+#define MMC_SWITCH_MODE_CLEAR_BITS  0x02    /* Clear bits which are 1 in value */
+#define MMC_SWITCH_MODE_WRITE_BYTE  0x03    /* Set target to value */
+
+#define MMC_SWITCH_MODE_SDR12       0
+#define MMC_SWITCH_MODE_SDR25       1
+#define MMC_SWITCH_MODE_SDR50       2
+#define MMC_SWITCH_MODE_SDR104      3
+#define MMC_SWITCH_MODE_DDR50       4
+
+#define MMC_SWITCH_MODE_DRV_TYPE_B  0
+#define MMC_SWITCH_MODE_DRV_TYPE_A  1
+#define MMC_SWITCH_MODE_DRV_TYPE_C  2
+#define MMC_SWITCH_MODE_DRV_TYPE_D  3
+
+#define MMC_SWITCH_MODE_CL_200MA    0
+#define MMC_SWITCH_MODE_CL_400MA    1
+#define MMC_SWITCH_MODE_CL_600MA    2
+#define MMC_SWITCH_MODE_CL_800MA    3
+
+/*
+ * MMC_ERASE arguments
+ */
+#define MMC_ERASE_SECURE_REQ        (1 << 31)
+#define MMC_ERASE_GC_REQ            (1 << 15)
+#define MMC_ERASE_DISCARD           (3 << 0)
+#define MMC_ERASE_TRIM              (1 << 0)
+#define MMC_ERASE_NORMAL            (0)
+
+#define HOST_BUS_WIDTH_1            (1)
+#define HOST_BUS_WIDTH_4            (4)
+#define HOST_BUS_WIDTH_8            (8)
+
+#define EMMC_BOOT_PULL_CMD_MODE     (0)
+#define EMMC_BOOT_RST_CMD_MODE      (1)
+
+enum {
+    EMMC_BOOT_PWR_RESET = 0,
+    EMMC_BOOT_RST_N_SIG,
+    EMMC_BOOT_PRE_IDLE_CMD
+};
+
+enum {
+    EMMC_PART_UNKNOWN = 0,
+    EMMC_PART_BOOT1,
+    EMMC_PART_BOOT2,
+    EMMC_PART_USER = 7
+};
+
+enum {
+    RESP_NONE = 0,
+    RESP_R1,
+    RESP_R2,
+    RESP_R3,
+    RESP_R4,
+    RESP_R5,
+    RESP_R6,
+    RESP_R7,
+    RESP_R1B
+};
+
+struct mmc_csd {
+    unsigned char  csd_struct;
+    unsigned char  mmca_vsn;
+    unsigned int   max_dtr;             /* max. data transfer rate */
+    unsigned int   read_blkbits;        /* max. read data block length */
+    unsigned int   capacity;            /* card capacity */
+};
+
+struct mmc_ext_csd {
+    unsigned int    sectors;
+    unsigned int    hs_max_dtr;
+    unsigned char   rev;
+    unsigned char   boot_info;
+    unsigned int    boot_part_sz;
+    unsigned int    rpmb_sz;
+    unsigned char   ddr_support;
+    unsigned char   hs400_support;
+    unsigned char   hs_timing;
+    unsigned char   part_cfg;
+    unsigned char   sec_support;
+    unsigned char   reset_en;
+};
+
+#define MMC_CAP_4_BIT_DATA      (1 << 0) /* Can the host do 4 bit transfers */
+#define MMC_CAP_MULTIWRITE      (1 << 1) /* Can accurately report bytes sent to card on error */
+#define MMC_CAP_BYTEBLOCK       (1 << 2) /* Can do non-log2 block sizes */
+#define MMC_CAP_MMC_HIGHSPEED   (1 << 3) /* Can do MMC high-speed timing */
+#define MMC_CAP_SD_HIGHSPEED    (1 << 4) /* Can do SD high-speed timing */
+#define MMC_CAP_8_BIT_DATA      (1 << 5) /* Can the host do 8 bit transfers */
+#define MMC_CAP_SD_UHS1         (1 << 6) /* Can do SD ultra-high-speed timing */
+#define MMC_CAP_DDR             (1 << 7) /* The host support dual data rate */
+#define MMC_CAP_EMMC_HS200      (1 << 8) /* The host support dual data rate */
+#define MMC_CAP_EMMC_HS400      (1 << 9) /* The host support dual data rate */
+
+struct mmc_host {
+    u8 host_id;
+    struct mmc_card *card;
+    u32 max_phys_segs;
+    addr_t base;      /* host base address */
+    u32 caps;         /* Host capabilities */
+    u32 f_min;        /* host min. frequency */
+    u32 f_max;        /* host max. frequency */
+    u32 clk;          /* host clock speed */
+    u32 sclk;         /* SD/MS clock speed */
+    u32 blklen;       /* block len */
+    u32 ocr;          /* current ocr */
+    u32 ocr_avail;    /* available ocr */
+    u32 timeout_ns;   /* data timeout ns */
+    u32 timeout_clks; /* data timeout clks */
+    u8  clksrc;       /* clock source */
+    u8  hclksrc;       /* clock source */
+    u8  curr_part;    /* host current working partition */
+    u32 intr_mask;    /* Interrupt mask */
+    u32  time_read;
+    void *priv;       /* private data */
+    mutex_t lock;    /* mutex lock for multi-thread */
+    int (*blk_read)(struct mmc_host *host, u8 *dst, u32 src, u32 nblks);
+    int (*blk_write)(struct mmc_host *host, u32 dst, u8 *src, u32 nblks);
+    bool skip_reinit;
+};
+
+#define MMC_TYPE_UNKNOWN    (0)          /* Unknown card */
+#define MMC_TYPE_MMC        (0x00000001) /* MMC card */
+#define MMC_TYPE_SD         (0x00000002) /* SD card */
+#define MMC_TYPE_SDIO       (0x00000004) /* SDIO card */
+
+/* MMC device */
+struct mmc_card {
+    struct mmc_host        *host;       /* the host this device belongs to */
+    unsigned int            nblks;
+    unsigned int            blklen;
+    unsigned int            ocr;
+    unsigned int            maxhz;
+    unsigned int            uhs_mode;
+    unsigned int            rca;        /* relative card address of device */
+    unsigned int            type;       /* card type */
+    unsigned int            sdio_funcs; /* number of SDIO functions */
+    unsigned short          state;      /* (our) card state */
+    unsigned short          ready;      /* card is ready or not */
+    u32                     raw_cid[4]; /* raw card CID */
+    u32                     raw_csd[4]; /* raw card CSD */
+    struct mmc_csd          csd;        /* card specific */
+    struct mmc_ext_csd      ext_csd;    /* mmc v4 extended card specific */
+    u8                      version;    /* the SD card version, 1.0, 2.0, or 3.0*/
+};
+
+struct mmc_command {
+    u32 opcode;
+    u32 arg;
+    u32 rsptyp;
+    u32 resp[4];
+    u32 timeout;
+    u32 retries;    /* max number of retries */
+    u32 error;      /* command error */
+};
+
+struct mmc_data {
+    u8  *buf;
+    struct mmc_command *cmd;
+    u32  blks;
+    u32  timeout;   /* ms */
+};
+
+#define mmc_card_mmc(c)             ((c)->type & MMC_TYPE_MMC)
+#define mmc_card_sd(c)              ((c)->type & MMC_TYPE_SD)
+
+#define mmc_card_set_host(c,h)      ((c)->host = (h))
+#define mmc_card_set_unknown(c)     ((c)->type = MMC_TYPE_UNKNOWN)
+#define mmc_card_set_mmc(c)         ((c)->type |= MMC_TYPE_MMC)
+#define mmc_card_set_sd(c)          ((c)->type |= MMC_TYPE_SD)
+
+#define mmc_card_present(c)         ((c)->state & MMC_STATE_PRESENT)
+#define mmc_card_readonly(c)        ((c)->state & MMC_STATE_READONLY)
+#define mmc_card_backyard(c)        ((c)->state & MMC_STATE_BACKYARD)
+#define mmc_card_highspeed(c)       ((c)->state & MMC_STATE_HIGHSPEED)
+#define mmc_card_uhs1(c)            ((c)->state & MMC_STATE_UHS1)
+#define mmc_card_hs200(c)           ((c)->state & MMC_STATE_HS200)
+#define mmc_card_hs400(c)           ((c)->state & MMC_STATE_HS400)
+#define mmc_card_ddr(c)             ((c)->state & MMC_STATE_DDR)
+#define mmc_card_blockaddr(c)       ((c)->state & MMC_STATE_BLOCKADDR)
+#define mmc_card_highcaps(c)        ((c)->state & MMC_STATE_HIGHCAPS)
+
+#define mmc_card_set_present(c)     ((c)->state |= MMC_STATE_PRESENT)
+#define mmc_card_set_readonly(c)    ((c)->state |= MMC_STATE_READONLY)
+#define mmc_card_set_backyard(c)    ((c)->state |= MMC_STATE_BACKYARD)
+#define mmc_card_set_highspeed(c)   ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_set_uhs1(c)        ((c)->state |= MMC_STATE_UHS1)
+#define mmc_card_set_hs200(c)       ((c)->state |= MMC_STATE_HS200)
+#define mmc_card_set_hs400(c)       ((c)->state |= MMC_STATE_HS400)
+#define mmc_card_set_ddr(c)         ((c)->state |= MMC_STATE_DDR)
+#define mmc_card_set_blockaddr(c)   ((c)->state |= MMC_STATE_BLOCKADDR)
+
+#define mmc_card_clear_present(c)     ((c)->state &= ~MMC_STATE_PRESENT)
+#define mmc_card_clear_readonly(c)    ((c)->state &= ~MMC_STATE_READONLY)
+#define mmc_card_clear_highspeed(c)   ((c)->state &= ~MMC_STATE_HIGHSPEED)
+#define mmc_card_clear_uhs1(c)        ((c)->state &= ~MMC_STATE_UHS1)
+#define mmc_card_clear_hs200(c)       ((c)->state &= ~MMC_STATE_HS200)
+#define mmc_card_clear_hs400(c)       ((c)->state &= ~MMC_STATE_HS400)
+#define mmc_card_clear_ddr(c)         ((c)->state &= ~MMC_STATE_DDR)
+#define mmc_card_clear_blockaddr(c)   ((c)->state &= ~MMC_STATE_BLOCKADDR)
+
+#define mmc_card_clr_ddr(c)         ((c)->state &= ~MMC_STATE_DDR)
+#define mmc_card_clr_speed_mode(c)  ((c)->state &= ~(MMC_STATE_HS400 | MMC_STATE_HS200 | MMC_STATE_UHS1 | MMC_STATE_HIGHSPEED | MMC_STATE_BACKYARD))
+
+#define mmc_card_name(c)            ((c)->cid.prod_name)
+
+#define mmc_op_multi(op)    (((op) == MMC_CMD_READ_MULTIPLE_BLOCK) || \
+        ((op) == MMC_CMD_WRITE_MULTIPLE_BLOCK))
+
+int mmc_get_boot_part(u32 *bootpart);
+int mmc_set_boot_part(u32 bootpart);
+struct mmc_card *emmc_init_stage1(bool *retry_opcond, bool skip_reinit);
+int emmc_init_stage2(struct mmc_card *card, bool retry_opcond, bool skip_reinit);
+int sdmmc_init(u8 host_id, bool skip_reinit);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mmc_ioctl.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mmc_ioctl.h
new file mode 100644
index 0000000..6afd29b
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mmc_ioctl.h
@@ -0,0 +1,76 @@
+#ifndef LINUX_MMC_IOCTL_H
+#define LINUX_MMC_IOCTL_H
+
+#include <sys/types.h>
+#include "generic_ioctl.h"
+
+struct mmc_ioc_cmd {
+	/* Implies direction of data.  true = write, false = read */
+	int write_flag;
+
+	/* Application-specific command.  true = precede with CMD55 */
+	int is_acmd;
+
+	u32 opcode;
+	u32 arg;
+	u32 response[4];  /* CMD response */
+	unsigned int flags;
+	unsigned int blksz;
+	unsigned int blocks;
+
+	/*
+	 * Sleep at least postsleep_min_us useconds, and at most
+	 * postsleep_max_us useconds *after* issuing command.  Needed for
+	 * some read commands for which cards have no other way of indicating
+	 * they're ready for the next command (i.e. there is no equivalent of
+	 * a "busy" indicator for read operations).
+	 */
+	unsigned int postsleep_min_us;
+	unsigned int postsleep_max_us;
+
+	/*
+	 * Override driver-computed timeouts.  Note the difference in units!
+	 */
+	unsigned int data_timeout_ns;
+	unsigned int cmd_timeout_ms;
+
+	/*
+	 * For 64-bit machines, the next member, ``u64 data_ptr``, wants to
+	 * be 8-byte aligned.  Make sure this struct is the same size when
+	 * built for 32-bit.
+	 */
+	u32 __pad;
+
+	/* DAT buffer */
+	u64 data_ptr;
+};
+#define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (u64)(unsigned long) ptr
+
+/**
+ * struct mmc_ioc_multi_cmd - multi command information
+ * @num_of_cmds: Number of commands to send. Must be equal to or less than
+ *	MMC_IOC_MAX_CMDS.
+ * @cmds: Array of commands with length equal to 'num_of_cmds'
+ */
+struct mmc_ioc_multi_cmd {
+	u64 num_of_cmds;
+	struct mmc_ioc_cmd cmds[0];
+};
+
+#define MMC_BLOCK_MAJOR 179
+#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd)
+/*
+ * MMC_IOC_MULTI_CMD: Used to send an array of MMC commands described by
+ *	the structure mmc_ioc_multi_cmd. The MMC driver will issue all
+ *	commands in array in sequence to card.
+ */
+#define MMC_IOC_MULTI_CMD _IOWR(MMC_BLOCK_MAJOR, 1, struct mmc_ioc_multi_cmd)
+/*
+ * Since this ioctl is only meant to enhance (and not replace) normal access
+ * to the mmc bus device, an upper data transfer limit of MMC_IOC_MAX_BYTES
+ * is enforced per ioctl call.  For larger data transfers, use the normal
+ * block device operations.
+ */
+#define MMC_IOC_MAX_BYTES  (512L * 1024)
+#define MMC_IOC_MAX_CMDS    255
+#endif /* LINUX_MMC_IOCTL_H */
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mmc_rpmb.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mmc_rpmb.h
new file mode 100755
index 0000000..237dff7
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mmc_rpmb.h
@@ -0,0 +1,59 @@
+
+
+#ifndef _MMC_RPMB_H
+#define _MMC_RPMB_H
+
+#include "mmc_core.h"
+
+/* ==================================================================================
+
+   RPMB definition
+
+====================================================================================*/
+#define RPMB_SZ_STUFF 196
+#define RPMB_SZ_MAC   32
+#define RPMB_SZ_DATA  256
+#define RPMB_SZ_NONCE 16
+
+#define RPMB_PROGRAM_KEY       1       /* Program RPMB Authentication Key */
+#define RPMB_GET_WRITE_COUNTER 2       /* Read RPMB write counter */
+#define RPMB_WRITE_DATA        3       /* Write data to RPMB partition */
+#define RPMB_READ_DATA         4       /* Read data from RPMB partition */
+#define RPMB_RESULT_READ       5       /* Read result request */
+#define RPMB_REQ               1       /* RPMB request mark */
+#define RPMB_RESP              (1 << 1)/* RPMB response mark */
+#define RPMB_AVALIABLE_SECTORS 8       /* 4K page size */
+
+#define RPMB_TYPE_BEG          510
+#define RPMB_RES_BEG           508
+#define RPMB_BLKS_BEG          506
+#define RPMB_ADDR_BEG          504
+#define RPMB_WCOUNTER_BEG      500
+
+#define RPMB_NONCE_BEG         484
+#define RPMB_DATA_BEG          228
+#define RPMB_MAC_BEG           196
+
+struct mmc_rpmb_cfg {
+    u16 type;                     /* RPMB request type */
+    u16 result;                  /* response or request result */
+    u16 blk_cnt;                  /* Number of blocks(half sector 256B) */
+    u16 addr;                     /* data address */
+    u32 *wc;                      /* write counter */
+    u8 *nonce;                    /* Ramdom number */
+    u8 *data;                     /* Buffer of the user data */
+    u8 *mac;                      /* Message Authentication Code */
+};
+
+struct mmc_rpmb_req {
+    struct mmc_rpmb_cfg *rpmb_cfg;
+    u8 *data_frame;
+};
+
+extern int mmc_rpmb_set_key(u8 *key);
+extern u32 mmc_rpmb_get_size(void);
+extern u32 mmc_rpmb_get_rel_wr_sec_c(void);
+
+extern int mmc_rpmb_block_read(int blknr, unsigned char blk[256]);
+extern int mmc_rpmb_block_write(int blknr, unsigned char blk[256]);
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/msdc.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/msdc.h
new file mode 100644
index 0000000..3d0dba4
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/msdc.h
@@ -0,0 +1,1035 @@
+/*
+ * 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
+
+#include <reg.h>
+#include <platform/msdc_cfg.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mmc_core.h>
+
+/*--------------------------------------------------------------------------*/
+/* Common Macro                                                             */
+/*--------------------------------------------------------------------------*/
+#define REG_ADDR(x)             ((volatile uint32_t *)(uintptr_t)(base + OFFSET_##x))
+
+/*--------------------------------------------------------------------------*/
+/* Common Definition                                                        */
+/*--------------------------------------------------------------------------*/
+#define MSDC_FIFO_SZ            (128)
+#define MSDC_FIFO_THD           (128)
+//#define MSDC_MAX_NUM            (2)
+
+#define MSDC_MS                 (0)
+#define MSDC_SDMMC              (1)
+
+#define MSDC_MODE_UNKNOWN       (0)
+#define MSDC_MODE_PIO           (1)
+#define MSDC_MODE_DMA_BASIC     (2)
+#define MSDC_MODE_DMA_DESC      (3)
+#define MSDC_MODE_DMA_ENHANCED  (4)
+#define MSDC_MODE_MMC_STREAM    (5)
+
+#define MSDC_BUS_1BITS          (0)
+#define MSDC_BUS_4BITS          (1)
+#define MSDC_BUS_8BITS          (2)
+
+#define MSDC_BURST_8B           (3)
+#define MSDC_BURST_16B          (4)
+#define MSDC_BURST_32B          (5)
+#define MSDC_BURST_64B          (6)
+
+#define MSDC_PIN_PULL_NONE      (0)
+#define MSDC_PIN_PULL_DOWN      (1)
+#define MSDC_PIN_PULL_UP        (2)
+#define MSDC_PIN_KEEP           (3)
+
+#ifdef FPGA_PLATFORM
+#define MSDC_OP_SCLK            (12000000)
+#define MSDC_MAX_SCLK           MSDC_OP_SCLK / 2
+#else
+#define MSDC_OP_SCLK            (200000000)
+#define MSDC_MAX_SCLK           (200000000)
+#endif
+
+#define MSDC_MIN_SCLK           (260000)
+
+#define MSDC_350K_SCLK          (350000)
+#define MSDC_400K_SCLK          (400000)
+#define MSDC_25M_SCLK           (25000000)
+#define MSDC_26M_SCLK           (26000000)
+#define MSDC_50M_SCLK           (50000000)
+#define MSDC_52M_SCLK           (52000000)
+#define MSDC_100M_SCLK          (100000000)
+#define MSDC_179M_SCLK          (179000000)
+#define MSDC_200M_SCLK          (200000000)
+#define MSDC_208M_SCLK          (208000000)
+#define MSDC_400M_SCLK          (400000000)
+#define MSDC_800M_SCLK          (800000000)
+
+#define MSDC_AUTOCMD12          (0x0001)
+#define MSDC_AUTOCMD23          (0x0002)
+#define MSDC_AUTOCMD19          (0x0003)
+
+#define TYPE_CMD_RESP_EDGE      (0)
+#define TYPE_WRITE_CRC_EDGE     (1)
+#define TYPE_READ_DATA_EDGE     (2)
+#define TYPE_WRITE_DATA_EDGE    (3)
+
+#define START_AT_RISING                 (0x0)
+#define START_AT_FALLING                (0x1)
+#define START_AT_RISING_AND_FALLING     (0x2)
+#define START_AT_RISING_OR_FALLING      (0x3)
+
+#define MSDC_DMA_BURST_8B       (3)
+#define MSDC_DMA_BURST_16B      (4)
+#define MSDC_DMA_BURST_32B      (5)
+#define MSDC_DMA_BURST_64B      (6)
+
+/*--------------------------------------------------------------------------*/
+/* Register Offset                                                          */
+/*--------------------------------------------------------------------------*/
+#define OFFSET_MSDC_CFG                  (0x00)
+#define OFFSET_MSDC_IOCON                (0x04)
+#define OFFSET_MSDC_PS                   (0x08)
+#define OFFSET_MSDC_INT                  (0x0c)
+#define OFFSET_MSDC_INTEN                (0x10)
+#define OFFSET_MSDC_FIFOCS               (0x14)
+#define OFFSET_MSDC_TXDATA               (0x18)
+#define OFFSET_MSDC_RXDATA               (0x1c)
+#define OFFSET_SDC_CFG                   (0x30)
+#define OFFSET_SDC_CMD                   (0x34)
+#define OFFSET_SDC_ARG                   (0x38)
+#define OFFSET_SDC_STS                   (0x3c)
+#define OFFSET_SDC_RESP0                 (0x40)
+#define OFFSET_SDC_RESP1                 (0x44)
+#define OFFSET_SDC_RESP2                 (0x48)
+#define OFFSET_SDC_RESP3                 (0x4c)
+#define OFFSET_SDC_BLK_NUM               (0x50)
+#define OFFSET_SDC_VOL_CHG               (0x54)
+#define OFFSET_SDC_CSTS                  (0x58)
+#define OFFSET_SDC_CSTS_EN               (0x5c)
+#define OFFSET_SDC_DCRC_STS              (0x60)
+#define OFFSET_SDC_AVG_CFG0              (0x64)
+
+/* Only for EMMC Controller 4 registers below */
+#define OFFSET_EMMC_CFG0                 (0x70)
+#define OFFSET_EMMC_CFG1                 (0x74)
+#define OFFSET_EMMC_STS                  (0x78)
+#define OFFSET_EMMC_IOCON                (0x7c)
+
+#define OFFSET_SDC_ACMD_RESP             (0x80)
+#define OFFSET_SDC_ACMD19_TRG            (0x84)
+#define OFFSET_SDC_ACMD19_STS            (0x88)
+#define OFFSET_MSDC_DMA_HIGH4BIT         (0x8C)
+#define OFFSET_MSDC_DMA_SA               (0x90)
+#define OFFSET_MSDC_DMA_CA               (0x94)
+#define OFFSET_MSDC_DMA_CTRL             (0x98)
+#define OFFSET_MSDC_DMA_CFG              (0x9c)
+#define OFFSET_MSDC_DBG_SEL              (0xa0)
+#define OFFSET_MSDC_DBG_OUT              (0xa4)
+#define OFFSET_MSDC_DMA_LEN              (0xa8)
+#define OFFSET_MSDC_PATCH_BIT0           (0xb0)
+#define OFFSET_MSDC_PATCH_BIT1           (0xb4)
+#define OFFSET_MSDC_PATCH_BIT2           (0xb8)
+
+/* Only for SD/SDIO Controller 6 registers below */
+#define OFFSET_DAT0_TUNE_CRC             (0xc0)
+#define OFFSET_DAT1_TUNE_CRC             (0xc4)
+#define OFFSET_DAT2_TUNE_CRC             (0xc8)
+#define OFFSET_DAT3_TUNE_CRC             (0xcc)
+#define OFFSET_CMD_TUNE_CRC              (0xd0)
+#define OFFSET_SDIO_TUNE_WIND            (0xd4)
+
+#define OFFSET_MSDC_PAD_TUNE             (0xF0)
+#define OFFSET_MSDC_PAD_TUNE0            (0xF0)
+#define OFFSET_MSDC_PAD_TUNE1            (0xF4)
+#define OFFSET_MSDC_DAT_RDDLY0           (0xF8)
+#define OFFSET_MSDC_DAT_RDDLY1           (0xFC)
+
+#define OFFSET_MSDC_DAT_RDDLY2           (0x100)
+#define OFFSET_MSDC_DAT_RDDLY3           (0x104)
+
+#define OFFSET_MSDC_HW_DBG               (0x110)
+#define OFFSET_MSDC_VERSION              (0x114)
+#define OFFSET_MSDC_ECO_VER              (0x118)
+
+/* Only for EMMC 5.0 Controller 4 registers below */
+#define OFFSET_EMMC50_PAD_CTL0           (0x180)
+#define OFFSET_EMMC50_PAD_DS_CTL0        (0x184)
+#define OFFSET_EMMC50_PAD_DS_TUNE        (0x188)
+#define OFFSET_EMMC50_PAD_CMD_TUNE       (0x18c)
+#define OFFSET_EMMC50_PAD_DAT01_TUNE     (0x190)
+#define OFFSET_EMMC50_PAD_DAT23_TUNE     (0x194)
+#define OFFSET_EMMC50_PAD_DAT45_TUNE     (0x198)
+#define OFFSET_EMMC50_PAD_DAT67_TUNE     (0x19c)
+#define OFFSET_EMMC51_CFG0               (0x204)
+#define OFFSET_EMMC50_CFG0               (0x208)
+#define OFFSET_EMMC50_CFG1               (0x20c)
+#define OFFSET_EMMC50_CFG2               (0x21c)
+#define OFFSET_EMMC50_CFG3               (0x220)
+#define OFFSET_EMMC50_CFG4               (0x224)
+#define OFFSET_SDC_FIFO_CFG              (0x228)
+/*--------------------------------------------------------------------------*/
+/* Register Address                                                         */
+/*--------------------------------------------------------------------------*/
+/* common register */
+#define MSDC_CFG                         REG_ADDR(MSDC_CFG)
+#define MSDC_IOCON                       REG_ADDR(MSDC_IOCON)
+#define MSDC_PS                          REG_ADDR(MSDC_PS)
+#define MSDC_INT                         REG_ADDR(MSDC_INT)
+#define MSDC_INTEN                       REG_ADDR(MSDC_INTEN)
+#define MSDC_FIFOCS                      REG_ADDR(MSDC_FIFOCS)
+#define MSDC_TXDATA                      REG_ADDR(MSDC_TXDATA)
+#define MSDC_RXDATA                      REG_ADDR(MSDC_RXDATA)
+
+/* sdmmc register */
+#define SDC_CFG                          REG_ADDR(SDC_CFG)
+#define SDC_CMD                          REG_ADDR(SDC_CMD)
+#define SDC_ARG                          REG_ADDR(SDC_ARG)
+#define SDC_STS                          REG_ADDR(SDC_STS)
+#define SDC_RESP0                        REG_ADDR(SDC_RESP0)
+#define SDC_RESP1                        REG_ADDR(SDC_RESP1)
+#define SDC_RESP2                        REG_ADDR(SDC_RESP2)
+#define SDC_RESP3                        REG_ADDR(SDC_RESP3)
+#define SDC_BLK_NUM                      REG_ADDR(SDC_BLK_NUM)
+#define SDC_VOL_CHG                      REG_ADDR(SDC_VOL_CHG)
+#define SDC_CSTS                         REG_ADDR(SDC_CSTS)
+#define SDC_CSTS_EN                      REG_ADDR(SDC_CSTS_EN)
+#define SDC_DCRC_STS                     REG_ADDR(SDC_DCRC_STS)
+#define SDC_AVG_CFG0                     REG_ADDR(SDC_AVG_CFG0)
+
+/* emmc register*/
+#define EMMC_CFG0                        REG_ADDR(EMMC_CFG0)
+#define EMMC_CFG1                        REG_ADDR(EMMC_CFG1)
+#define EMMC_STS                         REG_ADDR(EMMC_STS)
+#define EMMC_IOCON                       REG_ADDR(EMMC_IOCON)
+
+/* auto command register */
+#define SDC_ACMD_RESP                    REG_ADDR(SDC_ACMD_RESP)
+#define SDC_ACMD19_TRG                   REG_ADDR(SDC_ACMD19_TRG)
+#define SDC_ACMD19_STS                   REG_ADDR(SDC_ACMD19_STS)
+
+/* dma register */
+#define MSDC_DMA_HIGH4BIT                REG_ADDR(MSDC_DMA_HIGH4BIT)
+#define MSDC_DMA_SA                      REG_ADDR(MSDC_DMA_SA)
+#define MSDC_DMA_CA                      REG_ADDR(MSDC_DMA_CA)
+#define MSDC_DMA_CTRL                    REG_ADDR(MSDC_DMA_CTRL)
+#define MSDC_DMA_CFG                     REG_ADDR(MSDC_DMA_CFG)
+
+/* debug register */
+#define MSDC_DBG_SEL                     REG_ADDR(MSDC_DBG_SEL)
+#define MSDC_DBG_OUT                     REG_ADDR(MSDC_DBG_OUT)
+#define MSDC_DMA_LEN                     REG_ADDR(MSDC_DMA_LEN)
+
+/* misc register */
+#define MSDC_PATCH_BIT0                  REG_ADDR(MSDC_PATCH_BIT0)
+#define MSDC_PATCH_BIT1                  REG_ADDR(MSDC_PATCH_BIT1)
+#define MSDC_PATCH_BIT2                  REG_ADDR(MSDC_PATCH_BIT2)
+#define DAT0_TUNE_CRC                    REG_ADDR(DAT0_TUNE_CRC)
+#define DAT1_TUNE_CRC                    REG_ADDR(DAT1_TUNE_CRC)
+#define DAT2_TUNE_CRC                    REG_ADDR(DAT2_TUNE_CRC)
+#define DAT3_TUNE_CRC                    REG_ADDR(DAT3_TUNE_CRC)
+#define CMD_TUNE_CRC                     REG_ADDR(CMD_TUNE_CRC)
+#define SDIO_TUNE_WIND                   REG_ADDR(SDIO_TUNE_WIND)
+#define MSDC_PAD_TUNE                    REG_ADDR(MSDC_PAD_TUNE)
+#define MSDC_PAD_TUNE0                   REG_ADDR(MSDC_PAD_TUNE0)
+#define MSDC_PAD_TUNE1                   REG_ADDR(MSDC_PAD_TUNE1)
+
+/* data read delay */
+#define MSDC_DAT_RDDLY0                  REG_ADDR(MSDC_DAT_RDDLY0)
+#define MSDC_DAT_RDDLY1                  REG_ADDR(MSDC_DAT_RDDLY1)
+#define MSDC_DAT_RDDLY2                  REG_ADDR(MSDC_DAT_RDDLY2)
+#define MSDC_DAT_RDDLY3                  REG_ADDR(MSDC_DAT_RDDLY3)
+
+#define MSDC_HW_DBG                      REG_ADDR(MSDC_HW_DBG)
+#define MSDC_VERSION                     REG_ADDR(MSDC_VERSION)
+#define MSDC_ECO_VER                     REG_ADDR(MSDC_ECO_VER)
+/* eMMC 5.0 register */
+#define EMMC50_PAD_CTL0                  REG_ADDR(EMMC50_PAD_CTL0)
+#define EMMC50_PAD_DS_CTL0               REG_ADDR(EMMC50_PAD_DS_CTL0)
+#define EMMC50_PAD_DS_TUNE               REG_ADDR(EMMC50_PAD_DS_TUNE)
+#define EMMC50_PAD_CMD_TUNE              REG_ADDR(EMMC50_PAD_CMD_TUNE)
+#define EMMC50_PAD_DAT01_TUNE            REG_ADDR(EMMC50_PAD_DAT01_TUNE)
+#define EMMC50_PAD_DAT23_TUNE            REG_ADDR(EMMC50_PAD_DAT23_TUNE)
+#define EMMC50_PAD_DAT45_TUNE            REG_ADDR(EMMC50_PAD_DAT45_TUNE)
+#define EMMC50_PAD_DAT67_TUNE            REG_ADDR(EMMC50_PAD_DAT67_TUNE)
+#define EMMC51_CFG0                      REG_ADDR(EMMC51_CFG0)
+#define EMMC50_CFG0                      REG_ADDR(EMMC50_CFG0)
+#define EMMC50_CFG1                      REG_ADDR(EMMC50_CFG1)
+#define EMMC50_CFG2                      REG_ADDR(EMMC50_CFG2)
+#define EMMC50_CFG3                      REG_ADDR(EMMC50_CFG3)
+#define EMMC50_CFG4                      REG_ADDR(EMMC50_CFG4)
+#define SDC_FIFO_CFG                     REG_ADDR(SDC_FIFO_CFG)
+
+/*--------------------------------------------------------------------------*/
+/* Register Mask                                                            */
+/*--------------------------------------------------------------------------*/
+
+/* MSDC_CFG mask */
+#define MSDC_CFG_MODE           (0x1   <<  0)     /* RW */
+#define MSDC_CFG_CKPDN          (0x1   <<  1)     /* RW */
+#define MSDC_CFG_RST            (0x1   <<  2)     /* A0 */
+#define MSDC_CFG_PIO            (0x1   <<  3)     /* RW */
+#define MSDC_CFG_CKDRVEN        (0x1   <<  4)     /* RW */
+#define MSDC_CFG_BV18SDT        (0x1   <<  5)     /* RW */
+#define MSDC_CFG_BV18PSS        (0x1   <<  6)     /* R  */
+#define MSDC_CFG_CKSTB          (0x1   <<  7)     /* R  */
+#define MSDC_CFG_CKDIV          (0xFFF <<  8)     /* RW   !!! MT2701 change 0xFF ->0xFFF*/
+#define MSDC_CFG_CKMOD          (0x3   << 20)     /* W1C  !!! MT2701 change 16 ->21 only for eMCC 5.0*/
+#define MSDC_CFG_CKMOD_HS400    (0x1   << 22)     /* RW   !!! MT2701 change 18 ->22 only for eMCC 5.0*/
+#define MSDC_CFG_START_BIT      (0x3   << 23)     /* RW   !!! MT2701 change 19 ->23 only for eMCC 5.0*/
+#define MSDC_CFG_SCLK_STOP_DDR  (0x1   << 25)     /* RW   !!! MT2701 change 21 ->25 */
+
+/* MSDC_IOCON mask */
+#define MSDC_IOCON_SDR104CKS    (0x1   <<  0)     /* RW */
+#define MSDC_IOCON_RSPL         (0x1   <<  1)     /* RW */
+#define MSDC_IOCON_R_D_SMPL     (0x1   <<  2)     /* RW */
+#define MSDC_IOCON_DSPL          MSDC_IOCON_R_D_SMPL /* alias */
+
+#define MSDC_IOCON_DDLSEL       (0x1   <<  3)     /* RW */
+#define MSDC_IOCON_DDR50CKD     (0x1   <<  4)     /* RW */
+#define MSDC_IOCON_R_D_SMPL_SEL (0x1   <<  5)     /* RW */
+#define MSDC_IOCON_W_D_SMPL     (0x1   <<  8)     /* RW */
+#define MSDC_IOCON_W_D_SMPL_SEL (0x1   <<  9)     /* RW */
+#define MSDC_IOCON_W_D0SPL      (0x1   << 10)     /* RW */
+#define MSDC_IOCON_W_D1SPL      (0x1   << 11)     /* RW */
+#define MSDC_IOCON_W_D2SPL      (0x1   << 12)     /* RW */
+#define MSDC_IOCON_W_D3SPL      (0x1   << 13)     /* RW */
+
+#define MSDC_IOCON_R_D0SPL      (0x1   << 16)     /* RW */
+#define MSDC_IOCON_R_D1SPL      (0x1   << 17)     /* RW */
+#define MSDC_IOCON_R_D2SPL      (0x1   << 18)     /* RW */
+#define MSDC_IOCON_R_D3SPL      (0x1   << 19)     /* RW */
+#define MSDC_IOCON_R_D4SPL      (0x1   << 20)     /* RW */
+#define MSDC_IOCON_R_D5SPL      (0x1   << 21)     /* RW */
+#define MSDC_IOCON_R_D6SPL      (0x1   << 22)     /* RW */
+#define MSDC_IOCON_R_D7SPL      (0x1   << 23)     /* RW */
+//#define MSDC_IOCON_RISCSZ       (0x3   << 24)     /* RW  !!! MT2701  remove*/
+
+/* MSDC_PS mask */
+#define MSDC_PS_CDEN            (0x1   <<  0)     /* RW */
+#define MSDC_PS_CDSTS           (0x1   <<  1)     /* RU  */
+
+#define MSDC_PS_CDDEBOUNCE      (0xF   << 12)     /* RW */
+#define MSDC_PS_DAT             (0xFF  << 16)     /* RU */
+#define MSDC_PS_DAT8PIN         (0xFF  << 16)     /* RU */
+#define MSDC_PS_DAT4PIN         (0xF   << 16)     /* RU */
+#define MSDC_PS_DAT0            (0x1   << 16)     /* RU */
+
+#define MSDC_PS_CMD             (0x1   << 24)     /* RU */
+
+#define MSDC_PS_WP              (0x1   << 31)     /* RU  */
+
+/* MSDC_INT mask */
+#define MSDC_INT_MMCIRQ         (0x1   <<  0)     /* W1C */
+#define MSDC_INT_CDSC           (0x1   <<  1)     /* W1C */
+
+#define MSDC_INT_ACMDRDY        (0x1   <<  3)     /* W1C */
+#define MSDC_INT_ACMDTMO        (0x1   <<  4)     /* W1C */
+#define MSDC_INT_ACMDCRCERR     (0x1   <<  5)     /* W1C */
+#define MSDC_INT_DMAQ_EMPTY     (0x1   <<  6)     /* W1C */
+#define MSDC_INT_SDIOIRQ        (0x1   <<  7)     /* W1C Only for SD/SDIO */
+#define MSDC_INT_CMDRDY         (0x1   <<  8)     /* W1C */
+#define MSDC_INT_CMDTMO         (0x1   <<  9)     /* W1C */
+#define MSDC_INT_RSPCRCERR      (0x1   << 10)     /* W1C */
+#define MSDC_INT_CSTA           (0x1   << 11)     /* R */
+#define MSDC_INT_XFER_COMPL     (0x1   << 12)     /* W1C */
+#define MSDC_INT_DXFER_DONE     (0x1   << 13)     /* W1C */
+#define MSDC_INT_DATTMO         (0x1   << 14)     /* W1C */
+#define MSDC_INT_DATCRCERR      (0x1   << 15)     /* W1C */
+#define MSDC_INT_ACMD19_DONE    (0x1   << 16)     /* W1C */
+#define MSDC_INT_BDCSERR        (0x1   << 17)     /* W1C */
+#define MSDC_INT_GPDCSERR       (0x1   << 18)     /* W1C */
+#define MSDC_INT_DMAPRO         (0x1   << 19)     /* W1C */
+#define MSDC_INT_GOBOUND        (0x1   << 20)     /* W1C Only for SD/SDIO ACMD 53*/
+#define MSDC_INT_ACMD53_DONE    (0x1   << 21)     /* W1C Only for SD/SDIO ACMD 53*/
+#define MSDC_INT_ACMD53_FAIL    (0x1   << 22)     /* W1C Only for SD/SDIO ACMD 53*/
+#define MSDC_INT_AXI_RESP_ERR   (0x1   << 23)     /* W1C Only for eMMC 5.0*/
+
+/* MSDC_INTEN mask */
+#define MSDC_INTEN_MMCIRQ       (0x1   <<  0)     /* RW */
+#define MSDC_INTEN_CDSC         (0x1   <<  1)     /* RW */
+
+#define MSDC_INTEN_ACMDRDY      (0x1   <<  3)     /* RW */
+#define MSDC_INTEN_ACMDTMO      (0x1   <<  4)     /* RW */
+#define MSDC_INTEN_ACMDCRCERR   (0x1   <<  5)     /* RW */
+#define MSDC_INTEN_DMAQ_EMPTY   (0x1   <<  6)     /* RW */
+#define MSDC_INTEN_SDIOIRQ      (0x1   <<  7)     /* RW Only for SDIO*/
+#define MSDC_INTEN_CMDRDY       (0x1   <<  8)     /* RW */
+#define MSDC_INTEN_CMDTMO       (0x1   <<  9)     /* RW */
+#define MSDC_INTEN_RSPCRCERR    (0x1   << 10)     /* RW */
+#define MSDC_INTEN_CSTA         (0x1   << 11)     /* RW */
+#define MSDC_INTEN_XFER_COMPL   (0x1   << 12)     /* RW */
+#define MSDC_INTEN_DXFER_DONE   (0x1   << 13)     /* RW */
+#define MSDC_INTEN_DATTMO       (0x1   << 14)     /* RW */
+#define MSDC_INTEN_DATCRCERR    (0x1   << 15)     /* RW */
+#define MSDC_INTEN_ACMD19_DONE  (0x1   << 16)     /* RW */
+#define MSDC_INTEN_BDCSERR      (0x1   << 17)     /* RW */
+#define MSDC_INTEN_GPDCSERR     (0x1   << 18)     /* RW */
+#define MSDC_INTEN_DMAPRO       (0x1   << 19)     /* RW */
+#define MSDC_INTEN_GOBOUND      (0x1   << 20)     /* RW  Only for SD/SDIO ACMD 53*/
+#define MSDC_INTEN_ACMD53_DONE  (0x1   << 21)     /* RW  Only for SD/SDIO ACMD 53*/
+#define MSDC_INTEN_ACMD53_FAIL  (0x1   << 22)     /* RW  Only for SD/SDIO ACMD 53*/
+#define MSDC_INTEN_AXI_RESP_ERR (0x1   << 23)     /* RW  Only for eMMC 5.0*/
+
+#define MSDC_INTEN_DFT       (  MSDC_INTEN_MMCIRQ        |MSDC_INTEN_CDSC        | MSDC_INTEN_ACMDRDY\
+                                |MSDC_INTEN_ACMDTMO      |MSDC_INTEN_ACMDCRCERR  | MSDC_INTEN_DMAQ_EMPTY /*|MSDC_INTEN_SDIOIRQ*/\
+                                |MSDC_INTEN_CMDRDY       |MSDC_INTEN_CMDTMO      | MSDC_INTEN_RSPCRCERR   |MSDC_INTEN_CSTA\
+                                |MSDC_INTEN_XFER_COMPL   |MSDC_INTEN_DXFER_DONE  | MSDC_INTEN_DATTMO      |MSDC_INTEN_DATCRCERR\
+                                |MSDC_INTEN_BDCSERR      |MSDC_INTEN_ACMD19_DONE | MSDC_INTEN_GPDCSERR     /*|MSDC_INTEN_DMAPRO*/\
+                                /*|MSDC_INTEN_GOBOUND   |MSDC_INTEN_ACMD53_DONE |MSDC_INTEN_ACMD53_FAIL |MSDC_INTEN_AXI_RESP_ERR*/)
+
+
+/* MSDC_FIFOCS mask */
+#define MSDC_FIFOCS_RXCNT       (0xFF  <<  0)     /* R */
+#define MSDC_FIFOCS_TXCNT       (0xFF  << 16)     /* R */
+#define MSDC_FIFOCS_CLR         (0x1   << 31)     /* RW */
+
+/* SDC_CFG mask */
+#define SDC_CFG_SDIOINTWKUP     (0x1   <<  0)     /* RW */
+#define SDC_CFG_INSWKUP         (0x1   <<  1)     /* RW */
+#define SDC_CFG_BUSWIDTH        (0x3   << 16)     /* RW */
+#define SDC_CFG_SDIO            (0x1   << 19)     /* RW */
+#define SDC_CFG_SDIOIDE         (0x1   << 20)     /* RW */
+#define SDC_CFG_INTATGAP        (0x1   << 21)     /* RW */
+#define SDC_CFG_DTOC            (0xFF  << 24)     /* RW */
+
+/* SDC_CMD mask */
+#define SDC_CMD_OPC             (0x3F  <<  0)     /* RW */
+#define SDC_CMD_BRK             (0x1   <<  6)     /* RW */
+#define SDC_CMD_RSPTYP          (0x7   <<  7)     /* RW */
+#define SDC_CMD_DTYP            (0x3   << 11)     /* RW */
+#define SDC_CMD_RW              (0x1   << 13)     /* RW */
+#define SDC_CMD_STOP            (0x1   << 14)     /* RW */
+#define SDC_CMD_GOIRQ           (0x1   << 15)     /* RW */
+#define SDC_CMD_BLKLEN          (0xFFF << 16)     /* RW */
+#define SDC_CMD_AUTOCMD         (0x3   << 28)     /* RW */
+#define SDC_CMD_VOLSWTH         (0x1   << 30)     /* RW */
+#define SDC_CMD_ACMD53          (0x1   << 31)     /* RW Only for SD/SDIO ACMD 53*/
+
+/* SDC_STS mask */
+#define SDC_STS_SDCBUSY         (0x1   <<  0)     /* RW */
+#define SDC_STS_CMDBUSY         (0x1   <<  1)     /* RW */
+#define SDC_STS_CMD_WR_BUSY     (0x1   << 16)     /* RW !!! MT2701  Add*/
+#define SDC_STS_SWR_COMPL       (0x1   << 31)     /* RW */
+
+/* SDC_VOL_CHG mask */
+#define SDC_VOL_CHG_VCHGCNT     (0xFFFF<<  0)     /* RW  !!! MT2701  Add*/
+/* SDC_DCRC_STS mask */
+#define SDC_DCRC_STS_POS        (0xFF  <<  0)     /* RO */
+#define SDC_DCRC_STS_NEG        (0xFF  <<  8)     /* RO */
+/* SDC_ADV_CFG0 mask */
+#define SDC_RX_ENHANCE_EN      (0x1 << 20)     /* RW */
+/* EMMC_CFG0 mask */
+#define EMMC_CFG0_BOOTSTART     (0x1   <<  0)     /* WO Only for eMMC */
+#define EMMC_CFG0_BOOTSTOP      (0x1   <<  1)     /* WO Only for eMMC */
+#define EMMC_CFG0_BOOTMODE      (0x1   <<  2)     /* RW Only for eMMC */
+#define EMMC_CFG0_BOOTACKDIS    (0x1   <<  3)     /* RW Only for eMMC */
+
+#define EMMC_CFG0_BOOTWDLY      (0x7   << 12)     /* RW Only for eMMC */
+#define EMMC_CFG0_BOOTSUPP      (0x1   << 15)     /* RW Only for eMMC */
+
+/* EMMC_CFG1 mask */
+#define EMMC_CFG1_BOOTDATTMC   (0xFFFFF<<  0)     /* RW Only for eMMC */
+#define EMMC_CFG1_BOOTACKTMC    (0xFFF << 20)     /* RW Only for eMMC */
+
+/* EMMC_STS mask */
+#define EMMC_STS_BOOTCRCERR     (0x1   <<  0)     /* W1C Only for eMMC */
+#define EMMC_STS_BOOTACKERR     (0x1   <<  1)     /* W1C Only for eMMC */
+#define EMMC_STS_BOOTDATTMO     (0x1   <<  2)     /* W1C Only for eMMC */
+#define EMMC_STS_BOOTACKTMO     (0x1   <<  3)     /* W1C Only for eMMC */
+#define EMMC_STS_BOOTUPSTATE    (0x1   <<  4)     /* RU Only for eMMC */
+#define EMMC_STS_BOOTACKRCV     (0x1   <<  5)     /* W1C Only for eMMC */
+#define EMMC_STS_BOOTDATRCV     (0x1   <<  6)     /* RU Only for eMMC */
+
+/* EMMC_IOCON mask */
+#define EMMC_IOCON_BOOTRST      (0x1   <<  0)     /* RW Only for eMMC */
+
+/* SDC_ACMD19_TRG mask */
+#define SDC_ACMD19_TRG_TUNESEL  (0xF   <<  0)     /* RW */
+
+/* DMA_SA_HIGH4BIT mask */
+#define DMA_SA_HIGH4BIT_L4BITS  (0xF   <<  0)     /* RW  !!! MT2701  Add*/
+/* MSDC_DMA_CTRL mask */
+#define MSDC_DMA_CTRL_START     (0x1   <<  0)     /* WO */
+#define MSDC_DMA_CTRL_STOP      (0x1   <<  1)     /* AO */
+#define MSDC_DMA_CTRL_RESUME    (0x1   <<  2)     /* WO */
+#define MSDC_DMA_CTRL_READYM    (0x1   <<  3)     /* RO  !!! MT2701  Add*/
+
+#define MSDC_DMA_CTRL_MODE      (0x1   <<  8)     /* RW */
+#define MSDC_DMA_CTRL_ALIGN     (0x1   <<  9)     /* RW !!! MT2701  Add*/
+#define MSDC_DMA_CTRL_LASTBUF   (0x1   << 10)     /* RW */
+#define MSDC_DMA_CTRL_SPLIT1K   (0x1   << 11)     /* RW !!! MT2701  Add*/
+#define MSDC_DMA_CTRL_BURSTSZ   (0x7   << 12)     /* RW */
+// #define MSDC_DMA_CTRL_XFERSZ    (0xffffUL << 16)/* RW */
+
+/* MSDC_DMA_CFG mask */
+#define MSDC_DMA_CFG_STS              (0x1  <<  0)     /* R */
+#define MSDC_DMA_CFG_DECSEN           (0x1  <<  1)     /* RW */
+#define MSDC_DMA_CFG_LOCKDISABLE      (0x1  <<  2)     /* RW !!! MT2701  Add*/
+//#define MSDC_DMA_CFG_BDCSERR        (0x1  <<  4)     /* R */
+//#define MSDC_DMA_CFG_GPDCSERR       (0x1  <<  5)     /* R */
+#define MSDC_DMA_CFG_AHBEN            (0x3  <<  8)     /* RW */
+#define MSDC_DMA_CFG_ACTEN            (0x3  << 12)     /* RW */
+
+#define MSDC_DMA_CFG_CS12B            (0x1  << 16)     /* RW */
+#define MSDC_DMA_CFG_OUTB_STOP        (0x1  << 17)     /* RW */
+
+/* MSDC_PATCH_BIT0 mask */
+//#define MSDC_PB0_RESV1              (0x1  <<  0)
+#define MSDC_PB0_EN_8BITSUP           (0x1  <<  1)    /* RW */
+#define MSDC_PB0_DIS_RECMDWR          (0x1  <<  2)    /* RW */
+//#define MSDC_PB0_RESV2                        (0x1  <<  3)
+#define MSDC_PB0_RDDATSEL             (0x1  <<  3)    /* RW !!! MT2701 Add for SD/SDIO/eMMC 4.5*/
+#define MSDC_PB0_ACMD53_CRCINTR       (0x1  <<  4)    /* RW !!! MT2701 Add only for SD/SDIO */
+#define MSDC_PB0_ACMD53_ONESHOT       (0x1  <<  5)    /* RW !!! MT2701 Add ony for SD/SDIO */
+//#define MSDC_PB0_RESV3                        (0x1  <<  6)
+#define MSDC_PB0_DESC_UP_SEL          (0x1  <<  6)    /* RW !!! MT2701  Add*/
+#define MSDC_PB0_INT_DAT_LATCH_CK_SEL (0x7  <<  7)    /* RW */
+#define MSDC_INT_DAT_LATCH_CK_SEL      MSDC_PB0_INT_DAT_LATCH_CK_SEL  /* alias */
+
+#define MSDC_PB0_CKGEN_MSDC_DLY_SEL   (0x1F << 10)    /* RW */
+#define MSDC_CKGEN_MSDC_DLY_SEL        MSDC_PB0_CKGEN_MSDC_DLY_SEL  /* alias */
+
+
+#define MSDC_PB0_FIFORD_DIS           (0x1  << 15)    /* RW */
+//#define MSDC_PB0_SDIO_DBSSEL                  (0x1  << 16)    /* RW !!! MT2701  change*/
+#define MSDC_PB0_MSDC_BLKNUMSEL       (0x1  << 16)    /* RW !!! MT2701  change ACMD23*/
+#define MSDC_PB0_BLKNUM_SEL           MSDC_PB0_MSDC_BLKNUMSEL /* alias */
+
+#define MSDC_PB0_SDIO_INTCSEL         (0x1  << 17)    /* RW */
+#define MSDC_PB0_SDIO_BSYDLY          (0xF  << 18)    /* RW */
+#define MSDC_PB0_SDC_WDOD             (0xF  << 22)    /* RW */
+#define MSDC_PB0_CMDIDRTSEL           (0x1  << 26)    /* RW */
+#define MSDC_PB0_CMDFAILSEL           (0x1  << 27)    /* RW */
+#define MSDC_PB0_SDIO_INTDLYSEL       (0x1  << 28)    /* RW */
+#define MSDC_PB0_SPCPUSH              (0x1  << 29)    /* RW */
+#define MSDC_PB0_DETWR_CRCTMO         (0x1  << 30)    /* RW */
+#define MSDC_PB0_EN_DRVRSP            (0x1  << 31)    /* RW */
+
+/* MSDC_PATCH_BIT1 mask */
+#define MSDC_PB1_WRDAT_CRCS_TA_CNTR   (0x7  <<  0)    /* RW */
+#define MSDC_PATCH_BIT1_WRDAT_CRCS    MSDC_PB1_WRDAT_CRCS_TA_CNTR /* alias */
+
+
+#define MSDC_PB1_CMD_RSP_TA_CNTR      (0x7  <<  3)    /* RW */
+#define MSDC_PATCH_BIT1_CMD_RSP       MSDC_PB1_CMD_RSP_TA_CNTR  /* alias */
+
+//#define MSDC_PB1_RESV3                        (0x3  <<  6)
+#define MSDC_PB1_GET_BUSY_MARGIN      (0x1  <<  6)    /* RW !!! MT2701  Add */
+#define MSDC_BUSY_CHECK_SEL           (0x1  <<  7)    /* RW !!! MT2712  Add */
+#define MSDC_PB1_BIAS_TUNE_28NM       (0xF  <<  8)    /* RW */
+#define MSDC_PB1_BIAS_EN18IO_28NM     (0x1  << 12)    /* RW */
+#define MSDC_PB1_BIAS_EXT_28NM        (0x1  << 13)    /* RW */
+
+//#define MSDC_PB1_RESV2                        (0x3  << 14)
+#define MSDC_PB1_RESET_GDMA           (0x1  << 15)    /* RW !!! MT2701  Add */
+//#define MSDC_PB1_RESV1                        (0x7F << 16)
+#define MSDC_PB1_EN_SINGLE_BURST      (0x1  << 16)    /* RW !!! MT2701  Add */
+#define MSDC_PB1_EN_FORCE_STOP_GDMA   (0x1  << 17)    /* RW !!! MT2701  Add  for eMMC 5.0 only*/
+#define MSDC_PB1_DCM_DIV_SEL2         (0x3  << 18)    /* RW !!! MT2701  Add  for eMMC 5.0 only*/
+#define MSDC_PB1_DCM_DIV_SEL1         (0x1  << 20)    /* RW !!! MT2701  Add */
+#define MSDC_PB1_DCM_EN               (0x1  << 21)    /* RW !!! MT2701  Add */
+#define MSDC_PB1_AXI_WRAP_CKEN        (0x1  << 22)    /* RW !!! MT2701  Add for eMMC 5.0 only*/
+#define MSDC_PB1_AHBCKEN              (0x1  << 23)    /* RW */
+#define MSDC_PB1_CKSPCEN              (0x1  << 24)    /* RW */
+#define MSDC_PB1_CKPSCEN              (0x1  << 25)    /* RW */
+#define MSDC_PB1_CKVOLDETEN           (0x1  << 26)    /* RW */
+#define MSDC_PB1_CKACMDEN             (0x1  << 27)    /* RW */
+#define MSDC_PB1_CKSDEN               (0x1  << 28)    /* RW */
+#define MSDC_PB1_CKWCTLEN             (0x1  << 29)    /* RW */
+#define MSDC_PB1_CKRCTLEN             (0x1  << 30)    /* RW */
+#define MSDC_PB1_CKSHBFFEN            (0x1  << 31)    /* RW */
+
+/* MSDC_PATCH_BIT2 mask */
+#define MSDC_PB2_ENHANCEGPD           (0x1  <<  0)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_SUPPORT64G           (0x1  <<  1)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_RESPWAIT             (0x3  <<  2)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGRDATCNT           (0x1F <<  4)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGRDAT              (0x1  <<  9)    /* RW !!! MT2701  Add */
+
+#define MSDC_PB2_INTCRESPSEL          (0x1  << 11)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGRESPCNT           (0x7  << 12)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGRESP              (0x1  << 15)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_RESPSTSENSEL         (0x7  << 16)    /* RW !!! MT2701  Add */
+
+#define MSDC_PB2_POPENCNT             (0xF  << 20)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGCRCSTSSEL         (0x1  << 24)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGCRCSTSEDGE        (0x1  << 25)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGCRCSTSCNT         (0x3  << 26)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGCRCSTS            (0x1  << 28)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CRCSTSENSEL          (0x7  << 29)    /* RW !!! MT2701  Add */
+
+
+/* SDIO_TUNE_WIND mask */
+#define SDIO_TUNE_WIND_TUNEWINDOW     (0x1F  <<  0)     /* RW !!! MT2701  Add for SD/SDIO only*/
+
+/* MSDC_PAD_TUNE/MSDC_PAD_TUNE0 mask */
+#define MSDC_PAD_TUNE_DATWRDLY        (0x1F  <<  0)     /* RW */
+
+#define MSDC_PAD_TUNE_DELAYEN         (0x1   <<  7)     /* RW !!! MT2701  Add*/
+#define MSDC_PAD_TUNE_DATRRDLY        (0x1F  <<  8)     /* RW */
+#define MSDC_PAD_TUNE_DATRRDLYSEL     (0x1   << 13)     /* RW !!! MT2701  Add*/
+
+#define MSDC_PAD_TUNE_RXDLYSEL        (0x1   << 15)     /* RW !!! MT2701  Add*/
+#define MSDC_PAD_TUNE_CMDRDLY         (0x1F  << 16)     /* RW */
+#define MSDC_PAD_TUNE_CMDRDLYSEL      (0x1   << 21)     /* RW !!! MT2701  Add*/
+#define MSDC_PAD_TUNE_CMDRRDLY        (0x1F  << 22)     /* RW */
+#define MSDC_PAD_TUNE_CLKTXDLY        (0x1F  << 27)     /* RW */
+
+/* MSDC_PAD_TUNE1 mask */
+
+#define MSDC_PAD_TUNE1_DATRRDLY2      (0x1F  <<  8)     /* RW  !!! MT2701  Add*/
+#define MSDC_PAD_TUNE1_DATRDLY2SEL    (0x1   << 13)     /* RW  !!! MT2701  Add*/
+
+#define MSDC_PAD_TUNE1_CMDRDLY2       (0x1F  << 16)     /* RW  !!! MT2701  Add*/
+#define MSDC_PAD_TUNE1_CMDRDLY2SEL    (0x1   << 21)     /* RW  !!! MT2701  Add*/
+
+
+/* MSDC_DAT_RDDLY0 mask */
+#define MSDC_DAT_RDDLY0_D3            (0x1F  <<  0)     /* RW */
+#define MSDC_DAT_RDDLY0_D2            (0x1F  <<  8)     /* RW */
+#define MSDC_DAT_RDDLY0_D1            (0x1F  << 16)     /* RW */
+#define MSDC_DAT_RDDLY0_D0            (0x1F  << 24)     /* RW */
+
+/* MSDC_DAT_RDDLY1 mask */
+#define MSDC_DAT_RDDLY1_D7            (0x1F  <<  0)     /* RW */
+
+#define MSDC_DAT_RDDLY1_D6            (0x1F  <<  8)     /* RW */
+
+#define MSDC_DAT_RDDLY1_D5            (0x1F  << 16)     /* RW */
+
+#define MSDC_DAT_RDDLY1_D4            (0x1F  << 24)     /* RW */
+
+/* MSDC_DAT_RDDLY2 mask */
+#define MSDC_DAT_RDDLY2_D3            (0x1F  <<  0)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY2_D2            (0x1F  <<  8)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY2_D1            (0x1F  << 16)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY2_D0            (0x1F  << 24)     /* RW !!! MT2701  Add*/
+
+/* MSDC_DAT_RDDLY3 mask */
+#define MSDC_DAT_RDDLY3_D7            (0x1F  <<  0)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY3_D6            (0x1F  <<  8)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY3_D5            (0x1F  << 16)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY3_D4            (0x1F  << 24)     /* RW !!! MT2701  Add*/
+
+/* MSDC_HW_DBG_SEL mask */
+#define MSDC_HW_DBG0_SEL              (0xFF  <<  0)     /* RW DBG3->DBG0 !!! MT2701  Change*/
+#define MSDC_HW_DBG1_SEL              (0x3F  <<  8)     /* RW DBG2->DBG1 !!! MT2701  Add*/
+
+#define MSDC_HW_DBG2_SEL              (0xFF  << 16)     /* RW DBG1->DBG2 !!! MT2701  Add*/
+//#define MSDC_HW_DBG_WRAPTYPE_SEL    (0x3   << 22)           /* RW !!! MT2701  Removed*/
+#define MSDC_HW_DBG3_SEL              (0x3F  << 24)     /* RW DBG0->DBG3 !!! MT2701  Add*/
+#define MSDC_HW_DBG_WRAP_SEL          (0x1   << 30)     /* RW */
+
+
+/* MSDC_EMMC50_PAD_CTL0 mask*/
+#define MSDC_EMMC50_PAD_CTL0_DCCSEL   (0x1  <<  0)     /* RW */
+#define MSDC_EMMC50_PAD_CTL0_HLSEL    (0x1  <<  1)     /* RW */
+#define MSDC_EMMC50_PAD_CTL0_DLP0     (0x3  <<  2)     /* RW */
+#define MSDC_EMMC50_PAD_CTL0_DLN0     (0x3  <<  4)     /* RW */
+#define MSDC_EMMC50_PAD_CTL0_DLP1     (0x3  <<  6)     /* RW */
+#define MSDC_EMMC50_PAD_CTL0_DLN1     (0x3  <<  8)     /* RW */
+
+/* MSDC_EMMC50_PAD_DS_CTL0 mask */
+#define MSDC_EMMC50_PAD_DS_CTL0_SR    (0x1  <<  0)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_R0    (0x1  <<  1)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_R1    (0x1  <<  2)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_PUPD  (0x1  <<  3)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_IES   (0x1  <<  4)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_SMT   (0x1  <<  5)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_RDSEL (0x3F <<  6)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_TDSEL (0xF  << 12)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_DRV   (0x7  << 16)     /* RW */
+
+
+/* EMMC50_PAD_DS_TUNE mask */
+#define MSDC_EMMC50_PAD_DS_TUNE_DLYSEL  (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_DS_TUNE_DLY2SEL (0x1  <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_DS_TUNE_DLY1    (0x1F <<  2)  /* RW */
+#define MSDC_EMMC50_PAD_DS_TUNE_DLY2    (0x1F <<  7)  /* RW */
+#define MSDC_EMMC50_PAD_DS_TUNE_DLY3    (0x1F << 12)  /* RW */
+
+/* EMMC50_PAD_CMD_TUNE mask */
+#define MSDC_EMMC50_PAD_CMD_TUNE_DLY3SEL (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_CMD_TUNE_RXDLY3  (0x1F <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_CMD_TUNE_TXDLY   (0x1F <<  6)  /* RW */
+
+/* EMMC50_PAD_DAT01_TUNE mask */
+#define MSDC_EMMC50_PAD_DAT0_RXDLY3SEL   (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_DAT0_RXDLY3      (0x1F <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_DAT0_TXDLY       (0x1F <<  6)  /* RW */
+#define MSDC_EMMC50_PAD_DAT1_RXDLY3SEL   (0x1  << 16)  /* RW */
+#define MSDC_EMMC50_PAD_DAT1_RXDLY3      (0x1F << 17)  /* RW */
+#define MSDC_EMMC50_PAD_DAT1_TXDLY       (0x1F << 22)  /* RW */
+
+/* EMMC50_PAD_DAT23_TUNE mask */
+#define MSDC_EMMC50_PAD_DAT2_RXDLY3SEL   (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_DAT2_RXDLY3      (0x1F <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_DAT2_TXDLY       (0x1F <<  6)  /* RW */
+#define MSDC_EMMC50_PAD_DAT3_RXDLY3SEL   (0x1  << 16)  /* RW */
+#define MSDC_EMMC50_PAD_DAT3_RXDLY3      (0x1F << 17)  /* RW */
+#define MSDC_EMMC50_PAD_DAT3_TXDLY       (0x1F << 22)  /* RW */
+
+/* EMMC50_PAD_DAT45_TUNE mask */
+#define MSDC_EMMC50_PAD_DAT4_RXDLY3SEL   (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_DAT4_RXDLY3      (0x1F <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_DAT4_TXDLY       (0x1F <<  6)  /* RW */
+#define MSDC_EMMC50_PAD_DAT5_RXDLY3SEL   (0x1  << 16)  /* RW */
+#define MSDC_EMMC50_PAD_DAT5_RXDLY3      (0x1F << 17)  /* RW */
+#define MSDC_EMMC50_PAD_DAT5_TXDLY       (0x1F << 22)  /* RW */
+
+/* EMMC50_PAD_DAT67_TUNE mask */
+#define MSDC_EMMC50_PAD_DAT6_RXDLY3SEL   (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_DAT6_RXDLY3      (0x1F <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_DAT6_TXDLY       (0x1F <<  6)  /* RW */
+#define MSDC_EMMC50_PAD_DAT7_RXDLY3SEL   (0x1  << 16)  /* RW */
+#define MSDC_EMMC50_PAD_DAT7_RXDLY3      (0x1F << 17)  /* RW */
+#define MSDC_EMMC50_PAD_DAT7_TXDLY       (0x1F << 22)  /* RW */
+
+/* EMMC51_CFG0 mask */
+#define MSDC_EMMC51_CFG_CMDQ_EN          (0x1   <<  0) /* RW !!! MT2701  Add*/
+#define MSDC_EMMC51_CFG_WDAT_CNT         (0x3FF <<  1) /* RW !!! MT2701  Add*/
+#define MSDC_EMMC51_CFG_RDAT_CNT         (0x3FF << 11) /* RW !!! MT2701  Add*/
+#define MSDC_EMMC51_CFG_CMDQ_CMD_EN      (0x1   << 21) /* RW !!! MT2701  Add*/
+
+
+/* EMMC50_CFG0 mask */
+#define MSDC_EMMC50_CFG_PADCMD_LATCHCK         (0x1  <<  0)  /* RW*/
+#define MSDC_EMMC50_CFG_CRCSTS_CNT             (0x3  <<  1)  /* RW*/
+#define MSDC_EMMC50_CFG_CRCSTS_EDGE            (0x1  <<  3)  /* RW*/
+#define MSDC_EMMC50_CFG_CRC_STS_EDGE           MSDC_EMMC50_CFG_CRCSTS_EDGE /*alias */
+
+#define MSDC_EMMC50_CFG_CRCSTS_SEL             (0x1  <<  4)  /* RW*/
+#define MSDC_EMMC50_CFG_CRC_STS_SEL            MSDC_EMMC50_CFG_CRCSTS_SEL /*alias */
+
+#define MSDC_EMMC50_CFG_ENDBIT_CHKCNT          (0xF  <<  5)  /* RW*/
+#define MSDC_EMMC50_CFG_CMDRSP_SEL             (0x1  <<  9)  /* RW*/
+#define MSDC_EMMC50_CFG_CMD_RESP_SEL           MSDC_EMMC50_CFG_CMDRSP_SEL  /*alias */
+
+#define MSDC_EMMC50_CFG_CMDEDGE_SEL            (0x1  << 10)  /* RW*/
+#define MSDC_EMMC50_CFG_ENDBIT_CNT             (0x3FF<< 11)  /* RW*/
+#define MSDC_EMMC50_CFG_READDAT_CNT            (0x7  << 21)  /* RW*/
+#define MSDC_EMMC50_CFG_EMMC50_MONSEL          (0x1  << 24)  /* RW*/
+#define MSDC_EMMC50_CFG_MSDC_WRVALID           (0x1  << 25)  /* RW*/
+#define MSDC_EMMC50_CFG_MSDC_RDVALID           (0x1  << 26)  /* RW*/
+#define MSDC_EMMC50_CFG_MSDC_WRVALID_SEL       (0x1  << 27)  /* RW*/
+#define MSDC_EMMC50_CFG_MSDC_RDVALID_SEL       (0x1  << 28)  /* RW*/
+#define MSDC_EMMC50_CFG_MSDC_TXSKEW_SEL        (0x1  << 29)  /* RW*/
+//#define MSDC_EMMC50_CFG_MSDC_GDMA_RESET      (0x1  << 31)  /* RW !!! MT2701  Removed*/
+
+/* EMMC50_CFG1 mask */
+#define MSDC_EMMC50_CFG1_WRPTR_MARGIN          (0xFF <<  0)  /* RW*/
+#define MSDC_EMMC50_CFG1_CKSWITCH_CNT          (0x7  <<  8)  /* RW*/
+#define MSDC_EMMC50_CFG1_RDDAT_STOP            (0x1  << 11)  /* RW*/
+#define MSDC_EMMC50_CFG1_WAIT8CLK_CNT          (0xF  << 12)  /* RW*/
+#define MSDC_EMMC50_CFG1_EMMC50_DBG_SEL        (0xFF << 16)  /* RW*/
+#define MSDC_EMMC50_CFG1_PSH_CNT               (0x7  << 24)  /* RW !!! MT2701  Add*/
+#define MSDC_EMMC50_CFG1_PSH_PS_SEL            (0x1  << 27)  /* RW !!! MT2701  Add*/
+#define MSDC_EMMC50_CFG1_DS_CFG                (0x1  << 28)  /* RW !!! MT2701  Add*/
+
+/* EMMC50_CFG2 mask */
+//#define MSDC_EMMC50_CFG2_AXI_GPD_UP          (0x1  <<  0)  /* RW !!! MT2701  Removed*/
+#define MSDC_EMMC50_CFG2_AXI_IOMMU_WR_EMI      (0x1  <<  1) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_SHARE_EN_WR_EMI   (0x1  <<  2) /* RW*/
+
+#define MSDC_EMMC50_CFG2_AXI_IOMMU_RD_EMI      (0x1  <<  7) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_SHARE_EN_RD_EMI   (0x1  <<  8) /* RW*/
+
+#define MSDC_EMMC50_CFG2_AXI_BOUND_128B        (0x1  << 13) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BOUND_256B        (0x1  << 14) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BOUND_512B        (0x1  << 15) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BOUND_1K          (0x1  << 16) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BOUND_2K          (0x1  << 17) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BOUND_4K          (0x1  << 18) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_RD_OUTSTANDING_NUM (0x1F << 19) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_RD_OUTS_NUM       MSDC_EMMC50_CFG2_AXI_RD_OUTSTANDING_NUM /*alias */
+
+#define MSDC_EMMC50_CFG2_AXI_SET_LET           (0xF  << 24) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_SET_LEN           MSDC_EMMC50_CFG2_AXI_SET_LET /*alias */
+
+#define MSDC_EMMC50_CFG2_AXI_RESP_ERR_TYPE     (0x3  << 28) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BUSY              (0x1  << 30) /* RW*/
+
+
+/* EMMC50_CFG3 mask */
+#define MSDC_EMMC50_CFG3_OUTSTANDING_WR        (0x1F <<  0) /* RW*/
+#define MSDC_EMMC50_CFG3_OUTS_WR               MSDC_EMMC50_CFG3_OUTSTANDING_WR /*alias */
+
+#define MSDC_EMMC50_CFG3_ULTRA_SET_WR          (0x3F <<  5) /* RW*/
+#define MSDC_EMMC50_CFG3_PREULTRA_SET_WR       (0x3F << 11) /* RW*/
+#define MSDC_EMMC50_CFG3_ULTRA_SET_RD          (0x3F << 17) /* RW*/
+#define MSDC_EMMC50_CFG3_PREULTRA_SET_RD       (0x3F << 23) /* RW*/
+
+/* EMMC50_CFG4 mask */
+#define MSDC_EMMC50_CFG4_IMPR_ULTRA_SET_WR     (0xFF <<  0) /* RW*/
+#define MSDC_EMMC50_CFG4_IMPR_ULTRA_SET_RD     (0xFF <<  8) /* RW*/
+#define MSDC_EMMC50_CFG4_ULTRA_EN              (0x3  << 16) /* RW*/
+#define MSDC_EMMC50_CFG4_WRAP_SEL              (0x1F << 18) /* RW !!! MT2701  Add*/
+
+/* SDC_FIFO_CFG mask */
+#define SDC_FIFO_CFG_WRVALIDSEL   (0x1 << 24)  /* RW */
+#define SDC_FIFO_CFG_RDVALIDSEL   (0x1 << 25)  /* RW */
+
+#if 1
+/* Chaotian Add GPIO top layer */
+#define MSDC_DRVN_GEAR0                       0
+#define MSDC_DRVN_GEAR1                       1
+#define MSDC_DRVN_GEAR2                       2
+#define MSDC_DRVN_GEAR3                       3
+#define MSDC_DRVN_GEAR4                       4
+#define MSDC_DRVN_GEAR5                       5
+#define MSDC_DRVN_GEAR6                       6
+#define MSDC_DRVN_GEAR7                       7
+#define MSDC_DRVN_DONT_CARE                   MSDC_DRVN_GEAR0
+
+/* for MT2712 */
+/* MSDC_CTRL0 is for MSDC0_CLK */
+#define MSDC_CTRL0          (GPIO_BASE + 0xc40)
+#define MSDC0_CLK_SMT       (0x1 << 13)
+#define MSDC0_DRV_CLK_MASK  (0x7 << 8)
+#define MSDC0_CLK_PUPD      (0x1 << 2) /* set to 1 --> pull down */
+#define MSDC0_CLK_R1R0      (0x3) /* set to 0x2 --> 50K */
+
+/* MSDC_CTRL1 is for MSDC0_CMD */
+#define MSDC_CTRL1          (GPIO_BASE + 0xc50)
+#define MSDC0_CMD_SMT       (0x1 << 13)
+#define MSDC0_DRV_CMD_MASK  (0x7 << 8)
+#define MSDC0_CMD_PUPD      (0x1 << 2) /* set to 0 --> pull up */
+#define MSDC0_CMD_R1R0      (0x3) /* set to 0x1 --> 10K */
+
+/* MSDC_CTRL2 is for MSDC0_DAT */
+#define MSDC_CTRL2          (GPIO_BASE + 0xc60)
+#define MSDC0_DAT_SMT       (0x1 << 13)
+#define MSDC0_DRV_DAT_MASK  (0x7 << 8)
+#define MSDC0_DAT_PUPD      (0x1 << 2) /* set to 0 --> pull up */
+#define MSDC0_DAT_R1R0      (0x3) /* set to 0x1 --> 10K */
+
+/* MSDC_CTRL4 is for MSDC0_DS */
+#define MSDC_CTRL4          (GPIO_BASE + 0xda0)
+#define MSDC0_DS_SMT        (0x1 << 13)
+#define MSDC0_DRV_DS_MASK   (0x7 << 8)
+#define MSDC0_DS_PUPD       (0x1 << 2) /* set to 1 --> pull down */
+#define MSDC0_DS_R1R0       (0x3) /* set to 0x2 --> 50K */
+
+/* for GPIO67 contrl */
+#define GPIO_MODE14 (GPIO_BASE + 0x5d0) /*0x7 << 6 --> GPIO67 mode */
+#define GPIO_DIR5   (GPIO_BASE + 0x40) /* bit3 --> GPIO67 DIR, b1 to output */
+#define GPIO_DOUT5  (GPIO_BASE + 0x340) /* bit3 -->GPIO67 output value, b1 to high */
+#endif
+
+typedef enum __MSDC_PIN_STATE {
+    MSDC_HIGHZ = 0,
+    MSDC_10KOHM,
+    MSDC_50KOHM,
+    MSDC_8KOHM,
+    MSDC_PST_MAX
+} MSDC_PIN_STATE;
+
+
+/* each PLL have different gears for select
+ * software can used mux interface from clock management module to select */
+enum {
+    MSDC50_CLKSRC4HCLK_26MHZ  = 0,
+    MSDC50_CLKSRC4HCLK_273MHZ,
+    MSDC50_CLKSRC4HCLK_182MHZ,
+    MSDC50_CLKSRC4HCLK_78MHZ,
+    MSDC_DONOTCARE_HCLK,
+    MSDC50_CLKSRC4HCLK_MAX
+};
+
+enum {
+    MSDC50_CLKSRC_26MHZ  = 0,
+    MSDC50_CLKSRC_400MHZ,  /* MSDCPLL_CK */
+    MSDC50_CLKSRC_182MHZ,  /*MSDCPLL_D2 */
+    MSDC50_CLKSRC_136MHZ,
+    MSDC50_CLKSRC_156MHZ,
+    MSDC50_CLKSRC_200MHZ,  /*MSDCPLL_D4 */
+    MSDC50_CLKSRC_100MHZ,
+    MSDC50_CLKSRC_50MHZ,
+    MSDC50_CLKSRC_MAX
+};
+
+/* MSDC0/1/2
+     PLL MUX SEL List */
+enum {
+    MSDC30_CLKSRC_26MHZ   = 0,
+    MSDC30_CLKSRC_200MHZ,
+    MSDC30_CLKSRC_182MHZ,
+    MSDC30_CLKSRC_91MHZ,
+    MSDC30_CLKSRC_156MHZ,
+    MSDC30_CLKSRC_104MHZ,
+    MSDC30_CLKSRC_MAX
+};
+
+#define MSDC50_CLKSRC_DEFAULT     MSDC50_CLKSRC_400MHZ
+#define MSDC30_CLKSRC_DEFAULT     MSDC30_CLKSRC_200MHZ
+
+typedef enum MT65XX_POWER_VOL_TAG {
+    VOL_DEFAULT,
+    VOL_0900 = 900,
+    VOL_1000 = 1000,
+    VOL_1100 = 1100,
+    VOL_1200 = 1200,
+    VOL_1300 = 1300,
+    VOL_1350 = 1350,
+    VOL_1500 = 1500,
+    VOL_1800 = 1800,
+    VOL_2000 = 2000,
+    VOL_2100 = 2100,
+    VOL_2500 = 2500,
+    VOL_2800 = 2800,
+    VOL_3000 = 3000,
+    VOL_3300 = 3300,
+    VOL_3400 = 3400,
+    VOL_3500 = 3500,
+    VOL_3600 = 3600
+} MT65XX_POWER_VOLTAGE;
+
+/*--------------------------------------------------------------------------*/
+/* Descriptor Structure                                                     */
+/*--------------------------------------------------------------------------*/
+#define DMA_FLAG_NONE       (0x00000000)
+#define DMA_FLAG_EN_CHKSUM  (0x00000001)
+#define DMA_FLAG_PAD_BLOCK  (0x00000002)
+#define DMA_FLAG_PAD_DWORD  (0x00000004)
+
+#define MSDC_WRITE32(addr, data)    writel(data, addr)
+#define MSDC_READ32(addr)           readl(addr)
+#define MSDC_WRITE8(addr, data)     writeb(data, addr)
+#define MSDC_READ8(addr)            readb(addr)
+
+#define MSDC_SET_BIT32(addr,mask) \
+    do {    \
+        unsigned int tv = MSDC_READ32(addr); \
+        tv |=((u32)(mask)); \
+        MSDC_WRITE32(addr,tv); \
+    } while (0)
+#define MSDC_CLR_BIT32(addr,mask) \
+    do {    \
+        unsigned int tv = MSDC_READ32(addr); \
+        tv &= ~((u32)(mask)); \
+        MSDC_WRITE32(addr,tv); \
+    } while (0)
+
+#define MSDC_SET_FIELD(reg,field,val) \
+    do { \
+        u32 tv = MSDC_READ32(reg); \
+        tv &= ~((u32)(field)); \
+        tv |= ((val) << (__builtin_ffs((u32)(field)) - 1)); \
+        MSDC_WRITE32(reg, tv); \
+    } while (0)
+
+#define MSDC_GET_FIELD(reg,field,val) \
+    do { \
+        u32 tv = MSDC_READ32(reg); \
+        val = ((tv & (field)) >> (__builtin_ffs((u32)(field)) - 1)); \
+    } while (0)
+
+#define MSDC_RETRY(expr,retry,cnt) \
+    do { \
+        uint32_t t = cnt; \
+        uint32_t r = retry; \
+        uint32_t c = cnt; \
+        while (r) { \
+            if (!(expr)) break; \
+            if (c-- == 0) { \
+                r--; spin(200); c = t; \
+            } \
+        } \
+        if (r == 0) \
+            dprintf(CRITICAL, "%s->%d: retry %d times failed!\n", __func__, \
+                    __LINE__, retry); \
+    } while (0)
+
+#define MSDC_RESET() \
+    do { \
+        MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_RST); \
+        MSDC_RETRY(MSDC_READ32(MSDC_CFG) & MSDC_CFG_RST, 5, 1000); \
+    } while (0)
+
+#define MSDC_CLR_INT() \
+    do { \
+        volatile uint32_t val = MSDC_READ32(MSDC_INT); \
+        MSDC_WRITE32(MSDC_INT, val); \
+    } while (0)
+
+#define MSDC_CLR_FIFO() \
+    do { \
+        MSDC_SET_BIT32(MSDC_FIFOCS, MSDC_FIFOCS_CLR); \
+        MSDC_RETRY(MSDC_READ32(MSDC_FIFOCS) & MSDC_FIFOCS_CLR, 5, 1000); \
+    } while (0)
+
+#define MSDC_FIFO_WRITE32(val)  MSDC_WRITE32(MSDC_TXDATA, val)
+#define MSDC_FIFO_READ32()      MSDC_READ32(MSDC_RXDATA)
+#define MSDC_FIFO_WRITE8(val)   MSDC_WRITE8(MSDC_TXDATA, val)
+#define MSDC_FIFO_READ8()       MSDC_READ8(MSDC_RXDATA)
+
+#define MSDC_TXFIFOCNT() \
+    ((MSDC_READ32(MSDC_FIFOCS) & MSDC_FIFOCS_TXCNT) >> 16)
+#define MSDC_RXFIFOCNT() \
+    ((MSDC_READ32(MSDC_FIFOCS) & MSDC_FIFOCS_RXCNT) >> 0)
+
+#define SDC_IS_BUSY()       (MSDC_READ32(SDC_STS) & SDC_STS_SDCBUSY)
+#define SDC_IS_CMD_BUSY()   (MSDC_READ32(SDC_STS) & SDC_STS_CMDBUSY)
+
+#define SDC_SEND_CMD(cmd,arg) \
+    do { \
+        MSDC_WRITE32(SDC_ARG, (arg)); \
+        MSDC_WRITE32(SDC_CMD, (cmd)); \
+    } while (0)
+
+#define MSDC_DMA_ON     MSDC_CLR_BIT32(MSDC_CFG, MSDC_CFG_PIO);
+#define MSDC_DMA_OFF    MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_PIO);
+
+#define MSDC_RELIABLE_WRITE     (0x1 << 0)
+#define MSDC_PACKED             (0x1 << 1)
+#define MSDC_TAG_REQUEST        (0x1 << 2)
+#define MSDC_CONTEXT_ID         (0x1 << 3)
+#define MSDC_FORCED_PROG        (0x1 << 4)
+
+#ifdef FPGA_PLATFORM
+#define msdc_pin_set(...)
+#define msdc_set_smt(...)
+#define msdc_set_driving(...)
+#endif
+
+int msdc_init(struct mmc_host *host);
+void msdc_config_bus(struct mmc_host *host, u32 width);
+int msdc_dma_transfer(struct mmc_host *host, struct mmc_data *data);
+int msdc_tune_bwrite(struct mmc_host *host, u32 dst, u8 *src, u32 nblks);
+int msdc_tune_bread(struct mmc_host *host, u8 *dst, u32 src, u32 nblks);
+void msdc_reset_tune_counter(struct mmc_host *host);
+int msdc_abort_handler(struct mmc_host *host, int abort_card);
+int msdc_tune_read(struct mmc_host *host);
+void msdc_config_clock(struct mmc_host *host, int state, u32 hz);
+int msdc_cmd(struct mmc_host *host, struct mmc_command *cmd);
+void msdc_set_timeout(struct mmc_host *host, u32 ns, u32 clks);
+void msdc_set_autocmd(struct mmc_host *host, int cmd);
+int msdc_get_autocmd(struct mmc_host *host);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/msdc_cfg.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/msdc_cfg.h
new file mode 100644
index 0000000..0afd634
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/msdc_cfg.h
@@ -0,0 +1,48 @@
+/*
+ * 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
+
+/*--------------------------------------------------------------------------*/
+/* Common Definition                                                        */
+/*--------------------------------------------------------------------------*/
+#ifdef MACH_FPGA
+#define FPGA_PLATFORM
+#endif
+
+/* HW deal with the 2K DMA boundary limitation, SW do nothing with it */
+/* Most of eMMC request in lk are sequential access, so it's no need to
+ * use descript DMA mode, I just remove relevant codes. JieWu@20160607 */
+#define MSDC_USE_DMA_MODE
+
+#define FEATURE_MMC_WR_TUNING
+#define FEATURE_MMC_RD_TUNING
+#define FEATURE_MMC_CM_TUNING
+
+/* Maybe we discard these macro definition */
+//#define MSDC_USE_PATCH_BIT2_TURNING_WITH_ASYNC
+
+/*--------------------------------------------------------------------------*/
+/* Debug Definition                                                         */
+/*--------------------------------------------------------------------------*/
+//#define KEEP_SLIENT_BUILD
+//#define ___MSDC_DEBUG___
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt2712.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt2712.h
new file mode 100644
index 0000000..64f5295
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt2712.h
@@ -0,0 +1,119 @@
+/*
+ * 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
+#include <compiler.h>
+#include <debug.h>
+
+#if LK_AS_BL33 == 0 /* LK as BL2 */
+/* program memory: L2C for BL2 */
+#define MEMORY_BASE_PHYS        (0x200000)
+#define MEMORY_APERTURE_SIZE    (0x40000UL)
+
+/* internal SRAM */
+#define SRAM_BASE_PHYS          (0x100000)
+#define SRAM_BASE_SIZE          (0x30000UL)
+
+/* memory for log store(part of internal sram) */
+#define MEMORY_LOG_PHYS         (SRAM_BASE_PHYS + SRAM_BASE_SIZE - \
+                                 SRAM_LOG_SIZE - MRDUMP_CB_SIZE)
+#define MEMORY_LOG_SIZE         (SRAM_LOG_SIZE)
+
+#else /* LK as BL33 */
+
+/* program memory and memory before mempool */
+#define MEMORY_BASE_PHYS        (0x40000000)
+#define MEMORY_APERTURE_SIZE    (0x33600000UL)
+
+/* non-secure accessible internal SRAM region */
+#define SRAM_BASE_PHYS          (0x118000)
+#define SRAM_BASE_SIZE          (0x18000UL)
+
+/* memory for log store(dram region) */
+#define MEMORY_LOG_PHYS         (0x43EC0000)
+#define MEMORY_LOG_SIZE         (0x40000)
+
+#endif
+
+/* cmsys sram */
+#define CMSYS_SRAM_PHYS         (0x130000)
+#define CMSYS_SRAM_SIZE         (0x20000UL)
+
+/* chip id, hw/sw version */
+#define CHIP_ID_BASE_PHYS       (0x08000000)
+#define CHIP_ID_BASE_SIZE       (0x200000)
+
+/* peripheral */
+#define PERIPHERAL_BASE_PHYS    (0x10000000)
+#define PERIPHERAL_BASE_SIZE    (0x10000000UL)
+
+/* dram */
+#define DRAM_BASE_PHY           (0x40000000UL)
+
+#if WITH_KERNEL_VM
+#define MEMORY_BASE_VIRT        (KERNEL_ASPACE_BASE + MEMORY_BASE_PHYS)
+#define SRAM_BASE_VIRT          (KERNEL_ASPACE_BASE + 0x300000)
+#define CMSYS_SRAM_VIRT         (KERNEL_ASPACE_BASE + CMSYS_SRAM_PHYS)
+#define CHIP_ID_BASE_VIRT       (KERNEL_ASPACE_BASE + CHIP_ID_BASE_PHYS)
+#define PERIPHERAL_BASE_VIRT    (KERNEL_ASPACE_BASE + PERIPHERAL_BASE_PHYS)
+#define DRAM_BASE_VIRT          (KERNEL_ASPACE_BASE + DRAM_BASE_PHY)
+
+#else
+#define MEMORY_BASE_VIRT        MEMORY_BASE_PHYS
+#define SRAM_BASE_VIRT          SRAM_BASE_PHYS
+#define CMSYS_SRAM_VIRT         CMSYS_SRAM_PHYS
+#define CHIP_ID_BASE_VIRT       CHIP_ID_BASE_PHYS
+#define PERIPHERAL_BASE_VIRT    PERIPHERAL_BASE_PHYS
+#define DRAM_BASE_VIRT          DRAM_BASE_PHY
+#endif
+
+/* LK/BL33 heap phy address */
+#define HEAP_BASE_PHY           0x734d0000UL
+#define HEAP_BASE_SIZE          0x30000
+
+/* |--176KB ARENA--|--8KB Log Buffer--|--8KB mrdump--|*/
+/* reserve 8KB sram for mrdump(last 8KB) */
+#define MRDUMP_CB_SIZE          0x2000
+/* reserve 8KB sram for log before dram init(only in bl2) */
+#define SRAM_LOG_SIZE           0x2000
+/* sram used as arena memory*/
+#define SRAM_ARENA_BASE         SRAM_BASE_PHYS
+#define SRAM_ARENA_SIZE         (SRAM_BASE_SIZE - MRDUMP_CB_SIZE - \
+                                 SRAM_LOG_SIZE)
+
+#define DRAM_ARENA_BASE         HEAP_BASE_PHY
+#define DRAM_ARENA_SIZE         HEAP_BASE_SIZE
+
+/* 256KB dram to store bl2/bl33 log */
+#define DRAM_LOG_ADDR           0x78032000
+#define DRAM_LOG_SIZE           0x40000
+
+/* 4KB use for LK2.0 transfer bootargs to BL33 */
+#define DRAM_BOOTARG_OFFSET     0x334cf000
+#define DRAM_BOOTARG_BASE       (DRAM_BASE_PHY + DRAM_BOOTARG_OFFSET)
+#define DRAM_BOOTARG_SIZE       0x1000
+
+/* interrupts */
+#define ARM_GENERIC_TIMER_VIRTUAL_INT 27
+#define ARM_GENERIC_TIMER_PHYSICAL_INT 30
+
+#define MAX_INT 292
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_gpio.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_gpio.h
new file mode 100644
index 0000000..bf0b66e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_gpio.h
@@ -0,0 +1,50 @@
+/*
+ * 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 GPIO_RDSEL0_EN    (GPIO_BASE + 0xA10)
+#define GPIO_RDSEL1_EN    (GPIO_BASE + 0xA20)
+#define GPIO_RDSEL2_EN    (GPIO_BASE + 0xA30)
+#define GPIO_RDSEL3_EN    (GPIO_BASE + 0xA40)
+#define GPIO_RDSEL4_EN    (GPIO_BASE + 0xA50)
+#define GPIO_RDSEL5_EN    (GPIO_BASE + 0xA60)
+#define GPIO_RDSEL6_EN    (GPIO_BASE + 0xA70)
+#define GPIO_RDSEL7_EN    (GPIO_BASE + 0xA80)
+#define GPIO_RDSEL8_EN    (GPIO_BASE + 0xA90)
+#define GPIO_RDSEL9_EN    (GPIO_BASE + 0xAA0)
+#define GPIO_RDSELA_EN    (GPIO_BASE + 0xAB0)
+#define GPIO_RDSELB_EN    (GPIO_BASE + 0xAC0)
+#define GPIO_RDSELC_EN    (GPIO_BASE + 0xAD0)
+#define GPIO_RDSELD_EN    (GPIO_BASE + 0xAE0)
+#define GPIO_RDSELE_EN    (GPIO_BASE + 0xAF0)
+#define GPIO_RDSELF_EN    (GPIO_BASE + 0xB00)
+#define GPIO_RDSEL10_EN   (GPIO_BASE + 0xB10)
+#define GPIO_RDSEL11_EN   (GPIO_BASE + 0xB20)
+#define GPIO_MSDC0_CTRL5  (GPIO_BASE + 0xC70)
+#define GPIO_MSDC1_CTRL5  (GPIO_BASE + 0xCB0)
+#define GPIO_MSDC2_CTRL5  (GPIO_BASE + 0xD10)
+#define GPIO_MSDC3_CTRL5  (GPIO_BASE + 0xD70)
+#define GPIO_EXMD_CTRL0   (GPIO_BASE + 0xE40)
+#define GPIO_NC_CTRL4     (GPIO_BASE + 0xF60)
+
+void mt_gpio_init(void);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_infracfg.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_infracfg.h
new file mode 100644
index 0000000..eb7a287
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_infracfg.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 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 <platform/mt2712.h>
+
+#define TOPAXI_PROT_EN      (INFRACFG_BASE + 0x220)
+#define TOPAXI_PROT_STA1    (INFRACFG_BASE + 0x228)
+#define TOPAXI_PROT_EN1     (INFRACFG_BASE + 0x250)
+#define TOPAXI_PROT_STA3    (INFRACFG_BASE + 0x258)
+#define TOPAXI_PROT_EN_SET  (INFRACFG_BASE + 0x260)
+#define TOPAXI_PROT_EN_CLR  (INFRACFG_BASE + 0x264)
+#define INFRA_MISC          (INFRACFG_BASE + 0xf00)
+
+/* TOPAXI_PROT_EN_SET and TOPAXI_PROT_EN_CLR setting */
+#define MFG_PROT_MASK       ((0x1 << 14) | (0x1 << 21) | (0x1 << 23))
+
+/* INFRA_MISC setting */
+#define DDR_4GB_SUPPORT_EN  (0x1 << 13)
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_irq.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_irq.h
new file mode 100644
index 0000000..3c23f0e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_irq.h
@@ -0,0 +1,275 @@
+/*
+ * 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 GIC_DIST_PENDING_SET            0x200
+#define GIC_DIST_ENABLE_SET             0x100
+#define GIC_DIST_ENABLE_CLEAR           0x180
+#define GIC_DIST_PENDING_CLEAR          0x280
+#define GIC_DIST_CTR                    0x004
+#define GIC_DIST_CTRL                   0x000
+#define GIC_DIST_TARGET                 0x800
+#define GIC_DIST_ACTIVE_BIT             0x300
+#define GIC_DIST_PRI                    0x400
+#define GIC_DIST_ICDISR                 0x80
+#define GIC_DIST_CONFIG                 0xc00
+#define GIC_DIST_SOFTINT                0xf00
+
+#define GIC_CPU_HIGHPRI                 0x18
+#define GIC_CPU_EOI                     0x10
+#define GIC_CPU_RUNNINGPRI              0x14
+#define GIC_CPU_BINPOINT                0x08
+#define GIC_CPU_INTACK                  0x0c
+#define GIC_CPU_CTRL                    0x00
+#define GIC_CPU_PRIMASK                 0x04
+
+/*
+ * Define IRQ code.
+ */
+#define GIC_PRIVATE_SIGNALS (32)
+
+#define GIC_PPI_OFFSET          (27)
+#define GIC_PPI_GLOBAL_TIMER    (GIC_PPI_OFFSET + 0)
+#define GIC_PPI_LEGACY_FIQ      (GIC_PPI_OFFSET + 1)
+#define GIC_PPI_PRIVATE_TIMER   (GIC_PPI_OFFSET + 2)
+#define GIC_PPI_WATCHDOG_TIMER  (GIC_PPI_OFFSET + 3)
+#define GIC_PPI_LEGACY_IRQ      (GIC_PPI_OFFSET + 4)
+
+#define USB_MCU_IRQ_BIT0_ID          104
+#define USB_MCU_IRQ_BIT1_ID          105
+#define TS_IRQ_BIT_ID                106
+#define TS_BATCH_IRQ_BIT_ID          107
+#define LOWBATTERY_IRQ_BIT_ID        108
+#define PWM_IRQ_BIT_ID               109
+#define THERM_CTRL_IRQ_BIT_ID        110
+#define MSDC0_IRQ_BIT_ID             111
+#define MSDC1_IRQ_BIT_ID             112
+#define MSDC2_IRQ_BIT_ID             113
+#define MSDC3_IRQ_BIT_ID             114
+#define I2C0_IRQ_BIT_ID              116
+#define I2C1_IRQ_BIT_ID              117
+#define I2C2_IRQ_BIT_ID              118
+#define I2C3_IRQ_BIT_ID              119
+#define I2C4_IRQ_BIT_ID              120
+#define I2C6_IRQ_BIT_ID              122
+#define UART0_IRQ_BIT_ID             123
+#define UART1_IRQ_BIT_ID             124
+#define UART2_IRQ_BIT_ID             125
+#define UART3_IRQ_BIT_ID             126
+#define NFIECC_IRQ_BIT_ID            127
+#define NFI_IRQ_BIT_ID               128
+#define AP_DMA_IRDA0_IRQ_BIT_ID      129
+#define AP_DMA_I2C0_IRQ_BIT_ID       130
+#define AP_DMA_I2C1_IRQ_BIT_ID       131
+#define AP_DMA_I2C2_IRQ_BIT_ID       132
+#define AP_DMA_I2C3_IRQ_BIT_ID       133
+#define AP_DMA_I2C4_IRQ_BIT_ID       134
+#define AP_DMA_UART0_TX_IRQ_BIT_ID   135
+#define AP_DMA_UART0_RX_IRQ_BIT_ID   136
+#define AP_DMA_UART1_TX_IRQ_BIT_ID   137
+#define AP_DMA_UART1_RX_IRQ_BIT_ID   138
+#define AP_DMA_UART2_TX_IRQ_BIT_ID   139
+#define AP_DMA_UART2_RX_IRQ_BIT_ID   140
+#define AP_DMA_UART3_TX_IRQ_BIT_ID   141
+#define AP_DMA_UART3_RX_IRQ_BIT_ID   142
+#define AP_DMA_UART4_TX_IRQ_BIT_ID   143
+#define AP_DMA_UART4_RX_IRQ_BIT_ID   144
+#define AP_DMA_UART5_TX_IRQ_BIT_ID   145
+#define AP_DMA_UART5_RX_IRQ_BIT_ID   146
+#define PE2_MAC_IRQ_P0_BIT_ID        147
+#define IRDA_IRQ_BIT_ID              148
+#define PE2_MAC_IRQ_P1_BIT_ID        149
+#define SPI0_IRQ_BIT_ID              150
+#define MSDC0_WAKEUP_PS_IRQ_BIT_ID   151
+#define MSDC1_WAKEUP_PS_IRQ_BIT_ID   152
+#define MSDC2_WAKEUP_PS_IRQ_BIT_ID   153
+#define SSUSB_DEV_INT_ID             154
+#define SSUSB_XHCI_INT_B_ID          155
+#define MSDC3_WAKEUP_PS_IRQ_BIT_ID   156
+#define PTP_FSM_IRQ_BIT_ID           157
+#define UART4_IRQ_BIT_ID             158
+#define UART5_IRQ_BIT_ID             159
+#define WDT_IRQ_BIT_ID               160
+#define DCC_APARM_IRQ_BIT_ID         164
+#define BUS_DBG_TRACKER_IRQ_BIT_ID   165
+#define APARM_DOMAIN_IRQ_BIT_ID      166
+#define APARM_DECERR_IRQ_BIT_ID      167
+#define DOMAIN_ABORT_IRQ_BIT0_ID     168
+#define APMIXEDSYS_TX_IRQ_ID         169
+#define MIPI_CSI_TX_IRQ_ID           170
+#define MIPI_DSI_TX_IRQ_ID           171
+#define INFRA_APB_ASYNC_IRQ_ID       172
+#define TRNG_IRQ_BIT_ID              173
+#define AFE_MCU_IRQ_BIT_ID           174
+#define CQ_DMA_IRQ_BIT_ID            175
+#define CQ_DMA_SEC_IRQ_BIT_ID        176
+#define MM2_IOMMU_IRQ_B_ID           177
+#define MM2_IOMMU_SEC_IRQ_B_ID       178
+#define MM1_IOMMU_IRQ_B_ID           179
+#define MM1_IOMMU_SEC_IRQ_B_ID       180
+#define REFRESH_RATE_IRQ_BIT_ID      181
+#define GCPU_IRQ_BIT_ID              182
+#define GCPU_DMX_IRQ_BIT_ID          183
+#define APXGPT_IRQ_BIT_ID            184
+#define EINT_IRQ_BIT0_ID             185
+#define EINT_IRQ_BIT1_ID             186
+#define EINT_EVENT_IRQ_BIT0_ID       187
+#define EINT_EVENT_IRQ_BIT1_ID       188
+#define EINT_DIRECT_IRQ_BIT0_ID      189
+#define EINT_DIRECT_IRQ_BIT1_ID      190
+#define EINT_DIRECT_IRQ_BIT2_ID      191
+#define EINT_DIRECT_IRQ_BIT3_ID      192
+#define IRRX_IRQ_BIT_ID              193
+#define KP_IRQ_BIT_ID                194
+#define SLEEP_IRQ_BIT0_ID            195
+#define SLEEP_IRQ_BIT1_ID            196
+#define SLEEP_IRQ_BIT2_ID            197
+#define SLEEP_IRQ_BIT3_ID            198
+#define SLEEP_IRQ_BIT4_ID            199
+#define SLEEP_IRQ_BIT5_ID            200
+#define SLEEP_IRQ_BIT6_ID            201
+#define SLEEP_IRQ_BIT7_ID            202
+#define SEJ_APXGPT_IRQ_BIT_ID        203
+#define SEJ_WDT_IRQ_BIT_ID           204
+#define SYS_TIMER_IRQ_BIT0_ID        208
+#define MM_MUTEX_IRQ_BIT_ID          209
+#define MDP_RDMA0_IRQ_BIT_ID         210
+#define MDP_RDMA1_IRQ_BIT_ID         211
+#define MDP_RSZ0_IRQ_BIT_ID          212
+#define MDP_RSZ1_IRQ_BIT_ID          213
+#define MDP_RSZ2_IRQ_BIT_ID          214
+#define MDP_TDSHP0_IRQ_BIT_ID        215
+#define MDP_TDSHP1_IRQ_BIT_ID        216
+#define MDP_WDMA_IRQ_BIT_ID          217
+#define MDP_WROT0_IRQ_BIT_ID         218
+#define MDP_WROT1_IRQ_BIT_ID         219
+#define DISP_OVL0_IRQ_BIT_ID         220
+#define DISP_OVL1_IRQ_BIT_ID         221
+#define DISP_RDMA0_IRQ_BIT_ID        222
+#define DISP_RDMA1_IRQ_BIT_ID        223
+#define DISP_RDMA2_IRQ_BIT_ID        224
+#define DISP_WDMA0_IRQ_BIT_ID        225
+#define DISP_WDMA1_IRQ_BIT_ID        226
+#define DISP_COLOR0_IRQ_BIT_ID       227
+#define DISP_COLOR1_IRQ_BIT_ID       228
+#define DISP_AAL_IRQ_BIT_ID          229
+#define DISP_GAMMA_IRQ_BIT_ID        230
+#define DISP_UFOE_IRQ_BIT_ID         231
+#define DSI0_IRQ_BIT_ID              232
+#define DSI1_IRQ_BIT_ID              233
+#define DPI0_IRQ_BIT_ID              234
+#define MJC_APB_ERR_IRQ_BIT_ID       235
+#define DISP_OD_IRQ_BIT_ID           236
+#define DPI1_IRQ_BIT_ID              237
+#define VENC_IRQ_BIT_ID              238
+#define SMI_LARB3_IRQ_BIT_ID         239
+#define JPGDEC1_IRQ_BIT_ID           240
+#define VEN2_IRQ_BIT_ID              242
+#define JPGDEC_IRQ_BIT_ID            243
+#define VDEC_IRQ_BIT_ID              244
+#define SMI_LARB1_IRQ_BIT_ID         245
+#define IMG_RESZ_IRQ_BIT_ID          246
+#define SMI_LARB0_IRQ_BIT_ID         247
+#define SMI_LARB4_IRQ_BIT_ID         248
+#define SMI_LARB2_IRQ_BIT_ID         249
+#define SENINF_IRQ_BIT_ID            250
+#define CAM0_IRQ_BIT_ID              251
+#define CAM1_IRQ_BIT_ID              252
+#define CAM2_IRQ_BIT_ID              253
+#define CAM_SV0_IRQ_BIT_ID           254
+#define CAM_SV1_IRQ_BIT_ID           255
+#define FD_IRQ_BIT_ID                256
+#define MFG_IRQ_BIT0_ID              257
+#define MFG_IRQ_BIT1_ID              258
+#define MFG_IRQ_BIT2_ID              259
+#define MFG_IRQ_BIT3_ID              260
+#define MFG_IRQ_BIT4_ID              261
+#define MFG_IRQ_BIT5_ID              262
+#define MFG_IRQ_BIT6_ID              263
+#define MFG_IRQ_BIT7_ID              264
+#define MD_WDT_IRQ_BIT_ID            265
+#define CLDMA_AP_IRQ_BIT_ID          266
+#define AP2MD_BUS_TIMEOUT_IRQ_BIT_ID 267
+#define SMI_LARB6_IRQ_BIT_ID         268
+#define MT_NOR_IRQ_ID                270
+#define RTC_IRQ_BIT_ID               271
+#define SMI_LARB7_IRQ_BIT_ID         272
+#define SMI_LARB5_IRQ_BIT_ID         273
+#define ASYS_MCU_IRQ_BIT_ID          274
+#define ASRC1_MCU_IRQ_BIT_ID         275
+#define ASRC2_MCU_IRQ_BIT_ID         276
+#define ASRC3_MCU_IRQ_BIT_ID         277
+#define ASRC4_MCU_IRQ_BIT_ID         278
+#define ASRC5_MCU_IRQ_BIT_ID         279
+#define SYS_TIMER_IRQ_BIT1_ID        284
+#define SYS_TIMER_IRQ_BIT2_ID        285
+#define SYS_TIMER_IRQ_BIT3_ID        286
+#define SYS_TIMER_IRQ_BIT4_ID        287
+#define SYS_TIMER_IRQ_BIT5_ID        288
+#define MDP_RDMA2_IRQ_BIT_ID         289
+#define MDP_RDMA3_IRQ_BIT_ID         290
+#define MDP_WROT2_IRQ_BIT_ID         291
+#define DISP_AAL1_IRQ_BIT_ID         292
+#define DISP_OD1_IRQ_BIT_ID          293
+#define DISP_OVL2_IRQ_BIT_ID         294
+#define DISP_COLOR2_IRQ_BIT_ID       295
+#define DISP_WDMA2_IRQ_BIT_ID        296
+#define MDP_TDSHP2_IRQ_BIT_ID        297
+#define DSI2_IRQ_BIT_ID              298
+#define DSI3_IRQ_BIT_ID              299
+#define CAM_SV2_IRQ_BIT_ID           300
+#define CAM_SV3_IRQ_BIT_ID           301
+#define CAM_SV4_IRQ_BIT_ID           302
+#define CAM_SV5_IRQ_BIT_ID           303
+#define DISPFMT_VSYNC_IRQ_BIT_ID     304
+#define VDO_DISP_END_IRQ_BIT_ID      305
+#define VDO_UNDER_RUN_IRQ_BIT_ID     306
+#define WR_CHANNEL_DI_IRQ_BIT_ID     307
+#define WR_CHANNEL_VDI_IRQ_BIT_ID    308
+#define NR_IRQ_BIT_ID                309
+#define VDOIN_IRQ_BIT_ID             310
+#define DUMMY0_IRQ_BIT_ID            311
+#define DUMMY1_IRQ_BIT_ID            312
+#define DUMMY2_IRQ_BIT_ID            313
+#define DUMMY3_IRQ_BIT_ID            314
+#define SPI1_IRQ_BIT_ID              315
+#define SPI2_IRQ_BIT_ID              316
+#define SPI3_IRQ_BIT_ID              317
+#define SPI4_IRQ_BIT_ID              318
+#define SPI5_IRQ_BIT_ID              319
+#define GCPU_MMU_IRQ_BIT_ID          320
+#define GCPU_MMU_SEC_IRQ_BIT_ID      321
+#define SRAM_ECC_ERR_IRQ_BIT_ID      322
+
+#define MT_NR_PPI   (5)
+#define MT_NR_SPI   (292)
+#define NR_IRQ_LINE  (GIC_PPI_OFFSET + MT_NR_PPI + MT_NR_SPI)
+
+#define EDGE_SENSITIVE 0
+#define LEVEL_SENSITIVE 1
+
+#define MT65xx_POLARITY_LOW   0
+#define MT65xx_POLARITY_HIGH  1
+
+void mt_irq_set_sens(unsigned int irq, unsigned int sens);
+void mt_irq_set_polarity(unsigned int irq, unsigned int polarity);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_pericfg.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_pericfg.h
new file mode 100644
index 0000000..053f979
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_pericfg.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017 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 <platform/mt2712.h>
+
+#define PERIAXI_BUS_CTL3    (PERICFG_BASE + 0x208)
+#define PERISYS_4G_SUPPORT  (0x1 << 11)
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_reg_base.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_reg_base.h
new file mode 100644
index 0000000..0abe9bc
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_reg_base.h
@@ -0,0 +1,71 @@
+/*
+ * 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
+
+#include <platform/mt2712.h>
+
+/* I/O mapping */
+#define IO_PHYS             PERIPHERAL_BASE_VIRT
+#define IO_SIZE             PERIPHERAL_BASE_SIZE
+
+#define CKSYS_BASE          IO_PHYS
+#define INFRACFG_BASE       (IO_PHYS + 0x00001000)
+#define SCP_BASE_CFG        (IO_PHYS + 0x00002000)
+#define PERICFG_BASE        (IO_PHYS + 0x00003000)
+/* IO register definitions */
+#define GPIO_BASE           (IO_PHYS + 0x00005000)
+#define SEJ_BASE            (IO_PHYS + 0x0000A000)
+#define SPM_BASE            (IO_PHYS + 0x00006000)
+#define TOP_RGU_BASE        (IO_PHYS + 0x00007000)
+#define APMIXED_BASE        (IO_PHYS + 0x00209000)
+#define GIC_CPU_BASE        (IO_PHYS + 0x00520000)
+#define GIC_DIST_BASE       (IO_PHYS + 0x00510000)
+#define MCUSYS_CFGREG_BASE  (IO_PHYS + 0x00220000)
+#define INT_POL_CTL0        (MCUSYS_CFGREG_BASE + 0xa80)
+
+#define UART0_BASE          (IO_PHYS + 0x01002000)
+#define UART1_BASE          (IO_PHYS + 0x01003000)
+#define UART2_BASE          (IO_PHYS + 0x01004000)
+#define UART3_BASE          (IO_PHYS + 0x01005000)
+#define MSDC0_BASE          (IO_PHYS + 0x01230000)
+#define MSDC1_BASE          (IO_PHYS + 0x01240000)
+#define NOR_BASE            (IO_PHYS + 0x0100D000)
+#define NFI_BASE            (IO_PHYS + 0x0100E000)
+#define NFIECC_BASE         (IO_PHYS + 0x0100F000)
+
+#define APMIXED_BASE        (IO_PHYS + 0x00209000)
+#define TRNG_BASE           (IO_PHYS + 0x0020F000)
+
+/* APB Module ssusb_top */
+#define USB3_BASE           (IO_PHYS + 0x01270000)
+#define USB3_SIF_BASE       (IO_PHYS + 0x01280000)
+#define USB3_IPPC_BASE      (IO_PHYS + 0x01280700)
+#define USB3_SIF2_BASE      (IO_PHYS + 0x01290000)
+
+#define MFGCFG_BASE         (IO_PHYS + 0x03000000)
+#define MMSYS_BASE          (IO_PHYS + 0x04000000)
+#define IMGSYS_BASE         (IO_PHYS + 0x05000000)
+#define BDPSYS_BASE         (IO_PHYS + 0x05010000)
+#define VDECSYS_BASE        (IO_PHYS + 0x06000000)
+#define VENCSYS_BASE        (IO_PHYS + 0x08000000)
+#define JPGDECSYS_BASE      (IO_PHYS + 0x09000000)
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_scp.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_scp.h
new file mode 100644
index 0000000..2aef6d8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mt_scp.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018 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
+
+/* start scp processor */
+void start_scpsys(void);
+
+/* stop scp processor */
+void stop_scpsys(void);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_devinfo.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_devinfo.h
new file mode 100644
index 0000000..26afe52
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_devinfo.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#pragma once
+
+#include <devinfo.h>
+
+int det_ca35_freq(void);
+int det_ca72_freq(void);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_key.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_key.h
new file mode 100644
index 0000000..d89f5a1
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_key.h
@@ -0,0 +1,26 @@
+/*
+ * 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
+
+bool check_download_key(void);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_mrdump.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_mrdump.h
new file mode 100644
index 0000000..8d7c7ca
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_mrdump.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 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.
+ */
+
+#ifndef _LK_MTK_MRDUMP_H_
+#define _LK_MTK_MRDUMP_H_
+
+#include <platform/mt2712.h>
+//last 8KB for mcontrol
+#define MRDUMP_CB_ADDR (SRAM_BASE_PHYS + SRAM_BASE_SIZE - MRDUMP_CB_SIZE) //end -8K
+
+#define MRDUMP_OUTPUT_PARTITION "userdata"
+
+#endif /* _LK_MTK_MRDUMP_H_ */
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_nor.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_nor.h
new file mode 100644
index 0000000..747460a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_nor.h
@@ -0,0 +1,4 @@
+#pragma once
+
+void nor_init_device(void);
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_serial_key.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_serial_key.h
new file mode 100644
index 0000000..5b05e1f
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_serial_key.h
@@ -0,0 +1,36 @@
+/*
+ * 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
+
+/* serial key */
+#if WITH_KERNEL_VM
+#define SERIAL_KEY_HI    (18446744005260632388UL)
+#define SERIAL_KEY_LO    (18446744005260632384UL)
+#define SERIAL_KEY_2_HI  (18446744005260632396UL)
+#define SERIAL_KEY_2_LO  (18446744005260632392UL)
+#else
+#define SERIAL_KEY_HI    (270557508U)
+#define SERIAL_KEY_LO    (270557504U)
+#define SERIAL_KEY_2_HI  (270557516U)
+#define SERIAL_KEY_2_LO  (270557512U)
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_trng.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_trng.h
new file mode 100644
index 0000000..ce762ce
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_trng.h
@@ -0,0 +1,40 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*
+* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek Software")
+* have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+* applicable license agreements with MediaTek Inc.
+*/
+
+#ifndef __MTK_TRNG_H__
+#define __MTK_TRNG_H__
+s32 trng_drv_get_random_data(u8 *buf, u32 len);
+
+#endif  /* !defined __MTK_TRNG_H__ */
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_wdt.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_wdt.h
new file mode 100644
index 0000000..2dd243a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/mtk_wdt.h
@@ -0,0 +1,166 @@
+/*
+ * 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
+
+#include <platform/mt_reg_base.h>
+#include <stdbool.h>
+
+#define ENABLE_WDT_MODULE       (1) /* Module switch */
+#define LK_WDT_DISABLE          (1)
+
+#define MTK_WDT_BASE            TOP_RGU_BASE
+
+#define MTK_WDT_MODE			(MTK_WDT_BASE+0x0000)
+#define MTK_WDT_LENGTH			(MTK_WDT_BASE+0x0004)
+#define MTK_WDT_RESTART			(MTK_WDT_BASE+0x0008)
+#define MTK_WDT_STATUS			(MTK_WDT_BASE+0x000C)
+#define MTK_WDT_INTERVAL		(MTK_WDT_BASE+0x0010)
+#define MTK_WDT_SWRST			(MTK_WDT_BASE+0x0014)
+#define MTK_WDT_SWSYSRST		(MTK_WDT_BASE+0x0018)
+#define MTK_WDT_NONRST_REG		(MTK_WDT_BASE+0x0020)
+#define MTK_WDT_NONRST_REG2		(MTK_WDT_BASE+0x0024)
+#define MTK_WDT_REQ_MODE		(MTK_WDT_BASE+0x0030)
+#define MTK_WDT_REQ_IRQ_EN		(MTK_WDT_BASE+0x0034)
+#define MTK_WDT_DRAMC_CTL		(MTK_WDT_BASE+0x0040)
+#define MTK_WDT_DEBUG_2_REG		(MTK_WDT_BASE+0x0508)
+
+/*WDT_MODE*/
+#define MTK_WDT_MODE_KEYMASK        (0xff00)
+#define MTK_WDT_MODE_KEY        (0x22000000)
+#define MTK_WDT_MODE_DDR_RESERVE  (0x0080)
+
+#define MTK_WDT_MODE_DUAL_MODE  (0x0040)
+#define MTK_WDT_MODE_IN_DIS     (0x0020) /* Reserved */
+#define MTK_WDT_MODE_AUTO_RESTART   (0x0010) /* Reserved */
+#define MTK_WDT_MODE_IRQ        (0x0008)
+#define MTK_WDT_MODE_EXTEN      (0x0004)
+#define MTK_WDT_MODE_EXT_POL        (0x0002)
+#define MTK_WDT_MODE_ENABLE     (0x0001)
+
+/*WDT_LENGTH*/
+#define MTK_WDT_LENGTH_TIME_OUT     (0xffe0)
+#define MTK_WDT_LENGTH_KEYMASK      (0x001f)
+#define MTK_WDT_LENGTH_KEY      (0x0008)
+
+/*WDT_RESTART*/
+#define MTK_WDT_RESTART_KEY     (0x1971)
+
+/*WDT_STATUS*/
+#define MTK_WDT_STATUS_HWWDT_RST_WITH_IRQ    (0xA0000000)
+#define MTK_WDT_STATUS_HWWDT_RST    (0x80000000)
+#define MTK_WDT_STATUS_SWWDT_RST    (0x40000000)
+#define MTK_WDT_STATUS_IRQWDT_RST   (0x20000000)
+#define MTK_WDT_STATUS_SECURITY_RST (1<<28)
+#define MTK_WDT_STATUS_DEBUGWDT_RST (0x00080000)
+#define MTK_WDT_STATUS_THERMAL_CTL_RST   (1<<18)
+#define MTK_WDT_STATUS_SPMWDT_RST          (0x0002)
+#define MTK_WDT_STATUS_SPM_THERMAL_RST     (0x0001)
+
+/* Reboot reason */
+#define RE_BOOT_REASON_UNKNOW           (0x00)
+#define RE_BOOT_BY_WDT_HW               (0x01)
+#define RE_BOOT_BY_WDT_SW               (0x02)
+#define RE_BOOT_WITH_INTTERUPT          (0x04)
+#define RE_BOOT_BY_SPM_THERMAL          (0x08)
+#define RE_BOOT_BY_SPM                  (0x10)
+#define RE_BOOT_BY_THERMAL_DIRECT       (0x20)
+#define RE_BOOT_BY_DEBUG                (0x40)
+#define RE_BOOT_BY_SECURITY             (0x80)
+
+#define RE_BOOT_ABNORMAL                (0xF0)
+
+#define WDT_NORMAL_REBOOT               (0x100)
+#define WDT_BY_PASS_PWK_REBOOT          (0x200)
+#define WDT_NOT_WDT_REBOOT              (0x400)
+//MTK_WDT_DEBUG_CTL
+#define MTK_DEBUG_CTL_KEY           (0x59000000)
+#define MTK_RG_DDR_PROTECT_EN       (0x00001)
+#define MTK_RG_MCU_LATH_EN          (0x00002)
+#define MTK_RG_DRAMC_SREF           (0x00100)
+#define MTK_RG_DRAMC_ISO            (0x00200)
+#define MTK_RG_CONF_ISO             (0x00400)
+#define MTK_DDR_RESERVE_RTA         (0x10000)  //sta
+#define MTK_DDR_SREF_STA            (0x20000)  //sta
+
+/* WDT_NONRST_REG2  */
+#define MTK_WDT_NONRST2_BOOT_MASK   (0xF)
+#define MTK_WDT_NONRST2_BOOT_CHARGER    1
+#define MTK_WDT_NONRST2_BOOT_RECOVERY   2
+#define MTK_WDT_NONRST2_BOOT_BOOTLOADER 3
+#define MTK_WDT_NONRST2_BOOT_DM_VERITY  4
+#define MTK_WDT_NONRST2_BOOT_KPOC       5
+#define MTK_WDT_NONRST2_BOOT_DDR_RSVD   6
+#define MTK_WDT_NONRST2_BOOT_META       7
+#define MTK_WDT_NONRST2_BOOT_RPMBPK     8
+#define MTK_WDT_NONRST2_BOOT_FASTBOOTD  9
+#define MTK_WDT_NONRST2_CM4_RESUME      21
+#define MTK_WDT_NONRST2_SHOW_LOGO       22
+
+/*WDT_INTERVAL*/
+#define MTK_WDT_INTERVAL_MASK       (0x0fff)
+
+/*WDT_SWRST*/
+#define MTK_WDT_SWRST_KEY       (0x1209)
+
+/*WDT_SWSYSRST*/
+#define MTK_WDT_SWSYS_RST_PWRAP_SPI_CTL_RST (0x0800)
+#define MTK_WDT_SWSYS_RST_APMIXED_RST   (0x0400)
+#define MTK_WDT_SWSYS_RST_MD_LITE_RST   (0x0200)
+#define MTK_WDT_SWSYS_RST_INFRA_AO_RST  (0x0100)
+#define MTK_WDT_SWSYS_RST_MD_RST    (0x0080)
+#define MTK_WDT_SWSYS_RST_DDRPHY_RST    (0x0040)
+#define MTK_WDT_SWSYS_RST_IMG_RST   (0x0020)
+#define MTK_WDT_SWSYS_RST_VDEC_RST  (0x0010)
+#define MTK_WDT_SWSYS_RST_VENC_RST  (0x0008)
+#define MTK_WDT_SWSYS_RST_MFG_RST   (0x0004)
+#define MTK_WDT_SWSYS_RST_DISP_RST  (0x0002)
+#define MTK_WDT_SWSYS_RST_INFRA_RST (0x0001)
+
+#define MTK_WDT_SWSYS_RST_KEY       (0x88000000)
+
+typedef enum wd_swsys_reset_type {
+    WD_MD_RST,
+} WD_SYS_RST_TYPE;
+
+void set_clr_fastboot_mode(bool flag);
+void set_clr_fastbootd_mode(bool flag);
+void set_clr_recovery_mode(bool flag);
+void clr_cm4_resume_mode(void);
+bool check_fastboot_mode(void);
+bool check_fastbootd_mode(void);
+bool check_recovery_mode(void);
+unsigned int mtk_wdt_check_status(void);
+void mtk_wdt_init(void);
+void mtk_wdt_disable(void);
+void rgu_dram_reserved(bool enable);
+int rgu_is_reserve_ddr_enabled(void);
+
+int rgu_is_dram_slf(void);
+
+void rgu_release_rg_dramc_conf_iso(void);
+
+void rgu_release_rg_dramc_iso(void);
+
+void rgu_release_rg_dramc_sref(void);
+int rgu_is_reserve_ddr_mode_success(void);
+void mtk_arch_reset(char mode);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_ecc_hal.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_ecc_hal.h
new file mode 100644
index 0000000..220a55e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_ecc_hal.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2017 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 <kernel/event.h>
+#include <kernel/mutex.h>
+#include <sys/types.h>
+
+#define     ECC_IDLE_MASK       NAND_BIT(0)
+#define     ECC_IRQ_EN          NAND_BIT(0)
+#define     ECC_OP_ENABLE       (1)
+#define     ECC_OP_DISABLE      (0)
+
+#define     ECC_ENCCON          (0x00)
+#define     ECC_ENCCNFG         (0x04)
+#define     ECC_CNFG_4BIT       (0)
+#define     ECC_CNFG_6BIT       (1)
+#define     ECC_CNFG_8BIT       (2)
+#define     ECC_CNFG_10BIT      (3)
+#define     ECC_CNFG_12BIT      (4)
+#define     ECC_CNFG_14BIT      (5)
+#define     ECC_CNFG_16BIT      (6)
+#define     ECC_CNFG_18BIT      (7)
+#define     ECC_CNFG_20BIT      (8)
+#define     ECC_CNFG_22BIT      (9)
+#define     ECC_CNFG_24BIT      (0xa)
+#define     ECC_CNFG_28BIT      (0xb)
+#define     ECC_CNFG_32BIT      (0xc)
+#define     ECC_CNFG_36BIT      (0xd)
+#define     ECC_CNFG_40BIT      (0xe)
+#define     ECC_CNFG_44BIT      (0xf)
+#define     ECC_CNFG_48BIT      (0x10)
+#define     ECC_CNFG_52BIT      (0x11)
+#define     ECC_CNFG_56BIT      (0x12)
+#define     ECC_CNFG_60BIT      (0x13)
+#define     ECC_CNFG_68BIT      (0x14)
+#define     ECC_CNFG_72BIT      (0x15)
+#define     ECC_CNFG_80BIT      (0x16)
+#define     ECC_MODE_SHIFT      (5)
+#define     ECC_MS_SHIFT        (16)
+#define     ECC_ENCDIADDR       (0x08)
+#define     ECC_ENCIDLE         (0x0c)
+#define     ECC_ENCSTA          (0x7c)
+#define     ENC_IDLE            NAND_BIT(0)
+#define     ECC_ENCIRQ_EN       (0x80)
+#define     ECC_ENCIRQ_STA      (0x84)
+#define     PG_IRQ_SEL          NAND_BIT(1)
+#define     ECC_PIO_DIRDY       (0x90)
+#define     PIO_DI_RDY          (0x01)
+#define     ECC_PIO_DI          (0x94)
+#define     ECC_DECCON          (0x100)
+#define     ECC_DECCNFG         (0x104)
+#define     DEC_EMPTY_EN        NAND_BIT(31)
+#define     DEC_CON_SHIFT       (12)
+#define     ECC_DECDIADDR       (0x108)
+#define     ECC_DECIDLE         (0x10c)
+#define     ECC_DECENUM(x)      (0x114 + (x) * sizeof(u32))
+#define     ERR_MASK            (0x7f)
+#define     ECC_DECDONE         (0x124)
+#define     ECC_DECIRQ_EN       (0x200)
+#define     ECC_DECIRQ_STA      (0x204)
+#define     ECC_DECFSM          (0x208)
+#define     FSM_MASK            (0x3f3fff0f)
+#define     FSM_IDLE            (0x01011101)
+
+#define     ECC_ENCPAR(x)       (0x300 + (x) * sizeof(u32))
+#define     ECC_DECEL(x)        (0x500 + (x) * sizeof(u32))
+#define     DECEL_MASK          (0x3fff)
+#define     ECC_TIMEOUT         (500000)
+
+#define     ECC_IDLE_REG(op)    ((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE)
+#define     ECC_CTL_REG(op)     ((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON)
+#define     ECC_IRQ_REG(op)     ((op) == ECC_ENCODE ? ECC_ENCIRQ_EN : ECC_DECIRQ_EN)
+#define     ECC_PARITY_BITS     (14)
+#define     MAX_ECC_STRENGTH    (80)
+
+#define     writew(v, a)        (*REG16(a) = (v))
+#define     readw(a)            (*REG16(a))
+
+struct mtk_ecc {
+    mutex_t lock;
+    event_t irq_event;
+    uintptr_t regs;
+    u32 sectors;
+};
+
+enum mtk_ecc_mode {
+    ECC_DMA_MODE = 0,
+    ECC_NFI_MODE = 1,
+    ECC_PIO_MODE = 2
+};
+
+enum mtk_ecc_operation {
+    ECC_ENCODE,
+    ECC_DECODE
+};
+
+enum mtk_ecc_deccon {
+    ECC_DEC_FER = 1,
+    ECC_DEC_LOCATE = 2,
+    ECC_DEC_CORRECT = 3
+};
+
+struct mtk_ecc_stats {
+    u32 corrected;
+    u32 bitflips;
+    u32 failed;
+};
+
+struct mtk_ecc_config {
+    enum mtk_ecc_operation op;
+    enum mtk_ecc_mode mode;
+    enum mtk_ecc_deccon deccon;
+    u32 addr;
+    u32 strength;
+    u32 sectors;
+    u32 len;
+};
+
+int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+                          u8 *data, u32 bytes, int polling);
+int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config, int polling);
+void mtk_ecc_disable(struct mtk_ecc *ecc);
+void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats, u32 sectors);
+int mtk_ecc_cpu_correct(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats, u8 *data, u32 sector, int polling);
+int mtk_ecc_wait_done(struct mtk_ecc *ecc, enum mtk_ecc_operation op, int polling);
+int mtk_ecc_hw_init(struct mtk_ecc **ext_ecc);
+int mtk_ecc_wait_decode_fsm_idle(struct mtk_ecc *ecc);
+int mtk_ecc_decode(struct mtk_ecc *ecc, struct mtk_ecc_config *config, u8 *data, u32 len, int polling);
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nand_bbt.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nand_bbt.h
new file mode 100644
index 0000000..3fdb9fb
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nand_bbt.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 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 <platform/nand/mtk_nand_nal.h>
+
+#define SCAN_BBT_MAXBLOCKS      4
+
+int mtk_nand_isbad_bbt(struct mtk_nand_chip *chip, u32 page);
+int mtk_nand_scan_bbt(struct mtk_nand_chip *chip);
+int mtk_nand_markbad_bbt(struct mtk_nand_chip *chip, u32 page);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nand_common.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nand_common.h
new file mode 100644
index 0000000..c009b75
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nand_common.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017 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 <platform.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+#define NAND_BIT(nr)        (1UL << (nr))
+#define NAND_GENMASK(h, l)  (((~0UL) << (l)) & (~0UL >> ((sizeof(unsigned long) * 8) - 1 - (h))))
+#define DIV_ROUND_UP(n,d)   (((n) + (d) - 1) / (d))
+#define clamp(val, lo, hi)  MIN((typeof(val))MAX(val, lo), hi)
+
+#define MTK_TIMEOUT         (500000)
+
+#define KB(x)               ((x) * 1024UL)
+#define MB(x)               (KB(x) * 1024UL)
+
+#define swap(a, b) \
+    do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while(0)
+
+/*
+ * wait until cond gets true or timeout.
+ *
+ * cond : C expression to wait
+ * timeout : usecs
+ *
+ * Returns:
+ * 0 : if cond = false after timeout elapsed.
+ * 1 : if cond = true after timeout elapsed,
+ * or the remain usecs if cond = true before timeout elapsed.
+ */
+#define check_with_timeout(cond, timeout)                      \
+({                                                             \
+    lk_bigtime_t __ret;                                        \
+    if (cond) {                                                \
+        __ret = timeout;                                       \
+    } else {                                                   \
+        lk_bigtime_t __end = current_time_hires() + timeout;   \
+                                                               \
+        for (;;) {                                             \
+            lk_bigtime_t __now = current_time_hires();         \
+                                                               \
+            if (cond) {                                        \
+                __ret = (__end > __now) ? (__end - __now) : 1; \
+                    break;                                     \
+            }                                                  \
+                                                               \
+            if (__end <= __now) {                              \
+                __ret = 0;                                     \
+                break;                                         \
+            }                                                  \
+        }                                                      \
+    }                                                          \
+    __ret;                                                     \
+})
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nand_nal.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nand_nal.h
new file mode 100644
index 0000000..545e915
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nand_nal.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2017 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 <platform/nand/mtk_ecc_hal.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+/* Select the chip by setting nCE to low */
+#define NAND_NCE                    0x01
+/* Select the command latch by setting CLE to high */
+#define NAND_CLE                    0x02
+/* Select the address latch by setting ALE to high */
+#define NAND_ALE                    0x04
+
+#define NAND_CTRL_CLE               (NAND_NCE | NAND_CLE)
+#define NAND_CTRL_ALE               (NAND_NCE | NAND_ALE)
+#define NAND_CTRL_CHANGE            0x80
+
+/*
+ * Standard NAND flash commands
+ */
+#define NAND_CMD_READ0              0
+#define NAND_CMD_READ1              1
+#define NAND_CMD_RNDOUT             5
+#define NAND_CMD_PAGEPROG           0x10
+#define NAND_CMD_READOOB            0x50
+#define NAND_CMD_ERASE1             0x60
+#define NAND_CMD_STATUS             0x70
+#define NAND_CMD_SEQIN              0x80
+#define NAND_CMD_RNDIN              0x85
+#define NAND_CMD_READID             0x90
+#define NAND_CMD_ERASE2             0xd0
+#define NAND_CMD_PARAM              0xec
+#define NAND_CMD_GET_FEATURES       0xee
+#define NAND_CMD_SET_FEATURES       0xef
+#define NAND_CMD_RESET              0xff
+#define NAND_CMD_LOCK               0x2a
+#define NAND_CMD_UNLOCK1            0x23
+#define NAND_CMD_UNLOCK2            0x24
+
+/* Extended commands for large page devices */
+#define NAND_CMD_READSTART          0x30
+#define NAND_CMD_READCACHESEQ       0x31
+#define NAND_CMD_READCACHELAST      0x3f
+#define NAND_CMD_RNDOUTSTART        0xE0
+#define NAND_CMD_CACHEDPROG         0x15
+#define NAND_CMD_NONE               -1
+
+/* Status bits */
+#define NAND_STATUS_FAIL            0x01
+#define NAND_STATUS_FAIL_N1         0x02
+#define NAND_STATUS_TRUE_READY      0x20
+#define NAND_STATUS_READY           0x40
+#define NAND_STATUS_WP              0x80
+
+/* Search good / bad pattern on the first and the second page */
+#define NAND_BBT_SCAN2NDPAGE        0x00008000
+/* Search good / bad pattern on the last page of the eraseblock */
+#define NAND_BBT_SCANLASTPAGE       0x00010000
+
+/* Chip has cache read function */
+#define NAND_CACHEREAD              0x00000004
+/* Chip has cache program function */
+#define NAND_CACHEPRG               0x00000008
+
+/*
+ * Some MLC NANDs need data scrambling to limit bitflips caused by repeated
+ * patterns.
+ */
+#define NAND_NEED_SCRAMBLING        0x00002000
+
+#define NAND_HAS_CACHEPROG(chip)    ((chip->options & NAND_CACHEPRG))
+#define NAND_HAS_CACHEREAD(chip)    ((chip->options & NAND_CACHEREAD))
+
+/* Max NAND ID length */
+#define NAND_MAX_ID_LEN             8
+
+struct mtk_nand_flash_dev {
+    const char *name;
+    u8 id[NAND_MAX_ID_LEN];
+    u8 id_len;
+
+    /* unit: KByte */
+    u32 chipsize;
+    u32 erasesize;
+    u32 pagesize;
+    u16 oobsize;
+    u32 fdmeccsize;
+    u8 bits_per_cell;
+
+    /* customized setting if need */
+    u32 acctiming;
+    u32 ecc_size;
+    u32 ecc_strength;
+    u32 bbt_options;
+    u32 options;
+};
+
+enum {
+    NAND_OPS_RAW_DMA_POLL = 0,
+    NAND_OPS_RAW_DMA_IRQ,
+    NAND_OPS_RAW_PIO_POLL,
+    NAND_OPS_RAW_PIO_IRQ,
+    NAND_OPS_ECC_DMA_POLL,
+    NAND_OPS_ECC_DMA_IRQ,
+    NAND_OPS_ECC_PIO_POLL,
+    NAND_OPS_ECC_PIO_IRQ,
+    NAND_OPS_ERASE_POLL,
+    NAND_OPS_ERASE_IRQ,
+};
+
+enum mtk_randomizer_operation {RAND_ENCODE, RAND_DECODE};
+
+struct mtk_nand_ops {
+    u32 mode;
+    u64 offset;
+    u64 len;
+    const u8 *writebuf;
+    u8 *readbuf;
+    /* ecc protected oob data */
+    u8 *oobeccbuf;
+    u32 oobeccoffs;
+    u32 oobecclen;
+    /* ecc unprotected oob data */
+    u8 *oobrawbuf;
+    u32 oobrawoffs;
+    u32 oobrawlen;
+    /* ecc parity data */
+    u8 *oobparitybuf;
+    u32 oobparityoffs;
+    u32 oobparitylen;
+};
+
+struct mtk_nand_chip {
+    u8 (*read_byte)(struct mtk_nand_chip *nand);
+    void (*write_byte)(struct mtk_nand_chip *nand, u8 byte);
+    void (*write_buf)(struct mtk_nand_chip *nand, const u8 *buf, int len);
+    void (*read_buf)(struct mtk_nand_chip *nand, u8 *buf, int len);
+    void (*select_chip)(struct mtk_nand_chip *nand, int chip);
+    void (*cmd_ctrl)(struct mtk_nand_chip *nand, int dat, unsigned int ctrl);
+    int (*dev_ready)(struct mtk_nand_chip *nand);
+    int (*wait_busy_irq)(struct mtk_nand_chip *nand);
+    void (*cmdfunc)(struct mtk_nand_chip *nand, unsigned command, int column,
+                    int page_addr);
+    int(*waitfunc)(struct mtk_nand_chip *this, int polling);
+
+    int (*block_bad)(struct mtk_nand_chip *nand, u64 ofs);
+    int (*block_markbad)(struct mtk_nand_chip *nand, u64 ofs);
+
+    int (*write_page_ecc_dma_polling)(struct mtk_nand_chip *chip, const u8 *buf,
+                                      int page);
+    int (*write_page_ecc_dma_irq)(struct mtk_nand_chip *chip, const u8 *buf,
+                                  int page);
+    int (*write_page_ecc_pio_polling)(struct mtk_nand_chip *chip, const u8 *buf,
+                                      int page);
+    int (*write_page_ecc_pio_irq)(struct mtk_nand_chip *chip, const u8 *buf,
+                                  int page);
+    int (*write_page_raw_dma_polling)(struct mtk_nand_chip *chip, const u8 *buf,
+                                      int page);
+    int (*write_page_raw_dma_irq)(struct mtk_nand_chip *chip, const u8 *buf,
+                                  int page);
+    int (*write_page_raw_pio_polling)(struct mtk_nand_chip *chip, const u8 *buf,
+                                      int page);
+    int (*write_page_raw_pio_irq)(struct mtk_nand_chip *chip, const u8 *buf,
+                                  int page);
+    int (*write_subpage_ecc_dma_polling)(struct mtk_nand_chip *chip, u32 offset,
+                                         u32 data_len, const u8 *buf, int page);
+    int (*write_subpage_ecc_dma_irq)(struct mtk_nand_chip *chip, u32 offset,
+                                     u32 data_len, const u8 *buf, int page);
+    int (*write_subpage_ecc_pio_polling)(struct mtk_nand_chip *chip, u32 offset,
+                                         u32 data_len, const u8 *buf, int page);
+    int (*write_subpage_ecc_pio_irq)(struct mtk_nand_chip *chip, u32 offset,
+                                     u32 data_len, const u8 *buf, int page);
+
+    int (*read_subpage_ecc_dma_polling)(struct mtk_nand_chip *chip, u32 off,
+                                        u32 len, u8 *p, int pg);
+    int (*read_subpage_ecc_dma_irq)(struct mtk_nand_chip *chip, u32 off,
+                                    u32 len, u8 *p, int pg);
+    int (*read_subpage_ecc_pio_polling)(struct mtk_nand_chip *chip, u32 off,
+                                        u32 len, u8 *p, int pg);
+    int (*read_subpage_ecc_pio_irq)(struct mtk_nand_chip *chip, u32 off,
+                                    u32 len, u8 *p, int pg);
+    int (*read_page_ecc_dma_polling)(struct mtk_nand_chip *chip, u8 *p, int pg);
+    int (*read_page_ecc_dma_irq)(struct mtk_nand_chip *chip, u8 *p, int pg);
+    int (*read_page_ecc_pio_polling)(struct mtk_nand_chip *chip, u8 *p, int pg);
+    int (*read_page_ecc_pio_irq)(struct mtk_nand_chip *chip, u8 *p, int pg);
+    int (*read_page_raw_dma_polling)(struct mtk_nand_chip *chip, u8 *buf, int page);
+    int (*read_page_raw_dma_irq)(struct mtk_nand_chip *chip, u8 *buf, int page);
+    int (*read_page_raw_pio_polling)(struct mtk_nand_chip *chip, u8 *buf, int page);
+    int (*read_page_raw_pio_irq)(struct mtk_nand_chip *chip, u8 *buf, int page);
+    void (*enable_randomizer)(struct mtk_nand_chip *chip, int page,
+                              enum mtk_randomizer_operation rand, int repage);
+    void (*disable_randomizer)(struct mtk_nand_chip *chip);
+    int (*fill_oob_ecc)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+    int (*fill_oob_raw)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+    int (*fill_oob_parity)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+    int (*transfer_oob_ecc)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+    int (*transfer_oob_raw)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+    int (*transfer_oob_parity)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+
+    /* nand device information */
+    u64 totalsize;
+    /* unit: Byte */
+    u64 chipsize;
+    u32 pagesize;
+    u32 oobsize;
+    u32 blocksize;
+    u32 ecc_size;
+    u32 ecc_strength;
+    u32 ecc_steps;
+    u32 subpagesize;
+    u32 fdm_ecc_size;
+    u32 oob_free_ecc_size;
+    u32 oob_free_raw_size;
+    u8 bits_per_cell;
+    u32 page_per_chip;
+    u32 page_per_block;
+    int chip_delay;
+    u32 options;
+    u8 numchips;
+    int activechip;
+
+    u8 *databuf;
+    u8 *oob_poi;
+
+    u8 *bbt;
+    u32 bbt_options;
+    int bbt_block;
+    int badblockpos;
+    int badblockbits;
+
+    struct mtk_ecc_stats stats;
+
+    void *priv;
+};
+
+static inline void *nand_get_controller_data(struct mtk_nand_chip *chip)
+{
+    return chip->priv;
+}
+
+static inline void nand_set_controller_data(struct mtk_nand_chip *chip, void *priv)
+{
+    chip->priv = priv;
+}
+
+static inline bool nand_is_slc(struct mtk_nand_chip *chip)
+{
+    return chip->bits_per_cell == 1;
+}
+
+extern struct mtk_nand_flash_dev nand_flash_devs[];
+int mtk_nand_erase(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops);
+int mtk_nand_write(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops);
+int mtk_nand_read(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops);
+int mtk_nand_block_isbad(struct mtk_nand_chip *chip, u32 page);
+int mtk_nand_block_markbad(struct mtk_nand_chip *chip, u32 page);
+int mtk_nand_init(void);
+int mtk_nand_scan(struct mtk_nand_chip *chip, int maxchips);
+int mtk_nand_scan_tail(struct mtk_nand_chip *chip);
+int nand_reset(struct mtk_nand_chip *chip, int chipnr);
+struct mtk_nand_chip *mtk_get_nand_chip(void);
+int mtk_nand_block_checkbad(struct mtk_nand_chip *chip, u32 page);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nfi_hal.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nfi_hal.h
new file mode 100644
index 0000000..6f00249
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/mtk_nfi_hal.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2017 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 <platform/nand/mtk_nand_nal.h>
+#include <kernel/mutex.h>
+#include <kernel/event.h>
+
+#define     NFI_CNFG                (0x00)
+#define     CNFG_AHB                NAND_BIT(0)
+#define     CNFG_READ_EN            NAND_BIT(1)
+#define     CNFG_DMA_BURST_EN       NAND_BIT(2)
+#define     CNFG_RESEED_SEC_EN      NAND_BIT(4)
+#define     CNFG_RAND_SEL           NAND_BIT(5)
+#define     CNFG_RAND_MASK          (3 << 4)
+#define     CNFG_BYTE_RW            NAND_BIT(6)
+#define     CNFG_HW_ECC_EN          NAND_BIT(8)
+#define     CNFG_AUTO_FMT_EN        NAND_BIT(9)
+#define     CNFG_OP_CUST            (6 << 12)
+#define     NFI_PAGEFMT             (0x04)
+#define     PAGEFMT_FDM_ECC_SHIFT   (12)
+#define     PAGEFMT_FDM_SHIFT       (8)
+#define     PAGEFMT_SPARE_16        (0)
+#define     PAGEFMT_SPARE_26        (1)
+#define     PAGEFMT_SPARE_27        (2)
+#define     PAGEFMT_SPARE_28        (3)
+#define     PAGEFMT_SPARE_32        (4)
+#define     PAGEFMT_SPARE_36        (5)
+#define     PAGEFMT_SPARE_40        (6)
+#define     PAGEFMT_SPARE_44        (7)
+#define     PAGEFMT_SPARE_48        (8)
+#define     PAGEFMT_SPARE_49        (9)
+#define     PAGEFMT_SPARE_50        (0xa)
+#define     PAGEFMT_SPARE_51        (0xb)
+#define     PAGEFMT_SPARE_52        (0xc)
+#define     PAGEFMT_SPARE_62        (0xd)
+#define     PAGEFMT_SPARE_61        (0xe)
+#define     PAGEFMT_SPARE_63        (0xf)
+#define     PAGEFMT_SPARE_64        (0x10)
+#define     PAGEFMT_SPARE_67        (0x11)
+#define     PAGEFMT_SPARE_74        (0x12)
+#define     PAGEFMT_SPARE_SHIFT     (16)
+#define     PAGEFMT_SEC_SEL_512     NAND_BIT(2)
+#define     PAGEFMT_512_2K          (0)
+#define     PAGEFMT_2K_4K           (1)
+#define     PAGEFMT_4K_8K           (2)
+#define     PAGEFMT_8K_16K          (3)
+#define     NFI_CON                 (0x08)
+#define     CON_FIFO_FLUSH          NAND_BIT(0)
+#define     CON_NFI_RST             NAND_BIT(1)
+#define     CON_BRD                 NAND_BIT(8)  /* burst  read */
+#define     CON_BWR                 NAND_BIT(9) /* burst  write */
+#define     CON_SEC_SHIFT           (12)
+#define     NFI_ACCCON              (0x0c)
+#define     NFI_INTR_EN             (0x10)
+#define     INTR_BUSY_RETURN_EN     NAND_BIT(4)
+#define     INTR_AHB_DONE_EN        NAND_BIT(6)
+#define     NFI_INTR_STA            (0x14)
+#define     NFI_CMD                 (0x20)
+#define     NFI_ADDRNOB             (0x30)
+#define     NFI_COLADDR             (0x34)
+#define     NFI_ROWADDR             (0x38)
+#define     NFI_STRDATA             (0x40)
+#define     STAR_EN                 (1)
+#define     STAR_DE                 (0)
+#define     NFI_CNRNB               (0x44)
+#define     NFI_DATAW               (0x50)
+#define     NFI_DATAR               (0x54)
+#define     NFI_PIO_DIRDY           (0x58)
+#define     PIO_DI_RDY              (0x01)
+#define     NFI_STA                 (0x60)
+#define     STA_CMD                 NAND_BIT(0)
+#define     STA_ADDR                NAND_BIT(1)
+#define     STA_BUSY                NAND_BIT(8)
+#define     STA_EMP_PAGE            NAND_BIT(12)
+#define     NFI_FSM_CUSTDATA        (0xe << 16)
+#define     NFI_FSM_MASK            (0xf << 16)
+#define     NFI_ADDRCNTR            (0x70)
+#define     CNTR_MASK               NAND_GENMASK(16, 12)
+#define     ADDRCNTR_SEC_SHIFT      (12)
+#define     ADDRCNTR_SEC(val)       (((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT)
+#define     NFI_STRADDR             (0x80)
+#define     NFI_BYTELEN             (0x84)
+#define     NFI_CSEL                (0x90)
+#define     NFI_FDML(x)             (0xa0 + (x) * sizeof(u32) * 2)
+#define     NFI_FDMM(x)             (0xa4 + (x) * sizeof(u32) * 2)
+#define     NFI_FDM_MAX_SIZE        (8)
+#define     NFI_FDM_MIN_SIZE        (1)
+#define     NFI_MASTER_STA          (0x224)
+#define     MASTER_STA_MASK         (0x0FFF)
+#define     MASTER_BUS_BUSY         (0x3)
+#define     NFI_RANDOM_CNFG         (0x238)
+#define     RAN_ENCODE_EN           NAND_BIT(0)
+#define     ENCODE_SEED_SHIFT       (1)
+#define     RAN_DECODE_EN           NAND_BIT(16)
+#define     DECODE_SEED_SHIFT       (17)
+#define     RAN_SEED_MASK           (0x7fff)
+#define     RAND_SEED_SHIFT(op)     \
+    ((op) == RAND_ENCODE ? ENCODE_SEED_SHIFT : DECODE_SEED_SHIFT)
+#define     RAND_EN(op)             \
+    ((op) == RAND_ENCODE ? RAN_ENCODE_EN : RAN_DECODE_EN)
+#define     NFI_EMPTY_THRESH        (0x23c)
+
+#define     MTK_RESET_TIMEOUT       (1000000)
+#define     MTK_MAX_SECTOR          (16)
+#define     MTK_NAND_MAX_NSELS      (2)
+
+struct mtk_nfc_bad_mark_ctl {
+    void (*bm_swap)(struct mtk_nand_chip *chip, u8 *buf, int raw);
+    u32 sec;
+    u32 pos;
+};
+
+/*
+ * FDM: region used to store free OOB data
+ */
+struct mtk_nfc_fdm {
+    u32 reg_size;
+    u32 ecc_size;
+};
+
+struct mtk_nfc {
+    mutex_t lock;
+    event_t irq_event;
+    struct mtk_ecc_config ecc_cfg;
+    struct mtk_ecc *ecc;
+    uintptr_t regs;
+    u8 *buffer;
+};
+
+struct mtk_nfc_nand_chip {
+    struct mtk_nand_chip chip;
+    struct mtk_nfc_bad_mark_ctl bad_mark;
+    struct mtk_nfc_fdm fdm;
+    u32 spare_per_sector;
+    u32 acctiming;
+};
+
+int mtk_nfc_nand_chip_init(struct mtk_nand_chip **ext_nand);
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/nand.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/nand.h
new file mode 100644
index 0000000..adbaf69
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/nand/nand.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 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
+
+int nand_init_device(void);
+void nand_dump_device_info(void);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/platform_blx.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/platform_blx.h
new file mode 100644
index 0000000..a2cd3be
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/platform_blx.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 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 <compiler.h>
+#include <debug.h>
+
+typedef enum {
+    BR_POWER_KEY = 0,
+    BR_USB,
+    BR_RTC,
+    BR_WDT,
+    BR_WDT_BY_PASS_PWK,
+    BR_TOOL_BY_PASS_PWK,
+    BR_2SEC_REBOOT,
+    BR_UNKNOWN,
+    BR_KERNEL_PANIC,
+    BR_WDT_SW,
+    BR_WST_HW,
+} boot_reason_t;
+
+void platform_memory_init(void);
+void platform_early_init_blx(void);
+boot_reason_t platform_boot_status(void);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/pll.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/pll.h
new file mode 100644
index 0000000..00b799c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/pll.h
@@ -0,0 +1,283 @@
+/*
+ * 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 <platform/mt_reg_base.h>
+
+/* APMIXEDSYS Register */
+#define AP_PLL_CON0             (APMIXED_BASE + 0x000)
+#define AP_PLL_CON2             (APMIXED_BASE + 0x008)
+#define AP_PLL_CON3             (APMIXED_BASE + 0x00C)
+#define AP_PLL_CON4             (APMIXED_BASE + 0x010)
+#define AP_PLL_CON5             (APMIXED_BASE + 0x014)
+#define AP_PLL_CON6             (APMIXED_BASE + 0x018)
+#define AP_PLL_CON7             (APMIXED_BASE + 0x01C)
+#define CLKSQ_STB_CON0          (APMIXED_BASE + 0x020)
+#define PLL_PWR_CON0            (APMIXED_BASE + 0x024)
+#define PLL_PWR_CON1            (APMIXED_BASE + 0x028)
+#define PLL_ISO_CON0            (APMIXED_BASE + 0x02C)
+#define PLL_ISO_CON1            (APMIXED_BASE + 0x030)
+#define PLL_STB_CON0            (APMIXED_BASE + 0x034)
+#define DIV_STB_CON0            (APMIXED_BASE + 0x038)
+#define PLL_CHG_CON0            (APMIXED_BASE + 0x03C)
+#define PLL_TEST_CON0           (APMIXED_BASE + 0x040)
+#define PLL_TEST_CON1           (APMIXED_BASE + 0x044)
+#define ARMCA35PLL_CON0         (APMIXED_BASE + 0x100)
+#define ARMCA35PLL_CON1         (APMIXED_BASE + 0x104)
+#define ARMCA35PLL_CON2         (APMIXED_BASE + 0x108)
+#define ARMCA35PLL_PWR_CON0     (APMIXED_BASE + 0x110)
+#define ARMCA72PLL_CON0         (APMIXED_BASE + 0x210)
+#define ARMCA72PLL_CON1         (APMIXED_BASE + 0x214)
+#define ARMCA72PLL_CON2         (APMIXED_BASE + 0x218)
+#define ARMCA72PLL_PWR_CON0     (APMIXED_BASE + 0x220)
+#define MAINPLL_CON0            (APMIXED_BASE + 0x230)
+#define MAINPLL_CON1            (APMIXED_BASE + 0x234)
+#define MAINPLL_CON2            (APMIXED_BASE + 0x238)
+#define MAINPLL_PWR_CON0        (APMIXED_BASE + 0x23C)
+#define UNIVPLL_CON0            (APMIXED_BASE + 0x240)
+#define UNIVPLL_CON1            (APMIXED_BASE + 0x244)
+#define UNIVPLL_CON2            (APMIXED_BASE + 0x248)
+#define UNIVPLL_PWR_CON0        (APMIXED_BASE + 0x24C)
+#define MMPLL_CON0              (APMIXED_BASE + 0x250)
+#define MMPLL_CON1              (APMIXED_BASE + 0x254)
+#define MMPLL_CON2              (APMIXED_BASE + 0x258)
+#define MMPLL_PWR_CON0          (APMIXED_BASE + 0x260)
+#define MSDCPLL_CON0            (APMIXED_BASE + 0x270)
+#define MSDCPLL_CON1            (APMIXED_BASE + 0x274)
+#define MSDCPLL_CON2            (APMIXED_BASE + 0x278)
+#define MSDCPLL_PWR_CON0        (APMIXED_BASE + 0x27C)
+#define VENCPLL_CON0            (APMIXED_BASE + 0x280)
+#define VENCPLL_CON1            (APMIXED_BASE + 0x284)
+#define VENCPLL_CON2            (APMIXED_BASE + 0x288)
+#define VENCPLL_PWR_CON0        (APMIXED_BASE + 0x28C)
+#define TVDPLL_CON0             (APMIXED_BASE + 0x290)
+#define TVDPLL_CON1             (APMIXED_BASE + 0x294)
+#define TVDPLL_CON2             (APMIXED_BASE + 0x298)
+#define TVDPLL_PWR_CON0         (APMIXED_BASE + 0x29C)
+#define ETHERPLL_CON0           (APMIXED_BASE + 0x300)
+#define ETHERPLL_CON1           (APMIXED_BASE + 0x304)
+#define ETHERPLL_CON2           (APMIXED_BASE + 0x308)
+#define ETHERPLL_PWR_CON0       (APMIXED_BASE + 0x30C)
+#define CVBSPLL_CON0            (APMIXED_BASE + 0x310)
+#define CVBSPLL_CON1            (APMIXED_BASE + 0x314)
+#define CVBSREFPLL_CON0         (APMIXED_BASE + 0x318)
+#define CVBSREFPLL_CON1         (APMIXED_BASE + 0x31C)
+#define VCODECPLL_CON0          (APMIXED_BASE + 0x320)
+#define VCODECPLL_CON1          (APMIXED_BASE + 0x324)
+#define VCODECPLL_CON2          (APMIXED_BASE + 0x328)
+#define VCODECPLL_PWR_CON0      (APMIXED_BASE + 0x32C)
+#define APLL1_CON0              (APMIXED_BASE + 0x330)
+#define APLL1_CON1              (APMIXED_BASE + 0x334)
+#define APLL1_CON2              (APMIXED_BASE + 0x338)
+#define APLL1_CON3              (APMIXED_BASE + 0x33C)
+#define APLL1_PWR_CON0          (APMIXED_BASE + 0x340)
+#define APLL2_CON0              (APMIXED_BASE + 0x350)
+#define APLL2_CON1              (APMIXED_BASE + 0x354)
+#define APLL2_CON2              (APMIXED_BASE + 0x358)
+#define APLL2_CON3              (APMIXED_BASE + 0x35C)
+#define APLL2_PWR_CON0          (APMIXED_BASE + 0x360)
+#define LVDSPLL_CON0            (APMIXED_BASE + 0x370)
+#define LVDSPLL_CON1            (APMIXED_BASE + 0x374)
+#define LVDSPLL_CON2            (APMIXED_BASE + 0x378)
+#define LVDSPLL_PWR_CON0        (APMIXED_BASE + 0x37C)
+#define LVDSPLL_SSC_CON0        (APMIXED_BASE + 0x380)
+#define LVDSPLL_SSC_CON1        (APMIXED_BASE + 0x384)
+#define LVDSPLL_SSC_CON2        (APMIXED_BASE + 0x388)
+#define LVDSPLL2_CON0           (APMIXED_BASE + 0x390)
+#define LVDSPLL2_CON1           (APMIXED_BASE + 0x394)
+#define LVDSPLL2_CON2           (APMIXED_BASE + 0x398)
+#define LVDSPLL2_PWR_CON0       (APMIXED_BASE + 0x39C)
+#define LVDSPLL2_SSC_CON0       (APMIXED_BASE + 0x400)
+#define LVDSPLL2_SSC_CON1       (APMIXED_BASE + 0x404)
+#define LVDSPLL2_SSC_CON2       (APMIXED_BASE + 0x408)
+#define MSDCPLL2_CON0           (APMIXED_BASE + 0x410)
+#define MSDCPLL2_CON1           (APMIXED_BASE + 0x414)
+#define MSDCPLL2_CON2           (APMIXED_BASE + 0x418)
+#define MSDCPLL2_PWR_CON0       (APMIXED_BASE + 0x41C)
+#define AP_AUXADC_CON0          (APMIXED_BASE + 0x420)
+#define AP_AUXADC_CON1          (APMIXED_BASE + 0x424)
+#define TS_CON0                 (APMIXED_BASE + 0x600)
+#define TS_CON1                 (APMIXED_BASE + 0x604)
+#define AP_ABIST_MON_CON0       (APMIXED_BASE + 0x800)
+#define AP_ABIST_MON_CON1       (APMIXED_BASE + 0x804)
+#define AP_ABIST_MON_CON2       (APMIXED_BASE + 0x808)
+#define AP_ABIST_MON_CON3       (APMIXED_BASE + 0x80C)
+#define OCCSCAN_CON0            (APMIXED_BASE + 0x810)
+#define CLKDIV_CON0             (APMIXED_BASE + 0x814)
+#define OCCSCAN_CON1            (APMIXED_BASE + 0x818)
+#define RSV_RW0_CON0            (APMIXED_BASE + 0x900)
+#define RSV_RW1_CON0            (APMIXED_BASE + 0x904)
+#define RSV_RO_CON0             (APMIXED_BASE + 0x908)
+#define AADC_CON0               (APMIXED_BASE + 0x910)
+#define AADC_CON1               (APMIXED_BASE + 0x914)
+#define AADC_CON2               (APMIXED_BASE + 0x918)
+#define AADC_CON3               (APMIXED_BASE + 0x91C)
+#define AADC_CON4               (APMIXED_BASE + 0x920)
+#define CVBS_CON0               (APMIXED_BASE + 0x930)
+#define CVBS_CON1               (APMIXED_BASE + 0x934)
+#define CVBS_CON2               (APMIXED_BASE + 0x938)
+#define CVBS_CON3               (APMIXED_BASE + 0x93C)
+#define CVBS_CON4               (APMIXED_BASE + 0x940)
+
+/* TOPCKGEN Register */
+#define CLK_MODE                (CKSYS_BASE + 0x000)
+#define DCM_CFG                 (CKSYS_BASE + 0x004)
+#define TST_SEL_0               (CKSYS_BASE + 0x020)
+#define TST_SEL_1               (CKSYS_BASE + 0x024)
+#define TST_SEL_2               (CKSYS_BASE + 0x028)
+#define TST_SEL_3               (CKSYS_BASE + 0x02C)
+#define TST_SEL_4               (CKSYS_BASE + 0x030)
+#define TST_SEL_5               (CKSYS_BASE + 0x034)
+#define CLK_CFG_0               (CKSYS_BASE + 0x040)
+#define CLK_CFG_0_SET           (CKSYS_BASE + 0x044)
+#define CLK_CFG_0_CLR           (CKSYS_BASE + 0x048)
+#define CLK_CFG_1               (CKSYS_BASE + 0x050)
+#define CLK_CFG_1_SET           (CKSYS_BASE + 0x054)
+#define CLK_CFG_1_CLR           (CKSYS_BASE + 0x058)
+#define CLK_CFG_2               (CKSYS_BASE + 0x060)
+#define CLK_CFG_2_SET           (CKSYS_BASE + 0x064)
+#define CLK_CFG_2_CLR           (CKSYS_BASE + 0x068)
+#define CLK_CFG_3               (CKSYS_BASE + 0x070)
+#define CLK_CFG_3_SET           (CKSYS_BASE + 0x074)
+#define CLK_CFG_3_CLR           (CKSYS_BASE + 0x078)
+#define CLK_CFG_4               (CKSYS_BASE + 0x080)
+#define CLK_CFG_4_SET           (CKSYS_BASE + 0x084)
+#define CLK_CFG_4_CLR           (CKSYS_BASE + 0x088)
+#define CLK_CFG_5               (CKSYS_BASE + 0x090)
+#define CLK_CFG_5_SET           (CKSYS_BASE + 0x094)
+#define CLK_CFG_5_CLR           (CKSYS_BASE + 0x098)
+#define CLK_CFG_6               (CKSYS_BASE + 0x0A0)
+#define CLK_CFG_6_SET           (CKSYS_BASE + 0x0A4)
+#define CLK_CFG_6_CLR           (CKSYS_BASE + 0x0A8)
+#define CLK_CFG_7               (CKSYS_BASE + 0x0B0)
+#define CLK_CFG_7_SET           (CKSYS_BASE + 0x0B4)
+#define CLK_CFG_7_CLR           (CKSYS_BASE + 0x0B8)
+#define CLK_CFG_8               (CKSYS_BASE + 0x0C0)
+#define CLK_CFG_8_SET           (CKSYS_BASE + 0x0C4)
+#define CLK_CFG_8_CLR           (CKSYS_BASE + 0x0C8)
+#define CLK_CFG_9               (CKSYS_BASE + 0x0D0)
+#define CLK_CFG_9_SET           (CKSYS_BASE + 0x0D4)
+#define CLK_CFG_9_CLR           (CKSYS_BASE + 0x0D8)
+#define CLK_CFG_M0              (CKSYS_BASE + 0x100)
+#define CLK_CFG_M1              (CKSYS_BASE + 0x104)
+#define CLK_CFG_M2              (CKSYS_BASE + 0x108)
+#define CLK_CFG_M3              (CKSYS_BASE + 0x10C)
+#define CLK_AUDDIV_0            (CKSYS_BASE + 0x120)
+#define CLK_AUDDIV_1            (CKSYS_BASE + 0x124)
+#define CLK_AUDDIV_2            (CKSYS_BASE + 0x128)
+#define CLK_AUDDIV_3            (CKSYS_BASE + 0x12C)
+#define CLK_AUDDIV_4            (CKSYS_BASE + 0x134)
+#define CLK_SCP_CFG_0           (CKSYS_BASE + 0x200)
+#define CLK_SCP_CFG_1           (CKSYS_BASE + 0x204)
+#define CLK_MISC_CFG_0          (CKSYS_BASE + 0x210)
+#define CLK_MISC_CFG_1          (CKSYS_BASE + 0x214)
+#define CLK_MISC_CFG_2          (CKSYS_BASE + 0x218)
+#define CLK_APB_MON             (CKSYS_BASE + 0x21C)
+#define CLK26CALI_0             (CKSYS_BASE + 0x220)
+#define CLK26CALI_1             (CKSYS_BASE + 0x224)
+#define CLK26CALI_2             (CKSYS_BASE + 0x228)
+#define CKSTA_REG               (CKSYS_BASE + 0x22C)
+#define TEST_MODE_CFG           (CKSYS_BASE + 0x230)
+#define MBIST_CFG_0             (CKSYS_BASE + 0x308)
+#define MBIST_CFG_1             (CKSYS_BASE + 0x30C)
+#define MBIST_CFG_2             (CKSYS_BASE + 0x310)
+#define MBIST_CFG_3             (CKSYS_BASE + 0x314)
+#define CLK_MSDC_DELAY_SEL_0    (CKSYS_BASE + 0x400)
+#define CLK_MSDC_DELAY_SEL_1    (CKSYS_BASE + 0x404)
+#define CLK_MSDC_DELAY_SEL_2    (CKSYS_BASE + 0x408)
+#define CLK_MSDC_DELAY_SEL_3    (CKSYS_BASE + 0x40C)
+#define CLK_MSDC_DELAY_SEL_4    (CKSYS_BASE + 0x410)
+#define TVD_ANAIF_CFG           (CKSYS_BASE + 0x420)
+#define CLK_CG_EN_CFG           (CKSYS_BASE + 0x424)
+#define ECC_RESET_CFG_1         (CKSYS_BASE + 0x428)
+#define ECC_RESET_CFG_2         (CKSYS_BASE + 0x42C)
+#define NORM_STRAP_CFG          (CKSYS_BASE + 0x430)
+#define CKGEN_BACKUP            (CKSYS_BASE + 0x434)
+#define CLK_CFG_10              (CKSYS_BASE + 0x500)
+#define CLK_CFG_10_SET          (CKSYS_BASE + 0x504)
+#define CLK_CFG_10_CLR          (CKSYS_BASE + 0x508)
+#define CLK_CFG_11              (CKSYS_BASE + 0x510)
+#define CLK_CFG_11_SET          (CKSYS_BASE + 0x514)
+#define CLK_CFG_11_CLR          (CKSYS_BASE + 0x518)
+#define CLK_CFG_12              (CKSYS_BASE + 0x520)
+#define CLK_CFG_12_SET          (CKSYS_BASE + 0x524)
+#define CLK_CFG_12_CLR          (CKSYS_BASE + 0x528)
+#define CLK_CFG_13              (CKSYS_BASE + 0x530)
+#define CLK_CFG_13_SET          (CKSYS_BASE + 0x534)
+#define CLK_CFG_13_CLR          (CKSYS_BASE + 0x538)
+#define CLK_CFG_14              (CKSYS_BASE + 0x540)
+#define CLK_CFG_14_SET          (CKSYS_BASE + 0x544)
+#define CLK_CFG_14_CLR          (CKSYS_BASE + 0x548)
+#define CLK_CFG_15              (CKSYS_BASE + 0x550)
+#define CLK_CFG_15_SET          (CKSYS_BASE + 0x554)
+#define CLK_CFG_15_CLR          (CKSYS_BASE + 0x558)
+#define CLK_CFG_16              (CKSYS_BASE + 0x560)
+#define CLK_CFG_16_SET          (CKSYS_BASE + 0x564)
+#define CLK_CFG_16_CLR          (CKSYS_BASE + 0x568)
+#define CLK_CFG_17              (CKSYS_BASE + 0x570)
+#define CLK_CFG_17_SET          (CKSYS_BASE + 0x574)
+#define CLK_CFG_17_CLR          (CKSYS_BASE + 0x578)
+
+/* INFRASYS Register, Infra DCM */
+#define TOP_CKMUXSEL            (INFRACFG_BASE + 0x000)
+#define TOP_CKDIV1              (INFRACFG_BASE + 0x008)
+#define TOP_DCMCTL              (INFRACFG_BASE + 0x010)
+
+#define INFRA_GLOBALCON_DCMCTL  (INFRACFG_BASE + 0x050)
+#define INFRA_GLOBALCON_DCMDBC  (INFRACFG_BASE + 0x054)
+#define INFRA_GLOBALCON_DCMFSEL (INFRACFG_BASE + 0x058)
+
+#define INFRA_APB_ASYNC_STA     (INFRACFG_BASE + 0x230)
+
+/* MCUCFG CLKMUX */
+#define mp0_pll_divider_cfg     (MCUSYS_CFGREG_BASE + 0x7A0)
+#define mp2_pll_divider_cfg     (MCUSYS_CFGREG_BASE + 0x7A8)
+#define bus_pll_divider_cfg     (MCUSYS_CFGREG_BASE + 0x7C0)
+
+/* SUBSYS_CG */
+#define INFRA_PDN_SET           (INFRACFG_BASE + 0x040)
+#define INFRA_PDN_CLR           (INFRACFG_BASE + 0x044)
+#define DEVAPC_PDN_SET          (INFRACFG_BASE + 0x070)
+#define TRNG_PDN_SET            (INFRACFG_BASE + 0x080)
+#define TRNG_PDN_CLR            (INFRACFG_BASE + 0x084)
+#define TRNG_PDN_STATUS         (INFRACFG_BASE + 0x088)
+#define PERI_GLOBALCON_PDN0_SET (PERICFG_BASE + 0x008)
+#define PERI_GLOBALCON_PDN1_SET (PERICFG_BASE + 0x00C)
+#define PERI_GLOBALCON_PDN0_CLR (PERICFG_BASE + 0x010)
+#define PERI_GLOBALCON_PDN1_CLR (PERICFG_BASE + 0x014)
+#define PERI_MSDC_CLK_EN        (PERICFG_BASE + 0x42C)
+#define MFG_CG_CLR              (MFGCFG_BASE + 0x8)
+#define MMSYS_CG0_SET           (MMSYS_BASE + 0x104)
+#define MMSYS_CG0_CLR           (MMSYS_BASE + 0x108)
+#define MMSYS_CG1_CLR           (MMSYS_BASE + 0x118)
+#define MMSYS_CG2_CLR           (MMSYS_BASE + 0x228)
+#define IMG_CG                  (IMGSYS_BASE + 0x0)
+#define BDP_DISPSYS_CG_CON0     (BDPSYS_BASE + 0x100)
+#define VDEC_CKEN_SET           (VDECSYS_BASE + 0x0)
+#define VDEC_LARB1_CKEN_SET     (VDECSYS_BASE + 0x8)
+#define VENC_CG_SET             (VENCSYS_BASE + 0x4)
+#define JPGDEC_CG_SET           (JPGDECSYS_BASE + 0x4)
+
+void mt_pll_init(void);
+void mt_pll_post_init(void);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/pmic.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/pmic.h
new file mode 100644
index 0000000..abad914
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/pmic.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#pragma once
+
+int rtq2134_set_bcpu_voltage(int target_vol);
+int rtq2134_set_lcpu_voltage(int target_vol);
+int rtq2134_set_core_voltage(int target_vol);
\ No newline at end of file
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/ram_console_def.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/ram_console_def.h
new file mode 100644
index 0000000..d3349a3
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/ram_console_def.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 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.
+ */
+
+#ifndef __RAM_CONSOLE_DEF_H__
+#define __RAM_CONSOLE_DEF_H__
+
+#include <platform/mt2712.h>
+
+// ram_console over dram for mt2712
+
+#ifdef RAM_CONSOLE_OVER_SRAM  // sram
+#define RAM_CONSOLE_DEF_ADDR RAM_CONSOLE_SRAM_ADDR
+#define RAM_CONSOLE_DEF_SIZE RAM_CONSOLE_SRAM_SIZE
+
+#else  // dram
+#define RAM_CONSOLE_DRAM_ADDR (DRAM_BASE_PHY + 0x38072000)
+#define RAM_CONSOLE_DRAM_SIZE (0x10000)
+
+#define RAM_CONSOLE_DEF_ADDR RAM_CONSOLE_DRAM_ADDR
+#define RAM_CONSOLE_DEF_SIZE RAM_CONSOLE_DRAM_SIZE
+#endif
+
+// align minirdump-reserved-memory in dts
+#define KE_RESERVED_MEM_ADDR (DRAM_BASE_PHY + 0x38162000)
+#define PSTORE_ADDR (DRAM_BASE_PHY + 0x38082000)
+#define PSTORE_SIZE 0xe0000
+
+#define PSTORE_RESERVE_ADDR PSTORE_ADDR
+#define PSTORE_RESERVE_SIZE PSTORE_SIZE
+#define PSTORE_PMSG_SIZE (0X40000)
+#define PSTORE_CONSOEL_SIZE (0X10000)
+
+#define MINIRDUMP_MEM_ADDR KE_RESERVED_MEM_ADDR
+#define MINIRDUMP_MEM_SIZE (0x10000)
+
+#define LOG_STORE_MEM_ADDR (DRAM_BASE_PHY + 0X38032000)
+#define LOG_STORE_MEM_SIZE (0X40000)
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/sej.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/sej.h
new file mode 100644
index 0000000..8da7f4a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/sej.h
@@ -0,0 +1,50 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*
+* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek Software")
+* have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+* applicable license agreements with MediaTek Inc.
+*/
+
+#ifndef SEJ_H
+#define SEJ_H
+
+#include <platform/mt_reg_base.h>
+
+/******************************************************************************
+ * EXPORT FUNCTION
+ ******************************************************************************/
+extern int sp_sej_ac_init(unsigned char mode);
+extern unsigned char *sp_sej_ac_run(unsigned char *buf, unsigned int size);
+extern int sp_sej_ac_done(void);
+extern unsigned int seclib_get_msg_auth_key(unsigned char *id, unsigned int id_size,
+unsigned char *key, unsigned int key_size);
+#endif /* SEJ_H */
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/spm_mtcmos.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/spm_mtcmos.h
new file mode 100644
index 0000000..f26432f
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/spm_mtcmos.h
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+void spm_mtcmos_poweron_config_enable(void);
+void spm_mtcmos_protect_mfg_bus(void);
+void spm_mtcmos_display_power_on(void);
+void spm_mtcmos_audio_power_on(void);
+void spm_mtcmos_mfg_power_on(void);
+void spm_mtcmos_mfg_sc1_power_on(void);
+void spm_mtcmos_mfg_sc2_power_on(void);
+void spm_mtcmos_mfg_sc3_power_on(void);
+void spm_mtcmos_isp_power_on(void);
+void spm_mtcmos_vdec_power_on(void);
+void spm_mtcmos_venc_power_on(void);
+void spm_mtcmos_usb_power_on(void);
+void spm_mtcmos_usb2_power_on(void);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/trapping.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/trapping.h
new file mode 100644
index 0000000..bd440ef
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/trapping.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 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 <platform/pll.h>   /* for CKGEN_BACKUP register definition */
+
+/* These trappings were referenced by Azalea BootROM to adjust boot
+ * configuration, add them here for LK reference */
+
+#define TRAPPING_SPI_NOR_4BYTE_ADDR_EN  (0x1 << 0)
+#define TRAPPING_BOOTDEV_SPEEDUP_EN     (0x1 << 1)
+#define TRAPPING_NAND_RANDOMIZER_EN     (0x1 << 2)
+
+#define TRAPPING_IS_SPI_NOR_4BYTE_ADDR_EN() \
+        (readl(CKGEN_BACKUP) & TRAPPING_SPI_NOR_4BYTE_ADDR_EN)
+
+#define TRAPPING_IS_EMMC_BOOT_BUS_WIDTH_8BIT() \
+        (readl(CKGEN_BACKUP) & TRAPPING_BOOTDEV_SPEEDUP_EN)
+
+#define TRAPPING_IS_NAND_RANDOMIZER_EN() \
+        (readl(CKGEN_BACKUP) & TRAPPING_NAND_RANDOMIZER_EN)
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/include/platform/udc-common.h b/src/bsp/lk/platform/mediatek/mt2712/include/platform/udc-common.h
new file mode 100644
index 0000000..1347794
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/include/platform/udc-common.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#pragma once
+
+#define UDC_TYPE_BULK_IN    1
+#define UDC_TYPE_BULK_OUT   2
diff --git a/src/bsp/lk/platform/mediatek/mt2712/plat_mp.c b/src/bsp/lk/platform/mediatek/mt2712/plat_mp.c
new file mode 100644
index 0000000..57c9313
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/plat_mp.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <arch/mp_mediatek.h>
+#include <kernel/mp.h>
+#include <kernel/thread.h>
+#include <platform/mtk_devinfo.h>
+#include <platform/pmic.h>
+#include <sys/types.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+/* mt2712 cpu id remapping table */
+const uint8_t mt2712_cpuid_map[] = {
+    0, 1, 2, 3,             // cluster 0 (little cores cluster)
+    0xff, 0xff, 0xff, 0xff, // cluster 1 (empty cluster)
+    4, 5                    // cluster 2 (big cores cluster)
+};
+
+const uint8_t *linear_cpuid_map = &mt2712_cpuid_map[0];
+
+struct smp_cpu_info smp_cpu = {
+    .id = { 0x0, 0x1, 0x2, 0x3, 0x200, 0x201 },
+    .cpu_on_mask = SMP_CPU_ON_MASK,
+};
+
+void plat_mp_assign_workcpu(thread_t *t)
+{
+    uint32_t worker_cpu;
+    uint32_t bootcpu = arch_curr_cpu_num();
+    uint32_t ca72_mask = smp_cpu.cpu_on_mask &
+        ~((1 << (1 << SMP_CPU_CLUSTER_SHIFT)) - 1);
+
+    ca72_mask &= ~(1 << bootcpu);
+    worker_cpu = bootcpu;
+    if (ca72_mask) {
+        worker_cpu = __builtin_ffs(ca72_mask) - 1;
+        if (!mp_is_cpu_active(worker_cpu))
+            worker_cpu = bootcpu;
+    }
+    thread_set_pinned_cpu(t, worker_cpu);
+}
+
+void plat_pre_cpu_on(void)
+{
+    int ca72_freq;
+
+    ca72_freq = det_ca72_freq();
+
+    /* The voltage is set to 1.05V when CA72 freq is higher than 1.4GHz. */
+    switch (ca72_freq) {
+        case CA72_SPD_1599MHZ:
+        case CA72_SPD_1495MHZ:
+        case CA72_SPD_1391MHZ: // treat as 1.4GHz
+            rtq2134_set_bcpu_voltage(1050);
+            spin(10); // delay 10us
+            break;
+    }
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/platform.c b/src/bsp/lk/platform/mediatek/mt2712/platform.c
new file mode 100644
index 0000000..ef9d252
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/platform.c
@@ -0,0 +1,157 @@
+/*
+ * 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 <compiler.h>
+#include <debug.h>
+#include <dev/interrupt/arm_gic.h>
+#include <dev/timer/arm_generic.h>
+#include <dev/uart.h>
+#include <err.h>
+#include <errno.h>
+#include <lib/mempool.h>
+#include <lk/init.h>
+#include <platform.h>
+#include <platform/platform_blx.h>
+#include <platform/gic.h>
+#include <platform/mtk_wdt.h>
+#include <platform/mt_gpio.h>
+#include <platform/mt_scp.h>
+#include <arch/ops.h>
+
+#if WITH_SMP
+#include <arch/mp_mediatek.h>
+#endif
+
+#if LOG_STORE_SUPPORT
+#include <lib/log_store.h>
+#endif
+
+void platform_early_init(void)
+{
+    uart_init_early();
+
+#if (LOG_STORE_SUPPORT == 1)
+    log_store_init(MEMORY_LOG_PHYS, MEMORY_LOG_SIZE);
+#endif
+
+    /* initialize the interrupt controller */
+    arm_gic_init();
+
+    arm_generic_timer_init(ARM_GENERIC_TIMER_PHYSICAL_INT, 13000000);
+
+    extern void  mtk_wdt_early_init(void) __attribute__((weak));
+    if (mtk_wdt_early_init)
+        mtk_wdt_early_init();
+    /* init AP watchdog and set timeout to 10 secs */
+    mtk_wdt_init();
+
+    /* init gpio */
+    mt_gpio_init();
+
+    /* bl2 or bl33 specific platform early init */
+    platform_early_init_blx();
+}
+
+void platform_init(void)
+{
+    int cache_ret, uncache_ret;
+
+    cache_ret = NO_ERROR;
+    if (!!CACHED_MEMPOOL_ADDR && !!CACHED_MEMPOOL_SIZE)
+        cache_ret = mempool_init((void *)CACHED_MEMPOOL_ADDR,
+                                 CACHED_MEMPOOL_SIZE, MEMPOOL_CACHE);
+
+    uncache_ret = NO_ERROR;
+    if (!!UNCACHED_MEMPOOL_ADDR && !!UNCACHED_MEMPOOL_SIZE)
+        uncache_ret = mempool_init((void *)UNCACHED_MEMPOOL_ADDR,
+                                   UNCACHED_MEMPOOL_SIZE, MEMPOOL_UNCACHE);
+
+    if ((cache_ret != NO_ERROR) || (uncache_ret != NO_ERROR))
+        platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_PANIC);
+}
+
+void platform_halt(platform_halt_action suggested_action,
+                   platform_halt_reason reason)
+{
+    switch (suggested_action) {
+        case HALT_ACTION_REBOOT:
+            dprintf(ALWAYS, "REBOOT (reason = %d)\n",reason);
+            mtk_arch_reset(1);
+            break;
+        default:
+            break;
+    }
+    dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason);
+    arch_disable_ints();
+    for (;;);
+}
+
+#if WITH_SMP
+void platform_quiesce(void)
+{
+    plat_mp_off();
+}
+#endif
+
+/*
+ * target_ab_set_active_bootdev() - set active boot device in ab boot flow
+ *
+ * this function is used to set the active boot device, aka slot in ab boot
+ * concept. For mt2712, the slot concept should be defined by the actual
+ * target. For targets that support ab boot concept should override this
+ * function.
+ *
+ * @slot: the slot # to be set as active boot device
+ *
+ * returns:
+ *     -ENOTSUP: function not supported
+ */
+__WEAK int target_ab_set_active_bootdev(int slot)
+{
+    return -ENOTSUP;
+}
+
+/*
+ * override the common plat_ab_set_active_bootdev() impl.
+ */
+int plat_ab_set_active_bootdev(int slot)
+{
+    return target_ab_set_active_bootdev(slot);
+}
+
+/* override blxboot plat_start_scpsys() impl. to start scpsys */
+void plat_start_scpsys(void)
+{
+    extern __WEAK void start_scpsys(void);
+
+    start_scpsys();
+}
+
+/* provide hook function called in blxboot, do something */
+static void plat_app_early_init(uint level)
+{
+#if (LOG_STORE_SUPPORT == 1)
+    log_store_switch_buffer(MEMORY_LOG_PHYS, DRAM_LOG_ADDR, DRAM_LOG_SIZE);
+#endif
+}
+
+LK_INIT_HOOK(plat_app_early_init, &plat_app_early_init, LK_INIT_LEVEL_APPS - 1);
diff --git a/src/bsp/lk/platform/mediatek/mt2712/platform_bl2.c b/src/bsp/lk/platform/mediatek/mt2712/platform_bl2.c
new file mode 100644
index 0000000..4600529
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/platform_bl2.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2018 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 <arch/ops.h>
+#include <boot_args.h>
+#include <debug.h>
+#include <err.h>
+#include <lk/init.h>
+#if WITH_KERNEL_VM
+#include <kernel/vm.h>
+#else
+#include <kernel/novm.h>
+#endif
+#include <memory.h>
+#include <platform.h>
+#include <platform/audio_clk_enable.h>
+#include <platform/dcm.h>
+#include <platform/mt_infracfg.h>
+#include <platform/mt_pericfg.h>
+#include <platform/mtk_wdt.h>
+#include <platform/pll.h>
+#include <string.h>
+#include <sys/types.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+extern __WEAK void stop_scpsys(void);
+
+static uint32_t g_boot_reason = 0;
+static uint32_t g_rgu_mode = 0;
+
+#if WITH_KERNEL_VM
+#define PROG_MEM_MAPPING_IDX    0
+#define CHIP_ID_MAPPING_IDX     1
+#define PERIPHERAL_MAPPING_IDX  2
+#define SRAM_MAPPING_IDX        3
+#define CMSYS_SRAM_MAPPING_IDX  4
+#define DRAM_MAPPING_IDX        5
+
+/* initial memory mappings. parsed by start.S */
+struct mmu_initial_mapping mmu_initial_mappings[] = {
+    {
+        .phys = MEMORY_BASE_PHYS,
+        .virt = MEMORY_BASE_VIRT,
+        .size = MEMORY_APERTURE_SIZE,
+        .flags = 0,
+        .name = "prog",
+    },
+    {
+        .phys = CHIP_ID_BASE_PHYS,
+        .virt = CHIP_ID_BASE_VIRT,
+        .size = CHIP_ID_BASE_SIZE,
+        .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE
+    },
+    {
+        .phys = PERIPHERAL_BASE_PHYS,
+        .virt = PERIPHERAL_BASE_VIRT,
+        .size = PERIPHERAL_BASE_SIZE,
+        .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
+        .name = "peripherals"
+    },
+
+    /* reserved for internal sram */
+    { .size = 0 },
+    /* reserved for cmsys sram */
+    { .size = 0 },
+    /* reserved for dram */
+    { .size = 0 },
+    /* null entry to terminate the list */
+    { .size = 0 }
+};
+
+static pmm_arena_t arena = {
+    .name = "sram",
+    .base = SRAM_ARENA_BASE,
+    .size = SRAM_ARENA_SIZE,
+    .flags = PMM_ARENA_FLAG_KMAP,
+    .priority = 1,
+};
+
+static pmm_arena_t dram_arena = {
+    .name = "dram",
+    .base = DRAM_ARENA_BASE,
+    .size = DRAM_ARENA_SIZE,
+    .flags = PMM_ARENA_FLAG_KMAP,
+    .priority = 0,
+};
+#endif /* WITH_KERNEL_VM */
+
+static inline bool is_4gb_dram(size_t dram_sz)
+{
+#define SIZE_GB (0x40000000ULL)
+
+    return ((SIZE_GB * 4) == dram_sz);
+}
+
+static inline size_t query_plat_dram_sz(void)
+{
+    return mt_mem_size();
+}
+
+static void setup_plat_mem(void)
+{
+#if WITH_KERNEL_VM
+    size_t dram_sz, mem_sz;
+    size_t unmap_dram_start_pa, unmap_dram_start_va;
+
+    arch_mmu_map(CMSYS_SRAM_VIRT, CMSYS_SRAM_PHYS,
+                 CMSYS_SRAM_SIZE >> PAGE_SIZE_SHIFT,
+                 ARCH_MMU_FLAG_UNCACHED);
+
+    /* add cmsys sram to mmu_initial_mappings struct for pa to va lookup */
+    mmu_initial_mappings[CMSYS_SRAM_MAPPING_IDX].phys = CMSYS_SRAM_PHYS;
+    mmu_initial_mappings[CMSYS_SRAM_MAPPING_IDX].virt = CMSYS_SRAM_VIRT;
+    mmu_initial_mappings[CMSYS_SRAM_MAPPING_IDX].size = CMSYS_SRAM_SIZE;
+    mmu_initial_mappings[CMSYS_SRAM_MAPPING_IDX].flags = 0;
+    mmu_initial_mappings[CMSYS_SRAM_MAPPING_IDX].name = "cmsys";
+
+    /*
+     * Except the dram range for uncached memory pool, all other dram ranges
+     * are all mapped as cacheable memory.
+     */
+    unmap_dram_start_pa = DRAM_BASE_PHY;
+
+    unmap_dram_start_va = DRAM_BASE_VIRT;
+
+    dram_sz = query_plat_dram_sz();
+    mem_sz = UNCACHED_MEMPOOL_ADDR - unmap_dram_start_va;
+    arch_mmu_map(unmap_dram_start_va, unmap_dram_start_pa,
+                 mem_sz >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+    arch_mmu_map(UNCACHED_MEMPOOL_ADDR, unmap_dram_start_pa + mem_sz,
+                 UNCACHED_MEMPOOL_SIZE >> PAGE_SIZE_SHIFT,
+                 ARCH_MMU_FLAG_UNCACHED);
+
+    mem_sz += UNCACHED_MEMPOOL_SIZE;
+    arch_mmu_map(UNCACHED_MEMPOOL_ADDR + UNCACHED_MEMPOOL_SIZE,
+                 unmap_dram_start_pa + mem_sz,
+                 (dram_sz - mem_sz) >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+
+    /* add dram to mmu_initial_mappings for pa to va lookup */
+    mmu_initial_mappings[DRAM_MAPPING_IDX].phys = DRAM_BASE_PHY;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].virt = DRAM_BASE_VIRT;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].size = dram_sz;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].flags = 0;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].name = "dram";
+
+    pmm_add_arena(&dram_arena);
+
+    if (is_4gb_dram(dram_sz)) {
+        *REG32(PERIAXI_BUS_CTL3) |= PERISYS_4G_SUPPORT;
+        *REG32(INFRA_MISC) |= DDR_4GB_SUPPORT_EN;
+    }
+#else
+    novm_add_arena("sram", SRAM_BASE_PHYS, SRAM_BASE_SIZE);
+#endif /* WITH_KERNEL_VM */
+}
+
+void *init_bootarg_buffer(void)
+{
+    void *bootarg = (void *)paddr_to_kvaddr(DRAM_BOOTARG_BASE);
+    memset((void *)bootarg, 0, DRAM_BOOTARG_SIZE);
+
+    return bootarg;
+}
+
+void *bl2_set_boot_args(uint32_t boot_mode)
+{
+    BOOT_ARGUMENT *bl2_bootarg = (BOOT_ARGUMENT *)init_bootarg_buffer();
+    extern u32 g_ddr_reserve_ready;
+    extern u32 g_ddr_reserve_ta_err;
+    extern u32 g_ddr_reserve_enable;
+
+    bl2_bootarg->maggic_number = BOOT_ARGUMENT_MAGIC;
+    bl2_bootarg->boot_mode  = boot_mode;
+    bl2_bootarg->boot_reason = g_boot_reason;
+    bl2_bootarg->rgu_mode = g_rgu_mode;
+    bl2_bootarg->ddr_reserve_enable = g_ddr_reserve_enable;
+    bl2_bootarg->ddr_reserve_success = (g_ddr_reserve_ta_err == 0) ? 1 : 0;
+    bl2_bootarg->ddr_reserve_ready = g_ddr_reserve_ready;
+    bl2_bootarg->dram_size = (u64)mt_mem_size();
+
+    LTRACEF("boot mode:%d boot_reason:%d rgu_mode:%d\n",
+                bl2_bootarg->boot_mode, bl2_bootarg->boot_reason, bl2_bootarg->rgu_mode);
+
+    LTRACEF("DDR reserve mode: enable = %d, success = %d, ready = %d\n",
+                bl2_bootarg->ddr_reserve_enable,
+                bl2_bootarg->ddr_reserve_success, bl2_bootarg->ddr_reserve_ready);
+    return (void *)bl2_bootarg;
+}
+
+void platform_memory_init(void)
+{
+    mt_mem_init();
+    setup_plat_mem();
+    mt_mem_test();
+}
+
+void platform_early_init_blx(void)
+{
+    /* in case scpsys is still running after sw reset, stop it */
+    stop_scpsys();
+    clr_cm4_resume_mode();
+
+    mt_pll_init();
+    mt_pll_post_init();
+
+    /* TODO: confirm audio clk enable in BL2 or BL33 */
+    mt_audio_clk_enable();
+
+    mt_dcm_init();
+
+    dprintf(CRITICAL, "BL2 Build Time: %s %s\n", __DATE__, __TIME__);
+}
+
+/* the function provide interface to do some thing in the begin to platform early init */
+static void platform_prepare_early_init(uint level)
+{
+#if WITH_KERNEL_VM
+    /*
+     * At this moment, arena memory was not added yet, so the arena memory to
+     * be added to mmu table must use existing page, otherwise the mmu map will
+     * fail. And the memory is needed becasue log store need it to store log and it
+     * need be ready before uart init done.
+     */
+    arch_mmu_map(SRAM_BASE_VIRT, SRAM_BASE_PHYS,
+                 SRAM_BASE_SIZE >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+
+    /* add internal sram to mmu_initial_mappings struct for pa to va lookup */
+    mmu_initial_mappings[SRAM_MAPPING_IDX].phys = SRAM_BASE_PHYS;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].virt = SRAM_BASE_VIRT;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].size = SRAM_BASE_SIZE;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].flags = 0;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].name = "isram";
+
+    /* map dram may need new page tables, add internal sram to arena memory */
+    pmm_add_arena(&arena);
+
+#endif /* WITH_KERNEL_VM */
+}
+
+LK_INIT_HOOK(plat_prepare_early_init,
+        &platform_prepare_early_init, LK_INIT_LEVEL_PLATFORM_EARLY - 1);
+
+void mtk_wdt_early_init(void)
+{
+    /* now the dram not init done, can not use dram to cache g_bootarg */
+    check_ddr_reserve_status();
+    g_boot_reason = mtk_wdt_check_status();
+    g_rgu_mode = readl(MTK_WDT_MODE);
+    LTRACEF("g_boot_reason:0x%x g_rgu_mode:0x%x\n", g_boot_reason, g_rgu_mode);
+}
+
+extern int write_efuse(unsigned int index, const unsigned char *data, unsigned int len)__attribute__((weak));
+extern void enable_vefuse(void)__attribute__((weak));
+extern void disable_vefuse(void)__attribute__((weak));
+
+int plat_write_lk_antirollback_version(int version)
+{
+    uint32_t write_data = 0;
+    int ret = 0;
+    #define PL_VER_INDEX 27
+
+    if (!write_efuse || !enable_vefuse || !disable_vefuse) {
+        LTRACEF("efuse read/write function is not supported");
+        return -1;
+    }
+
+    if (version < 1 || version > 16) {
+        LTRACEF("lk version (%d)not support", version);
+        return -1;
+    }
+
+    write_data = (1 << (version - 1)) | (1 << (version - 1 + 16));
+
+    enable_vefuse();
+
+    ret = write_efuse(PL_VER_INDEX, (const unsigned char *)(&write_data), 4);
+
+    disable_vefuse();
+    return ret;
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt2712/platform_bl33.c b/src/bsp/lk/platform/mediatek/mt2712/platform_bl33.c
new file mode 100644
index 0000000..31f9062
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/platform_bl33.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2018 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 <arch/ops.h>
+#include <boot_args.h>
+#include <debug.h>
+#include <err.h>
+#if WITH_KERNEL_VM
+#include <kernel/vm.h>
+#else
+#include <kernel/novm.h>
+#endif
+#include <lib/kcmdline.h>
+#include <platform.h>
+#include <platform/mt2712.h>
+#include <platform/mtk_wdt.h>
+#include <platform/platform_blx.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+#if WITH_KERNEL_VM
+#define PROG_MEM_MAPPING_IDX    0
+#define CHIP_ID_MAPPING_IDX     1
+#define PERIPHERAL_MAPPING_IDX  2
+#define SRAM_MAPPING_IDX        3
+#define DRAM_MAPPING_IDX        4
+
+BOOT_ARGUMENT *g_boot_arg;
+extern ulong lk_boot_args[4];
+
+/* initial memory mappings. parsed by start.S */
+struct mmu_initial_mapping mmu_initial_mappings[] = {
+    {
+        .phys = MEMORY_BASE_PHYS,
+        .virt = MEMORY_BASE_VIRT,
+        .size = MEMORY_APERTURE_SIZE,
+        .flags = 0,
+        .name = "prog"
+    },
+    {
+        .phys = CHIP_ID_BASE_PHYS,
+        .virt = CHIP_ID_BASE_VIRT,
+        .size = CHIP_ID_BASE_SIZE,
+        .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE
+    },
+    {
+        .phys = PERIPHERAL_BASE_PHYS,
+        .virt = PERIPHERAL_BASE_VIRT,
+        .size = PERIPHERAL_BASE_SIZE,
+        .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
+        .name = "peripherals"
+    },
+
+    /* reserved for internal sram */
+    { .size = 0 },
+    /* reserved for dram */
+    { .size = 0 },
+    /* null entry to terminate the list */
+    { .size = 0 }
+};
+
+static pmm_arena_t dram_arena = {
+    .name = "dram",
+    .base = DRAM_ARENA_BASE,
+    .size = DRAM_ARENA_SIZE,
+    .flags = PMM_ARENA_FLAG_KMAP,
+    .priority = 0,
+};
+#endif /* WITH_KERNEL_VM */
+
+static inline size_t query_plat_dram_sz(void)
+{
+    return g_boot_arg->dram_size;
+}
+
+static void setup_plat_mem(void)
+{
+#if WITH_KERNEL_VM
+    size_t unmap_dram_sz, mapped_mem_sz;
+    size_t unmap_dram_start_pa, unmap_dram_start_va;
+
+    /* dram arena memory are already mapped in mmu initial mappings */
+    pmm_add_arena(&dram_arena);
+
+    arch_mmu_map(SRAM_BASE_VIRT, SRAM_BASE_PHYS,
+                 SRAM_BASE_SIZE >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+
+    /* add internal sram to mmu_initial_mappings for pa to va lookup */
+    mmu_initial_mappings[SRAM_MAPPING_IDX].phys = SRAM_BASE_PHYS;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].virt = SRAM_BASE_VIRT;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].size = SRAM_BASE_SIZE;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].flags = 0;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].name = "sram";
+
+    /*
+     * Except the dram range for uncached memory pool, all other dram ranges
+     * are all mapped as cacheable memory.
+     */
+
+    /* BL33 initial mapping already maps a portion of dram, map the rest here */
+    unmap_dram_start_pa = MEMORY_BASE_PHYS + MEMORY_APERTURE_SIZE;
+    unmap_dram_start_va = MEMORY_BASE_VIRT + MEMORY_APERTURE_SIZE;
+
+    mapped_mem_sz = UNCACHED_MEMPOOL_ADDR - unmap_dram_start_va;
+    arch_mmu_map(unmap_dram_start_va, unmap_dram_start_pa,
+                 mapped_mem_sz >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+    arch_mmu_map(UNCACHED_MEMPOOL_ADDR, unmap_dram_start_pa + mapped_mem_sz,
+                 UNCACHED_MEMPOOL_SIZE >> PAGE_SIZE_SHIFT,
+                 ARCH_MMU_FLAG_UNCACHED);
+
+    unmap_dram_sz = query_plat_dram_sz() - MEMORY_APERTURE_SIZE;
+    mapped_mem_sz += UNCACHED_MEMPOOL_SIZE;
+    arch_mmu_map(UNCACHED_MEMPOOL_ADDR + UNCACHED_MEMPOOL_SIZE,
+                 unmap_dram_start_pa + mapped_mem_sz,
+                 (unmap_dram_sz - mapped_mem_sz) >> PAGE_SIZE_SHIFT,
+                 ARCH_MMU_FLAG_CACHED);
+
+    /* add dram to mmu_initial_mappings for pa to va lookup */
+    mmu_initial_mappings[DRAM_MAPPING_IDX].phys = unmap_dram_start_pa;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].virt = unmap_dram_start_va;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].size = unmap_dram_sz;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].flags = 0;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].name = "dram";
+#else
+    novm_add_arena("sram", SRAM_BASE_PHYS, SRAM_BASE_SIZE);
+#endif /* WITH_KERNEL_VM */
+}
+
+void platform_get_bootargs(void)
+{
+    g_boot_arg  = (BOOT_ARGUMENT *)paddr_to_kvaddr(lk_boot_args[0]);
+    if((g_boot_arg == NULL) ||
+        (*(unsigned int *)g_boot_arg != BOOT_ARGUMENT_MAGIC)) {
+        dprintf(CRITICAL, "%s failed (g_boot_arg:%p)\n", __func__, g_boot_arg);
+        g_boot_arg = NULL;
+        return;
+    }
+
+    dprintf(ALWAYS, "%s pa:0x%lx va:%p dram size:0x%llx\n",
+            __func__, lk_boot_args[0], g_boot_arg, g_boot_arg->dram_size);
+}
+
+void platform_memory_init(void)
+{
+    /* bootargs memory should be included in initial mmu mapping */
+    platform_get_bootargs();
+    setup_plat_mem();
+}
+
+void platform_early_init_blx(void)
+{
+    dprintf(CRITICAL, "BL33 Build Time: %s %s\n", __DATE__, __TIME__);
+}
+
+int platform_wdt_boot_check(void)
+{
+    unsigned int wdt_sta = g_boot_arg->boot_reason;
+    unsigned int rgu_mode = g_boot_arg->rgu_mode;
+
+    if (wdt_sta & (MTK_WDT_STATUS_HWWDT_RST|MTK_WDT_STATUS_SWWDT_RST|MTK_WDT_STATUS_SPMWDT_RST)) {
+        if (rgu_mode & MTK_WDT_MODE_AUTO_RESTART)
+        {
+            /* HW/SW reboot, and auto restart is set, means bypass power key */
+            LTRACEF("SW reset with bypass power key flag\n");
+            return WDT_BY_PASS_PWK_REBOOT;
+        } else {
+            LTRACEF("SW reset without bypass power key flag\n");
+            return WDT_NORMAL_REBOOT;
+        }
+    }
+    return WDT_NOT_WDT_REBOOT;
+}
+
+boot_reason_t platform_boot_status(void)
+{
+    if (platform_wdt_boot_check() == WDT_NORMAL_REBOOT) {
+        LTRACEF("WDT normal boot!\n");
+        return BR_WDT;
+    } else if(platform_wdt_boot_check() == WDT_BY_PASS_PWK_REBOOT) {
+        LTRACEF("WDT reboot bypass power key!\n");
+        return BR_WDT_BY_PASS_PWK;
+    }
+    dprintf(CRITICAL, "BL33 check Boot status-WDT\n");
+
+    /*TODO implement rtc_boot_check*/
+    /*TODO implement mtk_detect_key*/
+    /*TODO implement usb_accessory_in*/
+    return BR_UNKNOWN;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt2712/rules.mk b/src/bsp/lk/platform/mediatek/mt2712/rules.mk
new file mode 100644
index 0000000..67d8a28
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt2712/rules.mk
@@ -0,0 +1,152 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+COMMON_PLAT := $(LOCAL_DIR)/../common
+
+ARCH ?= arm64
+ARM_CPU ?= cortex-a53
+WITH_SMP ?= 0
+WITH_KERNEL_VM ?= 1
+
+LK_HEAP_IMPLEMENTATION ?= miniheap
+
+GLOBAL_INCLUDES += -I$(LK_TOP_DIR)/include \
+
+MODULE_SRCS += \
+    $(COMMON_PLAT)/debug.c \
+    $(COMMON_PLAT)/fastboot_oem_cmd/oem_ab_cmd.c \
+    $(COMMON_PLAT)/fastboot_oem_cmd/oem_mac_cmd.c \
+    $(COMMON_PLAT)/interrupts.c \
+    $(COMMON_PLAT)/boot_mode.c \
+    $(LOCAL_DIR)/boot_mode.c \
+    $(LOCAL_DIR)/fixup/plat_fixup.c \
+    $(LOCAL_DIR)/platform.c \
+
+# check bcb (bootloader control block) for recovery mode
+BCB_RECOVERY_SUPPORT ?= 0
+
+ifeq ($(WITH_SMP),1)
+SMP_MAX_CPUS := 6 # if we need only one big core, set this to 5
+SMP_CPU_CLUSTER_SHIFT := 2
+SMP_CPU_ON_MASK ?= 0x11 # mask for which cpu to be on
+
+MODULE_SRCS += \
+    $(COMMON_PLAT)/arch/$(ARCH)/mp.c \
+    $(LOCAL_DIR)/plat_mp.c
+
+GLOBAL_DEFINES += SMP_CPU_ON_MASK=$(SMP_CPU_ON_MASK)
+endif
+
+ifeq ($(LK_AS_BL33),1)
+MODULE_SRCS += \
+    $(COMMON_PLAT)/fastboot_oem_cmd/oem_efuse_cmd.c
+endif
+
+GLOBAL_INCLUDES += \
+    $(COMMON_PLAT)/include \
+
+MACH_TYPE := 2712
+
+ifeq ($(WITH_KERNEL_VM),1)
+KERNEL_ASPACE_BASE ?= 0xfffffff000000000
+KERNEL_ASPACE_SIZE ?= 0x0000000180000000
+MMU_IDENT_SIZE_SHIFT ?= 32
+endif
+
+SCRATCH_SIZE        := 0x02000000 # 32MB
+
+# mempool configuration
+ifeq ($(WITH_KERNEL_VM),1)
+CACHED_MEMPOOL_ADDR ?= 0xfffffff073800000
+CACHED_MEMPOOL_SIZE ?= 0x02800000 # 40MB
+UNCACHED_MEMPOOL_ADDR ?= 0xfffffff073600000
+UNCACHED_MEMPOOL_SIZE ?= 0x200000 # 2MB
+BL33_ADDR ?= 0xfffffff073500000
+else
+CACHED_MEMPOOL_ADDR ?= 0 # don't care this when mmu is off
+CACHED_MEMPOOL_SIZE ?= 0
+UNCACHED_MEMPOOL_ADDR ?= 0x73600000
+UNCACHED_MEMPOOL_SIZE ?= 0x0c800000 # 200MB
+BL33_ADDR ?= 0x73500000
+endif
+
+# if DEBUG is not 0, enable debug feature
+ifneq ($(DEBUG),0)
+LOG_STORE_SUPPORT ?= 1
+endif
+
+# LK build as BL2 or BL33 setting
+LK_AS_BL33 ?= 0
+
+# CA35 FREQ:
+# CA35_FREQ_806MHZ (0.8G), CA35_FREQ_1001MHZ (1.0G), CA35_FREQ_1196MHZ (1.2G)
+CA35_FREQ ?= CA35_FREQ_1196MHZ
+
+# CA72 FREQ:
+# CA72_FREQ_1001MHZ(1.0G), CA72_FREQ_1196MHZ(1.2G), CA72_FREQ_1391MHZ(1.4G),
+# CA72_FREQ_1495MHZ(1.5G), CA72_FREQ_1599MHZ(1.6G)
+CA72_FREQ ?= CA72_FREQ_1599MHZ
+
+MODULE_DEPS += \
+    dev/interrupt/arm_gic \
+    dev/timer/arm_generic \
+    lib/bio \
+    lib/fastboot \
+    lib/fdt \
+    lib/fit \
+    lib/kcmdline \
+    lib/partition \
+    lib/mempool
+
+ifeq ($(LOG_STORE_SUPPORT),1)
+MODULE_DEPS += \
+    lib/log_store
+
+GLOBAL_DEFINES += LOG_STORE_SUPPORT=$(LOG_STORE_SUPPORT)
+endif
+
+# if BOOTAPP is not specified elsewhere, and AVB is required, choose 'avbboot'
+ifeq ($(strip $(SECURE_BOOT_ENABLE)),yes)
+ifeq ($(strip $(SECURE_BOOT_TYPE)),avb)
+BOOTAPP ?= avbboot
+endif
+endif
+
+# otherwise, choose 'fitboot'
+BOOTAPP ?= fitboot
+
+MODULES += app/$(BOOTAPP)
+
+# RTC OSC Removal
+ifeq ($(strip $(MTK_CLK32K_EXT_REMOVAL_SUPPORT)),yes)
+GLOBAL_DEFINES += MTK_CLK32K_EXT_REMOVAL_SUPPORT=1
+endif
+
+GLOBAL_DEFINES += MTK_THERMAL_RESET_SUPPORT
+
+ifeq ($(WITH_KERNEL_VM),1)
+GLOBAL_DEFINES += MMU_IDENT_SIZE_SHIFT=$(MMU_IDENT_SIZE_SHIFT)
+else
+GLOBAL_DEFINES += NOVM_MAX_ARENAS=2
+endif
+
+GLOBAL_DEFINES += \
+    RAMBASE=$(RAMBASE) \
+    MACH_TYPE=$(MACH_TYPE) \
+    PLATFORM_SUPPORTS_PANIC_SHELL=1 \
+    WITH_NO_FP=1 \
+    CACHED_MEMPOOL_ADDR=$(CACHED_MEMPOOL_ADDR) \
+    CACHED_MEMPOOL_SIZE=$(CACHED_MEMPOOL_SIZE) \
+    UNCACHED_MEMPOOL_ADDR=$(UNCACHED_MEMPOOL_ADDR) \
+    UNCACHED_MEMPOOL_SIZE=$(UNCACHED_MEMPOOL_SIZE) \
+    BL33_ADDR=$(BL33_ADDR) \
+    $(CA35_FREQ) \
+    $(CA72_FREQ) \
+    LK_AS_BL33=$(LK_AS_BL33) \
+    BCB_RECOVERY_SUPPORT=$(BCB_RECOVERY_SUPPORT)
+
+LINKER_SCRIPT += \
+    $(BUILDDIR)/system-onesegment.ld
+
+include $(LOCAL_DIR)/bl2_bl33_options.mk
+include make/module.mk $(LOCAL_DIR)/drivers/rules.mk
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/display/ddp.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/ddp.c
new file mode 100644
index 0000000..ef0b38e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/ddp.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <platform/addressmap.h>
+#include <platform/ddp.h>
+#include <platform/ddp_debug.h>
+#include <platform/mtcmos.h>
+
+static void disp_config_main_path_connection(void)
+{
+	write32(&mmsys_cfg->disp_ovl0_mout_en, OVL0_MOUT_EN_OVL0_2L);
+	write32(&mmsys_cfg->disp_ovl0_2l_mout_en, OVL0_2L_MOUT_EN_DISP_PATH0);
+	write32(&mmsys_cfg->disp_path0_sel_in, DISP_PATH0_SEL_IN_OVL0_2L);
+	write32(&mmsys_cfg->disp_rdma0_sout_sel_in, RDMA0_SOUT_SEL_IN_COLOR);
+
+#if HDMI_MAIN_PATH
+	write32(&mmsys_cfg->disp_dither0_mout_en, DITHER0_MOUT_EN_DISP_DPI0);
+	write32(&mmsys_cfg->dpi0_sel_in, DPI0_SEL_IN_DITHER0_MOUT);
+#else
+	write32(&mmsys_cfg->disp_dither0_mout_en, DITHER0_MOUT_EN_DISP_DSI0);
+	write32(&mmsys_cfg->dsi0_sel_in, DSI0_SEL_IN_DITHER0_MOUT);
+#endif
+}
+
+static void disp_config_main_path_mutex(void)
+{
+	write32(&disp_mutex->mutex[0].mod, MUTEX_MOD_MAIN_PATH);
+
+#if HDMI_MAIN_PATH
+	/* Clock source from DPI0 */
+	write32(&disp_mutex->mutex[0].ctl,
+		MUTEX_SOF_DPI0 | (MUTEX_SOF_DPI0 << 6));
+#else
+	/* Clock source from DSI0 */
+	write32(&disp_mutex->mutex[0].ctl,
+		MUTEX_SOF_DSI0 | (MUTEX_SOF_DSI0 << 6));
+#endif
+	write32(&disp_mutex->mutex[0].en, BIT(0));
+}
+
+static void ovl_bgclr_in_sel(u32 idx)
+{
+	setbits_le32(&disp_ovl[idx]->datapath_con, BIT(2));
+}
+
+static void enable_pq(struct disp_pq_regs *const regs, u32 width, u32 height,
+		      int enable_relay)
+{
+	write32(&regs->size, height << 16 | width);
+	if (enable_relay)
+		write32(&regs->cfg, PQ_RELAY_MODE);
+	write32(&regs->en, PQ_EN);
+}
+
+static void main_disp_path_setup(u32 width, u32 height, u32 vrefresh)
+{
+	u32 idx = 0;
+	u32 pixel_clk = width * height * vrefresh;
+
+	for (idx = 0; idx < MAIN_PATH_OVL_NR; idx++)
+		ovl_set_roi(idx, width, height, idx ? 0 : 0xff0000ff);
+
+	rdma_config(width, height, pixel_clk, 5 * KiB);
+	color_start(width, height);
+	enable_pq(disp_ccorr, width, height, 1);
+	enable_pq(disp_aal, width, height, 0);
+	enable_pq(disp_gamma, width, height, 0);
+	enable_pq(disp_dither, width, height, 1);
+	disp_config_main_path_connection();
+	disp_config_main_path_mutex();
+}
+
+static void disp_clock_on(void)
+{
+	ddp_log("mmsys_cg_con 0x%X 0x%X CON0_DISP_ALL 0x%X CON1_DISP_ALL 0x%X\n",
+	mmsys_cfg->mmsys_cg_con0,
+	mmsys_cfg->mmsys_cg_con1,
+	CG_CON0_DISP_ALL, CG_CON1_DISP_ALL);
+
+	clrbits_le32(&mmsys_cfg->mmsys_cg_con0, CG_CON0_DISP_ALL);
+
+#if HDMI_MAIN_PATH
+	clrbits_le32(&mmsys_cfg->mmsys_cg_con1, CG_CON1_DISP_DPI0 |
+						CG_CON1_DISP_DPI0_INTERFACE);
+#else
+	clrbits_le32(&mmsys_cfg->mmsys_cg_con1, CG_CON1_DISP_DSI0 |
+						CG_CON1_DISP_DSI0_INTERFACE);
+#endif
+}
+
+static void disp_turn_off_m4u_larb(void)
+{
+	/* Turn off M4U port. */
+	clrbits_le32((SMI_LARB0 + SMI_LARB_NON_SEC_CON), BIT(0));
+}
+
+void mtk_ddp_init(void)
+{
+	mtcmos_display_power_on();
+
+	mtcmos_protect_display_bus();
+
+	disp_clock_on();
+
+	disp_turn_off_m4u_larb();
+}
+
+void mtk_ddp_mode_set(u32 width, u32 height, u32 addr)
+{
+	u32 fmt = OVL_INFMT_RGB888;
+	u32 bpp = 3;
+	u32 vrefresh = 60;
+	u32 idx = 0;
+
+	main_disp_path_setup(width, height, vrefresh);
+
+	rdma_start();
+
+	ovl_layer_config(fmt, bpp, width, height, addr);
+
+	ovl_bgclr_in_sel(1);
+
+	for (idx = 0; idx < MAIN_PATH_OVL_NR; idx++)
+		ovl_enable(idx);
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/display/ddp_common.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/ddp_common.c
new file mode 100644
index 0000000..898dad3
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/ddp_common.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <platform/addressmap.h>
+#include <platform/ddp.h>
+#include <platform/ddp_debug.h>
+
+#define RDMA_FIFO_PSEUDO_SIZE(bytes)            (((bytes) / 16) << 16)
+#define RDMA_OUTPUT_VALID_FIFO_THRESHOLD(bytes) ((bytes) / 16)
+
+void ovl_set_roi(u32 idx, u32 width, u32 height, u32 color)
+{
+	write32(&disp_ovl[idx]->roi_size, height << 16 | width);
+	write32(&disp_ovl[idx]->roi_bgclr, color);
+}
+
+void rdma_start(void)
+{
+	setbits_le32(&disp_rdma0->global_con, RDMA_ENGINE_EN);
+}
+
+void rdma_config(u32 width, u32 height, u32 pixel_clk, u32 fifo_size)
+{
+	u32 threshold;
+	u32 reg;
+
+	clrsetbits_le32(&disp_rdma0->size_con_0, 0x1FFF, width);
+	clrsetbits_le32(&disp_rdma0->size_con_1, 0xFFFFF, height);
+
+	/*
+	 * Enable FIFO underflow since DSI and DPI can't be blocked. Set the
+	 * output threshold to 6 microseconds with 7/6 overhead to account for
+	 * blanking, and with a pixel depth of 4 bytes:
+	 */
+	threshold = pixel_clk * 4 * 7 / 1000;
+
+	if (threshold > fifo_size)
+		threshold = fifo_size;
+
+	reg = RDMA_FIFO_UNDERFLOW_EN | RDMA_FIFO_PSEUDO_SIZE(fifo_size) |
+	      RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold);
+
+	write32(&disp_rdma0->fifo_con, reg);
+}
+
+void color_start(u32 width, u32 height)
+{
+
+	write32(&disp_color0->width, width);
+	write32(&disp_color0->height, height);
+	write32(&disp_color0->cfg_main, COLOR_BYPASS_ALL | COLOR_SEQ_SEL);
+	write32(&disp_color0->start, BIT(0));
+}
+
+void ovl_layer_config(u32 fmt, u32 bpp, u32 width, u32 height, u32 addr)
+{
+	struct disp_ovl_regs *const ovl0 = disp_ovl[0];
+
+	ddp_log("addr 0x%X\n", addr);
+
+	write32(&ovl0->layer[0].con, fmt << 12);
+	write32(&ovl0->layer[0].src_size, height << 16 | width);
+	write32(&ovl0->layer[0].pitch, (width * bpp) & 0xFFFF);
+
+	/* Enable layer */
+	write32(&ovl0->rdma[0].ctrl, BIT(0));
+	write32(&ovl0->rdma[0].mem_gmc_setting, RDMA_MEM_GMC);
+
+	setbits_le32(&ovl0->src_con, BIT(0));
+
+	write32(&ovl0->l0_addr, addr);
+
+	write32(&ovl0->en, 0x1);
+}
+
+void ovl_enable(u32 idx)
+{
+	struct disp_ovl_regs *const ovl0 = disp_ovl[idx];
+
+	write32(&ovl0->en, 0x1);
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/display/disp_pwm.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/disp_pwm.c
new file mode 100644
index 0000000..2056306
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/disp_pwm.c
@@ -0,0 +1,125 @@
+/*

+ * Copyright (c) 2020 MediaTek Inc.

+ *

+ * Use of this source code is governed by a MIT-style

+ * license that can be found in the LICENSE file or at

+ * https://opensource.org/licenses/MIT

+ */

+

+#include <assert.h>

+#include <platform/mm_common.h>

+#include <platform/ddp_debug.h>

+#include <platform/mt_reg_base.h>

+

+#define DISP_PWM_EN		0x00

+#define ENABLE_MASK		BIT(0)

+

+#define PWM_CLKDIV_SHIFT	16

+#define PWM_CLKDIV_MAX		0x3ff

+#define PWM_CLKDIV_MASK		(PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT)

+

+#define PWM_PERIOD_BIT_WIDTH	12

+#define PWM_PERIOD_MASK		((1 << PWM_PERIOD_BIT_WIDTH) - 1)

+

+#define PWM_HIGH_WIDTH_SHIFT	16

+#define PWM_HIGH_WIDTH_MASK	(0x1fff << PWM_HIGH_WIDTH_SHIFT)

+

+#define DIV_ROUND_UP(x,y) (((x) + ((y) - 1)) / (y))

+#define NSEC_PER_SEC 1000000000

+

+#define DISP_PWM_CON_0 0x18

+#define DISP_PWM_CON_1 0x1c

+#define DISP_PWM_DEBUG 0x80

+#define FORCE_COMMIT 3

+

+struct mtk_disp_pwm_ipc_config{

+	u64 rate;

+	u64 duty_ns;

+	u64 period_ns;

+};

+

+static void mtk_disp_pwm_update_bits(u32 offset, u32 mask, u32 data)

+{

+	u32 value;

+

+	value = readl(DISP_PWM0_BASE + offset);

+

+	value &= ~mask;

+	value |= data;

+

+	writel(value, DISP_PWM0_BASE + offset);

+}

+

+static void mtk_disp_pwm_config(u64 rate, u64 period_ns, u64 duty_ns)

+{

+	u64 clk_div, period, high_width, value;

+	u64 div;

+	u32 temp;

+

+	/*

+	 * Find period, high_width and clk_div to suit duty_ns and period_ns.

+	 * Calculate proper div value to keep period value in the bound.

+	 *

+	 * period_ns = 10^9 * (clk_div + 1) * (period + 1) / PWM_CLK_RATE

+	 * duty_ns = 10^9 * (clk_div + 1) * high_width / PWM_CLK_RATE

+	 *

+	 * period = (PWM_CLK_RATE * period_ns) / (10^9 * (clk_div + 1)) - 1

+	 * high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1))

+	 */

+

+	ddp_log("rate: %lld \n", rate);

+	ddp_log(" period_ns: %lld \n", period_ns);

+	ddp_log(" duty_ns: %lld\n", duty_ns);

+

+	clk_div = DIV_ROUND_UP(rate * period_ns, NSEC_PER_SEC) >> PWM_PERIOD_BIT_WIDTH;

+	if (clk_div > PWM_CLKDIV_MAX)

+		return;

+

+	div = 1000000000 * (clk_div + 1);

+	period = DIV_ROUND_UP(rate * period_ns, div);

+	if (period > 0)

+		period--;

+

+	high_width = DIV_ROUND_UP(rate * duty_ns, div);

+	value = period | (high_width << PWM_HIGH_WIDTH_SHIFT);

+

+	ddp_log(" period: %d\n", period);

+	ddp_log(" high_width: %d\n", high_width);

+	ddp_log("clk_div: %d, value %d\n", clk_div, value);

+

+	mtk_disp_pwm_update_bits(DISP_PWM_CON_0, PWM_CLKDIV_MASK, clk_div << PWM_CLKDIV_SHIFT);

+	mtk_disp_pwm_update_bits(DISP_PWM_CON_1, PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, value);

+

+	mtk_disp_pwm_update_bits(DISP_PWM_DEBUG, FORCE_COMMIT, FORCE_COMMIT);

+}

+

+void bl_pin_ctrl(u32 enable)

+{

+	/* config DISP_PWM_PIN as disp_pwm mode */

+	clrsetbits_le32(GPIO_BASE + 0x350, 0xf << 12, 1 << 12); //gpio54 mode disp_pwm   disp_pwm pin

+}

+

+u32 lcm_if_set_backlight(u32 level, u32 level_max, bool use_default_level)

+{

+	u64 rate, period_ns, duty_ns;

+

+	if (use_default_level) {

+		level = 10;

+		level_max = 15;

+	}

+

+	rate = 104000000;

+	period_ns = 1000000;

+	duty_ns = level * period_ns / (level_max + 1);

+

+	/* config topckgen disp_pwm clock mux */

+	setbits_le32(TOPCKGEN_BASE + 0x000000b8, 0xff);

+	setbits_le32(TOPCKGEN_BASE + 0x00000004, BIT(28));

+

+	bl_pin_ctrl(1);

+

+	mtk_disp_pwm_config(rate, period_ns, duty_ns);

+	mtk_disp_pwm_update_bits(DISP_PWM_EN, ENABLE_MASK, ENABLE_MASK);

+

+	return 0;

+}

diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/display/dpi.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/dpi.c
new file mode 100644
index 0000000..d01067e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/dpi.c
@@ -0,0 +1,807 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <sys/types.h>
+#include <reg.h>
+#include <platform/mm_common.h>
+#include <platform/mt_reg_base.h>
+#include <debug.h>
+#include <stdlib.h>
+
+#define bool uchar
+#define false 0
+#define true 1
+#define WARN_ON(condition) (condition)
+
+#define DPI_EN			0x00
+#define EN				BIT(0)
+
+#define DPI_RET			0x04
+#define RST				BIT(0)
+
+#define DPI_INTEN		0x08
+#define INT_VSYNC_EN			BIT(0)
+#define INT_VDE_EN			BIT(1)
+#define INT_UNDERFLOW_EN		BIT(2)
+
+#define DPI_INTSTA		0x0C
+#define INT_VSYNC_STA			BIT(0)
+#define INT_VDE_STA			BIT(1)
+#define INT_UNDERFLOW_STA		BIT(2)
+
+#define DPI_CON			0x10
+#define BG_ENABLE			BIT(0)
+#define IN_RB_SWAP			BIT(1)
+#define INTL_EN				BIT(2)
+#define TDFP_EN				BIT(3)
+#define CLPF_EN				BIT(4)
+#define YUV422_EN			BIT(5)
+#define CSC_ENABLE			BIT(6)
+#define R601_SEL			BIT(7)
+#define EMBSYNC_EN			BIT(8)
+#define VS_LODD_EN			BIT(16)
+#define VS_LEVEN_EN			BIT(17)
+#define VS_RODD_EN			BIT(18)
+#define VS_REVEN			BIT(19)
+#define FAKE_DE_LODD			BIT(20)
+#define FAKE_DE_LEVEN			BIT(21)
+#define FAKE_DE_RODD			BIT(22)
+#define FAKE_DE_REVEN			BIT(23)
+
+#define DPI_OUTPUT_SETTING	0x14
+#define CH_SWAP				0
+#define CH_SWAP_MASK			(0x7 << 0)
+#define SWAP_RGB			0x00
+#define SWAP_GBR			0x01
+#define SWAP_BRG			0x02
+#define SWAP_RBG			0x03
+#define SWAP_GRB			0x04
+#define SWAP_BGR			0x05
+#define BIT_SWAP			BIT(3)
+#define B_MASK				BIT(4)
+#define G_MASK				BIT(5)
+#define R_MASK				BIT(6)
+#define DE_MASK				BIT(8)
+#define HS_MASK				BIT(9)
+#define VS_MASK				BIT(10)
+#define DE_POL				BIT(12)
+#define HSYNC_POL			BIT(13)
+#define VSYNC_POL			BIT(14)
+#define CK_POL				BIT(15)
+#define OEN_OFF				BIT(16)
+#define EDGE_SEL			BIT(17)
+#define OUT_BIT				18
+#define OUT_BIT_MASK			(0x3 << 18)
+#define OUT_BIT_8			0x00
+#define OUT_BIT_10			0x01
+#define OUT_BIT_12			0x02
+#define OUT_BIT_16			0x03
+#define YC_MAP				20
+#define YC_MAP_MASK			(0x7 << 20)
+#define YC_MAP_RGB			0x00
+#define YC_MAP_CYCY			0x04
+#define YC_MAP_YCYC			0x05
+#define YC_MAP_CY			0x06
+#define YC_MAP_YC			0x07
+
+#define DPI_SIZE		0x18
+#define HSIZE				0
+#define HSIZE_MASK			(0x1FFF << 0)
+#define VSIZE				16
+#define VSIZE_MASK			(0x1FFF << 16)
+
+#define DPI_DDR_SETTING		0x1C
+#define DDR_EN				BIT(0)
+#define DDDR_SEL			BIT(1)
+#define DDR_4PHASE			BIT(2)
+#define DDR_WIDTH			(0x3 << 4)
+#define DDR_PAD_MODE			(0x1 << 8)
+
+#define DPI_TGEN_HWIDTH		0x20
+#define HPW				0
+#define HPW_MASK			(0xFFF << 0)
+
+#define DPI_TGEN_HPORCH		0x24
+#define HBP				0
+#define HBP_MASK			(0xFFF << 0)
+#define HFP				16
+#define HFP_MASK			(0xFFF << 16)
+
+#define DPI_TGEN_VWIDTH		0x28
+#define DPI_TGEN_VPORCH		0x2C
+
+#define VSYNC_WIDTH_SHIFT		0
+#define VSYNC_WIDTH_MASK		(0xFFF << 0)
+#define VSYNC_HALF_LINE_SHIFT		16
+#define VSYNC_HALF_LINE_MASK		BIT(16)
+#define VSYNC_BACK_PORCH_SHIFT		0
+#define VSYNC_BACK_PORCH_MASK		(0xFFF << 0)
+#define VSYNC_FRONT_PORCH_SHIFT		16
+#define VSYNC_FRONT_PORCH_MASK		(0xFFF << 16)
+
+#define DPI_BG_HCNTL		0x30
+#define BG_RIGHT			(0x1FFF << 0)
+#define BG_LEFT				(0x1FFF << 16)
+
+#define DPI_BG_VCNTL		0x34
+#define BG_BOT				(0x1FFF << 0)
+#define BG_TOP				(0x1FFF << 16)
+
+#define DPI_BG_COLOR		0x38
+#define BG_B				(0xF << 0)
+#define BG_G				(0xF << 8)
+#define BG_R				(0xF << 16)
+
+#define DPI_FIFO_CTL		0x3C
+#define FIFO_VALID_SET			(0x1F << 0)
+#define FIFO_RST_SEL			(0x1 << 8)
+
+#define DPI_STATUS		0x40
+#define VCOUNTER			(0x1FFF << 0)
+#define DPI_BUSY			BIT(16)
+#define OUTEN				BIT(17)
+#define FIELD				BIT(20)
+#define TDLR				BIT(21)
+
+#define DPI_TMODE		0x44
+#define DPI_OEN_ON			BIT(0)
+
+#define DPI_CHECKSUM		0x48
+#define DPI_CHECKSUM_MASK		(0xFFFFFF << 0)
+#define DPI_CHECKSUM_READY		BIT(30)
+#define DPI_CHECKSUM_EN			BIT(31)
+
+#define DPI_DUMMY		0x50
+#define DPI_DUMMY_MASK			(0xFFFFFFFF << 0)
+
+#define DPI_TGEN_VWIDTH_LEVEN	0x68
+#define DPI_TGEN_VPORCH_LEVEN	0x6C
+#define DPI_TGEN_VWIDTH_RODD	0x70
+#define DPI_TGEN_VPORCH_RODD	0x74
+#define DPI_TGEN_VWIDTH_REVEN	0x78
+#define DPI_TGEN_VPORCH_REVEN	0x7C
+
+#define DPI_ESAV_VTIMING_LODD	0x80
+#define ESAV_VOFST_LODD			(0xFFF << 0)
+#define ESAV_VWID_LODD			(0xFFF << 16)
+
+#define DPI_ESAV_VTIMING_LEVEN	0x84
+#define ESAV_VOFST_LEVEN		(0xFFF << 0)
+#define ESAV_VWID_LEVEN			(0xFFF << 16)
+
+#define DPI_ESAV_VTIMING_RODD	0x88
+#define ESAV_VOFST_RODD			(0xFFF << 0)
+#define ESAV_VWID_RODD			(0xFFF << 16)
+
+#define DPI_ESAV_VTIMING_REVEN	0x8C
+#define ESAV_VOFST_REVEN		(0xFFF << 0)
+#define ESAV_VWID_REVEN			(0xFFF << 16)
+
+#define DPI_ESAV_FTIMING	0x90
+#define ESAV_FOFST_ODD			(0xFFF << 0)
+#define ESAV_FOFST_EVEN			(0xFFF << 16)
+
+#define DPI_CLPF_SETTING	0x94
+#define CLPF_TYPE			(0x3 << 0)
+#define ROUND_EN			BIT(4)
+
+#define DPI_Y_LIMIT		0x98
+#define Y_LIMINT_BOT			0
+#define Y_LIMINT_BOT_MASK		(0xFFF << 0)
+#define Y_LIMINT_TOP			16
+#define Y_LIMINT_TOP_MASK		(0xFFF << 16)
+
+#define DPI_C_LIMIT		0x9C
+#define C_LIMIT_BOT			0
+#define C_LIMIT_BOT_MASK		(0xFFF << 0)
+#define C_LIMIT_TOP			16
+#define C_LIMIT_TOP_MASK		(0xFFF << 16)
+
+#define DPI_YUV422_SETTING	0xA0
+#define UV_SWAP				BIT(0)
+#define CR_DELSEL			BIT(4)
+#define CB_DELSEL			BIT(5)
+#define Y_DELSEL			BIT(6)
+#define DE_DELSEL			BIT(7)
+
+#define DPI_EMBSYNC_SETTING	0xA4
+#define EMBSYNC_R_CR_EN			BIT(0)
+#define EMPSYNC_G_Y_EN			BIT(1)
+#define EMPSYNC_B_CB_EN			BIT(2)
+#define ESAV_F_INV			BIT(4)
+#define ESAV_V_INV			BIT(5)
+#define ESAV_H_INV			BIT(6)
+#define ESAV_CODE_MAN			BIT(8)
+#define VS_OUT_SEL			(0x7 << 12)
+
+#define DPI_ESAV_CODE_SET0	0xA8
+#define ESAV_CODE0			(0xFFF << 0)
+#define ESAV_CODE1			(0xFFF << 16)
+
+#define DPI_ESAV_CODE_SET1	0xAC
+#define ESAV_CODE2			(0xFFF << 0)
+#define ESAV_CODE3_MSB			BIT(16)
+
+#define EDGE_SEL_EN			BIT(5)
+#define H_FRE_2N			BIT(25)
+
+enum mtk_dpi_out_bit_num {
+	MTK_DPI_OUT_BIT_NUM_8BITS,
+	MTK_DPI_OUT_BIT_NUM_10BITS,
+	MTK_DPI_OUT_BIT_NUM_12BITS,
+	MTK_DPI_OUT_BIT_NUM_16BITS
+};
+
+enum mtk_dpi_out_yc_map {
+	MTK_DPI_OUT_YC_MAP_RGB,
+	MTK_DPI_OUT_YC_MAP_CYCY,
+	MTK_DPI_OUT_YC_MAP_YCYC,
+	MTK_DPI_OUT_YC_MAP_CY,
+	MTK_DPI_OUT_YC_MAP_YC
+};
+
+enum mtk_dpi_out_channel_swap {
+	MTK_DPI_OUT_CHANNEL_SWAP_RGB,
+	MTK_DPI_OUT_CHANNEL_SWAP_GBR,
+	MTK_DPI_OUT_CHANNEL_SWAP_BRG,
+	MTK_DPI_OUT_CHANNEL_SWAP_RBG,
+	MTK_DPI_OUT_CHANNEL_SWAP_GRB,
+	MTK_DPI_OUT_CHANNEL_SWAP_BGR
+};
+
+enum mtk_dpi_out_color_format {
+	MTK_DPI_COLOR_FORMAT_RGB,
+	MTK_DPI_COLOR_FORMAT_RGB_FULL,
+	MTK_DPI_COLOR_FORMAT_YCBCR_444,
+	MTK_DPI_COLOR_FORMAT_YCBCR_422,
+	MTK_DPI_COLOR_FORMAT_XV_YCC,
+	MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL,
+	MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
+};
+
+#define DRM_MODE_FLAG_PHSYNC		BIT(0)
+#define DRM_MODE_FLAG_NHSYNC		BIT(1)
+#define DRM_MODE_FLAG_PVSYNC		BIT(2)
+#define DRM_MODE_FLAG_NVSYNC		BIT(3)
+#define DRM_MODE_FLAG_INTERLACE	BIT(4)
+#define DRM_MODE_FLAG_DBLSCAN	BIT(5)
+#define DRM_MODE_FLAG_CSYNC		BIT(6)
+#define DRM_MODE_FLAG_PCSYNC		BIT(7)
+#define DRM_MODE_FLAG_NCSYNC		BIT(8)
+#define DRM_MODE_FLAG_HSKEW		BIT(9)
+#define DRM_MODE_FLAG_BCAST		BIT(10)
+#define DRM_MODE_FLAG_PIXMUX		BIT(11)
+#define DRM_MODE_FLAG_DBLCLK		BIT(12)
+#define DRM_MODE_FLAG_CLKDIV2		BIT(13)
+#define DRM_MODE_FLAG_3D_MASK			(0x1f << 14)
+#define  DRM_MODE_FLAG_3D_NONE		(0 << 14)
+#define  DRM_MODE_FLAG_3D_FRAME_PACKING		(1 << 14)
+#define  DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE	(2 << 14)
+#define  DRM_MODE_FLAG_3D_LINE_ALTERNATIVE	(3 << 14)
+#define  DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL	(4 << 14)
+#define  DRM_MODE_FLAG_3D_L_DEPTH		(5 << 14)
+#define  DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH	(6 << 14)
+#define  DRM_MODE_FLAG_3D_TOP_AND_BOTTOM	(7 << 14)
+#define  DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF	(8 << 14)
+
+struct videomode {
+	u32 pixelclock;
+
+	u32 hactive;
+	u32 hfront_porch;
+	u32 hback_porch;
+	u32 hsync_len;
+
+	u32 vactive;
+	u32 vfront_porch;
+	u32 vback_porch;
+	u32 vsync_len;
+
+	u32 flags; /* display flags */
+};
+
+enum mtk_dpi_polarity {
+	MTK_DPI_POLARITY_RISING,
+	MTK_DPI_POLARITY_FALLING,
+};
+
+struct mtk_dpi_polarities {
+	enum mtk_dpi_polarity de_pol;
+	enum mtk_dpi_polarity ck_pol;
+	enum mtk_dpi_polarity hsync_pol;
+	enum mtk_dpi_polarity vsync_pol;
+};
+
+struct mtk_dpi_sync_param {
+	u32 sync_width;
+	u32 front_porch;
+	u32 back_porch;
+	bool shift_half_line;
+};
+
+struct mtk_dpi_yc_limit {
+	u16 y_top;
+	u16 y_bottom;
+	u16 c_top;
+	u16 c_bottom;
+};
+
+static const struct videomode hd720p60 = {
+	.pixelclock =74250000, /* Hz*/
+	.hactive = 1280,
+	.hfront_porch = 110,
+	.hback_porch = 220,
+	.hsync_len = 40,
+	.vactive = 720,
+	.vfront_porch = 5,
+	.vback_porch = 20,
+	.vsync_len = 5,
+	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC
+};
+
+struct mtk_dpi {
+	u64 dpi_regs;
+	u64 tvd_pll_regs;
+	u64 top_ckgen_regs;
+	struct videomode *mode;
+	struct mtk_dpi_yc_limit limit;
+	struct mtk_dpi_polarities dpi_pol;
+	enum mtk_dpi_out_color_format color_format;
+	enum mtk_dpi_out_yc_map yc_map;
+	enum mtk_dpi_out_bit_num bit_num;
+	enum mtk_dpi_out_channel_swap channel_swap;
+};
+
+static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
+{
+	u32 tmp = readl(dpi->dpi_regs + offset) & ~mask;
+
+	tmp |= (val & mask);
+	writel(tmp, dpi->dpi_regs + offset);
+}
+
+static u32 mt8183_calculate_factor(int clock)
+{
+	if (clock <= 20000)
+		return 8;
+	else if (clock <= 167000)
+		return 4;
+	else
+		return 2;
+}
+
+static void mtk_dpi_sw_reset(struct mtk_dpi *dpi, bool reset)
+{
+	mtk_dpi_mask(dpi, DPI_RET, reset ? RST : 0, RST);
+}
+
+static void mtk_dpi_enable(struct mtk_dpi *dpi)
+{
+	mtk_dpi_mask(dpi, DPI_EN, EN, EN);
+}
+
+static void mtk_dpi_disable(struct mtk_dpi *dpi)
+{
+	mtk_dpi_mask(dpi, DPI_EN, 0, EN);
+}
+
+static void mtk_dpi_config_hsync(struct mtk_dpi *dpi,
+				 struct mtk_dpi_sync_param *sync)
+{
+	mtk_dpi_mask(dpi, DPI_TGEN_HWIDTH,
+		     sync->sync_width << HPW, HPW_MASK);
+	mtk_dpi_mask(dpi, DPI_TGEN_HPORCH,
+		     sync->back_porch << HBP, HBP_MASK);
+	mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, sync->front_porch << HFP,
+		     HFP_MASK);
+}
+
+static void mtk_dpi_config_vsync(struct mtk_dpi *dpi,
+				 struct mtk_dpi_sync_param *sync,
+				 u32 width_addr, u32 porch_addr)
+{
+	mtk_dpi_mask(dpi, width_addr,
+		     sync->sync_width << VSYNC_WIDTH_SHIFT,
+		     VSYNC_WIDTH_MASK);
+	mtk_dpi_mask(dpi, width_addr,
+		     sync->shift_half_line << VSYNC_HALF_LINE_SHIFT,
+		     VSYNC_HALF_LINE_MASK);
+	mtk_dpi_mask(dpi, porch_addr,
+		     sync->back_porch << VSYNC_BACK_PORCH_SHIFT,
+		     VSYNC_BACK_PORCH_MASK);
+	mtk_dpi_mask(dpi, porch_addr,
+		     sync->front_porch << VSYNC_FRONT_PORCH_SHIFT,
+		     VSYNC_FRONT_PORCH_MASK);
+}
+
+static void mtk_dpi_config_vsync_lodd(struct mtk_dpi *dpi,
+				      struct mtk_dpi_sync_param *sync)
+{
+	mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH, DPI_TGEN_VPORCH);
+}
+
+static void mtk_dpi_config_vsync_leven(struct mtk_dpi *dpi,
+				       struct mtk_dpi_sync_param *sync)
+{
+	mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_LEVEN,
+			     DPI_TGEN_VPORCH_LEVEN);
+}
+
+static void mtk_dpi_config_vsync_rodd(struct mtk_dpi *dpi,
+				      struct mtk_dpi_sync_param *sync)
+{
+	mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_RODD,
+			     DPI_TGEN_VPORCH_RODD);
+}
+
+static void mtk_dpi_config_vsync_reven(struct mtk_dpi *dpi,
+				       struct mtk_dpi_sync_param *sync)
+{
+	mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_REVEN,
+			     DPI_TGEN_VPORCH_REVEN);
+}
+
+static void mtk_dpi_config_pol(struct mtk_dpi *dpi,
+			       struct mtk_dpi_polarities *dpi_pol)
+{
+	unsigned int pol;
+
+	pol = (dpi_pol->ck_pol == MTK_DPI_POLARITY_RISING ? 0 : CK_POL) |
+	      (dpi_pol->de_pol == MTK_DPI_POLARITY_RISING ? 0 : DE_POL) |
+	      (dpi_pol->hsync_pol == MTK_DPI_POLARITY_RISING ? 0 : HSYNC_POL) |
+	      (dpi_pol->vsync_pol == MTK_DPI_POLARITY_RISING ? 0 : VSYNC_POL);
+	mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, pol,
+		     CK_POL | DE_POL | HSYNC_POL | VSYNC_POL);
+}
+
+static void mtk_dpi_config_3d(struct mtk_dpi *dpi, bool en_3d)
+{
+	mtk_dpi_mask(dpi, DPI_CON, en_3d ? TDFP_EN : 0, TDFP_EN);
+}
+
+static void mtk_dpi_config_interface(struct mtk_dpi *dpi, bool inter)
+{
+	mtk_dpi_mask(dpi, DPI_CON, inter ? INTL_EN : 0, INTL_EN);
+}
+
+static void mtk_dpi_config_fb_size(struct mtk_dpi *dpi, u32 width, u32 height)
+{
+	mtk_dpi_mask(dpi, DPI_SIZE, width << HSIZE, HSIZE_MASK);
+	mtk_dpi_mask(dpi, DPI_SIZE, height << VSIZE, VSIZE_MASK);
+}
+
+static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi,
+					 struct mtk_dpi_yc_limit *limit)
+{
+	mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_bottom << Y_LIMINT_BOT,
+		     Y_LIMINT_BOT_MASK);
+	mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_top << Y_LIMINT_TOP,
+		     Y_LIMINT_TOP_MASK);
+	mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_bottom << C_LIMIT_BOT,
+		     C_LIMIT_BOT_MASK);
+	mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_top << C_LIMIT_TOP,
+		     C_LIMIT_TOP_MASK);
+}
+
+static void mtk_dpi_config_bit_num(struct mtk_dpi *dpi,
+				   enum mtk_dpi_out_bit_num num)
+{
+	u32 val;
+
+	switch (num) {
+	case MTK_DPI_OUT_BIT_NUM_8BITS:
+		val = OUT_BIT_8;
+		break;
+	case MTK_DPI_OUT_BIT_NUM_10BITS:
+		val = OUT_BIT_10;
+		break;
+	case MTK_DPI_OUT_BIT_NUM_12BITS:
+		val = OUT_BIT_12;
+		break;
+	case MTK_DPI_OUT_BIT_NUM_16BITS:
+		val = OUT_BIT_16;
+		break;
+	default:
+		val = OUT_BIT_8;
+		break;
+	}
+	mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << OUT_BIT,
+		     OUT_BIT_MASK);
+}
+
+static void mtk_dpi_config_yc_map(struct mtk_dpi *dpi,
+				  enum mtk_dpi_out_yc_map map)
+{
+	u32 val;
+
+	switch (map) {
+	case MTK_DPI_OUT_YC_MAP_RGB:
+		val = YC_MAP_RGB;
+		break;
+	case MTK_DPI_OUT_YC_MAP_CYCY:
+		val = YC_MAP_CYCY;
+		break;
+	case MTK_DPI_OUT_YC_MAP_YCYC:
+		val = YC_MAP_YCYC;
+		break;
+	case MTK_DPI_OUT_YC_MAP_CY:
+		val = YC_MAP_CY;
+		break;
+	case MTK_DPI_OUT_YC_MAP_YC:
+		val = YC_MAP_YC;
+		break;
+	default:
+		val = YC_MAP_RGB;
+		break;
+	}
+
+	mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << YC_MAP, YC_MAP_MASK);
+}
+
+static void mtk_dpi_config_channel_swap(struct mtk_dpi *dpi,
+					enum mtk_dpi_out_channel_swap swap)
+{
+	u32 val;
+
+	switch (swap) {
+	case MTK_DPI_OUT_CHANNEL_SWAP_RGB:
+		val = SWAP_RGB;
+		break;
+	case MTK_DPI_OUT_CHANNEL_SWAP_GBR:
+		val = SWAP_GBR;
+		break;
+	case MTK_DPI_OUT_CHANNEL_SWAP_BRG:
+		val = SWAP_BRG;
+		break;
+	case MTK_DPI_OUT_CHANNEL_SWAP_RBG:
+		val = SWAP_RBG;
+		break;
+	case MTK_DPI_OUT_CHANNEL_SWAP_GRB:
+		val = SWAP_GRB;
+		break;
+	case MTK_DPI_OUT_CHANNEL_SWAP_BGR:
+		val = SWAP_BGR;
+		break;
+	default:
+		val = SWAP_RGB;
+		break;
+	}
+
+	mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << CH_SWAP, CH_SWAP_MASK);
+}
+
+static void mtk_dpi_config_yuv422_enable(struct mtk_dpi *dpi, bool enable)
+{
+	mtk_dpi_mask(dpi, DPI_CON, enable ? YUV422_EN : 0, YUV422_EN);
+}
+
+static void mtk_dpi_config_csc_enable(struct mtk_dpi *dpi, bool enable)
+{
+	mtk_dpi_mask(dpi, DPI_CON, enable ? CSC_ENABLE : 0, CSC_ENABLE);
+}
+
+static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable)
+{
+	mtk_dpi_mask(dpi, DPI_CON, enable ? IN_RB_SWAP : 0, IN_RB_SWAP);
+}
+
+static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi)
+{
+	mtk_dpi_mask(dpi, 0xe0, H_FRE_2N, H_FRE_2N);
+}
+
+static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi)
+{
+	mtk_dpi_mask(dpi, 0xe0, 0, EDGE_SEL_EN);
+}
+
+static void mtk_dpi_config_dual_edge(struct mtk_dpi *dpi)
+{
+	mtk_dpi_mask(dpi, DPI_DDR_SETTING, DDR_EN | DDR_4PHASE,
+		     DDR_EN | DDR_4PHASE);
+	mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, EDGE_SEL, EDGE_SEL);
+}
+
+static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
+					enum mtk_dpi_out_color_format format)
+{
+	if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_444) ||
+	    (format == MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL)) {
+		mtk_dpi_config_yuv422_enable(dpi, false);
+		mtk_dpi_config_csc_enable(dpi, true);
+		mtk_dpi_config_swap_input(dpi, false);
+		mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_BGR);
+	} else if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_422) ||
+		   (format == MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL)) {
+		mtk_dpi_config_yuv422_enable(dpi, true);
+		mtk_dpi_config_csc_enable(dpi, true);
+		mtk_dpi_config_swap_input(dpi, true);
+		mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
+	} else {
+		mtk_dpi_config_yuv422_enable(dpi, false);
+		mtk_dpi_config_csc_enable(dpi, false);
+		mtk_dpi_config_swap_input(dpi, false);
+		mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
+	}
+}
+
+static void mtk_dpi_power_off(struct mtk_dpi *dpi)
+{
+	mtk_dpi_disable(dpi);
+}
+
+static void mtk_dpi_reg_base_init(struct mtk_dpi *dpi)
+{
+	dpi->dpi_regs = DPI_BASE;
+	dpi->tvd_pll_regs = APMIXED_BASE;
+	dpi->top_ckgen_regs = TOPCKGEN_BASE;
+}
+
+static void mtk_set_dpi_clock(struct mtk_dpi *dpi)
+{
+	u32 pixel_clock = dpi->mode->pixelclock;
+	u32 div, post_div0,  top_div;
+	u32 val;
+	u32 pcw;
+
+	pixel_clock = pixel_clock / 1000;  // change to KHz to avoid u64
+
+	for (val = 0; val < 8; val++) {
+		div = 1 << (val + 1);
+		if (pixel_clock * div >= 1000000)
+			break;
+	}
+
+	if (val >= 7) {
+		post_div0 = 4;
+		top_div = 4;
+	} else if (val >= 4) {
+		post_div0 = 4;
+		top_div = val + 1 - post_div0;
+	} else {
+		top_div = 1;
+		post_div0 = val;
+	}
+
+	// pcw = (((u64)pixel_clock * div) << 14, 26000000);
+
+	pcw = (pixel_clock *  div * 1024) / 1625;
+
+	/* tvd pll con0 */
+	writel(1 | 1 << 8, dpi->tvd_pll_regs + 0x260);
+	writel(post_div0 << 24 | pcw, dpi->tvd_pll_regs + 0x264);
+	writel(1, dpi->tvd_pll_regs + 0x26c);
+	writel((readl(dpi->top_ckgen_regs + 0xa0) & 0xff00ffff) |
+	       (top_div << 16), dpi->top_ckgen_regs + 0xa0);
+	writel(1 << 26, dpi->top_ckgen_regs + 0x4);
+}
+
+static void mtk_dpi_power_on(struct mtk_dpi *dpi)
+{
+	mtk_dpi_enable(dpi);
+}
+
+static void mtk_dpi_set_display_mode(struct mtk_dpi *dpi)
+{
+	struct mtk_dpi_sync_param hsync;
+	struct mtk_dpi_sync_param vsync_lodd = { 0 };
+	struct mtk_dpi_sync_param vsync_leven = { 0 };
+	struct mtk_dpi_sync_param vsync_rodd = { 0 };
+	struct mtk_dpi_sync_param vsync_reven = { 0 };
+	struct videomode *mode;
+	u32 i, counter;
+
+	mode = dpi->mode;
+
+	hsync.sync_width = mode->hsync_len;
+	hsync.back_porch = mode->hback_porch;
+	hsync.front_porch = mode->hfront_porch;
+	hsync.shift_half_line = false;
+
+	vsync_lodd.sync_width = mode->vsync_len;
+	vsync_lodd.back_porch = mode->vback_porch;
+	vsync_lodd.front_porch = mode->vfront_porch;
+	vsync_lodd.shift_half_line = false;
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE &&
+	    mode->flags & DRM_MODE_FLAG_3D_MASK) {
+		vsync_leven = vsync_lodd;
+		vsync_rodd = vsync_lodd;
+		vsync_reven = vsync_lodd;
+		vsync_leven.shift_half_line = true;
+		vsync_reven.shift_half_line = true;
+	} else if (mode->flags & DRM_MODE_FLAG_INTERLACE &&
+		   !(mode->flags & DRM_MODE_FLAG_3D_MASK)) {
+		vsync_leven = vsync_lodd;
+		vsync_leven.shift_half_line = true;
+	} else if (!(mode->flags & DRM_MODE_FLAG_INTERLACE) &&
+		   mode->flags & DRM_MODE_FLAG_3D_MASK) {
+		vsync_rodd = vsync_lodd;
+	}
+
+	mtk_set_dpi_clock(dpi);
+	mtk_dpi_sw_reset(dpi, true);
+	mtk_dpi_config_pol(dpi, &dpi->dpi_pol);
+
+	mtk_dpi_config_hsync(dpi, &hsync);
+	mtk_dpi_config_vsync_lodd(dpi, &vsync_lodd);
+	mtk_dpi_config_vsync_rodd(dpi, &vsync_rodd);
+	mtk_dpi_config_vsync_leven(dpi, &vsync_leven);
+	mtk_dpi_config_vsync_reven(dpi, &vsync_reven);
+
+	mtk_dpi_config_3d(dpi, !!(mode->flags & DRM_MODE_FLAG_3D_MASK));
+	mtk_dpi_config_interface(dpi, !!(mode->flags &
+					 DRM_MODE_FLAG_INTERLACE));
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		mtk_dpi_config_fb_size(dpi, mode->hactive, mode->vactive / 2);
+	else
+		mtk_dpi_config_fb_size(dpi, mode->hactive, mode->vactive);
+
+	mtk_dpi_config_channel_limit(dpi, &dpi->limit);
+	mtk_dpi_config_bit_num(dpi, dpi->bit_num);
+	mtk_dpi_config_channel_swap(dpi, dpi->channel_swap);
+	mtk_dpi_config_yc_map(dpi, dpi->yc_map);
+	mtk_dpi_config_color_format(dpi, dpi->color_format);
+	mtk_dpi_config_2n_h_fre(dpi);
+	mtk_dpi_config_disable_edge(dpi);
+	mtk_dpi_config_dual_edge(dpi);
+	mtk_dpi_sw_reset(dpi, false);
+	mtk_dpi_power_on(dpi);
+	//writel(0x41, dpi->dpi_regs + 0xf00);
+
+	dprintf(CRITICAL, "bbb 0x40 = 0x%X\n", readl(dpi->dpi_regs + 0x40));
+
+	for (i = 0; i < 0x100; i = i +4)
+		dprintf(CRITICAL, "dpi_reg[0x%x] = 0x%X\n", i, readl(dpi->dpi_regs + i));
+
+	for (i = 0; i < 0x30; i = i +4)
+		dprintf(CRITICAL, "tvd_pll_reg[0x%x] = 0x%X\n", i, readl(dpi->tvd_pll_regs + 0x260 + i));
+
+	dprintf(CRITICAL, "top_ck_reg[0x4] = 0x%X\n", readl(dpi->top_ckgen_regs + 0x4));
+	dprintf(CRITICAL, "top_ck_reg[0xa0] = 0x%X\n", readl(dpi->top_ckgen_regs + 0xa0));
+}
+
+/* Config pin13 - pin28 DPI mode */
+void dpi_set_pinmode(void)
+{
+	writel( (readl(GPIO_BASE + 0x310) & 0xfffff) | 0x11100000, GPIO_BASE + 0x310);
+	writel(0x11111111, GPIO_BASE + 0x320);
+	writel( (readl(GPIO_BASE + 0x330) & 0xfffff000) | 0x11111 , GPIO_BASE + 0x330);
+}
+
+
+void mtk_dpi_init(void)
+{
+	struct mtk_dpi *dpi;
+
+	dpi = malloc(sizeof(struct mtk_dpi));
+
+	dpi->dpi_regs = DPI_BASE;
+	dpi->tvd_pll_regs = APMIXED_BASE;
+	dpi->top_ckgen_regs = TOPCKGEN_BASE;
+	dpi->mode = &hd720p60;
+	dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
+	dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
+	dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS;
+	dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB;
+	dpi->limit.c_bottom = 0x0010;
+	dpi->limit.c_top = 0x0FE0;
+	dpi->limit.y_bottom = 0x0010;
+	dpi->limit.y_top = 0x0FE0;
+	dpi->dpi_pol.ck_pol = MTK_DPI_POLARITY_FALLING;
+	dpi->dpi_pol.de_pol = MTK_DPI_POLARITY_RISING;
+	dpi->dpi_pol.hsync_pol = dpi->mode->flags & DRM_MODE_FLAG_PHSYNC ?
+			    MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
+	dpi->dpi_pol.vsync_pol = dpi->mode->flags & DRM_MODE_FLAG_PVSYNC ?
+			    MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
+
+	mtk_dpi_set_display_mode(dpi);
+	dpi_set_pinmode();
+	free(dpi);
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/display/dsi.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/dsi.c
new file mode 100644
index 0000000..0873c67
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/dsi.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <assert.h>
+#include <platform/mm_common.h>
+#include <platform/mtk_timer.h>
+#include <platform/dsi.h>
+#include <platform/ddp_debug.h>
+
+void mtk_dsi_configure_mipi_tx(int data_rate, u32 lanes)
+{
+	unsigned int txdiv0, txdiv1;
+	u64 pcw;
+
+	if (data_rate >= 2000) {
+		txdiv0 = 0;
+		txdiv1 = 0;
+	} else if (data_rate >= 1000) {
+		txdiv0 = 1;
+		txdiv1 = 0;
+	} else if (data_rate >= 500) {
+		txdiv0 = 2;
+		txdiv1 = 0;
+	} else if (data_rate > 250) {
+		/* (data_rate == 250MHz) is a special case that should go to the
+		   else-block below (txdiv0 = 4) */
+		txdiv0 = 3;
+		txdiv1 = 0;
+	} else {
+		/* MIN = 125 */
+		assert(data_rate >= MTK_DSI_DATA_RATE_MIN_MHZ);
+		txdiv0 = 4;
+		txdiv1 = 0;
+	}
+
+	clrbits_le32(&mipi_tx->pll_con4, BIT(11) | BIT(10));
+	setbits_le32(&mipi_tx->pll_pwr, AD_DSI_PLL_SDM_PWR_ON);
+	udelay(30);
+	clrbits_le32(&mipi_tx->pll_pwr, AD_DSI_PLL_SDM_ISO_EN);
+
+	pcw = (u64)data_rate * (1 << txdiv0) * (1 << txdiv1);
+	pcw <<= 24;
+	pcw /= 26;
+
+	write32(&mipi_tx->pll_con0, pcw);
+	clrsetbits_le32(&mipi_tx->pll_con1, RG_DSI_PLL_POSDIV, txdiv0 << 8);
+	udelay(30);
+	setbits_le32(&mipi_tx->pll_con1, RG_DSI_PLL_EN);
+
+	/* BG_LPF_EN / BG_CORE_EN */
+	write32(&mipi_tx->lane_con, 0x3fff0180);
+	udelay(40);
+	write32(&mipi_tx->lane_con, 0x3fff00c0);
+
+	/* Switch OFF each Lane */
+	clrbits_le32(&mipi_tx->d0_sw_ctl_en, DSI_SW_CTL_EN);
+	clrbits_le32(&mipi_tx->d1_sw_ctl_en, DSI_SW_CTL_EN);
+	clrbits_le32(&mipi_tx->d2_sw_ctl_en, DSI_SW_CTL_EN);
+	clrbits_le32(&mipi_tx->d3_sw_ctl_en, DSI_SW_CTL_EN);
+	clrbits_le32(&mipi_tx->ck_sw_ctl_en, DSI_SW_CTL_EN);
+
+	setbits_le32(&mipi_tx->ck_ckmode_en, DSI_CK_CKMODE_EN);
+}
+
+void mtk_dsi_reset(void)
+{
+
+	ddp_func();
+
+	write32(&dsi0->dsi_force_commit, 
+		DSI_FORCE_COMMIT_USE_MMSYS | DSI_FORCE_COMMIT_ALWAYS);
+	write32(&dsi0->dsi_con_ctrl, 1);
+	write32(&dsi0->dsi_con_ctrl, 0);
+}
+
+void mtk_dsi_override_phy_timing(struct mtk_phy_timing *timing)
+{
+	/* Do nothing */
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/display/dsi_common.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/dsi_common.c
new file mode 100644
index 0000000..23b50c5
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/dsi_common.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <assert.h>
+#include <platform/mm_common.h>
+#include <platform/mtk_timer.h>
+#include <platform/dsi.h>
+#include <platform/dsi_common.h>
+#include <string.h>
+#include <platform/ddp_debug.h>
+
+static unsigned int mtk_dsi_get_bits_per_pixel(u32 format)
+{
+	switch (format) {
+	case MIPI_DSI_FMT_RGB565:
+		return 16;
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		return 18;
+	case MIPI_DSI_FMT_RGB666:
+	case MIPI_DSI_FMT_RGB888:
+		return 24;
+	}
+	dprintf(CRITICAL, "%s: WARN: Unknown format %d, assuming 24 bpp\n",
+	       __func__, format);
+	return 24;
+}
+
+static int mtk_dsi_get_data_rate(u32 bits_per_pixel, u32 lanes,
+				 struct videomode *vm)
+{
+	/* data_rate = pixel_clock * bits_per_pixel * mipi_ratio / lanes
+	 * Note pixel_clock comes in kHz and returned data_rate is in Mbps.
+	 * mipi_ratio is the clk coefficient to balance the pixel clk in MIPI
+	 * for older platforms which do not have complete implementation in HFP.
+	 * Newer platforms should just set that to 1.0 (100 / 100).
+	 */
+	int data_rate = vm->pixelclock * bits_per_pixel *
+			MTK_DSI_MIPI_RATIO_NUMERATOR /
+			(1000 * lanes * MTK_DSI_MIPI_RATIO_DENOMINATOR);
+	dprintf(CRITICAL, "DSI data_rate: %d Mbps\n", data_rate);
+
+	if (data_rate < MTK_DSI_DATA_RATE_MIN_MHZ) {
+		dprintf(CRITICAL, "data rate (%dMbps) must be >=%dMbps. "
+		       "Please check the pixel clock (%u), bits per pixel(%u), "
+		       "mipi_ratio (%d%%) and number of lanes (%d)\n",
+		       data_rate, MTK_DSI_DATA_RATE_MIN_MHZ,
+		       vm->pixelclock, bits_per_pixel,
+		       (100 * MTK_DSI_MIPI_RATIO_NUMERATOR /
+			MTK_DSI_MIPI_RATIO_DENOMINATOR), lanes);
+		return -1;
+	}
+	return data_rate;
+}
+
+static void mtk_dsi_phy_timing(int data_rate, struct mtk_phy_timing *phy_timing)
+{
+	u32 cycle_time, ui;
+
+	ddp_func();
+
+	memset(phy_timing, 0, sizeof(*phy_timing));
+
+	phy_timing->lpx = (60 * data_rate / (8 * 1000)) + 1;
+	phy_timing->da_hs_prepare = (80 * data_rate + 4 * 1000) / 8000;
+	phy_timing->da_hs_zero = (170 * data_rate + 10 * 1000) / 8000 + 1 -
+			     phy_timing->da_hs_prepare;
+	phy_timing->da_hs_trail = phy_timing->da_hs_prepare + 1;
+
+	phy_timing->ta_go = 4 * phy_timing->lpx - 2;
+	phy_timing->ta_sure = phy_timing->lpx + 2;
+	phy_timing->ta_get = 4 * phy_timing->lpx;
+	phy_timing->da_hs_exit = 2 * phy_timing->lpx + 1;
+
+	phy_timing->da_hs_sync = 1;
+
+	phy_timing->clk_hs_prepare = 70 * data_rate / (8 * 1000);
+	phy_timing->clk_hs_post = phy_timing->clk_hs_prepare + 8;
+	phy_timing->clk_hs_trail = phy_timing->clk_hs_prepare;
+	phy_timing->clk_hs_zero = phy_timing->clk_hs_trail * 4;
+	phy_timing->clk_hs_exit = 2 * phy_timing->clk_hs_trail;
+
+	/* Allow board-specific tuning. */
+	mtk_dsi_override_phy_timing(phy_timing);
+
+	u32 timcon0, timcon1, timcon2, timcon3;
+
+	timcon0 = phy_timing->lpx | phy_timing->da_hs_prepare << 8 |
+		  phy_timing->da_hs_zero << 16 | phy_timing->da_hs_trail << 24;
+	timcon1 = phy_timing->ta_go | phy_timing->ta_sure << 8 |
+		  phy_timing->ta_get << 16 | phy_timing->da_hs_exit << 24;
+	timcon2 = phy_timing->da_hs_sync << 8 | phy_timing->clk_hs_zero << 16 |
+		  phy_timing->clk_hs_trail << 24;
+	timcon3 = phy_timing->clk_hs_prepare | phy_timing->clk_hs_post << 8 |
+		  phy_timing->clk_hs_exit << 16;
+
+	write32(&dsi0->dsi_phy_timecon0, timcon0);
+	write32(&dsi0->dsi_phy_timecon1, timcon1);
+	write32(&dsi0->dsi_phy_timecon2, timcon2);
+	write32(&dsi0->dsi_phy_timecon3, timcon3);
+}
+
+static void mtk_dsi_clk_hs_mode_enable(void)
+{
+	setbits_le32(&dsi0->dsi_phy_lccon, LC_HS_TX_EN);
+}
+
+static void mtk_dsi_clk_hs_mode_disable(void)
+{
+	clrbits_le32(&dsi0->dsi_phy_lccon, LC_HS_TX_EN);
+}
+
+static void mtk_dsi_set_mode(u32 mode_flags)
+{
+	u32 tmp_reg1 = 0;
+
+	if (mode_flags & MIPI_DSI_MODE_VIDEO) {
+		tmp_reg1 = SYNC_PULSE_MODE;
+
+		if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+			tmp_reg1 = BURST_MODE;
+
+		if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+			tmp_reg1 = SYNC_PULSE_MODE;
+	}
+
+	write32(&dsi0->dsi_mode_ctrl, tmp_reg1);
+}
+
+static void mtk_dsi_rxtx_control(u32 mode_flags, u32 lanes)
+{
+	u32 tmp_reg = 0;
+
+	switch (lanes) {
+	case 1:
+		tmp_reg = 1 << 2;
+		break;
+	case 2:
+		tmp_reg = 3 << 2;
+		break;
+	case 3:
+		tmp_reg = 7 << 2;
+		break;
+	case 4:
+	default:
+		tmp_reg = 0xf << 2;
+		break;
+	}
+
+	tmp_reg |= (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) << 6;
+	tmp_reg |= (mode_flags & MIPI_DSI_MODE_EOT_PACKET) >> 3;
+
+	write32(&dsi0->dsi_txrx_ctrl, tmp_reg);
+}
+
+static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format, u32 lanes,
+				      struct videomode *vm,
+				      const struct mtk_phy_timing *phy_timing)
+{
+	u32 hsync_active_byte;
+	u32 hbp_byte;
+	u32 hfp_byte;
+	u32 bytes_per_pixel;
+	u32 packet_fmt;
+	u32 hactive;
+	u32 data_phy_cycles;
+
+	ddp_func();
+
+	bytes_per_pixel = DIV_ROUND_UP(mtk_dsi_get_bits_per_pixel(format), 8);
+
+	write32(&dsi0->dsi_vsa_nl, vm->vsync_len);
+	write32(&dsi0->dsi_vbp_nl, vm->vback_porch);
+	write32(&dsi0->dsi_vfp_nl, vm->vfront_porch);
+	write32(&dsi0->dsi_vact_nl, vm->vactive);
+
+	unsigned int hspw = 0;
+	if ((mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0)
+		hspw = vm->hsync_len;
+
+	hbp_byte = (vm->hback_porch + hspw) * bytes_per_pixel - 10;
+	hsync_active_byte = vm->hsync_len * bytes_per_pixel - 10;
+	hfp_byte = vm->hfront_porch * bytes_per_pixel;
+
+	data_phy_cycles = phy_timing->lpx + phy_timing->da_hs_prepare +
+		phy_timing->da_hs_zero + phy_timing->da_hs_exit + 3;
+
+	u32 delta = 12;
+	if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+		delta += 6;
+
+	u32 d_phy = phy_timing->d_phy;
+	if (d_phy == 0)
+		d_phy = data_phy_cycles * lanes + delta;
+
+	if ((vm->hfront_porch + vm->hback_porch) * bytes_per_pixel > d_phy) {
+		hfp_byte -= d_phy * vm->hfront_porch / (vm->hfront_porch + vm->hback_porch);
+		hbp_byte -= d_phy * vm->hback_porch / (vm->hfront_porch + vm->hback_porch);
+	} else {
+
+		dprintf(CRITICAL, "HFP + HBP is not greater than d-phy, FPS < 60Hz "
+		       "and the panel may not work properly.\n");
+	}
+
+	write32(&dsi0->dsi_hsa_wc, hsync_active_byte);
+	write32(&dsi0->dsi_hbp_wc, hbp_byte);
+	write32(&dsi0->dsi_hfp_wc, hfp_byte);
+
+	switch (format) {
+	case MIPI_DSI_FMT_RGB888:
+		packet_fmt = PACKED_PS_24BIT_RGB888;
+		break;
+	case MIPI_DSI_FMT_RGB666:
+		packet_fmt = LOOSELY_PS_18BIT_RGB666;
+		break;
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		packet_fmt = PACKED_PS_18BIT_RGB666;
+		break;
+	case MIPI_DSI_FMT_RGB565:
+		packet_fmt = PACKED_PS_16BIT_RGB565;
+		break;
+	default:
+		packet_fmt = PACKED_PS_24BIT_RGB888;
+		break;
+	}
+
+	hactive = vm->hactive;
+	packet_fmt |= (hactive * bytes_per_pixel) & DSI_PS_WC;
+
+	write32(&dsi0->dsi_psctrl,
+		PIXEL_STREAM_CUSTOM_HEADER << DSI_PSCON_CUSTOM_HEADER_SHIFT |
+		packet_fmt);
+
+	/* Older systems like MT8173 do not support size_con. */
+	if (MTK_DSI_HAVE_SIZE_CON)
+		write32(&dsi0->dsi_size_con,
+			vm->vactive << DSI_SIZE_CON_HEIGHT_SHIFT |
+			hactive << DSI_SIZE_CON_WIDTH_SHIFT);
+}
+
+static void mtk_dsi_start(void)
+{
+	write32(&dsi0->dsi_start, 0);
+	/* Only start master DSI */
+	write32(&dsi0->dsi_start, 1);
+}
+
+static bool mtk_dsi_is_read_command(u32 type)
+{
+	switch (type) {
+	case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
+	case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
+	case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
+	case MIPI_DSI_DCS_READ:
+		return true;
+	}
+	return false;
+}
+
+static void mtk_dsi_cmdq(const u8 *data, u8 len, u32 type)
+{
+	const u8 *tx_buf = data;
+	u32 config;
+	int i = 0, j;
+
+	while (read32(&dsi0->dsi_intsta) & DSI_BUSY) {
+		if (i > 10) {
+			dprintf(CRITICAL, "%s: cannot get DSI ready for sending commands"
+			       " after 20ms and the panel may not work properly.\n",
+			       __func__);
+			return;
+		}
+		i++;
+		mdelay(2);
+	}
+
+	write32(&dsi0->dsi_intsta, 0);
+
+	if (mtk_dsi_is_read_command(type))
+		config = BTA;
+	else
+		config = (len > 2) ? LONG_PACKET : SHORT_PACKET;
+
+	if (len <= 2) {
+		uint32_t val = (type << 8) | config;
+		for (i = 0; i < len; i++)
+			val |= tx_buf[i] << (i + 2) * 8;
+		write32(&dsi0->dsi_cmdq[0], val);
+		write32(&dsi0->dsi_cmdq_size, 1);
+	} else {
+		/* TODO(hungte) Replace by buffer_to_fifo32_prefix */
+		write32(&dsi0->dsi_cmdq[0], (len << 16) | (type << 8) | config);
+		for (i = 0; i < len; i += 4) {
+			uint32_t val = 0;
+			for (j = 0; j < ((len - i) < 4 ? (len - i) : 4); j++)
+				val |= tx_buf[i + j] << j * 8;
+			write32(&dsi0->dsi_cmdq[i / 4 + 1], val);
+		}
+		write32(&dsi0->dsi_cmdq_size, 1 + DIV_ROUND_UP(len, 4));
+	}
+
+	mtk_dsi_start();
+
+	mdelay(2);
+
+	if ((read32(&dsi0->dsi_intsta) & CMD_DONE_INT_FLAG) == 0)
+		dprintf(CRITICAL, "%s: failed sending DSI command, "
+		       "panel may not work.\n", __func__);
+}
+
+static void mtk_dsi_send_init_commands(const u8 *buf)
+{
+	if (!buf)
+		return;
+	const struct lcm_init_command *init = (const void *)buf;
+
+	ddp_func();
+
+	/*
+	 * The given commands should be in a buffer containing a packed array of
+	 * lcm_init_command and each element may be in variable size so we have
+	 * to parse and scan.
+	 */
+
+	for (; init->cmd != LCM_END_CMD; init = (const void *)buf) {
+		/*
+		 * For some commands like DELAY, the init->len should not be
+		 * counted for buf.
+		 */
+		buf += sizeof(*init);
+
+		u32 cmd = init->cmd, len = init->len;
+		u32 type;
+
+		switch (cmd) {
+		case LCM_DELAY_CMD:
+			mdelay(len);
+			continue;
+
+		case LCM_DCS_CMD:
+			switch (len) {
+			case 0:
+				return;
+			case 1:
+				type = MIPI_DSI_DCS_SHORT_WRITE;
+				break;
+			case 2:
+				type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
+				break;
+			default:
+				type = MIPI_DSI_DCS_LONG_WRITE;
+				break;
+			}
+			break;
+
+		case LCM_GENERIC_CMD:
+			switch (len) {
+			case 0:
+				type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM;
+				break;
+			case 1:
+				type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM;
+				break;
+			case 2:
+				type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM;
+				break;
+			default:
+				type = MIPI_DSI_GENERIC_LONG_WRITE;
+				break;
+			}
+			break;
+
+		default:
+			dprintf(CRITICAL, "%s: Unknown cmd: %d, "
+			       "abort panel initialization.\n", __func__, cmd);
+			return;
+
+		}
+
+		buf += len;
+		mtk_dsi_cmdq(init->data, len, type);
+	}
+}
+
+static void mtk_dsi_reset_dphy(void)
+{
+	setbits_le32(&dsi0->dsi_con_ctrl, DPHY_RESET);
+	clrbits_le32(&dsi0->dsi_con_ctrl, DPHY_RESET);
+}
+
+int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, struct videomode *vm,
+		 const u8 *init_commands)
+{
+	int data_rate;
+	u32 bits_per_pixel = mtk_dsi_get_bits_per_pixel(format);
+	struct mtk_phy_timing phy_timing;
+
+	ddp_func();
+
+	data_rate = mtk_dsi_get_data_rate(bits_per_pixel, lanes, vm);
+	if (data_rate < 0)
+		return -1;
+
+	mtk_dsi_configure_mipi_tx(data_rate, lanes);
+
+	mtk_dsi_reset();
+	mtk_dsi_set_mode(0);
+	
+	mtk_dsi_phy_timing(data_rate, &phy_timing);
+	mtk_dsi_rxtx_control(mode_flags, lanes);
+	mdelay(1);
+	mtk_dsi_reset_dphy();
+	mtk_dsi_clk_hs_mode_disable();
+	mtk_dsi_config_vdo_timing(mode_flags, format, lanes, vm, &phy_timing);
+	mtk_dsi_clk_hs_mode_enable();
+	mtk_dsi_send_init_commands(init_commands);
+	mtk_dsi_set_mode(mode_flags);
+	mtk_dsi_start();
+	return 0;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/display/mt_bmpio.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/mt_bmpio.c
new file mode 100644
index 0000000..b940da0
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/mt_bmpio.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <debug.h>
+#include <string.h>
+#include <platform/ddp_debug.h>
+
+
+typedef short		WORD;
+typedef int		DWORD;
+typedef int		LONG;
+
+#pragma pack(2)
+typedef struct tagBITMAPFILEHEADER {
+	WORD	bfType;
+	DWORD	bfSize;
+	WORD	bfReserved1;
+	WORD	bfReserved2;
+	DWORD	bfOffBits;
+} BITMAPFILEHEADER;
+#pragma pack()
+
+#pragma pack(2)
+typedef struct tagBITMAPINFOHEADER{
+	DWORD	biSize;
+	LONG	biWidth;
+	LONG	biHeight;
+	WORD	biPlanes;
+	WORD	biBitCount;
+	DWORD	biCompression;
+	DWORD	biSizeImage;
+	DWORD	biClrUsed;
+	DWORD	bfReserved1;
+	DWORD	biClrImportant;
+	DWORD	bfReserved2;
+} BITMAPINFOHEADER;
+#pragma pack()
+
+#define BMP_FILE_HEADER_SIZE (sizeof(BITMAPFILEHEADER))
+#define BMP_INFO_HEADER_SIZE (sizeof(BITMAPINFOHEADER))
+
+void dump_bmp_file_header(BITMAPFILEHEADER *bitmapfileheader)
+{
+	ddp_log("bitmapfileheader:\n");
+	ddp_log("bfType %c%c\n", (bitmapfileheader->bfType>>8), bitmapfileheader->bfType);
+	ddp_log("bfSize %d\n", bitmapfileheader->bfSize);
+	ddp_log("bfReserved1 %d\n", bitmapfileheader->bfReserved1);
+	ddp_log("bfReserved2 %d\n", bitmapfileheader->bfReserved2);
+	ddp_log("bfOffBits %d\n", bitmapfileheader->bfOffBits);
+}
+
+void dump_bmp_info_header(BITMAPINFOHEADER *bitmapinfoheader)
+{
+	ddp_log("bitmapinfoheader:\n");
+
+	ddp_log("sizeof WORD %lu:\n", sizeof(WORD));
+	ddp_log("sizeof DWORD %lu:\n", sizeof(DWORD));
+	ddp_log("sizeof LONG %lu:\n", sizeof(LONG));
+
+	ddp_log("biSize %d\n", bitmapinfoheader->biSize);
+	ddp_log("biWidth %d\n", bitmapinfoheader->biWidth);
+	ddp_log("biHeight %d\n", bitmapinfoheader->biHeight);
+	ddp_log("biPlanes %d\n", bitmapinfoheader->biPlanes);
+	ddp_log("biBitCount %d\n", bitmapinfoheader->biBitCount);
+	ddp_log("biCompression %d\n", bitmapinfoheader->biCompression);
+
+	ddp_log("biSizeImage %d\n", bitmapinfoheader->biSizeImage);
+	ddp_log("biClrUsed %d\n", bitmapinfoheader->biClrUsed);
+	ddp_log("bfReserved1 %d\n", bitmapinfoheader->bfReserved1);
+
+	ddp_log("biClrImportant %d\n", bitmapinfoheader->biClrImportant);
+	ddp_log("bfReserved2 %d\n", bitmapinfoheader->bfReserved2);
+}
+
+u32 mt_read_bmp_header(u8 *bmp_file_buf,
+		       u32 *PicWidth,
+		       u32 *PicHeight)
+{
+	BITMAPFILEHEADER bitmapfileheader;
+	BITMAPINFOHEADER bitmapinfoheader;
+
+	u32 file_size;
+
+	memcpy(&bitmapfileheader, bmp_file_buf, sizeof(bitmapfileheader));
+	memcpy(&bitmapinfoheader, bmp_file_buf + sizeof(bitmapfileheader), sizeof(bitmapinfoheader));
+
+	*PicWidth = bitmapinfoheader.biWidth;
+	*PicHeight = bitmapinfoheader.biHeight;
+
+	file_size = BMP_FILE_HEADER_SIZE + BMP_INFO_HEADER_SIZE + (*PicWidth * *PicHeight) * 3;
+
+	return file_size;
+}
+
+int mt_read_bmp(u8 *bmp_file_buf,
+		u8 *data_buff,
+		u32 *PicWidth,
+		u32 *PicHeight)
+{
+	BITMAPFILEHEADER bitmapfileheader;
+	BITMAPINFOHEADER bitmapinfoheader;
+
+	u8 *tmp_buf;
+
+	u32 x = 0, y = 0;
+	u32 appendCnt;
+	u32 tmp;
+	u32 width;
+	u32 height;
+
+	int tmp0;
+	int tmp1;
+	int tmp2;
+
+	memcpy(&bitmapfileheader,bmp_file_buf, sizeof(bitmapfileheader));
+	memcpy(&bitmapinfoheader,bmp_file_buf + sizeof(bitmapfileheader), sizeof(bitmapinfoheader));
+
+#if 0
+	dump_bmp_file_header(&bitmapfileheader);
+	dump_bmp_info_header(&bitmapinfoheader);
+#endif
+
+	tmp_buf = bmp_file_buf + sizeof(bitmapfileheader) + sizeof(bitmapinfoheader);
+
+	*PicWidth = bitmapinfoheader.biWidth;
+	*PicHeight = bitmapinfoheader.biHeight;
+
+	width = *PicWidth;
+	height = *PicHeight;
+
+	ddp_log("pic size %u x %u\n", *PicWidth, *PicHeight);
+
+	if ((*PicWidth > 1920) || (*PicHeight > 1920)) {
+		dprintf(CRITICAL, "invalid pic size %u x %u\n", *PicWidth, *PicHeight);
+		return 0;
+	}
+
+	for(y = 0; y < height; y++) {
+		for(x = 0; x < width; x++) {
+			data_buff[((height - 1 - y) * width + x) * 3 + 0] = tmp0 = tmp_buf[(y * width + x) * 3 + 0];
+			data_buff[((height - 1 - y) * width + x) * 3 + 1] = tmp1 = tmp_buf[(y * width + x) * 3 + 1];
+			data_buff[((height - 1 - y) * width + x) * 3 + 2] = tmp2 = tmp_buf[(y * width + x) * 3 + 2];
+		}
+
+		// One line should align with 16byte
+		if(((width * 3) % 4) != 0) {
+			appendCnt = 4 - ((width * 3) % 4);
+			for(x = 0; x < appendCnt; x++) {
+				tmp = 0; /* to do */
+				ddp_log("%c ", tmp);
+			}
+			ddp_log("%s aglin .\n", __func__);
+		}
+	}
+
+	ddp_log("read end x %d y %d\n", x, y);
+
+	return 0;
+}
+
+
+
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/display/mt_disp.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/mt_disp.c
new file mode 100644
index 0000000..15d6976
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/mt_disp.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <arch/ops.h>
+#include <debug.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <platform/disp.h>
+#include <lib/bio.h>
+#include <lk/init.h>
+#include <platform/mtk_timer.h>
+
+#include <platform/ddp.h>
+#include <platform/ddp_debug.h>
+#if !HDMI_MAIN_PATH
+#include <platform/panel.h>
+#endif
+/*
+* logo size example, 1280x720*3 + bmp header = 2.7M
+*/
+#define LOGO_PHY_ADDR		0x45000000
+
+#if WITH_KERNEL_VM
+/* refer src\bsp\lk\target\aiv8167m3v4-emmc512-test\rules.mk*/
+/* dram virtual addr 0xffff00000d600000 */
+/* dram physical addr 0x40000000 */
+/* logo dram physical addr 0x5d900000 defined in dts file */
+#define DRAM_VIRT_ADDR		0xfffffff040000000
+#define DRAM_PHY_ADDR		0x40000000
+#define LOGO_ADDR (DRAM_VIRT_ADDR + (LOGO_PHY_ADDR - DRAM_PHY_ADDR))
+#else
+#define LOGO_ADDR LOGO_PHY_ADDR
+#endif
+
+#define BMP_FILE_HEADER_SIZE 14
+#define BMP_INFO_HEADER_SIZE 40
+#define LOGO_HEADER_SIZE (BMP_FILE_HEADER_SIZE + BMP_INFO_HEADER_SIZE)
+
+extern int mt_read_bmp(u8 *bmp_file_buf,
+		u8 *data_buff,
+		u32 *PicWidth,
+		u32 *PicHeight);
+
+extern u32 mt_read_bmp_header(u8 *bmp_file_buf,
+			u32 *PicWidth,
+			u32 *PicHeight);
+
+#if HDMI_MAIN_PATH
+extern void mtk_dpi_init(void);
+extern void it6621_main();
+#endif
+
+void dump_logo_data(u32 *logo_data, u32 start, u32 end)
+{
+	u32 idx = 0;
+
+	for (idx = start; idx < end; idx++) {
+		if (idx % 4 == 0)
+			dprintf(CRITICAL, "%slogo[%08X] ", idx?"\n":"", idx*4);
+		dprintf(CRITICAL, "%08X ", logo_data[idx]);
+	}
+	dprintf(CRITICAL, "\n");
+}
+
+int mt_disp_read_logo_data(u32 *logo_phy_addr, u32 *logo_width, u32 *logo_height)
+{
+	u8 *logo_file_buf;
+	u8 *logo_data_buf;
+	u32 logo_file_size;
+	u32 logo_data_size;
+	struct bdev *nand_logo;
+	u32 len = 0;
+
+	nand_logo = bio_open_by_label("logo");
+	if (!nand_logo) {
+		dprintf(CRITICAL, "%s logo open fail\n", __func__);
+		return -1;
+	}
+
+	ddp_log(
+	"BASE_VIRT %p WITH_KERNEL_VM %d IO_PHYS %p nand_logo %p\n",
+	(void *)PERIPHERAL_BASE_VIRT,
+	WITH_KERNEL_VM,
+	(void *)IO_PHYS,
+	nand_logo);
+
+	logo_file_buf = (unsigned char *)LOGO_ADDR;
+
+	len = bio_read(nand_logo, (void *)logo_file_buf, 0, LOGO_HEADER_SIZE);
+	if (len == 0) {
+		dprintf(CRITICAL, "read error. LINE: %d\n", __LINE__);
+		return -1;
+	}
+	ddp_log("bio_read len %d\n", len);
+
+	mt_read_bmp_header(logo_file_buf, logo_width, logo_height);
+
+	logo_data_size = (*logo_width) * (*logo_height) * 3;
+	logo_file_size = align_to((logo_data_size + LOGO_HEADER_SIZE), BUF_ALIGN_SIZE);
+	logo_data_buf = (unsigned char *)(LOGO_ADDR + logo_file_size);
+	*logo_phy_addr = LOGO_PHY_ADDR + logo_file_size;
+
+	ddp_log("logo_file_buf %p logo_data_buf %p (0x%X) logo_file_size %d\n",
+	logo_file_buf, logo_data_buf, *logo_phy_addr, logo_file_size);
+
+	len = bio_read(nand_logo, (void *)(logo_file_buf + LOGO_HEADER_SIZE), 0, (logo_file_size - LOGO_HEADER_SIZE));
+	if (len == 0) {
+		dprintf(CRITICAL, "read error. LINE: %d\n", __LINE__);
+		return -1;
+	}
+	ddp_log("bio_read len %d\n", len);
+
+	mt_read_bmp(logo_file_buf, logo_data_buf, logo_width, logo_height);
+
+	arch_clean_cache_range((addr_t)logo_data_buf, logo_data_size);
+
+	bio_close(nand_logo);
+
+	return 0;
+}
+
+static void mt_disp_init(uint level)
+{
+	u32 logo_phy_addr;
+	u32 logo_width;
+	u32 logo_height;
+	int ret;
+#if !HDMI_MAIN_PATH
+	struct panel_description *panel_desc;
+#endif
+	dprintf(CRITICAL, "%s level 0x%X\n", __func__, level);
+
+	ret = mt_disp_read_logo_data(&logo_phy_addr, &logo_width, &logo_height);
+	if (ret < 0) {
+		dprintf(CRITICAL, "%s read logo data fail\n", __func__);
+		//return -1;
+	}
+
+	mtk_ddp_init();
+
+#if HDMI_MAIN_PATH
+	mtk_dpi_init();
+	it6621_main();
+#else
+	panel_desc = panel_get_desc();
+	if (!panel_desc) {
+		dprintf(CRITICAL, "%s get panel info fail\n", __func__);
+		return;
+	}
+
+	panel_desc->power_on();
+	mtk_dsi_init(panel_desc->s->dsi->flag, panel_desc->s->dsi->format, panel_desc->s->dsi->lanes, &panel_desc->s->vm, panel_desc->s->init);
+#endif
+	mtk_ddp_mode_set(logo_width, logo_height, logo_phy_addr);
+
+#if !HDMI_MAIN_PATH
+	panel_desc->backlight_enable();
+#endif
+
+	return;
+}
+
+LK_INIT_HOOK(mt_disp_init, &mt_disp_init, LK_INIT_LEVEL_APPS - 1);
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/display/panel_tpv_ph060pb16a.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/panel_tpv_ph060pb16a.c
new file mode 100644
index 0000000..fdad00c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/display/panel_tpv_ph060pb16a.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include "platform/panel.h"
+#include <platform/mtk_timer.h>
+#include "platform/mt_reg_base.h"
+#include "../../include/platform/mt6358.h"
+#include "../../include/platform/regulator_core.h"
+
+struct dsi_info dsi = {
+	.lanes = 4,
+	.flag = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
+	.format = MIPI_DSI_FMT_RGB888,
+};
+
+struct panel_serializable_data TPV_PH060PB16A = {
+	.vm = {
+		.pixelclock = 135930,/* pixelclock in KHz */
+
+		.hactive = 1080,
+		.hfront_porch = 40,
+		.hback_porch = 20,
+		.hsync_len = 10,
+
+		.vactive = 1920,
+		.vfront_porch = 40,
+		.vback_porch = 8,
+		.vsync_len = 2,
+
+		.vrefresh = 60,
+	},
+	.init = {
+		INIT_DCS_CMD(0x00, 0x00),
+		INIT_DCS_CMD(0xFF, 0x19, 0x01, 0x01, 0x00),
+		INIT_DCS_CMD(0x00, 0x80),
+		INIT_DCS_CMD(0xFF, 0x19, 0x01),
+		INIT_DCS_CMD(0x00, 0x00),
+		INIT_DCS_CMD(0x1C, 0x33),
+		INIT_DCS_CMD(0x00, 0xA0),
+		INIT_DCS_CMD(0xC1, 0xE8),
+		INIT_DCS_CMD(0x00, 0xA7),
+		INIT_DCS_CMD(0xC1, 0x00),
+		INIT_DCS_CMD(0x00, 0x90),
+		INIT_DCS_CMD(0xC0, 0x00, 0x2F, 0x00, 0x00,
+					   0x00, 0x01),
+		INIT_DCS_CMD(0x00, 0xC0),
+		INIT_DCS_CMD(0xC0, 0x00, 0x2F, 0x00, 0x00,
+					   0x00, 0x01),
+		INIT_DCS_CMD(0x00, 0x9A),
+		INIT_DCS_CMD(0xC0, 0x1E),
+		INIT_DCS_CMD(0x00, 0xAC),
+		INIT_DCS_CMD(0xC0, 0x06),
+		INIT_DCS_CMD(0x00, 0xDC),
+		INIT_DCS_CMD(0xC0, 0x06),
+		INIT_DCS_CMD(0x00, 0x81),
+		INIT_DCS_CMD(0xA5, 0x06),
+		INIT_DCS_CMD(0x00, 0x82),
+		INIT_DCS_CMD(0xC4, 0xF0),
+		INIT_DCS_CMD(0x00, 0x92),
+		INIT_DCS_CMD(0xE9, 0x00),
+		INIT_DCS_CMD(0x00, 0x90),
+		INIT_DCS_CMD(0xF3, 0x01),
+		INIT_DCS_CMD(0x00, 0x82),
+		INIT_DCS_CMD(0xA5, 0x1F),
+		INIT_DCS_CMD(0x00, 0x93),
+		INIT_DCS_CMD(0xC5, 0x19),
+		INIT_DCS_CMD(0x00, 0x95),
+		INIT_DCS_CMD(0xC5, 0x28),
+		INIT_DCS_CMD(0x00, 0x97),
+		INIT_DCS_CMD(0xC5, 0x18),
+		INIT_DCS_CMD(0x00, 0x99),
+		INIT_DCS_CMD(0xC5, 0x23),
+		INIT_DCS_CMD(0x00, 0x9B),
+		INIT_DCS_CMD(0xC5, 0x44, 0x40),
+		INIT_DCS_CMD(0x00, 0x00),
+		INIT_DCS_CMD(0xD9, 0x00, 0xBA),
+		INIT_DCS_CMD(0x00, 0x00),
+		INIT_DCS_CMD(0xD8, 0x1B, 0x1B),
+		INIT_DCS_CMD(0x00, 0xB3),
+		INIT_DCS_CMD(0xC0, 0xCC),
+		INIT_DCS_CMD(0x00, 0xBC),
+		INIT_DCS_CMD(0xC0, 0x00),
+		INIT_DCS_CMD(0x00, 0x84),
+		INIT_DCS_CMD(0xC4, 0x22),
+		INIT_DCS_CMD(0x00, 0x94),
+		INIT_DCS_CMD(0xC1, 0x84),
+		INIT_DCS_CMD(0x00, 0x98),
+		INIT_DCS_CMD(0xC1, 0x74),
+		INIT_DCS_CMD(0x00, 0x80),
+		INIT_DCS_CMD(0xC4, 0x38),
+		INIT_DCS_CMD(0x00, 0xCD),
+		INIT_DCS_CMD(0xF5, 0x19),
+		INIT_DCS_CMD(0x00, 0xDB),
+		INIT_DCS_CMD(0xF5, 0x19),
+		INIT_DCS_CMD(0x00, 0xF5),
+		INIT_DCS_CMD(0xC1, 0x40),
+		INIT_DCS_CMD(0x00, 0xB9),
+		INIT_DCS_CMD(0xC0, 0x11),
+		INIT_DCS_CMD(0x00, 0x8D),
+		INIT_DCS_CMD(0xF5, 0x20),
+		INIT_DCS_CMD(0x00, 0x80),
+		INIT_DCS_CMD(0xC0, 0x00, 0x86, 0x00, 0x0A,
+					   0x0A, 0x00, 0x86, 0x0A, 0x0A, 0x00,
+					   0x86, 0x00, 0x0A, 0x0A),
+		INIT_DCS_CMD(0x00, 0xF0),
+		INIT_DCS_CMD(0xC3, 0x00, 0x00, 0x00, 0x00,
+					   0x00, 0x80),
+		INIT_DCS_CMD(0x00, 0xA0),
+		INIT_DCS_CMD(0xC0, 0x00, 0x00, 0x03, 0x00,
+					   0x00, 0x1E, 0x06),
+		INIT_DCS_CMD(0x00, 0xD0),
+		INIT_DCS_CMD(0xC0, 0x00, 0x00, 0x03, 0x00,
+					   0x00, 0x1E, 0x06),
+		INIT_DCS_CMD(0x00, 0x90),
+		INIT_DCS_CMD(0xC2, 0x84, 0x01, 0x3B, 0x40),
+		INIT_DCS_CMD(0x00, 0xB0),
+		INIT_DCS_CMD(0xC2, 0x02, 0x01, 0x45, 0x43,
+					   0x02, 0x01, 0x45, 0x43),
+		INIT_DCS_CMD(0x00, 0x80),
+		INIT_DCS_CMD(0xC3, 0x84, 0x08, 0x03, 0x00,
+					   0x02, 0x89, 0x82, 0x08, 0x03, 0x00,
+					   0x02, 0x89),
+		INIT_DCS_CMD(0x00, 0x90),
+		INIT_DCS_CMD(0xC3, 0x83, 0x08, 0x03, 0x00,
+					   0x02, 0x89, 0x81, 0x08, 0x03, 0x00,
+					   0x02, 0x89),
+		INIT_DCS_CMD(0x00, 0x80),
+		INIT_DCS_CMD(0xCC, 0x09, 0x0D, 0x11, 0x12,
+					   0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+					   0x0E, 0x28, 0x28, 0x28, 0x28),
+		INIT_DCS_CMD(0x00, 0x90),
+		INIT_DCS_CMD(0xCC, 0x0D, 0x09, 0x14, 0x13,
+					   0x12, 0x11, 0x15, 0x16, 0x17, 0x18,
+					   0x0E, 0x28, 0x28, 0x28, 0x28),
+		INIT_DCS_CMD(0x00, 0xA0),
+		INIT_DCS_CMD(0xCC, 0x1D, 0x1E, 0x1F, 0x19,
+					   0x1A, 0x1B, 0x1C, 0x20, 0x21, 0x22,
+					   0x23, 0x24, 0x25, 0x26, 0x27),
+		INIT_DCS_CMD(0x00, 0xB0),
+		INIT_DCS_CMD(0xCC, 0x01, 0x02, 0x03, 0x05,
+					   0x06, 0x07, 0x04, 0x08),
+		INIT_DCS_CMD(0x00, 0xC0),
+		INIT_DCS_CMD(0xCC, 0x00, 0x00, 0x00, 0x00,
+					   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					   0x00, 0x77),
+		INIT_DCS_CMD(0x00, 0xD0),
+		INIT_DCS_CMD(0xCC, 0xFF, 0x0F, 0x30, 0xC0,
+					   0x0F, 0x30, 0x00, 0x00, 0x33, 0x03,
+					   0x00, 0x77),
+		INIT_DCS_CMD(0x00, 0xDE),
+		INIT_DCS_CMD(0xCC, 0x00),
+		INIT_DCS_CMD(0x00, 0x80),
+		INIT_DCS_CMD(0xCB, 0x00, 0x00, 0x00, 0x00,
+					   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					   0x30, 0x00, 0x00, 0x00, 0x00),
+		INIT_DCS_CMD(0x00, 0x90),
+		INIT_DCS_CMD(0xCB, 0x30, 0x00, 0xC0, 0x00,
+					   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					   0x00, 0x00, 0x00, 0x00, 0x00),
+		INIT_DCS_CMD(0x00, 0xA0),
+		INIT_DCS_CMD(0xCB, 0x15, 0x15, 0x05, 0xF5,
+					   0x05, 0xF5, 0x00, 0x00, 0x00, 0x00,
+					   0x15, 0x00, 0x00, 0x00, 0x00),
+		INIT_DCS_CMD(0x00, 0xB0),
+		INIT_DCS_CMD(0xCB, 0x00, 0x01, 0xFD, 0x00,
+					   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					   0x00, 0x00, 0x00, 0x00, 0x00),
+		INIT_DCS_CMD(0x00, 0xC0),
+		INIT_DCS_CMD(0xCB, 0x00, 0x00, 0x00, 0x00,
+					   0x00, 0x00, 0x77, 0x77),
+		INIT_DCS_CMD(0x00, 0xD0),
+		INIT_DCS_CMD(0xCB, 0x00, 0x00, 0x00, 0x00,
+					   0x00, 0x00, 0x77, 0x77),
+		INIT_DCS_CMD(0x00, 0xE0),
+		INIT_DCS_CMD(0xCB, 0x00, 0x00, 0x00, 0x01,
+					   0x01, 0x01, 0x77, 0x77),
+		INIT_DCS_CMD(0x00, 0xF0),
+		INIT_DCS_CMD(0xCB, 0x11, 0x11, 0x11, 0x11,
+					   0x11, 0x11, 0x77, 0x77),
+		INIT_DCS_CMD(0x00, 0x80),
+		INIT_DCS_CMD(0xCD, 0x3F, 0x3F, 0x3F, 0x3F,
+					   0x3F, 0x3F, 0x3F, 0x3F, 0x01, 0x12,
+					   0x11, 0x03, 0x04, 0x0B, 0x17),
+		INIT_DCS_CMD(0x00, 0x90),
+		INIT_DCS_CMD(0xCD, 0x3D, 0x02, 0x3D, 0x25,
+					   0x25, 0x25, 0x1F, 0x20, 0x21, 0x25, 0x25),
+		INIT_DCS_CMD(0x00, 0xA0),
+		INIT_DCS_CMD(0xCD, 0x3F, 0x3F, 0x3F, 0x3F,
+					   0x3F, 0x3F, 0x3F, 0x3F, 0x01, 0x12,
+					   0x11, 0x05, 0x06, 0x0B, 0x17),
+		INIT_DCS_CMD(0x00, 0xB0),
+		INIT_DCS_CMD(0xCD, 0x17, 0x02, 0x3D, 0x25,
+					   0x25, 0x25, 0x1F, 0x20, 0x21, 0x25, 0x25),
+		INIT_DCS_CMD(0x00, 0x00),
+		INIT_DCS_CMD(0xE1, 0x56, 0x56, 0x59, 0x60,
+					   0x64, 0x67, 0x6d, 0x79, 0x7e, 0x8c,
+					   0x93, 0x99, 0x62, 0x5e, 0x5e, 0x4f,
+					   0x3e, 0x2f, 0x24, 0x1d, 0x16, 0x0c,
+					   0x08, 0x04),
+		INIT_DCS_CMD(0x00, 0x00),
+		INIT_DCS_CMD(0xE2, 0x56, 0x56, 0x59, 0x60,
+				   0x64, 0x67, 0x6d, 0x79, 0x7e, 0x8c,
+				   0x93, 0x99, 0x62, 0x5e, 0x5a, 0x4b,
+				   0x3e, 0x2f, 0x24, 0x1d, 0x16, 0x0c,
+				   0x08, 0x04),
+		INIT_DCS_CMD(0x00, 0x00),
+		INIT_DCS_CMD(0xE3, 0x53, 0x56, 0x58, 0x5c,
+				   0x61, 0x65, 0x6c, 0x77, 0x7c, 0x8b,
+				   0x93, 0x99, 0x62, 0x5e, 0x5d, 0x4f,
+				   0x3e, 0x2e, 0x24, 0x1d, 0x16, 0x0c,
+				   0x07, 0x04),
+		INIT_DCS_CMD(0x00, 0x00),
+		INIT_DCS_CMD(0xE4, 0x53, 0x56, 0x58, 0x5c,
+				   0x61, 0x65, 0x6c, 0x77, 0x7c, 0x8b,
+				   0x93, 0x99, 0x62, 0x5e, 0x59, 0x4b,
+				   0x3e, 0x2e, 0x24, 0x1d, 0x16, 0x0c,
+					   0x07, 0x04),
+		INIT_DCS_CMD(0x00, 0x00),
+		INIT_DCS_CMD(0xE5, 0x20, 0x22, 0x29, 0x35,
+					   0x3f, 0x45, 0x51, 0x63, 0x6e, 0x81,
+					   0x8c, 0x95, 0x64, 0x5f, 0x5e, 0x4e,
+					   0x3e, 0x2e, 0x24, 0x1d, 0x16, 0x0c,
+					   0x07, 0x04),
+		INIT_DCS_CMD(0x00, 0x00),
+		INIT_DCS_CMD(0xE6, 0x20, 0x22, 0x29, 0x35,
+					   0x3f, 0x45, 0x51, 0x63, 0x6e, 0x81,
+					   0x8c, 0x95, 0x64, 0x5f, 0x5a, 0x4a,
+					   0x3e, 0x2e, 0x24, 0x1d, 0x16, 0x0c,
+					   0x07, 0x04),
+		INIT_DCS_CMD(0x00, 0xD4),
+		INIT_DCS_CMD(0xC3, 0x01, 0x01, 0x01, 0x01),
+		INIT_DCS_CMD(0x00, 0xF7),
+		INIT_DCS_CMD(0xC3, 0x03, 0x1B, 0x00, 0x00),
+		INIT_DCS_CMD(0x00, 0xF2),
+		INIT_DCS_CMD(0xC1, 0x80, 0x0F, 0x0F),
+		INIT_DCS_CMD(0x00, 0xC2),
+		INIT_DCS_CMD(0xC5, 0x12),
+		INIT_DCS_CMD(0x00, 0xA8),
+		INIT_DCS_CMD(0xC4, 0x11),
+		INIT_DCS_CMD(0x00, 0x00),
+		INIT_DCS_CMD(0xFF, 0xFF, 0xFF, 0xFF),
+
+		INIT_DCS_CMD(0x11),
+		INIT_DELAY_CMD(120),
+
+		INIT_DCS_CMD(0x29),
+		INIT_DELAY_CMD(50),
+		INIT_END_CMD,
+	},
+	.dsi = &dsi,
+};
+
+extern u32 lcm_if_set_backlight(u32 level, u32 level_max, bool use_default_level);
+
+static void tpv_ph060_power_on(void)
+{
+	ddp_func();
+
+	clrbits_le32(GPIO_BASE + 0x110, 1 << 11); //gpio43 mode gpio  as output output low disp_pwm pin
+	setbits_le32(GPIO_BASE + 0x10, 1 << 11); //gpio43 mode gpio  as output   disp_pwm pin
+
+	clrbits_le32(GPIO_BASE + 0x140, 1 << 30); //gpio158 mode gpio  as output output low poweren pin
+	setbits_le32(GPIO_BASE + 0x40, 1 << 30); //gpio158 mode gpio	as output	poweren pin
+
+	clrbits_le32(GPIO_BASE + 0x140, 1 << 31); //gpio159 mode gpio  as output output low poweren pin
+	setbits_le32(GPIO_BASE + 0x40, 1 << 31); //gpio159 mode gpio	as output	poweren pin
+
+	clrbits_le32(GPIO_BASE + 0x110, 1 << 13); //gpio45 mode gpio  as output output low reset pin
+	setbits_le32(GPIO_BASE + 0x10, 1 << 13); //gpio45 mode gpio	as output	reset pin
+
+	/* set gpio mode */
+	clrsetbits_le32(GPIO_BASE + 0x350, 0xf << 20, 0); //gpio45 mode gpio       reset pin
+	clrsetbits_le32(GPIO_BASE + 0x430, 0xf << 24, 0); //gpio158 mode gpio   poweren pin 1.8v
+	clrsetbits_le32(GPIO_BASE + 0x430, 0xf << 28, 0); //gpio159 mode gpio   poweren pin  3.3v
+	clrsetbits_le32(GPIO_BASE + 0x350, 0xf << 12, 0); //gpio43 mode gpio     disp_pwm pin
+
+	setbits_le32(GPIO_BASE + 0x50, 1 << 6); //gpio166 mode gpio	as output	ext_poweren pin
+	setbits_le32(GPIO_BASE + 0x150, 1 << 6); //gpio166 mode gpio  as output output low ext_poweren pin
+	clrsetbits_le32(GPIO_BASE + 0x440, 0xf << 24, 0); //gpio166 mode gpio   ext_poweren pin  3.3v
+
+	setbits_le32(GPIO_BASE + 0x140, 1 << 30); //gpio158 mode gpio  as output output high poweren pin
+	setbits_le32(GPIO_BASE + 0x140, 1 << 31); //gpio159 mode gpio  as output output high poweren pin
+	mdelay(30);
+	setbits_le32(GPIO_BASE + 0x110, 1 << 13); //gpio45 mode gpio  as output output high reset pin
+	mdelay(100);
+}
+
+static void enable_backlight(void)
+{
+	ddp_func();
+
+	lcm_if_set_backlight(10, 16, false);
+}
+
+struct panel_description tpv_ph060pb16a_desc = {
+	.name = "tpv_ph060pb16a",
+	.s = &TPV_PH060PB16A,
+	.power_on = tpv_ph060_power_on,
+	.backlight_enable = enable_backlight,
+};
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/i2c/i2c.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/i2c/i2c.c
new file mode 100644
index 0000000..4737349
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/i2c/i2c.c
@@ -0,0 +1,721 @@
+/*
+ * 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.
+*/
+#include <platform/i2c.h>
+
+void i2c_writel(struct mtk_i2c *i2c, uint32_t offset,
+		 uint32_t value)
+{
+	writel(value, (i2c->base + offset));
+}
+
+uint32_t i2c_readl(struct mtk_i2c *i2c, uint32_t offset)
+{
+	return readl(i2c->base + offset);
+}
+
+void i2c_clock_enable(struct mtk_i2c *i2c)
+{
+	switch (i2c->id) {
+	case 0:
+		writel(MTK_I2C0_CLK_OFFSET, MTK_I2C_CLK_CLR0);
+		break;
+	case 1:
+		writel(MTK_I2C1_CLK_OFFSET, MTK_I2C_CLK_CLR0);
+		break;
+	case 2:
+		writel(MTK_I2C2_CLK_OFFSET, MTK_I2C_CLK_CLR0);
+		break;
+	case 3:
+		writel(MTK_I2C3_CLK_OFFSET, MTK_I2C_CLK_CLR0);
+		break;
+	case 4:
+		writel(MTK_I2C4_CLK_OFFSET, MTK_I2C_CLK_CLR1);
+		break;
+	case 5:
+		writel(MTK_I2C5_CLK_OFFSET, MTK_I2C_CLK_CLR1);
+		break;
+	case 6:
+		writel(MTK_I2C6_CLK_OFFSET, MTK_I2C_CLK_CLR2);
+		break;
+	case 7:
+		writel(MTK_I2C7_CLK_OFFSET, MTK_I2C_CLK_CLR2);
+		break;
+	default:
+		I2CERR("i2c clk enable, invalid para: i2c->id=%d\n",i2c->id);
+	}
+}
+
+void i2c_clock_disable(struct mtk_i2c *i2c)
+{
+	switch (i2c->id) {
+	case 0:
+		writel(MTK_I2C0_CLK_OFFSET, MTK_I2C_CLK_SET0);
+		break;
+	case 1:
+		writel(MTK_I2C1_CLK_OFFSET, MTK_I2C_CLK_SET0);
+		break;
+	case 2:
+		writel(MTK_I2C2_CLK_OFFSET, MTK_I2C_CLK_SET0);
+		break;
+	case 3:
+		writel(MTK_I2C3_CLK_OFFSET, MTK_I2C_CLK_SET0);
+		break;
+	case 4:
+		writel(MTK_I2C4_CLK_OFFSET, MTK_I2C_CLK_SET1);
+		break;
+	case 5:
+		writel(MTK_I2C5_CLK_OFFSET, MTK_I2C_CLK_SET1);
+		break;
+	case 6:
+		writel(MTK_I2C6_CLK_OFFSET, MTK_I2C_CLK_SET2);
+		break;
+	case 7:
+		writel(MTK_I2C7_CLK_OFFSET, MTK_I2C_CLK_SET2);
+		break;
+	default:
+		I2CERR("i2c clk enable, invalid para: i2c->id=%d\n",i2c->id);
+	}
+}
+
+int mtk_i2c_init_base(struct mtk_i2c *i2c)
+{
+	switch (i2c->id) {
+	case I2C0:
+		i2c->base = I2C0_BASE;
+		break;
+	case I2C1:
+		i2c->base = I2C1_BASE;
+		break;
+	case I2C2:
+		i2c->base = I2C2_BASE;
+		break;
+	case I2C3:
+		i2c->base = I2C3_BASE;
+		break;
+	case I2C4:
+		i2c->base = I2C4_BASE;
+		break;
+	case I2C5:
+		i2c->base = I2C5_BASE;
+		break;
+	case I2C6:
+		i2c->base = I2C6_BASE;
+		break;
+	case I2C7:
+		i2c->base = I2C7_BASE;
+		break;
+	default:
+		I2CERR("invalid para: i2c->id=%d\n", i2c->id);
+		break;
+	}
+
+	i2c->clk = MTK_I2C_SOURCE_CLK;
+	i2c->clk_src_div = MTK_I2C_CLK_DIV;
+
+	return 0;
+}
+
+void mtk_i2c_init_hw(struct mtk_i2c *i2c)
+{
+	uint16_t control_reg;
+
+	i2c_writel(i2c, OFFSET_SOFTRESET, I2C_SOFT_RST);
+
+	i2c_writel(i2c, OFFSET_IO_CONFIG, I2C_IO_CONFIG_OPEN_DRAIN);
+
+	control_reg = I2C_CONTROL_ACKERR_DET_EN | I2C_CONTROL_CLK_EXT_EN;
+
+	i2c_writel(i2c, OFFSET_CONTROL, control_reg);
+
+	i2c_writel(i2c, OFFSET_CLOCK_DIV, (I2C_DEFAULT_CLK_DIV - 1));
+
+	i2c_writel(i2c, OFFSET_DELAY_LEN, I2C_DELAY_LEN);
+}
+
+static int mtk_i2c_calculate_speed(unsigned int clk_src,
+				   unsigned int target_speed,
+				   unsigned int *timing_step_cnt,
+				   unsigned int *timing_sample_cnt)
+{
+	unsigned int step_cnt;
+	unsigned int sample_cnt;
+	unsigned int max_step_cnt;
+	unsigned int base_sample_cnt = MAX_SAMPLE_CNT_DIV;
+	unsigned int base_step_cnt;
+	unsigned int opt_div;
+	unsigned int best_mul;
+	unsigned int cnt_mul;
+
+	if (target_speed > MAX_FS_PLUS_SPEED)
+		max_step_cnt = MAX_HS_STEP_CNT_DIV;
+	else
+		max_step_cnt = MAX_STEP_CNT_DIV;
+
+	base_step_cnt = max_step_cnt;
+
+	/* find the best combination */
+	opt_div = DIV_ROUND_UP(clk_src >> 1, target_speed);
+	best_mul = MAX_SAMPLE_CNT_DIV * max_step_cnt;
+
+	/* Search for the best pair (sample_cnt, step_cnt) with
+	* 0 < sample_cnt < MAX_SAMPLE_CNT_DIV
+	* 0 < step_cnt < max_step_cnt
+	* sample_cnt * step_cnt >= opt_div
+	* optimizing for sample_cnt * step_cnt being minimal
+	*/
+	for (sample_cnt = 1; sample_cnt <= MAX_SAMPLE_CNT_DIV; sample_cnt++) {
+		step_cnt = DIV_ROUND_UP(opt_div, sample_cnt);
+		cnt_mul = step_cnt * sample_cnt;
+		if (step_cnt > max_step_cnt)
+			continue;
+
+		if (cnt_mul < best_mul) {
+			best_mul = cnt_mul;
+			base_sample_cnt = sample_cnt;
+			base_step_cnt = step_cnt;
+			if (best_mul == opt_div)
+				break;
+		}
+	}
+
+	sample_cnt = base_sample_cnt;
+	step_cnt = base_step_cnt;
+
+	if ((clk_src / (2 * sample_cnt * step_cnt)) > target_speed) {
+		I2CERR("Unsupported speed (%u KHz)\n", target_speed);
+		return -EINVAL_I2C;
+	}
+
+	*timing_step_cnt = step_cnt - 1;
+	*timing_sample_cnt = sample_cnt - 1;
+
+	return 0;
+}
+
+int mtk_i2c_set_speed(struct mtk_i2c *i2c)
+{
+	unsigned int clk_src;
+	unsigned int step_cnt;
+	unsigned int sample_cnt;
+	unsigned int l_step_cnt;
+	unsigned int l_sample_cnt;
+	unsigned int target_speed;
+	unsigned int duty = 50;
+	int ret;
+
+	if (i2c->speed == 0)
+		i2c->speed = I2C_DEFAULT_SPEED;
+
+	if (i2c->speed == I2C_DEFAULT_SPEED) {
+		i2c->clock_div_reg = I2C_CLK_DIV_100K;
+		i2c->htiming_reg = I2C_HTIMING_100K;
+		i2c->ltiming_reg = I2C_LTIMING_100K;
+		i2c->high_speed_reg = 0;
+	} else if (i2c->speed == MAX_FS_MODE_SPEED) {
+		i2c->clock_div_reg = I2C_CLK_DIV_400K;
+		i2c->htiming_reg = I2C_HTIMING_400K;
+		i2c->ltiming_reg = I2C_LTIMING_400K;
+		i2c->high_speed_reg = 0;
+	} else if (i2c->speed == MAX_FS_PLUS_SPEED) {
+		i2c->clock_div_reg = I2C_CLK_DIV_1000K;
+		i2c->htiming_reg = I2C_HTIMING_1000K;
+		i2c->ltiming_reg = I2C_LTIMING_1000K;
+		i2c->high_speed_reg = 0;
+	} else {
+		i2c->clock_div_reg = I2C_DEFAULT_CLK_DIV;
+
+		if (i2c->clk_src_div == 0)
+			i2c->clk_src_div = MTK_I2C_CLK_DIV;
+
+		i2c->clk_src_div *= i2c->clock_div_reg;
+
+		clk_src = (i2c->clk) / (i2c->clk_src_div);
+		target_speed = i2c->speed;
+
+		if (target_speed > MAX_FS_PLUS_SPEED) {
+			/* Set master code speed register */
+			ret = mtk_i2c_calculate_speed(clk_src, MAX_FS_PLUS_SPEED,
+						      &l_step_cnt, &l_sample_cnt);
+			if (ret < 0)
+				return ret;
+
+
+			/* Set the high speed mode register */
+			ret = mtk_i2c_calculate_speed(clk_src, target_speed,
+						      &step_cnt, &sample_cnt);
+			if (ret < 0)
+				return ret;
+
+			i2c->high_speed_reg = 0x3 |
+				(sample_cnt & 0x7) << 12 |
+				(step_cnt & 0x7) << 8;
+
+			i2c->htiming_reg =
+				(l_sample_cnt & 0x7) << 8 |
+				(l_step_cnt & 0x3f) << 0;
+
+
+			i2c->ltiming_reg = (l_sample_cnt << 6) | (l_step_cnt << 0) |
+					  (sample_cnt & 0x7) << 12 |
+					  (step_cnt & 0x7) << 9;
+		} else {
+			if (target_speed > I2C_DEFAULT_SPEED && target_speed <= MAX_FS_MODE_SPEED)
+				duty = DUTY_CYCLE;
+
+			ret = mtk_i2c_calculate_speed(clk_src,
+				(target_speed * 50 / duty), &step_cnt, &sample_cnt);
+			if (ret < 0)
+				return ret;
+
+			ret = mtk_i2c_calculate_speed(clk_src,
+				(target_speed * 50 / (100 - duty)), &l_step_cnt, &l_sample_cnt);
+			if (ret < 0)
+				return ret;
+
+			i2c->htiming_reg =
+				(sample_cnt & 0x7) << 8 |
+				(step_cnt & 0x3f) << 0;
+
+			i2c->ltiming_reg = (l_sample_cnt & 0x7) << 6 |
+					  (l_step_cnt & 0x3f) << 0;
+			/* Disable the high speed transaction */
+			i2c->high_speed_reg = 0x0;
+		}
+	}
+
+	i2c_writel(i2c, OFFSET_HTIMING, i2c->htiming_reg);
+	i2c_writel(i2c, OFFSET_LTIMING, i2c->ltiming_reg);
+	i2c_writel(i2c, OFFSET_HS, i2c->high_speed_reg);
+
+	return 0;
+}
+
+static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
+			       int num, int left_num)
+{
+	bool tmo = false;
+	bool trans_error = false;
+	uint8_t *data_buf = msgs->buf;
+	uint16_t data_len = msgs->len;
+	uint16_t read_len;
+	uint16_t addr_reg;
+	uint16_t start_reg;
+	uint16_t control_reg;
+	uint16_t restart_flag = 0;
+	uint32_t tmo_poll = I2C_POLL_VALUE;
+	int ret;
+
+	i2c->irq_stat = 0;
+
+	if (i2c->auto_restart)
+		restart_flag = I2C_RS_TRANSFER;
+
+	control_reg = i2c_readl(i2c, OFFSET_CONTROL) &
+		      ~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS);
+
+	if ((i2c->speed > MAX_FS_PLUS_SPEED) ||
+	    ((num > 1) && !(i2c->mode & I2C_MULTI_STOP)))
+		control_reg |= I2C_CONTROL_RS;
+
+	if (i2c->op == I2C_MASTER_WRRD)
+		control_reg |= I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS;
+
+	if (i2c->dma_en)
+		control_reg |= I2C_CONTROL_DMA_EN;
+
+	i2c_writel(i2c, OFFSET_CONTROL, control_reg);
+
+	/* set start condition */
+	if (i2c->speed <= I2C_DEFAULT_SPEED)
+		i2c_writel(i2c, OFFSET_EXT_CONF, I2C_ST_START_CON);
+	else
+		i2c_writel(i2c, OFFSET_EXT_CONF, I2C_FS_START_CON);
+
+	addr_reg = msgs->addr << 1;
+	if (i2c->op == I2C_MASTER_RD)
+		addr_reg |= 0x1;
+
+	i2c_writel(i2c, OFFSET_SLAVE_ADDR, addr_reg);
+
+	/* clear interrupt status */
+	i2c_writel(i2c, OFFSET_INTR_STAT, I2C_RS_TRANSFER | I2C_ACKERR |
+		   I2C_TRANSAC_COMP);
+
+	i2c_writel(i2c, OFFSET_FIFO_ADDR_CLR, I2C_FIFO_ADDR_CLR);
+
+	if (i2c->poll_en)
+		i2c_writel(i2c, OFFSET_INTR_MASK, 0);
+	else
+		i2c_writel(i2c, OFFSET_INTR_MASK, restart_flag | I2C_ACKERR |
+			   I2C_TRANSAC_COMP);
+
+	/* set transfer and transaction len */
+	if (i2c->op == I2C_MASTER_WRRD) {
+		i2c_writel(i2c, OFFSET_TRANSFER_LEN, msgs->len);
+		i2c_writel(i2c, OFFSET_TRANSFER_LEN_AUX, (msgs + 1)->len);
+		i2c_writel(i2c, OFFSET_TRANSAC_LEN, I2C_WRRD_TRANAC_VALUE);
+	} else {
+		i2c_writel(i2c, OFFSET_TRANSFER_LEN, msgs->len);
+		i2c_writel(i2c, OFFSET_TRANSAC_LEN, num);
+	}
+
+	if (i2c->dma_en) {
+		/* not support*/
+	} else {
+		if (i2c->op != I2C_MASTER_RD) {
+			data_buf = msgs->buf;
+			data_len = msgs->len;
+
+			while (data_len--)
+				i2c_writel(i2c, OFFSET_DATA_PORT,
+					   *(data_buf++));
+		}
+	}
+
+	if (!i2c->auto_restart) {
+		start_reg = I2C_TRANSAC_START;
+	} else {
+		start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG;
+		if (left_num >= 1)
+			start_reg |= I2C_RS_MUL_CNFG;
+	}
+	i2c_writel(i2c, OFFSET_START, start_reg);
+
+	if (i2c->poll_en) {
+		for (;;) {
+			i2c->irq_stat = i2c_readl(i2c, OFFSET_INTR_STAT);
+
+			if (i2c->irq_stat & (I2C_TRANSAC_COMP | restart_flag)) {
+				tmo = false;
+				if (i2c->irq_stat & I2C_ACKERR)
+					trans_error = true;
+				break;
+			}
+
+			udelay(1);
+			tmo_poll--;
+			if (tmo_poll == 0) {
+				tmo = true;
+				break;
+			}
+		}
+	} else {
+		/* not support irq*/
+	}
+
+	/* clear interrupt mask */
+	i2c_writel(i2c, OFFSET_INTR_MASK, ~(restart_flag | I2C_ACKERR |
+					    I2C_TRANSAC_COMP));
+
+	if ((!tmo) && (!trans_error)) {
+		if (!i2c->dma_en && i2c->op != I2C_MASTER_WR &&
+		    !(i2c->mode & I2C_FIFO_FORCE)) {
+			data_buf = (i2c->op == I2C_MASTER_RD) ?
+				   msgs->buf : (msgs + 1)->buf;
+			data_len = (i2c->op == I2C_MASTER_RD) ?
+				   msgs->len : (msgs + 1)->len;
+				read_len = (i2c_readl(i2c, OFFSET_FIFO_STAT) >> 4)
+					   & 0xf;
+
+			if (read_len == data_len) {
+				while (data_len--)
+					*(data_buf++) = i2c_readl(i2c,
+							OFFSET_DATA_PORT);
+			} else {
+				I2CERR("fifo read error!\n");
+				I2CERR("data_len %x, read_len %x\n",
+					data_len, read_len);
+				return -EREMOTEIO_I2C;
+			}
+		}
+	} else {
+		/* timeout or ACKERR */
+		if (tmo) {
+			I2CERR("id=%d, addr: %x, transfer timeout\n",
+				   i2c->id, msgs->addr);
+			ret = -ETIMEDOUT_I2C;
+		} else {
+			I2CERR("id=%d, addr: %x, I2C_ACKERR\n",
+				   i2c->id, msgs->addr);
+			ret = -ENXIO_I2C;
+		}
+
+		return ret;
+	}
+	return 0;
+}
+
+int mtk_i2c_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, int num)
+{
+	uint8_t num_cnt;
+	int left_num = num;
+	int ret;
+
+	mtk_i2c_init_base(i2c);
+	i2c_clock_enable(i2c);
+	mtk_i2c_init_hw(i2c);
+
+	ret = mtk_i2c_set_speed(i2c);
+	if (ret) {
+		I2CERR("Failed to set the speed.\n");
+		goto err_exit;
+	}
+
+	for (num_cnt = 0; num_cnt < num; num_cnt++) {
+		if (((msgs + num_cnt)->addr) > 0x7f) {
+			I2CERR("i2c addr: msgs[%d]->addr(%x) > 0x7f, error!\n",
+			       num_cnt, ((msgs + num_cnt)->addr));
+			ret = -EINVAL_I2C;
+			goto err_exit;
+		}
+
+		if (!(msgs + num_cnt)->buf) {
+			I2CERR("msgs[%d]->buf is NULL.\n", num_cnt);
+			ret = -EINVAL_I2C;
+			goto err_exit;
+		}
+
+		if ((msgs + num_cnt)->len == 0) {
+			I2CERR("msgs[%d]->len == 0, error!\n", num_cnt);
+			ret = -EINVAL_I2C;
+			goto err_exit;
+		}
+
+		if ((msgs + num_cnt)->len > I2C_FIFO_SIZE) {
+			I2CERR("msgs->len > %d, error!\n", I2C_FIFO_SIZE);
+			ret = -EINVAL_I2C;
+			goto err_exit;
+		}
+	}
+
+	if ((num == 1) || ((!i2c->dma_en) && (num == 2) &&
+	    (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
+	    (msgs[0].addr == msgs[1].addr)) && !(i2c->mode & I2C_MULTI_TRANS)))
+		i2c->auto_restart = false;
+	else
+		i2c->auto_restart = true;
+
+	while (left_num--) {
+		if (msgs->flags & I2C_M_RD)
+			i2c->op = I2C_MASTER_RD;
+		else
+			i2c->op = I2C_MASTER_WR;
+
+		if (!i2c->auto_restart) {
+			if (num == 2) {
+				/* combined two messages into one transaction */
+				i2c->op = I2C_MASTER_WRRD;
+				left_num--;
+			}
+		}
+
+		ret = mtk_i2c_do_transfer(i2c, msgs, num, left_num);
+		if (ret < 0)
+			goto err_exit;
+
+		msgs++;
+	}
+
+	ret = I2C_OK;
+
+err_exit:
+	i2c_clock_disable(i2c);
+	return ret;
+}
+
+int mtk_i2c_read(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,
+		 uint8_t *buffer, uint16_t len)
+{
+	int ret = I2C_OK;
+	struct i2c_msg msgs;
+	struct mtk_i2c i2c_mtk;
+	struct mtk_i2c *i2c = &i2c_mtk;
+
+	memset(i2c, 0, sizeof(struct mtk_i2c));
+
+	i2c->poll_en = true;
+	i2c->dma_en = false;
+	i2c->auto_restart = false;
+	i2c->pushpull = false;
+	i2c->filter_msg = false;
+	i2c->id = bus_num;
+	i2c->addr = device_addr;
+	i2c->speed = speed_khz;
+	i2c->mode = 0;
+
+	msgs.addr = i2c->addr;
+	msgs.flags = 1;
+	msgs.buf = buffer;
+	msgs.len = len;
+	ret = mtk_i2c_transfer(i2c, &msgs, 1);
+
+	if ((i2c->filter_msg == false) && (ret != I2C_OK))
+		I2CERR("mtk_i2c_read fails(%d).\n", ret);
+
+	return ret;
+}
+
+int mtk_i2c_write(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,
+		  uint8_t *buffer, uint16_t len)
+{
+	int ret = I2C_OK;
+	struct i2c_msg msgs;
+	struct mtk_i2c i2c_mtk;
+	struct mtk_i2c *i2c = &i2c_mtk;
+
+	memset(i2c, 0, sizeof(struct mtk_i2c));
+
+	i2c->poll_en = true;
+	i2c->dma_en = false;
+	i2c->auto_restart = false;
+	i2c->pushpull = false;
+	i2c->filter_msg = false;
+	i2c->id = bus_num;
+	i2c->addr = device_addr;
+	i2c->speed = speed_khz;
+	i2c->mode = 0;
+
+	msgs.addr = i2c->addr;
+	msgs.flags = 0;
+	msgs.buf = buffer;
+	msgs.len = len;
+	ret = mtk_i2c_transfer(i2c, &msgs, 1);
+
+	if ((i2c->filter_msg == false) && (ret != I2C_OK))
+		I2CERR("mtk_i2c_write fails(%d).\n", ret);
+
+	return ret;
+}
+
+int mtk_i2c_write_read(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,
+		       uint8_t *write_buffer, uint8_t *read_buffer,
+		       uint16_t write_len, uint16_t read_len)
+{
+	int ret = I2C_OK;
+	struct i2c_msg msgs[2];
+	struct mtk_i2c i2c_mtk;
+	struct mtk_i2c *i2c = &i2c_mtk;
+
+	memset(i2c, 0, sizeof(struct mtk_i2c));
+
+	i2c->poll_en = true;
+	i2c->dma_en = false;
+	i2c->auto_restart = false;
+	i2c->pushpull = false;
+	i2c->filter_msg = false;
+	i2c->id = bus_num;
+	i2c->addr = device_addr;
+	i2c->speed = speed_khz;
+	i2c->mode = 0;
+
+	msgs[0].addr = i2c->addr;
+	msgs[0].flags = 0;
+	msgs[0].buf = write_buffer;
+	msgs[0].len = write_len;
+
+	msgs[1].addr = i2c->addr;
+	msgs[1].flags = 1;
+	msgs[1].buf = read_buffer;
+	msgs[1].len = read_len;
+	ret = mtk_i2c_transfer(i2c, msgs, 2);
+
+	if ((i2c->filter_msg == false) && (ret != I2C_OK))
+		I2CERR("mtk_i2c_write_read fails(%d).\n", ret);
+
+	return ret;
+}
+
+void mtk_i2c_init(void)
+{
+	u32 tmp;
+	/*enable i2c arbitration*/
+	//DRV_WriteReg8(PERICFG_I2C_ARBITRATION,
+	//DRV_Reg8(PERICFG_I2C_ARBITRATION) | 0x7);
+
+	/*swtich clock to PLL*/
+	tmp = readl(MODULE_CLK_SEL_BASE);
+	writel(tmp | USE_PLL_MUX, MODULE_CLK_SEL_BASE);
+
+	/* Disable I2C2 & I2C4 rollback mode */
+	writel(0, I2C2_BASE_SE + OFFSET_ROLLBACK);
+	writel(0, I2C4_BASE_SE + OFFSET_ROLLBACK);
+
+	/* Enable I2C2 & I2C4 buf/imm mode */
+	tmp = readl(I2C2_BASE_SE + OFFSET_MULTI_DMA);
+	writel(SHADOW_REG_MODE | tmp, I2C2_BASE_SE + OFFSET_MULTI_DMA);
+	tmp = readl(I2C4_BASE_SE + OFFSET_MULTI_DMA);
+	writel(SHADOW_REG_MODE | tmp, I2C4_BASE_SE + OFFSET_MULTI_DMA);
+
+	I2C_SET_REG32(IOCFG_RB_BASE + 0xF0, (0x7 << 9) | (0x7 << 19),
+		  (0 << 9) | (0 << 19));
+	I2C_SET_REG32(IOCFG_RB_BASE + 0x60, (0x1 << 21) | (0x1 << 22),
+		  (0x1 << 21) | (0x1 << 22));
+	I2C_SET_REG32(IOCFG_RB_BASE + 0x80, (0x1 << 21) | (0x1 << 22),
+		  (0x1 << 21) | (0x1 << 22));
+
+	I2C_SET_REG32(IOCFG_RB_BASE + 0xF0, (0x7 << 12) | (0x7 << 22),
+		  (0 << 12) | (0 << 22));
+	I2C_SET_REG32(IOCFG_RB_BASE + 0x60, (0x1 << 20) | (0x1 << 23),
+		  (0x1 << 20) | (0x1 << 23));
+	I2C_SET_REG32(IOCFG_RB_BASE + 0x80, (0x1 << 20) | (0x1 << 23),
+		  (0x1 << 20) | (0x1 << 23));
+
+	I2C_SET_REG32(IOCFG_RM_BASE + 0xF0, (0x7 << 14) | (0x7 << 24),
+		  (0 << 14) | (0 << 24));
+	I2C_SET_REG32(IOCFG_RM_BASE + 0x60, (0x3 << 28), (0x03 << 28));
+	I2C_SET_REG32(IOCFG_RM_BASE + 0x80, (0x3 << 28), (0x03 << 28));
+
+	I2C_SET_REG32(IOCFG_BL_BASE + 0xF0, (0x7 << 7) | (0x7 << 12),
+		  (0 << 7) | (0 << 12));
+	I2C_SET_REG32(IOCFG_BL_BASE + 0x60, (0x3 << 0), (0x03 << 0));
+	I2C_SET_REG32(IOCFG_BL_BASE + 0x80, (0x3 << 0), (0x03 << 0));
+
+	I2C_SET_REG32(IOCFG_RM_BASE + 0xF0, (0x7 << 17) | (0x7 << 27),
+		  (0 << 17) | (0 << 27));
+	I2C_SET_REG32(IOCFG_RM_BASE+ 0x60, (0x3 << 30), (0x03 << 30));
+	I2C_SET_REG32(IOCFG_RM_BASE+ 0x80, (0x3 << 30), (0x03 << 30));
+
+	I2C_SET_REG32(IOCFG_LB_BASE + 0xF0, (0x7 << 15) | (0x7 << 20),
+		  (0 << 15) | (0 << 20));
+	I2C_SET_REG32(IOCFG_LB_BASE + 0x60, (0x3 << 13), (0x03 << 13));
+	I2C_SET_REG32(IOCFG_LB_BASE + 0x80, (0x3 << 13), (0x03 << 13));
+
+	/* Switch internal resistor */
+	/* 0x0:75k 0x1:5k */
+	/* 0x2:15k 0x3:1k */
+	/* SDA0[6:5] SCL0[16:15] */
+	/* SDA1[8:7] SCL1[18:17] */
+	I2C_SET_REG32(IOCFG_RB_BASE + 0xF0, 0x781E0, 0x781E0);
+	/* SDA2[11:10] SCL2[21:20] */
+	/* SDA4[13:12] SCL4[23:22] */
+	I2C_SET_REG32(IOCFG_RM_BASE + 0xF0, 0xF03C00, 0xF03C00);
+	/* SDA3[6:5] SCL3[10:11] */
+	I2C_SET_REG32(IOCFG_BL_BASE + 0xF0, 0x0C60, 0x0C60);
+	/* SDA5[14:13] SCL5[19:18] */
+	/*I2C_SET_REG32(IOCFG_LB_BASE + 0xF0, 0xC6000, 0xC6000);*/
+
+	/*SET I2C6 GPIO MODE3*/
+#if HDMI_MAIN_PATH
+	writel( readl(GPIO_BASE + 0x3E0) | (0x3 << 4) | (0x3 << 8), GPIO_BASE + 0x3E0);
+#endif
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/IO.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/IO.c
new file mode 100644
index 0000000..faf2a22
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/IO.c
@@ -0,0 +1,125 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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 "itx_typedef.h"
+#include "mcu.h"
+#include "IO.h"
+#include "../../include/platform/i2c.h"
+
+
+unsigned char HDMITX_ReadI2C_Byte(unsigned char RegAddr)
+{
+	//unsigned char p_data;
+
+	//it66121_i2c_read_byte(RegAddr, &p_data);
+
+	unsigned char write_buf;
+	unsigned char read_buf;
+
+	write_buf = RegAddr;
+
+	mtk_i2c_write_read(6, (0x98>>1), 100, &write_buf, &read_buf, 1, 1);
+	return read_buf;
+}
+
+SYS_STATUS HDMITX_WriteI2C_Byte(unsigned char RegAddr, unsigned char d)
+{
+	//bool flag;
+
+	unsigned char buf[] = {RegAddr, d};
+
+	//flag = it66121_i2c_write_byte(RegAddr, d);
+
+	mtk_i2c_write(6, (0x98>>1), 100, buf, sizeof(buf));
+
+	return 0;
+}
+
+SYS_STATUS HDMITX_ReadI2C_ByteN(unsigned char RegAddr, unsigned char *pData, int N)
+{
+#if 0
+	bool flag;
+
+	flag = it66121_i2c_read_block(RegAddr, pData, N);
+
+	return flag;
+#else
+	int i;
+
+	for (i = 0; i < N; i++)
+		pData[i] = HDMITX_ReadI2C_Byte(RegAddr + i);
+
+	return 0;
+#endif
+}
+
+SYS_STATUS HDMITX_WriteI2C_ByteN(unsigned char RegAddr, unsigned char *pData, int N)
+{
+#if 0
+	bool flag;
+
+	flag = it66121_i2c_write_block(RegAddr, pData, N);
+	return flag;
+#else
+	int i;
+
+	for (i = 0; i < N; i++)
+		HDMITX_WriteI2C_Byte((RegAddr + i), pData[i]);
+
+	return 0;
+#endif
+}
+
+SYS_STATUS HDMITX_SetI2C_Byte(unsigned char Reg, unsigned char Mask, unsigned char Value)
+{
+	unsigned char Temp;
+
+	if (Mask != 0xFF) {
+		Temp = HDMITX_ReadI2C_Byte(Reg);
+		Temp &= (~Mask);
+		Temp |= Value & Mask;
+	} else {
+		Temp = Value;
+	}
+	return HDMITX_WriteI2C_Byte(Reg, Temp);
+}
+
+SYS_STATUS HDMITX_ToggleBit(unsigned char Reg, unsigned char n)
+{
+	unsigned char Temp;
+
+	Temp = HDMITX_ReadI2C_Byte(Reg);
+/* HDMITX_DEBUG_PRINTF(("INVERVIT  0x%bx[%bx]",Reg,n)); */
+	/* IT66121_LOG("reg%02X = %02X -> toggle %dth bit ->",(int)Reg,(int)Temp,(int)n) ; */
+	Temp ^= (1 << n);
+	/* IT66121_LOG(" %02X\n",(int)Temp) ; */
+
+/* HDMITX_DEBUG_PRINTF(("0x%bx\n",Temp)); */
+	return HDMITX_WriteI2C_Byte(Reg, Temp);
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/IO.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/IO.h
new file mode 100644
index 0000000..1bae8b6
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/IO.h
@@ -0,0 +1,66 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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.
+*/
+
+#ifndef _IO_h_
+#define _IO_h_
+#include "mcu.h"
+/* #include "main.h" */
+#include "utility.h"
+#include "itx_typedef.h"
+
+//#define u8 unsigned char
+/* ///////////////////////////////////////////////////////////////////////////// */
+/* Start: I2C for 8051 */
+/* ///////////////////////////////////////////////////////////////////////////// */
+/* ///////////////////////////////////////////////////////////////////////////// */
+/* I2C for original function call */
+/* ///////////////////////////////////////////////////////////////////////////// */
+int it66121_i2c_read_byte(unsigned char addr, unsigned char *data);
+int it66121_i2c_write_byte(unsigned char addr, unsigned char data);
+
+int it66121_i2c_read_block(unsigned char addr, unsigned char *data, int len);
+int it66121_i2c_write_block(unsigned char addr, unsigned char *data, int len);
+
+
+
+unsigned char HDMITX_ReadI2C_Byte(unsigned char RegAddr);
+SYS_STATUS HDMITX_WriteI2C_Byte(unsigned char RegAddr, unsigned char d);
+SYS_STATUS HDMITX_ReadI2C_ByteN(unsigned char RegAddr, unsigned char *pData, int N);
+SYS_STATUS HDMITX_WriteI2C_ByteN(unsigned char RegAddr, unsigned char *pData, int N);
+SYS_STATUS HDMITX_SetI2C_Byte(unsigned char Reg, unsigned char Mask, unsigned char Value);
+SYS_STATUS HDMITX_ToggleBit(unsigned char Reg, unsigned char n);
+
+/*unsigned char CEC_ReadI2C_Byte(unsigned char RegAddr);*/
+/*SYS_STATUS CEC_WriteI2C_Byte(unsigned char RegAddr,unsigned char d);*/
+/*SYS_STATUS CEC_ReadI2C_ByteN(unsigned char RegAddr,unsigned char *pData,int N);*/
+/*SYS_STATUS CEC_WriteI2C_ByteN(unsigned char RegAddr,unsigned char _CODE *pData,int N);*/
+/*SYS_STATUS CEC_SetI2C_Byte(unsigned char Reg,unsigned char Mask,unsigned char Value);*/
+/*SYS_STATUS CEC_ToggleBit(unsigned char Reg,unsigned char n);*/
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/csc.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/csc.c
new file mode 100644
index 0000000..2919c57
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/csc.c
@@ -0,0 +1,95 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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 "itx_config.h"
+#include "itx_typedef.h"
+
+#if (defined(SUPPORT_OUTPUTYUV)) && (defined(SUPPORT_INPUTRGB))
+
+unsigned char bCSCMtx_RGB2YUV_ITU601_16_235[] = {
+	0x00, 0x80, 0x00,
+	0xB2, 0x04, 0x65, 0x02, 0xE9, 0x00,
+	0x93, 0x3C, 0x18, 0x04, 0x55, 0x3F,
+	0x49, 0x3D, 0x9F, 0x3E, 0x18, 0x04
+};
+
+unsigned char bCSCMtx_RGB2YUV_ITU601_0_255[] = {
+	0x10, 0x80, 0x10,
+	0x09, 0x04, 0x0E, 0x02, 0xC9, 0x00,
+	0x0F, 0x3D, 0x84, 0x03, 0x6D, 0x3F,
+	0xAB, 0x3D, 0xD1, 0x3E, 0x84, 0x03
+};
+
+unsigned char bCSCMtx_RGB2YUV_ITU709_16_235[] = {
+	0x00, 0x80, 0x00,
+	0xB8, 0x05, 0xB4, 0x01, 0x94, 0x00,
+	0x4a, 0x3C, 0x17, 0x04, 0x9F, 0x3F,
+	0xD9, 0x3C, 0x10, 0x3F, 0x17, 0x04
+};
+
+unsigned char bCSCMtx_RGB2YUV_ITU709_0_255[] = {
+	0x10, 0x80, 0x10,
+	0xEa, 0x04, 0x77, 0x01, 0x7F, 0x00,
+	0xD0, 0x3C, 0x83, 0x03, 0xAD, 0x3F,
+	0x4B, 0x3D, 0x32, 0x3F, 0x83, 0x03
+};
+#endif
+
+#if (defined(SUPPORT_OUTPUTRGB)) && (defined(SUPPORT_INPUTYUV))
+
+unsigned char bCSCMtx_YUV2RGB_ITU601_16_235[] = {
+	0x00, 0x00, 0x00,
+	0x00, 0x08, 0x6B, 0x3A, 0x50, 0x3D,
+	0x00, 0x08, 0xF5, 0x0A, 0x02, 0x00,
+	0x00, 0x08, 0xFD, 0x3F, 0xDA, 0x0D
+};
+
+unsigned char bCSCMtx_YUV2RGB_ITU601_0_255[] = {
+	0x04, 0x00, 0xA7,
+	0x4F, 0x09, 0x81, 0x39, 0xDD, 0x3C,
+	0x4F, 0x09, 0xC4, 0x0C, 0x01, 0x00,
+	0x4F, 0x09, 0xFD, 0x3F, 0x1F, 0x10
+};
+
+unsigned char bCSCMtx_YUV2RGB_ITU709_16_235[] = {
+	0x00, 0x00, 0x00,
+	0x00, 0x08, 0x55, 0x3C, 0x88, 0x3E,
+	0x00, 0x08, 0x51, 0x0C, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x84, 0x0E
+};
+
+unsigned char bCSCMtx_YUV2RGB_ITU709_0_255[] = {
+	0x04, 0x00, 0xA7,
+	0x4F, 0x09, 0xBA, 0x3B, 0x4B, 0x3E,
+	0x4F, 0x09, 0x57, 0x0E, 0x02, 0x00,
+	0x4F, 0x09, 0xFE, 0x3F, 0xE8, 0x10
+};
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/debug_hdmi.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/debug_hdmi.h
new file mode 100644
index 0000000..34cc638
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/debug_hdmi.h
@@ -0,0 +1,97 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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.
+*/
+
+
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+#include "stdio.h"
+#define Debug_message 1
+/* #pragma message("debug.h") */
+#define HDMITX_DEBUG_PRINTF(fmt, arg...)  printf(fmt, ##arg)
+#define HDMITX_DEBUG_PRINTF1(fmt, arg...) printf(fmt, ##arg)
+#define HDMITX_DEBUG_PRINTF2(fmt, arg...) printf(fmt, ##arg)
+#define HDMITX_DEBUG_PRINTF3(fmt, arg...) printf(fmt, ##arg)
+
+#define HDCP_DEBUG_PRINTF(fmt, arg...)	/* printk(fmt, ##arg) */
+#define HDCP_DEBUG_PRINTF1(fmt, arg...)	/* printk(fmt, ##arg) */
+#define HDCP_DEBUG_PRINTF2(fmt, arg...)	/* printk(fmt, ##arg) */
+#define HDCP_DEBUG_PRINTF3(fmt, arg...)	/* printk(fmt, ##arg) */
+
+#if 1
+#define EDID_DEBUG_PRINTF(fmt, arg...)  printf(fmt, ##arg)
+#define EDID_DEBUG_PRINTF1(fmt, arg...) printf(fmt, ##arg)
+#define EDID_DEBUG_PRINTF2(fmt, arg...) printf(fmt, ##arg)
+#define EDID_DEBUG_PRINTF3(fmt, arg...) printf(fmt, ##arg)
+
+#else
+#define EDID_DEBUG_LOG_ON 0
+#define EDID_DEBUG_PRINTF(fmt, arg...) \
+do { \
+	if (EDID_DEBUG_LOG_ON) { \
+		pr_debug("[EDID]%s,%d ", __func__, __LINE__); pr_debug(fmt, ##arg); } \
+} while (0)
+
+#define EDID_DEBUG_PRINTF1(fmt, arg...) \
+do { \
+	if (EDID_DEBUG_LOG_ON) { \
+		pr_debug("[EDID]%s,%d ", __func__, __LINE__); pr_debug(fmt, ##arg); } \
+} while (0)
+
+#define EDID_DEBUG_PRINTF2(fmt, arg...) \
+do { \
+	if (EDID_DEBUG_LOG_ON) { \
+		pr_err("[EDID]%s,%d ", __func__, __LINE__); pr_err(fmt, ##arg); } \
+} while (0)
+
+#define EDID_DEBUG_PRINTF3(fmt, arg...) \
+do { \
+	if (EDID_DEBUG_LOG_ON) { \
+		pr_err("[EDID]%s,%d ", __func__, __LINE__); pr_err(fmt, ##arg); } \
+} while (0)
+
+#endif
+
+#define HDMITX_DEBUG_INFO
+
+
+#define IT66121_LOG_on		1
+#define IT66121_LOG(fmt, arg...) \
+do { \
+	if (IT66121_LOG_on) { \
+		printf("[hdmi_it66121]%s,%d ", __func__, __LINE__); printf(fmt, ##arg); } \
+} while (0)
+
+#define it66121_FUNC()	\
+do { \
+	if (IT66121_LOG_on) { \
+		printf("[hdmi_it66121] %s\n", __func__); } \
+} while (0)
+
+
+#endif				/* _DEBUG_H_ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmi_drv.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmi_drv.c
new file mode 100644
index 0000000..69c9a87
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmi_drv.c
@@ -0,0 +1,170 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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 "hdmitx.h" */
+#ifdef SUPPORT_CEC
+#include "hdmitx_cec.h"
+#endif
+
+#include <reg.h>
+
+#include "debug_hdmi.h"
+#include "hdmitx_drv.h"
+#include "hdmitx_sys.h"
+#include "itx_typedef.h"
+#include "inc/hdmi_drv.h"
+#include "hdmitx.h"
+#include "../../include/platform/mt6358.h"
+#include "../../include/platform/regulator_core.h"
+#include "../../include/platform/mt_reg_base.h"
+
+
+unsigned char real_edid[256];
+extern unsigned char tmp_HPD,notify_hpd_flag,notify_hpd_out;
+
+void delay(int ms)
+{
+	int i,j;
+	for(i = 0; i < 100*ms; i++)
+		for(j = 0; j < 1000; j++)
+		{
+			;
+		}
+}
+int ite66121_pmic_power_on(void)
+{
+//	struct mtk_regulator reg_vrf12;
+	struct mtk_regulator reg_vcn18;
+	struct mtk_regulator reg_vcn33;
+
+//	mtk_regulator_get("vrf12", &reg_vrf12);
+//	mtk_regulator_enable(&reg_vrf12, 1);
+
+	pmic_config_interface(0x1c32, 0x1, 0xFFFF, 0);
+	pmic_config_interface(0x1c30, 0x1, 0xFFFF, 0);
+
+	mtk_regulator_get("vcn18", &reg_vcn18);
+	mtk_regulator_enable(&reg_vcn18, 1);
+
+	mtk_regulator_get("vcn33", &reg_vcn33);
+	mtk_regulator_enable(&reg_vcn33, 1);
+
+	return 1;
+}
+void HDMI_reset(void)
+{
+	//gpio160:  it66121 reset pin
+	writel( readl(GPIO_BASE + 0x440) &  0xfffffff0 , GPIO_BASE + 0x440);
+
+	writel( readl(GPIO_BASE + 0x050 ) | 1 , GPIO_BASE + 0x050); //dir
+
+	writel( readl(GPIO_BASE + 0x150 ) & 0xfffffffe , GPIO_BASE + 0x150); //dout 0
+
+	delay(10000);
+
+	writel( readl(GPIO_BASE + 0x150 ) | 1 , GPIO_BASE + 0x150); //dout 1
+}
+int it66121_power_on(void)
+{
+	IT66121_LOG(">>> %s\n", __func__);
+
+	ite66121_pmic_power_on();
+	delay(500000);
+	/* Reset The it66121 IC */
+	HDMI_reset();
+	//msleep(5);
+	delay(500000);
+
+    /*for first-second byte i2c ack err*/
+	IT66121_LOG("w-n 0xE:0x%x \n",HDMITX_ReadI2C_Byte(0xE));
+	IT66121_LOG("w-n 0xE:0x%x \n",HDMITX_ReadI2C_Byte(0xE));
+
+	/* This leave for it66121 internal init function */
+	InitHDMITX_Variable();
+	InitHDMITX();
+	HDMITX_ChangeDisplayOption(HDMI_720p60, HDMI_RGB444);
+
+	//test i2c ok or not
+	IT66121_LOG("w-n 0xE:0x%x \n",HDMITX_ReadI2C_Byte(0xE));
+	IT66121_LOG("w-n 0x61:0x%x \n",HDMITX_ReadI2C_Byte(0x61));
+
+	IT66121_LOG("<<< %s,\n", __func__);
+	return 0;
+}
+
+int it66121_video_config(enum HDMI_VIDEO_RESOLUTION vformat, enum HDMI_VIDEO_INPUT_FORMAT vin,
+				int vout)
+{
+
+	HDMI_Video_Type it66121_video_type = HDMI_480i60_16x9;
+
+
+	IT66121_LOG(">>> %s vformat:0x%x,\n", __func__,vformat);
+
+	if (vformat == HDMI_VIDEO_720x480p_60Hz)
+		it66121_video_type = HDMI_480p60;
+	else if (vformat == HDMI_VIDEO_1280x720p_60Hz)
+		it66121_video_type = HDMI_720p60;
+	else if (vformat == HDMI_VIDEO_1920x1080p_30Hz)
+		it66121_video_type = HDMI_1080p30;
+	else {
+		IT66121_LOG("error:it66121_video_config vformat=%d\n", vformat);
+		it66121_video_type = HDMI_720p60;
+	}
+
+	HDMITX_ChangeDisplayOption(it66121_video_type, HDMI_RGB444);
+	HDMITX_SetOutput();
+
+	IT66121_LOG("<<< %s,\n", __func__);
+
+	return 0;
+}
+
+
+void gpio_mode_set(void)
+{
+// gpio13-28 mode1 --- dpi mode
+	writel( (readl(GPIO_BASE + 0x310) & (~(0xfff < 20)) ) | 0x11100000, GPIO_BASE + 0x310);
+
+	writel( (readl(GPIO_BASE + 0x320) &  (~0xffffffff) ) | 0x11111111, GPIO_BASE + 0x320);
+
+	writel( (readl(GPIO_BASE + 0x330) &  (~0xfffff) ) | 0x11111 , GPIO_BASE + 0x330);
+
+	//i2c6 GPIO mode3  also set in mtk_i2c_init() i2c.c
+	//printf("w-n 0x3E0:0x%x\n", readl(GPIO_BASE + 0x3E0));
+	//writel( readl(GPIO_BASE + 0x3E0) | (0x3 << 4) | (0x3 << 8), GPIO_BASE + 0x3E0);
+}
+void it6621_main()
+{
+	gpio_mode_set();
+	it66121_power_on();
+	it66121_video_config(HDMI_VIDEO_1280x720p_60Hz,
+			HDMI_VIN_FORMAT_RGB888, HDMI_VOUT_FORMAT_RGB888);
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx.h
new file mode 100644
index 0000000..f248d20
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx.h
@@ -0,0 +1,75 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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.
+*/
+
+
+#ifndef _HDMITX_H_
+#define _HDMITX_H_
+/*#define unsigned char unsigned char*/
+#include "IO.h"
+#include "utility.h"
+
+
+#include "debug_hdmi.h"
+#include "itx_config.h"
+#include "itx_typedef.h"
+#include "hdmitx_drv.h"
+
+#define HDMITX_MAX_DEV_COUNT 1
+
+
+/* ///////////////////////////////////////////////////////////////////// */
+/* Output Mode Type */
+/* ///////////////////////////////////////////////////////////////////// */
+
+#define RES_ASPEC_4x3 0
+#define RES_ASPEC_16x9 1
+#define F_MODE_REPT_NO 0
+#define F_MODE_REPT_TWICE 1
+#define F_MODE_REPT_QUATRO 3
+#define F_MODE_CSC_ITU601 0
+#define F_MODE_CSC_ITU709 1
+
+
+#define TIMER_LOOP_LEN 10
+#define MS(x) (((x)+(TIMER_LOOP_LEN-1))/TIMER_LOOP_LEN)	/* for timer loop */
+
+/* #define SUPPORT_AUDI_AudSWL 16 // Jeilin case. */
+#define SUPPORT_AUDI_AudSWL 24	/* Jeilin case. */
+
+#if (SUPPORT_AUDI_AudSWL == 16)
+#define CHTSTS_SWCODE 0x02
+#elif(SUPPORT_AUDI_AudSWL == 18)
+#define CHTSTS_SWCODE 0x04
+#elif(SUPPORT_AUDI_AudSWL == 20)
+#define CHTSTS_SWCODE 0x03
+#else
+#define CHTSTS_SWCODE 0x0B
+#endif
+
+#endif				/* _HDMITX_H_ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_drv.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_drv.c
new file mode 100644
index 0000000..c65442b
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_drv.c
@@ -0,0 +1,3042 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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 "hdmitx.h"
+#include "hdmitx_drv.h"
+#define FALLING_EDGE_TRIGGER
+
+
+#define MSCOUNT 1000
+#define LOADING_UPDATE_TIMEOUT (3000/32)	/* 3sec */
+/* unsigned short u8msTimer = 0 ; */
+/* unsigned short TimerServF = TRUE ; */
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Authentication status */
+/* //////////////////////////////////////////////////////////////////// */
+
+/* #define TIMEOUT_WAIT_AUTH MS(2000) */
+
+HDMITXDEV hdmiTxDev[HDMITX_MAX_DEV_COUNT];
+
+#ifndef INV_INPUT_PCLK
+#define PCLKINV 0
+#else
+#define PCLKINV B_TX_VDO_LATCH_EDGE
+#endif
+
+#ifndef INV_INPUT_ACLK
+#define InvAudCLK 0
+#else
+#define InvAudCLK B_TX_AUDFMT_FALL_EDGE_SAMPLE_WS
+#endif
+
+#define INIT_CLK_HIGH
+/* #define INIT_CLK_LOW */
+
+RegSetEntry HDMITX_Init_Table[] = {
+
+	{0x0F, 0x40, 0x00}
+	,
+
+	{0x62, 0x08, 0x00}
+	,
+	{0x64, 0x04, 0x00}
+	,
+	{0x01, 0x00, 0x00}
+	,			/* idle(100); */
+
+	{0x04, 0x20, 0x20}
+	,
+	{0x04, 0x1D, 0x1D}
+	,
+	{0x01, 0x00, 0x00}
+	,			/* idle(100); */
+	{0x0F, 0x01, 0x00}
+	,			/* bank 0 ; */
+#ifdef INIT_CLK_LOW
+	{0x62, 0x90, 0x10}
+	,
+	{0x64, 0x89, 0x09}
+	,
+	{0x68, 0x10, 0x10}
+	,
+#endif
+
+	{0xD1, 0x0E, 0x0C}
+	,
+	{0x65, 0x03, 0x00}
+	,
+#ifdef NON_SEQUENTIAL_YCBCR422	/* for ITE HDMIRX */
+	{0x71, 0xFC, 0x1C}
+	,
+#else
+	{0x71, 0xFC, 0x18}
+	,
+#endif
+
+	{0x8D, 0xFF, CEC_I2C_SLAVE_ADDR}
+	,
+	{0x0F, 0x08, 0x08}
+	,
+
+	{0xF8, 0xFF, 0xC3}
+	,
+	{0xF8, 0xFF, 0xA5}
+	,
+	{0x20, 0x80, 0x80}
+	,
+	{0x37, 0x01, 0x00}
+	,
+	{0x20, 0x80, 0x00}
+	,
+	{0xF8, 0xFF, 0xFF}
+	,
+
+	{0x59, 0xD8, 0x40 | PCLKINV}
+	,
+	{0xE1, 0x20, InvAudCLK}
+	,
+	{0x05, 0xC0, 0x40}
+	,
+	{REG_TX_INT_MASK1, 0xFF, ~(B_TX_RXSEN_MASK | B_TX_HPD_MASK)}
+	,
+	{REG_TX_INT_MASK2, 0xFF, ~(B_TX_KSVLISTCHK_MASK | B_TX_AUTH_DONE_MASK | B_TX_AUTH_FAIL_MASK)}
+	,
+	{REG_TX_INT_MASK3, 0xFF, ~(B_TX_VIDSTABLE_MASK)}
+	,
+	{0x0C, 0xFF, 0xFF}
+	,
+	{0x0D, 0xFF, 0xFF}
+	,
+	{0x0E, 0x03, 0x03}
+	,
+
+	{0x0C, 0xFF, 0x00}
+	,
+	{0x0D, 0xFF, 0x00}
+	,
+	{0x0E, 0x02, 0x00}
+	,
+	{0x09, 0x03, 0x00}
+	,			/* Enable HPD and RxSen Interrupt */
+
+	/* {0x6a, 0xff, 0x31}, //hh test */
+	{0, 0, 0}
+};
+
+RegSetEntry HDMITX_DefaultVideo_Table[] = {
+
+	/* ////////////////////////////////////////////////// */
+	/* Config default output format. */
+	/* ////////////////////////////////////////////////// */
+	{0x72, 0xff, 0x00}
+	,
+	{0x70, 0xff, 0x00}
+	,
+#ifndef DEFAULT_INPUT_YCBCR
+/* GenCSC\RGB2YUV_ITU709_16_235.c */
+	{0x72, 0xFF, 0x02}
+	,
+	{0x73, 0xFF, 0x00}
+	,
+	{0x74, 0xFF, 0x80}
+	,
+	{0x75, 0xFF, 0x00}
+	,
+	{0x76, 0xFF, 0xB8}
+	,
+	{0x77, 0xFF, 0x05}
+	,
+	{0x78, 0xFF, 0xB4}
+	,
+	{0x79, 0xFF, 0x01}
+	,
+	{0x7A, 0xFF, 0x93}
+	,
+	{0x7B, 0xFF, 0x00}
+	,
+	{0x7C, 0xFF, 0x49}
+	,
+	{0x7D, 0xFF, 0x3C}
+	,
+	{0x7E, 0xFF, 0x18}
+	,
+	{0x7F, 0xFF, 0x04}
+	,
+	{0x80, 0xFF, 0x9F}
+	,
+	{0x81, 0xFF, 0x3F}
+	,
+	{0x82, 0xFF, 0xD9}
+	,
+	{0x83, 0xFF, 0x3C}
+	,
+	{0x84, 0xFF, 0x10}
+	,
+	{0x85, 0xFF, 0x3F}
+	,
+	{0x86, 0xFF, 0x18}
+	,
+	{0x87, 0xFF, 0x04}
+	,
+#else
+/* GenCSC\YUV2RGB_ITU709_16_235.c */
+	{0x0F, 0x01, 0x00}
+	,
+	{0x72, 0xFF, 0x03}
+	,
+	{0x73, 0xFF, 0x00}
+	,
+	{0x74, 0xFF, 0x80}
+	,
+	{0x75, 0xFF, 0x00}
+	,
+	{0x76, 0xFF, 0x00}
+	,
+	{0x77, 0xFF, 0x08}
+	,
+	{0x78, 0xFF, 0x53}
+	,
+	{0x79, 0xFF, 0x3C}
+	,
+	{0x7A, 0xFF, 0x89}
+	,
+	{0x7B, 0xFF, 0x3E}
+	,
+	{0x7C, 0xFF, 0x00}
+	,
+	{0x7D, 0xFF, 0x08}
+	,
+	{0x7E, 0xFF, 0x51}
+	,
+	{0x7F, 0xFF, 0x0C}
+	,
+	{0x80, 0xFF, 0x00}
+	,
+	{0x81, 0xFF, 0x00}
+	,
+	{0x82, 0xFF, 0x00}
+	,
+	{0x83, 0xFF, 0x08}
+	,
+	{0x84, 0xFF, 0x00}
+	,
+	{0x85, 0xFF, 0x00}
+	,
+	{0x86, 0xFF, 0x87}
+	,
+	{0x87, 0xFF, 0x0E}
+	,
+#endif
+	/* 2012/12/20 added by Keming's suggestion test */
+	{0x88, 0xF0, 0x00}
+	,
+	/* ~jauchih.tseng@ite.com.tw */
+	{0x04, 0x08, 0x00}
+	,
+	{0, 0, 0}
+};
+
+RegSetEntry HDMITX_SetHDMI_Table[] = {
+
+	/* ////////////////////////////////////////////////// */
+	/* Config default HDMI Mode */
+	/* ////////////////////////////////////////////////// */
+	{0xC0, 0x01, 0x01}
+	,
+	{0xC1, 0x03, 0x03}
+	,
+	{0xC6, 0x03, 0x03}
+	,
+	{0, 0, 0}
+};
+
+RegSetEntry HDMITX_SetDVI_Table[] = {
+
+	/* ////////////////////////////////////////////////// */
+	/* Config default HDMI Mode */
+	/* ////////////////////////////////////////////////// */
+	{0x0F, 0x01, 0x01}
+	,
+	{0x58, 0xFF, 0x00}
+	,
+	{0x0F, 0x01, 0x00}
+	,
+	{0xC0, 0x01, 0x00}
+	,
+	{0xC1, 0x03, 0x02}
+	,
+	{0xC6, 0x03, 0x00}
+	,
+	{0, 0, 0}
+};
+
+RegSetEntry HDMITX_DefaultAVIInfo_Table[] = {
+
+	/* ////////////////////////////////////////////////// */
+	/* Config default avi infoframe */
+	/* ////////////////////////////////////////////////// */
+	{0x0F, 0x01, 0x01}
+	,
+	{0x58, 0xFF, 0x10}
+	,
+	{0x59, 0xFF, 0x08}
+	,
+	{0x5A, 0xFF, 0x00}
+	,
+	{0x5B, 0xFF, 0x00}
+	,
+	{0x5C, 0xFF, 0x00}
+	,
+	{0x5D, 0xFF, 0x57}
+	,
+	{0x5E, 0xFF, 0x00}
+	,
+	{0x5F, 0xFF, 0x00}
+	,
+	{0x60, 0xFF, 0x00}
+	,
+	{0x61, 0xFF, 0x00}
+	,
+	{0x62, 0xFF, 0x00}
+	,
+	{0x63, 0xFF, 0x00}
+	,
+	{0x64, 0xFF, 0x00}
+	,
+	{0x65, 0xFF, 0x00}
+	,
+	{0x0F, 0x01, 0x00}
+	,
+	{0xCD, 0x03, 0x03}
+	,
+	{0, 0, 0}
+};
+
+RegSetEntry HDMITX_DeaultAudioInfo_Table[] = {
+
+	/* ////////////////////////////////////////////////// */
+	/* Config default audio infoframe */
+	/* ////////////////////////////////////////////////// */
+	{0x0F, 0x01, 0x01}
+	,
+	{0x68, 0xFF, 0x00}
+	,
+	{0x69, 0xFF, 0x00}
+	,
+	{0x6A, 0xFF, 0x00}
+	,
+	{0x6B, 0xFF, 0x00}
+	,
+	{0x6C, 0xFF, 0x00}
+	,
+	{0x6D, 0xFF, 0x71}
+	,
+	{0x0F, 0x01, 0x00}
+	,
+	{0xCE, 0x03, 0x03}
+	,
+
+	{0, 0, 0}
+};
+
+RegSetEntry HDMITX_Aud_CHStatus_LPCM_20bit_48Khz[] = {
+	{0x0F, 0x01, 0x01}
+	,
+	{0x33, 0xFF, 0x00}
+	,
+	{0x34, 0xFF, 0x18}
+	,
+	{0x35, 0xFF, 0x00}
+	,
+	{0x91, 0xFF, 0x00}
+	,
+	{0x92, 0xFF, 0x00}
+	,
+	{0x93, 0xFF, 0x01}
+	,
+	{0x94, 0xFF, 0x00}
+	,
+	{0x98, 0xFF, 0x02}
+	,
+	{0x99, 0xFF, 0xDA}
+	,
+	{0x0F, 0x01, 0x00}
+	,
+	{0, 0, 0}		/* end of table */
+};
+
+RegSetEntry HDMITX_AUD_SPDIF_2ch_24bit[] = {
+	{0x0F, 0x11, 0x00}
+	,
+	{0x04, 0x14, 0x04}
+	,
+	{0xE0, 0xFF, 0xD1}
+	,
+	{0xE1, 0xFF, 0x01}
+	,
+	{0xE2, 0xFF, 0xE4}
+	,
+	{0xE3, 0xFF, 0x10}
+	,
+	{0xE4, 0xFF, 0x00}
+	,
+	{0xE5, 0xFF, 0x00}
+	,
+	{0x04, 0x14, 0x00}
+	,
+	{0, 0, 0}		/* end of table */
+};
+
+RegSetEntry HDMITX_AUD_I2S_2ch_24bit[] = {
+	{0x0F, 0x11, 0x00}
+	,
+	{0x04, 0x14, 0x04}
+	,
+	{0xE0, 0xFF, 0xC1}
+	,
+	{0xE1, 0xFF, 0x01}
+	,
+	{0xE2, 0xFF, 0xE4}
+	,
+	{0xE3, 0xFF, 0x00}
+	,
+	{0xE4, 0xFF, 0x00}
+	,
+	{0xE5, 0xFF, 0x00}
+	,
+	{0x04, 0x14, 0x00}
+	,
+	{0, 0, 0}		/* end of table */
+};
+
+RegSetEntry HDMITX_DefaultAudio_Table[] = {
+
+	/* ////////////////////////////////////////////////// */
+	/* Config default audio output format. */
+	/* ////////////////////////////////////////////////// */
+	{0x0F, 0x21, 0x00}
+	,
+	{0x04, 0x14, 0x04}
+	,
+	{0xE0, 0xFF, 0xC1}
+	,
+	{0xE1, 0xFF, 0x01}
+	,
+	{0xE2, 0xFF, 0xE4}
+	,
+	{0xE3, 0xFF, 0x00}
+	,
+	{0xE4, 0xFF, 0x00}
+	,
+	{0xE5, 0xFF, 0x00}
+	,
+	{0x0F, 0x01, 0x01}
+	,
+	{0x33, 0xFF, 0x00}
+	,
+	{0x34, 0xFF, 0x18}
+	,
+	{0x35, 0xFF, 0x00}
+	,
+	{0x91, 0xFF, 0x00}
+	,
+	{0x92, 0xFF, 0x00}
+	,
+	{0x93, 0xFF, 0x01}
+	,
+	{0x94, 0xFF, 0x00}
+	,
+	{0x98, 0xFF, 0x02}
+	,
+	{0x99, 0xFF, 0xDB}
+	,
+	{0x0F, 0x01, 0x00}
+	,
+	{0x04, 0x14, 0x00}
+	,
+
+	{0x00, 0x00, 0x00}	/* End of Table. */
+};
+
+RegSetEntry HDMITX_PwrDown_Table[] = {
+	/* Enable GRCLK */
+	{0x0F, 0x40, 0x00}
+	,
+	/* PLL Reset */
+	{0x61, 0x10, 0x10}
+	,			/* DRV_RST */
+	{0x62, 0x08, 0x00}
+	,			/* XP_RESETB */
+	{0x64, 0x04, 0x00}
+	,			/* IP_RESETB */
+	{0x01, 0x00, 0x00}
+	,			/* idle(100); */
+
+	/* PLL PwrDn */
+	{0x61, 0x20, 0x20}
+	,			/* PwrDn DRV */
+	{0x62, 0x44, 0x44}
+	,			/* PwrDn XPLL */
+	{0x64, 0x40, 0x40}
+	,			/* PwrDn IPLL */
+
+	/* HDMITX PwrDn */
+	{0x05, 0x01, 0x01}
+	,			/* PwrDn PCLK */
+	{0x0F, 0x78, 0x78}
+	,			/* PwrDn GRCLK */
+	{0x00, 0x00, 0x00}	/* End of Table. */
+};
+
+RegSetEntry HDMITX_PwrOn_Table[] = {
+	{0x0F, 0x78, 0x38}
+	,			/* PwrOn GRCLK */
+	{0x05, 0x01, 0x00}
+	,			/* PwrOn PCLK */
+
+	/* PLL PwrOn */
+	{0x61, 0x20, 0x00}
+	,			/* PwrOn DRV */
+	{0x62, 0x44, 0x00}
+	,			/* PwrOn XPLL */
+	{0x64, 0x40, 0x00}
+	,			/* PwrOn IPLL */
+
+	/* PLL Reset OFF */
+	{0x61, 0x10, 0x00}
+	,			/* DRV_RST */
+	{0x62, 0x08, 0x08}
+	,			/* XP_RESETB */
+	{0x64, 0x04, 0x04}
+	,			/* IP_RESETB */
+	{0x0F, 0x78, 0x08}
+	,			/* PwrOn IACLK */
+	{0x00, 0x00, 0x00}	/* End of Table. */
+};
+
+#ifdef DETECT_VSYNC_CHG_IN_SAV
+bool EnSavVSync = FALSE;
+#endif
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function Prototype */
+/* //////////////////////////////////////////////////////////////////// */
+
+void HDMITX_InitTxDev(const HDMITXDEV *pInstance)
+{
+	if (pInstance && 0 < HDMITX_MAX_DEV_COUNT)
+		hdmiTxDev[0] = *pInstance;
+}
+
+void InitHDMITX(void)
+{
+	IT66121_LOG("hdmi_ite66121 %s\n", __func__);
+
+#if 1				/* hh test */
+	hdmitx_LoadRegSetting(HDMITX_Init_Table);
+	/* HDMITX_WriteI2C_Byte(REG_TX_INT_CTRL,hdmiTxDev[0].bIntType); */
+	hdmiTxDev[0].bIntPOL = (hdmiTxDev[0].bIntType & B_TX_INTPOL_ACTH) ? TRUE : FALSE;
+
+	/* Avoid power loading in un play status. */
+	/* //////////////////////////////////////////////////////////////// */
+	/* Setup HDCP ROM */
+	/* //////////////////////////////////////////////////////////////// */
+#ifdef HDMITX_INPUT_INFO
+	hdmiTxDev[0].RCLK = CalcRCLK();
+#endif
+	hdmitx_LoadRegSetting(HDMITX_DefaultVideo_Table);
+	hdmitx_LoadRegSetting(HDMITX_SetHDMI_Table);
+	hdmitx_LoadRegSetting(HDMITX_DefaultAVIInfo_Table);
+	hdmitx_LoadRegSetting(HDMITX_DeaultAudioInfo_Table);
+	hdmitx_LoadRegSetting(HDMITX_Aud_CHStatus_LPCM_20bit_48Khz);
+	hdmitx_LoadRegSetting(HDMITX_AUD_SPDIF_2ch_24bit);
+#else
+
+	/* hh test */
+/* Change to Bank 0 */
+	HDMITX_WriteI2C_Byte(0x0F, 0x00);
+/* HDMITX Reset Enable */
+	HDMITX_WriteI2C_Byte(0x04, 0xFF);
+	mdelay(100);
+/* HDMITX Reset Disable */
+	HDMITX_WriteI2C_Byte(0x04, 0x1F);
+/* Switch to PC program DDC mode */
+	HDMITX_WriteI2C_Byte(0x10, 0x01);
+/* HDCP Registers, reg20[0] CPDesired, reg20h[1] 1.1Feature */
+	HDMITX_WriteI2C_Byte(0x20, 0x00);
+	HDMITX_WriteI2C_Byte(0x22, 0x02);
+/* Clock Control Registers */
+	HDMITX_WriteI2C_Byte(0x58, 0x11);
+	HDMITX_WriteI2C_Byte(0x59, 0x00);
+/* input format */
+	HDMITX_WriteI2C_Byte(0x70, 0x48);
+/* input color mode reg70[7:6], sync_emb reg70[3] */
+	HDMITX_WriteI2C_Byte(0x71, 0x00);
+/* EnUdFilt reg72[6], CSCSel reg72h[1:0] */
+	HDMITX_WriteI2C_Byte(0x72, 0x02);
+	HDMITX_WriteI2C_Byte(0x73, 0x10);
+	HDMITX_WriteI2C_Byte(0x74, 0x80);
+	HDMITX_WriteI2C_Byte(0x75, 0x10);
+/* CSC Matrix : RGB to YUV */
+	HDMITX_WriteI2C_Byte(0x76, 0xB2);
+	HDMITX_WriteI2C_Byte(0x77, 0x04);
+	HDMITX_WriteI2C_Byte(0x78, 0x64);
+	HDMITX_WriteI2C_Byte(0x79, 0x02);
+	HDMITX_WriteI2C_Byte(0x7A, 0xE9);
+	HDMITX_WriteI2C_Byte(0x7B, 0x00);
+	HDMITX_WriteI2C_Byte(0x7C, 0x93);
+	HDMITX_WriteI2C_Byte(0x7D, 0x1C);
+	HDMITX_WriteI2C_Byte(0x7E, 0x16);
+	HDMITX_WriteI2C_Byte(0x7F, 0x04);
+	HDMITX_WriteI2C_Byte(0x80, 0x56);
+	HDMITX_WriteI2C_Byte(0x81, 0x1F);
+	HDMITX_WriteI2C_Byte(0x82, 0x49);
+	HDMITX_WriteI2C_Byte(0x83, 0x1D);
+	HDMITX_WriteI2C_Byte(0x84, 0x9F);
+	HDMITX_WriteI2C_Byte(0x85, 0x1E);
+	HDMITX_WriteI2C_Byte(0x86, 0x16);
+	HDMITX_WriteI2C_Byte(0x87, 0x04);
+	HDMITX_WriteI2C_Byte(0x88, 0xC0);
+	HDMITX_WriteI2C_Byte(0x89, 0x0D);
+	HDMITX_WriteI2C_Byte(0x8A, 0xC0);
+	HDMITX_WriteI2C_Byte(0x8B, 0x0D);
+	HDMITX_WriteI2C_Byte(0x8C, 0xC0);
+	HDMITX_WriteI2C_Byte(0x8D, 0x0D);
+/* SYNC/DE Generation */
+	HDMITX_WriteI2C_Byte(0x0F, 0x00);
+	HDMITX_WriteI2C_Byte(0x90, 0x16);
+	HDMITX_WriteI2C_Byte(0x91, 0x67);
+	HDMITX_WriteI2C_Byte(0x92, 0x04);
+	HDMITX_WriteI2C_Byte(0x93, 0x04);
+	HDMITX_WriteI2C_Byte(0x94, 0x61);
+	HDMITX_WriteI2C_Byte(0x95, 0x01);
+	HDMITX_WriteI2C_Byte(0x96, 0x28);
+	HDMITX_WriteI2C_Byte(0x97, 0x00);
+	HDMITX_WriteI2C_Byte(0x98, 0xED);
+	HDMITX_WriteI2C_Byte(0x99, 0x02);
+	HDMITX_WriteI2C_Byte(0x9A, 0x19);
+	HDMITX_WriteI2C_Byte(0x9B, 0xE9);
+	HDMITX_WriteI2C_Byte(0x9C, 0x20);
+	HDMITX_WriteI2C_Byte(0x9D, 0x07);
+	HDMITX_WriteI2C_Byte(0x9E, 0xD7);
+	HDMITX_WriteI2C_Byte(0x9F, 0x53);
+	HDMITX_WriteI2C_Byte(0xA0, 0x00);
+	HDMITX_WriteI2C_Byte(0xA1, 0x50);
+	HDMITX_WriteI2C_Byte(0xA2, 0xEE);
+	HDMITX_WriteI2C_Byte(0xA3, 0x32);
+	HDMITX_WriteI2C_Byte(0xA4, 0x38);
+	HDMITX_WriteI2C_Byte(0xA5, 0x03);
+	HDMITX_WriteI2C_Byte(0xA6, 0xF0);
+	HDMITX_WriteI2C_Byte(0xB1, 0x00);
+	HDMITX_WriteI2C_Byte(0xB2, 0x00);
+	HDMITX_WriteI2C_Byte(0xA8, 0x01);
+/* PGEn = regA8[0] */
+	HDMITX_WriteI2C_Byte(0xA9, 0x00);	/* 11 */
+	HDMITX_WriteI2C_Byte(0xAA, 0x20);
+	HDMITX_WriteI2C_Byte(0xAB, 0x20);
+	HDMITX_WriteI2C_Byte(0xAC, 0x20);
+	HDMITX_WriteI2C_Byte(0xAD, 0x00);
+	HDMITX_WriteI2C_Byte(0xAE, 0x00);
+	HDMITX_WriteI2C_Byte(0xAF, 0x04);
+	HDMITX_WriteI2C_Byte(0xB0, 0x08);
+/* HDMI General Control , HDMIMODE REGC0H[0] */
+	HDMITX_WriteI2C_Byte(0xC0, 0x01);
+	HDMITX_WriteI2C_Byte(0xC1, 0x00);
+	HDMITX_WriteI2C_Byte(0xC2, 0x0A);
+	HDMITX_WriteI2C_Byte(0xC3, 0x08);
+	HDMITX_WriteI2C_Byte(0xC4, 0x00);
+	HDMITX_WriteI2C_Byte(0xC5, 0x00);
+	HDMITX_WriteI2C_Byte(0xC6, 0x03);
+	HDMITX_WriteI2C_Byte(0xC7, 0x00);
+	HDMITX_WriteI2C_Byte(0xC8, 0x00);
+	HDMITX_WriteI2C_Byte(0xC9, 0x03);
+	HDMITX_WriteI2C_Byte(0xCA, 0x00);
+	HDMITX_WriteI2C_Byte(0xCB, 0x00);
+	HDMITX_WriteI2C_Byte(0xCC, 0x00);
+	HDMITX_WriteI2C_Byte(0xCD, 0x03);
+	HDMITX_WriteI2C_Byte(0xCE, 0x03);
+	HDMITX_WriteI2C_Byte(0xCF, 0x00);
+	HDMITX_WriteI2C_Byte(0xD0, 0x00);
+/* Audio Channel Registers */
+	HDMITX_WriteI2C_Byte(0xE0, 0xDF);	/* [7:6]=REGAudSWL, [5]=REGSPDIFTC, [4]=REGAudSel, [3:0]=REGAudioEn */
+	HDMITX_WriteI2C_Byte(0xE1, 0x01);
+	HDMITX_WriteI2C_Byte(0xE2, 0x00);	/* SRC0/1/2/3 maps to SRC0 */
+	HDMITX_WriteI2C_Byte(0xE3, 0x00);
+	HDMITX_WriteI2C_Byte(0xE4, 0x08);
+/* Change to Bank 1 */
+	HDMITX_WriteI2C_Byte(0x0F, 0x01);
+/* N/CTS Packet */
+	HDMITX_WriteI2C_Byte(0x30, 0x00);
+	HDMITX_WriteI2C_Byte(0x31, 0x00);
+	HDMITX_WriteI2C_Byte(0x32, 0x00);
+	HDMITX_WriteI2C_Byte(0x33, 0x00);
+	HDMITX_WriteI2C_Byte(0x34, 0x60);
+	HDMITX_WriteI2C_Byte(0x35, 0x00);
+/* Audio Sample Packet */
+	HDMITX_WriteI2C_Byte(0x36, 0x00);
+	HDMITX_WriteI2C_Byte(0x37, 0x30);
+/* Null Packet */
+	HDMITX_WriteI2C_Byte(0x38, 0x00);
+	HDMITX_WriteI2C_Byte(0x39, 0x00);
+	HDMITX_WriteI2C_Byte(0x3A, 0x00);
+	HDMITX_WriteI2C_Byte(0x3B, 0x00);
+	HDMITX_WriteI2C_Byte(0x3C, 0x00);
+	HDMITX_WriteI2C_Byte(0x3D, 0x00);
+	HDMITX_WriteI2C_Byte(0x3E, 0x00);
+	HDMITX_WriteI2C_Byte(0x3F, 0x00);
+	HDMITX_WriteI2C_Byte(0x40, 0x00);
+	HDMITX_WriteI2C_Byte(0x41, 0x00);
+	HDMITX_WriteI2C_Byte(0x42, 0x00);
+	HDMITX_WriteI2C_Byte(0x43, 0x00);
+	HDMITX_WriteI2C_Byte(0x44, 0x00);
+	HDMITX_WriteI2C_Byte(0x45, 0x00);
+	HDMITX_WriteI2C_Byte(0x46, 0x00);
+	HDMITX_WriteI2C_Byte(0x47, 0x00);
+	HDMITX_WriteI2C_Byte(0x48, 0x00);
+	HDMITX_WriteI2C_Byte(0x49, 0x00);
+	HDMITX_WriteI2C_Byte(0x4A, 0x00);
+	HDMITX_WriteI2C_Byte(0x4B, 0x00);
+	HDMITX_WriteI2C_Byte(0x4C, 0x00);
+	HDMITX_WriteI2C_Byte(0x4D, 0x00);
+	HDMITX_WriteI2C_Byte(0x4E, 0x00);
+	HDMITX_WriteI2C_Byte(0x4F, 0x00);
+	HDMITX_WriteI2C_Byte(0x50, 0x00);
+	HDMITX_WriteI2C_Byte(0x51, 0x00);
+	HDMITX_WriteI2C_Byte(0x52, 0x00);
+	HDMITX_WriteI2C_Byte(0x53, 0x00);
+	HDMITX_WriteI2C_Byte(0x54, 0x00);
+	HDMITX_WriteI2C_Byte(0x55, 0x00);
+	HDMITX_WriteI2C_Byte(0x56, 0x00);
+/* AVI Packet */
+	HDMITX_WriteI2C_Byte(0x58, 0x20);	/* D[6:5] color mode */
+	HDMITX_WriteI2C_Byte(0x59, 0x08);
+	HDMITX_WriteI2C_Byte(0x5A, 0x00);
+	HDMITX_WriteI2C_Byte(0x5B, 0x04);	/* Video Format Code */
+	HDMITX_WriteI2C_Byte(0x5C, 0x00);
+	HDMITX_WriteI2C_Byte(0x5D, 0x43);	/* CheckSum */
+	HDMITX_WriteI2C_Byte(0x5E, 0x00);
+	HDMITX_WriteI2C_Byte(0x5F, 0x00);
+	HDMITX_WriteI2C_Byte(0x60, 0x00);
+	HDMITX_WriteI2C_Byte(0x61, 0x00);
+	HDMITX_WriteI2C_Byte(0x62, 0x00);
+	HDMITX_WriteI2C_Byte(0x63, 0x00);
+	HDMITX_WriteI2C_Byte(0x64, 0x00);
+	HDMITX_WriteI2C_Byte(0x65, 0x00);
+/* AUDIO Info Frame */
+	HDMITX_WriteI2C_Byte(0x68, 0x07);	/* should be 00, temp assign for solving MulCh problem */
+	HDMITX_WriteI2C_Byte(0x69, 0x00);
+	HDMITX_WriteI2C_Byte(0x6A, 0x00);
+	HDMITX_WriteI2C_Byte(0x6B, 0x1F);	/* InfoCA */
+	HDMITX_WriteI2C_Byte(0x6C, 0x00);
+	HDMITX_WriteI2C_Byte(0x6D, 0x4B);	/* CA=1F */
+/* SPD Packet */
+	HDMITX_WriteI2C_Byte(0x70, 0x00);	/* Checksum */
+	HDMITX_WriteI2C_Byte(0x71, 0x00);
+	HDMITX_WriteI2C_Byte(0x72, 0x00);
+	HDMITX_WriteI2C_Byte(0x73, 0x00);
+	HDMITX_WriteI2C_Byte(0x74, 0x00);
+	HDMITX_WriteI2C_Byte(0x75, 0x00);
+	HDMITX_WriteI2C_Byte(0x76, 0x00);
+	HDMITX_WriteI2C_Byte(0x78, 0x00);
+	HDMITX_WriteI2C_Byte(0x79, 0x00);
+	HDMITX_WriteI2C_Byte(0x7A, 0x00);
+	HDMITX_WriteI2C_Byte(0x7B, 0x00);
+	HDMITX_WriteI2C_Byte(0x7C, 0x00);
+	HDMITX_WriteI2C_Byte(0x7D, 0x00);
+	HDMITX_WriteI2C_Byte(0x7E, 0x00);
+	HDMITX_WriteI2C_Byte(0x7F, 0x00);
+	HDMITX_WriteI2C_Byte(0x80, 0x00);
+	HDMITX_WriteI2C_Byte(0x81, 0x00);
+	HDMITX_WriteI2C_Byte(0x82, 0x00);
+	HDMITX_WriteI2C_Byte(0x83, 0x00);
+	HDMITX_WriteI2C_Byte(0x84, 0x00);
+	HDMITX_WriteI2C_Byte(0x85, 0x00);
+	HDMITX_WriteI2C_Byte(0x86, 0x00);
+	HDMITX_WriteI2C_Byte(0x87, 0x00);
+	HDMITX_WriteI2C_Byte(0x88, 0x00);
+	HDMITX_WriteI2C_Byte(0x89, 0x00);
+/* MPEG Info Frame */
+	HDMITX_WriteI2C_Byte(0x8A, 0x00);
+	HDMITX_WriteI2C_Byte(0x8B, 0x00);
+	HDMITX_WriteI2C_Byte(0x8C, 0x00);
+	HDMITX_WriteI2C_Byte(0x8D, 0x00);
+	HDMITX_WriteI2C_Byte(0x8E, 0x00);
+	HDMITX_WriteI2C_Byte(0x8F, 0x00);	/* Checksum */
+/* Audio Channel Status */
+	HDMITX_WriteI2C_Byte(0x91, 0x00);
+	HDMITX_WriteI2C_Byte(0x92, 0x80);
+	HDMITX_WriteI2C_Byte(0x93, 0x04);
+	HDMITX_WriteI2C_Byte(0x94, 0x21);
+	HDMITX_WriteI2C_Byte(0x95, 0x43);
+	HDMITX_WriteI2C_Byte(0x96, 0x65);
+	HDMITX_WriteI2C_Byte(0x97, 0x87);
+	HDMITX_WriteI2C_Byte(0x98, 0x0E);	/* Sampling Frequency */
+	HDMITX_WriteI2C_Byte(0x99, 0x1B);
+/* Change to Bank 0 */
+	HDMITX_WriteI2C_Byte(0x0F, 0x00);
+/* HDMITX VCLK Reset Disable */
+	HDMITX_WriteI2C_Byte(0x04, 0x14);
+	HDMITX_WriteI2C_Byte(0xF3, 0x00);
+	HDMITX_WriteI2C_Byte(0xF4, 0x00);
+/* All HDMITX Reset Disable */
+	HDMITX_WriteI2C_Byte(0x04, 0x15);
+/* Enable HDMITX AFE */
+	HDMITX_WriteI2C_Byte(0x61, 0x00);
+#endif
+	/* ////////////////////////////////////////////////// */
+
+/* HDMITX_DEBUG_PRINTF( */
+/* "-----------------------------------------------------\n" */
+/* "Init HDMITX\n" */
+/* "-----------------------------------------------------\n"); */
+
+	/*DumpHDMITXReg();*/
+}
+
+bool getHDMITX_LinkStatus(void)
+{
+
+	unsigned char reg2 = 0xff;
+	unsigned char reg1 = HDMITX_ReadI2C_Byte(REG_TX_SYS_STATUS);
+
+	IT66121_LOG("hdmi_ite66121 %s\n", __func__);
+
+	if (B_TX_RXSENDETECT & reg1) {
+		reg2 = HDMITX_ReadI2C_Byte(REG_TX_AFE_DRV_CTRL);
+		if (reg2 == 0) {
+			IT66121_LOG("getHDMITX_LinkStatus(reg[0E]=%x, reg[61]=%x) OK!!\n",
+					    reg1, reg2);
+			return TRUE;
+		}
+	}
+	IT66121_LOG("GetTMDS(reg[0E]=%x, reg[61]=%x) NOT Ready()!!\n", reg1, reg2);
+
+	return FALSE;
+}
+
+unsigned char CheckHDMITX(unsigned char *pHPD, unsigned char *pHPDChange)
+{
+
+	unsigned char intdata1, intdata2, intdata3, sysstat;
+	unsigned char intclr3 = 0;
+	unsigned char PrevHPD = hdmiTxDev[0].bHPD;
+	unsigned char HPD;
+
+	IT66121_LOG("hdmi_ite66121 %s\n", __func__);
+
+	sysstat = HDMITX_ReadI2C_Byte(REG_TX_SYS_STATUS);
+	/* HDMITX_DEBUG_PRINTF("REG_TX_SYS_STATUS = %X\n",sysstat); */
+
+	if ((sysstat & (B_TX_HPDETECT /*|B_TX_RXSENDETECT */)) ==
+	    (B_TX_HPDETECT /*|B_TX_RXSENDETECT */)) {
+		HPD = TRUE;
+	} else {
+		HPD = FALSE;
+	}
+	/* CheckClockStable(sysstat); */
+	/* 2007/06/20 added by jj_tseng@chipadvanced.com */
+
+	if (pHPDChange)
+		*pHPDChange = (PrevHPD != HPD) ? TRUE : FALSE;
+	/* default give pHPDChange value compared to previous HPD value. */
+
+	if (HPD == FALSE)
+		hdmiTxDev[0].bAuthenticated = FALSE;
+
+	if (sysstat & B_TX_INT_ACTIVE) {
+		/* HDMITX_DEBUG_PRINTF("REG_TX_SYS_STATUS = 0x%x\n",(int)sysstat); */
+
+		intdata1 = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1);
+		/* HDMITX_DEBUG_PRINTF("INT_Handler: reg%X = %X\n",(int)REG_TX_INT_STAT1,(int)intdata1); */
+		if (intdata1 & B_TX_INT_AUD_OVERFLOW) {
+			HDMITX_DEBUG_PRINTF("B_TX_INT_AUD_OVERFLOW.\n");
+			HDMITX_OrReg_Byte(REG_TX_SW_RST, (B_HDMITX_AUD_RST | B_TX_AREF_RST));
+			HDMITX_AndReg_Byte(REG_TX_SW_RST, ~(B_HDMITX_AUD_RST | B_TX_AREF_RST));
+			/* AudioDelayCnt=AudioOutDelayCnt; */
+			/* LastRefaudfreqnum=0; */
+		}
+		if (intdata1 & B_TX_INT_DDCFIFO_ERR) {
+			HDMITX_DEBUG_PRINTF("DDC FIFO Error.\n");
+			hdmitx_ClearDDCFIFO();
+			hdmiTxDev[0].bAuthenticated = FALSE;
+		}
+		if (intdata1 & B_TX_INT_DDC_BUS_HANG) {
+			HDMITX_DEBUG_PRINTF("DDC BUS HANG.\n");
+			hdmitx_AbortDDC();
+
+			if (hdmiTxDev[0].bAuthenticated) {
+				HDMITX_DEBUG_PRINTF
+				    ("when DDC hang,and aborted DDC,the HDCP authentication need to restart.\n");
+#ifdef SUPPORT_HDCP
+				hdmitx_hdcp_ResumeAuthentication();
+#endif
+			}
+		}
+		if (intdata1 & (B_TX_INT_HPD_PLUG /*|B_TX_INT_RX_SENSE */)) {
+
+			if (pHPDChange)
+				*pHPDChange = TRUE;
+
+			if (HPD == FALSE) {
+
+				/*HDMITX_WriteI2C_Byte(REG_TX_SW_RST,B_TX_AREF_RST|B_HDMITX_VID_RST| */
+				/*B_HDMITX_AUD_RST|B_TX_HDCP_RST_HDMITX); */
+				/*delay1ms(1); */
+				/*HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL,B_TX_AFE_DRV_RST|B_TX_AFE_DRV_PWD); */
+
+				/* HDMITX_DEBUG_PRINTF("Unplug,%x %x\n",*/
+				/*(int)HDMITX_ReadI2C_Byte(REG_TX_SW_RST),*/
+				/*(int)HDMITX_ReadI2C_Byte(REG_TX_AFE_DRV_CTRL)); */
+			}
+		}
+		if (intdata1 & (B_TX_INT_RX_SENSE))
+			hdmiTxDev[0].bAuthenticated = FALSE;
+
+		intdata2 = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT2);
+		/* HDMITX_DEBUG_PRINTF("INT_Handler: reg%X = %X\n",(int)REG_TX_INT_STAT2,(int)intdata2); */
+
+#ifdef SUPPORT_HDCP
+		if (intdata2 & B_TX_INT_AUTH_DONE) {
+			HDMITX_DEBUG_PRINTF("interrupt Authenticate Done.\n");
+			HDMITX_OrReg_Byte(REG_TX_INT_MASK2, (unsigned char) B_TX_AUTH_DONE_MASK);
+			/* hdmiTxDev[0].bAuthenticated = TRUE ; */
+			/* setHDMITX_AVMute(FALSE); */
+		}
+		if (intdata2 & B_TX_INT_AUTH_FAIL) {
+			hdmiTxDev[0].bAuthenticated = FALSE;
+			/* HDMITX_DEBUG_PRINTF("interrupt Authenticate Fail.\n"); */
+			hdmitx_AbortDDC();	/* @emily add */
+			/* hdmitx_hdcp_ResumeAuthentication(); */
+		}
+#endif				/* SUPPORT_HDCP */
+
+
+		/*  intdata3 = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT3);*/
+		/*  if(intdata3 & B_TX_INT_VIDSTABLE)*/
+		 /*  {*/
+		 /*  sysstat = HDMITX_ReadI2C_Byte(REG_TX_SYS_STATUS);*/
+		 /*  if(sysstat & B_TXVIDSTABLE)*/
+		 /*  {*/
+		 /*  hdmitx_FireAFE();*/
+		 /*  }*/
+		 /*  }*/
+
+		intdata3 = HDMITX_ReadI2C_Byte(0xEE);
+		if (intdata3) {
+			HDMITX_WriteI2C_Byte(0xEE, intdata3);	/* clear ext interrupt ; */
+			HDMITX_DEBUG_PRINTF("%s%s%s%s%s%s%s\n",
+					    (intdata3 & 0x40) ? "video parameter change " : "",
+					    (intdata3 & 0x20) ? "HDCP Pj check done " : "",
+					    (intdata3 & 0x10) ? "HDCP Ri check done " : "",
+					    (intdata3 & 0x8) ? "DDC bus hang " : "",
+					    (intdata3 & 0x4) ? "Video input FIFO auto reset " : "",
+					    (intdata3 & 0x2) ? "No audio input interrupt  " : "",
+					    (intdata3 & 0x1) ? "Audio decode error interrupt " :
+					    "");
+		}
+		HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0, 0xFF);
+		HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1, 0xFF);
+		intclr3 =
+		    (HDMITX_ReadI2C_Byte(REG_TX_SYS_STATUS)) | B_TX_CLR_AUD_CTS | B_TX_INTACTDONE;
+		HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS, intclr3);	/* clear interrupt. */
+		intclr3 &= ~(B_TX_INTACTDONE);
+		HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS, intclr3);	/* INTACTDONE reset to zero. */
+	}
+	/*  */
+	/* else */
+	/* { */
+	/* if(pHPDChange) */
+	/* { */
+	/* if(HPD != PrevHPD) */
+	/* { */
+	/* *pHPDChange = TRUE; */
+	/* } */
+	/* else */
+	/* { */
+	/* *pHPDChange = FALSE; */
+	/* } */
+	/* } */
+	/* } */
+	if (pHPDChange) {
+		if ((*pHPDChange == TRUE) && (HPD == FALSE)) {
+			HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL,
+					     B_TX_AFE_DRV_RST | B_TX_AFE_DRV_PWD);
+		}
+	}
+	if (pHPD)
+		*pHPD = HPD;
+
+	hdmiTxDev[0].bHPD = HPD;
+	return HPD;
+}
+
+void HDMITX_PowerOn(void)
+{
+	IT66121_LOG("hdmi_ite66121 %s\n", __func__);
+
+	hdmitx_LoadRegSetting(HDMITX_PwrOn_Table);
+}
+
+void HDMITX_PowerDown(void)
+{
+	IT66121_LOG("hdmi_ite66121 %s\n", __func__);
+	hdmitx_LoadRegSetting(HDMITX_PwrDown_Table);
+}
+
+void setHDMITX_AVMute(unsigned char bEnable)
+{
+	Switch_HDMITX_Bank(0);
+	HDMITX_SetI2C_Byte(REG_TX_GCP, B_TX_SETAVMUTE, bEnable ? B_TX_SETAVMUTE : 0);
+	HDMITX_WriteI2C_Byte(REG_TX_PKT_GENERAL_CTRL, B_TX_ENABLE_PKT | B_TX_REPEAT_PKT);
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_LoadRegSetting() */
+/* Input: RegSetEntry SettingTable[] ; */
+/* Return: N/A */
+/* Remark: if an entry {0, 0, 0} will be terminated. */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_LoadRegSetting(RegSetEntry table[])
+{
+
+	int i;
+
+	IT66121_LOG("hdmi_ite66121 %s\n", __func__);
+
+	for (i = 0;; i++) {
+		if (table[i].offset == 0 && table[i].invAndMask == 0 && table[i].OrMask == 0) {
+			return;
+		} else if (table[i].invAndMask == 0 && table[i].OrMask == 0) {
+			/* MITX_DEBUG_PRINTF2("delay(%d)\n",(int)table[i].offset); */
+			delay1ms(table[i].offset);
+		} else if (table[i].invAndMask == 0xFF) {
+			/* MITX_DEBUG_PRINTF2("HDMITX_WriteI2C_Byte(%02x,%02x)\n",*/
+			/* (int)table[i].offset,(int)table[i].OrMask); */
+			HDMITX_WriteI2C_Byte(table[i].offset, table[i].OrMask);
+		} else {
+			/* MITX_DEBUG_PRINTF2("HDMITX_SetI2C_Byte(%02x,%02x,%02x)\n",*/
+			/*	(int)table[i].offset,(int)table[i].invAndMask,(int)table[i].OrMask); */
+			HDMITX_SetI2C_Byte(table[i].offset, table[i].invAndMask, table[i].OrMask);
+		}
+	}
+}
+
+/****************************************** */
+/* @file   <hdmitx_ddc.c> */
+/* *******************************************/
+
+bool getHDMITX_EDIDBlock(int EDIDBlockID, unsigned char *pEDIDData)
+{
+	if (!pEDIDData)
+		return FALSE;
+
+	if (getHDMITX_EDIDBytes(pEDIDData, EDIDBlockID / 2, (EDIDBlockID % 2) * 128, 128) ==
+	    ER_FAIL) {
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: getHDMITX_EDIDBytes */
+/* Parameter: pData - the pointer of buffer to receive EDID ucdata. */
+/* bSegment - the segment of EDID readback. */
+/* offset - the offset of EDID ucdata in the segment. in byte. */
+/* count - the read back bytes count,cannot exceed 32 */
+/* Return: ER_SUCCESS if successfully getting EDID. ER_FAIL otherwise. */
+/* Remark: function for read EDID ucdata from receiver. */
+/* Side-Effect: DDC master will set to be HOST. DDC FIFO will be used and dirty. */
+/* //////////////////////////////////////////////////////////////////// */
+
+SYS_STATUS getHDMITX_EDIDBytes(unsigned char *pData, unsigned char bSegment, unsigned char offset, short Count)
+{
+	short RemainedCount, ReqCount;
+	unsigned char bCurrOffset;
+	short TimeOut;
+	unsigned char *pBuff = pData;
+	unsigned char ucdata;
+
+	/* HDMITX_DEBUG_PRINTF("getHDMITX_EDIDBytes(%08lX,%d,%d,%d)\n",*/
+	/* (ULONG)pData,(int)bSegment,(int)offset,(int)Count); */
+	if (!pData) {
+	/* HDMITX_DEBUG_PRINTF("getHDMITX_EDIDBytes(): */
+	/* Invallid pData pointer %08lX\n",(ULONG)pData); */
+		return ER_FAIL;
+	}
+	if (HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1) & B_TX_INT_DDC_BUS_HANG) {
+		HDMITX_DEBUG_PRINTF("Called hdmitx_AboutDDC()\n");
+		hdmitx_AbortDDC();
+
+	}
+	/* HDMITX_OrReg_Byte(REG_TX_INT_CTRL,(1<<1)); */
+
+	hdmitx_ClearDDCFIFO();
+
+	RemainedCount = Count;
+	bCurrOffset = offset;
+
+	Switch_HDMITX_Bank(0);
+
+	while (RemainedCount > 0) {
+
+		ReqCount = (RemainedCount > DDC_FIFO_MAXREQ) ? DDC_FIFO_MAXREQ : RemainedCount;
+		/* HDMITX_DEBUG_PRINTF("getHDMITX_EDIDBytes(): */
+		/* ReqCount = %d,bCurrOffset = %d\n",(int)ReqCount,(int)bCurrOffset); */
+
+		HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
+		HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD, CMD_FIFO_CLR);
+
+		for (TimeOut = 0; TimeOut < 200; TimeOut++) {
+			ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS);
+
+			if (ucdata & B_TX_DDC_DONE)
+				break;
+
+			if ((ucdata & B_TX_DDC_ERROR)
+			    || (HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1) & B_TX_INT_DDC_BUS_HANG)) {
+				HDMITX_DEBUG_PRINTF("Called hdmitx_AboutDDC()\n");
+				hdmitx_AbortDDC();
+				return ER_FAIL;
+			}
+		}
+		/* HDMITX_DEBUG_PRINTF("start getting EDID data via DDC..\n"); */
+		HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
+		HDMITX_WriteI2C_Byte(REG_TX_DDC_HEADER, DDC_EDID_ADDRESS);	/* for EDID ucdata get */
+		HDMITX_WriteI2C_Byte(REG_TX_DDC_REQOFF, bCurrOffset);
+		HDMITX_WriteI2C_Byte(REG_TX_DDC_REQCOUNT, (unsigned char) ReqCount);
+		HDMITX_WriteI2C_Byte(REG_TX_DDC_EDIDSEG, bSegment);
+		HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD, CMD_EDID_READ);
+
+		bCurrOffset += ReqCount;
+		RemainedCount -= ReqCount;
+
+		for (TimeOut = 250; TimeOut > 0; TimeOut--) {
+			//msleep(20);// fix build error
+			ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS);
+			if (ucdata & B_TX_DDC_DONE)
+				break;
+
+			if (ucdata & B_TX_DDC_ERROR) {
+				HDMITX_DEBUG_PRINTF
+				    ("getHDMITX_EDIDBytes(): DDC_STATUS = %02X,fail.\n",
+				     (int)ucdata);
+				/* HDMITX_AndReg_Byte(REG_TX_INT_CTRL,~(1<<1)); */
+				return ER_FAIL;
+			}
+		}
+		if (TimeOut == 0) {
+			HDMITX_DEBUG_PRINTF("getHDMITX_EDIDBytes(): DDC TimeOut.\n");
+			/* HDMITX_AndReg_Byte(REG_TX_INT_CTRL,~(1<<1)); */
+			return ER_FAIL;
+		}
+		do {
+			*(pBuff++) = HDMITX_ReadI2C_Byte(REG_TX_DDC_READFIFO);
+			ReqCount--;
+		} while (ReqCount > 0);
+
+	}
+	/* HDMITX_AndReg_Byte(REG_TX_INT_CTRL,~(1<<1)); */
+	return ER_SUCCESS;
+}
+
+/* /////////////////////////// */
+/* DDC Function. */
+/* //////////////////////////////////////////////////////////////////// */
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_ClearDDCFIFO */
+/* Parameter: N/A */
+/* Return: N/A */
+/* Remark: clear the DDC FIFO. */
+/* Side-Effect: DDC master will set to be HOST. */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_ClearDDCFIFO(void)
+{
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD, CMD_FIFO_CLR);
+}
+
+void hdmitx_GenerateDDCSCLK(void)
+{
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD, CMD_GEN_SCLCLK);
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_AbortDDC */
+/* Parameter: N/A */
+/* Return: N/A */
+/* Remark: Force abort DDC and reset DDC bus. */
+/* Side-Effect: */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_AbortDDC(void)
+{
+	unsigned char CPDesire, SWReset, DDCMaster;
+	unsigned char uc, timeout, i;
+	/* save the SW reset,DDC master,and CP Desire setting. */
+	SWReset = HDMITX_ReadI2C_Byte(REG_TX_SW_RST);
+	CPDesire = HDMITX_ReadI2C_Byte(REG_TX_HDCP_DESIRE);
+	DDCMaster = HDMITX_ReadI2C_Byte(REG_TX_DDC_MASTER_CTRL);
+
+	HDMITX_WriteI2C_Byte(REG_TX_HDCP_DESIRE, CPDesire & (~B_TX_CPDESIRE));	/* @emily change order */
+	HDMITX_WriteI2C_Byte(REG_TX_SW_RST, SWReset | B_TX_HDCP_RST_HDMITX);	/* @emily change order */
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
+
+	/* 2009/01/15 modified by Jau-Chih.Tseng@ite.com.tw */
+	/* do abort DDC twice. */
+	for (i = 0; i < 2; i++) {
+		HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD, CMD_DDC_ABORT);
+
+		for (timeout = 0; timeout < 200; timeout++) {
+			uc = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS);
+			if (uc & B_TX_DDC_DONE)
+				break;	/* success */
+
+			if (uc & (B_TX_DDC_NOACK | B_TX_DDC_WAITBUS | B_TX_DDC_ARBILOSE)) {
+/* HDMITX_DEBUG_PRINTF("hdmitx_AbortDDC Fail by reg16=%02X\n",(int)uc); */
+				break;
+			}
+			delay1ms(1);	/* delay 1 ms to stable. */
+		}
+	}
+	/* ~Jau-Chih.Tseng@ite.com.tw */
+
+}
+
+/****************************************** */
+/* @file   <hdmitx_vid.c> */
+/* *******************************************/
+
+
+/* //////////////////////////////////////////////////////////////////// */
+/* utility function for main.. */
+/* //////////////////////////////////////////////////////////////////// */
+
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function Body. */
+/* //////////////////////////////////////////////////////////////////// */
+
+void HDMITX_DisableVideoOutput(void)
+{
+
+	unsigned char uc = HDMITX_ReadI2C_Byte(REG_TX_SW_RST) | B_HDMITX_VID_RST;
+
+	IT66121_LOG("hdmi_ite66121 %s\n", __func__);
+
+	HDMITX_WriteI2C_Byte(REG_TX_SW_RST, uc);
+	HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL, B_TX_AFE_DRV_RST | B_TX_AFE_DRV_PWD);
+	HDMITX_SetI2C_Byte(0x62, 0x90, 0x00);
+	HDMITX_SetI2C_Byte(0x64, 0x89, 0x00);
+}
+
+bool HDMITX_EnableVideoOutput(VIDEOPCLKLEVEL level, unsigned char inputColorMode, unsigned char outputColorMode,
+			      unsigned char bHDMI)
+{
+	/* bInputVideoMode,bOutputVideoMode,hdmiTxDev[0].bInputVideoSignalType,*/
+	/* bAudioInputType,should be configured by upper F/W or loaded from EEPROM. */
+	/* should be configured by initsys.c */
+	/* VIDEOPCLKLEVEL level ; */
+
+	HDMITX_WriteI2C_Byte(REG_TX_SW_RST,
+			     B_HDMITX_VID_RST | B_HDMITX_AUD_RST | B_TX_AREF_RST |
+			     B_TX_HDCP_RST_HDMITX);
+
+	hdmiTxDev[0].bHDMIMode = (unsigned char) bHDMI;
+	/* 2009/12/09 added by jau-chih.tseng@ite.com.tw */
+	Switch_HDMITX_Bank(1);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB1, 0x00);
+	Switch_HDMITX_Bank(0);
+	/* ~jau-chih.tseng@ite.com.tw */
+
+	if (hdmiTxDev[0].bHDMIMode)
+		setHDMITX_AVMute(TRUE);
+
+	hdmitx_SetInputMode(inputColorMode, hdmiTxDev[0].bInputVideoSignalType);
+
+	hdmitx_SetCSCScale(inputColorMode, outputColorMode);
+
+	if (hdmiTxDev[0].bHDMIMode)
+		HDMITX_WriteI2C_Byte(REG_TX_HDMI_MODE, B_TX_HDMI_MODE);
+	else
+		HDMITX_WriteI2C_Byte(REG_TX_HDMI_MODE, B_TX_DVI_MODE);
+
+#ifdef INVERT_VID_LATCHEDGE
+	uc = HDMITX_ReadI2C_Byte(REG_TX_CLK_CTRL1);
+	uc |= B_TX_VDO_LATCH_EDGE;
+	HDMITX_WriteI2C_Byte(REG_TX_CLK_CTRL1, uc);
+#endif
+
+	hdmitx_SetupAFE(level);	/* pass if High Freq request */
+	HDMITX_WriteI2C_Byte(REG_TX_SW_RST,
+			     B_HDMITX_AUD_RST | B_TX_AREF_RST | B_TX_HDCP_RST_HDMITX);
+
+/* hh test */
+
+	/*HDMITX_WriteI2C_Byte(0x90, 0x1F);*/
+	/*HDMITX_WriteI2C_Byte(0x91, 0x67);*/
+	/*HDMITX_WriteI2C_Byte(0x92, 0x06);*/
+	/*HDMITX_WriteI2C_Byte(0x93, 0x06);*/
+	/*HDMITX_WriteI2C_Byte(0x94, 0x61);*/
+	/*HDMITX_WriteI2C_Byte(0x95, 0x02);*/
+	/*HDMITX_WriteI2C_Byte(0x96, 0x2A);*/
+	/*HDMITX_WriteI2C_Byte(0x97, 0x00);*/
+	/*HDMITX_WriteI2C_Byte(0x9A, 0x18);*/
+	/*HDMITX_WriteI2C_Byte(0x9B, 0xE8);*/
+	/*HDMITX_WriteI2C_Byte(0x9C, 0x20);*/
+	/*HDMITX_WriteI2C_Byte(0x9D, 0xFF);*/
+	/*HDMITX_WriteI2C_Byte(0x9E, 0xFF);*/
+	/*HDMITX_WriteI2C_Byte(0x9F, 0xFF);*/
+	/*HDMITX_WriteI2C_Byte(0xA0, 0x00);*/
+	/*HDMITX_WriteI2C_Byte(0xA1, 0x50);*/
+	/*HDMITX_WriteI2C_Byte(0xA2, 0xFF);*/
+	/*HDMITX_WriteI2C_Byte(0xA3, 0x3F);*/
+
+
+	hdmitx_FireAFE();
+
+	return TRUE;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* export this for dynamic change input signal */
+/* //////////////////////////////////////////////////////////////////// */
+bool setHDMITX_VideoSignalType(unsigned char inputSignalType)
+{
+	hdmiTxDev[0].bInputVideoSignalType = inputSignalType;
+	/* hdmitx_SetInputMode(inputColorMode,hdmiTxDev[0].bInputVideoSignalType); */
+	return TRUE;
+}
+
+/* void CheckClockStable(unsigned char SystemStat) */
+/* { */
+/* static unsigned char Stablecnt=20; */
+/* if(0==(SystemStat&B_TXVIDSTABLE)) */
+/* { */
+/* if(0==Stablecnt--) */
+/* { */
+/* HDMITX_ToggleBit(0x59,3); */
+/* Stablecnt=20; */
+/* } */
+/* } */
+/* else */
+/* { */
+/* Stablecnt=20; */
+/* } */
+/* } */
+
+void setHDMITX_ColorDepthPhase(unsigned char ColorDepth, unsigned char bPhase)
+{
+#ifdef IT6615
+	unsigned char uc;
+	unsigned char bColorDepth;
+
+	if (ColorDepth == 30) {
+		bColorDepth = B_TX_CD_30;
+		HDMITX_DEBUG_PRINTF("bColorDepth = B_TX_CD_30\n");
+	} else if (ColorDepth == 36) {
+		bColorDepth = B_TX_CD_36;
+		HDMITX_DEBUG_PRINTF("bColorDepth = B_TX_CD_36\n");
+	}
+
+	/*   else if (ColorDepth == 24)*/
+	/*  {*/
+	/*   bColorDepth = B_TX_CD_24 ;*/
+	/*	bColorDepth = 0 ;*/
+	/*	modify JJ by mail 20100423 1800  not indicated*/
+	/*  }*/
+
+	else
+		bColorDepth = 0;	/* not indicated */
+
+	Switch_HDMITX_Bank(0);
+	HDMITX_SetI2C_Byte(REG_TX_GCP, B_TX_COLOR_DEPTH_MASK, bColorDepth);
+	HDMITX_DEBUG_PRINTF("setHDMITX_ColorDepthPhase(%02X), regC1 = %02X\n", (int)bColorDepth,
+			    (int)HDMITX_ReadI2C_Byte(REG_TX_GCP));
+#endif
+}
+
+#ifdef SUPPORT_SYNCEMBEDDED
+
+struct CRT_TimingSetting {
+	unsigned char fmt;
+	WORD HActive;
+	WORD VActive;
+	WORD HTotal;
+	WORD VTotal;
+	WORD H_FBH;
+	WORD H_SyncW;
+	WORD H_BBH;
+	WORD V_FBH;
+	WORD V_SyncW;
+	WORD V_BBH;
+	unsigned char Scan:1;
+	unsigned char VPolarity:1;
+	unsigned char HPolarity:1;
+};
+
+/* VDEE_L,   VDEE_H, VRS2S_L, VRS2S_H, VRS2E_L, VRS2E_H, HalfL_L, */
+/* HalfL_H, VDE2S_L, VDE2S_H, HVP&Progress */
+struct CRT_TimingSetting TimingTable[] = {
+	/* VIC   H     V    HTotal VTotal  HFT   HSW     HBP VF VSW   VB */
+	{1, 640, 480, 800, 525, 16, 96, 48, 10, 2, 33, PROG, Vneg, Hneg},
+	/* 640x480@60Hz         - CEA Mode [ 1] */
+	{2, 720, 480, 858, 525, 16, 62, 60, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 720x480@60Hz         - CEA Mode [ 2] */
+	{3, 720, 480, 858, 525, 16, 62, 60, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 720x480@60Hz         - CEA Mode [ 3] */
+	{4, 1280, 720, 1650, 750, 110, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@60Hz        - CEA Mode [ 4] */
+	{5, 1920, 540, 2200, 562, 88, 44, 148, 2, 5, 15, INTERLACE, Vpos, Hpos},
+	/* 1920x1080(I)@60Hz    - CEA Mode [ 5] */
+	{6, 720, 240, 858, 262, 19, 62, 57, 4, 3, 15, INTERLACE, Vneg, Hneg},
+	/* 720x480(I)@60Hz      - CEA Mode [ 6] */
+	{7, 720, 240, 858, 262, 19, 62, 57, 4, 3, 15, INTERLACE, Vneg, Hneg},
+	/* 720x480(I)@60Hz      - CEA Mode [ 7] */
+	/* {  8,  720,  240,    858,  262,   19,    62,    57,  4, 3,  15,      PROG, Vneg, Hneg},*/
+	/* 720x480(I)@60Hz      - CEA Mode [ 8] */
+	/* {  9,  720,  240,    858,  262,   19,    62,    57,  4, 3,  15,      PROG, Vneg, Hneg},*/
+	/* 720x480(I)@60Hz      - CEA Mode [ 9] */
+	/* { 10,  720,  240,    858,  262,   19,    62,    57,  4, 3,  15, INTERLACE, Vneg, Hneg},*/
+	/* 720x480(I)@60Hz      - CEA Mode [10] */
+	/* { 11,  720,  240,    858,  262,   19,    62,    57,  4, 3,  15, INTERLACE, Vneg, Hneg},*/
+	/* 720x480(I)@60Hz      - CEA Mode [11] */
+	/* { 12,  720,  240,    858,  262,   19,    62,    57,  4, 3,  15,      PROG, Vneg, Hneg},*/
+	/* 720x480(I)@60Hz      - CEA Mode [12] */
+	/* { 13,  720,  240,    858,  262,   19,    62,    57,  4, 3,  15,      PROG, Vneg, Hneg},*/
+	/* 720x480(I)@60Hz      - CEA Mode [13] */
+	/* { 14, 1440,  480,   1716,  525,   32,   124,   120,  9, 6,  30,      PROG, Vneg, Hneg},*/
+	/* 1440x480@60Hz        - CEA Mode [14] */
+	/* { 15, 1440,  480,   1716,  525,   32,   124,   120,  9, 6,  30,      PROG, Vneg, Hneg},*/
+	/* 1440x480@60Hz        - CEA Mode [15] */
+	{16, 1920, 1080, 2200, 1125, 88, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@60Hz       - CEA Mode [16] */
+	{17, 720, 576, 864, 625, 12, 64, 68, 5, 5, 39, PROG, Vneg, Hneg},
+	/* 720x576@50Hz         - CEA Mode [17] */
+	{18, 720, 576, 864, 625, 12, 64, 68, 5, 5, 39, PROG, Vneg, Hneg},
+	/* 720x576@50Hz         - CEA Mode [18] */
+	{19, 1280, 720, 1980, 750, 440, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@50Hz        - CEA Mode [19] */
+	{20, 1920, 540, 2640, 562, 528, 44, 148, 2, 5, 15, INTERLACE, Vpos, Hpos},
+	/* 1920x1080(I)@50Hz    - CEA Mode [20] */
+	{21, 720, 288, 864, 312, 12, 63, 69, 2, 3, 19, INTERLACE, Vneg, Hneg},
+	/* 1440x576(I)@50Hz     - CEA Mode [21] */
+	{22, 720, 288, 864, 312, 12, 63, 69, 2, 3, 19, INTERLACE, Vneg, Hneg},
+	/* 1440x576(I)@50Hz     - CEA Mode [22] */
+	/* { 23,  720,  288,    864,  312,   12,    63,    69,  2, 3,  19,      PROG, Vneg, Hneg},*/
+	/* 1440x288@50Hz        - CEA Mode [23] */
+	/* { 24,  720,  288,    864,  312,   12,    63,    69,  2, 3,  19,      PROG, Vneg, Hneg},*/
+	/* 1440x288@50Hz        - CEA Mode [24] */
+	/* { 25,  720,  288,    864,  312,   12,    63,    69,  2, 3,  19, INTERLACE, Vneg, Hneg},*/
+	/* 1440x576(I)@50Hz     - CEA Mode [25] */
+	/* { 26,  720,  288,    864,  312,   12,    63,    69,  2, 3,  19, INTERLACE, Vneg, Hneg},*/
+	/* 1440x576(I)@50Hz     - CEA Mode [26] */
+	/* { 27,  720,  288,    864,  312,   12,    63,    69,  2, 3,  19,      PROG, Vneg, Hneg},*/
+	/* 1440x288@50Hz        - CEA Mode [27] */
+	/* { 28,  720,  288,    864,  312,   12,    63,    69,  2, 3,  19,      PROG, Vneg, Hneg},*/
+	/* 1440x288@50Hz        - CEA Mode [28] */
+	/* { 29, 1440,  576,   1728,  625,   24,   128,   136,  5, 5,  39,      PROG, Vpos, Hneg},*/
+	/* 1440x576@50Hz        - CEA Mode [29] */
+	/* { 30, 1440,  576,   1728,  625,   24,   128,   136,  5, 5,  39,      PROG, Vpos, Hneg},*/
+	/* 1440x576@50Hz        - CEA Mode [30] */
+	{31, 1920, 1080, 2640, 1125, 528, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@50Hz       - CEA Mode [31] */
+	{32, 1920, 1080, 2750, 1125, 638, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@24Hz       - CEA Mode [32] */
+	{33, 1920, 1080, 2640, 1125, 528, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@25Hz       - CEA Mode [33] */
+	{34, 1920, 1080, 2200, 1125, 88, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@30Hz       - CEA Mode [34] */
+	/* { 35, 2880,  480, 1716*2,  525, 32*2, 124*2, 120*2,  9, 6,  30,      PROG, Vneg, Hneg},*/
+	/* 2880x480@60Hz        - CEA Mode [35] */
+	/* { 36, 2880,  480, 1716*2,  525, 32*2, 124*2, 120*2,  9, 6,  30,      PROG, Vneg, Hneg},*/
+	/* 2880x480@60Hz        - CEA Mode [36] */
+	/* { 37, 2880,  576,   3456,  625, 24*2, 128*2, 136*2,  5, 5,  39,      PROG, Vneg, Hneg},*/
+	/* 2880x576@50Hz        - CEA Mode [37] */
+	/* { 38, 2880,  576,   3456,  625, 24*2, 128*2, 136*2,  5, 5,  39,      PROG, Vneg, Hneg},*/
+	/* 2880x576@50Hz        - CEA Mode [38] */
+	/* { 39, 1920,  540,   2304,  625,   32,   168,   184, 23, 5,  57, INTERLACE, Vneg, Hpos},*/
+	/* 1920x1080@50Hz       - CEA Mode [39] */
+	/* { 40, 1920,  540,   2640,  562,  528,    44,   148,  2, 5,  15, INTERLACE, Vpos, Hpos},*/
+	/* 1920x1080(I)@100Hz   - CEA Mode [40] */
+	/* { 41, 1280,  720,   1980,  750,  440,    40,   220,  5, 5,  20,      PROG, Vpos, Hpos},*/
+	/* 1280x720@100Hz       - CEA Mode [41] */
+	/* { 42,  720,  576,    864,  625,   12,    64,    68,  5, 5,  39,      PROG, Vneg, Hneg},*/
+	/* 720x576@100Hz        - CEA Mode [42] */
+	/* { 43,  720,  576,    864,  625,   12,    64,    68,  5, 5,  39,      PROG, Vneg, Hneg},*/
+	/* 720x576@100Hz        - CEA Mode [43] */
+	/* { 44,  720,  288,    864,  312,   12,    63,    69,  2, 3,  19, INTERLACE, Vneg, Hneg},*/
+	/* 1440x576(I)@100Hz    - CEA Mode [44] */
+	/* { 45,  720,  288,    864,  312,   12,    63,    69,  2, 3,  19, INTERLACE, Vneg, Hneg},*/
+	/* 1440x576(I)@100Hz    - CEA Mode [45] */
+	/* { 46, 1920,  540,   2200,  562,   88,    44,   148,  2, 5,  15, INTERLACE, Vpos, Hpos},*/
+	/* 1920x1080(I)@120Hz   - CEA Mode [46] */
+	/* { 47, 1280,  720,   1650,  750,  110,    40,   220,  5, 5,  20,      PROG, Vpos, Hpos},*/
+	/* 1280x720@120Hz       - CEA Mode [47] */
+	/* { 48,  720,  480,    858,  525,   16,    62,    60,  9, 6,  30,      PROG, Vneg, Hneg},*/
+	/* 720x480@120Hz        - CEA Mode [48] */
+	/* { 49,  720,  480,    858,  525,   16,    62,    60,  9, 6,  30,      PROG, Vneg, Hneg},*/
+	/* 720x480@120Hz        - CEA Mode [49] */
+	/* { 50,  720,  240,    858,  262,   19,    62,    57,  4, 3,  15, INTERLACE, Vneg, Hneg},*/
+	/* 720x480(I)@120Hz     - CEA Mode [50] */
+	/* { 51,  720,  240,    858,  262,   19,    62,    57,  4, 3,  15, INTERLACE, Vneg, Hneg},*/
+	/* 720x480(I)@120Hz     - CEA Mode [51] */
+	/* { 52,  720,  576,    864,  625,   12,    64,    68,  5, 5,  39,      PROG, Vneg, Hneg},*/
+	/* 720x576@200Hz        - CEA Mode [52] */
+	/* { 53,  720,  576,    864,  625,   12,    64,    68,  5, 5,  39,      PROG, Vneg, Hneg},*/
+	/* 720x576@200Hz        - CEA Mode [53] */
+	/* { 54,  720,  288,    864,  312,   12,    63,    69,  2, 3,  19, INTERLACE, Vneg, Hneg},*/
+	/* 1440x576(I)@200Hz    - CEA Mode [54] */
+	/* { 55,  720,  288,    864,  312,   12,    63,    69,  2, 3,  19, INTERLACE, Vneg, Hneg},*/
+	/* 1440x576(I)@200Hz    - CEA Mode [55] */
+	/* { 56,  720,  480,    858,  525,   16,    62,    60,  9, 6,  30,      PROG, Vneg, Hneg},*/
+	/* 720x480@120Hz        - CEA Mode [56] */
+	/* { 57,  720,  480,    858,  525,   16,    62,    60,  9, 6,  30,      PROG, Vneg, Hneg},*/
+	/* 720x480@120Hz        - CEA Mode [57] */
+	/* { 58,  720,  240,    858,  262,   19,    62,    57,  4, 3,  15, INTERLACE, Vneg, Hneg},*/
+	/* 720x480(I)@120Hz     - CEA Mode [58] */
+	/* { 59,  720,  240,    858,  262,   19,    62,    57,  4, 3,  15, INTERLACE, Vneg, Hneg},*/
+	/* 720x480(I)@120Hz     - CEA Mode [59] */
+	{60, 1280, 720, 3300, 750, 1760, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@24Hz        - CEA Mode [60] */
+	{61, 1280, 720, 3960, 750, 2420, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@25Hz        - CEA Mode [61] */
+	{62, 1280, 720, 3300, 750, 1760, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@30Hz        - CEA Mode [62] */
+	/* { 63, 1920, 1080,   2200, 1125,   88,    44,   148,  4, 5,  36,      PROG, Vpos, Hpos},*/
+	/* 1920x1080@120Hz      - CEA Mode [63] */
+	/* { 64, 1920, 1080,   2640, 1125,  528,    44,   148,  4, 5,  36,      PROG, Vpos, Hpos},*/
+	/* 1920x1080@100Hz      - CEA Mode [64] */
+};
+
+#define MaxIndex (sizeof(TimingTable)/sizeof(struct CRT_TimingSetting))
+bool setHDMITX_SyncEmbeddedByVIC(unsigned char VIC, unsigned char bInputType)
+{
+	int i;
+	unsigned char fmt_index = 0;
+
+	/* if Embedded Video,need to generate timing with pattern register */
+	Switch_HDMITX_Bank(0);
+
+	HDMITX_DEBUG_PRINTF("setHDMITX_SyncEmbeddedByVIC(%d,%x)\n", (int)VIC, (int)bInputType);
+	if (VIC > 0) {
+		for (i = 0; i < MaxIndex; i++) {
+			if (TimingTable[i].fmt == VIC) {
+				fmt_index = i;
+				HDMITX_DEBUG_PRINTF("fmt_index=%02x)\n", (int)fmt_index);
+				HDMITX_DEBUG_PRINTF("***Fine Match Table ***\n");
+				break;
+			}
+		}
+	} else {
+		HDMITX_DEBUG_PRINTF(("***No Match VIC == 0 ***\n"));
+		return FALSE;
+	}
+	if (i >= MaxIndex) {
+		/* return FALSE; */
+		HDMITX_DEBUG_PRINTF("***No Match VIC ***\n");
+		return FALSE;
+	}
+	/* if( bInputSignalType & T_MODE_SYNCEMB ) */
+	{
+		int HTotal, HDES, VTotal, VDES;
+		int HDEW, VDEW, HFP, HSW, VFP, VSW;
+		int HRS, HRE;
+		int VRS, VRE;
+		int H2ndVRRise;
+		int VRS2nd, VRE2nd;
+		unsigned char Pol;
+
+		HTotal = TimingTable[fmt_index].HTotal;
+		HDEW = TimingTable[fmt_index].HActive;
+		HFP = TimingTable[fmt_index].H_FBH;
+		HSW = TimingTable[fmt_index].H_SyncW;
+		HDES = HSW + TimingTable[fmt_index].H_BBH;
+		VTotal = TimingTable[fmt_index].VTotal;
+		VDEW = TimingTable[fmt_index].VActive;
+		VFP = TimingTable[fmt_index].V_FBH;
+		VSW = TimingTable[fmt_index].V_SyncW;
+		VDES = VSW + TimingTable[fmt_index].V_BBH;
+
+		Pol = (TimingTable[fmt_index].HPolarity == Hpos) ? (1 << 1) : 0;
+		Pol |= (TimingTable[fmt_index].VPolarity == Vpos) ? (1 << 2) : 0;
+
+		/* SyncEmb case===== */
+		if (bInputType & T_MODE_CCIR656) {
+			HRS = HFP - 1;
+		} else {
+			HRS = HFP - 2;
+			/*   if(VIC==HDMI_1080p60 ||*/
+			/*   VIC==HDMI_1080p50 )*/
+			/*   {*/
+			/*   HDMITX_OrReg_Byte(0x59, (1<<3));*/
+			/*   }*/
+			/*   else*/
+			/*   {*/
+			/*   HDMITX_AndReg_Byte(0x59, ~(1<<3));*/
+			/*   }*/
+
+		}
+		HRE = HRS + HSW;
+		H2ndVRRise = HRS + HTotal / 2;
+
+		VRS = VFP;
+		VRE = VRS + VSW;
+
+		/* VTotal>>=1; */
+
+		if (TimingTable[fmt_index].Scan == PROG) {	/* progressive mode */
+			VRS2nd = 0xFFF;
+			VRE2nd = 0x3F;
+		} else {	/* interlaced mode */
+			if (TimingTable[fmt_index].fmt == 39) {
+				VRS2nd = VRS + VTotal - 1;
+				VRE2nd = VRS2nd + VSW;
+			} else {
+				VRS2nd = VRS + VTotal;
+				VRE2nd = VRS2nd + VSW;
+			}
+		}
+#ifdef DETECT_VSYNC_CHG_IN_SAV
+		if (EnSavVSync) {
+			VRS -= 1;
+			VRE -= 1;
+			if (!pSetVTiming->ScanMode)	{
+				/* interlaced mode */
+				VRS2nd -= 1;
+				VRE2nd -= 1;
+			}
+		}
+#endif				/* DETECT_VSYNC_CHG_IN_SAV */
+		HDMITX_SetI2C_Byte(0x90, 0x06, Pol);
+		/* write H2ndVRRise */
+		HDMITX_SetI2C_Byte(0x90, 0xF0, (H2ndVRRise & 0x0F) << 4);
+		HDMITX_WriteI2C_Byte(0x91, (H2ndVRRise & 0x0FF0) >> 4);
+		/* write HRS/HRE */
+		HDMITX_WriteI2C_Byte(0x95, HRS & 0xFF);
+		HDMITX_WriteI2C_Byte(0x96, HRE & 0xFF);
+		HDMITX_WriteI2C_Byte(0x97, ((HRE & 0x0F00) >> 4) + ((HRS & 0x0F00) >> 8));
+		/* write VRS/VRE */
+		HDMITX_WriteI2C_Byte(0xa0, VRS & 0xFF);
+		HDMITX_WriteI2C_Byte(0xa1, ((VRE & 0x0F) << 4) + ((VRS & 0x0F00) >> 8));
+		HDMITX_WriteI2C_Byte(0xa2, VRS2nd & 0xFF);
+		HDMITX_WriteI2C_Byte(0xa6, (VRE2nd & 0xF0) + ((VRE & 0xF0) >> 4));
+		HDMITX_WriteI2C_Byte(0xa3, ((VRE2nd & 0x0F) << 4) + ((VRS2nd & 0xF00) >> 8));
+		HDMITX_WriteI2C_Byte(0xa4, H2ndVRRise & 0xFF);
+		HDMITX_WriteI2C_Byte(0xa5,
+				     (/*EnDEOnly */ 0 << 5) +
+				     ((TimingTable[fmt_index].Scan ==
+				       INTERLACE) ? (1 << 4) : 0) + ((H2ndVRRise & 0xF00) >> 8));
+		HDMITX_SetI2C_Byte(0xb1, 0x51,
+				   ((HRE & 0x1000) >> 6) + ((HRS & 0x1000) >> 8) +
+				   ((HDES & 0x1000) >> 12));
+		HDMITX_SetI2C_Byte(0xb2, 0x05,
+				   ((H2ndVRRise & 0x1000) >> 10) + ((H2ndVRRise & 0x1000) >> 12));
+	}
+	return TRUE;
+}
+
+#endif				/* SUPPORT_SYNCEMBEDDED */
+
+/* ~jj_tseng@chipadvanced.com 2007/01/02 */
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_SetInputMode */
+/* Parameter: InputMode,bInputSignalType */
+/* InputMode - use [1:0] to identify the color space for reg70[7:6], */
+/* definition: */
+/* #define F_MODE_RGB444  0 */
+/* #define F_MODE_YUV422 1 */
+/* #define F_MODE_YUV444 2 */
+/* #define F_MODE_CLRMOD_MASK 3 */
+/* bInputSignalType - defined the CCIR656 D[0],SYNC Embedded D[1],and */
+/* DDR input in D[2]. */
+/* Return: N/A */
+/* Remark: program Reg70 with the input value. */
+/* Side-Effect: Reg70. */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_SetInputMode(unsigned char InputColorMode, unsigned char bInputSignalType)
+{
+	unsigned char ucData;
+
+	ucData = HDMITX_ReadI2C_Byte(REG_TX_INPUT_MODE);
+	ucData &= ~(M_TX_INCOLMOD | B_TX_2X656CLK | B_TX_SYNCEMB | B_TX_INDDR | B_TX_PCLKDIV2);
+	/* ucData |= 0x01;//input clock delay 1 for 1080P DDR */
+
+	switch (InputColorMode & F_MODE_CLRMOD_MASK) {
+	case F_MODE_YUV422:
+		ucData |= B_TX_IN_YUV422;
+		break;
+	case F_MODE_YUV444:
+		ucData |= B_TX_IN_YUV444;
+		break;
+	case F_MODE_RGB444:
+	default:
+		ucData |= B_TX_IN_RGB;
+		break;
+	}
+	if (bInputSignalType & T_MODE_PCLKDIV2) {
+		ucData |= B_TX_PCLKDIV2;
+		HDMITX_DEBUG_PRINTF("PCLK Divided by 2 mode\n");
+	}
+	if (bInputSignalType & T_MODE_CCIR656) {
+		ucData |= B_TX_2X656CLK;
+		HDMITX_DEBUG_PRINTF("CCIR656 mode\n");
+	}
+	if (bInputSignalType & T_MODE_SYNCEMB) {
+		ucData |= B_TX_SYNCEMB;
+		HDMITX_DEBUG_PRINTF("Sync Embedded mode\n");
+	}
+	if (bInputSignalType & T_MODE_INDDR) {
+		ucData |= B_TX_INDDR;
+		HDMITX_DEBUG_PRINTF("Input DDR mode\n");
+	}
+	HDMITX_WriteI2C_Byte(REG_TX_INPUT_MODE, ucData);
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_SetCSCScale */
+/* Parameter: bInputMode - */
+/* D[1:0] - Color Mode */
+/* D[4] - Colorimetry 0: ITU_BT601 1: ITU_BT709 */
+/* D[5] - Quantization 0: 0_255 1: 16_235 */
+/* D[6] - Up/Dn Filter 'Required' */
+/* 0: no up/down filter */
+/* 1: enable up/down filter when csc need. */
+/* D[7] - Dither Filter 'Required' */
+/* 0: no dither enabled. */
+/* 1: enable dither and dither free go "when required". */
+/* bOutputMode - */
+/* D[1:0] - Color mode. */
+/* Return: N/A */
+/* Remark: reg72~reg8D will be programmed depended the input with table. */
+/* Side-Effect: */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_SetCSCScale(unsigned char bInputMode, unsigned char bOutputMode)
+{
+	unsigned char ucData = 0, csc = 0;
+	unsigned char i;
+	unsigned char filter = 0;	/* filter is for Video CTRL DN_FREE_GO,EN_DITHER,and ENUDFILT */
+
+	/* (1) YUV422 in,RGB/YUV444 output (Output is 8-bit,input is 12-bit) */
+	/* (2) YUV444/422  in,RGB output (CSC enable,and output is not YUV422) */
+	/* (3) RGB in,YUV444 output   (CSC enable,and output is not YUV422) */
+	/*  */
+	/* YUV444/RGB24 <-> YUV422 need set up/down filter. */
+	HDMITX_DEBUG_PRINTF("hdmitx_SetCSCScale(unsigned char bInputMode = %x,unsigned char bOutputMode = %x)\n",
+			    (int)bInputMode, (int)bOutputMode);
+	switch (bInputMode & F_MODE_CLRMOD_MASK) {
+#ifdef SUPPORT_INPUTYUV444
+	case F_MODE_YUV444:
+		HDMITX_DEBUG_PRINTF("Input mode is YUV444 ");
+		switch (bOutputMode & F_MODE_CLRMOD_MASK) {
+		case F_MODE_YUV444:
+			HDMITX_DEBUG_PRINTF("Output mode is YUV444\n");
+			csc = B_HDMITX_CSC_BYPASS;
+			break;
+
+		case F_MODE_YUV422:
+			HDMITX_DEBUG_PRINTF("Output mode is YUV422\n");
+			if (bInputMode & F_VIDMODE_EN_UDFILT) {
+				/* YUV444 to YUV422 need up/down filter for processing. */
+				filter |= B_TX_EN_UDFILTER;
+			}
+			csc = B_HDMITX_CSC_BYPASS;
+			break;
+		case F_MODE_RGB444:
+			HDMITX_DEBUG_PRINTF("Output mode is RGB24\n");
+			csc = B_HDMITX_CSC_YUV2RGB;
+			if (bInputMode & F_VIDMODE_EN_DITHER) {
+				/* YUV444 to RGB24 need dither */
+				filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO;
+			}
+			break;
+		}
+		break;
+#endif
+
+#ifdef SUPPORT_INPUTYUV422
+	case F_MODE_YUV422:
+		HDMITX_DEBUG_PRINTF("Input mode is YUV422\n");
+		switch (bOutputMode & F_MODE_CLRMOD_MASK) {
+		case F_MODE_YUV444:
+			HDMITX_DEBUG_PRINTF("Output mode is YUV444\n");
+			csc = B_HDMITX_CSC_BYPASS;
+			if (bInputMode & F_VIDMODE_EN_UDFILT) {
+				/* YUV422 to YUV444 need up filter */
+				filter |= B_TX_EN_UDFILTER;
+			}
+			if (bInputMode & F_VIDMODE_EN_DITHER) {
+				/* YUV422 to YUV444 need dither */
+				filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO;
+			}
+			break;
+		case F_MODE_YUV422:
+			HDMITX_DEBUG_PRINTF("Output mode is YUV422\n");
+			csc = B_HDMITX_CSC_BYPASS;
+
+			break;
+
+		case F_MODE_RGB444:
+			HDMITX_DEBUG_PRINTF("Output mode is RGB24\n");
+			csc = B_HDMITX_CSC_YUV2RGB;
+			if (bInputMode & F_VIDMODE_EN_UDFILT) {
+				/* YUV422 to RGB24 need up/dn filter. */
+				filter |= B_TX_EN_UDFILTER;
+			}
+			if (bInputMode & F_VIDMODE_EN_DITHER) {
+				/* YUV422 to RGB24 need dither */
+				filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO;
+			}
+			break;
+		}
+		break;
+#endif
+
+#ifdef SUPPORT_INPUTRGB
+	case F_MODE_RGB444:
+		HDMITX_DEBUG_PRINTF("Input mode is RGB24\n");
+		switch (bOutputMode & F_MODE_CLRMOD_MASK) {
+		case F_MODE_YUV444:
+			HDMITX_DEBUG_PRINTF("Output mode is YUV444\n");
+			csc = B_HDMITX_CSC_RGB2YUV;
+
+			if (bInputMode & F_VIDMODE_EN_DITHER) {
+				/* RGB24 to YUV444 need dither */
+				filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO;
+			}
+			break;
+
+		case F_MODE_YUV422:
+			HDMITX_DEBUG_PRINTF("Output mode is YUV422\n");
+			if (bInputMode & F_VIDMODE_EN_UDFILT) {
+				/* RGB24 to YUV422 need down filter. */
+				filter |= B_TX_EN_UDFILTER;
+			}
+			if (bInputMode & F_VIDMODE_EN_DITHER) {
+				/* RGB24 to YUV422 need dither */
+				filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO;
+			}
+			csc = B_HDMITX_CSC_RGB2YUV;
+			break;
+
+		case F_MODE_RGB444:
+			HDMITX_DEBUG_PRINTF("Output mode is RGB24\n");
+			csc = B_HDMITX_CSC_BYPASS;
+			break;
+		}
+		break;
+#endif
+	}
+#ifndef DISABLE_HDMITX_CSC
+
+#ifdef SUPPORT_INPUTRGB
+	/* set the CSC metrix registers by colorimetry and quantization */
+	if (csc == B_HDMITX_CSC_RGB2YUV) {
+		HDMITX_DEBUG_PRINTF("CSC = RGB2YUV %x ", csc);
+		switch (bInputMode & (F_VIDMODE_ITU709 | F_VIDMODE_16_235)) {
+		case F_VIDMODE_ITU709 | F_VIDMODE_16_235:
+			HDMITX_DEBUG_PRINTF("ITU709 16-235 ");
+			for (i = 0; i < SIZEOF_CSCMTX; i++) {
+				HDMITX_WriteI2C_Byte(REG_TX_CSC_YOFF + i,
+						     bCSCMtx_RGB2YUV_ITU709_16_235[i]);
+				HDMITX_DEBUG_PRINTF("reg%02X <- %02X\n", (int)(i + REG_TX_CSC_YOFF),
+						    (int)bCSCMtx_RGB2YUV_ITU709_16_235[i]);
+			}
+			break;
+		case F_VIDMODE_ITU709 | F_VIDMODE_0_255:
+			HDMITX_DEBUG_PRINTF("ITU709 0-255 ");
+			for (i = 0; i < SIZEOF_CSCMTX; i++) {
+				HDMITX_WriteI2C_Byte(REG_TX_CSC_YOFF + i,
+						     bCSCMtx_RGB2YUV_ITU709_0_255[i]);
+				HDMITX_DEBUG_PRINTF("reg%02X <- %02X\n", (int)(i + REG_TX_CSC_YOFF),
+						    (int)bCSCMtx_RGB2YUV_ITU709_0_255[i]);
+			}
+			break;
+		case F_VIDMODE_ITU601 | F_VIDMODE_16_235:
+			HDMITX_DEBUG_PRINTF("ITU601 16-235 ");
+			for (i = 0; i < SIZEOF_CSCMTX; i++) {
+				HDMITX_WriteI2C_Byte(REG_TX_CSC_YOFF + i,
+						     bCSCMtx_RGB2YUV_ITU601_16_235[i]);
+				HDMITX_DEBUG_PRINTF("reg%02X <- %02X\n", (int)(i + REG_TX_CSC_YOFF),
+						    (int)bCSCMtx_RGB2YUV_ITU601_16_235[i]);
+			}
+			break;
+		case F_VIDMODE_ITU601 | F_VIDMODE_0_255:
+		default:
+			HDMITX_DEBUG_PRINTF("ITU601 0-255 ");
+			for (i = 0; i < SIZEOF_CSCMTX; i++) {
+				HDMITX_WriteI2C_Byte(REG_TX_CSC_YOFF + i,
+						     bCSCMtx_RGB2YUV_ITU601_0_255[i]);
+				HDMITX_DEBUG_PRINTF("reg%02X <- %02X\n", (int)(i + REG_TX_CSC_YOFF),
+						    (int)bCSCMtx_RGB2YUV_ITU601_0_255[i]);
+			}
+			break;
+		}
+	}
+#endif
+
+#ifdef SUPPORT_INPUTYUV
+	if (csc == B_HDMITX_CSC_YUV2RGB) {
+		HDMITX_DEBUG_PRINTF("CSC = YUV2RGB %x ", csc);
+
+		switch (bInputMode & (F_VIDMODE_ITU709 | F_VIDMODE_16_235)) {
+		case F_VIDMODE_ITU709 | F_VIDMODE_16_235:
+			HDMITX_DEBUG_PRINTF("ITU709 16-235 ");
+			for (i = 0; i < SIZEOF_CSCMTX; i++) {
+				HDMITX_WriteI2C_Byte(REG_TX_CSC_YOFF + i,
+						     bCSCMtx_YUV2RGB_ITU709_16_235[i]);
+				HDMITX_DEBUG_PRINTF("reg%02X <- %02X\n", (int)(i + REG_TX_CSC_YOFF),
+						    (int)bCSCMtx_YUV2RGB_ITU709_16_235[i]);
+			}
+			break;
+		case F_VIDMODE_ITU709 | F_VIDMODE_0_255:
+			HDMITX_DEBUG_PRINTF("ITU709 0-255 ");
+			for (i = 0; i < SIZEOF_CSCMTX; i++) {
+				HDMITX_WriteI2C_Byte(REG_TX_CSC_YOFF + i,
+						     bCSCMtx_YUV2RGB_ITU709_0_255[i]);
+				HDMITX_DEBUG_PRINTF("reg%02X <- %02X\n", (int)(i + REG_TX_CSC_YOFF),
+						    (int)bCSCMtx_YUV2RGB_ITU709_0_255[i]);
+			}
+			break;
+		case F_VIDMODE_ITU601 | F_VIDMODE_16_235:
+			HDMITX_DEBUG_PRINTF("ITU601 16-235 ");
+			for (i = 0; i < SIZEOF_CSCMTX; i++) {
+				HDMITX_WriteI2C_Byte(REG_TX_CSC_YOFF + i,
+						     bCSCMtx_YUV2RGB_ITU601_16_235[i]);
+				HDMITX_DEBUG_PRINTF("reg%02X <- %02X\n", (int)(i + REG_TX_CSC_YOFF),
+						    (int)bCSCMtx_YUV2RGB_ITU601_16_235[i]);
+			}
+			break;
+		case F_VIDMODE_ITU601 | F_VIDMODE_0_255:
+		default:
+			HDMITX_DEBUG_PRINTF("ITU601 0-255 ");
+			for (i = 0; i < SIZEOF_CSCMTX; i++) {
+				HDMITX_WriteI2C_Byte(REG_TX_CSC_YOFF + i,
+						     bCSCMtx_YUV2RGB_ITU601_0_255[i]);
+				HDMITX_DEBUG_PRINTF("reg%02X <- %02X\n", (int)(i + REG_TX_CSC_YOFF),
+						    (int)bCSCMtx_YUV2RGB_ITU601_0_255[i]);
+			}
+			break;
+		}
+	}
+#endif
+#else				/* DISABLE_HDMITX_CSC */
+	csc = B_HDMITX_CSC_BYPASS;
+#endif				/* DISABLE_HDMITX_CSC */
+
+	if (csc == B_HDMITX_CSC_BYPASS)
+		HDMITX_SetI2C_Byte(0xF, 0x10, 0x10);
+	else
+		HDMITX_SetI2C_Byte(0xF, 0x10, 0x00);
+
+	ucData =
+	    HDMITX_ReadI2C_Byte(REG_TX_CSC_CTRL) & ~(M_TX_CSC_SEL | B_TX_DNFREE_GO | B_TX_EN_DITHER
+						     | B_TX_EN_UDFILTER);
+	ucData |= filter | csc;
+
+	HDMITX_WriteI2C_Byte(REG_TX_CSC_CTRL, ucData);
+
+	/* set output Up/Down Filter,Dither control */
+
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_SetupAFE */
+/* Parameter: VIDEOPCLKLEVEL level */
+/* PCLK_LOW - for 13.5MHz (for mode less than 1080p) */
+/* PCLK MEDIUM - for 25MHz~74MHz */
+/* PCLK HIGH - PCLK > 80Hz (for 1080p mode or above) */
+/* Return: N/A */
+/* Remark: set reg62~reg65 depended on HighFreqMode */
+/* reg61 have to be programmed at last and after video stable input. */
+/* Side-Effect: */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_SetupAFE(VIDEOPCLKLEVEL level)
+{
+
+	HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL, B_TX_AFE_DRV_RST);	/* 0x10 */
+	switch (level) {
+	case PCLK_HIGH:
+		HDMITX_SetI2C_Byte(0x62, 0x90, 0x80);
+		HDMITX_SetI2C_Byte(0x64, 0x89, 0x80);
+		HDMITX_SetI2C_Byte(0x68, 0x10, 0x80);
+		HDMITX_DEBUG_PRINTF("hdmitx_SetupAFE()===================HIGHT\n");
+		break;
+	default:
+		HDMITX_SetI2C_Byte(0x62, 0x90, 0x10);
+		HDMITX_SetI2C_Byte(0x64, 0x89, 0x09);
+		HDMITX_SetI2C_Byte(0x68, 0x10, 0x10);
+		HDMITX_DEBUG_PRINTF("hdmitx_SetupAFE()===================LOW\n");
+		break;
+	}
+	HDMITX_SetI2C_Byte(REG_TX_SW_RST, B_TX_REF_RST_HDMITX | B_HDMITX_VID_RST, 0);
+	HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL, 0);
+	delay1ms(1);
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_FireAFE */
+/* Parameter: N/A */
+/* Return: N/A */
+/* Remark: write reg61 with 0x04 */
+/* When program reg61 with 0x04,then audio and video circuit work. */
+/* Side-Effect: N/A */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_FireAFE(void)
+{
+	Switch_HDMITX_Bank(0);
+	HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL, 0);
+}
+
+/****************************************** */
+/* @file   <hdmitx_aud.c> */
+/* *******************************************/
+
+unsigned char AudioDelayCnt;
+unsigned char LastRefaudfreqnum;
+bool bForceCTS = FALSE;
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Audio Output */
+/* //////////////////////////////////////////////////////////////////// */
+
+void setHDMITX_ChStat(unsigned char ucIEC60958ChStat[])
+{
+	unsigned char uc;
+
+	Switch_HDMITX_Bank(1);
+	uc = (ucIEC60958ChStat[0] << 1) & 0x7C;
+	HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_MODE, uc);
+	HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_CAT, ucIEC60958ChStat[1]);	/* 192, audio CATEGORY */
+	HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_SRCNUM, ucIEC60958ChStat[2] & 0xF);
+	HDMITX_WriteI2C_Byte(REG_TX_AUD0CHST_CHTNUM, (ucIEC60958ChStat[2] >> 4) & 0xF);
+	HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_CA_FS, ucIEC60958ChStat[3]);	/* choose clock */
+	HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_OFS_WL, ucIEC60958ChStat[4]);
+	Switch_HDMITX_Bank(0);
+}
+
+void setHDMITX_UpdateChStatFs(ULONG Fs)
+{
+	unsigned char uc;
+
+	/* /////////////////////////////////// */
+	/* Fs should be the following value. */
+	/* #define AUDFS_22p05KHz  4 */
+	/* #define AUDFS_44p1KHz 0 */
+	/* #define AUDFS_88p2KHz 8 */
+	/* #define AUDFS_176p4KHz    12 */
+	/*  */
+	/* #define AUDFS_24KHz  6 */
+	/* #define AUDFS_48KHz  2 */
+	/* #define AUDFS_96KHz  10 */
+	/* #define AUDFS_192KHz 14 */
+	/*  */
+	/* #define AUDFS_768KHz 9 */
+	/*  */
+	/* #define AUDFS_32KHz  3 */
+	/* #define AUDFS_OTHER    1 */
+	/* /////////////////////////////////// */
+
+	Switch_HDMITX_Bank(1);
+	uc = HDMITX_ReadI2C_Byte(REG_TX_AUDCHST_CA_FS);	/* choose clock */
+	HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_CA_FS, uc);	/* choose clock */
+	uc &= 0xF0;
+	uc |= (Fs & 0xF);
+
+	uc = HDMITX_ReadI2C_Byte(REG_TX_AUDCHST_OFS_WL);
+	uc &= 0xF;
+	uc |= ((~Fs) << 4) & 0xF0;
+	HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_OFS_WL, uc);
+
+	Switch_HDMITX_Bank(0);
+}
+
+void setHDMITX_LPCMAudio(unsigned char AudioSrcNum, unsigned char AudSWL, bool bSPDIF)
+{
+
+	unsigned char AudioEnable, AudioFormat;
+
+	AudioEnable = 0;
+	AudioFormat = hdmiTxDev[0].bOutputAudioMode;
+
+	switch (AudSWL) {
+	case 16:
+		AudioEnable |= M_TX_AUD_16BIT;
+		break;
+	case 18:
+		AudioEnable |= M_TX_AUD_18BIT;
+		break;
+	case 20:
+		AudioEnable |= M_TX_AUD_20BIT;
+		break;
+	case 24:
+	default:
+		AudioEnable |= M_TX_AUD_24BIT;
+		break;
+	}
+	if (bSPDIF) {
+		AudioFormat &= ~0x40;
+		AudioEnable |= B_TX_AUD_SPDIF | B_TX_AUD_EN_I2S0;
+	} else {
+		AudioFormat |= 0x40;
+		switch (AudioSrcNum) {
+		case 4:
+			AudioEnable |=
+			    B_TX_AUD_EN_I2S3 | B_TX_AUD_EN_I2S2 | B_TX_AUD_EN_I2S1 |
+			    B_TX_AUD_EN_I2S0;
+			break;
+
+		case 3:
+			AudioEnable |= B_TX_AUD_EN_I2S2 | B_TX_AUD_EN_I2S1 | B_TX_AUD_EN_I2S0;
+			break;
+
+		case 2:
+			AudioEnable |= B_TX_AUD_EN_I2S1 | B_TX_AUD_EN_I2S0;
+			break;
+
+		case 1:
+		default:
+			AudioFormat &= ~0x40;
+			AudioEnable |= B_TX_AUD_EN_I2S0;
+			break;
+
+		}
+	}
+	AudioFormat |= 0x01;	/* mingchih add */
+	hdmiTxDev[0].bAudioChannelEnable = AudioEnable;
+
+	Switch_HDMITX_Bank(0);
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0, AudioEnable & 0xF0);
+
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL1, AudioFormat);
+	/* regE1 bOutputAudioMode should be loaded from ROM image. */
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_FIFOMAP, 0xE4);	/* default mapping. */
+#ifdef USE_SPDIF_CHSTAT
+	if (bSPDIF)
+		HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL3, B_TX_CHSTSEL);
+	else
+		HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL3, 0);
+
+#else				/* not USE_SPDIF_CHSTAT */
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL3, 0);
+#endif				/* USE_SPDIF_CHSTAT */
+
+	HDMITX_WriteI2C_Byte(REG_TX_AUD_SRCVALID_FLAT, 0x00);
+	HDMITX_WriteI2C_Byte(REG_TX_AUD_HDAUDIO, 0x00);	/* regE5 = 0 ; */
+
+	if (bSPDIF) {
+		unsigned char i;
+
+		HDMITX_OrReg_Byte(0x5c, (1 << 6));
+		for (i = 0; i < 100; i++) {
+			if (HDMITX_ReadI2C_Byte(REG_TX_CLK_STATUS2) & B_TX_OSF_LOCK)
+				break;	/* stable clock. */
+		}
+	}
+}
+
+void setHDMITX_NLPCMAudio(bool bSPDIF)	/* no Source Num, no I2S. */
+{
+	unsigned char AudioEnable, AudioFormat;
+	unsigned char i;
+
+	AudioFormat = 0x01;	/* NLPCM must use standard I2S mode. */
+	if (bSPDIF)
+		AudioEnable = M_TX_AUD_24BIT | B_TX_AUD_SPDIF;
+	else
+		AudioEnable = M_TX_AUD_24BIT;
+
+
+	Switch_HDMITX_Bank(0);
+	/* HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0, M_TX_AUD_24BIT|B_TX_AUD_SPDIF); */
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0, AudioEnable);
+	/* HDMITX_AndREG_Byte(REG_TX_SW_RST,~(B_HDMITX_AUD_RST|B_TX_AREF_RST)); */
+
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL1, 0x01);	/* regE1 bOutputAudioMode should be loaded from ROM image. */
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_FIFOMAP, 0xE4);	/* default mapping. */
+
+#ifdef USE_SPDIF_CHSTAT
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL3, B_TX_CHSTSEL);
+#else				/* not USE_SPDIF_CHSTAT */
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL3, 0);
+#endif				/* USE_SPDIF_CHSTAT */
+
+	HDMITX_WriteI2C_Byte(REG_TX_AUD_SRCVALID_FLAT, 0x00);
+	HDMITX_WriteI2C_Byte(REG_TX_AUD_HDAUDIO, 0x00);	/* regE5 = 0 ; */
+
+	if (bSPDIF) {
+		for (i = 0; i < 100; i++) {
+			if (HDMITX_ReadI2C_Byte(REG_TX_CLK_STATUS2) & B_TX_OSF_LOCK)
+				break;	/* stable clock. */
+		}
+	}
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0, AudioEnable | B_TX_AUD_EN_I2S0);
+}
+
+void setHDMITX_HBRAudio(bool bSPDIF)
+{
+	/* unsigned char rst; */
+	Switch_HDMITX_Bank(0);
+
+	/* rst = HDMITX_ReadI2C_Byte(REG_TX_SW_RST); */
+	/* rst &= ~(B_HDMITX_AUD_RST|B_TX_AREF_RST); */
+
+	/* HDMITX_WriteI2C_Byte(REG_TX_SW_RST, rst | B_HDMITX_AUD_RST ); */
+
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL1, 0x47);	/* regE1 bOutputAudioMode should be loaded from ROM image. */
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_FIFOMAP, 0xE4);	/* default mapping. */
+
+	if (bSPDIF) {
+		HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0, M_TX_AUD_24BIT | B_TX_AUD_SPDIF);
+		HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL3, B_TX_CHSTSEL);
+	} else {
+		HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0, M_TX_AUD_24BIT);
+		HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL3, 0);
+	}
+	HDMITX_WriteI2C_Byte(REG_TX_AUD_SRCVALID_FLAT, 0x08);
+	HDMITX_WriteI2C_Byte(REG_TX_AUD_HDAUDIO, B_TX_HBR);	/* regE5 = 0 ; */
+
+	/* uc = HDMITX_ReadI2C_Byte(REG_TX_CLK_CTRL1); */
+	/* uc &= ~M_TX_AUD_DIV ; */
+	/* HDMITX_WriteI2C_Byte(REG_TX_CLK_CTRL1, uc); */
+
+	if (bSPDIF) {
+		unsigned char i;
+
+		for (i = 0; i < 100; i++) {
+			if (HDMITX_ReadI2C_Byte(REG_TX_CLK_STATUS2) & B_TX_OSF_LOCK)
+				break;	/* stable clock. */
+		}
+		HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0,
+				     M_TX_AUD_24BIT | B_TX_AUD_SPDIF | B_TX_AUD_EN_SPDIF);
+	} else {
+		HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0,
+				     M_TX_AUD_24BIT | B_TX_AUD_EN_I2S3 | B_TX_AUD_EN_I2S2 |
+				     B_TX_AUD_EN_I2S1 | B_TX_AUD_EN_I2S0);
+	}
+	HDMITX_AndReg_Byte(0x5c, ~(1 << 6));
+	hdmiTxDev[0].bAudioChannelEnable = HDMITX_ReadI2C_Byte(REG_TX_AUDIO_CTRL0);
+	/* HDMITX_WriteI2C_Byte(REG_TX_SW_RST, rst  ); */
+}
+
+void setHDMITX_DSDAudio(void)
+{
+	/* to be continue */
+	/* unsigned char rst; */
+	/* rst = HDMITX_ReadI2C_Byte(REG_TX_SW_RST); */
+
+	/* HDMITX_WriteI2C_Byte(REG_TX_SW_RST, rst | (B_HDMITX_AUD_RST|B_TX_AREF_RST) ); */
+
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL1, 0x41);	/* regE1 bOutputAudioMode should be loaded from ROM image. */
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_FIFOMAP, 0xE4);	/* default mapping. */
+
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0, M_TX_AUD_24BIT);
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL3, 0);
+
+	HDMITX_WriteI2C_Byte(REG_TX_AUD_SRCVALID_FLAT, 0x00);
+	HDMITX_WriteI2C_Byte(REG_TX_AUD_HDAUDIO, B_TX_DSD);	/* regE5 = 0 ; */
+	/* HDMITX_WriteI2C_Byte(REG_TX_SW_RST, rst & ~(B_HDMITX_AUD_RST|B_TX_AREF_RST) ); */
+
+	/* uc = HDMITX_ReadI2C_Byte(REG_TX_CLK_CTRL1); */
+	/* uc &= ~M_TX_AUD_DIV ; */
+	/* HDMITX_WriteI2C_Byte(REG_TX_CLK_CTRL1, uc); */
+
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0,
+			     M_TX_AUD_24BIT | B_TX_AUD_EN_I2S3 | B_TX_AUD_EN_I2S2 | B_TX_AUD_EN_I2S1
+			     | B_TX_AUD_EN_I2S0);
+}
+
+void HDMITX_DisableAudioOutput(void)
+{
+	/* unsigned char uc = (HDMITX_ReadI2C_Byte(REG_TX_SW_RST) | (B_HDMITX_AUD_RST | B_TX_AREF_RST)); */
+	/* HDMITX_WriteI2C_Byte(REG_TX_SW_RST,uc); */
+	AudioDelayCnt = AudioOutDelayCnt;
+	LastRefaudfreqnum = 0;
+	HDMITX_SetI2C_Byte(REG_TX_SW_RST, (B_HDMITX_AUD_RST | B_TX_AREF_RST),
+			   (B_HDMITX_AUD_RST | B_TX_AREF_RST));
+	HDMITX_SetI2C_Byte(0x0F, 0x10, 0x10);
+}
+
+void HDMITX_EnableAudioOutput(unsigned char AudioType, bool bSPDIF, ULONG SampleFreq, unsigned char ChNum,
+			      unsigned char *pIEC60958ChStat, ULONG TMDSClock)
+{
+	static unsigned char ucIEC60958ChStat[5];
+
+	unsigned char Fs;
+
+	AudioDelayCnt = 36;
+	LastRefaudfreqnum = 0;
+	hdmiTxDev[0].TMDSClock = TMDSClock;
+	hdmiTxDev[0].bAudioChannelEnable = 0;
+	hdmiTxDev[0].bSPDIF_OUT = bSPDIF;
+
+	HDMITX_DEBUG_PRINTF1("HDMITX_EnableAudioOutput(%02X, %s, %ld, %d, %p, %ld);\n",
+			     AudioType, bSPDIF ? "SPDIF" : "I2S", SampleFreq, ChNum,
+			     pIEC60958ChStat, TMDSClock);
+
+	HDMITX_OrReg_Byte(REG_TX_SW_RST, (B_HDMITX_AUD_RST | B_TX_AREF_RST));
+	HDMITX_WriteI2C_Byte(REG_TX_CLK_CTRL0,
+			     B_TX_AUTO_OVER_SAMPLING_CLOCK | B_TX_EXT_256FS | 0x01);
+
+	HDMITX_SetI2C_Byte(0x0F, 0x10, 0x00);	/* power on the ACLK */
+
+	if (bSPDIF) {
+		if (AudioType == T_AUDIO_HBR)
+			HDMITX_WriteI2C_Byte(REG_TX_CLK_CTRL0, 0x81);
+
+		HDMITX_OrReg_Byte(REG_TX_AUDIO_CTRL0, B_TX_AUD_SPDIF);
+	} else {
+		HDMITX_AndReg_Byte(REG_TX_AUDIO_CTRL0, (~B_TX_AUD_SPDIF));
+	}
+	if (AudioType != T_AUDIO_DSD) {
+		/* one bit audio have no channel status. */
+		switch (SampleFreq) {
+		case 44100L:
+			Fs = AUDFS_44p1KHz;
+			break;
+		case 88200L:
+			Fs = AUDFS_88p2KHz;
+			break;
+		case 176400L:
+			Fs = AUDFS_176p4KHz;
+			break;
+		case 32000L:
+			Fs = AUDFS_32KHz;
+			break;
+		case 48000L:
+			Fs = AUDFS_48KHz;
+			break;
+		case 96000L:
+			Fs = AUDFS_96KHz;
+			break;
+		case 192000L:
+			Fs = AUDFS_192KHz;
+			break;
+		case 768000L:
+			Fs = AUDFS_768KHz;
+			break;
+		default:
+			SampleFreq = 48000L;
+			Fs = AUDFS_48KHz;
+			break;	/* default, set Fs = 48KHz. */
+		}
+#ifdef SUPPORT_AUDIO_MONITOR
+		hdmiTxDev[0].bAudFs = AUDFS_OTHER;
+#else
+		hdmiTxDev[0].bAudFs = Fs;
+#endif
+		setHDMITX_NCTS(hdmiTxDev[0].bAudFs);
+		if (pIEC60958ChStat == NULL) {
+			ucIEC60958ChStat[0] = 0;
+			ucIEC60958ChStat[1] = 0;
+			ucIEC60958ChStat[2] = (ChNum + 1) / 2;
+
+			if (ucIEC60958ChStat[2] < 1)
+				ucIEC60958ChStat[2] = 1;
+			else if (ucIEC60958ChStat[2] > 4)
+				ucIEC60958ChStat[2] = 4;
+
+			ucIEC60958ChStat[3] = Fs;
+			ucIEC60958ChStat[4] = (((~Fs) << 4) & 0xF0) | CHTSTS_SWCODE;	/* Fs | 24bit word length */
+			pIEC60958ChStat = ucIEC60958ChStat;
+		}
+	}
+	HDMITX_SetI2C_Byte(REG_TX_SW_RST, (B_HDMITX_AUD_RST | B_TX_AREF_RST), B_TX_AREF_RST);
+
+	switch (AudioType) {
+	case T_AUDIO_HBR:
+		HDMITX_DEBUG_PRINTF("T_AUDIO_HBR\n");
+		pIEC60958ChStat[0] |= 1 << 1;
+		pIEC60958ChStat[2] = 0;
+		pIEC60958ChStat[3] &= 0xF0;
+		pIEC60958ChStat[3] |= AUDFS_768KHz;
+		pIEC60958ChStat[4] |= (((~AUDFS_768KHz) << 4) & 0xF0) | 0xB;
+		setHDMITX_ChStat(pIEC60958ChStat);
+		setHDMITX_HBRAudio(bSPDIF);
+
+		break;
+	case T_AUDIO_DSD:
+		HDMITX_DEBUG_PRINTF("T_AUDIO_DSD\n");
+		setHDMITX_DSDAudio();
+		break;
+	case T_AUDIO_NLPCM:
+		HDMITX_DEBUG_PRINTF("T_AUDIO_NLPCM\n");
+		pIEC60958ChStat[0] |= 1 << 1;
+		setHDMITX_ChStat(pIEC60958ChStat);
+		setHDMITX_NLPCMAudio(bSPDIF);
+		break;
+	case T_AUDIO_LPCM:
+		HDMITX_DEBUG_PRINTF("T_AUDIO_LPCM\n");
+		pIEC60958ChStat[0] &= ~(1 << 1);
+
+		setHDMITX_ChStat(pIEC60958ChStat);
+		setHDMITX_LPCMAudio((ChNum + 1) / 2, SUPPORT_AUDI_AudSWL, bSPDIF);
+		/* can add auto adjust */
+		break;
+	}
+	HDMITX_AndReg_Byte(REG_TX_INT_MASK1, (~B_TX_AUDIO_OVFLW_MASK));
+	HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0, hdmiTxDev[0].bAudioChannelEnable);
+
+	HDMITX_SetI2C_Byte(REG_TX_SW_RST, (B_HDMITX_AUD_RST | B_TX_AREF_RST), 0);
+}
+
+void hdmitx_AutoAdjustAudio(void)
+{
+	unsigned long SampleFreq, cTMDSClock;
+	unsigned long N;
+	ULONG aCTS = 0;
+	unsigned char fs, uc, LoopCnt = 10;
+
+	if (bForceCTS) {
+		Switch_HDMITX_Bank(0);
+		HDMITX_WriteI2C_Byte(0xF8, 0xC3);
+		HDMITX_WriteI2C_Byte(0xF8, 0xA5);
+		HDMITX_AndReg_Byte(REG_TX_PKT_SINGLE_CTRL, ~B_TX_SW_CTS);	/* D[1] = 0, HW auto count CTS */
+		HDMITX_WriteI2C_Byte(0xF8, 0xFF);
+	}
+	/* delay1ms(50); */
+	Switch_HDMITX_Bank(1);
+	N = ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudN2) & 0xF) << 16;
+	N |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudN1)) << 8;
+	N |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudN0));
+
+	while (LoopCnt--) {
+		ULONG TempCTS = 0;
+
+		aCTS = ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt2)) << 12;
+		aCTS |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt1)) << 4;
+		aCTS |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt0) & 0xf0) >> 4;
+		if (aCTS == TempCTS)
+			break;
+
+		TempCTS = aCTS;
+	}
+	Switch_HDMITX_Bank(0);
+	if (aCTS == 0) {
+		HDMITX_DEBUG_PRINTF("aCTS== 0");
+		return;
+	}
+	uc = HDMITX_ReadI2C_Byte(REG_TX_GCP);
+
+	cTMDSClock = hdmiTxDev[0].TMDSClock;
+	/* TMDSClock=GetInputPclk(); */
+	HDMITX_DEBUG_PRINTF("PCLK = %u0,000\n", (WORD) (cTMDSClock / 10000));
+	switch (uc & 0x70) {
+	case 0x50:
+		cTMDSClock *= 5;
+		cTMDSClock /= 4;
+		break;
+	case 0x60:
+		cTMDSClock *= 3;
+		cTMDSClock /= 2;
+	}
+	SampleFreq = cTMDSClock / aCTS;
+	SampleFreq *= N;
+	SampleFreq /= 128;
+	/* SampleFreq=48000; */
+
+	HDMITX_DEBUG_PRINTF("SampleFreq = %u0\n", (WORD) (SampleFreq / 10));
+	if (SampleFreq > 31000L && SampleFreq <= 38050L)
+		fs = AUDFS_32KHz;
+	else if (SampleFreq < 46550L)
+		fs = AUDFS_44p1KHz;	/* 46050 */
+	else if (SampleFreq < 68100L)
+		fs = AUDFS_48KHz;
+	else if (SampleFreq < 92100L)
+		fs = AUDFS_88p2KHz;
+	else if (SampleFreq < 136200L)
+		fs = AUDFS_96KHz;
+	else if (SampleFreq < 184200L)
+		fs = AUDFS_176p4KHz;
+	else if (SampleFreq < 240200L)
+		fs = AUDFS_192KHz;
+	else if (SampleFreq < 800000L)
+		fs = AUDFS_768KHz;
+	else {
+		fs = AUDFS_OTHER;
+		HDMITX_DEBUG_PRINTF("fs = AUDFS_OTHER\n");
+	}
+	if (hdmiTxDev[0].bAudFs != fs) {
+		hdmiTxDev[0].bAudFs = fs;
+		setHDMITX_NCTS(hdmiTxDev[0].bAudFs);	/* set N, CTS by new generated clock. */
+		/* CurrCTS=0; */
+	}
+}
+
+bool hdmitx_IsAudioChang(void)
+{
+	/* ULONG pCTS=0; */
+	unsigned char FreDiff = 0, Refaudfreqnum;
+
+	/* Switch_HDMITX_Bank(1); */
+	/* pCTS = ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt2)) << 12 ; */
+	/* pCTS |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt1)) <<4 ; */
+	/* pCTS |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt0)&0xf0)>>4  ; */
+	/* Switch_HDMITX_Bank(0); */
+	Switch_HDMITX_Bank(0);
+	Refaudfreqnum = HDMITX_ReadI2C_Byte(0x60);
+	/* HDMITX_DEBUG_PRINTF(("Refaudfreqnum=%X    pCTS= %u",(WORD)Refaudfreqnum,(WORD)(pCTS/10000))); */
+	/* if((pCTS%10000)<1000)HDMITX_DEBUG_PRINTF(("0")); */
+	/* if((pCTS%10000)<100)HDMITX_DEBUG_PRINTF(("0")); */
+	/* if((pCTS%10000)<10)HDMITX_DEBUG_PRINTF(("0")); */
+	/* HDMITX_DEBUG_PRINTF(("%u\n",(WORD)(pCTS%10000))); */
+	if ((1 << 4) & HDMITX_ReadI2C_Byte(0x5f))
+		/* IT66121_LOG("=======XXXXXXXXXXX=========\n"); */
+		return FALSE;
+
+	if (LastRefaudfreqnum > Refaudfreqnum)
+		FreDiff = LastRefaudfreqnum - Refaudfreqnum;
+	else
+		FreDiff = Refaudfreqnum - LastRefaudfreqnum;
+
+	LastRefaudfreqnum = Refaudfreqnum;
+	if (FreDiff > 3) {
+		HDMITX_DEBUG_PRINTF("Aduio FreDiff=%d\n", (int)FreDiff);
+		HDMITX_OrReg_Byte(REG_TX_PKT_SINGLE_CTRL, (1 << 5));
+		HDMITX_AndReg_Byte(REG_TX_AUDIO_CTRL0, 0xF0);
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
+
+void setHDMITX_AudioChannelEnable(bool EnableAudio_b)
+{
+	static bool AudioOutStatus = FALSE;
+
+	if (EnableAudio_b) {
+		if (AudioDelayCnt == 0) {
+			/* if(hdmiTxDev[0].bAuthenticated==FALSE) */
+			/* {HDMITX_EnableHDCP(TRUE);} */
+#ifdef SUPPORT_AUDIO_MONITOR
+			if (hdmitx_IsAudioChang()) {
+				hdmitx_AutoAdjustAudio();
+#else
+			if (AudioOutStatus == FALSE) {
+				setHDMITX_NCTS(hdmiTxDev[0].bAudFs);
+#endif
+				HDMITX_WriteI2C_Byte(REG_TX_AUD_SRCVALID_FLAT, 0);
+				HDMITX_OrReg_Byte(REG_TX_PKT_SINGLE_CTRL, (1 << 5));
+				HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0,
+						     hdmiTxDev[0].bAudioChannelEnable);
+				/* HDMITX_OrREG_Byte(0x59,(1<<2));  //for test */
+				HDMITX_AndReg_Byte(REG_TX_PKT_SINGLE_CTRL, (~0x3C));
+				HDMITX_AndReg_Byte(REG_TX_PKT_SINGLE_CTRL, (~(1 << 5)));
+				IT66121_LOG("Audio Out Enable\n");
+#ifndef SUPPORT_AUDIO_MONITOR
+				AudioOutStatus = TRUE;
+#endif
+			}
+		} else {
+			AudioOutStatus = FALSE;
+			if (0 == (HDMITX_ReadI2C_Byte(REG_TX_CLK_STATUS2) & 0x10))
+				AudioDelayCnt--;
+			else
+				AudioDelayCnt = AudioOutDelayCnt;
+		}
+	} else {
+		/* CurrCTS=0; */
+	}
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: setHDMITX_NCTS */
+/* Parameter: PCLK - video clock in Hz. */
+/* Fs - Encoded audio sample rate */
+/* AUDFS_22p05KHz  4 */
+/* AUDFS_44p1KHz 0 */
+/* AUDFS_88p2KHz 8 */
+/* AUDFS_176p4KHz    12 */
+/*  */
+/* AUDFS_24KHz  6 */
+/* AUDFS_48KHz  2 */
+/* AUDFS_96KHz  10 */
+/* AUDFS_192KHz 14 */
+/*  */
+/* AUDFS_768KHz 9 */
+/*  */
+/* AUDFS_32KHz  3 */
+/* AUDFS_OTHER    1 */
+/* Return: ER_SUCCESS if success */
+/* Remark: set N value,the CTS will be auto generated by HW. */
+/* Side-Effect: register bank will reset to bank 0. */
+/* //////////////////////////////////////////////////////////////////// */
+
+void setHDMITX_NCTS(unsigned char Fs)
+{
+	ULONG n;
+	unsigned char LoopCnt = 255, CTSStableCnt = 0;
+	ULONG diff;
+	ULONG CTS = 0, LastCTS = 0;
+	bool HBR_mode;
+	/* unsigned char aVIC; */
+
+	if (B_TX_HBR & HDMITX_ReadI2C_Byte(REG_TX_AUD_HDAUDIO))
+		HBR_mode = TRUE;
+	else
+		HBR_mode = FALSE;
+
+	switch (Fs) {
+	case AUDFS_32KHz:
+		n = 4096;
+		break;
+	case AUDFS_44p1KHz:
+		n = 6272;
+		break;
+	case AUDFS_48KHz:
+		n = 6144;
+		break;
+	case AUDFS_88p2KHz:
+		n = 12544;
+		break;
+	case AUDFS_96KHz:
+		n = 12288;
+		break;
+	case AUDFS_176p4KHz:
+		n = 25088;
+		break;
+	case AUDFS_192KHz:
+		n = 24576;
+		break;
+	case AUDFS_768KHz:
+		n = 24576;
+		break;
+	default:
+		n = 6144;
+	}
+	/* tr_printk((" n = %ld\n",n)); */
+	Switch_HDMITX_Bank(1);
+	HDMITX_WriteI2C_Byte(REGPktAudN0, (unsigned char) ((n) & 0xFF));
+	HDMITX_WriteI2C_Byte(REGPktAudN1, (unsigned char) ((n >> 8) & 0xFF));
+	HDMITX_WriteI2C_Byte(REGPktAudN2, (unsigned char) ((n >> 16) & 0xF));
+
+	if (bForceCTS) {
+		ULONG SumCTS = 0;
+
+		while (LoopCnt--) {
+			delay1ms(30);
+			CTS = ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt2)) << 12;
+			CTS |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt1)) << 4;
+			CTS |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt0) & 0xf0) >> 4;
+			if (CTS == 0) {
+				continue;
+			} else {
+				if (LastCTS > CTS)
+					diff = LastCTS - CTS;
+				else
+					diff = CTS - LastCTS;
+
+				HDMITX_DEBUG_PRINTF("LastCTS= %u%u", (WORD) (LastCTS / 10000),
+						    (WORD) (LastCTS % 10000));
+				HDMITX_DEBUG_PRINTF("       CTS= %u%u\n", (WORD) (CTS / 10000),
+						    (WORD) (CTS % 10000));
+				LastCTS = CTS;
+				if (diff < 5) {
+					CTSStableCnt++;
+					SumCTS += CTS;
+				} else {
+					CTSStableCnt = 0;
+					SumCTS = 0;
+					continue;
+				}
+				if (CTSStableCnt >= 32) {
+					LastCTS = (SumCTS >> 5);
+					break;
+				}
+			}
+		}
+		/* HDMITX_WriteI2C_Byte(REGPktAudCTS0,(unsigned char)((LastCTS)&0xFF)); */
+		/* HDMITX_WriteI2C_Byte(REGPktAudCTS1,(unsigned char)((LastCTS>>8)&0xFF)); */
+		/* HDMITX_WriteI2C_Byte(REGPktAudCTS2,(unsigned char)((LastCTS>>16)&0xF)); */
+	}
+
+	HDMITX_WriteI2C_Byte(REGPktAudCTS0, 0);
+	HDMITX_WriteI2C_Byte(REGPktAudCTS1, 0);
+	HDMITX_WriteI2C_Byte(REGPktAudCTS2, 0);
+	Switch_HDMITX_Bank(0);
+
+	HDMITX_WriteI2C_Byte(0xF8, 0xC3);
+	HDMITX_WriteI2C_Byte(0xF8, 0xA5);
+	HDMITX_AndReg_Byte(REG_TX_PKT_SINGLE_CTRL, ~B_TX_SW_CTS);
+	HDMITX_WriteI2C_Byte(0xF8, 0xFF);
+#if 0
+#ifdef Force_CTS		/* 0929 */
+	bForceCTS = TRUE;
+	HDMITX_WriteI2C_Byte(0xF8, 0xC3);
+	HDMITX_WriteI2C_Byte(0xF8, 0xA5);
+	if (bForceCTS)
+		HDMITX_OrReg_Byte(REG_TX_PKT_SINGLE_CTRL, B_TX_SW_CTS);	/* D[1] = 0, HW auto count CTS */
+	else
+		HDMITX_AndReg_Byte(REG_TX_PKT_SINGLE_CTRL, ~B_TX_SW_CTS);	/* D[1] = 0, HW auto count CTS */
+
+	HDMITX_WriteI2C_Byte(0xF8, 0xFF);
+#else
+	HDMITX_AndReg_Byte(REG_TX_PKT_SINGLE_CTRL, ~B_TX_SW_CTS);	/* D[1] = 0, HW auto count CTS */
+#endif
+#endif
+
+	/*   if(FALSE==HBR_mode) */
+	/*	LPCM*/
+	/*   {*/
+	/*   unsigned char uData;*/
+	/*   Switch_HDMITX_Bank(1);*/
+	/*   Fs = AUDFS_768KHz ;*/
+	/*   HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_CA_FS,0x00|Fs);*/
+	/*   Fs = ~Fs ; // OFS is the one's complement of FS*/
+	/*   uData = (0x0f&HDMITX_ReadI2C_Byte(REG_TX_AUDCHST_OFS_WL));*/
+	/*   HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_OFS_WL,(Fs<<4)|uData);*/
+	/*   Switch_HDMITX_Bank(0);*/
+	/*   } */
+}
+
+/****************************************** */
+/* @file   <hdmitx_pkt.c> */
+/* *******************************************/
+
+bool HDMITX_EnableVSInfoFrame(unsigned char bEnable, unsigned char *pVSInfoFrame)
+{
+	if (!bEnable) {
+		hdmitx_DISABLE_VSDB_PKT();
+		return TRUE;
+	}
+	if (hdmitx_SetVSIInfoFrame((VendorSpecific_InfoFrame *) pVSInfoFrame) == ER_SUCCESS)
+		return TRUE;
+
+	return FALSE;
+}
+
+bool HDMITX_EnableAVIInfoFrame(unsigned char bEnable, unsigned char *pAVIInfoFrame)
+{
+	if (!bEnable) {
+		hdmitx_DISABLE_AVI_INFOFRM_PKT();
+		return TRUE;
+	}
+	if (hdmitx_SetAVIInfoFrame((AVI_InfoFrame *) pAVIInfoFrame) == ER_SUCCESS)
+		return TRUE;
+
+	return FALSE;
+}
+
+bool HDMITX_EnableAudioInfoFrame(unsigned char bEnable, unsigned char *pAudioInfoFrame)
+{
+	if (!bEnable) {
+		hdmitx_DISABLE_AVI_INFOFRM_PKT();
+		return TRUE;
+	}
+	if (hdmitx_SetAudioInfoFrame((Audio_InfoFrame *) pAudioInfoFrame) == ER_SUCCESS)
+		return TRUE;
+
+	return FALSE;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_SetAVIInfoFrame() */
+/* Parameter: pAVIInfoFrame - the pointer to HDMI AVI Infoframe ucData */
+/* Return: N/A */
+/* Remark: Fill the AVI InfoFrame ucData,and count checksum,then fill into */
+/* AVI InfoFrame registers. */
+/* Side-Effect: N/A */
+/* //////////////////////////////////////////////////////////////////// */
+
+SYS_STATUS hdmitx_SetAVIInfoFrame(AVI_InfoFrame *pAVIInfoFrame)
+{
+	int i;
+	unsigned char checksum;
+
+	if (!pAVIInfoFrame)
+		return ER_FAIL;
+
+	Switch_HDMITX_Bank(1);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB1, pAVIInfoFrame->pktbyte.AVI_DB[0]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB2, pAVIInfoFrame->pktbyte.AVI_DB[1]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB3, pAVIInfoFrame->pktbyte.AVI_DB[2]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB4, pAVIInfoFrame->pktbyte.AVI_DB[3]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB5, pAVIInfoFrame->pktbyte.AVI_DB[4]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB6, pAVIInfoFrame->pktbyte.AVI_DB[5]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB7, pAVIInfoFrame->pktbyte.AVI_DB[6]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB8, pAVIInfoFrame->pktbyte.AVI_DB[7]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB9, pAVIInfoFrame->pktbyte.AVI_DB[8]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB10, pAVIInfoFrame->pktbyte.AVI_DB[9]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB11, pAVIInfoFrame->pktbyte.AVI_DB[10]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB12, pAVIInfoFrame->pktbyte.AVI_DB[11]);
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB13, pAVIInfoFrame->pktbyte.AVI_DB[12]);
+	for (i = 0, checksum = 0; i < 13; i++)
+		checksum -= pAVIInfoFrame->pktbyte.AVI_DB[i];
+
+	/*   HDMITX_DEBUG_PRINTF(("SetAVIInfo(): "));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB1)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB2)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB3)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB4)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB5)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB6)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB7)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB8)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB9)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB10)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB11)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB12)));*/
+	/*   HDMITX_DEBUG_PRINTF(("%02X ",(int)HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB13)));*/
+	/*   HDMITX_DEBUG_PRINTF(("\n"));*/
+
+	checksum -= AVI_INFOFRAME_VER + AVI_INFOFRAME_TYPE + AVI_INFOFRAME_LEN;
+	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_SUM, checksum);
+
+	Switch_HDMITX_Bank(0);
+	hdmitx_ENABLE_AVI_INFOFRM_PKT();
+	return ER_SUCCESS;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_SetAudioInfoFrame() */
+/* Parameter: pAudioInfoFrame - the pointer to HDMI Audio Infoframe ucData */
+/* Return: N/A */
+/* Remark: Fill the Audio InfoFrame ucData,and count checksum,then fill into */
+/* Audio InfoFrame registers. */
+/* Side-Effect: N/A */
+/* //////////////////////////////////////////////////////////////////// */
+
+SYS_STATUS hdmitx_SetAudioInfoFrame(Audio_InfoFrame *pAudioInfoFrame)
+{
+	unsigned char checksum;
+
+	if (!pAudioInfoFrame)
+		return ER_FAIL;
+
+	Switch_HDMITX_Bank(1);
+	checksum = 0x100 - (AUDIO_INFOFRAME_VER + AUDIO_INFOFRAME_TYPE + AUDIO_INFOFRAME_LEN);
+	HDMITX_WriteI2C_Byte(REG_TX_PKT_AUDINFO_CC, pAudioInfoFrame->pktbyte.AUD_DB[0]);
+	checksum -= HDMITX_ReadI2C_Byte(REG_TX_PKT_AUDINFO_CC);
+	checksum &= 0xFF;
+	HDMITX_WriteI2C_Byte(REG_TX_PKT_AUDINFO_SF, pAudioInfoFrame->pktbyte.AUD_DB[1]);
+	checksum -= HDMITX_ReadI2C_Byte(REG_TX_PKT_AUDINFO_SF);
+	checksum &= 0xFF;
+	HDMITX_WriteI2C_Byte(REG_TX_PKT_AUDINFO_CA, pAudioInfoFrame->pktbyte.AUD_DB[3]);
+	checksum -= HDMITX_ReadI2C_Byte(REG_TX_PKT_AUDINFO_CA);
+	checksum &= 0xFF;
+	HDMITX_WriteI2C_Byte(REG_TX_PKT_AUDINFO_DM_LSV, pAudioInfoFrame->pktbyte.AUD_DB[4]);
+	checksum -= HDMITX_ReadI2C_Byte(REG_TX_PKT_AUDINFO_DM_LSV);
+	checksum &= 0xFF;
+
+	HDMITX_WriteI2C_Byte(REG_TX_PKT_AUDINFO_SUM, checksum);
+
+	Switch_HDMITX_Bank(0);
+	hdmitx_ENABLE_AUD_INFOFRM_PKT();
+	return ER_SUCCESS;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_SetSPDInfoFrame() */
+/* Parameter: pSPDInfoFrame - the pointer to HDMI SPD Infoframe ucData */
+/* Return: N/A */
+/* Remark: Fill the SPD InfoFrame ucData,and count checksum,then fill into */
+/* SPD InfoFrame registers. */
+/* Side-Effect: N/A */
+/* //////////////////////////////////////////////////////////////////// */
+
+SYS_STATUS hdmitx_SetSPDInfoFrame(SPD_InfoFrame *pSPDInfoFrame)
+{
+	int i;
+	unsigned char ucData;
+
+	if (!pSPDInfoFrame)
+		return ER_FAIL;
+
+	Switch_HDMITX_Bank(1);
+	for (i = 0, ucData = 0; i < 25; i++) {
+		ucData -= pSPDInfoFrame->pktbyte.SPD_DB[i];
+		HDMITX_WriteI2C_Byte(REG_TX_PKT_SPDINFO_PB1 + i, pSPDInfoFrame->pktbyte.SPD_DB[i]);
+	}
+	ucData -= SPD_INFOFRAME_VER + SPD_INFOFRAME_TYPE + SPD_INFOFRAME_LEN;
+	HDMITX_WriteI2C_Byte(REG_TX_PKT_SPDINFO_SUM, ucData);	/* checksum */
+	Switch_HDMITX_Bank(0);
+	hdmitx_ENABLE_SPD_INFOFRM_PKT();
+	return ER_SUCCESS;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_SetMPEGInfoFrame() */
+/* Parameter: pMPEGInfoFrame - the pointer to HDMI MPEG Infoframe ucData */
+/* Return: N/A */
+/* Remark: Fill the MPEG InfoFrame ucData,and count checksum,then fill into */
+/* MPEG InfoFrame registers. */
+/* Side-Effect: N/A */
+/* //////////////////////////////////////////////////////////////////// */
+
+SYS_STATUS hdmitx_SetMPEGInfoFrame(MPEG_InfoFrame *pMPGInfoFrame)
+{
+	int i;
+	unsigned char ucData;
+
+	if (!pMPGInfoFrame)
+		return ER_FAIL;
+
+	Switch_HDMITX_Bank(1);
+
+	HDMITX_WriteI2C_Byte(REG_TX_PKT_MPGINFO_FMT,
+			     pMPGInfoFrame->info.FieldRepeat | (pMPGInfoFrame->info.
+								MpegFrame << 1));
+	HDMITX_WriteI2C_Byte(REG_TX_PKG_MPGINFO_DB0, pMPGInfoFrame->pktbyte.MPG_DB[0]);
+	HDMITX_WriteI2C_Byte(REG_TX_PKG_MPGINFO_DB1, pMPGInfoFrame->pktbyte.MPG_DB[1]);
+	HDMITX_WriteI2C_Byte(REG_TX_PKG_MPGINFO_DB2, pMPGInfoFrame->pktbyte.MPG_DB[2]);
+	HDMITX_WriteI2C_Byte(REG_TX_PKG_MPGINFO_DB3, pMPGInfoFrame->pktbyte.MPG_DB[3]);
+
+	for (ucData = 0, i = 0; i < 5; i++)
+		ucData -= pMPGInfoFrame->pktbyte.MPG_DB[i];
+
+	ucData -= MPEG_INFOFRAME_VER + MPEG_INFOFRAME_TYPE + MPEG_INFOFRAME_LEN;
+
+	HDMITX_WriteI2C_Byte(REG_TX_PKG_MPGINFO_SUM, ucData);
+
+	Switch_HDMITX_Bank(0);
+	hdmitx_ENABLE_SPD_INFOFRM_PKT();
+
+	return ER_SUCCESS;
+}
+
+/* 2009/12/04 added by Ming-chih.lung@ite.com.tw */
+
+SYS_STATUS hdmitx_SetVSIInfoFrame(VendorSpecific_InfoFrame *pVSIInfoFrame)
+{
+	unsigned char ucData = 0;
+
+	if (!pVSIInfoFrame)
+		return ER_FAIL;
+
+	Switch_HDMITX_Bank(1);
+	HDMITX_WriteI2C_Byte(0x80, pVSIInfoFrame->pktbyte.VS_DB[3]);
+	HDMITX_WriteI2C_Byte(0x81, pVSIInfoFrame->pktbyte.VS_DB[4]);
+
+	ucData -= pVSIInfoFrame->pktbyte.VS_DB[3];
+	ucData -= pVSIInfoFrame->pktbyte.VS_DB[4];
+
+	if (pVSIInfoFrame->pktbyte.VS_DB[4] & (1 << 7)) {
+		ucData -= pVSIInfoFrame->pktbyte.VS_DB[5];
+		HDMITX_WriteI2C_Byte(0x82, pVSIInfoFrame->pktbyte.VS_DB[5]);
+		ucData -= VENDORSPEC_INFOFRAME_TYPE + VENDORSPEC_INFOFRAME_VER + 6 + 0x0C + 0x03;
+	} else {
+		ucData -= VENDORSPEC_INFOFRAME_TYPE + VENDORSPEC_INFOFRAME_VER + 5 + 0x0C + 0x03;
+	}
+
+	pVSIInfoFrame->pktbyte.CheckSum = ucData;
+
+	HDMITX_WriteI2C_Byte(0x83, pVSIInfoFrame->pktbyte.CheckSum);
+	Switch_HDMITX_Bank(0);
+	HDMITX_WriteI2C_Byte(REG_TX_3D_INFO_CTRL, B_TX_ENABLE_PKT | B_TX_REPEAT_PKT);
+	return ER_SUCCESS;
+}
+
+SYS_STATUS hdmitx_Set_GeneralPurpose_PKT(unsigned char *pData)
+{
+	int i;
+
+	if (pData == NULL)
+		return ER_FAIL;
+
+	Switch_HDMITX_Bank(1);
+	for (i = 0x38; i <= 0x56; i++)
+		HDMITX_WriteI2C_Byte(i, pData[i - 0x38]);
+
+	Switch_HDMITX_Bank(0);
+	hdmitx_ENABLE_GeneralPurpose_PKT();
+	/* hdmitx_ENABLE_NULL_PKT(); */
+	return ER_SUCCESS;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: DumpHDMITXReg() */
+/* Parameter: N/A */
+/* Return: N/A */
+/* Remark: Debug function,dumps the registers of CAT6611. */
+/* Side-Effect: N/A */
+/* //////////////////////////////////////////////////////////////////// */
+
+#if 1				/* defined(Debug_message) && Debug_message */
+void DumpHDMITXReg(void)
+{
+	int i, j;
+	unsigned char ucData = 0;
+
+	HDMITX_DEBUG_PRINTF("--------");
+	for (j = 0; j < 16; j++) {
+		HDMITX_DEBUG_PRINTF("-%02X", (int)j);
+		if ((j == 3) || (j == 7) || (j == 11))
+			HDMITX_DEBUG_PRINTF("--");
+
+	}
+	HDMITX_DEBUG_PRINTF("\n-------------------------------------------------------------\n");
+
+	Switch_HDMITX_Bank(0);
+
+	for (i = 0; i < 0x100; i += 16) {
+		HDMITX_DEBUG_PRINTF("[%3X]--", i);
+		for (j = 0; j < 16; j++) {
+			if ((i + j) != 0x17) {
+				ucData = HDMITX_ReadI2C_Byte((unsigned char) ((i + j) & 0xFF));
+				HDMITX_DEBUG_PRINTF("-%02X", (int)ucData);
+			} else {
+				HDMITX_DEBUG_PRINTF("-XX %d", (int)ucData);	/* for DDC FIFO */
+			}
+			if ((j == 3) || (j == 7) || (j == 11))
+				HDMITX_DEBUG_PRINTF("--");
+
+		}
+		HDMITX_DEBUG_PRINTF("\n");
+		if ((i % 0x40) == 0x30)
+			HDMITX_DEBUG_PRINTF("-------------------------------------------------------------\n");
+
+	}
+	Switch_HDMITX_Bank(1);
+	for (i = 0x130; i < 0x200; i += 16) {
+		HDMITX_DEBUG_PRINTF("[%3X]--", i);
+		for (j = 0; j < 16; j++) {
+			ucData = HDMITX_ReadI2C_Byte((unsigned char) ((i + j) & 0xFF));
+			HDMITX_DEBUG_PRINTF("-%02X", (int)ucData);
+			if ((j == 3) || (j == 7) || (j == 11))
+				HDMITX_DEBUG_PRINTF("--");
+		}
+		HDMITX_DEBUG_PRINTF("\n");
+		if ((i % 0x40) == 0x20)
+			HDMITX_DEBUG_PRINTF("-------------------------------------------------------------\n");
+	}
+	HDMITX_DEBUG_PRINTF("-------------------------------------------------------------\n");
+	Switch_HDMITX_Bank(0);
+}
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_drv.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_drv.h
new file mode 100644
index 0000000..3e126f0
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_drv.h
@@ -0,0 +1,899 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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.
+*/
+
+
+#ifndef _HDMITX_DRV_H_
+#define _HDMITX_DRV_H_
+
+#include "itx_typedef.h"
+#define bool unsigned char
+
+/* #define EXTERN_HDCPROM */
+/* /////////////////////////////////////// */
+/* DDC Address */
+/* /////////////////////////////////////// */
+#define DDC_HDCP_ADDRESS 0x74
+#define DDC_EDID_ADDRESS 0xA0
+#define DDC_FIFO_MAXREQ 0x20
+
+/* I2C address */
+
+#define _80MHz 80000000
+#define HDMI_TX_I2C_SLAVE_ADDR 0x98
+#define CEC_I2C_SLAVE_ADDR 0x9C
+/* ///////////////////////////////////////////////////////////////////// */
+/* Register offset */
+/* ///////////////////////////////////////////////////////////////////// */
+
+#define REG_TX_VENDOR_ID0   0x00
+#define REG_TX_VENDOR_ID1   0x01
+#define REG_TX_DEVICE_ID0   0x02
+#define REG_TX_DEVICE_ID1   0x03
+#define FALSE                       0
+#define TRUE                        1
+
+#define O_TX_DEVID 0
+#define M_TX_DEVID 0xF
+#define O_TX_REVID 4
+#define M_TX_REVID 0xF
+
+#define REG_TX_SW_RST       0x04
+#define B_TX_ENTEST    (1<<7)
+#define B_TX_REF_RST_HDMITX (1<<5)
+#define B_TX_AREF_RST (1<<4)
+#define B_HDMITX_VID_RST (1<<3)
+#define B_HDMITX_AUD_RST (1<<2)
+#define B_TX_HDMI_RST (1<<1)
+#define B_TX_HDCP_RST_HDMITX (1<<0)
+
+#define REG_TX_INT_CTRL 0x05
+#define B_TX_INTPOL_ACTL 0
+#define B_TX_INTPOL_ACTH (1<<7)
+#define B_TX_INT_PUSHPULL 0
+#define B_TX_INT_OPENDRAIN (1<<6)
+
+#define REG_TX_INT_STAT1    0x06
+#define B_TX_INT_AUD_OVERFLOW  (1<<7)
+#define B_TX_INT_ROMACQ_NOACK  (1<<6)
+#define B_TX_INT_RDDC_NOACK    (1<<5)
+#define B_TX_INT_DDCFIFO_ERR   (1<<4)
+#define B_TX_INT_ROMACQ_BUS_HANG   (1<<3)
+#define B_TX_INT_DDC_BUS_HANG  (1<<2)
+#define B_TX_INT_RX_SENSE  (1<<1)
+#define B_TX_INT_HPD_PLUG  (1<<0)
+
+#define REG_TX_INT_STAT2    0x07
+#define B_TX_INT_HDCP_SYNC_DET_FAIL  (1<<7)
+#define B_TX_INT_VID_UNSTABLE  (1<<6)
+#define B_TX_INT_PKTACP    (1<<5)
+#define B_TX_INT_PKTNULL  (1<<4)
+#define B_TX_INT_PKTGENERAL   (1<<3)
+#define B_TX_INT_KSVLIST_CHK   (1<<2)
+#define B_TX_INT_AUTH_DONE (1<<1)
+#define B_TX_INT_AUTH_FAIL (1<<0)
+
+#define REG_TX_INT_STAT3    0x08
+#define B_TX_INT_AUD_CTS   (1<<6)
+#define B_TX_INT_VSYNC     (1<<5)
+#define B_TX_INT_VIDSTABLE (1<<4)
+#define B_TX_INT_PKTMPG    (1<<3)
+#define B_TX_INT_PKTSPD    (1<<2)
+#define B_TX_INT_PKTAUD    (1<<1)
+#define B_TX_INT_PKTAVI    (1<<0)
+
+#define REG_TX_INT_MASK1    0x09
+#define B_TX_AUDIO_OVFLW_MASK (1<<7)
+#define B_TX_DDC_NOACK_MASK (1<<5)
+#define B_TX_DDC_FIFO_ERR_MASK (1<<4)
+#define B_TX_DDC_BUS_HANG_MASK (1<<2)
+#define B_TX_RXSEN_MASK (1<<1)
+#define B_TX_HPD_MASK (1<<0)
+
+#define REG_TX_INT_MASK2    0x0A
+#define B_TX_PKT_AVI_MASK (1<<7)
+#define B_TX_PKT_VID_UNSTABLE_MASK (1<<6)
+#define B_TX_PKT_ACP_MASK (1<<5)
+#define B_TX_PKT_NULL_MASK (1<<4)
+#define B_TX_PKT_GEN_MASK (1<<3)
+#define B_TX_KSVLISTCHK_MASK (1<<2)
+#define B_TX_AUTH_DONE_MASK (1<<1)
+#define B_TX_AUTH_FAIL_MASK (1<<0)
+
+#define REG_TX_INT_MASK3    0x0B
+#define B_TX_HDCP_SYNC_DET_FAIL_MASK (1<<6)
+#define B_TX_AUDCTS_MASK (1<<5)
+#define B_TX_VSYNC_MASK (1<<4)
+#define B_TX_VIDSTABLE_MASK (1<<3)
+#define B_TX_PKT_MPG_MASK (1<<2)
+#define B_TX_PKT_SPD_MASK (1<<1)
+#define B_TX_PKT_AUD_MASK (1<<0)
+
+#define REG_TX_INT_CLR0      0x0C
+#define B_TX_CLR_PKTACP    (1<<7)
+#define B_TX_CLR_PKTNULL   (1<<6)
+#define B_TX_CLR_PKTGENERAL    (1<<5)
+#define B_TX_CLR_KSVLISTCHK    (1<<4)
+#define B_TX_CLR_AUTH_DONE  (1<<3)
+#define B_TX_CLR_AUTH_FAIL  (1<<2)
+#define B_TX_CLR_RXSENSE   (1<<1)
+#define B_TX_CLR_HPD       (1<<0)
+
+#define REG_TX_INT_CLR1       0x0D
+#define B_TX_CLR_VSYNC (1<<7)
+#define B_TX_CLR_VIDSTABLE (1<<6)
+#define B_TX_CLR_PKTMPG    (1<<5)
+#define B_TX_CLR_PKTSPD    (1<<4)
+#define B_TX_CLR_PKTAUD    (1<<3)
+#define B_TX_CLR_PKTAVI    (1<<2)
+#define B_TX_CLR_HDCP_SYNC_DET_FAIL  (1<<1)
+#define B_TX_CLR_VID_UNSTABLE        (1<<0)
+
+#define REG_TX_SYS_STATUS     0x0E
+    /* readonly */
+#define B_TX_INT_ACTIVE    (1<<7)
+#define B_TX_HPDETECT      (1<<6)
+#define B_TX_RXSENDETECT   (1<<5)
+#define B_TXVIDSTABLE   (1<<4)
+    /* read/write */
+#define O_TX_CTSINTSTEP    2
+#define M_TX_CTSINTSTEP    (3<<2)
+#define B_TX_CLR_AUD_CTS     (1<<1)
+#define B_TX_INTACTDONE    (1<<0)
+
+#define REG_TX_BANK_CTRL        0x0F
+#define B_TX_BANK0 0
+#define B_TX_BANK1 1
+
+/* DDC */
+
+#define REG_TX_DDC_MASTER_CTRL   0x10
+#define B_TX_MASTERROM (1<<1)
+#define B_TX_MASTERDDC (0<<1)
+#define B_TX_MASTERHOST    (1<<0)
+#define B_TX_MASTERHDCP    (0<<0)
+
+#define REG_TX_DDC_HEADER  0x11
+#define REG_TX_DDC_REQOFF  0x12
+#define REG_TX_DDC_REQCOUNT    0x13
+#define REG_TX_DDC_EDIDSEG 0x14
+#define REG_TX_DDC_CMD 0x15
+#define CMD_DDC_SEQ_BURSTREAD 0
+#define CMD_LINK_CHKREAD  2
+#define CMD_EDID_READ   3
+#define CMD_FIFO_CLR    9
+#define CMD_GEN_SCLCLK  0xA
+#define CMD_DDC_ABORT   0xF
+
+#define REG_TX_DDC_STATUS  0x16
+#define B_TX_DDC_DONE  (1<<7)
+#define B_TX_DDC_ACT   (1<<6)
+#define B_TX_DDC_NOACK (1<<5)
+#define B_TX_DDC_WAITBUS   (1<<4)
+#define B_TX_DDC_ARBILOSE  (1<<3)
+#define B_TX_DDC_ERROR     (B_TX_DDC_NOACK|B_TX_DDC_WAITBUS|B_TX_DDC_ARBILOSE)
+#define B_TX_DDC_FIFOFULL  (1<<2)
+#define B_TX_DDC_FIFOEMPTY (1<<1)
+
+#define REG_TX_DDC_READFIFO    0x17
+#define REG_TX_ROM_STARTADDR   0x18
+#define REG_TX_HDCP_HEADER 0x19
+#define REG_TX_ROM_HEADER  0x1A
+#define REG_TX_BUSHOLD_T   0x1B
+#define REG_TX_ROM_STAT    0x1C
+#define B_TX_ROM_DONE  (1<<7)
+#define B_TX_ROM_ACTIVE	(1<<6)
+#define B_TX_ROM_NOACK	(1<<5)
+#define B_TX_ROM_WAITBUS	(1<<4)
+#define B_TX_ROM_ARBILOSE	(1<<3)
+#define B_TX_ROM_BUSHANG	(1<<2)
+
+/* HDCP */
+#define REG_TX_AN_GENERATE 0x1F
+#define B_TX_START_CIPHER_GEN  1
+#define B_TX_STOP_CIPHER_GEN   0
+
+#define REG_TX_CLK_CTRL0 0x58
+#define O_TX_OSCLK_SEL 5
+#define M_TX_OSCLK_SEL 3
+#define B_TX_AUTO_OVER_SAMPLING_CLOCK (1<<4)
+#define O_TX_EXT_MCLK_SEL  2
+#define M_TX_EXT_MCLK_SEL  (3<<O_TX_EXT_MCLK_SEL)
+#define B_TX_EXT_128FS (0<<O_TX_EXT_MCLK_SEL)
+#define B_TX_EXT_256FS (1<<O_TX_EXT_MCLK_SEL)
+#define B_TX_EXT_512FS (2<<O_TX_EXT_MCLK_SEL)
+#define B_TX_EXT_1024FS (3<<O_TX_EXT_MCLK_SEL)
+
+#define REG_TX_SHA_SEL       0x50
+#define REG_TX_SHA_RD_BYTE1  0x51
+#define REG_TX_SHA_RD_BYTE2  0x52
+#define REG_TX_SHA_RD_BYTE3  0x53
+#define REG_TX_SHA_RD_BYTE4  0x54
+#define REG_TX_AKSV_RD_BYTE5 0x55
+
+
+#define REG_TX_CLK_CTRL1 0x59
+#define B_TX_EN_TXCLK_COUNT    (1<<5)
+#define B_TX_VDO_LATCH_EDGE    (1<<3)
+
+#define REG_TX_CLK_STATUS1 0x5E
+#define REG_TX_CLK_STATUS2 0x5F
+#define B_TX_IP_LOCK (1<<7)
+#define B_TX_XP_LOCK (1<<6)
+#define B_TX_OSF_LOCK (1<<5)
+
+#define REG_TX_AUD_COUNT 0x60
+#define REG_TX_AFE_DRV_CTRL 0x61
+
+#define B_TX_AFE_DRV_PWD    (1<<5)
+#define B_TX_AFE_DRV_RST    (1<<4)
+
+/* Input Data Format Register */
+#define REG_TX_INPUT_MODE  0x70
+#define O_TX_INCLKDLY	0
+#define M_TX_INCLKDLY	3
+#define B_TX_INDDR	    (1<<2)
+#define B_TX_SYNCEMB	(1<<3)
+#define B_TX_2X656CLK	(1<<4)
+#define B_TX_PCLKDIV2  (1<<5)
+#define M_TX_INCOLMOD	(3<<6)
+#define B_TX_IN_RGB    0
+#define B_TX_IN_YUV422 (1<<6)
+#define B_TX_IN_YUV444 (2<<6)
+
+#define REG_TX_TXFIFO_RST  0x71
+#define B_TX_ENAVMUTERST	1
+#define B_TXFFRST	(1<<1)
+
+#define REG_TX_CSC_CTRL    0x72
+#define B_HDMITX_CSC_BYPASS    0
+#define B_HDMITX_CSC_RGB2YUV   2
+#define B_HDMITX_CSC_YUV2RGB   3
+#define M_TX_CSC_SEL       3
+#define B_TX_EN_DITHER      (1<<7)
+#define B_TX_EN_UDFILTER    (1<<6)
+#define B_TX_DNFREE_GO      (1<<5)
+
+#define SIZEOF_CSCMTX 21
+#define SIZEOF_CSCGAIN 6
+#define SIZEOF_CSCOFFSET 3
+
+
+#define REG_TX_CSC_YOFF 0x73
+#define REG_TX_CSC_COFF 0x74
+#define REG_TX_CSC_RGBOFF 0x75
+
+#define REG_TX_CSC_MTX11_L 0x76
+#define REG_TX_CSC_MTX11_H 0x77
+#define REG_TX_CSC_MTX12_L 0x78
+#define REG_TX_CSC_MTX12_H 0x79
+#define REG_TX_CSC_MTX13_L 0x7A
+#define REG_TX_CSC_MTX13_H 0x7B
+#define REG_TX_CSC_MTX21_L 0x7C
+#define REG_TX_CSC_MTX21_H 0x7D
+#define REG_TX_CSC_MTX22_L 0x7E
+#define REG_TX_CSC_MTX22_H 0x7F
+#define REG_TX_CSC_MTX23_L 0x80
+#define REG_TX_CSC_MTX23_H 0x81
+#define REG_TX_CSC_MTX31_L 0x82
+#define REG_TX_CSC_MTX31_H 0x83
+#define REG_TX_CSC_MTX32_L 0x84
+#define REG_TX_CSC_MTX32_H 0x85
+#define REG_TX_CSC_MTX33_L 0x86
+#define REG_TX_CSC_MTX33_H 0x87
+
+#define REG_TX_CSC_GAIN1V_L 0x88
+#define REG_TX_CSC_GAIN1V_H 0x89
+#define REG_TX_CSC_GAIN2V_L 0x8A
+#define REG_TX_CSC_GAIN2V_H 0x8B
+#define REG_TX_CSC_GAIN3V_L 0x8C
+#define REG_TX_CSC_GAIN3V_H 0x8D
+
+#define REG_TX_HVPol 0x90
+#define REG_TX_HfPixel 0x91
+#define REG_TX_HSSL 0x95
+#define REG_TX_HSEL 0x96
+#define REG_TX_HSH 0x97
+#define REG_TX_VSS1 0xA0
+#define REG_TX_VSE1 0xA1
+#define REG_TX_VSS2 0xA2
+#define REG_TX_VSE2 0xA3
+
+/* HDMI General Control Registers */
+
+#define REG_TX_HDMI_MODE   0xC0
+#define B_TX_HDMI_MODE 1
+#define B_TX_DVI_MODE  0
+#define REG_TX_AV_MUTE 0xC1
+#define REG_TX_GCP     0xC1
+#define B_TX_CLR_AVMUTE    0
+#define B_TX_SET_AVMUTE    1
+#define B_TX_SETAVMUTE        (1<<0)
+#define B_TX_BLUE_SCR_MUTE   (1<<1)
+#define B_TX_NODEF_PHASE    (1<<2)
+#define B_TX_PHASE_RESYNC   (1<<3)
+
+#define O_TX_COLOR_DEPTH     4
+#define M_TX_COLOR_DEPTH     7
+#define B_TX_COLOR_DEPTH_MASK (M_TX_COLOR_DEPTH<<O_TX_COLOR_DEPTH)
+#define B_TX_CD_NODEF  0
+#define B_TX_CD_24     (4<<4)
+#define B_TX_CD_30     (5<<4)
+#define B_TX_CD_36     (6<<4)
+#define B_TX_CD_48     (7<<4)
+#define REG_TX_PKT_GENERAL_CTRL    0xC6
+
+#define REG_TX_OESS_CYCLE  0xC3
+
+
+/* /////////////////////////////////////////////////////////////////// */
+/* Macro */
+/* /////////////////////////////////////////////////////////////////// */
+#define Switch_HDMITX_Bank(x)   HDMITX_SetI2C_Byte(0x0f, 1, (x)&1)
+#define HDMITX_OrReg_Byte(reg, ormask) HDMITX_SetI2C_Byte(reg, (ormask), (ormask))
+#define HDMITX_AndReg_Byte(reg, andmask) HDMITX_WriteI2C_Byte(reg, (HDMITX_ReadI2C_Byte(reg) & (andmask)))
+
+/* /////////////////////////////////////////////////////////////////// */
+/* data structure */
+/* /////////////////////////////////////////////////////////////////// */
+struct _HDMITXDEV {
+
+	unsigned char I2C_DEV;
+	unsigned char I2C_ADDR;
+
+	/* /////////////////////////////////////////////// */
+	/* Interrupt Type */
+	/* /////////////////////////////////////////////// */
+	unsigned char bIntType;		/* = 0 ; */
+	/* /////////////////////////////////////////////// */
+	/* Video Property */
+	/* /////////////////////////////////////////////// */
+	unsigned char bInputVideoSignalType;	/* for Sync Embedded,CCIR656,InputDDR */
+	/* /////////////////////////////////////////////// */
+	/* Audio Property */
+	/* /////////////////////////////////////////////// */
+	unsigned char bOutputAudioMode;	/* = 0 ; */
+	unsigned char bAudioChannelSwap;	/* = 0 ; */
+	unsigned char bAudioChannelEnable;
+	unsigned char bAudFs;
+	unsigned long TMDSClock;
+	unsigned long RCLK;
+	unsigned char bAuthenticated:1;
+	unsigned char bHDMIMode:1;
+	unsigned char bIntPOL:1;		/* 0 = Low Active */
+	unsigned char bHPD:1;
+	/* 2009/11/11 added by jj_tseng@ite.com.tw */
+	unsigned char bSPDIF_OUT;
+	unsigned char TxEMEMStatus:1;
+	/* ~jau-chih.tseng@ite.com.tw 2009/11/11 */
+};
+#define HDMITXDEV struct _HDMITXDEV
+
+/* 2008/02/27 added by jj_tseng@chipadvanced.com */
+enum _MODE_ID {
+	UNKNOWN_MODE = 0,
+	CEA_640x480p60,
+	CEA_720x480p60,
+	CEA_1280x720p60,
+	CEA_1920x1080i60,
+	CEA_720x480i60,
+	CEA_720x240p60,
+	CEA_1440x480i60,
+	CEA_1440x240p60,
+	CEA_2880x480i60,
+	CEA_2880x240p60,
+	CEA_1440x480p60,
+	CEA_1920x1080p60,
+	CEA_720x576p50,
+	CEA_1280x720p50,
+	CEA_1920x1080i50,
+	CEA_720x576i50,
+	CEA_1440x576i50,
+	CEA_720x288p50,
+	CEA_1440x288p50,
+	CEA_2880x576i50,
+	CEA_2880x288p50,
+	CEA_1440x576p50,
+	CEA_1920x1080p50,
+	CEA_1920x1080p24,
+	CEA_1920x1080p25,
+	CEA_1920x1080p30,
+	VESA_640x350p85,
+	VESA_640x400p85,
+	VESA_720x400p85,
+	VESA_640x480p60,
+	VESA_640x480p72,
+	VESA_640x480p75,
+	VESA_640x480p85,
+	VESA_800x600p56,
+	VESA_800x600p60,
+	VESA_800x600p72,
+	VESA_800x600p75,
+	VESA_800X600p85,
+	VESA_840X480p60,
+	VESA_1024x768p60,
+	VESA_1024x768p70,
+	VESA_1024x768p75,
+	VESA_1024x768p85,
+	VESA_1152x864p75,
+	VESA_1280x768p60R,
+	VESA_1280x768p60,
+	VESA_1280x768p75,
+	VESA_1280x768p85,
+	VESA_1280x960p60,
+	VESA_1280x960p85,
+	VESA_1280x1024p60,
+	VESA_1280x1024p75,
+	VESA_1280X1024p85,
+	VESA_1360X768p60,
+	VESA_1400x768p60R,
+	VESA_1400x768p60,
+	VESA_1400x1050p75,
+	VESA_1400x1050p85,
+	VESA_1440x900p60R,
+	VESA_1440x900p60,
+	VESA_1440x900p75,
+	VESA_1440x900p85,
+	VESA_1600x1200p60,
+	VESA_1600x1200p65,
+	VESA_1600x1200p70,
+	VESA_1600x1200p75,
+	VESA_1600x1200p85,
+	VESA_1680x1050p60R,
+	VESA_1680x1050p60,
+	VESA_1680x1050p75,
+	VESA_1680x1050p85,
+	VESA_1792x1344p60,
+	VESA_1792x1344p75,
+	VESA_1856x1392p60,
+	VESA_1856x1392p75,
+	VESA_1920x1200p60R,
+	VESA_1920x1200p60,
+	VESA_1920x1200p75,
+	VESA_1920x1200p85,
+	VESA_1920x1440p60,
+	VESA_1920x1440p75,
+};
+#define MODE_ID enum _MODE_ID
+
+/* ~jj_tseng@chipadvanced.com */
+
+struct _RegSetEntry {
+	unsigned char offset;
+	unsigned char invAndMask;
+	unsigned char OrMask;
+};
+#define RegSetEntry struct _RegSetEntry
+
+#include "hdmitx_hdcp.h"
+#include "hdmitx_input.h"
+
+
+/* Audio Channel Control */
+#define REG_TX_AUDIO_CTRL0 0xE0
+#define M_TX_AUD_SWL (3<<6)
+#define M_TX_AUD_16BIT (0<<6)
+#define M_TX_AUD_18BIT (1<<6)
+#define M_TX_AUD_20BIT (2<<6)
+#define M_TX_AUD_24BIT (3<<6)
+
+#define B_TX_SPDIFTC (1<<5)
+
+#define B_TX_AUD_SPDIF (1<<4)
+#define B_TX_AUD_I2S (0<<4)
+#define B_TX_AUD_EN_I2S3   (1<<3)
+#define B_TX_AUD_EN_I2S2   (1<<2)
+#define B_TX_AUD_EN_I2S1   (1<<1)
+#define B_TX_AUD_EN_I2S0   (1<<0)
+#define B_TX_AUD_EN_SPDIF  1
+
+#define REG_TX_AUDIO_CTRL1 0xE1
+#define B_TX_AUD_FULLPKT (1<<6)
+
+#define B_TX_AUDFMT_STD_I2S (0<<0)
+#define B_TX_AUDFMT_32BIT_I2S (1<<0)
+#define B_TX_AUDFMT_LEFT_JUSTIFY (0<<1)
+#define B_TX_AUDFMT_RIGHT_JUSTIFY (1<<1)
+#define B_TX_AUDFMT_DELAY_1T_TO_WS (0<<2)
+#define B_TX_AUDFMT_NO_DELAY_TO_WS (1<<2)
+#define B_TX_AUDFMT_WS0_LEFT   (0<<3)
+#define B_TX_AUDFMT_WS0_RIGHT   (1<<3)
+#define B_TX_AUDFMT_MSB_SHIFT_FIRST (0<<4)
+#define B_TX_AUDFMT_LSB_SHIFT_FIRST (1<<4)
+#define B_TX_AUDFMT_RISE_EDGE_SAMPLE_WS (0<<5)
+#define B_TX_AUDFMT_FALL_EDGE_SAMPLE_WS (1<<5)
+
+#define REG_TX_AUDIO_FIFOMAP 0xE2
+#define O_TX_FIFO3SEL 6
+#define O_TX_FIFO2SEL 4
+#define O_TX_FIFO1SEL 2
+#define O_TX_FIFO0SEL 0
+#define B_TX_SELSRC3  3
+#define B_TX_SELSRC2  2
+#define B_TX_SELSRC1  1
+#define B_TX_SELSRC0  0
+
+#define REG_TX_AUDIO_CTRL3 0xE3
+#define B_TX_AUD_MULCH (1<<7)
+#define B_TX_EN_ZERO_CTS (1<<6)
+#define B_TX_CHSTSEL (1<<4)
+#define B_TX_S3RLCHG (1<<3)
+#define B_TX_S2RLCHG (1<<2)
+#define B_TX_S1RLCHG (1<<1)
+#define B_TX_S0RLCHG (1<<0)
+
+#define REG_TX_AUD_SRCVALID_FLAT 0xE4
+#define B_TX_AUD_SPXFLAT_SRC3 (1<<7)
+#define B_TX_AUD_SPXFLAT_SRC2 (1<<6)
+#define B_TX_AUD_SPXFLAT_SRC1 (1<<5)
+#define B_TX_AUD_SPXFLAT_SRC0 (1<<4)
+#define B_TX_AUD_ERR2FLAT (1<<3)
+#define B_TX_AUD_S3VALID (1<<2)
+#define B_TX_AUD_S2VALID (1<<1)
+#define B_TX_AUD_S1VALID (1<<0)
+
+#define REG_TX_AUD_HDAUDIO 0xE5
+#define B_TX_HBR   (1<<3)
+#define B_TX_DSD   (1<<1)
+
+/* //////////////////////////////////////// */
+/* Bank 1 */
+/* //////////////////////////////////////// */
+
+#define REGPktAudCTS0 0x30	/* 7:0 */
+#define REGPktAudCTS1 0x31	/* 15:8 */
+#define REGPktAudCTS2 0x32	/* 19:16 */
+#define REGPktAudN0 0x33	/* 7:0 */
+#define REGPktAudN1 0x34	/* 15:8 */
+#define REGPktAudN2 0x35	/* 19:16 */
+#define REGPktAudCTSCnt0 0x35	/* 3:0 */
+#define REGPktAudCTSCnt1 0x36	/* 11:4 */
+#define REGPktAudCTSCnt2 0x37	/* 19:12 */
+
+
+#define REG_TX_AUDCHST_MODE    0x91	/* 191 REG_TX_AUD_CHSTD[2:0] 6:4 */
+				 /* REG_TX_AUD_CHSTC 3 */
+				 /* REG_TX_AUD_NLPCM 2 */
+				 /* REG_TX_AUD_MONO 0 */
+#define REG_TX_AUDCHST_CAT     0x92	/* 192 REG_TX_AUD_CHSTCAT 7:0 */
+#define REG_TX_AUDCHST_SRCNUM  0x93	/* 193 REG_TX_AUD_CHSTSRC 3:0 */
+#define REG_TX_AUD0CHST_CHTNUM 0x94	/* 194 REG_TX_AUD0_CHSTCHR 7:4 */
+				 /* REG_TX_AUD0_CHSTCHL 3:0 */
+#define REG_TX_AUD1CHST_CHTNUM 0x95	/* 195 REG_TX_AUD1_CHSTCHR 7:4 */
+				 /* REG_TX_AUD1_CHSTCHL 3:0 */
+#define REG_TX_AUD2CHST_CHTNUM 0x96	/* 196 REG_TX_AUD2_CHSTCHR 7:4 */
+				 /* REG_TX_AUD2_CHSTCHL 3:0 */
+#define REG_TX_AUD3CHST_CHTNUM 0x97	/* 197 REG_TX_AUD3_CHSTCHR 7:4 */
+				 /* REG_TX_AUD3_CHSTCHL 3:0 */
+#define REG_TX_AUDCHST_CA_FS   0x98	/* 198 REG_TX_AUD_CHSTCA 5:4 */
+				 /* REG_TX_AUD_CHSTFS 3:0 */
+#define REG_TX_AUDCHST_OFS_WL  0x99	/* 199 REG_TX_AUD_CHSTOFS 7:4 */
+				 /* REG_TX_AUD_CHSTWL 3:0 */
+
+#define REG_TX_PKT_SINGLE_CTRL 0xC5
+#define B_TX_SINGLE_PKT    1
+#define B_TX_BURST_PKT
+#define B_TX_SW_CTS    (1<<1)
+
+#define REG_TX_NULL_CTRL 0xC9
+#define REG_TX_ACP_CTRL 0xCA
+#define REG_TX_ISRC1_CTRL 0xCB
+#define REG_TX_ISRC2_CTRL 0xCC
+#define REG_TX_AVI_INFOFRM_CTRL 0xCD
+#define REG_TX_AUD_INFOFRM_CTRL 0xCE
+#define REG_TX_SPD_INFOFRM_CTRL 0xCF
+#define REG_TX_MPG_INFOFRM_CTRL 0xD0
+#define B_TX_ENABLE_PKT    1
+#define B_TX_REPEAT_PKT    (1<<1)
+
+#define REG_TX_3D_INFO_CTRL 0xD2
+
+/* //////////////////////////////////////// */
+/* COMMON PACKET for NULL,ISRC1,ISRC2,SPD */
+/* //////////////////////////////////////// */
+
+#define	REG_TX_PKT_HB00 0x38
+#define	REG_TX_PKT_HB01 0x39
+#define	REG_TX_PKT_HB02 0x3A
+
+#define	REG_TX_PKT_PB00 0x3B
+#define	REG_TX_PKT_PB01 0x3C
+#define	REG_TX_PKT_PB02 0x3D
+#define	REG_TX_PKT_PB03 0x3E
+#define	REG_TX_PKT_PB04 0x3F
+#define	REG_TX_PKT_PB05 0x40
+#define	REG_TX_PKT_PB06 0x41
+#define	REG_TX_PKT_PB07 0x42
+#define	REG_TX_PKT_PB08 0x43
+#define	REG_TX_PKT_PB09 0x44
+#define	REG_TX_PKT_PB10 0x45
+#define	REG_TX_PKT_PB11 0x46
+#define	REG_TX_PKT_PB12 0x47
+#define	REG_TX_PKT_PB13 0x48
+#define	REG_TX_PKT_PB14 0x49
+#define	REG_TX_PKT_PB15 0x4A
+#define	REG_TX_PKT_PB16 0x4B
+#define	REG_TX_PKT_PB17 0x4C
+#define	REG_TX_PKT_PB18 0x4D
+#define	REG_TX_PKT_PB19 0x4E
+#define	REG_TX_PKT_PB20 0x4F
+#define	REG_TX_PKT_PB21 0x50
+#define	REG_TX_PKT_PB22 0x51
+#define	REG_TX_PKT_PB23 0x52
+#define	REG_TX_PKT_PB24 0x53
+#define	REG_TX_PKT_PB25 0x54
+#define	REG_TX_PKT_PB26 0x55
+#define	REG_TX_PKT_PB27 0x56
+
+#define REG_TX_AVIINFO_DB1 0x58
+#define REG_TX_AVIINFO_DB2 0x59
+#define REG_TX_AVIINFO_DB3 0x5A
+#define REG_TX_AVIINFO_DB4 0x5B
+#define REG_TX_AVIINFO_DB5 0x5C
+#define REG_TX_AVIINFO_DB6 0x5E
+#define REG_TX_AVIINFO_DB7 0x5F
+#define REG_TX_AVIINFO_DB8 0x60
+#define REG_TX_AVIINFO_DB9 0x61
+#define REG_TX_AVIINFO_DB10 0x62
+#define REG_TX_AVIINFO_DB11 0x63
+#define REG_TX_AVIINFO_DB12 0x64
+#define REG_TX_AVIINFO_DB13 0x65
+#define REG_TX_AVIINFO_SUM 0x5D
+
+#define REG_TX_PKT_AUDINFO_CC 0x68	/* [2:0] */
+#define REG_TX_PKT_AUDINFO_SF 0x69	/* [4:2] */
+#define REG_TX_PKT_AUDINFO_CA 0x6B	/* [7:0] */
+
+#define REG_TX_PKT_AUDINFO_DM_LSV 0x6C	/* [7][6:3] */
+#define REG_TX_PKT_AUDINFO_SUM 0x6D	/* [7:0] */
+
+/* Source Product Description Info Frame */
+#define REG_TX_PKT_SPDINFO_SUM 0x70
+#define REG_TX_PKT_SPDINFO_PB1 0x71
+#define REG_TX_PKT_SPDINFO_PB2 0x72
+#define REG_TX_PKT_SPDINFO_PB3 0x73
+#define REG_TX_PKT_SPDINFO_PB4 0x74
+#define REG_TX_PKT_SPDINFO_PB5 0x75
+#define REG_TX_PKT_SPDINFO_PB6 0x76
+#define REG_TX_PKT_SPDINFO_PB7 0x77
+#define REG_TX_PKT_SPDINFO_PB8 0x78
+#define REG_TX_PKT_SPDINFO_PB9 0x79
+#define REG_TX_PKT_SPDINFO_PB10 0x7A
+#define REG_TX_PKT_SPDINFO_PB11 0x7B
+#define REG_TX_PKT_SPDINFO_PB12 0x7C
+#define REG_TX_PKT_SPDINFO_PB13 0x7D
+#define REG_TX_PKT_SPDINFO_PB14 0x7E
+#define REG_TX_PKT_SPDINFO_PB15 0x7F
+#define REG_TX_PKT_SPDINFO_PB16 0x80
+#define REG_TX_PKT_SPDINFO_PB17 0x81
+#define REG_TX_PKT_SPDINFO_PB18 0x82
+#define REG_TX_PKT_SPDINFO_PB19 0x83
+#define REG_TX_PKT_SPDINFO_PB20 0x84
+#define REG_TX_PKT_SPDINFO_PB21 0x85
+#define REG_TX_PKT_SPDINFO_PB22 0x86
+#define REG_TX_PKT_SPDINFO_PB23 0x87
+#define REG_TX_PKT_SPDINFO_PB24 0x88
+#define REG_TX_PKT_SPDINFO_PB25 0x89
+
+#define REG_TX_PKT_MPGINFO_FMT 0x8A
+#define B_TX_MPG_FR 1
+#define B_TX_MPG_MF_I  (1<<1)
+#define B_TX_MPG_MF_B  (2<<1)
+#define B_TX_MPG_MF_P  (3<<1)
+#define B_TX_MPG_MF_MASK (3<<1)
+#define REG_TX_PKG_MPGINFO_DB0 0x8B
+#define REG_TX_PKG_MPGINFO_DB1 0x8C
+#define REG_TX_PKG_MPGINFO_DB2 0x8D
+#define REG_TX_PKG_MPGINFO_DB3 0x8E
+#define REG_TX_PKG_MPGINFO_SUM 0x8F
+
+#define Frame_Pcaking 0
+#define Top_and_Botton 6
+#define Side_by_Side 8
+
+/* ////////////////////////////////////////////////// */
+/* Function Prototype */
+/* ////////////////////////////////////////////////// */
+#define hdmitx_ENABLE_NULL_PKT()        \
+	{ HDMITX_WriteI2C_Byte(REG_TX_NULL_CTRL, B_TX_ENABLE_PKT|B_TX_REPEAT_PKT); }
+#define hdmitx_ENABLE_ACP_PKT()          \
+	{ HDMITX_WriteI2C_Byte(REG_TX_ACP_CTRL, B_TX_ENABLE_PKT|B_TX_REPEAT_PKT); }
+#define hdmitx_ENABLE_ISRC1_PKT()        \
+	{ HDMITX_WriteI2C_Byte(REG_TX_ISRC1_CTRL, B_TX_ENABLE_PKT|B_TX_REPEAT_PKT); }
+#define hdmitx_ENABLE_ISRC2_PKT()        \
+	{ HDMITX_WriteI2C_Byte(REG_TX_ISRC2_CTRL, B_TX_ENABLE_PKT|B_TX_REPEAT_PKT); }
+#define hdmitx_ENABLE_AVI_INFOFRM_PKT()  \
+	{ HDMITX_WriteI2C_Byte(REG_TX_AVI_INFOFRM_CTRL, B_TX_ENABLE_PKT|B_TX_REPEAT_PKT); }
+#define hdmitx_ENABLE_AUD_INFOFRM_PKT()  \
+	{ HDMITX_WriteI2C_Byte(REG_TX_AUD_INFOFRM_CTRL, B_TX_ENABLE_PKT|B_TX_REPEAT_PKT); }
+#define hdmitx_ENABLE_SPD_INFOFRM_PKT()  \
+	{ HDMITX_WriteI2C_Byte(REG_TX_SPD_INFOFRM_CTRL, B_TX_ENABLE_PKT|B_TX_REPEAT_PKT); }
+#define hdmitx_ENABLE_MPG_INFOFRM_PKT()  \
+	{ HDMITX_WriteI2C_Byte(REG_TX_MPG_INFOFRM_CTRL, B_TX_ENABLE_PKT|B_TX_REPEAT_PKT); }
+#define hdmitx_ENABLE_GeneralPurpose_PKT() \
+	{ HDMITX_WriteI2C_Byte(REG_TX_NULL_CTRL, B_TX_ENABLE_PKT|B_TX_REPEAT_PKT); }
+#define hdmitx_DISABLE_VSDB_PKT()        \
+	{ HDMITX_WriteI2C_Byte(REG_TX_3D_INFO_CTRL, 0); }
+#define hdmitx_DISABLE_NULL_PKT()        \
+	{ HDMITX_WriteI2C_Byte(REG_TX_NULL_CTRL, 0); }
+#define hdmitx_DISABLE_ACP_PKT()         \
+	{ HDMITX_WriteI2C_Byte(REG_TX_ACP_CTRL, 0); }
+#define hdmitx_DISABLE_ISRC1_PKT()       \
+	{ HDMITX_WriteI2C_Byte(REG_TX_ISRC1_CTRL, 0); }
+#define hdmitx_DISABLE_ISRC2_PKT()       \
+	{ HDMITX_WriteI2C_Byte(REG_TX_ISRC2_CTRL, 0); }
+#define hdmitx_DISABLE_AVI_INFOFRM_PKT() \
+	{ HDMITX_WriteI2C_Byte(REG_TX_AVI_INFOFRM_CTRL, 0); }
+#define hdmitx_DISABLE_AUD_INFOFRM_PKT() \
+	{ HDMITX_WriteI2C_Byte(REG_TX_AUD_INFOFRM_CTRL, 0); }
+#define hdmitx_DISABLE_SPD_INFOFRM_PKT() \
+	{ HDMITX_WriteI2C_Byte(REG_TX_SPD_INFOFRM_CTRL, 0); }
+#define hdmitx_DISABLE_MPG_INFOFRM_PKT() \
+	{ HDMITX_WriteI2C_Byte(REG_TX_MPG_INFOFRM_CTRL, 0); }
+#define hdmitx_DISABLE_GeneralPurpose_PKT() \
+	{ HDMITX_WriteI2C_Byte(REG_TX_NULL_CTRL, 0); }
+
+/* //////////////////////////////////////////////////////////////////// */
+/* External Interface */
+/* //////////////////////////////////////////////////////////////////// */
+
+enum _VIDEOPCLKLEVEL {
+	PCLK_LOW = 0,
+	PCLK_MEDIUM,
+	PCLK_HIGH
+};
+#define VIDEOPCLKLEVEL enum _VIDEOPCLKLEVEL
+
+/* 2008/08/18 added by jj_tseng@chipadvanced.com */
+/* /////////////////////////////////////////////////////////////////////////////////// */
+/* HDMITX function prototype */
+/* /////////////////////////////////////////////////////////////////////////////////// */
+void InitHDMITX(void);
+void HDMITX_InitTxDev(const HDMITXDEV *pInstance);
+unsigned char CheckHDMITX(unsigned char *pHPD, unsigned char *pHPDChange);
+bool getHDMITX_LinkStatus(void);
+void HDMITX_PowerOn(void);
+void HDMITX_PowerDown(void);
+
+void hdmitx_LoadRegSetting(RegSetEntry table[]);
+/* /////////////////////////////////////////////////////////////////////////////////// */
+/* HDMITX video function prototype */
+/* /////////////////////////////////////////////////////////////////////////////////// */
+void HDMITX_DisableVideoOutput(void);
+bool HDMITX_EnableVideoOutput(VIDEOPCLKLEVEL level, unsigned char inputColorMode, unsigned char outputColorMode,
+			      unsigned char bHDMI);
+bool setHDMITX_VideoSignalType(unsigned char inputSignalType);
+void setHDMITX_ColorDepthPhase(unsigned char ColorDepth, unsigned char bPhase);
+void hdmitx_LoadRegSetting(RegSetEntry table[]);
+
+extern HDMITXDEV hdmiTxDev[1];
+
+void hdmitx_SetInputMode(unsigned char InputMode, unsigned char bInputSignalType);
+void hdmitx_SetCSCScale(unsigned char bInputMode, unsigned char bOutputMode);
+void hdmitx_SetupAFE(VIDEOPCLKLEVEL PCLKLevel);
+void hdmitx_FireAFE(void);
+
+#ifndef DISABLE_HDMITX_CSC
+#if (defined(SUPPORT_OUTPUTYUV)) && (defined(SUPPORT_INPUTRGB))
+extern unsigned char bCSCMtx_RGB2YUV_ITU601_16_235[];
+extern unsigned char bCSCMtx_RGB2YUV_ITU601_0_255[];
+extern unsigned char bCSCMtx_RGB2YUV_ITU709_16_235[];
+extern unsigned char bCSCMtx_RGB2YUV_ITU709_0_255[];
+#endif
+
+#if (defined(SUPPORT_OUTPUTRGB)) && (defined(SUPPORT_INPUTYUV))
+extern unsigned char bCSCMtx_YUV2RGB_ITU601_16_235[];
+extern unsigned char bCSCMtx_YUV2RGB_ITU601_0_255[];
+extern unsigned char bCSCMtx_YUV2RGB_ITU709_16_235[];
+extern unsigned char bCSCMtx_YUV2RGB_ITU709_0_255[];
+
+#endif
+#endif				/* DISABLE_HDMITX_CSC */
+
+/* TBD ... */
+/* #ifdef SUPPORT_DEGEN */
+/* bool ProgramDEGenModeByID(MODE_ID id,unsigned char bInputSignalType); */
+/* #endif // SUPPORT_DEGEN */
+
+#ifdef SUPPORT_SYNCEMBEDDED
+bool setHDMITX_SyncEmbeddedByVIC(unsigned char VIC, unsigned char bInputSignalType);
+#endif
+
+
+void hdmitx_SetInputMode(unsigned char InputMode, unsigned char bInputSignalType);
+void hdmitx_SetCSCScale(unsigned char bInputMode, unsigned char bOutputMode);
+void hdmitx_SetupAFE(VIDEOPCLKLEVEL level);
+void hdmitx_FireAFE(void);
+
+/* /////////////////////////////////////////////////////////////////////////////////// */
+/* HDMITX audio function prototype */
+/* /////////////////////////////////////////////////////////////////////////////////// */
+void HDMITX_DisableAudioOutput(void);
+void HDMITX_EnableAudioOutput(unsigned char AudioType, bool bSPDIF, ULONG SampleFreq, unsigned char ChNum,
+			      unsigned char *pIEC60958ChStat, ULONG TMDSClock);
+
+void setHDMITX_AudioChannelEnable(bool EnableAudio_b);
+void setHDMITX_ChStat(unsigned char ucIEC60958ChStat[]);
+void setHDMITX_DSDAudio(void);
+void setHDMITX_HBRAudio(bool bSPDIF);
+void setHDMITX_LPCMAudio(unsigned char AudioSrcNum, unsigned char AudSWL, bool bSPDIF);
+void setHDMITX_NCTS(unsigned char Fs);
+void setHDMITX_NLPCMAudio(bool bSPDIF);
+void setHDMITX_UpdateChStatFs(ULONG Fs);
+
+bool hdmitx_IsAudioChang(void);
+void hdmitx_AutoAdjustAudio(void);
+
+/* /////////////////////////////////////////////////////////////////////////////////// */
+/* HDMITX hdcp function prototype */
+/* /////////////////////////////////////////////////////////////////////////////////// */
+bool HDMITX_EnableHDCP(unsigned char bEnable);
+bool getHDMITX_AuthenticationDone(void);
+
+/* /////////////////////////////////////////////////////////////////////////////////// */
+/* HDMITX pkt/infoframe function prototype */
+/* /////////////////////////////////////////////////////////////////////////////////// */
+void setHDMITX_AVMute(unsigned char bEnable);
+bool HDMITX_EnableAVIInfoFrame(unsigned char bEnable, unsigned char *pAVIInfoFrame);
+bool HDMITX_EnableAudioInfoFrame(unsigned char bEnable, unsigned char *pAudioInfoFrame);
+bool HDMITX_EnableVSInfoFrame(unsigned char bEnable, unsigned char *pVSInfoFrame);
+
+SYS_STATUS hdmitx_SetAVIInfoFrame(AVI_InfoFrame *pAVIInfoFrame);
+SYS_STATUS hdmitx_SetAudioInfoFrame(Audio_InfoFrame *pAudioInfoFrame);
+SYS_STATUS hdmitx_SetSPDInfoFrame(SPD_InfoFrame *pSPDInfoFrame);
+SYS_STATUS hdmitx_SetMPEGInfoFrame(MPEG_InfoFrame *pMPGInfoFrame);
+SYS_STATUS hdmitx_SetVSIInfoFrame(VendorSpecific_InfoFrame *pVSIInfoFrame);
+SYS_STATUS hdmitx_Set_GeneralPurpose_PKT(unsigned char *pData);
+/* /////////////////////////////////////////////////////////////////////////////////// */
+/* HDMITX ddc/edid function prototype */
+/* /////////////////////////////////////////////////////////////////////////////////// */
+bool getHDMITX_EDIDBlock(int EDIDBlockID, unsigned char *pEDIDData);
+SYS_STATUS getHDMITX_EDIDBytes(unsigned char *pData, unsigned char bSegment, unsigned char offset, short Count);
+
+void hdmitx_GenerateDDCSCLK(void);
+void hdmitx_ClearDDCFIFO(void);
+void hdmitx_AbortDDC(void);
+
+#if 1				/* defined(Debug_message) && (Debug_message==1) */
+void DumpHDMITXReg(void);
+#else
+#define DumpHDMITXReg()
+#endif
+
+/* ////////////////////////////////////////////////////////////////// */
+/* Required Interfance */
+/* ////////////////////////////////////////////////////////////////// */
+unsigned char HDMITX_ReadI2C_Byte(unsigned char RegAddr);
+SYS_STATUS HDMITX_WriteI2C_Byte(unsigned char RegAddr, unsigned char d);
+SYS_STATUS HDMITX_ReadI2C_ByteN(unsigned char RegAddr, unsigned char *pData, int N);
+SYS_STATUS HDMITX_WriteI2C_ByteN(unsigned char RegAddr, unsigned char *pData, int N);
+SYS_STATUS HDMITX_SetI2C_Byte(unsigned char Reg, unsigned char Mask, unsigned char Value);
+SYS_STATUS HDMITX_ToggleBit(unsigned char Reg, unsigned char n);
+
+
+#endif				/* _HDMITX_DRV_H_ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_hdcp.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_hdcp.c
new file mode 100644
index 0000000..97fc3bf
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_hdcp.c
@@ -0,0 +1,991 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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 "hdmitx.h"
+#include "hdmitx_drv.h"
+#include "sha1.h"
+
+#ifdef SUPPORT_HDCP
+static unsigned char countbit(unsigned char b);
+#endif
+
+#ifdef SUPPORT_SHA
+unsigned char SHABuff[64];
+unsigned char V[20];
+unsigned char KSVList[32];
+unsigned char Vr[20];
+unsigned char M0[8];
+#endif
+
+#ifdef SUPPORT_HDCP
+
+bool HDMITX_EnableHDCP(unsigned char bEnable)
+{
+#ifdef SUPPORT_HDCP
+	if (bEnable) {
+		if (hdmitx_hdcp_Authenticate() == ER_FAIL) {
+			/* IT66121_LOG("ER_FAIL == hdmitx_hdcp_Authenticate\n"); */
+			hdmitx_hdcp_ResetAuth();
+			return FALSE;
+		}
+	} else {
+		hdmiTxDev[0].bAuthenticated = FALSE;
+		hdmitx_hdcp_ResetAuth();
+	}
+#endif
+	return TRUE;
+}
+
+bool getHDMITX_AuthenticationDone(void)
+{
+	/* HDCP_DEBUG_PRINTF((" getHDMITX_AuthenticationDone() = %s\n",hdmiTxDev[0].bAuthenticated?"TRUE":"FALSE" )); */
+	return hdmiTxDev[0].bAuthenticated;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Authentication */
+/* //////////////////////////////////////////////////////////////////// */
+void hdmitx_hdcp_ClearAuthInterrupt(void)
+{
+	/* unsigned char uc ; */
+	/* uc = HDMITX_ReadI2C_Byte(REG_TX_INT_MASK2) &*/
+	/* (~(B_TX_KSVLISTCHK_MASK|B_TX_AUTH_DONE_MASK|B_TX_AUTH_FAIL_MASK)); */
+	HDMITX_SetI2C_Byte(REG_TX_INT_MASK2,
+			   B_TX_KSVLISTCHK_MASK | B_TX_AUTH_DONE_MASK | B_TX_AUTH_FAIL_MASK, 0);
+	HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0,
+			     B_TX_CLR_AUTH_FAIL | B_TX_CLR_AUTH_DONE | B_TX_CLR_KSVLISTCHK);
+	HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1, 0);
+	HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS, B_TX_INTACTDONE);
+}
+
+void hdmitx_hdcp_ResetAuth(void)
+{
+	HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL, 0);
+	HDMITX_WriteI2C_Byte(REG_TX_HDCP_DESIRE, 0);
+	HDMITX_OrReg_Byte(REG_TX_SW_RST, B_TX_HDCP_RST_HDMITX);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
+	hdmitx_hdcp_ClearAuthInterrupt();
+	hdmitx_AbortDDC();
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_hdcp_Auth_Fire() */
+/* Parameter: N/A */
+/* Return: N/A */
+/* Remark: write anything to reg21 to enable HDCP authentication by HW */
+/* Side-Effect: N/A */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_hdcp_Auth_Fire(void)
+{
+	/* HDCP_DEBUG_PRINTF(("hdmitx_hdcp_Auth_Fire():\n")); */
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHDCP);
+	/* MASTERHDCP,no need command but fire. */
+	HDMITX_WriteI2C_Byte(REG_TX_AUTHFIRE, 1);
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_hdcp_StartAnCipher */
+/* Parameter: N/A */
+/* Return: N/A */
+/* Remark: Start the Cipher to free run for random number. When stop,An is */
+/* ready in Reg30. */
+/* Side-Effect: N/A */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_hdcp_StartAnCipher(void)
+{
+	HDMITX_WriteI2C_Byte(REG_TX_AN_GENERATE, B_TX_START_CIPHER_GEN);
+	delay1ms(1);		/* delay 1 ms */
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_hdcp_StopAnCipher */
+/* Parameter: N/A */
+/* Return: N/A */
+/* Remark: Stop the Cipher,and An is ready in Reg30. */
+/* Side-Effect: N/A */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_hdcp_StopAnCipher(void)
+{
+	HDMITX_WriteI2C_Byte(REG_TX_AN_GENERATE, B_TX_STOP_CIPHER_GEN);
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_hdcp_GenerateAn */
+/* Parameter: N/A */
+/* Return: N/A */
+/* Remark: start An ciper random run at first,then stop it. Software can get */
+/* an in reg30~reg38,the write to reg28~2F */
+/* Side-Effect: */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_hdcp_GenerateAn(void)
+{
+	unsigned char Data[8];
+	unsigned char i = 0;
+#if 1
+	hdmitx_hdcp_StartAnCipher();
+	/* HDMITX_WriteI2C_Byte(REG_TX_AN_GENERATE,B_TX_START_CIPHER_GEN); */
+	/* delay1ms(1); // delay 1 ms */
+	/* HDMITX_WriteI2C_Byte(REG_TX_AN_GENERATE,B_TX_STOP_CIPHER_GEN); */
+
+	hdmitx_hdcp_StopAnCipher();
+
+	Switch_HDMITX_Bank(0);
+	/* new An is ready in reg30 */
+	HDMITX_ReadI2C_ByteN(REG_TX_AN_GEN, Data, 8);
+#else
+	Data[0] = 0;
+	Data[1] = 0;
+	Data[2] = 0;
+	Data[3] = 0;
+	Data[4] = 0;
+	Data[5] = 0;
+	Data[6] = 0;
+	Data[7] = 0;
+#endif
+	for (i = 0; i < 8; i++)
+		HDMITX_WriteI2C_Byte(REG_TX_AN + i, Data[i]);
+	/* HDMITX_WriteI2C_ByteN(REG_TX_AN,Data,8); */
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_hdcp_GetBCaps */
+/* Parameter: pBCaps - pointer of byte to get BCaps. */
+/* pBStatus - pointer of two bytes to get BStatus */
+/* Return: ER_SUCCESS if successfully got BCaps and BStatus. */
+/* Remark: get B status and capability from HDCP receiver via DDC bus. */
+/* Side-Effect: */
+/* //////////////////////////////////////////////////////////////////// */
+
+SYS_STATUS hdmitx_hdcp_GetBCaps(unsigned char *pBCaps, unsigned short *pBStatus)
+{
+	unsigned char ucdata;
+	unsigned char TimeOut;
+
+	Switch_HDMITX_Bank(0);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_HEADER, DDC_HDCP_ADDRESS);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_REQOFF, 0x40);	/* BCaps offset */
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_REQCOUNT, 3);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD, CMD_DDC_SEQ_BURSTREAD);
+
+	for (TimeOut = 200; TimeOut > 0; TimeOut--) {
+		delay1ms(1);
+
+		ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS);
+
+		if (ucdata & B_TX_DDC_DONE) {
+			/* HDCP_DEBUG_PRINTF(("hdmitx_hdcp_GetBCaps(): DDC Done.\n")); */
+			break;
+		}
+		if (ucdata & B_TX_DDC_ERROR) {
+/* HDCP_DEBUG_PRINTF(("hdmitx_hdcp_GetBCaps(): DDC fail by reg16=%02X.\n",ucdata)); */
+			return ER_FAIL;
+		}
+	}
+	if (TimeOut == 0)
+		return ER_FAIL;
+#if 1
+	ucdata = HDMITX_ReadI2C_Byte(REG_TX_BSTAT + 1);
+
+	*pBStatus = (unsigned short)ucdata;
+	*pBStatus <<= 8;
+	ucdata = HDMITX_ReadI2C_Byte(REG_TX_BSTAT);
+	*pBStatus |= ((unsigned short)ucdata & 0xFF);
+	*pBCaps = HDMITX_ReadI2C_Byte(REG_TX_BCAP);
+#else
+	*pBCaps = HDMITX_ReadI2C_Byte(0x17);
+	*pBStatus = HDMITX_ReadI2C_Byte(0x17) & 0xFF;
+	*pBStatus |= (int)(HDMITX_ReadI2C_Byte(0x17) & 0xFF) << 8;
+	HDCP_DEBUG_PRINTF("hdmitx_hdcp_GetBCaps(): ucdata = %02X\n",
+			  (int)HDMITX_ReadI2C_Byte(0x16));
+#endif
+	return ER_SUCCESS;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_hdcp_GetBKSV */
+/* Parameter: pBKSV - pointer of 5 bytes buffer for getting BKSV */
+/* Return: ER_SUCCESS if successfuly got BKSV from Rx. */
+/* Remark: Get BKSV from HDCP receiver. */
+/* Side-Effect: N/A */
+/* //////////////////////////////////////////////////////////////////// */
+
+SYS_STATUS hdmitx_hdcp_GetBKSV(unsigned char *pBKSV)
+{
+	unsigned char ucdata;
+	unsigned char TimeOut;
+
+	Switch_HDMITX_Bank(0);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_HEADER, DDC_HDCP_ADDRESS);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_REQOFF, 0x00);	/* BKSV offset */
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_REQCOUNT, 5);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD, CMD_DDC_SEQ_BURSTREAD);
+
+	for (TimeOut = 200; TimeOut > 0; TimeOut--) {
+		delay1ms(1);
+
+		ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS);
+		if (ucdata & B_TX_DDC_DONE) {
+			HDCP_DEBUG_PRINTF("hdmitx_hdcp_GetBCaps(): DDC Done.\n");
+			break;
+		}
+		if (ucdata & B_TX_DDC_ERROR) {
+			HDCP_DEBUG_PRINTF
+			    ("hdmitx_hdcp_GetBCaps(): DDC No ack or arbilose,%x,maybe cable did not connected. Fail.\n",
+			     ucdata);
+			return ER_FAIL;
+		}
+	}
+	if (TimeOut == 0)
+		return ER_FAIL;
+	HDMITX_ReadI2C_ByteN(REG_TX_BKSV, (unsigned char *) pBKSV, 5);
+
+	return ER_SUCCESS;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function:hdmitx_hdcp_Authenticate */
+/* Parameter: N/A */
+/* Return: ER_SUCCESS if Authenticated without error. */
+/* Remark: do Authentication with Rx */
+/* Side-Effect: */
+/* 1. hdmiTxDev[0].bAuthenticated global variable will be TRUE when authenticated. */
+/* 2. Auth_done interrupt and AUTH_FAIL interrupt will be enabled. */
+/* //////////////////////////////////////////////////////////////////// */
+static unsigned char countbit(unsigned char b)
+{
+	unsigned char i, count;
+
+	for (i = 0, count = 0; i < 8; i++) {
+		if (b & (1 << i))
+			count++;
+	}
+	return count;
+}
+
+void hdmitx_hdcp_Reset(void)
+{
+	unsigned char uc;
+
+	uc = HDMITX_ReadI2C_Byte(REG_TX_SW_RST) | B_TX_HDCP_RST_HDMITX;
+	HDMITX_WriteI2C_Byte(REG_TX_SW_RST, uc);
+	HDMITX_WriteI2C_Byte(REG_TX_HDCP_DESIRE, 0);
+	HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL, 0);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERHOST);
+	hdmitx_ClearDDCFIFO();
+	hdmitx_AbortDDC();
+}
+
+SYS_STATUS hdmitx_hdcp_Authenticate(void)
+{
+	unsigned char ucdata;
+	unsigned char BCaps;
+	unsigned short BStatus;
+	unsigned short TimeOut;
+
+	/* unsigned char revoked = FALSE ; */
+	unsigned char BKSV[5];
+
+	hdmiTxDev[0].bAuthenticated = FALSE;
+	if (0 == (B_TXVIDSTABLE & HDMITX_ReadI2C_Byte(REG_TX_SYS_STATUS)))
+		return ER_FAIL;
+
+	/* Authenticate should be called after AFE setup up. */
+
+	HDCP_DEBUG_PRINTF("hdmitx_hdcp_Authenticate():\n");
+	hdmitx_hdcp_Reset();
+
+	Switch_HDMITX_Bank(0);
+
+	for (TimeOut = 0; TimeOut < 80; TimeOut++) {
+		delay1ms(15);
+
+		if (hdmitx_hdcp_GetBCaps(&BCaps, &BStatus) != ER_SUCCESS) {
+			HDCP_DEBUG_PRINTF("hdmitx_hdcp_GetBCaps fail.\n");
+			return ER_FAIL;
+		}
+		/* HDCP_DEBUG_PRINTF(("(%d)Reg16 = %02X\n",idx++,(int)HDMITX_ReadI2C_Byte(0x16))); */
+
+		if (B_TX_HDMI_MODE == (HDMITX_ReadI2C_Byte(REG_TX_HDMI_MODE) & B_TX_HDMI_MODE)) {
+			if ((BStatus & B_TX_CAP_HDMI_MODE) == B_TX_CAP_HDMI_MODE)
+				break;
+		} else {
+			if ((BStatus & B_TX_CAP_HDMI_MODE) != B_TX_CAP_HDMI_MODE)
+				break;
+		}
+	}
+	/*   if((BStatus & M_TX_DOWNSTREAM_COUNT)> 6)*/
+	/*   {*/
+	/*   HDCP_DEBUG_PRINTF(("Down Stream Count %d is over maximum supported number 6,fail.\n",*/
+	/*	(int)(BStatus & M_TX_DOWNSTREAM_COUNT)));*/
+	/*   return ER_FAIL ;*/
+	/*   }*/
+
+	HDCP_DEBUG_PRINTF("BCAPS = %02X BSTATUS = %04X\n", (int)BCaps, BStatus);
+	hdmitx_hdcp_GetBKSV(BKSV);
+	HDCP_DEBUG_PRINTF("BKSV %02X %02X %02X %02X %02X\n", (int)BKSV[0], (int)BKSV[1],
+			  (int)BKSV[2], (int)BKSV[3], (int)BKSV[4]);
+
+	for (TimeOut = 0, ucdata = 0; TimeOut < 5; TimeOut++)
+		ucdata += countbit(BKSV[TimeOut]);
+
+	if (ucdata != 20) {
+		HDCP_DEBUG_PRINTF("countbit error\n");
+		return ER_FAIL;
+
+	}
+	Switch_HDMITX_Bank(0);
+	/* switch bank action should start on direct register writing of each function. */
+
+	HDMITX_AndReg_Byte(REG_TX_SW_RST, ~(B_TX_HDCP_RST_HDMITX));
+
+	HDMITX_WriteI2C_Byte(REG_TX_HDCP_DESIRE, B_TX_CPDESIRE);
+	hdmitx_hdcp_ClearAuthInterrupt();
+
+	hdmitx_hdcp_GenerateAn();
+	HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL, 0);
+	hdmiTxDev[0].bAuthenticated = FALSE;
+
+	hdmitx_ClearDDCFIFO();
+
+	if ((BCaps & B_TX_CAP_HDMI_REPEATER) == 0) {
+		hdmitx_hdcp_Auth_Fire();
+		/* wait for status ; */
+
+		for (TimeOut = 250; TimeOut > 0; TimeOut--) {
+			delay1ms(5);	/* delay 1ms */
+			ucdata = HDMITX_ReadI2C_Byte(REG_TX_AUTH_STAT);
+			/* HDCP_DEBUG_PRINTF("reg46 = %02x reg16 = %02x\n",*/
+			/* (int)ucdata,(int)HDMITX_ReadI2C_Byte(0x16)); */
+
+			if (ucdata & B_TX_AUTH_DONE) {
+				hdmiTxDev[0].bAuthenticated = TRUE;
+				break;
+			}
+			ucdata = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT2);
+			if (ucdata & B_TX_INT_AUTH_FAIL) {
+
+				HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0, B_TX_CLR_AUTH_FAIL);
+				HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1, 0);
+				HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS, B_TX_INTACTDONE);
+				HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS, 0);
+
+				HDCP_DEBUG_PRINTF
+				    ("hdmitx_hdcp_Authenticate()-receiver: Authenticate fail\n");
+				hdmiTxDev[0].bAuthenticated = FALSE;
+				return ER_FAIL;
+			}
+		}
+		if (TimeOut == 0) {
+			HDCP_DEBUG_PRINTF
+			    ("hdmitx_hdcp_Authenticate()-receiver: Time out. return fail\n");
+			hdmiTxDev[0].bAuthenticated = FALSE;
+			return ER_FAIL;
+		}
+		return ER_SUCCESS;
+	}
+	return hdmitx_hdcp_Authenticate_Repeater();
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_hdcp_VerifyIntegration */
+/* Parameter: N/A */
+/* Return: ER_SUCCESS if success,if AUTH_FAIL interrupt status,return fail. */
+/* Remark: no used now. */
+/* Side-Effect: */
+/* //////////////////////////////////////////////////////////////////// */
+
+SYS_STATUS hdmitx_hdcp_VerifyIntegration(void)
+{
+	/* if any interrupt issued a Auth fail,returned the Verify Integration fail. */
+
+	if (HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1) & B_TX_INT_AUTH_FAIL) {
+		hdmitx_hdcp_ClearAuthInterrupt();
+		hdmiTxDev[0].bAuthenticated = FALSE;
+		return ER_FAIL;
+	}
+	if (hdmiTxDev[0].bAuthenticated == TRUE)
+		return ER_SUCCESS;
+
+	return ER_FAIL;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_hdcp_Authenticate_Repeater */
+/* Parameter: BCaps and BStatus */
+/* Return: ER_SUCCESS if success,if AUTH_FAIL interrupt status,return fail. */
+/* Remark: */
+/* Side-Effect: as Authentication */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_hdcp_CancelRepeaterAuthenticate(void)
+{
+	HDCP_DEBUG_PRINTF("hdmitx_hdcp_CancelRepeaterAuthenticate");
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERDDC | B_TX_MASTERHOST);
+	hdmitx_AbortDDC();
+	HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL, B_TX_LISTFAIL | B_TX_LISTDONE);
+	hdmitx_hdcp_ClearAuthInterrupt();
+}
+
+void hdmitx_hdcp_ResumeRepeaterAuthenticate(void)
+{
+	HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL, B_TX_LISTDONE);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERHDCP);
+}
+
+#if 0				/* def SUPPORT_SHA */
+/* #define SHA_BUFF_COUNT 17 */
+/* ULONG w[SHA_BUFF_COUNT]; */
+/*  */
+/* ULONG sha[5] ; */
+/*  */
+/* #define rol(x,y) (((x) << (y)) | (((ULONG)x) >> (32-y))) */
+/*  */
+/* void SHATransform(ULONG * h) */
+/* { */
+/* int t,i; */
+/* ULONG tmp ; */
+/*  */
+/* h[0] = 0x67452301 ; */
+/* h[1] = 0xefcdab89; */
+/* h[2] = 0x98badcfe; */
+/* h[3] = 0x10325476; */
+/* h[4] = 0xc3d2e1f0; */
+/* for( t = 0 ; t < 80 ; t++ ) */
+/* { */
+/* if((t>=16)&&(t<80)) { */
+/* i=(t+SHA_BUFF_COUNT-3)%SHA_BUFF_COUNT; */
+/* tmp = w[i]; */
+/* i=(t+SHA_BUFF_COUNT-8)%SHA_BUFF_COUNT; */
+/* tmp ^= w[i]; */
+/* i=(t+SHA_BUFF_COUNT-14)%SHA_BUFF_COUNT; */
+/* tmp ^= w[i]; */
+/* i=(t+SHA_BUFF_COUNT-16)%SHA_BUFF_COUNT; */
+/* tmp ^= w[i]; */
+/* w[t%SHA_BUFF_COUNT] = rol(tmp,1); */
+/* //HDCP_DEBUG_PRINTF(("w[%2d] = %08lX\n",t,w[t%SHA_BUFF_COUNT])); */
+/* } */
+/*  */
+/* if((t>=0)&&(t<20)) { */
+/* tmp = rol(h[0],5) + ((h[1] & h[2]) | (h[3] & ~h[1])) + h[4] + w[t%SHA_BUFF_COUNT] + 0x5a827999; */
+/* //HDCP_DEBUG_PRINTF(("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4])); */
+/*  */
+/* h[4] = h[3]; */
+/* h[3] = h[2]; */
+/* h[2] = rol(h[1],30); */
+/* h[1] = h[0]; */
+/* h[0] = tmp; */
+/*  */
+/* } */
+/* if((t>=20)&&(t<40)) { */
+/* tmp = rol(h[0],5) + (h[1] ^ h[2] ^ h[3]) + h[4] + w[t%SHA_BUFF_COUNT] + 0x6ed9eba1; */
+/* //HDCP_DEBUG_PRINTF(("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4])); */
+/* h[4] = h[3]; */
+/* h[3] = h[2]; */
+/* h[2] = rol(h[1],30); */
+/* h[1] = h[0]; */
+/* h[0] = tmp; */
+/* } */
+/* if((t>=40)&&(t<60)) { */
+/* tmp = rol(h[0], 5) + ((h[1] & h[2]) | (h[1] & h[3]) | (h[2] & h[3])) + h[4] + w[t%SHA_BUFF_COUNT] + */
+/* 0x8f1bbcdc; */
+/* //HDCP_DEBUG_PRINTF(("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4])); */
+/* h[4] = h[3]; */
+/* h[3] = h[2]; */
+/* h[2] = rol(h[1],30); */
+/* h[1] = h[0]; */
+/* h[0] = tmp; */
+/* } */
+/* if((t>=60)&&(t<80)) { */
+/* tmp = rol(h[0],5) + (h[1] ^ h[2] ^ h[3]) + h[4] + w[t%SHA_BUFF_COUNT] + 0xca62c1d6; */
+/* //HDCP_DEBUG_PRINTF(("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4])); */
+/* h[4] = h[3]; */
+/* h[3] = h[2]; */
+/* h[2] = rol(h[1],30); */
+/* h[1] = h[0]; */
+/* h[0] = tmp; */
+/* } */
+/* } */
+/* HDCP_DEBUG_PRINTF(("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4])); */
+/*  */
+/* h[0] += 0x67452301 ; */
+/* h[1] += 0xefcdab89; */
+/* h[2] += 0x98badcfe; */
+/* h[3] += 0x10325476; */
+/* h[4] += 0xc3d2e1f0; */
+/* //    HDCP_DEBUG_PRINTF(("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4])); */
+/* } */
+/*  */
+/*  ---------------------------------------------------------------------- */
+/* * Outer SHA algorithm: take an arbitrary length byte string, */
+/* * convert it into 16-word blocks with the prescribed padding at */
+/* * the end,and pass those blocks to the core SHA algorithm. */
+/* */ */
+/*  */
+/* void SHA_Simple(void *p,LONG len,unsigned char *output) */
+/* { */
+/* // SHA_State s; */
+/* int i, t ; */
+/* ULONG c ; */
+/* char *pBuff = p ; */
+/*  */
+/* for(i=0;i < len;i+=4) */
+/* { */
+/*  */
+/* t=i/4; */
+/* w[t]=0; */
+/* *((char *)&c)= pBuff[i]; */
+/* *((char *)&c+1)= pBuff[i+1]; */
+/* *((char *)&c+2)= pBuff[i+2]; */
+/* *((char *)&c+3)= pBuff[i+3]; */
+/* w[t]=c; */
+/* } */
+/*  */
+/* c=0x80; */
+/* c<<=((3-len%4)*8); */
+/* w[t] |= c; */
+/*  */
+/*  */
+/* for( i = 0 ; i < len ; i++ ) */
+/* { */
+/* t = i/4 ; */
+/* if( i%4 == 0 ) */
+/* { */
+/* w[t] = 0 ; */
+/* } */
+/* c = pBuff[i] ; */
+/* c &= 0xFF ; */
+/* c <<= (3-(i%4))*8 ; */
+/* w[t] |= c ; */
+/* //        HDCP_DEBUG_PRINTF(("pBuff[%d] = %02x, c = %08lX, w[%d] = %08lX\n",i,pBuff[i],c,t,w[t])); */
+/* } */
+/*  */
+/* t = i/4 ; */
+/* if( i%4 == 0 ) */
+/* { */
+/* w[t] = 0 ; */
+/* } */
+/* c = 0x80; */
+/* c <<= ((3-i%4)*8); */
+/* w[t]|= c ; */
+/* */ */
+/* t++ ; */
+/* for( ; t < 15 ; t++ ) */
+/* { */
+/* w[t] = 0 ; */
+/* } */
+/* w[15] = len*8  ; */
+/*  */
+/* for( t = 0 ; t< 16 ; t++ ) */
+/* { */
+/* HDCP_DEBUG_PRINTF(("w[%2d] = %08lX\n",t,w[t])); */
+/* } */
+/*  */
+/* SHATransform(sha); */
+/*  */
+/* for( i = 0 ; i < 5 ; i++ ) */
+/* { */
+/* output[i*4] = (unsigned char)(sha[i]&0xFF); */
+/* output[i*4+1] = (unsigned char)((sha[i]>>8)&0xFF); */
+/* output[i*4+2] = (unsigned char)((sha[i]>>16)&0xFF); */
+/* output[i*4+3]   = (unsigned char)((sha[i]>>24)&0xFF); */
+/* } */
+/* } */
+#endif				/* 0 */
+
+#ifdef SUPPORT_SHA
+
+SYS_STATUS hdmitx_hdcp_CheckSHA(unsigned char pM0[], unsigned short BStatus, unsigned char pKSVList[],
+				int cDownStream, unsigned char Vr[])
+{
+	int i, n;
+
+	for (i = 0; i < cDownStream * 5; i++)
+		SHABuff[i] = pKSVList[i];
+
+	SHABuff[i++] = BStatus & 0xFF;
+	SHABuff[i++] = (BStatus >> 8) & 0xFF;
+	for (n = 0; n < 8; n++, i++)
+		SHABuff[i] = pM0[n];
+
+	n = i;
+	/* SHABuff[i++] = 0x80 ; // end mask */
+	for (; i < 64; i++)
+		SHABuff[i] = 0;
+
+	/* n = cDownStream * 5 + 2  + 8  ; */
+	/* n *= 8 ; */
+	/* SHABuff[62] = (n>>8) & 0xff ; */
+	/* SHABuff[63] = (n>>8) & 0xff ; */
+
+/*  for(i = 0 ; i < 64 ; i++)*/
+/*  {*/
+/*	if(i % 16 == 0)*/
+/*	{*/
+/*	    HDCP_DEBUG_PRINTF(("SHA[]: "));*/
+/*	}*/
+/*	HDCP_DEBUG_PRINTF((" %02X",SHABuff[i]));*/
+/*	if((i%16)==15)*/
+/*	{*/
+/*	    HDCP_DEBUG_PRINTF(("\n"));*/
+/*	}*/
+/*    }*/
+
+	SHA_Simple(SHABuff, n, V);
+	for (i = 0; i < 20; i++) {
+		if (V[i] != Vr[i]) {
+			HDCP_DEBUG_PRINTF("V[] =");
+			for (i = 0; i < 20; i++)
+				HDCP_DEBUG_PRINTF(" %02X", (int)V[i]);
+
+			HDCP_DEBUG_PRINTF("\nVr[] =");
+			for (i = 0; i < 20; i++)
+				HDCP_DEBUG_PRINTF(" %02X", (int)Vr[i]);
+
+			return ER_FAIL;
+		}
+	}
+	return ER_SUCCESS;
+}
+
+#endif				/* SUPPORT_SHA */
+
+SYS_STATUS hdmitx_hdcp_GetKSVList(unsigned char *pKSVList, unsigned char cDownStream)
+{
+	unsigned char TimeOut = 100;
+	unsigned char ucdata;
+
+	if (cDownStream == 0)
+		return ER_SUCCESS;
+
+	if (/* cDownStream == 0 || */ pKSVList == NULL)
+		return ER_FAIL;
+
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERHOST);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_HEADER, 0x74);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_REQOFF, 0x43);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_REQCOUNT, cDownStream * 5);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD, CMD_DDC_SEQ_BURSTREAD);
+
+	for (TimeOut = 200; TimeOut > 0; TimeOut--) {
+
+		ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS);
+		if (ucdata & B_TX_DDC_DONE) {
+			HDCP_DEBUG_PRINTF("hdmitx_hdcp_GetKSVList(): DDC Done.\n");
+			break;
+		}
+		if (ucdata & B_TX_DDC_ERROR) {
+			HDCP_DEBUG_PRINTF
+			    ("hdmitx_hdcp_GetKSVList(): DDC Fail by REG_TX_DDC_STATUS = %x.\n",
+			     ucdata);
+			return ER_FAIL;
+		}
+		delay1ms(5);
+	}
+	if (TimeOut == 0)
+		return ER_FAIL;
+
+	HDCP_DEBUG_PRINTF("hdmitx_hdcp_GetKSVList(): KSV");
+	for (TimeOut = 0; TimeOut < cDownStream * 5; TimeOut++) {
+		pKSVList[TimeOut] = HDMITX_ReadI2C_Byte(REG_TX_DDC_READFIFO);
+		HDCP_DEBUG_PRINTF(" %02X", (int)pKSVList[TimeOut]);
+	}
+	HDCP_DEBUG_PRINTF("\n");
+	return ER_SUCCESS;
+}
+
+SYS_STATUS hdmitx_hdcp_GetVr(unsigned char *pVr)
+{
+	unsigned char TimeOut;
+	unsigned char ucdata;
+
+	if (pVr == NULL)
+		return ER_FAIL;
+
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL, B_TX_MASTERHOST);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_HEADER, 0x74);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_REQOFF, 0x20);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_REQCOUNT, 20);
+	HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD, CMD_DDC_SEQ_BURSTREAD);
+
+	for (TimeOut = 200; TimeOut > 0; TimeOut--) {
+		ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS);
+		if (ucdata & B_TX_DDC_DONE) {
+			HDCP_DEBUG_PRINTF("hdmitx_hdcp_GetVr(): DDC Done.\n");
+			break;
+		}
+		if (ucdata & B_TX_DDC_ERROR) {
+			HDCP_DEBUG_PRINTF
+			    ("hdmitx_hdcp_GetVr(): DDC fail by REG_TX_DDC_STATUS = %x.\n",
+			     (int)ucdata);
+			return ER_FAIL;
+		}
+		delay1ms(5);
+	}
+	if (TimeOut == 0) {
+		HDCP_DEBUG_PRINTF("hdmitx_hdcp_GetVr(): DDC fail by timeout.\n");
+		return ER_FAIL;
+	}
+	Switch_HDMITX_Bank(0);
+
+	for (TimeOut = 0; TimeOut < 5; TimeOut++) {
+		HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL, TimeOut);
+		pVr[TimeOut * 4] = (ULONG) HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE1);
+		pVr[TimeOut * 4 + 1] = (ULONG) HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE2);
+		pVr[TimeOut * 4 + 2] = (ULONG) HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE3);
+		pVr[TimeOut * 4 + 3] = (ULONG) HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE4);
+/* HDCP_DEBUG_PRINTF(("V' = %02X %02X %02X %02X\n",*/
+/*(int)pVr[TimeOut*4],(int)pVr[TimeOut*4+1],(int)pVr[TimeOut*4+2],(int)pVr[TimeOut*4+3])); */
+	}
+	return ER_SUCCESS;
+}
+
+SYS_STATUS hdmitx_hdcp_GetM0(unsigned char *pM0)
+{
+	int i;
+
+	if (!pM0)
+		return ER_FAIL;
+
+	HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL, 5);	/* read m0[31:0] from reg51~reg54 */
+	pM0[0] = HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE1);
+	pM0[1] = HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE2);
+	pM0[2] = HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE3);
+	pM0[3] = HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE4);
+	HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL, 0);	/* read m0[39:32] from reg55 */
+	pM0[4] = HDMITX_ReadI2C_Byte(REG_TX_AKSV_RD_BYTE5);
+	HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL, 1);	/* read m0[47:40] from reg55 */
+	pM0[5] = HDMITX_ReadI2C_Byte(REG_TX_AKSV_RD_BYTE5);
+	HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL, 2);	/* read m0[55:48] from reg55 */
+	pM0[6] = HDMITX_ReadI2C_Byte(REG_TX_AKSV_RD_BYTE5);
+	HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL, 3);	/* read m0[63:56] from reg55 */
+	pM0[7] = HDMITX_ReadI2C_Byte(REG_TX_AKSV_RD_BYTE5);
+
+	HDCP_DEBUG_PRINTF("M[] =");
+	for (i = 0; i < 8; i++)
+		HDCP_DEBUG_PRINTF("0x%02x,", (int)pM0[i]);
+
+	HDCP_DEBUG_PRINTF("\n");
+	return ER_SUCCESS;
+}
+
+SYS_STATUS hdmitx_hdcp_Authenticate_Repeater(void)
+{
+	unsigned char uc, ii;
+	/* unsigned char revoked ; */
+	/* int i ; */
+	unsigned char cDownStream;
+
+	unsigned char BCaps;
+	unsigned short BStatus;
+	unsigned short TimeOut;
+
+	HDCP_DEBUG_PRINTF("Authentication for repeater\n");
+	/* emily add for test,abort HDCP */
+	/* 2007/10/01 marked by jj_tseng@chipadvanced.com */
+	/* HDMITX_WriteI2C_Byte(0x20,0x00); */
+	/* HDMITX_WriteI2C_Byte(0x04,0x01); */
+	/* HDMITX_WriteI2C_Byte(0x10,0x01); */
+	/* HDMITX_WriteI2C_Byte(0x15,0x0F); */
+	/* delay1ms(100); */
+	/* HDMITX_WriteI2C_Byte(0x04,0x00); */
+	/* HDMITX_WriteI2C_Byte(0x10,0x00); */
+	/* HDMITX_WriteI2C_Byte(0x20,0x01); */
+	/* delay1ms(100); */
+	/* test07 = HDMITX_ReadI2C_Byte(0x7); */
+	/* test06 = HDMITX_ReadI2C_Byte(0x6); */
+	/* test08 = HDMITX_ReadI2C_Byte(0x8); */
+	/* ~jj_tseng@chipadvanced.com */
+	/* end emily add for test */
+	/* //////////////////////////////////// */
+	/* Authenticate Fired */
+	/* //////////////////////////////////// */
+
+	hdmitx_hdcp_GetBCaps(&BCaps, &BStatus);
+	delay1ms(2);
+	if ((B_TX_INT_HPD_PLUG | B_TX_INT_RX_SENSE) & HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1)) {
+		HDCP_DEBUG_PRINTF("HPD Before Fire Auth\n");
+		goto hdmitx_hdcp_Repeater_Fail;
+	}
+	hdmitx_hdcp_Auth_Fire();
+	/* delay1ms(550); // emily add for test */
+	for (ii = 0; ii < 55; ii++) {
+		/* delay1ms(550); // emily add for test */
+		if ((B_TX_INT_HPD_PLUG | B_TX_INT_RX_SENSE) & HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1))
+			goto hdmitx_hdcp_Repeater_Fail;
+
+		delay1ms(10);
+	}
+	for (TimeOut = /*250*6 */ 10; TimeOut > 0; TimeOut--) {
+		HDCP_DEBUG_PRINTF("TimeOut = %d wait part 1\n", TimeOut);
+		if ((B_TX_INT_HPD_PLUG | B_TX_INT_RX_SENSE) & HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1)) {
+			HDCP_DEBUG_PRINTF("HPD at wait part 1\n");
+			goto hdmitx_hdcp_Repeater_Fail;
+		}
+		uc = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1);
+		if (uc & B_TX_INT_DDC_BUS_HANG) {
+			HDCP_DEBUG_PRINTF("DDC Bus hang\n");
+			goto hdmitx_hdcp_Repeater_Fail;
+		}
+		uc = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT2);
+
+		if (uc & B_TX_INT_AUTH_FAIL) {
+			/*   HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0,B_TX_CLR_AUTH_FAIL);*/
+			/*   HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1,0);*/
+			/*   HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,B_TX_INTACTDONE);*/
+			/*   HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,0);*/
+
+			HDCP_DEBUG_PRINTF
+			    ("hdmitx_hdcp_Authenticate_Repeater(): B_TX_INT_AUTH_FAIL.\n");
+			goto hdmitx_hdcp_Repeater_Fail;
+		}
+		/* emily add for test */
+		/* test =(HDMITX_ReadI2C_Byte(0x7)&0x4)>>2 ; */
+		if (uc & B_TX_INT_KSVLIST_CHK) {
+			HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0, B_TX_CLR_KSVLISTCHK);
+			HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1, 0);
+			HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS, B_TX_INTACTDONE);
+			HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS, 0);
+			HDCP_DEBUG_PRINTF("B_TX_INT_KSVLIST_CHK\n");
+			break;
+		}
+		delay1ms(5);
+	}
+	if (TimeOut == 0) {
+		HDCP_DEBUG_PRINTF("Time out for wait KSV List checking interrupt\n");
+		goto hdmitx_hdcp_Repeater_Fail;
+	}
+	/* ///////////////////////////////////// */
+	/* clear KSVList check interrupt. */
+	/* ///////////////////////////////////// */
+
+	for (TimeOut = 500; TimeOut > 0; TimeOut--) {
+		HDCP_DEBUG_PRINTF("TimeOut=%d at wait FIFO ready\n", TimeOut);
+		if ((B_TX_INT_HPD_PLUG | B_TX_INT_RX_SENSE) & HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1)) {
+			HDCP_DEBUG_PRINTF("HPD at wait FIFO ready\n");
+			goto hdmitx_hdcp_Repeater_Fail;
+		}
+		if (hdmitx_hdcp_GetBCaps(&BCaps, &BStatus) == ER_FAIL) {
+			HDCP_DEBUG_PRINTF("Get BCaps fail\n");
+			goto hdmitx_hdcp_Repeater_Fail;
+		}
+		if (BCaps & B_TX_CAP_KSV_FIFO_RDY) {
+			HDCP_DEBUG_PRINTF("FIFO Ready\n");
+			break;
+		}
+		delay1ms(5);
+
+	}
+	if (TimeOut == 0) {
+		HDCP_DEBUG_PRINTF("Get KSV FIFO ready TimeOut\n");
+		goto hdmitx_hdcp_Repeater_Fail;
+	}
+	HDCP_DEBUG_PRINTF("Wait timeout = %d\n", TimeOut);
+
+	hdmitx_ClearDDCFIFO();
+	hdmitx_GenerateDDCSCLK();
+	cDownStream = (BStatus & M_TX_DOWNSTREAM_COUNT);
+
+	if (/*cDownStream == 0 || */ cDownStream > 6
+	    || BStatus & (B_TX_MAX_CASCADE_EXCEEDED | B_TX_DOWNSTREAM_OVER)) {
+		HDCP_DEBUG_PRINTF("Invalid Down stream count,fail\n");
+		goto hdmitx_hdcp_Repeater_Fail;
+	}
+#ifdef SUPPORT_SHA
+	if (hdmitx_hdcp_GetKSVList(KSVList, cDownStream) == ER_FAIL)
+		goto hdmitx_hdcp_Repeater_Fail;
+
+#if 0
+	for (i = 0; i < cDownStream; i++) {
+		revoked = FALSE;
+		uc = 0;
+		for (TimeOut = 0; TimeOut < 5; TimeOut++) {
+			/* check bit count */
+			uc += countbit(KSVList[i * 5 + TimeOut]);
+		}
+		if (uc != 20)
+			revoked = TRUE;
+
+		if (revoked) {
+/* HDCP_DEBUG_PRINTF(("KSVFIFO[%d] = %02X %02X %02X %02X %02X is revoked\n",*/
+/*i,(int)KSVList[i*5],(int)KSVList[i*5+1],(int)KSVList[i*5+2],*/
+/*(int)KSVList[i*5+3],(int)KSVList[i*5+4])); */
+			goto hdmitx_hdcp_Repeater_Fail;
+		}
+	}
+#endif
+
+	if (hdmitx_hdcp_GetVr(Vr) == ER_FAIL)
+		goto hdmitx_hdcp_Repeater_Fail;
+
+	if (hdmitx_hdcp_GetM0(M0) == ER_FAIL)
+		goto hdmitx_hdcp_Repeater_Fail;
+
+	/* do check SHA */
+	if (hdmitx_hdcp_CheckSHA(M0, BStatus, KSVList, cDownStream, Vr) == ER_FAIL)
+		goto hdmitx_hdcp_Repeater_Fail;
+
+	if ((B_TX_INT_HPD_PLUG | B_TX_INT_RX_SENSE) & HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1)) {
+		HDCP_DEBUG_PRINTF("HPD at Final\n");
+		goto hdmitx_hdcp_Repeater_Fail;
+	}
+#endif				/* SUPPORT_SHA */
+
+	hdmitx_hdcp_ResumeRepeaterAuthenticate();
+	hdmiTxDev[0].bAuthenticated = TRUE;
+	return ER_SUCCESS;
+
+hdmitx_hdcp_Repeater_Fail:
+	hdmitx_hdcp_CancelRepeaterAuthenticate();
+	return ER_FAIL;
+}
+
+/* //////////////////////////////////////////////////////////////////// */
+/* Function: hdmitx_hdcp_ResumeAuthentication */
+/* Parameter: N/A */
+/* Return: N/A */
+/* Remark: called by interrupt handler to restart Authentication and Encryption. */
+/* Side-Effect: as Authentication and Encryption. */
+/* //////////////////////////////////////////////////////////////////// */
+
+void hdmitx_hdcp_ResumeAuthentication(void)
+{
+	setHDMITX_AVMute(TRUE);
+	if (hdmitx_hdcp_Authenticate() == ER_SUCCESS)
+		;
+
+	setHDMITX_AVMute(FALSE);
+}
+
+#endif				/* SUPPORT_HDCP */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_hdcp.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_hdcp.h
new file mode 100644
index 0000000..648e69d
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_hdcp.h
@@ -0,0 +1,111 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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.
+*/
+
+#ifndef _HDMITX_HDCP_H_
+#define _HDMITX_HDCP_H_
+
+#include "itx_typedef.h"
+#define bool unsigned char
+
+#define REG_TX_HDCP_DESIRE 0x20
+#define B_TX_ENABLE_HDPC11 (1<<1)
+#define B_TX_CPDESIRE  (1<<0)
+
+#define REG_TX_AUTHFIRE    0x21
+#define REG_TX_LISTCTRL    0x22
+#define B_TX_LISTFAIL  (1<<1)
+#define B_TX_LISTDONE  (1<<0)
+
+#define REG_TX_AKSV    0x23
+#define REG_TX_AKSV0   0x23
+#define REG_TX_AKSV1   0x24
+#define REG_TX_AKSV2   0x25
+#define REG_TX_AKSV3   0x26
+#define REG_TX_AKSV4   0x27
+
+#define REG_TX_AN  0x28
+#define REG_TX_AN_GEN  0x30
+#define REG_TX_ARI     0x38
+#define REG_TX_ARI0    0x38
+#define REG_TX_ARI1    0x39
+#define REG_TX_APJ     0x3A
+
+#define REG_TX_BKSV    0x3B
+#define REG_TX_BRI     0x40
+#define REG_TX_BRI0    0x40
+#define REG_TX_BRI1    0x41
+#define REG_TX_BPJ     0x42
+#define REG_TX_BCAP    0x43
+#define B_TX_CAP_HDMI_REPEATER (1<<6)
+#define B_TX_CAP_KSV_FIFO_RDY  (1<<5)
+#define B_TX_CAP_HDMI_FAST_MODE    (1<<4)
+#define B_CAP_HDCP_1p1  (1<<1)
+#define B_TX_CAP_FAST_REAUTH   (1<<0)
+#define REG_TX_BSTAT   0x44
+#define REG_TX_BSTAT0   0x44
+#define REG_TX_BSTAT1   0x45
+#define B_TX_CAP_HDMI_MODE (1<<12)
+#define B_TX_CAP_DVI_MODE (0<<12)
+#define B_TX_MAX_CASCADE_EXCEEDED  (1<<11)
+#define M_TX_REPEATER_DEPTH    (0x7<<8)
+#define O_TX_REPEATER_DEPTH    8
+#define B_TX_DOWNSTREAM_OVER   (1<<7)
+#define M_TX_DOWNSTREAM_COUNT  0x7F
+
+#define REG_TX_AUTH_STAT 0x46
+#define B_TX_AUTH_DONE (1<<7)
+/* ////////////////////////////////////////////////// */
+/* Function Prototype */
+/* ////////////////////////////////////////////////// */
+extern HDMITXDEV hdmiTxDev[1];
+
+
+bool getHDMITX_AuthenticationDone(void);
+void hdmitx_hdcp_ClearAuthInterrupt(void);
+void hdmitx_hdcp_ResetAuth(void);
+void hdmitx_hdcp_Auth_Fire(void);
+void hdmitx_hdcp_StartAnCipher(void);
+void hdmitx_hdcp_StopAnCipher(void);
+void hdmitx_hdcp_GenerateAn(void);
+SYS_STATUS hdmitx_hdcp_GetBCaps(unsigned char *pBCaps, unsigned short *pBStatus);
+SYS_STATUS hdmitx_hdcp_GetBKSV(unsigned char *pBKSV);
+
+void hdmitx_hdcp_Reset(void);
+SYS_STATUS hdmitx_hdcp_Authenticate(void);
+SYS_STATUS hdmitx_hdcp_VerifyIntegration(void);
+void hdmitx_hdcp_CancelRepeaterAuthenticate(void);
+void hdmitx_hdcp_ResumeRepeaterAuthenticate(void);
+SYS_STATUS hdmitx_hdcp_CheckSHA(unsigned char pM0[], unsigned short BStatus, unsigned char pKSVList[],
+				int cDownStream, unsigned char Vr[]);
+SYS_STATUS hdmitx_hdcp_GetKSVList(unsigned char *pKSVList, unsigned char cDownStream);
+SYS_STATUS hdmitx_hdcp_GetVr(unsigned char *pVr);
+SYS_STATUS hdmitx_hdcp_GetM0(unsigned char *pM0);
+SYS_STATUS hdmitx_hdcp_Authenticate_Repeater(void);
+void hdmitx_hdcp_ResumeAuthentication(void);
+#endif				/* _HDMITX_HDCP_H_ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_input.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_input.c
new file mode 100644
index 0000000..32cfc93
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_input.c
@@ -0,0 +1,202 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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 "hdmitx.h"
+#include "hdmitx_drv.h"
+
+#ifdef HDMITX_INPUT_INFO
+
+
+#define InitCEC() HDMITX_SetI2C_Byte(0x0F, 0x08, 0x00)
+#define DisableCEC() HDMITX_SetI2C_Byte(0x0F, 0x08, 0x08)
+
+LONG CalcAudFS(void)
+{
+	/* LONG RCLK ; */
+	LONG Cnt;
+	LONG FS;
+
+	/* RCLK = CalcRCLK(); */
+	Switch_HDMITX_Bank(0);
+	Cnt = (LONG) HDMITX_ReadI2C_Byte(0x60);
+	FS = hdmiTxDev[0].RCLK / 2;
+	FS /= Cnt;
+	HDMITX_DEBUG_PRINTF1(("FS = %ld RCLK = %ld, Cnt = %ld\n", FS, hdmiTxDev[0].RCLK, Cnt));
+	return FS;
+}
+
+LONG CalcPCLK(void)
+{
+	unsigned char uc, div;
+	int i;
+	long sum, count, PCLK;
+
+	Switch_HDMITX_Bank(0);
+	uc = HDMITX_ReadI2C_Byte(0x5F) & 0x80;
+
+	if (!uc)
+		return 0;
+
+	/* InitCEC(); */
+	/* // uc = CEC_ReadI2C_Byte(0x09) & 0xFE ; */
+	/* CEC_WriteI2C_Byte(0x09, 1); */
+	/* delay1ms(100); */
+	/* CEC_WriteI2C_Byte(0x09, 0); */
+	/* RCLK = CEC_ReadI2C_Byte(0x47); */
+	/* RCLK <<= 8 ; */
+	/* RCLK |= CEC_ReadI2C_Byte(0x46); */
+	/* RCLK <<= 8 ; */
+	/* RCLK |= CEC_ReadI2C_Byte(0x45); */
+	/* DisableCEC(); */
+	/* // RCLK *= 160 ; // RCLK /= 100 ; */
+	/* // RCLK in KHz. */
+
+	HDMITX_SetI2C_Byte(0xD7, 0xF0, 0x80);
+	delay1ms(1);
+	HDMITX_SetI2C_Byte(0xD7, 0x80, 0x00);
+
+	count = HDMITX_ReadI2C_Byte(0xD7) & 0xF;
+	count <<= 8;
+	count |= HDMITX_ReadI2C_Byte(0xD8);
+
+	for (div = 7; div > 0; div--) {
+		/* IT66121_LOG("div = %d\n",(int)div) ; */
+		if (count < (1 << (11 - div)))
+			break;
+
+	}
+	HDMITX_SetI2C_Byte(0xD7, 0x70, div << 4);
+
+	uc = HDMITX_ReadI2C_Byte(0xD7) & 0x7F;
+	for (i = 0, sum = 0; i < 100; i++) {
+		HDMITX_WriteI2C_Byte(0xD7, uc | 0x80);
+		delay1ms(1);
+		HDMITX_WriteI2C_Byte(0xD7, uc);
+
+		count = HDMITX_ReadI2C_Byte(0xD7) & 0xF;
+		count <<= 8;
+		count |= HDMITX_ReadI2C_Byte(0xD8);
+		sum += count;
+	}
+	sum /= 100;
+	count = sum;
+
+	HDMITX_DEBUG_PRINTF1(("RCLK(in GetPCLK) = %ld\n", hdmiTxDev[0].RCLK));
+	HDMITX_DEBUG_PRINTF1(("div = %d, count = %d\n", (int)div, (int)count));
+	HDMITX_DEBUG_PRINTF1(("count = %ld\n", count));
+
+	PCLK = hdmiTxDev[0].RCLK * 128 / count * 16;
+	PCLK *= (1 << div);
+
+	if (HDMITX_ReadI2C_Byte(0x70) & 0x10)
+		PCLK /= 2;
+
+	HDMITX_DEBUG_PRINTF1(("PCLK = %ld\n", PCLK));
+	return PCLK;
+}
+
+LONG CalcRCLK(void)
+{
+	/* unsigned char uc ; */
+	int i;
+	long sum, RCLKCNT;
+
+	InitCEC();
+	sum = 0;
+	for (i = 0; i < 5; i++) {
+		/* uc = CEC_ReadI2C_Byte(0x09) & 0xFE ; */
+		CEC_WriteI2C_Byte(0x09, 1);
+		delay1ms(100);
+		CEC_WriteI2C_Byte(0x09, 0);
+		RCLKCNT = CEC_ReadI2C_Byte(0x47);
+		RCLKCNT <<= 8;
+		RCLKCNT |= CEC_ReadI2C_Byte(0x46);
+		RCLKCNT <<= 8;
+		RCLKCNT |= CEC_ReadI2C_Byte(0x45);
+		/* HDMITX_DEBUG_PRINTF1(("RCLK = %ld\n",RCLKCNT) ); */
+		sum += RCLKCNT;
+	}
+	DisableCEC();
+	RCLKCNT = sum * 32;
+	HDMITX_DEBUG_PRINTF("RCLK = %ld,%03ld,%03ld\n", RCLKCNT / 1000000,
+			    (RCLKCNT % 1000000) / 1000, RCLKCNT % 1000);
+	return RCLKCNT;
+}
+
+unsigned short hdmitx_getInputHTotal(void)
+{
+	unsigned char uc;
+	unsigned short hTotal;
+
+	HDMITX_SetI2C_Byte(0x0F, 1, 0);
+	HDMITX_SetI2C_Byte(0xA8, 8, 8);
+
+	uc = HDMITX_ReadI2C_Byte(0xB2);
+	hTotal = (uc & 1) ? (1 << 12) : 0;
+	uc = HDMITX_ReadI2C_Byte(0x91);
+	hTotal |= ((unsigned short)uc) << 4;
+	uc = HDMITX_ReadI2C_Byte(0x90);
+	hTotal |= (uc & 0xF0) >> 4;
+	HDMITX_SetI2C_Byte(0xA8, 8, 0);
+	return hTotal;
+}
+
+unsigned short hdmitx_getInputVTotal(void)
+{
+	unsigned char uc;
+	unsigned short vTotal;
+
+	HDMITX_SetI2C_Byte(0x0F, 1, 0);
+	HDMITX_SetI2C_Byte(0xA8, 8, 8);
+
+	uc = HDMITX_ReadI2C_Byte(0x99);
+	vTotal = ((unsigned short)uc & 0xF) << 8;
+	uc = HDMITX_ReadI2C_Byte(0x98);
+	vTotal |= uc;
+	HDMITX_SetI2C_Byte(0xA8, 8, 0);
+	return vTotal;
+}
+
+bool hdmitx_isInputInterlace(void)
+{
+	unsigned char uc;
+
+	HDMITX_SetI2C_Byte(0x0F, 1, 0);
+	HDMITX_SetI2C_Byte(0xA8, 8, 8);
+
+	uc = HDMITX_ReadI2C_Byte(0xA5);
+	HDMITX_SetI2C_Byte(0xA8, 8, 0);
+	return uc & (1 << 4) ? TRUE : FALSE;
+}
+
+unsigned char hdmitx_getAudioCount(void)
+{
+	return HDMITX_ReadI2C_Byte(REG_TX_AUD_COUNT);
+}
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_input.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_input.h
new file mode 100644
index 0000000..ba60a17
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_input.h
@@ -0,0 +1,48 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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.
+*/
+
+#ifndef _HDMITX_DEBUG_H_
+#define _HDMITX_DEBUG_H_
+
+
+#ifdef HDMITX_INPUT_INFO
+extern HDMITXDEV hdmiTxDev[HDMITX_MAX_DEV_COUNT];
+
+LONG CalcRCLK(void);
+LONG CalcPCLK(void);
+LONG CalcAudFS(void);
+LONG CalcRCLK(void);
+unsigned char hdmitx_getAudioCount(void);
+
+unsigned short hdmitx_getInputHTotal(void);
+unsigned short hdmitx_getInputVTotal(void);
+bool hdmitx_isInputInterlace(void);
+#endif
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_sys.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_sys.c
new file mode 100644
index 0000000..bc2f077
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_sys.c
@@ -0,0 +1,1489 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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 "hdmitx.h"
+#include "hdmitx_sys.h"
+//#include <linux/switch.h>
+
+extern unsigned char real_edid[256];
+
+_CODE HDMITXDEV InstanceData = {
+
+	0,			/* unsigned char I2C_DEV ; */
+	HDMI_TX_I2C_SLAVE_ADDR,	/* unsigned char I2C_ADDR ; */
+
+	/* /////////////////////////////////////////////// */
+	/* Interrupt Type */
+	/* /////////////////////////////////////////////// */
+	0x40,			/* unsigned char bIntType ; // = 0 ; */
+	/* /////////////////////////////////////////////// */
+	/* Video Property */
+	/* /////////////////////////////////////////////// */
+	INPUT_SIGNAL_TYPE,	/* unsigned char bInputVideoSignalType ; // for Sync Embedded,CCIR656,InputDDR */
+
+	/* /////////////////////////////////////////////// */
+	/* Audio Property */
+	/* /////////////////////////////////////////////// */
+	I2S_FORMAT,		/* unsigned char bOutputAudioMode ; // = 0 ; */
+	FALSE,			/* unsigned char bAudioChannelSwap ; // = 0 ; */
+	0x01,			/* unsigned char bAudioChannelEnable ; */
+	INPUT_SAMPLE_FREQ,	/* unsigned char bAudFs ; */
+	0,			/* unsigned long TMDSClock ; */
+	FALSE,			/* unsigned char bAuthenticated:1 ; */
+	FALSE,			/* unsigned char bHDMIMode: 1; */
+	FALSE,			/* unsigned char bIntPOL:1 ; // 0 = Low Active */
+	FALSE,			/* unsigned char bHPD:1 ; */
+};
+
+#ifdef HDMITX_INPUT_INFO
+/* HDMI_VTiming currVTiming ; */
+/* ////////////////////////////////////////////////////////////////////////////// */
+/* HDMI VTable */
+/* ////////////////////////////////////////////////////////////////////////////// */
+static HDMI_VTiming _CODE s_VMTable[] = {
+
+	{1, 0, 640, 480, 800, 525, 25175000L, 0x89, 16, 96, 48, 10, 2, 33, PROG, Vneg, Hneg},
+		/* 640x480@60Hz */
+	{2, 0, 720, 480, 858, 525, 27000000L, 0x80, 16, 62, 60, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 720x480@60Hz */
+	{3, 0, 720, 480, 858, 525, 27000000L, 0x80, 16, 62, 60, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 720x480@60Hz */
+	{4, 0, 1280, 720, 1650, 750, 74250000L, 0x2E, 110, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@60Hz */
+	{5, 0, 1920, 540, 2200, 562, 74250000L, 0x2E, 88, 44, 148, 2, 5, 15, INTERLACE, Vpos, Hpos},
+	/* 1920x1080(I)@60Hz */
+	{6, 1, 720, 240, 858, 262, 13500000L, 0x100, 19, 62, 57, 4, 3, 15, INTERLACE, Vneg, Hneg},
+	/* 720x480(I)@60Hz */
+	{7, 1, 720, 240, 858, 262, 13500000L, 0x100, 19, 62, 57, 4, 3, 15, INTERLACE, Vneg, Hneg},
+	/* 720x480(I)@60Hz */
+	{8, 1, 720, 240, 858, 262, 13500000L, 0x100, 19, 62, 57, 4, 3, 15, PROG, Vneg, Hneg},
+	/* 720x480(I)@60Hz */
+	{9, 1, 720, 240, 858, 262, 13500000L, 0x100, 19, 62, 57, 4, 3, 15, PROG, Vneg, Hneg},
+	/* 720x480(I)@60Hz */
+	{10, 2, 720, 240, 858, 262, 54000000L, 0x40, 19, 62, 57, 4, 3, 15, INTERLACE, Vneg, Hneg},
+	/* 720x480(I)@60Hz */
+	{11, 2, 720, 240, 858, 262, 54000000L, 0x40, 19, 62, 57, 4, 3, 15, INTERLACE, Vneg, Hneg},
+	/* 720x480(I)@60Hz */
+	{12, 2, 720, 240, 858, 262, 54000000L, 0x40, 19, 62, 57, 4, 3, 15, PROG, Vneg, Hneg},
+	/* 720x480(I)@60Hz */
+	{13, 2, 720, 240, 858, 262, 54000000L, 0x40, 19, 62, 57, 4, 3, 15, PROG, Vneg, Hneg},
+	/* 720x480(I)@60Hz */
+	{14, 1, 1440, 480, 1716, 525, 54000000L, 0x40, 32, 124, 120, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 1440x480@60Hz */
+	{15, 1, 1440, 480, 1716, 525, 54000000L, 0x40, 32, 124, 120, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 1440x480@60Hz */
+	{16, 0, 1920, 1080, 2200, 1125, 148500000L, 0x17, 88, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@60Hz */
+	{17, 0, 720, 576, 864, 625, 27000000L, 0x80, 12, 64, 68, 5, 5, 39, PROG, Vneg, Hneg},
+	/* 720x576@50Hz */
+	{18, 0, 720, 576, 864, 625, 27000000L, 0x80, 12, 64, 68, 5, 5, 39, PROG, Vneg, Hneg},
+	/* 720x576@50Hz */
+	{19, 0, 1280, 720, 1980, 750, 74250000L, 0x2E, 440, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@50Hz */
+	{20, 0, 1920, 540, 2640, 562, 74250000L, 0x2E, 528, 44, 148, 2, 5, 15, INTERLACE, Vpos, Hpos},
+	/* 1920x1080(I)@50Hz */
+	{21, 1, 720, 288, 864, 312, 13500000L, 0x100, 12, 63, 69, 2, 3, 19, INTERLACE, Vneg, Hneg},
+	/* 1440x576(I)@50Hz */
+	{22, 1, 720, 288, 864, 312, 13500000L, 0x100, 12, 63, 69, 2, 3, 19, INTERLACE, Vneg, Hneg},
+	/* 1440x576(I)@50Hz */
+	{23, 1, 720, 288, 864, 312, 13500000L, 0x100, 12, 63, 69, 2, 3, 19, PROG, Vneg, Hneg},
+	/* 1440x288@50Hz */
+	{24, 1, 720, 288, 864, 312, 13500000L, 0x100, 12, 63, 69, 2, 3, 19, PROG, Vneg, Hneg},
+	/* 1440x288@50Hz */
+	{25, 2, 720, 288, 864, 312, 13500000L, 0x100, 12, 63, 69, 2, 3, 19, INTERLACE, Vneg, Hneg},
+	/* 1440x576(I)@50Hz */
+	{26, 2, 720, 288, 864, 312, 13500000L, 0x100, 12, 63, 69, 2, 3, 19, INTERLACE, Vneg, Hneg},
+	/* 1440x576(I)@50Hz */
+	{27, 2, 720, 288, 864, 312, 13500000L, 0x100, 12, 63, 69, 2, 3, 19, PROG, Vneg, Hneg},
+	/* 1440x288@50Hz */
+	{28, 2, 720, 288, 864, 312, 13500000L, 0x100, 12, 63, 69, 2, 3, 19, PROG, Vneg, Hneg},
+	/* 1440x288@50Hz */
+	{29, 1, 1440, 576, 1728, 625, 54000000L, 0x40, 24, 128, 136, 5, 5, 39, PROG, Vpos, Hneg},
+	/* 1440x576@50Hz */
+	{30, 1, 1440, 576, 1728, 625, 54000000L, 0x40, 24, 128, 136, 5, 5, 39, PROG, Vpos, Hneg},
+	/* 1440x576@50Hz */
+	{31, 0, 1920, 1080, 2640, 1125, 148500000L, 0x17, 528, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@50Hz */
+	{32, 0, 1920, 1080, 2750, 1125, 74250000L, 0x2E, 638, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@24Hz */
+	{33, 0, 1920, 1080, 2640, 1125, 74250000L, 0x2E, 528, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@25Hz */
+	{34, 0, 1920, 1080, 2200, 1125, 74250000L, 0x2E, 88, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@30Hz */
+
+	{35, 2, 2880, 480, 1716 * 2, 525, 108000000L, 0x20, 32 * 2, 124 * 2, 120 * 2, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 2880x480@60Hz */
+	{36, 2, 2880, 480, 1716 * 2, 525, 108000000L, 0x20, 32 * 2, 124 * 2, 120 * 2, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 2880x480@60Hz */
+	{37, 1, 2880, 576, 3456, 625, 108000000L, 0x20, 24 * 2, 128 * 2, 136 * 2, 5, 5, 39, PROG, Vneg, Hneg},
+	/* 2880x576@50Hz */
+	{38, 2, 2880, 576, 3456, 625, 108000000L, 0x20, 24 * 2, 128 * 2, 136 * 2, 5, 5, 39, PROG, Vneg, Hneg},
+	/* 2880x576@50Hz */
+
+	{39, 0, 1920, 540, 2304, 625, 72000000L, 0x17, 32, 168, 184, 23, 5, 57, INTERLACE, Vneg, Hpos},
+	/* 1920x1080@50Hz */
+	/* 100Hz */
+	{40, 0, 1920, 540, 2640, 562, 148500000L, 0x17, 528, 44, 148, 2, 5, 15, INTERLACE, Vpos, Hpos},
+	/* 1920x1080(I)@100Hz */
+	{41, 0, 1280, 720, 1980, 750, 148500000L, 0x17, 440, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@100Hz */
+	{42, 0, 720, 576, 864, 625, 54000000L, 0x40, 12, 64, 68, 5, 5, 39, PROG, Vneg, Hneg},
+	/* 720x576@100Hz */
+	{43, 0, 720, 576, 864, 625, 54000000L, 0x40, 12, 64, 68, 5, 5, 39, PROG, Vneg, Hneg},
+	/* 720x576@100Hz */
+	{44, 1, 720, 288, 864, 312, 27000000L, 0x80, 12, 63, 69, 2, 3, 19, INTERLACE, Vneg, Hneg},
+	/* 1440x576(I)@100Hz */
+	{45, 1, 720, 288, 864, 312, 27000000L, 0x80, 12, 63, 69, 2, 3, 19, INTERLACE, Vneg, Hneg},
+	/* 1440x576(I)@100Hz */
+	/* 120Hz */
+	{46, 0, 1920, 540, 2200, 562, 148500000L, 0x17, 88, 44, 148, 2, 5, 15, INTERLACE, Vpos, Hpos},
+	/* 1920x1080(I)@120Hz */
+	{47, 0, 1280, 720, 1650, 750, 148500000L, 0x17, 110, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@120Hz */
+	{48, 0, 720, 480, 858, 525, 54000000L, 0x40, 16, 62, 60, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 720x480@120Hz */
+	{49, 0, 720, 480, 858, 525, 54000000L, 0x40, 16, 62, 60, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 720x480@120Hz */
+	{50, 1, 720, 240, 858, 262, 27000000L, 0x80, 19, 62, 57, 4, 3, 15, INTERLACE, Vneg, Hneg},
+	/* 720x480(I)@120Hz */
+	{51, 1, 720, 240, 858, 262, 27000000L, 0x80, 19, 62, 57, 4, 3, 15, INTERLACE, Vneg, Hneg},
+	/* 720x480(I)@120Hz */
+
+	/* 200Hz */
+	{52, 0, 720, 576, 864, 625, 108000000L, 0x20, 12, 64, 68, 5, 5, 39, PROG, Vneg, Hneg},
+	/* 720x576@200Hz */
+	{53, 0, 720, 576, 864, 625, 108000000L, 0x20, 12, 64, 68, 5, 5, 39, PROG, Vneg, Hneg},
+	/* 720x576@200Hz */
+	{54, 1, 720, 288, 864, 312, 54000000L, 0x40, 12, 63, 69, 2, 3, 19, INTERLACE, Vneg, Hneg},
+	/* 1440x576(I)@200Hz */
+	{55, 1, 720, 288, 864, 312, 54000000L, 0x40, 12, 63, 69, 2, 3, 19, INTERLACE, Vneg, Hneg},
+	/* 1440x576(I)@200Hz */
+	/* 240Hz */
+	{56, 0, 720, 480, 858, 525, 108000000L, 0x20, 16, 62, 60, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 720x480@120Hz */
+	{57, 0, 720, 480, 858, 525, 108000000L, 0x20, 16, 62, 60, 9, 6, 30, PROG, Vneg, Hneg},
+	/* 720x480@120Hz */
+	{58, 1, 720, 240, 858, 262, 54000000L, 0x40, 19, 62, 57, 4, 3, 15, INTERLACE, Vneg, Hneg},
+	/* 720x480(I)@120Hz */
+	{59, 1, 720, 240, 858, 262, 54000000L, 0x40, 19, 62, 57, 4, 3, 15, INTERLACE, Vneg, Hneg},
+	/* 720x480(I)@120Hz */
+	/* 720p low resolution */
+	{60, 0, 1280, 720, 3300, 750, 59400000L, 0x3A, 1760, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@24Hz */
+	{61, 0, 1280, 720, 3960, 750, 74250000L, 0x2E, 2420, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@25Hz */
+	{62, 0, 1280, 720, 3300, 750, 74250000L, 0x2E, 1760, 40, 220, 5, 5, 20, PROG, Vpos, Hpos},
+	/* 1280x720@30Hz */
+	/* 1080p high refresh rate */
+	{63, 0, 1920, 1080, 2200, 1125, 297000000L, 0x0B, 88, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@120Hz */
+	{64, 0, 1920, 1080, 2640, 1125, 297000000L, 0x0B, 528, 44, 148, 4, 5, 36, PROG, Vpos, Hpos},
+	/* 1920x1080@100Hz */
+	/* VESA mode */
+	{0, 0, 640, 350, 832, 445, 31500000L, 0x6D, 32, 64, 96, 32, 3, 60, PROG, Vneg, Hpos},
+	/* 640x350@85 */
+	{0, 0, 640, 400, 832, 445, 31500000L, 0x6D, 32, 64, 96, 1, 3, 41, PROG, Vneg, Hneg},
+	/* 640x400@85 */
+	{0, 0, 832, 624, 1152, 667, 57283000L, 0x3C, 32, 64, 224, 1, 3, 39, PROG, Vneg, Hneg},
+	/* 832x624@75Hz */
+	{0, 0, 720, 350, 900, 449, 28322000L, 0x7A, 18, 108, 54, 59, 2, 38, PROG, Vneg, Hneg},
+	/* 720x350@70Hz */
+	{0, 0, 720, 400, 900, 449, 28322000L, 0x7A, 18, 108, 54, 13, 2, 34, PROG, Vpos, Hneg},
+	/* 720x400@70Hz */
+	{0, 0, 720, 400, 936, 446, 35500000L, 0x61, 36, 72, 108, 1, 3, 42, PROG, Vpos, Hneg},
+	/* 720x400@85 */
+	{0, 0, 640, 480, 800, 525, 25175000L, 0x89, 16, 96, 48, 10, 2, 33, PROG, Vneg, Hneg},
+	/* 640x480@60 */
+	{0, 0, 640, 480, 832, 520, 31500000L, 0x6D, 24, 40, 128, 9, 3, 28, PROG, Vneg, Hneg},
+	/* 640x480@72 */
+	{0, 0, 640, 480, 840, 500, 31500000L, 0x6D, 16, 64, 120, 1, 3, 16, PROG, Vneg, Hneg},
+	/* 640x480@75 */
+	{0, 0, 640, 480, 832, 509, 36000000L, 0x60, 56, 56, 80, 1, 3, 25, PROG, Vneg, Hneg},
+	/* 640x480@85 */
+	{0, 0, 800, 600, 1024, 625, 36000000L, 0x60, 24, 72, 128, 1, 2, 22, PROG, Vpos, Hpos},
+	/* 800x600@56 */
+	{0, 0, 800, 600, 1056, 628, 40000000L, 0x56, 40, 128, 88, 1, 4, 23, PROG, Vpos, Hpos},
+	/* 800x600@60 */
+	{0, 0, 800, 600, 1040, 666, 50000000L, 0x45, 56, 120, 64, 37, 6, 23, PROG, Vpos, Hpos},
+	/* 800x600@72 */
+	{0, 0, 800, 600, 1056, 625, 49500000L, 0x45, 16, 80, 160, 1, 3, 21, PROG, Vpos, Hpos},
+	/* 800x600@75 */
+	{0, 0, 800, 600, 1048, 631, 56250000L, 0x3D, 32, 64, 152, 1, 3, 27, PROG, Vpos, Hpos},
+	/* 800X600@85 */
+	{0, 0, 848, 480, 1088, 517, 33750000L, 0x66, 16, 112, 112, 6, 8, 23, PROG, Vpos, Hpos},
+	/* 840X480@60 */
+	{0, 0, 1024, 384, 1264, 408, 44900000L, 0x4C, 8, 176, 56, 0, 4, 20, INTERLACE, Vpos, Hpos},
+	/* 1024x768(I)@87Hz */
+	{0, 0, 1024, 768, 1344, 806, 65000000L, 0x35, 24, 136, 160, 3, 6, 29, PROG, Vneg, Hneg},
+	/* 1024x768@60 */
+	{0, 0, 1024, 768, 1328, 806, 75000000L, 0x2E, 24, 136, 144, 3, 6, 29, PROG, Vneg, Hneg},
+	/* 1024x768@70 */
+	{0, 0, 1024, 768, 1312, 800, 78750000L, 0x2B, 16, 96, 176, 1, 3, 28, PROG, Vpos, Hpos},
+	/* 1024x768@75 */
+	{0, 0, 1024, 768, 1376, 808, 94500000L, 0x24, 48, 96, 208, 1, 3, 36, PROG, Vpos, Hpos},
+	/* 1024x768@85 */
+	{0, 0, 1152, 864, 1600, 900, 108000000L, 0x20, 64, 128, 256, 1, 3, 32, PROG, Vpos, Hpos},
+	/* 1152x864@75 */
+	{0, 0, 1280, 768, 1440, 790, 68250000L, 0x32, 48, 32, 80, 3, 7, 12, PROG, Vneg, Hpos},
+	/* 1280x768@60-R */
+	{0, 0, 1280, 768, 1664, 798, 79500000L, 0x2B, 64, 128, 192, 3, 7, 20, PROG, Vpos, Hneg},
+	/* 1280x768@60 */
+	{0, 0, 1280, 768, 1696, 805, 102250000L, 0x21, 80, 128, 208, 3, 7, 27, PROG, Vpos, Hneg},
+	/* 1280x768@75 */
+	{0, 0, 1280, 768, 1712, 809, 117500000L, 0x1D, 80, 136, 216, 3, 7, 31, PROG, Vpos, Hneg},
+	/* 1280x768@85 */
+
+	{0, 0, 1280, 800, 1440, 823, 71000000L, 0x31, 48, 32, 80, 3, 6, 14, PROG, Vpos, Hneg},
+	/* 1280x800@60Hz */
+	{0, 0, 1280, 800, 1680, 831, 83500000L, 0x29, 72, 128, 200, 3, 6, 22, PROG, Vpos, Hneg},
+	/* 1280x800@60Hz */
+	{0, 0, 1280, 800, 1696, 838, 106500000L, 0x20, 80, 128, 208, 3, 6, 29, PROG, Vpos, Hneg},
+	/* 1280x800@75Hz */
+	{0, 0, 1280, 800, 1712, 843, 122500000L, 0x1C, 80, 136, 216, 3, 6, 34, PROG, Vpos, Hneg},
+	/* 1280x800@85Hz */
+
+
+	{0, 0, 1280, 960, 1800, 1000, 108000000L, 0x20, 96, 112, 312, 1, 3, 36, PROG, Vpos, Hpos},
+	/* 1280x960@60 */
+	{0, 0, 1280, 960, 1728, 1011, 148500000L, 0x17, 64, 160, 224, 1, 3, 47, PROG, Vpos, Hpos},
+	/* 1280x960@85 */
+	{0, 0, 1280, 1024, 1688, 1066, 108000000L, 0x20, 48, 112, 248, 1, 3, 38, PROG, Vpos, Hpos},
+	/* 1280x1024@60 */
+	{0, 0, 1280, 1024, 1688, 1066, 135000000L, 0x19, 16, 144, 248, 1, 3, 38, PROG, Vpos, Hpos},
+	/* 1280x1024@75 */
+	{0, 0, 1280, 1024, 1728, 1072, 157500000L, 0x15, 64, 160, 224, 1, 3, 44, PROG, Vpos, Hpos},
+	/* 1280X1024@85 */
+	{0, 0, 1360, 768, 1792, 795, 85500000L, 0x28, 64, 112, 256, 3, 6, 18, PROG, Vpos, Hpos},
+	/* 1360X768@60 */
+
+	{0, 0, 1366, 768, 1792, 798, 85500000L, 0x28, 70, 143, 213, 3, 3, 24, PROG, Vpos, Hpos},
+	/* 1366X768@60 */
+	{0, 0, 1366, 768, 1500, 800, 72000000L, 0x30, 14, 56, 64, 1, 3, 28, PROG, Vpos, Hpos},
+	/* 1360X768@60 */
+	{0, 0, 1400, 1050, 1560, 1080, 101000000L, 0x22, 48, 32, 80, 3, 4, 23, PROG, Vneg, Hpos},
+	/* 1400x768@60-R */
+	{0, 0, 1400, 1050, 1864, 1089, 121750000L, 0x1C, 88, 144, 232, 3, 4, 32, PROG, Vpos, Hneg},
+	/* 1400x768@60 */
+	{0, 0, 1400, 1050, 1896, 1099, 156000000L, 0x16, 104, 144, 248, 3, 4, 42, PROG, Vpos, Hneg},
+	/* 1400x1050@75 */
+	{0, 0, 1400, 1050, 1912, 1105, 179500000L, 0x13, 104, 152, 256, 3, 4, 48, PROG, Vpos, Hneg},
+	/* 1400x1050@85 */
+	{0, 0, 1440, 900, 1600, 926, 88750000L, 0x26, 48, 32, 80, 3, 6, 17, PROG, Vneg, Hpos},
+	/* 1440x900@60-R */
+	{0, 0, 1440, 900, 1904, 934, 106500000L, 0x20, 80, 152, 232, 3, 6, 25, PROG, Vpos, Hneg},
+	/* 1440x900@60 */
+	{0, 0, 1440, 900, 1936, 942, 136750000L, 0x19, 96, 152, 248, 3, 6, 33, PROG, Vpos, Hneg},
+	/* 1440x900@75 */
+	{0, 0, 1440, 900, 1952, 948, 157000000L, 0x16, 104, 152, 256, 3, 6, 39, PROG, Vpos, Hneg},
+	/* 1440x900@85 */
+	{0, 0, 1600, 1200, 2160, 1250, 162000000L, 0x15, 64, 192, 304, 1, 3, 46, PROG, Vpos, Hpos},
+	/* 1600x1200@60 */
+	{0, 0, 1600, 1200, 2160, 1250, 175500000L, 0x13, 64, 192, 304, 1, 3, 46, PROG, Vpos, Hpos},
+	/* 1600x1200@65 */
+	{0, 0, 1600, 1200, 2160, 1250, 189000000L, 0x12, 64, 192, 304, 1, 3, 46, PROG, Vpos, Hpos},
+	/* 1600x1200@70 */
+	{0, 0, 1600, 1200, 2160, 1250, 202500000L, 0x11, 64, 192, 304, 1, 3, 46, PROG, Vpos, Hpos},
+	/* 1600x1200@75 */
+	{0, 0, 1600, 1200, 2160, 1250, 229500000L, 0x0F, 64, 192, 304, 1, 3, 46, PROG, Vpos, Hpos},
+	/* 1600x1200@85 */
+	{0, 0, 1680, 1050, 1840, 1080, 119000000L, 0x1D, 48, 32, 80, 3, 6, 21, PROG, Vneg, Hpos},
+	/* 1680x1050@60-R */
+	{0, 0, 1680, 1050, 2240, 1089, 146250000L, 0x17, 104, 176, 280, 3, 6, 30, PROG, Vpos, Hneg},
+	/* 1680x1050@60 */
+	{0, 0, 1680, 1050, 2272, 1099, 187000000L, 0x12, 120, 176, 296, 3, 6, 40, PROG, Vpos, Hneg},
+	/* 1680x1050@75 */
+	{0, 0, 1680, 1050, 2288, 1105, 214750000L, 0x10, 128, 176, 304, 3, 6, 46, PROG, Vpos, Hneg},
+	/* 1680x1050@85 */
+	{0, 0, 1792, 1344, 2448, 1394, 204750000L, 0x10, 128, 200, 328, 1, 3, 46, PROG, Vpos, Hneg},
+	/* 1792x1344@60 */
+	{0, 0, 1792, 1344, 2456, 1417, 261000000L, 0x0D, 96, 216, 352, 1, 3, 69, PROG, Vpos, Hneg},
+	/* 1792x1344@75 */
+	{0, 0, 1856, 1392, 2528, 1439, 218250000L, 0x0F, 96, 224, 352, 1, 3, 43, PROG, Vpos, Hneg},
+	/* 1856x1392@60 */
+	{0, 0, 1856, 1392, 2560, 1500, 288000000L, 0x0C, 128, 224, 352, 1, 3, 104, PROG, Vpos, Hneg},
+
+	/* 1856x1392@75 */
+	{0, 0, 1920, 1200, 2080, 1235, 154000000L, 0x16, 48, 32, 80, 3, 6, 26, PROG, Vneg, Hpos},
+	/* 1920x1200@60-R */
+	{0, 0, 1920, 1200, 2592, 1245, 193250000L, 0x11, 136, 200, 336, 3, 6, 36, PROG, Vpos, Hneg},
+	/* 1920x1200@60 */
+	{0, 0, 1920, 1200, 2608, 1255, 245250000L, 0x0E, 136, 208, 344, 3, 6, 46, PROG, Vpos, Hneg},
+	/* 1920x1200@75 */
+	{0, 0, 1920, 1200, 2624, 1262, 281250000L, 0x0C, 144, 208, 352, 3, 6, 53, PROG, Vpos, Hneg},
+	/* 1920x1200@85 */
+	{0, 0, 1920, 1440, 2600, 1500, 234000000L, 0x0E, 128, 208, 344, 1, 3, 56, PROG, Vpos, Hneg},
+	/* 1920x1440@60 */
+	{0, 0, 1920, 1440, 2640, 1500, 297000000L, 0x0B, 144, 224, 352, 1, 3, 56, PROG, Vpos, Hneg},
+	/* 1920x1440@75 */
+};
+
+#define     SizeofVMTable   (sizeof(s_VMTable)/sizeof(HDMI_VTiming))
+
+
+#else
+#define     SizeofVMTable    0
+#endif
+
+#define DIFF(a, b) (((a) > (b))?((a)-(b)):((b)-(a)))
+
+/* ////////////////////////////////////////////////////////////////////////////// */
+/* EDID */
+/* ////////////////////////////////////////////////////////////////////////////// */
+static RX_CAP RxCapability;
+bool it66121_bChangeMode = FALSE;
+bool it66121_bChangeAudio = FALSE;
+
+unsigned char CommunBuff[128];
+/* _XDATA AVI_InfoFrame AviInfo; */
+/* _XDATA Audio_InfoFrame AudioInfo ; */
+/* _XDATA VendorSpecific_InfoFrame VS_Info; */
+_CODE unsigned char CA[] = { 0, 0, 0, 02, 0x3, 0x7, 0xB, 0xF, 0x1F };
+
+/* ////////////////////////////////////////////////////////////////////////////// */
+/* Program utility. */
+/* ////////////////////////////////////////////////////////////////////////////// */
+
+
+unsigned char bInputColorMode = INPUT_COLOR_MODE;
+unsigned char OutputColorDepth = INPUT_COLOR_DEPTH;
+unsigned char bOutputColorMode = OUTPUT_COLOR_MODE;
+
+unsigned char iVideoModeSelect;
+
+unsigned int sink_support_resolution;
+
+ULONG VideoPixelClock;
+unsigned char VIC;			/* 480p60 */
+unsigned char pixelrep;			/* no pixelrepeating */
+HDMI_Aspec aspec;
+HDMI_Colorimetry Colorimetry;
+
+ULONG ulAudioSampleFS = INPUT_SAMPLE_FREQ_HZ;
+/* unsigned char bAudioSampleFreq = INPUT_SAMPLE_FREQ ; */
+unsigned char bOutputAudioChannel = OUTPUT_CHANNEL;
+
+bool bHDMIMode;
+unsigned char bAudioEnable;
+unsigned char HPDStatus = FALSE;
+unsigned char HPDChangeStatus = FALSE;
+unsigned char bOutputAudioType = CNOFIG_INPUT_AUDIO_TYPE;
+
+void InitHDMITX_Variable(void)
+{
+	IT66121_LOG("hdmi_ite66121 %s\n", __func__);
+
+	HDMITX_InitTxDev(&InstanceData);
+	HPDStatus = FALSE;
+	HPDChangeStatus = FALSE;
+}
+
+bool AudioModeDetect(void)
+{
+	setHDMITX_AudioChannelEnable(bAudioEnable);
+	return TRUE;
+}
+
+void HDMITX_ChangeColorDepth(unsigned char colorDepth)
+{
+#ifdef IT6615
+	HDMITX_DEBUG_PRINTF("OHDMITX_ChangeColorDepth(%02X)\n", (int)colorDepth);
+	OutputColorDepth = colorDepth;
+#else
+	OutputColorDepth = 0;
+#endif
+}
+
+void HDMITX_SetOutput(void)
+{
+
+	VIDEOPCLKLEVEL level;
+	unsigned long TMDSClock = VideoPixelClock * (pixelrep + 1);
+
+	IT66121_LOG("hdmi_ite66121 %s\n", __func__);
+
+	HDMITX_DisableAudioOutput();
+	/* HDMITX_EnableHDCP(FALSE); */
+
+	if (TMDSClock > 80000000L)
+		level = PCLK_HIGH;
+	else if (TMDSClock > 20000000L)
+		level = PCLK_MEDIUM;
+	else
+		level = PCLK_LOW;
+
+#ifdef IT6615
+	HDMITX_DEBUG_PRINTF("OutputColorDepth = %02X\n", (int)OutputColorDepth);
+	setHDMITX_ColorDepthPhase(OutputColorDepth, 0);
+#endif
+
+	setHDMITX_VideoSignalType(InstanceData.bInputVideoSignalType);
+#ifdef SUPPORT_SYNCEMBEDDED
+	if (InstanceData.bInputVideoSignalType & T_MODE_SYNCEMB)
+		setHDMITX_SyncEmbeddedByVIC(VIC, InstanceData.bInputVideoSignalType);
+
+#endif
+
+	HDMITX_DEBUG_PRINTF("level = %d, ,bInputColorMode=%x,bOutputColorMode=%x,bHDMIMode=%x\n",
+			    (int)level, (int)bInputColorMode, (int)bOutputColorMode,
+			    (int)bHDMIMode);
+	HDMITX_EnableVideoOutput(level, bInputColorMode, bOutputColorMode, bHDMIMode);
+
+	if (bHDMIMode) {
+#ifdef OUTPUT_3D_MODE
+		ConfigfHdmiVendorSpecificInfoFrame(OUTPUT_3D_MODE);
+#endif
+		/* HDMITX_EnableHDCP(TRUE); */
+		ConfigAVIInfoFrame(VIC, pixelrep);
+
+		HDMITX_SetAudioOutput();
+
+		/* if( bAudioEnable ) */
+		/* { */
+		/* ConfigAudioInfoFrm(); */
+		/* #ifdef SUPPORT_HBR_AUDIO */
+		/* HDMITX_EnableAudioOutput(T_AUDIO_HBR,*/
+		/* CONFIG_INPUT_AUDIO_SPDIF, 768000L,8,NULL,TMDSClock); */
+		/* #else */
+		/*  HDMITX_EnableAudioOutput(T_AUDIO_LPCM, FALSE, */
+		/*  ulAudioSampleFS,OUTPUT_CHANNEL,NULL,TMDSClock); */
+		/* HDMITX_EnableAudioOutput(CNOFIG_INPUT_AUDIO_TYPE, */
+		/*  CONFIG_INPUT_AUDIO_SPDIF, ulAudioSampleFS,bOutputAudioChannel,NULL,TMDSClock); */
+		/* #endif */
+		/* } */
+
+	} else {
+		HDMITX_EnableAVIInfoFrame(FALSE, NULL);
+		HDMITX_EnableVSInfoFrame(FALSE, NULL);
+	}
+	setHDMITX_AVMute(FALSE);
+	it66121_bChangeMode = FALSE;
+	/* DumpHDMITXReg() ; */
+}
+
+void HDMITX_ChangeAudioOption(unsigned char Option, unsigned char channelNum, unsigned char AudioFs)
+{
+
+	switch (Option) {
+	case T_AUDIO_HBR:
+		bOutputAudioType = T_AUDIO_HBR;
+		ulAudioSampleFS = 768000L;
+		bOutputAudioChannel = 8;
+		return;
+	case T_AUDIO_NLPCM:
+		bOutputAudioType = T_AUDIO_NLPCM;
+		bOutputAudioChannel = 2;
+		break;
+	default:
+		bOutputAudioType = T_AUDIO_LPCM;
+		if (channelNum < 1)
+			bOutputAudioChannel = 1;
+		else if (channelNum > 8)
+			bOutputAudioChannel = 8;
+		else
+			bOutputAudioChannel = channelNum;
+
+		break;
+	}
+
+	switch (AudioFs) {
+	case AUDFS_44p1KHz:
+		ulAudioSampleFS = 44100L;
+		break;
+	case AUDFS_88p2KHz:
+		ulAudioSampleFS = 88200L;
+		break;
+	case AUDFS_176p4KHz:
+		ulAudioSampleFS = 176400L;
+		break;
+
+	case AUDFS_48KHz:
+		ulAudioSampleFS = 48000L;
+		break;
+	case AUDFS_96KHz:
+		ulAudioSampleFS = 96000L;
+		break;
+	case AUDFS_192KHz:
+		ulAudioSampleFS = 192000L;
+		break;
+
+	case AUDFS_768KHz:
+		ulAudioSampleFS = 768000L;
+		break;
+
+	case AUDFS_32KHz:
+		ulAudioSampleFS = 32000L;
+		break;
+	default:
+		ulAudioSampleFS = 48000L;
+		break;
+	}
+	HDMITX_DEBUG_PRINTF
+	    ("HDMITX_ChangeAudioOption():bOutputAudioType = %02X, ulAudioSampleFS = %8ld, bOutputAudioChannel = %d\n",
+	     (int)bOutputAudioType, ulAudioSampleFS, (int)bOutputAudioChannel);
+	it66121_bChangeAudio = TRUE;
+}
+
+void HDMITX_SetAudioOutput(void)
+{
+	HDMITX_DEBUG_PRINTF("HDMITX_SetAudioOutput: %d\n", bAudioEnable);
+	if (bAudioEnable) {
+		ConfigAudioInfoFrm();
+		/* HDMITX_EnableAudioOutput(T_AUDIO_LPCM, FALSE, ulAudioSampleFS,OUTPUT_CHANNEL,NULL,TMDSClock); */
+		HDMITX_EnableAudioOutput(
+						/* CNOFIG_INPUT_AUDIO_TYPE, */
+						bOutputAudioType,
+						CONFIG_INPUT_AUDIO_SPDIF,
+						ulAudioSampleFS,
+						bOutputAudioChannel,
+						NULL, VideoPixelClock * (pixelrep + 1));
+		it66121_bChangeAudio = FALSE;
+	}
+}
+/* static unsigned char deb_count=0; */
+unsigned char tmp_HPD, tmp_HPDChange ,notify_hpd_flag,notify_hpd_out;
+/* static int tim=0; */
+void HDMITX_DevLoopProc(void)
+{
+	static unsigned char DevLoopCount;
+
+	it66121_FUNC();
+	CheckHDMITX(&tmp_HPD, &tmp_HPDChange);
+	IT66121_LOG("HPDStatus= %x; HPDChangeStatus= %x;\n", tmp_HPD, tmp_HPDChange);
+	/* debounce time deb_count */
+#if 0
+	if (tmp_HPD == HPDStatus)
+		deb_count = 1;
+	else
+		deb_count--;
+	if (deb_count == 0) {
+		HPDChangeStatus = 1;
+		HPDStatus = tmp_HPD;
+	} else {
+		HPDChangeStatus = 0;
+	}
+#else
+	HPDStatus = tmp_HPD;
+	HPDChangeStatus = tmp_HPDChange;
+#endif
+	if (HPDChangeStatus) {
+		if (HPDStatus) {
+			/* switch_set_state(&hdmi_switch_data, HDMI_PLUG_ACTIVE); */
+#if 1
+			/* init_hdmi_disp_path(1); */
+			HDMITX_PowerOn();
+			ParseEDID();
+			notify_hpd_flag = 1;   /*add for hpd notify */
+
+			if (RxCapability.ValidHDMI) {
+				bHDMIMode = TRUE;
+
+				if (RxCapability.VideoMode & (1 << 6))
+					bAudioEnable = TRUE;
+
+				if (RxCapability.VideoMode & (1 << 5)) {
+					bOutputColorMode &= ~F_MODE_CLRMOD_MASK;
+					bOutputColorMode |= F_MODE_YUV444;
+				} else if (RxCapability.VideoMode & (1 << 4)) {
+					bOutputColorMode &= ~F_MODE_CLRMOD_MASK;
+					bOutputColorMode |= F_MODE_YUV422;
+				}
+#ifdef IT6615
+				if (RxCapability.dc.uc & (HDMI_DC_SUPPORT_36 | HDMI_DC_SUPPORT_30))
+					setHDMITX_ColorDepthPhase(OutputColorDepth, 0);
+				else
+					OutputColorDepth = B_TX_CD_NODEF;
+
+#else
+				OutputColorDepth = B_TX_CD_NODEF;
+#endif
+			} else {
+				bHDMIMode = FALSE;
+				bAudioEnable = FALSE;
+				OutputColorDepth = B_TX_CD_NODEF;
+				/* HDMITX_DisableAudioOutput(); */
+				/* HDMITX_DisableVideoOutput(); */
+#ifdef SUPPORT_HDCP
+				HDMITX_EnableHDCP(FALSE);
+#endif
+			}
+
+			/* bOutputColorMode = F_MODE_RGB444; */
+			if (hdmi_util.state_callback) {
+				hdmi_util.state_callback(1);
+				hdmi_invoke_cable_callbacks(HDMI_STATE_ACTIVE);
+			}
+
+			HDMITX_DEBUG_PRINTF("HPD change HDMITX_SetOutput();\n");
+			/* HDMITX_SetOutput(); */
+			it66121_bChangeMode = TRUE;
+			it66121_bChangeAudio = TRUE;
+#endif
+		} else {
+			/* unplug mode, ... */
+			notify_hpd_out = 1;
+			HDMITX_DEBUG_PRINTF("HPD OFF HDMITX_DisableVideoOutput()\n");
+			HDMITX_DisableVideoOutput();
+			HDMITX_PowerDown();
+			sink_support_resolution = 0;
+			/* switch_set_state(&hdmi_switch_data, HDMI_PLUG_NO_DEVICE); */
+			/* init_hdmi_disp_path(0); */
+			if (hdmi_util.state_callback) {
+				hdmi_util.state_callback(0);
+				hdmi_invoke_cable_callbacks(HDMI_STATE_NO_DEVICE);
+			}
+			it66121_bChangeAudio = FALSE;
+		}
+	} else {
+		notify_hpd_flag = 0;   /*add for hpd notify ,clear flag */
+		notify_hpd_out = 0;
+
+	/* no stable but need to process mode change procedure */
+		if (DevLoopCount >= 20)
+			DevLoopCount = 0;
+
+#ifdef HDMITX_AUTO_MONITOR_INPUT
+		if (DevLoopCount == 0) {
+			HDMITX_MonitorInputVideoChange();
+			HDMITX_MonitorInputAudioChange();
+		}
+#endif
+
+		if (HPDStatus) {
+#ifdef HDMITX_AUTO_MONITOR_INPUT
+			if (it66121_bChangeMode && (VIC > 0))
+#else
+			if (it66121_bChangeMode)
+#endif
+			{
+			#if 1
+				HDMITX_DEBUG_PRINTF("Mode change HDMITX_SetOutput();\n");
+				HDMITX_SetOutput();
+				/* HDMITX_EnableHDCP(TRUE); */
+				it66121_bChangeMode = FALSE;
+			#endif
+			}
+			/* /hh test */
+			/* HDMITX_WriteI2C_Byte(0xf8, 0xc3); */
+			/* HDMITX_WriteI2C_Byte(0xf8, 0xa5); */
+			/* HDMITX_WriteI2C_Byte(0xf3, 0x19); */
+			/* HDMITX_WriteI2C_Byte(0xf8, 0xff); */
+
+			/* hh test */
+			/* HDMITX_WriteI2C_Byte(0x6A, 0xFF); */
+
+			if (getHDMITX_LinkStatus()) {
+				/* AudioModeDetect(); */
+#ifdef SUPPORT_HDCP
+				if (getHDMITX_AuthenticationDone() == FALSE) {
+					HDMITX_DEBUG_PRINTF
+					    ("getHDMITX_AuthenticationDone() ==FALSE\n");
+					HDMITX_EnableHDCP(TRUE);
+					setHDMITX_AVMute(FALSE);
+				}
+#endif
+			}
+
+			if (it66121_bChangeAudio)
+				HDMITX_SetAudioOutput();
+
+		}
+	}
+
+	DevLoopCount++;
+
+
+	HDMITX_WriteI2C_Byte(REG_TX_INT_MASK1, 0x00);
+}
+
+#ifdef HDMITX_AUTO_MONITOR_INPUT
+
+void HDMITX_MonitorInputAudioChange(void)
+{
+	static ULONG prevAudioSampleFS;
+	LONG AudioFS;
+
+	if (!bAudioEnable) {
+		prevAudioSampleFS = 0;
+	} else {
+		AudioFS = CalcAudFS();
+		HDMITX_DEBUG_PRINTF1(("Audio Chagne, Audio clock = %ldHz\n", AudioFS));
+		if (AudioFS > 188000L) {
+			/* 192KHz */
+			ulAudioSampleFS = 192000L;
+		} else if (AudioFS > 144000L) {
+		/* 176.4KHz */
+			ulAudioSampleFS = 176400L;
+		} else if (AudioFS > 93000L) {
+		/* 96KHz */
+			ulAudioSampleFS = 96000L;
+		} else if (AudioFS > 80000L) {
+		/* 88.2KHz */
+			ulAudioSampleFS = 88200L;
+		} else if (AudioFS > 45000L) {
+		/* 48 KHz */
+			ulAudioSampleFS = 48000L;
+		} else if (AudioFS > 36000L) {
+		/* 44.1KHz */
+			ulAudioSampleFS = 44100L;
+		} else {
+		/* 32KHz */
+			ulAudioSampleFS = 32000L;
+		}
+
+		if (!it66121_bChangeMode) {
+			if (ulAudioSampleFS != prevAudioSampleFS) {
+				HDMITX_DEBUG_PRINTF("ulAudioSampleFS = %ldHz -> %ldHz\n",
+						    ulAudioSampleFS, ulAudioSampleFS);
+				ConfigAudioInfoFrm();
+				HDMITX_EnableAudioOutput(CNOFIG_INPUT_AUDIO_TYPE,
+							 CONFIG_INPUT_AUDIO_SPDIF, ulAudioSampleFS,
+							 OUTPUT_CHANNEL, NULL, 0);
+				/* HDMITX_EnableAudioOutput(T_AUDIO_LPCM,*/
+				/* FALSE, ulAudioSampleFS,OUTPUT_CHANNEL,NULL,0); */
+
+			}
+		}
+
+		prevAudioSampleFS = ulAudioSampleFS;
+
+	}
+}
+
+int HDMITX_SearchVICIndex(ULONG PCLK, unsigned short HTotal, unsigned short VTotal, unsigned char ScanMode)
+{
+#define SEARCH_COUNT 4
+	unsigned long pclkDiff;
+	int i;
+	char hit;
+	int iMax[SEARCH_COUNT] = { 0 };
+	char hitMax[SEARCH_COUNT] = { 0 };
+	char i2;
+
+	for (i = 0; i < SizeofVMTable; i++) {
+		if (s_VMTable[i].VIC == 0)
+			break;
+
+		hit = 0;
+
+		if (ScanMode == s_VMTable[i].ScanMode) {
+			hit++;
+
+			if (ScanMode == INTERLACE) {
+				if (DIFF(VTotal / 2, s_VMTable[i].VTotal) < 10)
+					hit++;
+			} else {
+				if (DIFF(VTotal, s_VMTable[i].VTotal) < 10)
+					hit++;
+			}
+
+			if (hit == 2) {
+				/* match scan mode and v-total */
+				if (DIFF(HTotal, s_VMTable[i].HTotal) < 40) {
+					hit++;
+
+					pclkDiff = DIFF(PCLK, s_VMTable[i].PCLK);
+					pclkDiff = (pclkDiff * 100) / s_VMTable[i].PCLK;
+
+					if (pclkDiff < 100)
+						hit += (100 - pclkDiff);
+				}
+			}
+		}
+
+		HDMITX_DEBUG_PRINTF(("i = %d, hit = %d\n", i, (int)hit));
+
+		if (hit) {
+			for (i2 = 0; i2 < SEARCH_COUNT; i2++) {
+				if (hitMax[i2] < hit) {
+					HDMITX_DEBUG_PRINTF(("replace iMax[%d] = %d => %d\n",
+							     (int)i2, iMax[i2], i));
+					hitMax[i2] = hit;
+					iMax[i2] = i;
+					break;
+				}
+			}
+		}
+	}
+
+	i = -1;
+	hit = 0;
+	for (i2 = 0; i2 < SEARCH_COUNT; i2++) {
+		HDMITX_DEBUG_PRINTF(("[%d] i = %d, hit = %d\n", (int)i2, iMax[i2],
+				     (int)hitMax[i2]));
+		if (hitMax[i2] > hit) {
+			hit = hitMax[i2];
+			i = iMax[i2];
+		}
+	}
+
+	if (hit > 2) {
+		HDMITX_DEBUG_PRINTF(("i = %d, hit = %d\n", i, (int)hit));
+		HDMITX_DEBUG_PRINTF((">> mode : %d %u x %u @%lu (%s)\n", (int)s_VMTable[i].VIC,
+				     s_VMTable[i].HActive, s_VMTable[i].VActive, s_VMTable[i].PCLK,
+				     (s_VMTable[i].ScanMode == 0) ? "i" : "p"));
+	} else {
+		i = -1;
+		HDMITX_DEBUG_PRINTF(("no matched\n"));
+	}
+
+	return i;
+}
+
+void HDMITX_MonitorInputVideoChange(void)
+{
+	static ULONG prevPCLK;
+	static unsigned short prevHTotal;
+	static unsigned short prevVTotal;
+	static unsigned char prevScanMode;
+	ULONG currPCLK;
+	ULONG diff;
+	unsigned short currHTotal, currVTotal;
+	unsigned char currScanMode;
+	int i;
+
+	currPCLK = CalcPCLK();
+	currHTotal = hdmitx_getInputHTotal();
+	currVTotal = hdmitx_getInputVTotal();
+	currScanMode = hdmitx_isInputInterlace() ? INTERLACE : PROG;
+	diff = DIFF(currPCLK, prevPCLK);
+
+	HDMITX_DEBUG_PRINTF(("HDMITX_MonitorInputVideoChange : pclk=%lu, ht=%u, vt=%u, dif=%lu\n",
+			     currPCLK, currHTotal, currVTotal, diff));
+
+	if (currHTotal == 0 || currVTotal == 0 || currPCLK == 0) {
+		it66121_bChangeMode = FALSE;
+		return;
+	}
+	if (diff > currPCLK / 20) {
+	/* 5% torrenlance */
+		it66121_bChangeMode = TRUE;
+	} else {
+		diff = DIFF(currHTotal, prevHTotal);
+		if (diff > 20)
+			it66121_bChangeMode = TRUE;
+
+		diff = DIFF(currVTotal, prevVTotal);
+		if (diff > 20)
+			it66121_bChangeMode = TRUE;
+	}
+
+	if (it66121_bChangeMode) {
+		HDMITX_DEBUG_PRINTF("PCLK = %ld -> %ld\n", prevPCLK, currPCLK);
+		HDMITX_DEBUG_PRINTF("HTotal = %d -> %d\n", prevHTotal, currHTotal);
+		HDMITX_DEBUG_PRINTF("VTotal = %d -> %d\n", prevVTotal, currVTotal);
+		HDMITX_DEBUG_PRINTF("ScanMode = %s -> %s\n", prevScanMode ? "P" : "I",
+				    currScanMode ? "P" : "I");
+
+		HDMITX_DEBUG_PRINTF("PCLK = %ld,(%dx%d) %s %s\n", currPCLK, currHTotal, currVTotal,
+				    (currScanMode == INTERLACE) ? "INTERLACED" : "PROGRESS",
+				    it66121_bChangeMode ? "CHANGE MODE" : "NO CHANGE MODE");
+
+		setHDMITX_AVMute(TRUE);
+#if 0
+		for (i = 0; (i < SizeofVMTable) && (s_VMTable[i].VIC != 0); i++) {
+			if (s_VMTable[i].VIC == 0)
+				break;
+			if (DIFF(currPCLK, s_VMTable[i].PCLK) > (s_VMTable[i].PCLK / 20))
+				continue;
+
+			if (DIFF(currHTotal, s_VMTable[i].HTotal) > 40)
+				continue;
+
+			if (currScanMode != s_VMTable[i].ScanMode)
+				continue;
+
+			if (currScanMode == INTERLACE) {
+				if (DIFF(currVTotal / 2, s_VMTable[i].VTotal) > 10)
+					continue;
+
+			} else {
+				if (DIFF(currVTotal, s_VMTable[i].VTotal) > 10)
+					continue;
+			}
+			IT66121_LOG("i = %d, VIC = %d\n", i, (int)s_VMTable[i].VIC);
+
+			break;
+		}
+#else
+		i = HDMITX_SearchVICIndex(currPCLK, currHTotal, currVTotal, currScanMode);
+#endif
+
+		if (i >= 0) {
+			VIC = s_VMTable[i].VIC;
+			pixelrep = s_VMTable[i].PixelRep;
+			VideoPixelClock = currPCLK;
+		} else {
+			VIC = 0;
+			pixelrep = 0;
+			VideoPixelClock = 0;
+		}
+	}
+
+	prevPCLK = currPCLK;
+	prevHTotal = currHTotal;
+	prevVTotal = currVTotal;
+	prevScanMode = currScanMode;
+
+}
+#endif				/* HDMITX_AUTO_MONITOR_INPUT */
+
+void HDMITX_ChangeDisplayOption(HDMI_Video_Type OutputVideoTiming,
+				HDMI_OutputColorMode OutputColorMode)
+{
+	IT66121_LOG("hdmi_ite66121 %s\n", __func__);
+
+	/* HDMI_Video_Type  t=HDMI_480i60_16x9; */
+	if ((F_MODE_RGB444) == (bOutputColorMode & F_MODE_CLRMOD_MASK)) {
+		/* Force output RGB in RGB only case */
+		OutputColorMode = F_MODE_RGB444;
+	} else if ((F_MODE_YUV422) == (bOutputColorMode & F_MODE_CLRMOD_MASK)) {
+	/* YUV422 only */
+		if (OutputColorMode == HDMI_YUV444)
+			OutputColorMode = F_MODE_YUV422;
+	} else if ((F_MODE_YUV444) == (bOutputColorMode & F_MODE_CLRMOD_MASK)) {
+	/* YUV444 only */
+		if (OutputColorMode == HDMI_YUV422)
+			OutputColorMode = F_MODE_YUV444;
+	}
+	switch (OutputVideoTiming) {
+	case HDMI_640x480p60:
+		VIC = 1;
+		VideoPixelClock = 25000000;
+		pixelrep = 0;
+		aspec = HDMI_4x3;
+		Colorimetry = HDMI_ITU601;
+		break;
+	case HDMI_480p60:
+		VIC = 2;
+		VideoPixelClock = 27000000;
+		pixelrep = 0;
+		aspec = HDMI_4x3;
+		Colorimetry = HDMI_ITU601;
+		break;
+	case HDMI_480p60_16x9:
+		VIC = 3;
+		VideoPixelClock = 27000000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU601;
+		break;
+	case HDMI_720p60:
+		VIC = 4;
+		VideoPixelClock = 74250000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU709;
+		break;
+	case HDMI_1080i60:
+		VIC = 5;
+		VideoPixelClock = 74250000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU709;
+		break;
+	case HDMI_480i60:
+		VIC = 6;
+		VideoPixelClock = 13500000;
+		pixelrep = 1;
+		aspec = HDMI_4x3;
+		Colorimetry = HDMI_ITU601;
+		break;
+	case HDMI_480i60_16x9:
+		VIC = 7;
+		VideoPixelClock = 13500000;
+		pixelrep = 1;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU601;
+		break;
+	case HDMI_1080p60:
+		VIC = 16;
+		VideoPixelClock = 148500000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU709;
+		break;
+	case HDMI_576p50:
+		VIC = 17;
+		VideoPixelClock = 27000000;
+		pixelrep = 0;
+		aspec = HDMI_4x3;
+		Colorimetry = HDMI_ITU601;
+		break;
+	case HDMI_576p50_16x9:
+		VIC = 18;
+		VideoPixelClock = 27000000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU601;
+		break;
+	case HDMI_720p50:
+		VIC = 19;
+		VideoPixelClock = 74250000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU709;
+		break;
+	case HDMI_1080i50:
+		VIC = 20;
+		VideoPixelClock = 74250000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU709;
+		break;
+	case HDMI_576i50:
+		VIC = 21;
+		VideoPixelClock = 13500000;
+		pixelrep = 1;
+		aspec = HDMI_4x3;
+		Colorimetry = HDMI_ITU601;
+		break;
+	case HDMI_576i50_16x9:
+		VIC = 22;
+		VideoPixelClock = 13500000;
+		pixelrep = 1;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU601;
+		break;
+	case HDMI_1080p50:
+		VIC = 31;
+		VideoPixelClock = 148500000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU709;
+		break;
+	case HDMI_1080p24:
+		VIC = 32;
+		VideoPixelClock = 74250000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU709;
+		break;
+	case HDMI_1080p25:
+		VIC = 33;
+		VideoPixelClock = 74250000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU709;
+		break;
+	case HDMI_1080p30:
+		VIC = 34;
+		VideoPixelClock = 74250000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU709;
+		break;
+
+	case HDMI_720p30:
+		VIC = 0;
+		VideoPixelClock = 74250000;
+		pixelrep = 0;
+		aspec = HDMI_16x9;
+		Colorimetry = HDMI_ITU709;
+
+#ifdef SUPPORT_SYNCEMBEDDED
+
+		/*   VTiming.HActive=1280 ;*/
+		/*   VTiming.VActive=720 ;*/
+		/*   VTiming.HTotal=3300 ;*/
+		/*   VTiming.VTotal=750 ;*/
+		/*   VTiming.PCLK=VideoPixelClock ;*/
+		/*   VTiming.xCnt=0x2E ;*/
+		/*   VTiming.HFrontPorch= 1760;*/
+		/*   VTiming.HSyncWidth= 40 ;*/
+		/*   VTiming.HBackPorch= 220 ;*/
+		/*   VTiming.VFrontPorch= 5;*/
+		/*   VTiming.VSyncWidth= 5 ;*/
+		/*   VTiming.VBackPorch= 20 ;*/
+		/*   VTiming.ScanMode=PROG ;*/
+		/*   VTiming.VPolarity=Vneg ;*/
+		/*   VTiming.HPolarity=Hneg ;*/
+
+#endif
+		break;
+	default:
+		it66121_bChangeMode = FALSE;
+		return;
+	}
+	switch (OutputColorMode) {
+	case HDMI_YUV444:
+		bOutputColorMode = F_MODE_YUV444;
+		break;
+	case HDMI_YUV422:
+		bOutputColorMode = F_MODE_YUV422;
+		break;
+	case HDMI_RGB444:
+	default:
+		bOutputColorMode = F_MODE_RGB444;
+		break;
+	}
+	if (Colorimetry == HDMI_ITU709)
+		bInputColorMode |= F_VIDMODE_ITU709;
+	else
+		bInputColorMode &= ~F_VIDMODE_ITU709;
+
+	/* if( Colorimetry != HDMI_640x480p60) */
+	if (OutputVideoTiming != HDMI_640x480p60)
+		bInputColorMode |= F_VIDMODE_16_235;
+	else
+		bInputColorMode &= ~F_VIDMODE_16_235;
+
+	it66121_bChangeMode = TRUE;
+}
+
+void ConfigAVIInfoFrame(unsigned char VIC, unsigned char pixelrep)
+{
+	AVI_InfoFrame *AviInfo;
+
+	IT66121_LOG("hdmi ConfigAVIInfoFrame VIC = %d\n", VIC);
+	AviInfo = (AVI_InfoFrame *) CommunBuff;
+
+	AviInfo->pktbyte.AVI_HB[0] = AVI_INFOFRAME_TYPE | 0x80;
+	AviInfo->pktbyte.AVI_HB[1] = AVI_INFOFRAME_VER;
+	AviInfo->pktbyte.AVI_HB[2] = AVI_INFOFRAME_LEN;
+
+	switch (bOutputColorMode) {
+	case F_MODE_YUV444:
+		/* AviInfo->info.ColorMode = 2 ; */
+		AviInfo->pktbyte.AVI_DB[0] = (2 << 5) | (1 << 4);
+		break;
+	case F_MODE_YUV422:
+		/* AviInfo->info.ColorMode = 1 ; */
+		AviInfo->pktbyte.AVI_DB[0] = (1 << 5) | (1 << 4);
+		break;
+	case F_MODE_RGB444:
+	default:
+		/* AviInfo->info.ColorMode = 0 ; */
+		AviInfo->pktbyte.AVI_DB[0] = (0 << 5) | (1 << 4);
+		break;
+	}
+	AviInfo->pktbyte.AVI_DB[1] = 8;
+	AviInfo->pktbyte.AVI_DB[1] |= (aspec != HDMI_16x9) ? (1 << 4) : (2 << 4);	/* 4:3 or 16:9 */
+	AviInfo->pktbyte.AVI_DB[1] |= (Colorimetry != HDMI_ITU709) ? (1 << 6) : (2 << 6);	/* 4:3 or 16:9 */
+	AviInfo->pktbyte.AVI_DB[2] = 0;
+	AviInfo->pktbyte.AVI_DB[3] = VIC;
+	AviInfo->pktbyte.AVI_DB[4] = pixelrep & 3;
+	AviInfo->pktbyte.AVI_DB[5] = 0;
+	AviInfo->pktbyte.AVI_DB[6] = 0;
+	AviInfo->pktbyte.AVI_DB[7] = 0;
+	AviInfo->pktbyte.AVI_DB[8] = 0;
+	AviInfo->pktbyte.AVI_DB[9] = 0;
+	AviInfo->pktbyte.AVI_DB[10] = 0;
+	AviInfo->pktbyte.AVI_DB[11] = 0;
+	AviInfo->pktbyte.AVI_DB[12] = 0;
+
+	HDMITX_EnableAVIInfoFrame(TRUE, (unsigned char *)AviInfo);
+}
+
+/* ////////////////////////////////////////////////////////////////////////////// */
+/* Function: ConfigAudioInfoFrm */
+/* Parameter: NumChannel, number from 1 to 8 */
+/* Return: ER_SUCCESS for successful. */
+/* Remark: Evaluate. The speakerplacement is only for reference. */
+/* For production, the caller of hdmitx_SetAudioInfoFrame should program */
+/* Speaker placement by actual status. */
+/* Side-Effect: */
+/* ////////////////////////////////////////////////////////////////////////////// */
+
+void ConfigAudioInfoFrm(void)
+{
+	int i;
+
+	Audio_InfoFrame *AudioInfo;
+
+	AudioInfo = (Audio_InfoFrame *) CommunBuff;
+
+	HDMITX_DEBUG_PRINTF("ConfigAudioInfoFrm(%d)\n", 2);
+
+	AudioInfo->pktbyte.AUD_HB[0] = AUDIO_INFOFRAME_TYPE;
+	AudioInfo->pktbyte.AUD_HB[1] = 1;
+	AudioInfo->pktbyte.AUD_HB[2] = AUDIO_INFOFRAME_LEN;
+	AudioInfo->pktbyte.AUD_DB[0] = 1;
+	for (i = 1; i < AUDIO_INFOFRAME_LEN; i++)
+		AudioInfo->pktbyte.AUD_DB[i] = 0;
+
+	HDMITX_EnableAudioInfoFrame(TRUE, (unsigned char *)AudioInfo);
+}
+
+void ConfigfHdmiVendorSpecificInfoFrame(unsigned char _3D_Stru)
+{
+	VendorSpecific_InfoFrame *VS_Info;
+
+	VS_Info = (VendorSpecific_InfoFrame *) CommunBuff;
+
+	VS_Info->pktbyte.VS_HB[0] = VENDORSPEC_INFOFRAME_TYPE | 0x80;
+	VS_Info->pktbyte.VS_HB[1] = VENDORSPEC_INFOFRAME_VER;
+	VS_Info->pktbyte.VS_HB[2] = (_3D_Stru == Side_by_Side) ? 6 : 5;
+	VS_Info->pktbyte.VS_DB[0] = 0x03;
+	VS_Info->pktbyte.VS_DB[1] = 0x0C;
+	VS_Info->pktbyte.VS_DB[2] = 0x00;
+	VS_Info->pktbyte.VS_DB[3] = 0x40;
+	switch (_3D_Stru) {
+	case Side_by_Side:
+	case Frame_Pcaking:
+	case Top_and_Botton:
+		VS_Info->pktbyte.VS_DB[4] = (_3D_Stru << 4);
+		break;
+	default:
+		VS_Info->pktbyte.VS_DB[4] = (Frame_Pcaking << 4);
+		break;
+	}
+	VS_Info->pktbyte.VS_DB[5] = 0x00;
+	HDMITX_EnableVSInfoFrame(TRUE, (unsigned char *) VS_Info);
+}
+
+/* /////////////////////////////////////////////////////////////////// */
+/* ParseEDID() */
+/* Check EDID check sum and EDID 1.3 extended segment. */
+/* /////////////////////////////////////////////////////////////////// */
+
+unsigned char ParseEDID(void)
+{
+
+	/* collect the EDID ucdata of segment 0 */
+	unsigned char *EDID_Buf;
+	unsigned char CheckSum;
+	unsigned char BlockCount;
+	unsigned char err;
+	unsigned char bValidCEA = FALSE;
+	int i, j;
+
+	IT66121_LOG("hdmi_ite66121 %s\n", __func__);
+
+	EDID_Buf = CommunBuff;
+	RxCapability.ValidCEA = FALSE;
+	RxCapability.ValidHDMI = FALSE;
+	RxCapability.dc.uc = 0;
+
+	getHDMITX_EDIDBlock(0, EDID_Buf);
+
+	for (i = 0, CheckSum = 0; i < 128; i++) {
+		CheckSum += EDID_Buf[i];
+		CheckSum &= 0xFF;
+		real_edid[i]= EDID_Buf[i];
+	}
+	/* Eep_Write(0x80, 0x80, EDID_Buf); */
+	if (CheckSum != 0)
+		return FALSE;
+
+	if (EDID_Buf[0] != 0x00 ||
+	    EDID_Buf[1] != 0xFF ||
+	    EDID_Buf[2] != 0xFF ||
+	    EDID_Buf[3] != 0xFF ||
+	    EDID_Buf[4] != 0xFF ||
+	    EDID_Buf[5] != 0xFF || EDID_Buf[6] != 0xFF || EDID_Buf[7] != 0x00) {
+		return FALSE;
+	}
+	/* HDMITX_DEBUG_PRINTF("EDID data:\n"); */
+	/*   for( i = 0 ; i < 128 ; i++ )*/
+	/*   {*/
+	/*   HDMITX_DEBUG_PRINTF("%02X%c",(int)EDID_Buf[i],(7 == (i&7))?'\n':' ');*/
+	/*   }*/
+
+
+	BlockCount = EDID_Buf[0x7E];
+
+	if (BlockCount == 0)
+		return TRUE;	/* do nothing. */
+	else if (BlockCount > 4)
+		BlockCount = 4;
+
+	/* read all segment for test */
+	for (i = 1; i <= BlockCount; i++) {
+		err = getHDMITX_EDIDBlock(i, EDID_Buf);
+		EDID_DEBUG_PRINTF1("EDID data:\n");
+		for (j = 0; j < 128; j++) {
+			EDID_DEBUG_PRINTF1("%02X%c", (int)EDID_Buf[j], (7 == (i & 7)) ? '\n' : ' ');
+			if (i == 1)
+				real_edid[j + 128] = EDID_Buf[j];
+		}
+		if (err) {
+			if (!bValidCEA && EDID_Buf[0] == 0x2 && EDID_Buf[1] == 0x3) {
+				err = ParseCEAEDID(EDID_Buf);
+				EDID_DEBUG_PRINTF("err = %s\n", err ? "SUCCESS" : "FAIL");
+				if (err) {
+					EDID_DEBUG_PRINTF("RxCapability.IEEEOUI = %lx\n",
+							  RxCapability.IEEEOUI);
+
+					if (RxCapability.IEEEOUI == 0x0c03) {
+						RxCapability.ValidHDMI = TRUE;
+						bValidCEA = TRUE;
+					} else {
+						RxCapability.ValidHDMI = FALSE;
+					}
+				}
+			}
+		}
+	}
+	return err;
+}
+void ite66121_AppGetEdidInfo(struct _HDMI_EDID_T *pv_get_info)
+{
+
+	pv_get_info->ui4_ntsc_resolution |= sink_support_resolution;
+	pv_get_info->ui4_pal_resolution |= sink_support_resolution;
+	pv_get_info->ui4_sink_dtd_ntsc_resolution |= sink_support_resolution;
+	pv_get_info->ui4_sink_dtd_pal_resolution |= sink_support_resolution;
+	pv_get_info->ui4_sink_cea_ntsc_resolution |= sink_support_resolution;
+	pv_get_info->ui4_sink_cea_pal_resolution |= sink_support_resolution;
+	pv_get_info->ui4_sink_native_ntsc_resolution |= sink_support_resolution;
+	pv_get_info->ui4_sink_native_pal_resolution |= sink_support_resolution;
+}
+bool ParseCEAEDID(unsigned char *pCEAEDID)
+{
+	unsigned char offset, End;
+	unsigned char count;
+	unsigned char tag;
+	int i;
+
+	if (pCEAEDID[0] != 0x02 || pCEAEDID[1] != 0x03)
+		return FALSE;	/* not a CEA BLOCK. */
+	End = pCEAEDID[2];	/* CEA description. */
+
+	RxCapability.VDOMode[0] = 0x00;
+	RxCapability.VDOMode[1] = 0x00;
+	RxCapability.VDOMode[2] = 0x00;
+	RxCapability.VDOMode[3] = 0x00;
+	RxCapability.VDOMode[4] = 0x00;
+	RxCapability.VDOMode[5] = 0x00;
+	RxCapability.VDOMode[6] = 0x00;
+	RxCapability.VDOMode[7] = 0x00;
+	RxCapability.PA[0] = 0x00;
+	RxCapability.PA[1] = 0x00;
+
+	RxCapability.VideoMode = pCEAEDID[3];
+
+	RxCapability.NativeVDOMode = 0xff;
+
+	for (offset = 4; offset < End;) {
+		tag = pCEAEDID[offset] >> 5;
+		count = pCEAEDID[offset] & 0x1f;
+		switch (tag) {
+		case 0x01:	/* Audio Data Block ; */
+			RxCapability.AUDDesCount = count / 3;
+			EDID_DEBUG_PRINTF("RxCapability.AUDDesCount = %d\n",
+					  (int)RxCapability.AUDDesCount);
+			offset++;
+			for (i = 0; i < RxCapability.AUDDesCount && i < MAX_AUDDES_COUNT; i++) {
+				RxCapability.AUDDes[i].uc[0] = pCEAEDID[offset + i * 3];
+				RxCapability.AUDDes[i].uc[1] = pCEAEDID[offset + i * 3 + 1];
+				RxCapability.AUDDes[i].uc[2] = pCEAEDID[offset + i * 3 + 2];
+			}
+			offset += count;
+			break;
+
+		case 0x02:	/* Video Data Block ; */
+			offset++;
+			for (i = 0, RxCapability.NativeVDOMode = 0xff; i < count; i++) {
+				unsigned char VIC;
+
+				VIC = pCEAEDID[offset + i] & (~0x80);
+				/* if( FindModeTableEntryByVIC(VIC) != -1 ) */
+				if (VIC < 64) {
+					if (VIC == 34 || VIC == 16 || VIC == 4 || VIC == 2)
+						sink_support_resolution |= SINK_480P | SINK_720P60
+									| SINK_1080P30;
+
+					RxCapability.VDOMode[VIC / 8] |= (1 << (VIC % 8));
+					EDID_DEBUG_PRINTF
+					    ("VIC = %d, RxCapability.VDOMode[%d]=%02X\n", (int)VIC,
+					     (int)VIC / 8, (int)RxCapability.VDOMode[VIC / 8]);
+					if ((pCEAEDID[offset + i] & 0x80)
+					    && (RxCapability.NativeVDOMode == 0xFF)) {
+						RxCapability.NativeVDOMode = VIC;
+						EDID_DEBUG_PRINTF("native = %d\n",
+								  RxCapability.NativeVDOMode);
+					}
+				}
+			}
+			offset += count;
+			break;
+
+		case 0x03:	/* Vendor Specific Data Block ; */
+			offset++;
+			RxCapability.IEEEOUI = (ULONG) pCEAEDID[offset + 2];
+			RxCapability.IEEEOUI <<= 8;
+			RxCapability.IEEEOUI += (ULONG) pCEAEDID[offset + 1];
+			RxCapability.IEEEOUI <<= 8;
+			RxCapability.IEEEOUI += (ULONG) pCEAEDID[offset];
+			EDID_DEBUG_PRINTF("IEEEOUI = %02X %02X %02X %lx", (int)pCEAEDID[offset + 2],
+					  (int)pCEAEDID[offset + 1], (int)pCEAEDID[offset],
+					  RxCapability.IEEEOUI);
+			if (RxCapability.IEEEOUI == 0x0C03) {
+				unsigned char nextoffset;
+
+				RxCapability.PA[0] = pCEAEDID[offset + 3];
+				RxCapability.PA[1] = pCEAEDID[offset + 4];
+				if (count > 5)
+					RxCapability.dc.uc = pCEAEDID[offset + 5] & 0x70;
+
+				if (count > 6)
+					RxCapability.MaxTMDSClock = pCEAEDID[offset + 6];
+
+				if (count > 7) {
+					nextoffset = 8;
+					if (pCEAEDID[offset + 7] & 0x80)
+						nextoffset += 2;
+						/* latency */
+					if (pCEAEDID[offset + 7] & 0x40)
+						nextoffset += 2;
+						/* interlace latency */
+					if (pCEAEDID[offset + 7] & 0x20) {
+						EDID_DEBUG_PRINTF("next offset = %d",
+								  (int)nextoffset);
+						RxCapability.Valid3D =
+						    (pCEAEDID[offset + nextoffset] & 0x80) ? TRUE :
+						    FALSE;
+					}	/* interlace latency */
+
+				}
+			}
+			offset += count;	/* ignore the remaind. */
+
+			break;
+
+		case 0x04:	/* Speaker Data Block ; */
+			offset++;
+			RxCapability.SpeakerAllocBlk.uc[0] = pCEAEDID[offset];
+			RxCapability.SpeakerAllocBlk.uc[1] = pCEAEDID[offset + 1];
+			RxCapability.SpeakerAllocBlk.uc[2] = pCEAEDID[offset + 2];
+			offset += 3;
+			break;
+		case 0x05:	/* VESA Data Block ; */
+			offset += count + 1;
+			break;
+		case 0x07:	/* Extended Data Block ; */
+			offset += count + 1;	/* ignore */
+			break;
+		default:
+			offset += count + 1;	/* ignore */
+		}
+	}
+	RxCapability.ValidCEA = TRUE;
+	return TRUE;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_sys.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_sys.h
new file mode 100644
index 0000000..5d1f02e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/hdmitx_sys.h
@@ -0,0 +1,328 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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.
+*/
+
+
+#ifndef _HDMITX_SYS_H_
+#define _HDMITX_SYS_H_
+
+#include "itx_typedef.h"
+#include "inc/hdmi_drv.h"
+#define I2S 0
+#define SPDIF 1
+
+#ifdef HDMITX_INPUT_INFO
+void HDMITX_MonitorInputVideoChange(void);
+void HDMITX_MonitorInputAudioChange(void);
+
+#endif
+
+unsigned char ParseEDID(void);
+bool ParseCEAEDID(unsigned char *pCEAEDID);
+void ConfigAVIInfoFrame(unsigned char VIC, unsigned char pixelrep);
+void ConfigAudioInfoFrm(void);
+void Config_GeneralPurpose_Infoframe(unsigned char *p3DInfoFrame);
+void ConfigfHdmiVendorSpecificInfoFrame(unsigned char _3D_Stru);
+void InitHDMITX_Variable(void);
+void HDMITX_SetOutput(void);
+void HDMITX_DevLoopProc(void);
+
+extern struct switch_dev hdmi_switch_data;
+extern void switch_host_interface_timing(int out);
+extern void init_hdmi_disp_path(int out);
+/* extern int start_output; */
+
+#ifndef I2S_FORMAT
+#define I2S_FORMAT 0x01		/* 32bit audio */
+#endif
+
+#ifndef INPUT_SAMPLE_FREQ
+#define INPUT_SAMPLE_FREQ AUDFS_48KHz
+#endif				/* INPUT_SAMPLE_FREQ */
+
+#ifndef INPUT_SAMPLE_FREQ_HZ
+#define INPUT_SAMPLE_FREQ_HZ 48000L
+#endif				/* INPUT_SAMPLE_FREQ_HZ */
+
+#ifndef OUTPUT_CHANNEL
+#define OUTPUT_CHANNEL 2
+#endif				/* OUTPUT_CHANNEL */
+
+#ifndef CNOFIG_INPUT_AUDIO_TYPE
+#define CNOFIG_INPUT_AUDIO_TYPE T_AUDIO_LPCM
+    /* #define CNOFIG_INPUT_AUDIO_TYPE T_AUDIO_NLPCM */
+    /* #define CNOFIG_INPUT_AUDIO_TYPE T_AUDIO_HBR */
+#endif				/* CNOFIG_INPUT_AUDIO_TYPE */
+
+#ifndef CONFIG_INPUT_AUDIO_SPDIF
+#define CONFIG_INPUT_AUDIO_SPDIF I2S
+    /* #define CONFIG_INPUT_AUDIO_SPDIF  SPDIF */
+#endif				/* CONFIG_INPUT_AUDIO_SPDIF */
+
+#ifndef INPUT_SIGNAL_TYPE
+#define INPUT_SIGNAL_TYPE 0	/* 24 bit sync separate */
+#endif
+
+/* ////////////////////////////////////////////////////////////////////////////// */
+/* Internal Data Type */
+/* ////////////////////////////////////////////////////////////////////////////// */
+
+enum _HDMI_Video_Type {
+	HDMI_Unknown = 0,
+	HDMI_640x480p60 = 1,
+	HDMI_480p60,
+	HDMI_480p60_16x9,
+	HDMI_720p60,
+	HDMI_1080i60,
+	HDMI_480i60,
+	HDMI_480i60_16x9,
+	HDMI_1080p60 = 16,
+	HDMI_576p50,
+	HDMI_576p50_16x9,
+	HDMI_720p50,
+	HDMI_1080i50,
+	HDMI_576i50,
+	HDMI_576i50_16x9,
+	HDMI_1080p50 = 31,
+	HDMI_1080p24,
+	HDMI_1080p25,
+	HDMI_1080p30,
+	HDMI_720p30 = 61,
+};
+#define HDMI_Video_Type enum _HDMI_Video_Type
+
+enum _HDMI_Aspec {
+	HDMI_4x3,
+	HDMI_16x9
+};
+#define HDMI_Aspec enum _HDMI_Aspec
+
+enum _HDMI_OutputColorMode {
+	HDMI_RGB444,
+	HDMI_YUV444,
+	HDMI_YUV422
+};
+#define HDMI_OutputColorMode enum _HDMI_OutputColorMode
+
+enum _HDMI_Colorimetry {
+	HDMI_ITU601,
+	HDMI_ITU709
+};
+#define HDMI_Colorimetry enum _HDMI_Colorimetry
+
+struct VideoTiming {
+	ULONG VideoPixelClock;
+	unsigned char VIC;
+	unsigned char pixelrep;
+	unsigned char outputVideoMode;
+};
+
+
+
+enum _TXVideo_State_Type {
+	TXVSTATE_Unplug = 0,
+	TXVSTATE_HPD,
+	TXVSTATE_WaitForMode,
+	TXVSTATE_WaitForVStable,
+	TXVSTATE_VideoInit,
+	TXVSTATE_VideoSetup,
+	TXVSTATE_VideoOn,
+	TXVSTATE_Reserved
+};
+#define TXVideo_State_Type enum _TXVideo_State_Type
+
+enum _TXAudio_State_Type {
+	TXASTATE_AudioOff = 0,
+	TXASTATE_AudioPrepare,
+	TXASTATE_AudioOn,
+	TXASTATE_AudioFIFOFail,
+	TXASTATE_Reserved
+};
+#define TXAudio_State_Type enum _TXAudio_State_Type
+
+/* /////////////////////////////////////// */
+/* RX Capability. */
+/* /////////////////////////////////////// */
+struct _LPCM_BitWidth {
+	unsigned char b16bit:1;
+	unsigned char b20bit:1;
+	unsigned char b24bit:1;
+	unsigned char Rsrv:5;
+};
+#define LPCM_BitWidth struct _LPCM_BitWidth
+
+enum _AUDIO_FORMAT_CODE {
+	AUD_RESERVED_0 = 0,
+	AUD_LPCM,
+	AUD_AC3,
+	AUD_MPEG1,
+	AUD_MP3,
+	AUD_MPEG2,
+	AUD_AAC,
+	AUD_DTS,
+	AUD_ATRAC,
+	AUD_ONE_BIT_AUDIO,
+	AUD_DOLBY_DIGITAL_PLUS,
+	AUD_DTS_HD,
+	AUD_MAT_MLP,
+	AUD_DST,
+	AUD_WMA_PRO,
+	AUD_RESERVED_15
+};
+#define AUDIO_FORMAT_CODE enum _AUDIO_FORMAT_CODE
+
+union _AUDDESCRIPTOR {
+	struct {
+		unsigned char channel:3;
+		unsigned char AudioFormatCode:4;
+		unsigned char Rsrv1:1;
+
+		unsigned char b32KHz:1;
+		unsigned char b44_1KHz:1;
+		unsigned char b48KHz:1;
+		unsigned char b88_2KHz:1;
+		unsigned char b96KHz:1;
+		unsigned char b176_4KHz:1;
+		unsigned char b192KHz:1;
+		unsigned char Rsrv2:1;
+		unsigned char ucCode;
+	} s;
+	unsigned char uc[3];
+};
+#define AUDDESCRIPTOR union _AUDDESCRIPTOR
+
+union _SPK_ALLOC {
+	struct {
+		unsigned char FL_FR:1;
+		unsigned char LFE:1;
+		unsigned char FC:1;
+		unsigned char RL_RR:1;
+		unsigned char RC:1;
+		unsigned char FLC_FRC:1;
+		unsigned char RLC_RRC:1;
+		unsigned char Reserve:1;
+		unsigned char Unuse[2];
+	} s;
+	unsigned char uc[3];
+};
+#define SPK_ALLOC union _SPK_ALLOC
+
+#define CEA_SUPPORT_UNDERSCAN (1<<7)
+#define CEA_SUPPORT_AUDIO (1<<6)
+#define CEA_SUPPORT_YUV444 (1<<5)
+#define CEA_SUPPORT_YUV422 (1<<4)
+#define CEA_NATIVE_MASK 0xF
+
+
+#define HDMI_DC_SUPPORT_AI (1<<7)
+#define HDMI_DC_SUPPORT_48 (1<<6)
+#define HDMI_DC_SUPPORT_36 (1<<5)
+#define HDMI_DC_SUPPORT_30 (1<<4)
+#define HDMI_DC_SUPPORT_Y444 (1<<3)
+#define HDMI_DC_SUPPORT_DVI_DUAL 1
+
+union _DCSUPPORT {
+	struct {
+		unsigned char DVI_Dual:1;
+		unsigned char Rsvd:2;
+		unsigned char DC_Y444:1;
+		unsigned char DC_30Bit:1;
+		unsigned char DC_36Bit:1;
+		unsigned char DC_48Bit:1;
+		unsigned char SUPPORT_AI:1;
+	} info;
+	unsigned char uc;
+};
+#define DCSUPPORT union _DCSUPPORT
+
+union _LATENCY_SUPPORT {
+	struct {
+		unsigned char Rsvd:6;
+		unsigned char I_Latency_Present:1;
+		unsigned char Latency_Present:1;
+	} info;
+	unsigned char uc;
+};
+#define LATENCY_SUPPORT union _LATENCY_SUPPORT
+
+#define HDMI_IEEEOUI 0x0c03
+#define MAX_VODMODE_COUNT 32
+#define MAX_AUDDES_COUNT 4
+
+struct _RX_CAP {
+	unsigned char VideoMode;
+	unsigned char NativeVDOMode;
+	unsigned char VDOMode[8];
+	unsigned char AUDDesCount;
+	AUDDESCRIPTOR AUDDes[MAX_AUDDES_COUNT];
+	unsigned char PA[2];
+	ULONG IEEEOUI;
+	DCSUPPORT dc;
+	unsigned char MaxTMDSClock;
+	LATENCY_SUPPORT lsupport;
+	SPK_ALLOC SpeakerAllocBlk;
+	unsigned char ValidCEA:1;
+	unsigned char ValidHDMI:1;
+	unsigned char Valid3D:1;
+};
+#define RX_CAP struct _RX_CAP
+
+/* ///////////////////////////////////////////////////////////////////// */
+/* Output Mode Type */
+/* ///////////////////////////////////////////////////////////////////// */
+
+#define RES_ASPEC_4x3 0
+#define RES_ASPEC_16x9 1
+#define F_MODE_REPT_NO 0
+#define F_MODE_REPT_TWICE 1
+#define F_MODE_REPT_QUATRO 3
+#define F_MODE_CSC_ITU601 0
+#define F_MODE_CSC_ITU709 1
+
+void InitHDMITX_Variable(void);
+void HDMITX_ChangeDisplayOption(HDMI_Video_Type VideoMode, HDMI_OutputColorMode OutputColorMode);
+void HDMITX_SetOutput(void);
+void HDMITX_DevLoopProc(void);
+void ConfigfHdmiVendorSpecificInfoFrame(unsigned char _3D_Stru);
+void HDMITX_ChangeAudioOption(unsigned char Option, unsigned char channelNum, unsigned char AudioFs);
+void HDMITX_SetAudioOutput(void);
+void HDMITX_ChangeColorDepth(unsigned char colorDepth);
+void HDMITX_ChangeDisplayOption(HDMI_Video_Type VideoMode, HDMI_OutputColorMode OutputColorMode);
+
+
+enum _HDMI_PLUG_STATE {
+	HDMI_PLUG_NO_DEVICE,
+	HDMI_PLUG_ACTIVE
+};
+#define HDMI_PLUG_STATE enum _HDMI_PLUG_STATE
+extern unsigned char HPDStatus;
+extern unsigned int sink_support_resolution;
+extern struct HDMI_UTIL_FUNCS hdmi_util;
+extern void ite66121_AppGetEdidInfo(struct _HDMI_EDID_T *pv_get_info);
+extern void hdmi_invoke_cable_callbacks(enum HDMI_STATE state);
+#endif				/* _HDMITX_SYS_H_ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/inc/hdmi_drv.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/inc/hdmi_drv.h
new file mode 100644
index 0000000..97532dc
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/inc/hdmi_drv.h
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+
+#ifndef __HDMI_DRV_H__
+#define __HDMI_DRV_H__
+#ifndef CONFIG_MTK_INTERNAL_HDMI_SUPPORT
+#endif
+#ifdef HDMI_MT8193_SUPPORT
+#include "mt8193hdmictrl.h"
+#include "mt8193edid.h"
+#include "mt8193cec.h"
+#endif
+
+#define AVD_TMR_ISR_TICKS   10
+#define MDI_BOUCING_TIMING  50	/* 20 //20ms */
+
+#ifdef CONFIG_MTK_INTERNAL_HDMI_SUPPORT
+#include "hdmicec.h"
+#endif
+
+#ifdef HDMI_ITE66121_SUPPORT
+#endif
+
+enum HDMI_TASK_COMMAND_TYPE_T {
+	HDMI_CEC_CMD = 0,
+	HDMI_PLUG_DETECT_CMD,
+	HDMI_HDCP_PROTOCAL_CMD,
+	HDMI_DISABLE_HDMI_TASK_CMD,
+	MAX_HDMI_TMR_NUMBER
+};
+
+#ifndef ARY_SIZE
+#define ARY_SIZE(x) (sizeof((x)) / sizeof((x[0])))
+#endif
+
+enum HDMI_POLARITY {
+	HDMI_POLARITY_RISING = 0,
+	HDMI_POLARITY_FALLING = 1
+};
+
+enum HDMI_CLOCK_PHASE {
+	HDMI_CLOCK_PHASE_0 = 0,
+	HDMI_CLOCK_PHASE_90 = 1
+};
+
+enum HDMI_COLOR_ORDER {
+	HDMI_COLOR_ORDER_RGB = 0,
+	HDMI_COLOR_ORDER_BGR = 1
+};
+
+enum IO_DRIVING_CURRENT {
+	IO_DRIVING_CURRENT_8MA = (1 << 0),
+	IO_DRIVING_CURRENT_4MA = (1 << 1),
+	IO_DRIVING_CURRENT_2MA = (1 << 2),
+	IO_DRIVING_CURRENT_SLEW_CNTL = (1 << 3),
+};
+
+struct HDMI_EDID_INFO_T {
+	unsigned int ui4_ntsc_resolution;	/* use EDID_VIDEO_RES_T, there are many resolution */
+	unsigned int ui4_pal_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned int ui4_sink_native_ntsc_resolution;
+	unsigned int ui4_sink_native_pal_resolution;
+	unsigned int ui4_sink_cea_ntsc_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned int ui4_sink_cea_pal_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned int ui4_sink_dtd_ntsc_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned int ui4_sink_dtd_pal_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned int ui4_sink_1st_dtd_ntsc_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned int ui4_sink_1st_dtd_pal_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned short ui2_sink_colorimetry;	/* use EDID_VIDEO_COLORIMETRY_T */
+	unsigned char ui1_sink_rgb_color_bit;	/* color bit for RGB */
+	unsigned char ui1_sink_ycbcr_color_bit;	/* color bit for YCbCr */
+	unsigned short ui2_sink_aud_dec;	/* use EDID_AUDIO_DECODER_T */
+	unsigned char ui1_sink_is_plug_in;	/* 1: Plug in 0:Plug Out */
+	unsigned int ui4_hdmi_pcm_ch_type;	/* use EDID_A_FMT_CH_TYPE */
+	unsigned int ui4_hdmi_pcm_ch3ch4ch5ch7_type;	/* use EDID_A_FMT_CH_TYPE1 */
+	unsigned int ui4_dac_pcm_ch_type;	/* use EDID_A_FMT_CH_TYPE */
+	unsigned char ui1_sink_i_latency_present;
+	unsigned char ui1_sink_p_audio_latency;
+	unsigned char ui1_sink_p_video_latency;
+	unsigned char ui1_sink_i_audio_latency;
+	unsigned char ui1_sink_i_video_latency;
+	unsigned char ui1ExtEdid_Revision;
+	unsigned char ui1Edid_Version;
+	unsigned char ui1Edid_Revision;
+	unsigned char ui1_Display_Horizontal_Size;
+	unsigned char ui1_Display_Vertical_Size;
+	unsigned int ui4_ID_Serial_Number;
+	unsigned int ui4_sink_cea_3D_resolution;
+	unsigned char ui1_sink_support_ai;	/* 0: not support AI, 1:support AI */
+	unsigned short ui2_sink_cec_address;
+	unsigned short ui1_sink_max_tmds_clock;
+	unsigned short ui2_sink_3D_structure;
+	unsigned int ui4_sink_cea_FP_SUP_3D_resolution;
+	unsigned int ui4_sink_cea_TOB_SUP_3D_resolution;
+	unsigned int ui4_sink_cea_SBS_SUP_3D_resolution;
+	unsigned short ui2_sink_ID_manufacturer_name;	/* (08H~09H) */
+	unsigned short ui2_sink_ID_product_code;	/* (0aH~0bH) */
+	unsigned int ui4_sink_ID_serial_number;	/* (0cH~0fH) */
+	unsigned char ui1_sink_week_of_manufacture;	/* (10H) */
+	unsigned char ui1_sink_year_of_manufacture;	/* (11H)  base on year 1990 */
+};
+
+#ifdef CONFIG_MTK_INTERNAL_HDMI_SUPPORT
+enum HDMI_VIDEO_RESOLUTION {
+	HDMI_VIDEO_720x480i_60Hz = 0,/* 0 */
+	HDMI_VIDEO_720x576i_50Hz,	/* 1 */
+	HDMI_VIDEO_720x480p_60Hz,	/* 2 */
+	HDMI_VIDEO_720x576p_50Hz,	/* 3 */
+	HDMI_VIDEO_1280x720p_60Hz,	/* 4 */
+	HDMI_VIDEO_1280x720p_50Hz,	/* 5 */
+	HDMI_VIDEO_1920x1080i_60Hz,	/* 6 */
+	HDMI_VIDEO_1920x1080i_50Hz,	/* 7 */
+	HDMI_VIDEO_1920x1080p_30Hz,	/* 8 */
+	HDMI_VIDEO_1920x1080p_25Hz,	/* 9 */
+	HDMI_VIDEO_1920x1080p_24Hz,	/* 10 */
+	HDMI_VIDEO_1920x1080p_23Hz,	/* 11 */
+	HDMI_VIDEO_1920x1080p_29Hz,	/* 12 */
+	HDMI_VIDEO_1920x1080p_60Hz,	/* 13 */
+	HDMI_VIDEO_1920x1080p_50Hz,	/* 14 */
+
+	HDMI_VIDEO_1280x720p3d_60Hz,	/* 15 */
+	HDMI_VIDEO_1280x720p3d_50Hz,	/* 16 */
+	HDMI_VIDEO_1920x1080i3d_60Hz,	/* 17 */
+	HDMI_VIDEO_1920x1080i3d_50Hz,	/* 18 */
+	HDMI_VIDEO_1920x1080p3d_24Hz,	/* 19 */
+	HDMI_VIDEO_1920x1080p3d_23Hz,	/* 20 */
+
+	/*the 2160 mean 3840x2160 */
+	HDMI_VIDEO_2160P_23_976HZ,	/* 21 */
+	HDMI_VIDEO_2160P_24HZ,	/* 22 */
+	HDMI_VIDEO_2160P_25HZ,	/* 23 */
+	HDMI_VIDEO_2160P_29_97HZ,	/* 24 */
+	HDMI_VIDEO_2160P_30HZ,	/* 25 */
+	/*the 2161 mean 4096x2160 */
+	HDMI_VIDEO_2161P_24HZ,	/* 26 */
+	HDMI_VIDEO_2160p_DSC_30Hz,/* 27 */
+	HDMI_VIDEO_2160p_DSC_24Hz,/* 28 */
+
+	RESOLUTION_3840X2160P_60HZ, /* 29 */
+	RESOLUTION_3840X2160P_50HZ, /* 30 */
+	RESOLUTION_4096X2161P_60HZ, /* 31 */
+	RESOLUTION_4096X2161P_50HZ, /* 32 */
+
+	HDMI_VIDEO_RESOLUTION_NUM
+};
+#else
+#if !defined(HDMI_MT8193_SUPPORT)
+enum HDMI_VIDEO_RESOLUTION {
+	HDMI_VIDEO_720x480p_60Hz = 0,
+	HDMI_VIDEO_1440x480i_60Hz = 1,
+	HDMI_VIDEO_1280x720p_60Hz = 2,
+	HDMI_VIDEO_1920x1080i_60Hz = 5,
+	HDMI_VIDEO_1920x1080p_30Hz = 6,
+	HDMI_VIDEO_720x480i_60Hz = 0xD,
+	HDMI_VIDEO_1920x1080p_60Hz = 0x0b,
+	HDMI_VIDEO_2160p_DSC_30Hz = 0x13,
+	HDMI_VIDEO_2160p_DSC_24Hz = 0x14,
+	HDMI_VIDEO_RESOLUTION_NUM
+};
+#endif
+#endif
+enum TEST_CASE_TYPE {
+	Test_RGB888 = 0, Test_YUV422 = 1, Test_YUV444 = 2, Test_Reserved = 3
+};
+
+enum HDMI_VIDEO_INPUT_FORMAT {
+	HDMI_VIN_FORMAT_RGB565,
+	HDMI_VIN_FORMAT_RGB666,
+	HDMI_VIN_FORMAT_RGB888,
+};
+
+enum HDMI_VIDEO_OUTPUT_FORMAT {
+	HDMI_VOUT_FORMAT_RGB888,
+	HDMI_VOUT_FORMAT_YUV422,
+	HDMI_VOUT_FORMAT_YUV444,
+
+	HDMI_VOUT_FORMAT_2D     = 1<<16,
+	HDMI_VOUT_FORMAT_3D_SBS = 1<<17,
+	HDMI_VOUT_FORMAT_3D_TAB = 1<<18,
+};
+
+/* Must align to MHL Tx chip driver define */
+enum HDMI_AUDIO_FORMAT {
+	HDMI_AUDIO_32K_2CH		= 0x01,
+	HDMI_AUDIO_44K_2CH		= 0x02,
+	HDMI_AUDIO_48K_2CH		= 0x03,
+	HDMI_AUDIO_96K_2CH		= 0x05,
+	HDMI_AUDIO_192K_2CH	    = 0x07,
+	HDMI_AUDIO_32K_8CH		= 0x81,
+	HDMI_AUDIO_44K_8CH		= 0x82,
+	HDMI_AUDIO_48K_8CH		= 0x83,
+	HDMI_AUDIO_96K_8CH		= 0x85,
+	HDMI_AUDIO_192K_8CH	    = 0x87,
+	HDMI_AUDIO_INITIAL		= 0xFF
+};
+
+enum HDMI_AUDIO_PCM_FORMAT {
+	HDMI_AUDIO_PCM_16bit_48000,
+	HDMI_AUDIO_PCM_16bit_44100,
+	HDMI_AUDIO_PCM_16bit_32000,
+	HDMI_AUDIO_SOURCE_STREAM,
+};
+
+struct HDMI_CONFIG {
+	enum HDMI_VIDEO_RESOLUTION vformat;
+	enum HDMI_VIDEO_INPUT_FORMAT vin;
+	enum HDMI_VIDEO_OUTPUT_FORMAT vout;
+	enum HDMI_AUDIO_FORMAT aformat;
+};
+
+enum HDMI_OUTPUT_MODE {
+	HDMI_OUTPUT_MODE_LCD_MIRROR,
+	HDMI_OUTPUT_MODE_VIDEO_MODE,
+	HDMI_OUTPUT_MODE_DPI_BYPASS
+};
+
+enum HDMI_CABLE_TYPE {
+	HDMI_CABLE,
+	MHL_CABLE,
+	MHL_SMB_CABLE,
+	MHL_2_CABLE,		/* /MHL 2.0 */
+	MHL_3D_GLASSES,
+	SLIMPORT_CABLE
+};
+
+enum HDMI_3D_FORMAT_ENUM {
+	HDMI_2D,
+	HDMI_3D_SBS,
+	HDMI_3D_TAB,
+	HDMI_3D_FP
+};
+
+struct HDMI_PARAMS {
+	unsigned int width;
+	unsigned int height;
+
+	struct HDMI_CONFIG init_config;
+
+	/* polarity parameters */
+	enum HDMI_POLARITY clk_pol;
+	enum HDMI_POLARITY de_pol;
+	enum HDMI_POLARITY vsync_pol;
+	enum HDMI_POLARITY hsync_pol;
+
+	/* timing parameters */
+	unsigned int hsync_pulse_width;
+	unsigned int hsync_back_porch;
+	unsigned int hsync_front_porch;
+	unsigned int vsync_pulse_width;
+	unsigned int vsync_back_porch;
+	unsigned int vsync_front_porch;
+
+	/* output format parameters */
+	enum HDMI_COLOR_ORDER rgb_order;
+
+	/* intermediate buffers parameters */
+	unsigned int intermediat_buffer_num;	/* 2..3 */
+
+	/* iopad parameters */
+	enum IO_DRIVING_CURRENT io_driving_current;
+	enum HDMI_OUTPUT_MODE output_mode;
+
+	int is_force_awake;
+	int is_force_landscape;
+
+	unsigned int scaling_factor;	/* determine the scaling of output screen size, valid value 0~10 */
+	/* 0 means no scaling, 5 means scaling to 95%, 10 means 90% */
+
+	bool NeedSwHDCP;
+	enum HDMI_CABLE_TYPE cabletype;
+	unsigned int HDCPSupported;
+	int is_3d_support;
+	unsigned int input_clock;
+#ifndef CONFIG_MTK_INTERNAL_HDMI_SUPPORT
+#endif
+};
+
+enum HDMI_STATE {
+	HDMI_STATE_NO_DEVICE,
+	HDMI_STATE_ACTIVE,
+	HDMI_STATE_CONNECTING,
+	HDMI_STATE_PLUGIN_ONLY,
+	HDMI_STATE_EDID_UPDATE,
+	HDMI_STATE_CEC_UPDATE,
+	HDMI_STATE_NO_DEVICE_IN_BOOT,
+	HDMI_STATE_ACTIVE_IN_BOOT,
+
+};
+
+enum HDMI_CEC_STATE {
+	HDMI_CEC_STATE_PLUG_OUT = 0,
+	HDMI_CEC_STATE_GET_PA,
+	HDMI_CEC_STATE_TX_STS,
+	HDMI_CEC_STATE_GET_CMD
+};
+
+enum HDMI_DEEP_COLOR_T {
+	HDMI_DEEP_COLOR_AUTO = 0,
+	HDMI_NO_DEEP_COLOR,
+	HDMI_DEEP_COLOR_10_BIT,
+	HDMI_DEEP_COLOR_12_BIT,
+	HDMI_DEEP_COLOR_16_BIT
+};
+
+enum HDMI_OUT_COLOR_SPACE_T {
+	HDMI_RGB = 0,
+	HDMI_RGB_FULL,
+	HDMI_YCBCR_444,
+	HDMI_YCBCR_422,
+	HDMI_XV_YCC,
+	HDMI_YCBCR_444_FULL,
+	HDMI_YCBCR_422_FULL
+};
+
+enum HDMI_AUDIO_SAMPLING_T {
+	HDMI_FS_32K = 0,
+	HDMI_FS_44K,
+	HDMI_FS_48K,
+	HDMI_FS_88K,
+	HDMI_FS_96K,
+	HDMI_FS_176K,
+	HDMI_FS_192K
+};
+
+struct HDMI_AUDIO_DEC_OUTPUT_CHANNEL_T {
+	unsigned short FL:1;	/* bit0 */
+	unsigned short FR:1;	/* bit1 */
+	unsigned short LFE:1;	/* bit2 */
+	unsigned short FC:1;	/* bit3 */
+	unsigned short RL:1;	/* bit4 */
+	unsigned short RR:1;	/* bit5 */
+	unsigned short RC:1;	/* bit6 */
+	unsigned short FLC:1;	/* bit7 */
+	unsigned short FRC:1;	/* bit8 */
+	unsigned short RRC:1;	/* bit9 */
+	unsigned short RLC:1;	/* bit10 */
+
+};
+
+enum HDMI_AUDIO_INPUT_TYPE_T {
+	SV_I2S = 0,
+	SV_SPDIF
+};
+
+enum HDMI_AUDIO_I2S_FMT_T {
+	HDMI_RJT_24BIT = 0,
+	HDMI_RJT_16BIT,
+	HDMI_LJT_24BIT,
+	HDMI_LJT_16BIT,
+	HDMI_I2S_24BIT,
+	HDMI_I2S_16BIT
+};
+
+enum SAMPLE_FREQUENCY_T {
+	MCLK_128FS,
+	MCLK_192FS,
+	MCLK_256FS,
+	MCLK_384FS,
+	MCLK_512FS,
+	MCLK_768FS,
+	MCLK_1152FS,
+};
+
+enum IEC_FRAME_RATE_T {
+	IEC_48K = 0,
+	IEC_96K,
+	IEC_192K,
+	IEC_768K,
+	IEC_44K,
+	IEC_88K,
+	IEC_176K,
+	IEC_705K,
+	IEC_16K,
+	IEC_22K,
+	IEC_24K,
+	IEC_32K,
+};
+
+
+union AUDIO_DEC_OUTPUT_CHANNEL_UNION_T {
+	struct HDMI_AUDIO_DEC_OUTPUT_CHANNEL_T bit;	/* HDMI_AUDIO_DEC_OUTPUT_CHANNEL_T */
+	unsigned short word;
+
+};
+
+struct HDMI_AV_INFO_T {
+	enum HDMI_VIDEO_RESOLUTION e_resolution;
+	unsigned char fgHdmiOutEnable;
+	unsigned char u2VerFreq;
+	unsigned char b_hotplug_state;
+	enum HDMI_OUT_COLOR_SPACE_T e_video_color_space;
+	enum HDMI_DEEP_COLOR_T e_deep_color_bit;
+	unsigned char ui1_aud_out_ch_number;
+	enum HDMI_AUDIO_SAMPLING_T e_hdmi_fs;
+	unsigned char bhdmiRChstatus[6];
+	unsigned char bhdmiLChstatus[6];
+	unsigned char bMuteHdmiAudio;
+	unsigned char u1HdmiI2sMclk;
+	unsigned char u1hdcponoff;
+	unsigned char u1audiosoft;
+	unsigned char fgHdmiTmdsEnable;
+	union AUDIO_DEC_OUTPUT_CHANNEL_UNION_T ui2_aud_out_ch;
+
+	unsigned char e_hdmi_aud_in;
+	unsigned char e_iec_frame;
+	unsigned char e_aud_code;
+	unsigned char u1Aud_Input_Chan_Cnt;
+	unsigned char e_I2sFmt;
+};
+
+
+/* --------------------------------------------------------------------------- */
+
+struct HDMI_UTIL_FUNCS {
+	void (*set_reset_pin)(unsigned int value);
+	int (*set_gpio_out)(unsigned int gpio, unsigned int value);
+	void (*udelay)(unsigned int us);
+	void (*mdelay)(unsigned int ms);
+	void (*wait_transfer_done)(void);
+	void (*state_callback)(enum HDMI_STATE state);
+	void (*cec_state_callback)(enum HDMI_CEC_STATE state);
+};
+
+#define SINK_480P      (1 << 0)
+#define SINK_720P60    (1 << 1)
+#define SINK_1080I60   (1 << 2)
+#define SINK_1080P60   (1 << 3)
+#define SINK_480P_1440 (1 << 4)
+#define SINK_480P_2880 (1 << 5)
+#define SINK_480I      (1 << 6)
+#define SINK_480I_1440 (1 << 7)
+#define SINK_480I_2880 (1 << 8)
+#define SINK_1080P30   (1 << 9)
+#define SINK_576P      (1 << 10)
+#define SINK_720P50    (1 << 11)
+#define SINK_1080I50   (1 << 12)
+#define SINK_1080P50   (1 << 13)
+#define SINK_576P_1440 (1 << 14)
+#define SINK_576P_2880 (1 << 15)
+#define SINK_576I      (1 << 16)
+#define SINK_576I_1440 (1 << 17)
+#define SINK_576I_2880 (1 << 18)
+#define SINK_1080P25   (1 << 19)
+#define SINK_1080P24   (1 << 20)
+#define SINK_1080P23976  (1 << 21)
+#define SINK_1080P2997   (1 << 22)
+#define SINK_2160p30   (1 << 23)
+#define SINK_2160p24   (1 << 24)
+
+struct _HDMI_EDID_T {
+	unsigned int ui4_ntsc_resolution;	/* use EDID_VIDEO_RES_T, there are many resolution */
+	unsigned int ui4_pal_resolution;	/* use EDID_VIDEO_RES_T */
+	/* use EDID_VIDEO_RES_T, only one NTSC resolution, Zero means none native NTSC resolution is available */
+	unsigned int ui4_sink_native_ntsc_resolution;
+	/* use EDID_VIDEO_RES_T, only one resolution, Zero means none native PAL resolution is available */
+	unsigned int ui4_sink_native_pal_resolution;
+	unsigned int ui4_sink_cea_ntsc_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned int ui4_sink_cea_pal_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned int ui4_sink_dtd_ntsc_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned int ui4_sink_dtd_pal_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned int ui4_sink_1st_dtd_ntsc_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned int ui4_sink_1st_dtd_pal_resolution;	/* use EDID_VIDEO_RES_T */
+	unsigned short ui2_sink_colorimetry;	/* use EDID_VIDEO_COLORIMETRY_T */
+	unsigned char ui1_sink_rgb_color_bit;	/* color bit for RGB */
+	unsigned char ui1_sink_ycbcr_color_bit;	/* color bit for YCbCr */
+	unsigned short ui2_sink_aud_dec;	/* use EDID_AUDIO_DECODER_T */
+	unsigned char ui1_sink_is_plug_in;	/* 1: Plug in 0:Plug Out */
+	unsigned int ui4_hdmi_pcm_ch_type;	/* use EDID_A_FMT_CH_TYPE */
+	unsigned int ui4_hdmi_pcm_ch3ch4ch5ch7_type;	/* use EDID_A_FMT_CH_TYPE1 */
+	unsigned int ui4_dac_pcm_ch_type;	/* use EDID_A_FMT_CH_TYPE */
+	unsigned char ui1_sink_i_latency_present;
+	unsigned char ui1_sink_p_audio_latency;
+	unsigned char ui1_sink_p_video_latency;
+	unsigned char ui1_sink_i_audio_latency;
+	unsigned char ui1_sink_i_video_latency;
+	unsigned char ui1ExtEdid_Revision;
+	unsigned char ui1Edid_Version;
+	unsigned char ui1Edid_Revision;
+	unsigned char ui1_Display_Horizontal_Size;
+	unsigned char ui1_Display_Vertical_Size;
+	unsigned int ui4_ID_Serial_Number;
+	unsigned int ui4_sink_cea_3D_resolution;
+	unsigned char ui1_sink_support_ai;	/* 0: not support AI, 1:support AI */
+	unsigned short ui2_sink_cec_address;
+	unsigned short ui1_sink_max_tmds_clock;
+	unsigned short ui2_sink_3D_structure;
+	unsigned int ui4_sink_cea_FP_SUP_3D_resolution;
+	unsigned int ui4_sink_cea_TOB_SUP_3D_resolution;
+	unsigned int ui4_sink_cea_SBS_SUP_3D_resolution;
+	unsigned short ui2_sink_ID_manufacturer_name;	/* (08H~09H) */
+	unsigned short ui2_sink_ID_product_code;	/* (0aH~0bH) */
+	unsigned int ui4_sink_ID_serial_number;	/* (0cH~0fH) */
+	unsigned char ui1_sink_week_of_manufacture;	/* (10H) */
+	unsigned char ui1_sink_year_of_manufacture;	/* (11H)  base on year 1990 */
+};
+
+typedef void (*CABLE_INSERT_CALLBACK)(enum HDMI_STATE state);
+
+struct HDMI_DRIVER {
+	void (*set_util_funcs)(const struct HDMI_UTIL_FUNCS *util);
+	void (*get_params)(struct HDMI_PARAMS *params);
+	int (*init)(void);
+	int (*enter)(void);
+	int (*exit)(void);
+	void (*suspend)(void);
+	void (*resume)(void);
+	int (*video_config)(enum HDMI_VIDEO_RESOLUTION vformat, enum HDMI_VIDEO_INPUT_FORMAT vin,
+			     int vou);
+	int  (*audio_config)(enum HDMI_AUDIO_FORMAT aformat, int bitWidth);
+	int (*video_enable)(bool enable);
+	int (*audio_enable)(bool enable);
+	int (*irq_enable)(bool enable);
+	int (*power_on)(void);
+	void (*power_off)(void);
+	enum HDMI_STATE (*get_state)(void);
+	void (*set_mode)(unsigned char ucMode);
+	void (*dump)(void);
+	int (*get_external_device_capablity)(void);
+	void (*force_on)(int from_uart_drv);
+	void (*register_callback)(CABLE_INSERT_CALLBACK cb);
+	void (*unregister_callback)(CABLE_INSERT_CALLBACK cb);
+#if !defined(CONFIG_MTK_INTERNAL_HDMI_SUPPORT)
+	void (*read)(unsigned char u8Reg);
+	void (*write)(unsigned char u8Reg, unsigned char u8Data);
+	void (*log_enable)(bool enable);
+#ifdef HDMI_ITE66121_SUPPORT
+	void (*getedid)(struct _HDMI_EDID_T *pv_get_info);
+#else
+	void (*getedid)(void *pv_get_info);
+#endif
+#else
+	void (*read)(unsigned long u2Reg, unsigned int *p4Data);
+	void (*write)(unsigned long u2Reg, unsigned int u4Data);
+	void (*log_enable)(u16 enable);
+	void (*InfoframeSetting)(u8 i1typemode, u8 i1typeselect);
+	void (*checkedid)(u8 i1noedid);
+	void (*colordeep)(u8 u1colorspace, u8 u1deepcolor);
+	void (*enablehdcp)(u8 u1hdcponoff);
+	void (*setcecrxmode)(u8 u1cecrxmode);
+	void (*hdmistatus)(void);
+	void (*hdcpkey)(u8 *pbhdcpkey);
+	void (*getedid)(struct _HDMI_EDID_T *pv_get_info);
+	void (*setcecla)(struct CEC_DRV_ADDR_CFG_T *prAddr);
+	void (*sendsltdata)(u8 *pu1Data);
+	void (*getceccmd)(struct CEC_FRAME_DESCRIPTION_IO *frame);
+	void (*getsltdata)(struct CEC_SLT_DATA *rCecSltData);
+	void (*setceccmd)(struct CEC_SEND_MSG_T *msg);
+	void (*cecenable)(u8 u1EnCec);
+	void (*getcecaddr)(struct CEC_ADDRESS_IO *cecaddr);
+	 u8 (*checkedidheader)(void);
+	int (*audiosetting)(struct HDMITX_AUDIO_PARA *audio_para);
+	int (*tmdsonoff)(unsigned char u1ionoff);
+	void (*mutehdmi)(unsigned char u1flagvideomute, unsigned char u1flagaudiomute);
+	void (*svpmutehdmi)(unsigned char u1svpvideomute, unsigned char u1svpaudiomute);
+	void (*cecusrcmd)(unsigned int cmd, unsigned int *result);
+	void (*getcectxstatus)(struct CEC_ACK_INFO_T *pt);
+	unsigned int (*gethdmistatus)(void);
+	void (*resolution_setting)(int res);
+#endif
+
+};
+/* --------------------------------------------------------------------------- */
+/* HDMI Driver Functions */
+/* --------------------------------------------------------------------------- */
+#ifdef HDMI_ITE66121_SUPPORT
+int it66121_i2c_read_byte(u8 addr, u8 *data);
+int it66121_i2c_write_byte(u8 addr, u8 data);
+int it66121_i2c_read_block(u8 addr, u8 *data, int len);
+int it66121_i2c_write_block(u8 addr, u8 *data, int len);
+int ite66121_pmic_power_on(void);
+int ite66121_pmic_power_off(void);
+#endif
+
+int it66121_power_on(void);
+void it66121_power_down(void);
+int it66121_video_config(enum HDMI_VIDEO_RESOLUTION vformat, enum HDMI_VIDEO_INPUT_FORMAT vin,
+				int vout);
+void it6621_main();
+
+extern unsigned int dst_is_dsi;
+extern struct semaphore hdmi_update_mutex;
+const struct HDMI_DRIVER *HDMI_GetDriver(void);
+void Notify_AP_MHL_TX_Event(unsigned int event, unsigned int event_param, void *param);
+extern int	chip_device_id;
+extern bool need_reset_usb_switch;
+#endif				/* __HDMI_DRV_H__ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/inc/hdmicec.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/inc/hdmicec.h
new file mode 100644
index 0000000..777424c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/inc/hdmicec.h
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+
+
+#ifndef __hdmicec_h__
+#define __hdmicec_h__
+#include "extd_hdmi.h"
+
+enum HDMI_CEC_RX_MODE {
+	CEC_NORMAL_MODE = 0,
+	CEC_CTS_MODE,
+	CEC_SLT_MODE
+};
+
+enum CEC_TX_FAIL {
+	FAIL_NONE = 0x00,
+	FAIL_DIR = 0x01,
+	FAIL_MODE = 0x02,
+	FAIL_ID = 0x04,
+	FAIL_SOURCE = 0x08,
+	FAIL_HEADER = 0x10,
+	FAIL_CMD = 0x20,
+	FAIL_DATA = 0x40,
+	FAIL_MAX = 0x80
+};
+
+enum CEC_SW_STATE {
+	STATE_WAIT_TX_DATA_TAKEN = 0x0001,
+	STATE_TX_NOACK = 0x0002,	/* CYJ.NOTE */
+	STATE_TXING_FRAME = 0x0004,
+	STATE_TX_FRAME_SUCCESS = 0x0008,
+	STATE_HW_RETX = 0x0010,
+
+	STATE_WAIT_RX_FRAME_COMPLETE = 0x0100,
+	STATE_RX_COMPLETE_NEW_FRAME = 0x0200,
+	STATE_HW_RX_OVERFLOW = 0x0400,
+	STATE_RX_GET_NEW_HEADER = 0x0800
+};
+
+enum CEC_ERR_STATUS {
+	ERR_TX_BUFFER_LOW = 0x0001,
+	ERR_TX_UNDERRUN = 0x0002,
+	ERR_TX_MISALARM = 0x0004,
+	ERR_RX_LOST_EOM = 0x0100,
+	ERR_RXQ_OVERFLOW = 0x0200,
+	ERR_RX_LOST_HEADER = 0x0400
+};
+
+enum CEC_OPCODE {
+	OPCODE_FEATURE_ABORT = 0x00,	/* 4 */
+	OPCODE_IMAGE_VIEW_ON = 0x04,	/* 2 */
+	OPCODE_TUNER_STEP_INCREMENT = 0x05,	/* 2 */
+	OPCODE_TUNER_STEP_DECREMENT = 0x06,	/* 2 */
+	OPCODE_TUNER_DEVICE_STATUS = 0x07,	/* 7 or 10 */
+	OPCODE_GIVE_TUNER_DEVICE_STATUS = 0x08,	/* 3 */
+	OPCODE_RECORD_ON = 0x09,	/* 3~10 */
+	OPCODE_RECORD_STATUS = 0x0A,	/* 3 */
+	OPCODE_RECORD_OFF = 0x0B,	/* 2 */
+	OPCODE_TEXT_VIEW_ON = 0x0D,	/* 2 */
+	OPCODE_RECORD_TV_SCREEN = 0x0F,	/* 2 */
+	OPCODE_GIVE_DECK_STATUS = 0x1A,	/* 3 */
+	OPCODE_DECK_STATUS = 0x1B,	/* 3 */
+	OPCODE_SET_MENU_LANGUAGE = 0x32,	/* 5 */
+	OPCODE_CLEAR_ANALOGUE_TIMER = 0x33,	/* 13 */
+	OPCODE_SET_ANALOGUE_TIMER = 0x34,	/* 13 */
+	OPCODE_TIMER_STATUS = 0x35,	/* 3 or 5 */
+	OPCODE_STANDBY = 0x36,	/* 2 */
+	OPCODE_PLAY = 0x41,	/* 3 */
+	OPCODE_DECK_CONTROL = 0x42,	/* 3 */
+	OPCODE_TIMER_CLEARED_STATUS = 0x43,	/* 3 */
+	OPCODE_USER_CONTROL_PRESSED = 0x44,	/* 3 */
+	OPCODE_USER_CONTROL_RELEASED = 0x45,	/* 2 */
+	OPCODE_GIVE_OSD_NAME = 0x46,	/* 2 */
+	OPCODE_SET_OSD_NAME = 0x47,	/* 3~16 */
+	OPCODE_SET_OSD_STRING = 0x64,	/* 4~16 */
+	OPCODE_SET_TIMER_PROGRAM_TITLE = 0x67,	/* 3~16 */
+	OPCODE_SYSTEM_AUDIO_MODE_REQUEST = 0x70,	/* 4 */
+	OPCODE_GIVE_AUDIO_STATUS = 0x71,	/* 2 */
+	OPCODE_SET_SYSTEM_AUDIO_MODE = 0x72,	/* 3 */
+	OPCODE_REPORT_AUDIO_STATUS = 0x7A,	/* 3 */
+	OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D,	/* 2 */
+	OPCODE_SYSTEM_AUDIO_MODE_STATUS = 0x7E,	/* 3 */
+	OPCODE_ROUTING_CHANGE = 0x80,	/* 6 */
+	OPCODE_ROUTING_INFORMATION = 0x81,	/* 4 */
+	OPCODE_ACTIVE_SOURCE = 0x82,	/* 4 */
+	OPCODE_GIVE_PHYSICAL_ADDRESS = 0x83,	/* 2 */
+	OPCODE_REPORT_PHYSICAL_ADDRESS = 0x84,	/* 5 */
+	OPCODE_REQUEST_ACTIVE_SOURCE = 0x85,	/* 2 */
+	OPCODE_SET_STREAM_PATH = 0x86,	/* 4 */
+	OPCODE_DEVICE_VENDOR_ID = 0x87,	/* 5 */
+	OPCODE_VENDOR_COMMAND = 0x89,	/* <= 16 */
+	OPCODE_VENDOR_REMOTE_BUTTON_DOWN = 0x8A,	/* <= 16 */
+	OPCODE_VENDOR_REMOTE_BUTTON_UP = 0x8B,	/* 2 */
+	OPCODE_GIVE_DEVICE_VENDOR_ID = 0x8C,	/* 2 */
+	OPCODE_MENU_REQUEST = 0x8D,	/* 3 */
+	OPCODE_MENU_STATUS = 0x8E,	/* 3 */
+	OPCODE_GIVE_DEVICE_POWER_STATUS = 0x8F,	/* 2 */
+	OPCODE_REPORT_POWER_STATUS = 0x90,	/* 3 */
+	OPCODE_GET_MENU_LANGUAGE = 0x91,	/* 2 */
+	OPCODE_SELECT_ANALOGUE_SERVICE = 0x92,	/* 6 */
+	OPCODE_SELECT_DIGITAL_SERVICE = 0x93,	/* 9 */
+	OPCODE_SET_DIGITAL_TIMER = 0x97,	/* 16 */
+	OPCODE_CLEAR_DIGITAL_TIMER = 0x99,	/* 16 */
+	OPCODE_SET_AUDIO_RATE = 0x9A,	/* 3 */
+	OPCODE_INACTIVE_SOURCE = 0x9D,	/* 4 */
+	OPCODE_CEC_VERSION = 0x9E,	/* 3 */
+	OPCODE_GET_CEC_VERSION = 0x9F,	/* 2 */
+	OPCODE_VENDOR_COMMAND_WITH_ID = 0xA0,	/* <= 16 */
+	OPCODE_CLEAR_EXTERNAL_TIMER = 0xA1,	/* 10 ~ 11 */
+	OPCODE_SET_EXTERNAL_TIMER = 0xA2,	/* 10 ~ 11 */
+	OPCODE_ABORT = 0xFF,	/* 2 */
+	OPCODE_NONE = 0xFFF
+};
+
+#define RX_Q_SIZE 32
+#define TX_Q_SIZE 32
+#define RETX_MAX_CNT 2
+#define CEC_MAX_MESG_SIZE 16
+
+#define CEC_MAX_DEV_LA_NUM 3
+#define CEC_MAX_OPERAND_SIZE       14
+#define LOCAL_CEC_MAX_OPERAND_SIZE 14
+
+/* --------FLD help macros, mask32 to mask8,mask16,maskalign ----------*/
+	/* mask32 -> mask8 */
+#define MSKB0(msk)	(unsigned char)((msk)&0xff)
+#define MSKB1(msk)	(unsigned char)(((msk)>>8)&0xff)
+#define MSKB2(msk)	(unsigned char)(((msk)>>16)&0xff)
+#define MSKB3(msk)	(unsigned char)(((msk)>>24)&0xff)
+/* mask32 -> mask16 */
+#define MSKW0(msk)	(unsigned short)((msk)&0xffff)
+#define MSKW1(msk)	(unsigned short)(((msk)>>8)&0xffff)
+#define MSKW2(msk)	(unsigned short)(((msk)>>16)&0xffff)
+						/* mask32 -> maskalign */
+#define MSKAlignB(msk)	(((msk)&0xff)?(msk):(\
+			((msk)&0xff00)?((msk)>>8):(\
+			((msk)&0xff0000)?((msk)>>16):((msk)>>24)\
+		)\
+	))
+/* --------FLD help macros, mask32 to mask8,mask16,maskalign ----------*/
+/* lint -save -e504  lint -restore*/
+#define Fld2Msk32(fld)	((((unsigned int)1<<Fld_wid(fld))-1)<<Fld_shft(fld))
+#define Fld2MskB0(fld)	MSKB0(Fld2Msk32(fld))
+#define Fld2MskB1(fld)	MSKB1(Fld2Msk32(fld))
+#define Fld2MskB2(fld)	MSKB2(Fld2Msk32(fld))
+#define Fld2MskB3(fld)	MSKB3(Fld2Msk32(fld))
+#define Fld2MskBX(fld, byte)	((unsigned char)((Fld2Msk32(fld)>>((byte&3)*8))&0xff))
+
+#define Fld2MskW0(fld)	MSKW0(Fld2Msk32(fld))
+#define Fld2MskW1(fld)	MSKW1(Fld2Msk32(fld))
+#define Fld2MskW2(fld)	MSKW2(Fld2Msk32(fld))
+#define Fld2MskWX(fld, byte)	((unsigned short)((Fld2Msk32(fld)>>((byte&3)*8))&0xffff))
+
+
+#define Fld2MskAlignB(fld)  MSKAlignB(Fld2Msk32(fld))
+#define FldshftAlign(fld)	((Fld_shft(fld) < 8)?Fld_shft(fld):(\
+			(Fld_shft(fld) < 16)?(Fld_shft(fld)-8):(\
+			(Fld_shft(fld) < 24)?(Fld_shft(fld)-16):(Fld_shft(fld)-24)\
+		)\
+	))
+#define ValAlign2Fld(val, fld)	((val) << FldshftAlign(fld))
+
+
+/* access method*/
+#define	AC_FULLB0		1
+#define	AC_FULLB1		2
+#define	AC_FULLB2		3
+#define	AC_FULLB3		4
+#define	AC_FULLW10		5
+#define	AC_FULLW21		6
+#define	AC_FULLW32		7
+#define	AC_FULLDW		8
+#define	AC_MSKB0		11
+#define	AC_MSKB1		12
+#define	AC_MSKB2		13
+#define	AC_MSKB3		14
+#define	AC_MSKW10		15
+#define	AC_MSKW21		16
+#define	AC_MSKW32		17
+#define	AC_MSKDW		18
+
+
+#define Fld(wid, shft, ac)	(((unsigned long)(wid)<<16)|((shft)<<8)|(ac))
+#define Fld_wid(fld)	    (unsigned char)(((fld)>>16)&0xff)
+#define Fld_shft(fld)	    (unsigned char)(((fld)>>8)&0xff)
+#define Fld_ac(fld)	        (unsigned char)((fld)&0xff)
+
+
+#define TR_CONFIG 0x00
+#define BYPASS Fld(1, 28, AC_MSKB3)	/* 28 */
+#define TR_DEVICE_ADDR3 Fld(4, 24, AC_MSKB3)	/* 27:24 */
+#define TR_DEVICE_ADDR2 Fld(4, 20, AC_MSKB2)	/* 23:20 */
+#define DEVICE_ADDR Fld(4, 16, AC_MSKB2)	/* 19:16 */
+#define CLEAR_CEC_IRQ Fld(1, 15, AC_MSKB1)	/* 19:16 */
+#define TX_G_EN Fld(1, 13, AC_MSKB1)	/* 13 */
+#define TX_EN Fld(1, 12, AC_MSKB1)	/* 12 */
+#define RX_G_EN Fld(1, 9, AC_MSKB1)	/* 9 */
+#define RX_EN Fld(1, 8, AC_MSKB1)	/* 8 */
+#define CEC_ID_EN Fld(1, 1, AC_MSKB0)	/* 1 */
+#define CEC_EN Fld(1, 0, AC_MSKB0)	/* 0 */
+
+#define CEC_CKGEN 0x04
+
+#define CEC_32K_PDN Fld(1, 19, AC_MSKB2)	/* 16 */
+#define CEC_27M_PDN Fld(1, 18, AC_MSKB2)	/* 16 */
+#define CLK_SEL_DIV Fld(1, 17, AC_MSKB2)	/* 16 */
+
+#define PDN Fld(1, 16, AC_MSKB2)	/* 16 */
+#define DIV_SEL Fld(16, 0, AC_FULLW10)	/* 15:0 */
+
+#define RX_T_START_R 0x08
+
+#define RX_TIMER_START_R_MAX Fld(11, 16, AC_MSKW32)	/* 26:16 */
+#define RX_TIMER_START_R_MIN Fld(11, 0, AC_MSKW10)	/* 10:0 */
+#define RX_T_START_F 0x0c
+
+#define RX_TIMER_START_F_MAX Fld(11, 16, AC_MSKW32)	/* 26:16 */
+#define RX_TIMER_START_F_MIN Fld(11, 0, AC_MSKW10)	/* 10:0 */
+#define RX_T_DATA 0x10
+
+#define RX_TIMER_DATA_SAMPLE Fld(11, 16, AC_MSKW32)	/* 26:16 */
+#define RX_TIMER_DATA_F_MIN Fld(11, 0, AC_MSKW10)	/* 10:0 */
+#define RX_T_ACK 0x14
+
+#define RX_TIMER_ACK_R Fld(11, 0, AC_MSKW10)	/* 10:0 */
+#define RX_T_ERROR 0x18
+
+#define RX_TIMER_ERROR_D Fld(11, 16, AC_MSKW32)	/* 26:16 */
+#define RX_TIMER_ERROR_S Fld(11, 0, AC_MSKW10)	/* 10:0 */
+#define TX_T_START 0x1c
+
+#define TX_TIMER_START_F Fld(11, 16, AC_MSKW32)	/* 26:16 */
+#define TX_TIMER_START_R Fld(11, 0, AC_MSKW10)	/* 10:0 */
+#define TX_T_DATA_R 0x20
+
+#define TX_TIMER_BIT1_R Fld(11, 16, AC_MSKW32)	/* 26:16 */
+#define TX_TIMER_BIT0_R Fld(11, 0, AC_MSKW10)	/* 10:0 */
+#define TX_T_DATA_F 0x24
+
+#define TX_TIMER_DATA_N Fld(11, 16, AC_MSKW32)	/* 26:16 */
+#define TX_TIMER_DATA_F Fld(11, 0, AC_MSKW10)	/* 10:0 */
+#define TX_ARB 0x28
+
+#define MAX_RETRANSMIT Fld(4, 12, AC_MSKB1)	/* 15:12 */
+#define BCNT_RETRANSMIT_3_0 Fld(5, 7, AC_MSKW10)	/* 11:7 */
+#define BCNT_NEW_MSG Fld(4, 4, AC_MSKB0)	/* 7:4 */
+#define BCNT_NEW_INIT Fld(4, 0, AC_MSKB0)	/* 3:0 */
+#define RX_HEADER 0x40
+
+#define RXED_M3_DATA_MASK Fld(4, 24, AC_MSKB3)	/* 27:24 */
+#define RXED_SRC Fld(4, 20, AC_MSKB2)	/* 23:20 */
+#define RXED_DST Fld(4, 16, AC_MSKB2)	/* 19:16 */
+#define RXED_H_EOM Fld(1, 15, AC_MSKB1)	/* 15 */
+#define RXED_D_EOM Fld(1, 13, AC_MSKB1)	/* 13 */
+#define RXED_M3_ID Fld(3, 8, AC_MSKB1)	/* 10:8 */
+#define RXED_M1_DIR Fld(1, 7, AC_MSKB0)	/* 7 */
+#define RXED_M1_PAS Fld(1, 6, AC_MSKB0)	/* 6 */
+#define RXED_M1_NAS Fld(1, 5, AC_MSKB0)	/* 5 */
+#define RXED_M1_DES Fld(1, 4, AC_MSKB0)	/* 4 */
+#define RXED_MODE Fld(2, 0, AC_MSKB0)	/* 1:0 */
+#define RX_DATA 0x44
+
+#define RXED_DATA Fld(32, 0, AC_FULLDW)	/* 31:0 */
+#define RX_HD_NEXT 0x48
+
+#define RXING_M3_DATA_MASK Fld(4, 24, AC_MSKB3)	/* 27:24 */
+#define RXING_SRC Fld(4, 20, AC_MSKB2)	/* 23:20 */
+#define RXING_DST Fld(4, 16, AC_MSKB2)	/* 19:16 */
+#define RXING_H_EOM Fld(1, 15, AC_MSKB1)	/* 15 */
+#define RXING_H_ACK Fld(1, 14, AC_MSKB1)	/* 14 */
+#define RXING_D_EOM Fld(1, 13, AC_MSKB1)	/* 13 */
+#define RXING_D_ACK Fld(1, 12, AC_MSKB1)	/* 12 */
+#define RXING_M3_ID Fld(3, 8, AC_MSKB1)	/* 10:8 */
+#define RXING_M1_DIR Fld(1, 7, AC_MSKB0)	/* 7 */
+#define RXING_M1_PAS Fld(1, 6, AC_MSKB0)	/* 6 */
+#define RXING_M1_NAS Fld(1, 5, AC_MSKB0)	/* 5 */
+#define RXING_M1_DES Fld(1, 4, AC_MSKB0)	/* 4 */
+#define RXING_MODE Fld(2, 0, AC_MSKB0)	/* 1:0 */
+#define RX_DATA_NEXT 0x4c
+
+#define RXING_DATA Fld(32, 0, AC_FULLDW)	/* 31:0 */
+#define RX_CAP_50 0x50
+
+#define M1_CAP_50 Fld(6, 10, AC_MSKB1)	/* 15:10 */
+#define RX_EVENT 0x54
+
+#define HDMI_PORD Fld(1, 25, AC_MSKB2)	/* 25 */
+#define HDMI_HTPLG Fld(1, 24, AC_MSKB2)	/* 24 */
+#define DATA_RDY Fld(1, 23, AC_MSKB2)	/* 23 */
+#define HEADER_RDY Fld(1, 22, AC_MSKB2)	/* 22 */
+#define MODE_RDY Fld(1, 21, AC_MSKB2)	/* 21 */
+#define OV Fld(1, 20, AC_MSKB2)	/* 20 */
+#define BR_SB_RDY Fld(1, 18, AC_MSKB2)	/* 18 */
+#define SB_RDY Fld(1, 17, AC_MSKB2)	/* 17 */
+#define BR_RDY Fld(1, 16, AC_MSKB2)	/* 16 */
+#define HDMI_PORD_INT_EN Fld(1, 9, AC_MSKB2)	/* 9 */
+#define HDMI_HTPLG_INT_EN Fld(1, 8, AC_MSKB2)	/* 8 */
+#define I_EN_DATA Fld(1, 7, AC_MSKB0)	/* 7 */
+#define I_EN_HEADER Fld(1, 6, AC_MSKB0)	/* 6 */
+#define I_EN_MODE Fld(1, 5, AC_MSKB0)	/* 5 */
+#define I_EN_OV Fld(1, 4, AC_MSKB0)	/* 4 */
+#define I_EN_PULSE Fld(1, 3, AC_MSKB0)	/* 3 */
+#define I_EN_BR_SB Fld(1, 2, AC_MSKB0)	/* 2 */
+#define I_EN_SB  Fld(1, 1, AC_MSKB0)	/* 1 */
+#define I_EN_BR Fld(1, 0, AC_MSKB0)	/* 0 */
+
+#define RX_GEN_WD 0x58
+
+#define HDMI_PORD_INT_CLR Fld(1, 18, AC_MSKB2)	/* 25 */
+#define RX_INT_CLR Fld(1, 17, AC_MSKB2)	/* 25 */
+#define HDMI_HTPLG_INT_CLR Fld(1, 16, AC_MSKB2)	/* 25 */
+#define BUF1_WD Fld(16, 16, AC_FULLW32)	/* 31:16 */
+#define BUF0_WD Fld(16, 0, AC_FULLW10)	/* 15:0 */
+#define HDMI_PORD_INT_32K_EN Fld(1, 2, AC_MSKB2)	/* 25 */
+#define RX_INT_32K_EN Fld(1, 1, AC_MSKB2)	/* 25 */
+#define HDMI_HTPLG_INT_32K_EN Fld(1, 0, AC_MSKB2)	/* 25 */
+#define RX_GEN_MASK 0x5c
+
+#define BUF1_MASK Fld(16, 16, AC_FULLW32)	/* 31:16 */
+#define BUF0_MASK Fld(16, 0, AC_FULLW10)	/* 15:0 */
+#define RX_GEN_RCVD 0x60
+
+#define BUF1_RCVD Fld(16, 16, AC_FULLW32)	/* 31:16 */
+#define BUF0_RCVD Fld(16, 0, AC_FULLW10)	/* 15:0 */
+#define RX_GEN_INTR 0x64
+
+#define BUF1_INTR Fld(16, 16, AC_FULLW32)	/* 31:16 */
+#define BUF0_INTR Fld(16, 0, AC_FULLW10)	/* 15:0 */
+#define RX_FAIL 0x68
+
+#define ERR_ONCE Fld(1, 4, AC_MSKB0)	/* 4 */
+#define ERR_H Fld(1, 0, AC_MSKB0)	/* 0 */
+#define RX_STATUS 0x6c
+
+#define RX_BIT_COUNTER Fld(4, 28, AC_MSKB3)	/* 31:28 */
+#define RX_TIMER Fld(11, 16, AC_MSKW32)	/* 26:16 */
+#define RX_G_PTR Fld(1, 15, AC_MSKB1)	/* 15 */
+#define RX_FSM Fld(14, 0, AC_MSKW10)	/* 13:0 */
+#define TX_HD_NEXT 0x80
+
+#define WTX_M3_DATA_MASK Fld(4, 24, AC_MSKB3)	/* 27:24 */
+#define WTX_SRC Fld(4, 20, AC_MSKB2)	/* 23:20 */
+#define WTX_DST Fld(4, 16, AC_MSKB2)	/* 19:16 */
+#define WTX_H_EOM Fld(1, 15, AC_MSKB1)	/* 15 */
+#define WTX_D_EOM Fld(1, 13, AC_MSKB1)	/* 13 */
+#define WTX_M3_ID Fld(3, 8, AC_MSKB1)	/* 10:8 */
+#define WTX_M1_DIR Fld(1, 7, AC_MSKB0)	/* 7 */
+#define WTX_M1_PAS Fld(1, 6, AC_MSKB0)	/* 6 */
+#define WTX_M1_NAS Fld(1, 5, AC_MSKB0)	/* 5 */
+#define WTX_M1_DES Fld(1, 4, AC_MSKB0)	/* 4 */
+#define WTX_MODE Fld(2, 0, AC_MSKB0)	/* 1:0 */
+#define TX_DATA_NEXT 0x84
+
+#define WTX_DATA Fld(32, 0, AC_FULLDW)	/* 31:0 */
+#define TX_HEADER 0x88
+
+#define TXING_M3_DATA_SENT Fld(4, 28, AC_MSKB3)	/* 31:28 */
+#define TXING_M3_DATA_MASK Fld(4, 24, AC_MSKB3)	/* 27:24 */
+#define TXING_SRC Fld(4, 20, AC_MSKB2)	/* 23:20 */
+#define TXING_DST Fld(4, 16, AC_MSKB2)	/* 19:16 */
+#define TXING_H_EOM Fld(1, 15, AC_MSKB1)	/* 15 */
+#define TXING_H_ACK Fld(1, 14, AC_MSKB1)	/* 14 */
+#define TXING_D_EOM Fld(1, 13, AC_MSKB1)	/* 13 */
+#define TXING_D_ACK Fld(1, 12, AC_MSKB1)	/* 12 */
+#define TXING_M3_ID Fld(3, 8, AC_MSKB1)	/* 10:8 */
+#define TXING_M1_DIR Fld(1, 7, AC_MSKB0)	/* 7 */
+#define TXING_M1_PAS Fld(1, 6, AC_MSKB0)	/* 6 */
+#define TXING_M1_NAS Fld(1, 5, AC_MSKB0)	/* 5 */
+#define TXING_M1_DES Fld(1, 4, AC_MSKB0)	/* 4 */
+#define TXING_MODE Fld(2, 0, AC_MSKB0)	/* 1:0 */
+#define TX_DATA 0x8c
+
+#define TXING_DATA Fld(32, 0, AC_FULLDW)	/* 31:0 */
+#define RX_CAP_90 0x90
+
+#define M1_CAP_90 Fld(6, 10, AC_MSKB1)	/* 15:10 */
+#define TX_EVENT 0x94
+
+#define UN Fld(1, 20, AC_MSKB2)	/* 20 */
+#define FAIL Fld(1, 19, AC_MSKB2)	/* 19 */
+#define LOWB Fld(1, 18, AC_MSKB2)	/* 18 */
+#define BS Fld(1, 17, AC_MSKB2)	/* 17 */
+#define RB_RDY Fld(1, 16, AC_MSKB2)	/* 16 */
+#define I_EN_UN Fld(1, 4, AC_MSKB0)	/* 4 */
+#define I_EN_FAIL Fld(1, 3, AC_MSKB0)	/* 3 */
+#define I_EN_LOW Fld(1, 2, AC_MSKB0)	/* 2 */
+#define I_EN_BS Fld(1, 1, AC_MSKB0)	/* 1 */
+#define I_EN_RB Fld(1, 0, AC_MSKB0)	/* 0 */
+#define TX_GEN_RD 0x98
+
+#define BUF1_RD Fld(16, 16, AC_FULLW32)	/* 31:16 */
+#define BUF0_RD Fld(16, 0, AC_FULLW10)	/* 15:0 */
+#define TX_GEN_MASK 0x9c
+
+#define BUF1_MASK Fld(16, 16, AC_FULLW32)	/* 31:16 */
+#define BUF0_MASK Fld(16, 0, AC_FULLW10)	/* 15:0 */
+#define TX_GEN_SENT 0xa0
+
+#define BUF1_SENT Fld(16, 16, AC_FULLW32)	/* 31:16 */
+#define BUF0_SENT Fld(16, 0, AC_FULLW10)	/* 15:0 */
+#define TX_GEN_INTR 0xa4
+
+#define BUF1_INTR Fld(16, 16, AC_FULLW32)	/* 31:16 */
+#define BUF0_INTR Fld(16, 0, AC_FULLW10)	/* 15:0 */
+#define TX_FAIL 0xa8
+
+#define RETX_MAX Fld(1, 28, AC_MSKB3)	/* 28 */
+#define DATA Fld(1, 24, AC_MSKB3)	/* 24 */
+#define CMD Fld(1, 20, AC_MSKB2)	/* 20 */
+#define HEADER Fld(1, 16, AC_MSKB2)	/* 16 */
+#define SOURCE Fld(1, 12, AC_MSKB1)	/* 12 */
+#define ID Fld(1, 8, AC_MSKB1)	/* 8 */
+#define FMODE Fld(1, 4, AC_MSKB0)	/* 4 */
+#define FDIR Fld(1, 0, AC_MSKB0)	/* 0 */
+#define TX_STATUS 0xac
+
+#define TX_BIT_COUNTER Fld(4, 28, AC_MSKB3)	/* 31:28 */
+#define TX_TIMER Fld(11, 16, AC_MSKW32)	/* 26:16 */
+#define TX_G_PTR Fld(1, 15, AC_MSKB1)	/* 15 */
+#define TX_FSM Fld(15, 0, AC_MSKW10)	/* 14:0 */
+#define TR_TEST 0xbc
+
+#define PAD_PULL_HIGH Fld(1, 31, AC_MSKB3)	/* 31 */
+#define PAD_ENABLE Fld(1, 30, AC_MSKB3)	/* 30 */
+
+#define RX_ADDR_CHECK Fld(1, 8, AC_MSKB1)	/* 8 */
+#define TX_COMP_TIM Fld(5, 0, AC_MSKB0)	/* 4:0 */
+
+struct CEC_LA_ADDRESS {
+	unsigned char ui1_num;
+	unsigned char aui1_la[3];
+	unsigned short ui2_pa;
+};
+
+struct CEC_SLT_DATA {
+	unsigned char u1Size;
+	unsigned char au1Data[14];
+};
+
+enum CEC_DRV_LOG_ADDR_T {
+	CEC_LOG_ADDR_TV = 0,
+	CEC_LOG_ADDR_REC_DEV_1,
+	CEC_LOG_ADDR_REC_DEV_2,
+	CEC_LOG_ADDR_TUNER_1,
+	CEC_LOG_ADDR_PLAYBACK_DEV_1,
+	CEC_LOG_ADDR_AUD_SYS,
+	CEC_LOG_ADDR_TUNER_2,
+	CEC_LOG_ADDR_TUNER_3,
+	CEC_LOG_ADDR_PLAYBACK_DEV_2,
+	CEC_LOG_ADDR_REC_DEV_3,
+	CEC_LOG_ADDR_TUNER_4,
+	CEC_LOG_ADDR_PLAYBACK_DEV_3,
+	CEC_LOG_ADDR_RESERVED_1,
+	CEC_LOG_ADDR_RESERVED_2,
+	CEC_LOG_ADDR_FREE_USE,
+	CEC_LOG_ADDR_UNREGED_BRDCST,
+	CEC_LOG_ADDR_MAX
+};
+
+enum CEC_CMD_STATE {
+	GET_CMD_ERR = 0x11,
+	GET_CMD_EMPTY = 0x33,
+	GET_CMD_UNEMPTY = 0x55
+};
+
+struct CEC_DRV_ADDR_CFG_T {
+	unsigned char ui1_la_num;
+	unsigned char e_la[CEC_MAX_DEV_LA_NUM];
+	unsigned short ui2_pa;
+	unsigned short h_cecm_svc;
+};
+
+struct CEC_FRAME_INFO_T {
+	unsigned char ui1_init_addr;
+	unsigned char ui1_dest_addr;
+	unsigned short ui2_opcode;
+	unsigned char aui1_operand[CEC_MAX_OPERAND_SIZE];
+	unsigned int z_operand_size;
+};
+
+struct CEC_SEND_MSG_T {
+	void *pv_tag;
+	struct CEC_FRAME_INFO_T t_frame_info;
+	unsigned char b_enqueue_ok;
+};
+
+enum HDMI_NFY_CEC_STATE_T {
+	HDMI_CEC_PLUG_OUT = 0,
+	HDMI_CEC_TX_STATUS,
+	HDMI_CEC_GET_CMD,
+};
+
+/* ACK condition */
+enum CEC_ACK_COND_T {
+	CEC_ACK_COND_OK = 0,
+	CEC_ACK_COND_NO_RESPONSE,
+};
+
+/* ACK info */
+struct CEC_ACK_INFO_T {
+	void *pv_tag;
+	enum CEC_ACK_COND_T e_ack_cond;
+};
+
+extern size_t hdmi_cec_on;
+extern size_t hdmi_hotplugstate;
+unsigned int hdmi_cec_2n(unsigned int u4Data);
+unsigned int hdmi_cec_maskvalue(unsigned int u4Width, unsigned int u4Startbit);
+extern void vNotifyAppHdmiCecState(enum HDMI_NFY_CEC_STATE_T u1hdmicecstate);
+extern void cec_timer_wakeup(void);
+
+unsigned int hdmi_cec_read(unsigned short u2Reg);
+void hdmi_cec_write(unsigned short u2Reg, unsigned int u4Data);
+void hdmi_cec_init(void);
+
+extern void hdmi_cec_init(void);
+extern unsigned char hdmi_cec_isrprocess(unsigned char u1rxmode);
+extern void hdmi_cec_mainloop(unsigned char u1rxmode);
+extern void hdmi_CECMWSetLA(struct CEC_DRV_ADDR_CFG_T *prAddr);
+extern void hdmi_u4CecSendSLTData(unsigned char *pu1Data);
+extern void hdmi_CECMWGet(struct CEC_FRAME_DESCRIPTION_IO *frame);
+extern void hdmi_GetSLTData(struct CEC_SLT_DATA *rCecSltData);
+extern void hdmi_CECMWSend(struct CEC_SEND_MSG_T *msg);
+extern void hdmi_CECMWSetEnableCEC(unsigned char u1EnCec);
+extern void hdmi_NotifyApiCECAddress(struct CEC_ADDRESS_IO *cecaddr);
+extern void hdmi_SetPhysicCECAddress(unsigned short u2pa, unsigned char u1la);
+extern unsigned int IS_HDMI_HTPLG(void);
+extern unsigned int IS_HDMI_PORD(void);
+extern void vClear_cec_irq(void);
+extern void vEnable_hotplug_pord_int(unsigned char u1enable);
+extern void vCec_pdn_32k(void);
+extern void hdmi_cec_api_get_txsts(struct CEC_ACK_INFO_T *pt);
+extern void hdmi_cec_api_get_cmd(struct CEC_FRAME_DESCRIPTION_IO *frame);
+extern void hdmi_cec_usr_cmd(unsigned int cmd, unsigned int *result);
+extern void hdmi_cec_power_on(unsigned char pwr);
+extern unsigned int hdmi_cec_read(unsigned short u2Reg);
+extern void cec_timer_sleep(void);
+extern unsigned char cec_clock;
+unsigned int hdmi_cec_2n(unsigned int u4Data);
+unsigned int hdmi_cec_maskvalue(unsigned int u4Width, unsigned int u4Startbit);
+extern void vNotifyAppHdmiCecState(enum HDMI_NFY_CEC_STATE_T u1hdmicecstate);
+
+/* unsigned int hdmi_cec_read(unsigned short u2Reg); */
+void hdmi_cec_write(unsigned short u2Reg, unsigned int u4Data);
+void hdmi_cec_init(void);
+extern void cec_timer_wakeup(void);
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/itx_config.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/itx_config.h
new file mode 100644
index 0000000..85eee09
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/itx_config.h
@@ -0,0 +1,157 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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.
+*/
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+/* #pragma message("config.h") */
+
+#ifdef EXTERN_HDCPROM
+/* #pragma message("Defined EXTERN_HDCPROM") */
+#endif				/* EXTERN_HDCPROM */
+
+#define SUPPORT_EDID
+/*#define SUPPORT_HDCP*/
+/* #define SUPPORT_SHA */
+/* #define SUPPORT_AUDIO_MONITOR */
+#define AudioOutDelayCnt 250
+
+
+
+/* //////////////////////////////////////////////////////////////////////////////////////// */
+/* Video Configuration */
+/* //////////////////////////////////////////////////////////////////////////////////////// */
+/* 2010/01/26 added a option to disable HDCP. */
+#define SUPPORT_OUTPUTYUV
+#define SUPPORT_OUTPUTRGB
+/* #define DISABLE_HDMITX_CSC */
+
+#define SUPPORT_INPUTRGB
+/* #define SUPPORT_INPUTYUV444 */
+/* #define SUPPORT_INPUTYUV422 */
+/* #define SUPPORT_SYNCEMBEDDED */
+/* #define SUPPORT_DEGEN */
+#define NON_SEQUENTIAL_YCBCR422
+
+
+
+#define INPUT_COLOR_MODE F_MODE_RGB444
+/* #define INPUT_COLOR_MODE F_MODE_YUV422 */
+/* #define INPUT_COLOR_MODE F_MODE_YUV444 */
+
+#define INPUT_COLOR_DEPTH 24
+/* #define INPUT_COLOR_DEPTH 30 */
+/* #define INPUT_COLOR_DEPTH 36 */
+
+/* #define OUTPUT_COLOR_MODE F_MODE_YUV422 */
+/* #define OUTPUT_COLOR_MODE F_MODE_YUV444 */
+#define OUTPUT_COLOR_MODE F_MODE_RGB444
+
+/* #define OUTPUT_3D_MODE Frame_Pcaking */
+/* #define OUTPUT_3D_MODE Top_and_Botton */
+/* #define OUTPUT_3D_MODE Side_by_Side */
+
+/* #define INV_INPUT_ACLK */
+ /* #define INV_INPUT_PCLK */
+
+#ifdef SUPPORT_SYNCEMBEDDED
+    /* #define INPUT_SIGNAL_TYPE (T_MODE_SYNCEMB)                 // 16 bit sync embedded */
+    /* #define INPUT_SIGNAL_TYPE (T_MODE_SYNCEMB | T_MODE_CCIR656) // 8 bit sync embedded */
+#define INPUT_SIGNAL_TYPE (T_MODE_SYNCEMB|T_MODE_INDDR|T_MODE_PCLKDIV2)	/* 16 bit sync embedded DDR */
+    /* #define INPUT_SIGNAL_TYPE (T_MODE_SYNCEMB|T_MODE_INDDR)      // 8  bit sync embedded DDR */
+
+#define SUPPORT_INPUTYUV422
+#ifdef INPUT_COLOR_MODE
+#undef INPUT_COLOR_MODE
+#endif				/* INPUT_COLOR_MODE */
+#define INPUT_COLOR_MODE F_MODE_YUV422
+#else
+    /* #pragma message ("Defined separated sync.") */
+    /* #define INPUT_SIGNAL_TYPE 0 // 24 bit sync separate */
+    /* #define INPUT_SIGNAL_TYPE ( T_MODE_DEGEN ) */
+#define INPUT_SIGNAL_TYPE (T_MODE_INDDR)
+    /* #define INPUT_SIGNAL_TYPE ( T_MODE_SYNCEMB) */
+    /* #define INPUT_SIGNAL_TYPE ( T_MODE_CCIR656 | T_MODE_SYNCEMB ) */
+#endif
+
+
+#if defined(SUPPORT_INPUTYUV444) || defined(SUPPORT_INPUTYUV422)
+#define SUPPORT_INPUTYUV
+#endif
+
+#ifdef SUPPORT_SYNCEMBEDDED
+/* #pragma message("defined SUPPORT_SYNCEMBEDDED for Sync Embedded timing input or CCIR656 input.") */
+#endif
+
+
+/* //////////////////////////////////////////////////////////////////////////////////////// */
+/* Audio Configuration */
+/* //////////////////////////////////////////////////////////////////////////////////////// */
+
+/* #define SUPPORT_HBR_AUDIO */
+#define USE_SPDIF_CHSTAT
+#ifndef SUPPORT_HBR_AUDIO
+#define INPUT_SAMPLE_FREQ AUDFS_44p1KHz
+#define INPUT_SAMPLE_FREQ_HZ 44100L
+#define OUTPUT_CHANNEL 2	/* 3 // 4 // 5//6 //7 //8 */
+
+#define CNOFIG_INPUT_AUDIO_TYPE T_AUDIO_LPCM
+    /* #define CNOFIG_INPUT_AUDIO_TYPE T_AUDIO_NLPCM */
+#define CONFIG_INPUT_AUDIO_SPDIF FALSE	/* I2S */
+    /* #define CONFIG_INPUT_AUDIO_SPDIF TRUE // SPDIF */
+
+    /* #define I2S_FORMAT 0x00 // 24bit I2S audio */
+#define I2S_FORMAT 0x01		/* 32bit I2S audio    hh: 0 for standard I2S */
+    /* #define I2S_FORMAT 0x02 // 24bit I2S audio, right justify */
+    /* #define I2S_FORMAT 0x03 // 32bit I2S audio, right justify */
+
+#else				/* SUPPORT_HBR_AUDIO */
+
+#define INPUT_SAMPLE_FREQ AUDFS_768KHz
+#define INPUT_SAMPLE_FREQ_HZ 768000L
+#define OUTPUT_CHANNEL 8
+#define CNOFIG_INPUT_AUDIO_TYPE T_AUDIO_HBR
+#define CONFIG_INPUT_AUDIO_SPDIF FALSE	/* I2S */
+    /* #define CONFIG_INPUT_AUDIO_SPDIF TRUE // SPDIF */
+#define I2S_FORMAT 0x47		/* 32bit audio */
+#endif
+
+
+
+/* //////////////////////////////////////////////////////////////////////////////////////// */
+/* Audio Monitor Configuration */
+/* //////////////////////////////////////////////////////////////////////////////////////// */
+/* #define HDMITX_AUTO_MONITOR_INPUT */
+/* #define HDMITX_INPUT_INFO */
+
+#ifdef HDMITX_AUTO_MONITOR_INPUT
+#define HDMITX_INPUT_INFO
+#endif
+
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/itx_typedef.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/itx_typedef.h
new file mode 100644
index 0000000..dfe370a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/itx_typedef.h
@@ -0,0 +1,393 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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 "hdmitx.h"
+#ifndef _TYPEDEF_H_
+#define _TYPEDEF_H_
+
+#if defined(CONFIG_ARCH_MT6575)
+#include <mach/mt6575_typedefs.h>
+#endif
+#if defined(CONFIG_ARCH_MT6577)
+/* #include <mach/mt_typedefs.h> */
+#endif
+#if defined(CONFIG_ARCH_MT6589)
+/* #include <mach/mt_typedefs.h> */
+#endif
+
+#if defined(CONFIG_ARCH_MT6592)
+/* #include <mach/mt_typedefs.h> */
+#endif
+
+
+/* //////////////////////////////////////////////// */
+/* data type */
+/* //////////////////////////////////////////////// */
+
+#define _CODE const
+
+#ifndef ULONG
+#define ULONG unsigned long
+#endif
+#ifndef WORD
+#define WORD unsigned short
+#endif
+
+
+#define SUCCESS 0
+#define FAIL -1
+
+#define ON 1
+#define OFF 0
+
+#define LO_ACTIVE TRUE
+#define HI_ACTIVE FALSE
+
+
+enum _SYS_STATUS {
+	ER_SUCCESS = 0,
+	ER_FAIL,
+	ER_RESERVED
+};
+#define SYS_STATUS enum _SYS_STATUS
+
+#define ABS(x) (((x) >= 0)?(x):(-(x)))
+
+
+
+
+
+/* ///////////////////////////////////////////////////////////////////// */
+/* Video Data Type */
+/* ///////////////////////////////////////////////////////////////////// */
+
+#define F_MODE_RGB444  0
+#define F_MODE_YUV422 1
+#define F_MODE_YUV444 2
+#define F_MODE_CLRMOD_MASK 3
+
+
+#define F_MODE_INTERLACE  1
+
+#define F_VIDMODE_ITU709  (1<<4)
+#define F_VIDMODE_ITU601  0
+
+#define F_VIDMODE_0_255   0
+#define F_VIDMODE_16_235  (1<<5)
+
+#define F_VIDMODE_EN_UDFILT (1<<6)
+#define F_VIDMODE_EN_DITHER (1<<7)
+
+#define T_MODE_CCIR656 (1<<0)
+#define T_MODE_SYNCEMB (1<<1)
+#define T_MODE_INDDR   (1<<2)
+#define T_MODE_PCLKDIV2 (1<<3)
+#define T_MODE_DEGEN (1<<4)
+#define T_MODE_SYNCGEN (1<<5)
+/* /////////////////////////////////////////////////////////////////// */
+/* Packet and Info Frame definition and datastructure. */
+/* /////////////////////////////////////////////////////////////////// */
+
+
+#define VENDORSPEC_INFOFRAME_TYPE 0x81
+#define AVI_INFOFRAME_TYPE  0x82
+#define SPD_INFOFRAME_TYPE 0x83
+#define AUDIO_INFOFRAME_TYPE 0x84
+#define MPEG_INFOFRAME_TYPE 0x85
+
+#define VENDORSPEC_INFOFRAME_VER 0x01
+#define AVI_INFOFRAME_VER  0x02
+#define SPD_INFOFRAME_VER 0x01
+#define AUDIO_INFOFRAME_VER 0x01
+#define MPEG_INFOFRAME_VER 0x01
+
+#define VENDORSPEC_INFOFRAME_LEN 5
+#define AVI_INFOFRAME_LEN 13
+#define SPD_INFOFRAME_LEN 25
+#define AUDIO_INFOFRAME_LEN 10
+#define MPEG_INFOFRAME_LEN 10
+
+#define ACP_PKT_LEN 9
+#define ISRC1_PKT_LEN 16
+#define ISRC2_PKT_LEN 16
+/*#define unsigned char unsigned char*/
+
+union _VendorSpecific_InfoFrame {
+	struct {
+		unsigned char Type;
+		unsigned char Ver;
+		unsigned char Len;
+
+		unsigned char CheckSum;
+
+		unsigned char IEEE_0;	/* PB1 */
+		unsigned char IEEE_1;	/* PB2 */
+		unsigned char IEEE_2;	/* PB3 */
+
+		unsigned char Rsvd:5;	/* PB4 */
+		unsigned char HDMI_Video_Format:3;
+
+		unsigned char Reserved_PB5:4;	/* PB5 */
+		unsigned char _3D_Structure:4;
+
+		unsigned char Reserved_PB6:4;	/* PB6 */
+		unsigned char _3D_Ext_Data:4;
+	} info;
+	struct {
+		unsigned char VS_HB[3];
+		unsigned char CheckSum;
+		unsigned char VS_DB[28];
+	} pktbyte;
+};
+#define VendorSpecific_InfoFrame union _VendorSpecific_InfoFrame
+
+union _AVI_InfoFrame {
+
+	struct {
+		unsigned char Type;
+		unsigned char Ver;
+		unsigned char Len;
+
+		unsigned char checksum;
+
+		unsigned char Scan:2;
+		unsigned char BarInfo:2;
+		unsigned char ActiveFmtInfoPresent:1;
+		unsigned char ColorMode:2;
+		unsigned char FU1:1;
+
+		unsigned char ActiveFormatAspectRatio:4;
+		unsigned char PictureAspectRatio:2;
+		unsigned char Colorimetry:2;
+
+		unsigned char Scaling:2;
+		unsigned char FU2:6;
+
+		unsigned char VIC:7;
+		unsigned char FU3:1;
+
+		unsigned char PixelRepetition:4;
+		unsigned char FU4:4;
+
+		short Ln_End_Top;
+		short Ln_Start_Bottom;
+		short Pix_End_Left;
+		short Pix_Start_Right;
+	} info;
+
+	struct {
+		unsigned char AVI_HB[3];
+		unsigned char checksum;
+		unsigned char AVI_DB[AVI_INFOFRAME_LEN];
+	} pktbyte;
+};
+#define AVI_InfoFrame union _AVI_InfoFrame
+
+union _Audio_InfoFrame {
+
+	struct {
+		unsigned char Type;
+		unsigned char Ver;
+		unsigned char Len;
+		unsigned char checksum;
+
+		unsigned char AudioChannelCount:3;
+		unsigned char RSVD1:1;
+		unsigned char AudioCodingType:4;
+
+		unsigned char SampleSize:2;
+		unsigned char SampleFreq:3;
+		unsigned char Rsvd2:3;
+
+		unsigned char FmtCoding;
+
+		unsigned char SpeakerPlacement;
+
+		unsigned char Rsvd3:3;
+		unsigned char LevelShiftValue:4;
+		unsigned char DM_INH:1;
+	} info;
+
+	struct {
+		unsigned char AUD_HB[3];
+		unsigned char checksum;
+		unsigned char AUD_DB[5];
+	} pktbyte;
+
+};
+#define Audio_InfoFrame union _Audio_InfoFrame
+
+union _MPEG_InfoFrame {
+	struct {
+		unsigned char Type;
+		unsigned char Ver;
+		unsigned char Len;
+		unsigned char checksum;
+
+		ULONG MpegBitRate;
+
+		unsigned char MpegFrame:2;
+		unsigned char Rvsd1:2;
+		unsigned char FieldRepeat:1;
+		unsigned char Rvsd2:3;
+	} info;
+	struct {
+		unsigned char MPG_HB[3];
+		unsigned char checksum;
+		unsigned char MPG_DB[MPEG_INFOFRAME_LEN];
+	} pktbyte;
+};
+#define MPEG_InfoFrame union _MPEG_InfoFrame
+
+union _SPD_InfoFrame {
+	struct {
+		unsigned char Type;
+		unsigned char Ver;
+		unsigned char Len;
+		unsigned char checksum;
+
+		char VN[8];
+		char PD[16];
+		unsigned char SourceDeviceInfomation;
+	} info;
+	struct {
+		unsigned char SPD_HB[3];
+		unsigned char checksum;
+		unsigned char SPD_DB[SPD_INFOFRAME_LEN];
+	} pktbyte;
+};
+#define SPD_InfoFrame union _SPD_InfoFrame
+
+/* ///////////////////////////////////////////////////////////////////////// */
+/* Using for interface. */
+/* ///////////////////////////////////////////////////////////////////////// */
+
+#define PROG 1
+#define INTERLACE 0
+#define Vneg 0
+#define Hneg 0
+#define Vpos 1
+#define Hpos 1
+
+struct _CEAVTiming {
+	WORD H_ActiveStart;
+	WORD H_ActiveEnd;
+	WORD H_SyncStart;
+	WORD H_SyncEnd;
+	WORD V_ActiveStart;
+	WORD V_ActiveEnd;
+	WORD V_SyncStart;
+	WORD V_SyncEnd;
+	WORD V2_ActiveStart;
+	WORD V2_ActiveEnd;
+	WORD HTotal;
+	WORD VTotal;
+};
+#define CEAVTiming struct _CEAVTiming
+
+struct _HDMI_VTiming {
+	unsigned char VIC;
+	unsigned char PixelRep;
+	WORD HActive;
+	WORD VActive;
+	WORD HTotal;
+	WORD VTotal;
+	ULONG PCLK;
+	unsigned char xCnt;
+	WORD HFrontPorch;
+	WORD HSyncWidth;
+	WORD HBackPorch;
+	unsigned char VFrontPorch;
+	unsigned char VSyncWidth;
+	unsigned char VBackPorch;
+	unsigned char ScanMode:1;
+	unsigned char VPolarity:1;
+	unsigned char HPolarity:1;
+};
+#define HDMI_VTiming struct _HDMI_VTiming
+
+/* //////////////////////////////////////////////////////////////// */
+/* Audio relate definition and macro. */
+/* //////////////////////////////////////////////////////////////// */
+
+/* 2008/08/15 added by jj_tseng@chipadvanced */
+#define F_AUDIO_ON  (1<<7)
+#define F_AUDIO_HBR (1<<6)
+#define F_AUDIO_DSD (1<<5)
+#define F_AUDIO_NLPCM (1<<4)
+#define F_AUDIO_LAYOUT_1 (1<<3)
+#define F_AUDIO_LAYOUT_0 (0<<3)
+
+/* HBR - 1100 */
+/* DSD - 1010 */
+/* NLPCM - 1001 */
+/* LPCM - 1000 */
+
+#define T_AUDIO_MASK 0xF0
+#define T_AUDIO_OFF 0
+#define T_AUDIO_HBR (F_AUDIO_ON|F_AUDIO_HBR)
+#define T_AUDIO_DSD (F_AUDIO_ON|F_AUDIO_DSD)
+#define T_AUDIO_NLPCM (F_AUDIO_ON|F_AUDIO_NLPCM)
+#define T_AUDIO_LPCM (F_AUDIO_ON)
+
+/* for sample clock */
+#define AUDFS_22p05KHz  4
+#define AUDFS_44p1KHz 0
+#define AUDFS_88p2KHz 8
+#define AUDFS_176p4KHz    12
+
+#define AUDFS_24KHz  6
+#define AUDFS_48KHz  2
+#define AUDFS_96KHz  10
+#define AUDFS_192KHz 14
+
+#define AUDFS_768KHz 9
+
+#define AUDFS_32KHz  3
+#define AUDFS_OTHER    1
+
+/* Audio Enable */
+#define ENABLE_SPDIF    (1<<4)
+#define ENABLE_I2S_SRC3  (1<<3)
+#define ENABLE_I2S_SRC2  (1<<2)
+#define ENABLE_I2S_SRC1  (1<<1)
+#define ENABLE_I2S_SRC0  (1<<0)
+
+#define AUD_SWL_NOINDICATE  0x0
+#define AUD_SWL_16          0x2
+#define AUD_SWL_17          0xC
+#define AUD_SWL_18          0x4
+#define AUD_SWL_20          0xA	/* for maximum 20 bit */
+#define AUD_SWL_21          0xD
+#define AUD_SWL_22          0x5
+#define AUD_SWL_23          0x9
+#define AUD_SWL_24          0xB
+
+
+#endif				/* _TYPEDEF_H_ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/itx_version.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/itx_version.h
new file mode 100644
index 0000000..4927d67
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/itx_version.h
@@ -0,0 +1,37 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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.
+*/
+
+
+#ifndef _VERSION_H_
+#define _VERSION_H_
+#define	VERSION_STRING	"ITE_HDMITX_SAMPLE_3.10"
+#endif				/* _VERSION_H_ */
+
+
+#define	short_VERSION_STRING	"V3.10"
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/mcu.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/mcu.h
new file mode 100644
index 0000000..254499f
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/mcu.h
@@ -0,0 +1,131 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+* 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.
+*/
+
+
+#ifndef _MCU_H_
+#define _MCU_H_
+#if 0
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+/* #include <linux/earlysuspend.h> */
+#include <linux/platform_device.h>
+#include <linux/atomic.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/reboot.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/completion.h>
+#endif
+
+/* #include <cust_eint.h> */
+/* #include "cust_gpio_usage.h" */
+/* #include "mach/eint.h" */
+/* #include "mach/irqs.h" */
+
+#if defined(CONFIG_ARCH_MT6575)
+#include <mach/mt6575_devs.h>
+#include <mach/mt6575_typedefs.h>
+#include <mach/mt6575_gpio.h>
+#include <mach/mt6575_pm_ldo.h>
+#elif defined(CONFIG_ARCH_MT6577)
+  /* #include <mach/mt_typedefs.h> */
+  /* #include <mach/mt_gpio.h> */
+#include <mach/mt_clock_manager.h>
+#include <mach/mt_mdp.h>
+#include <mach/mt_reg_base.h>
+#endif
+
+
+/* #define MySon */
+/* #define Unixtar */
+
+/***************************************/
+/* DEBUG INFO define                   */
+/**************************************/
+/* #define Build_LIB */
+/* #define MODE_RS232 */
+
+
+
+/*************************************/
+/*Port Using Define                  */
+/*************************************/
+
+/* #define _1PORT_ */
+
+
+
+/************************************/
+/* Function DEfine                  */
+/***********************************/
+
+
+/* #define       _HBR_I2S_ */
+
+
+/* ///////////////////////////////////////////////////////////////////////////// */
+/* Include file */
+/* ///////////////////////////////////////////////////////////////////////////// */
+
+/* ////////////////////////////////////////////////////////////////////////////// */
+
+/* ///////////////////////////////////////////////////////////////////////////// */
+/* Constant Definition */
+/* ///////////////////////////////////////////////////////////////////////////// */
+#define TX0DEV            0
+#define TX0ADR    0x98
+#define TX0CECADR     0x9C
+
+#define RXADR            0x90
+
+#define EDID_ADR        0xA0	/* alex 070321 */
+
+#define DELAY_TIME        1	/* unit=1 us; */
+#define IDLE_TIME        100	/* unit=1 ms; */
+
+#define HIGH            1
+#define LOW                0
+
+
+#define HPDON        1
+#define HPDOFF        0
+
+
+#endif				/* _MCU_H_ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/sha1.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/sha1.c
new file mode 100644
index 0000000..2e2da24
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/sha1.c
@@ -0,0 +1,182 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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 "sha1.h"
+
+#ifndef DISABLE_HDCP
+
+#define WCOUNT 17
+ULONG VH[5];
+ULONG w[WCOUNT];
+
+#define rol(x, y)(((x) << (y)) | (((ULONG)x) >> (32-y)))
+
+void SHATransform(ULONG *h)
+{
+	int t;
+	ULONG tmp;
+
+	h[0] = 0x67452301;
+	h[1] = 0xefcdab89;
+	h[2] = 0x98badcfe;
+	h[3] = 0x10325476;
+	h[4] = 0xc3d2e1f0;
+
+	for (t = 0; t < 20; t++) {
+		if (t >= 16) {
+			tmp =
+			    w[(t - 3) % WCOUNT] ^ w[(t - 8) % WCOUNT] ^ w[(t -
+									   14) % WCOUNT] ^ w[(t -
+											      16) %
+											     WCOUNT];
+			w[(t) % WCOUNT] = rol(tmp, 1);
+		}
+		HDCP_DEBUG_PRINTF2(("w[%d]=%08lX\n", t, w[(t) % WCOUNT]));
+
+		tmp =
+		    rol(h[0],
+			5) + ((h[1] & h[2]) | (h[3] & ~h[1])) + h[4] + w[(t) % WCOUNT] + 0x5a827999;
+		HDCP_DEBUG_PRINTF2(("%08lX %08lX %08lX %08lX %08lX\n", h[0], h[1], h[2], h[3],
+				    h[4]));
+
+		h[4] = h[3];
+		h[3] = h[2];
+		h[2] = rol(h[1], 30);
+		h[1] = h[0];
+		h[0] = tmp;
+
+	}
+	for (t = 20; t < 40; t++) {
+		tmp =
+		    w[(t - 3) % WCOUNT] ^ w[(t - 8) % WCOUNT] ^ w[(t - 14) % WCOUNT] ^ w[(t -
+											  16) %
+											 WCOUNT];
+		w[(t) % WCOUNT] = rol(tmp, 1);
+		HDCP_DEBUG_PRINTF2(("w[%d]=%08lX\n", t, w[(t) % WCOUNT]));
+		tmp = rol(h[0], 5) + (h[1] ^ h[2] ^ h[3]) + h[4] + w[(t) % WCOUNT] + 0x6ed9eba1;
+		HDCP_DEBUG_PRINTF2(("%08lX %08lX %08lX %08lX %08lX\n", h[0], h[1], h[2], h[3],
+				    h[4]));
+		h[4] = h[3];
+		h[3] = h[2];
+		h[2] = rol(h[1], 30);
+		h[1] = h[0];
+		h[0] = tmp;
+	}
+	for (t = 40; t < 60; t++) {
+		tmp =
+		    w[(t - 3) % WCOUNT] ^ w[(t - 8) % WCOUNT] ^ w[(t - 14) % WCOUNT] ^ w[(t -
+											  16) %
+											 WCOUNT];
+		w[(t) % WCOUNT] = rol(tmp, 1);
+		HDCP_DEBUG_PRINTF2(("w[%d]=%08lX\n", t, w[(t) % WCOUNT]));
+		tmp =
+		    rol(h[0],
+			5) + ((h[1] & h[2]) | (h[1] & h[3]) | (h[2] & h[3])) + h[4] +
+		    w[(t) % WCOUNT] + 0x8f1bbcdc;
+		HDCP_DEBUG_PRINTF2(("%08lX %08lX %08lX %08lX %08lX\n", h[0], h[1], h[2], h[3],
+				    h[4]));
+		h[4] = h[3];
+		h[3] = h[2];
+		h[2] = rol(h[1], 30);
+		h[1] = h[0];
+		h[0] = tmp;
+	}
+	for (t = 60; t < 80; t++) {
+		tmp =
+		    w[(t - 3) % WCOUNT] ^ w[(t - 8) % WCOUNT] ^ w[(t - 14) % WCOUNT] ^ w[(t -
+											  16) %
+											 WCOUNT];
+		w[(t) % WCOUNT] = rol(tmp, 1);
+		HDCP_DEBUG_PRINTF2(("w[%d]=%08lX\n", t, w[(t) % WCOUNT]));
+		tmp = rol(h[0], 5) + (h[1] ^ h[2] ^ h[3]) + h[4] + w[(t) % WCOUNT] + 0xca62c1d6;
+		HDCP_DEBUG_PRINTF2(("%08lX %08lX %08lX %08lX %08lX\n", h[0], h[1], h[2], h[3],
+				    h[4]));
+		h[4] = h[3];
+		h[3] = h[2];
+		h[2] = rol(h[1], 30);
+		h[1] = h[0];
+		h[0] = tmp;
+	}
+	HDCP_DEBUG_PRINTF2(("%08lX %08lX %08lX %08lX %08lX\n", h[0], h[1], h[2], h[3], h[4]));
+	h[0] += 0x67452301;
+	h[1] += 0xefcdab89;
+	h[2] += 0x98badcfe;
+	h[3] += 0x10325476;
+	h[4] += 0xc3d2e1f0;
+
+	HDCP_DEBUG_PRINTF2(("%08lX %08lX %08lX %08lX %08lX\n", h[0], h[1], h[2], h[3], h[4]));
+}
+
+void SHA_Simple(void *p, WORD len, unsigned char *output)
+{
+	/* SHA_State s; */
+	WORD i, t;
+	ULONG c;
+	unsigned char *pBuff = p;
+
+	for (i = 0; i < len; i++) {
+		t = i / 4;
+		if (i % 4 == 0)
+			w[t] = 0;
+
+		c = pBuff[i];
+		c <<= (3 - (i % 4)) * 8;
+		w[t] |= c;
+		HDCP_DEBUG_PRINTF2(("pBuff[%d]=%02X,c=%08lX,w[%d]=%08lX\n", (int)i, (int)pBuff[i],
+				    c, (int)t, w[t]));
+	}
+	t = i / 4;
+	if (i % 4 == 0)
+		w[t] = 0;
+
+	/* c=0x80 << ((3-i%4)*24); */
+	c = 0x80;
+	c <<= ((3 - i % 4) * 8);
+	w[t] |= c;
+	t++;
+	for (; t < 15; t++)
+		w[t] = 0;
+
+	w[15] = len * 8;
+
+	for (i = 0; i < 16; i++)
+		HDCP_DEBUG_PRINTF2(("w[%d] = %08lX\n", i, w[i]));
+
+	SHATransform(VH);
+
+	for (i = 0; i < 5; i++) {
+		output[i * 4 + 3] = (unsigned char) ((VH[i] >> 24) & 0xFF);
+		output[i * 4 + 2] = (unsigned char) ((VH[i] >> 16) & 0xFF);
+		output[i * 4 + 1] = (unsigned char) ((VH[i] >> 8) & 0xFF);
+		output[i * 4 + 0] = (unsigned char) (VH[i] & 0xFF);
+	}
+}
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/sha1.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/sha1.h
new file mode 100644
index 0000000..ab2ea26
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/sha1.h
@@ -0,0 +1,57 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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.
+*/
+
+
+#ifndef _SHA_1_H_
+#define _SHA_1_H_
+
+#include "mcu.h"
+
+#include "itx_config.h"
+#include "itx_typedef.h"
+
+#ifndef HDCP_DEBUG_PRINTF
+#define HDCP_DEBUG_PRINTF(x)
+#endif				/* HDCP_DEBUG_PRINTF */
+
+#ifndef HDCP_DEBUG_PRINTF1
+#define HDCP_DEBUG_PRINTF1(x)
+#endif				/* HDCP_DEBUG_PRINTF1 */
+
+#ifndef HDCP_DEBUG_PRINTF2
+#define HDCP_DEBUG_PRINTF2(x)
+#endif				/* HDCP_DEBUG_PRINTF2 */
+
+
+#ifndef DISABLE_HDCP
+void SHA_Simple(void *p, WORD len, unsigned char *output);
+void SHATransform(ULONG *h);
+#endif
+
+#endif				/* _SHA_1_H_ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/utility.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/utility.c
new file mode 100644
index 0000000..cbcd7c4
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/utility.c
@@ -0,0 +1,59 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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 "mcu.h"
+#include "hdmitx.h"
+/* #include "TimerProcess.h" */
+
+void delay1ms(unsigned short ms)
+{
+	//mdelay(ms);// fix build error
+	int i = 0;
+	int j = 0;
+	for (i = 0; i < ms ; i++) {
+		for (j = 0; j < 100000 ; j++) {
+			;
+		}
+	}
+}
+
+
+void HoldSystem(void)
+{
+}
+
+#if 1				/* def SUPPORT_UART_CMD */
+/* ///////////////////////////////////////////////////////////////////////////// */
+/* I2C for original function call */
+/* ///////////////////////////////////////////////////////////////////////////// */
+
+void DumpReg(unsigned char dumpAddress)
+{
+}
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/utility.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/utility.h
new file mode 100644
index 0000000..182f978
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/it66121/utility.h
@@ -0,0 +1,97 @@
+/*
+* HDMI support
+*
+* Copyright (C) 2013 ITE Tech. Inc.
+* Author: Hermes Wu <hermes.wu@ite.com.tw>
+*
+* HDMI TX driver for IT66121
+*
+*
+* 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.
+*/
+
+
+#ifndef _Utility_h_
+#define _Utility_h_
+#include "mcu.h"
+#include "itx_typedef.h"
+
+/* #define MS_TimeOut(x) (((x)+LOOPMS-1)/LOOPMS) */
+/* #define MS_TimeOut(x) ((x)+1)//(x/20)+1 */
+/*#define VSTATE_MISS_SYNC_COUNT MS_TimeOut(2000)*/
+/*#define VSATE_CONFIRM_SCDT_COUNT MS_TimeOut(150)*/
+/*#define AUDIO_READY_TIMEOUT MS_TimeOut(200)*/
+/*#define AUDIO_STABLE_TIMEOUT MS_TimeOut(1000)*/
+/*#define VSATE_CONFIRM_SCDT_COUNT MS_TimeOut(0)*/
+/*#define AUDIO_READY_TIMEOUT MS_TimeOut(10)*/
+/*#define AUDIO_STABLE_TIMEOUT MS_TimeOut(100)*/
+
+
+
+/*#define MUTE_RESUMING_TIMEOUT MS_TimeOut(2500)*/
+/*#define HDCP_WAITING_TIMEOUT MS_TimeOut(3000)*/
+
+/*#define FORCE_SWRESET_TIMEOUT  MS_TimeOut(32766)*/
+
+
+
+#define VSTATE_CDR_DISCARD_TIME		 MS_TimeOut(6000)
+
+#define VSTATE_MISS_SYNC_COUNT         MS_TimeOut(5000)
+#define VSTATE_SWRESET_TIMEOUT_COUNT MS_TimeOut(50)
+#define VSATE_CONFIRM_SCDT_COUNT     MS_TimeOut(20)
+#define AUDIO_READY_TIMEOUT         MS_TimeOut(20)
+#define AUDIO_STABLE_TIMEOUT         MS_TimeOut(20)	/* MS_TimeOut(1000) */
+
+#define MUTE_RESUMING_TIMEOUT         MS_TimeOut(2500)
+#define HDCP_WAITING_TIMEOUT         MS_TimeOut(3000)
+
+#define FORCE_SWRESET_TIMEOUT          MS_TimeOut(15000)
+
+#define TX_UNPLUG_TIMEOUT           MS_TimeOut(300)
+#define TX_WAITVIDSTBLE_TIMEOUT     MS_TimeOut(100)
+
+#define TX_HDCP_TIMEOUT             MS_TimeOut(6000)
+
+
+
+#define CAT_HDMI_PORTA 0
+#define CAT_HDMI_PORTB 1
+/* ///////////////////////////////////////////////////// */
+/* Global variable */
+/* ////////////////////////////////////////////////////// */
+/* alex 070327 */
+/* for chroma2229 audio error */
+
+/* ///////////////////////////////////////////////////////// */
+/* Function Prototype */
+/* ///////////////////////////////////////////////////////// */
+
+/* void SetTxLED(unsigned char device,bool status); */
+
+void HoldSystem(void);
+void delay1ms(unsigned short ms);
+void HoldSystem(void);
+
+void ConfigfHdmiVendorSpecificInfoFrame(unsigned char _3D_Stru);
+void SetOutputColorDepthPhase(unsigned char ColorDepth, unsigned char bPhase);
+
+
+#endif				/* _Utility_h_ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/key/mtk_key.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/key/mtk_key.c
new file mode 100644
index 0000000..0a7887f
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/key/mtk_key.c
@@ -0,0 +1,35 @@
+/*
+ * 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 <platform/mt_reg_base.h>
+#include <reg.h>
+#include <stdio.h>
+#include <platform/mtk_key.h>
+
+#define GPIO_BASE (IO_PHYS + 0x0005000)
+#define GPIO_DIN3          (GPIO_BASE + 0x220)
+
+bool check_download_key(void)
+{
+    return (readl(GPIO_DIN3) & (1U << 29)) == 0;
+}
\ No newline at end of file
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/mmc/mmc_core.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/mmc/mmc_core.c
new file mode 100644
index 0000000..bfcc855
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/mmc/mmc_core.c
@@ -0,0 +1,1884 @@
+/*
+ * 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 <config.h>
+#include <platform/msdc.h>
+#include <platform/mmc_core.h>
+#include <platform/mmc_ioctl.h>
+#include <lib/bio.h>
+#include <lib/heap.h>
+#include <lib/partition.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+#include <kernel/mutex.h>
+
+#pragma pack(8)
+
+#pragma GCC push_options
+#pragma GCC optimize("O1")
+
+struct mmc_host msdc_host0;
+struct mmc_card emmc_card;
+
+struct mmc_dev_t {
+	bdev_t bdev;
+	u32 part_id;
+	struct mmc_host *host;
+	struct mmc_card *card;
+}__attribute__((aligned(8)));
+
+static const unsigned int tran_exp[] = {
+	10000,100000,1000000,10000000,
+	0,0,0,0
+};
+
+static const unsigned char tran_mant[] = {
+	0,  10, 12, 13, 15, 20, 25, 30,
+	35, 40, 45, 50, 55, 60, 70, 80,
+};
+
+static const unsigned char mmc_tran_mant[] = {
+	0,  10, 12, 13, 15, 20, 26, 30,
+	35, 40, 45, 52, 55, 60, 70, 80,
+};
+
+static u32 unstuff_bits(u32 *resp, u32 start, u32 size)
+{
+	const u32 __mask = (1 << (size)) - 1;
+	const int __off = 3 - ((start) / 32);
+	const int __shft = (start) & 31;
+	u32 __res;
+
+	__res = resp[__off] >> __shft;
+	if ((size) + __shft >= 32)
+		__res |= resp[__off-1] << (32 - __shft);
+	return __res & __mask;
+}
+
+#define UNSTUFF_BITS(r,s,sz)    unstuff_bits(r,s,sz)
+
+static int mmc_cmd(struct mmc_host *host, struct mmc_command *cmd)
+{
+	int err;
+	int retry = cmd->retries;
+
+	if (cmd->opcode == MMC_CMD_APP_CMD) {
+		host->app_cmd = 1;
+		host->app_cmd_arg = cmd->arg;
+	} else {
+		host->app_cmd = 0;
+	}
+
+	do {
+		err = msdc_cmd(host, cmd);
+		if (err == MMC_ERR_NONE ||
+		    cmd->opcode == MMC_CMD21) /* do not tuning CMD21 */
+			break;
+	} while (retry--);
+
+	return err;
+}
+
+static int mmc_app_cmd(struct mmc_host *host, struct mmc_command *cmd,
+			     u32 rca, int retries)
+{
+	int err = MMC_ERR_FAILED;
+	struct mmc_command appcmd;
+
+	appcmd.opcode  = MMC_CMD_APP_CMD;
+	appcmd.arg     = rca << 16;
+	appcmd.rsptyp  = RESP_R1;
+	appcmd.retries = CMD_RETRIES;
+	appcmd.timeout = CMD_TIMEOUT;
+
+	do {
+		err = mmc_cmd(host, &appcmd);
+
+		if (err == MMC_ERR_NONE)
+			err = mmc_cmd(host, cmd);
+		if (err == MMC_ERR_NONE)
+			break;
+	} while (retries--);
+
+	return err;
+}
+
+static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
+{
+	int bit;
+
+	ocr &= host->ocr_avail;
+
+	bit = __builtin_ffs(ocr);
+	if (bit) {
+		bit -= 1;
+		ocr &= 3 << bit;
+	} else {
+		ocr = 0;
+	}
+	return ocr;
+}
+
+static inline int mmc_go_idle(struct mmc_host *host)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_GO_IDLE_STATE, 0, RESP_NONE, {0},
+	CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+
+    return mmc_cmd(host, &cmd);
+}
+
+static int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
+{
+	struct mmc_command cmd;
+	int err;
+	static const u8 test_pattern = 0xAA;
+	u8 result_pattern;
+
+	/*
+	 * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+	 * before SD_APP_OP_COND. This command will harmlessly fail for
+	 * SD 1.0 cards.
+	 */
+
+	cmd.opcode  = SD_CMD_SEND_IF_COND;
+	cmd.arg     = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+	cmd.rsptyp  = RESP_R1;
+	cmd.retries = 0;
+	cmd.timeout = CMD_TIMEOUT;
+
+	err = mmc_cmd(host, &cmd);
+
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	result_pattern = cmd.resp[0] & 0xFF;
+
+	if (result_pattern != test_pattern)
+		return MMC_ERR_INVALID;
+
+	return MMC_ERR_NONE;
+}
+
+/*
+ * return MMC_ERR_RETRY means that need re-send CMD1 in stage 2
+ */
+static int mmc_send_op_cond_once(struct mmc_host *host,
+					   u32 ocr, u32 *rocr)
+{
+	int i, err = 0;
+	struct mmc_command cmd = {
+		MMC_CMD_SEND_OP_COND, 0, RESP_R3, {0},
+		CMD_TIMEOUT, 0, 0
+	};
+
+	cmd.arg = ocr;
+
+	for (i = 1; i; i--) {
+		err = mmc_cmd(host, &cmd);
+		if (err)
+			break;
+
+		/* if we're just probing, do a single pass */
+		if (ocr == 0)
+			break;
+
+		if (cmd.resp[0] & MMC_CARD_BUSY)
+			break;
+
+		err = MMC_ERR_RETRY;
+	}
+
+	if (!err && rocr)
+		*rocr = cmd.resp[0];
+
+	return err;
+}
+
+static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+	int i, err = 0;
+	struct mmc_command cmd = {
+		MMC_CMD_SEND_OP_COND, 0, RESP_R3, {0},
+		CMD_TIMEOUT, 0, 0
+	};
+
+	cmd.arg = ocr;
+
+	for (i = 100; i; i--) {
+		err = mmc_cmd(host, &cmd);
+		if (err)
+			break;
+
+		/* if we're just probing, do a single pass */
+		if (ocr == 0)
+			break;
+
+		if (cmd.resp[0] & MMC_CARD_BUSY)
+			break;
+
+		err = MMC_ERR_TIMEOUT;
+
+		spin(10000);
+	}
+
+	if (!err && rocr)
+		*rocr = cmd.resp[0];
+
+	return err;
+}
+
+static int mmc_send_app_op_cond_once(struct mmc_host *host,
+						u32 ocr, u32 *rocr)
+{
+	struct mmc_command cmd;
+	int i, err = 0;
+
+	cmd.opcode  = SD_ACMD_SEND_OP_COND;
+	cmd.arg     = ocr;
+	cmd.rsptyp  = RESP_R3;
+	cmd.retries = CMD_RETRIES;
+	cmd.timeout = CMD_TIMEOUT;
+
+	for (i = 1; i; i--) {
+		err = mmc_app_cmd(host, &cmd, 0, CMD_RETRIES);
+		if (err != MMC_ERR_NONE)
+			break;
+
+		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+			break;
+
+		err = MMC_ERR_RETRY;
+	}
+
+	if (rocr)
+		*rocr = cmd.resp[0];
+
+	return err;
+}
+
+static int mmc_send_app_op_cond(struct mmc_host *host,
+					 u32 ocr, u32 *rocr)
+{
+	struct mmc_command cmd;
+	int i, err = 0;
+
+	cmd.opcode  = SD_ACMD_SEND_OP_COND;
+	cmd.arg     = ocr;
+	cmd.rsptyp  = RESP_R3;
+	cmd.retries = CMD_RETRIES;
+	cmd.timeout = CMD_TIMEOUT;
+
+	for (i = 100; i; i--) {
+		err = mmc_app_cmd(host, &cmd, 0, CMD_RETRIES);
+		if (err != MMC_ERR_NONE)
+			break;
+
+		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+			break;
+
+		err = MMC_ERR_TIMEOUT;
+
+		spin(10000);
+	}
+
+	if (rocr)
+		*rocr = cmd.resp[0];
+
+	return err;
+}
+
+static int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
+{
+	int ret;
+	struct mmc_command cmd = {
+		MMC_CMD_ALL_SEND_CID, 0, RESP_R2, {0},
+		CMD_TIMEOUT, CMD_RETRIES, 0
+	};
+
+	ret = mmc_cmd(host, &cmd);
+	if (ret == MMC_ERR_NONE) {
+		memcpy(cid, &cmd.resp[0], sizeof(u32) * 4);
+		dprintf(INFO, "eMMC CID: %08x%08x%08x%08x\n",
+			cid[0], cid[1], cid[2], cid[3]);
+	}
+
+	return ret;
+}
+
+static int mmc_send_relative_addr(struct mmc_host *host,
+					struct mmc_card *card,
+					unsigned int *rca)
+{
+	int err;
+	struct mmc_command cmd;
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	if (mmc_card_mmc(card)) { /* set rca */
+		cmd.opcode  = MMC_CMD_SET_RELATIVE_ADDR;
+		cmd.arg     = *rca << 16;
+		cmd.rsptyp  = RESP_R1;
+		cmd.retries = CMD_RETRIES;
+		cmd.timeout = CMD_TIMEOUT;
+	} else {  /* send rca */
+		cmd.opcode  = SD_CMD_SEND_RELATIVE_ADDR;
+		cmd.arg     = 0;
+		cmd.rsptyp  = RESP_R6;
+		cmd.retries = CMD_RETRIES;
+		cmd.timeout = CMD_TIMEOUT;
+	}
+
+	err = mmc_cmd(host, &cmd);
+	if ((err == MMC_ERR_NONE) && !mmc_card_mmc(card))
+		*rca = cmd.resp[0] >> 16;
+
+	return err;
+}
+
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+	struct mmc_command cmd = {
+		MMC_CMD_SELECT_CARD, 0, RESP_R1B, {0},
+		CMD_TIMEOUT, CMD_RETRIES, 0
+	};
+
+	cmd.arg = card->rca << 16;
+
+	return mmc_cmd(host, &cmd);
+}
+
+static int mmc_deselect_card(struct mmc_host *host, struct mmc_card *card)
+{
+	/* deslect cmd has no response */
+	struct mmc_command cmd = {
+		MMC_CMD_SELECT_CARD, 0, RESP_NONE, {0},
+		CMD_TIMEOUT, CMD_RETRIES, 0
+	};
+
+	return mmc_cmd(host, &cmd);
+}
+
+static int mmc_send_status(struct mmc_host *host, struct mmc_card *card,
+                           u32 *status)
+{
+	int err;
+	struct mmc_command cmd = {
+		MMC_CMD_SEND_STATUS, 0, RESP_R1, {0},
+		CMD_TIMEOUT, CMD_RETRIES, 0
+	};
+
+	cmd.arg = card->rca << 16;
+
+	err = mmc_cmd(host, &cmd);
+	if (err == MMC_ERR_NONE)
+		*status = cmd.resp[0];
+
+	return err;
+}
+
+static int mmc_switch(struct mmc_host *host, struct mmc_card *card,
+                      u8 set, u8 index, u8 value)
+{
+	int err;
+	u32 status = 0, count = 0;
+	struct mmc_command cmd = {
+		MMC_CMD_SWITCH, 0, RESP_R1B, {0},
+		CMD_TIMEOUT, CMD_RETRIES, 0
+	};
+
+	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) |
+	      	  (value << 8) | set;
+
+	err = mmc_cmd(host, &cmd);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	do {
+		err = mmc_send_status(host, card, &status);
+		if (err) {
+			dprintf(CRITICAL, "[eMMC] Fail to send status %d\n",
+				err);
+		    	break;
+		}
+		if (status & R1_SWITCH_ERROR) {
+			dprintf(CRITICAL, "[eMMC] switch error. arg(0x%x)\n",
+				cmd.arg);
+		    	return MMC_ERR_FAILED;
+		}
+		if (count++ >= 600000) {
+		    	dprintf(CRITICAL, "[%s]: timeout happend, count=%d, status=0x%x\n",
+		            	__func__, count, status);
+		    	break;
+		}
+	} while (!(status & R1_READY_FOR_DATA) ||
+		 (R1_CURRENT_STATE(status) == 7));
+
+	if (!err && (index == EXT_CSD_PART_CFG))
+		host->curr_part = value & 0x7;
+
+	return err;
+}
+
+static int mmc_read_csds(struct mmc_host *host, struct mmc_card *card)
+{
+	int err;
+	struct mmc_command cmd = {
+		MMC_CMD_SEND_CSD, 0, RESP_R2, {0},
+		CMD_TIMEOUT * 100, CMD_RETRIES, 0
+	};
+
+	cmd.arg = card->rca << 16;
+
+	err = mmc_cmd(host, &cmd);
+	if (err == MMC_ERR_NONE) {
+		unsigned int e, m;
+		card->csd.mmca_vsn = UNSTUFF_BITS(&cmd.resp[0], 122, 4);
+		m = UNSTUFF_BITS(&cmd.resp[0], 99, 4);
+		e = UNSTUFF_BITS(&cmd.resp[0], 96, 3);
+		card->csd.max_dtr = tran_exp[e] * mmc_tran_mant[m];
+		e = UNSTUFF_BITS(&cmd.resp[0], 47, 3);
+		m = UNSTUFF_BITS(&cmd.resp[0], 62, 12);
+		card->csd.capacity = (1 + m) << (e + 2);
+		card->csd.read_blkbits = UNSTUFF_BITS(&cmd.resp[0], 80, 4);
+		memcpy(&card->raw_csd, &cmd.resp[0], sizeof(u32) * 4);
+	}
+
+	return err;
+}
+
+static int mmc_decode_csd(struct mmc_card *card)
+{
+	struct mmc_csd *csd = &card->csd;
+	unsigned int e, m, csd_struct;
+	u32 *resp = card->raw_csd;
+
+	/* common part; some part are updated later according to spec. */
+	csd_struct = unstuff_bits(resp, 126, 2);
+	csd->csd_struct = csd_struct;
+
+	/* For MMC
+	 * We only understand CSD structure v1.1 and v1.2.
+	 * v1.2 has extra information in bits 15, 11 and 10.
+	 */
+	if ((mmc_card_mmc(card) &&
+	    (csd_struct != CSD_STRUCT_VER_1_0 &&
+	     csd_struct != CSD_STRUCT_VER_1_1 &&
+	     csd_struct != CSD_STRUCT_VER_1_2 &&
+	     csd_struct != CSD_STRUCT_EXT_CSD )) ||
+	    (mmc_card_sd(card) &&
+	     (csd_struct != 0 && csd_struct!=1 ))
+	   ) {
+		dprintf(ALWAYS, "Unknown CSD ver %d\n", csd_struct);
+		return MMC_ERR_INVALID;
+	}
+
+	m = unstuff_bits(resp, 99, 4);
+	e = unstuff_bits(resp, 96, 3);
+	csd->max_dtr      = tran_exp[e] * tran_mant[m];
+
+	/* update later according to spec. */
+	csd->read_blkbits = unstuff_bits(resp, 80, 4);
+
+	e = unstuff_bits(resp, 47, 3);
+	m = unstuff_bits(resp, 62, 12);
+	csd->capacity = (1 + m) << (e + 2);
+
+	/* Specific part */
+	if (mmc_card_sd(card)) {
+		switch (csd_struct) {
+		case 0:
+			break;
+		case 1:
+			/*
+			 * This is a block-addressed SDHC card. Most
+			 * interesting fields are unused and have fixed
+			 * values. To avoid getting tripped by buggy cards,
+			 * we assume those fixed values ourselves.
+			 */
+			mmc_card_set_blockaddr(card);
+
+			m = unstuff_bits(resp, 48, 22);
+			csd->capacity     = (1 + m) << 10;
+
+			csd->read_blkbits = 9;
+			break;
+		}
+	} else {
+		csd->mmca_vsn = unstuff_bits(resp, 122, 4);
+	}
+
+	return 0;
+}
+
+static void mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+	u32 caps = card->host->caps;
+	u8 card_type = ext_csd[EXT_CSD_CARD_TYPE];
+
+	card->ext_csd.sectors =
+		ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+		ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+		ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+		ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+
+	card->ext_csd.rev = ext_csd[EXT_CSD_REV];
+	card->ext_csd.boot_info = ext_csd[EXT_CSD_BOOT_INFO];
+	card->ext_csd.boot_part_sz = ext_csd[EXT_CSD_BOOT_SIZE_MULT] * 128 * 1024;
+	card->ext_csd.rpmb_sz = ext_csd[EXT_CSD_RPMB_SIZE_MULT] * 128 * 1024;
+
+	if (card->ext_csd.sectors)
+		mmc_card_set_blockaddr(card);
+
+	if (caps & MMC_CAP_EMMC_HS400 &&
+			card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+		card->ext_csd.hs400_support = 1;
+		card->ext_csd.hs_max_dtr = 200000000;
+	} else if (caps & MMC_CAP_EMMC_HS200 &&
+			card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
+		card->ext_csd.hs_max_dtr = 200000000;
+	} else if (caps & MMC_CAP_DDR &&
+			card_type & EXT_CSD_CARD_TYPE_DDR_52) {
+		card->ext_csd.ddr_support = 1;
+		card->ext_csd.hs_max_dtr = 52000000;
+	} else if (caps & MMC_CAP_MMC_HIGHSPEED &&
+			card_type & EXT_CSD_CARD_TYPE_52) {
+		card->ext_csd.hs_max_dtr = 52000000;
+	} else if (card_type & EXT_CSD_CARD_TYPE_26) {
+		card->ext_csd.hs_max_dtr = 26000000;
+	} else {
+		/* MMC v4 spec says this cannot happen */
+		dprintf(CRITICAL, "[eMMC] MMCv4 but HS unsupported\n");
+	}
+
+	card->ext_csd.part_cfg = ext_csd[EXT_CSD_PART_CFG];
+	card->ext_csd.sec_support = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
+	card->ext_csd.reset_en = ext_csd[EXT_CSD_RST_N_FUNC];
+}
+
+/* Read and decode extended CSD. */
+static int mmc_read_ext_csd(struct mmc_host *host, struct mmc_card *card)
+{
+	int err = MMC_ERR_NONE;
+	u8 *ext_csd;
+	int result = MMC_ERR_NONE;
+	struct mmc_data data;
+	struct mmc_command cmd = {
+		MMC_CMD_SEND_EXT_CSD, 0, RESP_R1, {0},
+		CMD_TIMEOUT, CMD_RETRIES, 0
+	};
+
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
+		dprintf(CRITICAL, "[eMMC] MMCA_VSN: %d. Skip EXT_CSD\n",
+				card->csd.mmca_vsn);
+		return MMC_ERR_NONE;
+	}
+
+	/*
+	 * As the ext_csd is so large and mostly unused, we don't store the
+	 * raw block in mmc_card.
+	 */
+	ext_csd = malloc(512);
+	ASSERT(ext_csd);
+	memset(ext_csd, 0, 512);
+
+	msdc_reset_tune_counter(host);
+
+	do {
+#ifdef MSDC_USE_DMA_MODE
+		MSDC_DMA_ON;
+#else
+		MSDC_DMA_OFF;
+#endif
+		MSDC_WRITE32(SDC_BLK_NUM, 1);
+		host->blklen = 512;
+		msdc_set_timeout(host, 100000000, 0);
+		err = mmc_cmd(host, &cmd);
+		if (err != MMC_ERR_NONE)
+			goto out;
+
+#ifdef MSDC_USE_DMA_MODE
+		data.cmd = &cmd;
+		data.blks = 1;
+		data.buf = ext_csd;
+		data.timeout = 100;
+		err = msdc_dma_transfer(host, &data);
+		MSDC_DMA_OFF;
+#else
+		err = msdc_pio_read(host, ext_csd, 512);
+#endif
+		if (err != MMC_ERR_NONE) {
+			if (msdc_abort_handler(host, 1))
+				dprintf(CRITICAL, "[eMMC] data abort failed\n");
+#ifdef FEATURE_MMC_RD_TUNING
+			result = msdc_tune_read(host);
+#endif
+		}
+	} while (err && result != MMC_ERR_READTUNEFAIL);
+	msdc_reset_tune_counter(host);
+	mmc_decode_ext_csd(card, ext_csd);
+
+out:
+	free(ext_csd);
+	return err;
+}
+
+static void mmc_set_clock(struct mmc_host *host, int state,
+				unsigned int hz)
+{
+	if (hz >= host->f_max) {
+		hz = host->f_max;
+	} else if (hz < host->f_min) {
+		hz = host->f_min;
+	}
+
+	msdc_config_clock(host, state, hz);
+}
+
+static int mmc_set_bus_width(struct mmc_host *host,
+				    struct mmc_card *card, int width)
+{
+	int err = MMC_ERR_NONE;
+	u32 arg = 0;
+	struct mmc_command cmd;
+
+	if (mmc_card_sd(card)) {
+		if (width == HOST_BUS_WIDTH_8) {
+			arg = SD_BUS_WIDTH_4;
+			width = HOST_BUS_WIDTH_4;
+		}
+
+		if ((width == HOST_BUS_WIDTH_4) &&
+		    (host->caps & MMC_CAP_4_BIT_DATA)) {
+			arg = SD_BUS_WIDTH_4;
+		} else {
+			arg = SD_BUS_WIDTH_1;
+			width = HOST_BUS_WIDTH_1;
+		}
+
+		cmd.opcode  = SD_ACMD_SET_BUSWIDTH;
+		cmd.arg     = arg;
+		cmd.rsptyp  = RESP_R1;
+		cmd.retries = CMD_RETRIES;
+		cmd.timeout = CMD_TIMEOUT;
+
+		err = mmc_app_cmd(host, &cmd, card->rca, 0);
+		if (err != MMC_ERR_NONE)
+			goto out;
+
+		msdc_config_bus(host, width);
+	} else if (mmc_card_mmc(card)) {
+
+		if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+			goto out;
+
+		if (width == HOST_BUS_WIDTH_8) {
+			if (host->caps & MMC_CAP_8_BIT_DATA) {
+				arg = EXT_CSD_BUS_WIDTH_8;
+			} else {
+				width = HOST_BUS_WIDTH_4;
+			}
+		}
+		if (width == HOST_BUS_WIDTH_4) {
+			if (host->caps & MMC_CAP_4_BIT_DATA) {
+				arg = EXT_CSD_BUS_WIDTH_4;
+			} else {
+				width = HOST_BUS_WIDTH_1;
+			}
+		}
+		if (width == HOST_BUS_WIDTH_1)
+			arg = EXT_CSD_BUS_WIDTH_1;
+
+		err = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_BUS_WIDTH, arg);
+		if (err != MMC_ERR_NONE) {
+			dprintf(CRITICAL, "[eMMC] Switch to bus width(%d) failed\n",
+				arg);
+			goto out;
+		}
+		mmc_card_clr_ddr(card);
+
+		msdc_config_bus(host, width);
+	}
+
+out:
+	return err;
+}
+
+static int mmc_set_ext_csd(struct mmc_card *card, u8 addr, u8 value)
+{
+	int err;
+
+	/* can't write */
+	if (192 <= addr || !card)
+		return MMC_ERR_INVALID;
+
+	err = mmc_switch(card->host, card, EXT_CSD_CMD_SET_NORMAL,
+		         addr, value);
+
+	if (err == MMC_ERR_NONE)
+		err = mmc_read_ext_csd(card->host, card);
+
+	return err;
+}
+
+static int mmc_set_reset_func(struct mmc_card *card, u8 enable)
+{
+	int err = MMC_ERR_FAILED;
+
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		goto out;
+
+	if (card->ext_csd.reset_en == 0) {
+		err = mmc_set_ext_csd(card, EXT_CSD_RST_N_FUNC, enable);
+		if (err == MMC_ERR_NONE)
+			card->ext_csd.reset_en = enable;
+	} else {
+		/* no need set */
+		return MMC_ERR_NONE;
+	}
+out:
+	return err;
+}
+
+static int mmc_set_boot_bus(struct mmc_card *card, u8 rst_bwidth,
+				  u8 mode, u8 bwidth)
+{
+	int err = MMC_ERR_FAILED;
+	u8 arg;
+
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		goto out;
+
+	arg = mode | rst_bwidth | bwidth;
+
+	err = mmc_set_ext_csd(card, EXT_CSD_BOOT_BUS_WIDTH, arg);
+out:
+	return err;
+}
+
+static int mmc_set_part_config(struct mmc_card *card, u8 cfg)
+{
+	int err = MMC_ERR_FAILED;
+
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		goto out;
+
+	err = mmc_set_ext_csd(card, EXT_CSD_PART_CFG, cfg);
+out:
+	return err;
+}
+
+static int mmc_switch_part(struct mmc_dev_t *dev)
+{
+	int err = MMC_ERR_NONE;
+	struct mmc_card *card;
+	struct mmc_host *host;
+	u8 cfg;
+
+	host = dev->host;
+	if (host->curr_part == dev->part_id)
+		/* already set to specific partition */
+		return MMC_ERR_NONE;
+
+	if (dev->part_id > EXT_CSD_PART_CFG_GP_PART_4) {
+		dprintf(CRITICAL, "[MSDC] Unsupported partid: %u\n",
+			dev->part_id);
+		return MMC_ERR_INVALID;
+	}
+
+	card = dev->card;
+	ASSERT(card);
+
+	cfg = card->ext_csd.part_cfg;
+	cfg = (cfg & ~0x7) | dev->part_id;
+	err = mmc_set_ext_csd(card, EXT_CSD_PART_CFG, cfg);
+	if (err)
+		dprintf(CRITICAL, "[MSDC] switch to part %u failed!\n",
+			dev->part_id);
+	card->ext_csd.part_cfg = cfg;
+
+	return err;
+}
+
+static int mmc_boot_config(struct mmc_card *card, u8 acken, u8 enpart,
+				 u8 buswidth, u8 busmode)
+{
+	int err = MMC_ERR_FAILED;
+	u8 val;
+	u8 rst_bwidth = 0;
+	u8 cfg;
+
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4 ||
+			!card->ext_csd.boot_info || card->ext_csd.rev < 3)
+		goto out;
+
+	cfg = card->ext_csd.part_cfg;
+	/* configure boot partition */
+	val = acken | enpart | (cfg & 0x7);
+	err = mmc_set_part_config(card, val);
+	if (err != MMC_ERR_NONE)
+		goto out;
+	else
+		card->ext_csd.part_cfg = val;
+
+	/* configure boot bus mode and width */
+	rst_bwidth = (buswidth != EXT_CSD_BOOT_BUS_WIDTH_1 ? 1 : 0) << 2;
+	dprintf(INFO, " =====Set boot Bus Width<%d>=======\n", buswidth);
+	dprintf(INFO, " =====Set boot Bus mode<%d>=======\n", busmode);
+	err = mmc_set_boot_bus(card, rst_bwidth, busmode, buswidth);
+out:
+
+	return err;
+}
+
+static int emmc_boot_prepare(struct mmc_card *card)
+{
+	int err = MMC_ERR_NONE;
+	u8 buswidth = EXT_CSD_BOOT_BUS_WIDTH_1;
+
+	err = mmc_boot_config(card, EXT_CSD_PART_CFG_EN_ACK,
+			EXT_CSD_PART_CFG_EN_BOOT_PART_1,
+			buswidth, EXT_CSD_BOOT_BUS_MODE_DEFT);
+	if (err)
+		goto exit;
+
+	err = mmc_set_reset_func(card, 1);
+exit:
+	return err;
+}
+
+static const u8 tuning_blk_pattern_4bit[] = {
+	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
+	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
+	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
+	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
+	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
+	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
+	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
+	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
+};
+
+static const u8 tuning_blk_pattern_8bit[] = {
+	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
+};
+
+int mmc_send_tuning(struct mmc_host *host, int *cmd_error)
+{
+	int err, ret = MMC_ERR_NONE;
+	const u8 *tuning_block_pattern;
+	u8 *tune_data;
+	u16 data_len;
+	struct mmc_command cmd;
+	struct mmc_data data;
+
+	cmd.opcode  = MMC_CMD21;
+	cmd.arg     = 0;
+	cmd.rsptyp  = RESP_R1;
+	cmd.retries = 0;
+	cmd.timeout = CMD_TIMEOUT;
+
+	if (host->caps & MMC_CAP_8_BIT_DATA) {
+		tuning_block_pattern = tuning_blk_pattern_8bit;
+		data_len = sizeof(tuning_blk_pattern_8bit);
+	} else {
+		tuning_block_pattern = tuning_blk_pattern_4bit;
+		data_len = sizeof(tuning_blk_pattern_4bit);
+	}
+
+	tune_data = (u8 *)malloc(512);
+	memset(tune_data, 0, data_len);
+	host->blklen = data_len;
+
+	MSDC_DMA_ON;
+	MSDC_WRITE32(SDC_BLK_NUM, 1);
+	msdc_set_timeout(host, 100000000, 0);
+
+	err = mmc_cmd(host, &cmd);
+	if (err) {
+		if(cmd_error)
+			*cmd_error = err;
+		ret = err;
+	}
+
+	data.cmd = &cmd;
+	data.blks = 1;
+	data.buf = (u8 *)tune_data;
+	data.timeout = 100; /* 100ms*/
+
+	err = msdc_dma_transfer(host, &data);
+	if (err) {
+		ret = err;
+		goto out;
+	}
+
+	if (memcmp(tune_data, tuning_block_pattern, data_len)) {
+		dprintf(ALWAYS, "CMD21 compare error\n");
+		err = -EIO;
+	}
+
+out:
+	MSDC_DMA_OFF;
+	free(tune_data);
+
+	return ret;
+}
+
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int ret;
+
+	ret = mmc_set_bus_width(host, card, HOST_BUS_WIDTH_8);
+	if (ret != MMC_ERR_NONE) {
+		dprintf(CRITICAL, "failed to set bus width!\n");
+		return ret;
+	}
+
+	ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+			EXT_CSD_HS_TIMEING_HS200);
+	if (ret != MMC_ERR_NONE) {
+		dprintf(CRITICAL, "failed to switch to hs200 mode!\n");
+		return ret;
+	}
+
+	mmc_card_set_hs200(card);
+	mmc_set_clock(host, card->state, card->ext_csd.hs_max_dtr);
+
+	return 0;
+}
+
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int ret;
+
+	ret = msdc_tune_cmd_data(host);
+	if (ret == MMC_ERR_FAILED) {
+		dprintf(CRITICAL, "hs200 tuning cmd error!\n");
+		return ret;
+	}
+
+	return MMC_ERR_NONE;
+}
+
+static int mmc_select_hs400(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int ret;
+
+	msdc_prepare_hs400_tuning(host);
+
+	mmc_set_clock(host, card->state, 50000000);
+	ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+			EXT_CSD_HS_TIMEING_HS);
+	if (ret != MMC_ERR_NONE) {
+		dprintf(CRITICAL, "switch to high-speed from hs200 failed, err:%d\n",
+			ret);
+		return ret;
+	}
+
+	ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8_DDR);
+	if (ret != MMC_ERR_NONE) {
+		dprintf(CRITICAL, "switch to bus width for hs400 failed, err:%d\n",
+			ret);
+		return ret;
+	}
+
+	ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+			EXT_CSD_HS_TIMEING_HS400);
+	if (ret != MMC_ERR_NONE) {
+		dprintf(CRITICAL, "switch to hs400 failed, err:%d\n", ret);
+		return ret;
+	}
+	mmc_card_set_hs400(card);
+	mmc_set_clock(host, card->state, card->ext_csd.hs_max_dtr);
+
+	msdc_hs400_revert_pad_delay(host);
+
+	return ret;
+}
+
+static int mmc_erase_start(struct mmc_card *card, u32 blknr)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_ERASE_GROUP_START, 0, RESP_R1, {0}, CMD_TIMEOUT, 3, 0
+    };
+    if (mmc_card_sd(card))
+        cmd.opcode = MMC_CMD_ERASE_WR_BLK_START;
+    cmd.arg = blknr;
+    return mmc_cmd(card->host, &cmd);
+}
+
+static int mmc_erase_end(struct mmc_card *card, u32 blknr)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_ERASE_GROUP_END, 0, RESP_R1, {0}, CMD_TIMEOUT, 3, 0
+    };
+    if (mmc_card_sd(card))
+        cmd.opcode = MMC_CMD_ERASE_WR_BLK_END;
+    cmd.arg = blknr;
+    return mmc_cmd(card->host, &cmd);
+}
+
+static int mmc_erase(struct mmc_card *card, u32 arg)
+{
+    int err;
+    u32 status;
+    struct mmc_command cmd = {
+        MMC_CMD_ERASE, 0, RESP_R1B, {0}, CMD_TIMEOUT, 3, 0
+    };
+    if (mmc_card_sd(card))
+        arg = 0;
+    cmd.arg = arg;
+
+	if (arg & MMC_ERASE_SECURE_REQ) {
+		if (!(card->ext_csd.sec_support & EXT_CSD_SEC_FEATURE_ER_EN))
+			return MMC_ERR_INVALID;
+	}
+	if ((arg & MMC_ERASE_GC_REQ) || (arg & MMC_ERASE_TRIM)) {
+		if (!(card->ext_csd.sec_support & EXT_CSD_SEC_FEATURE_GB_CL_EN))
+			return MMC_ERR_INVALID;
+	}
+
+    err = mmc_cmd(card->host, &cmd);
+	if (err)
+		return err;
+
+	do {
+		err = mmc_send_status(card->host, card, &status);
+		if (err)
+			break;
+		if (R1_STATUS(status) != 0)
+			break;
+	} while (R1_CURRENT_STATE(status) == 7);
+
+	return err;
+}
+
+static int mmc_do_trim(struct mmc_card *card, off_t start_addr, size_t len)
+{
+	int err = MMC_ERR_NONE;
+	off_t end_addr;
+
+	if (len < card->blklen) {
+		dprintf(CRITICAL, "%s: invalid len: %ld\n", __func__, len);
+		return MMC_ERR_INVALID;
+	}
+
+	end_addr =((start_addr + len) / card->blklen - 1) * card->blklen;
+
+	if (mmc_card_highcaps(card)) {
+		start_addr >>= MMC_BLOCK_BITS_SHFT;
+		end_addr >>= MMC_BLOCK_BITS_SHFT;
+	}
+
+	err = mmc_erase_start(card, start_addr);
+	if (err)
+		goto error;
+
+	err = mmc_erase_end(card, end_addr);
+	if (err)
+		goto error;
+
+	err = mmc_erase(card, MMC_ERASE_TRIM);
+
+error:
+	if (err)
+		dprintf(CRITICAL, "%s: erase range (0x%llx~0x%llx) failed,Err<%d>\n",
+				__func__, start_addr, end_addr, err);
+
+	return err;
+}
+
+static int mmc_dev_bread(struct mmc_card *card, unsigned long blknr,
+			       u32 blkcnt, u8 *dst)
+{
+	struct mmc_host *host = card->host;
+	u32 blksz = host->blklen;
+	int tune = 0;
+	int retry = 3;
+	int err;
+	unsigned long src;
+
+	src = mmc_card_highcaps(card) ? blknr : blknr * blksz;
+
+	do {
+		if (!tune) {
+			err = host->blk_read(host, (uchar *)dst, src, blkcnt);
+		} else {
+#ifdef FEATURE_MMC_RD_TUNING
+			if (mmc_card_mmc(card) && mmc_card_hs400(card)) {
+				dprintf(CRITICAL,"start hs400 read tune\n");
+				err = msdc_tune_rw_hs400(host, (uchar *)dst, src, blkcnt, 0);
+			} else {
+				err = msdc_tune_bread(host, (uchar *)dst, src, blkcnt);
+			}
+#endif
+			if (err && (host->sclk > (host->f_max >> 4)))
+				mmc_set_clock(host, card->state, host->sclk >> 1);
+		}
+		if (err == MMC_ERR_NONE) {
+			break;
+		}
+
+		if (err == MMC_ERR_BADCRC ||
+		    err == MMC_ERR_ACMD_RSPCRC ||
+		    err == MMC_ERR_CMD_RSPCRC) {
+			tune = 1;
+			retry++;
+		} else if (err == MMC_ERR_READTUNEFAIL ||
+			   err == MMC_ERR_CMDTUNEFAIL) {
+			dprintf(CRITICAL, "[eMMC] Fail to tuning,%s",
+					(err == MMC_ERR_CMDTUNEFAIL) ?
+					"cmd tune failed!\n" : "read tune failed!\n");
+			break;
+		}
+	} while (retry--);
+
+	return err;
+}
+
+static int mmc_dev_bwrite(struct mmc_card *card, unsigned long blknr,
+		u32 blkcnt, const u8 *src)
+{
+	struct mmc_host *host = card->host;
+	u32 blksz = host->blklen;
+	u32 status;
+	int tune = 0;
+	int retry = 3;
+	int err;
+	unsigned long dst;
+
+	dst = mmc_card_highcaps(card) ? blknr : blknr * blksz;
+
+	do {
+		if (!tune) {
+			err = host->blk_write(host, dst, (uchar *)src, blkcnt);
+		} else {
+#ifdef FEATURE_MMC_WR_TUNING
+			if (mmc_card_mmc(card) && mmc_card_hs400(card)) {
+				dprintf(CRITICAL,"start hs400 write tune\n");
+				err = msdc_tune_rw_hs400(host, (uchar *)dst, (ulong)src, blkcnt, 1);
+			} else {
+				err = msdc_tune_bwrite(host, dst, (uchar *)src, blkcnt);
+			}
+#endif
+			if (err && (host->sclk > (host->f_max >> 4)))
+				mmc_set_clock(host, card->state, host->sclk >> 1);
+		}
+		if (err == MMC_ERR_NONE) {
+			do {
+				err = mmc_send_status(host, card, &status);
+				if (err) {
+					dprintf(CRITICAL, "[eMMC] Fail to send status %d\n",
+						err);
+					break;
+				}
+			} while (!(status & R1_READY_FOR_DATA) ||
+					(R1_CURRENT_STATE(status) == 7));
+			dprintf(INFO, "[eMMC] Write %d bytes (DONE)\n", blkcnt * blksz);
+			break;
+		}
+
+		if (err == MMC_ERR_BADCRC ||
+		    err == MMC_ERR_ACMD_RSPCRC ||
+		    err == MMC_ERR_CMD_RSPCRC) {
+			tune = 1;
+			retry++;
+		} else if (err == MMC_ERR_WRITETUNEFAIL ||
+		           err == MMC_ERR_CMDTUNEFAIL) {
+			dprintf(CRITICAL, "[eMMC] Fail to tuning,%s",
+					(err == MMC_ERR_CMDTUNEFAIL) ?
+					"cmd tune failed!\n" :
+					"write tune failed!\n");
+			break;
+		}
+	} while (retry--);
+
+	return err;
+}
+
+static ssize_t mmc_block_read(struct bdev *dev, void *buf, bnum_t block,
+		uint count)
+{
+	struct mmc_dev_t *__dev = (struct mmc_dev_t *)dev;
+	struct mmc_host *host = __dev->host;
+	struct mmc_card *card = __dev->card;
+	u32 maxblks = host->max_phys_segs;
+	u32 leftblks, totalblks = count;
+	ssize_t ret = 0;
+
+	mutex_acquire(&host->lock);
+	if (mmc_switch_part(__dev)) {
+		ret = ERR_IO;
+		goto done;
+	}
+
+	do {
+		leftblks = ((count > maxblks) ? maxblks : count);
+		if (mmc_dev_bread(card, (unsigned long)block, leftblks, buf)) {
+			ret = ERR_IO;
+			goto done;
+		}
+		block += leftblks;
+		buf += maxblks * dev->block_size;
+		count -= leftblks;
+	} while (count);
+
+	if (dev->block_size * totalblks > 0x7fffffffU)
+		/* ssize_t is defined as signed, should take a look here */
+		dprintf(CRITICAL, "[MSDC] %s: WARN! The return size is overflow! 0x%lx\n",
+				__func__, dev->block_size * totalblks);
+
+done:
+	mutex_release(&host->lock);
+	return ret ? ret : (ssize_t)dev->block_size * totalblks;
+}
+
+static ssize_t mmc_block_write(struct bdev *dev, const void *buf, bnum_t block,
+		uint count)
+{
+	struct mmc_dev_t *__dev = (struct mmc_dev_t *)dev;
+	struct mmc_host *host = __dev->host;
+	struct mmc_card *card = __dev->card;
+	u32 maxblks = host->max_phys_segs;
+	u32 leftblks, totalblks = count;
+	ssize_t ret = 0;
+
+	mutex_acquire(&host->lock);
+	if (mmc_switch_part(__dev)) {
+		ret = ERR_IO;
+		goto done;
+	}
+
+	do {
+		leftblks = ((count > maxblks) ? maxblks : count);
+		if (mmc_dev_bwrite(card, (unsigned long)block, leftblks, buf)) {
+			ret = ERR_IO;
+			goto done;
+		}
+		block += leftblks;
+		buf = (u8 *)buf + maxblks * dev->block_size;
+		count -= leftblks;
+	} while (count);
+
+	if (dev->block_size * totalblks > 0x7fffffffU)
+		/* ssize_t is defined as signed, should take a look here */
+		dprintf(CRITICAL, "[MSDC] %s: WARN! The return size is overflow! 0x%lx\n",
+				__func__, dev->block_size * totalblks);
+
+done:
+	mutex_release(&host->lock);
+	return ret ? ret: (ssize_t)dev->block_size * totalblks;
+}
+
+static ssize_t mmc_wrap_erase(struct bdev *bdev, off_t offset, size_t len)
+{
+	struct mmc_dev_t *dev = (struct mmc_dev_t *)bdev;
+	struct mmc_host *host = dev->host;
+	ssize_t ret = 0;
+
+	mutex_acquire(&host->lock);
+	if (mmc_switch_part(dev)) {
+		ret = ERR_IO;
+		goto done;
+	}
+
+	/* ATTENTION:
+	 * We use TRIM here, which is block-based(512B) wipping,
+	 * If using ERASE here, please ensure the offset & size are
+	 * erase-group aligned,
+	 * OTHERWISE, some valid data may be wiped. refer to JEDEC spec:
+	 * The Device will ignore all LSB's below the Erase Group size,
+	 * effectively ROUNDING the address DOWN to the Erase Group boundary. */
+	ASSERT(dev && len);
+	if ((offset % MMC_BLOCK_SIZE) || (len % MMC_BLOCK_SIZE)) {
+		dprintf(CRITICAL, "%s: offset(0x%llx)/len(%lu) is not block-aligned!\n",
+				__func__, offset, len);
+		ret = ERR_IO;
+		goto done;
+	}
+
+	ASSERT(dev->card);
+	if (mmc_do_trim(dev->card, offset, len)) {
+		ret = ERR_IO;
+		goto done;
+	}
+
+done:
+	mutex_release(&host->lock);
+	return ret ? ret: (ssize_t)len;
+}
+
+static ssize_t mmc_rpmb_dummy_read(struct bdev *dev, void *buf, bnum_t block,
+		uint count)
+{
+	return 0;
+}
+
+static ssize_t mmc_rpmb_dummy_write(struct bdev *dev, const void *buf, bnum_t block,
+		uint count)
+{
+	return 0;
+}
+
+static ssize_t mmc_rpmb_dummy_erase(struct bdev *bdev, off_t offset, size_t len)
+{
+	return 0;
+}
+
+static int mmc_set_block_count(struct mmc_host *host, unsigned int blockcount,
+		bool is_rel_write)
+{
+	struct mmc_command cmd = {0};
+
+	cmd.opcode = MMC_CMD_SET_BLOCK_COUNT;
+	cmd.arg = blockcount & 0x0000FFFF;
+	if (is_rel_write)
+		cmd.arg |= 1 << 31;
+	cmd.rsptyp = RESP_R1;
+
+	return mmc_cmd(host, &cmd);
+}
+
+static int mmc_rpmb_ioctl_cmd(struct bdev *dev, struct mmc_ioc_cmd *arg)
+{
+#if 0
+	struct mmc_dev_t *__dev = (struct mmc_dev_t *)dev;
+	struct mmc_host *host = __dev->host;
+	//struct mmc_card *card = __dev->card;
+	struct mmc_command cmd = {0};
+	struct mmc_data data = {0};
+	int ret = 0;
+	int old_autocmd = msdc_get_autocmd(host);
+
+	msdc_set_autocmd(host, 0);
+	cmd.opcode = arg->opcode;
+	cmd.arg = arg->arg;
+	cmd.rsptyp = arg->flags; /* arg->flags must be type of enum of RESP_NONE ~ RESP_R1B */
+
+	if (arg->blocks) {
+		ret = mmc_set_block_count(host, arg->blocks,
+				arg->write_flag & (1 << 31));
+		if (ret != MMC_ERR_NONE) {
+			dprintf(CRITICAL, "mmc cmd23 failed!\n");
+			goto out;
+		}
+	}
+
+	if (arg->blocks) {
+		MSDC_DMA_ON;
+		MSDC_WRITE32(SDC_BLK_NUM, arg->blocks);
+		host->blklen = 512;
+		msdc_set_timeout(host, 100000000, 0);
+		ret = mmc_cmd(host, &cmd);
+		if (ret != MMC_ERR_NONE) {
+			dprintf(CRITICAL, "mmc cmd failed\n");
+			goto out;
+		}
+
+		data.cmd = &cmd;
+		data.blks = arg->blocks;
+		data.buf = (uchar *)arg->data_ptr;
+		data.timeout = 100;
+		ret = msdc_dma_transfer(host, &data);
+		MSDC_DMA_OFF;
+
+	} else {
+		ret = mmc_cmd(host, &cmd);
+	}
+
+out:
+	msdc_set_autocmd(host, old_autocmd);
+	return ret;
+#endif
+	return 0;
+}
+
+static int mmc_rpmb_ioctl(struct bdev *dev, int request, void *argp)
+{
+	struct mmc_dev_t *__dev = (struct mmc_dev_t *)dev;
+	struct mmc_host *host = __dev->host;
+	int ret = 0;
+
+	mutex_acquire(&host->lock);
+	if (mmc_switch_part(__dev)) {
+		ret = ERR_IO;
+		goto done;
+	}
+
+	switch (request) {
+		case MMC_IOC_CMD:
+			ret = mmc_rpmb_ioctl_cmd(dev, (struct mmc_ioc_cmd *)argp);
+			break;
+		default:
+			ret = ERR_INVALID_ARGS;
+			break;
+	}
+
+done:
+	mutex_release(&host->lock);
+	return ret;
+}
+
+static int mmc_init_mem_card_stage1(struct mmc_host *host,
+		struct mmc_card *card, u32 ocr)
+{
+	int err;
+
+	/*
+	 * Sanity check the voltages that the card claims to
+	 * support.
+	 */
+	if (ocr & 0x7F)
+		ocr &= ~0x7F;
+
+	ocr = host->ocr = mmc_select_voltage(host, ocr);
+
+	/*
+	 * Can we support the voltage(s) of the card(s)?
+	 */
+	if (!host->ocr) {
+		err = MMC_ERR_FAILED;
+		goto out;
+	}
+
+	err = mmc_go_idle(host);
+	if (err != MMC_ERR_NONE) {
+		dprintf(CRITICAL, "[eMMC] Fail in GO_IDLE_STATE cmd\n");
+		goto out;
+	}
+
+	/* send interface condition */
+	if (mmc_card_sd(card))
+		err = mmc_send_if_cond(host, ocr);
+
+	/* host support HCS[30] */
+	ocr |= (1 << 30);
+
+	/* send operation condition */
+	if (mmc_card_sd(card)) {
+		err = mmc_send_app_op_cond_once(host, ocr, &card->ocr);
+	} else {
+		/* The extra bit indicates that we support high capacity */
+		err = mmc_send_op_cond_once(host, ocr, &card->ocr);
+	}
+
+out:
+	/* MMC_ERR_RETRY is not error */
+	return err;
+}
+
+static int mmc_init_mem_card_stage2(struct mmc_host *host,
+		struct mmc_card *card, bool retry_opcond)
+{
+	int err = MMC_ERR_NONE;
+	u32 ocr = host->ocr;
+
+	/* host support HCS[30] */
+	ocr |= (1 << 30);
+
+	if (retry_opcond) {
+		/* send operation condition */
+		if (mmc_card_sd(card)) {
+			err = mmc_send_app_op_cond(host, ocr, &card->ocr);
+		} else {
+			/* The extra bit indicates that we support high capacity */
+			err = mmc_send_op_cond(host, ocr, &card->ocr);
+		}
+	}
+
+	if (err != MMC_ERR_NONE) {
+		dprintf(INFO, "Fail in SEND_OP_COND cmd\n");
+		goto out;
+	}
+
+	/* set hcs bit if a high-capacity card */
+	card->state |= ((card->ocr >> 30) & 0x1) ? MMC_STATE_HIGHCAPS : 0;
+	/* send cid */
+	err = mmc_all_send_cid(host, card->raw_cid);
+	if (err != MMC_ERR_NONE) {
+		dprintf(CRITICAL, "[eMMC] Fail in SEND_CID cmd\n");
+		goto out;
+	}
+
+	/* assign a rca */
+	card->rca = 0x1;
+
+	/* set/send rca */
+	err = mmc_send_relative_addr(host, card, &card->rca);
+	if (err != MMC_ERR_NONE) {
+		dprintf(CRITICAL, "[eMMC] Fail in SEND_RCA cmd\n");
+		goto out;
+	}
+
+	/* send csd */
+	err = mmc_read_csds(host, card);
+	if (err != MMC_ERR_NONE) {
+		dprintf(CRITICAL, "[eMMC] Fail in SEND_CSD cmd\n");
+		goto out;
+	}
+	mmc_decode_csd(card);
+
+	/* select this card */
+	err = mmc_select_card(host, card);
+	if (err != MMC_ERR_NONE) {
+		dprintf(CRITICAL, "[eMMC] Fail in select card cmd\n");
+		goto out;
+	}
+
+	if (mmc_card_sd(card)) {
+		/* set bus width */
+		mmc_set_bus_width(host, card, HOST_BUS_WIDTH_4);
+		/* compute bus speed.  usd defalut speed */
+		card->maxhz = 26000000;
+		mmc_set_clock(host, card->state, card->maxhz);
+	} else {
+
+		/* send ext csd */
+		err = mmc_read_ext_csd(host, card);
+		if (err != MMC_ERR_NONE) {
+			dprintf(CRITICAL, "[eMMC] Fail in SEND_EXT_CSD cmd\n");
+			goto out;
+		}
+		if (host->caps & MMC_CAP_EMMC_HS200 ) {
+			err = mmc_select_hs200(card);
+			if (err != MMC_ERR_NONE)
+				goto select_hs;
+
+			err = mmc_hs200_tuning(card);
+			if (err != MMC_ERR_NONE)
+				goto select_hs;
+
+			if (host->caps & MMC_CAP_EMMC_HS400 &&
+			    card->ext_csd.hs400_support) {
+				err = mmc_select_hs400(card);
+				if (err != MMC_ERR_NONE)
+					goto select_hs;
+				goto card_init_done;
+			}
+		}
+
+select_hs:
+		/* activate high speed (if supported) */
+		if ((card->ext_csd.hs_max_dtr != 0) && (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
+			mmc_set_clock(host, 0, host->f_min);
+			err = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
+			if (err == MMC_ERR_NONE) {
+				dprintf(INFO, "[eMMC] Switched to High-Speed mode!\n");
+				mmc_card_clear_hs200(card);
+				mmc_card_clear_hs400(card);
+				mmc_card_clear_ddr(card);
+				mmc_card_set_highspeed(card);
+				mmc_set_clock(host, card->state, 50000000);
+				/* set bus width */
+				mmc_set_bus_width(host, card, HOST_BUS_WIDTH_8);
+			}
+		}
+
+card_init_done:
+		/* compute bus speed. */
+		card->maxhz = (unsigned int)-1;
+
+		if (mmc_card_highspeed(card) || mmc_card_hs400(card)) {
+			if (card->maxhz > card->ext_csd.hs_max_dtr)
+				card->maxhz = card->ext_csd.hs_max_dtr;
+		} else if (card->maxhz > card->csd.max_dtr) {
+			card->maxhz = card->csd.max_dtr;
+		}
+	}
+
+	if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
+		/* The EXT_CSD sector count is in number or 512 byte sectors. */
+		card->blklen = MMC_BLOCK_SIZE;
+		card->nblks  = card->ext_csd.sectors;
+	} else {
+		/* The CSD capacity field is in units of read_blkbits.
+		 * set_capacity takes units of 512 bytes.
+		 */
+		card->blklen = MMC_BLOCK_SIZE;
+		host->blklen = MMC_BLOCK_SIZE;
+		card->nblks  = card->csd.capacity << (card->csd.read_blkbits - 9);
+	}
+
+	dprintf(CRITICAL,"[eMMC/SD] Size: %d MB, Max.Speed: %d kHz, blklen(%d), nblks(%d), ro(%d)\n",
+			((card->nblks / 1024) * card->blklen) / 1024 , card->maxhz / 1000,
+			card->blklen, card->nblks, mmc_card_readonly(card));
+
+	card->ready = 1;
+
+	dprintf(INFO, "[eMMC/SD] Initialized\n");
+out:
+	return err;
+}
+
+static int mmc_init_card_stage1(struct mmc_host *host, struct mmc_card *card)
+{
+	int err;
+	u32 ocr;
+
+	dprintf(INFO, "[%s]: start\n", __func__);
+	memset(card, 0, sizeof(struct mmc_card));
+
+	mmc_card_set_present(card);
+	mmc_card_set_host(card, host);
+	mmc_card_set_unknown(card);
+
+	err = mmc_go_idle(host);
+	if (err != MMC_ERR_NONE) {
+		dprintf(CRITICAL, "[eMMC] Fail in GO_IDLE_STATE cmd\n");
+		goto out;
+	}
+
+	/* send interface condition */
+	if (host->host_id)
+		mmc_send_if_cond(host, host->ocr_avail);
+
+	/* query operation condition */
+
+	if (host->host_id) {
+		err = mmc_send_app_op_cond(host, 0, &ocr);
+		if (err != MMC_ERR_NONE) {
+			err = mmc_send_op_cond(host, 0, &ocr);
+			if (err != MMC_ERR_NONE) {
+				dprintf(INFO, "Fail in MMC_CMD_SEND_OP_COND/SD_ACMD_SEND_OP_COND cmd\n");
+				goto out;
+			}
+			mmc_card_set_mmc(card);
+		} else {
+			mmc_card_set_sd(card);
+		}
+	} else {
+		err = mmc_send_op_cond(host, 0, &ocr);
+		if (err != MMC_ERR_NONE) {
+			dprintf(INFO, "Fail in MMC_CMD_SEND_OP_COND/SD_ACMD_SEND_OP_COND cmd\n");
+			goto out;
+		}
+		mmc_card_set_mmc(card);
+	}
+
+	host->card = card;
+	err = mmc_init_mem_card_stage1(host, card, ocr);
+
+out:
+	return err;
+}
+
+static int mmc_init_card_stage2(struct mmc_host *host, struct mmc_card *card,
+		bool retry_opcond)
+{
+	int err;
+
+	err = mmc_init_mem_card_stage2(host, card, retry_opcond);
+	if (err) {
+		dprintf(CRITICAL, "[%s]: failed, err=%d\n", __func__, err);
+		return err;
+	}
+	host->card = card;
+	dprintf(INFO, "[%s]: finish successfully\n",__func__);
+	return 0;
+}
+
+static inline int mmc_init_host(struct mmc_host *host)
+{
+	mutex_init(&host->lock);
+	return msdc_init(host);
+}
+
+static void mmc_bio_ops(const void *name, const int part_id, const int nblks,
+		struct mmc_host *host, struct mmc_card *card)
+{
+	struct mmc_dev_t *dev;
+
+	dev = malloc(sizeof(struct mmc_dev_t));
+	/* malloc fail */
+	ASSERT(dev);
+	/* construct the block device */
+	memset(dev, 0, sizeof(struct mmc_dev_t));
+
+	/* setup partition id*/
+	dev->part_id = part_id;
+	/* setup host */
+	dev->host = host;
+	/* setup card */
+	dev->card = card;
+	/* bio block device register */
+	bio_initialize_bdev(&dev->bdev, name,
+			card->blklen, nblks,
+			0, NULL, BIO_FLAGS_NONE);
+	/* override our block device hooks */
+	if (part_id == EXT_CSD_PART_CFG_RPMB_PART) {
+		dev->bdev.read_block = mmc_rpmb_dummy_read;
+		dev->bdev.write_block = mmc_rpmb_dummy_write;
+		dev->bdev.erase = mmc_rpmb_dummy_erase;
+		dev->bdev.ioctl = mmc_rpmb_ioctl;
+	} else {
+		dev->bdev.read_block = mmc_block_read;
+		dev->bdev.write_block = mmc_block_write;
+		dev->bdev.erase = mmc_wrap_erase;
+	}
+	bio_register_device(&dev->bdev);
+	partition_publish(dev->bdev.name, 0x0);
+}
+
+struct mmc_card *emmc_init_stage1(bool *retry_opcond)
+{
+	int err = MMC_ERR_NONE;
+	struct mmc_host *host;
+	struct mmc_card *card;
+
+	host = &msdc_host0;
+	/* construct the block device */
+	memset(host, 0, sizeof(struct mmc_host));
+	host->host_id = 0;
+
+	card = &emmc_card;
+	/* construct the block device */
+	memset(card, 0, sizeof(struct mmc_card));
+
+	err = mmc_init_host(host);
+
+	if (err == MMC_ERR_NONE)
+		err = mmc_init_card_stage1(host, card);
+
+	if (err && err != MMC_ERR_RETRY) {
+		dprintf(CRITICAL, "failed in %s \n", __func__);
+		return NULL;
+	} else if (err == MMC_ERR_RETRY) {
+		*retry_opcond = true;
+	} else {
+		*retry_opcond = false;
+	}
+
+	return card;
+}
+
+int emmc_init_stage2(struct mmc_card *card, bool retry_opcond)
+{
+	int err = MMC_ERR_NONE;
+	struct mmc_host *host;
+	int boot_part_nblks = 0;
+	int rpmb_part_nblks = 0;
+
+	host = card->host;
+	err = mmc_init_card_stage2(host, card, retry_opcond);
+	/* mmc init fail */
+	ASSERT(err == MMC_ERR_NONE);
+
+	err = emmc_boot_prepare(card);
+	ASSERT(err == MMC_ERR_NONE);
+
+	mmc_bio_ops("mmc0", EXT_CSD_PART_CFG_DEFT_PART, card->nblks, host, card);
+	boot_part_nblks = card->ext_csd.boot_part_sz/card->blklen;
+	mmc_bio_ops("mmc0boot0", EXT_CSD_PART_CFG_BOOT_PART_1, boot_part_nblks,
+			host, card);
+	mmc_bio_ops("mmc0boot1", EXT_CSD_PART_CFG_BOOT_PART_2, boot_part_nblks,
+			host, card);
+	rpmb_part_nblks = card->ext_csd.rpmb_sz/card->blklen;
+	mmc_bio_ops("mmc0rpmb", EXT_CSD_PART_CFG_RPMB_PART, rpmb_part_nblks,
+			host, card);
+
+	return err;
+}
+
+int sdmmc_init(u8 host_id)
+{
+	int err = MMC_ERR_NONE;
+	struct mmc_host *host;
+	struct mmc_card *card;
+	bool retry_opcond;
+
+	dprintf(CRITICAL, "%s enter %d\n", __func__, host_id);
+
+	host = malloc(sizeof(struct mmc_host));
+	/* malloc fail */
+	if (!host) {
+		dprintf(INFO, "Failed to malloc host!\n");
+		err = -ENOMEM;
+		goto end;
+	}
+	/* construct the block device */
+	memset(host, 0, sizeof(struct mmc_host));
+	host->host_id = host_id;
+
+	card = malloc(sizeof(struct mmc_card));
+	/* malloc fail */
+	if (!card) {
+		dprintf(INFO, "Failed to malloc card!\n");
+		free(host);
+		err = -ENOMEM;
+		goto end;
+	}
+	/* construct the block device */
+	memset(card, 0, sizeof(struct mmc_card));
+
+	err = mmc_init_host(host);
+
+	if (err == MMC_ERR_NONE)
+		err = mmc_init_card_stage1(host, card);
+	/* mmc init fail */
+	if (err && err != MMC_ERR_RETRY) {
+		dprintf(INFO, "mmc_init_card fail!\n");
+		free(host);
+		free(card);
+		goto end;
+	} else if (err == MMC_ERR_RETRY) {
+		retry_opcond = true;
+	} else {
+		retry_opcond = false;
+	}
+
+	err = mmc_init_card_stage2(host, card, retry_opcond);
+	if (err != MMC_ERR_NONE) {
+		dprintf(INFO, "mmc_init_card fail!\n");
+		free(host);
+		free(card);
+		goto end;
+	}
+	mmc_bio_ops("sdmmc1", EXT_CSD_PART_CFG_DEFT_PART, card->nblks, host, card);
+
+end:
+	return err;
+}
+
+#pragma GCC pop_options
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/mmc/msdc.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/mmc/msdc.c
new file mode 100644
index 0000000..3eaa0c4
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/mmc/msdc.c
@@ -0,0 +1,2243 @@
+/*
+ * 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.
+ */
+#define MSDC_DEBUG_KICKOFF
+
+#include <platform/msdc.h>
+#include <platform/mmc_core.h>
+#include <kernel/event.h>
+#include <kernel/vm.h>
+#include <platform/interrupts.h>
+#include <platform/mt_irq.h>
+#include <string.h>
+#include <assert.h>
+
+#pragma GCC push_options
+#pragma GCC optimize("O1")
+
+struct msdc_delay_phase {
+	u8 maxlen;
+	u8 start;
+	u8 final_phase;
+}__attribute__((aligned(8)));
+
+struct msdc_priv_t{
+	int autocmd;
+	int rdsmpl;
+	int wdsmpl;
+	int rsmpl;
+	int start_bit;
+};
+
+static int msdc_rsp[] = {
+	0,  /* RESP_NONE */
+	1,  /* RESP_R1 */
+	2,  /* RESP_R2 */
+	3,  /* RESP_R3 */
+	4,  /* RESP_R4 */
+	1,  /* RESP_R5 */
+	1,  /* RESP_R6 */
+	1,  /* RESP_R7 */
+	7,  /* RESP_R1b */
+};
+
+struct msdc_cust {
+	unsigned char  clk_src;           /* host clock source */
+	unsigned char  hclk_src;          /* host clock source */
+	unsigned char  cmd_edge;          /* command latch edge */
+	unsigned char  data_edge;         /* data latch edge */
+#define MSDC_SMPL_RISING        (0)
+#define MSDC_SMPL_FALLING       (1)
+#define MSDC_SMPL_SEPERATE      (2)
+	unsigned char  clk_drv;           /* clock pad driving */
+	unsigned char  cmd_drv;           /* command pad driving */
+	unsigned char  dat_drv;           /* data pad driving */
+	unsigned char  rst_drv;           /* reset pin pad driving */
+	unsigned char  ds_drv;            /* ds pad driving */
+	unsigned char  data_pins;         /* data pins */
+	unsigned int   data_offset;       /* data address offset */
+	unsigned int   flags;             /* hardware capability flags */
+#define MSDC_CD_PIN_EN      (1 << 0)  /* card detection pin is wired   */
+#define MSDC_WP_PIN_EN      (1 << 1)  /* write protection pin is wired */
+#define MSDC_RST_PIN_EN     (1 << 2)  /* emmc reset pin is wired */
+#define MSDC_SDIO_IRQ       (1 << 3)  /* use internal sdio irq (bus) */
+#define MSDC_EXT_SDIO_IRQ   (1 << 4)  /* use external sdio irq */
+#define MSDC_REMOVABLE      (1 << 5)  /* removable slot */
+#define MSDC_SYS_SUSPEND    (1 << 6)  /* suspended by system */
+#define MSDC_HIGHSPEED      (1 << 7)  /* high-speed mode support */
+#define MSDC_UHS1           (1 << 8)  /* uhs-1 mode support */
+#define MSDC_DDR            (1 << 9)  /* ddr mode support */
+#define MSDC_HS200          (1 << 10) /* hs200 mode support(eMMC4.5) */
+#define MSDC_HS400          (1 << 11) /* hs200 mode support(eMMC5.0) */
+} msdc_cap[2] = {
+    {
+        MSDC50_CLKSRC_DEFAULT,     /* host clock source */
+        MSDC50_CLKSRC4HCLK_273MHZ, /* host clock source */
+        MSDC_SMPL_RISING,          /* command latch edge */
+        MSDC_SMPL_RISING,   	   /* data latch edge */
+        MSDC_DRVN_GEAR3,           /* clock pad driving */
+        MSDC_DRVN_GEAR3,           /* command pad driving */
+        MSDC_DRVN_GEAR3,           /* data pad driving */
+        MSDC_DRVN_GEAR3,           /* rst pad driving */
+        MSDC_DRVN_GEAR3,           /* ds pad driving */
+        8,                         /* data pins */
+        0,                         /* data address offset */
+        MSDC_HIGHSPEED | MSDC_HS200 | MSDC_HS400
+    },
+
+    {
+        MSDC50_CLKSRC_DEFAULT,     /* host clock source */
+        MSDC50_CLKSRC4HCLK_273MHZ, /* host clock source */
+        MSDC_SMPL_RISING,   	   /* command latch edge */
+        MSDC_SMPL_RISING,          /* data latch edge */
+        MSDC_DRVN_GEAR2,           /* clock pad driving */
+        MSDC_DRVN_GEAR2,           /* command pad driving */
+        MSDC_DRVN_GEAR2,           /* data pad driving */
+        MSDC_DRVN_GEAR2,           /* rst pad driving */
+        MSDC_DRVN_GEAR2,           /* ds pad driving */
+        4,                         /* data pins */
+        0,                         /* data address offset */
+        MSDC_HIGHSPEED
+    },
+};
+
+static event_t msdc_int_event;
+static u32 g_int_status = 0;
+static struct msdc_priv_t msdc_priv;
+
+#ifndef FPGA_PLATFORM
+static u32 hclks_msdc30[] = {
+	26000000, 208000000, 200000000, 156000000,
+        182000000, 156000000, 178280000
+};
+
+/* add function for MSDC_PAD_CTL handle */
+static void msdc_set_smt(struct mmc_host *host, int smt)
+{
+	if (smt)
+		MSDC_SET_FIELD(MSDC0_SMT_ADDR, MSDC0_SMT_MASK, 0x1F);
+	else
+		MSDC_SET_FIELD(MSDC0_SMT_ADDR, MSDC0_SMT_MASK, 0);
+}
+
+static void msdc_set_ies(struct mmc_host *host, int ies)
+{
+	if (ies)
+		MSDC_SET_FIELD(MSDC0_IES_ADDR, MSDC0_IES_MASK, 0x1F);
+	else
+		MSDC_SET_FIELD(MSDC0_IES_ADDR, MSDC0_IES_MASK, 0);
+}
+
+/* pull up means that host driver the line to HIGH
+ * pull down means that host driver the line to LOW */
+static void msdc_pin_set(struct mmc_host *host)
+{
+	/* driver CLK/DAT pin */
+	ASSERT(host);
+
+	MSDC_SET_FIELD(MSDC0_PULLEN_ADDR, MSDC0_PULLEN_MASK, 0xFFF);
+	MSDC_SET_FIELD(MSDC0_PULLSEL_ADDR, MSDC0_PULLSEL_MASK, 0xDFB);
+	MSDC_SET_FIELD(MSDC0_PUPD0_ADDR, 0xFFFFFFFF, 0x11111611);
+	MSDC_SET_FIELD(MSDC0_PUPD1_ADDR, 0xFFFF, 0x1161);
+}
+
+/* host can modify from 0-7 */
+static void msdc_set_driving(struct mmc_host *host, struct msdc_cust *msdc_cap)
+{
+	ASSERT(host);
+	ASSERT(msdc_cap);
+
+	if (host && msdc_cap) {
+		MSDC_SET_FIELD(MSDC0_DRV7_ADDR, MSDC0_CLK_DRV_MASK, msdc_cap->clk_drv);
+		MSDC_SET_FIELD(MSDC0_DRV7_ADDR, MSDC0_CMD_DRV_MASK, msdc_cap->cmd_drv);
+		MSDC_SET_FIELD(MSDC0_DRV7_ADDR, MSDC0_DAT_DRV_MASK, msdc_cap->dat_drv);
+		MSDC_SET_FIELD(MSDC0_DRV7_ADDR, MSDC0_DSL_DRV_MASK, msdc_cap->ds_drv);
+	}
+}
+
+static void msdc_set_pin_mode(struct mmc_host *host)
+{
+	ASSERT(host);
+	MSDC_SET_FIELD(MSDC0_GPIO_MODE16_ADDR, (0xFFFFFF << 8), 0x111111);
+	MSDC_SET_FIELD(MSDC0_GPIO_MODE17_ADDR, (0xFFFFFF), 0x111111);
+}
+
+
+static void msdc_gpio_and_pad_init(struct mmc_host *host)
+{
+	/*set smt enable*/
+	msdc_set_smt(host, 1);
+
+	/*set ies enable*/
+	msdc_set_ies(host, 1);
+
+	/*set pupd enable*/
+	msdc_pin_set(host);
+
+	/* set gpio to msdc mode*/
+	msdc_set_pin_mode(host);
+
+	/*set driving*/
+	msdc_set_driving(host, &msdc_cap[host->host_id]);
+
+}
+
+static int pmic_config_interface(int a, int b, int c, int d)
+{
+	return 0;
+}
+
+static void msdc_set_card_pwr(struct mmc_host *host, int on)
+{
+	int ret;
+
+	/* VMCH=3.3V */
+	ret = pmic_config_interface(0xAB,0x7,0x7,4);
+
+	if (ret == 0) {
+		if (on) {
+			/* VMCH_EN=1 */
+			ret = pmic_config_interface(0xAB,0x1,0x1,0);
+		} else {
+			/* VMCH_EN=0 */
+			ret = pmic_config_interface(0xAB,0x0,0x1,0);
+		}
+	}
+
+	if (ret != 0) {
+		dprintf(CRITICAL, "PMIC: Set MSDC Host Power Fail\n");
+	} else {
+		spin(3000);
+	}
+}
+
+static void msdc_set_host_pwr(struct mmc_host *host, int on)
+{
+	int ret;
+
+	/* VMC=3.3V */
+	ret = pmic_config_interface(0xA7,0x7,0x7,4);
+
+	if (ret == 0) {
+		if (on) {
+			/* VMC_EN=1 */
+			ret = pmic_config_interface(0xA7,0x1,0x1,0);
+		} else {
+			/* VMC_EN=0 */
+			ret = pmic_config_interface(0xA7,0x0,0x1,0);
+		}
+	}
+
+	if (ret != 0)
+		dprintf(CRITICAL, "PMIC: Set MSDC Card Power Fail\n");
+}
+#else
+#define PWR_GPIO            (0x10001E84)
+#define PWR_GPIO_EO         (0x10001E88)
+
+#define PWR_MASK_EN         (0x1 << 8)
+#define PWR_MASK_VOL_18     (0x1 << 9)
+#define PWR_MASK_VOL_33     (0x1 << 10)
+#define PWR_MASK_L4         (0x1 << 11)
+#define PWR_MSDC_DIR        (PWR_MASK_EN | PWR_MASK_VOL_18 | PWR_MASK_VOL_33 | PWR_MASK_L4)
+
+#define MSDC0_PWR_MASK_EN         (0x1 << 12)
+#define MSDC0_PWR_MASK_VOL_18     (0x1 << 13)
+#define MSDC0_PWR_MASK_VOL_33     (0x1 << 14)
+#define MSDC0_PWR_MASK_L4         (0x1 << 15)
+#define MSDC0_PWR_MSDC_DIR        (MSDC0_PWR_MASK_EN | MSDC0_PWR_MASK_VOL_18 | MSDC0_PWR_MASK_VOL_33 | MSDC0_PWR_MASK_L4)
+
+static void msdc_clr_gpio(u32 bits)
+{
+	switch (bits) {
+		case MSDC0_PWR_MASK_EN:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_EN),0);
+			MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_EN),0);
+			break;
+		case MSDC0_PWR_MASK_VOL_18:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+			MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+			break;
+		case MSDC0_PWR_MASK_VOL_33:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+			MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+			break;
+		case MSDC0_PWR_MASK_L4:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    MSDC0_PWR_MASK_L4, 0);
+			MSDC_SET_FIELD(PWR_GPIO_EO, MSDC0_PWR_MASK_L4, 0);
+			break;
+		case PWR_MASK_EN:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_EN,0);
+			MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_EN,0);
+			break;
+		case PWR_MASK_VOL_18:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+			MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+			break;
+		case PWR_MASK_VOL_33:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+			MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+			break;
+		case PWR_MASK_L4:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_L4, 0);
+			MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_L4, 0);
+			break;
+		default:
+			dprintf(CRITICAL, "[%s:%s]invalid value: 0x%x\n", __FILE__, __func__, bits);
+			break;
+	}
+}
+
+static void msdc_set_gpio(u32 bits)
+{
+	switch (bits) {
+		case MSDC0_PWR_MASK_EN:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    MSDC0_PWR_MASK_EN,1);
+			MSDC_SET_FIELD(PWR_GPIO_EO, MSDC0_PWR_MASK_EN,1);
+			break;
+		case MSDC0_PWR_MASK_VOL_18:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 1);
+			MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 1);
+			break;
+		case MSDC0_PWR_MASK_VOL_33:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 2);
+			MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 2);
+			break;
+		case MSDC0_PWR_MASK_L4:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    MSDC0_PWR_MASK_L4, 1);
+			MSDC_SET_FIELD(PWR_GPIO_EO, MSDC0_PWR_MASK_L4, 1);
+			break;
+		case PWR_MASK_EN:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_EN,1);
+			MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_EN,1);
+			break;
+		case PWR_MASK_VOL_18:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 1);
+			MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 1);
+			break;
+		case PWR_MASK_VOL_33:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 2);
+			MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 2);
+			break;
+		case PWR_MASK_L4:
+			/* check for set before */
+			MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_L4, 1);
+			MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_L4, 1);
+			break;
+		default:
+			dprintf(CRITICAL, "[%s:%s]invalid value: 0x%x\n", __FILE__, __func__, bits);
+			break;
+	}
+}
+
+static void msdc_set_card_pwr(struct mmc_host *host, int on)
+{
+	if (on) {
+		msdc_set_gpio(MSDC0_PWR_MASK_VOL_18);
+		msdc_set_gpio(MSDC0_PWR_MASK_L4);
+		msdc_set_gpio(MSDC0_PWR_MASK_EN);
+	} else {
+		msdc_clr_gpio(MSDC0_PWR_MASK_EN);
+		msdc_clr_gpio(MSDC0_PWR_MASK_VOL_18);
+		msdc_clr_gpio(MSDC0_PWR_MASK_L4);
+	}
+	spin(10000);
+}
+
+static void msdc_set_host_level_pwr(struct mmc_host *host, u32 level)
+{
+	msdc_clr_gpio(PWR_MASK_VOL_18);
+	msdc_clr_gpio(PWR_MASK_VOL_33);
+
+	if (level) {
+		msdc_set_gpio(PWR_MASK_VOL_18);
+	} else {
+		msdc_set_gpio(PWR_MASK_VOL_33);
+	}
+	msdc_set_gpio(PWR_MASK_L4);
+}
+
+static void msdc_set_host_pwr(struct mmc_host *host, int on)
+{
+	msdc_set_host_level_pwr(host, 0);
+}
+#endif
+
+static void msdc_set_startbit(struct mmc_host *host, u8 start_bit)
+{
+	struct msdc_priv_t *priv = (struct msdc_priv_t *)host->priv;
+
+	/* set start bit */
+	MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_START_BIT, start_bit);
+	priv->start_bit = start_bit;
+	dprintf(INFO, "start bit = %d, MSDC_CFG[0x%x]\n",
+		start_bit, MSDC_READ32(MSDC_CFG));
+}
+
+static void msdc_set_smpl(struct mmc_host *host, u8 HS400,
+				u8 mode, u8 type)
+{
+	int i=0;
+	struct msdc_priv_t *priv = (struct msdc_priv_t *)host->priv;
+	static u8 read_data_edge[8] = {
+		MSDC_SMPL_RISING, MSDC_SMPL_RISING,
+		MSDC_SMPL_RISING, MSDC_SMPL_RISING,
+		MSDC_SMPL_RISING, MSDC_SMPL_RISING,
+		MSDC_SMPL_RISING, MSDC_SMPL_RISING
+	};
+	static u8 write_data_edge[4] = {
+		MSDC_SMPL_RISING, MSDC_SMPL_RISING,
+		MSDC_SMPL_RISING, MSDC_SMPL_RISING
+	};
+
+	switch (type) {
+		case TYPE_CMD_RESP_EDGE:
+			if (HS400) {
+				/* eMMC5.0 only output resp at CLK pin, so no need to select DS pin */
+				/* latch cmd resp at CLK pin */
+				MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_PADCMD_LATCHCK, 0);
+				MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CMD_RESP_SEL, 0);
+			}
+
+			if (mode == MSDC_SMPL_RISING || mode == MSDC_SMPL_FALLING) {
+				MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, mode);
+				priv->rsmpl = mode;
+			} else {
+				dprintf(CRITICAL, "[%s]: invalid resp parameter: HS400=%d, type=%d, mode=%d\n",
+					__func__, HS400, type, mode);
+			}
+			break;
+
+		case TYPE_WRITE_CRC_EDGE:
+			if (HS400) {
+				/* latch write crc status at DS pin */
+				MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_SEL, 1);
+			} else {
+				/* latch write crc status at CLK pin */
+				MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_SEL, 0);
+			}
+
+			if (mode == MSDC_SMPL_RISING ||
+			    mode == MSDC_SMPL_FALLING) {
+				if (HS400) {
+					MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_EDGE, mode);
+				} else {
+					MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL_SEL, 0);
+					MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL, mode);
+				}
+				priv->wdsmpl = mode;
+			} else if (mode == MSDC_SMPL_SEPERATE && !HS400) {
+				/* only dat0 is for write crc status. */
+				MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D0SPL, write_data_edge[0]);
+				priv->wdsmpl = mode;
+			} else {
+				dprintf(CRITICAL, "[%s]: invalid crc parameter: HS400=%d, type=%d, mode=%d\n",
+					__func__, HS400, type, mode);
+			}
+			break;
+
+		case TYPE_READ_DATA_EDGE:
+			if (HS400) {
+				/* for HS400, start bit is output both on rising and falling edge */
+				msdc_set_startbit(host, START_AT_RISING_AND_FALLING);
+				priv->start_bit = START_AT_RISING_AND_FALLING;
+			} else {
+				/* for the other mode, start bit is only output on rising edge.
+				but DDR50 can try falling edge if error casued by pad delay */
+				msdc_set_startbit(host, START_AT_RISING);
+				priv->start_bit = START_AT_RISING;
+			}
+			if (mode == MSDC_SMPL_RISING || mode == MSDC_SMPL_FALLING) {
+				MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL_SEL, 0);
+				MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL, mode);
+				priv->rdsmpl = mode;
+			} else if (mode == MSDC_SMPL_SEPERATE) {
+				MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL_SEL, 1);
+				for (i=0; i<8; i++) {
+					MSDC_SET_FIELD(MSDC_IOCON, (MSDC_IOCON_R_D0SPL << i), read_data_edge[i]);
+				}
+				priv->rdsmpl = mode;
+			} else {
+				dprintf(CRITICAL, "[%s]: invalid read parameter: HS400=%d, type=%d, mode=%d\n",
+					__func__, HS400, type, mode);
+			}
+			break;
+
+		case TYPE_WRITE_DATA_EDGE:
+			/* latch write crc status at CLK pin */
+			MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_SEL, 0);
+
+			if (mode == MSDC_SMPL_RISING|| mode == MSDC_SMPL_FALLING) {
+				MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL_SEL, 0);
+				MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL, mode);
+				priv->wdsmpl = mode;
+			} else if (mode == MSDC_SMPL_SEPERATE) {
+				MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL_SEL, 1);
+				for (i=0; i<4; i++) {
+					/* dat0~4 is for SDIO card. */
+					MSDC_SET_FIELD(MSDC_IOCON, (MSDC_IOCON_W_D0SPL << i), write_data_edge[i]);
+				}
+				priv->wdsmpl = mode;
+			} else {
+				dprintf(CRITICAL, "[%s]: invalid write parameter: HS400=%d, type=%d, mode=%d\n",
+					__func__, HS400, type, mode);
+			}
+			break;
+
+		default:
+			dprintf(CRITICAL, "[%s]: invalid parameter: HS400=%d, type=%d, mode=%d\n",
+				__func__, HS400, type, mode);
+			break;
+	}
+}
+
+void msdc_set_timeout(struct mmc_host *host, u32 ns, u32 clks)
+{
+	u32 timeout, clk_ns;
+	u32 mode = 0;
+
+	if (host->sclk == 0) {
+		timeout = 0;
+	} else {
+		clk_ns  = 1000000000UL / host->sclk;
+		timeout = (ns + clk_ns - 1) / clk_ns + clks;
+		/* in 1048576 sclk cycle unit */
+		timeout = (timeout + (1 << 20) - 1) >> 20;
+		MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, mode);
+		/* DDR mode will double the clk cycles for data timeout */
+		timeout = mode >= 2 ? timeout * 2 : timeout;
+		timeout = timeout > 1 ? timeout - 1 : 0;
+		timeout = timeout > 255 ? 255 : timeout;
+	}
+	MSDC_SET_FIELD(SDC_CFG, SDC_CFG_DTOC, timeout);
+	dprintf(INFO, "[MSDC] Set read data timeout: %dns %dclks -> %d (65536 sclk cycles)\n",
+			ns, clks, timeout + 1);
+}
+
+void msdc_set_autocmd(struct mmc_host *host, int cmd)
+{
+	struct msdc_priv_t *priv = (struct msdc_priv_t *)host->priv;
+
+	priv->autocmd = cmd;
+}
+
+int msdc_get_autocmd(struct mmc_host *host)
+{
+	struct msdc_priv_t *priv = (struct msdc_priv_t *)host->priv;
+
+	return priv->autocmd;
+}
+
+static int msdc_send_cmd(struct mmc_host *host, struct mmc_command *cmd)
+{
+	struct msdc_priv_t *priv = (struct msdc_priv_t *)host->priv;
+	u32 opcode = cmd->opcode;
+	u32 rsptyp = cmd->rsptyp;
+	u32 rawcmd;
+	u32 error = MMC_ERR_NONE;
+
+	/* rawcmd :
+	 * vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 |
+	 * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode
+	 */
+	rawcmd = (opcode & ~(SD_CMD_BIT | SD_CMD_APP_BIT)) |
+		msdc_rsp[rsptyp] << 7 | host->blklen << 16;
+
+	if (opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
+		rawcmd |= ((2 << 11) | (1 << 13));
+		if (priv->autocmd & MSDC_AUTOCMD12) {
+			rawcmd |= (1 << 28);
+		} else if (priv->autocmd & MSDC_AUTOCMD23) {
+			rawcmd |= (2 << 28);
+		}
+	} else if (opcode == MMC_CMD_WRITE_BLOCK || opcode == MMC_CMD50) {
+		rawcmd |= ((1 << 11) | (1 << 13));
+	} else if (opcode == MMC_CMD_READ_MULTIPLE_BLOCK) {
+		rawcmd |= (2 << 11);
+		if (priv->autocmd & MSDC_AUTOCMD12) {
+			rawcmd |= (1 << 28);
+		} else if (priv->autocmd & MSDC_AUTOCMD23) {
+			rawcmd |= (2 << 28);
+		}
+	} else if (opcode == MMC_CMD_READ_SINGLE_BLOCK ||
+			opcode == SD_ACMD_SEND_SCR ||
+			opcode == SD_CMD_SWITCH ||
+			opcode == MMC_CMD_SEND_EXT_CSD ||
+			opcode == MMC_CMD_SEND_WRITE_PROT ||
+			opcode == MMC_CMD_SEND_WRITE_PROT_TYPE ||
+			opcode == MMC_CMD21) {
+		rawcmd |= (1 << 11);
+	} else if (opcode == MMC_CMD_STOP_TRANSMISSION) {
+		rawcmd |= (1 << 14);
+		rawcmd &= ~(0x0FFF << 16);
+	} else if (opcode == SD_IO_RW_EXTENDED) {
+		if (cmd->arg & 0x80000000)  /* R/W flag */
+			rawcmd |= (1 << 13);
+		if ((cmd->arg & 0x08000000) && ((cmd->arg & 0x1FF) > 1))
+			rawcmd |= (2 << 11); /* multiple block mode */
+		else
+			rawcmd |= (1 << 11);
+	} else if (opcode == SD_IO_RW_DIRECT) {
+		if ((cmd->arg & 0x80000000) && ((cmd->arg >> 9) & 0x1FFFF))
+			rawcmd |= (1 << 14); /* I/O abt */
+	} else if (opcode == SD_CMD_VOL_SWITCH) {
+		rawcmd |= (1 << 30);
+	} else if (opcode == SD_CMD_SEND_TUNING_BLOCK) {
+		rawcmd |= (1 << 11); /* CHECKME */
+		if (priv->autocmd & MSDC_AUTOCMD19)
+			rawcmd |= (3 << 28);
+	} else if (opcode == MMC_CMD_GO_IRQ_STATE) {
+		rawcmd |= (1 << 15);
+	} else if (opcode == MMC_CMD_WRITE_DAT_UNTIL_STOP) {
+		rawcmd |= ((1<< 13) | (3 << 11));
+	} else if (opcode == MMC_CMD_READ_DAT_UNTIL_STOP) {
+		rawcmd |= (3 << 11);
+	}
+
+	dprintf(INFO, "+[MSDC%d] CMD(%d): ARG(0x%x), RAW(0x%x), BLK_NUM(0x%x) RSP(%d)\n",
+		host->host_id, (opcode & ~(SD_CMD_BIT | SD_CMD_APP_BIT)),
+		cmd->arg, rawcmd, MSDC_READ32(SDC_BLK_NUM), rsptyp);
+
+	while (SDC_IS_CMD_BUSY());
+	if ((rsptyp == RESP_R1B) ||
+	    (opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK) ||
+	    (opcode == MMC_CMD_WRITE_BLOCK) ||
+	    (opcode == MMC_CMD_READ_MULTIPLE_BLOCK) ||
+	    (opcode == MMC_CMD_READ_SINGLE_BLOCK))
+		while (SDC_IS_BUSY());
+
+	SDC_SEND_CMD(rawcmd, cmd->arg);
+
+end:
+	cmd->error = error;
+
+	return error;
+}
+
+static int msdc_wait_cmd_done(struct mmc_host *host, struct mmc_command *cmd)
+{
+	u32 rsptyp = cmd->rsptyp;
+	u32 status;
+	u32 opcode = (cmd->opcode & ~(SD_CMD_BIT | SD_CMD_APP_BIT));
+	u32 error = MMC_ERR_NONE;
+	u32 wints = MSDC_INT_CMDTMO | MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR |
+		MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO;
+	u32 *resp = &cmd->resp[0];
+	struct msdc_priv_t *priv = (struct msdc_priv_t *)host->priv;
+
+	while (1) {
+		/* Wait for interrupt coming */
+		while (((status = MSDC_READ32(MSDC_INT)) & wints) == 0);
+		MSDC_WRITE32(MSDC_INT, (status & wints));
+		if (~wints & status)
+			dprintf(CRITICAL, "msdc_wait_cmd_done Unexpected INT(0x%x)\n",
+					~wints & status);
+
+		if (status & MSDC_INT_CMDRDY)
+			break;
+		else if (status & MSDC_INT_RSPCRCERR) {
+			if (opcode != MMC_CMD21)
+				dprintf(CRITICAL, "[MSDC] cmd%d CRCERR! (0x%x)\n",
+					opcode, status);
+			error = MMC_ERR_BADCRC;
+			goto err;
+		} else if (status & MSDC_INT_CMDTMO) {
+			dprintf(CRITICAL, "[MSDC] cmd%d TMO! (0x%x)\n",
+				opcode, status);
+			error = MMC_ERR_TIMEOUT;
+			goto err;
+		} else if (priv->autocmd & MSDC_AUTOCMD23) {
+			if (status & MSDC_INT_ACMDRDY)
+				/* Autocmd rdy is set prior to cmd rdy */
+				continue;
+			else if (status & MSDC_INT_ACMDCRCERR) {
+				dprintf(CRITICAL, "[MSDC] autocmd23 CRCERR! (0x%x)\n",
+					status);
+				error = MMC_ERR_ACMD_RSPCRC;
+				goto err;
+			} else if (status & MSDC_INT_ACMDTMO) {
+				dprintf(CRITICAL, "[MSDC] autocmd23 TMO! (0x%x)\n",
+					status);
+				error = MMC_ERR_ACMD_TIMEOUT;
+				goto err;
+			}
+		} else {
+			dprintf(CRITICAL, "[MSDC] cmd%d UNEXPECT status! (0x%x)\n",
+					opcode, status);
+			error = MMC_ERR_UNEXPECT;
+			goto err;
+		}
+	}
+
+	switch (rsptyp) {
+		case RESP_NONE:
+			dprintf(INFO, "-[MSDC] CMD(%d): RSP(%d)\n",
+					opcode, rsptyp);
+			break;
+		case RESP_R2:
+			*resp++ = MSDC_READ32(SDC_RESP3);
+			*resp++ = MSDC_READ32(SDC_RESP2);
+			*resp++ = MSDC_READ32(SDC_RESP1);
+			*resp++ = MSDC_READ32(SDC_RESP0);
+			dprintf(INFO, "-[MSDC] CMD(%d): RSP(%d) = 0x%x 0x%x 0x%x 0x%x\n",
+					opcode, cmd->rsptyp, cmd->resp[0], cmd->resp[1],
+					cmd->resp[2], cmd->resp[3]);
+			break;
+		default: /* Response types 1, 3, 4, 5, 6, 7(1b) */
+			cmd->resp[0] = MSDC_READ32(SDC_RESP0);
+			dprintf(INFO, "-[MSDC] CMD(%d): RSP(%d) = 0x%x\n",
+					opcode, cmd->rsptyp, cmd->resp[0]);
+			break;
+	}
+
+err:
+	if (rsptyp == RESP_R1B)
+		while ((MSDC_READ32(MSDC_PS) & MSDC_PS_DAT0) != MSDC_PS_DAT0);
+
+	cmd->error = error;
+
+	if (cmd->opcode == MMC_CMD_APP_CMD && error == MMC_ERR_NONE) {
+		host->app_cmd = 1;
+		host->app_cmd_arg = cmd->arg;
+	} else {
+		host->app_cmd = 0;
+	}
+
+	return error;
+}
+
+int msdc_cmd(struct mmc_host *host, struct mmc_command *cmd)
+{
+	int err;
+
+	err = msdc_send_cmd(host, cmd);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	err = msdc_wait_cmd_done(host, cmd);
+
+	if (err && cmd->opcode != MMC_CMD21) {
+		u32 tmp = MSDC_READ32(SDC_CMD);
+
+		/* check if data is used by the command or not */
+		if (tmp & SDC_CMD_DTYP) {
+			if (msdc_abort_handler(host, 1)) {
+				dprintf(CRITICAL, "[MSDC] abort failed\n");
+			}
+		}
+
+		if (cmd->opcode == MMC_CMD_APP_CMD ||
+		    cmd->opcode == SD_CMD_SEND_IF_COND) {
+			if (err ==  MMC_ERR_TIMEOUT)
+				return err;
+		}
+
+		err = msdc_tune_cmdrsp(host, cmd);
+	}
+
+	return err;
+}
+
+static void msdc_abort(struct mmc_host *host)
+{
+	dprintf(CRITICAL, "[MSDC] Abort: MSDC_FIFOCS=%xh MSDC_PS=%xh SDC_STS=%xh\n",
+			MSDC_READ32(MSDC_FIFOCS), MSDC_READ32(MSDC_PS), MSDC_READ32(SDC_STS));
+	/* reset controller */
+	MSDC_RESET();
+
+	/* clear fifo */
+	MSDC_CLR_FIFO();
+
+	/* make sure txfifo and rxfifo are empty */
+	if (MSDC_TXFIFOCNT() != 0 || MSDC_RXFIFOCNT() != 0) {
+		dprintf(INFO, "[MSDC] Abort: TXFIFO(%d), RXFIFO(%d) != 0\n",
+				MSDC_TXFIFOCNT(), MSDC_RXFIFOCNT());
+	}
+
+	/* clear all interrupts */
+	MSDC_CLR_INT();
+}
+
+int msdc_abort_handler(struct mmc_host *host, int abort_card)
+{
+	struct mmc_command stat_cmd;
+	struct mmc_command stop_cmd;
+	u32 status = 0;
+	u32 state = 0;
+	int err;
+
+	while (state != 4) {
+		msdc_abort(host);
+
+		stat_cmd.opcode  = MMC_CMD_SEND_STATUS;
+		stat_cmd.arg     = host->card->rca << 16;
+		stat_cmd.rsptyp  = RESP_R1;
+		stat_cmd.retries = CMD_RETRIES;
+		stat_cmd.timeout = CMD_TIMEOUT;
+
+		msdc_send_cmd(host, &stat_cmd);
+		err = msdc_wait_cmd_done(host, &stat_cmd);
+		if (err == MMC_ERR_NONE)
+			status = stat_cmd.resp[0];
+		else
+			dprintf(INFO, "get card state fail<%d>\n", err);
+
+		state = R1_CURRENT_STATE(status);
+		dprintf(INFO, "check card state<%d>\n", status);
+		if (state == 5 || state == 6) {
+			dprintf(INFO, "state<%d> need cmd12 to stop\n", state);
+			if (abort_card) {
+				stop_cmd.opcode  = MMC_CMD_STOP_TRANSMISSION;
+				stop_cmd.rsptyp  = RESP_R1B;
+				stop_cmd.arg     = 0;
+				stop_cmd.retries = CMD_RETRIES;
+				stop_cmd.timeout = CMD_TIMEOUT;
+				msdc_send_cmd(host, &stop_cmd);
+				msdc_wait_cmd_done(host, &stop_cmd);
+			} else if (state == 7) {
+				dprintf(INFO, "state<%d> card is busy\n", state);
+				spin(100000);
+			} else if (state != 4) {
+				dprintf(INFO, "state<%d> ??? \n", state);
+				return 1;
+			}
+		}
+	}
+	msdc_abort(host);
+	return 0;
+}
+
+static u32 msdc_intr_wait(struct mmc_host *host, u32 intrs)
+{
+	u32 sts = 0;
+	u32 tmo = 0xFFFF;
+	int ret = 0;
+
+	/* warning that interrupts are not enabled */
+	ret = event_wait_timeout(&msdc_int_event, tmo);
+	if (ret != 0) {
+		dprintf(CRITICAL, "[%s]: failed to get event INT=0x%x\n",
+				__func__, MSDC_READ32(MSDC_INT));
+		g_int_status = 0;
+		return 0;
+	}
+
+	sts = g_int_status;
+	g_int_status = 0;
+
+	if (~intrs & sts)
+		dprintf(CRITICAL, "msdc_intr_wait Unexpected INT(0x%x)\n", ~intrs & sts);
+
+	return sts;
+}
+
+static enum handler_return msdc_interrupt_handler(void *arg)
+{
+	struct mmc_host *host = arg;
+
+	/* Save & Clear the interrupt */
+	g_int_status = MSDC_READ32(MSDC_INT);
+	MSDC_WRITE32(MSDC_INT, g_int_status);
+	MSDC_WRITE32(MSDC_INTEN, 0);
+
+	/* MUST BE *false*! otherwise, schedule in interrupt */
+	event_signal(&msdc_int_event, false);
+
+	return INT_RESCHEDULE;
+}
+
+#ifdef MSDC_USE_DMA_MODE
+static void msdc_flush_membuf(void *buf, u32 len)
+{
+	arch_clean_invalidate_cache_range((addr_t)buf,len);
+}
+
+static int msdc_dma_wait_done(struct mmc_host *host, struct mmc_command *cmd)
+{
+	struct msdc_priv_t *priv = (struct msdc_priv_t *)host->priv;
+	u32 status;
+	u32 error = MMC_ERR_NONE;
+	u32 wints = MSDC_INT_XFER_COMPL | MSDC_INT_DATTMO | MSDC_INT_DATCRCERR |
+		MSDC_INT_DXFER_DONE | MSDC_INT_DMAQ_EMPTY |
+		MSDC_INT_ACMDRDY | MSDC_INT_ACMDTMO | MSDC_INT_ACMDCRCERR |
+		MSDC_INT_CMDRDY | MSDC_INT_CMDTMO | MSDC_INT_RSPCRCERR;
+
+	do {
+		status = msdc_intr_wait(host, wints);
+
+		if (status & MSDC_INT_XFER_COMPL) {
+			if (mmc_op_multi(cmd->opcode) && (priv->autocmd & MSDC_AUTOCMD12)) {
+				/* acmd rdy should be checked after xfer_done been held */
+				if (status & MSDC_INT_ACMDRDY) {
+					break;
+				} else if (status & MSDC_INT_ACMDTMO) {
+					dprintf(CRITICAL, "[MSDC] ACMD12 timeout(%xh)\n",
+						status);
+					error = MMC_ERR_ACMD_TIMEOUT;
+					goto end;
+				} else if (status & MSDC_INT_ACMDCRCERR) {
+					dprintf(CRITICAL, "[MSDC] ACMD12 CRC error(%xh)\n",
+						status);
+					error = MMC_ERR_ACMD_RSPCRC;
+					goto end;
+				}
+			} else
+				break;
+		}
+
+		if (status == 0 || status & MSDC_INT_DATTMO) {
+			dprintf(CRITICAL, "[MSDC] DMA DAT timeout(%xh)\n",
+				status);
+			error = MMC_ERR_TIMEOUT;
+			goto end;
+		} else if (status & MSDC_INT_DATCRCERR) {
+			//if (cmd->opcode != MMC_CMD21)
+				dprintf(CRITICAL, "[MSDC] DMA DAT CRC error(%xh)\n",
+					status);
+			error = MMC_ERR_BADCRC;
+			goto end;
+		} else {
+			dprintf(CRITICAL, "[MSDC] Unexpect status(0x%x)\n",
+				status);
+			error = MMC_ERR_UNEXPECT;
+			goto end;
+		}
+	} while (1);
+
+end:
+	if (error)
+		MSDC_RESET();
+
+	return error;
+}
+
+int msdc_dma_transfer(struct mmc_host *host, struct mmc_data *data)
+{
+	int err;
+	paddr_t pa;
+
+	/* Set dma timeout */
+	msdc_set_timeout(host, data->timeout * 1000000, 0);
+	/* DRAM address */
+#if WITH_KERNEL_VM
+	pa = kvaddr_to_paddr(data->buf);
+#else
+	pa = (paddr_t)(data->buf);
+#endif
+	if (sizeof(pa) > 4)
+		dprintf(INFO, "[MSDC] WARN: 64bit physical address!\n");
+	MSDC_WRITE32(MSDC_DMA_SA, (u32)pa);
+	MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_BURSTSZ, 6);
+	/* BASIC_DMA mode */
+	MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 0);
+	/* This is the last buffer */
+	MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_LASTBUF, 1);
+	/* Total transfer size */
+	MSDC_WRITE32(MSDC_DMA_LEN, data->blks * host->blklen);
+	/* Set interrupts bit */
+	MSDC_SET_BIT32(MSDC_INTEN,
+			MSDC_INT_XFER_COMPL | MSDC_INT_DATTMO | MSDC_INT_DATCRCERR);
+	/* Clean & Invalidate cache */
+	msdc_flush_membuf(data->buf, data->blks * host->blklen);
+	/* Trigger DMA start */
+	MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1);
+	/* wait DMA transferring done */
+	err = msdc_dma_wait_done(host, data->cmd);
+	msdc_flush_membuf(data->buf, data->blks * host->blklen);
+	if (err && data->cmd->opcode != MMC_CMD21) {
+		dprintf(CRITICAL, "[MSDC] DMA failed! err(%d)\n", err);
+		if (msdc_abort_handler(host, 1)) {
+			dprintf(CRITICAL, "[MSDC] eMMC cannot back to TRANS mode!\n");
+			return MMC_ERR_FAILED;
+		}
+	}
+
+	/* Check DMA status and stop DMA transfer */
+	MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 1);
+	while (MSDC_READ32(MSDC_DMA_CFG) & MSDC_DMA_CFG_STS);
+
+	return err;
+}
+
+static int msdc_dma_rw(struct mmc_host *host, u8 *buf, u32 blkaddr, u32 nblks, bool rd)
+{
+	int multi, err;
+	struct mmc_command cmd;
+	struct mmc_data data;
+
+	ASSERT(nblks <= host->max_phys_segs);
+
+	dprintf(INFO, "[MSDC] %s data %d blks %s 0x%x\n",
+			rd ? "Read" : "Write", nblks,
+			rd ? "from" : "to", blkaddr);
+
+	multi = nblks > 1 ? 1 : 0;
+	/* DMA and block number _MUST_BE_ set prior to issuing command */
+	MSDC_DMA_ON;
+	MSDC_WRITE32(SDC_BLK_NUM, nblks);
+
+	/* send read command */
+	if (rd)
+		cmd.opcode = multi ? MMC_CMD_READ_MULTIPLE_BLOCK :
+				     MMC_CMD_READ_SINGLE_BLOCK;
+	else
+		cmd.opcode = multi ? MMC_CMD_WRITE_MULTIPLE_BLOCK :
+				     MMC_CMD_WRITE_BLOCK;
+	cmd.arg = blkaddr;
+	cmd.rsptyp  = RESP_R1;
+	cmd.retries = 0;
+	cmd.timeout = CMD_TIMEOUT;
+
+	err = msdc_cmd(host, &cmd);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	data.cmd = &cmd;
+	data.blks = nblks;
+	data.buf = buf;
+	if (rd)
+		data.timeout = 100;
+	else
+		data.timeout = 250;
+
+	err = msdc_dma_transfer(host, &data);
+	MSDC_DMA_OFF;
+
+	return err;
+}
+
+static int msdc_dma_bread(struct mmc_host *host,
+				u8 *dst, u32 src, u32 nblks)
+{
+	return msdc_dma_rw(host, dst, src, nblks, true);
+}
+
+static int msdc_dma_bwrite(struct mmc_host *host,
+				u32 dst, u8 *src, u32 nblks)
+{
+	return msdc_dma_rw(host, src, dst, nblks, false);
+}
+#else
+static int msdc_pio_read_word(struct mmc_host *host, u32 *ptr, u32 size)
+{
+	int err = MMC_ERR_NONE;
+	u32 ints = MSDC_INT_DATCRCERR | MSDC_INT_DATTMO | MSDC_INT_XFER_COMPL;
+	u32 status;
+	u32 totalsz = size;
+	u8  done = 0;
+	u8 *u8ptr;
+	u32 dcrc=0;
+
+	while (1) {
+		status = MSDC_READ32(MSDC_INT);
+		MSDC_WRITE32(MSDC_INT, status);
+		if (status & ~ints)
+			dprintf(CRITICAL, "msdc_pio_read_word Unexpected INT(0x%x)\n", status);
+		if (status & MSDC_INT_DATCRCERR) {
+			MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+			dprintf(CRITICAL, "[MSDC] DAT CRC error (0x%x), Left:%d/%d bytes, RXFIFO:%d,dcrc:0x%x\n",
+					status, size, totalsz, MSDC_RXFIFOCNT(),dcrc);
+			err = MMC_ERR_BADCRC;
+			break;
+		} else if (status & MSDC_INT_DATTMO) {
+			dprintf(CRITICAL, "[MSDC] DAT TMO error (0x%x), Left: %d/%d bytes, RXFIFO:%d\n",
+					status, size, totalsz, MSDC_RXFIFOCNT());
+			err = MMC_ERR_TIMEOUT;
+			break;
+		} else if (status & MSDC_INT_ACMDCRCERR) {
+			MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+			dprintf(CRITICAL, "[MSDC] AUTOCMD CRC error (0x%x), Left:%d/%d bytes, RXFIFO:%d,dcrc:0x%x\n",
+					status, size, totalsz, MSDC_RXFIFOCNT(),dcrc);
+			err = MMC_ERR_ACMD_RSPCRC;
+			break;
+		} else if (status & MSDC_INT_XFER_COMPL) {
+			done = 1;
+		}
+
+		if (size == 0 && done)
+			break;
+
+		/* Note. RXFIFO count would be aligned to 4-bytes alignment size */
+		if ((size >=  MSDC_FIFO_THD) && (MSDC_RXFIFOCNT() >= MSDC_FIFO_THD)) {
+			int left = MSDC_FIFO_THD >> 2;
+			do {
+				*ptr++ = MSDC_FIFO_READ32();
+			} while (--left);
+			size -= MSDC_FIFO_THD;
+			dprintf(INFO, "[MSDC] Read %d bytes, RXFIFOCNT: %d,  Left: %d/%d\n",
+					MSDC_FIFO_THD, MSDC_RXFIFOCNT(), size, totalsz);
+		} else if ((size < MSDC_FIFO_THD) && MSDC_RXFIFOCNT() >= size) {
+			while (size) {
+				if (size > 3) {
+					*ptr++ = MSDC_FIFO_READ32();
+				} else {
+					u8ptr = (u8 *)ptr;
+					while (size --)
+						*u8ptr++ = MSDC_FIFO_READ8();
+				}
+			}
+			dprintf(INFO, "[MSDC] Read left bytes, RXFIFOCNT: %d, Left: %d/%d\n",
+					MSDC_RXFIFOCNT(), size, totalsz);
+		}
+	}
+
+	return err;
+}
+
+static int msdc_pio_read(struct mmc_host *host, u32 *ptr, u32 size)
+{
+	int err = msdc_pio_read_word(host, (u32 *)ptr, size);
+
+	if (err != MMC_ERR_NONE) {
+		msdc_abort(host); /* reset internal fifo and state machine */
+		dprintf(CRITICAL, "[MSDC] %d-bit PIO Read Error (%d)\n", 32, err);
+	}
+
+	return err;
+}
+
+static int msdc_pio_write_word(struct mmc_host *host, u32 *ptr, u32 size)
+{
+	int err = MMC_ERR_NONE;
+	u32 ints = MSDC_INT_DATCRCERR | MSDC_INT_DATTMO | MSDC_INT_XFER_COMPL;
+	//u32 timeout = 250000;
+	u32 status;
+	u8 *u8ptr;
+	struct msdc_priv_t *priv = (struct msdc_priv_t *)host->priv;
+
+	while (1) {
+		status = MSDC_READ32(MSDC_INT);
+		MSDC_WRITE32(MSDC_INT, status);
+		if (status & ~ints) {
+			dprintf(CRITICAL, "msdc_pio_write_word Unexpected INT(0x%x)\n", status);
+		}
+		if (status & MSDC_INT_DATCRCERR) {
+			dprintf(CRITICAL, "[MSDC] DAT CRC error (0x%x), Left DAT: %d bytes\n",
+					status, size);
+			err = MMC_ERR_BADCRC;
+			break;
+		} else if (status & MSDC_INT_DATTMO) {
+			dprintf(CRITICAL, "[MSDC] DAT TMO error (0x%x), Left DAT: %d bytes, MSDC_FIFOCS=%xh\n",
+					status, size, MSDC_READ32(MSDC_FIFOCS));
+			err = MMC_ERR_TIMEOUT;
+			break;
+		} else if (status & MSDC_INT_ACMDCRCERR) {
+			dprintf(CRITICAL, "[MSDC] AUTO CMD CRC error (0x%x), Left DAT: %d bytes\n",
+					status, size);
+			err = MMC_ERR_ACMD_RSPCRC;
+			break;
+		} else if (status & MSDC_INT_XFER_COMPL) {
+			if (size == 0) {
+				dprintf(INFO, "[MSDC] all data flushed to card\n");
+				break;
+			} else
+				dprintf(INFO, "[MSDC]<CHECKME> XFER_COMPL before all data written\n");
+		}
+
+		if (size == 0)
+			continue;
+
+		if (size >= MSDC_FIFO_SZ) {
+			if (MSDC_TXFIFOCNT() == 0) {
+				int left = MSDC_FIFO_SZ >> 2;
+				do {
+					MSDC_FIFO_WRITE32(*ptr);
+					ptr++;
+				} while (--left);
+				size -= MSDC_FIFO_SZ;
+			}
+		} else if (size < MSDC_FIFO_SZ && MSDC_TXFIFOCNT() == 0) {
+			while (size ) {
+				if (size > 3) {
+					MSDC_FIFO_WRITE32(*ptr);
+					ptr++;
+					size -= 4;
+				} else {
+					u8ptr = (u8 *)ptr;
+					while (size --) {
+						MSDC_FIFO_WRITE8(*u8ptr);
+						u8ptr++;
+					}
+				}
+			}
+		}
+	}
+
+	return err;
+}
+
+static int msdc_pio_write(struct mmc_host *host, u32 *ptr, u32 size)
+{
+	int err = msdc_pio_write_word(host, (u32 *)ptr, size);
+
+	if (err != MMC_ERR_NONE) {
+		msdc_abort(host); /* reset internal fifo and state machine */
+		dprintf(CRITICAL, "[MSDC] PIO Write Error (%d)\n", err);
+	}
+
+	return err;
+}
+
+static int msdc_pio_bread(struct mmc_host *host, u8 *dst, u32 src, u32 nblks)
+{
+	struct msdc_priv_t *priv = (struct msdc_priv_t *)host->priv;
+	u32 blksz = host->blklen;
+	int err = MMC_ERR_NONE, derr = MMC_ERR_NONE;
+	int multi;
+	struct mmc_command cmd;
+	struct mmc_command stop;
+	u32 *ptr = (u32 *)dst;
+
+	dprintf(INFO, "[MSDC] Read data %d bytes from 0x%x\n", nblks * blksz, src);
+
+	multi = nblks > 1 ? 1 : 0;
+
+	MSDC_WRITE32(SDC_BLK_NUM, nblks);
+	msdc_set_timeout(host, 100000000, 0);
+
+	/* send read command */
+	cmd.opcode  = multi ? MMC_CMD_READ_MULTIPLE_BLOCK : MMC_CMD_READ_SINGLE_BLOCK;
+	cmd.rsptyp  = RESP_R1;
+	cmd.arg     = src;
+	cmd.retries = 0;
+	cmd.timeout = CMD_TIMEOUT;
+	err = msdc_cmd(host, &cmd);
+
+	if (err != MMC_ERR_NONE)
+		goto done;
+
+	err = derr = msdc_pio_read(host, (u32 *)ptr, nblks * blksz);
+
+done:
+	if (err != MMC_ERR_NONE) {
+		if (derr != MMC_ERR_NONE) {
+			dprintf(CRITICAL, "[MSDC] Read data error (%d)\n", derr);
+			if (msdc_abort_handler(host, 1))
+				dprintf(CRITICAL, "[MSDC] abort failed\n");
+		} else {
+			dprintf(CRITICAL, "[MSDC] Read error (%d)\n", err);
+		}
+	}
+	return (derr == MMC_ERR_NONE) ? err : derr;
+}
+
+static int msdc_pio_bwrite(struct mmc_host *host, u32 dst, u8 *src, u32 nblks)
+{
+	struct msdc_priv_t *priv = (struct msdc_priv_t *)host->priv;
+	int err = MMC_ERR_NONE, derr = MMC_ERR_NONE;
+	int multi;
+	u32 blksz = host->blklen;
+	struct mmc_command cmd;
+	struct mmc_command stop;
+	u32 *ptr = (u32 *)src;
+
+	dprintf(CRITICAL, "[MSDC] Write data %d bytes to 0x%x\n", nblks * blksz, dst);
+
+	multi = nblks > 1 ? 1 : 0;
+
+	MSDC_WRITE32(SDC_BLK_NUM, nblks);
+
+	/* No need since MSDC always waits 8 cycles for write data timeout */
+
+	/* send write command */
+	cmd.opcode  = multi ? MMC_CMD_WRITE_MULTIPLE_BLOCK : MMC_CMD_WRITE_BLOCK;
+	cmd.rsptyp  = RESP_R1;
+	cmd.arg     = dst;
+	cmd.retries = 0;
+	cmd.timeout = CMD_TIMEOUT;
+	err = msdc_cmd(host, &cmd);
+
+	if (err != MMC_ERR_NONE)
+		goto done;
+
+	err = derr = msdc_pio_write(host, (u32 *)ptr, nblks * blksz);
+
+done:
+	if (err != MMC_ERR_NONE) {
+		if (derr != MMC_ERR_NONE) {
+			dprintf(CRITICAL, "[MSDC] Write data error (%d)\n", derr);
+			if (msdc_abort_handler(host, 1))
+				dprintf(CRITICAL, "[MSDC] abort failed\n");
+		} else {
+			dprintf(CRITICAL, "[MSDC] Write error (%d)\n", err);
+		}
+	}
+	return (derr == MMC_ERR_NONE) ? err : derr;
+}
+#endif
+
+
+static void msdc_config_clksrc(struct mmc_host *host, u32 clksrc, u32 hclksrc)
+{
+	ASSERT(host);
+	host->clksrc  = clksrc;
+	host->hclksrc = hclksrc;
+#ifndef FPGA_PLATFORM
+	if (host->host_id == 0)
+		host->clk     = 400 * 1000 * 1000;
+	else
+		host->clk     = 200 * 1000 * 1000;
+#else
+	host->clk = MSDC_OP_SCLK;
+#endif
+
+	/* Chaotian, may need update this part of code */
+	dprintf(INFO, "[info][%s] pll_clk %u (%uMHz), pll_hclk %u\n",
+			__func__, host->clksrc, host->clk/1000000, host->hclksrc);
+}
+
+void msdc_config_clock(struct mmc_host *host, int state, u32 hz)
+{
+	u32 mode = 0;
+	u32 div;
+	u32 sclk;
+	u32 u4buswidth=0;
+
+	if (hz >= host->f_max) {
+		hz = host->f_max;
+	} else if (hz < host->f_min) {
+		hz = host->f_min;
+	}
+
+	msdc_config_clksrc(host, host->clksrc, host->hclksrc);
+	MSDC_CLR_BIT32(MSDC_CFG, MSDC_CFG_CKMOD_HS400);
+	MSDC_SET_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS);
+
+	if (state & MMC_STATE_HS400) {
+		mode = 0x3;
+		div = 0; /* we let hs400 mode fixed at 200Mhz */
+		sclk = host->clk >> 1;
+		MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_CKMOD_HS400);
+		MSDC_CLR_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS);
+	} else if (state&MMC_STATE_DDR) {
+		mode = 0x2; /* ddr mode and use divisor */
+		if (hz >= (host->clk >> 2)) {
+			div  = 0;              /* mean div = 1/2 */
+			sclk = host->clk >> 2; /* sclk = clk/div/2. 2: internal divisor */
+		} else {
+			div  = (host->clk + ((hz << 2) - 1)) / (hz << 2);
+			sclk = (host->clk >> 2) / div;
+			div  = (div >> 1);     /* since there is 1/2 internal divisor */
+		}
+	} else if (hz >= host->clk) {
+		mode = 0x1; /* no divisor and divisor is ignored */
+		div  = 0;
+		sclk = host->clk;
+	} else {
+		mode = 0x0; /* use divisor */
+		if (hz >= (host->clk >> 1)) {
+			div  = 0;              /* mean div = 1/2 */
+			sclk = host->clk >> 1; /* sclk = clk / 2 */
+		} else {
+			div  = (host->clk + ((hz << 2) - 1)) / (hz << 2);
+			sclk = (host->clk >> 2) / div;
+		}
+	}
+	host->sclk = sclk;
+
+	/* set clock mode and divisor */
+	MSDC_SET_FIELD(MSDC_CFG, (MSDC_CFG_CKMOD |MSDC_CFG_CKDIV),\
+			(mode << 12) | div);
+	/* wait clock stable */
+	while (!(MSDC_READ32(MSDC_CFG) & MSDC_CFG_CKSTB));
+
+	MSDC_GET_FIELD(SDC_CFG,SDC_CFG_BUSWIDTH,u4buswidth);
+
+	dprintf(INFO,
+			"[MSDC] SET_CLK(%dkHz): SCLK(%dkHz) MODE(%d) DIV(%d) DS(%d) RS(%d) buswidth(%s)\n",
+			hz/1000, sclk/1000, mode, div, msdc_cap[host->host_id].data_edge,
+			msdc_cap[host->host_id].cmd_edge,
+			(u4buswidth == 0) ?
+			"1-bit" : (u4buswidth == 1) ?
+			"4-bits" : (u4buswidth == 2) ?
+			"8-bits" : "undefined");
+}
+
+void msdc_hs400_revert_pad_delay(struct mmc_host *host)
+{
+	/* HS400 use DS tuning base on pad delay as 0*/
+	MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, 0);
+}
+
+void msdc_prepare_hs400_tuning(struct mmc_host *host)
+{
+	/* eMMC5.0 pad ds delay */
+	MSDC_WRITE32(TOP_EMMC50_PAD_DS_TUNE, 0x12813);
+
+	/*hs400 mode must set it to 0 */
+	MSDC_CLR_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS);
+	MSDC_SET_BIT32(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_SEL);
+	MSDC_SET_FIELD(EMMC50_CFG3, MSDC_EMMC50_CFG3_OUTS_WR, 2);
+}
+
+extern int mmc_send_tuning(struct mmc_host *host, int *cmd_error);
+
+static u32 test_delay_bit(u32 delay, u32 bit)
+{
+	bit %= PAD_DELAY_MAX;
+	return delay & (1 << bit);
+}
+
+static int get_delay_len(u32 delay, u32 start_bit)
+{
+	u32 i;
+
+	for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) {
+		if (test_delay_bit(delay, start_bit + i) == 0)
+			return i;
+	}
+	return PAD_DELAY_MAX - start_bit;
+}
+
+static struct msdc_delay_phase get_best_delay(u32 delay)
+{
+	int start = 0, len = 0;
+	int start_final = 0, len_final = 0;
+	u8 final_phase = 0xff;
+	struct msdc_delay_phase delay_phase = { 0, };
+
+	if (delay == 0) {
+		dprintf(CRITICAL, "phase error: [map:%x]\n", delay);
+		delay_phase.final_phase = final_phase;
+		return delay_phase;
+	}
+
+	while (start < PAD_DELAY_MAX) {
+		len = get_delay_len(delay, start);
+		if (len_final < len) {
+			start_final = start;
+			len_final = len;
+		}
+		start += len ? len : 1;
+		if (len >= 12 && start_final < 4)
+			break;
+	}
+
+	/* The rule is that to find the smallest delay cell */
+	if (start_final == 0)
+		final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX;
+	else
+		final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX;
+	dprintf(ALWAYS, "phase: [map:%x] [maxlen:%d] [final:%d]\n",
+			delay, len_final, final_phase);
+
+	delay_phase.maxlen = len_final;
+	delay_phase.start = start_final;
+	delay_phase.final_phase = final_phase;
+	return delay_phase;
+}
+
+int msdc_tune_cmd_data(struct mmc_host *host)
+{
+	u32 rise_delay = 0, fall_delay = 0;
+	struct msdc_delay_phase final_rise_delay;
+	struct msdc_delay_phase final_fall_delay = { .start = 0, };
+	u8 final_delay, final_maxlen;
+	int cmd_err;
+	int i, ret;
+
+	MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+	MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_R_D_SMPL);
+	MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_W_D_SMPL);
+	for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+		MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY, i);
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, i);
+		ret = mmc_send_tuning(host, &cmd_err);
+		if (!ret)
+			rise_delay |= (1 << i);
+	}
+	final_rise_delay = get_best_delay(rise_delay);
+	if (final_rise_delay.maxlen >= 12 ||
+	    (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
+		goto skip_fall;
+
+	MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+	MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_R_D_SMPL);
+	MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_W_D_SMPL);
+	for (i = 0; i < PAD_DELAY_MAX; i++) {
+		MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY, i);
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, i);
+		ret = mmc_send_tuning(host, &cmd_err);
+		if (!ret)
+			fall_delay |= (1 << i);
+	}
+	final_fall_delay = get_best_delay(fall_delay);
+
+skip_fall:
+	final_maxlen = MAX(final_rise_delay.maxlen, final_fall_delay.maxlen);
+	if (final_maxlen == final_rise_delay.maxlen) {
+		MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+		MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_R_D_SMPL);
+		MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_W_D_SMPL);
+		MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY,
+			      final_rise_delay.final_phase);
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY,
+				final_fall_delay.final_phase);
+		final_delay = final_rise_delay.final_phase;
+	} else {
+		MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+		MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_R_D_SMPL);
+		MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_W_D_SMPL);
+		MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY,
+			      final_fall_delay.final_phase);
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY,
+			      final_fall_delay.final_phase);
+		final_delay = final_fall_delay.final_phase;
+	}
+
+	dprintf(ALWAYS, "Final cmd/data pad delay new: %x\n", final_delay);
+	return final_delay == 0xff ? MMC_ERR_FAILED : 0;
+}
+
+void msdc_config_bus(struct mmc_host *host, u32 width)
+{
+	u32 val,mode, div;
+
+	val = (width == HOST_BUS_WIDTH_8) ? 2 :
+		(width == HOST_BUS_WIDTH_4) ? 1 : 0;
+
+	MSDC_SET_FIELD(SDC_CFG, SDC_CFG_BUSWIDTH, val);
+	MSDC_GET_FIELD(MSDC_CFG,MSDC_CFG_CKMOD,mode);
+	MSDC_GET_FIELD(MSDC_CFG,MSDC_CFG_CKDIV,div);
+
+	dprintf(INFO, "CLK (%dMHz), SCLK(%dkHz) MODE(%d) DIV(%d) buswidth(%u-bits)\n",
+			host->clk/1000000, host->sclk/1000, mode, div, width);
+}
+
+void msdc_clock(struct mmc_host *host, int on)
+{
+	/* Chaotian, may need update this part of code */
+	dprintf(INFO, "[MSDC] Turn %s %s clock \n", on ? "on" : "off", "host");
+}
+
+static void msdc_host_power(struct mmc_host *host, int on)
+{
+	dprintf(INFO, "[MSDC] Turn %s %s power \n", on ? "on" : "off", "host");
+}
+
+static void msdc_card_power(struct mmc_host *host, int on)
+{
+	dprintf(INFO, "[MSDC] Turn %s %s power \n", on ? "on" : "off", "card");
+	return; /* power always on, return directly */
+
+	if (on) {
+		msdc_set_card_pwr(host, 1);
+	} else {
+		msdc_set_card_pwr(host, 0);
+	}
+}
+
+void msdc_power(struct mmc_host *host, u8 mode)
+{
+	if (mode == MMC_POWER_ON || mode == MMC_POWER_UP) {
+		msdc_host_power(host, 1);
+		msdc_card_power(host, 1);
+	} else {
+		msdc_card_power(host, 0);
+		msdc_host_power(host, 0);
+	}
+}
+
+void msdc_reset_tune_counter(struct mmc_host *host)
+{
+	host->time_read = 0;
+}
+
+#ifdef FEATURE_MMC_CM_TUNING
+int msdc_tune_cmdrsp(struct mmc_host *host, struct mmc_command *cmd)
+{
+	int result = MMC_ERR_CMDTUNEFAIL;
+	unsigned int orig_rsmpl, cur_rsmpl, rsmpl, orig_clkmode;
+	unsigned int orig_dly1 = 0, orig_dly1_sel, cur_dly1;
+	unsigned int orig_dly2 = 0, orig_dly2_sel, cur_dly2, cur_dly2_sel;
+	unsigned int orig_dly = 0, cur_dly;
+	unsigned int dly;
+	u8 hs400 = 0;
+#if MSDC_TUNE_LOG
+	u32 times = 0;
+#endif
+
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+	hs400 = (orig_clkmode == 3) ? 1 : 0;
+	MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, orig_rsmpl);
+
+	MSDC_GET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY, orig_dly1);
+	MSDC_GET_FIELD(EMMC_TOP_CMD, PAD_CMD_RD_RXDLY_SEL, orig_dly1_sel);
+	MSDC_GET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY2, orig_dly2);
+	MSDC_GET_FIELD(EMMC_TOP_CMD, PAD_CMD_RD_RXDLY2_SEL, orig_dly2_sel);
+	orig_dly = orig_dly1 * orig_dly1_sel + orig_dly2 * orig_dly2_sel;
+
+	dly = 0;
+	do {
+		for (rsmpl = 0; rsmpl < 2; rsmpl++) {
+			cur_rsmpl = (orig_rsmpl + rsmpl) % 2;
+			msdc_set_smpl(host, hs400, cur_rsmpl, TYPE_CMD_RESP_EDGE);
+			if (host->sclk <= 400000) {
+				msdc_set_smpl(host, hs400, 0, TYPE_CMD_RESP_EDGE);
+			}
+			if (cmd->opcode != MMC_CMD_STOP_TRANSMISSION) {
+				if (host->app_cmd){
+					struct mmc_command appcmd;
+					int retries = 10;
+					host->app_cmd = 0;
+					appcmd.opcode = MMC_CMD_APP_CMD;
+					appcmd.arg = host->app_cmd_arg;
+					appcmd.rsptyp  = RESP_R1;
+					appcmd.retries = CMD_RETRIES;
+					appcmd.timeout = CMD_TIMEOUT;
+
+					do {
+						result = msdc_cmd(host, &appcmd);
+						if (result == MMC_ERR_NONE)
+							break;
+					} while (retries--);
+					host->app_cmd = 1;
+					if (result != MMC_ERR_NONE)
+						return MMC_ERR_CMDTUNEFAIL;
+				}
+				result = msdc_send_cmd(host, cmd);
+				if (result == MMC_ERR_TIMEOUT)
+					rsmpl--;
+				if (result != MMC_ERR_NONE && cmd->opcode != MMC_CMD_STOP_TRANSMISSION) {
+					if (cmd->opcode == MMC_CMD_READ_MULTIPLE_BLOCK
+					 || cmd->opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK
+					 || cmd->opcode == MMC_CMD_READ_SINGLE_BLOCK
+					 || cmd->opcode == MMC_CMD_WRITE_BLOCK
+					 || cmd->opcode == MMC_CMD_SEND_WRITE_PROT_TYPE)
+						msdc_abort_handler(host,1);
+					continue;
+				}
+				result = msdc_wait_cmd_done(host, cmd);
+			} else if (cmd->opcode == MMC_CMD_STOP_TRANSMISSION) {
+				result = MMC_ERR_NONE;
+				goto Pass;
+			} else
+				result = MMC_ERR_BADCRC;
+
+		    #if MSDC_TUNE_LOG
+			/* for debugging */
+			{
+				u32 t_dly1, t_dly2, t_dly1_sel, t_dly2_sel, t_rsmpl;
+
+				MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, t_rsmpl);
+
+				MSDC_GET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY, t_dly1);
+				MSDC_GET_FIELD(EMMC_TOP_CMD, PAD_CMD_RD_RXDLY_SEL, t_dly1_sel);
+				MSDC_GET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY2, t_dly2);
+				MSDC_GET_FIELD(EMMC_TOP_CMD, PAD_CMD_RD_RXDLY2_SEL, t_dly2_sel);
+
+				times++;
+				dprintf(INFO, "[SD%d] <TUNE_CMD%d><%d><%s> CMDRRDLY=%d, RSPL=%dh\n",
+					host->id, (cmd->opcode & (~(SD_CMD_BIT | SD_CMD_APP_BIT))),
+					times, (result == MMC_ERR_NONE) ? "PASS" : "FAIL",
+					t_dly1 * t_dly1_sel + t_dly2 * t_dly2_sel, t_rsmpl);
+				dprintf(INFO, "[SD%d] <TUNE_CMD><%d><%s> CMDRRDLY1=%xh, CMDRRDLY1SEL=%x,"
+					" CMDRRDLY2=%xh, CMDRRDLY2SEL=%xh\n",
+					host->id, times, (result == MMC_ERR_NONE) ? "PASS" : "FAIL",
+					t_dly1, t_dly1_sel, t_dly2, t_dly2_sel);
+			}
+		    #endif
+
+			if (result == MMC_ERR_NONE) {
+				host->app_cmd = 0;
+				goto Pass;
+			}
+
+			if (cmd->opcode == MMC_CMD_READ_MULTIPLE_BLOCK
+			 || cmd->opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK
+			 || cmd->opcode == MMC_CMD_READ_SINGLE_BLOCK
+			 ||cmd->opcode == MMC_CMD_WRITE_BLOCK)
+				msdc_abort_handler(host,1);
+		}
+
+		cur_dly = (orig_dly + dly + 1) % 63;
+		if (cur_dly < 32) {
+			cur_dly1 = cur_dly;
+			cur_dly2 = 0;
+			cur_dly2_sel = 0;
+		} else {
+			cur_dly1 = 31;
+			cur_dly2 = cur_dly - 31;
+			cur_dly2_sel = 1;
+		}
+
+		MSDC_SET_BIT32(EMMC_TOP_CMD, PAD_CMD_RD_RXDLY_SEL);
+		MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY, cur_dly1);
+		MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY2, cur_dly2);
+		MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RD_RXDLY2_SEL, cur_dly2_sel);
+	} while (++dly <= 62);
+
+    dprintf(INFO, "Msdc async tune CMD failed\n");
+    return MMC_ERR_CMDTUNEFAIL;
+Pass:
+    dprintf(INFO, "Msdc async tune CMD Pass\n");
+    return result;
+}
+#endif
+
+#ifdef FEATURE_MMC_RD_TUNING
+int msdc_tune_bread(struct mmc_host *host, uchar *dst, ulong src, ulong nblks)
+{
+	int result = MMC_ERR_CMDTUNEFAIL;
+	unsigned int orig_rdsmpl, cur_rdsmpl, rdsmpl, orig_clkmode;
+	unsigned int rdsmpl_end;
+	unsigned int orig_dly1 = 0, orig_dly1_sel, cur_dly1;
+	unsigned int orig_dly2 = 0, orig_dly2_sel, cur_dly2, cur_dly2_sel;
+	unsigned int orig_dly = 0, cur_dly;
+	unsigned int dly;
+	u32 dcrc = 0;
+	u32 hs400;
+	u8 ddr = 0;
+#if MSDC_TUNE_LOG
+	u32 times = 0;
+#endif
+
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+	hs400 = (orig_clkmode==3) ? 1 : 0;
+	if (orig_clkmode==2 || orig_clkmode==3)
+		ddr = 1;
+	else
+		ddr = 0;
+
+	MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_PB0_RD_DAT_SEL, orig_rdsmpl);
+
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, orig_dly1);
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL, orig_dly1_sel);
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2, orig_dly2);
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2_SEL, orig_dly2_sel);
+
+	orig_dly = orig_dly1 * orig_dly1_sel + orig_dly2 * orig_dly2_sel;
+
+	if (ddr)
+		rdsmpl_end = 0;
+	else
+		rdsmpl_end = 1;
+
+	dly = 0;
+	do {
+
+		for (rdsmpl = 0; rdsmpl <= rdsmpl_end; rdsmpl++) {
+
+			cur_rdsmpl = (orig_rdsmpl + rdsmpl) % 2;
+			msdc_set_smpl(host, hs400, cur_rdsmpl, TYPE_READ_DATA_EDGE);
+
+			result = host->blk_read(host, dst, src, nblks);
+			if (result == MMC_ERR_CMDTUNEFAIL || result == MMC_ERR_CMD_RSPCRC || result == MMC_ERR_ACMD_RSPCRC)
+				goto Pass;
+
+			MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+
+			#if MSDC_TUNE_LOG
+			/* for debugging */
+			{
+				u32 t_dly1, t_dly2, t_dly1_sel, t_dly2_sel, t_rdsmpl;
+				times++;
+
+				if (hs400)
+					MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL, t_rdsmpl);
+				else
+					MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_PB0_RD_DAT_SEL, t_rdsmpl);
+
+				MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, t_dly1);
+				MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL, t_dly1_sel);
+				MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2, t_dly2);
+				MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2_SEL, t_dly2_sel);
+
+				dprintf(INFO, "[SD%d] <TUNE_READ><%d><%s> DATRRDLY=%d, RSPL=%dh\n",
+					host->id, times, (result == MMC_ERR_NONE) ? "PASS" : "FAIL",
+					t_dly1 * t_dly1_sel + t_dly2 * t_dly2_sel, t_rdsmpl);
+				dprintf(INFO, "[SD%d] <TUNE_READ><%d><%s> DATRRDLY1=%xh, DATRRDLY1SEL=%x,"
+					" DATRRDLY2=%xh, DATRRDLY2SEL=%xh\n",
+					host->id, times, (result == MMC_ERR_NONE) ? "PASS" : "FAIL",
+					t_dly1, t_dly1_sel, t_dly2, t_dly2_sel);
+			}
+			#endif
+
+			if (result == MMC_ERR_NONE && dcrc == 0) {
+				goto Pass;
+			} else {
+				result = MMC_ERR_BADCRC;
+			}
+
+		}
+
+		cur_dly = (orig_dly + dly + 1) % 63;
+		if (cur_dly < 32) {
+			cur_dly1 = cur_dly;
+			cur_dly2 = 0;
+			cur_dly2_sel = 0;
+		} else {
+			cur_dly1 = 31;
+			cur_dly2 = cur_dly - 31;
+			cur_dly2_sel = 1;
+		}
+
+		MSDC_SET_BIT32(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL);
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, cur_dly1);
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2, cur_dly2);
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2_SEL, cur_dly2_sel);
+	} while (dly++ <= 62);
+
+    dprintf(INFO, "Msdc async tune bread failed\n");
+    return MMC_ERR_CMDTUNEFAIL;
+Pass:
+    dprintf(INFO, "Msdc async tune bread Pass\n");
+    return result;
+}
+
+int msdc_tune_read(struct mmc_host *host)
+{
+	int result = MMC_ERR_CMDTUNEFAIL;
+	unsigned int orig_rdsmpl, cur_rdsmpl, orig_clkmode;
+	unsigned int orig_dly1 = 0, orig_dly1_sel, cur_dly1;
+	unsigned int orig_dly2 = 0, orig_dly2_sel, cur_dly2, cur_dly2_sel;
+	unsigned int orig_dly = 0, cur_dly;
+	unsigned int hs400;
+	u32 tune_limit_times;
+	u8 ddr = 0;
+
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+	hs400 = (orig_clkmode==3) ? 1 : 0;
+	if (orig_clkmode==2 || orig_clkmode==3)
+		ddr = 1;
+	else
+		ddr = 0;
+
+	if (ddr) {
+		tune_limit_times = 64;
+	} else {
+		tune_limit_times = 127;
+
+		MSDC_GET_FIELD(MSDC_PATCH_BIT0, MSDC_PB0_RD_DAT_SEL, orig_rdsmpl);
+		cur_rdsmpl = (orig_rdsmpl + 1) % 2;
+		msdc_set_smpl(host, hs400, cur_rdsmpl, TYPE_READ_DATA_EDGE);
+
+		if (cur_rdsmpl == 1)
+			goto out;
+	}
+
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, orig_dly1);
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL, orig_dly1_sel);
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2, orig_dly2);
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2_SEL, orig_dly2_sel);
+
+	orig_dly = orig_dly1 * orig_dly1_sel + orig_dly2 * orig_dly2_sel;
+
+	cur_dly = (orig_dly + 1) % 63;
+	if (cur_dly < 32) {
+		cur_dly1 = cur_dly;
+		cur_dly2 = 0;
+		cur_dly2_sel = 0;
+	} else {
+		cur_dly1 = 31;
+		cur_dly2 = cur_dly - 31;
+		cur_dly2_sel = 1;
+	}
+
+	MSDC_SET_BIT32(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL);
+	MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, cur_dly1);
+	MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2, cur_dly2);
+	MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2_SEL, cur_dly2_sel);
+
+out:
+	++(host->time_read);
+	if (host->time_read == tune_limit_times)
+		result = MMC_ERR_READTUNEFAIL;
+
+	return result;
+}
+
+int msdc_tune_rw_hs400(struct mmc_host *host, uchar *dst, ulong src,
+				ulong nblks, unsigned int rw)
+{
+	u32 ds_dly1 = 0, ds_dly3 = 0, orig_ds_dly1 = 0, orig_ds_dly3 = 0;
+	u32 ds_dly1_count, ds_dly3_count = 0;
+	int result = MMC_ERR_READTUNEFAIL;
+#if MSDC_TUNE_LOG
+	u32 times = 0;
+#endif
+
+	if (host->host_id != 0) {
+		return result;
+	}
+
+	dprintf(INFO, "[tune][%s:%d] start hs400 read tune\n", __func__, __LINE__);
+
+	MSDC_GET_FIELD(TOP_EMMC50_PAD_DS_TUNE, PAD_DS_DLY1, orig_ds_dly1);
+	MSDC_GET_FIELD(TOP_EMMC50_PAD_DS_TUNE, PAD_DS_DLY3, orig_ds_dly3);
+
+	ds_dly3 = orig_ds_dly3;
+	ds_dly1 = orig_ds_dly1;
+	do {
+		if (ds_dly3 >= 31) {
+			ds_dly3 = 0;
+		} else {
+			ds_dly3 += 1;
+		}
+		MSDC_SET_FIELD(TOP_EMMC50_PAD_DS_TUNE, PAD_DS_DLY3, ds_dly3);
+
+		ds_dly1_count = 0;
+		do {
+			if (ds_dly1 == 0) {
+				ds_dly1 = 31;
+			} else {
+				ds_dly1 -= 1;
+			}
+
+			MSDC_SET_FIELD(TOP_EMMC50_PAD_DS_TUNE, PAD_DS_DLY1, ds_dly1);
+
+			/* resend the r/w command */
+			if (rw == 0) {
+				result = host->blk_read(host, dst, src, nblks);
+			} else if (rw == 1) {
+				result = host->blk_write(host, (ulong) dst, (uchar *) src, nblks);
+			}
+
+		#if MSDC_TUNE_LOG
+			/* for debugging */
+			{
+				times++;
+				if (rw == 0) {
+					dprintf(INFO, "[SD%d] <TUNE_BREAD_%d><%s><cmd%d:0x%x> ret=%d, DS_DLY1=%d, DS_DLY3=%d\n",
+						host->id, times, result == MMC_ERR_NONE ? "PASS" : "FAIL", (nblks == 1 ? 17 : 18), (unsigned int)dst,
+						result, ds_dly1, ds_dly3);
+				} else if (rw == 1) {
+					dprintf(INFO, "[SD%d] <TUNE_BEWRITE_%d><%s><cmd%d:0x%x> ret=%d, DS_DLY1=%d, DS_DLY3=%d\n",
+						host->id, times, result == MMC_ERR_NONE ? "PASS" : "FAIL", (nblks == 1 ? 24 : 25), (unsigned int)dst,
+						result, ds_dly1, ds_dly3);
+				}
+			}
+		#endif
+
+			if (result == MMC_ERR_CMDTUNEFAIL || result == MMC_ERR_CMD_RSPCRC)
+				goto done;
+
+			if (result == MMC_ERR_NONE) {
+				goto done;
+			}
+
+		} while (++ds_dly1_count < 32);
+	} while (++ds_dly3_count < 32);
+
+done:
+	return result;
+}
+#endif
+
+#ifdef FEATURE_MMC_WR_TUNING
+int msdc_tune_bwrite(struct mmc_host *host, ulong dst, uchar *src, ulong nblks)
+{
+	int result = MMC_ERR_CMDTUNEFAIL;
+	unsigned int orig_dsmpl, cur_dsmpl, dsmpl, dsmpl_end, orig_clkmode;
+	unsigned int orig_dly1 = 0, orig_dly1_sel, cur_dly1;
+	unsigned int orig_dly2 = 0, orig_dly2_sel, cur_dly2, cur_dly2_sel;
+	unsigned int orig_dly = 0, cur_dly;
+	unsigned int dly;
+	u8 hs400 = 0, ddr;
+#if MSDC_TUNE_LOG
+	u32 times = 0;
+#endif
+
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+	hs400 = (orig_clkmode == 3) ? 1 : 0;
+	if (orig_clkmode==2 || orig_clkmode==3)
+		ddr = 1;
+	else
+		ddr = 0;
+
+	if (host->host_id==0) {
+		if (hs400)
+			MSDC_GET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_EDGE, orig_dsmpl);
+		else
+			MSDC_GET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTSEDGE, orig_dsmpl);
+	} else {
+		MSDC_GET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTSEDGE, orig_dsmpl);
+	}
+
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, orig_dly1);
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL, orig_dly1_sel);
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2, orig_dly2);
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2_SEL, orig_dly2_sel);
+
+	orig_dly = orig_dly1 * orig_dly1_sel + orig_dly2 * orig_dly2_sel;
+
+	if (ddr)
+		dsmpl_end = 0;
+	else
+		dsmpl_end = 1;
+	dly = 0;
+	do {
+		for (dsmpl = 0; dsmpl <= dsmpl_end; dsmpl++) {
+
+			cur_dsmpl = (orig_dsmpl + dsmpl) % 2;
+			msdc_set_smpl(host, hs400, cur_dsmpl, TYPE_WRITE_CRC_EDGE);
+
+			result = host->blk_write(host, dst, src, nblks);
+			if (result == MMC_ERR_CMDTUNEFAIL || result == MMC_ERR_CMD_RSPCRC || result == MMC_ERR_ACMD_RSPCRC)
+				goto Pass;
+
+			#if MSDC_TUNE_LOG
+			/* for debugging */
+			{
+				u32 t_dly1, t_dly2, t_dly1_sel, t_dly2_sel, t_dsmpl;
+				times++;
+
+				if (hs400)
+					MSDC_GET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_EDGE, t_dsmpl);
+				else
+					MSDC_GET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTSEDGE, t_dsmpl);
+
+				MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, t_dly1);
+				MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL, t_dly1_sel);
+				MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2, t_dly2);
+				MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2_SEL, t_dly2_sel);
+
+				dprintf(INFO, "[SD%d] <TUNE_WRITE><%d><%s> DATRRDLY=%d, RDSPL=%dh\n",
+					host->id, times, (result == MMC_ERR_NONE) ? "PASS" : "FAIL",
+					t_dly1 * t_dly1_sel + t_dly2 * t_dly2_sel, t_dsmpl);
+				dprintf(INFO, "[SD%d] <TUNE_WRITE><%d><%s> DATRRDLY1=%xh, DATRRDLY1SEL=%x,"
+					" DATRRDLY2=%xh, DATRRDLY2SEL=%xh\n",
+					host->id, times, (result == MMC_ERR_NONE) ? "PASS" : "FAIL",
+					t_dly1, t_dly1_sel, t_dly2, t_dly2_sel);
+			}
+			#endif
+
+			if (result == MMC_ERR_NONE) {
+				goto Pass;
+			} else {
+				result = MMC_ERR_BADCRC;
+			}
+		}
+
+		cur_dly = (orig_dly + dly + 1) % 63;
+		if (cur_dly < 32) {
+			cur_dly1 = cur_dly;
+			cur_dly2 = 0;
+			cur_dly2_sel = 0;
+		} else {
+			cur_dly1 = 31;
+			cur_dly2 = cur_dly - 31;
+			cur_dly2_sel = 1;
+		}
+
+		MSDC_SET_BIT32(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL);
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, cur_dly1);
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2, cur_dly2);
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY2_SEL, cur_dly2_sel);
+	} while (dly++ <= 62);
+
+    dprintf(INFO, "Msdc async tune bwrite failed\n");
+    return MMC_ERR_CMDTUNEFAIL;
+Pass:
+    dprintf(INFO, "Msdc async tune bwrite Pass\n");
+    return result;
+}
+#endif
+
+void msdc_emmc_boot_stop(struct mmc_host *host)
+{
+	u32 count = 0;
+
+	/* Step5. stop the boot mode */
+	MSDC_WRITE32(SDC_ARG, 0x00000000);
+	MSDC_WRITE32(SDC_CMD, 0x00001000);
+
+	MSDC_SET_FIELD(EMMC_CFG0, EMMC_CFG0_BOOTWDLY, 2);
+	MSDC_SET_BIT32(EMMC_CFG0, EMMC_CFG0_BOOTSTOP);
+	while (MSDC_READ32(EMMC_STS) & EMMC_STS_BOOTUPSTATE) {
+		spin(1000);
+		count++;
+		if (count >= 1000) {
+			dprintf(ALWAYS, "Timeout to wait EMMC to leave boot state!\n");
+			break;
+		}
+	}
+
+	/* Step6. */
+	MSDC_CLR_BIT32(EMMC_CFG0, EMMC_CFG0_BOOTSUPP);
+
+	/* Step7. clear EMMC_STS bits */
+	MSDC_WRITE32(EMMC_STS, MSDC_READ32(EMMC_STS));
+}
+
+int msdc_init(struct mmc_host *host)
+{
+	struct msdc_priv_t *priv = &msdc_priv;
+
+	dprintf(INFO, "[%s]: Host controller intialization start \n", __func__);
+	memset(priv, 0, sizeof(struct msdc_priv_t));
+
+	host->base = host->host_id ? MSDC1_BASE: MSDC0_BASE;;
+	host->base_top = host->host_id ? MSDC1_TOP_BASE: MSDC0_TOP_BASE;
+	host->clksrc = msdc_cap[host->host_id].clk_src;
+	host->hclksrc= msdc_cap[host->host_id].hclk_src;
+#ifndef FPGA_PLATFORM
+	host->f_max  = hclks_msdc30[host->clksrc];
+#else
+	host->f_max  = MSDC_MAX_SCLK;
+#endif
+	host->f_min  = MSDC_MIN_SCLK;
+	host->blklen = 0;
+	host->app_cmd = 0;
+	host->app_cmd_arg = 0;
+	host->priv   = (void *)priv;
+	host->caps   = MMC_CAP_MULTIWRITE;
+
+	if (msdc_cap[host->host_id].flags & MSDC_HIGHSPEED)
+		host->caps |= (MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED);
+	if (msdc_cap[host->host_id].flags & MSDC_DDR)
+		host->caps |= MMC_CAP_DDR;
+	if (msdc_cap[host->host_id].data_pins == 4)
+		host->caps |= MMC_CAP_4_BIT_DATA;
+	if (msdc_cap[host->host_id].data_pins == 8)
+		host->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
+	if (msdc_cap[host->host_id].flags & MSDC_HS200)
+		host->caps |= MMC_CAP_EMMC_HS200;
+	if (msdc_cap[host->host_id].flags & MSDC_HS400)
+		host->caps |= MMC_CAP_EMMC_HS400;
+
+	host->ocr_avail = MMC_VDD_32_33;  /* TODO: To be customized */
+
+	/* Configure BASIC_DMA + AUTOCMD12 for better R/W performance
+	 * NOTE: ACMD23 only support transferring size of up to 32M */
+	priv->autocmd = MSDC_AUTOCMD12;
+	if (priv->autocmd == MSDC_AUTOCMD23)
+		/* The maximal transferring size is size of *[15:0] number of blocks* */
+		host->max_phys_segs = 0xffff;
+	else
+		/* The maximal transferring size is size of DMA_LENGTH */
+		host->max_phys_segs = (UINT_MAX & ~511) >> MMC_BLOCK_BITS_SHFT;
+
+	priv->rdsmpl       = msdc_cap[host->host_id].data_edge;
+	priv->wdsmpl       = msdc_cap[host->host_id].data_edge;
+	priv->rsmpl       = msdc_cap[host->host_id].cmd_edge;
+
+#ifdef MSDC_USE_DMA_MODE
+	host->blk_read  = msdc_dma_bread;
+	host->blk_write = msdc_dma_bwrite;
+	dprintf(INFO, "Transfer method: DMA\n");
+#else
+	host->blk_read  = msdc_pio_bread;
+	host->blk_write = msdc_pio_bwrite;
+	dprintf(INFO, "Transfer method: PIO\n");
+#endif
+
+	priv->rdsmpl       = msdc_cap[host->host_id].data_edge;
+	priv->rsmpl       = msdc_cap[host->host_id].cmd_edge;
+
+	/* disable EMMC boot mode */
+	msdc_emmc_boot_stop(host);
+
+	msdc_power(host, MMC_POWER_OFF);
+	msdc_power(host, MMC_POWER_ON);
+
+	/* set to SD/MMC mode */
+	MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_MODE, MSDC_SDMMC);
+	MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_PIO);
+	MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_CKPDN);
+
+	MSDC_RESET();
+	MSDC_CLR_FIFO();
+	MSDC_CLR_INT();
+
+	/* use async fifo and disable internal delay*/
+	MSDC_SET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_RESPWAITCNT, 3);
+	MSDC_SET_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS);
+	MSDC_CLR_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGRESP);
+	MSDC_SET_BIT32(EMMC_TOP_CONTROL, SDC_RX_ENH_EN);
+
+	/* use data tune */
+	MSDC_SET_BIT32(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL);
+	MSDC_CLR_BIT32(EMMC_TOP_CONTROL, DATA_K_VALUE_SEL);
+	MSDC_SET_BIT32(EMMC_TOP_CMD, PAD_CMD_RD_RXDLY_SEL);
+
+	/* use stop clock*/
+	MSDC_CLR_BIT32(SDC_FIFO_CFG, SDC_FIFO_CFG_WR_VALID_SEL);
+	MSDC_CLR_BIT32(SDC_FIFO_CFG, SDC_FIFO_CFG_RD_VALID_SEL);
+	MSDC_SET_BIT32(MSDC_PATCH_BIT1, MSDC_PB1_STATE_CLEAR);
+	MSDC_SET_BIT32(MSDC_PATCH_BIT1, MSDC_PB1_POP_MARK_WATER);
+
+	/* use rising buf data */
+	MSDC_CLR_BIT32(MSDC_PATCH_BIT0, MSDC_PB0_RD_DAT_SEL);
+	MSDC_SET_BIT32(MSDC_PATCH_BIT0, MSDC_PB0_DESCUP);
+
+#if defined(MMC_MSDC_DRV_CTP)
+	/* enable wake up events */
+	MSDC_SET_BIT32(SDC_CFG, SDC_CFG_INSWKUP);
+#endif
+	/* Disable support 64G */
+	MSDC_CLR_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_SUPPORT64G);
+
+#ifndef FPGA_PLATFORM
+	msdc_gpio_and_pad_init(host);
+#endif
+	/* set sampling edge */
+	MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, msdc_cap[host->host_id].cmd_edge);
+	MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL, msdc_cap[host->host_id].data_edge);
+
+	/* write crc timeout detection */
+	MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_PB0_DETWR_CRCTMO, 1);
+
+	msdc_set_startbit(host, START_AT_RISING);
+
+	msdc_config_bus(host, HOST_BUS_WIDTH_1);
+	msdc_config_clock(host, 0, MSDC_MIN_SCLK);
+	msdc_set_timeout(host, 100000000, 0);
+
+	/* disable SDIO func */
+	MSDC_SET_FIELD(SDC_CFG, SDC_CFG_SDIO, 0);
+	MSDC_SET_FIELD(SDC_CFG, SDC_CFG_SDIOIDE, 0);
+	MSDC_SET_FIELD(SDC_CFG, SDC_CFG_INSWKUP, 0);
+
+	/* Clear all interrupts first */
+	MSDC_CLR_INT();
+	MSDC_WRITE32(MSDC_INTEN, 0);
+
+#ifdef MSDC_USE_DMA_MODE
+	/* Register msdc irq */
+	mt_irq_set_sens(MT_MSDC0_IRQ_ID + host->host_id, LEVEL_SENSITIVE);
+	mt_irq_set_polarity(MT_MSDC0_IRQ_ID + host->host_id, MT65xx_POLARITY_LOW);
+	event_init(&msdc_int_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+	register_int_handler(MT_MSDC0_IRQ_ID + host->host_id, msdc_interrupt_handler, host);
+	unmask_interrupt(MT_MSDC0_IRQ_ID + host->host_id);
+#endif
+
+	dprintf(INFO, "[%s]: Host controller intialization done\n", __func__);
+	return 0;
+}
+
+#pragma GCC pop_options
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/mmc/rules.mk b/src/bsp/lk/platform/mediatek/mt6771/drivers/mmc/rules.mk
new file mode 100644
index 0000000..bb46477
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/mmc/rules.mk
@@ -0,0 +1,12 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/msdc.c \
+    $(LOCAL_DIR)/mmc_core.c \
+
+MODULE_DEPS += \
+    lib/bio \
+    lib/partition \
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/mtcmos/mtcmos.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/mtcmos/mtcmos.c
new file mode 100644
index 0000000..a031aed
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/mtcmos/mtcmos.c
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include <platform/infracfg.h>
+#include <platform/mt_typedefs.h>
+#include <platform/mtcmos.h>
+#include <platform/smi_common.h>
+
+enum {
+    DISP_PROT_STEP1_0_MASK = 0x3 << 16,
+    DISP_PROT_STEP2_0_MASK = 0x3 << 10,
+    DISP_PROT_STEP2_1_MASK = 0xff,
+};
+
+void mtcmos_protect_display_bus(void)
+{
+    OUTREG32(&mt8183_infracfg->infra_topaxi_protecten_clr,
+        DISP_PROT_STEP2_0_MASK);
+    OUTREG32(&mt8183_smi_common->smi_common_clamp_en_clr, DISP_PROT_STEP2_1_MASK);
+    OUTREG32(&mt8183_infracfg->infra_topaxi_protecten_1_clr,
+        DISP_PROT_STEP1_0_MASK);
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/pll/fmeter.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/pll/fmeter.c
new file mode 100644
index 0000000..a2bb3c8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/pll/fmeter.c
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+#include <debug.h>
+#include <platform/mt_gpt.h>
+#include <platform/mt_typedefs.h>
+#include <platform/pll.h>
+
+#if 1 //workaround temporarily, should be removed once gpt delay function is ready.
+#define udelay(usec) spin(usec)
+#define mdelay(msec) udelay((msec)*1000)
+#endif
+
+static const char *ckgen_array[] = {
+    "hd_faxi_ck",
+    "hf_fmm_ck",
+    "hf_fimg_ck",
+    "hf_fcam_ck",
+    "hf_fdsp_ck",
+    "hf_fdsp1_ck",
+    "hf_fdsp2_ck",
+    "hf_fipu_if_ck",
+    "hf_fmfg_ck",
+    "f_fmfg_52m_ck",
+    "f_fcamtg_ck",
+    "f_fcamtg2_ck",
+    "f_fcamtg3_ck",
+    "f_fcamtg4_ck",
+    "f_fuart_ck",
+    "hf_fspi_ck",
+    "hf_fmsdc50_0_hclk_ck",
+    "hf_fmsdc50_0_ck",
+    "hf_fmsdc30_1_ck",
+    "hf_fmsdc30_2_ck",
+    "hf_faudio_ck",
+    "hf_faud_intbus_ck",
+    "hf_fpmicspi_ck",
+    "f_fpwrap_ulposc_ck",
+    "hf_fatb_ck",
+    "hf_fpwrmcu_ck",
+    "hf_fdpi0_ck",
+    "hf_fscam_ck",
+    "f_fdisp_pwm_ck",
+    "f_fusb_top_ck",
+    "f_fssusb_xhci_ck",
+    "hg_fspm_ck",
+    "f_fi2c_ck",
+    "hf_fscp_ck",
+    "f_fseninf_ck",
+    "f_fdxcc_ck",
+    "hf_faud_engin1_ck",
+    "hf_faud_engin2_ck",
+    "hf_faes_ufsfde_ck",
+    "hf_fufs_ck",
+    "hf_faud_1_ck",
+    "hf_faud_2_ck",
+    "N/A",
+    "N/A",
+    "N/A",
+    "N/A",
+    "N/A",
+    "N/A",
+    "hf_fref_mm_ck",
+    "hf_fref_cam_ck",
+    "hf_hddrphycfg_ck",
+    "f_ufs_mp_sap_cfg_ck",
+    "f_ufs_tick1us_ck",
+    "hd_faxi_east_ck",
+    "hd_faxi_west_ck",
+    "hd_faxi_north_ck",
+    "hd_faxi_south_ck",
+    "hg_fmipicfg_tx_ck",
+    "fmem_ck_bfe_dcm_ch0",
+    "fmem_ck_aft_dcm_ch0",
+    "fmem_ck_bfe_dcm_ch1",
+    "fmem_ck_aft_dcm_ch1",
+    "dramc_pll104m_ck"
+};
+
+static const char *abist_array[] = {
+    "AD_WBG_DIG_CK_832M",
+    "AD_WBG_DIG_CK_960M",
+    "UFS_MP_CLK2FREQ",
+    "AD_CSI0A_CDPHY_DELAYCAL_CK",
+    "AD_CSI0B_CDPHY_DELAYCAL_CK",
+    "AD_CSI1A_DPHY_DELAYCAL_CK",
+    "AD_CSI1B_DPHY_DELAYCAL_CK",
+    "AD_CSI2A_DPHY_DELAYCAL_CK",
+    "AD_CSI2B_DPHY_DELAYCAL_CK",
+    "AD_MDBPIPLL_CK",
+    "AD_MDBRPPLL_CK",
+    "AD_MDMCUPLL_CK",
+    "AD_MDTXPLL_CK",
+    "AD_MDVDSPPLL_CK",
+    "N/A",
+    "AD_MDPLL1_FS26M_CK",
+    "N/A",
+    "N/A",
+    "N/A",
+    "AD_ARMPLL_L_CK",
+    "N/A",
+    "AD_ARMPLL_LL_CK",
+    "AD_MAINPLL_1092M_CK",
+    "AD_UNIVPLL_1248M_CK",
+    "AD_MFGPLL_CK",
+    "AD_MSDCPLL_CK",
+    "AD_MMPLL_CK",
+    "AD_APLL1_CK",
+    "AD_APLL2_CK",
+    "AD_APPLLGP_TST_CK",
+    "N/A",
+    "AD_UNIV_192M_CK",
+    "N/A",
+    "AD_TVDPLL_CK",
+    "AD_DSI0_MPPLL_TST_CK",
+    "AD_DSI0_LNTC_DSICLK",
+    "AD_OSC_CK_2",
+    "AD_OSC_CK",
+    "rtc32k_ck_i",
+    "mcusys_arm_clk_out_all",
+    "AD_OSC_SYNC_CK",
+    "AD_OSC_SYNC_CK_2",
+    "msdc01_in_ck",
+    "msdc02_in_ck",
+    "msdc11_in_ck",
+    "msdc12_in_ck",
+    "N/A",
+    "N/A",
+    "AD_CCIPLL_CK",
+    "AD_MPLL_208M_CK",
+    "AD_WBG_DIG_CK_416M",
+    "AD_WBG_B_DIG_CK_64M",
+    "AD_WBG_W_DIG_CK_160M",
+    "N/A",
+    "DA_UNIV_48M_DIV_CK",
+    "N/A",
+    "DA_MPLL_52M_DIV_CK",
+    "N/A",
+    "N/A",
+    "ckmon1_ck",
+    "ckmon2_ck",
+    "ckmon3_ck",
+    "ckmon4_ck"
+};
+
+static unsigned int mt_get_abist_freq(unsigned int id)
+{
+    int output = 0, i = 0;
+    unsigned int temp, clk26cali_0, clk_dbg_cfg, clk_misc_cfg_0, clk26cali_1;
+
+    clk_dbg_cfg = INREG32(&mtk_topckgen->clk_dbg_cfg);
+    /* sel abist_cksw and enable freq meter sel abist */
+    OUTREG32(&mtk_topckgen->clk_dbg_cfg, (clk_dbg_cfg & 0xFFC0FFFC) | (id << 16));
+    clk_misc_cfg_0 = INREG32(&mtk_topckgen->clk_misc_cfg_0);
+    OUTREG32(&mtk_topckgen->clk_misc_cfg_0, (clk_misc_cfg_0 & 0x00FFFFFF)); /* select divider */
+    clk26cali_0 = INREG32(&mtk_topckgen->clk26cali_0);
+    clk26cali_1 = INREG32(&mtk_topckgen->clk26cali_1);
+    OUTREG32(&mtk_topckgen->clk26cali_0, 0x1000);
+    OUTREG32(&mtk_topckgen->clk26cali_0, 0x1010);
+
+    /* wait frequency meter finish */
+    while (INREG32(&mtk_topckgen->clk26cali_0) & 0x10) {
+        mdelay(10);
+        i++;
+        if(i > 10)
+            break;
+    }
+
+    temp = INREG32(&mtk_topckgen->clk26cali_1) & 0xFFFF;
+
+    output = ((temp * 26000) ) / 1024; /* KHz */
+
+    OUTREG32(&mtk_topckgen->clk_dbg_cfg, clk_dbg_cfg);
+    OUTREG32(&mtk_topckgen->clk_misc_cfg_0, clk_misc_cfg_0);
+    OUTREG32(&mtk_topckgen->clk26cali_0, clk26cali_0);
+    OUTREG32(&mtk_topckgen->clk26cali_1, clk26cali_1);
+
+    return output;
+}
+
+static unsigned int mt_get_ckgen_freq(unsigned int id)
+{
+    int output = 0, i = 0;
+    unsigned int temp, clk26cali_0, clk_dbg_cfg, clk_misc_cfg_0, clk26cali_1;
+
+    clk_dbg_cfg = INREG32(&mtk_topckgen->clk_dbg_cfg);
+    /* sel ckgen_cksw[22] and enable freq meter sel ckgen[21:16], 01:hd_faxi_ck */
+    OUTREG32(&mtk_topckgen->clk_dbg_cfg, (clk_dbg_cfg & 0xFFFFC0FC) | (id << 8) | (0x1));
+
+    clk_misc_cfg_0 = INREG32(&mtk_topckgen->clk_misc_cfg_0);
+    OUTREG32(&mtk_topckgen->clk_misc_cfg_0, (clk_misc_cfg_0 & 0x00FFFFFF)); /* select divider */
+    clk26cali_0 = INREG32(&mtk_topckgen->clk26cali_0);
+    clk26cali_1 = INREG32(&mtk_topckgen->clk26cali_1);
+    OUTREG32(&mtk_topckgen->clk26cali_0, 0x1000);
+    OUTREG32(&mtk_topckgen->clk26cali_0, 0x1010);
+
+    /* wait frequency meter finish */
+    while (INREG32(&mtk_topckgen->clk26cali_0) & 0x10) {
+        mdelay(10);
+        i++;
+        if(i > 10)
+            break;
+    }
+
+    temp = INREG32(&mtk_topckgen->clk26cali_1) & 0xFFFF;
+
+    output = ((temp * 26000) ) / 1024; /* KHz */
+
+    OUTREG32(&mtk_topckgen->clk_dbg_cfg, clk_dbg_cfg);
+    OUTREG32(&mtk_topckgen->clk_misc_cfg_0, clk_misc_cfg_0);
+    OUTREG32(&mtk_topckgen->clk26cali_0, clk26cali_0);
+    OUTREG32(&mtk_topckgen->clk26cali_1, clk26cali_1);
+
+    return output;
+}
+
+void mt_fmeter_dump(void)
+{
+    unsigned int temp;
+
+    dprintf(CRITICAL, "abist (KHz):\n");
+    for(temp = 1; temp < 64; temp++)
+        dprintf(CRITICAL, "[%u] %s: %u\n", temp, abist_array[temp-1], mt_get_abist_freq(temp));
+
+    dprintf(CRITICAL, "ckgen (KHz):\n");
+    for(temp = 1; temp < 64; temp++)
+        dprintf(CRITICAL, "[%u] %s: %u\n", temp, ckgen_array[temp-1], mt_get_ckgen_freq(temp));
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/pll/pll.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/pll/pll.c
new file mode 100644
index 0000000..1b16ea4
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/pll/pll.c
@@ -0,0 +1,374 @@
+/*
+ * 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.
+ */
+
+#include <platform/infracfg.h>
+#include <platform/mcucfg.h>
+#include <platform/mt_gpt.h>
+#include <platform/mt_typedefs.h>
+#include <platform/pll.h>
+
+#if 1 //workaround temporarily, should be removed once gpt delay function is ready.
+#include <debug.h>
+#define udelay(usec) spin(usec)
+#endif
+
+#define FMETER_EN    0
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+enum mux_id {
+    TOP_AXI_SEL = 0,
+    TOP_MM_SEL,
+    TOP_IMG_SEL,
+    TOP_CAM_SEL,
+    TOP_DSP_SEL,
+    TOP_DSP1_SEL,
+    TOP_DSP2_SEL,
+    TOP_IPU_IF_SEL,
+    TOP_MFG_SEL,
+    TOP_MFG_52M_SEL,
+    TOP_CAMTG_SEL,
+    TOP_CAMTG2_SEL,
+    TOP_CAMTG3_SEL,
+    TOP_CAMTG4_SEL,
+    TOP_UART_SEL,
+    TOP_SPI_SEL,
+    TOP_MSDC50_0_HCLK_SEL,
+    TOP_MSDC50_0_SEL,
+    TOP_MSDC30_1_SEL,
+    TOP_MSDC30_2_SEL,
+    TOP_AUDIO_SEL,
+    TOP_AUD_INTBUS_SEL,
+    TOP_PMICSPI_SEL,
+    TOP_PWRAP_ULPOSC_SEL,
+    TOP_ATB_SEL,
+    TOP_PWRMCU_SEL,
+    TOP_DPI0_SEL,
+    TOP_SCAM_SEL,
+    TOP_DISP_PWM_SEL,
+    TOP_USB_TOP_SEL,
+    TOP_SSUSB_XHCI_SEL,
+    TOP_SPM_SEL,
+    TOP_I2C_SEL,
+    TOP_SCP_SEL,
+    TOP_SENINF_SEL,
+    TOP_DXCC_SEL,
+    TOP_AUD_ENGEN1_SEL,
+    TOP_AUD_ENGEN2_SEL,
+    TOP_AES_UFSFDE_SEL,
+    TOP_UFS_SEL,
+    TOP_AUD_1_SEL,
+    TOP_AUD_2_SEL,
+    TOP_NR_MUX
+};
+
+#define MUX(_id, _reg, _mux_shift, _mux_width, _upd_reg, _upd_shift) \
+    [_id] = {                                                        \
+        .reg = &mtk_topckgen->_reg,                                  \
+        .mux_shift = _mux_shift,                                     \
+        .mux_width = _mux_width,                                     \
+        .upd_reg = &mtk_topckgen->_upd_reg,                          \
+        .upd_shift = _upd_shift,                                     \
+    }
+
+static const struct mux muxes[] = {
+    /* CLK_CFG_0 */
+    MUX(TOP_AXI_SEL, clk_cfg_0, 0, 2, clk_cfg_update, 0),
+    MUX(TOP_MM_SEL, clk_cfg_0, 8, 3, clk_cfg_update, 1),
+    MUX(TOP_IMG_SEL, clk_cfg_0, 16, 3, clk_cfg_update, 2),
+    MUX(TOP_CAM_SEL, clk_cfg_0, 24, 4, clk_cfg_update, 3),
+    /* CLK_CFG_1 */
+    MUX(TOP_DSP_SEL, clk_cfg_1, 0, 4, clk_cfg_update, 4),
+    MUX(TOP_DSP1_SEL, clk_cfg_1, 8, 4, clk_cfg_update, 5),
+    MUX(TOP_DSP2_SEL, clk_cfg_1, 16, 4, clk_cfg_update, 6),
+    MUX(TOP_IPU_IF_SEL, clk_cfg_1, 24, 4, clk_cfg_update, 7),
+    /* CLK_CFG_2 */
+    MUX(TOP_MFG_SEL, clk_cfg_2, 0, 2, clk_cfg_update, 8),
+    MUX(TOP_MFG_52M_SEL, clk_cfg_2, 8, 2, clk_cfg_update, 9),
+    MUX(TOP_CAMTG_SEL, clk_cfg_2, 16, 3, clk_cfg_update, 10),
+    MUX(TOP_CAMTG2_SEL, clk_cfg_2, 24, 3, clk_cfg_update, 11),
+    /* CLK_CFG_3 */
+    MUX(TOP_CAMTG3_SEL, clk_cfg_3, 0, 3, clk_cfg_update, 12),
+    MUX(TOP_CAMTG4_SEL, clk_cfg_3, 8, 3, clk_cfg_update, 13),
+    MUX(TOP_UART_SEL, clk_cfg_3, 16, 1, clk_cfg_update, 14),
+    MUX(TOP_SPI_SEL, clk_cfg_3, 24, 2, clk_cfg_update, 15),
+    /* CLK_CFG_4 */
+    MUX(TOP_MSDC50_0_HCLK_SEL, clk_cfg_4, 0, 2, clk_cfg_update, 16),
+    MUX(TOP_MSDC50_0_SEL, clk_cfg_4, 8, 3, clk_cfg_update, 17),
+    MUX(TOP_MSDC30_1_SEL, clk_cfg_4, 16, 3, clk_cfg_update, 18),
+    MUX(TOP_MSDC30_2_SEL, clk_cfg_4, 24, 3, clk_cfg_update, 19),
+    /* CLK_CFG_5 */
+    MUX(TOP_AUDIO_SEL, clk_cfg_5, 0, 2, clk_cfg_update, 20),
+    MUX(TOP_AUD_INTBUS_SEL, clk_cfg_5, 8, 2, clk_cfg_update, 21),
+    MUX(TOP_PMICSPI_SEL, clk_cfg_5, 16, 2, clk_cfg_update, 22),
+    MUX(TOP_PWRAP_ULPOSC_SEL, clk_cfg_5, 24, 2, clk_cfg_update, 23),
+    /* CLK_CFG_6 */
+    MUX(TOP_ATB_SEL, clk_cfg_6, 0, 2, clk_cfg_update, 24),
+    MUX(TOP_PWRMCU_SEL, clk_cfg_6, 8, 3, clk_cfg_update, 25),
+    MUX(TOP_DPI0_SEL, clk_cfg_6, 16, 4, clk_cfg_update, 26),
+    MUX(TOP_SCAM_SEL, clk_cfg_6, 24, 1, clk_cfg_update, 27),
+    /* CLK_CFG_7 */
+    MUX(TOP_DISP_PWM_SEL, clk_cfg_7, 0, 3, clk_cfg_update, 28),
+    MUX(TOP_USB_TOP_SEL, clk_cfg_7, 8, 2, clk_cfg_update, 29),
+    MUX(TOP_SSUSB_XHCI_SEL, clk_cfg_7, 16, 2, clk_cfg_update, 30),
+    MUX(TOP_SPM_SEL, clk_cfg_7, 24, 1, clk_cfg_update1, 0),
+    /* CLK_CFG_8 */
+    MUX(TOP_I2C_SEL, clk_cfg_8, 0, 2, clk_cfg_update1, 1),
+    MUX(TOP_SCP_SEL, clk_cfg_8, 8, 3, clk_cfg_update1, 2),
+    MUX(TOP_SENINF_SEL, clk_cfg_8, 16, 2, clk_cfg_update1, 3),
+    MUX(TOP_DXCC_SEL, clk_cfg_8, 24, 2, clk_cfg_update1, 4),
+    /* CLK_CFG_9 */
+    MUX(TOP_AUD_ENGEN1_SEL, clk_cfg_9, 0, 2, clk_cfg_update1, 5),
+    MUX(TOP_AUD_ENGEN2_SEL, clk_cfg_9, 8, 2, clk_cfg_update1, 6),
+    MUX(TOP_AES_UFSFDE_SEL, clk_cfg_9, 16, 3, clk_cfg_update1, 7),
+    MUX(TOP_UFS_SEL, clk_cfg_9, 24, 2, clk_cfg_update1, 8),
+    /* CLK_CFG_10 */
+    MUX(TOP_AUD_1_SEL, clk_cfg_10, 0, 1, clk_cfg_update1, 9),
+    MUX(TOP_AUD_2_SEL, clk_cfg_10, 8, 1, clk_cfg_update1, 10),
+};
+
+struct mux_sel {
+    enum mux_id id;
+    unsigned int sel;
+};
+
+static const struct mux_sel mux_sels[] = {
+    /* CLK_CFG_0 */
+    { .id = TOP_AXI_SEL, .sel = 2 },           /* 2: mainpll_d7 */
+    { .id = TOP_MM_SEL, .sel = 1 },            /* 1: mmpll_d7 */
+    { .id = TOP_IMG_SEL, .sel = 1 },           /* 1: mmpll_d6 */
+    { .id = TOP_CAM_SEL, .sel = 1 },           /* 1: mainpll_d2 */
+    /* CLK_CFG_1 */
+    { .id = TOP_DSP_SEL, .sel = 1 },           /* 1: mmpll_d6 */
+    { .id = TOP_DSP1_SEL, .sel = 1 },          /* 1: mmpll_d6 */
+    { .id = TOP_DSP2_SEL, .sel = 1 },          /* 1: mmpll_d6 */
+    { .id = TOP_IPU_IF_SEL, .sel = 1 },        /* 1: mmpll_d6 */
+    /* CLK_CFG_2 */
+    { .id = TOP_MFG_SEL, .sel = 1 },           /* 1: mfgpll_ck */
+    { .id = TOP_MFG_52M_SEL, .sel = 3 },       /* 3: univpll_d3_d8 */
+    { .id = TOP_CAMTG_SEL, .sel = 1 },         /* 1: univ_192m_d8 */
+    { .id = TOP_CAMTG2_SEL, .sel = 1 },        /* 1: univ_192m_d8 */
+    /* CLK_CFG_3 */
+    { .id = TOP_CAMTG3_SEL, .sel = 1 },        /* 1: univ_192m_d8 */
+    { .id = TOP_CAMTG4_SEL, .sel = 1 },        /* 1: univ_192m_d8 */
+    { .id = TOP_UART_SEL, .sel = 0 },          /* 0: clk26m */
+    { .id = TOP_SPI_SEL, .sel = 1 },           /* 1: mainpll_d5_d2 */
+    /* CLK_CFG_4 */
+    { .id = TOP_MSDC50_0_HCLK_SEL, .sel = 1 }, /* 1: mainpll_d2_d2 */
+    { .id = TOP_MSDC50_0_SEL, .sel = 1 },      /* 1: msdcpll_ck */
+    { .id = TOP_MSDC30_1_SEL, .sel = 4 },      /* 4: msdcpll_d2 */
+    { .id = TOP_MSDC30_2_SEL, .sel = 1 },      /* 1: univpll_d3_d2 */
+    /* CLK_CFG_5 */
+    { .id = TOP_AUDIO_SEL, .sel = 0 },         /* 0: clk26m */
+    { .id = TOP_AUD_INTBUS_SEL, .sel = 1 },    /* 1: mainpll_d2_d4 */
+    { .id = TOP_PMICSPI_SEL, .sel = 0 },       /* 0: clk26m */
+    { .id = TOP_PWRAP_ULPOSC_SEL, .sel = 0 },  /* 0: clk26m */
+    /* CLK_CFG_6 */
+    { .id = TOP_ATB_SEL, .sel = 1 },           /* 1: mainpll_d2_d2 */
+    { .id = TOP_PWRMCU_SEL, .sel = 2 },        /* 2: mainpll_d2_d2 */
+    { .id = TOP_DPI0_SEL, .sel = 1 },          /* 1: tvdpll_d2 */
+    { .id = TOP_SCAM_SEL, .sel = 1 },          /* 1: mainpll_d5_d2 */
+    /* CLK_CFG_7 */
+    { .id = TOP_DISP_PWM_SEL, .sel = 0 },      /* 0: clk26m */
+    { .id = TOP_USB_TOP_SEL, .sel = 3 },       /* 3: univpll_d5_d2 */
+    { .id = TOP_SSUSB_XHCI_SEL, .sel = 3 },    /* 3: univpll_d5_d2 */
+    { .id = TOP_SPM_SEL, .sel = 1 },           /* 1: mainpll_d2_d8 */
+    /* CLK_CFG_8 */
+    { .id = TOP_I2C_SEL, .sel = 2 },           /* 2: univpll_d5_d2 */
+    { .id = TOP_SCP_SEL, .sel = 1 },           /* 1: univpll_d2_d8 */
+    { .id = TOP_SENINF_SEL, .sel = 1 },        /* 1: univpll_d2_d2 */
+    { .id = TOP_DXCC_SEL, .sel = 1 },          /* 1: mainpll_d2_d2 */
+    /* CLK_CFG_9 */
+    { .id = TOP_AUD_ENGEN1_SEL, .sel = 3 },    /* 3: apll1_d8 */
+    { .id = TOP_AUD_ENGEN2_SEL, .sel = 3 },    /* 3: apll2_d8 */
+    { .id = TOP_AES_UFSFDE_SEL, .sel = 3 },    /* 3: mainpll_d3 */
+    { .id = TOP_UFS_SEL, .sel = 1 },           /* 1: mainpll_d2_d4 */
+    /* CLK_CFG_10 */
+    { .id = TOP_AUD_1_SEL, .sel = 1 },         /* 1: apll1_ck */
+    { .id = TOP_AUD_2_SEL, .sel = 1 },         /* 1: apll2_ck */
+};
+
+#define MMPLL_RSTB_SHIFT    (23)
+
+enum pll_id {
+    APMIXED_ARMPLL_LL,
+    APMIXED_ARMPLL_L,
+    APMIXED_CCIPLL,
+    APMIXED_MAINPLL,
+    APMIXED_UNIVPLL,
+    APMIXED_MSDCPLL,
+    APMIXED_MMPLL,
+    APMIXED_MFGPLL,
+    APMIXED_TVDPLL,
+    APMIXED_APLL1,
+    APMIXED_APLL2,
+    APMIXED_MPLL,
+    APMIXED_PLL_MAX
+};
+
+const unsigned int pll_div_rate[] = {
+    3800UL * MHz,
+    1900 * MHz,
+    950 * MHz,
+    475 * MHz,
+    237500 * KHz,
+    0,
+};
+
+static const struct pll plls[] = {
+    PLL(APMIXED_ARMPLL_LL, armpll_ll_con0, armpll_ll_pwr_con0,
+        PLL_RSTB_SHIFT, 22, armpll_ll_con1, 24, armpll_ll_con1, 0,
+        pll_div_rate),
+    PLL(APMIXED_ARMPLL_L, armpll_l_con0, armpll_l_pwr_con0,
+        PLL_RSTB_SHIFT, 22, armpll_l_con1, 24, armpll_l_con1, 0,
+        pll_div_rate),
+    PLL(APMIXED_CCIPLL, ccipll_con0, ccipll_pwr_con0,
+        PLL_RSTB_SHIFT, 22, ccipll_con1, 24, ccipll_con1, 0,
+        pll_div_rate),
+    PLL(APMIXED_MAINPLL, mainpll_con0, mainpll_pwr_con0,
+        PLL_RSTB_SHIFT, 22, mainpll_con1, 24, mainpll_con1, 0,
+        pll_div_rate),
+    PLL(APMIXED_UNIVPLL, univpll_con0, univpll_pwr_con0,
+        PLL_RSTB_SHIFT, 22, univpll_con1, 24, univpll_con1, 0,
+        pll_div_rate),
+    PLL(APMIXED_MSDCPLL, msdcpll_con0, msdcpll_pwr_con0,
+        NO_RSTB_SHIFT, 22, msdcpll_con1, 24, msdcpll_con1, 0,
+        pll_div_rate),
+    PLL(APMIXED_MMPLL, mmpll_con0, mmpll_pwr_con0,
+        MMPLL_RSTB_SHIFT, 22, mmpll_con1, 24, mmpll_con1, 0,
+        pll_div_rate),
+    PLL(APMIXED_MFGPLL, mfgpll_con0, mfgpll_pwr_con0,
+        NO_RSTB_SHIFT, 22, mfgpll_con1, 24, mfgpll_con1, 0,
+        pll_div_rate),
+    PLL(APMIXED_TVDPLL, tvdpll_con0, tvdpll_pwr_con0,
+        NO_RSTB_SHIFT, 22, tvdpll_con1, 24, tvdpll_con1, 0,
+        pll_div_rate),
+    PLL(APMIXED_APLL1, apll1_con0, apll1_pwr_con0,
+        NO_RSTB_SHIFT, 32, apll1_con0, 1, apll1_con1, 0,
+        pll_div_rate),
+    PLL(APMIXED_APLL2, apll2_con0, apll2_pwr_con0,
+        NO_RSTB_SHIFT, 32, apll2_con0, 1, apll2_con1, 0,
+        pll_div_rate),
+    PLL(APMIXED_MPLL, mpll_con0, mpll_pwr_con0,
+        NO_RSTB_SHIFT, 22, mpll_con1, 24, mpll_con1, 0,
+        pll_div_rate),
+};
+
+struct rate {
+    enum pll_id id;
+    unsigned int rate;
+};
+
+static const struct rate rates[] = {
+    { .id = APMIXED_ARMPLL_LL, .rate = ARMPLL_LL_HZ },
+    { .id = APMIXED_ARMPLL_L, .rate = ARMPLL_L_HZ },
+    { .id = APMIXED_CCIPLL, .rate = CCIPLL_HZ },
+    { .id = APMIXED_MAINPLL, .rate = MAINPLL_HZ },
+    { .id = APMIXED_UNIVPLL, .rate = UNIVPLL_HZ },
+    { .id = APMIXED_MSDCPLL, .rate = MSDCPLL_HZ },
+    { .id = APMIXED_MMPLL, .rate = MMPLL_HZ },
+    { .id = APMIXED_MFGPLL, .rate = MFGPLL_HZ },
+    { .id = APMIXED_TVDPLL, .rate = TVDPLL_HZ },
+    { .id = APMIXED_APLL1, .rate = APLL1_HZ },
+    { .id = APMIXED_APLL2, .rate = APLL2_HZ },
+    { .id = APMIXED_MPLL, .rate = MPLL_HZ },
+};
+
+void pll_set_pcw_change(const struct pll *pll)
+{
+    SETREG32(pll->div_reg, PLL_PCW_CHG);
+}
+
+void mt_pll_init(void)
+{
+    size_t i;
+
+    /* enable univpll & mainpll div */
+    SETREG32(&mtk_apmixed->ap_pll_con2, 0x1FFE << 16);
+
+    /* enable clock square1 low-pass filter */
+    SETREG32(&mtk_apmixed->ap_pll_con0, 0x2);
+
+    /* xPLL PWR ON */
+    for (i = 0; i < APMIXED_PLL_MAX; i++)
+        SETREG32(plls[i].pwr_reg, PLL_PWR_ON);
+
+    udelay(PLL_PWR_ON_DELAY);
+
+    /* xPLL ISO Disable */
+    for (i = 0; i < APMIXED_PLL_MAX; i++)
+        CLRREG32(plls[i].pwr_reg, PLL_ISO);
+
+    udelay(PLL_ISO_DELAY);
+
+    /* xPLL Frequency Set */
+    for (i = 0; i < ARRAY_SIZE(rates); i++)
+        pll_set_rate(&plls[rates[i].id], rates[i].rate);
+
+    /* AUDPLL Tuner Frequency Set */
+    OUTREG32(&mtk_apmixed->apll1_con2,
+        INREG32(&mtk_apmixed->apll1_con1) + 1);
+    OUTREG32(&mtk_apmixed->apll2_con2,
+        INREG32(&mtk_apmixed->apll2_con1) + 1);
+
+    /* xPLL Frequency Enable */
+    for (i = 0; i < APMIXED_PLL_MAX; i++)
+        SETREG32(plls[i].reg, PLL_EN);
+
+    /* wait for PLL stable */
+    udelay(PLL_EN_DELAY);
+
+    /* xPLL DIV RSTB */
+    for (i = 0; i < APMIXED_PLL_MAX; i++) {
+        if (plls[i].rstb_shift != NO_RSTB_SHIFT)
+            SETREG32(plls[i].reg, 1 << plls[i].rstb_shift);
+    }
+
+    /* MCUCFG CLKMUX */
+    MASKREG32(&mt8183_mcucfg->mp0_pll_divider_cfg, DIV_MASK, DIV_1);
+    MASKREG32(&mt8183_mcucfg->mp2_pll_divider_cfg, DIV_MASK, DIV_1);
+    MASKREG32(&mt8183_mcucfg->bus_pll_divider_cfg, DIV_MASK, DIV_2);
+
+    MASKREG32(&mt8183_mcucfg->mp0_pll_divider_cfg, MUX_MASK,
+        MUX_SRC_ARMPLL);
+    MASKREG32(&mt8183_mcucfg->mp2_pll_divider_cfg, MUX_MASK,
+        MUX_SRC_ARMPLL);
+    MASKREG32(&mt8183_mcucfg->bus_pll_divider_cfg, MUX_MASK,
+        MUX_SRC_ARMPLL);
+
+    /* enable infrasys DCM */
+    SETREG32(&mt8183_infracfg->infra_bus_dcm_ctrl, 0x3 << 21);
+
+    /*
+     * TOP CLKMUX -- DO NOT CHANGE WITHOUT ADJUSTING <soc/pll.h> CONSTANTS!
+     */
+    for (i = 0; i < ARRAY_SIZE(mux_sels); i++)
+        mux_set_sel(&muxes[mux_sels[i].id], mux_sels[i].sel);
+
+    /* enable [14] dramc_pll104m_ck */
+    SETREG32(&mtk_topckgen->clk_misc_cfg_0, 1 << 14);
+
+#if FMETER_EN
+    mt_fmeter_dump();
+#endif
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/pmic/mt6358.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/pmic/mt6358.c
new file mode 100644
index 0000000..b815e10
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/pmic/mt6358.c
@@ -0,0 +1,855 @@
+/*
+ * 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.
+ */
+
+#include <compiler.h>
+#include <debug.h>
+#include <platform/mt6358.h>
+#include <platform/pmic_wrap.h>
+#include <platform/regulator_core.h>
+
+static struct pmic_setting init_setting[] = {
+	/* [15:0]: TMA_KEY */
+	{0x3A8, 0x9CA7, 0xFFFF, 0},
+	/* [1:1]: RG_SRCLKEN_IN0_HW_MODE */
+	/* [3:3]: RG_SRCLKEN_IN1_HW_MODE */
+	{0x1E, 0xA, 0xA, 0},
+	/* [12:8]: RG_MON_GRP_SEL */
+	{0x22, 0x1F00, 0x1F00, 0},
+	/* [0:0]: RG_SMT_WDTRSTB_IN */
+	{0x2E, 0x1, 0x1, 0},
+	/* [0:0]: RG_SMT_SPI_CLK */
+	{0x30, 0x1, 0x1, 0},
+	/* [3:0]: RG_OCTL_SRCLKEN_IN0 */
+	/* [7:4]: RG_OCTL_SRCLKEN_IN1 */
+	/* [11:8]: RG_OCTL_RTC_32K1V8_0 */
+	/* [15:12]: RG_OCTL_RTC_32K1V8_1 */
+	{0x36, 0x8888, 0xFFFF, 0},
+	/* [3:0]: RG_OCTL_AUD_CLK_MOSI */
+	/* [7:4]: RG_OCTL_AUD_DAT_MOSI0 */
+	/* [11:8]: RG_OCTL_AUD_DAT_MOSI1 */
+	/* [15:12]: RG_OCTL_AUD_SYNC_MOSI */
+	{0x3A, 0x8888, 0xFFFF, 0},
+	/* [3:0]: RG_OCTL_AUD_CLK_MISO */
+	/* [7:4]: RG_OCTL_AUD_DAT_MISO0 */
+	/* [11:8]: RG_OCTL_AUD_DAT_MISO1 */
+	/* [15:12]: RG_OCTL_AUD_SYNC_MISO */
+	{0x3C, 0x8888, 0xFFFF, 0},
+	/* [3:0]: RG_OCTL_HOMEKEY */
+	/* [7:4]: RG_OCTL_SCP_VREQ_VAO */
+	/* [11:8]: RG_OCTL_SD_CARD_DET_N */
+	{0x3E, 0x888, 0xFFF, 0},
+	/* [15:0]: GPIO_PULLEN0 */
+	{0x94, 0x0, 0xFFFF, 0},
+	/* [3:3]: RG_INTRP_PRE_OC_CK_PDN */
+	/* [4:4]: RG_EFUSE_CK_PDN */
+	{0x10C, 0x18, 0x18, 0},
+	/* [2:2]: RG_TRIM_128K_CK_PDN */
+	{0x112, 0x4, 0x4, 0},
+	/* [3:3]: RG_RTC_32K1V8_SEL */
+	{0x118, 0x8, 0x8, 0},
+	/* [7:7]: RG_PMU_VXO22_ON */
+	/* [8:8]: RG_PMU_VXO22_ON_SW_EN */
+	{0x12A, 0x100, 0x180, 0},
+	/* [4:4]: RG_SRCVOLTEN_LP_EN */
+	/* [7:7]: RG_SRCLKEN2_LP_EN */
+	/* [11:11]: RG_BUCK_PFM_FLAG_SW_EN */
+	/* [13:13]: RG_DCXO26M_RDY_SW_EN */
+	{0x134, 0x80, 0x2890, 0},
+	/* [5:5]: RG_WDTRSTB_DEB */
+	{0x14C, 0x20, 0x20, 0},
+	/* [0:0]: RG_INT_MASK_BUCK_TOP */
+	/* [1:1]: RG_INT_MASK_LDO_TOP */
+	/* [2:2]: RG_INT_MASK_PSC_TOP */
+	/* [3:3]: RG_INT_MASK_SCK_TOP */
+	/* [4:4]: RG_INT_MASK_BM_TOP */
+	/* [5:5]: RG_INT_MASK_HK_TOP */
+	/* [6:6]: RG_INT_MASK_XPP_TOP */
+	/* [7:7]: RG_INT_MASK_AUD_TOP */
+	/* [8:8]: RG_INT_MASK_MISC_TOP */
+	{0x198, 0x0, 0x1FF, 0},
+	/* [8:7]: XO_AAC_MODE_LPM */
+	/* [10:9]: XO_AAC_MODE_FPM */
+	{0x790, 0x280, 0x780, 0},
+	/* [13:13]: XO_AUDIO_EN_M */
+	{0x7AC, 0x0, 0x2000, 0},
+	/* [6:6]: RG_RST_DRVSEL */
+	{0x98A, 0x40, 0x40, 0},
+	/* [0:0]: RG_PWRHOLD */
+	{0xA08, 0x1, 0x1, 0},
+	/* [8:8]: RG_UVLO_DEC_EN */
+	{0xA38, 0x0, 0x100, 0},
+	/* [5:5]: RG_STRUP_LONG_PRESS_EXT_CHR_CTRL */
+	/* [6:6]: RG_STRUP_LONG_PRESS_EXT_PWRKEY_CTRL */
+	/* [7:7]: RG_STRUP_LONG_PRESS_EXT_SPAR_CTRL */
+	/* [8:8]: RG_STRUP_LONG_PRESS_EXT_RTCA_CTRL */
+	/* [15:15]: RG_STRUP_ENVTEM_CTRL */
+	{0xA3C, 0x81E0, 0x81E0, 0},
+	/* [0:0]: RG_STRUP_VDRAM2_PG_H2L_EN */
+	/* [1:1]: RG_STRUP_VEMC_PG_H2L_EN */
+	/* [2:2]: RG_STRUP_VSRAM_PROC12_PG_H2L_EN */
+	/* [3:3]: RG_STRUP_VSRAM_PROC11_PG_H2L_EN */
+	/* [4:4]: RG_STRUP_VA12_PG_H2L_EN */
+	/* [5:5]: RG_STRUP_VSRAM_GPU_PG_H2L_EN */
+	/* [6:6]: RG_STRUP_VSRAM_OTHERS_PG_H2L_EN */
+	/* [7:7]: RG_STRUP_VAUX18_PG_H2L_EN */
+	/* [8:8]: RG_STRUP_VDRAM1_PG_H2L_EN */
+	/* [9:9]: RG_STRUP_VPROC12_PG_H2L_EN */
+	/* [10:10]: RG_STRUP_VPROC11_PG_H2L_EN */
+	/* [11:11]: RG_STRUP_VS1_PG_H2L_EN */
+	/* [12:12]: RG_STRUP_VGPU_PG_H2L_EN */
+	/* [13:13]: RG_STRUP_VMODEM_PG_H2L_EN */
+	/* [14:14]: RG_STRUP_VCORE_PG_H2L_EN */
+	/* [15:15]: RG_STRUP_VS2_PG_H2L_EN */
+	{0xA44, 0xFFFF, 0xFFFF, 0},
+	/* [13:13]: RG_STRUP_RSV_PG_H2L_EN */
+	/* [14:14]: RG_STRUP_VAUD28_PG_H2L_EN */
+	/* [15:15]: RG_STRUP_VUSB_PG_H2L_EN */
+	{0xA46, 0xE000, 0xE000, 0},
+	/* [10:10]: RG_SDN_DLY_ENB */
+	{0xA62, 0x400, 0x400, 0},
+	/* [2:2]: FG_RNG_EN_MODE */
+	/* [3:3]: FG_RNG_EN_SW */
+	{0xC8A, 0x4, 0xC, 0},
+	/* [1:1]: RG_AUXADC_1M_CK_PDN_HWEN */
+	/* [3:3]: RG_AUXADC_CK_PDN_HWEN */
+	/* [5:5]: RG_AUXADC_RNG_CK_PDN_HWEN */
+	/* [7:7]: RG_AUXADC_32K_CK_PDN_HWEN */
+	/* [9:9]: RG_AUXADC_1K_CK_PDN_HWEN */
+	/* [11:11]: RG_HK_INTRP_CK_PDN_HWEN */
+	{0xF8C, 0xAAA, 0xAAA, 0},
+	/* [15:15]: AUXADC_CK_AON */
+	{0x1188, 0x0, 0x8000, 0},
+	/* [14:12]: AUXADC_AVG_NUM_CH0 */
+	{0x119E, 0x6000, 0x7000, 0},
+	/* [13:12]: AUXADC_TRIM_CH6_SEL */
+	{0x11A2, 0x0, 0x3000, 0},
+	/* [14:14]: AUXADC_START_SHADE_EN */
+	{0x11B0, 0x4000, 0x4000, 0},
+	/* [8:8]: AUXADC_DATA_REUSE_EN */
+	{0x11B4, 0x0, 0x100, 0},
+	/* [9:0]: AUXADC_MDRT_DET_PRD */
+	/* [15:15]: AUXADC_MDRT_DET_EN */
+	{0x123A, 0x8040, 0x83FF, 0},
+	/* [2:2]: AUXADC_MDRT_DET_WKUP_EN */
+	{0x123E, 0x4, 0x4, 0},
+	/* [0:0]: AUXADC_MDRT_DET_START_SEL */
+	{0x1242, 0x1, 0x1, 0},
+	/* [2:2]: AUXADC_LBAT_CK_SW_MODE */
+	/* [4:4]: AUXADC_BAT_TEMP_CK_SW_MODE */
+	/* [6:6]: AUXADC_LBAT2_CK_SW_MODE */
+	/* [8:8]: AUXADC_NAG_CK_SW_MODE */
+	{0x1260, 0x0, 0x154, 0},
+	/* [3:3]: RG_BUCK_DCM_MODE */
+	{0x1312, 0x8, 0x8, 0},
+	/* [8:8]: RG_BUCK_K_CK_EN */
+	{0x1334, 0x0, 0x100, 0},
+	/* [8:8]: RG_BUCK_VPA_OC_SDN_EN */
+	{0x1346, 0x100, 0x100, 0},
+	/* [6:0]: RG_BUCK_VPROC11_VOSEL_SLEEP */
+	{0x138A, 0x10, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VPROC11_SFCHG_FRATE */
+	{0x138C, 0x15, 0x7F, 0},
+	/* [5:4]: RG_BUCK_VPROC11_DVS_EN_CTRL */
+	/* [13:12]: RG_BUCK_VPROC11_DVS_DOWN_CTRL */
+	{0x138E, 0x1030, 0x3030, 0},
+	/* [6:0]: RG_BUCK_VPROC12_VOSEL_SLEEP */
+	{0x140A, 0x10, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VPROC12_SFCHG_FRATE */
+	{0x140C, 0x15, 0x7F, 0},
+	/* [5:4]: RG_BUCK_VPROC12_DVS_EN_CTRL */
+	/* [13:12]: RG_BUCK_VPROC12_DVS_DOWN_CTRL */
+	{0x140E, 0x1030, 0x3030, 0},
+	/* [6:0]: RG_BUCK_VCORE_VOSEL_SLEEP */
+	{0x148A, 0x10, 0x7F, 0},
+	/* [5:4]: RG_BUCK_VCORE_DVS_EN_CTRL */
+	/* [13:12]: RG_BUCK_VCORE_DVS_DOWN_CTRL */
+	{0x148E, 0x1030, 0x3030, 0},
+	/* [5:5]: RG_BUCK_VCORE_OSC_SEL_DIS */
+	{0x14A2, 0x20, 0x20, 0},
+	/* [6:0]: RG_BUCK_VGPU_VOSEL_SLEEP */
+	{0x150A, 0x10, 0x7F, 0},
+	/* [5:4]: RG_BUCK_VGPU_DVS_EN_CTRL */
+	/* [13:12]: RG_BUCK_VGPU_DVS_DOWN_CTRL */
+	{0x150E, 0x1030, 0x3030, 0},
+	/* [6:0]: RG_BUCK_VMODEM_VOSEL_SLEEP */
+	{0x158A, 0x8, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VMODEM_SFCHG_FRATE */
+	/* [14:8]: RG_BUCK_VMODEM_SFCHG_RRATE */
+	{0x158C, 0x90C, 0x7F7F, 0},
+	/* [5:4]: RG_BUCK_VMODEM_DVS_EN_CTRL */
+	/* [13:12]: RG_BUCK_VMODEM_DVS_DOWN_CTRL */
+	{0x158E, 0x1030, 0x3030, 0},
+	/* [3:2]: RG_BUCK_VMODEM_OC_WND */
+	{0x159C, 0x8, 0xC, 0},
+	/* [5:5]: RG_BUCK_VMODEM_OSC_SEL_DIS */
+	{0x15A2, 0x20, 0x20, 0},
+	/* [6:0]: RG_BUCK_VS1_VOSEL_SLEEP */
+	{0x168A, 0x50, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VS1_SFCHG_FRATE */
+	/* [14:8]: RG_BUCK_VS1_SFCHG_RRATE */
+	{0x168C, 0x1964, 0x7F7F, 0},
+	/* [5:4]: RG_BUCK_VS1_DVS_EN_CTRL */
+	/* [13:12]: RG_BUCK_VS1_DVS_DOWN_CTRL */
+	{0x168E, 0x2020, 0x3030, 0},
+	/* [5:5]: RG_BUCK_VS1_OSC_SEL_DIS */
+	{0x16A2, 0x20, 0x20, 0},
+	/* [6:0]: RG_BUCK_VS1_VOTER_VOSEL */
+	{0x16AA, 0x48, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VS2_SFCHG_FRATE */
+	/* [14:8]: RG_BUCK_VS2_SFCHG_RRATE */
+	{0x170C, 0x1964, 0x7F7F, 0},
+	/* [5:4]: RG_BUCK_VS2_DVS_EN_CTRL */
+	/* [13:12]: RG_BUCK_VS2_DVS_DOWN_CTRL */
+	{0x170E, 0x2020, 0x3030, 0},
+	/* [6:0]: RG_BUCK_VS2_VOTER_VOSEL */
+	{0x172A, 0x3C, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VPA_SFCHG_FRATE */
+	/* [14:8]: RG_BUCK_VPA_SFCHG_RRATE */
+	{0x178C, 0x202, 0x7F7F, 0},
+	/* [1:0]: RG_BUCK_VPA_DVS_TRANST_TD */
+	/* [5:4]: RG_BUCK_VPA_DVS_TRANST_CTRL */
+	/* [6:6]: RG_BUCK_VPA_DVS_TRANST_ONCE */
+	{0x178E, 0x70, 0x73, 0},
+	/* [3:2]: RG_BUCK_VPA_OC_WND */
+	{0x1790, 0xC, 0xC, 0},
+	/* [5:0]: RG_BUCK_VPA_VOSEL_DLC011 */
+	/* [13:8]: RG_BUCK_VPA_VOSEL_DLC111 */
+	{0x1798, 0x2810, 0x3F3F, 0},
+	/* [13:8]: RG_BUCK_VPA_VOSEL_DLC001 */
+	{0x179A, 0x800, 0x3F00, 0},
+	/* [0:0]: RG_BUCK_VPA_MSFG_EN */
+	{0x179E, 0x1, 0x1, 0},
+	/* [13:12]: RG_VPA_BURSTH */
+	{0x1808, 0x2000, 0x3000, 0},
+	/* [5:5]: RG_VPROC11_FCOT */
+	/* [6:6]: RG_VPROC12_FCOT */
+	{0x180C, 0x60, 0x60, 0},
+	/* [1:0]: RG_VPROC11_TB_WIDTH */
+	/* [3:2]: RG_VPROC12_TB_WIDTH */
+	/* [5:4]: RG_VPROC11_UG_SR */
+	/* [7:6]: RG_VPROC11_LG_SR */
+	/* [9:8]: RG_VPROC12_UG_SR */
+	/* [11:10]: RG_VPROC12_LG_SR */
+	/* [14:12]: RG_VPROC11_PFM_TON */
+	{0x1814, 0x3FF0, 0x7FFF, 0},
+	/* [2:0]: RG_VPROC12_PFM_TON */
+	{0x1816, 0x3, 0x7, 0},
+	/* [5:0]: RG_VPROC11_TRAN_BST */
+	/* [12:7]: RG_VPROC12_TRAN_BST */
+	/* [15:13]: RG_VPROC11_COTRAMP_SLP */
+	{0x181A, 0x6081, 0xFFBF, 0},
+	/* [2:0]: RG_VPROC12_COTRAMP_SLP */
+	/* [8:7]: RG_VPROC11_VREFTB */
+	/* [10:9]: RG_VPROC12_VREFTB */
+	{0x181C, 0x503, 0x787, 0},
+	/* [15:0]: RG_VPROC11_RSV */
+	{0x181E, 0xA662, 0xFFFF, 0},
+	/* [15:0]: RG_VPROC12_RSV */
+	{0x1820, 0xA662, 0xFFFF, 0},
+	/* [2:0]: RG_VPROC11_CSP */
+	/* [5:3]: RG_VPROC11_CSN */
+	/* [8:6]: RG_VPROC12_CSP */
+	/* [11:9]: RG_VPROC12_CSN */
+	{0x1824, 0xDB6, 0xFFF, 0},
+	/* [5:5]: RG_VCORE_FCOT */
+	/* [6:6]: RG_VGPU_FCOT */
+	/* [8:8]: RG_VCORE_TBDIS */
+	{0x1828, 0x160, 0x160, 0},
+	/* [1:0]: RG_VCORE_TB_WIDTH */
+	/* [3:2]: RG_VGPU_TB_WIDTH */
+	/* [5:4]: RG_VCORE_UG_SR */
+	/* [7:6]: RG_VCORE_LG_SR */
+	/* [9:8]: RG_VGPU_UG_SR */
+	/* [11:10]: RG_VGPU_LG_SR */
+	/* [14:12]: RG_VCORE_PFM_TON */
+	{0x1830, 0x3FF0, 0x7FFF, 0},
+	/* [2:0]: RG_VGPU_PFM_TON */
+	{0x1832, 0x3, 0x7, 0},
+	/* [5:0]: RG_VCORE_TRAN_BST */
+	/* [12:7]: RG_VGPU_TRAN_BST */
+	/* [15:13]: RG_VCORE_COTRAMP_SLP */
+	{0x1836, 0x6081, 0xFFBF, 0},
+	/* [2:0]: RG_VGPU_COTRAMP_SLP */
+	/* [8:7]: RG_VCORE_VREFTB */
+	/* [10:9]: RG_VGPU_VREFTB */
+	{0x1838, 0x503, 0x787, 0},
+	/* [15:0]: RG_VCORE_RSV */
+	{0x183A, 0xA262, 0xFFFF, 0},
+	/* [15:0]: RG_VGPU_RSV */
+	{0x183C, 0xA262, 0xFFFF, 0},
+	/* [11:0]: RG_VCORE_CSP */
+	/* [5:3]: RG_VCORE_CSN */
+	/* [8:6]: RG_VGPU_CSP */
+	/* [11:9]: RG_VGPU_CSN */
+	{0x1840, 0xDB6, 0xFFF, 0},
+	/* [2:0]: RG_VPROC11_RPSI1_TRIM */
+	{0x1854, 0x0, 0x7, 0},
+	/* [12:10]: RG_VPROC12_RPSI1_TRIM */
+	{0x1856, 0x0, 0x1C00, 0},
+	/* [2:0]: RG_VCORE_RPSI1_TRIM */
+	{0x185C, 0x0, 0x7, 0},
+	/* [12:10]: RG_VGPU_RPSI1_TRIM */
+	{0x185E, 0x0, 0x1C00, 0},
+	/* [5:2]: RG_VMODEM_RCOMP */
+	/* [6:6]: RG_VMODEM_TB_DIS */
+	/* [11:9]: RG_VMODEM_PFM_TON */
+	{0x1888, 0x420, 0xE7C, 0},
+	/* [2:0]: RG_VMODEM_COTRAMP_SLP */
+	/* [11:10]: RG_VMODEM_VREFUP */
+	/* [13:12]: RG_VMODEM_TB_WIDTH */
+	{0x188A, 0x801, 0x3C07, 0},
+	/* [1:0]: RG_VMODEM_UG_SR */
+	/* [3:2]: RG_VMODEM_LG_SR */
+	/* [5:4]: RG_VMODEM_CCOMP */
+	{0x188C, 0x1F, 0x3F, 0},
+	/* [15:0]: RG_VMODEM_RSV */
+	{0x188E, 0x129A, 0xFFFF, 0},
+	/* [5:3]: RG_VMODEM_CSN */
+	/* [8:6]: RG_VMODEM_SONIC_PFM_TON */
+	{0x1894, 0x58, 0x1F8, 0},
+	/* [5:2]: RG_VDRAM1_RCOMP */
+	/* [6:6]: RG_VDRAM1_TB_DIS */
+	{0x1896, 0x1C, 0x7C, 0},
+	/* [2:0]: RG_VDRAM1_COTRAMP_SLP */
+	/* [11:10]: RG_VDRAM1_VREFUP */
+	/* [13:12]: RG_VDRAM1_TB_WIDTH */
+	{0x1898, 0x1805, 0x3C07, 0},
+	/* [3:0]: RG_VDRAM1_UG_SR */
+	{0x189A, 0xF, 0xF, 0},
+	/* [15:0]: RG_VDRAM1_RSV */
+	{0x189C, 0x221A, 0xFFFF, 0},
+	/* [2:0]: RG_VDRAM1_CSP */
+	/* [5:3]: RG_VDRAM1_CSN */
+	{0x18A0, 0x2E, 0x3F, 0},
+	/* [6:6]: RG_VS1_TB_DIS */
+	{0x18A2, 0x0, 0x40, 0},
+	/* [2:0]: RG_VS1_COTRAMP_SLP */
+	/* [11:10]: RG_VS1_VREFUP */
+	/* [13:12]: RG_VS1_TB_WIDTH */
+	{0x18A4, 0x2C06, 0x3C07, 0},
+	/* [1:0]: RG_VS1_UG_SR */
+	/* [3:2]: RG_VS1_LG_SR */
+	{0x18A6, 0xF, 0xF, 0},
+	/* [15:0]: RG_VS1_RSV */
+	{0x18A8, 0x221A, 0xFFFF, 0},
+	/* [2:0]: RG_VS1_CSP */
+	/* [5:3]: RG_VS1_CSN */
+	{0x18AC, 0x2E, 0x3F, 0},
+	/* [6:6]: RG_VS2_TB_DIS */
+	{0x18AE, 0x0, 0x40, 0},
+	/* [2:0]: RG_VS2_COTRAMP_SLP */
+	/* [11:10]: RG_VS2_VREFUP */
+	/* [13:12]: RG_VS2_TB_WIDTH */
+	{0x18B0, 0x1805, 0x3C07, 0},
+	/* [1:0]: RG_VS2_UG_SR */
+	/* [3:2]: RG_VS2_LG_SR */
+	{0x18B2, 0xF, 0xF, 0},
+	/* [15:0]: RG_VS2_RSV */
+	{0x18B4, 0x221A, 0xFFFF, 0},
+	/* [2:0]: RG_VS2_CSP */
+	/* [5:3]: RG_VS2_CSN */
+	{0x18B8, 0x2E, 0x3F, 0},
+	/* [5:4]: RG_VPA_CSMIR */
+	/* [7:6]: RG_VPA_CSL */
+	/* [10:10]: RG_VPA_AZC_EN */
+	{0x18BC, 0x50, 0x4F0, 0},
+	/* [3:2]: RG_VPA_SLEW */
+	/* [5:4]: RG_VPA_SLEW_NMOS */
+	/* [7:6]: RG_VPA_MIN_ON */
+	{0x18BE, 0x3C, 0xFC, 0},
+	/* [9:8]: RG_VPA_MIN_PK */
+	{0x18C0, 0x0, 0x300, 0},
+	/* [7:0]: RG_VPA_RSV1 */
+	/* [15:8]: RG_VPA_RSV2 */
+	{0x18C2, 0x8886, 0xFFFF, 0},
+	/* [11:8]: RG_VPA_NLIM_SEL */
+	{0x18D8, 0x700, 0xF00, 0},
+	/* [0:0]: RG_LDO_32K_CK_PDN_HWEN */
+	/* [1:1]: RG_LDO_INTRP_CK_PDN_HWEN */
+	{0x1A0E, 0x3, 0x3, 0},
+	/* [0:0]: RG_LDO_DCM_MODE */
+	{0x1A10, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VFE28_CK_SW_MODE */
+	{0x1A12, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VXO22_CK_SW_MODE */
+	{0x1A14, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VRF18_CK_SW_MODE */
+	{0x1A16, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VRF12_CK_SW_MODE */
+	{0x1A18, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VEFUSE_CK_SW_MODE */
+	{0x1A1A, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN33_CK_SW_MODE */
+	{0x1A1C, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN28_CK_SW_MODE */
+	{0x1A1E, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN18_CK_SW_MODE */
+	{0x1A20, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMA1_CK_SW_MODE */
+	{0x1A22, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMA2_CK_SW_MODE */
+	{0x1A24, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMD_CK_SW_MODE */
+	{0x1A26, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMIO_CK_SW_MODE */
+	{0x1A28, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VLDO28_CK_SW_MODE */
+	{0x1A2A, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VA12_CK_SW_MODE */
+	{0x1A2C, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VAUX18_CK_SW_MODE */
+	{0x1A2E, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VAUD28_CK_SW_MODE */
+	{0x1A30, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VIO28_CK_SW_MODE */
+	{0x1A32, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VIO18_CK_SW_MODE */
+	{0x1A34, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VSRAM_PROC11_CK_SW_MODE */
+	{0x1A36, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VSRAM_PROC12_CK_SW_MODE */
+	{0x1A38, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VSRAM_OTHERS_CK_SW_MODE */
+	{0x1A3A, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VSRAM_GPU_CK_SW_MODE */
+	{0x1A3C, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VDRAM2_CK_SW_MODE */
+	{0x1A3E, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VMC_CK_SW_MODE */
+	{0x1A40, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VMCH_CK_SW_MODE */
+	{0x1A42, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VEMC_CK_SW_MODE */
+	{0x1A44, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VSIM1_CK_SW_MODE */
+	{0x1A46, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VSIM2_CK_SW_MODE */
+	{0x1A48, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VIBR_CK_SW_MODE */
+	{0x1A4A, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VUSB_CK_SW_MODE */
+	{0x1A4C, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VBIF28_CK_SW_MODE */
+	{0x1A4E, 0x0, 0x1, 0},
+	/* [6:0]: RG_LDO_VSRAM_PROC11_VOSEL_SLEEP */
+	{0x1B48, 0x10, 0x7F, 0},
+	/* [6:0]: RG_LDO_VSRAM_PROC11_SFCHG_FRATE */
+	/* [14:8]: RG_LDO_VSRAM_PROC11_SFCHG_RRATE */
+	{0x1B4A, 0xF15, 0x7F7F, 0},
+	/* [6:0]: RG_LDO_VSRAM_PROC12_VOSEL_SLEEP */
+	{0x1B8A, 0x10, 0x7F, 0},
+	/* [6:0]: RG_LDO_VSRAM_PROC12_SFCHG_FRATE */
+	/* [14:8]: RG_LDO_VSRAM_PROC12_SFCHG_RRATE */
+	{0x1B8C, 0xF15, 0x7F7F, 0},
+	/* [6:0]: RG_LDO_VSRAM_OTHERS_VOSEL_SLEEP */
+	{0x1BA8, 0x38, 0x7F, 0},
+	/* [6:0]: RG_LDO_VSRAM_OTHERS_SFCHG_FRATE */
+	/* [14:8]: RG_LDO_VSRAM_OTHERS_SFCHG_RRATE */
+	{0x1BAA, 0x70F, 0x7F7F, 0},
+	/* [1:0]: RG_LDO_VSRAM_OTHERS_DVS_TRANS_TD */
+	{0x1BAC, 0x0, 0x3, 0},
+	/* [6:0]: RG_LDO_VSRAM_GPU_VOSEL_SLEEP */
+	{0x1BCA, 0x10, 0x7F, 0},
+	/* [6:0]: RG_LDO_VSRAM_GPU_SFCHG_FRATE */
+	/* [14:8]: RG_LDO_VSRAM_GPU_SFCHG_RRATE */
+	{0x1BCC, 0x70F, 0x7F7F, 0},
+	/* [4:0]: RG_VSRAM_PROC11_RSV_H */
+	{0x1EA2, 0x1B, 0x1F, 0},
+	/* [12:10]: RG_VSRAM_PROC12_RSV_H */
+	{0x1EA4, 0xC00, 0x1C00, 0},
+	/* [12:10]: RG_VSRAM_OTHERS_RSV_H */
+	{0x1EA6, 0xC00, 0x1C00, 0},
+	/* [12:10]: RG_VSRAM_GPU_RSV_H */
+	{0x1EA8, 0xC00, 0x1C00, 0},
+	/* [15:0]: TMA_KEY */
+	{0x3A8, 0x0, 0xFFFF, 0},
+
+	/* MT6358 HW tracking init */
+	/* [6:0]: RG_LDO_VSRAM_PROC11_VOSEL_DELTA */
+	/* [14:8]: RG_LDO_VSRAM_PROC11_VOSEL_OFFSET */
+	{0x1B66, 0x1000, 0x7F7F, 0},
+	/* [6:0]: RG_LDO_VSRAM_PROC11_VOSEL_ON_LB */
+	/* [14:8]: RG_LDO_VSRAM_PROC11_VOSEL_ON_HB */
+	{0x1B68, 0x6340, 0x7F7F, 0},
+	/* [1:1]: RG_LDO_VSRAM_PROC11_TRACK_ON_CTRL */
+	/* [2:2]: RG_LDO_VSRAM_PROC11_TRACK_VPROC11_ON_CTRL */
+	{0x1B64, 0x6, 0x6, 0},
+	/* [6:0]: RG_LDO_VSRAM_PROC12_VOSEL_DELTA */
+	/* [14:8]: RG_LDO_VSRAM_PROC12_VOSEL_OFFSET */
+	{0x1B6E, 0x1000, 0x7F7F, 0},
+	/* [6:0]: RG_LDO_VSRAM_PROC12_VOSEL_ON_LB */
+	/* [14:8]: RG_LDO_VSRAM_PROC12_VOSEL_ON_HB */
+	{0x1B70, 0x6340, 0x7F7F, 0},
+	/* [2:1]: RG_LDO_VSRAM_PROC12_TRACK_ON_CTRL */
+	/* [2:2]: RG_LDO_VSRAM_PROC12_TRACK_VPROC12_ON_CTRL */
+	{0x1B6C, 0x6, 0x6, 0},
+};
+
+static struct pmic_setting lp_setting[] = {
+	/* Suspend */
+	/* [0:0]: RG_BUCK_VPROC11_SW_OP_EN */
+	{0x1390, 0x1, 0x1, 0},
+	/* [0:0]: RG_BUCK_VCORE_SW_OP_EN */
+	{0x1490, 0x1, 0x1, 0},
+	/* [0:0]: RG_BUCK_VGPU_SW_OP_EN */
+	{0x1510, 0x1, 0x1, 0},
+	/* [0:0]: RG_BUCK_VMODEM_SW_OP_EN */
+	{0x1590, 0x1, 0x1, 0},
+	/* [0:0]: RG_BUCK_VS1_SW_OP_EN */
+	{0x1690, 0x1, 0x1, 0},
+	/* [1:1]: RG_BUCK_VS2_HW0_OP_EN */
+	{0x1710, 0x1, 0x1, 1},
+	/* [1:1]: RG_BUCK_VS2_HW0_OP_CFG */
+	{0x1716, 0x1, 0x1, 1},
+	/* [1:1]: RG_BUCK_VDRAM1_HW0_OP_EN */
+	{0x1610, 0x1, 0x1, 1},
+	/* [1:1]: RG_BUCK_VDRAM1_HW0_OP_CFG */
+	{0x1616, 0x1, 0x1, 1},
+	/* [0:0]: RG_BUCK_VPROC12_SW_OP_EN */
+	{0x1410, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VSRAM_GPU_SW_OP_EN */
+	{0x1BD0, 0x1, 0x1, 0},
+	/* [1:1]: RG_LDO_VSRAM_OTHERS_HW0_OP_EN */
+	{0x1BAE, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VSRAM_OTHERS_HW0_OP_CFG */
+	{0x1BB4, 0x1, 0x1, 1},
+	/* [0:0]: RG_LDO_VSRAM_PROC11_SW_OP_EN */
+	{0x1B4E, 0x1, 0x1, 0},
+	/* [1:1]: RG_LDO_VXO22_HW0_OP_EN */
+	{0x1A8A, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VXO22_HW0_OP_CFG */
+	{0x1A90, 0x1, 0x1, 1},
+	/* [2:2]: RG_LDO_VRF18_HW1_OP_EN */
+	{0x1C1E, 0x1, 0x1, 2},
+	/* [2:2]: RG_LDO_VRF18_HW1_OP_CFG */
+	{0x1C24, 0x0, 0x1, 2},
+	/* [2:2]: RG_LDO_VRF12_HW1_OP_EN */
+	{0x1C32, 0x1, 0x1, 2},
+	/* [2:2]: RG_LDO_VRF12_HW1_OP_CFG */
+	{0x1C38, 0x0, 0x1, 2},
+	/* [0:0]: RG_LDO_VEFUSE_SW_OP_EN */
+	{0x1C46, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN33_SW_OP_EN */
+	{0x1D1E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN33_SW_OP_EN */
+	{0x1D1E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN28_SW_OP_EN */
+	{0x1D8A, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN18_SW_OP_EN */
+	{0x1C5A, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMA1_SW_OP_EN */
+	{0x1C6E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMD_SW_OP_EN */
+	{0x1C9E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMA2_SW_OP_EN */
+	{0x1C8A, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VSRAM_PROC12_SW_OP_EN */
+	{0x1B90, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMIO_SW_OP_EN */
+	{0x1CB2, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VLDO28_SW_OP_EN */
+	{0x1D34, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VLDO28_SW_OP_EN */
+	{0x1D34, 0x1, 0x1, 0},
+	/* [1:1]: RG_LDO_VA12_HW0_OP_EN */
+	{0x1A9E, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VA12_HW0_OP_CFG */
+	{0x1AA4, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VAUX18_HW0_OP_EN */
+	{0x1AB2, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VAUX18_HW0_OP_CFG */
+	{0x1AB8, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VAUD28_HW0_OP_EN */
+	{0x1AC6, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VAUD28_HW0_OP_CFG */
+	{0x1ACC, 0x1, 0x1, 1},
+	/* [0:0]: RG_LDO_VIO28_SW_OP_EN */
+	{0x1ADA, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VIO18_SW_OP_EN */
+	{0x1AEE, 0x1, 0x1, 0},
+	/* [2:2]: RG_LDO_VFE28_HW1_OP_EN */
+	{0x1C0A, 0x1, 0x1, 2},
+	/* [2:2]: RG_LDO_VFE28_HW1_OP_CFG */
+	{0x1C10, 0x0, 0x1, 2},
+	/* [1:1]: RG_LDO_VDRAM2_HW0_OP_EN */
+	{0x1B0A, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VDRAM2_HW0_OP_CFG */
+	{0x1B10, 0x1, 0x1, 1},
+	/* [0:0]: RG_LDO_VMC_SW_OP_EN */
+	{0x1CC6, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VMCH_SW_OP_EN */
+	{0x1CDA, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VEMC_SW_OP_EN */
+	{0x1B1E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VSIM1_SW_OP_EN */
+	{0x1D4A, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VSIM2_SW_OP_EN */
+	{0x1D5E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VIBR_SW_OP_EN */
+	{0x1D0A, 0x1, 0x1, 0},
+	/* [1:1]: RG_LDO_VUSB_HW0_OP_EN */
+	{0x1B32, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VUSB_HW0_OP_CFG */
+	{0x1B38, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VUSB_HW0_OP_EN */
+	{0x1B32, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VUSB_HW0_OP_CFG */
+	{0x1B38, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VBIF28_HW0_OP_EN */
+	{0x1DA0, 0x1, 0x1, 1},
+	/* [1:1]: RG_LDO_VBIF28_HW0_OP_CFG */
+	{0x1DA6, 0x0, 0x1, 1},
+
+	/* Deep idle setting */
+	/* [0:0]: RG_BUCK_VPROC11_SW_OP_EN */
+	{0x1390, 0x1, 0x1, 0},
+	/* [0:0]: RG_BUCK_VCORE_SW_OP_EN */
+	{0x1490, 0x1, 0x1, 0},
+	/* [0:0]: RG_BUCK_VGPU_SW_OP_EN */
+	{0x1510, 0x1, 0x1, 0},
+	/* [0:0]: RG_BUCK_VMODEM_SW_OP_EN */
+	{0x1590, 0x1, 0x1, 0},
+	/* [0:0]: RG_BUCK_VS1_SW_OP_EN */
+	{0x1690, 0x1, 0x1, 0},
+	/* [3:3]: RG_BUCK_VS2_HW2_OP_EN */
+	{0x1710, 0x1, 0x1, 3},
+	/* [3:3]: RG_BUCK_VS2_HW2_OP_CFG */
+	{0x1716, 0x1, 0x1, 3},
+	/* [3:3]: RG_BUCK_VDRAM1_HW2_OP_EN */
+	{0x1610, 0x1, 0x1, 3},
+	/* [3:3]: RG_BUCK_VDRAM1_HW2_OP_CFG */
+	{0x1616, 0x1, 0x1, 3},
+	/* [0:0]: RG_BUCK_VPROC12_SW_OP_EN */
+	{0x1410, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VSRAM_GPU_SW_OP_EN */
+	{0x1BD0, 0x1, 0x1, 0},
+	/* [3:3]: RG_LDO_VSRAM_OTHERS_HW2_OP_EN */
+	{0x1BAE, 0x1, 0x1, 3},
+	/* [3:3]: RG_LDO_VSRAM_OTHERS_HW2_OP_CFG */
+	{0x1BB4, 0x1, 0x1, 3},
+	/* [0:0]: RG_LDO_VSRAM_PROC11_SW_OP_EN */
+	{0x1B4E, 0x1, 0x1, 0},
+	/* [3:3]: RG_LDO_VXO22_HW2_OP_EN */
+	{0x1A8A, 0x1, 0x1, 3},
+	/* [3:3]: RG_LDO_VXO22_HW2_OP_CFG */
+	{0x1A90, 0x1, 0x1, 3},
+	/* [2:2]: RG_LDO_VRF18_HW1_OP_EN */
+	{0x1C1E, 0x1, 0x1, 2},
+	/* [2:2]: RG_LDO_VRF18_HW1_OP_CFG */
+	{0x1C24, 0x0, 0x1, 2},
+	/* [2:2]: RG_LDO_VRF12_HW1_OP_EN */
+	{0x1C32, 0x1, 0x1, 2},
+	/* [2:2]: RG_LDO_VRF12_HW1_OP_CFG */
+	{0x1C38, 0x0, 0x1, 2},
+	/* [0:0]: RG_LDO_VEFUSE_SW_OP_EN */
+	{0x1C46, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN33_SW_OP_EN */
+	{0x1D1E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN33_SW_OP_EN */
+	{0x1D1E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN28_SW_OP_EN */
+	{0x1D8A, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN18_SW_OP_EN */
+	{0x1C5A, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMA1_SW_OP_EN */
+	{0x1C6E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMD_SW_OP_EN */
+	{0x1C9E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMA2_SW_OP_EN */
+	{0x1C8A, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VSRAM_PROC12_SW_OP_EN */
+	{0x1B90, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMIO_SW_OP_EN */
+	{0x1CB2, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VLDO28_SW_OP_EN */
+	{0x1D34, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VLDO28_SW_OP_EN */
+	{0x1D34, 0x1, 0x1, 0},
+	/* [3:3]: RG_LDO_VA12_HW2_OP_EN */
+	{0x1A9E, 0x1, 0x1, 3},
+	/* [3:3]: RG_LDO_VA12_HW2_OP_CFG */
+	{0x1AA4, 0x1, 0x1, 3},
+	/* [3:3]: RG_LDO_VAUX18_HW2_OP_EN */
+	{0x1AB2, 0x1, 0x1, 3},
+	/* [3:3]: RG_LDO_VAUX18_HW2_OP_CFG */
+	{0x1AB8, 0x1, 0x1, 3},
+	/* [0:0]: RG_LDO_VAUD28_SW_OP_EN */
+	{0x1AC6, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VIO28_SW_OP_EN */
+	{0x1ADA, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VIO18_SW_OP_EN */
+	{0x1AEE, 0x1, 0x1, 0},
+	/* [2:2]: RG_LDO_VFE28_HW1_OP_EN */
+	{0x1C0A, 0x1, 0x1, 2},
+	/* [2:2]: RG_LDO_VFE28_HW1_OP_CFG */
+	{0x1C10, 0x0, 0x1, 2},
+	/* [3:3]: RG_LDO_VDRAM2_HW2_OP_EN */
+	{0x1B0A, 0x1, 0x1, 3},
+	/* [3:3]: RG_LDO_VDRAM2_HW2_OP_CFG */
+	{0x1B10, 0x1, 0x1, 3},
+	/* [0:0]: RG_LDO_VMC_SW_OP_EN */
+	{0x1CC6, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VMCH_SW_OP_EN */
+	{0x1CDA, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VEMC_SW_OP_EN */
+	{0x1B1E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VSIM1_SW_OP_EN */
+	{0x1D4A, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VSIM2_SW_OP_EN */
+	{0x1D5E, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VIBR_SW_OP_EN */
+	{0x1D0A, 0x1, 0x1, 0},
+	/* [3:3]: RG_LDO_VUSB_HW2_OP_EN */
+	{0x1B32, 0x1, 0x1, 3},
+	/* [3:3]: RG_LDO_VUSB_HW2_OP_CFG */
+	{0x1B38, 0x1, 0x1, 3},
+	/* [3:3]: RG_LDO_VUSB_HW2_OP_EN */
+	{0x1B32, 0x1, 0x1, 3},
+	/* [3:3]: RG_LDO_VUSB_HW2_OP_CFG */
+	{0x1B38, 0x1, 0x1, 3},
+	/* [3:3]: RG_LDO_VBIF28_HW2_OP_EN */
+	{0x1DA0, 0x1, 0x1, 3},
+	/* [3:3]: RG_LDO_VBIF28_HW2_OP_CFG */
+	{0x1DA6, 0x0, 0x1, 3},
+};
+
+void pmic_set_power_hold(bool enable)
+{
+	pwrap_write_field(PMIC_PWRHOLD, (enable) ? 1 : 0, 0x1, 0);
+}
+
+static void pmic_wdt_set(void)
+{
+	/* [5]=1, RG_WDTRSTB_DEB */
+	pwrap_write_field(PMIC_TOP_RST_MISC_SET, 0x0020, 0xFFFF, 0);
+	/* [1]=0, RG_WDTRSTB_MODE */
+	pwrap_write_field(PMIC_TOP_RST_MISC_CLR, 0x0002, 0xFFFF, 0);
+	/* [0]=1, RG_WDTRSTB_EN */
+	pwrap_write_field(PMIC_TOP_RST_MISC_SET, 0x0001, 0xFFFF, 0);
+}
+
+static void mt6358_init_setting(void)
+{
+	for (size_t i = 0; i < countof(init_setting); i++)
+		pwrap_write_field(
+			init_setting[i].addr, init_setting[i].val,
+			init_setting[i].mask, init_setting[i].shift);
+}
+
+static void wk_sleep_voltage_by_ddr(void)
+{
+	if (pwrap_read_field(PMIC_VM_MODE, 0x3, 0) == 0x2)
+		pwrap_write_field(PMIC_VDRAM1_VOSEL_SLEEP, 0x3A, 0x7F, 0);
+}
+
+static void wk_power_down_seq(void)
+{
+	/* Write TMA KEY with magic number */
+	pwrap_write_field(PMIC_TOP_TMA_KEY, 0x9CA7, 0xFFFF, 0);
+	/* Set VPROC12 sequence to VA12 */
+	pwrap_write_field(PMIC_CPSDSA4, 0xA, 0x1F, 0);
+	pwrap_write_field(PMIC_TOP_TMA_KEY, 0x0, 0xFFFF, 0);
+}
+
+static void mt6358_lp_setting(void)
+{
+	for (size_t i = 0; i < countof(lp_setting); i++)
+		pwrap_write_field(
+			lp_setting[i].addr, lp_setting[i].val,
+			lp_setting[i].mask, lp_setting[i].shift);
+}
+
+int mt6358_init(void)
+{
+	if (pwrap_init()) {
+		dprintf(CRITICAL, "ERROR - Failed to initialize pmic wrap!");
+		return -1;
+	}
+
+	pmic_set_power_hold(true);
+	pmic_wdt_set();
+	mt6358_init_setting();
+	wk_sleep_voltage_by_ddr();
+	wk_power_down_seq();
+	mt6358_lp_setting();
+	mt6358_regulator_init();
+
+	return 0;
+}
+
+/* external api */
+/*
+ * PMIC Access APIs
+ */
+
+u16 pmic_read_interface (u16 RegNum, u16 *val, u16 MASK, u16 SHIFT)
+{
+	u16 return_value = 0;
+	u16 pmic_reg = 0;
+	u16 rdata;
+
+	return_value = pwrap_read(RegNum, &rdata);
+	pmic_reg = rdata;
+	if (return_value != 0) {
+		dprintf(CRITICAL, "[PMIC]Reg[0x%x] pmic_wrap read data fail\n", RegNum);
+		return return_value;
+	}
+
+	pmic_reg &= (MASK << SHIFT);
+	*val = (pmic_reg >> SHIFT);
+
+	return return_value;
+}
+
+u16 pmic_config_interface (u16 RegNum, u16 val, u16 MASK, u16 SHIFT)
+{
+	u16 return_value = 0;
+	u16 pmic_reg = 0;
+	u16 rdata;
+
+	return_value = pwrap_read(RegNum, &rdata);
+	pmic_reg = rdata;
+	if (return_value != 0) {
+		dprintf(CRITICAL, "[PMIC]Reg[0x%x] pmic_wrap read data fail\n", RegNum);
+		return return_value;
+	}
+
+	pmic_reg &= ~(MASK << SHIFT);
+	pmic_reg |= (val << SHIFT);
+
+	return_value = pwrap_write(RegNum, pmic_reg);
+	if (return_value != 0) {
+		dprintf(CRITICAL, "[PMIC]Reg[0x%x] pmic_wrap write 0x%x fail\n", RegNum, pmic_reg);
+		return return_value;
+	}
+
+	return return_value;
+}
+
+u16 get_dram_type(void)
+{
+	u16 val;
+
+	pmic_read_interface(PMIC_VM_MODE, &val, 0x3, 0);
+	return val;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/pmic/regulator_core.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/pmic/regulator_core.c
new file mode 100644
index 0000000..10ed687
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/pmic/regulator_core.c
@@ -0,0 +1,376 @@
+/*
+ * 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.
+ */
+
+#include <debug.h>
+#include <platform/mt6358.h>
+#include <platform/regulator_core.h>
+#include <string.h>
+
+#define REGULATOR_DEBUG
+#if defined(REGULATOR_DEBUG)
+#define mreg_dbg_print(fmt, arg...) dprintf(CRITICAL, "[%s]" fmt, __func__,  ## arg)
+#else
+#define mreg_dbg_print(fmt, arg...)
+#endif
+
+static const unsigned int vdram2_volts[] = {
+	600000,
+	1800000,
+};
+
+static const unsigned int vio18_volts[] = {
+	1800000,
+};
+
+static const int vdram2_idxs[] = {
+	0, 12,
+};
+
+static const int fix_idxs[] = {
+	0,
+};
+
+static struct mt6358_ldo_info ldo_ext_info[] = {
+	mt6358_ldo_decl(vdram2_volts, vdram2_idxs),
+	mt6358_ldo_decl(vio18_volts, fix_idxs),
+};
+
+static const int votrim_2_type[] = {
+	0, (-1)*10000, (-1)*20000, (-1)*30000, (-1)*40000, (-1)*50000, (-1)*60000, (-1)*70000,
+	80000, 70000, 60000, 50000, 40000, 30000, 20000, 10000,
+};
+
+static struct mt6358_ldo_trim_info ldo_trim_info[] = {
+	mt6358_ldo_trim_decl(vdram2, votrim_2_type),
+	mt6358_ldo_trim_decl(vio18, votrim_2_type),
+};
+
+static struct mt6358_regulator_info mt6358_regu_info[] = {
+	mt6358_decl(vsram_others),
+	mt6358_decl(vcore),
+	mt6358_decl(vdram1),
+	mt6358_decl(vdram2),
+	mt6358_decl(vio18),
+	mt6358_decl(vrf12),
+	mt6358_decl(vcn18),
+	mt6358_decl(vcn33),
+};
+
+static unsigned int mt6358_ldo_convert_data(unsigned char id, unsigned int cnvdata, volseltran transtype)
+{
+	int i = 0, n_size = 0;
+	unsigned int choice = 0xFFFF;
+	const unsigned int *pVoltage;
+	const unsigned int *iDx;
+
+	if ((mt6358_regu_info[id].extinfo->pvoltages != NULL) && (mt6358_regu_info[id].extinfo->idxs != NULL)) {
+		pVoltage = mt6358_regu_info[id].extinfo->pvoltages;
+		iDx = mt6358_regu_info[id].extinfo->idxs;
+		n_size = mt6358_regu_info[id].extinfo->n_size;
+		mreg_dbg_print("cnvdata %d, n_size %d\n", cnvdata, n_size);
+		for (i = 0; i <= n_size; i++) {
+			if (transtype == VOLTOSEL && pVoltage[i] == cnvdata) {
+				choice = iDx[i];
+				break;
+			} else if (transtype == SELTOVOL && iDx[i] == cnvdata) {
+				choice = pVoltage[i];
+				break;
+			}
+		}
+	}
+
+	return choice;
+}
+
+static int mt6358_set_voltage(unsigned char id, unsigned int volt, unsigned int max_volt) {
+	unsigned short selector = 0;
+	int ret = 0;
+
+	if (volt > mt6358_regu_info[id].max_uV || volt < mt6358_regu_info[id].min_uV) {
+		mreg_dbg_print("vp\n");
+		mreg_dbg_print("%d, %d, %d, %d\n", volt, mt6358_regu_info[id].max_uV, mt6358_regu_info[id].min_uV, id);
+		return -1;
+	}
+
+	if (mt6358_regu_info[id].rtype == REGULAR_VOLTAGE)
+		selector = DIV_ROUND_UP((volt - mt6358_regu_info[id].min_uV),
+			mt6358_regu_info[id].step_uV);
+	else if (mt6358_regu_info[id].rtype == NON_REGULAR_VOLTAGE) {
+		selector = mt6358_ldo_convert_data(id, volt, VOLTOSEL);
+		if (selector == 0xFFFF) {
+			mreg_dbg_print("vnf\n"); /* voltage not found */
+			return -1;
+		}
+	} else if (mt6358_regu_info[id].rtype == FIXED_REGULAR_VOLTAGE) {
+		if (mt6358_ldo_convert_data(id, volt, VOLTOSEL) == 0)
+			return 0;
+		else {
+			mreg_dbg_print("vswf\n");
+			return -1;
+		}
+	}
+
+	mreg_dbg_print("1 %d,%d\n", id, selector);
+
+	ret = pmic_config_interface(mt6358_regu_info[id].vol_reg, selector,
+		mt6358_regu_info[id].vol_mask, mt6358_regu_info[id].vol_shift);
+	return ret;
+}
+
+static int mt6358_get_voltage(unsigned char id)
+{
+	unsigned short selector = 0;
+	unsigned int volt = 0;
+	int ret = 0;
+
+	if (mt6358_regu_info[id].da_vol_reg != 0) {
+		ret = pmic_read_interface(
+			mt6358_regu_info[id].da_vol_reg,
+			&selector,
+			mt6358_regu_info[id].da_vol_mask,
+			mt6358_regu_info[id].da_vol_shift);
+	} else {
+		ret = pmic_read_interface(
+			mt6358_regu_info[id].vol_reg,
+			&selector,
+			mt6358_regu_info[id].vol_mask,
+			mt6358_regu_info[id].vol_shift);
+	}
+
+	if (ret)
+		return -1;
+
+	if (mt6358_regu_info[id].rtype == REGULAR_VOLTAGE)
+		volt = ((selector * mt6358_regu_info[id].step_uV) + mt6358_regu_info[id].min_uV);
+
+	mreg_dbg_print("get volt %d, %d, %d\n", id, selector, volt);
+	if (volt > mt6358_regu_info[id].max_uV || volt < mt6358_regu_info[id].min_uV) {
+		mreg_dbg_print("vgw\n");
+		return -1;
+	}
+
+	return volt;
+}
+
+static int mt6358_enable(unsigned char id, unsigned char en)
+{
+	int ret = 0;
+
+	if (mt6358_regu_info[id].enable_reg == 0)
+		return -1;
+	mreg_dbg_print("2 %d,%d\n", id, en);
+	ret = pmic_config_interface(mt6358_regu_info[id].enable_reg, en, 0x1,
+		mt6358_regu_info[id].enable_shift);
+
+	return ret;
+}
+
+static int mt6358_is_enabled(unsigned char id)
+{
+	unsigned short en = 0;
+	unsigned int ret = 0;
+
+	if (mt6358_regu_info[id].enable_reg == 0)
+		return -1;
+	ret = pmic_read_interface(mt6358_regu_info[id].enable_reg, &en, 0x1,
+		mt6358_regu_info[id].enable_shift);
+	mreg_dbg_print("3 %d,%d\n", id, en);
+
+	return (ret ? ret : en) ;
+}
+
+static int mt6358_set_mode(unsigned char id, unsigned char mode)
+{
+	int ret = 0;
+
+	if (mt6358_regu_info[id].mode_reg == 0)
+		return -1;
+	mreg_dbg_print("4 %d,%d\n", id, mode);
+	ret = pmic_config_interface(mt6358_regu_info[id].mode_reg, mode, 0x1,
+		mt6358_regu_info[id].mode_shift);
+
+	return ret;
+}
+
+static int mt6358_get_mode(unsigned char id)
+{
+	unsigned short mode = 0;
+	int ret = 0;
+
+	if (mt6358_regu_info[id].mode_reg == 0)
+		return -1;
+	ret = pmic_read_interface(mt6358_regu_info[id].mode_reg, &mode, 0x1,
+		mt6358_regu_info[id].mode_shift);
+	mreg_dbg_print("5 %d,%d\n", id, mode);
+
+	return (ret ? ret: mode);
+}
+
+static int mt6358_ldo_votrim_convert_data(unsigned char id, int cnvdata, trimseltran transtype)
+{
+	int i = 0, trim_size = 0, choice = -1;
+	const int *trim_Voltage;
+
+	if ((mt6358_regu_info[id].triminfo->trim_voltages != NULL)) {
+		trim_Voltage = mt6358_regu_info[id].triminfo->trim_voltages;
+		trim_size = mt6358_regu_info[id].triminfo->trim_size;
+		mreg_dbg_print("votrim_size %d, cnvdata %d\n", trim_size, cnvdata);
+		switch (transtype) {
+		case TRIMTOSEL:
+			if (cnvdata > 0) {
+				for (i = trim_size/2; i < trim_size; i++) {
+					choice = i;
+					if (trim_Voltage[i] <= cnvdata) {
+						mreg_dbg_print("trim_Voltage:%d, cnvdata:%d\n", trim_Voltage[i], cnvdata);
+						break;
+					}
+				}
+			} else if (cnvdata < 0) {
+				for (i = trim_size/2 - 1; i >= 0; i--) {
+					choice = i;
+					if (trim_Voltage[i] >= cnvdata) {
+						mreg_dbg_print("trim_Voltage:%d, cnvdata:%d\n", trim_Voltage[i], cnvdata);
+						break;
+					}
+				}
+			} else
+				choice = 0;
+			break;
+		case SELTOTRIM:
+			choice = trim_Voltage[cnvdata];
+			break;
+		default:
+			break;
+		}
+	}
+
+	return choice;
+}
+
+static int mt6358_set_votrim(unsigned char id, int trim_volt) {
+	int selector = 0;
+	int ret = 0;
+
+	selector = mt6358_ldo_votrim_convert_data(id, trim_volt, TRIMTOSEL);
+	if (selector == -1)
+		return -1;
+
+	if ((mt6358_regu_info[id].triminfo->trim_voltages != NULL)) {
+		mreg_dbg_print("6 %d,%d\n", id, selector);
+		pmic_config_interface(PMIC_TOP_TMA_KEY, 0x9CA7,
+			0xFFFF, 0);
+		ret = pmic_config_interface(
+			mt6358_regu_info[id].triminfo->trim_reg,
+			(unsigned int)selector,	0xF, 0);
+		pmic_config_interface(PMIC_TOP_TMA_KEY, 0,
+			0xFFFF, 0);
+	}
+
+	return ret;
+}
+
+static int mt6358_get_votrim(unsigned char id)
+{
+	unsigned short selector = 0;
+	int ret = 0;
+
+	ret = pmic_read_interface(mt6358_regu_info[id].triminfo->trim_reg,
+		&selector, 0xF, 0);
+	if (ret)
+		return -1;
+
+	ret = mt6358_ldo_votrim_convert_data(id, selector, SELTOTRIM);
+
+	mreg_dbg_print("7 %d,%d,%d\n", id, selector,ret);
+
+	return ret;
+}
+
+static struct regulator_ctrl mt6358_regulator_ctrl = {
+	.set_voltage = mt6358_set_voltage,
+	.get_voltage = mt6358_get_voltage,
+	.enable = mt6358_enable,
+	.is_enabled = mt6358_is_enabled,
+	.set_mode = mt6358_set_mode,
+	.get_mode = mt6358_get_mode,
+	.set_votrim = mt6358_set_votrim,
+	.get_votrim = mt6358_get_votrim,
+};
+
+static struct mtk_regulator mt6358_regulator[] = {
+	{
+		.name = "vsram_others",
+		.id = MTK_REGULATOR_VSRAM_OTHERS,
+		.reg_ops = &mt6358_regulator_ctrl,
+	}, {
+		.name = "vcore",
+		.id = MTK_REGULATOR_VCORE,
+		.reg_ops = &mt6358_regulator_ctrl,
+	}, {
+		.name = "vdram1",
+		.id = MTK_REGULATOR_VDRAM1,
+		.reg_ops = &mt6358_regulator_ctrl,
+	}, {
+		.name = "vdram2",
+		.id = MTK_REGULATOR_VDRAM2,
+		.reg_ops = &mt6358_regulator_ctrl,
+	}, {
+		.name = "vio18",
+		.id = MTK_REGULATOR_VIO18,
+		.reg_ops = &mt6358_regulator_ctrl,
+	}, {
+		.name = "vrf12",
+		.id = MTK_REGULATOR_VRF12,
+		.reg_ops = &mt6358_regulator_ctrl,
+	}, {
+		.name = "vcn18",
+		.id = MTK_REGULATOR_VCN18,
+		.reg_ops = &mt6358_regulator_ctrl,
+	}, {
+		.name = "vcn33",
+		.id = MTK_REGULATOR_VCN33,
+		.reg_ops = &mt6358_regulator_ctrl,
+	},
+};
+
+int mt6358_regulator_init(void)
+{
+	int ret = 0;
+	unsigned int i = 0;
+
+	for (i = 0; i < MTK_REGULATOR_MAX_NR; i++) {
+		if (mt6358_regu_info[i].rtype != REGULAR_VOLTAGE && i >= MTK_REGULATOR_LDO_SUPPORT)
+				mt6358_regu_info[i].extinfo = &ldo_ext_info[(i-MTK_REGULATOR_LDO_SUPPORT)];
+
+		if (mt6358_regu_info[i].rtype != REGULAR_VOLTAGE  && i >= MTK_REGULATOR_LDO_SUPPORT)
+				mt6358_regu_info[i].triminfo = &ldo_trim_info[(i-MTK_REGULATOR_LDO_SUPPORT)];
+
+		ret = mtk_simple_regulator_register(&mt6358_regulator[i]);
+		if (ret < 0) {
+			/* register mtk regulator error */
+			mreg_dbg_print("[PMIC] regulator %s\n", mt6358_regulator[i].name);
+			return ret;
+		}
+	}
+	return 0;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/pmic_wrap/pmic_wrap.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/pmic_wrap/pmic_wrap.c
new file mode 100644
index 0000000..b26844b
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/pmic_wrap/pmic_wrap.c
@@ -0,0 +1,347 @@
+/*
+ * 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.
+ */
+
+#include <platform/infracfg.h>
+#include <platform/pll.h>
+#include <platform/pmic_wrap.h>
+#include <reg.h>
+
+#define PRIORITY_FIELD(x)		((x % 4) * 8)
+#define PRIORITY_IN(id, priority)	(id << PRIORITY_FIELD(priority))
+#define PRIORITY_OUT(id, priority)	(priority << PRIORITY_FIELD(id))
+
+enum {
+	MD_ADCINF0 =  8,
+	MD_ADCINF1 =  9,
+	STAUPD     = 10,
+	GPSINF0    = 11,
+
+	PRIORITY_IN_SEL_2 = PRIORITY_IN(MD_ADCINF0,  9) |
+			    PRIORITY_IN(MD_ADCINF1, 10) |
+			    PRIORITY_IN(STAUPD,      8) |
+			    PRIORITY_IN(GPSINF0,    11),
+
+	PRIORITY_OUT_SEL_2 = PRIORITY_OUT(MD_ADCINF0,  9) |
+			     PRIORITY_OUT(MD_ADCINF1, 10) |
+			     PRIORITY_OUT(STAUPD,      8) |
+			     PRIORITY_OUT(GPSINF0,    11),
+};
+
+#define PENDING_US(x) x
+enum {
+	STARVE_ENABLE = 0x1 << 10,
+	COUNTER0_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x2),
+	COUNTER1_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x3),
+	COUNTER2_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x3),
+	COUNTER3_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x3),
+	COUNTER4_PENDING_THRES = STARVE_ENABLE | PENDING_US(0xf),
+	COUNTER5_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x20),
+	COUNTER6_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x28),
+	COUNTER7_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x28),
+	COUNTER8_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x13),
+	COUNTER9_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x17),
+	COUNTER10_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x17),
+	COUNTER11_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x7c),
+	COUNTER12_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x7c),
+	COUNTER13_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x340),
+	COUNTER16_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x340),
+};
+
+
+static void pwrap_soft_reset(void)
+{
+	writel(0x1, &mt8183_infracfg->infra_globalcon_rst2_set);
+	writel(0x1, &mt8183_infracfg->infra_globalcon_rst2_clr);
+}
+
+static void pwrap_spi_clk_set(void)
+{
+	writel(ULPOSC_OFF | ULPOSC_INV | ULPOSC_SEL_1 | ULPOSC_SEL_2,
+		&mtk_topckgen->clk_cfg_5_clr);
+	writel(ULPOSC_SEL_1, &mtk_topckgen->clk_cfg_5_set);
+	writel(ULPOSC_CLK, &mtk_topckgen->clk_cfg_update);
+
+	writel(TIMER_CG | AP_CG | MD_CG | CONN_CG,
+		&mt8183_infracfg->module_sw_cg_0_set);
+	writel(MODEM_TEMP_SHARE_CG, &mt8183_infracfg->module_sw_cg_2_set);
+
+	pwrap_soft_reset();
+
+	writel(TIMER_CG | AP_CG | MD_CG | CONN_CG,
+		&mt8183_infracfg->module_sw_cg_0_clr);
+	writel(MODEM_TEMP_SHARE_CG, &mt8183_infracfg->module_sw_cg_2_clr);
+}
+
+static s32 pwrap_init_dio(u16 dio_en)
+{
+	pwrap_write_nochk(PMIC_DEW_DIO_EN, dio_en);
+
+	if (wait_for_state_ready(wait_for_sync,
+		100, &mtk_pwrap->wacs2_rdata, 0))
+	return E_PWR_TIMEOUT;
+
+	writel(dio_en, &mtk_pwrap->dio_en);
+	return 0;
+}
+
+static void pwrap_lock_spislvreg(void)
+{
+	pwrap_write_nochk(PMIC_SPISLV_KEY, 0x0);
+}
+
+static void pwrap_initstaupd(void)
+{
+	writel(SIG_PMIC_0 | INT_STA_PMIC_0 | MD_ADC_DATA0 |
+		MD_ADC_DATA1 | GPS_ADC_DATA0 | GPS_ADC_DATA1,
+		&mtk_pwrap->staupd_grpen);
+
+	/* CRC */
+	pwrap_write_nochk(PMIC_DEW_CRC_EN, 0x1);
+	writel(0x1, &mtk_pwrap->crc_en);
+	writel(PMIC_DEW_CRC_VAL, &mtk_pwrap->sig_adr);
+
+	writel(PMIC_CPU_INT_STA, &mtk_pwrap->eint_sta0_adr);
+
+	/* MD ADC Interface */
+	writel((PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31,
+		&mtk_pwrap->md_auxadc_rdata_latest_addr);
+	writel((PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31,
+		&mtk_pwrap->md_auxadc_rdata_wp_addr);
+	for (size_t i = 0; i < 32; i++)
+		writel((PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31,
+			&mtk_pwrap->md_auxadc_rdata[i]);
+
+	writel((PMIC_AUXADC_RQST1 << 16) + PMIC_AUXADC_RQST0,
+		&mtk_pwrap->int_gps_auxadc_cmd_addr);
+	writel((GPS_MAIN << 16) + GPS_SUBSYS, &mtk_pwrap->int_gps_auxadc_cmd);
+	writel((PMIC_AUXADC_ADC32 << 16) + PMIC_AUXADC_ADC17,
+		&mtk_pwrap->int_gps_auxadc_rdata_addr);
+
+	writel(PMIC_AUXADC_ADC31, &mtk_pwrap->ext_gps_auxadc_rdata_addr);
+}
+
+static void pwrap_starve_set(void)
+{
+	writel(ARB_PRIORITY, &mtk_pwrap->harb_hprio);
+	writel(COUNTER0_PENDING_THRES, &mtk_pwrap->starv_counter_0);
+	writel(COUNTER1_PENDING_THRES, &mtk_pwrap->starv_counter_1);
+	writel(COUNTER2_PENDING_THRES, &mtk_pwrap->starv_counter_2);
+	writel(COUNTER3_PENDING_THRES, &mtk_pwrap->starv_counter_3);
+	writel(COUNTER4_PENDING_THRES, &mtk_pwrap->starv_counter_4);
+	writel(COUNTER5_PENDING_THRES, &mtk_pwrap->starv_counter_5);
+	writel(COUNTER6_PENDING_THRES, &mtk_pwrap->starv_counter_6);
+	writel(COUNTER7_PENDING_THRES, &mtk_pwrap->starv_counter_7);
+	writel(COUNTER8_PENDING_THRES, &mtk_pwrap->starv_counter_8);
+	writel(COUNTER9_PENDING_THRES, &mtk_pwrap->starv_counter_9);
+	writel(COUNTER10_PENDING_THRES, &mtk_pwrap->starv_counter_10);
+	writel(COUNTER11_PENDING_THRES, &mtk_pwrap->starv_counter_11);
+	writel(COUNTER12_PENDING_THRES, &mtk_pwrap->starv_counter_12);
+	writel(COUNTER13_PENDING_THRES, &mtk_pwrap->starv_counter_13);
+	writel(COUNTER16_PENDING_THRES, &mtk_pwrap->starv_counter_16);
+}
+
+static void pwrap_enable(void)
+{
+	writel(ARB_USER_EN, &mtk_pwrap->hiprio_arb_en);
+	writel(0x1, &mtk_pwrap->wacs0_en);
+	writel(0x1, &mtk_pwrap->wacs2_en);
+	writel(0x1, &mtk_pwrap->wacs_p2p_en);
+	writel(0x1, &mtk_pwrap->wacs_md32_en);
+	writel(STA_PD_98_5_US, &mtk_pwrap->staupd_ctrl);
+	writel(WATCHDOG_TIMER_7_5_MS, &mtk_pwrap->wdt_unit);
+	writel(WDT_MONITOR_ALL, &mtk_pwrap->wdt_src_en_0);
+	writel(WDT_MONITOR_ALL, &mtk_pwrap->wdt_src_en_1);
+	writel(0x1, &mtk_pwrap->timer_en);
+	writel(INT0_MONITOR, &mtk_pwrap->int0_en);
+	writel(INT1_MONITOR, &mtk_pwrap->int1_en);
+}
+
+static s32 pwrap_init_sistrobe(void)
+{
+	u16 rdata;
+	int si_sample_ctrl;
+	int test_data[30] = {
+		0x6996, 0x9669, 0x6996, 0x9669, 0x6996, 0x9669, 0x6996,
+		0x9669, 0x6996, 0x9669, 0x5AA5, 0xA55A, 0x5AA5, 0xA55A,
+		0x5AA5, 0xA55A, 0x5AA5, 0xA55A, 0x5AA5, 0xA55A, 0x1B27,
+		0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27,
+		0x1B27, 0x1B27};
+
+	for (si_sample_ctrl = 0; si_sample_ctrl < 16; si_sample_ctrl++) {
+		writel(si_sample_ctrl << 5, &mtk_pwrap->si_sample_ctrl);
+
+		pwrap_read_nochk(PMIC_DEW_READ_TEST, &rdata);
+		if (rdata == DEFAULT_VALUE_READ_TEST)
+			break;
+	}
+
+	if (si_sample_ctrl == 16)
+		return E_CLK_EDGE;
+
+	if (si_sample_ctrl == 15)
+		return E_CLK_LAST_SETTING;
+
+	/*
+	 * Add the delay time of SPI data from PMIC to align the start boundary
+	 * to current sampling clock edge.
+	 */
+	for (int si_dly = 0; si_dly < 10; si_dly++) {
+		pwrap_write_nochk(PMIC_RG_SPI_CON2, si_dly);
+
+		int start_boundary_found = 0;
+		for (size_t i = 0; i < 30; i++) {
+			pwrap_write_nochk(PMIC_DEW_WRITE_TEST, test_data[i]);
+			pwrap_read_nochk(PMIC_DEW_WRITE_TEST, &rdata);
+			if ((rdata & 0x7fff) != (test_data[i] & 0x7fff)) {
+				start_boundary_found = 1;
+				break;
+			}
+		}
+		if (start_boundary_found == 1)
+			break;
+	}
+
+	/*
+	 * Change the sampling clock edge to the next one which is the middle
+	 * of SPI data window.
+	 */
+	writel(++si_sample_ctrl << 5, &mtk_pwrap->si_sample_ctrl);
+
+	/* Read Test */
+	pwrap_read_nochk(PMIC_DEW_READ_TEST, &rdata);
+	if (rdata != DEFAULT_VALUE_READ_TEST) {
+		pwrap_err("rdata = %#x, exp = %#x\n", rdata,
+			  DEFAULT_VALUE_READ_TEST);
+		return E_PWR_READ_TEST_FAIL;
+	}
+
+	return 0;
+}
+
+static void pwrap_init_spislv(void)
+{
+	/* Turn on IO filter function */
+	pwrap_write_nochk(PMIC_FILTER_CON0, SPI_FILTER);
+	/* Turn on IO SMT function to improve noise immunity */
+	pwrap_write_nochk(PMIC_SMT_CON1, SPI_SMT);
+	/* Turn off IO pull function for power saving */
+	pwrap_write_nochk(PMIC_GPIO_PULLEN0_CLR, SPI_PULL_DISABLE);
+	/* Enable SPI R/W in suspend mode */
+	pwrap_write_nochk(PMIC_RG_SPI_CON0, 0x1);
+	/* Set PMIC GPIO driving current to 4mA */
+	pwrap_write_nochk(PMIC_DRV_CON1, SPI_DRIVING);
+}
+
+static void pwrap_init_reg_clock(void)
+{
+	writel(0x1, &mtk_pwrap->ext_ck_write);
+
+	pwrap_write_nochk(PMIC_DEW_RDDMY_NO, DUMMY_READ_CYCLES);
+	writel(DUMMY_READ_CYCLES, &mtk_pwrap->rddmy);
+
+	writel(0, &mtk_pwrap->cshext_write);
+	writel(0, &mtk_pwrap->cshext_read);
+	writel(0, &mtk_pwrap->cslext_write);
+	writel(0, &mtk_pwrap->cslext_read);
+}
+
+s32 pwrap_init(void)
+{
+	s32 sub_return = 0, sub_return1 = 0;
+	u16 rdata;
+
+
+	pwrap_spi_clk_set();
+
+	/* Reset spislv */
+	sub_return = pwrap_reset_spislv();
+	if (sub_return != 0) {
+		pwrap_err("reset_spislv fail, ret=%d\n", sub_return);
+		return E_PWR_INIT_RESET_SPI;
+	}
+
+	/* Enable WRAP */
+	writel(0x1, &mtk_pwrap->wrap_en);
+
+	/* Enable WACS2 */
+	writel(0x1, &mtk_pwrap->wacs2_en);
+	writel(WACS2, &mtk_pwrap->hiprio_arb_en); /* ONLY WACS2 */
+
+	/* SPI Waveform Configuration */
+	pwrap_init_reg_clock();
+
+	/* SPI Slave Configuration */
+	pwrap_init_spislv();
+
+	/* Enable DIO mode */
+	sub_return = pwrap_init_dio(1);
+	if (sub_return != 0) {
+		pwrap_err("dio test error, ret=%d\n", sub_return);
+		return E_PWR_INIT_DIO;
+	}
+
+	/* Input data calibration flow; */
+	sub_return = pwrap_init_sistrobe();
+	if (sub_return != 0) {
+		pwrap_err("InitSiStrobe fail,ret=%d\n", sub_return);
+		return E_PWR_INIT_SIDLY;
+	}
+
+	/*
+	 * Write test using WACS2,
+	 * make sure the read/write function ready.
+	 */
+	sub_return = pwrap_write_nochk(PMIC_DEW_WRITE_TEST, WRITE_TEST_VALUE);
+	sub_return1 = pwrap_read_nochk(PMIC_DEW_WRITE_TEST, &rdata);
+	if (rdata != WRITE_TEST_VALUE || sub_return || sub_return1) {
+		pwrap_err("write error, rdata=%#x, return=%d, return1=%d\n",
+			  rdata, sub_return, sub_return1);
+		return E_PWR_INIT_WRITE_TEST;
+	}
+
+	/*
+	 * Status update function initialization
+	 * 1. Signature Checking using CRC (CRC 0 only)
+	 * 2. EINT update
+	 * 3. Read back Auxadc thermal data for GPS
+	 */
+	pwrap_initstaupd();
+
+	writel(PRIORITY_IN_SEL_2, &mtk_pwrap->priority_user_sel_2);
+	writel(PRIORITY_OUT_SEL_2, &mtk_pwrap->arbiter_out_sel_2);
+
+	pwrap_starve_set();
+
+	pwrap_enable();
+
+	/* Initialization Done */
+	writel(0x1, &mtk_pwrap->init_done0);
+	writel(0x1, &mtk_pwrap->init_done2);
+	writel(0x1, &mtk_pwrap->init_done_p2p);
+	writel(0x1, &mtk_pwrap->init_done_md32);
+
+	/* Lock SPISLV Registers */
+	pwrap_lock_spislvreg();
+
+	return 0;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/rtc/rtc.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/rtc/rtc.c
new file mode 100644
index 0000000..ecb5819
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/rtc/rtc.c
@@ -0,0 +1,347 @@
+/*
+ * 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.
+ */
+
+#include <platform/rtc_common.h>
+#include <platform/rtc.h>
+#include <platform/mt6358.h>
+#include <platform/pmic_wrap.h>
+
+#define RTC_GPIO_USER_MASK    ((1 << 13) - (1 << 8))
+
+bool rtc_bootloader_check(void)
+{
+    u16 pdn1;
+
+    rtc_read(RTC_PDN1, &pdn1);
+    if (pdn1 & RTC_PDN1_FAST_BOOT)
+        return true;
+    else
+        return false;
+}
+
+void rtc_bootloader_set_clr(bool value)
+{
+    u16 pdn1;
+
+    if (!rtc_writeif_unlock()) { /* Unlock for reload */
+        rtc_info("rtc_writeif_unlock() fail\n");
+        return;
+    }
+    rtc_read(RTC_PDN1, &pdn1);
+    if (value)
+        pdn1 |= RTC_PDN1_FAST_BOOT;
+    else
+        pdn1 &= ~RTC_PDN1_FAST_BOOT;
+    rtc_write(RTC_PDN1, pdn1);
+    rtc_write_trigger();
+}
+
+/* initialize rtc setting of using dcxo clock */
+static int rtc_enable_dcxo(void)
+{
+    u16 bbpu, con, osc32con, sec;
+
+    rtc_read(RTC_BBPU, &bbpu);
+    rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
+    rtc_write_trigger();
+
+    mdelay(1);
+    if (!rtc_writeif_unlock()) { /* Unlock for reload */
+        rtc_info("rtc_writeif_unlock() failed\n");
+        return 0;
+    }
+
+    rtc_read(RTC_OSC32CON, &osc32con);
+    osc32con &= ~(RTC_EMBCK_SRC_SEL | RTC_EMBCK_SEL_MODE_MASK
+                | RTC_GPS_CKOUT_EN);
+    osc32con |= RTC_XOSC32_ENB | RTC_REG_XOSC32_ENB
+                | RTC_EMB_K_EOSC32_MODE | RTC_EMBCK_SEL_OPTION;
+    if (!rtc_xosc_write(osc32con)) {
+        rtc_info("rtc_xosc_write() failed\n");
+        return 0;
+    }
+
+    rtc_read(RTC_CON, &con);
+    rtc_read(RTC_OSC32CON, &osc32con);
+    rtc_read(RTC_AL_SEC, &sec);
+    rtc_info("con=0x%x, osc32con=0x%x, sec=0x%x\n", con, osc32con, sec);
+
+    return 1;
+}
+
+/* initialize rtc related gpio */
+static int rtc_gpio_init(void)
+{
+    u16 con;
+
+    /* RTC_32K1V8 clock change from 128k div 4 source
+     * to RTC 32k source
+     */
+    pwrap_write_field(PMIC_RG_TOP_CKSEL_CON0_SET, 0x1, 0x1, 3);
+
+    /* Export 32K clock RTC_32K1V8_1 */
+    pwrap_write_field(PMIC_RG_TOP_CKPDN_CON1_CLR, 0x1, 0x1, 1);
+
+    /* Export 32K clock RTC_32K2V8 */
+    rtc_read(RTC_CON, &con);
+    con &= (RTC_CON_LPSTA_RAW | RTC_CON_LPRST | RTC_CON_EOSC32_LPEN
+            | RTC_CON_XOSC32_LPEN);
+    con |= (RTC_CON_GPEN | RTC_CON_GOE);
+    con &= ~(RTC_CON_F32KOB);
+    rtc_write(RTC_CON, con);
+
+    return rtc_write_trigger();
+}
+
+/* set xosc mode */
+void rtc_osc_init(void)
+{
+    /* enable 32K export */
+    rtc_gpio_init();
+}
+
+/* enable lpd subroutine */
+static int rtc_lpen(u16 con)
+{
+    con &= ~RTC_CON_LPRST;
+    rtc_write(RTC_CON, con);
+    if (!rtc_write_trigger())
+        return 0;
+
+    con |= RTC_CON_LPRST;
+    rtc_write(RTC_CON, con);
+    if (!rtc_write_trigger())
+        return 0;
+
+    con &= ~RTC_CON_LPRST;
+    rtc_write(RTC_CON, con);
+    if (!rtc_write_trigger())
+        return 0;
+
+    return 1;
+}
+
+/* low power detect setting */
+static int rtc_lpd_init(void)
+{
+    u16 con, sec;
+
+    /* set RTC_LPD_OPT */
+    rtc_read(RTC_AL_SEC, &sec);
+    sec |= RTC_LPD_OPT_F32K_CK_ALIVE;
+    rtc_write(RTC_AL_SEC, sec);
+    if (!rtc_write_trigger())
+        return 0;
+
+    /* init XOSC32 to detect 32k clock stop */
+    rtc_read(RTC_CON, &con);
+    con |= RTC_CON_XOSC32_LPEN;
+    if (!rtc_lpen(con))
+        return 0;
+
+    /* init EOSC32 to detect rtc low power */
+    rtc_read(RTC_CON, &con);
+    con |= RTC_CON_EOSC32_LPEN;
+    if (!rtc_lpen(con))
+        return 0;
+
+    rtc_read(RTC_CON, &con);
+    con &= ~RTC_CON_XOSC32_LPEN;
+    rtc_write(RTC_CON, con);
+
+    /* set RTC_LPD_OPT */
+    rtc_read(RTC_AL_SEC, &sec);
+    sec &= ~RTC_LPD_OPT_MASK;
+    sec |= RTC_LPD_OPT_EOSC_LPD;
+    rtc_write(RTC_AL_SEC, sec);
+    if (!rtc_write_trigger())
+        return 0;
+
+    return 1;
+}
+
+static bool rtc_hw_init(void)
+{
+    u16 bbpu;
+
+    rtc_read(RTC_BBPU, &bbpu);
+    rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_INIT);
+    rtc_write_trigger();
+
+    udelay(500);
+
+    rtc_read(RTC_BBPU, &bbpu);
+    rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
+    rtc_write_trigger();
+
+    rtc_read(RTC_BBPU, &bbpu);
+    if (bbpu & RTC_BBPU_INIT) {
+        rtc_info("timeout\n");
+        return false;
+    }
+
+    return true;
+}
+
+/* write powerkeys to enable rtc functions */
+static int rtc_powerkey_init(void)
+{
+    rtc_write(RTC_POWERKEY1, RTC_POWERKEY1_KEY);
+    rtc_write(RTC_POWERKEY2, RTC_POWERKEY2_KEY);
+    return rtc_write_trigger();
+}
+
+/* rtc init check */
+int rtc_init(u8 recover)
+{
+    int ret;
+
+    rtc_info("recovery: %d\n", recover);
+
+    /* write powerkeys to enable rtc functions */
+    if (!rtc_powerkey_init()) {
+        ret = -RTC_STATUS_POWERKEY_INIT_FAIL;
+        goto err;
+    }
+
+    /* write interface unlock need to be set after powerkey match */
+    if (!rtc_writeif_unlock()) {
+        ret = -RTC_STATUS_WRITEIF_UNLOCK_FAIL;
+        goto err;
+    }
+
+    if (recover)
+        mdelay(20);
+
+    if (!rtc_gpio_init()) {
+        ret = -RTC_STATUS_GPIO_INIT_FAIL;
+        goto err;
+    }
+
+    if (!rtc_hw_init()) {
+        ret = -RTC_STATUS_HW_INIT_FAIL;
+        goto err;
+    }
+
+    if (!rtc_reg_init()) {
+        ret = -RTC_STATUS_REG_INIT_FAIL;
+        goto err;
+    }
+
+    if (!rtc_lpd_init()) {
+        ret = -RTC_STATUS_LPD_INIT_FAIL;
+        goto err;
+    }
+
+    /* After lpd init, powerkeys need to be written again to enable
+     * low power detect function.
+     */
+    if (!rtc_powerkey_init()) {
+        ret = -RTC_STATUS_POWERKEY_INIT_FAIL;
+        goto err;
+    }
+
+    return RTC_STATUS_OK;
+err:
+    rtc_info("init fail: ret=%d\n", ret);
+    return ret;
+}
+
+/* enable rtc bbpu */
+void rtc_bbpu_power_on(void)
+{
+    u16 bbpu;
+    int ret;
+
+    /* pull powerhold high, control by pmic */
+    pmic_set_power_hold(true);
+
+    /* pull PWRBB high */
+    bbpu = RTC_BBPU_KEY | RTC_BBPU_AUTO | RTC_BBPU_RELOAD | RTC_BBPU_PWREN;
+    rtc_write(RTC_BBPU, bbpu);
+    ret = rtc_write_trigger();
+    rtc_info("rtc_write_trigger=%d\n", ret);
+
+    rtc_read(RTC_BBPU, &bbpu);
+    rtc_info("done BBPU=%#x\n", bbpu);
+}
+
+void poweroff(void)
+{
+    u16 bbpu;
+
+    if (!rtc_writeif_unlock())
+        rtc_info("rtc_writeif_unlock() failed\n");
+    /* pull PWRBB low */
+    bbpu = RTC_BBPU_KEY | RTC_BBPU_RELOAD | RTC_BBPU_PWREN;
+    rtc_write(RTC_BBPU, bbpu);
+
+    pmic_set_power_hold(false);
+    mdelay(1);
+}
+
+static void dcxo_init(void)
+{
+    /* Buffer setting */
+    rtc_write(PMIC_RG_DCXO_CW15, 0xA2AA);
+    rtc_write(PMIC_RG_DCXO_CW13, 0x98E9);
+    rtc_write(PMIC_RG_DCXO_CW16, 0x9855);
+
+    /* 26M enable control */
+    /* Enable clock buffer XO_SOC, XO_CEL */
+    rtc_write(PMIC_RG_DCXO_CW00, 0x4805);
+    rtc_write(PMIC_RG_DCXO_CW11, 0x8000);
+
+    /* Load thermal coefficient */
+    rtc_write(PMIC_RG_TOP_TMA_KEY, 0x9CA7);
+    rtc_write(PMIC_RG_DCXO_CW21, 0x12A7);
+    rtc_write(PMIC_RG_DCXO_ELR0, 0xD004);
+    rtc_write(PMIC_RG_TOP_TMA_KEY, 0x0000);
+
+    /* Adjust OSC FPM setting */
+    rtc_write(PMIC_RG_DCXO_CW07, 0x8FFE);
+
+    /* Re-Calibrate OSC current */
+    rtc_write(PMIC_RG_DCXO_CW09, 0x008F);
+    udelay(100);
+    rtc_write(PMIC_RG_DCXO_CW09, 0x408F);
+    mdelay(5);
+}
+
+/* the rtc boot flow entry */
+void rtc_boot(void)
+{
+    /* dcxo clock init settings */
+    dcxo_init();
+
+    /* dcxo 32k init settings */
+    pwrap_write_field(PMIC_RG_DCXO_CW02, 0xF, 0xF, 0);
+    pwrap_write_field(PMIC_RG_SCK_TOP_CON0, 0x1, 0x1, 0);
+
+    /* using dcxo 32K clock */
+    if (!rtc_enable_dcxo())
+        rtc_info("rtc_enable_dcxo() failed\n");
+
+    rtc_boot_common();
+    rtc_bbpu_power_on();
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/rules.mk b/src/bsp/lk/platform/mediatek/mt6771/drivers/rules.mk
new file mode 100644
index 0000000..0569aed
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/rules.mk
@@ -0,0 +1,79 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/../../common/drivers/mtcmos/mtcmos.c \
+    $(LOCAL_DIR)/../../common/drivers/pll/pll.c \
+    $(LOCAL_DIR)/../../common/drivers/pmic_wrap/pmic_wrap_common.c \
+    $(LOCAL_DIR)/../../common/drivers/pmic/regulator.c \
+    $(LOCAL_DIR)/../../common/drivers/rtc/rtc_common.c \
+    $(LOCAL_DIR)/../../common/drivers/uart/uart.c \
+    $(LOCAL_DIR)/mtcmos/mtcmos.c \
+    $(LOCAL_DIR)/pll/fmeter.c \
+    $(LOCAL_DIR)/pll/pll.c \
+    $(LOCAL_DIR)/pmic_wrap/pmic_wrap.c \
+    $(LOCAL_DIR)/pmic/mt6358.c \
+    $(LOCAL_DIR)/pmic/regulator_core.c \
+    $(LOCAL_DIR)/rtc/rtc.c \
+    $(LOCAL_DIR)/wdt/mtk_wdt.c \
+    $(LOCAL_DIR)/../../../../../dramk_8183/dram/dramc_pi_basic_api.c \
+    $(LOCAL_DIR)/../../../../../dramk_8183/dram/dramc_pi_calibration_api.c \
+    $(LOCAL_DIR)/../../../../../dramk_8183/dram/dramc_pi_ddr_reserve.c \
+    $(LOCAL_DIR)/../../../../../dramk_8183/dram/dramc_pi_main.c \
+    $(LOCAL_DIR)/../../../../../dramk_8183/dram/emi.c \
+    $(LOCAL_DIR)/../../../../../dramk_8183/dram/Hal_io.c \
+    $(LOCAL_DIR)/../../../../../dramk_8183/dram/memory.c \
+    $(LOCAL_DIR)/../../common/drivers/emi/emi_info_v1.c \
+    $(LOCAL_DIR)/usb/usbphy.c \
+    $(LOCAL_DIR)/usb/mtu3.c \
+    $(LOCAL_DIR)/usb/mtu3_qmu.c \
+    $(LOCAL_DIR)/key/mtk_key.c \
+    $(LOCAL_DIR)/timer/timer.c \
+    $(LOCAL_DIR)/i2c/i2c.c \
+    $(LOCAL_DIR)/sspm/sspm.c \
+    $(LOCAL_DIR)/spmfw/spmfw.c \
+
+GLOBAL_INCLUDES += \
+    $(LOCAL_DIR)/include \
+    $(LOCAL_DIR)/../../../../../dramk_8183/dram/inc \
+
+MODULE_DEPS += \
+    lib/mempool \
+
+include make/module.mk
+
+ifeq ($(WITH_DISPLAY), 1)
+MODULE_SRCS += \
+    $(LOCAL_DIR)/display/mt_disp.c \
+    $(LOCAL_DIR)/display/mt_bmpio.c \
+    $(LOCAL_DIR)/display/ddp.c \
+    $(LOCAL_DIR)/display/ddp_common.c
+endif
+
+ifeq ($(HDMI_MAIN_PATH), 1)
+MODULE_SRCS += \
+    $(LOCAL_DIR)/display/dpi.c
+else
+MODULE_SRCS += \
+    $(LOCAL_DIR)/display/dsi.c \
+    $(LOCAL_DIR)/display/disp_pwm.c \
+    $(LOCAL_DIR)/display/dsi_common.c
+endif
+
+ifeq ($(WITH_PANEL_TPV_PH060PB16A), 1)
+MODULE_SRCS += \
+    $(LOCAL_DIR)/display/panel_tpv_ph060pb16a.c
+endif
+
+ifeq ($(WITH_HDMI), 1)
+MODULE_SRCS += \
+    $(LOCAL_DIR)/it66121/csc.c \
+    $(LOCAL_DIR)/it66121/hdmi_drv.c \
+    $(LOCAL_DIR)/it66121/hdmitx_drv.c \
+    $(LOCAL_DIR)/it66121/hdmitx_hdcp.c \
+    $(LOCAL_DIR)/it66121/hdmitx_input.c \
+    $(LOCAL_DIR)/it66121/hdmitx_sys.c \
+    $(LOCAL_DIR)/it66121/IO.c \
+    $(LOCAL_DIR)/it66121/sha1.c \
+    $(LOCAL_DIR)/it66121/utility.c
+endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/spmfw/spmfw.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/spmfw/spmfw.c
new file mode 100644
index 0000000..29addd1
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/spmfw/spmfw.c
@@ -0,0 +1,89 @@
+/*
+ * 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.
+*/
+#include <errno.h>
+#include <kernel/thread.h>
+#include <lib/mempool.h>
+#include <platform/mtk_wdt.h>
+#include <stdbool.h>
+
+#include "fit.h"
+
+#define SPMFW_MEM_SIZE 0x02000000
+
+struct fit_load_spmfw_data {
+    char *part_name;
+    void *buf;
+};
+
+static int fit_load_spmfw_thread(void *arg)
+{
+    int err;
+    struct fit_load_spmfw_data *fit_data = (struct fit_load_spmfw_data *)arg;
+
+
+    err = fit_get_image(fit_data->part_name, &fit_data->buf);
+    if (err) {
+        dprintf(CRITICAL, "load spmfw fit image from partition failed\n");
+        return err;
+    }
+
+    /* TODO: decide verify policy with config. */
+    dprintf(CRITICAL, "verify fit conf sig: %s\n", fit_data->part_name);
+    err = fit_conf_verify_sig(NULL, fit_data->buf);
+    if (err < 0)
+        return err;
+
+    err = fit_load_image(NULL, "kernel", fit_data->buf, NULL, NULL,
+                         NULL, true);
+    if (err && (err != -ENOENT)) {
+        dprintf(CRITICAL, "%s load kernel failed\n", fit_data->part_name);
+        return err;
+    }
+
+    return 0;
+}
+
+void fit_load_spmfw_image(void)
+{
+    int ret_spmfw;
+    thread_t *spmfw_t;
+    struct fit_load_spmfw_data spmfw;
+
+    spmfw.buf = mempool_alloc(SPMFW_MEM_SIZE, MEMPOOL_ANY);
+    spmfw.part_name = "spmfw";
+
+    spmfw_t = thread_create("spmfw_ctl", fit_load_spmfw_thread, &spmfw,
+                           DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+    if (!spmfw_t) {
+        dprintf(CRITICAL, "create load thread spmfw failed\n");
+        return;
+    }
+    thread_resume(spmfw_t);
+    thread_join(spmfw_t, &ret_spmfw, INFINITE_TIME);
+
+    if (ret_spmfw) {
+        dprintf(CRITICAL, "load spmfw image failed\n");
+        return;
+    }
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/sspm/sspm.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/sspm/sspm.c
new file mode 100644
index 0000000..0d0e849
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/sspm/sspm.c
@@ -0,0 +1,212 @@
+/*
+ * 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.
+*/
+#include <errno.h>
+#include <kernel/thread.h>
+#include <lib/mempool.h>
+#include <platform/mtk_wdt.h>
+#include <platform/sspm.h>
+#include <stdbool.h>
+#include "fit.h"
+
+chip_ver_t mt_get_chip_sw_ver(void)
+{
+    chip_ver_t sw_ver;
+    unsigned int ver;
+
+    ver = DRV_Reg32(APSW_VER);
+    if (0 == ver)
+        sw_ver = CHIP_VER_E1;
+    else  //0x1
+        sw_ver = CHIP_VER_E2;
+
+    return sw_ver;
+}
+static void *sspm_memcpy(void *dest, const void *src, int count)
+{
+    unsigned int *tmp = dest;
+    const unsigned int *s = src;
+
+    while (count > 0) {
+        *tmp++ = *s++;
+        count -= 4;
+    }
+
+    return dest;
+}
+int load_sspm_part()
+{
+    uintptr_t load_addr;
+    ptimg_hdr_t *hdr;
+    unsigned char *img, *pmimg, *dmimg, *ximg;
+    unsigned int pmsize, dmsize, xsize;
+    struct sspm_info_t *info;
+    chip_ver_t chip_ver = mt_get_chip_sw_ver();
+
+    /* separate ptimg */
+    pmimg = NULL;
+    dmimg = NULL;
+    ximg = NULL;
+    pmsize = 0;
+    dmsize = 0;
+    xsize = 0;
+    load_addr = SSPM_REAL_ADDR; //SSPM_LOADADDRESS + offset
+    hdr = (ptimg_hdr_t *) load_addr;
+
+    dprintf(INFO, "sspm hdr->magic = 0x%x\n", hdr->magic);
+    while (hdr->magic == PT_MAGIC) {
+        img = ((char *) hdr) + hdr->hdr_size;
+        switch (hdr->id) {
+            case PT_ID_SSPM_PM:
+                pmimg = img;
+                pmsize = hdr->img_size;
+                break;
+            case PT_ID_SSPM_DM:
+                dmimg = img;
+                dmsize = hdr->img_size;
+                break;
+            case PT_ID_SSPM_XFILE:
+                ximg = img;
+                xsize = hdr->img_size;
+                break;
+        }
+        img += ROUNDUP(hdr->img_size, hdr->align);
+        hdr = (ptimg_hdr_t *) img;
+    }
+    if (!pmimg || !dmimg || !ximg) {
+        dprintf(CRITICAL, "SSPM partition missing - PM:%p, DM:%p (@%p)\n",
+                pmimg, dmimg, (void *)load_addr);
+        return -1;
+    }
+
+    dprintf(INFO, "pmimg: %p(%d bytes), dmimg: %p(%d bytes), ximg: %p(%d bytes)\n",
+            pmimg, pmsize, dmimg, dmsize, ximg, xsize);
+
+    sspm_memcpy((unsigned char *) CFG_SSPMP_MEMADDR, pmimg, pmsize);
+    info = (struct sspm_info_t *) (load_addr - ROUNDUP(sizeof(*info), 4));
+    memset(info, 0, ROUNDUP(sizeof(*info), 4));
+
+    info->sspm_dm_ofs = (unsigned int)dmimg - (unsigned int)info;
+    info->sspm_dm_sz = dmsize;
+
+    info->rd_ofs = ROUNDUP(SSPM_PART_SZ, SSPM_MEM_ALIGN);
+    info->rd_sz = SSPM_RD_SZ;
+
+    info->xfile_addr = (uintptr_t)ximg - sizeof(ptimg_hdr_t);
+    info->xfile_sz = sizeof(ptimg_hdr_t) + xsize + sizeof(unsigned int); // with postfix 'END'
+
+    dprintf(INFO, "sspm @%p: dm_ofs %p(%d bytes), rd_ofs %p(%d bytes), xfile addr %p(%d bytes)\n",
+            info, (void*)(info->sspm_dm_ofs), info->sspm_dm_sz, (void*)(info->rd_ofs), info->rd_sz,
+            (void*)(info->xfile_addr), info->xfile_sz);
+
+    if ( (pmsize + dmsize + xsize + 3 * sizeof(ptimg_hdr_t)) > SSPM_PART_SZ) {
+       dprintf(CRITICAL, "SSPM is over %dK, the coredump will overwrite it!\n", SSPM_PART_SZ/1024);
+    }
+
+    mtk_wdt_request_mode_set(MTK_WDT_STATUS_SSPM_RST, WD_REQ_RST_MODE);
+    mtk_wdt_request_en_set(MTK_WDT_STATUS_SSPM_RST, WD_REQ_EN);
+
+#if SSPM_DBG_MODE
+    //Setup GPIO pinmux SSPM JTAG
+    DRV_SetReg32(SSPM_JTAG_SET, 0x00666660);
+
+    if (chip_ver == CHIP_VER_E1) {
+        //Setup GPIO pinmux for SSPM UART0
+        DRV_SetReg32(SSPM_UART_SET0, 0x10000000);
+        DRV_SetReg32(SSPM_UART_SET1, 0x00000001);
+    } else {
+        //Setup GPIO pinmux for SSPM UART1
+        DRV_SetReg32(SSPM_UART_SET1, 0x00044000);
+    }
+#endif
+
+    DRV_WriteReg32(SSPM_CFGREG_GPR0, (unsigned int) (load_addr - ROUNDUP(sizeof(*info), 4)));
+    DRV_WriteReg32(SSPM_CFGREG_GPR6, chip_ver);
+    arch_clean_invalidate_cache_range(SSPM_LOAD_ADDR, SSPM_MEM_SIZE);
+    DRV_SetReg32(SSPM_SW_RSTN, 0x1);
+
+    return 0;
+}
+struct fit_load_sspm_data {
+    char *part_name;
+    void *buf;
+};
+static int fit_load_sspm_thread(void *arg)
+{
+    int err;
+    struct fit_load_sspm_data *fit_data = (struct fit_load_sspm_data *)arg;
+
+    err = fit_get_image(fit_data->part_name, &fit_data->buf);
+    if (err) {
+        dprintf(CRITICAL, "load sspm fit image from partition failed\n");
+        return err;
+    }
+
+    /* TODO: decide verify policy with config. */
+    dprintf(CRITICAL, "verify fit conf sig: %s\n", fit_data->part_name);
+    err = fit_conf_verify_sig(NULL, fit_data->buf);
+    if (err < 0)
+        return err;
+
+    err = fit_load_image(NULL, "kernel", fit_data->buf, NULL, NULL,
+                         NULL, true);
+    if (err && (err != -ENOENT)) {
+        dprintf(CRITICAL, "%s load kernel failed\n", fit_data->part_name);
+        return err;
+    }
+
+    return 0;
+}
+
+void fit_load_sspm_image(void)
+{
+#ifdef SSPM_PART_NAME
+    int ret_sspm;
+    thread_t *sspm_t;
+    void *sspm_buf;
+    struct fit_load_sspm_data sspm;
+
+    sspm_buf = mempool_alloc(SSPM_MEM_SIZE, MEMPOOL_ANY);
+    sspm.part_name = (char *)SSPM_PART_NAME;
+    sspm.buf = sspm_buf;
+
+    sspm_t = thread_create("sspm_ctl", fit_load_sspm_thread, &sspm,
+                           DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+    if (!sspm_t) {
+        dprintf(CRITICAL, "create load thread sspm failed\n");
+        return;
+    }
+    thread_resume(sspm_t);
+    thread_join(sspm_t, &ret_sspm, INFINITE_TIME);
+
+    if (ret_sspm) {
+        dprintf(CRITICAL, "load sspm image failed\n");
+        return;
+    }
+    /* verify sspm */
+    ret_sspm = load_sspm_part();
+    if (ret_sspm){
+        dprintf(CRITICAL, "load sspm part failed\n");
+        return;
+    }
+#endif
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/timer/timer.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/timer/timer.c
new file mode 100644
index 0000000..6889941
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/timer/timer.c
@@ -0,0 +1,55 @@
+/*
+ * 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 <platform/mtk_timer.h>
+
+/* delay msec mseconds */
+extern lk_time_t current_time(void);
+void mdelay(unsigned long msec)
+{
+    lk_time_t start = current_time();
+
+    while (start + msec > current_time());
+}
+
+/* delay usec useconds */
+extern lk_bigtime_t current_time_hires(void);
+void udelay(unsigned long usec)
+{
+    lk_bigtime_t start = current_time_hires();
+
+    while (start + usec > current_time_hires());
+}
+
+/*
+ * busy wait
+ */
+void gpt_busy_wait_us(u32 timeout_us)
+{
+    udelay(timeout_us);
+}
+
+void gpt_busy_wait_ms(u32 timeout_ms)
+{
+    mdelay(timeout_ms);
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/md1122.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/md1122.c
new file mode 100644
index 0000000..d2f1fb5
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/md1122.c
@@ -0,0 +1,170 @@
+/*
+ * MD1122 usb2.0 phy board for FPGA
+ *
+ * Copyright 2016 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#include <debug.h>
+#include <platform/ssusb.h>
+#include <platform/ssusb_sifslv_ippc.h>
+#include <platform/u3phy-i2c.h>
+
+#define MD1122_I2C_ADDR 0x60
+#define PHY_VERSION_BANK 0x20
+#define PHY_VERSION_ADDR 0xe4
+
+static void *g_ippc_port_addr;
+
+int USB_PHY_Write_Register8(unsigned char data, unsigned char addr)
+{
+    u3phy_write_reg(g_ippc_port_addr, MD1122_I2C_ADDR, addr, data);
+
+    return 0;
+}
+
+unsigned char USB_PHY_Read_Register8(unsigned char addr)
+{
+    unsigned char data;
+
+    data = u3phy_read_reg(g_ippc_port_addr, MD1122_I2C_ADDR, addr);
+
+    return data;
+}
+
+unsigned int get_phy_verison(void)
+{
+    unsigned int version = 0;
+
+    u3phy_write_reg8(g_ippc_port_addr, MD1122_I2C_ADDR, 0xff, PHY_VERSION_BANK);
+
+    version = u3phy_read_reg32(g_ippc_port_addr, MD1122_I2C_ADDR, PHY_VERSION_ADDR);
+    dprintf(ALWAYS, "ssusb phy version: %x %p\n", version, g_ippc_port_addr);
+
+    return version;
+}
+
+
+int md1122_u3phy_init(void *i2c_port_base)
+{
+    g_ippc_port_addr = i2c_port_base;
+
+    if (get_phy_verison() != 0xa60810a) {
+        dprintf(ALWAYS,"get phy version failed\n");
+        return -1;
+    }
+
+    /* usb phy initial sequence */
+    USB_PHY_Write_Register8(0x00, 0xFF);
+    dprintf(INFO,"****************before bank 0x00*************************\n");
+    dprintf(INFO,"0x00~0x0F 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
+            USB_PHY_Read_Register8(0x00),USB_PHY_Read_Register8(0x01),USB_PHY_Read_Register8(0x02),USB_PHY_Read_Register8(0x03),
+            USB_PHY_Read_Register8(0x04),USB_PHY_Read_Register8(0x05),USB_PHY_Read_Register8(0x06),USB_PHY_Read_Register8(0x07),
+            USB_PHY_Read_Register8(0x08),USB_PHY_Read_Register8(0x09),USB_PHY_Read_Register8(0x0A),USB_PHY_Read_Register8(0x0B),
+            USB_PHY_Read_Register8(0x0C),USB_PHY_Read_Register8(0x0D),USB_PHY_Read_Register8(0x0E),USB_PHY_Read_Register8(0x0F));
+    dprintf(INFO,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(INFO,"[U2P]addr: 0x05, value: %x\n", USB_PHY_Read_Register8(0x05));
+    dprintf(INFO,"[U2P]addr: 0x18, value: %x\n", USB_PHY_Read_Register8(0x18));
+    dprintf(INFO,"*****************after **********************************\n");
+    USB_PHY_Write_Register8(0x55, 0x05);
+    USB_PHY_Write_Register8(0x84, 0x18);
+
+
+    dprintf(INFO,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(INFO,"[U2P]addr: 0x05, value: %x\n", USB_PHY_Read_Register8(0x05));
+    dprintf(INFO,"[U2P]addr: 0x18, value: %x\n", USB_PHY_Read_Register8(0x18));
+    dprintf(INFO,"****************before bank 0x10*************************\n");
+    USB_PHY_Write_Register8(0x10, 0xFF);
+    dprintf(INFO,"0x00~0x0F 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
+            USB_PHY_Read_Register8(0x00),USB_PHY_Read_Register8(0x01),USB_PHY_Read_Register8(0x02),USB_PHY_Read_Register8(0x03),
+            USB_PHY_Read_Register8(0x04),USB_PHY_Read_Register8(0x05),USB_PHY_Read_Register8(0x06),USB_PHY_Read_Register8(0x07),
+            USB_PHY_Read_Register8(0x08),USB_PHY_Read_Register8(0x09),USB_PHY_Read_Register8(0x0A),USB_PHY_Read_Register8(0x0B),
+            USB_PHY_Read_Register8(0x0C),USB_PHY_Read_Register8(0x0D),USB_PHY_Read_Register8(0x0E),USB_PHY_Read_Register8(0x0F));
+    dprintf(INFO,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(INFO,"[U2P]addr: 0x0A, value: %x\n", USB_PHY_Read_Register8(0x0A));
+    dprintf(INFO,"*****************after **********************************\n");
+
+    USB_PHY_Write_Register8(0x84, 0x0A);
+
+    dprintf(INFO,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(INFO,"[U2P]addr: 0x0A, value: %x\n", USB_PHY_Read_Register8(0x0A));
+    dprintf(INFO,"****************before bank 0x40*************************\n");
+    USB_PHY_Write_Register8(0x40, 0xFF);
+    dprintf(INFO,"0x00~0x0F 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
+            USB_PHY_Read_Register8(0x00),USB_PHY_Read_Register8(0x01),USB_PHY_Read_Register8(0x02),USB_PHY_Read_Register8(0x03),
+            USB_PHY_Read_Register8(0x04),USB_PHY_Read_Register8(0x05),USB_PHY_Read_Register8(0x06),USB_PHY_Read_Register8(0x07),
+            USB_PHY_Read_Register8(0x08),USB_PHY_Read_Register8(0x09),USB_PHY_Read_Register8(0x0A),USB_PHY_Read_Register8(0x0B),
+            USB_PHY_Read_Register8(0x0C),USB_PHY_Read_Register8(0x0D),USB_PHY_Read_Register8(0x0E),USB_PHY_Read_Register8(0x0F));
+    dprintf(INFO,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(INFO,"[U2P]addr: 0x38, value: %x\n", USB_PHY_Read_Register8(0x38));
+    dprintf(INFO,"[U2P]addr: 0x42, value: %x\n", USB_PHY_Read_Register8(0x42));
+    dprintf(INFO,"[U2P]addr: 0x08, value: %x\n", USB_PHY_Read_Register8(0x08));
+    dprintf(INFO,"[U2P]addr: 0x09, value: %x\n", USB_PHY_Read_Register8(0x09));
+    dprintf(INFO,"[U2P]addr: 0x0C, value: %x\n", USB_PHY_Read_Register8(0x0C));
+    dprintf(INFO,"[U2P]addr: 0x0E, value: %x\n", USB_PHY_Read_Register8(0x0E));
+    dprintf(INFO,"[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x10));
+    dprintf(INFO,"[U2P]addr: 0x14, value: %x\n", USB_PHY_Read_Register8(0x14));
+    dprintf(INFO,"*****************after **********************************\n");
+
+    USB_PHY_Write_Register8(0x46, 0x38);
+    USB_PHY_Write_Register8(0x40, 0x42);
+    USB_PHY_Write_Register8(0xAB, 0x08);
+    USB_PHY_Write_Register8(0x0C, 0x09);
+    USB_PHY_Write_Register8(0x71, 0x0C);
+    USB_PHY_Write_Register8(0x4F, 0x0E);
+    USB_PHY_Write_Register8(0xE1, 0x10);
+    USB_PHY_Write_Register8(0x5F, 0x14);
+    dprintf(INFO,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(INFO,"[U2P]addr: 0x38, value: %x\n", USB_PHY_Read_Register8(0x38));
+    dprintf(INFO,"[U2P]addr: 0x42, value: %x\n", USB_PHY_Read_Register8(0x42));
+    dprintf(INFO,"[U2P]addr: 0x08, value: %x\n", USB_PHY_Read_Register8(0x08));
+    dprintf(INFO,"[U2P]addr: 0x09, value: %x\n", USB_PHY_Read_Register8(0x09));
+    dprintf(INFO,"[U2P]addr: 0x0C, value: %x\n", USB_PHY_Read_Register8(0x0C));
+    dprintf(INFO,"[U2P]addr: 0x0E, value: %x\n", USB_PHY_Read_Register8(0x0E));
+    dprintf(INFO,"[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x10));
+    dprintf(INFO,"[U2P]addr: 0x14, value: %x\n", USB_PHY_Read_Register8(0x14));
+    dprintf(INFO,"****************before bank 0x60*************************\n");
+    USB_PHY_Write_Register8(0x60, 0xFF);
+    dprintf(INFO,"0x00~0x0F 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",
+            USB_PHY_Read_Register8(0x00),USB_PHY_Read_Register8(0x01),USB_PHY_Read_Register8(0x02),USB_PHY_Read_Register8(0x03),
+            USB_PHY_Read_Register8(0x04),USB_PHY_Read_Register8(0x05),USB_PHY_Read_Register8(0x06),USB_PHY_Read_Register8(0x07),
+            USB_PHY_Read_Register8(0x08),USB_PHY_Read_Register8(0x09),USB_PHY_Read_Register8(0x0A),USB_PHY_Read_Register8(0x0B),
+            USB_PHY_Read_Register8(0x0C),USB_PHY_Read_Register8(0x0D),USB_PHY_Read_Register8(0x0E),USB_PHY_Read_Register8(0x0F));
+    dprintf(INFO,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(INFO,"[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x14));
+    dprintf(INFO,"*****************after **********************************\n");
+
+    USB_PHY_Write_Register8(0x03, 0x14);
+    dprintf(INFO,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(INFO,"[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x14));
+    dprintf(INFO,"****************before bank 0x00*************************\n");
+    USB_PHY_Write_Register8(0x00, 0xFF);
+    dprintf(INFO,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(INFO,"[U2P]addr: 0x6A, value: %x\n", USB_PHY_Read_Register8(0x6A));
+    dprintf(INFO,"[U2P]addr: 0x68, value: %x\n", USB_PHY_Read_Register8(0x68));
+    dprintf(INFO,"[U2P]addr: 0x6C, value: %x\n", USB_PHY_Read_Register8(0x6C));
+    dprintf(INFO,"[U2P]addr: 0x6D, value: %x\n", USB_PHY_Read_Register8(0x6D));
+    USB_PHY_Write_Register8(0x04, 0x6A);
+    USB_PHY_Write_Register8(0x08, 0x68);
+    USB_PHY_Write_Register8(0x26, 0x6C);
+    USB_PHY_Write_Register8(0x36, 0x6D);
+    dprintf(INFO,"*****************after **********************************\n");
+    dprintf(INFO,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(INFO,"[U2P]addr: 0x6A, value: %x\n", USB_PHY_Read_Register8(0x6A));
+    dprintf(INFO,"[U2P]addr: 0x68, value: %x\n", USB_PHY_Read_Register8(0x68));
+    dprintf(INFO,"[U2P]addr: 0x6C, value: %x\n", USB_PHY_Read_Register8(0x6C));
+    dprintf(INFO,"[U2P]addr: 0x6D, value: %x\n", USB_PHY_Read_Register8(0x6D));
+
+    dprintf(INFO,"[U2P]%s, end\n", __func__);
+    return 0;
+}
+
+void mt_usb_phy_poweron(void)
+{
+    md1122_u3phy_init((void *)U3D_SSUSB_FPGA_I2C_OUT_0P);
+}
+
+void mt_usb_phy_poweroff(void)
+{
+    return;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3.c
new file mode 100644
index 0000000..413a3d4
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3.c
@@ -0,0 +1,1824 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in
+ *  the documentation and/or other materials provided with the
+ *  distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <arch/ops.h>
+#include <debug.h>
+#include <errno.h>
+#include <lib/mempool.h>
+#include <platform.h>
+#include <platform/interrupts.h>
+#include <platform/mt_irq.h>
+#include <platform/mt_usbphy.h>
+#include <platform/reg_utils.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "mtu3.h"
+#include "mtu3_qmu.h"
+
+#pragma GCC push_options
+#pragma GCC optimize("O1")
+
+#define DBG_C(x...) dprintf(CRITICAL, "[USB] " x)
+/* use compile option DEBUG=1 to enable following logs */
+#define DBG_I(x...) dprintf(INFO, "[USB] " x)
+#define DBG_S(x...) dprintf(SPEW, "[USB] " x)
+
+/* bits used in ep interrupts etc */
+#define EPT_RX(n) (1 << ((n) + 16))
+#define EPT_TX(n) (1 << (n))
+
+#define EP0 0
+
+/* Request types */
+#define USB_TYPE_STANDARD   (0x00 << 5)
+#define USB_TYPE_CLASS      (0x01 << 5)
+#define USB_TYPE_VENDOR     (0x02 << 5)
+#define USB_TYPE_RESERVED   (0x03 << 5)
+
+/* values used in GET_STATUS requests */
+#define USB_STAT_SELFPOWERED    0x01
+
+/* USB recipients */
+#define USB_RECIP_DEVICE    0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT  0x02
+#define USB_RECIP_OTHER     0x03
+
+/* Endpoints */
+#define USB_EP_NUM_MASK 0x0f        /* in bEndpointAddress */
+#define USB_EP_DIR_MASK 0x80
+
+#define USB_TYPE_MASK   0x60
+#define USB_RECIP_MASK  0x1f
+
+static struct mu3d g_u3d;
+
+
+static void dump_setup_packet(const char *str, struct usb_setup *sp)
+{
+    DBG_I("\n");
+    DBG_I("%s", str);
+    DBG_I("	   bmRequestType = %x\n", sp->request_type);
+    DBG_I("	   bRequest = %x\n", sp->request);
+    DBG_I("	   wValue = %x\n", sp->value);
+    DBG_I("	   wIndex = %x\n", sp->index);
+    DBG_I("	   wLength = %x\n", sp->length);
+}
+
+static void *udc_zalloc(size_t size)
+{
+    void *buf;
+
+    buf = mempool_alloc(size, MEMPOOL_ANY);
+    if (buf)
+        memset(buf, 0, size);
+
+    return buf;
+}
+
+/* descriptors APIs */
+
+static void change_eps_maxp(struct udc_descriptor *desc, u8 *buf, int len)
+{
+    struct udc_gadget *g = g_u3d.gadget;
+    int n;
+
+    /* only supports HS/FS bulk,  default maxp of all eps is 512, change it to 64 when FS; */
+    if ((g_u3d.speed == SSUSB_SPEED_FULL) &&
+            (desc->tag == ((CONFIGURATION << 8) | EP0))) {
+
+        buf += (9 + 9);  /* size of (config + interface) */
+        for (n = 0; n < g->ifc_endpoints; n++) {
+            if ((9 + 9 + 5 + (7 * n)) >= len)
+                break;
+
+            buf[4] = 0x40;  /* ept->maxpkt; 64bytes */
+            buf[5] = 0x00;  /* ept->maxpkt >> 8; 64bytes */
+            buf += 7;
+        }
+    }
+}
+
+static void copy_desc(struct udc_request *req, void *data, int length)
+{
+    memcpy(req->buffer, data, length);
+    req->length = length;
+}
+
+static struct udc_descriptor *udc_descriptor_alloc(unsigned int type,
+        unsigned int num, unsigned int len)
+{
+    struct udc_descriptor *desc;
+
+    if ((len > 255) || (len < 2) || (num > 255) || (type > 255)) {
+        DBG_C("%s invalid argument\n", __func__);
+        return NULL;
+    }
+
+    desc = udc_zalloc(sizeof(struct udc_descriptor) + len);
+    if (!desc) {
+        DBG_C("alloc desc failed (type:%d)\n", type);
+        return NULL;
+    }
+
+    desc->next = 0;
+    desc->tag = (type << 8) | num;
+    desc->len = len;
+    desc->data[0] = len;
+    desc->data[1] = type;
+
+    return desc;
+}
+
+static void udc_descriptor_register(struct udc_descriptor *desc, int dtype)
+{
+    if (dtype == DESC_TYPE_U2) {
+        desc->next = g_u3d.desc_list;
+        g_u3d.desc_list = desc;
+    } else {
+        desc->next = g_u3d.desc_list_u3;
+        g_u3d.desc_list_u3 = desc;
+    }
+}
+
+static unsigned int udc_string_desc_alloc(const char *str, int dtype)
+{
+    struct udc_descriptor *desc;
+    unsigned char *data;
+    unsigned int len;
+    unsigned int *str_id;
+
+    if (dtype == DESC_TYPE_U2)
+        str_id = &g_u3d.next_string_id;
+    else
+        str_id = &g_u3d.next_string_id_u3;
+
+    if (*str_id > 255)
+        return 0;
+
+    if (!str)
+        return 0;
+
+    len = strlen(str);
+    desc = udc_descriptor_alloc(STRING, *str_id, len * 2 + 2);
+    if (!desc)
+        return 0;
+
+    *str_id += 1;
+
+    /* expand ascii string to utf16 */
+    data = desc->data + 2;
+    while (len-- > 0) {
+        *data++ = *str++;
+        *data++ = 0;
+    }
+
+    udc_descriptor_register(desc, dtype);
+    return desc->tag & 0xff;
+}
+
+static void udc_ept_desc_fill(struct udc_endpoint *ept, unsigned char *data, int dtype)
+{
+    data[0] = 7;
+    data[1] = ENDPOINT;
+    data[2] = ept->num | (ept->in ? USB_DIR_IN : USB_DIR_OUT);
+    data[3] = 0x02;     /* bulk -- the only kind we support */
+    data[4] = 0x00;     /* ept->maxpkt; u2: 512bytes, u3: 1024 by default */
+    data[5] = (dtype == DESC_TYPE_U2) ? 0x02 : 0x04; /* ept->maxpkt >> 8; */
+    data[6] = ept->in ? 0x01 : 0x00;
+}
+
+static void udc_companion_desc_fill(uint8_t *data)
+{
+    data[0] = 6;
+    data[1] = SS_EP_COMP;
+    data[2] = 0x0f;     /* max burst: 0x0~0xf */
+    data[3] = 0x00;
+    data[4] = 0x00;
+    data[5] = 0x00;
+}
+
+static unsigned int udc_ifc_desc_size(struct udc_gadget *g, int dtype)
+{
+    int tmp = 7; /* ep desc */
+
+    tmp += ((dtype == DESC_TYPE_U2) ? 0 : 6); /* u3: add Companion desc */
+    return 9 + g->ifc_endpoints * tmp;
+}
+
+static void udc_ifc_desc_fill(struct udc_gadget *g, unsigned char *data, int dtype)
+{
+    unsigned int n;
+
+    data[0] = 0x09;
+    data[1] = INTERFACE;
+    data[2] = 0x00;     /* ifc number */
+    data[3] = 0x00;     /* alt number */
+    data[4] = g->ifc_endpoints; /* 0x02 */
+    data[5] = g->ifc_class;     /* 0xff */
+    data[6] = g->ifc_subclass;  /* 0x42 */
+    data[7] = g->ifc_protocol;  /* 0x03 */
+    data[8] = udc_string_desc_alloc(g->ifc_string, dtype);
+
+    data += 9;
+    for (n = 0; n < g->ifc_endpoints; n++) {
+        udc_ept_desc_fill(g->ept[n], data, dtype);
+        data += 7;
+        if (dtype == DESC_TYPE_U3) {
+            udc_companion_desc_fill(data);
+            data += 6;
+        }
+    }
+}
+
+/* create our device descriptor */
+static int udc_create_dev_desc(struct udc_device *udev, int dtype)
+{
+    struct udc_descriptor *desc;
+    unsigned char *data;
+
+    desc = udc_descriptor_alloc(DEVICE, EP0, 18);
+    if (!desc)
+        return -ENOMEM;
+
+    data = desc->data;
+    data[2] = 0x00;     /* usb spec minor rev */
+    data[3] = (dtype == DESC_TYPE_U2) ? 0x02 : 0x03; /* usb spec major rev */
+    data[4] = 0x00;     /* class */
+    data[5] = 0x00;     /* subclass */
+    data[6] = 0x00;     /* protocol */
+    data[7] = (dtype == DESC_TYPE_U2) ? 0x40 : 0x09; /* maxp on ept 0 */
+    memcpy(data + 8, &udev->vendor_id, sizeof(short));
+    memcpy(data + 10, &udev->product_id, sizeof(short));
+    memcpy(data + 12, &udev->version_id, sizeof(short));
+    data[14] = udc_string_desc_alloc(udev->manufacturer, dtype);
+    data[15] = udc_string_desc_alloc(udev->product, dtype);
+    data[16] = udc_string_desc_alloc(udev->serialno, dtype);
+    data[17] = 1;       /* number of configurations */
+    udc_descriptor_register(desc, dtype);
+    return 0;
+}
+
+/* create our BOS Binary Device Object descriptor - USB3 (FULL) */
+static int udc_create_u3_bos_desc(void)
+{
+    struct udc_descriptor *desc;
+    unsigned char *data;
+
+    desc = udc_descriptor_alloc(BOS, EP0, 22);
+    if (!desc)
+        return -ENOMEM;
+
+    data = desc->data;
+    data[0] = 0x05;     /* bLength of BOS Header */
+    data[2] = 0x16;     /* wTotalLength[0] */
+    data[3] = 0x00;     /* wTotalLength[1] */
+    data[4] = 0x02;     /* bNumDeviceCaps: number of separate device*/
+    /* capability descriptors in BOS */
+
+    /* BOS 1 */
+    data[5] = 0x07;     /* bLength: 7 */
+    data[6] = 0x10;     /* bDescriptorType: DEVICE CAPABILITY */
+    data[7] = 0x02;     /* bDevCapabilityType: USB 2.0 Ext Descriptor */
+    data[8] = 0x02;     /* bmAttributes[4]: LPM (SuperSpeed) */
+    data[9] = 0x00;
+    data[10] = 0x00;
+    data[11] = 0x00;
+
+    /* BOS 2 */
+    data[12] = 0x0A;        /* bLength: 10 */
+    data[13] = 0x10;        /* bDescriptorType: DEVICE CAPABILITY */
+    data[14] = 0x03;        /* bDevCapabilityType: SuperSpeed */
+    data[15] = 0x00;        /* bmAttributes: Don't support LTM */
+    data[16] = 0x0E;        /* wSpeedsSupported[0]: b'1110 */
+    data[17] = 0x00;        /* wSpeedsSupported[1] */
+    data[18] = 0x01;        /* bFunctionalitySupport */
+    data[19] = 0x0A;        /* bU1DevExitLat: Less than 10us */
+    data[20] = 0x20;        /* wU2DevExitLat[0]: 32us */
+    data[21] = 0x00;        /* wU2DevExitLat[1] */
+
+    udc_descriptor_register(desc, DESC_TYPE_U3);
+    return 0;
+}
+
+static int udc_create_config_desc(struct udc_gadget *gadget, int dtype)
+{
+    struct udc_descriptor *desc;
+    unsigned char *data;
+    unsigned int size;
+
+    /* create our configuration descriptor */
+    size = 9 + udc_ifc_desc_size(gadget, dtype);
+    desc = udc_descriptor_alloc(CONFIGURATION, EP0, size);
+    if (!desc)
+        return -ENOMEM;
+
+    data = desc->data;
+    data[0] = 0x09;
+    data[2] = size;
+    data[3] = size >> 8;
+    data[4] = 0x01;     /* number of interfaces */
+    data[5] = 0x01;     /* configuration value */
+    data[6] = 0x00;     /* configuration string */
+    data[7] = 0x80;     /* attributes */
+    /* max power u2: (250ma), u3: 400ma  */
+    data[8] = (dtype == DESC_TYPE_U2) ? 0x80 : 0x32;
+
+    udc_ifc_desc_fill(gadget, data + 9, dtype);
+    udc_descriptor_register(desc, dtype);
+    return 0;
+}
+
+static int udc_create_language_table_desc(int dtype)
+{
+    struct udc_descriptor *desc;
+
+    /* create and register a language table descriptor */
+    /* language 0x0409 is US English */
+    desc = udc_descriptor_alloc(STRING, EP0, 4);
+    if (!desc)
+        return -ENOMEM;
+
+    desc->data[2] = 0x09;
+    desc->data[3] = 0x04;
+    udc_descriptor_register(desc, dtype);
+    return 0;
+}
+
+static int udc_create_descriptors(struct udc_device *udev, struct udc_gadget *gadget)
+{
+    udc_create_dev_desc(udev, DESC_TYPE_U2);
+    udc_create_config_desc(gadget, DESC_TYPE_U2);
+    udc_create_language_table_desc(DESC_TYPE_U2);
+
+    if (g_u3d.is_u3_ip) {
+        udc_create_dev_desc(udev, DESC_TYPE_U3);
+        udc_create_u3_bos_desc();
+        udc_create_config_desc(gadget, DESC_TYPE_U3);
+        udc_create_language_table_desc(DESC_TYPE_U3);
+    }
+
+#if 0
+    {
+        struct udc_descriptor *desc;
+
+        DBG_I("%s: dump u2 desc_list\n", __func__);
+        for (desc = g_u3d.desc_list; desc; desc = desc->next) {
+            DBG_I("tag: %04x\n", desc->tag);
+            DBG_I("len: %d\n", desc->len);
+            DBG_I("data:");
+            hexdump8(desc->data, desc->len);
+        }
+
+        DBG_I("%s: dump u3 desc_list\n", __func__);
+        for (desc = g_u3d.desc_list_u3; desc; desc = desc->next) {
+            DBG_I("tag: %04x\n", desc->tag);
+            DBG_I("len: %d\n", desc->len);
+            DBG_I("data:");
+            hexdump8(desc->data, desc->len);
+        }
+    }
+#endif
+
+    return 0;
+}
+
+/* hardware access APIs */
+
+int wait_for_value(paddr_t addr, u32 msk, u32 value, int us_intvl, int count)
+{
+    int i;
+
+    for (i = 0; i < count; i++) {
+        if ((readl(addr) & msk) == value)
+            return 0;
+
+        spin(us_intvl);
+    }
+
+    return -ETIMEDOUT;
+}
+
+static inline void writel_rep(volatile void *addr, const void *buffer,
+                              unsigned int count)
+{
+    if (count) {
+        const u32 *buf = buffer;
+
+        do {
+            writel(*buf++, addr);
+        } while (--count);
+    }
+}
+
+static inline void readl_rep(const volatile void *addr, void *buffer,
+                             unsigned int count)
+{
+    if (count) {
+        u32 *buf = buffer;
+
+        do {
+            u32 x = readl(addr);
+            *buf++ = x;
+        } while (--count);
+    }
+}
+
+static int pio_read_fifo(int ep_num, u8 *dst, u16 len)
+{
+    void *fifo = (void *)(paddr_t)(USB_FIFO(ep_num));
+    u32 index = 0;
+    u32 value;
+
+    if (len >= 4) {
+        readl_rep(fifo, dst, len >> 2);
+        index = len & ~0x03;
+    }
+    if (len & 0x3) {
+        value = readl(fifo);
+        memcpy(&dst[index], &value, len & 0x3);
+    }
+
+    DBG_I("%s - ep_num: %d, len: %d, dst: %p\n",
+          __func__, ep_num, len, dst);
+
+    return len;
+}
+
+static void pio_write_fifo(int ep_num, u8 *src, u16 len)
+{
+    void *fifo = (void *)(paddr_t)(USB_FIFO(ep_num));
+    u32 index = 0;
+
+    DBG_I("%s - ep_num: %d, len: %d, src: %p\n",
+          __func__, ep_num, len, src);
+
+    if (len >= 4) {
+        writel_rep(fifo, src, len >> 2);
+        index = len & ~0x03;
+    }
+    if (len & 0x02) {
+        writew(*(u16 *)&src[index], fifo);
+        index += 2;
+    }
+    if (len & 0x01)
+        writeb(src[index], fifo);
+}
+
+static int mu3d_check_clk_sts(void)
+{
+    u32 check_val;
+    int ret = 0;
+
+    check_val = SSUSB_SYS125_RST_B_STS | SSUSB_SYSPLL_STABLE |
+                SSUSB_REF_RST_B_STS;
+    if (g_u3d.is_u3_ip)
+        check_val |= SSUSB_U3_MAC_RST_B_STS;
+
+    ret = wait_for_value(U3D_SSUSB_IP_PW_STS1, check_val, check_val, 100, 100);
+    if (ret) {
+        DBG_C("SSUSB_SYS125_RST_B_STS NG\n");
+        goto err;
+    } else {
+        DBG_I("clk sys125:OK\n");
+    }
+
+    ret = wait_for_value(U3D_SSUSB_IP_PW_STS2, SSUSB_U2_MAC_SYS_RST_B_STS,
+                         SSUSB_U2_MAC_SYS_RST_B_STS, 100, 100);
+    if (ret) {
+        DBG_C("SSUSB_U2_MAC_SYS_RST_B_STS NG\n");
+        goto err;
+    } else {
+        DBG_I("clk mac2:OK\n");
+    }
+
+    return 0;
+
+err:
+    DBG_C("Refer clocks stability check failed!\n");
+    return ret;
+}
+
+static void mu3d_ssusb_enable(void)
+{
+    clrbits32_r(SSUSB_IP_SW_RST, U3D_SSUSB_IP_PW_CTRL0);
+    clrbits32_r(SSUSB_IP_DEV_PDN, U3D_SSUSB_IP_PW_CTRL2);
+    clrbits32_r((SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN |
+                 SSUSB_U2_PORT_HOST_SEL), U3D_SSUSB_U2_CTRL_0P);
+    if (g_u3d.is_u3_ip)
+        clrbits32_r((SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN |
+                     SSUSB_U3_PORT_HOST_SEL), U3D_SSUSB_U3_CTRL_0P);
+
+    mu3d_check_clk_sts();
+}
+
+/* enable/disable U3D SS function */
+static void mu3d_ss_func_set(bool enable)
+{
+    /* If usb3_en==0, LTSSM will go to SS.Disable state */
+    if (enable)
+        setbits32_r(USB3_EN, U3D_USB3_CONFIG);
+    else
+        clrbits32_r(USB3_EN, U3D_USB3_CONFIG);
+
+    DBG_C("U3 pullup D%s\n", enable ? "+" : "-");
+}
+
+/* set/clear U3D HS device soft connect */
+static void mu3d_hs_softconn_set(bool enable)
+{
+    if (enable)
+        setbits32_r(SOFT_CONN | SUSPENDM_ENABLE, U3D_POWER_MANAGEMENT);
+    else
+        clrbits32_r(SOFT_CONN | SUSPENDM_ENABLE, U3D_POWER_MANAGEMENT);
+
+    DBG_C("U2 pullup D%s\n", enable ? "+" : "-");
+}
+
+static void mu3d_soft_connect(void)
+{
+    if (g_u3d.is_u3_ip && g_u3d.speed > SSUSB_SPEED_HIGH)
+        mu3d_ss_func_set(true);
+    else
+        mu3d_hs_softconn_set(true);
+}
+
+static void mu3d_soft_disconnect(void)
+{
+    if (g_u3d.is_u3_ip && g_u3d.speed > SSUSB_SPEED_HIGH)
+        mu3d_ss_func_set(false);
+    else
+        mu3d_hs_softconn_set(false);
+}
+
+static void mu3d_dev_reset(void)
+{
+    setbits32_r(SSUSB_DEV_SW_RST, U3D_SSUSB_DEV_RST_CTRL);
+    clrbits32_r(SSUSB_DEV_SW_RST, U3D_SSUSB_DEV_RST_CTRL);
+}
+
+static void mu3d_intr_enable(void)
+{
+    u32 value;
+
+    /* enable LV1 ISR */
+    value = BMU_INTR | QMU_INTR | MAC3_INTR | MAC2_INTR | EP_CTRL_INTR;
+    writel(value, U3D_LV1IESR);
+    /* enable U2 common interrupts */
+    value = SUSPEND_INTR | RESUME_INTR | RESET_INTR;
+    writel(value, U3D_COMMON_USB_INTR_ENABLE);
+
+    clrbits32_r(DC_SESSION, U3D_DEVICE_CONTROL);
+    setbits32_r(VBUS_FRC_EN | VBUS_ON, U3D_MISC_CTRL);
+
+    /* Enable U3 LTSSM interrupts */
+    if (g_u3d.is_u3_ip) {
+        value = HOT_RST_INTR | WARM_RST_INTR | VBUS_RISE_INTR |
+                VBUS_FALL_INTR | ENTER_U3_INTR | EXIT_U3_INTR;
+        writel(value, U3D_LTSSM_INTR_ENABLE);
+    }
+
+    /* Enable QMU interrupts. */
+    value = TXQ_CSERR_INT | TXQ_LENERR_INT | RXQ_CSERR_INT |
+            RXQ_LENERR_INT | RXQ_ZLPERR_INT;
+    writel(value, U3D_QIESR1);
+    /* Enable speed change interrupt */
+    writel(SSUSB_DEV_SPEED_CHG_INTR, U3D_DEV_LINK_INTR_ENABLE);
+}
+
+static void mu3d_intr_disable(void)
+{
+    writel(0xffffffff, U3D_EPISR);
+    writel(0xffffffff, U3D_QISAR0);
+    writel(0xffffffff, U3D_QISAR1);
+    writel(0xffffffff, U3D_TQERRIR0);
+    writel(0xffffffff, U3D_RQERRIR0);
+    writel(0xffffffff, U3D_RQERRIR1);
+    writel(0xffffffff, U3D_LV1IECR);
+    writel(0xffffffff, U3D_EPIECR);
+
+    /* clear registers */
+    writel(0xffffffff, U3D_QIECR0);
+    writel(0xffffffff, U3D_QIECR1);
+    writel(0xffffffff, U3D_TQERRIECR0);
+    writel(0xffffffff, U3D_RQERRIECR0);
+    writel(0xffffffff, U3D_RQERRIECR1);
+    writel(0xffffffff, U3D_COMMON_USB_INTR);
+}
+
+static void mu3d_reg_init(void)
+{
+    if (g_u3d.is_u3_ip) {
+        /* disable LGO_U1/U2 by default */
+        clrbits32_r(SW_U1_ACCEPT_ENABLE | SW_U2_ACCEPT_ENABLE |
+                     SW_U1_REQUEST_ENABLE | SW_U2_REQUEST_ENABLE,
+                     U3D_LINK_POWER_CONTROL);
+        /* device responses to u3_exit from host automatically */
+        clrbits32_r(SOFT_U3_EXIT_EN, U3D_LTSSM_CTRL);
+        /* automatically build U2 link when U3 detect fail */
+        setbits32_r(U2U3_AUTO_SWITCH, U3D_USB2_TEST_MODE);
+    }
+    /* delay about 0.1us from detecting reset to send chirp-K */
+    clrbits32_r(WTCHRP_MSK, U3D_LINK_RESET_INFO);
+    /* U2/U3 detected by HW */
+    writel(0, U3D_DEVICE_CONF);
+    /* enable QMU 16B checksum */
+    setbits32_r(QMU_CS16B_EN, U3D_QCR0);
+    /* vbus detected by HW */
+    clrbits32_r(VBUS_FRC_EN | VBUS_ON, U3D_MISC_CTRL);
+}
+
+static USB_SPEED mu3d_get_speed(void)
+{
+    const char *spd_str[] = {"UNKNOW", "FS", "HS", "SS", "SSP"};
+    USB_SPEED spd;
+
+    switch (SSUSB_DEV_SPEED(readl(U3D_DEVICE_CONF))) {
+        case 1:
+            spd = SSUSB_SPEED_FULL;
+            break;
+        case 3:
+            spd = SSUSB_SPEED_HIGH;
+            break;
+        case 4:
+            spd = SSUSB_SPEED_SUPER;
+            break;
+        case 5:
+            spd = SSUSB_SPEED_SUPER_PLUS;
+            break;
+        default:
+            spd = SSUSB_SPEED_UNKNOWN;
+            break;
+    }
+
+    DBG_C("%s (%d) is detected\n", spd_str[spd % ARRAY_SIZE(spd_str)], spd);
+    return spd;
+}
+
+/* SSP is not supported tmp. */
+static void mu3d_set_speed(USB_SPEED spd)
+{
+    const char *spd_str[] = {"UNKNOW", "FS", "HS", "SS", "SSP"};
+
+    switch (spd) {
+        case SSUSB_SPEED_FULL:
+            clrbits32_r(USB3_EN, U3D_USB3_CONFIG);
+            clrbits32_r(HS_ENABLE, U3D_POWER_MANAGEMENT);
+            break;
+        case SSUSB_SPEED_HIGH:
+            clrbits32_r(USB3_EN, U3D_USB3_CONFIG);
+            setbits32_r(HS_ENABLE, U3D_POWER_MANAGEMENT);
+            break;
+        case SSUSB_SPEED_SUPER:
+            /* fall through */
+        default:
+            clrbits32_r(SSUSB_U3_PORT_SSP_SPEED, U3D_SSUSB_U3_CTRL_0P);
+            break;
+    }
+    DBG_I("%s %s (%d)\n", __func__, spd_str[spd % ARRAY_SIZE(spd_str)], spd);
+}
+
+static inline void mu3d_set_address(int addr)
+{
+    writel(DEV_ADDR(addr), U3D_DEVICE_CONF);
+}
+
+struct udc_endpoint *mtu3_find_ep(int ep_num, u8 dir)
+{
+    struct udc_endpoint *ep_list = g_u3d.eps;
+    int i;
+    u8 in;
+
+    /* convert dir to in */
+    if (dir == USB_DIR_IN)
+        in = 1;
+    else
+        in = 0;
+
+    for (i = 1; i < MT_EP_NUM; i++) {
+        if ((ep_list[i].num == ep_num) && (ep_list[i].in == in))
+            return &ep_list[i];
+    }
+    return NULL;
+}
+
+static void mu3d_flush_fifo(u8 ep_num, u8 dir)
+{
+    if (ep_num == 0) {
+        setbits32_r(EP0_RST, U3D_EP_RST);
+        clrbits32_r(EP0_RST, U3D_EP_RST);
+    } else {
+        setbits32_r(EP_RST((dir == USB_DIR_IN), ep_num), U3D_EP_RST);
+        clrbits32_r(EP_RST((dir == USB_DIR_IN), ep_num), U3D_EP_RST);
+    }
+}
+
+static void ep0_stall_set(bool set, u32 pktrdy)
+{
+    u32 csr;
+
+    /* EP0_SENTSTALL is W1C */
+    csr = readl(U3D_EP0CSR) & EP0_W1C_BITS;
+    if (set)
+        csr |= EP0_SENDSTALL | pktrdy;
+    else
+        csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL;
+    writel(csr, U3D_EP0CSR);
+
+    g_u3d.ep0_state = EP0_IDLE;
+}
+
+/*
+ * Return value indicates the TxFIFO size of 2^n bytes, (ex: value 10 means 2^10 =
+ * 1024 bytes.) TXFIFOSEGSIZE should be equal or bigger than 4. The TxFIFO size of
+ * 2^n bytes also should be equal or bigger than TXMAXPKTSZ. This EndPoint occupy
+ * total memory size  (TX_SLOT + 1 )*2^TXFIFOSEGSIZE bytes.
+ */
+static u8 get_seg_size(u32 maxp)
+{
+    /* Set fifo size(double buffering is currently not enabled) */
+    switch (maxp) {
+        case 8:
+        case 16:
+            return USB_FIFOSZ_SIZE_16;
+        case 32:
+            return USB_FIFOSZ_SIZE_32;
+        case 64:
+            return USB_FIFOSZ_SIZE_64;
+        case 128:
+            return USB_FIFOSZ_SIZE_128;
+        case 256:
+            return USB_FIFOSZ_SIZE_256;
+        case 512:
+            return USB_FIFOSZ_SIZE_512;
+        case 1023:
+        case 1024:
+        case 2048:
+        case 3072:
+        case 4096:
+            return USB_FIFOSZ_SIZE_1024;
+        default:
+            DBG_I("The maxp %d is not supported\n", maxp);
+            return USB_FIFOSZ_SIZE_512;
+    }
+}
+
+static void mu3d_setup_ep(unsigned int ep_num, struct udc_endpoint *ept)
+{
+    u32 csr0, csr1, csr2;
+    u32 fifo_addr;
+    u8 seg_size;
+
+    /* Nothing needs to be done for ep0 */
+    if (ep_num == 0)
+        return;
+
+    /* In LK (FASTBOOT) will use BULK transfer only */
+    if (ept->type != USB_EP_XFER_BULK)
+        DBG_C("ep type is wrong, should be bulk,\n");
+
+    /* Set fifo address, fifo size, and fifo max packet size */
+    DBG_I("%s: %s, maxpkt: %d\n", __func__, ept->name, ept->maxpkt);
+
+    /* Set fifo size(only supports single buffering) */
+    seg_size = get_seg_size(ept->maxpkt);
+
+    if (ept->in) {  /* TX case */
+        mu3d_flush_fifo(ep_num, USB_DIR_IN);
+
+        csr0 = TX_TXMAXPKTSZ(ept->maxpkt);
+
+        /* only support BULK, set 0 for burst, slot, mult, num_pkts  */
+        csr1 = TX_TYPE(TYPE_BULK);
+
+        fifo_addr = g_u3d.tx_fifo_addr + (U3D_FIFO_SIZE_UNIT * ep_num);
+        csr2 = TX_FIFOADDR(fifo_addr >> 4);
+        csr2 |= TX_FIFOSEGSIZE(seg_size);
+
+#ifdef SUPPORT_QMU
+        csr0 |= TX_DMAREQEN;
+        /* Enable QMU Done interrupt */
+        setbits32_r(QMU_TX_DONE_INT(ep_num), U3D_QIESR0);
+#else
+        setbits32_r(EP_TXISR(ep_num), U3D_EPIECR);  /* W1C */
+        setbits32_r(EP_TXISR(ep_num), U3D_EPIESR);  /* W1S */
+#endif
+
+        writel(csr0, MU3D_EP_TXCR0(ep_num));
+        writel(csr1, MU3D_EP_TXCR1(ep_num));
+        writel(csr2, MU3D_EP_TXCR2(ep_num));
+
+    } else {    /* RX case */
+        mu3d_flush_fifo(ep_num, USB_DIR_OUT);
+
+        csr0 = RX_RXMAXPKTSZ(ept->maxpkt);
+
+        /* only support BULK, set 0 for burst, slot, mult, num_pkts  */
+        csr1 = RX_TYPE(TYPE_BULK);
+
+        fifo_addr = g_u3d.rx_fifo_addr + (U3D_FIFO_SIZE_UNIT * ep_num);
+        csr2 = RX_FIFOADDR(fifo_addr >> 4);
+        csr2 |= RX_FIFOSEGSIZE(seg_size);
+
+#ifdef SUPPORT_QMU
+        csr0 |= RX_DMAREQEN;
+        /* Enable QMU Done interrupt */
+        setbits32_r(QMU_RX_DONE_INT(ep_num), U3D_QIESR0);
+#else
+        setbits32_r(EP_RXISR(ep_num), U3D_EPIECR);  /* W1C */
+        /* enable it when queue RX request */
+        /* setbits32_r(EP_RXISR(ep_num), U3D_EPIESR);*/   /* W1S */
+#endif
+        writel(csr0, MU3D_EP_RXCR0(ep_num));
+        writel(csr1, MU3D_EP_RXCR1(ep_num));
+        writel(csr2, MU3D_EP_RXCR2(ep_num));
+    }
+
+#ifdef SUPPORT_QMU
+    mtu3_qmu_start(ept);
+#endif
+}
+
+static void mu3d_ep0en(void)
+{
+    u32 temp = 0;
+    struct udc_endpoint *ep0 = g_u3d.ep0;
+
+    sprintf(ep0->name, "ep0");
+    ep0->type = USB_EP_XFER_CTRL;
+    ep0->num = EP0;
+    if (g_u3d.speed == SSUSB_SPEED_SUPER)
+        ep0->maxpkt = EP0_MAX_PACKET_SIZE_U3;
+    else
+        ep0->maxpkt = EP0_MAX_PACKET_SIZE;
+
+    temp = readl(U3D_EP0CSR);
+    temp &= ~(EP0_MAXPKTSZ_MSK | EP0_AUTOCLEAR | EP0_AUTOSET | EP0_DMAREQEN);
+    temp |= EP0_MAXPKTSZ(ep0->maxpkt);
+    temp &= EP0_W1C_BITS;
+    writel(temp, U3D_EP0CSR);
+
+    /* enable EP0 interrupts */
+    setbits32_r(EP_EP0ISR, U3D_EPIESR);
+}
+
+static void mu3d_get_ip_vers(void)
+{
+    g_u3d.is_u3_ip = 0; //!!SSUSB_IP_DEV_U3_PORT_NUM(val);
+    DBG_C("IP version 0x%x(%s IP)\n", readl(U3D_SSUSB_HW_ID),
+          g_u3d.is_u3_ip ? "U3" : "U2");
+}
+
+static void mu3d_hw_init(void)
+{
+    mu3d_dev_reset();
+    mu3d_ssusb_enable();
+    mu3d_intr_disable();
+    mu3d_reg_init();
+    mu3d_set_speed(g_u3d.speed);
+    mu3d_intr_enable();
+    mu3d_ep0en();
+}
+
+static void mtu3_setup_eps(void)
+{
+    struct udc_endpoint *ep_list = g_u3d.eps;
+    USB_SPEED speed = g_u3d.speed;
+    int maxp = 512;
+    int i;
+
+    if (speed == SSUSB_SPEED_FULL)
+        maxp = 64;
+    else if (speed == SSUSB_SPEED_HIGH)
+        maxp = 512;
+    else if (speed == SSUSB_SPEED_SUPER)
+        maxp = 1024;
+
+    for (i = 1; i < MT_EP_NUM; i++) {
+        if (ep_list[i].num != 0) { /* allocated */
+            ep_list[i].maxpkt = maxp;
+            mu3d_setup_ep(ep_list[i].num, &ep_list[i]);
+        }
+    }
+}
+
+
+/* usb generic functions */
+
+void handle_ept_complete(struct udc_endpoint *ept, int status)
+{
+    struct udc_request *req;
+    struct mu3d_req *mreq;
+    unsigned int actual;
+
+    req = ept->req;
+    mreq = to_mu3d_req(req);
+    if (req) {
+        ept->req = NULL;
+
+        if (status)
+            DBG_C("%s: %s FAIL status: %d\n", __func__, ept->name, status);
+
+        actual = status ? 0 : mreq->actual;
+
+        DBG_I("%s: %s, req: %p: complete: %d/%d: status: %d\n",
+              __func__, ept->name, req, actual, req->length, status);
+
+        if (req->complete)
+            req->complete(req, actual, status);
+    }
+}
+
+static int mtu3_read_fifo(struct udc_endpoint *ept)
+{
+    struct udc_request *req = ept->req;
+    struct mu3d_req *mreq = to_mu3d_req(req);
+    int ep_num = ept->num;
+    u32 count = 0;
+
+    if (mreq) {
+        if (ep_num == 0)
+            count = readl(U3D_RXCOUNT0);
+        else
+            count = EP_RX_COUNT(readl(MU3D_EP_RXCR3(ep_num)));
+
+        count = MIN(req->length - mreq->actual, count);
+        pio_read_fifo(ep_num, req->buffer + mreq->actual, count);
+#if 0
+        if (ep_num != 0) {
+            DBG_I("%s: &req->buffer: %p\n", __func__, req->buffer);
+            DBG_I("dump data:\n");
+            hexdump8(req->buffer, len);
+        }
+#endif
+        mreq->actual += count;
+
+        DBG_I("%s: ep%dout, mreq: %p, buf: %p, length: %d, actual: %d\n",
+              __func__, ep_num, mreq, req->buffer, req->length, mreq->actual);
+    }
+
+    return count;
+}
+
+static int mtu3_write_fifo(struct udc_endpoint *ept)
+{
+    struct udc_request *req = ept->req;
+    struct mu3d_req *mreq = to_mu3d_req(req);
+    unsigned char *buf;
+    int ep_num = ept->num;
+    int count = 0;
+
+    if (mreq) {
+        DBG_I("%s: ep%din mreq: %p, length: %d, actual: %d, maxp: %d\n",
+              __func__, ep_num, mreq, req->length, mreq->actual, ept->maxpkt);
+
+        count = MIN(req->length - mreq->actual, ept->maxpkt);
+        buf = req->buffer + mreq->actual;
+        pio_write_fifo(ep_num, buf, count);
+        mreq->actual += count;
+    }
+
+    return count;
+}
+
+static void mtu3_ep0_write(void)
+{
+    struct udc_endpoint *ep0 = g_u3d.ep0;
+    struct udc_request *req = ep0->req;
+    struct mu3d_req *mreq = to_mu3d_req(req);
+    unsigned int count = 0;
+    u32 csr0;
+
+    csr0 = readl(U3D_EP0CSR);
+    if (csr0 & EP0_TXPKTRDY) {
+        DBG_I("%s: ep0 is not ready to be written\n", __func__);
+        return;
+    }
+
+    count = mtu3_write_fifo(ep0);
+
+    /* hardware limitiation: can't set (EP0_TXPKTRDY | EP0_DATAEND) at same time */
+    csr0 |= (EP0_TXPKTRDY);
+    writel(csr0, U3D_EP0CSR);
+
+    DBG_I("%s: length=%d, actual=%d\n", __func__, req->length, mreq->actual);
+    if ((count < ep0->maxpkt) || (req->length == mreq->actual)) {
+        /* last packet */
+        mreq->actual = 0;
+        g_u3d.ep0_state = EP0_TX_END;
+    }
+}
+
+static void mtu3_ep0_read(void)
+{
+    struct udc_endpoint *ep0 = g_u3d.ep0;
+    struct udc_request *req = ep0->req;
+    struct mu3d_req *mreq = to_mu3d_req(req);
+    unsigned int count = 0;
+    u32 csr0 = 0;
+
+    csr0 = readl(U3D_EP0CSR);
+
+    /* erroneous ep0 interrupt */
+    if (!(csr0 & EP0_RXPKTRDY))
+        return;
+
+    count = mtu3_read_fifo(ep0);
+
+    /* work around: cannot set  (EP0_RXPKTRDY | EP0_DATAEND) at same time */
+    csr0 |= (EP0_RXPKTRDY);
+    writel(csr0, U3D_EP0CSR);
+
+    if ((count < ep0->maxpkt) || (mreq->actual == req->length)) {
+        /* last packet */
+        csr0 |= EP0_DATAEND;
+        g_u3d.ep0_state = EP0_IDLE;
+    } else {
+        /* more packets are waiting to be transferred */
+        csr0 |= EP0_RXPKTRDY;
+    }
+
+    writel(csr0, U3D_EP0CSR);
+}
+
+static int std_get_descs(struct udc_request *req, struct usb_setup *setup)
+{
+    struct udc_descriptor *desc = NULL;
+
+    if (g_u3d.speed <= SSUSB_SPEED_HIGH)
+        desc = g_u3d.desc_list;
+    else
+        desc = g_u3d.desc_list_u3;
+
+    for (; desc; desc = desc->next) {
+        if (desc->tag == setup->value) {
+            unsigned int len = desc->len;
+
+            if (len > setup->length)
+                len = setup->length;
+
+            copy_desc(req, desc->data, len);
+            change_eps_maxp(desc, req->buffer, len);
+            return 0;
+        }
+    }
+    /* descriptor lookup failed */
+    return -EINVAL;
+}
+
+static int ep0_standard_setup(struct usb_setup *setup)
+{
+    struct udc_gadget *gadget = g_u3d.gadget;
+    struct udc_request *req = g_u3d.ep0->req;
+    u8 *cp = req->buffer;
+    u8 ep_num;  /* ep number */
+    u8 dir; /* DIR */
+    u32 csr;
+
+    dump_setup_packet("Device Request\n", setup);
+
+    if ((setup->request_type & USB_TYPE_MASK) != 0)
+        return -EINVAL; /* Class-specific requests are handled elsewhere */
+
+    /* handle all requests that return data (direction bit set on bm RequestType) */
+    if ((setup->request_type & USB_EP_DIR_MASK)) {
+        /* send the descriptor */
+        g_u3d.ep0_state = EP0_TX;
+
+        switch (setup->request) {
+                /* data stage: from device to host */
+            case GET_STATUS:
+                DBG_I("GET_STATUS\n");
+                req->length = 2;
+                cp[0] = cp[1] = 0;
+
+                switch (setup->request_type & USB_RECIP_MASK) {
+                    case USB_RECIP_DEVICE:
+                        cp[0] = USB_STAT_SELFPOWERED;
+                        break;
+                    case USB_RECIP_OTHER:
+                        req->length = 0;
+                        break;
+                    default:
+                        break;
+                }
+                return 0;
+            case GET_DESCRIPTOR:
+                DBG_I("GET_DESCRIPTOR\n");
+                return std_get_descs(req, setup);
+            case GET_CONFIGURATION:
+                DBG_I("GET_CONFIGURATION\n");
+                break;
+            case GET_INTERFACE:
+                DBG_I("GET_INTERFACE\n");
+                break;
+            default:
+                DBG_C("Unsupported command with TX data stage\n");
+                break;
+        }
+    } else {
+        switch (setup->request) {
+            case SET_ADDRESS:
+                DBG_I("SET_ADDRESS\n");
+                g_u3d.address = (setup->value);
+                mu3d_set_address(g_u3d.address);
+                return 0;
+            case SET_CONFIGURATION:
+                DBG_I("SET_CONFIGURATION\n");
+                g_u3d.usb_online = setup->value ? 1 : 0;
+                if (setup->value == 1) {
+                    mtu3_setup_eps();
+                    spin(50);
+                    gadget->notify(gadget, UDC_EVENT_ONLINE);
+                } else {
+                    gadget->notify(gadget, UDC_EVENT_OFFLINE);
+                }
+                DBG_C("usb_online: %d\n", g_u3d.usb_online);
+                return 0;
+            case CLEAR_FEATURE:
+                DBG_I("CLEAR_FEATURE\n");
+                ep_num = setup->index & 0xf;
+                dir = setup->index & 0x80;
+                if ((setup->value == 0) && (setup->length == 0)) {
+                    DBG_I("Clear Feature: ep: %d dir: %d\n", ep_num, dir);
+
+                    switch (dir) {
+                        case USB_DIR_OUT:
+                            csr = readl(MU3D_EP_TXCR0(ep_num)) & TX_W1C_BITS;
+                            csr = (csr & (~TX_SENDSTALL)) | TX_SENTSTALL;
+                            writel(csr, MU3D_EP_TXCR0(ep_num));
+                            DBG_I("clear tx stall ep: %d dir: %d\n", ep_num, dir);
+
+                            setbits32_r((BIT(16) << ep_num), U3D_EP_RST);
+                            clrbits32_r((BIT(16) << ep_num), U3D_EP_RST);
+                            break;
+                        case USB_DIR_IN:
+                            csr = readl(MU3D_EP_RXCR0(ep_num)) & RX_W1C_BITS;
+                            csr = (csr & (~RX_SENDSTALL)) | RX_SENTSTALL;
+                            writel(csr, MU3D_EP_RXCR0(ep_num));
+
+                            DBG_I("clear rx stall ep: %d dir: %d\n", ep_num, dir);
+
+                            setbits32_r((BIT(0) << ep_num), U3D_EP_RST);
+                            clrbits32_r((BIT(0) << ep_num), U3D_EP_RST);
+
+                            break;
+                        default:
+                            break;
+                    }
+                    return 0;
+                }
+
+            default:
+                DBG_I("setup->request: %x, setup->value: %x\n",
+                      setup->request, setup->value);
+                DBG_C("Unsupported command with RX data stage\n");
+                break;
+        } /* switch request */
+    }
+
+    return -EINVAL;
+}
+
+static void mtu3_ep0_setup(void)
+{
+    struct usb_setup setup;
+    int stall = -ENOTSUP;
+    u32 csr0;
+    u32 len;
+
+    csr0 = readl(U3D_EP0CSR);
+    if (!(csr0 & EP0_SETUPPKTRDY))
+        return;
+
+    len = readl(U3D_RXCOUNT0);
+    if (len != 8) {
+        DBG_C("SETUP packet len %d != 8?\n", len);
+        return;
+    }
+
+    /* unload fifo */
+    pio_read_fifo(EP0, (u8 *)&setup, len);
+
+    /* decode command */
+    if (((setup.request_type) & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+        DBG_I("Standard Request\n");
+        stall = ep0_standard_setup(&setup);
+    }
+
+    /* command is not supported, inlcude  USB_TYPE_CLASS & USB_TYPE_VENDOR */
+    if (stall) {
+        dump_setup_packet("REQUEST NOT SUPPORTED\n", &setup);
+        ep0_stall_set(true, EP0_SETUPPKTRDY);
+        return;
+    }
+
+    /* handle EP0 state */
+    switch (g_u3d.ep0_state) {
+        case EP0_TX:
+            DBG_I("%s: EP0_TX\n", __func__);
+            csr0 = readl(U3D_EP0CSR);
+            csr0 |= (EP0_SETUPPKTRDY | EP0_DPHTX);
+            writel(csr0, U3D_EP0CSR);
+
+            mtu3_ep0_write();
+            break;
+        case EP0_RX:
+            DBG_I("%s: EP0_RX\n", __func__);
+            csr0 = readl(U3D_EP0CSR);
+            csr0 |= (EP0_SETUPPKTRDY);
+            writel(csr0, U3D_EP0CSR);
+            break;
+        case EP0_IDLE:
+            /* no data stage */
+            DBG_I("%s: EP0_IDLE\n", __func__);
+            csr0 = readl(U3D_EP0CSR);
+            csr0 |= (EP0_SETUPPKTRDY | EP0_DATAEND);
+            writel(csr0, U3D_EP0CSR);
+            break;
+        default:
+            break;
+    }
+}
+
+static void mtu3_ep0_isr(void)
+{
+    u32 csr0;
+
+    csr0 = readl(U3D_EP0CSR);
+
+    if (csr0 & EP0_SENTSTALL) {
+        DBG_I("USB: [EP0] SENTSTALL\n");
+        ep0_stall_set(false, 0);
+        csr0 = readl(U3D_EP0CSR);
+    }
+
+    switch (g_u3d.ep0_state) {
+        case EP0_IDLE:
+            DBG_I("%s: EP0_IDLE\n", __func__);
+            mtu3_ep0_setup();
+            break;
+        case EP0_TX:
+            DBG_I("%s: EP0_TX\n", __func__);
+            mtu3_ep0_write();
+            break;
+        case EP0_TX_END:
+            DBG_I("%s: EP0_TX_END\n", __func__);
+            csr0 |= EP0_DATAEND;
+            writel(csr0, U3D_EP0CSR);
+            g_u3d.ep0_state = EP0_IDLE;
+            break;
+        case EP0_RX:
+            DBG_I("%s: EP0_RX\n", __func__);
+            mtu3_ep0_read();
+            g_u3d.ep0_state = EP0_IDLE;
+            break;
+        default:
+            DBG_I("[ERR]: Unrecognized ep0 state %d", g_u3d.ep0_state);
+            break;
+    }
+}
+
+#ifndef SUPPORT_QMU
+/* PIO: TX packet */
+static int mtu3_epx_write(struct udc_endpoint *ept)
+{
+    int ep_num = ept->num;
+    int count;
+    u32 csr;
+
+    /* only for non-ep0 */
+    if (ep_num == 0)
+        return -EACCES;
+
+    if (!ept->in)
+        return -EINVAL;
+
+    csr = readl(MU3D_EP_TXCR0(ep_num));
+    if (csr & TX_TXPKTRDY) {
+        DBG_I("%s: ep%d is busy!\n", __func__, ep_num);
+        return -EBUSY;
+    }
+    count = mtu3_write_fifo(ept);
+
+    csr |= TX_TXPKTRDY;
+    writel(csr, MU3D_EP_TXCR0(ep_num));
+
+    return count;
+}
+
+static void mtu3_epx_isr(u8 ep_num, u8 dir)
+{
+    struct udc_endpoint *ept;
+    struct mu3d_req *mreq;
+    struct udc_request *req;
+    u32 csr;
+    u32 count;
+
+    ept = mtu3_find_ep(ep_num, dir);
+    if (!ept || !ept->req)
+        return;
+
+    DBG_I("%s Interrupt\n", ept->name);
+    req = ept->req;
+    mreq = to_mu3d_req(req);
+
+    if (dir == USB_DIR_IN) {
+        csr = readl(MU3D_EP_TXCR0(ep_num));
+        if (csr & TX_SENTSTALL) {
+            DBG_C("EP%dIN: STALL\n", ep_num);
+            handle_ept_complete(ept, -EPIPE);
+            /* exception handling: implement this!! */
+            return;
+        }
+
+        if (csr & TX_TXPKTRDY) {
+            DBG_C("%s: EP%dIN is busy\n", __func__, ep_num);
+            return;
+        }
+
+        if (req->length == mreq->actual) {
+            handle_ept_complete(ept, 0);
+            return;
+        }
+
+        count = mtu3_write_fifo(ept);
+        if (count) {
+            csr |= TX_TXPKTRDY;
+            writel(csr, MU3D_EP_TXCR0(ep_num));
+        }
+
+        DBG_I("EP%dIN, count=%d, %d/%d\n",
+              ep_num, count, mreq->actual, req->length);
+
+    } else {
+        csr = readl(MU3D_EP_RXCR0(ep_num));
+        if (csr & RX_SENTSTALL) {
+            DBG_C("EP%dOUT: STALL\n", ep_num);
+            /* exception handling: implement this!! */
+            return;
+        }
+
+        if (!(csr & RX_RXPKTRDY)) {
+            DBG_I("EP%dOUT: ERRONEOUS INTERRUPT\n", ep_num);
+            return;
+        }
+
+        count = mtu3_read_fifo(ept);
+
+        DBG_I("EP%dOUT, count = %d\n", ep_num, count);
+
+        /* write 1 to clear RXPKTRDY */
+        csr |= RX_RXPKTRDY;
+        writel(csr, MU3D_EP_RXCR0(ep_num));
+
+        if (readl(MU3D_EP_RXCR0(ep_num)) & RX_RXPKTRDY)
+            DBG_I("%s: rxpktrdy clear failed\n", __func__);
+
+        if ((req->length == mreq->actual) || (count < ept->maxpkt)) {
+            /* disable EP RX intr */
+            setbits32_r(EP_RXISR(ep_num), U3D_EPIECR);  /* W1C */
+            handle_ept_complete(ept, 0);
+        }
+    }
+}
+#endif
+
+/* handle abnormal DATA transfer if we had any, like USB unplugged */
+static void mtu3_suspend(void)
+{
+    struct udc_gadget *gadget = g_u3d.gadget;
+    struct udc_endpoint *ep_list = g_u3d.eps;
+    struct udc_endpoint *ept;
+    int i;
+
+    g_u3d.usb_online = 0;
+    gadget->notify(gadget, UDC_EVENT_OFFLINE);
+
+    /* error out any pending reqs, except ep0 */
+    for (i = 1; i < MT_EP_NUM; i++) {
+        ept = &ep_list[i];
+        /* End operation when encounter uninitialized ept */
+        if (ept->num == 0)
+            break;
+
+        DBG_I("%s: %s, req: %p\n", __func__, ept->name, ept->req);
+
+        mtu3_qmu_flush(ept);
+
+        if (ept->req)
+            handle_ept_complete(ept, -ESHUTDOWN);
+    }
+}
+
+static void mtu3_status_reset(void)
+{
+    g_u3d.ep0_state = EP0_IDLE;
+    g_u3d.address = 0;
+}
+
+static void mtu3_link_isr(void)
+{
+    u32 linkint;
+
+    linkint = readl(U3D_DEV_LINK_INTR) & readl(U3D_DEV_LINK_INTR_ENABLE);
+    writel(linkint, U3D_DEV_LINK_INTR);
+
+    if (linkint & SSUSB_DEV_SPEED_CHG_INTR) {
+        DBG_I("[INTR] Speed Change\n");
+        g_u3d.speed = mu3d_get_speed();
+        if (g_u3d.speed == SSUSB_SPEED_UNKNOWN)
+            mtu3_suspend();
+        else
+            mu3d_ep0en();
+    }
+}
+
+static void mtu3_u2_common_isr(void)
+{
+    u32 intrusb = 0;
+
+    intrusb = readl(U3D_COMMON_USB_INTR) & readl(U3D_COMMON_USB_INTR_ENABLE);
+    writel(intrusb, U3D_COMMON_USB_INTR);
+
+    if (intrusb & RESET_INTR) {
+        DBG_I("[INTR] Reset\n");
+        mtu3_status_reset();
+    }
+
+    if (intrusb & SUSPEND_INTR) {
+        DBG_I("[INTR] Suspend\n");
+        mtu3_suspend();
+    }
+
+    if (intrusb & RESUME_INTR)
+        DBG_I("[INTR] Resume\n");
+
+}
+
+static void mtu3_u3_ltssm_isr(void)
+{
+    u32 ltssm;
+
+    ltssm = readl(U3D_LTSSM_INTR) & readl(U3D_LTSSM_INTR_ENABLE);
+    writel(ltssm, U3D_LTSSM_INTR); /* W1C */
+    DBG_I("=== LTSSM[%x] ===\n", ltssm);
+
+    if (ltssm & (HOT_RST_INTR | WARM_RST_INTR))
+        mtu3_status_reset();
+
+    if (ltssm & VBUS_FALL_INTR) {
+        mu3d_ss_func_set(false);
+        mtu3_status_reset();
+    }
+
+    if (ltssm & VBUS_RISE_INTR)
+        mu3d_ss_func_set(true);
+
+    if (ltssm & ENTER_U3_INTR)
+        mtu3_suspend();
+
+    if (ltssm & EXIT_U3_INTR)
+        DBG_I("[INTR] Resume\n");
+
+}
+
+static void mtu3_bmu_isr(void)
+{
+    u32 intrep;
+
+    intrep = readl(U3D_EPISR) & readl(U3D_EPIER);
+    writel(intrep, U3D_EPISR);
+    DBG_I("[INTR] BMU[tx:%x, rx:%x] IER: %x\n",
+          intrep & 0xffff, intrep >> 16, readl(U3D_EPIER));
+
+    /* For EP0 */
+    if (intrep & 0x1) {
+        mtu3_ep0_isr();
+        intrep &= ~0x1;
+    }
+
+#ifndef SUPPORT_QMU
+    if (intrep) {
+        u32 ep_num;
+
+        for (ep_num = 1; ep_num <= (MT_EP_NUM / 2); ep_num++) {
+            if (intrep & EPT_RX(ep_num))
+                mtu3_epx_isr(ep_num, USB_DIR_OUT);
+
+            if (intrep & EPT_TX(ep_num))
+                mtu3_epx_isr(ep_num, USB_DIR_IN);
+        }
+    }
+#endif
+}
+
+static enum handler_return mtu3_isr(void *arg)
+{
+    u32 lv1_isr;
+
+    lv1_isr = readl(U3D_LV1ISR);  /* LV1ISR is RU */
+    lv1_isr &= readl(U3D_LV1IER);
+    DBG_I("[INTR] lv1_isr:0x%x\n", lv1_isr);
+
+    if (lv1_isr & EP_CTRL_INTR)
+        mtu3_link_isr();
+
+    if (lv1_isr & MAC2_INTR)
+        mtu3_u2_common_isr();
+
+    if (lv1_isr & MAC3_INTR)
+        mtu3_u3_ltssm_isr();
+
+    if (lv1_isr & BMU_INTR)
+        mtu3_bmu_isr();
+
+    if (lv1_isr & QMU_INTR)
+        mtu3_qmu_isr();
+
+    return INT_RESCHEDULE;
+}
+
+static void mu3d_isr_init(void)
+{
+    mt_irq_set_sens(SSUSB_DEV_INT_ID, LEVEL_SENSITIVE);
+    mt_irq_set_polarity(SSUSB_DEV_INT_ID, MT65xx_POLARITY_LOW);
+    register_int_handler(SSUSB_DEV_INT_ID, mtu3_isr, NULL);
+    unmask_interrupt(SSUSB_DEV_INT_ID);
+}
+
+/* gadget common APIs */
+
+static int g_u3d_init(void)
+{
+    struct mu3d_req *mreq = &g_u3d.ep0_mreq;
+    struct udc_request *req = &mreq->req;
+
+    mu3d_get_ip_vers();
+    g_u3d.ep0_state = EP0_IDLE;
+    g_u3d.address = 0;
+    if (g_u3d.is_u3_ip) {
+        g_u3d.speed = U3D_U3IP_DFT_SPEED;
+        g_u3d.tx_fifo_addr = U3IP_TX_FIFO_START_ADDR;
+        g_u3d.rx_fifo_addr = U3IP_RX_FIFO_START_ADDR;
+    } else {
+        g_u3d.speed = U3D_U2IP_DFT_SPEED;
+        g_u3d.tx_fifo_addr = U2IP_TX_FIFO_START_ADDR;
+        g_u3d.rx_fifo_addr = U2IP_RX_FIFO_START_ADDR;
+    }
+
+    g_u3d.ep0 = &g_u3d.eps[EP0];
+
+    req->buffer = udc_zalloc(512);
+    if (!req->buffer)
+        return -ENOMEM;
+
+    g_u3d.ep0->req = req;
+    g_u3d.ept_alloc_table = EPT_TX(0) | EPT_RX(0);
+    g_u3d.desc_list = NULL;
+    g_u3d.next_string_id = 1;
+    g_u3d.next_string_id_u3 = 1;
+
+    return mtu3_qmu_init();
+}
+
+int udc_init(struct udc_device *dev)
+{
+    g_u3d_init();
+    g_u3d.udev = dev;
+    return 0;
+}
+
+static struct udc_endpoint *_udc_endpoint_alloc(unsigned char num,
+        unsigned char in, unsigned short max_pkt)
+{
+    struct udc_endpoint *ep_list = g_u3d.eps;
+    struct udc_endpoint *ept;
+    int ret;
+    int i;
+
+    /* allocated and enabled by default */
+    if (num == EP0)
+        return NULL;
+
+    /*
+     * find an unused slot in ep_list from EP1 to MAX_EP
+     * for example, EP1 will use 2 eps, one for IN and the other for OUT
+     */
+    for (i = 1; i < MT_EP_NUM; i++) {
+        if (ep_list[i].num == 0) /* usable */
+            break;
+    }
+    if (i == MT_EP_NUM) /* ep has been exhausted. */
+        return NULL;
+
+    ept = &ep_list[i];
+    sprintf(ept->name, "ep%d%s", num, in ? "in" : "out");
+
+    ret = mtu3_gpd_ring_alloc(ept);
+    if (ret) {
+        DBG_C("%s gpd alloc failed\n", ept->name);
+        return NULL;
+    }
+
+    /* only supports BULK */
+    ept->type = USB_EP_XFER_BULK;
+    ept->maxpkt = max_pkt;
+    ept->num = num;
+    ept->in = in;
+    ept->req = NULL;
+
+    /* store EPT_TX/RX info */
+    if (ept->in)
+        ept->bit = EPT_TX(num);
+    else
+        ept->bit = EPT_RX(num);
+
+    /* write parameters to this ep (write to hardware) when SET_CONFIG */
+
+    DBG_I("%s @%p/%p max=%d bit=%x\n", ept->name,
+          ept, &ep_list, max_pkt, ept->bit);
+
+    return &ep_list[i];
+}
+
+struct udc_endpoint *udc_endpoint_alloc(unsigned int type, unsigned int maxpkt)
+{
+    struct udc_endpoint *ept;
+    unsigned int n;
+    unsigned int in;
+
+    DBG_I("%s\n", __func__);
+
+    if (type == UDC_BULK_IN)
+        in = 1;
+    else if (type == UDC_BULK_OUT)
+        in = 0;
+    else
+        return NULL;
+
+    /* udc_endpoint_alloc is used for EPx except EP0 */
+    for (n = 1; n < MT_EP_NUM; n++) {
+        unsigned int bit = in ? EPT_TX(n) : EPT_RX(n);
+
+        if (g_u3d.ept_alloc_table & bit)
+            continue;
+
+        ept = _udc_endpoint_alloc(n, in, maxpkt);
+        if (ept) {
+            g_u3d.ept_alloc_table |= bit;
+            return ept;
+        }
+    }
+
+    return NULL;
+}
+
+void udc_endpoint_free(struct udc_endpoint *ept)
+{
+    if (ept->num)
+        mtu3_gpd_ring_free(ept);
+}
+
+struct udc_request *udc_request_alloc(void)
+{
+    struct mu3d_req *mreq;
+
+    mreq = udc_zalloc(sizeof(*mreq));
+
+    return mreq ? &mreq->req : NULL;
+}
+
+void udc_request_free(struct udc_request *req)
+{
+    free(req);
+}
+
+int udc_request_queue(struct udc_endpoint *ept, struct udc_request *req)
+{
+    struct mu3d_req *mreq = to_mu3d_req(req);
+    int ret = 0;
+
+    DBG_I("%s: %s, req=%p, buf: %p, length=%d\n", __func__,
+          ept->name, req, req->buffer, req->length);
+
+    if (!g_u3d.usb_online)
+        return -ENXIO;
+
+    mask_interrupt(SSUSB_DEV_INT_ID);
+    ept->req = req;
+    mreq->ept = ept;
+    mreq->actual = 0;
+
+#ifdef SUPPORT_QMU
+    if (req->length > GPD_BUF_SIZE) {
+        DBG_C("req length > supported MAX:%d requested:%d\n",
+              GPD_BUF_SIZE, req->length);
+        ret = -EOPNOTSUPP;
+        goto out;
+    }
+
+    if (mtu3_prepare_transfer(ept)) {
+        ret = -EAGAIN;
+        goto out;
+    }
+
+    arch_clean_invalidate_cache_range((addr_t)req->buffer, req->length);
+    mtu3_insert_gpd(ept, mreq);
+    mtu3_qmu_resume(ept);
+#else
+
+    /*
+     * PIO mode:
+     * when class driver shares a buffer to TX and RX data,
+     * mtu3 sends a data to host, then host sends a data back immediately,
+     * cause EP TX and RX interrupts arise at the same time,
+     * but the buffer is using by the TX, so no buffer for RX to receive data.
+     * To fix the issue:
+     * disable EP RX intrrupt by default, enable it when queue RX
+     * request and disable it again when complete the request.
+     */
+    if (ept->in)
+        mtu3_epx_write(ept);
+    else
+        setbits32_r(EP_RXISR(ept->num), U3D_EPIESR);    /* W1S */
+#endif
+
+out:
+    unmask_interrupt(SSUSB_DEV_INT_ID);
+
+    return ret;
+}
+
+int udc_register_gadget(struct udc_gadget *gadget)
+{
+    if (g_u3d.gadget) {
+        DBG_C("only one gadget supported\n");
+        return -EBUSY;
+    }
+    g_u3d.gadget = gadget;
+
+    return 0;
+}
+
+int udc_start(void)
+{
+    struct udc_device *udev = g_u3d.udev;
+    struct udc_gadget *gadget = g_u3d.gadget;
+
+    if (!udev) {
+        DBG_C("udc cannot start before init\n");
+        return -ENODEV;
+    }
+    if (!gadget) {
+        DBG_C("udc has no gadget registered\n");
+        return -ENXIO;
+    }
+    DBG_I("%s\n", __func__);
+
+    udc_create_descriptors(udev, gadget);
+    mt_usb_phy_poweron();
+    mu3d_hw_init();
+    mu3d_isr_init();
+    mu3d_soft_connect();
+
+    return 0;
+}
+
+int udc_stop(void)
+{
+    mu3d_soft_disconnect();
+    mt_usb_phy_poweroff();
+
+    return 0;
+}
+
+#pragma GCC pop_options
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3.h
new file mode 100644
index 0000000..5f05d55
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * 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 <dev/udc.h>
+#include <hw/usb.h>
+#include <reg.h>
+
+struct udc_endpoint;
+struct mu3d_req;
+
+#include "mtu3_hw_regs.h"
+#include "mtu3_qmu.h"
+
+/* if want to use PIO mode, comment out the following macro */
+#define SUPPORT_QMU
+
+/* two bulk and ep0 */
+#define MT_EP_NUM 3
+#define MAX_EP_NUM 8
+
+#define DESC_TYPE_U2 0
+#define DESC_TYPE_U3 1
+
+/* U3 IP: EP0, TX, RX has separate SRAMs */
+#define U3IP_TX_FIFO_START_ADDR   0
+#define U3IP_RX_FIFO_START_ADDR   0
+
+/* U2 IP: EP0, TX, RX share one SRAM. 0-63 bytes are reserved for EP0 */
+#define U2IP_TX_FIFO_START_ADDR   (64)
+#define U2IP_RX_FIFO_START_ADDR   (64 + 512 * (MAX_EP_NUM))
+
+#define U3D_U3IP_DFT_SPEED SSUSB_SPEED_SUPER
+#define U3D_U2IP_DFT_SPEED SSUSB_SPEED_HIGH
+
+/*
+ * fastboot only supports BULK, alloc 1024B for each ep and offset are
+ * also fixed, such as, offset-1024 for ep1, offset-2048 for ep2;
+ * so MT_EP_NUM should not greater than 9(ep0 + 4 bulk in + 4 bulk out)
+ */
+#define U3D_FIFO_SIZE_UNIT 1024
+
+#define EP0_MAX_PACKET_SIZE 64
+#define EP0_MAX_PACKET_SIZE_U3 512
+
+#define USB_FIFOSZ_SIZE_8       (0x03)
+#define USB_FIFOSZ_SIZE_16      (0x04)
+#define USB_FIFOSZ_SIZE_32      (0x05)
+#define USB_FIFOSZ_SIZE_64      (0x06)
+#define USB_FIFOSZ_SIZE_128     (0x07)
+#define USB_FIFOSZ_SIZE_256     (0x08)
+#define USB_FIFOSZ_SIZE_512     (0x09)
+#define USB_FIFOSZ_SIZE_1024    (0x0A)
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+typedef enum {
+    EP0_IDLE = 0,
+    EP0_RX,
+    EP0_TX,
+    EP0_TX_END,
+} EP0_STATE;
+
+/* MTK USB3 ssusb defines */
+typedef enum {
+    SSUSB_SPEED_UNKNOWN = 0,
+    SSUSB_SPEED_FULL = 1,
+    SSUSB_SPEED_HIGH = 2,
+    SSUSB_SPEED_SUPER = 3,
+    SSUSB_SPEED_SUPER_PLUS = 4,
+} USB_SPEED;
+
+#define USB_EP_XFER_CTRL    0
+#define USB_EP_XFER_ISO     1
+#define USB_EP_XFER_BULK    2
+#define USB_EP_XFER_INT     3
+
+/* USB transfer directions */
+#define USB_DIR_IN  0x80
+#define USB_DIR_OUT 0x00
+
+struct udc_descriptor {
+    struct udc_descriptor *next;
+    unsigned short tag; /* ((TYPE << 8) | NUM) */
+    unsigned short len; /* total length */
+    unsigned char data[0];
+};
+
+struct mu3d_req {
+    struct udc_request req; /* should be first */
+    struct udc_endpoint *ept;
+    struct qmu_gpd *gpd;
+    unsigned int actual;    /* data already sent/rcv */
+};
+
+/* endpoint data */
+struct udc_endpoint {
+    struct udc_request *req;
+    struct mtu3_gpd_ring gpd_ring;
+    char name[12];
+    unsigned int maxpkt;
+    unsigned char num;
+    unsigned char in;
+    unsigned char type; /* Transfer type */
+    unsigned int bit;   /* EPT_TX/EPT_RX */
+};
+
+struct mu3d {
+    struct udc_device *udev;
+    struct udc_gadget *gadget;
+    EP0_STATE ep0_state;
+    USB_SPEED speed;
+    u32 tx_fifo_addr;
+    u32 rx_fifo_addr;
+
+    struct udc_endpoint eps[MT_EP_NUM]; /* index 0 is fixed as EP0 */
+    struct udc_endpoint *ep0;
+    struct mu3d_req ep0_mreq;
+    u32 ept_alloc_table;
+
+    struct udc_descriptor *desc_list;
+    unsigned int next_string_id;
+    struct udc_descriptor *desc_list_u3;
+    unsigned int next_string_id_u3;
+
+    u8 address;
+    unsigned usb_online:1;
+    unsigned is_u3_ip:1;
+};
+
+#ifndef writew
+#define writew(v, a)    (*REG16(a) = (v))
+#endif
+#ifndef readw
+#define readw(a)        (*REG16(a))
+#endif
+
+int wait_for_value(paddr_t addr, u32 msk, u32 value, int us_intvl, int count);
+struct udc_endpoint *mtu3_find_ep(int ep_num, u8 dir);
+void handle_ept_complete(struct udc_endpoint *ept, int status);
+static int pio_read_fifo(int ep_num, u8 *dst, u16 len) __attribute__((noinline));
+
+static inline struct mu3d_req *to_mu3d_req(struct udc_request *req)
+{
+    return (struct mu3d_req *)req;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3_hw_regs.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3_hw_regs.h
new file mode 100644
index 0000000..fa36bba
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3_hw_regs.h
@@ -0,0 +1,494 @@
+/*
+ * mtu3_hw_regs.h - MediaTek USB3 DRD register and field definitions
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * 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 <platform/mt_reg_base.h>
+
+/* segment offset of MAC register */
+#define SSUSB_DEV_BASE              (USB3_BASE + 0x1000)
+#define SSUSB_EPCTL_CSR_BASE        (USB3_BASE + 0x1800)
+#define SSUSB_USB3_MAC_CSR_BASE     (USB3_BASE + 0x2400)
+#define SSUSB_USB3_SYS_CSR_BASE     (USB3_BASE + 0x2400)
+#define SSUSB_USB2_CSR_BASE         (USB3_BASE + 0x3400)
+
+/* IPPC register in Infra */
+#define SSUSB_SIFSLV_IPPC_BASE      (USB3_BASE + 0x3E00)
+
+
+#define BITS_PER_LONG 32
+#ifndef BIT
+#define BIT(bit) (1UL << (bit))
+#endif
+#ifndef GENMASK
+#define GENMASK(h, l) \
+    ((u32)(((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))))
+#endif
+
+/* SSUSB_DEV REGISTER DEFINITION */
+#define U3D_LV1ISR      (SSUSB_DEV_BASE + 0x0000)
+#define U3D_LV1IER      (SSUSB_DEV_BASE + 0x0004)
+#define U3D_LV1IESR     (SSUSB_DEV_BASE + 0x0008)
+#define U3D_LV1IECR     (SSUSB_DEV_BASE + 0x000C)
+
+#define U3D_EPISR       (SSUSB_DEV_BASE + 0x0080)
+#define U3D_EPIER       (SSUSB_DEV_BASE + 0x0084)
+#define U3D_EPIESR      (SSUSB_DEV_BASE + 0x0088)
+#define U3D_EPIECR      (SSUSB_DEV_BASE + 0x008C)
+
+#define U3D_EP0CSR      (SSUSB_DEV_BASE + 0x0100)
+#define U3D_RXCOUNT0    (SSUSB_DEV_BASE + 0x0108)
+#define U3D_RESERVED    (SSUSB_DEV_BASE + 0x010C)
+#define U3D_TX1CSR0     (SSUSB_DEV_BASE + 0x0110)
+#define U3D_TX1CSR1     (SSUSB_DEV_BASE + 0x0114)
+#define U3D_TX1CSR2     (SSUSB_DEV_BASE + 0x0118)
+
+#define U3D_RX1CSR0     (SSUSB_DEV_BASE + 0x0210)
+#define U3D_RX1CSR1     (SSUSB_DEV_BASE + 0x0214)
+#define U3D_RX1CSR2     (SSUSB_DEV_BASE + 0x0218)
+#define U3D_RX1CSR3     (SSUSB_DEV_BASE + 0x021C)
+
+#define U3D_FIFO0       (SSUSB_DEV_BASE + 0x0300)
+
+#define U3D_QCR0        (SSUSB_DEV_BASE + 0x0400)
+#define U3D_QCR1        (SSUSB_DEV_BASE + 0x0404)
+#define U3D_QCR2        (SSUSB_DEV_BASE + 0x0408)
+#define U3D_QCR3        (SSUSB_DEV_BASE + 0x040C)
+
+#define U3D_TXQCSR1     (SSUSB_DEV_BASE + 0x0510)
+#define U3D_TXQSAR1     (SSUSB_DEV_BASE + 0x0514)
+#define U3D_TXQCPR1     (SSUSB_DEV_BASE + 0x0518)
+
+#define U3D_RXQCSR1     (SSUSB_DEV_BASE + 0x0610)
+#define U3D_RXQSAR1     (SSUSB_DEV_BASE + 0x0614)
+#define U3D_RXQCPR1     (SSUSB_DEV_BASE + 0x0618)
+#define U3D_RXQLDPR1    (SSUSB_DEV_BASE + 0x061C)
+
+#define U3D_QISAR0      (SSUSB_DEV_BASE + 0x0700)
+#define U3D_QIER0       (SSUSB_DEV_BASE + 0x0704)
+#define U3D_QIESR0      (SSUSB_DEV_BASE + 0x0708)
+#define U3D_QIECR0      (SSUSB_DEV_BASE + 0x070C)
+#define U3D_QISAR1      (SSUSB_DEV_BASE + 0x0710)
+#define U3D_QIER1       (SSUSB_DEV_BASE + 0x0714)
+#define U3D_QIESR1      (SSUSB_DEV_BASE + 0x0718)
+#define U3D_QIECR1      (SSUSB_DEV_BASE + 0x071C)
+
+#define U3D_TQERRIR0        (SSUSB_DEV_BASE + 0x0780)
+#define U3D_TQERRIER0       (SSUSB_DEV_BASE + 0x0784)
+#define U3D_TQERRIESR0      (SSUSB_DEV_BASE + 0x0788)
+#define U3D_TQERRIECR0      (SSUSB_DEV_BASE + 0x078C)
+#define U3D_RQERRIR0        (SSUSB_DEV_BASE + 0x07C0)
+#define U3D_RQERRIER0       (SSUSB_DEV_BASE + 0x07C4)
+#define U3D_RQERRIESR0      (SSUSB_DEV_BASE + 0x07C8)
+#define U3D_RQERRIECR0      (SSUSB_DEV_BASE + 0x07CC)
+#define U3D_RQERRIR1        (SSUSB_DEV_BASE + 0x07D0)
+#define U3D_RQERRIER1       (SSUSB_DEV_BASE + 0x07D4)
+#define U3D_RQERRIESR1      (SSUSB_DEV_BASE + 0x07D8)
+#define U3D_RQERRIECR1      (SSUSB_DEV_BASE + 0x07DC)
+
+#define U3D_CAP_EP0FFSZ     (SSUSB_DEV_BASE + 0x0C04)
+#define U3D_CAP_EPNTXFFSZ   (SSUSB_DEV_BASE + 0x0C08)
+#define U3D_CAP_EPNRXFFSZ   (SSUSB_DEV_BASE + 0x0C0C)
+#define U3D_CAP_EPINFO      (SSUSB_DEV_BASE + 0x0C10)
+#define U3D_MISC_CTRL       (SSUSB_DEV_BASE + 0x0C84)
+
+/* SSUSB_DEV FIELD DEFINITION */
+/* U3D_LV1ISR */
+#define EP_CTRL_INTR    BIT(5)
+#define MAC2_INTR       BIT(4)
+#define DMA_INTR        BIT(3)
+#define MAC3_INTR       BIT(2)
+#define QMU_INTR        BIT(1)
+#define BMU_INTR        BIT(0)
+
+/* U3D_LV1IECR */
+#define LV1IECR_MSK     GENMASK(31, 0)
+
+/* U3D_EPISR */
+#define EP_RXISR(x)     (BIT(16) << (x))
+#define EP_TXISR(x)     (BIT(0) << (x))
+#define EP_EP0ISR       BIT(0)
+
+/* U3D_EP0CSR */
+#define EP0_AUTOCLEAR   BIT(30)
+#define EP0_AUTOSET     BIT(29)
+#define EP0_DMAREQEN    BIT(28)
+#define EP0_SENDSTALL   BIT(25)
+#define EP0_FIFOFULL    BIT(23)
+#define EP0_SENTSTALL   BIT(22)
+#define EP0_DPHTX       BIT(20)
+#define EP0_DATAEND     BIT(19)
+#define EP0_TXPKTRDY        BIT(18)
+#define EP0_SETUPPKTRDY     BIT(17)
+#define EP0_RXPKTRDY        BIT(16)
+#define EP0_MAXPKTSZ_MSK    GENMASK(9, 0)
+#define EP0_MAXPKTSZ(x)     ((x) & EP0_MAXPKTSZ_MSK)
+#define EP0_W1C_BITS    (~(EP0_RXPKTRDY | EP0_SETUPPKTRDY | EP0_SENTSTALL))
+
+/* U3D_TX1CSR0 */
+#define TX_AUTOSET      BIT(30)
+#define TX_DMAREQEN     BIT(29)
+#define TX_FIFOFULL     BIT(25)
+#define TX_FIFOEMPTY    BIT(24)
+#define TX_SENTSTALL    BIT(22)
+#define TX_SENDSTALL    BIT(21)
+#define TX_TXPKTRDY     BIT(16)
+#define TX_TXMAXPKTSZ_MSK   GENMASK(10, 0)
+#define TX_TXMAXPKTSZ(x)    ((x) & TX_TXMAXPKTSZ_MSK)
+#define TX_W1C_BITS     (~(TX_SENTSTALL))
+
+/* U3D_TX1CSR1 */
+#define TX_MULT(x)      (((x) & 0x3) << 22)
+#define TX_MAX_PKT(x)   (((x) & 0x3f) << 16)
+#define TX_SLOT(x)      (((x) & 0x3f) << 8)
+#define TX_TYPE(x)      (((x) & 0x3) << 4)
+#define TX_SS_BURST(x)      (((x) & 0xf) << 0)
+
+/* for TX_TYPE & RX_TYPE */
+#define TYPE_BULK       (0x0)
+#define TYPE_INT        (0x1)
+#define TYPE_ISO        (0x2)
+#define TYPE_MSK        (0x3)
+
+/* U3D_TX1CSR2 */
+#define TX_BINTERVAL(x)     (((x) & 0xff) << 24)
+#define TX_FIFOSEGSIZE(x)   (((x) & 0xf) << 16)
+#define TX_FIFOADDR(x)      (((x) & 0x1fff) << 0)
+
+/* U3D_RX1CSR0 */
+#define RX_AUTOCLEAR    BIT(30)
+#define RX_DMAREQEN     BIT(29)
+#define RX_SENTSTALL    BIT(22)
+#define RX_SENDSTALL    BIT(21)
+#define RX_RXPKTRDY     BIT(16)
+#define RX_RXMAXPKTSZ_MSK   GENMASK(10, 0)
+#define RX_RXMAXPKTSZ(x)    ((x) & RX_RXMAXPKTSZ_MSK)
+#define RX_W1C_BITS     (~(RX_SENTSTALL | RX_RXPKTRDY))
+
+/* U3D_RX1CSR1 */
+#define RX_MULT(x)      (((x) & 0x3) << 22)
+#define RX_MAX_PKT(x)   (((x) & 0x3f) << 16)
+#define RX_SLOT(x)      (((x) & 0x3f) << 8)
+#define RX_TYPE(x)      (((x) & 0x3) << 4)
+#define RX_SS_BURST(x)  (((x) & 0xf) << 0)
+
+/* U3D_RX1CSR2 */
+#define RX_BINTERVAL(x)     (((x) & 0xff) << 24)
+#define RX_FIFOSEGSIZE(x)   (((x) & 0xf) << 16)
+#define RX_FIFOADDR(x)      (((x) & 0x1fff) << 0)
+
+/* U3D_RX1CSR3 */
+#define EP_RX_COUNT(x)      (((x) >> 16) & 0x7ff)
+
+/* U3D_FIFO: ep(0-15)*/
+#define U3D_FIFO(x)         (U3D_FIFO0 + ((x) * 0x10))
+#define USB_FIFO(x)         (U3D_FIFO(x))
+
+/* U3D_QCR0 */
+#define QMU_RX_CS_EN(x)     (BIT(16) << (x))
+#define QMU_TX_CS_EN(x)     (BIT(0) << (x))
+#define QMU_CS16B_EN        BIT(0)
+
+/* U3D_QCR1 */
+#define QMU_TX_ZLP(x)       (BIT(0) << (x))
+
+/* U3D_QCR3 */
+#define QMU_RX_COZ(x)       (BIT(16) << (x))
+#define QMU_RX_ZLP(x)       (BIT(0) << (x))
+
+/* U3D_TXQCSR1 */
+/* U3D_RXQCSR1 */
+#define QMU_Q_ACTIVE    BIT(15)
+#define QMU_Q_STOP      BIT(2)
+#define QMU_Q_RESUME    BIT(1)
+#define QMU_Q_START     BIT(0)
+
+/* U3D_QISAR0, U3D_QIER0, U3D_QIESR0, U3D_QIECR0 */
+#define QMU_RX_DONE_INT(x)  (BIT(16) << (x))
+#define QMU_TX_DONE_INT(x)  (BIT(0) << (x))
+
+/* U3D_QISAR1, U3D_QIER1, U3D_QIESR1, U3D_QIECR1 */
+#define RXQ_ZLPERR_INT      BIT(20)
+#define RXQ_LENERR_INT      BIT(18)
+#define RXQ_CSERR_INT       BIT(17)
+#define RXQ_EMPTY_INT       BIT(16)
+#define TXQ_LENERR_INT      BIT(2)
+#define TXQ_CSERR_INT       BIT(1)
+#define TXQ_EMPTY_INT       BIT(0)
+
+/* U3D_TQERRIR0, U3D_TQERRIER0, U3D_TQERRIESR0, U3D_TQERRIECR0 */
+#define QMU_TX_LEN_ERR(x)   (BIT(16) << (x))
+#define QMU_TX_CS_ERR(x)    (BIT(0) << (x))
+
+/* U3D_RQERRIR0, U3D_RQERRIER0, U3D_RQERRIESR0, U3D_RQERRIECR0 */
+#define QMU_RX_LEN_ERR(x)   (BIT(16) << (x))
+#define QMU_RX_CS_ERR(x)    (BIT(0) << (x))
+
+/* U3D_RQERRIR1, U3D_RQERRIER1, U3D_RQERRIESR1, U3D_RQERRIECR1 */
+#define QMU_RX_ZLP_ERR(n)   (BIT(16) << (n))
+
+/* U3D_CAP_EPINFO */
+#define CAP_RX_EP_NUM(x)    (((x) >> 8) & 0x1f)
+#define CAP_TX_EP_NUM(x)    ((x) & 0x1f)
+
+/* U3D_MISC_CTRL */
+#define VBUS_ON         BIT(1)
+#define VBUS_FRC_EN     BIT(0)
+
+
+/* SSUSB_EPCTL_CSR REGISTER DEFINITION */
+#define U3D_DEVICE_CONF     (SSUSB_EPCTL_CSR_BASE + 0x0000)
+#define U3D_EP_RST          (SSUSB_EPCTL_CSR_BASE + 0x0004)
+
+#define U3D_DEV_LINK_INTR_ENABLE    (SSUSB_EPCTL_CSR_BASE + 0x0050)
+#define U3D_DEV_LINK_INTR       (SSUSB_EPCTL_CSR_BASE + 0x0054)
+
+/* SSUSB_EPCTL_CSR FIELD DEFINITION */
+/* U3D_DEVICE_CONF */
+#define DEV_ADDR_MSK    GENMASK(30, 24)
+#define DEV_ADDR(x)     ((0x7f & (x)) << 24)
+#define HW_USB2_3_SEL       BIT(18)
+#define SW_USB2_3_SEL_EN    BIT(17)
+#define SW_USB2_3_SEL       BIT(16)
+#define SSUSB_DEV_SPEED(x)  ((x) & 0x7)
+
+/* U3D_EP_RST */
+#define EP1_IN_RST      BIT(17)
+#define EP1_OUT_RST     BIT(1)
+#define EP_RST(is_in, epnum)    (((is_in) ? BIT(16) : BIT(0)) << (epnum))
+#define EP0_RST         BIT(0)
+
+/* U3D_DEV_LINK_INTR_ENABLE */
+/* U3D_DEV_LINK_INTR */
+#define SSUSB_DEV_SPEED_CHG_INTR    BIT(0)
+
+
+/* SSUSB_USB3_MAC_CSR REGISTER DEFINITION */
+#define U3D_LTSSM_CTRL      (SSUSB_USB3_MAC_CSR_BASE + 0x0010)
+#define U3D_USB3_CONFIG     (SSUSB_USB3_MAC_CSR_BASE + 0x001C)
+
+#define U3D_LTSSM_INTR_ENABLE   (SSUSB_USB3_MAC_CSR_BASE + 0x013C)
+#define U3D_LTSSM_INTR      (SSUSB_USB3_MAC_CSR_BASE + 0x0140)
+
+/* SSUSB_USB3_MAC_CSR FIELD DEFINITION */
+/* U3D_LTSSM_CTRL */
+#define FORCE_POLLING_FAIL  BIT(4)
+#define FORCE_RXDETECT_FAIL BIT(3)
+#define SOFT_U3_EXIT_EN     BIT(2)
+#define COMPLIANCE_EN       BIT(1)
+#define U1_GO_U2_EN     BIT(0)
+
+/* U3D_USB3_CONFIG */
+#define USB3_EN         BIT(0)
+
+/* U3D_LTSSM_INTR_ENABLE */
+/* U3D_LTSSM_INTR */
+#define U3_RESUME_INTR      BIT(18)
+#define U3_LFPS_TMOUT_INTR  BIT(17)
+#define VBUS_FALL_INTR      BIT(16)
+#define VBUS_RISE_INTR      BIT(15)
+#define RXDET_SUCCESS_INTR  BIT(14)
+#define EXIT_U3_INTR        BIT(13)
+#define EXIT_U2_INTR        BIT(12)
+#define EXIT_U1_INTR        BIT(11)
+#define ENTER_U3_INTR       BIT(10)
+#define ENTER_U2_INTR       BIT(9)
+#define ENTER_U1_INTR       BIT(8)
+#define ENTER_U0_INTR       BIT(7)
+#define RECOVERY_INTR       BIT(6)
+#define WARM_RST_INTR       BIT(5)
+#define HOT_RST_INTR        BIT(4)
+#define LOOPBACK_INTR       BIT(3)
+#define COMPLIANCE_INTR     BIT(2)
+#define SS_DISABLE_INTR     BIT(1)
+#define SS_INACTIVE_INTR    BIT(0)
+
+/* SSUSB_USB3_SYS_CSR REGISTER DEFINITION */
+#define U3D_LINK_UX_INACT_TIMER (SSUSB_USB3_SYS_CSR_BASE + 0x020C)
+#define U3D_LINK_POWER_CONTROL  (SSUSB_USB3_SYS_CSR_BASE + 0x0210)
+#define U3D_LINK_ERR_COUNT      (SSUSB_USB3_SYS_CSR_BASE + 0x0214)
+
+/* SSUSB_USB3_SYS_CSR FIELD DEFINITION */
+/* U3D_LINK_UX_INACT_TIMER */
+#define DEV_U2_INACT_TIMEOUT_MSK    GENMASK(23, 16)
+#define DEV_U2_INACT_TIMEOUT_VALUE(x)   (((x) & 0xff) << 16)
+#define U2_INACT_TIMEOUT_MSK        GENMASK(15, 8)
+#define U1_INACT_TIMEOUT_MSK        GENMASK(7, 0)
+#define U1_INACT_TIMEOUT_VALUE(x)   ((x) & 0xff)
+
+/* U3D_LINK_POWER_CONTROL */
+#define SW_U2_ACCEPT_ENABLE     BIT(9)
+#define SW_U1_ACCEPT_ENABLE     BIT(8)
+#define UX_EXIT         BIT(5)
+#define LGO_U3          BIT(4)
+#define LGO_U2          BIT(3)
+#define LGO_U1          BIT(2)
+#define SW_U2_REQUEST_ENABLE    BIT(1)
+#define SW_U1_REQUEST_ENABLE    BIT(0)
+
+/* U3D_LINK_ERR_COUNT */
+#define CLR_LINK_ERR_CNT    BIT(16)
+#define LINK_ERROR_COUNT    GENMASK(15, 0)
+
+/* SSUSB_USB2_CSR REGISTER DEFINITION */
+#define U3D_POWER_MANAGEMENT        (SSUSB_USB2_CSR_BASE + 0x0004)
+#define U3D_DEVICE_CONTROL          (SSUSB_USB2_CSR_BASE + 0x000C)
+#define U3D_USB2_TEST_MODE          (SSUSB_USB2_CSR_BASE + 0x0014)
+#define U3D_COMMON_USB_INTR_ENABLE  (SSUSB_USB2_CSR_BASE + 0x0018)
+#define U3D_COMMON_USB_INTR         (SSUSB_USB2_CSR_BASE + 0x001C)
+#define U3D_LINK_RESET_INFO         (SSUSB_USB2_CSR_BASE + 0x0024)
+#define U3D_USB20_FRAME_NUM         (SSUSB_USB2_CSR_BASE + 0x003C)
+#define U3D_USB20_LPM_PARAMETER     (SSUSB_USB2_CSR_BASE + 0x0044)
+#define U3D_USB20_MISC_CONTROL      (SSUSB_USB2_CSR_BASE + 0x004C)
+
+/* SSUSB_USB2_CSR FIELD DEFINITION */
+/* U3D_POWER_MANAGEMENT */
+#define LPM_BESL_STALL      BIT(14)
+#define LPM_BESLD_STALL     BIT(13)
+#define LPM_RWP         BIT(11)
+#define LPM_HRWE        BIT(10)
+#define LPM_MODE(x)     (((x) & 0x3) << 8)
+#define ISO_UPDATE      BIT(7)
+#define SOFT_CONN       BIT(6)
+#define HS_ENABLE       BIT(5)
+#define RESUME          BIT(2)
+#define SUSPENDM_ENABLE     BIT(0)
+
+/* U3D_DEVICE_CONTROL */
+#define DC_HOSTREQ      BIT(1)
+#define DC_SESSION      BIT(0)
+
+/* U3D_USB2_TEST_MODE */
+#define U2U3_AUTO_SWITCH    BIT(10)
+#define LPM_FORCE_STALL     BIT(8)
+#define FIFO_ACCESS         BIT(6)
+#define FORCE_FS            BIT(5)
+#define FORCE_HS            BIT(4)
+#define TEST_PACKET_MODE    BIT(3)
+#define TEST_K_MODE         BIT(2)
+#define TEST_J_MODE         BIT(1)
+#define TEST_SE0_NAK_MODE   BIT(0)
+
+/* U3D_COMMON_USB_INTR_ENABLE */
+/* U3D_COMMON_USB_INTR */
+#define LPM_RESUME_INTR BIT(9)
+#define LPM_INTR        BIT(8)
+#define DISCONN_INTR    BIT(5)
+#define CONN_INTR       BIT(4)
+#define SOF_INTR        BIT(3)
+#define RESET_INTR      BIT(2)
+#define RESUME_INTR     BIT(1)
+#define SUSPEND_INTR    BIT(0)
+
+/* U3D_LINK_RESET_INFO */
+#define WTCHRP_MSK      GENMASK(19, 16)
+
+/* U3D_USB20_LPM_PARAMETER */
+#define LPM_BESLCK_U3(x)    (((x) & 0xf) << 12)
+#define LPM_BESLCK(x)       (((x) & 0xf) << 8)
+#define LPM_BESLDCK(x)      (((x) & 0xf) << 4)
+#define LPM_BESL            GENMASK(3, 0)
+
+/* U3D_USB20_MISC_CONTROL */
+#define LPM_U3_ACK_EN       BIT(0)
+
+/* SSUSB_SIFSLV_IPPC REGISTER DEFINITION */
+#define U3D_SSUSB_IP_PW_CTRL0   (SSUSB_SIFSLV_IPPC_BASE + 0x0000)
+#define U3D_SSUSB_IP_PW_CTRL1   (SSUSB_SIFSLV_IPPC_BASE + 0x0004)
+#define U3D_SSUSB_IP_PW_CTRL2   (SSUSB_SIFSLV_IPPC_BASE + 0x0008)
+#define U3D_SSUSB_IP_PW_CTRL3   (SSUSB_SIFSLV_IPPC_BASE + 0x000C)
+#define U3D_SSUSB_IP_PW_STS1    (SSUSB_SIFSLV_IPPC_BASE + 0x0010)
+#define U3D_SSUSB_IP_PW_STS2    (SSUSB_SIFSLV_IPPC_BASE + 0x0014)
+#define U3D_SSUSB_OTG_STS       (SSUSB_SIFSLV_IPPC_BASE + 0x0018)
+#define U3D_SSUSB_OTG_STS_CLR   (SSUSB_SIFSLV_IPPC_BASE + 0x001C)
+#define U3D_SSUSB_IP_XHCI_CAP   (SSUSB_SIFSLV_IPPC_BASE + 0x0024)
+#define U3D_SSUSB_IP_DEV_CAP    (SSUSB_SIFSLV_IPPC_BASE + 0x0028)
+#define U3D_SSUSB_OTG_INT_EN    (SSUSB_SIFSLV_IPPC_BASE + 0x002C)
+#define U3D_SSUSB_U3_CTRL_0P    (SSUSB_SIFSLV_IPPC_BASE + 0x0030)
+#define U3D_SSUSB_U2_CTRL_0P    (SSUSB_SIFSLV_IPPC_BASE + 0x0050)
+#define U3D_SSUSB_REF_CK_CTRL   (SSUSB_SIFSLV_IPPC_BASE + 0x008C)
+#define U3D_SSUSB_DEV_RST_CTRL  (SSUSB_SIFSLV_IPPC_BASE + 0x0098)
+#define U3D_SSUSB_HW_ID         (SSUSB_SIFSLV_IPPC_BASE + 0x00A0)
+#define U3D_SSUSB_HW_SUB_ID     (SSUSB_SIFSLV_IPPC_BASE + 0x00A4)
+#define U3D_SSUSB_IP_SPARE0     (SSUSB_SIFSLV_IPPC_BASE + 0x00C8)
+
+/* SSUSB_SIFSLV_IPPC FIELD DEFINITION */
+/* U3D_SSUSB_IP_PW_CTRL0 */
+#define SSUSB_IP_SW_RST         BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL1 */
+#define SSUSB_IP_HOST_PDN       BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL2 */
+#define SSUSB_IP_DEV_PDN        BIT(0)
+
+/* U3D_SSUSB_IP_PW_CTRL3 */
+#define SSUSB_IP_PCIE_PDN       BIT(0)
+
+/* U3D_SSUSB_IP_PW_STS1 */
+#define SSUSB_IP_SLEEP_STS      BIT(30)
+#define SSUSB_U3_MAC_RST_B_STS  BIT(16)
+#define SSUSB_XHCI_RST_B_STS    BIT(11)
+#define SSUSB_SYS125_RST_B_STS  BIT(10)
+#define SSUSB_REF_RST_B_STS     BIT(8)
+#define SSUSB_SYSPLL_STABLE     BIT(0)
+
+/* U3D_SSUSB_IP_PW_STS2 */
+#define SSUSB_U2_MAC_SYS_RST_B_STS  BIT(0)
+
+/* U3D_SSUSB_OTG_STS */
+#define SSUSB_VBUS_VALID        BIT(9)
+
+/* U3D_SSUSB_OTG_STS_CLR */
+#define SSUSB_VBUS_INTR_CLR     BIT(6)
+
+/* U3D_SSUSB_IP_XHCI_CAP */
+#define SSUSB_IP_XHCI_U2_PORT_NUM(x)    (((x) >> 8) & 0xff)
+#define SSUSB_IP_XHCI_U3_PORT_NUM(x)    ((x) & 0xff)
+
+/* U3D_SSUSB_IP_DEV_CAP */
+#define SSUSB_IP_DEV_U3_PORT_NUM(x) ((x) & 0xff)
+
+/* U3D_SSUSB_OTG_INT_EN */
+#define SSUSB_VBUS_CHG_INT_A_EN     BIT(7)
+#define SSUSB_VBUS_CHG_INT_B_EN     BIT(6)
+
+/* U3D_SSUSB_U3_CTRL_0P */
+#define SSUSB_U3_PORT_SSP_SPEED BIT(9)
+#define SSUSB_U3_PORT_HOST_SEL  BIT(2)
+#define SSUSB_U3_PORT_PDN       BIT(1)
+#define SSUSB_U3_PORT_DIS       BIT(0)
+
+/* U3D_SSUSB_U2_CTRL_0P */
+#define SSUSB_U2_PORT_OTG_SEL   BIT(7)
+#define SSUSB_U2_PORT_HOST_SEL  BIT(2)
+#define SSUSB_U2_PORT_PDN       BIT(1)
+#define SSUSB_U2_PORT_DIS       BIT(0)
+
+/* U3D_SSUSB_DEV_RST_CTRL */
+#define SSUSB_DEV_SW_RST        BIT(0)
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3_qmu.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3_qmu.c
new file mode 100644
index 0000000..65143b8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3_qmu.c
@@ -0,0 +1,556 @@
+/*
+ * mtu3_qmu.c - Queue Management Unit driver for device controller
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Queue Management Unit (QMU) is designed to unload SW effort
+ * to serve DMA interrupts.
+ * By preparing General Purpose Descriptor (GPD) and Buffer Descriptor (BD),
+ * SW links data buffers and triggers QMU to send / receive data to
+ * host / from device at a time.
+ * And now only GPD is supported.
+ *
+ * For more detailed information, please refer to QMU Programming Guide
+ */
+
+#include <arch/ops.h>
+#include <debug.h>
+#include <errno.h>
+#include <kernel/vm.h>
+#include <lib/mempool.h>
+#include <platform/reg_utils.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include "mtu3.h"
+#include "mtu3_hw_regs.h"
+#include "mtu3_qmu.h"
+
+#pragma GCC push_options
+#pragma GCC optimize("O1")
+
+#define QMU_CHECKSUM_LEN    16
+
+#define GPD_FLAGS_HWO   BIT(0)
+#define GPD_FLAGS_BDP   BIT(1)
+#define GPD_FLAGS_BPS   BIT(2)
+#define GPD_FLAGS_IOC   BIT(7)
+
+#define GPD_EXT_FLAG_ZLP    BIT(5)
+
+#define DBG_C(x...) dprintf(CRITICAL, "[USB][QMU] " x)
+#define DBG_I(x...) dprintf(INFO, "[USB][QMU] " x)
+#define DBG_S(x...) dprintf(SPEW, "[USB][QMU] " x)
+
+#ifdef SUPPORT_QMU
+
+static paddr_t va_to_pa(void *vaddr)
+{
+#if WITH_KERNEL_VM
+    return kvaddr_to_paddr(vaddr);
+#else
+    return (paddr_t)vaddr;
+#endif
+}
+
+static void *pa_to_va(paddr_t paddr)
+{
+#if WITH_KERNEL_VM
+    return paddr_to_kvaddr(paddr);
+#else
+    return (void *)paddr;
+#endif
+}
+
+static struct qmu_gpd *gpd_dma_to_virt(struct mtu3_gpd_ring *ring,
+                                       paddr_t dma_addr)
+{
+    paddr_t dma_base = ring->dma;
+    struct qmu_gpd *gpd_head = ring->start;
+    u32 offset = (dma_addr - dma_base) / sizeof(*gpd_head);
+
+    if (offset >= MAX_GPD_NUM)
+        return NULL;
+
+    return gpd_head + offset;
+}
+
+static paddr_t gpd_virt_to_dma(struct mtu3_gpd_ring *ring,
+                               struct qmu_gpd *gpd)
+{
+    paddr_t dma_base = ring->dma;
+    struct qmu_gpd *gpd_head = ring->start;
+    u32 offset;
+
+    offset = gpd - gpd_head;
+    if (offset >= MAX_GPD_NUM)
+        return 0;
+
+    return dma_base + (offset * sizeof(*gpd));
+}
+
+static void gpd_ring_init(struct mtu3_gpd_ring *ring, struct qmu_gpd *gpd)
+{
+    ring->start = gpd;
+    ring->enqueue = gpd;
+    ring->dequeue = gpd;
+    ring->end = gpd + MAX_GPD_NUM - 1;
+}
+
+static void reset_gpd_list(struct udc_endpoint *mep)
+{
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    struct qmu_gpd *gpd = ring->start;
+
+    if (gpd) {
+        gpd->flag &= ~GPD_FLAGS_HWO;
+        gpd_ring_init(ring, gpd);
+    }
+}
+
+int mtu3_gpd_ring_alloc(struct udc_endpoint *mep)
+{
+    struct qmu_gpd *gpd;
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    u32 size;
+
+    /* software own all gpds as default */
+    size = sizeof(struct qmu_gpd) * MAX_GPD_NUM;
+    gpd = (struct qmu_gpd *)mempool_alloc(size, MEMPOOL_UNCACHE);
+    if (gpd == NULL)
+        return -ENOMEM;
+
+    memset(gpd, 0, size);
+    ring->dma = va_to_pa(gpd);
+    gpd_ring_init(ring, gpd);
+    return 0;
+}
+
+void mtu3_gpd_ring_free(struct udc_endpoint *mep)
+{
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+
+    mempool_free(ring->start);
+    memset(ring, 0, sizeof(*ring));
+}
+
+/*
+ * calculate check sum of a gpd or bd
+ * add "noinline" and "mb" to prevent wrong calculation
+ */
+static u8 qmu_calc_checksum(u8 *data)
+{
+    u8 chksum = 0;
+    int i;
+
+    data[1] = 0x0;  /* set checksum to 0 */
+
+    mb();   /* ensure the gpd/bd is really up-to-date */
+    for (i = 0; i < QMU_CHECKSUM_LEN; i++)
+        chksum += data[i];
+
+    /* Default: HWO=1, @flag[bit0] */
+    chksum += 1;
+
+    return 0xFF - chksum;
+}
+
+void mtu3_qmu_resume(struct udc_endpoint *mep)
+{
+    int epnum = mep->num;
+    paddr_t qcsr;
+
+    qcsr = mep->in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
+
+    writel(QMU_Q_RESUME, qcsr);
+    if (!(readl(qcsr) & QMU_Q_ACTIVE))
+        writel(QMU_Q_RESUME, qcsr);
+}
+
+static struct qmu_gpd *advance_enq_gpd(struct mtu3_gpd_ring *ring)
+{
+    if (ring->enqueue < ring->end)
+        ring->enqueue++;
+    else
+        ring->enqueue = ring->start;
+
+    return ring->enqueue;
+}
+
+static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring)
+{
+    if (ring->dequeue < ring->end)
+        ring->dequeue++;
+    else
+        ring->dequeue = ring->start;
+
+    return ring->dequeue;
+}
+
+/* check if a ring is emtpy */
+static int gpd_ring_empty(struct mtu3_gpd_ring *ring)
+{
+    struct qmu_gpd *enq = ring->enqueue;
+    struct qmu_gpd *next;
+
+    if (ring->enqueue < ring->end)
+        next = enq + 1;
+    else
+        next = ring->start;
+
+    /* one gpd is reserved to simplify gpd preparation */
+    return next == ring->dequeue;
+}
+
+int mtu3_prepare_transfer(struct udc_endpoint *mep)
+{
+    return gpd_ring_empty(&mep->gpd_ring);
+}
+
+static int mtu3_prepare_tx_gpd(struct udc_endpoint *mep, struct mu3d_req *mreq)
+{
+    struct qmu_gpd *enq;
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    struct qmu_gpd *gpd = ring->enqueue;
+    struct udc_request *req = &mreq->req;
+
+    /* set all fields to zero as default value */
+    memset(gpd, 0, sizeof(*gpd));
+
+    gpd->buffer = (u32)va_to_pa(req->buffer);
+    gpd->buf_len = (req->length);
+    gpd->flag |= GPD_FLAGS_IOC;
+
+    /* get the next GPD */
+    enq = advance_enq_gpd(ring);
+    DBG_I("TX %s queue gpd=%p, enq=%p\n", mep->name, gpd, enq);
+
+    enq->flag &= ~GPD_FLAGS_HWO;
+    gpd->next_gpd = (u32)gpd_virt_to_dma(ring, enq);
+
+    if (mep->type != USB_EP_XFER_ISO)
+        gpd->ext_flag |= GPD_EXT_FLAG_ZLP;
+
+    gpd->chksum = qmu_calc_checksum((u8 *)gpd);
+    gpd->flag |= GPD_FLAGS_HWO;
+
+    mreq->gpd = gpd;
+
+    return 0;
+}
+
+static int mtu3_prepare_rx_gpd(struct udc_endpoint *mep, struct mu3d_req *mreq)
+{
+    struct qmu_gpd *enq;
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    struct qmu_gpd *gpd = ring->enqueue;
+    struct udc_request *req = &mreq->req;
+
+    /* set all fields to zero as default value */
+    memset(gpd, 0, sizeof(*gpd));
+
+    gpd->buffer = (u32)va_to_pa(req->buffer);
+    gpd->data_buf_len = req->length;
+    gpd->flag |= GPD_FLAGS_IOC;
+
+    /* get the next GPD */
+    enq = advance_enq_gpd(ring);
+    DBG_I("RX %s queue gpd=%p, enq=%p\n", mep->name, gpd, enq);
+
+    enq->flag &= ~GPD_FLAGS_HWO;
+    gpd->next_gpd = (u32)gpd_virt_to_dma(ring, enq);
+    gpd->chksum = qmu_calc_checksum((u8 *)gpd);
+    gpd->flag |= GPD_FLAGS_HWO;
+
+    mreq->gpd = gpd;
+
+    return 0;
+}
+
+void mtu3_insert_gpd(struct udc_endpoint *mep, struct mu3d_req *mreq)
+{
+    if (mep->in)
+        mtu3_prepare_tx_gpd(mep, mreq);
+    else
+        mtu3_prepare_rx_gpd(mep, mreq);
+}
+
+int mtu3_qmu_start(struct udc_endpoint *mep)
+{
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    u8 epnum = mep->num;
+
+    if (mep->in) {
+        /* set QMU start address */
+        writel(ring->dma, USB_QMU_TQSAR(mep->num));
+        setbits32_r(TX_DMAREQEN, MU3D_EP_TXCR0(mep->num));
+        setbits32_r(QMU_TX_CS_EN(epnum), U3D_QCR0);
+        /* send zero length packet according to ZLP flag in GPD */
+        setbits32_r(QMU_TX_ZLP(epnum), U3D_QCR1);
+        writel(QMU_TX_LEN_ERR(epnum) | QMU_TX_CS_ERR(epnum), U3D_TQERRIESR0);
+
+        if (readl(USB_QMU_TQCSR(epnum)) & QMU_Q_ACTIVE) {
+            DBG_C("%s Active Now!\n", mep->name);
+            return 0;
+        }
+        writel(QMU_Q_START, USB_QMU_TQCSR(epnum));
+
+    } else {
+        writel(ring->dma, USB_QMU_RQSAR(mep->num));
+        setbits32_r(RX_DMAREQEN, MU3D_EP_RXCR0(mep->num));
+        setbits32_r(QMU_RX_CS_EN(epnum), U3D_QCR0);
+        /* don't expect ZLP */
+        clrbits32_r(QMU_RX_ZLP(epnum), U3D_QCR3);
+        /* move to next GPD when receive ZLP */
+        setbits32_r(QMU_RX_COZ(epnum), U3D_QCR3);
+        writel(QMU_RX_LEN_ERR(epnum) | QMU_RX_CS_ERR(epnum), U3D_RQERRIESR0);
+        writel(QMU_RX_ZLP_ERR(epnum), U3D_RQERRIESR1);
+
+        if (readl(USB_QMU_RQCSR(epnum)) & QMU_Q_ACTIVE) {
+            DBG_C("%s Active Now!\n", mep->name);
+            return 0;
+        }
+        writel(QMU_Q_START, USB_QMU_RQCSR(epnum));
+    }
+    DBG_I("%s's qmu start now!\n", mep->name);
+
+    return 0;
+}
+
+/* may called in atomic context */
+static void mtu3_qmu_stop(struct udc_endpoint *mep)
+{
+    int epnum = mep->num;
+    paddr_t qcsr;
+    int ret;
+
+    qcsr = mep->in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
+
+    if (!(readl(qcsr) & QMU_Q_ACTIVE)) {
+        DBG_C("%s's qmu is inactive now!\n", mep->name);
+        return;
+    }
+    writel(QMU_Q_STOP, qcsr);
+
+    ret = wait_for_value(qcsr, QMU_Q_ACTIVE, 0, 10, 100);
+    if (ret) {
+        DBG_C("stop %s's qmu failed\n", mep->name);
+        return;
+    }
+
+    DBG_I("%s's qmu stop now!\n", mep->name);
+}
+
+void mtu3_qmu_flush(struct udc_endpoint *mep)
+{
+    DBG_I("%s flush QMU %s\n", __func__, mep->name);
+
+    /*Stop QMU */
+    mtu3_qmu_stop(mep);
+    reset_gpd_list(mep);
+}
+
+static void qmu_done_tx(u8 epnum)
+{
+    struct udc_endpoint *mep = mtu3_find_ep(epnum, USB_DIR_IN);
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    struct qmu_gpd *gpd = ring->dequeue;
+    struct qmu_gpd *gpd_current = NULL;
+    struct udc_request *request = NULL;
+    struct mu3d_req *mreq;
+    paddr_t gpd_dma;
+
+    gpd_dma = readl(USB_QMU_TQCPR(epnum));
+    /*transfer phy address got from QMU register to virtual address */
+    gpd_current = gpd_dma_to_virt(ring, gpd_dma);
+
+    DBG_I("%s %s, last=%p, current=%p, enq=%p\n",
+          __func__, mep->name, gpd, gpd_current, ring->enqueue);
+
+    while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+
+        request = mep->req;
+        mreq = to_mu3d_req(request);
+        if (mreq == NULL || mreq->gpd != gpd) {
+            DBG_C("no correct TX req is found\n");
+            break;
+        }
+
+        mreq->actual = gpd->buf_len;
+        handle_ept_complete(mep, 0);
+        gpd = advance_deq_gpd(ring);
+    }
+
+    DBG_I("%s EP%dIN, deq=%p, enq=%p, complete\n",
+          __func__, epnum, ring->dequeue, ring->enqueue);
+}
+
+static void qmu_done_rx(u8 epnum)
+{
+    struct udc_endpoint *mep = mtu3_find_ep(epnum, USB_DIR_OUT);
+    struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+    struct qmu_gpd *gpd = ring->dequeue;
+    struct qmu_gpd *gpd_current = NULL;
+    struct udc_request *request = NULL;
+    struct mu3d_req *mreq;
+    paddr_t gpd_dma;
+
+    gpd_dma = readl(USB_QMU_RQCPR(epnum));
+    gpd_current = gpd_dma_to_virt(ring, gpd_dma);
+
+    DBG_I("%s %s, last=%p, current=%p, enq=%p\n",
+          __func__, mep->name, gpd, gpd_current, ring->enqueue);
+
+    while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) {
+
+        request = mep->req;
+        mreq = to_mu3d_req(request);
+        if (mreq == NULL || mreq->gpd != gpd) {
+            DBG_C("no correct RX req is found\n");
+            break;
+        }
+        mreq->actual = gpd->buf_len;
+        handle_ept_complete(mep, 0);
+        gpd = advance_deq_gpd(ring);
+    }
+
+    DBG_I("%s EP%dOUT, deq=%p, enq=%p, complete\n",
+          __func__, epnum, ring->dequeue, ring->enqueue);
+}
+
+static void qmu_done_isr(u32 done_status)
+{
+    int i;
+
+    for (i = 1; i <= (MT_EP_NUM / 2); i++) {
+        if (done_status & QMU_RX_DONE_INT(i))
+            qmu_done_rx(i);
+        if (done_status & QMU_TX_DONE_INT(i))
+            qmu_done_tx(i);
+    }
+}
+
+static void qmu_exception_isr(u32 qmu_status)
+{
+    u32 errval;
+    int i;
+
+    if ((qmu_status & RXQ_CSERR_INT) || (qmu_status & RXQ_LENERR_INT)) {
+        errval = readl(U3D_RQERRIR0);
+        for (i = 1; i <= (MT_EP_NUM / 2); i++) {
+            if (errval & QMU_RX_CS_ERR(i))
+                DBG_C("Rx EP%d CS error!\n", i);
+
+            if (errval & QMU_RX_LEN_ERR(i))
+                DBG_C("RX EP%d Length error\n", i);
+        }
+        writel(errval, U3D_RQERRIR0);
+    }
+
+    if (qmu_status & RXQ_ZLPERR_INT) {
+        errval = readl(U3D_RQERRIR1);
+        for (i = 1; i <= (MT_EP_NUM / 2); i++) {
+            if (errval & QMU_RX_ZLP_ERR(i))
+                DBG_I("RX EP%d Recv ZLP\n", i);
+        }
+        writel(errval, U3D_RQERRIR1);
+    }
+
+    if ((qmu_status & TXQ_CSERR_INT) || (qmu_status & TXQ_LENERR_INT)) {
+        errval = readl(U3D_TQERRIR0);
+        for (i = 1; i <= (MT_EP_NUM / 2); i++) {
+            if (errval & QMU_TX_CS_ERR(i))
+                DBG_C("Tx EP%d checksum error!\n", i);
+
+            if (errval & QMU_TX_LEN_ERR(i))
+                DBG_I("Tx EP%d send ZLP failed\n", i);
+        }
+        writel(errval, U3D_TQERRIR0);
+    }
+}
+
+enum handler_return mtu3_qmu_isr(void)
+{
+    u32 qmu_status;
+    u32 qmu_done_status;
+
+    /* U3D_QISAR1 is read update */
+    qmu_status = readl(U3D_QISAR1);
+    qmu_status &= readl(U3D_QIER1);
+
+    qmu_done_status = readl(U3D_QISAR0);
+    qmu_done_status &= readl(U3D_QIER0);
+    writel(qmu_done_status, U3D_QISAR0); /* W1C */
+    DBG_I("[INTR] QMUdone[TX=%x, RX=%x] QMUexp[%x]\n",
+          (qmu_done_status & 0xFFFF), qmu_done_status >> 16,
+          qmu_status);
+
+    if (qmu_done_status)
+        qmu_done_isr(qmu_done_status);
+
+    if (qmu_status)
+        qmu_exception_isr(qmu_status);
+
+    return INT_RESCHEDULE;
+}
+
+int mtu3_qmu_init(void)
+{
+    if (QMU_GPD_SIZE != 16) {
+        DBG_C("QMU_GPD size SHOULD be 16 Bytes");
+        return -EFAULT;
+    }
+    return 0;
+}
+
+#else   /* PIO mode */
+
+void mtu3_qmu_flush(struct udc_endpoint *mep)
+{}
+
+int mtu3_gpd_ring_alloc(struct udc_endpoint *mep)
+{
+    return 0;
+}
+
+void mtu3_gpd_ring_free(struct udc_endpoint *mep)
+{}
+
+enum handler_return mtu3_qmu_isr(void)
+{
+    return INT_NO_RESCHEDULE;
+}
+
+int mtu3_qmu_init(void)
+{
+    return 0;
+}
+
+#endif  /* SUPPORT_QMU */
+
+#pragma GCC pop_options
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3_qmu.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3_qmu.h
new file mode 100644
index 0000000..9dfaa89
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/mtu3_qmu.h
@@ -0,0 +1,113 @@
+/*
+ * mtu3_qmu.h - Queue Management Unit driver header
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * 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 "mtu3.h"
+
+struct qmu_gpd;
+
+#define MAX_GPD_NUM         4
+#define QMU_GPD_SIZE        (sizeof(struct qmu_gpd))
+#define QMU_GPD_RING_SIZE   ((MAX_GPD_NUM) * (QMU_GPD_SIZE))
+
+#define GPD_BUF_SIZE        65532
+
+#define MU3D_EP_TXCR0(epnum)    (U3D_TX1CSR0 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_TXCR1(epnum)    (U3D_TX1CSR1 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_TXCR2(epnum)    (U3D_TX1CSR2 + (((epnum) - 1) * 0x10))
+
+#define MU3D_EP_RXCR0(epnum)    (U3D_RX1CSR0 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_RXCR1(epnum)    (U3D_RX1CSR1 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_RXCR2(epnum)    (U3D_RX1CSR2 + (((epnum) - 1) * 0x10))
+#define MU3D_EP_RXCR3(epnum)    (U3D_RX1CSR3 + (((epnum) - 1) * 0x10))
+
+#define USB_QMU_RQCSR(epnum)    (U3D_RXQCSR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_RQSAR(epnum)    (U3D_RXQSAR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_RQCPR(epnum)    (U3D_RXQCPR1 + (((epnum) - 1) * 0x10))
+
+#define USB_QMU_TQCSR(epnum)    (U3D_TXQCSR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_TQSAR(epnum)    (U3D_TXQSAR1 + (((epnum) - 1) * 0x10))
+#define USB_QMU_TQCPR(epnum)    (U3D_TXQCPR1 + (((epnum) - 1) * 0x10))
+
+
+/* U3D_QCR0 */
+#define QMU_RX_CS_EN(x)     (BIT(16) << (x))
+#define QMU_TX_CS_EN(x)     (BIT(0) << (x))
+#define QMU_CS16B_EN        BIT(0)
+
+/* U3D_QCR1 */
+#define QMU_TX_ZLP(x)       (BIT(0) << (x))
+
+/* U3D_QCR3 */
+#define QMU_RX_COZ(x)       (BIT(16) << (x))
+#define QMU_RX_ZLP(x)       (BIT(0) << (x))
+
+/* U3D_TXQCSR1 */
+/* U3D_RXQCSR1 */
+#define QMU_Q_ACTIVE    BIT(15)
+#define QMU_Q_STOP      BIT(2)
+#define QMU_Q_RESUME    BIT(1)
+#define QMU_Q_START     BIT(0)
+
+/* U3D_QISAR0, U3D_QIER0, U3D_QIESR0, U3D_QIECR0 */
+#define QMU_RX_DONE_INT(x)  (BIT(16) << (x))
+#define QMU_TX_DONE_INT(x)  (BIT(0) << (x))
+
+
+struct qmu_gpd {
+    u8 flag;
+    u8 chksum;
+    u16 data_buf_len;
+    u32 next_gpd;
+    u32 buffer;
+    u16 buf_len;
+    u8 ext_len;
+    u8 ext_flag;
+} __attribute__((packed));
+
+struct mtu3_gpd_ring {
+    paddr_t dma;
+    struct qmu_gpd *start;
+    struct qmu_gpd *end;
+    struct qmu_gpd *enqueue;
+    struct qmu_gpd *dequeue;
+};
+
+int mtu3_qmu_start(struct udc_endpoint *mep);
+void mtu3_qmu_resume(struct udc_endpoint *mep);
+void mtu3_qmu_flush(struct udc_endpoint *mep);
+
+void mtu3_insert_gpd(struct udc_endpoint *mep, struct mu3d_req *mreq);
+int mtu3_prepare_transfer(struct udc_endpoint *mep);
+
+int mtu3_gpd_ring_alloc(struct udc_endpoint *mep);
+void mtu3_gpd_ring_free(struct udc_endpoint *mep);
+
+enum handler_return mtu3_qmu_isr(void);
+int mtu3_qmu_init(void);
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/u3phy-i2c.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/u3phy-i2c.c
new file mode 100644
index 0000000..4f0378a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/u3phy-i2c.c
@@ -0,0 +1,352 @@
+#include <debug.h>
+#include <reg.h>
+
+#define PHY_TRUE 1
+#define PHY_FALSE 0
+
+#define SDA 0
+#define SCL 1
+
+#define INPUT 0
+#define OUTPUT 1
+
+#define SSUSB_FPGA_I2C_OUT_OFFSET 0
+#define SSUSB_FPGA_I2C_IN_OFFSET  0x04
+
+#define SSUSB_FPGA_I2C_SDA_OUT (1<<0)
+#define SSUSB_FPGA_I2C_SDA_OEN (1<<1)
+#define SSUSB_FPGA_I2C_SCL_OUT (1<<2)
+#define SSUSB_FPGA_I2C_SCL_OEN (1<<3)
+
+#define SSUSB_FPGA_I2C_SDA_IN_OFFSET 0
+#define SSUSB_FPGA_I2C_SCL_IN_OFFSET 1
+
+#define I2C_DELAY 10
+
+typedef unsigned char u8;
+typedef unsigned int u32;
+
+static void i2c_dummy_delay(volatile unsigned int count)
+{
+    do {
+        count--;
+    } while (count>0);
+}
+
+void gpio_set_direction(void *i2c_port_base, unsigned char gpio_dir, unsigned char gpio_pin)
+{
+    unsigned int temp;
+    void *addr;
+
+    addr = i2c_port_base + SSUSB_FPGA_I2C_OUT_OFFSET;
+
+    temp = readl(addr);
+
+    if (gpio_pin == SDA) {
+        if (gpio_dir==OUTPUT) {
+            temp |= SSUSB_FPGA_I2C_SDA_OEN;
+            writel(temp, addr);
+        } else {
+            temp &= ~SSUSB_FPGA_I2C_SDA_OEN;
+            writel(temp, addr);
+        }
+    } else {
+        if (gpio_dir==OUTPUT) {
+            temp |= SSUSB_FPGA_I2C_SCL_OEN;
+            writel(temp, addr);
+        } else {
+            temp &= ~SSUSB_FPGA_I2C_SCL_OEN;
+            writel(temp, addr);
+        }
+    }
+}
+
+void gpio_set_value(void *i2c_port_base, unsigned char value, unsigned char gpio_pin)
+{
+    unsigned int temp;
+    void *addr;
+
+    addr = i2c_port_base + SSUSB_FPGA_I2C_OUT_OFFSET;
+
+    temp = readl(addr);
+
+    if (gpio_pin == SDA) {
+        if (value == 1) {
+            temp |= SSUSB_FPGA_I2C_SDA_OUT;
+            writel(temp, addr);
+        } else {
+            temp &= ~SSUSB_FPGA_I2C_SDA_OUT;
+            writel(temp, addr);
+        }
+    } else {
+        if (value == 1) {
+            temp |= SSUSB_FPGA_I2C_SCL_OUT;
+            writel(temp, addr);
+        } else {
+            temp &= ~SSUSB_FPGA_I2C_SCL_OUT;
+            writel(temp, addr);
+        }
+    }
+}
+
+unsigned char gpio_get_value(void *i2c_port_base, unsigned char gpio_pin)
+{
+    unsigned char temp;
+    void *addr;
+
+    addr = i2c_port_base + SSUSB_FPGA_I2C_IN_OFFSET;
+
+    temp = readl(addr);
+
+    if (gpio_pin == SDA)
+        temp = (temp >> SSUSB_FPGA_I2C_SDA_IN_OFFSET) & 0x01;
+    else
+        temp = (temp >> SSUSB_FPGA_I2C_SCL_IN_OFFSET) & 0x01;
+
+    return temp;
+}
+
+void i2c_stop(void *i2c_port_base)
+{
+    gpio_set_direction(i2c_port_base, OUTPUT, SDA);
+    gpio_set_value(i2c_port_base, 0, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 0, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 1, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 1, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_direction(i2c_port_base, INPUT, SCL);
+    gpio_set_direction(i2c_port_base, INPUT, SDA);
+}
+
+void i2c_start(void *i2c_port_base) /* Prepare the SDA and SCL for sending/receiving */
+{
+    gpio_set_direction(i2c_port_base, OUTPUT, SCL);
+    gpio_set_direction(i2c_port_base, OUTPUT, SDA);
+    gpio_set_value(i2c_port_base, 1, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 1, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 0, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 0, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+}
+
+u32 i2c_send_byte(void *i2c_port_base, u8 data) /* return 0 --> ack */
+{
+    int i, ack;
+
+    gpio_set_direction(i2c_port_base, OUTPUT, SDA);
+
+    for (i=8; --i>0;) {
+        gpio_set_value(i2c_port_base, (data>>i)&0x01, SDA);
+        i2c_dummy_delay(I2C_DELAY);
+        gpio_set_value(i2c_port_base,  1, SCL); /* high */
+        i2c_dummy_delay(I2C_DELAY);
+        gpio_set_value(i2c_port_base,  0, SCL); /* low */
+        i2c_dummy_delay(I2C_DELAY);
+    }
+    gpio_set_value(i2c_port_base, (data>>i)&0x01, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base,  1, SCL); /* high */
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base,  0, SCL); /* low */
+    i2c_dummy_delay(I2C_DELAY);
+
+    gpio_set_value(i2c_port_base, 0, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_direction(i2c_port_base, INPUT, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 1, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    ack = gpio_get_value(i2c_port_base,SDA); /* ack 1: error , 0:ok */
+    gpio_set_value(i2c_port_base, 0, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+
+    if (ack==1)
+        return PHY_FALSE;
+    else
+        return PHY_TRUE;
+}
+
+void i2c_receive_byte(void *i2c_port_base, u8 *data, u8 ack)
+{
+    int i;
+    u32 dataCache;
+
+    dataCache = 0;
+    gpio_set_direction(i2c_port_base, INPUT, SDA);
+
+    for (i=8; --i>=0;) {
+        dataCache <<= 1;
+        i2c_dummy_delay(I2C_DELAY);
+        gpio_set_value(i2c_port_base, 1, SCL);
+        i2c_dummy_delay(I2C_DELAY);
+        dataCache |= gpio_get_value(i2c_port_base,SDA);
+        gpio_set_value(i2c_port_base, 0, SCL);
+        i2c_dummy_delay(I2C_DELAY);
+    }
+
+    gpio_set_direction(i2c_port_base, OUTPUT, SDA);
+    gpio_set_value(i2c_port_base, ack, SDA);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 1, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    gpio_set_value(i2c_port_base, 0, SCL);
+    i2c_dummy_delay(I2C_DELAY);
+    *data = (u8)dataCache;
+}
+
+
+int i2c_write_reg(void *i2c_port_base, u8 dev_id, u8 addr, u8 data)
+{
+    int acknowledge=0;
+
+    i2c_start(i2c_port_base);
+
+    acknowledge=i2c_send_byte(i2c_port_base,(dev_id<<1) & 0xff);
+    if (acknowledge)
+        acknowledge=i2c_send_byte(i2c_port_base,addr);
+    else
+        return PHY_FALSE;
+
+    acknowledge=i2c_send_byte(i2c_port_base,data);
+    if (acknowledge) {
+        i2c_stop(i2c_port_base);
+        return PHY_TRUE;
+    } else {
+        return PHY_FALSE;
+    }
+}
+
+int i2c_read_reg(void *i2c_port_base, u8 dev_id, u8 addr, u8 *data)
+{
+    int acknowledge=0;
+
+    i2c_start(i2c_port_base);
+
+    acknowledge=i2c_send_byte(i2c_port_base,(dev_id<<1) & 0xff);
+    if (acknowledge)
+        acknowledge=i2c_send_byte(i2c_port_base,addr);
+    else
+        return PHY_FALSE;
+
+    i2c_start(i2c_port_base);
+
+    acknowledge=i2c_send_byte(i2c_port_base,((dev_id<<1) & 0xff) | 0x01);
+    if (acknowledge)
+        i2c_receive_byte(i2c_port_base,data, 1);  /* ack 0: ok , 1 error */
+    else
+        return PHY_FALSE;
+
+    i2c_stop(i2c_port_base);
+
+    return acknowledge;
+}
+
+int u3phy_write_reg(void *i2c_port_base, u8 dev_id, u8 address, int value)
+{
+    int ret;
+
+    ret = i2c_write_reg(i2c_port_base, dev_id, address, value);
+    if (ret == PHY_FALSE) {
+        dprintf(ALWAYS, "Write failed(dev_id: %x, addr: 0x%x, val: 0x%x)\n", dev_id, address, value);
+        return PHY_FALSE;
+    }
+
+    return PHY_TRUE;
+}
+
+unsigned char u3phy_read_reg(void *i2c_port_base, u8 dev_id,  u8 address)
+{
+    u8 buf;
+    int ret;
+
+    /* buf = (char *)kmalloc(1, GFP_NOIO); */
+    ret = i2c_read_reg(i2c_port_base, dev_id, address, &buf);
+    if (ret == PHY_FALSE) {
+        dprintf(ALWAYS, "Read failed(dev_id: %x, addr: 0x%x)\n", dev_id, address);
+        return PHY_FALSE;
+    }
+    ret = buf;
+
+    return ret;
+
+}
+
+int u3phy_write_reg32(void *i2c_port_base, u8 dev_id, u32 addr, u32 data)
+{
+    u8 addr8;
+    u8 data_0, data_1, data_2, data_3;
+
+    addr8 = addr & 0xff;
+    data_0 = data & 0xff;
+    data_1 = (data>>8) & 0xff;
+    data_2 = (data>>16) & 0xff;
+    data_3 = (data>>24) & 0xff;
+
+    u3phy_write_reg(i2c_port_base, dev_id, addr8, data_0);
+    u3phy_write_reg(i2c_port_base, dev_id, addr8+1, data_1);
+    u3phy_write_reg(i2c_port_base, dev_id, addr8+2, data_2);
+    u3phy_write_reg(i2c_port_base, dev_id, addr8+3, data_3);
+
+    return 0;
+}
+
+unsigned int u3phy_read_reg32(void *i2c_port_base, u8 dev_id, u32 addr)
+{
+    u8 addr8;
+    u32 data;
+
+    addr8 = addr & 0xff;
+
+    data = u3phy_read_reg(i2c_port_base, dev_id, addr8);
+    data |= (u3phy_read_reg(i2c_port_base, dev_id, addr8+1) << 8);
+    data |= (u3phy_read_reg(i2c_port_base, dev_id, addr8+2) << 16);
+    data |= (u3phy_read_reg(i2c_port_base, dev_id, addr8+3) << 24);
+
+    return data;
+}
+
+
+int u3phy_write_reg8(void *i2c_port_base, u8 dev_id, u32 addr, u8 data)
+{
+    u8 addr8;
+
+    addr8 = addr & 0xff;
+    u3phy_write_reg(i2c_port_base, dev_id, addr8, data);
+
+    return PHY_TRUE;
+}
+
+unsigned char u3phy_read_reg8(void *i2c_port_base, u8 dev_id, u32 addr)
+{
+    u8 addr8;
+    u32 data;
+
+    addr8 = addr & 0xff;
+    data = u3phy_read_reg(i2c_port_base, dev_id, addr8);
+
+    return data;
+}
+
+
+unsigned int u3phy_readlmsk(void *i2c_port_base, unsigned char i2c_addr, unsigned int reg_addr32, unsigned int offset, unsigned int mask)
+{
+    return  ((u3phy_read_reg32(i2c_port_base, i2c_addr, reg_addr32) & mask) >> offset);
+}
+
+int u3phy_writelmsk(void *i2c_port_base, unsigned char i2c_addr, unsigned int reg_addr32, unsigned int offset, unsigned int mask, unsigned int data)
+{
+    unsigned int cur_value;
+    unsigned int new_value;
+
+    cur_value = u3phy_read_reg32(i2c_port_base, i2c_addr, reg_addr32);
+    new_value = (cur_value & (~mask)) | ((data << offset) & mask);
+    u3phy_write_reg32(i2c_port_base, i2c_addr, reg_addr32, new_value);
+
+    return 0;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/usbphy.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/usbphy.c
new file mode 100644
index 0000000..9dcc592
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/usbphy.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in
+ *  the documentation and/or other materials provided with the
+ *  distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mt_typedefs.h>
+#include <platform/reg_utils.h>
+
+#include "usbphy.h"
+
+#pragma GCC push_options
+#pragma GCC optimize("O1")
+
+#ifdef DBG_USB_PHY
+#define PHY_LOG(x...) dprintf(INFO, "[USB][PHY] " x)
+#else
+#define PHY_LOG(x...) do{} while(0)
+#endif
+
+/* 2712E1 can't set RG_AVALID */
+#define U3D_U2PHYDEV_MASK   (E60802_RG_IDDIG | /*E60802_RG_AVALID |*/ \
+    E60802_RG_BVALID | E60802_RG_VBUSVALID)
+
+#define U3D_U2PHYFRCDEV_MASK (E60802_FORCE_IDDIG | /*E60802_FORCE_AVALID |*/ \
+    E60802_FORCE_BVALID | E60802_FORCE_SESSEND | E60802_FORCE_VBUSVALID)
+
+void mt_usb_phy_poweron(void)
+{
+    PHY_LOG("%s\n", __func__);
+
+    /* switch to USB function */
+    clrbits32_r(E60802_FORCE_UART_EN, U3D_U2PHYDTM0);
+    clrbits32_r(E60802_RG_UART_EN, U3D_U2PHYDTM1);
+    clrbits32_r(E60802_RG_USB20_GPIO_CTL, U3D_U2PHYACR4);
+    clrbits32_r(E60802_USB20_GPIO_MODE, U3D_U2PHYACR4);
+    /* DP/DM BC1.1 path Disable */
+    clrbits32_r(E60802_RG_USB20_BC11_SW_EN, U3D_USBPHYACR6);
+    /* Internal R bias enable */
+    setbits32_r(E60802_RG_USB20_INTR_EN, U3D_USBPHYACR0);
+    /* 100U from u2 */
+    clrbits32_r(E60802_RG_USB20_HS_100U_U3_EN, U3D_USBPHYACR5);
+    /* let suspendm=1, enable usb 480MHz pll */
+    setbits32_r(E60802_RG_SUSPENDM, U3D_U2PHYDTM0);
+    /* force_suspendm=1 */
+    setbits32_r(E60802_FORCE_SUSPENDM, U3D_U2PHYDTM0);
+    /* wait 2 ms for USBPLL stable */
+    spin(2000);
+    /* power on device mode */
+    clrbits32_r(E60802_RG_SESSEND, U3D_U2PHYDTM1);
+    /* NOTE: mt2712E1 can't set RG_AVALID */
+    setbits32_r(U3D_U2PHYDEV_MASK, U3D_U2PHYDTM1);
+    /* enable force into device mode */
+    setbits32_r(U3D_U2PHYFRCDEV_MASK, U3D_U2PHYDTM1);
+    /* wait mac ready */
+    spin(2000);
+    /* apply MAC clock related setting after phy init */
+}
+
+void mt_usb_phy_poweroff(void)
+{
+    /* power down device mode */
+    clrbits32_r(E60802_RG_VBUSVALID | E60802_RG_BVALID | E60802_RG_AVALID, U3D_U2PHYDTM1);
+    setbits32_r(E60802_RG_IDDIG | E60802_RG_SESSEND, U3D_U2PHYDTM1);
+
+    /* cleaer device force mode */
+    clrbits32_r(U3D_U2PHYFRCDEV_MASK, U3D_U2PHYDTM1);
+
+    clrbits32_r(E60802_RG_SUSPENDM, U3D_U2PHYDTM0);
+    setbits32_r(E60802_FORCE_SUSPENDM, U3D_U2PHYDTM0);
+    spin(2000);
+    PHY_LOG("%s\n", __func__);
+}
+
+#pragma GCC pop_options
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/usbphy.h b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/usbphy.h
new file mode 100644
index 0000000..21c2b24
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/usb/usbphy.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright(c) 2013 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
+
+/* APB Module ssusb_top_sif - USB3_SIF2_BASE */
+#define SSUSB_SIFSLV_U2PHY_COM_BASE     (USB3_SIF_BASE + 0x300)
+#define SSUSB_SIFSLV_SPLLC_BASE         (USB3_SIF_BASE + 0x700)
+#define SSUSB_SIFSLV_U3PHYD_BASE        (USB3_SIF_BASE + 0x900)
+#define SSUSB_SIFSLV_U3PHYA_BASE        (USB3_SIF_BASE + 0xB00)
+#define SSUSB_SIFSLV_U3PHYA_DA_BASE     (USB3_SIF_BASE + 0xC00)
+
+/* referenecd from ssusb_USB20_PHY_regmap_com_T28.xls */
+#define U3D_USBPHYACR0              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0000) /* bit 2~bit 30 */
+#define U3D_USBPHYACR1              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0004)
+#define U3D_USBPHYACR2              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0008) /* bit 0~ bit15 */
+#define U3D_USBPHYACR4              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0010)
+#define U3D_USBPHYACR5              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0014)
+#define U3D_USBPHYACR6              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0018)
+#define U3D_U2PHYACR3               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x001c)
+#define U3D_U2PHYACR4               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0020) /* bit8~ bit18 */
+#define U3D_U2PHYAMON0              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0024)
+#define U3D_U2PHYDCR0               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0060)
+#define U3D_U2PHYDCR1               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0064)
+#define U3D_U2PHYDTM0               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0068)
+#define U3D_U2PHYDTM1               (SSUSB_SIFSLV_U2PHY_COM_BASE+0x006C)
+#define U3D_U2PHYDMON0              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0070)
+#define U3D_U2PHYDMON1              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0074)
+#define U3D_U2PHYDMON2              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0078)
+#define U3D_U2PHYDMON3              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x007C)
+#define U3D_U2PHYBC12C              (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0080)
+#define U3D_U2PHYBC12C1             (SSUSB_SIFSLV_U2PHY_COM_BASE+0x0084)
+#define U3D_U2PHYREGFPPC            (SSUSB_SIFSLV_U2PHY_COM_BASE+0x00e0)
+#define U3D_U2PHYVERSIONC           (SSUSB_SIFSLV_U2PHY_COM_BASE+0x00f0)
+#define U3D_U2PHYREGFCOM            (SSUSB_SIFSLV_U2PHY_COM_BASE+0x00fc)
+
+/* U3D_USBPHYACR0 */
+#define E60802_RG_USB20_MPX_OUT_SEL               (0x7<<28) /* 30:28 */
+#define E60802_RG_USB20_TX_PH_ROT_SEL             (0x7<<24) /* 26:24 */
+#define E60802_RG_USB20_PLL_DIVEN                 (0x7<<20) /* 22:20 */
+#define E60802_RG_USB20_PLL_BR                    (0x1<<18) /* 18:18 */
+#define E60802_RG_USB20_PLL_BP                    (0x1<<17) /* 17:17 */
+#define E60802_RG_USB20_PLL_BLP                   (0x1<<16) /* 16:16 */
+#define E60802_RG_USB20_USBPLL_FORCE_ON           (0x1<<15) /* 15:15 */
+#define E60802_RG_USB20_PLL_FBDIV                 (0x7f<<8) /* 14:8 */
+#define E60802_RG_USB20_PLL_PREDIV                (0x3<<6) /* 7:6 */
+#define E60802_RG_USB20_INTR_EN                   (0x1<<5) /* 5:5 */
+#define E60802_RG_USB20_REF_EN                    (0x1<<4) /* 4:4 */
+#define E60802_RG_USB20_BGR_DIV                   (0x3<<2) /* 3:2 */
+#define E60802_RG_SIFSLV_CHP_EN                   (0x1<<1) /* 1:1 */
+#define E60802_RG_SIFSLV_BGR_EN                   (0x1<<0) /* 0:0 */
+
+/* U3D_USBPHYACR1 */
+#define E60802_RG_USB20_INTR_CAL                  (0x1f<<19) /* 23:19 */
+#define E60802_RG_USB20_OTG_VBUSTH                (0x7<<16) /* 18:16 */
+#define E60802_RG_USB20_VRT_VREF_SEL              (0x7<<12) /* 14:12 */
+#define E60802_RG_USB20_TERM_VREF_SEL             (0x7<<8) /* 10:8 */
+#define E60802_RG_USB20_MPX_SEL                   (0xff<<0) /* 7:0 */
+
+/* U3D_USBPHYACR2 */
+#define E60802_RG_SIFSLV_MAC_BANDGAP_EN           (0x1<<17) /* 17:17 */
+#define E60802_RG_SIFSLV_MAC_CHOPPER_EN           (0x1<<16) /* 16:16 */
+#define E60802_RG_USB20_CLKREF_REV                (0xffff<<0) /* 15:0 */
+
+/* U3D_USBPHYACR4 */
+#define E60802_RG_USB20_DP_ABIST_SOURCE_EN        (0x1<<31) /* 31:31 */
+#define E60802_RG_USB20_DP_ABIST_SELE             (0xf<<24) /* 27:24 */
+#define E60802_RG_USB20_ICUSB_EN                  (0x1<<16) /* 16:16 */
+#define E60802_RG_USB20_LS_CR                     (0x7<<12) /* 14:12 */
+#define E60802_RG_USB20_FS_CR                     (0x7<<8) /* 10:8 */
+#define E60802_RG_USB20_LS_SR                     (0x7<<4) /* 6:4 */
+#define E60802_RG_USB20_FS_SR                     (0x7<<0) /* 2:0 */
+
+/* U3D_USBPHYACR5 */
+#define E60802_RG_USB20_DISC_FIT_EN               (0x1<<28) /* 28:28 */
+#define E60802_RG_USB20_INIT_SQ_EN_DG             (0x3<<26) /* 27:26 */
+#define E60802_RG_USB20_HSTX_TMODE_SEL            (0x3<<24) /* 25:24 */
+#define E60802_RG_USB20_SQD                       (0x3<<22) /* 23:22 */
+#define E60802_RG_USB20_DISCD                     (0x3<<20) /* 21:20 */
+#define E60802_RG_USB20_HSTX_TMODE_EN             (0x1<<19) /* 19:19 */
+#define E60802_RG_USB20_PHYD_MONEN                (0x1<<18) /* 18:18 */
+#define E60802_RG_USB20_INLPBK_EN                 (0x1<<17) /* 17:17 */
+#define E60802_RG_USB20_CHIRP_EN                  (0x1<<16) /* 16:16 */
+#define E60802_RG_USB20_HSTX_SRCAL_EN             (0x1<<15) /* 15:15 */
+#define E60802_RG_USB20_HSTX_SRCTRL               (0x7<<12) /* 14:12 */
+#define E60802_RG_USB20_HS_100U_U3_EN             (0x1<<11) /* 11:11 */
+#define E60802_RG_USB20_GBIAS_ENB                 (0x1<<10) /* 10:10 */
+#define E60802_RG_USB20_DM_ABIST_SOURCE_EN        (0x1<<7) /* 7:7 */
+#define E60802_RG_USB20_DM_ABIST_SELE             (0xf<<0) /* 3:0 */
+
+/* U3D_USBPHYACR6 */
+#define E60802_RG_USB20_ISO_EN                    (0x1<<31) /* 31:31 */
+#define E60802_RG_USB20_PHY_REV                   (0xef<<24) /* 31:24 */
+#define E60802_RG_USB20_BC11_SW_EN                (0x1<<23) /* 23:23 */
+#define E60802_RG_USB20_SR_CLK_SEL                (0x1<<22) /* 22:22 */
+#define E60802_RG_USB20_OTG_VBUSCMP_EN            (0x1<<20) /* 20:20 */
+#define E60802_RG_USB20_OTG_ABIST_EN              (0x1<<19) /* 19:19 */
+#define E60802_RG_USB20_OTG_ABIST_SELE            (0x7<<16) /* 18:16 */
+#define E60802_RG_USB20_HSRX_MMODE_SELE           (0x3<<12) /* 13:12 */
+#define E60802_RG_USB20_HSRX_BIAS_EN_SEL          (0x3<<9) /* 10:9 */
+#define E60802_RG_USB20_HSRX_TMODE_EN             (0x1<<8) /* 8:8 */
+#define E60802_RG_USB20_DISCTH                    (0xf<<4) /* 7:4 */
+#define E60802_RG_USB20_SQTH                      (0xf<<0) /* 3:0 */
+
+/* U3D_U2PHYACR3 */
+#define E60802_RG_USB20_HSTX_DBIST                (0xf<<28) /* 31:28 */
+#define E60802_RG_USB20_HSTX_BIST_EN              (0x1<<26) /* 26:26 */
+#define E60802_RG_USB20_HSTX_I_EN_MODE            (0x3<<24) /* 25:24 */
+#define E60802_RG_USB20_USB11_TMODE_EN            (0x1<<19) /* 19:19 */
+#define E60802_RG_USB20_TMODE_FS_LS_TX_EN         (0x1<<18) /* 18:18 */
+#define E60802_RG_USB20_TMODE_FS_LS_RCV_EN        (0x1<<17) /* 17:17 */
+#define E60802_RG_USB20_TMODE_FS_LS_MODE          (0x1<<16) /* 16:16 */
+#define E60802_RG_USB20_HS_TERM_EN_MODE           (0x3<<13) /* 14:13 */
+#define E60802_RG_USB20_PUPD_BIST_EN              (0x1<<12) /* 12:12 */
+#define E60802_RG_USB20_EN_PU_DM                  (0x1<<11) /* 11:11 */
+#define E60802_RG_USB20_EN_PD_DM                  (0x1<<10) /* 10:10 */
+#define E60802_RG_USB20_EN_PU_DP                  (0x1<<9) /* 9:9 */
+#define E60802_RG_USB20_EN_PD_DP                  (0x1<<8) /* 8:8 */
+
+/* U3D_U2PHYACR4 */
+#define E60802_RG_USB20_DP_100K_MODE              (0x1<<18) /* 18:18 */
+#define E60802_RG_USB20_DM_100K_EN                (0x1<<17) /* 17:17 */
+#define E60802_USB20_DP_100K_EN                   (0x1<<16) /* 16:16 */
+#define E60802_USB20_GPIO_DM_I                    (0x1<<15) /* 15:15 */
+#define E60802_USB20_GPIO_DP_I                    (0x1<<14) /* 14:14 */
+#define E60802_USB20_GPIO_DM_OE                   (0x1<<13) /* 13:13 */
+#define E60802_USB20_GPIO_DP_OE                   (0x1<<12) /* 12:12 */
+#define E60802_RG_USB20_GPIO_CTL                  (0x1<<9) /* 9:9 */
+#define E60802_USB20_GPIO_MODE                    (0x1<<8) /* 8:8 */
+#define E60802_RG_USB20_TX_BIAS_EN                (0x1<<5) /* 5:5 */
+#define E60802_RG_USB20_TX_VCMPDN_EN              (0x1<<4) /* 4:4 */
+#define E60802_RG_USB20_HS_SQ_EN_MODE             (0x3<<2) /* 3:2 */
+#define E60802_RG_USB20_HS_RCV_EN_MODE            (0x3<<0) /* 1:0 */
+
+/* U3D_U2PHYAMON0 */
+#define E60802_RGO_USB20_GPIO_DM_O                (0x1<<1) /* 1:1 */
+#define E60802_RGO_USB20_GPIO_DP_O                (0x1<<0) /* 0:0 */
+
+/* U3D_U2PHYDCR0 */
+#define E60802_RG_USB20_CDR_TST                   (0x3<<30) /* 31:30 */
+#define E60802_RG_USB20_GATED_ENB                 (0x1<<29) /* 29:29 */
+#define E60802_RG_USB20_TESTMODE                  (0x3<<26) /* 27:26 */
+#define E60802_RG_SIFSLV_USB20_PLL_STABLE         (0x1<<25) /* 25:25 */
+#define E60802_RG_SIFSLV_USB20_PLL_FORCE_ON       (0x1<<24) /* 24:24 */
+#define E60802_RG_USB20_PHYD_RESERVE              (0xffff<<8) /* 23:8 */
+#define E60802_RG_USB20_EBTHRLD                   (0x1<<7) /* 7:7 */
+#define E60802_RG_USB20_EARLY_HSTX_I              (0x1<<6) /* 6:6 */
+#define E60802_RG_USB20_TX_TST                    (0x1<<5) /* 5:5 */
+#define E60802_RG_USB20_NEGEDGE_ENB               (0x1<<4) /* 4:4 */
+#define E60802_RG_USB20_CDR_FILT                  (0xf<<0) /* 3:0 */
+
+/* U3D_U2PHYDCR1 */
+#define E60802_RG_USB20_PROBE_SEL                 (0xff<<24) /* 31:24 */
+#define E60802_RG_USB20_DRVVBUS                   (0x1<<23) /* 23:23 */
+#define E60802_RG_DEBUG_EN                        (0x1<<22) /* 22:22 */
+#define E60802_RG_USB20_OTG_PROBE                 (0x3<<20) /* 21:20 */
+#define E60802_RG_USB20_SW_PLLMODE                (0x3<<18) /* 19:18 */
+#define E60802_RG_USB20_BERTH                     (0x3<<16) /* 17:16 */
+#define E60802_RG_USB20_LBMODE                    (0x3<<13) /* 14:13 */
+#define E60802_RG_USB20_FORCE_TAP                 (0x1<<12) /* 12:12 */
+#define E60802_RG_USB20_TAPSEL                    (0xfff<<0) /* 11:0 */
+
+/* U3D_U2PHYDTM0 */
+#define E60802_RG_UART_MODE                       (0x3<<30) /* 31:30 */
+#define E60802_FORCE_UART_I                       (0x1<<29) /* 29:29 */
+#define E60802_FORCE_UART_BIAS_EN                 (0x1<<28) /* 28:28 */
+#define E60802_FORCE_UART_TX_OE                   (0x1<<27) /* 27:27 */
+#define E60802_FORCE_UART_EN                      (0x1<<26) /* 26:26 */
+#define E60802_FORCE_USB_CLKEN                    (0x1<<25) /* 25:25 */
+#define E60802_FORCE_DRVVBUS                      (0x1<<24) /* 24:24 */
+#define E60802_FORCE_DATAIN                       (0x1<<23) /* 23:23 */
+#define E60802_FORCE_TXVALID                      (0x1<<22) /* 22:22 */
+#define E60802_FORCE_DM_PULLDOWN                  (0x1<<21) /* 21:21 */
+#define E60802_FORCE_DP_PULLDOWN                  (0x1<<20) /* 20:20 */
+#define E60802_FORCE_XCVRSEL                      (0x1<<19) /* 19:19 */
+#define E60802_FORCE_SUSPENDM                     (0x1<<18) /* 18:18 */
+#define E60802_FORCE_TERMSEL                      (0x1<<17) /* 17:17 */
+#define E60802_FORCE_OPMODE                       (0x1<<16) /* 16:16 */
+#define E60802_UTMI_MUXSEL                        (0x1<<15) /* 15:15 */
+#define E60802_RG_RESET                           (0x1<<14) /* 14:14 */
+#define E60802_RG_DATAIN                          (0xf<<10) /* 13:10 */
+#define E60802_RG_TXVALIDH                        (0x1<<9) /* 9:9 */
+#define E60802_RG_TXVALID                         (0x1<<8) /* 8:8 */
+#define E60802_RG_DMPULLDOWN                      (0x1<<7) /* 7:7 */
+#define E60802_RG_DPPULLDOWN                      (0x1<<6) /* 6:6 */
+#define E60802_RG_XCVRSEL                         (0x3<<4) /* 5:4 */
+#define E60802_RG_SUSPENDM                        (0x1<<3) /* 3:3 */
+#define E60802_RG_TERMSEL                         (0x1<<2) /* 2:2 */
+#define E60802_RG_OPMODE                          (0x3<<0) /* 1:0 */
+
+/* U3D_U2PHYDTM1 */
+#define E60802_RG_USB20_PRBS7_EN                  (0x1<<31) /* 31:31 */
+#define E60802_RG_USB20_PRBS7_BITCNT              (0x3f<<24) /* 29:24 */
+#define E60802_RG_USB20_CLK48M_EN                 (0x1<<23) /* 23:23 */
+#define E60802_RG_USB20_CLK60M_EN                 (0x1<<22) /* 22:22 */
+#define E60802_RG_UART_I                          (0x1<<19) /* 19:19 */
+#define E60802_RG_UART_BIAS_EN                    (0x1<<18) /* 18:18 */
+#define E60802_RG_UART_TX_OE                      (0x1<<17) /* 17:17 */
+#define E60802_RG_UART_EN                         (0x1<<16) /* 16:16 */
+#define E60802_RG_IP_U2_PORT_POWER                (0x1<<15) /* 15:15 */
+#define E60802_FORCE_IP_U2_PORT_POWER             (0x1<<14) /* 14:14 */
+#define E60802_FORCE_VBUSVALID                    (0x1<<13) /* 13:13 */
+#define E60802_FORCE_SESSEND                      (0x1<<12) /* 12:12 */
+#define E60802_FORCE_BVALID                       (0x1<<11) /* 11:11 */
+#define E60802_FORCE_AVALID                       (0x1<<10) /* 10:10 */
+#define E60802_FORCE_IDDIG                        (0x1<<9) /* 9:9 */
+#define E60802_FORCE_IDPULLUP                     (0x1<<8) /* 8:8 */
+#define E60802_RG_VBUSVALID                       (0x1<<5) /* 5:5 */
+#define E60802_RG_SESSEND                         (0x1<<4) /* 4:4 */
+#define E60802_RG_BVALID                          (0x1<<3) /* 3:3 */
+#define E60802_RG_AVALID                          (0x1<<2) /* 2:2 */
+#define E60802_RG_IDDIG                           (0x1<<1) /* 1:1 */
+#define E60802_RG_IDPULLUP                        (0x1<<0) /* 0:0 */
+
+/* U3D_U2PHYDMON0 */
+#define E60802_RG_USB20_PRBS7_BERTH               (0xff<<0) /* 7:0 */
+
+/* U3D_U2PHYDMON1 */
+#define E60802_USB20_UART_O                       (0x1<<31) /* 31:31 */
+#define E60802_RGO_USB20_LB_PASS                  (0x1<<30) /* 30:30 */
+#define E60802_RGO_USB20_LB_DONE                  (0x1<<29) /* 29:29 */
+#define E60802_AD_USB20_BVALID                    (0x1<<28) /* 28:28 */
+#define E60802_USB20_IDDIG                        (0x1<<27) /* 27:27 */
+#define E60802_AD_USB20_VBUSVALID                 (0x1<<26) /* 26:26 */
+#define E60802_AD_USB20_SESSEND                   (0x1<<25) /* 25:25 */
+#define E60802_AD_USB20_AVALID                    (0x1<<24) /* 24:24 */
+#define E60802_USB20_LINE_STATE                   (0x3<<22) /* 23:22 */
+#define E60802_USB20_HST_DISCON                   (0x1<<21) /* 21:21 */
+#define E60802_USB20_TX_READY                     (0x1<<20) /* 20:20 */
+#define E60802_USB20_RX_ERROR                     (0x1<<19) /* 19:19 */
+#define E60802_USB20_RX_ACTIVE                    (0x1<<18) /* 18:18 */
+#define E60802_USB20_RX_VALIDH                    (0x1<<17) /* 17:17 */
+#define E60802_USB20_RX_VALID                     (0x1<<16) /* 16:16 */
+#define E60802_USB20_DATA_OUT                     (0xffff<<0) /* 15:0 */
+
+/* U3D_U2PHYDMON2 */
+#define E60802_RGO_TXVALID_CNT                    (0xff<<24) /* 31:24 */
+#define E60802_RGO_RXACTIVE_CNT                   (0xff<<16) /* 23:16 */
+#define E60802_RGO_USB20_LB_BERCNT                (0xff<<8) /* 15:8 */
+#define E60802_USB20_PROBE_OUT                    (0xff<<0) /* 7:0 */
+
+/* U3D_U2PHYDMON3 */
+#define E60802_RGO_USB20_PRBS7_ERRCNT             (0xffff<<16) /* 31:16 */
+#define E60802_RGO_USB20_PRBS7_DONE               (0x1<<3) /* 3:3 */
+#define E60802_RGO_USB20_PRBS7_LOCK               (0x1<<2) /* 2:2 */
+#define E60802_RGO_USB20_PRBS7_PASS               (0x1<<1) /* 1:1 */
+#define E60802_RGO_USB20_PRBS7_PASSTH             (0x1<<0) /* 0:0 */
+
+/* U3D_U2PHYBC12C */
+#define E60802_RG_SIFSLV_CHGDT_DEGLCH_CNT         (0xf<<28) /* 31:28 */
+#define E60802_RG_SIFSLV_CHGDT_CTRL_CNT           (0xf<<24) /* 27:24 */
+#define E60802_RG_SIFSLV_CHGDT_FORCE_MODE         (0x1<<16) /* 16:16 */
+#define E60802_RG_CHGDT_ISRC_LEV                  (0x3<<14) /* 15:14 */
+#define E60802_RG_CHGDT_VDATSRC                   (0x1<<13) /* 13:13 */
+#define E60802_RG_CHGDT_BGVREF_SEL                (0x7<<10) /* 12:10 */
+#define E60802_RG_CHGDT_RDVREF_SEL                (0x3<<8) /* 9:8 */
+#define E60802_RG_CHGDT_ISRC_DP                   (0x1<<7) /* 7:7 */
+#define E60802_RG_SIFSLV_CHGDT_OPOUT_DM           (0x1<<6) /* 6:6 */
+#define E60802_RG_CHGDT_VDAT_DM                   (0x1<<5) /* 5:5 */
+#define E60802_RG_CHGDT_OPOUT_DP                  (0x1<<4) /* 4:4 */
+#define E60802_RG_SIFSLV_CHGDT_VDAT_DP            (0x1<<3) /* 3:3 */
+#define E60802_RG_SIFSLV_CHGDT_COMP_EN            (0x1<<2) /* 2:2 */
+#define E60802_RG_SIFSLV_CHGDT_OPDRV_EN           (0x1<<1) /* 1:1 */
+#define E60802_RG_CHGDT_EN                        (0x1<<0) /* 0:0 */
+
+/* U3D_U2PHYBC12C1 */
+#define E60802_RG_CHGDT_REV                       (0xff<<0) /* 7:0 */
+
+/* U3D_REGFPPC */
+#define E60802_USB11_OTG_REG                      (0x1<<4) /* 4:4 */
+#define E60802_USB20_OTG_REG                      (0x1<<3) /* 3:3 */
+#define E60802_CHGDT_REG                          (0x1<<2) /* 2:2 */
+#define E60802_USB11_REG                          (0x1<<1) /* 1:1 */
+#define E60802_USB20_REG                          (0x1<<0) /* 0:0 */
+
+/* U3D_VERSIONC */
+#define E60802_VERSION_CODE_REGFILE               (0xff<<24) /* 31:24 */
+#define E60802_USB11_VERSION_CODE                 (0xff<<16) /* 23:16 */
+#define E60802_VERSION_CODE_ANA                   (0xff<<8) /* 15:8 */
+#define E60802_VERSION_CODE_DIG                   (0xff<<0) /* 7:0 */
+
+/* U3D_REGFCOM */
+#define E60802_RG_PAGE                            (0xff<<24) /* 31:24 */
+#define E60802_I2C_MODE                           (0x1<<16) /* 16:16 */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/drivers/wdt/mtk_wdt.c b/src/bsp/lk/platform/mediatek/mt6771/drivers/wdt/mtk_wdt.c
new file mode 100644
index 0000000..d2fa1f0
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/drivers/wdt/mtk_wdt.c
@@ -0,0 +1,1146 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+/* Use PMIC common API for PMIC full reset detection */
+#define CFG_APWDT_PMIC_FULL_RST_COMMON_API  1
+
+/* Timestamp for WDT */
+#define CFG_APWDT_DBG_TIMESTAMP             0
+
+#if 0
+#include "typedefs.h"
+#include "platform.h"
+#include "dramc_common.h"
+#include "dramc_register.h"
+#include "dramc_pi_api.h"
+#include "emi_hw.h"
+#include "pmic.h"
+#endif
+
+#include <debug.h>
+#include <reg.h>
+#include <platform/mt_reg_base.h>
+#include <string.h>
+#include <platform/mtk_wdt.h>
+#include <platform/mt_typedefs.h>
+#include <platform/mt_gpt.h>
+
+#if !CFG_APWDT_PMIC_FULL_RST_COMMON_API
+#include "upmu_hw.h"
+#endif
+
+unsigned int g_rgu_status = RE_BOOT_REASON_UNKNOW;
+
+#if 1
+
+static unsigned int timeout;
+static unsigned int rgu_mode;
+
+#if CONFIG_WDT_DBG_TIMESTAMP
+#include "timer.h"
+static ulong time;
+#endif
+
+static bool mtk_wd_CheckNonResetReg2(unsigned int offset)
+{
+    u32 tmp;
+    tmp = readl(MTK_WDT_NONRST_REG2);
+    if (tmp & (1U << offset))
+        return true;
+    else
+        return false;
+}
+
+static void mtk_wd_SetNonResetReg2(unsigned int offset, bool value)
+{
+    u32 reg;
+
+    reg = readl(MTK_WDT_NONRST_REG2);
+    if (value)
+        reg |= (1U << offset);
+    else
+        reg &= ~(1U << offset);
+
+    writel(reg, MTK_WDT_NONRST_REG2);
+}
+
+void set_clr_fastboot_mode(bool flag)
+{
+    if (flag == true)
+        mtk_wd_SetNonResetReg2(0x2, 1);
+    else if (flag == false)
+        mtk_wd_SetNonResetReg2(0x2, 0);
+
+    dprintf(INFO, "set_clr_fastboot_mode\n");
+}
+
+void set_clr_recovery_mode(bool flag)
+{
+    if (flag == true)
+        mtk_wd_SetNonResetReg2(0x1, 1);
+    else if (flag == false)
+        mtk_wd_SetNonResetReg2(0x1, 0);
+
+    dprintf(INFO, "set_clr_recovery_mode\n");
+}
+
+bool check_fastboot_mode(void)
+{
+#if !(CFG_FPGA_PLATFORM)
+    //return mtk_wd_CheckNonResetReg2(0x2);
+	return false;
+#else
+	return false;
+#endif
+}
+
+bool check_recovery_mode(void)
+{
+    return mtk_wd_CheckNonResetReg2(0x1);
+}
+
+static void mtk_wdt_check_last_stage(void)
+{
+	unsigned int reg;
+	unsigned int last_stage;
+
+	/* check reboot source */
+	reg = readl(MTK_WDT_NONRST_REG2);
+
+	printf("rst from: ");
+
+	last_stage = (reg >> MTK_WDT_NONRST2_STAGE_OFS) & RGU_STAGE_MASK;
+
+	if (last_stage == RGU_STAGE_PRELOADER)
+		printf("pl\n");
+	else if (last_stage == RGU_STAGE_LK)
+		printf("lk\n");
+	else if (last_stage == RGU_STAGE_KERNEL)
+		printf("kernel\n");
+	else
+		printf("?\n");
+
+	reg = (reg & ~(RGU_STAGE_MASK << MTK_WDT_NONRST2_LAST_STAGE_OFS)) |
+		(last_stage << MTK_WDT_NONRST2_LAST_STAGE_OFS);
+
+	writel(reg, MTK_WDT_NONRST_REG2);
+}
+
+static void mtk_wdt_mark_stage(unsigned int stage)
+{
+	unsigned int reg = readl(MTK_WDT_NONRST_REG2);
+
+	reg = (reg & ~(RGU_STAGE_MASK << MTK_WDT_NONRST2_STAGE_OFS))
+		| (stage << MTK_WDT_NONRST2_STAGE_OFS);
+
+	writel(reg, MTK_WDT_NONRST_REG2);
+}
+
+static void mtk_wdt_reset_deglitch_enable(void)
+{
+	writel(MTK_WDT_RSTDEG_EN1_KEY, MTK_WDT_RSTDEG_EN1);
+	writel(MTK_WDT_RSTDEG_EN2_KEY |
+		(MTK_WDT_RSTDEG_CLOCK_32K << MTK_WDT_RSTDEG_CLOCK_SELETC_SHIFT) |
+		(MTK_WDT_RSTDEG_LATENCY_230NS_183US << MTK_WDT_RSTDEG_LATENCY_SHIFT),
+		MTK_WDT_RSTDEG_EN2);
+	printf("%s: MTK_WDT_RSTDEG_EN1(%x), MTK_WDT_RSTDEG_EN2(%x)\n", __func__,
+		readl(MTK_WDT_RSTDEG_EN1), readl(MTK_WDT_RSTDEG_EN2));
+}
+
+void mtk_wdt_disable(void)
+{
+	u32 tmp;
+
+	tmp = readl(MTK_WDT_MODE);
+	tmp &= ~MTK_WDT_MODE_ENABLE;		/* disable watchdog */
+	tmp |= (MTK_WDT_MODE_KEY);		 /* need key then write is allowed */
+	writel(tmp, MTK_WDT_MODE);
+}
+
+void mtk_wdt_enable(void)
+{
+	u32 tmp;
+
+	tmp = readl(MTK_WDT_MODE);
+	tmp |= MTK_WDT_MODE_ENABLE;		/* enable watchdog */
+	tmp |= (MTK_WDT_MODE_KEY);		 /* need key then write is allowed */
+	writel(tmp, MTK_WDT_MODE);
+}
+
+static void mtk_wdt_reset(char mode)
+{
+	/* Watchdog Rest */
+	unsigned int wdt_mode_val;
+
+	writel(MTK_WDT_RESTART_KEY, MTK_WDT_RESTART);
+	/*set latch register to 0 before sw reset*/
+	/* writel((MTK_WDT_LENGTH_CTL_KEY | 0x0), MTK_WDT_LATCH_CTL); */
+
+	wdt_mode_val = readl(MTK_WDT_MODE);
+	/* clear autorestart bit: autoretart: 1, bypass power key, 0: not bypass power key */
+#if CFG_USB_AUTO_DETECT
+	wdt_mode_val &= (~MTK_WDT_MODE_AUTO_RESTART);
+#endif
+	/* make sure WDT mode is hw reboot mode, can not config isr mode */
+	wdt_mode_val &= (~(MTK_WDT_MODE_IRQ|MTK_WDT_MODE_DUAL_MODE));
+
+	if (mode) { /* mode != 0 means by pass power key reboot, We using auto_restart bit as by pass power key flag */
+		wdt_mode_val = wdt_mode_val | (MTK_WDT_MODE_KEY|MTK_WDT_MODE_EXTEN|MTK_WDT_MODE_AUTO_RESTART);
+		writel(wdt_mode_val, MTK_WDT_MODE);
+	} else{
+		wdt_mode_val = wdt_mode_val | (MTK_WDT_MODE_KEY|MTK_WDT_MODE_EXTEN);
+		writel(wdt_mode_val, MTK_WDT_MODE);
+	}
+
+	printf("mtk_wdt_reset WDT MODE=%x\n", readl(MTK_WDT_MODE));
+	gpt_busy_wait_us(100);
+	writel(MTK_WDT_SWRST_KEY, MTK_WDT_SWRST);
+}
+
+static unsigned int mtk_wdt_get_status(void)
+{
+	static unsigned int wdt_sta = 0;
+	static unsigned int wdt_sta_handled = 0;
+	unsigned int reg;
+
+	/*
+	 * Note:
+	 * Because WDT_STA register will be cleared after writing WDT_MODE,
+	 * we use a static variable to keep orinigal WDT_STA.
+	 *
+	 * After reset, static varialbe will always be clear to 0,
+	 * so only read WDT_STA when static variable is 0 is OK
+	 *
+	 * Use "wdt_sta_handled" to indicate if WDT_STATUS is preserved.
+	 * Do not use "wdt_sta" as indication because dummy handling will be
+	 * executed in case WDT_STATUS is 0 originally.
+	 */
+	if (wdt_sta_handled == 0) {
+
+		wdt_sta = readl(MTK_WDT_STATUS);
+
+		wdt_sta_handled = 1;
+
+		/* Check if any special flag is in non-reset register */
+		reg = readl(MTK_WDT_NONRST_REG2);
+
+		/* Check SSPM reset flag */
+		if (reg & MTK_WDT_NONRST2_SSPM_RESET) {
+
+			printf("NONRST_REG2: SSPM reset flag found, 0x%x\n", reg);
+
+			wdt_sta = wdt_sta | MTK_WDT_STATUS_SSPM_RST;
+
+			/* clear deliberate SW reset flag */
+			reg = reg & ~(MTK_WDT_NONRST2_SSPM_RESET);
+			writel(reg, MTK_WDT_NONRST_REG2);
+		}
+	}
+
+	return wdt_sta;
+}
+
+static unsigned int mtk_wdt_get_debug_ctl(void)
+{
+	static unsigned int wdt_debug_ctl = 0;
+
+	/*
+	 * Note:
+	 * Because some bits in register DEBUG_CTL will be cleared after
+	 * writing WDT_MODE, we use a static variable to keep original DEBUG_CTL.
+	 *
+	 * Effected Bits:
+	 * 16: ddr_reserve_success
+	 * 18: emi_dcs_success
+	 * 20: dvfsrc_success
+	 */
+	if (wdt_debug_ctl == 0)
+		wdt_debug_ctl = readl(MTK_WDT_DEBUG_CTL);
+
+	return wdt_debug_ctl;
+}
+
+void mtk_wdt_keep_essential_info(void)
+{
+	mtk_wdt_get_status();
+	mtk_wdt_get_debug_ctl();
+}
+
+int mtk_wdt_boot_check(void);
+
+static void mtk_wdt_check_trig_reboot_reason(void)
+{
+	int ret;
+
+	/* check and mark stages */
+	mtk_wdt_check_last_stage();
+
+	mtk_wdt_mark_stage(RGU_STAGE_PRELOADER);
+
+	/* check bypass power key info */
+	ret = mtk_wdt_boot_check();
+
+	printf("bypass pwrkey: ");
+
+	if (ret == WDT_BY_PASS_PWK_REBOOT)
+		printf("set\n");
+	else if (ret == WDT_NORMAL_REBOOT)
+		printf("NOT set\n");
+	else
+		printf("wdt does not trigger rst\n");
+}
+
+static void mtk_wdt_mode_config(BOOL dual_mode_en,
+					BOOL irq,
+					BOOL ext_en,
+					BOOL ext_pol,
+					BOOL wdt_en)
+{
+	unsigned int tmp;
+
+	/* printf(" mtk_wdt_mode_config mode value=%x\n",readl(MTK_WDT_MODE)); */
+	tmp = readl(MTK_WDT_MODE);
+	tmp |= MTK_WDT_MODE_KEY;
+
+	/* Bit 0 : Whether enable watchdog or not */
+	if (wdt_en == TRUE)
+		tmp |= MTK_WDT_MODE_ENABLE;
+	else
+		tmp &= ~MTK_WDT_MODE_ENABLE;
+
+	/* Bit 1 : Configure extern reset signal polarity. */
+	if (ext_pol == TRUE)
+		tmp |= MTK_WDT_MODE_EXT_POL;
+	else
+		tmp &= ~MTK_WDT_MODE_EXT_POL;
+
+	/* Bit 2 : Whether enable external reset signal */
+	if (ext_en == TRUE)
+		tmp |= MTK_WDT_MODE_EXTEN;
+	else
+		tmp &= ~MTK_WDT_MODE_EXTEN;
+
+	/* Bit 3 : Whether generating interrupt instead of reset signal */
+	if (irq == TRUE)
+		tmp |= MTK_WDT_MODE_IRQ;
+	else
+		tmp &= ~MTK_WDT_MODE_IRQ;
+
+	/* Bit 6 : Whether enable debug module reset */
+	if (dual_mode_en == TRUE)
+		tmp |= MTK_WDT_MODE_DUAL_MODE;
+	else
+		tmp &= ~MTK_WDT_MODE_DUAL_MODE;
+
+	/* Bit 4: WDT_Auto_restart, this is a reserved bit, we use it as bypass powerkey flag. */
+	/* Because HW reboot always need reboot to kernel, we set it always. */
+	tmp |= MTK_WDT_MODE_AUTO_RESTART;
+
+	writel(tmp, MTK_WDT_MODE);
+	/* dual_mode(1); //always dual mode */
+	/* mdelay(100); */
+	printf("mtk_wdt_mode_config mode value=%x, tmp:%x\n", readl(MTK_WDT_MODE), tmp);
+
+}
+/* EXPORT_SYMBOL(mtk_wdt_mode_config); */
+
+static void mtk_wdt_set_time_out_value(UINT32 value)
+{
+	/*
+	* TimeOut = BitField 15:5
+	* Key	  = BitField  4:0 = 0x08
+	*/
+
+	/* sec * 32768 / 512 = sec * 64 = sec * 1 << 6 */
+	timeout = (unsigned int)(value * (1 << 6));
+	timeout = timeout << 5;
+	writel((timeout | MTK_WDT_LENGTH_KEY), MTK_WDT_LENGTH);
+}
+
+void mtk_wdt_timestamp_init(void)
+{
+#if CONFIG_WDT_DBG_TIMESTAMP
+	printf("init done! elapsed time: %d ms\n", get_timer(time));
+	time = get_timer(0);
+#endif
+}
+
+void mtk_wdt_timestamp_update(void)
+{
+#if CONFIG_WDT_DBG_TIMESTAMP
+	ulong time_elapse;
+
+	time_elapse = get_timer(time);
+
+	if (time_elapse) {
+		/*
+		 * Since wdt kicking may be very frequency, set threshold to avoid
+		 * lousy message.
+		 *
+		 * Preloader does not reset system while WDT timeout, thus debug message
+		 * shall appear for timeout cases (long elapsed time).
+		 */
+		if (time_elapse > 5)
+			printf("kick wdt! elapsed time: %d ms\n", get_timer(time));
+
+		time = get_timer(0);
+	}
+#endif
+}
+
+void mtk_wdt_restart(void)
+{
+	/* Reset WatchDogTimer's counting value to time out value */
+	/* ie., keepalive() */
+
+	writel(MTK_WDT_RESTART_KEY, MTK_WDT_RESTART);
+
+	mtk_wdt_timestamp_update();
+}
+
+void mtk_wdt_sw_reset(void)
+{
+	printf ("WDT SW RESET\n");
+	mtk_wdt_reset(1);/* NOTE here, this reset will cause by pass power key */
+
+	/* system will reset */
+
+	while (1)
+	{
+		printf ("SW reset happen ...\n");
+	};
+}
+
+static void mtk_wdt_hw_reset(void)
+{
+	printf("WDT_HW_Reset_test\n");
+
+	/* 1. set WDT timeout 1 secs, 1*64*512/32768 = 1sec */
+	mtk_wdt_set_time_out_value(1);
+
+	/* 2. enable WDT debug reset enable, generating irq disable, ext reset disable */
+	/* ext reset signal low, wdt enalbe */
+	mtk_wdt_mode_config(TRUE, FALSE, FALSE, FALSE, TRUE);
+
+	/* 3. reset the watch dog timer to the value set in WDT_LENGTH register */
+	mtk_wdt_restart();
+
+	/* 4. system will reset */
+	while (1);
+}
+
+int mtk_wdt_boot_check(void)
+{
+	unsigned int wdt_sta = mtk_wdt_get_status();
+	int ret = WDT_NOT_WDT_REBOOT;
+
+	/*
+	 * For DA download hope to timeout reboot, and boot to u-boot/kernel configurable reason,
+	 * we set both timeout reboot and software reboot can check whether bypass power key.
+	 */
+	if (wdt_sta & (MTK_WDT_STATUS_HWWDT_RST | MTK_WDT_STATUS_SWWDT_RST |
+		MTK_WDT_STATUS_SPM_THERMAL_RST | MTK_WDT_STATUS_SPMWDT_RST |
+		MTK_WDT_STATUS_THERMAL_DIRECT_RST | MTK_WDT_STATUS_SECURITY_RST |
+		MTK_WDT_STATUS_DEBUGWDT_RST | MTK_WDT_STATUS_EINT_RST |
+		MTK_WDT_STATUS_SYSRST_RST | MTK_WDT_STATUS_DVFSP_RST |
+		MTK_WDT_STATUS_SSPM_RST)) {
+		if (rgu_mode & MTK_WDT_MODE_AUTO_RESTART) {
+
+			/* HW or SW reboot, and auto restart is set, means bypass power key */
+			ret = WDT_BY_PASS_PWK_REBOOT;
+
+		} else {
+
+			/* HW or SW reboot, but auto restart is not set, means NOT bypass power key */
+			ret = WDT_NORMAL_REBOOT;
+		}
+	} else {
+		/*
+		 * For PMIC full reset, return "bypass pwr key reboot" to help AEE works.
+		 * I.e., Prevent entering charger mode.
+		 */
+		if (mtk_wdt_is_pmic_full_reset()) {
+			printf("PMIC full rst: true\n");
+			ret = WDT_BY_PASS_PWK_REBOOT;
+		}
+	}
+
+	return ret;
+}
+
+int mtk_wdt_is_pmic_full_reset(void)
+{
+#if 0
+#if CFG_APWDT_PMIC_FULL_RST_COMMON_API
+
+	unsigned int val;
+
+	/* Use PMIC common API for PMIC full reset detection */
+
+	val = is_pmic_cold_reset();
+
+#else
+
+	static unsigned int val = 0;
+	static unsigned int handled = 0;
+
+	/*
+	 * PMIC common API may be failed in some platforms.
+	 *
+	 * Use a non-volatile register (reset only after battery is removed)
+	 * for PMIC full reset detection.
+	 *
+	 * In such platforms, use bit 0 in register PMIC_RG_RSV_SWREG.
+	 */
+
+	if (!handled) {
+
+		pmic_read_interface(PMIC_RG_RSV_SWREG_ADDR, &val, 0x1, 0);
+
+		if (val)
+			pmic_config_interface(PMIC_RG_RSV_SWREG_ADDR, 0, 0x1, 0);
+
+		printf("PMIC full rst: %d\n", val);
+
+		handled = 1;
+	}
+
+#endif
+
+	return val ? 1 : 0;
+#endif
+	return 0;
+}
+
+void mtk_arch_reset(char mode)
+{
+	printf("mtk_arch_reset at pre-loader!\n");
+
+	/* mtk_wdt_hw_reset(); */
+	mtk_wdt_reset(mode);
+
+	while (1);
+}
+
+int rgu_dram_reserved(int enable)
+{
+	volatile unsigned int tmp = 0, ret = 0;
+
+	/*
+	 * DDR reserved mode may be switched on/off anytime by caller.
+	 *
+	 * DDR reserved mode switch on/off flow will modify register MODE.
+	 * Since register STATUS and some bits in DEBUG_CTL will be reset
+	 * if register MODE has any changes. Keep those register values first
+	 * before register MODE is written later.
+	 */
+	mtk_wdt_keep_essential_info();
+
+	if (enable == 1)
+	{
+		/* enable ddr reserved mode */
+		tmp = readl(MTK_WDT_MODE);
+		tmp |= (MTK_WDT_MODE_DDR_RESERVE|MTK_WDT_MODE_KEY);
+		writel(tmp, MTK_WDT_MODE);
+
+	} else if (enable == 0)
+	{
+		/* disable ddr reserved mode, set reset mode,
+				disable watchdog output reset signal */
+		tmp = readl(MTK_WDT_MODE);
+		tmp &= (~MTK_WDT_MODE_DDR_RESERVE);
+		tmp |= MTK_WDT_MODE_KEY;
+		writel(tmp, MTK_WDT_MODE);
+	} else
+	{
+		printf("Wrong input %d, should be 1(enable) or 0(disable) in %s\n", enable, __func__);
+		ret = -1;
+	}
+	printf("%s: MTK_WDT_MODE(%x)\n", __func__, tmp);
+	return ret;
+}
+
+int rgu_is_reserve_ddr_enabled(void)
+{
+	unsigned int wdt_mode;
+
+	wdt_mode = readl(MTK_WDT_MODE);
+
+	if (wdt_mode & MTK_WDT_MODE_DDR_RESERVE)
+		return 1;
+	else
+		return 0;
+}
+
+int rgu_is_dram_slf(void)
+{
+	unsigned int wdt_dbg_ctrl;
+
+	wdt_dbg_ctrl = readl(MTK_WDT_DEBUG_CTL);
+
+	if (wdt_dbg_ctrl & MTK_DDR_SREF_STA) {
+		printf("DDR is in self-refresh. %x\n", wdt_dbg_ctrl);
+		return 1;
+	} else {
+		printf("DDR is not in self-refresh. %x\n", wdt_dbg_ctrl);
+		return 0;
+	}
+}
+
+int rgu_wait_for_reg_update_done(uint64_t reg_addr, unsigned mask, unsigned target_val)
+{
+	unsigned timeout_ms = 5;
+	unsigned int read_val;
+	unsigned int read_times = 0;
+	unsigned int elapsed_ms = 0;
+
+	while (1) {
+
+		read_val = readl(reg_addr);
+
+		if (target_val == (read_val & mask))
+			break;
+
+		read_times++;
+
+		if (read_times && 0 == (read_times % 100)) {
+
+			mdelay(1);
+			elapsed_ms += 1;
+
+			if (elapsed_ms > timeout_ms) {
+				printf("%s: ERROR! Update reg 0x%x timeout! Mask: 0x%x Target: 0x%x\n",
+				       __func__, reg_addr, mask, target_val);
+
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int rgu_update_reg(uint64_t reg, u32 func, u32 bits)
+{
+	volatile unsigned int val;
+	int ret;
+
+	val = readl(reg);
+
+	if (func == RGU_REG_SET)
+		val |= bits;
+	else if (func == RGU_REG_CLR)
+		val &= (~bits);
+	else
+		return -1;
+
+	/* add unlock key */
+	if (reg == MTK_WDT_DEBUG_CTL)
+		val |= MTK_DEBUG_CTL_KEY;
+	else if (reg == MTK_WDT_DEBUG_CTL2)
+		val |= MTK_DEBUG_CTL2_KEY;
+	else {
+		printf("%s: Invalid! Set bit 0x%x in reg 0x%x fail!\n", __func__,
+			bits, reg);
+		return -1;
+	}
+
+	/* update register */
+	writel(val, reg);
+
+	/* wait until register updating done */
+	if (func == RGU_REG_SET)
+		val = bits;
+	else
+		val = 0;
+
+	/*
+	 * Must ensure waiting-done API has timeout mechanism
+	 * because in some scenarios with security feature toggled,
+	 * below registers will be read-only. Writting operation
+	 * will get timeout here.
+	 *
+	 * DEBUG_CTL / DEBUG_CLT2 / DDR_RESERVE_MODE bit in MODE
+	 */
+	ret = rgu_wait_for_reg_update_done(reg, bits, val);
+
+	printf("%s: %d, bits: 0x%x, addr: 0x%x, val: 0x%x\n", __func__,
+		func, bits, reg, readl(reg));
+
+	return ret;
+}
+
+int rgu_is_reserve_ddr_mode_success(void)
+{
+	unsigned int wdt_dbg_ctrl;
+
+	/*
+	 * MTK_DDR_RESERVE_RTA bit will be reset by modifying register MODE.
+	 * Read DEBUG_CTL value kept by mtk_wdt_get_debug_ctl().
+	 */
+	wdt_dbg_ctrl = mtk_wdt_get_debug_ctl();
+
+	if (wdt_dbg_ctrl & MTK_DDR_RESERVE_RTA) {
+		printf("WDT DDR reserve mode success! %x\n", wdt_dbg_ctrl);
+		return 1;
+	} else {
+		printf("WDT DDR reserve mode FAIL! %x\n", wdt_dbg_ctrl);
+		return 0;
+	}
+}
+
+int rgu_cfg_emi_dcs_en(int enable)
+{
+	int ret;
+
+	if (enable == 1) {
+
+		ret = rgu_update_reg(MTK_WDT_DEBUG_CTL2,
+			RGU_REG_SET, MTK_RGU_EMI_DCS_EN);
+
+	} else if (enable == 0) {
+
+		ret = rgu_update_reg(MTK_WDT_DEBUG_CTL2,
+			RGU_REG_CLR, MTK_RGU_EMI_DCS_EN);
+
+	} else
+		ret = -1;
+
+	return ret;
+}
+
+int rgu_release_rg_dramc_conf_iso(void)
+{
+	int ret;
+	int success;
+
+	ret = rgu_update_reg(MTK_WDT_DEBUG_CTL,
+		RGU_REG_CLR, MTK_RG_CONF_ISO);
+
+	success = rgu_is_reserve_ddr_mode_success();
+
+	printf("DDR RESERVE Success %d\n", success);
+
+	return ret;
+}
+
+int rgu_release_rg_dramc_iso(void)
+{
+	return rgu_update_reg(MTK_WDT_DEBUG_CTL, RGU_REG_CLR, MTK_RG_DRAMC_ISO);
+}
+
+int rgu_release_rg_dramc_sref(void)
+{
+	return rgu_update_reg(MTK_WDT_DEBUG_CTL, RGU_REG_CLR, MTK_RG_DRAMC_SREF);
+}
+
+int rgu_is_emi_dcs_success(void)
+{
+	unsigned int wdt_dbg_ctrl;
+	unsigned int success;
+
+	/*
+	 * MTK_RGU_EMI_DCS_SUCCESS bit will be reset by modifying register MODE.
+	 * Read DEBUG_CTL value kept by mtk_wdt_get_debug_ctl().
+	 */
+	wdt_dbg_ctrl = mtk_wdt_get_debug_ctl();
+
+	success = (wdt_dbg_ctrl & MTK_RGU_EMI_DCS_SUCCESS) >> MTK_RGU_EMI_DCS_SUCCESS_OFFSET;
+
+	printf("EMI_DCS_SUCCESS %d\n", success);
+
+	return success;
+}
+
+int rgu_is_emi_dcs_enable(void)
+{
+	unsigned int reg;
+
+	reg = readl(MTK_WDT_DEBUG_CTL2);
+
+	if (reg & MTK_RGU_EMI_DCS_EN)
+		return 1;
+	else
+		return 0;
+}
+
+int rgu_is_dvfsrc_success(void)
+{
+	unsigned int wdt_dbg_ctrl;
+	unsigned int success;
+
+	/*
+	 * MTK_RGU_EMI_DCS_SUCCESS bit will be reset by modifying register MODE.
+	 * Read DEBUG_CTL value kept by mtk_wdt_get_debug_ctl().
+	 */
+	wdt_dbg_ctrl = mtk_wdt_get_debug_ctl();
+
+	success = (wdt_dbg_ctrl & MTK_RGU_DVFSRC_SUCCESS) >> MTK_RGU_DVFSRC_SUCCESS_OFFSET;
+
+	printf("DVFSRC_SUCCESS %d\n", success);
+
+	return success;
+}
+
+int rgu_is_dvfsrc_enable(void)
+{
+	unsigned int reg;
+
+	reg = readl(MTK_WDT_DEBUG_CTL2);
+
+	if (reg & MTK_RGU_DVFSRC_EN)
+		return 1;
+	else
+		return 0;
+}
+
+void rgu_swsys_reset(WD_SYS_RST_TYPE reset_type)
+{
+	if (reset_type == WD_MD_RST) {
+		unsigned int wdt_dbg_ctrl;
+
+		wdt_dbg_ctrl = readl(MTK_WDT_SWSYSRST);
+		wdt_dbg_ctrl |= MTK_WDT_SWSYS_RST_KEY;
+		wdt_dbg_ctrl |= 0x80; /* 1<<7 */
+		writel(wdt_dbg_ctrl, MTK_WDT_SWSYSRST);
+		udelay(1000);
+		wdt_dbg_ctrl = readl(MTK_WDT_SWSYSRST);
+		wdt_dbg_ctrl |= MTK_WDT_SWSYS_RST_KEY;
+		wdt_dbg_ctrl &= (~0x80); /* ~(1<<7) */
+		writel(wdt_dbg_ctrl, MTK_WDT_SWSYSRST);
+		/* printf("rgu pl md reset\n"); */
+	}
+}
+
+int mtk_wdt_request_en_set(int mark_bit, WD_REQ_CTL en)
+{
+	unsigned int tmp;
+
+	if ((mark_bit != MTK_WDT_STATUS_SSPM_RST) &&
+		(mark_bit != MTK_WDT_STATUS_SYSRST_RST) &&
+		(mark_bit != MTK_WDT_STATUS_EINT_RST) &&
+		(mark_bit != MTK_WDT_STATUS_SPM_THERMAL_RST))
+		return -1;
+
+	tmp = readl(MTK_WDT_REQ_MODE);
+	tmp |= MTK_WDT_REQ_MODE_KEY;
+
+	if (en == WD_REQ_EN)
+		tmp |= (mark_bit);
+	if (en == WD_REQ_DIS)
+		tmp &= ~(mark_bit);
+
+	writel(tmp, MTK_WDT_REQ_MODE);
+
+	return 0;
+}
+
+int mtk_wdt_request_mode_set(int mark_bit, WD_REQ_MODE mode)
+{
+	unsigned int tmp;
+
+	if ((mark_bit != MTK_WDT_STATUS_SSPM_RST) &&
+		(mark_bit != MTK_WDT_STATUS_SYSRST_RST) &&
+		(mark_bit != MTK_WDT_STATUS_EINT_RST) &&
+		(mark_bit != MTK_WDT_STATUS_SPM_THERMAL_RST))
+		return -1;
+
+	tmp = readl(MTK_WDT_REQ_IRQ_EN);
+	tmp |= MTK_WDT_REQ_IRQ_KEY;
+
+	if (mode == WD_REQ_IRQ_MODE)
+		tmp |= (mark_bit);
+	if (mode == WD_REQ_RST_MODE)
+		tmp &= ~(mark_bit);
+
+	writel(tmp, MTK_WDT_REQ_IRQ_EN);
+
+	return 0;
+}
+
+void mtk_wdt_init(void)
+{
+	unsigned wdt_sta;
+	unsigned int wdt_ctrl;
+
+	/*
+	 * Since RGU init flow will modify WDT_MODE which will reset WDT_STA and some bits
+	 * in WDT_DEBUG_CTL, preserve these registers in static global variable first.
+	 */
+	mtk_wdt_keep_essential_info();
+
+	/* Dump RGU regisers */
+	printf("MODE:               0x%x\n", readl(MTK_WDT_MODE));
+	printf("STA:                0x%x\n", mtk_wdt_get_status());
+	printf("LENGTH:             0x%x\n", readl(MTK_WDT_LENGTH));
+	printf("INTERVAL:           0x%x\n", readl(MTK_WDT_INTERVAL));
+	printf("SWSYSRST:           0x%x\n", readl(MTK_WDT_SWSYSRST));
+	printf("LATCH_CTL:          0x%x\n", readl(MTK_WDT_LATCH_CTL));
+	printf("NONRST_REG2:        0x%x\n", readl(MTK_WDT_NONRST_REG2));
+	printf("DEBUG_CTL:          0x%x\n", mtk_wdt_get_debug_ctl());
+
+	wdt_sta = mtk_wdt_get_status();
+
+	rgu_mode = readl(MTK_WDT_MODE);
+
+	if ((wdt_sta & MTK_WDT_STATUS_HWWDT_RST) && (rgu_mode & MTK_WDT_MODE_AUTO_RESTART)) {
+		/* Time out reboot always by pass power key */
+		g_rgu_status = RE_BOOT_BY_WDT_HW;
+	} else if (wdt_sta & MTK_WDT_STATUS_SWWDT_RST)
+		g_rgu_status = RE_BOOT_BY_WDT_SW;
+	else
+		g_rgu_status = RE_BOOT_REASON_UNKNOW;
+
+	if (wdt_sta & MTK_WDT_STATUS_IRQWDT_RST)
+		g_rgu_status |= RE_BOOT_WITH_INTTERUPT;
+
+	if (wdt_sta & MTK_WDT_STATUS_SPM_THERMAL_RST)
+		g_rgu_status |= RE_BOOT_BY_SPM_THERMAL;
+
+	if (wdt_sta & MTK_WDT_STATUS_SPMWDT_RST)
+		g_rgu_status |= RE_BOOT_BY_SPM;
+
+	if (wdt_sta & MTK_WDT_STATUS_THERMAL_DIRECT_RST)
+		g_rgu_status |= RE_BOOT_BY_THERMAL_DIRECT;
+
+	if (wdt_sta & MTK_WDT_STATUS_DEBUGWDT_RST)
+		g_rgu_status |= RE_BOOT_BY_DEBUG;
+
+	if (wdt_sta & MTK_WDT_STATUS_SECURITY_RST)
+		g_rgu_status |= RE_BOOT_BY_SECURITY;
+
+	if (wdt_sta & MTK_WDT_STATUS_SYSRST_RST)
+		g_rgu_status |= RE_BOOT_BY_SYSRST;
+
+	if (wdt_sta & MTK_WDT_STATUS_SSPM_RST)
+		g_rgu_status |= RE_BOOT_BY_SSPM_RST;
+
+	/* SW workaround to avoid EINT_RST be triggered with other RST behavior */
+	if ((wdt_sta & MTK_WDT_STATUS_EINT_RST) && (g_rgu_status == RE_BOOT_REASON_UNKNOW))
+		g_rgu_status |= RE_BOOT_BY_EINT;
+
+	if (mtk_wdt_is_pmic_full_reset())
+		g_rgu_status |= RE_BOOT_BY_PMIC_FULL_RST;
+
+	printf("g_rgu_status: %d (0x%x)\n", g_rgu_status, g_rgu_status);
+
+	mtk_wdt_mode_config(FALSE, FALSE, FALSE, FALSE, FALSE); /* Wirte Mode register will clear status register */
+	mtk_wdt_check_trig_reboot_reason();
+
+	/* Setting timeout 10s */
+	mtk_wdt_set_time_out_value(16);
+
+#if (!CFG_APWDT_DISABLE)
+	/* Config HW reboot mode */
+	mtk_wdt_mode_config(TRUE, TRUE, TRUE, FALSE, TRUE);
+	mtk_wdt_restart();
+#endif
+
+	mtk_wdt_timestamp_init();
+
+	mtk_wdt_reset_deglitch_enable();
+
+	/* Configure WDT_LATCH_CTL */
+
+	wdt_ctrl = readl(MTK_WDT_LATCH_CTL);
+	wdt_ctrl |= MTK_LATCH_CTL_KEY;
+	wdt_ctrl |= MTK_RG_LATH_EN;
+	wdt_ctrl |= MTK_RG_MCU_LATH_EN | MTK_RG_SPM_LATH_EN;
+	wdt_ctrl |= MTK_RG_MPO_EXT_OFF_EN | MTK_RG_GPU_EXT_OFF_EN | MTK_RG_MD_EXT_OFF_EN;
+	wdt_ctrl &= ~(MTK_RG_MCU_LATCH_SELECT | MTK_RG_SPM_LATCH_SELECT);
+	wdt_ctrl |= MTK_RG_DRAMC_LATH_EN;
+	wdt_ctrl |= (MTK_RG_DRAMC_RD_TEST_EN | MTK_RG_DRAMC_RDWT_TEST_EN);
+	writel(wdt_ctrl, MTK_WDT_LATCH_CTL);
+
+	/* Configure WDT_LATCH_CTL2 */
+
+	wdt_ctrl = readl(MTK_WDT_LATCH_CTL2);
+	wdt_ctrl |= MTK_LATCH_CTL2_KEY;
+
+	/* DFD feature */
+	wdt_ctrl |= MTK_RG_MCU_DFD_EN;
+	wdt_ctrl &= ~(MTK_RG_MCU_DFD_TIMEOUT_MASK << MTK_RG_MCU_DFD_TIMEOUT_OFS);
+	wdt_ctrl |= (MTK_RG_MCU_DFD_TIMEOUT_VALUE << MTK_RG_MCU_DFD_TIMEOUT_OFS);
+
+	writel(wdt_ctrl, MTK_WDT_LATCH_CTL2);
+
+	/*
+	 * Configure WDT_DEBUG_CTL
+	 *
+	 * Release DDR reserve mode related control.
+	 *
+	 * Release DCS EN/PAUSE and DVFSRC EN/PAUSE in RGU initialization.
+	 * NOTE: This job must be done earlier than DVS/DVFSRC initialization.
+	 */
+	rgu_update_reg(MTK_WDT_DEBUG_CTL, RGU_REG_CLR,
+		MTK_RGU_EMI_DCS_PAUSE | MTK_RGU_DVFSRC_PAUSE);
+
+	rgu_update_reg(MTK_WDT_DEBUG_CTL2, RGU_REG_CLR,
+		MTK_RGU_EMI_DCS_EN | MTK_RGU_DVFSRC_EN);
+
+	printf("%s: MTK_WDT_DEBUG_CTL(0x%x)\n", __func__,
+		readl(MTK_WDT_DEBUG_CTL));
+
+	printf("%s: MTK_WDT_DEBUG_CTL2(0x%x)\n", __func__,
+		readl(MTK_WDT_DEBUG_CTL2));
+
+	printf("%s: MTK_WDT_LATCH_CTL(0x%x)\n", __func__,
+		readl(MTK_WDT_LATCH_CTL));
+
+	/* disable spm thermal rst */
+	mtk_wdt_request_en_set(MTK_WDT_STATUS_SPM_THERMAL_RST, WD_REQ_DIS);
+	mtk_wdt_request_mode_set(MTK_WDT_STATUS_SPM_THERMAL_RST, WD_REQ_RST_MODE);
+
+	/* disable sysrst */
+	mtk_wdt_request_en_set(MTK_WDT_STATUS_SYSRST_RST, WD_REQ_DIS);
+
+	/* disable irq of sysrst */
+	mtk_wdt_request_mode_set(MTK_WDT_STATUS_SYSRST_RST, WD_REQ_RST_MODE);
+
+	/* disable irq of eint */
+	mtk_wdt_request_mode_set(MTK_WDT_STATUS_EINT_RST, WD_REQ_RST_MODE);
+
+	printf("%s: MTK_WDT_REQ_MODE(%x), MTK_WDT_REQ_IRQ_EN(%x)\n", __func__,
+		readl(MTK_WDT_REQ_MODE), readl(MTK_WDT_REQ_IRQ_EN));
+
+	mtk_wdt_timestamp_update();
+}
+
+#else /* Using dummy WDT functions */
+void mtk_wdt_init(void)
+{
+	printf("PL WDT Dummy init called\n");
+}
+
+void mtk_arch_reset(char mode)
+{
+	printf("PL WDT Dummy arch reset called\n");
+}
+
+int mtk_wdt_boot_check(void)
+{
+	printf("PL WDT Dummy mtk_wdt_boot_check called\n");
+	return 0;
+}
+
+void mtk_wdt_disable(void)
+{
+	printf("UB WDT Dummy mtk_wdt_disable called\n");
+}
+
+void mtk_wdt_restart(void)
+{
+	printf("UB WDT Dummy mtk_wdt_restart called\n");
+}
+
+static void mtk_wdt_sw_reset(void)
+{
+	/* printf("UB WDT Dummy mtk_wdt_sw_reset called\n"); */
+}
+
+static void mtk_wdt_hw_reset(void)
+{
+	printf("UB WDT Dummy mtk_wdt_hw_reset called\n");
+}
+
+int rgu_dram_reserved(int enable)
+{
+	volatile unsigned int ret = 0;
+
+	printf("dummy RGU %s\n", __func__);
+	return ret;
+}
+
+int rgu_is_reserve_ddr_enabled(void)
+{
+	printf("dummy RGU %s\n", __func__);
+	return 0;
+}
+
+int rgu_is_dram_slf(void)
+{
+	printf("dummy RGU %s\n", __func__);
+	return 0;
+}
+
+int rgu_release_rg_dramc_conf_iso(void)
+{
+	printf("dummy RGU %s\n", __func__);
+	return 0;
+}
+
+int rgu_release_rg_dram_setting(void)
+{
+	printf("dummy RGU %s\n", __func__);
+	return 0;
+}
+
+int rgu_release_rg_dramc_iso(void)
+{
+	printf("dummy RGU %s\n", __func__);
+	return 0;
+}
+
+int rgu_release_rg_dramc_sref(void)
+{
+	printf("dummy RGU %s\n", __func__);
+	return 0;
+}
+
+int rgu_is_reserve_ddr_mode_success(void)
+{
+	printf("dummy RGU %s\n", __func__);
+	return 0;
+}
+
+void rgu_swsys_reset(WD_SYS_RST_TYPE reset_type)
+{
+	/* printf("dummy RGU %s\n", __func__); */
+}
+
+int mtk_wdt_request_en_set(int mark_bit, WD_REQ_CTL en)
+{
+	printf("dummy RGU %s\n", __func__);
+	return 0;
+}
+
+int mtk_wdt_request_mode_set(int mark_bit, WD_REQ_MODE mode)
+{
+	printf("dummy RGU %s\n", __func__);
+}
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/addressmap.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/addressmap.h
new file mode 100644
index 0000000..a72e1f8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/addressmap.h
@@ -0,0 +1,32 @@
+
+
+#ifndef __INCLUDE_ADDRESSMAP_H__
+#define __INCLUDE_ADDRESSMAP_H__
+
+#include <platform/mt6771.h>
+
+enum {
+	IO_PHYS		= PERIPHERAL_BASE_VIRT,
+};
+
+enum {
+	MMSYS_BASE		= IO_PHYS + 0x04000000,
+	DISP_OVL0_BASE		= IO_PHYS + 0x04008000,
+	DISP_OVL0_2L_BASE	= IO_PHYS + 0x04009000,
+	DISP_OVL1_2L_BASE	= IO_PHYS + 0x0400A000,
+	DISP_RDMA0_BASE		= IO_PHYS + 0x0400B000,
+	DISP_RDMA1_BASE		= IO_PHYS + 0x0400C000,
+	DISP_WDMA0_BASE		= IO_PHYS + 0x0400D000,
+	DISP_COLOR0_BASE	= IO_PHYS + 0x0400E000,
+	DISP_CCORR0_BASE	= IO_PHYS + 0x0400F000,
+	DISP_AAL0_BASE		= IO_PHYS + 0x04010000,
+	DISP_GAMMA0_BASE	= IO_PHYS + 0x04011000,
+	DISP_DITHER0_BASE	= IO_PHYS + 0x04012000,
+	DSI0_BASE		= IO_PHYS + 0x04014000,
+	DPI0_BASE		= IO_PHYS + 0x04015000,
+	DISP_MUTEX_BASE		= IO_PHYS + 0x04016000,
+	SMI_LARB0		= IO_PHYS + 0x04017000,
+	MIPITX_BASE		= IO_PHYS + 0x01E50000,
+};
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/ddp.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/ddp.h
new file mode 100644
index 0000000..9c41d82
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/ddp.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#ifndef _MT8183_SOC_DDP_H_
+#define _MT8183_SOC_DDP_H_
+
+#include <platform/addressmap.h>
+#include <platform/ddp_common.h>
+#include <sys/types.h>
+
+#define MAIN_PATH_OVL_NR 2
+
+struct mmsys_cfg_regs {
+	u32 reserved_0x000[64];		/* 0x000 */
+	u32 mmsys_cg_con0;		/* 0x100 */
+	u32 mmsys_cg_set0;		/* 0x104 */
+	u32 mmsys_cg_clr0;		/* 0x108 */
+	u32 reserved_0x10C;		/* 0x10C */
+	u32 mmsys_cg_con1;		/* 0x110 */
+	u32 mmsys_cg_set1;		/* 0x114 */
+	u32 mmsys_cg_clr1;		/* 0x118 */
+	u32 reserved_0x11C[889];	/* 0x11C */
+	u32 disp_ovl0_mout_en;		/* 0xF00 */
+	u32 disp_ovl0_2l_mout_en;	/* 0xF04 */
+	u32 disp_ovl1_2l_mout_en;	/* 0xF08 */
+	u32 disp_dither0_mout_en;	/* 0xF0C */
+	u32 reserved_0xF10[5];		/* 0xF10 - 0xF20 */
+	u32 disp_path0_sel_in;		/* 0xF24 */
+	u32 reserved_0xF28;		/* 0xF28 */
+	u32 dsi0_sel_in;		/* 0xF2C */
+	u32 dpi0_sel_in;		/* 0xF30 */
+	u32 reserved_0xF34;		/* 0xF34 */
+	u32 disp_ovl0_2l_sel_in;	/* 0xF38 */
+	u32 reserved_0xF3C[5];		/* 0xF3C - 0xF4C */
+	u32 disp_rdma0_sout_sel_in;	/* 0xF50 */
+	u32 disp_rdma1_sout_sel_in;	/* 0xF54 */
+	u32 reserved_0xF58[3];		/* 0xF58 - 0xF60 */
+	u32 dpi0_sel_sout_sel_in;	/* 0xF64 */
+};
+
+check_member(mmsys_cfg_regs, mmsys_cg_con0, 0x100);
+check_member(mmsys_cfg_regs, dpi0_sel_sout_sel_in, 0xF64);
+static struct mmsys_cfg_regs *const mmsys_cfg =
+	(void *)MMSYS_BASE;
+
+
+/* DISP_REG_CONFIG_MMSYS_CG_CON0
+   Configures free-run clock gating 0
+	0: Enable clock
+	1: Clock gating  */
+enum {
+	CG_CON0_SMI_COMMON	= BIT(0),
+	CG_CON0_SMI_LARB0	= BIT(1),
+	CG_CON0_GALS_COMMON0	= BIT(3),
+	CG_CON0_GALS_COMMON1	= BIT(4),
+	CG_CON0_DISP_OVL0	= BIT(20),
+	CG_CON0_DISP_OVL0_2L	= BIT(21),
+	CG_CON0_DISP_OVL1_2L	= BIT(22),
+	CG_CON0_DISP_RDMA0	= BIT(23),
+	CG_CON0_DISP_RDMA1	= BIT(24),
+	CG_CON0_DISP_WDMA0	= BIT(25),
+	CG_CON0_DISP_COLOR0	= BIT(26),
+	CG_CON0_DISP_CCORR0	= BIT(27),
+	CG_CON0_DISP_AAL0	= BIT(28),
+	CG_CON0_DISP_GAMMA0	= BIT(29),
+	CG_CON0_DISP_DITHER0	= BIT(30),
+	CG_CON0_DISP_ALL	= CG_CON0_SMI_COMMON |
+				  CG_CON0_SMI_LARB0 |
+				  CG_CON0_GALS_COMMON0 |
+				  CG_CON0_GALS_COMMON1 |
+				  CG_CON0_DISP_OVL0 |
+				  CG_CON0_DISP_OVL0_2L |
+				  CG_CON0_DISP_RDMA0 |
+				  CG_CON0_DISP_COLOR0 |
+				  CG_CON0_DISP_CCORR0 |
+				  CG_CON0_DISP_AAL0 |
+				  CG_CON0_DISP_DITHER0 |
+				  CG_CON0_DISP_GAMMA0,
+	CG_CON0_ALL		= 0xffffffff
+};
+
+/* DISP_REG_CONFIG_MMSYS_CG_CON1
+   Configures free-run clock gating 1
+	0: Enable clock
+	1: Clock gating */
+enum {
+	CG_CON1_DISP_DSI0		= BIT(0),
+	CG_CON1_DISP_DSI0_INTERFACE	= BIT(1),
+	CG_CON1_DISP_DPI0		= BIT(2),
+	CG_CON1_DISP_DPI0_INTERFACE	= BIT(3),
+	CG_CON1_DISP_26M		= BIT(7),
+
+	CG_CON1_DISP_ALL		= 0xffffffff
+};
+
+enum {
+	OVL0_MOUT_EN_RDMA0		= BIT(0),
+	OVL0_MOUT_EN_OVL0_2L		= BIT(4),
+	OVL0_2L_MOUT_EN_DISP_PATH0	= BIT(0),
+	OVL1_2L_MOUT_EN_DISP_RDMA1	= BIT(4),
+	DITHER0_MOUT_EN_DISP_DSI0	= BIT(0),
+	DITHER0_MOUT_EN_DISP_DPI0	= BIT(2),
+};
+
+enum {
+	DISP_PATH0_SEL_IN_OVL0		= 0,
+	DISP_PATH0_SEL_IN_OVL0_2L	= 1,
+	DSI0_SEL_IN_DITHER0_MOUT	= 0,
+	DSI0_SEL_IN_RDMA0		= 1,
+	DPI0_SEL_IN_DITHER0_MOUT	= 3,
+	RDMA0_SOUT_SEL_IN_DSI0		= 0,
+	RDMA0_SOUT_SEL_IN_COLOR		= 1,
+};
+
+struct disp_mutex_regs {
+	u32 inten;
+	u32 intsta;
+	u32 reserved0[6];
+	struct {
+		u32 en;
+		u32 dummy;
+		u32 rst;
+		u32 ctl;
+		u32 mod;
+		u32 reserved[3];
+	} mutex[12];
+};
+
+static struct disp_mutex_regs *const disp_mutex = (void *)DISP_MUTEX_BASE;
+
+enum {
+	MUTEX_MOD_DISP_RDMA0	= BIT(0),
+	MUTEX_MOD_DISP_RDMA1	= BIT(1),
+	MUTEX_MOD_DISP_OVL0	= BIT(9),
+	MUTEX_MOD_DISP_OVL0_2L	= BIT(10),
+	MUTEX_MOD_DISP_OVL1_2L	= BIT(11),
+	MUTEX_MOD_DISP_WDMA0	= BIT(12),
+	MUTEX_MOD_DISP_COLOR0	= BIT(13),
+	MUTEX_MOD_DISP_CCORR0	= BIT(14),
+	MUTEX_MOD_DISP_AAL0	= BIT(15),
+	MUTEX_MOD_DISP_GAMMA0	= BIT(16),
+	MUTEX_MOD_DISP_DITHER0	= BIT(17),
+	MUTEX_MOD_DISP_PWM0	= BIT(28),
+	MUTEX_MOD_MAIN_PATH	= MUTEX_MOD_DISP_OVL0 | MUTEX_MOD_DISP_OVL0_2L |
+				  MUTEX_MOD_DISP_RDMA0 | MUTEX_MOD_DISP_COLOR0 |
+				  MUTEX_MOD_DISP_CCORR0 | MUTEX_MOD_DISP_AAL0 |
+				  MUTEX_MOD_DISP_GAMMA0 |
+				  MUTEX_MOD_DISP_DITHER0,
+};
+
+enum {
+	MUTEX_SOF_SINGLE_MODE = 0,
+	MUTEX_SOF_DSI0 = 1,
+	MUTEX_SOF_DPI0 = 2,
+};
+
+struct disp_pq_regs {
+	u32 en;
+	u32 reset;
+	u32 inten;
+	u32 intsta;
+	u32 status;
+	u32 reserved0[3];
+	u32 cfg;
+	u32 reserved1[3];
+	u32 size;
+};
+
+enum {
+	PQ_EN		= BIT(0),
+	PQ_RELAY_MODE	= BIT(0),
+};
+
+static struct disp_pq_regs *const disp_ccorr = (void *)DISP_CCORR0_BASE;
+
+static struct disp_pq_regs *const disp_aal = (void *)DISP_AAL0_BASE;
+
+static struct disp_pq_regs *const disp_gamma = (void *)DISP_GAMMA0_BASE;
+
+static struct disp_pq_regs *const disp_dither = (void *)DISP_DITHER0_BASE;
+
+enum {
+	SMI_LARB_NON_SEC_CON	= 0x380,
+};
+
+void mtk_ddp_init(void);
+void mtk_ddp_mode_set(u32 width, u32 height, u32 addr);
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/ddp_common.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/ddp_common.h
new file mode 100644
index 0000000..8113838
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/ddp_common.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#ifndef _DDP_COMMON_H_
+#define _DDP_COMMON_H_
+
+#include <platform/addressmap.h>
+#include <sys/types.h>
+#include <platform/mm_common.h>
+
+
+struct disp_ovl_regs {
+	u32 sta;
+	u32 inten;
+	u32 intsta;
+	u32 en;
+	u32 trig;
+	u32 rst;
+	u8 reserved0[8];
+	u32 roi_size;
+	u32 datapath_con;
+	u32 roi_bgclr;
+	u32 src_con;
+	struct {
+		u32 con;
+		u32 srckey;
+		u32 src_size;
+		u32 offset;
+		u32 reserved0;
+		u32 pitch;
+		u32 reserved1[2];
+	} layer[4];
+	u8 reserved8[16];
+	struct {
+		u32 ctrl;
+		u32 mem_start_trig;
+		u32 mem_gmc_setting;
+		u32 mem_slow_con;
+		u32 fifo_ctrl;
+		u8 reserved[12];
+	} rdma[4];
+	u8 reserved12[148];
+	u32 debug_mon_sel;
+	u8 reserved13[8];
+	u32 rdma_mem_gmc_setting2[4];
+	u8 reserved14[16];
+	u32 dummy;
+	u8 reserved15[60];
+	u32 flow_ctrl_dbg;
+	u32 addcon_dbg;
+	u32 outmux_dbg;
+	u32 rdma_dbg[4];
+	u8 reserved16[3300];
+	u32 l0_addr;
+	u8 reserved17[28];
+	u32 l1_addr;
+	u8 reserved18[28];
+	u32 l2_addr;
+	u8 reserved19[28];
+	u32 l3_addr;
+};
+
+static struct disp_ovl_regs *const disp_ovl[2] = {
+	(void *)DISP_OVL0_BASE,(void *)DISP_OVL0_2L_BASE
+};
+
+struct disp_rdma_regs {
+	u32 int_enable;
+	u32 int_status;
+	u8 reserved0[8];
+	u32 global_con;
+	u32 size_con_0;
+	u32 size_con_1;
+	u32 target_line;
+	u8 reserved1[4];
+	u32 mem_con;
+	u32 mem_start_addr;
+	u32 mem_src_pitch;
+	u32 mem_gmc_setting_0;
+	u32 mem_slow_con;
+	u32 mem_gmc_setting_1;
+	u8 reserved2[4];
+	u32 fifo_con;
+	u8 reserved3[16];
+	u32 cf[3][3];
+	u32 cf_pre_add[3];
+	u32 cf_post_add[3];
+	u32 dummy;
+	u32 debug_out_sel;
+};
+
+enum {
+	RDMA_ENGINE_EN		= BIT(0),
+	RDMA_FIFO_UNDERFLOW_EN	= BIT(31),
+	RDMA_MEM_GMC = 0x40402020,
+};
+
+static struct disp_rdma_regs *const disp_rdma0 = (void *)DISP_RDMA0_BASE;
+
+struct disp_color_regs {
+	u8 reserved0[1024];
+	u32 cfg_main;
+	u8 reserved1[2044];
+	u32 start;
+	u8 reserved2[76];
+	u32 width;
+	u32 height;
+};
+
+
+static struct disp_color_regs *const disp_color0 = (void *)DISP_COLOR0_BASE;
+
+
+enum {
+	COLOR_BYPASS_ALL = BIT(7),
+	COLOR_SEQ_SEL    = BIT(13),
+};
+
+enum OVL_INPUT_FORMAT {
+	OVL_INFMT_RGB565 = 0,
+	OVL_INFMT_RGB888 = 1,
+	OVL_INFMT_RGBA8888 = 2,
+	OVL_INFMT_ARGB8888 = 3,
+	OVL_INFMT_UYVY = 4,
+	OVL_INFMT_YUYV = 5,
+	OVL_INFMT_UNKNOWN = 16,
+
+	OVL_COLOR_BASE = 30,
+	OVL_INFMT_BGR565 = OVL_INFMT_RGB565 + OVL_COLOR_BASE,
+	OVL_INFMT_BGR888 = OVL_INFMT_RGB888 + OVL_COLOR_BASE,
+	OVL_INFMT_BGRA8888 = OVL_INFMT_RGBA8888 + OVL_COLOR_BASE,
+	OVL_INFMT_ABGR8888 = OVL_INFMT_ARGB8888 + OVL_COLOR_BASE,
+};
+
+void ovl_set_roi(u32 idx, u32 width, u32 height, u32 color);
+void rdma_start(void);
+void rdma_config(u32 width, u32 height, u32 pixel_clk, u32 fifo_size);
+void color_start(u32 width, u32 height);
+void ovl_layer_config(u32 fmt, u32 bpp, u32 width, u32 height, u32 addr);
+void ovl_enable(u32 idx);
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/ddp_debug.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/ddp_debug.h
new file mode 100644
index 0000000..effcfb6
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/ddp_debug.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#ifndef __DDP_DEBUG_H__
+#define __DDP_DEBUG_H__
+
+#include <debug.h>
+
+#if 1
+#define ddp_log(fmt, args...) dprintf(CRITICAL, "%s "fmt, __func__, ##args)
+
+#define ddp_func() ddp_log("\n")
+#endif
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/disp.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/disp.h
new file mode 100644
index 0000000..061ce6f
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/disp.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#ifndef DISP_H
+#define DISP_H
+
+#define LOGO_ENABLE 0
+
+#if LOGO_ENABLE
+extern unsigned int logo_128x160[];
+#endif
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/dsi.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/dsi.h
new file mode 100644
index 0000000..af8a308
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/dsi.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#ifndef _DSI_REG_H_
+#define _DSI_REG_H_
+
+#include <platform/dsi_common.h>
+
+/* MIPITX_REG */
+#define MTK_DSI_MIPI_RATIO_NUMERATOR 100
+#define MTK_DSI_MIPI_RATIO_DENOMINATOR 100
+#define MTK_DSI_DATA_RATE_MIN_MHZ 125
+#define MTK_DSI_HAVE_SIZE_CON 1
+#define PIXEL_STREAM_CUSTOM_HEADER 0xb
+
+/* MIPITX is SOC specific and cannot live in common. */
+
+/* MIPITX_REG */
+struct mipi_tx_regs {
+	u32 reserved0[3];
+	u32 lane_con;
+	u32 reserved1[6];
+	u32 pll_pwr;
+	u32 pll_con0;
+	u32 pll_con1;
+	u32 pll_con2;
+	u32 pll_con3;
+	u32 pll_con4;
+	u32 reserved2[65];
+	u32 d2_sw_ctl_en;
+	u32 reserved3[63];
+	u32 d0_sw_ctl_en;
+	u32 reserved4[56];
+	u32 ck_ckmode_en;
+	u32 reserved5[6];
+	u32 ck_sw_ctl_en;
+	u32 reserved6[63];
+	u32 d1_sw_ctl_en;
+	u32 reserved7[63];
+	u32 d3_sw_ctl_en;
+};
+
+check_member(mipi_tx_regs, pll_con4, 0x3c);
+check_member(mipi_tx_regs, d3_sw_ctl_en, 0x544);
+static struct mipi_tx_regs *const mipi_tx = (void *)MIPITX_BASE;
+
+/* Register values */
+#define DSI_CK_CKMODE_EN	BIT(0)
+#define DSI_SW_CTL_EN		BIT(0)
+#define AD_DSI_PLL_SDM_PWR_ON	BIT(0)
+#define AD_DSI_PLL_SDM_ISO_EN	BIT(1)
+
+#define RG_DSI_PLL_EN		BIT(4)
+#define RG_DSI_PLL_POSDIV	(0x7 << 8)
+
+/* SOC specific functions */
+void mtk_dsi_pin_drv_ctrl(void);
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/dsi_common.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/dsi_common.h
new file mode 100644
index 0000000..7db2be3
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/dsi_common.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#ifndef SOC_MEDIATEK_DSI_COMMON_H
+#define SOC_MEDIATEK_DSI_COMMON_H
+
+#include <sys/types.h>
+#include <platform/addressmap.h>
+#include <platform/mm_common.h>
+
+enum mipi_dsi_pixel_format {
+	MIPI_DSI_FMT_RGB888,
+	MIPI_DSI_FMT_RGB666,
+	MIPI_DSI_FMT_RGB666_PACKED,
+	MIPI_DSI_FMT_RGB565
+};
+
+/* video mode */
+enum {
+	MIPI_DSI_MODE_VIDEO = BIT(0),
+	/* video burst mode */
+	MIPI_DSI_MODE_VIDEO_BURST = BIT(1),
+	/* video pulse mode */
+	MIPI_DSI_MODE_VIDEO_SYNC_PULSE = BIT(2),
+	/* enable auto vertical count mode */
+	MIPI_DSI_MODE_VIDEO_AUTO_VERT = BIT(3),
+	/* enable hsync-end packets in vsync-pulse and v-porch area */
+	MIPI_DSI_MODE_VIDEO_HSE = BIT(4),
+	/* disable hfront-porch area */
+	MIPI_DSI_MODE_VIDEO_HFP = BIT(5),
+	/* disable hback-porch area */
+	MIPI_DSI_MODE_VIDEO_HBP = BIT(6),
+	/* disable hsync-active area */
+	MIPI_DSI_MODE_VIDEO_HSA = BIT(7),
+	/* flush display FIFO on vsync pulse */
+	MIPI_DSI_MODE_VSYNC_FLUSH = BIT(8),
+	/* disable EoT packets in HS mode */
+	MIPI_DSI_MODE_EOT_PACKET = BIT(9),
+	/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
+	MIPI_DSI_CLOCK_NON_CONTINUOUS = BIT(10),
+	/* transmit data in low power */
+	MIPI_DSI_MODE_LPM = BIT(11)
+};
+
+struct videomode {
+	u64 pixelclock;	/* pixelclock in KHz */
+
+	u32 hactive;
+	u32 hfront_porch;
+	u32 hback_porch;
+	u32 hsync_len;
+
+	u32 vactive;
+	u32 vfront_porch;
+	u32 vback_porch;
+	u32 vsync_len;
+	u32 vrefresh;
+};
+
+struct dsi_regs {
+	u32 dsi_start;
+	u8 reserved0[4];
+	u32 dsi_inten;
+	u32 dsi_intsta;
+	u32 dsi_con_ctrl;
+	u32 dsi_mode_ctrl;
+	u32 dsi_txrx_ctrl;
+	u32 dsi_psctrl;
+	u32 dsi_vsa_nl;
+	u32 dsi_vbp_nl;
+	u32 dsi_vfp_nl;
+	u32 dsi_vact_nl;
+	u32 dsi_lfr_con;  /* Available since MT8183 */
+	u32 dsi_lfr_sta;  /* Available since MT8183 */
+	u32 dsi_size_con;  /* Available since MT8183 */
+	u32 dsi_vfp_early_stop;  /* Available since MT8183 */
+	u32 reserved1[4];
+	u32 dsi_hsa_wc;
+	u32 dsi_hbp_wc;
+	u32 dsi_hfp_wc;
+	u32 dsi_bllp_wc;
+	u32 dsi_cmdq_size;
+	u32 dsi_hstx_cklp_wc;
+	u8 reserved2[156];
+	u32 dsi_phy_lccon;
+	u32 dsi_phy_ld0con;
+	u8 reserved3[4];
+	u32 dsi_phy_timecon0;
+	u32 dsi_phy_timecon1;
+	u32 dsi_phy_timecon2;
+	u32 dsi_phy_timecon3;
+	u8 reserved4[16];
+	u32 dsi_vm_cmd_con;
+	u8 reserved5[92];
+	u32 dsi_force_commit;  /* Available since MT8183 */
+	u8 reserved6[108];
+	u32 dsi_cmdq[128];
+};
+static struct dsi_regs *const dsi0 = (void *)DSI0_BASE;
+
+check_member(dsi_regs, dsi_phy_lccon, 0x104);
+check_member(dsi_regs, dsi_phy_timecon3, 0x11c);
+check_member(dsi_regs, dsi_vm_cmd_con, 0x130);
+check_member(dsi_regs, dsi_force_commit, 0x190);
+check_member(dsi_regs, dsi_cmdq, 0x200);
+
+/* DSI_INTSTA */
+enum {
+	LPRX_RD_RDY_INT_FLAG = BIT(0),
+	CMD_DONE_INT_FLAG    = BIT(1),
+	TE_RDY_INT_FLAG      = BIT(2),
+	VM_DONE_INT_FLAG     = BIT(3),
+	EXT_TE_RDY_INT_FLAG  = BIT(4),
+	DSI_BUSY             = BIT(31),
+};
+
+/* DSI_CON_CTRL */
+enum {
+	DSI_RESET = BIT(0),
+	DSI_EN = BIT(1),
+	DPHY_RESET = BIT(2),
+	DSI_DUAL = BIT(4),
+};
+
+/* DSI_MODE_CTRL */
+enum {
+	MODE = 3,
+	CMD_MODE = 0,
+	SYNC_PULSE_MODE = 1,
+	SYNC_EVENT_MODE = 2,
+	BURST_MODE = 3,
+	FRM_MODE = BIT(16),
+	MIX_MODE = BIT(17)
+};
+
+/* DSI_PSCTRL */
+enum {
+	DSI_PS_WC = 0x3fff,
+	DSI_PS_SEL = (3 << 16),
+	PACKED_PS_16BIT_RGB565 = (0 << 16),
+	LOOSELY_PS_18BIT_RGB666 = (1 << 16),
+	PACKED_PS_18BIT_RGB666 = (2 << 16),
+	PACKED_PS_24BIT_RGB888 = (3 << 16),
+
+	DSI_PSCON_CUSTOM_HEADER_SHIFT = 26,
+};
+
+/* DSI_SIZE_CON */
+enum {
+	DSI_SIZE_CON_HEIGHT_SHIFT = 16,
+	DSI_SIZE_CON_WIDTH_SHIFT = 0,
+};
+
+/* DSI_CMDQ_SIZE */
+enum {
+	CMDQ_SIZE = 0x3f,
+};
+
+/* DSI_PHY_LCCON */
+enum {
+	LC_HS_TX_EN = BIT(0),
+	LC_ULPM_EN = BIT(1),
+	LC_WAKEUP_EN = BIT(2)
+};
+
+/*DSI_PHY_LD0CON */
+enum {
+	LD0_RM_TRIG_EN = BIT(0),
+	LD0_ULPM_EN = BIT(1),
+	LD0_WAKEUP_EN = BIT(2)
+};
+
+enum {
+	LPX = (0xff << 0),
+	HS_PRPR = (0xff << 8),
+	HS_ZERO = (0xff << 16),
+	HS_TRAIL = (0xff << 24)
+};
+
+enum {
+	TA_GO = (0xff << 0),
+	TA_SURE = (0xff << 8),
+	TA_GET = (0xff << 16),
+	DA_HS_EXIT = (0xff << 24)
+};
+
+enum {
+	CONT_DET = (0xff << 0),
+	CLK_ZERO = (0xf << 16),
+	CLK_TRAIL = (0xff << 24)
+};
+
+enum {
+	CLK_HS_PRPR = (0xff << 0),
+	CLK_HS_POST = (0xff << 8),
+	CLK_HS_EXIT = (0xf << 16)
+};
+
+/* DSI_VM_CMD_CON */
+enum {
+	VM_CMD_EN = BIT(0),
+	TS_VFP_EN = BIT(5),
+};
+
+/* DSI_CMDQ0 */
+enum {
+	CONFIG         = (0xff << 0),
+	SHORT_PACKET   = 0,
+	LONG_PACKET    = 2,
+	BTA            = BIT(2),
+	DATA_ID        = (0xff << 8),
+	DATA_0         = (0xff << 16),
+	DATA_1         = (0xff << 24),
+};
+
+/* DSI_FORCE_COMMIT */
+enum {
+	DSI_FORCE_COMMIT_USE_MMSYS = BIT(0),
+	DSI_FORCE_COMMIT_ALWAYS = BIT(1),
+};
+
+/* MIPI DSI Processor-to-Peripheral transaction types */
+enum {
+	MIPI_DSI_V_SYNC_START				= 0x01,
+	MIPI_DSI_V_SYNC_END				= 0x11,
+	MIPI_DSI_H_SYNC_START				= 0x21,
+	MIPI_DSI_H_SYNC_END				= 0x31,
+
+	MIPI_DSI_COLOR_MODE_OFF				= 0x02,
+	MIPI_DSI_COLOR_MODE_ON				= 0x12,
+	MIPI_DSI_SHUTDOWN_PERIPHERAL			= 0x22,
+	MIPI_DSI_TURN_ON_PERIPHERAL			= 0x32,
+
+	MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM		= 0x03,
+	MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM		= 0x13,
+	MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM		= 0x23,
+
+	MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM		= 0x04,
+	MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM		= 0x14,
+	MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM		= 0x24,
+
+	MIPI_DSI_DCS_SHORT_WRITE			= 0x05,
+	MIPI_DSI_DCS_SHORT_WRITE_PARAM			= 0x15,
+
+	MIPI_DSI_DCS_READ				= 0x06,
+
+	MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE		= 0x37,
+
+	MIPI_DSI_END_OF_TRANSMISSION			= 0x08,
+
+	MIPI_DSI_NULL_PACKET				= 0x09,
+	MIPI_DSI_BLANKING_PACKET			= 0x19,
+	MIPI_DSI_GENERIC_LONG_WRITE			= 0x29,
+	MIPI_DSI_DCS_LONG_WRITE				= 0x39,
+
+	MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20	= 0x0c,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24		= 0x1c,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16		= 0x2c,
+
+	MIPI_DSI_PACKED_PIXEL_STREAM_30			= 0x0d,
+	MIPI_DSI_PACKED_PIXEL_STREAM_36			= 0x1d,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12		= 0x3d,
+
+	MIPI_DSI_PACKED_PIXEL_STREAM_16			= 0x0e,
+	MIPI_DSI_PACKED_PIXEL_STREAM_18			= 0x1e,
+	MIPI_DSI_PIXEL_STREAM_3BYTE_18			= 0x2e,
+	MIPI_DSI_PACKED_PIXEL_STREAM_24			= 0x3e,
+};
+
+/* MIPI DSI Peripheral-to-Processor transaction types */
+enum {
+	MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT	= 0x02,
+	MIPI_DSI_RX_END_OF_TRANSMISSION			= 0x08,
+	MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE	= 0x11,
+	MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE	= 0x12,
+	MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE		= 0x1a,
+	MIPI_DSI_RX_DCS_LONG_READ_RESPONSE		= 0x1c,
+	MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE	= 0x21,
+	MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE	= 0x22,
+};
+
+/* MIPI DCS commands */
+enum {
+	MIPI_DCS_NOP			= 0x00,
+	MIPI_DCS_SOFT_RESET		= 0x01,
+	MIPI_DCS_GET_DISPLAY_ID		= 0x04,
+	MIPI_DCS_GET_RED_CHANNEL	= 0x06,
+	MIPI_DCS_GET_GREEN_CHANNEL	= 0x07,
+	MIPI_DCS_GET_BLUE_CHANNEL	= 0x08,
+	MIPI_DCS_GET_DISPLAY_STATUS	= 0x09,
+	MIPI_DCS_GET_POWER_MODE		= 0x0A,
+	MIPI_DCS_GET_ADDRESS_MODE	= 0x0B,
+	MIPI_DCS_GET_PIXEL_FORMAT	= 0x0C,
+	MIPI_DCS_GET_DISPLAY_MODE	= 0x0D,
+	MIPI_DCS_GET_SIGNAL_MODE	= 0x0E,
+	MIPI_DCS_GET_DIAGNOSTIC_RESULT	= 0x0F,
+	MIPI_DCS_ENTER_SLEEP_MODE	= 0x10,
+	MIPI_DCS_EXIT_SLEEP_MODE	= 0x11,
+	MIPI_DCS_ENTER_PARTIAL_MODE	= 0x12,
+	MIPI_DCS_ENTER_NORMAL_MODE	= 0x13,
+	MIPI_DCS_EXIT_INVERT_MODE	= 0x20,
+	MIPI_DCS_ENTER_INVERT_MODE	= 0x21,
+	MIPI_DCS_SET_GAMMA_CURVE	= 0x26,
+	MIPI_DCS_SET_DISPLAY_OFF	= 0x28,
+	MIPI_DCS_SET_DISPLAY_ON		= 0x29,
+	MIPI_DCS_SET_COLUMN_ADDRESS	= 0x2A,
+	MIPI_DCS_SET_PAGE_ADDRESS	= 0x2B,
+	MIPI_DCS_WRITE_MEMORY_START	= 0x2C,
+	MIPI_DCS_WRITE_LUT		= 0x2D,
+	MIPI_DCS_READ_MEMORY_START	= 0x2E,
+	MIPI_DCS_SET_PARTIAL_AREA	= 0x30,
+	MIPI_DCS_SET_SCROLL_AREA	= 0x33,
+	MIPI_DCS_SET_TEAR_OFF		= 0x34,
+	MIPI_DCS_SET_TEAR_ON		= 0x35,
+	MIPI_DCS_SET_ADDRESS_MODE	= 0x36,
+	MIPI_DCS_SET_SCROLL_START	= 0x37,
+	MIPI_DCS_EXIT_IDLE_MODE		= 0x38,
+	MIPI_DCS_ENTER_IDLE_MODE	= 0x39,
+	MIPI_DCS_SET_PIXEL_FORMAT	= 0x3A,
+	MIPI_DCS_WRITE_MEMORY_CONTINUE	= 0x3C,
+	MIPI_DCS_READ_MEMORY_CONTINUE	= 0x3E,
+	MIPI_DCS_SET_TEAR_SCANLINE	= 0x44,
+	MIPI_DCS_GET_SCANLINE		= 0x45,
+	MIPI_DCS_READ_DDB_START		= 0xA1,
+	MIPI_DCS_READ_DDB_CONTINUE	= 0xA8,
+};
+
+struct mtk_phy_timing {
+	u8 lpx;
+	u8 da_hs_prepare;
+	u8 da_hs_zero;
+	u8 da_hs_trail;
+
+	u8 ta_go;
+	u8 ta_sure;
+	u8 ta_get;
+	u8 da_hs_exit;
+
+	u8 da_hs_sync;
+	u8 clk_hs_zero;
+	u8 clk_hs_trail;
+
+	u8 clk_hs_prepare;
+	u8 clk_hs_post;
+	u8 clk_hs_exit;
+
+	u32 d_phy;
+};
+
+/* Definitions for cmd in lcm_init_command */
+#define LCM_END_CMD 0
+#define LCM_DELAY_CMD 1
+#define LCM_GENERIC_CMD 2
+#define LCM_DCS_CMD 3
+#define DIV_ROUND_UP(x,y) (((x) + ((y) - 1)) / (y))
+
+struct lcm_init_command {
+	u8 cmd;
+	u8 len;
+	u8 data[];
+};
+
+/* Functions that each SOC should provide. */
+void mtk_dsi_reset(void);
+void mtk_dsi_configure_mipi_tx(int data_rate, u32 lanes);
+
+/* Functions as weak no-ops that can be overridden. */
+void mtk_dsi_override_phy_timing(struct mtk_phy_timing *timing);
+
+/* Public API provided in common/dsi.c */
+int mtk_dsi_bpp_from_format(u32 format);
+int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, struct videomode *vm,
+		 const u8 *init_commands);
+
+#endif /* SOC_MEDIATEK_DSI_COMMON_H */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/generic_ioctl.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/generic_ioctl.h
new file mode 100644
index 0000000..84c2ec8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/generic_ioctl.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_ASM_GENERIC_IOCTL_H
+#define _UAPI_ASM_GENERIC_IOCTL_H
+#define _IOC_NRBITS 8
+#define _IOC_TYPEBITS 8
+#ifndef _IOC_SIZEBITS
+#define _IOC_SIZEBITS 14
+#endif
+#ifndef _IOC_DIRBITS
+#define _IOC_DIRBITS 2
+#endif
+#define _IOC_NRMASK ((1 << _IOC_NRBITS) - 1)
+#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS) - 1)
+#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS) - 1)
+#define _IOC_DIRMASK ((1 << _IOC_DIRBITS) - 1)
+#define _IOC_NRSHIFT 0
+#define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS)
+#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS)
+#define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS)
+#ifndef _IOC_NONE
+#define _IOC_NONE 0U
+#endif
+#ifndef _IOC_WRITE
+#define _IOC_WRITE 1U
+#endif
+#ifndef _IOC_READ
+#define _IOC_READ 2U
+#endif
+#define _IOC(dir,type,nr,size) (((dir) << _IOC_DIRSHIFT) | ((type) << _IOC_TYPESHIFT) | ((nr) << _IOC_NRSHIFT) | ((size) << _IOC_SIZESHIFT))
+#define _IOC_TYPECHECK(t) (sizeof(t))
+#define _IO(type,nr) _IOC(_IOC_NONE, (type), (nr), 0)
+#define _IOR(type,nr,size) _IOC(_IOC_READ, (type), (nr), (_IOC_TYPECHECK(size)))
+#define _IOW(type,nr,size) _IOC(_IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size)))
+#define _IOWR(type,nr,size) _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size)))
+#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ, (type), (nr), sizeof(size))
+#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE, (type), (nr), sizeof(size))
+#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), sizeof(size))
+#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT ((_IOC_WRITE | _IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/gic.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/gic.h
new file mode 100644
index 0000000..1292fe9
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/gic.h
@@ -0,0 +1,26 @@
+/*
+ * 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
+#include <platform/mt6771.h>
+
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/i2c.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/i2c.h
new file mode 100644
index 0000000..a5ce017
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/i2c.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#ifndef SOC_MEDIATEK_MT8183_I2C_H
+#define SOC_MEDIATEK_MT8183_I2C_H
+
+#include <stdio.h>
+#include <platform.h>
+#include <reg.h>
+#include <string.h>
+#include <mt_reg_base.h>
+#include <mtk_timer.h>
+
+#define I2C_SET_REG32(reg, field, val) \
+    do { \
+        unsigned int tv = readl(reg); \
+        tv &= ~(field); \
+        tv |= (val); \
+        writel(tv, reg); \
+    } while(0)
+
+#ifndef DIV_ROUND_UP
+#define DIV_ROUND_UP(x, y) (((x) + ((y) - 1)) / (y))
+#endif
+
+#define I2CTAG "[I2C-LK] "
+#define I2CLOG(x...) printf(x)
+#define I2CERR(x...) printf(x)
+
+#define I2CBIT(nr) (1UL << (nr))
+#define I2CBITMASK(a, b) (I2CBIT(a+1) - I2CBIT(b))
+#define I2C2_BASE_SE (IO_PHYS + 0x1009000)
+#define I2C4_BASE_SE (IO_PHYS + 0x1008000)
+#define OFFSET_MULTI_DMA   0xf8c
+#define OFFSET_ROLLBACK    0xf98
+
+#define MODULE_CLK_SEL_BASE (IO_PHYS + 0x0001098)
+#define USE_PLL_MUX         0x800
+#define SHADOW_REG_MODE           (1 << 1)
+
+/***For internal pull-up resister setting***/
+#define IOCFG_RM_BASE			    (IO_PHYS + 0x1D20000)
+#define IOCFG_RB_BASE			    (IO_PHYS + 0x1D30000)
+#define IOCFG_LB_BASE			    (IO_PHYS + 0x1E70000)
+#define IOCFG_BL_BASE			    (IO_PHYS + 0x1E90000)
+#define IOCFG_LT_BASE			    (IO_PHYS + 0x1F20000)
+
+#define I2C0_BASE (IO_PHYS + 0x1007000)
+#define I2C1_BASE (IO_PHYS + 0x1011000)
+#define I2C2_BASE (IO_PHYS + 0x1009100)
+#define I2C3_BASE (IO_PHYS + 0x100F000)
+#define I2C4_BASE (IO_PHYS + 0x1008100)
+#define I2C5_BASE (IO_PHYS + 0x1017000)
+#define I2C6_BASE (IO_PHYS + 0x1005000)
+#define I2C7_BASE (IO_PHYS + 0x101A000)
+#define I2C8_BASE (IO_PHYS + 0x101B000)
+
+#define MTK_I2C_CLK_SET0	(IO_PHYS + 0x1080)
+#define MTK_I2C_CLK_CLR0	(IO_PHYS + 0x1084)
+#define MTK_I2C_CLK_STA0	(IO_PHYS + 0x1090)
+#define MTK_I2C_CLK_SET1	(IO_PHYS + 0x10a4)
+#define MTK_I2C_CLK_CLR1	(IO_PHYS + 0x10a8)
+#define MTK_I2C_CLK_STA1	(IO_PHYS + 0x10ac)
+#define MTK_I2C_CLK_SET2	(IO_PHYS + 0x10c0)
+#define MTK_I2C_CLK_CLR2	(IO_PHYS + 0x10c4)
+#define MTK_I2C_CLK_STA2	(IO_PHYS + 0x10c8)
+#define MTK_I2C0_CLK_OFFSET	(0x1 << 11)
+#define MTK_I2C1_CLK_OFFSET	(0x1 << 12)
+#define MTK_I2C2_CLK_OFFSET	(0x1 << 13)
+#define MTK_I2C3_CLK_OFFSET	(0x1 << 14)
+#define MTK_I2C4_CLK_OFFSET	(0x1 << 7)
+#define MTK_I2C5_CLK_OFFSET	(0x1 << 18)
+#define MTK_I2C6_CLK_OFFSET	(0x1 << 6)
+#define MTK_I2C7_CLK_OFFSET	(0x1 << 22)
+
+#define I2C_OK                              0x0000
+#define ENXIO_I2C							6
+#define EAGAIN_I2C                          11  /* Try again */
+#define EINVAL_I2C                          22  /* Invalid argument */
+#define EOPNOTSUPP_I2C                      95  /* Operation not supported on transport endpoint */
+#define ETIMEDOUT_I2C                       110 /* Connection timed out */
+#define EREMOTEIO_I2C                       121 /* Remote I/O error */
+#define ENOTSUPP_I2C                        524 /* Remote I/O error */
+#define I2C_WRITE_FAIL_HS_NACKERR           0xA013
+#define I2C_WRITE_FAIL_ACKERR               0xA014
+#define I2C_WRITE_FAIL_TIMEOUT              0xA015
+#define DUTY_CYCLE			    45
+
+
+#define I2C_FIFO_SIZE			8
+#define I2C_RS_TRANSFER			I2CBIT(4)
+#define I2C_ARB_LOSE			I2CBIT(3)
+#define I2C_HS_NACKERR			I2CBIT(2)
+#define I2C_ACKERR				I2CBIT(1)
+#define I2C_TRANSAC_COMP		I2CBIT(0)
+#define I2C_TRANSAC_START		I2CBIT(0)
+#define I2C_RS_MUL_CNFG			I2CBIT(15)
+#define I2C_RS_MUL_TRIG			I2CBIT(14)
+#define I2C_SOFT_RST			0x0001
+#define I2C_FIFO_ADDR_CLR		0x0001
+#define I2C_WRRD_TRANAC_VALUE	0x0002
+#define I2C_M_RD				0x0001
+
+#define I2C_CONTROL_RS          (0x1 << 1)
+#define I2C_CONTROL_DMA_EN      (0x1 << 2)
+#define I2C_CONTROL_CLK_EXT_EN      (0x1 << 3)
+#define I2C_CONTROL_DIR_CHANGE      (0x1 << 4)
+#define I2C_CONTROL_ACKERR_DET_EN   (0x1 << 5)
+#define I2C_CONTROL_TRANSFER_LEN_CHANGE (0x1 << 6)
+#define I2C_CONTROL_WRAPPER          (0x1 << 0)
+
+#define MTK_I2C_SOURCE_CLK 133000
+#define MTK_I2C_CLK_DIV 1
+#define I2C_DEFAULT_CLK_DIV 2
+#define I2C_CLK_DIV_100K I2C_DEFAULT_CLK_DIV
+#define I2C_HTIMING_100K 0x537
+#define I2C_LTIMING_100K 0x177
+#define I2C_CLK_DIV_400K I2C_DEFAULT_CLK_DIV
+#define I2C_HTIMING_400K 0x218
+#define I2C_LTIMING_400K 0x6d
+#define I2C_CLK_DIV_1000K I2C_DEFAULT_CLK_DIV
+#define I2C_HTIMING_1000K 0x21
+#define I2C_LTIMING_1000K 0x21
+
+#define I2C_DEFAULT_SPEED		100
+#define MAX_FS_MODE_SPEED		400
+#define MAX_FS_PLUS_SPEED		1000
+#define MAX_SAMPLE_CNT_DIV		8
+#define MAX_STEP_CNT_DIV		64
+#define MAX_HS_STEP_CNT_DIV		8
+#define I2C_TIME_DEFAULT_VALUE	0x0003
+#define DUTY_CYCLE			    45
+#define I2C_POLL_VALUE 0xfffff
+
+#define I2C_ST_START_CON		0x8001
+#define I2C_FS_START_CON		0x1800
+#define I2C_DELAY_LEN			0x0002
+
+#define DMA_ADDRESS_HIGH          (0xC0000000)
+
+#define I2C_IO_CONFIG_OPEN_DRAIN	0x0003
+#define I2C_IO_CONFIG_PUSH_PULL		0x0000
+
+#define I2C_FIFO_FORCE			I2CBIT(0)
+#define I2C_DCM_ENABLE			I2CBIT(1)
+#define I2C_CONTI_TRANS			I2CBIT(2)
+#define I2C_EXTEN_SET			I2CBIT(3)
+#define I2C_ACTIME_SET			I2CBIT(4)
+#define I2C_MULTI_TRANS			I2CBIT(5)
+#define I2C_MULTI_STOP			I2CBIT(6)
+#define I2C_CLOCK_STRETCH		I2CBIT(7)
+
+/* offset is different in mt6771 */
+/******************************************register operation***********************************/
+enum I2C_REGS_OFFSET {
+	OFFSET_DATA_PORT      = 0x0,
+	OFFSET_SLAVE_ADDR     = 0x04,
+	OFFSET_INTR_MASK      = 0x08,
+	OFFSET_INTR_STAT      = 0x0C,
+	OFFSET_CONTROL        = 0x10,
+	OFFSET_TRANSFER_LEN   = 0x14,
+	OFFSET_TRANSAC_LEN    = 0x18,
+	OFFSET_DELAY_LEN      = 0x1C,
+	OFFSET_HTIMING        = 0x20,
+	OFFSET_START          = 0x24,
+	OFFSET_EXT_CONF       = 0x28,
+	OFFSET_LTIMING        = 0x2C,
+	OFFSET_HS             = 0x30,
+	OFFSET_IO_CONFIG      = 0x34,
+	OFFSET_FIFO_ADDR_CLR  = 0x38,
+	OFFSET_TRANSFER_LEN_AUX = 0x44,
+	OFFSET_CLOCK_DIV      = 0x48,
+	OFFSET_SOFTRESET      = 0x50,
+	OFFSET_DEBUGSTAT      = 0xe4,
+	OFFSET_DEBUGCTRL      = 0xe8,
+	OFFSET_FIFO_STAT      = 0xf4,
+	OFFSET_FIFO_THRESH    = 0xf8,
+	OFFSET_DCM_EN         = 0xf88,
+};
+
+enum i2c_trans_st_rs {
+	I2C_TRANS_STOP = 0,
+	I2C_TRANS_REPEATED_START,
+};
+
+enum mtk_trans_op {
+	I2C_MASTER_WR = 1,
+	I2C_MASTER_RD,
+	I2C_MASTER_WRRD,
+};
+
+enum mtk_i2c_bus_num {
+	I2C0 = 0,
+	I2C1 = 1,
+	I2C2 = 2,
+	I2C3 = 3,
+	I2C4 = 4,
+	I2C5 = 5,
+	I2C6 = 6,
+	I2C7 = 7,
+	I2C8 = 8,
+};
+
+struct i2c_msg {
+	/** slave address */
+	uint16_t addr;
+	/** i2c transfer operation mode */
+	uint16_t flags;
+	/** msg length */
+	uint16_t len;
+	/** pointer to msg data */
+	uint8_t *buf;
+};
+
+struct mtk_i2c {
+	/** dma mode flag */
+	bool dma_en;
+	/** polling mode flag */
+	bool poll_en;
+	/** IO config push-pull mode */
+	bool pushpull;
+	/** filter error message */
+	bool filter_msg;
+	/** multi-transfer repeated start enable */
+	bool auto_restart;
+	bool msg_complete;
+	/** slave device 7bits address */
+	uint8_t addr;
+	/** i2c bus number */
+	uint8_t id;
+	uint8_t mode;
+	uint16_t irqnr;
+	/** i2c interrupt status */
+	uint16_t irq_stat;
+	/** clock_div register value */
+	uint16_t clock_div_reg;
+	/** timing register value */
+	uint16_t htiming_reg;
+	uint16_t ltiming_reg;
+
+	uint16_t control_reg;
+	uint16_t timing_reg;
+	uint16_t high_speed_reg;
+	uint16_t con_num;
+	uint16_t delay_len;
+	uint16_t ext_time;
+	uint16_t scl_ratio;
+	uint16_t hs_scl_ratio;
+	uint16_t scl_mis_comp;
+	uint16_t sta_stop_time;
+	uint16_t hs_sta_stop_time;
+	uint16_t sda_time;
+	/** i2c base address */
+	addr_t base;
+	/** i2c dma base address */
+	addr_t dmabase;
+	/** source clock KHz */
+	uint32_t clk;
+	/** source clock divide */
+	uint32_t clk_src_div;
+	/** i2c transfer speed */
+	uint32_t speed;
+	/** i2c transfer operation mode */
+	enum mtk_trans_op op;
+};
+
+/* external API */
+void mtk_i2c_init(void);
+int mtk_i2c_read(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,
+		 uint8_t *buffer, uint16_t len);
+int mtk_i2c_write(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,
+		  uint8_t *buffer, uint16_t len);
+int mtk_i2c_write_read(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,
+		       uint8_t *write_buffer, uint8_t *read_buffer,
+		       uint16_t write_len, uint16_t read_len);
+
+#endif /* SOC_MEDIATEK_MT8183_RTC_H */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/infracfg.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/infracfg.h
new file mode 100644
index 0000000..c3af2ac
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/infracfg.h
@@ -0,0 +1,271 @@
+/*
+ * 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.
+ */
+
+#ifndef SOC_MEDIATEK_MT8183_INFRACFG_H
+#define SOC_MEDIATEK_MT8183_INFRACFG_H
+
+#include <platform/mt_reg_base.h>
+
+struct mt8183_infracfg_regs {
+    unsigned int reserved1[20];
+    unsigned int infra_globalcon_dcmctl;
+    unsigned int reserved2[7];
+    unsigned int infra_bus_dcm_ctrl;
+    unsigned int peri_bus_dcm_ctrl;
+    unsigned int mem_dcm_ctrl;
+    unsigned int dfs_mem_dcm_ctrl;
+    unsigned int module_sw_cg_0_set;
+    unsigned int module_sw_cg_0_clr;
+    unsigned int module_sw_cg_1_set;
+    unsigned int module_sw_cg_1_clr;
+    unsigned int module_sw_cg_0_sta;
+    unsigned int module_sw_cg_1_sta;
+    unsigned int module_clk_sel;
+    unsigned int mem_cg_ctrl;
+    unsigned int p2p_rx_clk_on;
+    unsigned int module_sw_cg_2_set;
+    unsigned int module_sw_cg_2_clr;
+    unsigned int module_sw_cg_2_sta;
+    unsigned int reserved3[1];
+    unsigned int dramc_wbr;
+    unsigned int reserved4[2];
+    unsigned int module_sw_cg_3_set;
+    unsigned int module_sw_cg_3_clr;
+    unsigned int module_sw_cg_3_sta;
+    unsigned int reserved5[13];
+    unsigned int i2c_dbtool_misc;
+    unsigned int md_sleep_ctrl_mask;
+    unsigned int pmicw_clock_ctrl;
+    unsigned int reserved6[5];
+    unsigned int infra_globalcon_rst0_set;
+    unsigned int infra_globalcon_rst0_clr;
+    unsigned int infra_globalcon_rst0_sta;
+    unsigned int reserved7[1];
+    unsigned int infra_globalcon_rst1_set;
+    unsigned int infra_globalcon_rst1_clr;
+    unsigned int infra_globalcon_rst1_sta;
+    unsigned int reserved8[1];
+    unsigned int infra_globalcon_rst2_set;
+    unsigned int infra_globalcon_rst2_clr;
+    unsigned int infra_globalcon_rst2_sta;
+    unsigned int reserved9[1];
+    unsigned int infra_globalcon_rst3_set;
+    unsigned int infra_globalcon_rst3_clr;
+    unsigned int infra_globalcon_rst3_sta;
+    unsigned int reserved10[41];
+    unsigned int infra_topaxi_si0_ctl;
+    unsigned int infra_topaxi_si1_ctl;
+    unsigned int infra_topaxi_mdbus_ctl;
+    unsigned int infra_mci_si0_ctl;
+    unsigned int infra_mci_si1_ctl;
+    unsigned int infra_mci_si2_ctl;
+    unsigned int infra_mci_async_ctl;
+    unsigned int infra_mci_cg_mfg_sec_sta;
+    unsigned int infra_topaxi_protecten;
+    unsigned int infra_topaxi_protecten_sta0;
+    unsigned int infra_topaxi_protecten_sta1;
+    unsigned int infra_axi_aslice_ctrl;
+    unsigned int infra_apb_async_sta;
+    unsigned int infra_topaxi_si2_ctl;
+    unsigned int reserved11[2];
+    unsigned int infra_mci_trans_con_read;
+    unsigned int infra_mci_trans_con_write;
+    unsigned int infra_mci_id_remap_con;
+    unsigned int infra_mci_emi_trans_con;
+    unsigned int infra_topaxi_protecten_1;
+    unsigned int infra_topaxi_protecten_sta0_1;
+    unsigned int infra_topaxi_protecten_sta1_1;
+    unsigned int reserved12[1];
+    unsigned int infra_topaxi_aslice_ctrl;
+    unsigned int reserved13[3];
+    unsigned int infra_topaxi_mi_ctrl;
+    unsigned int infra_topaxi_cbip_aslice_ctrl;
+    unsigned int infra_topaxi_cbip_slice_ctrl;
+    unsigned int infra_top_master_sideband;
+    unsigned int reserved14[1];
+    unsigned int infra_topaxi_trans_limiter;
+    unsigned int infra_topaxi_emi_gmc_l2c_ctrl;
+    unsigned int infra_topaxi_cbip_slice_ctrl_1;
+    unsigned int infra_mfg_slave_gals_ctrl;
+    unsigned int infra_mfg_master_m0_gals_ctrl;
+    unsigned int infra_mfg_master_m1_gals_ctrl;
+    unsigned int infra_top_master_sideband_1;
+    unsigned int infra_topaxi_protecten_set;
+    unsigned int infra_topaxi_protecten_clr;
+    unsigned int infra_topaxi_protecten_1_set;
+    unsigned int infra_topaxi_protecten_1_clr;
+    unsigned int infra_topaxi_cbip_slice_ctrl_2;
+    unsigned int reserved15[3];
+    unsigned int infra_topaxi_protecten_mcu;
+    unsigned int infra_topaxi_protecten_mcu_set;
+    unsigned int infra_topaxi_protecten_mcu_clr;
+    unsigned int reserved16[1];
+    unsigned int infra_topaxi_protecten_mm;
+    unsigned int infra_topaxi_protecten_mm_set;
+    unsigned int infra_topaxi_protecten_mm_clr;
+    unsigned int reserved17[1];
+    unsigned int infra_topaxi_protecten_mcu_sta0;
+    unsigned int infra_topaxi_protecten_mcu_sta1;
+    unsigned int infra_topaxi_protecten_mm_sta0;
+    unsigned int infra_topaxi_protecten_mm_sta1;
+    unsigned int reserved18[4];
+    unsigned int md1_bank0_map0;
+    unsigned int md1_bank0_map1;
+    unsigned int md1_bank0_map2;
+    unsigned int md1_bank0_map3;
+    unsigned int md1_bank1_map0;
+    unsigned int md1_bank1_map1;
+    unsigned int md1_bank1_map2;
+    unsigned int md1_bank1_map3;
+    unsigned int md1_bank4_map0;
+    unsigned int md1_bank4_map1;
+    unsigned int md1_bank4_map2;
+    unsigned int md1_bank4_map3;
+    unsigned int md2_bank0_map0;
+    unsigned int md2_bank0_map1;
+    unsigned int md2_bank0_map2;
+    unsigned int md2_bank0_map3;
+    unsigned int reserved19[4];
+    unsigned int md2_bank4_map0;
+    unsigned int md2_bank4_map1;
+    unsigned int md2_bank4_map2;
+    unsigned int md2_bank4_map3;
+    unsigned int c2k_config;
+    unsigned int c2k_status;
+    unsigned int c2k_spm_ctrl;
+    unsigned int reserved20[1];
+    unsigned int ap2md_dummy;
+    unsigned int reserved21[3];
+    unsigned int conn_map0;
+    unsigned int cldma_map0;
+    unsigned int conn_map1;
+    unsigned int conn_bus_con;
+    unsigned int mcusys_dfd_map;
+    unsigned int conn_map2;
+    unsigned int reserved22[26];
+    unsigned int peri_cci_sideband_con;
+    unsigned int mfg_cci_sideband_con;
+    unsigned int reserved23[62];
+    unsigned int infra_ao_dbg_con0;
+    unsigned int infra_ao_dbg_con1;
+    unsigned int infra_ao_dbg_con2;
+    unsigned int infra_ao_dbg_con3;
+    unsigned int md_dbg_ck_con;
+    unsigned int infra_ao_dbg_sta;
+    unsigned int reserved24[58];
+    unsigned int mfg_misc_con;
+    unsigned int reserved25[63];
+    unsigned int infra_rsvd0;
+    unsigned int infra_rsvd1;
+    unsigned int infra_rsvd2;
+    unsigned int infra_rsvd3;
+    unsigned int reserved26[92];
+    unsigned int md1_sbc_key0;
+    unsigned int md1_sbc_key1;
+    unsigned int md1_sbc_key2;
+    unsigned int md1_sbc_key3;
+    unsigned int md1_sbc_key4;
+    unsigned int md1_sbc_key5;
+    unsigned int md1_sbc_key6;
+    unsigned int md1_sbc_key7;
+    unsigned int md1_sbc_key_lock;
+    unsigned int reserved27[1];
+    unsigned int md1_misc_lock;
+    unsigned int md1_misc;
+    unsigned int c2k_sbc_key0;
+    unsigned int c2k_sbc_key1;
+    unsigned int c2k_sbc_key2;
+    unsigned int c2k_sbc_key3;
+    unsigned int c2k_sbc_key4;
+    unsigned int c2k_sbc_key5;
+    unsigned int c2k_sbc_key6;
+    unsigned int c2k_sbc_key7;
+    unsigned int c2k_sbc_key_lock;
+    unsigned int reserved28[11];
+    unsigned int infra_bonding;
+    unsigned int reserved29[63];
+    unsigned int infra_ao_scpsys_apb_async_sta;
+    unsigned int infra_ao_md32_tx_apb_async_sta;
+    unsigned int infra_ao_md32_rx_apb_async_sta;
+    unsigned int infra_ao_cksys_apb_async_sta;
+    unsigned int infra_ao_pmic_wrap_tx_apb_async_sta;
+    unsigned int reserved30[59];
+    unsigned int pll_ulposc_con0;
+    unsigned int pll_ulposc_con1;
+    unsigned int reserved31[2];
+    unsigned int pll_auxadc_con0;
+    unsigned int scp_infra_irq_set;
+    unsigned int scp_infra_irq_clr;
+    unsigned int scp_infra_ctrl;
+    unsigned int reserved32[56];
+    unsigned int cldma_ctrl;
+    unsigned int reserved33[63];
+    unsigned int infrabus_dbg0;
+    unsigned int infrabus_dbg1;
+    unsigned int infrabus_dbg2;
+    unsigned int infrabus_dbg3;
+    unsigned int infrabus_dbg4;
+    unsigned int infrabus_dbg5;
+    unsigned int infrabus_dbg6;
+    unsigned int infrabus_dbg7;
+    unsigned int infrabus_dbg8;
+    unsigned int infrabus_dbg9;
+    unsigned int infrabus_dbg10;
+    unsigned int infrabus_dbg11;
+    unsigned int infrabus_dbg12;
+    unsigned int infrabus_dbg13;
+    unsigned int infrabus_dbg14;
+    unsigned int infrabus_dbg15;
+    unsigned int infrabus_dbg16;
+    unsigned int infrabus_dbg17;
+    unsigned int infrabus_dbg18;
+    unsigned int infrabus_dbg19;
+    unsigned int infrabus_dbg20;
+    unsigned int infrabus_dbg21;
+    unsigned int infrabus_dbg22;
+    unsigned int infrabus_dbg23;
+    unsigned int reserved34[104];
+    unsigned int infra_misc;
+    unsigned int infra_acp;
+    unsigned int misc_config;
+    unsigned int infra_misc2;
+    unsigned int mdsys_misc_con;
+    unsigned int reserved35[27];
+    unsigned int infra_ao_sec_con;
+    unsigned int infra_ao_sec_cg_con0;
+    unsigned int infra_ao_sec_cg_con1;
+    unsigned int infra_ao_sec_rst_con0;
+    unsigned int infra_ao_sec_rst_con1;
+    unsigned int infra_ao_sec_rst_con2;
+    unsigned int reserved36[1];
+    unsigned int infra_ao_sec_cg_con2;
+    unsigned int infra_ao_sec_rst_con3;
+    unsigned int infra_ao_sec_cg_con3;
+    unsigned int reserved37[2];
+    unsigned int infra_ao_sec_hyp;
+};
+
+static struct mt8183_infracfg_regs *const mt8183_infracfg =
+    (void *)INFRACFG_AO_BASE;
+
+#endif    /* SOC_MEDIATEK_MT8183_INFRACFG_H */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mcucfg.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mcucfg.h
new file mode 100644
index 0000000..a7b4f72
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mcucfg.h
@@ -0,0 +1,358 @@
+/*
+ * 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.
+ */
+
+#ifndef SOC_MEDIATEK_MT8183_MCUCFG_H
+#define SOC_MEDIATEK_MT8183_MCUCFG_H
+
+#include <platform/mt_reg_base.h>
+
+struct mt8183_mcucfg_regs {
+    unsigned int mp0_ca7l_cache_config;
+    unsigned int mp0_cpu0_mem_delsel0;
+    unsigned int mp0_cpu0_mem_delsel1;
+    unsigned int reserved1[6];
+    unsigned int mp0_cache_mem_delsel0;
+    unsigned int mp0_cache_mem_delsel1;
+    unsigned int mp0_axi_config;
+    unsigned int mp0_misc_config0;
+    unsigned int reserved2[1];
+    unsigned int mp0_misc_config2;
+    unsigned int mp0_misc_config3;
+    unsigned int mp0_misc_config4;
+    unsigned int mp0_misc_config5;
+    unsigned int mp0_misc_config6;
+    unsigned int mp0_misc_config7;
+    unsigned int mp0_misc_config8;
+    unsigned int mp0_misc_config9;
+    unsigned int mp0_ca7l_cfg_dis;
+    unsigned int mp0_ca7l_clken_ctrl;
+    unsigned int mp0_ca7l_rst_ctrl;
+    unsigned int mp0_ca7l_misc_config;
+    unsigned int mp0_ca7l_dbg_pwr_ctrl;
+    unsigned int mp0_rw_rsvd0;
+    unsigned int mp0_rw_rsvd1;
+    unsigned int mp0_ro_rsvd;
+    unsigned int reserved3[1];
+    unsigned int mp0_l2_cache_parity1_rdata;
+    unsigned int mp0_l2_cache_parity2_rdata;
+    unsigned int reserved4[1];
+    unsigned int mp0_rgu_dcm_config;
+    unsigned int mp0_ca53_specific_ctrl;
+    unsigned int mp0_esr_case;
+    unsigned int mp0_esr_mask;
+    unsigned int mp0_esr_trig_en;
+    unsigned int reserved5[1];
+    unsigned int mp0_ses_cg_en;
+    unsigned int reserved6[216];
+    unsigned int mp_dbg_ctrl;
+    unsigned int reserved7[1];
+    unsigned int mp0_ca7l_ir_mon;
+    unsigned int reserved8[32];
+    unsigned int mp_dfd_ctrl;
+    unsigned int dfd_cnt_l;
+    unsigned int dfd_cnt_h;
+    unsigned int misccfg_ro_rsvd;
+    unsigned int reserved9[1];
+    unsigned int dvm_dbg_monitor_gpu;
+    unsigned int dvm_dbg_monitor_psys;
+    unsigned int dvm_dbg_monitor_mp1;
+    unsigned int dvm_dbg_monitor_mp0;
+    unsigned int dvm_dbg_monitor_mp2;
+    unsigned int reserved10[2];
+    unsigned int dvm_op_arid_mp0;
+    unsigned int dvm_op_arid_mp1;
+    unsigned int dvm_op_arid_mp2;
+    unsigned int reserved11[5];
+    unsigned int cci_s6_if_debug;
+    unsigned int reserved12[7];
+    unsigned int mp1_rst_status;
+    unsigned int mp1_dbg_ctrl;
+    unsigned int mp1_dbg_flag;
+    unsigned int mp1_ca7l_ir_mon;
+    unsigned int reserved13[32];
+    unsigned int mcusys_dbg_mon_sel_a;
+    unsigned int mcusys_dbg_mon;
+    unsigned int misccfg_sec_vio_status0;
+    unsigned int misccfg_sec_vio_status1;
+    unsigned int cci_top_if_debug;
+    unsigned int cci_m0_if_debug;
+    unsigned int cci_m1_if_debug;
+    unsigned int cci_m2_if_debug;
+    unsigned int cci_s1_if_debug;
+    unsigned int cci_s2_if_debug;
+    unsigned int cci_s3_if_debug;
+    unsigned int cci_s4_if_debug;
+    unsigned int cci_m0_tra_debug;
+    unsigned int cci_m1_tra_debug;
+    unsigned int cci_m2_tra_debug;
+    unsigned int cci_s1_tra_debug;
+    unsigned int cci_s2_tra_debug;
+    unsigned int cci_s3_tra_debug;
+    unsigned int cci_s4_tra_debug;
+    unsigned int cci_tra_dbg_cfg;
+    unsigned int cci_s5_if_debug;
+    unsigned int cci_s5_tra_debug;
+    unsigned int gic500_int_mask;
+    unsigned int core_rst_en_latch;
+    unsigned int reserved14[3];
+    unsigned int dbg_core_ret;
+    unsigned int mcusys_config_a;
+    unsigned int mcusys_config1_a;
+    unsigned int mcusys_gic_peribase_a;
+    unsigned int mcusys_pinmux;
+    unsigned int sec_range0_start;
+    unsigned int sec_range0_end;
+    unsigned int sec_range_enable;
+    unsigned int l2c_mm_base;
+    unsigned int reserved15[8];
+    unsigned int aclken_div;
+    unsigned int pclken_div;
+    unsigned int l2c_sram_ctrl;
+    unsigned int armpll_jit_ctrl;
+    unsigned int cci_addrmap;
+    unsigned int cci_config;
+    unsigned int cci_periphbase;
+    unsigned int cci_nevntcntovfl;
+    unsigned int cci_status;
+    unsigned int cci_acel_s1_ctrl;
+    unsigned int mcusys_bus_fabric_dcm_ctrl;
+    unsigned int mcu_misc_dcm_ctrl;
+    unsigned int xgpt_ctl;
+    unsigned int xgpt_idx;
+    unsigned int reserved16[3];
+    unsigned int mcusys_rw_rsvd0;
+    unsigned int mcusys_rw_rsvd1;
+    unsigned int reserved17[13];
+    unsigned int gic500_delsel_ctl;
+    unsigned int etb_delsel_ctl;
+    unsigned int etb_rst_ctl;
+    unsigned int reserved18[13];
+    unsigned int mp_gen_timer_reset_mask_secur_en;
+    unsigned int mp_gen_timer_reset_mask_0;
+    unsigned int mp_gen_timer_reset_mask_1;
+    unsigned int mp_gen_timer_reset_mask_2;
+    unsigned int mp_gen_timer_reset_mask_3;
+    unsigned int mp_gen_timer_reset_mask_4;
+    unsigned int mp_gen_timer_reset_mask_5;
+    unsigned int mp_gen_timer_reset_mask_6;
+    unsigned int mp_gen_timer_reset_mask_7;
+    unsigned int reserved19[7];
+    unsigned int mp_cci_adb400_dcm_config;
+    unsigned int mp_sync_dcm_config;
+    unsigned int reserved20[1];
+    unsigned int mp_sync_dcm_cluster_config;
+    unsigned int sw_udi;
+    unsigned int reserved21[1];
+    unsigned int gic_sync_dcm;
+    unsigned int big_dbg_pwr_ctrl;
+    unsigned int gic_cpu_periphbase;
+    unsigned int axi_cpu_config;
+    unsigned int reserved22[2];
+    unsigned int mcsib_sys_ctrl1;
+    unsigned int mcsib_sys_ctrl2;
+    unsigned int mcsib_sys_ctrl3;
+    unsigned int mcsib_sys_ctrl4;
+    unsigned int mcsib_dbg_ctrl1;
+    unsigned int pwrmcu_apb2to1;
+    unsigned int reserved23[1];
+    unsigned int mp1_spmc;
+    unsigned int reserved24[1];
+    unsigned int mp1_spmc_sram_ctl;
+    unsigned int reserved25[1];
+    unsigned int mp1_sw_rst_wait_cycle;
+    unsigned int mp0_pll_divider_cfg;
+    unsigned int reserved26[1];
+    unsigned int mp2_pll_divider_cfg;
+    unsigned int reserved27[5];
+    unsigned int bus_pll_divider_cfg;
+    unsigned int reserved28[7];
+    unsigned int clusterid_aff1;
+    unsigned int clusterid_aff2;
+    unsigned int hack_ice_rom_table_access;
+    unsigned int mp_top_mem_delay_cfg;
+    unsigned int l2c_cfg_mp0;
+    unsigned int reserved29[1];
+    unsigned int l2c_cfg_mp2;
+    unsigned int reserved30[1];
+    unsigned int cci_bw_pmu_ctl;
+    unsigned int cci_bw_pmu_cnt0to1_sel;
+    unsigned int cci_bw_pmu_cnt2to3_sel;
+    unsigned int cci_bw_pmu_cnt4to5_sel;
+    unsigned int cci_bw_pmu_cnt6to7_sel;
+    unsigned int cci_bw_pmu_cnt0to3_mask;
+    unsigned int cci_bw_pmu_cnt4to7_mask;
+    unsigned int cci_bw_pmu_ref_cnt;
+    unsigned int cci_bw_pmu_acc_cnt0;
+    unsigned int cci_bw_pmu_acc_cnt1;
+    unsigned int cci_bw_pmu_acc_cnt2;
+    unsigned int cci_bw_pmu_acc_cnt3;
+    unsigned int cci_bw_pmu_acc_cnt4;
+    unsigned int cci_bw_pmu_acc_cnt5;
+    unsigned int cci_bw_pmu_acc_cnt6;
+    unsigned int cci_bw_pmu_acc_cnt7;
+    unsigned int reserved31[8];
+    unsigned int cci_bw_pmu_id_ext_cnt0to3;
+    unsigned int cci_bw_pmu_id_ext_cnt4to7;
+    unsigned int cci_bw_pmu_mask_ext_cnt0to3;
+    unsigned int cci_bw_pmu_mask_ext_cnt4to7;
+    unsigned int reserved32[16];
+    unsigned int etb_acc_ctl;
+    unsigned int etb_ck_ctl;
+    unsigned int reserved33[4];
+    unsigned int mbista_mp1_ocp_con;
+    unsigned int reserved34[1];
+    unsigned int mbista_gic_con;
+    unsigned int mbista_gic_result;
+    unsigned int mbista_mcsib_sf1_con;
+    unsigned int mbista_mcsib_sf1_result;
+    unsigned int mbista_mcsib_sf2_con;
+    unsigned int mbista_mcsib_sf2_result;
+    unsigned int reserved35[2];
+    unsigned int mbista_rstb;
+    unsigned int mbista_all_result;
+    unsigned int reserved36[2];
+    unsigned int mp0_hang_monitor_ctrl0;
+    unsigned int mp0_hang_monitor_ctrl1;
+    unsigned int reserved37[2];
+    unsigned int mp1_hang_monitor_ctrl0;
+    unsigned int mp1_hang_monitor_ctrl1;
+    unsigned int reserved38[2];
+    unsigned int mp2_hang_monitor_ctrl0;
+    unsigned int mp2_hang_monitor_ctrl1;
+    unsigned int reserved39[6];
+    unsigned int gpu_hang_monitor_ctrl0;
+    unsigned int gpu_hang_monitor_ctrl1;
+    unsigned int reserved40[2];
+    unsigned int psys_hang_monitor_ctrl0;
+    unsigned int psys_hang_monitor_ctrl1;
+    unsigned int reserved41[42];
+    unsigned int sec_pol_ctl_en0;
+    unsigned int sec_pol_ctl_en1;
+    unsigned int sec_pol_ctl_en2;
+    unsigned int sec_pol_ctl_en3;
+    unsigned int sec_pol_ctl_en4;
+    unsigned int sec_pol_ctl_en5;
+    unsigned int sec_pol_ctl_en6;
+    unsigned int sec_pol_ctl_en7;
+    unsigned int sec_pol_ctl_en8;
+    unsigned int sec_pol_ctl_en9;
+    unsigned int sec_pol_ctl_en10;
+    unsigned int sec_pol_ctl_en11;
+    unsigned int sec_pol_ctl_en12;
+    unsigned int sec_pol_ctl_en13;
+    unsigned int sec_pol_ctl_en14;
+    unsigned int sec_pol_ctl_en15;
+    unsigned int sec_pol_ctl_en16;
+    unsigned int sec_pol_ctl_en17;
+    unsigned int sec_pol_ctl_en18;
+    unsigned int sec_pol_ctl_en19;
+    unsigned int reserved42[12];
+    unsigned int int_pol_ctl0;
+    unsigned int int_pol_ctl1;
+    unsigned int int_pol_ctl2;
+    unsigned int int_pol_ctl3;
+    unsigned int int_pol_ctl4;
+    unsigned int int_pol_ctl5;
+    unsigned int int_pol_ctl6;
+    unsigned int int_pol_ctl7;
+    unsigned int int_pol_ctl8;
+    unsigned int int_pol_ctl9;
+    unsigned int int_pol_ctl10;
+    unsigned int int_pol_ctl11;
+    unsigned int int_pol_ctl12;
+    unsigned int int_pol_ctl13;
+    unsigned int int_pol_ctl14;
+    unsigned int int_pol_ctl15;
+    unsigned int int_pol_ctl16;
+    unsigned int int_pol_ctl17;
+    unsigned int int_pol_ctl18;
+    unsigned int int_pol_ctl19;
+    unsigned int reserved43[12];
+    unsigned int dfd_internal_ctl;
+    unsigned int dfd_internal_counter;
+    unsigned int dfd_internal_pwr_on;
+    unsigned int dfd_internal_chain_legth_0;
+    unsigned int dfd_internal_shift_clk_ratio;
+    unsigned int dfd_internal_counter_return;
+    unsigned int dfd_internal_sram_access;
+    unsigned int dfd_internal_chain_length_1;
+    unsigned int dfd_internal_chain_length_2;
+    unsigned int dfd_internal_chain_length_3;
+    unsigned int dfd_internal_test_so_0;
+    unsigned int dfd_internal_test_so_1;
+    unsigned int dfd_internal_num_of_test_so_gp;
+    unsigned int dfd_internal_test_so_over_64;
+    unsigned int dfd_internal_mask_out;
+    unsigned int dfd_internal_sw_ns_trigger;
+    unsigned int dfd_internal_mcsib;
+    unsigned int dfd_internal_mcsib_sel_status;
+    unsigned int dfd_internal_sram_base_addr;
+    unsigned int dfd_internal_sram_delsel;
+    unsigned int mcsib_iccs_ctrl1;
+    unsigned int reserved44[1];
+    unsigned int mcu_all_pwr_on_ctrl;
+    unsigned int emi_wfifo;
+    unsigned int mcsia_dcm_en;
+    unsigned int reserved45[294];
+    unsigned int mcu_apb_base;
+    unsigned int reserved46[384];
+    unsigned int mp0_cpu_avg_stall_ratio;
+    unsigned int mp0_cpu0_avg_stall_ratio_ctrl;
+    unsigned int mp0_cpu1_avg_stall_ratio_ctrl;
+    unsigned int mp0_cpu2_avg_stall_ratio_ctrl;
+    unsigned int mp0_cpu3_avg_stall_ratio_ctrl;
+    unsigned int mp0_avg_stall_ratio_status;
+    unsigned int mp0_cpu0_stall_counter;
+    unsigned int mp0_cpu1_stall_counter;
+    unsigned int mp0_cpu2_stall_counter;
+    unsigned int mp0_cpu3_stall_counter;
+    unsigned int mp0_cpu0_non_wfi_counter;
+    unsigned int mp0_cpu1_non_wfi_counter;
+    unsigned int mp0_cpu2_non_wfi_counter;
+    unsigned int mp0_cpu3_non_wfi_counter;
+    unsigned int reserved47[370];
+    unsigned int cpusys0_sparkvretcntrl;
+    unsigned int cpusys0_sparken;
+    unsigned int cpusys0_amuxsel;
+    unsigned int cpusys0_cg_dis;
+    unsigned int cpusys0_cpu0_counter;
+    unsigned int cpusys0_cpu1_counter;
+    unsigned int cpusys0_cpu2_counter;
+    unsigned int cpusys0_cpu3_counter;
+    unsigned int cpusys0_spark_debug_overwrite;
+    unsigned int reserved48[3];
+    unsigned int cpusys0_cpu0_spmc_ctl;
+    unsigned int cpusys0_cpu1_spmc_ctl;
+    unsigned int cpusys0_cpu2_spmc_ctl;
+    unsigned int cpusys0_cpu3_spmc_ctl;
+    unsigned int sesv3_rg_toggle;
+    unsigned int reserved49[7];
+    unsigned int mp0_sync_dcm_cgavg_ctrl;
+    unsigned int mp0_sync_dcm_cgavg_fact;
+    unsigned int mp0_sync_dcm_cgavg_rfact;
+    unsigned int mp0_sync_dcm_cgavg;
+};
+
+static struct mt8183_mcucfg_regs *const mt8183_mcucfg = (void *)MCUCFG_BASE;
+
+#endif  /* SOC_MEDIATEK_MT8183_MCUCFG_H */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mm_common.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mm_common.h
new file mode 100644
index 0000000..d5bb413
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mm_common.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#ifndef _MM_COMMON_H_
+#define _MM_COMMON_H_
+
+#include <platform/addressmap.h>
+#include <reg.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#define read32(addr)			readl(addr)
+#define write32(addr, val)		writel((val), (addr))
+#define BIT(nr)				(1 << (nr))
+#define setbits_le32(addr, val)		writel((readl(addr) | (val)), (addr))
+#define clrbits_le32(addr, val)		writel((readl(addr) & ~(val)), (addr))
+#define clrsetbits_le32(addr, clear, set)	writel(((readl(addr) & ~(clear)) | (set)), (addr))
+#define KiB				1024
+#define BUF_ALIGN_SIZE 0x1000
+#define align_to(value, n) ((value + n - 1) / n * (n))
+
+#define member_size(TYPE, MEMBER)	(sizeof(((TYPE *) 0)->MEMBER))
+#define check_member(structure, member, offset) STATIC_ASSERT( \
+offsetof(struct structure, member) == offset)
+
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mmc_core.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mmc_core.h
new file mode 100644
index 0000000..8023071
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mmc_core.h
@@ -0,0 +1,657 @@
+/*
+ * 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
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <kernel/mutex.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MMC_BLOCK_BITS_SHFT             (9)
+#define MMC_BLOCK_SIZE                  (1 << MMC_BLOCK_BITS_SHFT)
+#define MMC_MAX_BLOCK_SIZE              (1 << MMC_BLOCK_BITS_SHFT)
+
+#define SDIO_MAX_FUNCS                  (7)
+
+#define SD_CMD_BIT                      (1 << 7)
+#define SD_CMD_APP_BIT                  (1 << 8)
+#define SD_CMD_AUTO_BIT                 (1 << 9)
+
+/* MMC command numbers */
+#define MMC_CMD_GO_IDLE_STATE           (0)              /* bc.   no response */
+#define MMC_CMD_SEND_OP_COND            (1)              /* bcr.  R3          */
+#define MMC_CMD_ALL_SEND_CID            (2)              /* bcr.  R2          */
+#define MMC_CMD_SET_RELATIVE_ADDR       (3)              /* ac.   R1          */
+#define MMC_CMD_SET_DSR                 (4)              /* bc.   no response */
+#define MMC_CMD_SLEEP_AWAKE             (5)              /* ac.   R1b         */
+#define MMC_CMD_SWITCH                  (6)              /* ac.   R1b         */
+#define MMC_CMD_SELECT_CARD             (7)              /* ac.   R1/R1b      */
+#define MMC_CMD_SEND_EXT_CSD            (8)              /* adtc. R1          */
+#define MMC_CMD_SEND_CSD                (9)              /* ac.   R2          */
+#define MMC_CMD_SEND_CID                (10)             /* ac.   R2          */
+#define MMC_CMD_READ_DAT_UNTIL_STOP     (11)             /* adtc. R1          */
+#define MMC_CMD_STOP_TRANSMISSION       (12)             /* ac.   R1/R1b      */
+#define MMC_CMD_SEND_STATUS             (13)             /* ac.   R1          */
+#define MMC_CMD_BUSTEST_R               (14)             /* adtc. R1          */
+#define MMC_CMD_GO_INACTIVE_STATE       (15)             /* ac.   no response */
+#define MMC_CMD_SET_BLOCKLEN            (16)             /* ac.   R1          */
+#define MMC_CMD_READ_SINGLE_BLOCK       (17)             /* adtc. R1          */
+#define MMC_CMD_READ_MULTIPLE_BLOCK     (18)             /* adtc. R1          */
+#define MMC_CMD_BUSTEST_W               (19)             /* adtc. R1          */
+#define MMC_CMD_WRITE_DAT_UNTIL_STOP    (20)             /* adtc. R1          */
+#define MMC_CMD21                       (21)             /* adtc. R1  Sandisk  */
+#define MMC_CMD_SET_BLOCK_COUNT         (23)             /* ac.   R1          */
+#define MMC_CMD_WRITE_BLOCK             (24)             /* adtc. R1          */
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK    (25)             /* adtc. R1          */
+#define MMC_CMD_PROGRAM_CID             (26)             /* adtc. R1          */
+#define MMC_CMD_PROGRAM_CSD             (27)             /* adtc. R1          */
+
+#define MMC_CMD_SET_WRITE_PROT          (28)             /* ac.   R1b         */
+#define MMC_CMD_CLR_WRITE_PROT          (29)             /* ac.   R1b         */
+#define MMC_CMD_SEND_WRITE_PROT         (30)             /* adtc. R1          */
+#define MMC_CMD_SEND_WRITE_PROT_TYPE    (31)             /* adtc. R1          */
+#define MMC_CMD_ERASE_WR_BLK_START      (32)
+#define MMC_CMD_ERASE_WR_BLK_END        (33)
+#define MMC_CMD_ERASE_GROUP_START       (35)             /* ac.   R1          */
+#define MMC_CMD_ERASE_GROUP_END         (36)             /* ac.   R1          */
+#define MMC_CMD_ERASE                   (38)             /* ac.   R1b         */
+#define MMC_CMD_FAST_IO                 (39)             /* ac.   R4          */
+#define MMC_CMD_GO_IRQ_STATE            (40)             /* bcr.  R5          */
+#define MMC_CMD_LOCK_UNLOCK             (42)             /* adtc. R1          */
+#define MMC_CMD50                       (50)             /* adtc. R1 Sandisk */
+#define MMC_CMD_APP_CMD                 (55)             /* ac.   R1          */
+#define MMC_CMD_GEN_CMD                 (56)             /* adtc. R1          */
+
+/* SD Card command numbers */
+#define SD_CMD_SEND_RELATIVE_ADDR       (3 | SD_CMD_BIT)
+#define SD_CMD_SWITCH                   (6 | SD_CMD_BIT)
+#define SD_CMD_SEND_IF_COND             (8 | SD_CMD_BIT)
+#define SD_CMD_VOL_SWITCH               (11 | SD_CMD_BIT)
+#define SD_CMD_SEND_TUNING_BLOCK        (19 | SD_CMD_BIT)
+#define SD_CMD_SPEED_CLASS_CTRL         (20 | SD_CMD_BIT)
+
+#define SD_ACMD_SET_BUSWIDTH            (6  | SD_CMD_APP_BIT)
+#define SD_ACMD_SD_STATUS               (13 | SD_CMD_APP_BIT)
+#define SD_ACMD_SEND_NR_WR_BLOCKS       (22 | SD_CMD_APP_BIT)
+#define SD_ACMD_SET_WR_ERASE_CNT        (23 | SD_CMD_APP_BIT)
+#define SD_ACMD_SEND_OP_COND            (41 | SD_CMD_APP_BIT)
+#define SD_ACMD_SET_CLR_CD              (42 | SD_CMD_APP_BIT)
+#define SD_ACMD_SEND_SCR                (51 | SD_CMD_APP_BIT)
+
+/* SDIO Card command numbers */
+#define SD_IO_SEND_OP_COND              (5 | SD_CMD_BIT) /* bcr. R4           */
+#define SD_IO_RW_DIRECT                 (52 | SD_CMD_BIT)/* ac.  R5           */
+#define SD_IO_RW_EXTENDED               (53 | SD_CMD_BIT)/* adtc. R5          */
+
+/* platform dependent command */
+#define SD_ATOCMD_STOP_TRANSMISSION     (12 | SD_CMD_AUTO_BIT)
+#define SD_ATOCMD_SET_BLOCK_COUNT       (23 | SD_CMD_AUTO_BIT)
+
+#define MMC_VDD_145_150 0x00000001  /* VDD voltage 1.45 - 1.50 */
+#define MMC_VDD_150_155 0x00000002  /* VDD voltage 1.50 - 1.55 */
+#define MMC_VDD_155_160 0x00000004  /* VDD voltage 1.55 - 1.60 */
+#define MMC_VDD_160_165 0x00000008  /* VDD voltage 1.60 - 1.65 */
+#define MMC_VDD_165_170 0x00000010  /* VDD voltage 1.65 - 1.70 */
+#define MMC_VDD_17_18   0x00000020  /* VDD voltage 1.7 - 1.8 */
+#define MMC_VDD_18_19   0x00000040  /* VDD voltage 1.8 - 1.9 */
+#define MMC_VDD_19_20   0x00000080  /* VDD voltage 1.9 - 2.0 */
+#define MMC_VDD_20_21   0x00000100  /* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22   0x00000200  /* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23   0x00000400  /* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24   0x00000800  /* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25   0x00001000  /* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26   0x00002000  /* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27   0x00004000  /* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28   0x00008000  /* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29   0x00010000  /* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30   0x00020000  /* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31   0x00040000  /* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32   0x00080000  /* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33   0x00100000  /* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34   0x00200000  /* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35   0x00400000  /* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36   0x00800000  /* VDD voltage 3.5 ~ 3.6 */
+#define MMC_CARD_BUSY   0x80000000  /* Card Power up status bit */
+#define MMC_VDD_165_195     0x00000080  /* VDD voltage 1.65 - 1.95 */ //Add this line by reference to include/linux/mmc/host.h in linux kernel
+#define MMC_VDD_27_36       0x00FF8000
+
+#define EMMC_VER_50   (50)
+#define EMMC_VER_45   (45)
+#define EMMC_VER_44   (44)
+#define EMMC_VER_43   (43)
+#define EMMC_VER_42   (42)
+#define SD_VER_10     (10)
+#define SD_VER_20     (20)
+#define SD_VER_30     (30)
+
+#define MMC_ERR_NONE          0
+#define MMC_ERR_TIMEOUT       1
+#define MMC_ERR_BADCRC        2
+#define MMC_ERR_FIFO          3
+#define MMC_ERR_FAILED        4
+#define MMC_ERR_INVALID       5
+#define MMC_ERR_CMDTUNEFAIL   6
+#define MMC_ERR_READTUNEFAIL  7
+#define MMC_ERR_WRITETUNEFAIL 8
+#define MMC_ERR_CMD_TIMEOUT   9
+#define MMC_ERR_CMD_RSPCRC    10
+#define MMC_ERR_ACMD_TIMEOUT  11
+#define MMC_ERR_ACMD_RSPCRC   12
+#define MMC_ERR_AXI_RSPCRC    13
+#define MMC_ERR_UNEXPECT      14
+#define MMC_ERR_RETRY         15
+
+#define MMC_POWER_OFF       0
+#define MMC_POWER_UP        1
+#define MMC_POWER_ON        2
+
+#define MMC_BUS_WIDTH_1     0
+#define MMC_BUS_WIDTH_4     2
+
+#define SD_BUS_WIDTH_1      0
+#define SD_BUS_WIDTH_4      2
+
+#define MMC_STATE_PRESENT       (1<<0)      /* present in sysfs */
+#define MMC_STATE_READONLY      (1<<1)      /* card is read-only */
+#define MMC_STATE_HIGHSPEED     (1<<2)      /* card is in high speed mode */
+#define MMC_STATE_BLOCKADDR     (1<<3)      /* card uses block-addressing */
+#define MMC_STATE_HIGHCAPS      (1<<4)
+#define MMC_STATE_UHS1          (1<<5)      /* card is in ultra high speed mode */
+#define MMC_STATE_DDR           (1<<6)      /* card is in ddr mode */
+#define MMC_STATE_HS200         (1<<7)
+#define MMC_STATE_HS400         (1<<8)
+#define MMC_STATE_BACKYARD      (1<<9)
+
+#define R1_OUT_OF_RANGE         (1UL << 31) /* er, c */
+#define R1_ADDRESS_ERROR        (1 << 30)   /* erx, c */
+#define R1_BLOCK_LEN_ERROR      (1 << 29)   /* er, c */
+#define R1_ERASE_SEQ_ERROR      (1 << 28)   /* er, c */
+#define R1_ERASE_PARAM          (1 << 27)   /* ex, c */
+#define R1_WP_VIOLATION         (1 << 26)   /* erx, c */
+#define R1_CARD_IS_LOCKED       (1 << 25)   /* sx, a */
+#define R1_LOCK_UNLOCK_FAILED   (1 << 24)   /* erx, c */
+#define R1_COM_CRC_ERROR        (1 << 23)   /* er, b */
+#define R1_ILLEGAL_COMMAND      (1 << 22)   /* er, b */
+#define R1_CARD_ECC_FAILED      (1 << 21)   /* ex, c */
+#define R1_CC_ERROR             (1 << 20)   /* erx, c */
+#define R1_ERROR                (1 << 19)   /* erx, c */
+#define R1_UNDERRUN             (1 << 18)   /* ex, c */
+#define R1_OVERRUN              (1 << 17)   /* ex, c */
+#define R1_CID_CSD_OVERWRITE    (1 << 16)   /* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP        (1 << 15)   /* sx, c */
+#define R1_CARD_ECC_DISABLED    (1 << 14)   /* sx, a */
+#define R1_ERASE_RESET          (1 << 13)   /* sr, c */
+#define R1_STATUS(x)            (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x)     ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
+#define R1_READY_FOR_DATA       (1 << 8)    /* sx, a */
+#define R1_SWITCH_ERROR         (1 << 7)    /* ex, b */
+#define R1_URGENT_BKOPS         (1 << 6)    /* sr, a */
+#define R1_APP_CMD              (1 << 5)    /* sr, c */
+
+/*
+ * Card Command Classes (CCC)
+ */
+#define CCC_BASIC               (1<<0)  /* (0) Basic protocol functions */
+/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
+#define CCC_STREAM_READ         (1<<1)  /* (1) Stream read commands */
+/* (CMD11) */
+#define CCC_BLOCK_READ          (1<<2)  /* (2) Block read commands */
+/* (CMD16,17,18) */
+#define CCC_STREAM_WRITE        (1<<3)  /* (3) Stream write commands */
+/* (CMD20) */
+#define CCC_BLOCK_WRITE         (1<<4)  /* (4) Block write commands */
+/* (CMD16,24,25,26,27) */
+#define CCC_ERASE               (1<<5)  /* (5) Ability to erase blocks */
+/* (CMD32,33,34,35,36,37,38,39) */
+#define CCC_WRITE_PROT          (1<<6)  /* (6) Able to write protect blocks */
+/* (CMD28,29,30) */
+#define CCC_LOCK_CARD           (1<<7)  /* (7) Able to lock down card */
+/* (CMD16,CMD42) */
+#define CCC_APP_SPEC            (1<<8)  /* (8) Application specific */
+/* (CMD55,56,57,ACMD*) */
+#define CCC_IO_MODE             (1<<9)  /* (9) I/O mode */
+/* (CMD5,39,40,52,53) */
+#define CCC_SWITCH              (1<<10) /* (10) High speed switch */
+/* (CMD6,34,35,36,37,50) */
+/* (11) Reserved */
+/* (CMD?) */
+
+/*
+ * CSD field definitions
+ */
+
+#define CSD_STRUCT_VER_1_0  0   /* Valid for system specification 1.0 - 1.2 */
+#define CSD_STRUCT_VER_1_1  1   /* Valid for system specification 1.4 - 2.2 */
+#define CSD_STRUCT_VER_1_2  2   /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
+#define CSD_STRUCT_EXT_CSD  3   /* Version is coded in CSD_STRUCTURE in EXT_CSD */
+
+#define CSD_SPEC_VER_0      0   /* Implements system specification 1.0 - 1.2 */
+#define CSD_SPEC_VER_1      1   /* Implements system specification 1.4 */
+#define CSD_SPEC_VER_2      2   /* Implements system specification 2.0 - 2.2 */
+#define CSD_SPEC_VER_3      3   /* Implements system specification 3.1 - 3.2 - 3.31 */
+#define CSD_SPEC_VER_4      4   /* Implements system specification 4.0 - 4.1 */
+
+/*
+ * EXT_CSD fields
+ */
+
+#define EXT_CSD_BADBLK_MGMT             134 /* R/W */
+#define EXT_CSD_ENH_START_ADDR          136 /* R/W 4 bytes */
+#define EXT_CSD_ENH_SIZE_MULT           140 /* R/W 3 bytes */
+#define EXT_CSD_GP1_SIZE_MULT           143 /* R/W 3 bytes */
+#define EXT_CSD_GP2_SIZE_MULT           146 /* R/W 3 bytes */
+#define EXT_CSD_GP3_SIZE_MULT           149 /* R/W 3 bytes */
+#define EXT_CSD_GP4_SIZE_MULT           152 /* R/W 3 bytes */
+#define EXT_CSD_PART_SET_COMPL          155 /* R/W */
+#define EXT_CSD_PART_ATTR               156 /* R/W 3 bytes */
+#define EXT_CSD_MAX_ENH_SIZE_MULT       157 /* R/W 3 bytes */
+#define EXT_CSD_PART_SUPPORT            160 /* R */
+#define EXT_CSD_HPI_MGMT                161 /* R/W/E_P (4.41) */
+#define EXT_CSD_RST_N_FUNC              162 /* R/W */
+#define EXT_CSD_BKOPS_EN                163 /* R/W (4.41) */
+#define EXT_CSD_BKOPS_START             164 /* W/E_P (4.41) */
+#define EXT_CSD_WR_REL_PARAM            166 /* R (4.41) */
+#define EXT_CSD_WR_REL_SET              167 /* R/W (4.41) */
+#define EXT_CSD_RPMB_SIZE_MULT          168 /* R */
+#define EXT_CSD_FW_CONFIG               169 /* R/W */
+#define EXT_CSD_USR_WP                  171 /* R/W, R/W/C_P & R/W/E_P */
+#define EXT_CSD_BOOT_WP                 173 /* R/W, R/W/C_P */
+#define EXT_CSD_ERASE_GRP_DEF           175 /* R/W/E */
+#define EXT_CSD_BOOT_BUS_WIDTH          177 /* R/W/E */
+#define EXT_CSD_BOOT_CONFIG_PROT        178 /* R/W & R/W/C_P */
+#define EXT_CSD_PART_CFG                179 /* R/W/E & R/W/E_P */
+#define EXT_CSD_ERASED_MEM_CONT         181 /* R */
+#define EXT_CSD_BUS_WIDTH               183 /* R/W */
+#define EXT_CSD_HS_TIMING               185 /* R/W */
+#define EXT_CSD_PWR_CLASS               187 /* R/W/E_P */
+#define EXT_CSD_CMD_SET_REV             189 /* R */
+#define EXT_CSD_CMD_SET                 191 /* R/W/E_P */
+#define EXT_CSD_REV                     192 /* R */
+#define EXT_CSD_STRUCT                  194 /* R */
+#define EXT_CSD_CARD_TYPE               196 /* RO */
+#define EXT_CSD_OUT_OF_INTR_TIME        198 /* R (4.41) */
+#define EXT_CSD_PART_SWITCH_TIME        199 /* R (4.41) */
+#define EXT_CSD_PWR_CL_52_195           200 /* R */
+#define EXT_CSD_PWR_CL_26_195           201 /* R */
+#define EXT_CSD_PWR_CL_52_360           202 /* R */
+#define EXT_CSD_PWR_CL_26_360           203 /* R */
+#define EXT_CSD_MIN_PERF_R_4_26         205 /* R */
+#define EXT_CSD_MIN_PERF_W_4_26         206 /* R */
+#define EXT_CSD_MIN_PERF_R_8_26_4_25    207 /* R */
+#define EXT_CSD_MIN_PERF_W_8_26_4_25    208 /* R */
+#define EXT_CSD_MIN_PERF_R_8_52         209 /* R */
+#define EXT_CSD_MIN_PERF_W_8_52         210 /* R */
+#define EXT_CSD_SEC_CNT                 212 /* RO, 4 bytes */
+#define EXT_CSD_S_A_TIMEOUT             217 /* R */
+#define EXT_CSD_S_C_VCCQ                219 /* R */
+#define EXT_CSD_S_C_VCC                 220 /* R */
+#define EXT_CSD_HC_WP_GPR_SIZE          221 /* R */
+#define EXT_CSD_REL_WR_SEC_C            222 /* R */
+#define EXT_CSD_ERASE_TIMEOUT_MULT      223 /* R */
+#define EXT_CSD_HC_ERASE_GRP_SIZE       224 /* R */
+#define EXT_CSD_ACC_SIZE                225 /* R */
+#define EXT_CSD_BOOT_SIZE_MULT          226 /* R */
+#define EXT_CSD_BOOT_INFO               228 /* R */
+#define EXT_CSD_SEC_TRIM_MULT           229 /* R */
+#define EXT_CSD_SEC_ERASE_MULT          230 /* R */
+#define EXT_CSD_SEC_FEATURE_SUPPORT     231 /* R */
+#define EXT_CSD_TRIM_MULT               232 /* R */
+#define EXT_CSD_MIN_PERF_DDR_R_8_52     234 /* R */
+#define EXT_CSD_MIN_PERF_DDR_W_8_52     235 /* R */
+#define EXT_CSD_PWR_CL_DDR_52_195       238 /* R */
+#define EXT_CSD_PWR_CL_DDR_52_360       239 /* R */
+#define EXT_CSD_INI_TIMEOUT_AP          241 /* R */
+#define EXT_CSD_CORRECT_PRG_SECTS_NUM   242 /* R, 4 bytes (4.41) */
+#define EXT_CSD_BKOPS_STATUS            246 /* R (4.41) */
+#define EXT_CSD_BKOPS_SUPP              502 /* R (4.41) */
+#define EXT_CSD_HPI_FEATURE             503 /* R (4.41) */
+#define EXT_CSD_S_CMD_SET               504 /* R */
+
+/*
+ * EXT_CSD field definitions
+ */
+
+/* SEC_FEATURE_SUPPORT[231] */
+#define EXT_CSD_SEC_FEATURE_ER_EN       (1<<0)
+#define EXT_CSD_SEC_FEATURE_BD_BLK_EN   (1<<2)
+#define EXT_CSD_SEC_FEATURE_GB_CL_EN    (1<<4)
+
+/* BOOT_INFO[228] */
+#define EXT_CSD_BOOT_INFO_ALT_BOOT      (1<<0)
+#define EXT_CSD_BOOT_INFO_DDR_BOOT      (1<<1)
+#define EXT_CSD_BOOT_INFO_HS_BOOT       (1<<2)
+
+#define EXT_CSD_CMD_SET_NORMAL          (1<<0)
+#define EXT_CSD_CMD_SET_SECURE          (1<<1)
+#define EXT_CSD_CMD_SET_CPSECURE        (1<<2)
+
+#define EXT_CSD_CARD_TYPE_26            (1<<0)  /* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_52            (1<<1)  /* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_DDR_52        (1<<2)  /* Card can run at DDR 52MHz@1.8V or 3V */
+#define EXT_CSD_CARD_TYPE_DDR_52_1_2V   (1<<3)  /* Card can run at DDR 52MHz@1.2V */
+#define EXT_CSD_CARD_TYPE_HS200_1_8V    (1<<4)  /* Card can run at 200MHz@ 1.8V*/
+#define EXT_CSD_CARD_TYPE_HS200_1_2V    (1<<5)  /* Card can run at 200MHz@ 1.2V*/
+#define EXT_CSD_CARD_TYPE_HS400_1_8V    (1<<6)  /* Card can run at 200MHz@ 1.8V*/
+#define EXT_CSD_CARD_TYPE_HS400_1_2V    (1<<7)  /* Card can run at 200MHz@ 1.2V*/
+
+/* BUS_WIDTH[183] */
+#define EXT_CSD_BUS_WIDTH_1             (0) /* Card is in 1 bit mode */
+#define EXT_CSD_BUS_WIDTH_4             (1) /* Card is in 4 bit mode */
+#define EXT_CSD_BUS_WIDTH_8             (2) /* Card is in 8 bit mode */
+#define EXT_CSD_BUS_WIDTH_4_DDR         (5) /* Card is in 4 bit mode + DDR */
+#define EXT_CSD_BUS_WIDTH_8_DDR         (6) /* Card is in 8 bit mode + DDR */
+
+/* high speed timing */
+#define EXT_CSD_HS_TIMEING_BACKWARDS    (0) /* selecting backwards compatibility interface timing */
+#define EXT_CSD_HS_TIMEING_HS           (1) /* selecting high speed  interface timing */
+#define EXT_CSD_HS_TIMEING_HS200        (2) /* selecting hs200 interface timing */
+#define EXT_CSD_HS_TIMEING_HS400        (3) /* selecting hs400 interface timing */
+
+/* ERASED_MEM_CONT[181] */
+#define EXT_CSD_ERASED_MEM_CONT_0       (0)
+#define EXT_CSD_ERASED_MEM_CONT_1       (1)
+
+/* PARTITION CONFIG[179] */
+#define EXT_CSD_PART_CFG_DEFT_PART      (0)
+#define EXT_CSD_PART_CFG_BOOT_PART_1    (1)
+#define EXT_CSD_PART_CFG_BOOT_PART_2    (2)
+#define EXT_CSD_PART_CFG_RPMB_PART      (3)
+#define EXT_CSD_PART_CFG_GP_PART_1      (4)
+#define EXT_CSD_PART_CFG_GP_PART_2      (5)
+#define EXT_CSD_PART_CFG_GP_PART_3      (6)
+#define EXT_CSD_PART_CFG_GP_PART_4      (7)
+#define EXT_CSD_PART_CFG_EN_NO_BOOT     (0 << 3)
+#define EXT_CSD_PART_CFG_EN_BOOT_PART_1 (1 << 3)
+#define EXT_CSD_PART_CFG_EN_BOOT_PART_2 (2 << 3)
+#define EXT_CSD_PART_CFG_EN_USER_AREA   (7 << 3)
+#define EXT_CSD_PART_CFG_EN_NO_ACK      (0 << 6)
+#define EXT_CSD_PART_CFG_EN_ACK         (1 << 6)
+
+/* BOOT_CONFIG_PROT[178] */
+#define EXT_CSD_EN_PWR_BOOT_CFG_PROT    (1)
+#define EXT_CSD_EN_PERM_BOOT_CFG_PROT   (1<<4)  /* Carefully */
+
+/* BOOT_BUS_WIDTH[177] */
+#define EXT_CSD_BOOT_BUS_WIDTH_1        (0)
+#define EXT_CSD_BOOT_BUS_WIDTH_4        (1)
+#define EXT_CSD_BOOT_BUS_WIDTH_8        (2)
+#define EXT_CSD_BOOT_BUS_RESET          (1 << 2)
+
+#define EXT_CSD_BOOT_BUS_MODE_DEFT      (0 << 3)
+#define EXT_CSD_BOOT_BUS_MODE_HS        (1 << 3)
+#define EXT_CSD_BOOT_BUS_MODE_DDR       (2 << 3)
+
+/* ERASE_GROUP_DEF[175] */
+#define EXT_CSD_ERASE_GRP_DEF_EN        (1)
+
+/* BOOT_WP[173] */
+#define EXT_CSD_BOOT_WP_EN_PWR_WP       (1)
+#define EXT_CSD_BOOT_WP_EN_PERM_WP      (1 << 2)
+#define EXT_CSD_BOOT_WP_DIS_PERM_WP     (1 << 4)
+#define EXT_CSD_BOOT_WP_DIS_PWR_WP      (1 << 6)
+
+/* USER_WP[171] */
+#define EXT_CSD_USR_WP_EN_PWR_WP        (1)
+#define EXT_CSD_USR_WP_EN_PERM_WP       (1<<2)
+#define EXT_CSD_USR_WP_DIS_PWR_WP       (1<<3)
+#define EXT_CSD_USR_WP_DIS_PERM_WP      (1<<4)
+#define EXT_CSD_USR_WP_DIS_CD_PERM_WP   (1<<6)
+#define EXT_CSD_USR_WP_DIS_PERM_PWD     (1<<7)
+
+/* RST_n_FUNCTION[162] */
+#define EXT_CSD_RST_N_TEMP_DIS          (0)
+#define EXT_CSD_RST_N_PERM_EN           (1) /* carefully */
+#define EXT_CSD_RST_N_PERM_DIS          (2) /* carefully */
+
+/* PARTITIONING_SUPPORT[160] */
+#define EXT_CSD_PART_SUPPORT_PART_EN     (1)
+#define EXT_CSD_PART_SUPPORT_ENH_ATTR_EN (1<<1)
+
+/* PARTITIONS_ATTRIBUTE[156] */
+#define EXT_CSD_PART_ATTR_ENH_USR       (1<<0)
+#define EXT_CSD_PART_ATTR_ENH_1         (1<<1)
+#define EXT_CSD_PART_ATTR_ENH_2         (1<<2)
+#define EXT_CSD_PART_ATTR_ENH_3         (1<<3)
+#define EXT_CSD_PART_ATTR_ENH_4         (1<<4)
+
+/* PARTITION_SETTING_COMPLETED[156] */
+#define EXT_CSD_PART_SET_COMPL_BIT      (1<<0)
+
+/*
+ * MMC_SWITCH access modes
+ */
+
+#define MMC_SWITCH_MODE_CMD_SET     0x00    /* Change the command set */
+#define MMC_SWITCH_MODE_SET_BITS    0x01    /* Set bits which are 1 in value */
+#define MMC_SWITCH_MODE_CLEAR_BITS  0x02    /* Clear bits which are 1 in value */
+#define MMC_SWITCH_MODE_WRITE_BYTE  0x03    /* Set target to value */
+
+#define MMC_SWITCH_MODE_SDR12       0
+#define MMC_SWITCH_MODE_SDR25       1
+#define MMC_SWITCH_MODE_SDR50       2
+#define MMC_SWITCH_MODE_SDR104      3
+#define MMC_SWITCH_MODE_DDR50       4
+
+#define MMC_SWITCH_MODE_DRV_TYPE_B  0
+#define MMC_SWITCH_MODE_DRV_TYPE_A  1
+#define MMC_SWITCH_MODE_DRV_TYPE_C  2
+#define MMC_SWITCH_MODE_DRV_TYPE_D  3
+
+#define MMC_SWITCH_MODE_CL_200MA    0
+#define MMC_SWITCH_MODE_CL_400MA    1
+#define MMC_SWITCH_MODE_CL_600MA    2
+#define MMC_SWITCH_MODE_CL_800MA    3
+
+/*
+ * MMC_ERASE arguments
+ */
+#define MMC_ERASE_SECURE_REQ        (1 << 31)
+#define MMC_ERASE_GC_REQ            (1 << 15)
+#define MMC_ERASE_DISCARD           (3 << 0)
+#define MMC_ERASE_TRIM              (1 << 0)
+#define MMC_ERASE_NORMAL            (0)
+
+#define HOST_BUS_WIDTH_1            (1)
+#define HOST_BUS_WIDTH_4            (4)
+#define HOST_BUS_WIDTH_8            (8)
+
+#define EMMC_BOOT_PULL_CMD_MODE     (0)
+#define EMMC_BOOT_RST_CMD_MODE      (1)
+
+enum {
+	EMMC_BOOT_PWR_RESET = 0,
+	EMMC_BOOT_RST_N_SIG,
+	EMMC_BOOT_PRE_IDLE_CMD
+};
+
+enum {
+	RESP_NONE = 0,
+	RESP_R1,
+	RESP_R2,
+	RESP_R3,
+	RESP_R4,
+	RESP_R5,
+	RESP_R6,
+	RESP_R7,
+	RESP_R1B
+};
+
+struct mmc_csd {
+	unsigned char  csd_struct;
+	unsigned char  mmca_vsn;
+	unsigned int   max_dtr;             /* max. data transfer rate */
+	unsigned int   read_blkbits;        /* max. read data block length */
+	unsigned int   capacity;            /* card capacity */
+};
+
+struct mmc_ext_csd {
+	unsigned int    sectors;
+	unsigned int    hs_max_dtr;
+	unsigned char   rev;
+	unsigned char   boot_info;
+	unsigned int    boot_part_sz;
+	unsigned int    rpmb_sz;
+	unsigned char   ddr_support;
+	unsigned char   hs400_support;
+	unsigned char   part_cfg;
+	unsigned char   sec_support;
+	unsigned char   reset_en;
+};
+
+#define MMC_CAP_4_BIT_DATA      (1 << 0) /* Can the host do 4 bit transfers */
+#define MMC_CAP_MULTIWRITE      (1 << 1) /* Can accurately report bytes sent to card on error */
+#define MMC_CAP_BYTEBLOCK       (1 << 2) /* Can do non-log2 block sizes */
+#define MMC_CAP_MMC_HIGHSPEED   (1 << 3) /* Can do MMC high-speed timing */
+#define MMC_CAP_SD_HIGHSPEED    (1 << 4) /* Can do SD high-speed timing */
+#define MMC_CAP_8_BIT_DATA      (1 << 5) /* Can the host do 8 bit transfers */
+#define MMC_CAP_SD_UHS1         (1 << 6) /* Can do SD ultra-high-speed timing */
+#define MMC_CAP_DDR             (1 << 7) /* The host support dual data rate */
+#define MMC_CAP_EMMC_HS200      (1 << 8) /* The host support dual data rate */
+#define MMC_CAP_EMMC_HS400      (1 << 9) /* The host support dual data rate */
+
+struct mmc_host {
+	u8 host_id;
+	struct mmc_card *card;
+	u32 max_phys_segs;
+	addr_t base;      /* host base address */
+	addr_t base_top;  /* host base address */
+	u32 caps;         /* Host capabilities */
+	u32 f_min;        /* host min. frequency */
+	u32 f_max;        /* host max. frequency */
+	u32 clk;          /* host clock speed */
+	u32 sclk;         /* SD/MS clock speed */
+	u32 blklen;       /* block len */
+	u32 ocr;          /* current ocr */
+	u32 ocr_avail;    /* available ocr */
+	u32 timeout_ns;   /* data timeout ns */
+	u32 timeout_clks; /* data timeout clks */
+	u8  clksrc;       /* clock source */
+	u8  hclksrc;       /* clock source */
+	u8  curr_part;     /* host current working partition */
+	u8  app_cmd;
+	u32  app_cmd_arg;
+	u32  time_read;
+	void *priv;       /* private data */
+	mutex_t lock;    /* mutex lock for multi-thread */
+	int (*blk_read)(struct mmc_host *host, u8 *dst, u32 src, u32 nblks);
+	int (*blk_write)(struct mmc_host *host, u32 dst, u8 *src, u32 nblks);
+};
+
+#define MMC_TYPE_UNKNOWN    (0)          /* Unknown card */
+#define MMC_TYPE_MMC        (0x00000001) /* MMC card */
+#define MMC_TYPE_SD         (0x00000002) /* SD card */
+#define MMC_TYPE_SDIO       (0x00000004) /* SDIO card */
+
+/* MMC device */
+struct mmc_card {
+	struct mmc_host        *host;       /* the host this device belongs to */
+	unsigned int            nblks;
+	unsigned int            blklen;
+	unsigned int            ocr;
+	unsigned int            maxhz;
+	unsigned int            uhs_mode;
+	unsigned int            rca;        /* relative card address of device */
+	unsigned int            type;       /* card type */
+	unsigned int            sdio_funcs; /* number of SDIO functions */
+	unsigned short          state;      /* (our) card state */
+	unsigned short          ready;      /* card is ready or not */
+	u32                     raw_cid[4]; /* raw card CID */
+	u32                     raw_csd[4]; /* raw card CSD */
+	struct mmc_csd          csd;        /* card specific */
+	struct mmc_ext_csd      ext_csd;    /* mmc v4 extended card specific */
+	u8                      version;    /* the SD card version, 1.0, 2.0, or 3.0*/
+};
+
+struct mmc_command {
+	u32 opcode;
+	u32 arg;
+	u32 rsptyp;
+	u32 resp[4];
+	u32 timeout;
+	u32 retries;    /* max number of retries */
+	u32 error;      /* command error */
+};
+
+struct mmc_data {
+	u8  *buf;
+	struct mmc_command *cmd;
+	u32  blks;
+	u32  timeout;   /* ms */
+};
+
+#define mmc_card_mmc(c)             ((c)->type & MMC_TYPE_MMC)
+#define mmc_card_sd(c)              ((c)->type & MMC_TYPE_SD)
+
+#define mmc_card_set_host(c,h)      ((c)->host = (h))
+#define mmc_card_set_unknown(c)     ((c)->type = MMC_TYPE_UNKNOWN)
+#define mmc_card_set_mmc(c)         ((c)->type |= MMC_TYPE_MMC)
+#define mmc_card_set_sd(c)          ((c)->type |= MMC_TYPE_SD)
+
+#define mmc_card_present(c)         ((c)->state & MMC_STATE_PRESENT)
+#define mmc_card_readonly(c)        ((c)->state & MMC_STATE_READONLY)
+#define mmc_card_backyard(c)        ((c)->state & MMC_STATE_BACKYARD)
+#define mmc_card_highspeed(c)       ((c)->state & MMC_STATE_HIGHSPEED)
+#define mmc_card_uhs1(c)            ((c)->state & MMC_STATE_UHS1)
+#define mmc_card_hs200(c)           ((c)->state & MMC_STATE_HS200)
+#define mmc_card_hs400(c)           ((c)->state & MMC_STATE_HS400)
+#define mmc_card_ddr(c)             ((c)->state & MMC_STATE_DDR)
+#define mmc_card_blockaddr(c)       ((c)->state & MMC_STATE_BLOCKADDR)
+#define mmc_card_highcaps(c)        ((c)->state & MMC_STATE_HIGHCAPS)
+
+#define mmc_card_set_present(c)     ((c)->state |= MMC_STATE_PRESENT)
+#define mmc_card_set_readonly(c)    ((c)->state |= MMC_STATE_READONLY)
+#define mmc_card_set_backyard(c)    ((c)->state |= MMC_STATE_BACKYARD)
+#define mmc_card_set_highspeed(c)   ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_set_uhs1(c)        ((c)->state |= MMC_STATE_UHS1)
+#define mmc_card_set_hs200(c)       ((c)->state |= MMC_STATE_HS200)
+#define mmc_card_set_hs400(c)       ((c)->state |= MMC_STATE_HS400)
+#define mmc_card_set_ddr(c)         ((c)->state |= MMC_STATE_DDR)
+#define mmc_card_set_blockaddr(c)   ((c)->state |= MMC_STATE_BLOCKADDR)
+
+#define mmc_card_clear_present(c)     ((c)->state &= ~MMC_STATE_PRESENT)
+#define mmc_card_clear_readonly(c)    ((c)->state &= ~MMC_STATE_READONLY)
+#define mmc_card_clear_highspeed(c)   ((c)->state &= ~MMC_STATE_HIGHSPEED)
+#define mmc_card_clear_uhs1(c)        ((c)->state &= ~MMC_STATE_UHS1)
+#define mmc_card_clear_hs200(c)       ((c)->state &= ~MMC_STATE_HS200)
+#define mmc_card_clear_hs400(c)       ((c)->state &= ~MMC_STATE_HS400)
+#define mmc_card_clear_ddr(c)         ((c)->state &= ~MMC_STATE_DDR)
+#define mmc_card_clear_blockaddr(c)   ((c)->state &= ~MMC_STATE_BLOCKADDR)
+
+#define mmc_card_clr_ddr(c)         ((c)->state &= ~MMC_STATE_DDR)
+#define mmc_card_clr_speed_mode(c)  ((c)->state &= ~(MMC_STATE_HS400 | MMC_STATE_HS200 | MMC_STATE_UHS1 | MMC_STATE_HIGHSPEED | MMC_STATE_BACKYARD))
+
+#define mmc_card_name(c)            ((c)->cid.prod_name)
+
+#define mmc_op_multi(op)    (((op) == MMC_CMD_READ_MULTIPLE_BLOCK) || \
+        ((op) == MMC_CMD_WRITE_MULTIPLE_BLOCK))
+
+struct mmc_card *emmc_init_stage1(bool *retry_opcond);
+int emmc_init_stage2(struct mmc_card *card, bool retry_opcond);
+int sdmmc_init(u8 host_id);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mmc_ioctl.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mmc_ioctl.h
new file mode 100644
index 0000000..6afd29b
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mmc_ioctl.h
@@ -0,0 +1,76 @@
+#ifndef LINUX_MMC_IOCTL_H
+#define LINUX_MMC_IOCTL_H
+
+#include <sys/types.h>
+#include "generic_ioctl.h"
+
+struct mmc_ioc_cmd {
+	/* Implies direction of data.  true = write, false = read */
+	int write_flag;
+
+	/* Application-specific command.  true = precede with CMD55 */
+	int is_acmd;
+
+	u32 opcode;
+	u32 arg;
+	u32 response[4];  /* CMD response */
+	unsigned int flags;
+	unsigned int blksz;
+	unsigned int blocks;
+
+	/*
+	 * Sleep at least postsleep_min_us useconds, and at most
+	 * postsleep_max_us useconds *after* issuing command.  Needed for
+	 * some read commands for which cards have no other way of indicating
+	 * they're ready for the next command (i.e. there is no equivalent of
+	 * a "busy" indicator for read operations).
+	 */
+	unsigned int postsleep_min_us;
+	unsigned int postsleep_max_us;
+
+	/*
+	 * Override driver-computed timeouts.  Note the difference in units!
+	 */
+	unsigned int data_timeout_ns;
+	unsigned int cmd_timeout_ms;
+
+	/*
+	 * For 64-bit machines, the next member, ``u64 data_ptr``, wants to
+	 * be 8-byte aligned.  Make sure this struct is the same size when
+	 * built for 32-bit.
+	 */
+	u32 __pad;
+
+	/* DAT buffer */
+	u64 data_ptr;
+};
+#define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (u64)(unsigned long) ptr
+
+/**
+ * struct mmc_ioc_multi_cmd - multi command information
+ * @num_of_cmds: Number of commands to send. Must be equal to or less than
+ *	MMC_IOC_MAX_CMDS.
+ * @cmds: Array of commands with length equal to 'num_of_cmds'
+ */
+struct mmc_ioc_multi_cmd {
+	u64 num_of_cmds;
+	struct mmc_ioc_cmd cmds[0];
+};
+
+#define MMC_BLOCK_MAJOR 179
+#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd)
+/*
+ * MMC_IOC_MULTI_CMD: Used to send an array of MMC commands described by
+ *	the structure mmc_ioc_multi_cmd. The MMC driver will issue all
+ *	commands in array in sequence to card.
+ */
+#define MMC_IOC_MULTI_CMD _IOWR(MMC_BLOCK_MAJOR, 1, struct mmc_ioc_multi_cmd)
+/*
+ * Since this ioctl is only meant to enhance (and not replace) normal access
+ * to the mmc bus device, an upper data transfer limit of MMC_IOC_MAX_BYTES
+ * is enforced per ioctl call.  For larger data transfers, use the normal
+ * block device operations.
+ */
+#define MMC_IOC_MAX_BYTES  (512L * 1024)
+#define MMC_IOC_MAX_CMDS    255
+#endif /* LINUX_MMC_IOCTL_H */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mmc_rpmb.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mmc_rpmb.h
new file mode 100644
index 0000000..5ebaa54
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mmc_rpmb.h
@@ -0,0 +1,22 @@
+/*
+ * opyright (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.
+ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/msdc.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/msdc.h
new file mode 100644
index 0000000..e29b04d
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/msdc.h
@@ -0,0 +1,296 @@
+/*
+ * 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
+
+#include <reg.h>
+#include <platform/msdc_cfg.h>
+#include <platform/mt_reg_base.h>
+#include <platform/msdc_reg.h>
+#include <platform/mmc_core.h>
+
+#define CMD_RETRIES                 5
+#define CMD_TIMEOUT                 100    /* 100ms */
+#define PAD_DELAY_MAX 	            32
+
+#define MSDC_DRVN_GEAR0             0
+#define MSDC_DRVN_GEAR1             1
+#define MSDC_DRVN_GEAR2             2
+#define MSDC_DRVN_GEAR3             3
+#define MSDC_DRVN_GEAR4             4
+#define MSDC_DRVN_GEAR5             5
+#define MSDC_DRVN_GEAR6             6
+#define MSDC_DRVN_GEAR7             7
+#define MSDC_DRVN_DONT_CARE         MSDC_DRVN_GEAR0
+
+
+#define MSDC_FIFO_SZ                128
+#define MSDC_FIFO_THD               64
+
+#define PAD_DELAY_MAX		    32
+
+#define MSDC_MS                     0
+#define MSDC_SDMMC                  1
+
+#define MSDC_MODE_UNKNOWN           0
+#define MSDC_MODE_PIO               1
+#define MSDC_MODE_DMA_BASIC         2
+#define MSDC_MODE_DMA_DESC          3
+#define MSDC_MODE_DMA_ENHANCED      4
+
+#define MSDC_BUS_1BITS              0
+#define MSDC_BUS_4BITS              1
+#define MSDC_BUS_8BITS              2
+
+#define MSDC_BRUST_8B               3
+#define MSDC_BRUST_16B              4
+#define MSDC_BRUST_32B              5
+#define MSDC_BRUST_64B              6
+
+#define MSDC_AUTOCMD12              1
+#define MSDC_AUTOCMD23              2
+#define MSDC_AUTOCMD19              3
+
+#define MSDC_PATH_USE_DELAY_LINE    0
+#define MSDC_PATH_USE_ASYNC_FIFO    1
+
+#define TYPE_CMD_RESP_EDGE          0
+#define TYPE_WRITE_CRC_EDGE         1
+#define TYPE_READ_DATA_EDGE         2
+#define TYPE_WRITE_DATA_EDGE        3
+
+#define START_AT_RISING             0
+#define START_AT_FALLING            1
+#define START_AT_RISING_AND_FALLING 2
+#define START_AT_RISING_OR_FALLING  3
+
+/* Tuning Parameter */
+#define DEFAULT_DEBOUNCE            8    /* 8 cycles */
+#define DEFAULT_DTOC                40   /* data timeout counter. 65536x40 sclk. */
+#define DEFAULT_WDOD                0    /* write data output delay. no delay. */
+#define DEFAULT_BSYDLY              8    /* card busy delay. 8 extend sclk */
+
+/* Timeout Parameter */
+#define TMO_IN_CLK_2POWER           20   /* 2^20=1048576 */
+#define EMMC_BOOT_TMO_IN_CLK_2POWER 16   /* 2^16=65536   */
+
+
+/* each PLL have different gears for select
+ * software can used mux interface from clock management module to select */
+enum {
+	MSDC50_CLKSRC4HCLK_26MHZ  = 0,
+	MSDC50_CLKSRC4HCLK_273MHZ,
+	MSDC50_CLKSRC4HCLK_182MHZ,
+	MSDC50_CLKSRC4HCLK_78MHZ,
+	MSDC_DONOTCARE_HCLK,
+	MSDC50_CLKSRC4HCLK_MAX
+};
+
+enum {
+	MSDC50_CLKSRC_26MHZ  = 0,
+	MSDC50_CLKSRC_400MHZ,  /* MSDCPLL_CK */
+	MSDC50_CLKSRC_182MHZ,  /*MSDCPLL_D2 */
+	MSDC50_CLKSRC_136MHZ,
+	MSDC50_CLKSRC_156MHZ,
+	MSDC50_CLKSRC_200MHZ,  /*MSDCPLL_D4 */
+	MSDC50_CLKSRC_100MHZ,
+	MSDC50_CLKSRC_50MHZ,
+	MSDC50_CLKSRC_MAX
+};
+
+/* MSDC0/1/2
+   PLL MUX SEL List */
+enum {
+	MSDC30_CLKSRC_26MHZ   = 0,
+	MSDC30_CLKSRC_200MHZ,
+	MSDC30_CLKSRC_182MHZ,
+	MSDC30_CLKSRC_91MHZ,
+	MSDC30_CLKSRC_156MHZ,
+	MSDC30_CLKSRC_104MHZ,
+	MSDC30_CLKSRC_MAX
+};
+
+#define MSDC_MIN_SCLK             260000
+#define MSDC50_CLKSRC_DEFAULT     MSDC50_CLKSRC_400MHZ
+#define MSDC30_CLKSRC_DEFAULT     MSDC30_CLKSRC_200MHZ
+
+enum MT65XX_POWER_VOL_TAG {
+	VOL_DEFAULT,
+	VOL_0900 = 900,
+	VOL_1000 = 1000,
+	VOL_1100 = 1100,
+	VOL_1200 = 1200,
+	VOL_1300 = 1300,
+	VOL_1350 = 1350,
+	VOL_1500 = 1500,
+	VOL_1800 = 1800,
+	VOL_2000 = 2000,
+	VOL_2100 = 2100,
+	VOL_2500 = 2500,
+	VOL_2800 = 2800,
+	VOL_3000 = 3000,
+	VOL_3300 = 3300,
+	VOL_3400 = 3400,
+	VOL_3500 = 3500,
+	VOL_3600 = 3600
+};
+
+/*--------------------------------------------------------------------------*/
+/* Descriptor Structure                                                     */
+/*--------------------------------------------------------------------------*/
+#define DMA_FLAG_NONE       (0x00000000)
+#define DMA_FLAG_EN_CHKSUM  (0x00000001)
+#define DMA_FLAG_PAD_BLOCK  (0x00000002)
+#define DMA_FLAG_PAD_DWORD  (0x00000004)
+
+#define MSDC_WRITE32(addr, data)    writel(data, addr)
+#define MSDC_READ32(addr)           readl(addr)
+#define MSDC_WRITE8(addr, data)     writeb(data, addr)
+#define MSDC_READ8(addr)            readb(addr)
+
+#define MSDC_SET_BIT32(addr,mask) \
+    do {    \
+        unsigned int tv = MSDC_READ32(addr); \
+        tv |=((u32)(mask)); \
+        MSDC_WRITE32(addr,tv); \
+    } while (0)
+#define MSDC_CLR_BIT32(addr,mask) \
+    do {    \
+        unsigned int tv = MSDC_READ32(addr); \
+        tv &= ~((u32)(mask)); \
+        MSDC_WRITE32(addr,tv); \
+    } while (0)
+
+#define MSDC_SET_FIELD(reg,field,val) \
+    do { \
+        u32 tv = MSDC_READ32(reg); \
+        tv &= ~((u32)(field)); \
+        tv |= ((val) << (__builtin_ffs((u32)(field)) - 1)); \
+        MSDC_WRITE32(reg, tv); \
+    } while (0)
+
+#define MSDC_GET_FIELD(reg,field,val) \
+    do { \
+        u32 tv = MSDC_READ32(reg); \
+        val = ((tv & (field)) >> (__builtin_ffs((u32)(field)) - 1)); \
+    } while (0)
+
+#define MSDC_RETRY(expr,retry,cnt) \
+    do { \
+        uint32_t t = cnt; \
+        uint32_t r = retry; \
+        uint32_t c = cnt; \
+        while (r) { \
+            if (!(expr)) break; \
+            if (c-- == 0) { \
+                r--; spin(200); c = t; \
+            } \
+        } \
+        if (r == 0) \
+            dprintf(CRITICAL, "%s->%d: retry %d times failed!\n", __func__, \
+                    __LINE__, retry); \
+    } while (0)
+
+#define MSDC_RESET() \
+    do { \
+        MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_RST); \
+        MSDC_RETRY(MSDC_READ32(MSDC_CFG) & MSDC_CFG_RST, 5, 1000); \
+    } while (0)
+
+#define MSDC_CLR_INT() \
+    do { \
+        volatile uint32_t val = MSDC_READ32(MSDC_INT); \
+        MSDC_WRITE32(MSDC_INT, val); \
+    } while (0)
+
+#define MSDC_CLR_FIFO() \
+    do { \
+        MSDC_SET_BIT32(MSDC_FIFOCS, MSDC_FIFOCS_CLR); \
+        MSDC_RETRY(MSDC_READ32(MSDC_FIFOCS) & MSDC_FIFOCS_CLR, 5, 1000); \
+    } while (0)
+
+#define MSDC_FIFO_WRITE32(val)  MSDC_WRITE32(MSDC_TXDATA, val)
+#define MSDC_FIFO_READ32()      MSDC_READ32(MSDC_RXDATA)
+#define MSDC_FIFO_WRITE8(val)   MSDC_WRITE8(MSDC_TXDATA, val)
+#define MSDC_FIFO_READ8()       MSDC_READ8(MSDC_RXDATA)
+
+#define MSDC_TXFIFOCNT() \
+    ((MSDC_READ32(MSDC_FIFOCS) & MSDC_FIFOCS_TXCNT) >> 16)
+#define MSDC_RXFIFOCNT() \
+    ((MSDC_READ32(MSDC_FIFOCS) & MSDC_FIFOCS_RXCNT) >> 0)
+
+#define SDC_IS_BUSY()       (MSDC_READ32(SDC_STS) & SDC_STS_SDCBUSY)
+#define SDC_IS_CMD_BUSY()   (MSDC_READ32(SDC_STS) & SDC_STS_CMDBUSY)
+
+#define SDC_SEND_CMD(cmd,arg) \
+    do { \
+        MSDC_WRITE32(SDC_ARG, (arg)); \
+        MSDC_WRITE32(SDC_CMD, (cmd)); \
+    } while (0)
+
+#define MSDC_DMA_ON     MSDC_CLR_BIT32(MSDC_CFG, MSDC_CFG_PIO);
+#define MSDC_DMA_OFF    MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_PIO);
+
+#define MSDC_RELIABLE_WRITE     (0x1 << 0)
+#define MSDC_PACKED             (0x1 << 1)
+#define MSDC_TAG_REQUEST        (0x1 << 2)
+#define MSDC_CONTEXT_ID         (0x1 << 3)
+#define MSDC_FORCED_PROG        (0x1 << 4)
+
+#ifndef MAX
+#define MAX(x, y)   ((x) >= (y))? (x): (y)
+#endif
+
+#ifndef MIN
+#define MIN(x, y)   ((x) <= (y))? (x): (y)
+#endif
+
+int msdc_init(struct mmc_host *host);
+void msdc_config_bus(struct mmc_host *host, u32 width);
+int msdc_dma_transfer(struct mmc_host *host, struct mmc_data *data);
+void msdc_reset_tune_counter(struct mmc_host *host);
+void msdc_hs400_revert_pad_delay(struct mmc_host *host);
+void msdc_prepare_hs400_tuning(struct mmc_host *host);
+int msdc_tune_cmd_data(struct mmc_host *host);
+int msdc_abort_handler(struct mmc_host *host, int abort_card);
+void msdc_config_clock(struct mmc_host *host, int state, u32 hz);
+int msdc_cmd(struct mmc_host *host, struct mmc_command *cmd);
+void msdc_set_timeout(struct mmc_host *host, u32 ns, u32 clks);
+void msdc_set_autocmd(struct mmc_host *host, int cmd);
+int msdc_get_autocmd(struct mmc_host *host);
+#ifdef FEATURE_MMC_CM_TUNING
+int msdc_tune_cmdrsp(struct mmc_host *host, struct mmc_command *cmd);
+#endif
+#ifdef FEATURE_MMC_RD_TUNING
+int msdc_tune_bread(struct mmc_host *host, uchar *dst, ulong src,
+			 ulong nblks);
+int msdc_tune_read(struct mmc_host *host);
+#endif
+#ifdef FEATURE_MMC_WR_TUNING
+int msdc_tune_bwrite(struct mmc_host *host, ulong dst, uchar *src, ulong nblks);
+#endif
+
+#if defined(FEATURE_MMC_RD_TUNING) || defined(FEATURE_MMC_WR_TUNING)
+int msdc_tune_rw_hs400(struct mmc_host *host, uchar *dst, ulong src,
+				ulong nblks, unsigned int rw);
+#endif
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/msdc_cfg.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/msdc_cfg.h
new file mode 100644
index 0000000..9320085
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/msdc_cfg.h
@@ -0,0 +1,45 @@
+/*
+ * 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
+
+/*--------------------------------------------------------------------------*/
+/* Common Definition                                                        */
+/*--------------------------------------------------------------------------*/
+#ifdef MACH_FPGA
+#define FPGA_PLATFORM
+#endif
+
+/* HW deal with the 2K DMA boundary limitation, SW do nothing with it */
+/* Most of eMMC request in lk are sequential access, so it's no need to
+ * use descript DMA mode, I just remove relevant codes. JieWu@20160607 */
+#define MSDC_USE_DMA_MODE
+
+#define FEATURE_MMC_WR_TUNING
+#define FEATURE_MMC_RD_TUNING
+#define FEATURE_MMC_CM_TUNING
+
+/*--------------------------------------------------------------------------*/
+/* Debug Definition                                                         */
+/*--------------------------------------------------------------------------*/
+//#define KEEP_SLIENT_BUILD
+//#define ___MSDC_DEBUG___
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/msdc_reg.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/msdc_reg.h
new file mode 100644
index 0000000..63fbc05
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/msdc_reg.h
@@ -0,0 +1,660 @@
+#ifndef __MSDC_REG_H__
+#define __MSDC_REG_H__
+
+/*--------------------------------------------------------------------------*/
+/* Common Macro                                                             */
+/*--------------------------------------------------------------------------*/
+#define REG_ADDR(x)                     ((volatile u32 *)(host->base + OFFSET_##x))
+
+/*--------------------------------------------------------------------------*/
+/* Register Offset                                                          */
+/*--------------------------------------------------------------------------*/
+#define OFFSET_MSDC_CFG                 (0x0)
+#define OFFSET_MSDC_IOCON               (0x04)
+#define OFFSET_MSDC_PS                  (0x08)
+#define OFFSET_MSDC_INT                 (0x0c)
+#define OFFSET_MSDC_INTEN               (0x10)
+#define OFFSET_MSDC_FIFOCS              (0x14)
+#define OFFSET_MSDC_TXDATA              (0x18)
+#define OFFSET_MSDC_RXDATA              (0x1c)
+#define OFFSET_SDC_CFG                  (0x30)
+#define OFFSET_SDC_CMD                  (0x34)
+#define OFFSET_SDC_ARG                  (0x38)
+#define OFFSET_SDC_STS                  (0x3c)
+#define OFFSET_SDC_RESP0                (0x40)
+#define OFFSET_SDC_RESP1                (0x44)
+#define OFFSET_SDC_RESP2                (0x48)
+#define OFFSET_SDC_RESP3                (0x4c)
+#define OFFSET_SDC_BLK_NUM              (0x50)
+#define OFFSET_SDC_VOL_CHG              (0x54)
+#define OFFSET_SDC_CSTS                 (0x58)
+#define OFFSET_SDC_CSTS_EN              (0x5c)
+#define OFFSET_SDC_DCRC_STS             (0x60)
+#define	OFFSET_SDC_CMD_STS		(0x64)
+#define OFFSET_EMMC_CFG0                (0x70)
+#define OFFSET_EMMC_CFG1                (0x74)
+#define OFFSET_EMMC_STS                 (0x78)
+#define OFFSET_EMMC_IOCON               (0x7c)
+#define OFFSET_SDC_ACMD_RESP            (0x80)
+#define OFFSET_SDC_ACMD19_TRG           (0x84)
+#define OFFSET_SDC_ACMD19_STS           (0x88)
+#define OFFSET_MSDC_DMA_SA_HIGH         (0x8C)
+#define OFFSET_MSDC_DMA_SA              (0x90)
+#define OFFSET_MSDC_DMA_CA              (0x94)
+#define OFFSET_MSDC_DMA_CTRL            (0x98)
+#define OFFSET_MSDC_DMA_CFG             (0x9c)
+#define OFFSET_MSDC_DBG_SEL             (0xa0)
+#define OFFSET_MSDC_DBG_OUT             (0xa4)
+#define OFFSET_MSDC_DMA_LEN             (0xa8)
+#define OFFSET_MSDC_PATCH_BIT0          (0xb0)
+#define OFFSET_MSDC_PATCH_BIT1          (0xb4)
+#define OFFSET_MSDC_PATCH_BIT2          (0xb8)
+#define OFFSET_MSDC_PAD_TUNE0           (0xf0)
+#define OFFSET_MSDC_HW_DBG              (0x110)
+#define OFFSET_MSDC_VERSION             (0x114)
+#define OFFSET_MSDC_ECO_VER             (0x118)
+#define OFFSET_EMMC51_CFG0              (0x204)
+#define OFFSET_EMMC50_CFG0              (0x208)
+#define OFFSET_EMMC50_CFG1              (0x20c)
+#define OFFSET_EMMC50_CFG2              (0x21c)
+#define OFFSET_EMMC50_CFG3              (0x220)
+#define OFFSET_EMMC50_CFG4              (0x224)
+#define	OFFSET_SDC_FIFO_CFG             (0x228)
+
+/*--------------------------------------------------------------------------*/
+/* Register Address                                                         */
+/*--------------------------------------------------------------------------*/
+/* common register */
+#define MSDC_CFG                        REG_ADDR(MSDC_CFG)
+#define MSDC_IOCON                      REG_ADDR(MSDC_IOCON)
+#define MSDC_PS                         REG_ADDR(MSDC_PS)
+#define MSDC_INT                        REG_ADDR(MSDC_INT)
+#define MSDC_INTEN                      REG_ADDR(MSDC_INTEN)
+#define MSDC_FIFOCS                     REG_ADDR(MSDC_FIFOCS)
+#define MSDC_TXDATA                     REG_ADDR(MSDC_TXDATA)
+#define MSDC_RXDATA                     REG_ADDR(MSDC_RXDATA)
+
+/* sdmmc register */
+#define SDC_CFG                         REG_ADDR(SDC_CFG)
+#define SDC_CMD                         REG_ADDR(SDC_CMD)
+#define SDC_ARG                         REG_ADDR(SDC_ARG)
+#define SDC_STS                         REG_ADDR(SDC_STS)
+#define SDC_RESP0                       REG_ADDR(SDC_RESP0)
+#define SDC_RESP1                       REG_ADDR(SDC_RESP1)
+#define SDC_RESP2                       REG_ADDR(SDC_RESP2)
+#define SDC_RESP3                       REG_ADDR(SDC_RESP3)
+#define SDC_BLK_NUM                     REG_ADDR(SDC_BLK_NUM)
+#define SDC_VOL_CHG                     REG_ADDR(SDC_VOL_CHG)
+#define SDC_CSTS                        REG_ADDR(SDC_CSTS)
+#define SDC_CSTS_EN                     REG_ADDR(SDC_CSTS_EN)
+#define SDC_DCRC_STS                    REG_ADDR(SDC_DCRC_STS)
+#define SDC_CMD_STS                     REG_ADDR(SDC_CMD_STS)
+
+/* emmc register*/
+#define EMMC_CFG0                       REG_ADDR(EMMC_CFG0)
+#define EMMC_CFG1                       REG_ADDR(EMMC_CFG1)
+#define EMMC_STS                        REG_ADDR(EMMC_STS)
+#define EMMC_IOCON                      REG_ADDR(EMMC_IOCON)
+
+/* auto command register */
+#define SDC_ACMD_RESP                   REG_ADDR(SDC_ACMD_RESP)
+#define SDC_ACMD19_TRG                  REG_ADDR(SDC_ACMD19_TRG)
+#define SDC_ACMD19_STS                  REG_ADDR(SDC_ACMD19_STS)
+
+/* dma register */
+#define MSDC_DMA_SA_HIGH                REG_ADDR(MSDC_DMA_SA_HIGH)
+#define MSDC_DMA_SA                     REG_ADDR(MSDC_DMA_SA)
+#define MSDC_DMA_CA                     REG_ADDR(MSDC_DMA_CA)
+#define MSDC_DMA_CTRL                   REG_ADDR(MSDC_DMA_CTRL)
+#define MSDC_DMA_CFG                    REG_ADDR(MSDC_DMA_CFG)
+#define MSDC_DMA_LEN                    REG_ADDR(MSDC_DMA_LEN)
+
+/* debug register */
+#define MSDC_DBG_SEL                    REG_ADDR(MSDC_DBG_SEL)
+#define MSDC_DBG_OUT                    REG_ADDR(MSDC_DBG_OUT)
+
+/* misc register */
+#define MSDC_PATCH_BIT0                 REG_ADDR(MSDC_PATCH_BIT0)
+#define MSDC_PATCH_BIT1                 REG_ADDR(MSDC_PATCH_BIT1)
+#define MSDC_PATCH_BIT2                 REG_ADDR(MSDC_PATCH_BIT2)
+#define MSDC_PAD_TUNE0                  REG_ADDR(MSDC_PAD_TUNE0)
+#define MSDC_HW_DBG                     REG_ADDR(MSDC_HW_DBG)
+#define MSDC_VERSION                    REG_ADDR(MSDC_VERSION)
+#define MSDC_ECO_VER                    REG_ADDR(MSDC_ECO_VER)
+
+/* eMMC 5.0 register */
+#define EMMC51_CFG0                     REG_ADDR(EMMC51_CFG0)
+#define EMMC50_CFG0                     REG_ADDR(EMMC50_CFG0)
+#define EMMC50_CFG1                     REG_ADDR(EMMC50_CFG1)
+#define EMMC50_CFG2                     REG_ADDR(EMMC50_CFG2)
+#define EMMC50_CFG3                     REG_ADDR(EMMC50_CFG3)
+#define EMMC50_CFG4                     REG_ADDR(EMMC50_CFG4)
+#define SDC_FIFO_CFG                    REG_ADDR(SDC_FIFO_CFG)
+
+/*--------------------------------------------------------------------------*/
+/* Register Mask                                                            */
+/*--------------------------------------------------------------------------*/
+
+/* MSDC_CFG mask */
+#define MSDC_CFG_MODE                   (0x1  << 0)     /* RW */
+#define MSDC_CFG_CKPDN                  (0x1  << 1)     /* RW */
+#define MSDC_CFG_RST                    (0x1  << 2)     /* A0 */
+#define MSDC_CFG_PIO                    (0x1  << 3)     /* RW */
+#define MSDC_CFG_CKDRVEN                (0x1  << 4)     /* RW */
+#define MSDC_CFG_BV18SDT                (0x1  << 5)     /* RW */
+#define MSDC_CFG_BV18PSS                (0x1  << 6)     /* R  */
+#define MSDC_CFG_CKSTB                  (0x1  << 7)     /* R  */
+#define MSDC_CFG_CKDIV                  (0xfff<< 8)    /* RW */
+#define MSDC_CFG_CKDIV_BITS             (12)
+#define MSDC_CFG_CKMOD                  (0x3  << 20)    /* W1C */
+#define MSDC_CFG_CKMOD_BITS             (2)
+#define MSDC_CFG_CKMOD_HS400            (0x1  << 22)    /* RW */
+#define MSDC_CFG_START_BIT              (0x3  << 23)    /* RW */
+#define MSDC_CFG_SCLK_STOP_DDR          (0x1  << 25)    /* RW */
+#define MSDC_CFG_DVFS_EN                (0x1  << 30)    /* RW */
+
+/* MSDC_IOCON mask */
+#define MSDC_IOCON_SDR104CKS            (0x1  << 0)     /* RW */
+#define MSDC_IOCON_RSPL                 (0x1  << 1)     /* RW */
+#define MSDC_IOCON_R_D_SMPL             (0x1  << 2)     /* RW */
+#define MSDC_IOCON_DDLSEL               (0x1  << 3)     /* RW */
+#define MSDC_IOCON_DDR50CKD             (0x1  << 4)     /* RW */
+#define MSDC_IOCON_R_D_SMPL_SEL         (0x1  << 5)     /* RW */
+#define MSDC_IOCON_W_D_SMPL             (0x1  << 8)     /* RW */
+#define MSDC_IOCON_W_D_SMPL_SEL         (0x1  << 9)     /* RW */
+#define MSDC_IOCON_W_D0SPL              (0x1  << 10)    /* RW */
+#define MSDC_IOCON_W_D1SPL              (0x1  << 11)    /* RW */
+#define MSDC_IOCON_W_D2SPL              (0x1  << 12)    /* RW */
+#define MSDC_IOCON_W_D3SPL              (0x1  << 13)    /* RW */
+#define MSDC_IOCON_R_D0SPL              (0x1  << 16)    /* RW */
+#define MSDC_IOCON_R_D1SPL              (0x1  << 17)    /* RW */
+#define MSDC_IOCON_R_D2SPL              (0x1  << 18)    /* RW */
+#define MSDC_IOCON_R_D3SPL              (0x1  << 19)    /* RW */
+#define MSDC_IOCON_R_D4SPL              (0x1  << 20)    /* RW */
+#define MSDC_IOCON_R_D5SPL              (0x1  << 21)    /* RW */
+#define MSDC_IOCON_R_D6SPL              (0x1  << 22)    /* RW */
+#define MSDC_IOCON_R_D7SPL              (0x1  << 23)    /* RW */
+
+/* MSDC_PS mask */
+#define MSDC_PS_CDEN                    (0x1  << 0)     /* RW */
+#define MSDC_PS_CDSTS                   (0x1  << 1)     /* R  */
+#define MSDC_PS_CDDEBOUNCE              (0xf  << 12)    /* RW */
+#define MSDC_PS_DAT                     (0xff << 16)    /* R  */
+#define MSDC_PS_DAT0            	(0x1  << 16)     /* RU */
+#define MSDC_PS_CMD                     (0x1  << 24)    /* R  */
+#define MSDC_PS_WP                      (0x1UL << 31)   /* R  */
+
+/* MSDC_INT mask */
+#define MSDC_INT_MMCIRQ                 (0x1  << 0)     /* W1C */
+#define MSDC_INT_CDSC                   (0x1  << 1)     /* W1C */
+#define MSDC_INT_ACMDRDY                (0x1  << 3)     /* W1C */
+#define MSDC_INT_ACMDTMO                (0x1  << 4)     /* W1C */
+#define MSDC_INT_ACMDCRCERR             (0x1  << 5)     /* W1C */
+#define MSDC_INT_DMAQ_EMPTY             (0x1  << 6)     /* W1C */
+#define MSDC_INT_SDIOIRQ                (0x1  << 7)     /* W1C */
+#define MSDC_INT_CMDRDY                 (0x1  << 8)     /* W1C */
+#define MSDC_INT_CMDTMO                 (0x1  << 9)     /* W1C */
+#define MSDC_INT_RSPCRCERR              (0x1  << 10)    /* W1C */
+#define MSDC_INT_CSTA                   (0x1  << 11)    /* R   */
+#define MSDC_INT_XFER_COMPL             (0x1  << 12)    /* W1C */
+#define MSDC_INT_DXFER_DONE             (0x1  << 13)    /* W1C */
+#define MSDC_INT_DATTMO                 (0x1  << 14)    /* W1C */
+#define MSDC_INT_DATCRCERR              (0x1  << 15)    /* W1C */
+#define MSDC_INT_ACMD19_DONE            (0x1  << 16)    /* W1C */
+#define MSDC_INT_BDCSERR                (0x1  << 17)    /* W1C */
+#define MSDC_INT_GPDCSERR               (0x1  << 18)    /* W1C */
+#define MSDC_INT_DMAPRO                 (0x1  << 19)    /* W1C */
+#define MSDC_INT_GEAR_OUT_BOUND         (0x1  << 20)    /* W1C */
+#define MSDC_INT_ACMD53_DONE            (0x1  << 21)    /* W1C */
+#define MSDC_INT_ACMD53_FAIL            (0x1  << 22)    /* W1C */
+#define MSDC_INT_AXI_RESP_ERR           (0x1  << 23)    /* W1C */
+
+/* MSDC_INTEN mask */
+#define MSDC_INTEN_MMCIRQ               (0x1  << 0)     /* RW */
+#define MSDC_INTEN_CDSC                 (0x1  << 1)     /* RW */
+#define MSDC_INTEN_ACMDRDY              (0x1  << 3)     /* RW */
+#define MSDC_INTEN_ACMDTMO              (0x1  << 4)     /* RW */
+#define MSDC_INTEN_ACMDCRCERR           (0x1  << 5)     /* RW */
+#define MSDC_INTEN_DMAQ_EMPTY           (0x1  << 6)     /* RW */
+#define MSDC_INTEN_SDIOIRQ              (0x1  << 7)     /* RW */
+#define MSDC_INTEN_CMDRDY               (0x1  << 8)     /* RW */
+#define MSDC_INTEN_CMDTMO               (0x1  << 9)     /* RW */
+#define MSDC_INTEN_RSPCRCERR            (0x1  << 10)    /* RW */
+#define MSDC_INTEN_CSTA                 (0x1  << 11)    /* RW */
+#define MSDC_INTEN_XFER_COMPL           (0x1  << 12)    /* RW */
+#define MSDC_INTEN_DXFER_DONE           (0x1  << 13)    /* RW */
+#define MSDC_INTEN_DATTMO               (0x1  << 14)    /* RW */
+#define MSDC_INTEN_DATCRCERR            (0x1  << 15)    /* RW */
+#define MSDC_INTEN_ACMD19_DONE          (0x1  << 16)    /* RW */
+#define MSDC_INTEN_BDCSERR              (0x1  << 17)    /* RW */
+#define MSDC_INTEN_GPDCSERR             (0x1  << 18)    /* RW */
+#define MSDC_INTEN_DMAPRO               (0x1  << 19)    /* RW */
+#define MSDC_INTEN_GOBOUND              (0x1  << 20)    /* RW */
+#define MSDC_INTEN_ACMD53_DONE          (0x1  << 21)    /* RW */
+#define MSDC_INTEN_ACMD53_FAIL          (0x1  << 22)    /* RW */
+#define MSDC_INTEN_AXI_RESP_ERR         (0x1  << 23)    /* RW */
+
+/* MSDC_FIFOCS mask */
+#define MSDC_FIFOCS_RXCNT               (0xff << 0)     /* R  */
+#define MSDC_FIFOCS_TXCNT               (0xff << 16)    /* R  */
+#define MSDC_FIFOCS_CLR                 (0x1UL << 31)   /* RW */
+
+/* SDC_CFG mask */
+#define SDC_CFG_SDIOINTWKUP             (0x1  << 0)     /* RW */
+#define SDC_CFG_INSWKUP                 (0x1  << 1)     /* RW */
+#define SDC_CFG_WRDTOC                  (0x1fff << 2)  /* RW */
+#define SDC_CFG_BUSWIDTH                (0x3  << 16)    /* RW */
+#define SDC_CFG_SDIO                    (0x1  << 19)    /* RW */
+#define SDC_CFG_SDIOIDE                 (0x1  << 20)    /* RW */
+#define SDC_CFG_INTATGAP                (0x1  << 21)    /* RW */
+#define SDC_CFG_DTOC                    (0xffUL << 24)  /* RW */
+
+/* SDC_CMD mask */
+#define SDC_CMD_OPC                     (0x3f << 0)     /* RW */
+#define SDC_CMD_BRK                     (0x1  << 6)     /* RW */
+#define SDC_CMD_RSPTYP                  (0x7  << 7)     /* RW */
+#define SDC_CMD_DTYP                    (0x3  << 11)    /* RW */
+#define SDC_CMD_RW                      (0x1  << 13)    /* RW */
+#define SDC_CMD_STOP                    (0x1  << 14)    /* RW */
+#define SDC_CMD_GOIRQ                   (0x1  << 15)    /* RW */
+#define SDC_CMD_BLKLEN                  (0xfff << 16)   /* RW */
+#define SDC_CMD_AUTOCMD                 (0x3  << 28)    /* RW */
+#define SDC_CMD_VOLSWTH                 (0x1  << 30)    /* RW */
+#define SDC_CMD_ACMD53                  (0x1UL << 31)   /* RW */
+
+/* SDC_STS mask */
+#define SDC_STS_SDCBUSY                 (0x1  << 0)     /* RW  */
+#define SDC_STS_CMDBUSY                 (0x1  << 1)     /* RW  */
+#define SDC_STS_START_BIT_CRCERR        (0x1  << 2)
+#define SDC_STS_CMD_WR_BUSY             (0x1  << 16)    /* W1C */
+#define SDC_STS_DATA_TIMEOUT_TYPE       (0x3  << 17)    /* RU */
+#define SDC_STS_CMD_TIMEOUT_TYPE        (0x3  << 19)    /* RU */
+#define SDC_STS_SWR_COMPL               (0x1  << 31)    /* RO  */
+
+/* SDC_VOL mask */
+#define SDC_VOL_CHGCNT                  (0xffff << 0)   /* RW  */
+
+/* SDC_DCRC_STS mask */
+#define SDC_DCRC_STS_POS                (0xff << 0)     /* RO */
+#define SDC_DCRC_STS_NEG                (0xff << 8)     /* RO */
+
+/* SDC_CMD_STS mask */
+#define SDC_CMD_STS_RESP_CRC            (0x7f << 0)     /* RU */
+#define SDC_CMD_STS_RESP_INDEX          (0x3f << 7)     /* RU */
+#define SDC_CMD_STS_RESP_ENDBIT         (0x1 << 13)     /* RU */
+#define SDC_CMD_STS_ENDBIT_CHECK        (0x1 << 14)     /* RW */
+#define SDC_CMD_STS_INDEX_CHECK         (0x1 << 15)     /* RW */
+
+/* EMMC_CFG0 mask */
+#define EMMC_CFG0_BOOTSTART             (0x1  << 0)     /* W  */
+#define EMMC_CFG0_BOOTSTOP              (0x1  << 1)     /* W  */
+#define EMMC_CFG0_BOOTMODE              (0x1  << 2)     /* RW */
+#define EMMC_CFG0_BOOTACKDIS            (0x1  << 3)     /* RW */
+#define EMMC_CFG0_BOOTWDLY              (0x7  << 12)    /* RW */
+#define EMMC_CFG0_BOOTSUPP              (0x1  << 15)    /* RW */
+
+/* EMMC_CFG1 mask */
+#define EMMC_CFG1_BOOTDATTMC            (0xfffff << 0)  /* RW */
+#define EMMC_CFG1_BOOTACKTMC            (0xfffUL << 20) /* RW */
+
+/* EMMC_STS mask */
+#define EMMC_STS_BOOTCRCERR             (0x1  << 0)     /* W1C */
+#define EMMC_STS_BOOTACKERR             (0x1  << 1)     /* W1C */
+#define EMMC_STS_BOOTDATTMO             (0x1  << 2)     /* W1C */
+#define EMMC_STS_BOOTACKTMO             (0x1  << 3)     /* W1C */
+#define EMMC_STS_BOOTUPSTATE            (0x1  << 4)     /* R   */
+#define EMMC_STS_BOOTACKRCV             (0x1  << 5)     /* W1C */
+#define EMMC_STS_BOOTDATRCV             (0x1  << 6)     /* R   */
+
+/* EMMC_IOCON mask */
+#define EMMC_IOCON_BOOTRST              (0x1  << 0)     /* RW */
+
+/* SDC_ACMD19_TRG mask */
+#define SDC_ACMD19_TRG_TUNESEL          (0xf  << 0)     /* RW */
+
+/* MSDC_DMA_SA_HIGH */
+#define MSDC_DMA_SURR_ADDR_HIGH4BIT     (0xf  << 0)     /* RW */
+
+/* MSDC_DMA_CTRL mask */
+#define MSDC_DMA_CTRL_START             (0x1  << 0)     /* W  */
+#define MSDC_DMA_CTRL_STOP              (0x1  << 1)     /* W  */
+#define MSDC_DMA_CTRL_RESUME            (0x1  << 2)     /* W  */
+#define MSDC_DMA_CTRL_REDAYM            (0x1  << 3)     /* RO */
+#define MSDC_DMA_CTRL_MODE              (0x1  << 8)     /* RW */
+#define MSDC_DMA_CTRL_ALIGN             (0x1  << 9)     /* RW */
+#define MSDC_DMA_CTRL_LASTBUF           (0x1  << 10)    /* RW */
+#define MSDC_DMA_CTRL_SPLIT1K           (0x1  << 11)    /* RW */
+#define MSDC_DMA_CTRL_BURSTSZ           (0x7  << 12)    /* RW */
+
+/* MSDC_DMA_CFG mask */
+#define MSDC_DMA_CFG_STS                (0x1  << 0)     /* R */
+#define MSDC_DMA_CFG_DECSEN             (0x1  << 1)     /* RW */
+#define MSDC_DMA_CFG_LOCKDISABLE        (0x1  << 2)     /* RW */
+#define MSDC_DMA_CFG_AHBEN              (0x3  << 8)     /* RW */
+#define MSDC_DMA_CFG_ACTEN              (0x3  << 12)    /* RW */
+#define MSDC_DMA_CFG_CS12B              (0x1  << 16)    /* RW */
+
+/* MSDC_PATCH_BIT0 mask */
+#define MSDC_PB0_EN_START_BIT_CHK_SUP   (0x1 << 0)
+#define MSDC_PB0_EN_8BITSUP             (0x1 << 1)
+#define MSDC_PB0_DIS_RECMDWR            (0x1 << 2)
+#define MSDC_PB0_RD_DAT_SEL             (0x1 << 3)
+#define MSDC_PB0_RESV2                  (0x3 << 4)
+#define MSDC_PB0_DESCUP                 (0x1 << 6)
+#define MSDC_PB0_INT_DAT_LATCH_CK_SEL   (0x7 << 7)
+#define MSDC_PB0_CKGEN_MSDC_DLY_SEL     (0x1f<<10)
+#define MSDC_PB0_FIFORD_DIS             (0x1 << 15)
+#define MSDC_PB0_BLKNUM_SEL             (0x1 << 16)
+#define MSDC_PB0_SDIO_INTCSEL           (0x1 << 17)
+#define MSDC_PB0_SDC_BSYDLY             (0xf << 18)
+#define MSDC_PB0_SDC_WDOD               (0xf << 22)
+#define MSDC_PB0_CMDIDRTSEL             (0x1 << 26)
+#define MSDC_PB0_CMDFAILSEL             (0x1 << 27)
+#define MSDC_PB0_SDIO_INTDLYSEL         (0x1 << 28)
+#define MSDC_PB0_SPCPUSH                (0x1 << 29)
+#define MSDC_PB0_DETWR_CRCTMO           (0x1 << 30)
+#define MSDC_PB0_EN_DRVRSP              (0x1 << 31)
+
+/* MSDC_PATCH_BIT1 mask */
+#define MSDC_PB1_WRDAT_CRCS_TA_CNTR     (0x7 << 0)
+#define MSDC_PB1_CMD_RSP_TA_CNTR        (0x7 << 3)
+#define MSDC_PB1_GET_BUSY_MA            (0x1 << 6)
+#define MSDC_PB1_CHECK_BUSY_SEL         (0x1 << 7)
+#define MSDC_PB1_STOP_DLY_SEL           (0xf << 8)
+#define MSDC_PB1_BIAS_EN18IO_28NM       (0x1 << 12)
+#define MSDC_PB1_BIAS_EXT_28NM          (0x1 << 13)
+#define MSDC_PB1_DDR_CMD_FIX_SEL        (0x1 << 14)
+#define MSDC_PB1_RESET_GDMA             (0x1 << 15)
+#define MSDC_PB1_SINGLE_BURST           (0x1 << 16)
+#define MSDC_PB1_FROCE_STOP             (0x1 << 17)
+#define MSDC_PB1_STATE_CLEAR		(0x1 << 19)
+#define MSDC_PB1_POP_MARK_WATER		(0x1 << 20)
+#define MSDC_PB1_DCM_EN                 (0x1 << 21)
+#define MSDC_PB1_AXI_WRAP_CKEN          (0x1 << 22)
+#define MSDC_PB1_CKCLK_GDMA_EN          (0x1 << 23)
+#define MSDC_PB1_CKSPCEN                (0x1 << 24)
+#define MSDC_PB1_CKPSCEN                (0x1 << 25)
+#define MSDC_PB1_CKVOLDETEN             (0x1 << 26)
+#define MSDC_PB1_CKACMDEN               (0x1 << 27)
+#define MSDC_PB1_CKSDEN                 (0x1 << 28)
+#define MSDC_PB1_CKWCTLEN               (0x1 << 29)
+#define MSDC_PB1_CKRCTLEN               (0x1 << 30)
+#define MSDC_PB1_CKSHBFFEN              (0x1UL << 31)
+
+/* MSDC_PATCH_BIT2 mask */
+#define MSDC_PB2_ENHANCEGPD             (0x1 << 0)
+#define MSDC_PB2_SUPPORT64G             (0x1 << 1)
+#define MSDC_PB2_RESPWAITCNT            (0x3 << 2)
+#define MSDC_PB2_CFGRDATCNT             (0x1f << 4)
+#define MSDC_PB2_CFGRDAT                (0x1 << 9)
+#define MSDC_PB2_INTCRESPSEL            (0x1 << 11)
+#define MSDC_PB2_CFGRESPCNT             (0x7 << 12)
+#define MSDC_PB2_CFGRESP                (0x1 << 15)
+#define MSDC_PB2_RESPSTENSEL            (0x7 << 16)
+#define MSDC_PB2_DDR50_SEL              (0x1 << 19)
+#define MSDC_PB2_POPENCNT               (0xf << 20)
+#define MSDC_PB2_CFG_CRCSTS_SEL         (0x1 << 24)
+#define MSDC_PB2_CFGCRCSTSEDGE          (0x1 << 25)
+#define MSDC_PB2_CFGCRCSTSCNT           (0x3 << 26)
+#define MSDC_PB2_CFGCRCSTS              (0x1 << 28)
+#define MSDC_PB2_CRCSTSENSEL            (0x7UL << 29)
+
+#define MSDC_MASK_ACMD53_CRC_ERR_INTR   (0x1<<4)
+#define MSDC_ACMD53_FAIL_ONE_SHOT       (0X1<<5)
+
+/* MSDC_PAD_TUNE mask */
+#define MSDC_PAD_TUNE0_DATWRDLY         (0x1f <<  0)     /* RW */
+#define MSDC_PAD_TUNE0_DELAYEN          (0x1  <<  7)     /* RW */
+#define MSDC_PAD_TUNE0_CMDRRDLY         (0x1fUL << 22)   /* RW */
+
+/* MSDC_HW_DBG_SEL mask */
+#define MSDC_HW_DBG0_SEL                (0xff << 0)
+#define MSDC_HW_DBG1_SEL                (0x3f << 8)
+#define MSDC_HW_DBG2_SEL                (0xff << 16)
+#define MSDC_HW_DBG3_SEL                (0x3f << 24)
+#define MSDC_HW_DBG_WRAPTYPE_SEL        (0x1  << 30)
+
+/* EMMC51_CFG0 mask */
+#define MSDC_EMMC51_CFG_CMDQEN          (0x1    <<  0)
+#define MSDC_EMMC51_CFG_NUM             (0x3f   <<  1)
+#define MSDC_EMMC51_CFG_RSPTYPE         (0x7    <<  7)
+#define MSDC_EMMC51_CFG_DTYPE           (0x3    << 10)
+#define MSDC_EMMC51_CFG_RDATCNT         (0x3ff  << 12)
+#define MSDC_EMMC51_CFG_WDATCNT         (0x3ff  << 22)
+
+/* EMMC50_CFG0 mask */
+#define MSDC_EMMC50_CFG_PADCMD_LATCHCK  (0x1 << 0)
+#define MSDC_EMMC50_CFG_CRC_STS_CNT     (0x3 << 1)
+#define MSDC_EMMC50_CFG_CRC_STS_EDGE    (0x1 << 3)
+#define MSDC_EMMC50_CFG_CRC_STS_SEL     (0x1 << 4)
+#define MSDC_EMMC50_CFG_END_BIT_CHK_CNT (0xf << 5)
+#define MSDC_EMMC50_CFG_CMD_RESP_SEL    (0x1 << 9)
+#define MSDC_EMMC50_CFG_CMD_EDGE_SEL    (0x1 << 10)
+#define MSDC_EMMC50_CFG_ENDBIT_CNT      (0x3ff << 11)
+#define MSDC_EMMC50_CFG_READ_DAT_CNT    (0x7 << 21)
+#define MSDC_EMMC50_CFG_EMMC50_MON_SEL  (0x1 << 24)
+#define MSDC_EMMC50_CFG_TXSKEW_SEL      (0x1 << 29)
+
+/* EMMC50_CFG1 mask */
+#define MSDC_EMMC50_CFG1_CKSWITCH_CNT   (0x7  << 8)
+#define MSDC_EMMC50_CFG1_RDDAT_STOP     (0x1  << 11)
+#define MSDC_EMMC50_CFG1_WAITCLK_CNT    (0xf  << 12)
+#define MSDC_EMMC50_CFG1_DBG_SEL        (0xff << 16)
+#define MSDC_EMMC50_CFG1_PSHCNT         (0x7  << 24)
+#define MSDC_EMMC50_CFG1_PSHPSSEL       (0x1  << 27)
+#define MSDC_EMMC50_CFG1_DSCFG          (0x1  << 28)
+#define MSDC_EMMC50_CFG1_SPARE1         (0x7UL << 29)
+
+/* EMMC50_CFG2_mask */
+/*#define MSDC_EMMC50_CFG2_AXI_GPD_UP             (0x1 << 0)*/
+#define MSDC_EMMC50_CFG2_AXI_IOMMU_WR_EMI       (0x1 << 1)
+#define MSDC_EMMC50_CFG2_AXI_SHARE_EN_WR_EMI    (0x1 << 2)
+#define MSDC_EMMC50_CFG2_AXI_IOMMU_RD_EMI       (0x1 << 7)
+#define MSDC_EMMC50_CFG2_AXI_SHARE_EN_RD_EMI    (0x1 << 8)
+#define MSDC_EMMC50_CFG2_AXI_BOUND_128B         (0x1 << 13)
+#define MSDC_EMMC50_CFG2_AXI_BOUND_256B         (0x1 << 14)
+#define MSDC_EMMC50_CFG2_AXI_BOUND_512B         (0x1 << 15)
+#define MSDC_EMMC50_CFG2_AXI_BOUND_1K           (0x1 << 16)
+#define MSDC_EMMC50_CFG2_AXI_BOUND_2K           (0x1 << 17)
+#define MSDC_EMMC50_CFG2_AXI_BOUND_4K           (0x1 << 18)
+#define MSDC_EMMC50_CFG2_AXI_RD_OUTS_NUM        (0x1f << 19)
+#define MSDC_EMMC50_CFG2_AXI_SET_LEN            (0xf << 24)
+#define MSDC_EMMC50_CFG2_AXI_RESP_ERR_TYPE      (0x3 << 28)
+#define MSDC_EMMC50_CFG2_AXI_BUSY               (0x1 << 30)
+
+/* EMMC50_CFG3_mask */
+#define MSDC_EMMC50_CFG3_OUTS_WR                (0x1f << 0)
+#define MSDC_EMMC50_CFG3_ULTRA_SET_WR           (0x3f << 5)
+#define MSDC_EMMC50_CFG3_PREULTRA_SET_WR        (0x3f << 11)
+#define MSDC_EMMC50_CFG3_ULTRA_SET_RD           (0x3f << 17)
+#define MSDC_EMMC50_CFG3_PREULTRA_SET_RD        (0x3f << 23)
+
+/* EMMC50_CFG4_mask */
+#define MSDC_EMMC50_CFG4_IMPR_ULTRA_SET_WR      (0xff << 0)
+#define MSDC_EMMC50_CFG4_IMPR_ULTRA_SET_RD      (0xff << 8)
+#define MSDC_EMMC50_CFG4_ULTRA_EN               (0x3  << 16)
+#define MSDC_EMMC50_CFG4_AXI_WRAP_DBG_SEL       (0x1f << 18)
+
+/* SDC_FIFO_CFG mask */
+#define SDC_FIFO_CFG_EMMC50_BLOCK_LENGTH        (0x1ff << 0)
+#define SDC_FIFO_CFG_WR_PTR_MARGIN              (0xff << 16)
+#define SDC_FIFO_CFG_WR_VALID_SEL               (0x1 << 24)
+#define SDC_FIFO_CFG_RD_VALID_SEL               (0x1 << 25)
+#define SDC_FIFO_CFG_WR_VALID                   (0x1 << 26)
+#define SDC_FIFO_CFG_RD_VALID                   (0x1 << 27)
+
+/*
+ *MSDC TOP REG
+ */
+#define REG_ADDR_TOP(x)                 ((volatile u32*)(host->base_top + OFFSET_##x))
+
+/* TOP REGISTER */
+#define OFFSET_EMMC_TOP_CONTROL         (0x00)
+#define OFFSET_EMMC_TOP_CMD             (0x04)
+#define OFFSET_TOP_EMMC50_PAD_CTL0      (0x08)
+#define OFFSET_TOP_EMMC50_PAD_DS_TUNE   (0x0c)
+#define OFFSET_TOP_EMMC50_PAD_DAT0_TUNE (0x10)
+#define OFFSET_TOP_EMMC50_PAD_DAT1_TUNE (0x14)
+#define OFFSET_TOP_EMMC50_PAD_DAT2_TUNE (0x18)
+#define OFFSET_TOP_EMMC50_PAD_DAT3_TUNE (0x1c)
+#define OFFSET_TOP_EMMC50_PAD_DAT4_TUNE (0x20)
+#define OFFSET_TOP_EMMC50_PAD_DAT5_TUNE (0x24)
+#define OFFSET_TOP_EMMC50_PAD_DAT6_TUNE (0x28)
+#define OFFSET_TOP_EMMC50_PAD_DAT7_TUNE (0x2c)
+
+#define EMMC_TOP_CONTROL                REG_ADDR_TOP(EMMC_TOP_CONTROL)
+#define EMMC_TOP_CMD                    REG_ADDR_TOP(EMMC_TOP_CMD)
+#define TOP_EMMC50_PAD_CTL0             REG_ADDR_TOP(TOP_EMMC50_PAD_CTL0)
+#define TOP_EMMC50_PAD_DS_TUNE          REG_ADDR_TOP(TOP_EMMC50_PAD_DS_TUNE)
+#define TOP_EMMC50_PAD_DAT0_TUNE        REG_ADDR_TOP(TOP_EMMC50_PAD_DAT0_TUNE)
+#define TOP_EMMC50_PAD_DAT1_TUNE        REG_ADDR_TOP(TOP_EMMC50_PAD_DAT1_TUNE)
+#define TOP_EMMC50_PAD_DAT2_TUNE        REG_ADDR_TOP(TOP_EMMC50_PAD_DAT2_TUNE)
+#define TOP_EMMC50_PAD_DAT3_TUNE        REG_ADDR_TOP(TOP_EMMC50_PAD_DAT3_TUNE)
+#define TOP_EMMC50_PAD_DAT4_TUNE        REG_ADDR_TOP(TOP_EMMC50_PAD_DAT4_TUNE)
+#define TOP_EMMC50_PAD_DAT5_TUNE        REG_ADDR_TOP(TOP_EMMC50_PAD_DAT5_TUNE)
+#define TOP_EMMC50_PAD_DAT6_TUNE        REG_ADDR_TOP(TOP_EMMC50_PAD_DAT6_TUNE)
+#define TOP_EMMC50_PAD_DAT7_TUNE        REG_ADDR_TOP(TOP_EMMC50_PAD_DAT7_TUNE)
+
+
+/* EMMC_TOP_CONTROL mask */
+#define PAD_RXDLY_SEL           (0x1 << 0)      /* RW */
+#define DELAY_EN                (0x1 << 1)      /* RW */
+#define PAD_DAT_RD_RXDLY2       (0x1f << 2)     /* RW */
+#define PAD_DAT_RD_RXDLY        (0x1f << 7)     /* RW */
+#define PAD_DAT_RD_RXDLY2_SEL   (0x1 << 12)     /* RW */
+#define PAD_DAT_RD_RXDLY_SEL    (0x1 << 13)     /* RW */
+#define DATA_K_VALUE_SEL        (0x1 << 14)     /* RW */
+#define SDC_RX_ENH_EN           (0x1 << 15)     /* RW */
+
+/* EMMC_TOP_CMD mask */
+#define PAD_CMD_RXDLY2          (0x1f << 0)     /* RW */
+#define PAD_CMD_RXDLY           (0x1f << 5)     /* RW */
+#define PAD_CMD_RD_RXDLY2_SEL   (0x1 << 10)     /* RW */
+#define PAD_CMD_RD_RXDLY_SEL    (0x1 << 11)     /* RW */
+#define PAD_CMD_TX_DLY          (0x1f << 12)    /* RW */
+
+/* TOP_EMMC50_PAD_CTL0 mask */
+#define HL_SEL                  (0x1 << 0)      /* RW */
+#define DCC_SEL                 (0x1 << 1)      /* RW */
+#define DLN1                    (0x3 << 2)      /* RW */
+#define DLN0                    (0x3 << 4)      /* RW */
+#define DLP1                    (0x3 << 6)      /* RW */
+#define DLP0                    (0x3 << 8)      /* RW */
+#define PAD_CLK_TXDLY           (0x1f << 10)    /* RW */
+
+/* TOP_EMMC50_PAD_DS_TUNE mask */
+#define PAD_DS_DLY3             (0x1f << 0)     /* RW */
+#define PAD_DS_DLY2             (0x1f << 5)     /* RW */
+#define PAD_DS_DLY1             (0x1f << 10)    /* RW */
+#define PAD_DS_DLY2_SEL         (0x1 << 15)     /* RW */
+#define PAD_DS_DLY_SEL          (0x1 << 16)     /* RW */
+
+/* TOP_EMMC50_PAD_DAT0_TUNE mask */
+#define DAT0_RD_DLY2            (0x1f << 0)     /* RW */
+#define DAT0_RD_DLY1            (0x1f << 5)     /* RW */
+#define PAD_DAT0_TX_DLY         (0x1f << 10)    /* RW */
+
+/* TOP_EMMC50_PAD_DAT1_TUNE mask */
+#define DAT1_RD_DLY2            (0x1f << 0)     /* RW */
+#define DAT1_RD_DLY1            (0x1f << 5)     /* RW */
+#define PAD_DAT1_TX_DLY         (0x1f << 10)    /* RW */
+
+/* TOP_EMMC50_PAD_DAT2_TUNE mask */
+#define DAT2_RD_DLY2            (0x1f << 0)     /* RW */
+#define DAT2_RD_DLY1            (0x1f << 5)     /* RW */
+#define PAD_DAT2_TX_DLY         (0x1f << 10)    /* RW */
+
+/* TOP_EMMC50_PAD_DAT3_TUNE mask */
+#define DAT3_RD_DLY2            (0x1f << 0)     /* RW */
+#define DAT3_RD_DLY1            (0x1f << 5)     /* RW */
+#define PAD_DAT3_TX_DLY         (0x1f << 10)    /* RW */
+
+/* TOP_EMMC50_PAD_DAT4_TUNE mask */
+#define DAT4_RD_DLY2            (0x1f << 0)     /* RW */
+#define DAT4_RD_DLY1            (0x1f << 5)     /* RW */
+#define PAD_DAT4_TX_DLY         (0x1f << 10)    /* RW */
+
+/* TOP_EMMC50_PAD_DAT5_TUNE mask */
+#define DAT5_RD_DLY2            (0x1f << 0)     /* RW */
+#define DAT5_RD_DLY1            (0x1f << 5)     /* RW */
+#define PAD_DAT5_TX_DLY         (0x1f << 10)    /* RW */
+
+/* TOP_EMMC50_PAD_DAT6_TUNE mask */
+#define DAT6_RD_DLY2            (0x1f << 0)     /* RW */
+#define DAT6_RD_DLY1            (0x1f << 5)     /* RW */
+#define PAD_DAT6_TX_DLY         (0x1f << 10)    /* RW */
+
+/* TOP_EMMC50_PAD_DAT7_TUNE mask */
+#define DAT7_RD_DLY2            (0x1f << 0)     /* RW */
+#define DAT7_RD_DLY1            (0x1f << 5)     /* RW */
+#define PAD_DAT7_TX_DLY         (0x1f << 10)    /* RW */
+
+/* MT8183 Platform */
+#define MSDC0_GPIO_BASE			(IO_PHYS + 0x1F30000)
+#define MSDC0_IES_ADDR			(MSDC0_GPIO_BASE + 0x0)
+#define MSDC0_IES_MASK			(0x1F)
+#define MSDC0_SMT_ADDR			(MSDC0_GPIO_BASE + 0x10)
+#define MSDC0_SMT_MASK			(0x1F)
+
+#define MSDC0_PULLEN_ADDR		(MSDC0_GPIO_BASE + 0x60)
+#define MSDC0_PULLEN_MASK		(0xFFF)
+
+#define MSDC0_PULLSEL_ADDR		(MSDC0_GPIO_BASE + 0x80)
+#define MSDC0_PULLSEL_MASK		(0xFFF)
+
+#define MSDC0_PUPD0_ADDR		(MSDC0_GPIO_BASE + 0xC0)
+#define MSDC0_PUPD_CMD_MASK		(0x7 << 0)
+#define MSDC0_PUPD_DAT0_MASK		(0x7 << 4)
+#define MSDC0_PUPD_CLK_MASK		(0x7 << 8)
+#define MSDC0_PUPD_DAT2_MASK		(0x7 << 12)
+#define MSDC0_PUPD_DAT4_MASK		(0x7 << 16)
+#define MSDC0_PUPD_DAT6_MASK		(0x7 << 20)
+#define MSDC0_PUPD_DAT1_MASK		(0x7 << 24)
+#define MSDC0_PUPD_DAT5_MASK		(0x7 << 28)
+
+#define MSDC0_PUPD1_ADDR		(MSDC0_GPIO_BASE + 0xD0)
+#define MSDC0_PUPD_DAT7_MASK		(0x7 << 0)
+#define MSDC0_PUPD_DSL_MASK		(0x7 << 4)
+#define MSDC0_PUPD_DAT3_MASK		(0x7 << 8)
+#define MSDC0_PUPD_RSTB_MASK		(0x7 << 12)
+
+#define MSDC0_DRV7_ADDR		(MSDC0_GPIO_BASE + 0xA0)
+#define MSDC0_CMD_DRV_MASK	(0xF << 0)
+#define MSDC0_DAT_DRV_MASK	(0xF << 4)
+#define MSDC0_CLK_DRV_MASK	(0xF << 8)
+#define MSDC0_DSL_DRV_MASK	(0xF << 12)
+#define MSDC0_RSTB_DRV_MASK	(0xF << 16)
+
+#define MSDC0_GPIO_MODE16_ADDR	(IO_PHYS + 0x00053F0)
+#define MSDC0_DAT6_MODE_MASK	(0xF << 28)
+#define MSDC0_DAT4_MODE_MASK	(0xF << 24)
+#define MSDC0_DAT2_MODE_MASK	(0xF << 20)
+#define MSDC0_CLK_MODE_MASK	(0xF << 16)
+#define MSDC0_DAT0_MODE_MASK	(0xF << 12)
+#define MSDC0_CMD_MODE_MASK	(0xF << 8)
+
+#define MSDC0_GPIO_MODE17_ADDR	(IO_PHYS + 0x0005400)
+#define MSDC0_RSTB_MODE_MASK	(0xF << 20)
+#define MSDC0_DAT3_MODE_MASK	(0xF << 16)
+#define MSDC0_DSL_MODE_MASK	(0xF << 12)
+#define MSDC0_DAT7_MODE_MASK	(0xF << 8)
+#define MSDC0_DAT5_MODE_MASK	(0xF << 4)
+#define MSDC0_DAT1_MODE_MASK	(0xF << 0)
+
+#define MSDC0_TDSEL6_ADDR	(MSDC0_GPIO_BASE + 0xB60)
+#define MSDC0_CLK_TDSEL_MASK	(0xF << 12)
+#define MSDC0_CMD_TDSEL_MASK	(0xF << 8)
+#define MSDC0_TDSEL7_ADDR	(MSDC0_GPIO_BASE + 0xB70)
+#define MSDC0_DAT_TDSEL_MASK	(0xF)
+#define MSDC0_RST_TDSEL_MASK	(0xF << 4)
+#define MSDC0_DS_TDSEL_MASK	(0xF << 8)
+
+#define MSDC0_RDSELE_ADDR	(MSDC0_GPIO_BASE + 0xCE0)
+#define MSDC0_CMD_RDSEL_MASK	(0x3F <<8)
+#define MSDC0_CLK_RDSEL_MASK	(0x3F)
+
+#define MSDC0_RDSELF_ADDR	(MSDC0_GPIO_BASE + 0xCF0)
+#define MSDC0_RST_RDSEL_MASK	(0x3F <<8)
+#define MSDC0_DAT_RDSEL_MASK	(0x3F)
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt6358.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt6358.h
new file mode 100644
index 0000000..fc4f57a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt6358.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#ifndef __MT6358_H
+#define __MT6358_H
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+enum {
+	PMIC_SWCID                    = 0x000a,
+	PMIC_VM_MODE                  = 0x004e,
+	PMIC_TOP_RST_MISC             = 0x014c,
+	PMIC_TOP_RST_MISC_SET         = 0x014e,
+	PMIC_TOP_RST_MISC_CLR         = 0x0150,
+	PMIC_TOP_TMA_KEY              = 0x03a8,
+	PMIC_PWRHOLD                  = 0x0a08,
+	PMIC_CPSDSA4                  = 0x0a2e,
+	PMIC_VDRAM1_VOSEL_SLEEP       = 0x160a,
+	PMIC_SMPS_ANA_CON0            = 0x1808,
+};
+
+enum {
+	MTK_REGULATOR_VSRAM_OTHERS,
+	MTK_REGULATOR_VCORE,
+	MTK_REGULATOR_VDRAM1,
+	MTK_REGULATOR_VDRAM2,
+	MTK_REGULATOR_LDO_SUPPORT = MTK_REGULATOR_VDRAM2,
+	MTK_REGULATOR_VIO18,
+	MTK_REGULATOR_VRF12,
+	MTK_REGULATOR_VCN18,
+	MTK_REGULATOR_VCN33,
+	MTK_REGULATOR_MAX_NR,
+};
+
+struct pmic_setting {
+	unsigned short addr;
+	unsigned short val;
+	unsigned short mask;
+	unsigned char shift;
+};
+
+int mt6358_init(void);
+void pmic_set_power_hold(bool enable);
+u16 pmic_read_interface (u16 RegNum, u16 *val, u16 MASK, u16 SHIFT);
+u16 pmic_config_interface (u16 RegNum, u16 val, u16 MASK, u16 SHIFT);
+u16 get_dram_type(void);
+
+#endif /* __MT6358_H */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt6771.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt6771.h
new file mode 100644
index 0000000..70be843
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt6771.h
@@ -0,0 +1,104 @@
+/*

+ * Copyright (c) 2018 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 <compiler.h>

+#include <debug.h>

+

+#if LK_AS_BL33 == 0 /* LK as BL2 */

+/* program memory: L2C for BL2 */

+#define MEMORY_BASE_PHYS     (0x200000)

+#define MEMORY_APERTURE_SIZE (0x80000UL)

+

+/* internal SRAM */

+#define SRAM_BASE_PHYS (0x100000)

+#define SRAM_BASE_SIZE (0x30000UL)

+

+#else /* LK as BL33 */

+

+/* program memory and memory before mempool */

+#define MEMORY_BASE_PHYS        (0x40000000)

+#define MEMORY_APERTURE_SIZE    (0xC300000UL)

+

+/* non-secure accessible internal SRAM region */

+#define SRAM_BASE_PHYS          (0x118000)

+#define SRAM_BASE_SIZE          (0x18000UL)

+#endif

+

+typedef enum {

+    BR_POWER_KEY = 0,

+    BR_USB,

+    BR_RTC,

+    BR_WDT,

+    BR_WDT_BY_PASS_PWK,

+    BR_TOOL_BY_PASS_PWK,

+    BR_2SEC_REBOOT,

+    BR_UNKNOWN,

+    BR_KERNEL_PANIC,

+    BR_WDT_SW,

+    BR_WDT_HW

+} boot_reason_t;

+

+/* register */

+#define REGISTER_BASE_PHYS (0x8000000)

+#define REGISTER_BASE_SIZE (0x4000000UL)

+

+

+/* peripheral */

+#define PERIPHERAL_BASE_PHYS (0x10000000)

+#define PERIPHERAL_BASE_SIZE (0x10000000UL)

+

+/* gic+peripheral */

+#define GIC_PERIPHERAL_BASE_PHYS (0xC000000)

+#define GIC_PERIPHERAL_BASE_SIZE (0x10000000UL)

+

+/* dram */

+#define DRAM_BASE_PHY  (0x40000000UL)

+

+#if WITH_KERNEL_VM

+#define MEMORY_BASE_VIRT        (KERNEL_ASPACE_BASE + MEMORY_BASE_PHYS)

+#define SRAM_BASE_VIRT          (KERNEL_ASPACE_BASE + 0x300000)

+#define REGISTER_BASE_VIRT       (KERNEL_ASPACE_BASE + REGISTER_BASE_PHYS)

+#define PERIPHERAL_BASE_VIRT     (KERNEL_ASPACE_BASE + PERIPHERAL_BASE_PHYS)

+#define GIC_PERIPHERAL_BASE_VIRT (KERNEL_ASPACE_BASE + 0xC000000)

+#define DRAM_BASE_VIRT           (KERNEL_ASPACE_BASE + DRAM_BASE_PHY)

+

+#else

+#define MEMORY_BASE_VIRT         MEMORY_BASE_PHYS

+#define SRAM_BASE_VIRT           SRAM_BASE_PHYS

+#define REGISTER_BASE_VIRT       REGISTER_BASE_PHYS

+#define PERIPHERAL_BASE_VIRT     PERIPHERAL_BASE_PHYS

+#define GIC_PERIPHERAL_BASE_VIRT GIC_PERIPHERAL_BASE_PHYS

+#define DRAM_BASE_VIRT           DRAM_BASE_PHY

+#endif

+

+#define SRAM_ARENA_BASE         SRAM_BASE_PHYS

+#define SRAM_ARENA_SIZE         SRAM_BASE_SIZE

+#define DRAM_ARENA_BASE         DRAM_BASE_PHY

+#define DRAM_ARENA_SIZE         SRAM_BASE_SIZE

+

+/* interrupts */

+#define ARM_GENERIC_TIMER_VIRTUAL_INT 27

+#define ARM_GENERIC_TIMER_PHYSICAL_INT 30

+

+#define MAX_INT 256

+

diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_gpt.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_gpt.h
new file mode 100644
index 0000000..c06138c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_gpt.h
@@ -0,0 +1,90 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2015. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ */
+
+#ifndef __MT6575_GPT_H__
+#define __MT6575_GPT_H__
+#include <sys/types.h>
+#include <stdbool.h>
+
+#define GPT_IRQEN_REG       ((volatile unsigned int*)(APXGPT_BASE))
+#define GPT_IRQSTA_REG      ((volatile unsigned int*)(APXGPT_BASE+0x04))
+#define GPT_IRQACK_REG      ((volatile unsigned int*)(APXGPT_BASE+0x08))
+
+#define GPT5_CON_REG        ((volatile unsigned int*)(APXGPT_BASE+0x50))
+#define GPT5_CLK_REG        ((volatile unsigned int*)(APXGPT_BASE+0x54))
+#define GPT5_COUNT_REG      ((volatile unsigned int*)(APXGPT_BASE+0x58))
+#define GPT5_COMPARE_REG    ((volatile unsigned int*)(APXGPT_BASE+0x5C))
+
+#define GPT_MODE4_ONE_SHOT (0x00 << 4)
+#define GPT_MODE4_REPEAT   (0x01 << 4)
+#define GPT_MODE4_KEEP_GO  (0x02 << 4)
+#define GPT_MODE4_FREERUN  (0x03 << 4)
+
+#define GPT_CLEAR       2
+
+#define GPT_ENABLE      1
+#define GPT_DISABLE     0
+
+#define GPT_CLK_SYS     (0x0 << 4)
+#define GPT_CLK_RTC     (0x1 << 4)
+
+#define GPT_DIV_BY_1        0
+#define GPT_DIV_BY_2        1
+
+#define CNTPCT_BIT_MASK_L 0x00000000FFFFFFFF
+#define CNTPCT_1US_TICK       ((unsigned int)13)           //    1000 / 76.92ns = 13.000
+#define CNTPCT_1MS_TICK       ((unsigned int)13000)        // 1000000 / 76.92ns = 13000.520
+
+static inline unsigned long long arch_counter_get_cntpct(void)
+{
+	unsigned long long cval;
+
+	__asm__ __volatile__("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
+	return cval;
+}
+
+extern void gpt_busy_wait_us(unsigned int timeout_us);
+extern void gpt_busy_wait_ms(unsigned int timeout_ms);
+
+extern unsigned long get_timer(unsigned long base);
+extern void mdelay(unsigned long msec);
+extern void udelay(unsigned long usec);
+extern void mtk_timer_init(void);
+
+void gpt_one_shot_irq(unsigned int ms);
+int gpt_irq_init(void);
+void gpt_irq_ack(void);
+extern unsigned int gpt4_tick2time_us (unsigned int tick);
+extern unsigned int gpt4_get_current_tick (void);
+extern bool gpt4_timeout_tick (unsigned int start_tick, unsigned int timeout_tick);
+extern unsigned int gpt4_time2tick_us (unsigned int time_us);
+
+#endif  /* !__MT6575_GPT_H__ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_irq.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_irq.h
new file mode 100644
index 0000000..2127fad
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_irq.h
@@ -0,0 +1,90 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2015. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ */
+
+#ifndef __MT_IRQ_H__
+#define __MT_IRQ_H__
+
+#include <stdint.h>
+
+#define GIC_DIST_CTRL           0x000
+#define GIC_DIST_ENABLE_SET     0x100
+#define GIC_DIST_ENABLE_CLEAR       0x180
+#define GIC_DIST_PENDING_SET        0x200
+#define GIC_DIST_PENDING_CLEAR      0x280
+#define GIC_DIST_ACTIVE_SET        0x300
+#define GIC_DIST_ACTIVE_CLEAR      0x380
+#define GIC_DIST_PRI            0x400
+#define GIC_DIST_CONFIG         0xc00
+#define GIC_DIST_IGRPMODR       0xd00
+#define GIC_DIST_ROUTE          0x6100
+#define GIC_REDIS_WAKER         0x14
+
+#define INT_POL_CTL0  (MCUCFG_BASE + 0xA80)
+
+/*
+ * Define hadware registers.
+ */
+
+/*
+ * Define IRQ code.
+ */
+
+#define GIC_PRIVATE_SIGNALS (32)
+
+#define GIC_PPI_OFFSET          (27)
+#define GIC_PPI_GLOBAL_TIMER    (GIC_PPI_OFFSET + 0)
+#define GIC_PPI_LEGACY_FIQ      (GIC_PPI_OFFSET + 1)
+#define GIC_PPI_PRIVATE_TIMER   (GIC_PPI_OFFSET + 2)
+#define GIC_PPI_WATCHDOG_TIMER  (GIC_PPI_OFFSET + 3)
+#define GIC_PPI_LEGACY_IRQ      (GIC_PPI_OFFSET + 4)
+
+
+#define MT_GPT_IRQ_ID   208
+#define SSUSB_DEV_INT_ID  104
+#define SSUSB_XHCI_INT_B_ID  73
+#define MT_NFI_IRQ_ID   128 /* fixme: need to confirm after SB do nand flash boot */
+#define MT_MSDC0_IRQ_ID 109
+#define MT_MSDC1_IRQ_ID 110
+
+#define MT_NR_PPI   (5)
+#define MT_NR_SPI   (241)//(224)
+#define NR_IRQ_LINE  (GIC_PPI_OFFSET + MT_NR_PPI + MT_NR_SPI)    // 5 PPIs and 224 SPIs
+
+#define EDGE_SENSITIVE 0
+#define LEVEL_SENSITIVE 1
+
+#define MT65xx_POLARITY_LOW   0
+#define MT65xx_POLARITY_HIGH  1
+
+void mt_irq_set_sens(unsigned int irq, unsigned int sens);
+void mt_irq_set_polarity(unsigned int irq, unsigned int polarity);
+
+#endif  /* !__MT_IRQ_H__ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_reg_base.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_reg_base.h
new file mode 100644
index 0000000..b973e08
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_reg_base.h
@@ -0,0 +1,601 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2015. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ */
+
+#ifndef __MT_REG_BASE
+#define __MT_REG_BASE
+
+#include <platform/mt6771.h>
+
+#define BOOTROM_BASE (0x00000000)
+#define BOOTSRAM_BASE (0x00100000)
+#define IO_PHYS             PERIPHERAL_BASE_VIRT
+#define IO_SIZE             PERIPHERAL_BASE_SIZE
+
+
+// APB Module cksys
+#define CKSYS_BASE IO_PHYS
+#define TOPCKGEN_BASE IO_PHYS
+
+
+// APB Module infracfg_ao
+#define INFRACFG_AO_BASE (IO_PHYS + 0x0001000)
+
+#define IOCFG_0_BASE (IO_PHYS + 0x1F20000)
+#define IOCFG_1_BASE (IO_PHYS + 0x1E80000)
+#define IOCFG_2_BASE (IO_PHYS + 0x1E70000)
+#define IOCFG_3_BASE (IO_PHYS + 0x1E90000)
+#define IOCFG_4_BASE (IO_PHYS + 0x1D30000)
+#define IOCFG_5_BASE (IO_PHYS + 0x1D20000)
+#define IOCFG_6_BASE (IO_PHYS + 0x1C50000)
+#define IOCFG_7_BASE (IO_PHYS + 0x1F30000)
+
+// APB Module wdt
+#define TOP_RGU_BASE (IO_PHYS + 0x0007000)
+
+// APB Module pericfg
+#define PERICFG_BASE (IO_PHYS + 0x0003000)
+
+// APB Module dramc
+#define DRAMC0_BASE (IO_PHYS + 0x0004000)
+
+// APB Module gpio
+#define GPIO_BASE (IO_PHYS + 0x0005000)
+
+// APB Module dvfsrc
+#define DVFSRC_BASE (IO_PHYS + 0x0012000)
+
+#define SPM_BASE (IO_PHYS + 0x0006000)
+
+// APB Module toprgu
+#define TOPRGU_BASE (IO_PHYS + 0x0007000)
+
+// APB Module apxgpt
+#define APXGPT_BASE (IO_PHYS + 0x0008000)
+
+// APB Module rsvd
+#define RSVD_BASE (IO_PHYS + 0x0009000)
+
+// APB Module ap_cirq_eint
+#define APIRQ_BASE (IO_PHYS + 0x000B000)
+
+// APB Module apmixed
+#define APMIXED_BASE (IO_PHYS + 0x000C000)
+
+// APB Module smi
+//#define SMI_COMMON_AO_BASE (0x10211000)
+
+// APB Module pmic_wrap
+#define PWRAP_BASE (IO_PHYS + 0x000D000)
+
+// APB Module device_apc_ao
+#define DEVAPC_AO_BASE (IO_PHYS + 0x000E000)
+
+// APB Module ddrphy
+#define DDRPHY_BASE (IO_PHYS + 0x000F000)
+
+// APB Module kp
+#define KP_BASE (IO_PHYS + 0x0010000)
+
+// APB Module DRAMC1_BASE
+//#define DRAMC1_BASE (0x10011000)
+
+// APB Module DDRPHY1_BASE
+//#define DDRPHY1_BASE (0x10012000)
+
+// APB Module md32
+#define MD32_BASE (IO_PHYS + 0x0058000)
+
+// APB Module dbgapb
+#define DBGAPB_BASE (IO_PHYS + 0x0100000)
+
+// APB Module mcucfg
+#define MCUCFG_BASE (IO_PHYS - 0x10000000 + 0x0C530000)
+
+// APB Module ca7mcucfg
+#define CA7MCUCFG_BASE (IO_PHYS + 0x0200000)
+
+// APB Module infracfg
+#define INFRACFG_BASE (IO_PHYS + 0x0201000)
+
+// APB Module sramrom
+#define SRAMROM_BASE (IO_PHYS + 0x0202000)
+
+// APB Module emi
+#define EMI_BASE (IO_PHYS + 0x0219000)
+#define EMI_MPU_BASE        (IO_PHYS + 0x0226000)
+#define DRAMC_CH_BASE       (IO_PHYS + 0x0228000)
+#define CHN0_EMI_BASE       (IO_PHYS + 0x022D000)
+#define CHN1_EMI_BASE       (IO_PHYS + 0x0235000)
+
+// APB Module sys_cirq
+#define SYS_CIRQ_BASE (IO_PHYS + 0x0204000)
+
+// APB Module mm_iommu
+#define M4U_BASE (IO_PHYS + 0x0205000)
+
+// APB Module device_apc
+#define DEVAPC_BASE (IO_PHYS + 0x0207000)
+
+// APB Module bus_dbg_tracker_cfg
+#define BUS_DBG_BASE (IO_PHYS + 0x0208000)
+
+// APB Module fhctl
+#define FHCTL_BASE (IO_PHYS + 0x000cF00)
+
+// APB Module ccif
+//#define AP_CCIF0_BASE (0x1020A000)
+
+// APB Module ccif
+//#define MD_CCIF0_BASE (0xA020B000)
+
+// APB Module gpio1
+//#define GPIO1_BASE (0x1020C000)
+
+// APB Module infra_mbist
+#define INFRA_MBIST_BASE (IO_PHYS + 0x020D000)
+
+// APB Module dramc_conf_nao
+#define DRAMC_NAO_BASE (IO_PHYS + 0x022C000)
+
+// APB Module trng
+#define TRNG_BASE (IO_PHYS + 0x020F000)
+
+// APB Module gcpu
+#define GCPU_BASE (IO_PHYS + 0x0210000)
+
+// APB Module gcpu_ns
+#define GCPU_NS_BASE (IO_PHYS + 0x0211000)
+
+// APB Module gcpu_ns
+#define GCE_BASE (IO_PHYS + 0x0212000)
+
+// APB Module dramc_conf_nao
+#define DRAMC1_NAO_BASE (IO_PHYS + 0x033C000)
+
+// APB Module perisys_iommu
+#define PERISYS_IOMMU_BASE (IO_PHYS + 0x0214000)
+
+// APB Module mipi_tx_config
+#define MIPI_TX0_BASE (0x11E50000)
+#define MIPI_TX1_BASE (0)
+
+// MIPI TX Config
+#define MIPI_TX_CONFIG_BASE (IO_PHYS + 0x0012000)
+
+// APB Module mipi_rx_ana_csi0
+#define MIPI_RX_ANA_CSI0_BASE (IO_PHYS + 0x0217000)
+
+// APB Module mipi_rx_ana_csi1
+#define MIPI_RX_ANA_CSI1_BASE (IO_PHYS + 0x0218000)
+
+// APB Module ca9
+#define CA9_BASE (IO_PHYS + 0x0220000)
+
+// APB Module gce
+#define GCE_BASE (IO_PHYS + 0x0212000)
+
+// APB Module cq_dma
+#define CQ_DMA_BASE (IO_PHYS + 0x0212000)
+
+// APB Module ap_dma
+#define AP_DMA_BASE (IO_PHYS + 0x1000000)
+
+// APB Module auxadc
+#define AUXADC_BASE (IO_PHYS + 0x1001000)
+
+// APB Module uart
+#define UART0_BASE (IO_PHYS + 0x1002000)
+
+// APB Module uart
+#define UART1_BASE (IO_PHYS + 0x1003000)
+
+// APB Module uart
+#define UART2_BASE (IO_PHYS + 0x1004000)
+
+// APB Module uart
+#define UART3_BASE (IO_PHYS + 0x1005000)
+
+// APB Module pwm
+#define PWM_BASE (IO_PHYS + 0x1006000)
+
+// APB Module spi
+#define SPI1_BASE (IO_PHYS + 0x100A000)
+
+// APB Module therm_ctrl
+#define THERM_CTRL_BASE (IO_PHYS + 0x100B000)
+
+// APB Module btif
+#define BTIF_BASE (IO_PHYS + 0x100C000)
+
+
+// APB Module nfi
+#define NFI_BASE (IO_PHYS + 0x100D000)
+
+// APB Module nfiecc
+#define NFIECC_BASE (IO_PHYS + 0x100E000)
+
+// APB Module nli_arb
+//#define NLI_ARB_BASE (0x1100F000)
+
+// APB Module usb2
+//#define USB_BASE (0x11200000)
+
+// APB Module usb_sif
+//#define USBSIF_BASE (0x11210000)
+
+// APB Module audio
+#define AUDIO_BASE (IO_PHYS + 0x1220000)
+
+// APB Module msdc
+#define MSDC0_BASE (IO_PHYS + 0x1230000)
+#define MSDC0_TOP_BASE (IO_PHYS + 0x1F50000)
+
+// APB Module msdc
+#define MSDC1_BASE (IO_PHYS + 0x1240000)
+#define MSDC1_TOP_BASE (IO_PHYS + 0x1E10000)
+
+// APB Module msdc
+#define MSDC2_BASE (IO_PHYS + 0x1250000)
+
+// APB Module msdc
+#define MSDC3_BASE (IO_PHYS + 0x1260000)
+
+// APB Module USB_1p
+#define ICUSB_BASE (IO_PHYS + 0x1270000)
+
+// APB Module ssusb_top
+#define USB3_BASE (IO_PHYS + 0x1200000)
+
+// APB Module ssusb_top_sif
+#define USB3_SIF_BASE (IO_PHYS + 0x1F40000)
+
+// APB Module mfg_top
+//#define MFGCFG_BASE (0x13FFF000)
+
+// APB Module han
+//#define HAN_BASE (0x13000000)
+
+// APB Module mmsys_config
+#define MMSYS_CONFIG_BASE (IO_PHYS + 0x4000000)
+
+// APB Module mdp_rdma
+#define MDP_RDMA0_BASE (IO_PHYS + 0x4001000)
+
+// APB Module mdp_rdma
+#define MDP_RDMA1_BASE (IO_PHYS + 0x4002000)
+
+// APB Module mdp_rsz
+#define MDP_RSZ0_BASE (IO_PHYS + 0x4003000)
+
+// APB Module mdp_rsz
+#define MDP_RSZ1_BASE (IO_PHYS + 0x4004000)
+
+// APB Module mdp_rsz
+#define MDP_RSZ2_BASE (IO_PHYS + 0x4005000)
+
+// APB Module disp_wdma
+#define MDP_WDMA_BASE (IO_PHYS + 0x4006000)
+
+// APB Module mdp_wrot
+#define MDP_WROT0_BASE (IO_PHYS + 0x4007000)
+
+// APB Module mdp_wrot
+#define MDP_WROT1_BASE (IO_PHYS + 0x4008000)
+
+// APB Module mdp_tdshp
+#define MDP_TDSHP0_BASE (IO_PHYS + 0x4009000)
+
+// APB Module mdp_tdshp
+#define MDP_TDSHP1_BASE (IO_PHYS + 0x400a000)
+
+// APB Module mdp_tdshp
+#define MDP_CROP_BASE (IO_PHYS + 0x400b000)
+
+// DISPSYS
+#define OVL0_BASE (IO_PHYS + 0x4008000)
+//#define OVL1_BASE (0x1400c000)
+#define DISP_OVL0_2L_BASE (IO_PHYS + 0x4009000)
+#define DISP_OVL1_2L_BASE (IO_PHYS + 0x400A000)
+#define DISP_RDMA0_BASE (IO_PHYS + 0x400B000)
+#define DISP_RDMA1_BASE (IO_PHYS + 0x400C000)
+//#define DISP_RDMA2_BASE (0x14011000)
+#define DISP_WDMA0_BASE (IO_PHYS + 0x400D000)
+//#define DISP_WDMA1_BASE (0x14013000)
+//#define DISP_UFOE_BASE (0x1401f000)
+//#define DISP_SPLIT0_BASE (0x14021000)
+//#define DISP_DSC_BASE (0x14020000)
+#define DSI0_BASE (IO_PHYS + 0x4014000)
+#define DSI1_BASE (0)
+#define MM_MUTEX_BASE (IO_PHYS + 0x4016000)
+
+/* gic from atf start */
+#if 1
+#define MT_GIC_BASE		(0x0C000000)
+#define GIC_REDIS_BASE_PHY  (MT_GIC_BASE + 0x100000)
+
+#define GIC_DIST_BASE  (IO_PHYS - 0x10000000 + 0x0C000000)
+#define GIC_REDIS_BASE (GIC_DIST_BASE + 0x100000)
+
+#define BASE_GICD_BASE		(MT_GIC_BASE)
+#define BASE_GICC_BASE		(MT_GIC_BASE + 0x400000)
+#define MT_GIC_RDIST_BASE	(MT_GIC_BASE + 0x100000)
+#define BASE_GICR_BASE		(MT_GIC_BASE + 0x100000)
+#define BASE_GICH_BASE		(MT_GIC_BASE + 0x4000)
+#define BASE_GICV_BASE		(MT_GIC_BASE + 0x6000)
+#define INT_POL_CTL0		(MCUCFG_BASE + 0xa80)
+#define INT_POL_SECCTL0		(MCUCFG_BASE+ 0xA00)
+#define SEC_POL_CTL_EN0		(MCUCFG_BASE+ 0xA00)
+#define GIC_SYNC_DCM		(MCUCFG_BASE + 0x758)
+#define GIC_SYNC_DCM_MASK	(0x3)
+#define GIC_SYNC_DCM_ON		(0x3)
+#define GIC_SYNC_DCM_OFF	(0x0)
+#endif
+/* gic from atf end */
+
+// PQ and AAL
+#define COLOR0_BASE (IO_PHYS + 0x400E000)
+//#define COLOR1_BASE (0x14015000)
+#define CCORR0_BASE  (IO_PHYS + 0x400F000)
+//#define CCORR1_BASE  (0x14017000)
+#define DISP_AAL0_BASE (IO_PHYS + 0x4010000)
+//#define DISP_AAL1_BASE (0x14019000)
+#define DISP_GAMMA0_BASE (IO_PHYS + 0x4011000)
+//#define DISP_GAMMA1_BASE (0x1401B000)
+//#define DISP_OD_BASE (0x1401C000)
+#define DITHER0_BASE (IO_PHYS + 0x4012000)
+//#define DITHER1_BASE (0x1401E000)
+
+
+// APB Module disp_dpi
+#define DPI_BASE (IO_PHYS + 0x4015000)
+
+// APB Module disp_pwm
+#define DISP_PWM0_BASE (IO_PHYS + 0x100E000)
+//#define DISP_PWM1_BASE (0x11150000)
+
+// APB Module smi_larb0
+#define SMI_LARB0_BASE (IO_PHYS + 0x4017000)
+
+// APB Module smi_larb1
+#define SMI_LARB1_BASE (IO_PHYS + 0x6010000)
+
+// APB Module smi
+#define SMI_COMMON_BASE (IO_PHYS + 0x4019000)
+
+// APB Module smi_larb
+#define SMI_LARB2_BASE (IO_PHYS + 0x5001000)
+
+// APB Module fake_eng
+#define FAKE_ENG_BASE (IO_PHYS + 0x5002000)
+
+// APB Module cam1
+#define CAM1_BASE (IO_PHYS + 0x5004000)
+
+// APB Module cam2
+#define CAM2_BASE (IO_PHYS + 0x5005000)
+
+// APB Module cam3
+#define CAM3_BASE (IO_PHYS + 0x5006000)
+
+// APB Module cam4
+#define CAM4_BASE (IO_PHYS + 0x5007000)
+
+// APB Module camsv
+#define CAMSV_BASE (IO_PHYS + 0x5009000)
+
+// APB Module camsv_top
+#define CAMSV_TOP_BASE (IO_PHYS + 0x5009000)
+
+// APB Module csi2
+#define CSI2_BASE (IO_PHYS + 0x5008000)
+
+// APB Module seninf
+#define SENINF_BASE (IO_PHYS + 0x5008000)
+
+// APB Module seninf_tg
+#define SENINF_TG_BASE (IO_PHYS + 0x5008000)
+
+// APB Module seninf_top
+#define SENINF_TOP_BASE (IO_PHYS + 0x5008000)
+
+// APB Module seninf_mux
+#define SENINF_MUX_BASE (IO_PHYS + 0x5008000)
+
+// APB Module mipi_rx_config
+#define MIPI_RX_CONFIG_BASE (IO_PHYS + 0x5008000)
+
+// APB Module scam
+#define SCAM_BASE (IO_PHYS + 0x5008C00)
+
+// APB Module ncsi2
+#define NCSI2_BASE (IO_PHYS + 0x5008000)
+
+// APB Module ccir656
+#define CCIR656_BASE (IO_PHYS + 0x5008000)
+
+// APB Module n3d_ctl
+#define N3D_CTL_BASE (IO_PHYS + 0x5008000)
+
+// APB Module fdvt
+#define FDVT_BASE (IO_PHYS + 0x500B000)
+
+// APB Module vdecsys_config
+#define VDEC_GCON_BASE (IO_PHYS + 0x6000000)
+
+// APB Module vdtop
+#define VDEC_BASE (IO_PHYS + 0x6020000)
+
+// APB Module vdtop
+#define VDTOP_BASE (IO_PHYS + 0x6020000)
+
+// APB Module vld
+#define VLD_BASE (IO_PHYS + 0x6021000)
+
+// APB Module vld_top
+#define VLD_TOP_BASE (IO_PHYS + 0x6021800)
+
+// APB Module mc
+#define MC_BASE (IO_PHYS + 0x6022000)
+
+// APB Module avc_vld
+#define AVC_VLD_BASE (IO_PHYS + 0x6023000)
+
+// APB Module avc_mv
+#define AVC_MV_BASE (IO_PHYS + 0x6024000)
+
+// APB Module vdec_pp
+#define VDEC_PP_BASE (IO_PHYS + 0x6025000)
+
+// APB Module hevc_vld
+#define HEVC_VLD_BASE (IO_PHYS + 0x6028000)
+
+// APB Module vp8_vld
+#define VP8_VLD_BASE (IO_PHYS + 0x6026800)
+
+// APB Module vp6
+#define VP6_BASE (IO_PHYS + 0x6027000)
+
+// APB Module vld2
+#define VLD2_BASE (IO_PHYS + 0x6027800)
+
+// APB Module mc_vmmu
+#define MC_VMMU_BASE (IO_PHYS + 0x6028000)
+
+// APB Module pp_vmmu
+#define PP_VMMU_BASE (IO_PHYS + 0x6029000)
+
+// APB Module mjc_config
+#define MJC_CONFIG_BASE (IO_PHYS + 0x7000000)
+
+// APB Module mjc_top
+#define MJC_TOP_BASE (IO_PHYS + 0x7001000)
+
+// APB Module venc_config
+#define VENC_GCON_BASE (IO_PHYS + 0x8000000)
+
+// APB Module smi_larb
+#define SMI_LARB3_BASE (IO_PHYS + 0x8001000)
+
+// APB Module venc
+#define VENC_BASE (IO_PHYS + 0x8002000)
+
+// APB Module jpgenc
+#define JPGENC_BASE (IO_PHYS + 0x8003000)
+
+// APB Module jpgdec
+#define JPGDEC_BASE (IO_PHYS + 0x8004000)
+
+// APB Module audiosys
+#define AUDIOSYS_BASE (IO_PHYS + 0x1220000)
+
+// rtc
+#define RTC_BASE (0x4000)
+
+//Marcos add for early porting
+//#define SYSRAM_BASE (0x19000000)
+//#define GIC_CPU_BASE  (CA9_BASE + 0x2000)
+#if defined(MACH_FPGA)
+// FPGA only
+#define DEVINFO_BASE (IO_PHYS + 0x0001000)
+#endif
+
+/* hardware version register */
+#define VER_BASE (IO_PHYS - 0x10000000 + 0x08000000)
+#define APHW_CODE           (VER_BASE)
+#define APHW_SUBCODE        (VER_BASE + 0x04)
+#define APHW_VER            (VER_BASE + 0x08)
+#define APSW_VER            (VER_BASE + 0x0C)
+
+////////////////////////////////////////
+
+
+/* Other define */
+#define NON_BOOTABLE                0
+#define RAW_BOOT                    1
+#define FAT_BOOT                    2
+
+#define CONFIG_STACKSIZE        (128*1024)    /* regular stack */
+
+// xuecheng, define this because we use zlib for boot logo compression
+#define CONFIG_ZLIB     1
+
+/*MTK Memory layout configuration*/
+#define MAX_NR_BANK    4
+
+#define DRAM_PHY_ADDR   0x40000000
+
+#define RIL_SIZE 0
+
+#define CFG_RAMDISK_LOAD_ADDR           (DRAM_PHY_ADDR + 0x4000000)
+#define CFG_BOOTIMG_LOAD_ADDR           (DRAM_PHY_ADDR + 0x8000)
+#ifdef USE_ITS_BOOTIMG
+#define CFG_BOOTIMG_LOAD_ADDR_64        (DRAM_PHY_ADDR + 0x80000)
+#endif
+#ifndef USE_ITS_BOOTIMG
+#define CFG_BOOTARGS_ADDR               (DRAM_PHY_ADDR + 0x100)
+#else
+#define CFG_BOOTARGS_ADDR               (DRAM_PHY_ADDR + 0x14000000)
+#endif
+
+/*Command passing to Kernel */
+#ifdef MTK_AB_OTA_UPDATER
+#define CMDLINE_ROOT ""
+#else
+#define CMDLINE_ROOT "root=/dev/ram"
+#endif
+
+#define COMMANDLINE_TO_KERNEL  "console=tty0 console=ttyS0,921600n1 root=/dev/mmcblk0p35 rootwait"
+
+
+#define CFG_FACTORY_NAME    "factory.img"
+#define HAVE_LK_TEXT_MENU
+
+#ifdef CONFIG_MTK_USB_UNIQUE_SERIAL
+//#define PDN_CTR           0xC0001020  /* IO_PHYS + 0x00001020 */
+#endif
+
+//Add here for eFuse, chip version checking -> analog register calibration
+#define M_HW_RES3                       0x10009170
+//#define M_HW_RES3_PHY                   IO_PHYS+M_HW_RES3
+#define RG_USB20_TERM_VREF_SEL_MASK     0xE000      //0b 1110,0000,0000,0000     15~13
+#define RG_USB20_CLKREF_REF_MASK        0x1C00      //0b 0001,1100,0000,0000     12~10
+#define RG_USB20_VRT_VREF_SEL_MASK      0x0380      //0b 0000,0011,1000,0000     9~7
+
+#define write_r(a, v) writel(v, a) /* need to fix it */
+#endif
+
+
+
+
+
+
+
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_typedefs.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_typedefs.h
new file mode 100644
index 0000000..8bcb6d9
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_typedefs.h
@@ -0,0 +1,171 @@
+/* ------------
+ *   Type definition.
+ */
+
+#ifndef _MTK_DVC_TEST_TYPEDEFS_H
+#define _MTK_DVC_TEST_TYPEDEFS_H
+
+
+/*==== CONSTANTS ==================================================*/
+
+#define IMPORT  EXTERN
+#ifndef __cplusplus
+#define EXTERN  extern
+#else
+#define EXTERN  extern "C"
+#endif
+#define LOCAL     static
+#define GLOBAL
+#define EXPORT    GLOBAL
+
+
+#define EQ        ==
+#define NEQ       !=
+#define AND       &&
+#define OR        ||
+#define XOR(A,B)  ((!(A) AND (B)) OR ((A) AND !(B)))
+
+#ifndef FALSE
+#define FALSE   0
+#endif
+
+#ifndef TRUE
+#define TRUE    1
+#endif
+
+#ifndef NULL
+#define NULL    0
+#endif
+
+#ifndef BOOL
+typedef unsigned char  BOOL;
+#endif
+
+typedef volatile unsigned char  *UINT8P;
+typedef volatile unsigned short *UINT16P;
+typedef volatile unsigned int   *UINT32P;
+
+
+typedef unsigned char   UINT8;
+typedef unsigned short  UINT16;
+typedef unsigned int    UINT32;
+typedef unsigned short  USHORT;
+typedef signed char     INT8;
+typedef signed short    INT16;
+typedef signed int      INT32;
+typedef signed int      DWORD;
+typedef void            VOID;
+typedef unsigned char   BYTE;
+typedef float           FLOAT;
+
+
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+typedef unsigned long long u64;
+
+typedef unsigned long long  U64;
+typedef unsigned int        U32;
+typedef unsigned short      U16;
+typedef unsigned char       U8;
+
+typedef signed char         s8;
+typedef signed short        s16;
+typedef signed int          s32;
+typedef signed long long    s64;
+
+typedef signed char         S8;
+typedef signed short        S16;
+typedef signed int          S32;
+typedef signed long long    S64;
+
+typedef unsigned int    kal_uint32;
+typedef unsigned short  kal_uint16;
+typedef unsigned char   kal_uint8;
+
+typedef signed int      kal_int32;
+typedef signed short    kal_int16;
+typedef signed char     kal_int8;
+
+typedef unsigned long ulong;
+typedef unsigned char uchar;
+typedef unsigned int uint;
+typedef signed char int8;
+typedef signed short int16;
+typedef signed long int32;
+typedef signed int intx;
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+typedef unsigned int uintx;
+
+typedef enum {
+	KAL_FALSE = 0,
+	KAL_TRUE  = 1,
+} kal_bool;
+
+/*==== EXPORT =====================================================*/
+
+#define MAXIMUM(A,B)       (((A)>(B))?(A):(B))
+#define MINIMUM(A,B)       (((A)<(B))?(A):(B))
+
+#define READ_REGISTER_UINT32(reg) \
+    (*(volatile unsigned int * const)(reg))
+
+#define WRITE_REGISTER_UINT32(reg, val) \
+    (*(volatile unsigned int * const)(reg)) = (val)
+
+#define READ_REGISTER_UINT16(reg) \
+    (*(volatile unsigned short * const)(reg))
+
+#define WRITE_REGISTER_UINT16(reg, val) \
+    (*(volatile unsigned short * const)(reg)) = (val)
+
+#define READ_REGISTER_UINT8(reg) \
+    (*(volatile unsigned char * const)(reg))
+
+#define WRITE_REGISTER_UINT8(reg, val) \
+    (*(volatile unsigned char * const)(reg)) = (val)
+
+#define INREG8(x)           READ_REGISTER_UINT8((unsigned char *)(x))
+#define OUTREG8(x, y)       WRITE_REGISTER_UINT8((unsigned char *)(x), (unsigned char)(y))
+#define SETREG8(x, y)       OUTREG8(x, INREG8(x)|(y))
+#define CLRREG8(x, y)       OUTREG8(x, INREG8(x)&~(y))
+#define MASKREG8(x, y, z)   OUTREG8(x, (INREG8(x)&~(y))|(z))
+
+#define INREG16(x)          READ_REGISTER_UINT16((unsigned short *)(x))
+#define OUTREG16(x, y)      WRITE_REGISTER_UINT16((unsigned short *)(x),(unsigned short)(y))
+#define SETREG16(x, y)      OUTREG16(x, INREG16(x)|(y))
+#define CLRREG16(x, y)      OUTREG16(x, INREG16(x)&~(y))
+#define MASKREG16(x, y, z)  OUTREG16(x, (INREG16(x)&~(y))|(z))
+
+#define INREG32(x)          READ_REGISTER_UINT32((unsigned int *)(x))
+#define OUTREG32(x, y)      WRITE_REGISTER_UINT32((unsigned int *)(x), (unsigned int )(y))
+#define SETREG32(x, y)      OUTREG32(x, INREG32(x)|(y))
+#define CLRREG32(x, y)      OUTREG32(x, INREG32(x)&~(y))
+#define MASKREG32(x, y, z)  OUTREG32(x, (INREG32(x)&~(y))|(z))
+
+
+#define DRV_Reg8(addr)              INREG8(addr)
+#define DRV_WriteReg8(addr, data)   OUTREG8(addr, data)
+#define DRV_SetReg8(addr, data)     SETREG8(addr, data)
+#define DRV_ClrReg8(addr, data)     CLRREG8(addr, data)
+
+#define DRV_Reg16(addr)             INREG16(addr)
+#define DRV_WriteReg16(addr, data)  OUTREG16(addr, data)
+#define DRV_SetReg16(addr, data)    SETREG16(addr, data)
+#define DRV_ClrReg16(addr, data)    CLRREG16(addr, data)
+
+#define DRV_Reg32(addr)             INREG32(addr)
+#define DRV_WriteReg32(addr, data)  OUTREG32(addr, data)
+#define DRV_SetReg32(addr, data)    SETREG32(addr, data)
+#define DRV_ClrReg32(addr, data)    CLRREG32(addr, data)
+
+// !!! DEPRECATED, WILL BE REMOVED LATER !!!
+#define DRV_Reg(addr)               DRV_Reg16(addr)
+#define DRV_WriteReg(addr, data)    DRV_WriteReg16(addr, data)
+#define DRV_SetReg(addr, data)      DRV_SetReg16(addr, data)
+#define DRV_ClrReg(addr, data)      DRV_ClrReg16(addr, data)
+
+#endif
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_uart.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_uart.h
new file mode 100644
index 0000000..d45d74e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_uart.h
@@ -0,0 +1,204 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef ___MTK_UART_H__
+#define ___MTK_UART_H__
+
+#include <platform/mt_reg_base.h>
+
+typedef enum {
+	UART1 = UART0_BASE,
+	UART2 = UART1_BASE,
+	UART3 = UART2_BASE,
+	UART4 = UART3_BASE
+} MTK_UART;
+
+#define UART_FIFO_SIZE              (16)
+#define IO_OFFSET                   (0)
+
+
+/* IER */
+#define UART_IER_ERBFI              (1 << 0) /* RX buffer conatins data int. */
+#define UART_IER_ETBEI              (1 << 1) /* TX FIFO threshold trigger int. */
+#define UART_IER_ELSI               (1 << 2) /* BE, FE, PE, or OE int. */
+#define UART_IER_EDSSI              (1 << 3) /* CTS change (DCTS) int. */
+#define UART_IER_XOFFI              (1 << 5)
+#define UART_IER_RTSI               (1 << 6)
+#define UART_IER_CTSI               (1 << 7)
+
+#define UART_IER_ALL_INTS          (UART_IER_ERBFI|UART_IER_ETBEI|UART_IER_ELSI|\
+                                    UART_IER_EDSSI|UART_IER_XOFFI|UART_IER_RTSI|\
+                                    UART_IER_CTSI)
+#define UART_IER_HW_NORMALINTS     (UART_IER_ERBFI|UART_IER_ELSI|UART_IER_EDSSI)
+#define UART_IER_HW_ALLINTS        (UART_IER_ERBFI|UART_IER_ETBEI| \
+                                    UART_IER_ELSI|UART_IER_EDSSI)
+
+/* FCR */
+#define UART_FCR_FIFOE              (1 << 0)
+#define UART_FCR_CLRR               (1 << 1)
+#define UART_FCR_CLRT               (1 << 2)
+#define UART_FCR_DMA1               (1 << 3)
+#define UART_FCR_RXFIFO_1B_TRI      (0 << 6)
+#define UART_FCR_RXFIFO_6B_TRI      (1 << 6)
+#define UART_FCR_RXFIFO_12B_TRI     (2 << 6)
+#define UART_FCR_RXFIFO_RX_TRI      (3 << 6)
+#define UART_FCR_TXFIFO_1B_TRI      (0 << 4)
+#define UART_FCR_TXFIFO_4B_TRI      (1 << 4)
+#define UART_FCR_TXFIFO_8B_TRI      (2 << 4)
+#define UART_FCR_TXFIFO_14B_TRI     (3 << 4)
+
+#define UART_FCR_FIFO_INIT          (UART_FCR_FIFOE|UART_FCR_CLRR|UART_FCR_CLRT)
+#define UART_FCR_NORMAL             (UART_FCR_FIFO_INIT | \
+                                     UART_FCR_TXFIFO_4B_TRI| \
+                                     UART_FCR_RXFIFO_12B_TRI)
+
+/* LCR */
+#define UART_LCR_BREAK              (1 << 6)
+#define UART_LCR_DLAB               (1 << 7)
+
+#define UART_WLS_5                  (0 << 0)
+#define UART_WLS_6                  (1 << 0)
+#define UART_WLS_7                  (2 << 0)
+#define UART_WLS_8                  (3 << 0)
+#define UART_WLS_MASK               (3 << 0)
+
+#define UART_1_STOP                 (0 << 2)
+#define UART_2_STOP                 (1 << 2)
+#define UART_1_5_STOP               (1 << 2)    /* Only when WLS=5 */
+#define UART_STOP_MASK              (1 << 2)
+
+#define UART_NONE_PARITY            (0 << 3)
+#define UART_ODD_PARITY             (0x1 << 3)
+#define UART_EVEN_PARITY            (0x3 << 3)
+#define UART_MARK_PARITY            (0x5 << 3)
+#define UART_SPACE_PARITY           (0x7 << 3)
+#define UART_PARITY_MASK            (0x7 << 3)
+
+/* MCR */
+#define UART_MCR_DTR                (1 << 0)
+#define UART_MCR_RTS                (1 << 1)
+#define UART_MCR_OUT1               (1 << 2)
+#define UART_MCR_OUT2               (1 << 3)
+#define UART_MCR_LOOP               (1 << 4)
+#define UART_MCR_XOFF               (1 << 7)    /* read only */
+#define UART_MCR_NORMAL             (UART_MCR_DTR|UART_MCR_RTS)
+
+/* LSR */
+#define UART_LSR_DR                 (1 << 0)
+#define UART_LSR_OE                 (1 << 1)
+#define UART_LSR_PE                 (1 << 2)
+#define UART_LSR_FE                 (1 << 3)
+#define UART_LSR_BI                 (1 << 4)
+#define UART_LSR_THRE               (1 << 5)
+#define UART_LSR_TEMT               (1 << 6)
+#define UART_LSR_FIFOERR            (1 << 7)
+
+/* MSR */
+#define UART_MSR_DCTS               (1 << 0)
+#define UART_MSR_DDSR               (1 << 1)
+#define UART_MSR_TERI               (1 << 2)
+#define UART_MSR_DDCD               (1 << 3)
+#define UART_MSR_CTS                (1 << 4)
+#define UART_MSR_DSR                (1 << 5)
+#define UART_MSR_RI                 (1 << 6)
+#define UART_MSR_DCD                (1 << 7)
+
+/* EFR */
+#define UART_EFR_EN                 (1 << 4)
+#define UART_EFR_AUTO_RTS           (1 << 6)
+#define UART_EFR_AUTO_CTS           (1 << 7)
+#define UART_EFR_SW_CTRL_MASK       (0xf << 0)
+
+#define UART_EFR_NO_SW_CTRL         (0)
+#define UART_EFR_NO_FLOW_CTRL       (0)
+#define UART_EFR_AUTO_RTSCTS        (UART_EFR_AUTO_RTS|UART_EFR_AUTO_CTS)
+#define UART_EFR_XON1_XOFF1         (0xa) /* TX/RX XON1/XOFF1 flow control */
+#define UART_EFR_XON2_XOFF2         (0x5) /* TX/RX XON2/XOFF2 flow control */
+#define UART_EFR_XON12_XOFF12       (0xf) /* TX/RX XON1,2/XOFF1,2 flow 
+control */
+
+#define UART_EFR_XON1_XOFF1_MASK    (0xa)
+#define UART_EFR_XON2_XOFF2_MASK    (0x5)
+
+/* IIR (Read Only) */
+#define UART_IIR_NO_INT_PENDING     (0x01)
+#define UART_IIR_RLS                (0x06) /* Receiver Line Status */
+#define UART_IIR_RDA                (0x04) /* Receive Data Available */
+#define UART_IIR_CTI                (0x0C) /* Character Timeout Indicator */
+#define UART_IIR_THRE               (0x02) /* Transmit Holding Register Empty 
+*/
+#define UART_IIR_MS                 (0x00) /* Check Modem Status Register */
+#define UART_IIR_SW_FLOW_CTRL       (0x10) /* Receive XOFF characters */
+#define UART_IIR_HW_FLOW_CTRL       (0x20) /* CTS or RTS Rising Edge */
+#define UART_IIR_FIFO_EN            (0xc0)
+#define UART_IIR_INT_MASK           (0x1f)
+
+/* RateFix */
+#define UART_RATE_FIX               (1 << 0)
+//#define UART_AUTORATE_FIX           (1 << 1)
+//#define UART_FREQ_SEL               (1 << 2)
+#define UART_FREQ_SEL               (1 << 1)
+
+#define UART_RATE_FIX_13M           (1 << 0) /* means UARTclk = APBclk / 4 */
+#define UART_AUTORATE_FIX_13M       (1 << 1)
+#define UART_FREQ_SEL_13M           (1 << 2)
+#define UART_RATE_FIX_ALL_13M       (UART_RATE_FIX_13M|UART_AUTORATE_FIX_13M| \
+                                     UART_FREQ_SEL_13M)
+
+#define UART_RATE_FIX_26M           (0 << 0) /* means UARTclk = APBclk / 2 */
+#define UART_AUTORATE_FIX_26M       (0 << 1)
+#define UART_FREQ_SEL_26M           (0 << 2)
+#define UART_RATE_FIX_ALL_26M       (UART_RATE_FIX_26M|UART_AUTORATE_FIX_26M| \
+                                     UART_FREQ_SEL_26M)
+
+#define UART_RATE_FIX_32M5          (0 << 0)    /* means UARTclk = APBclk / 2 */
+#define UART_FREQ_SEL_32M5          (0 << 1)
+#define UART_RATE_FIX_ALL_32M5      (UART_RATE_FIX_32M5|UART_FREQ_SEL_32M5)
+
+#define UART_RATE_FIX_16M25         (0 << 0)    /* means UARTclk = APBclk / 4 */
+#define UART_FREQ_SEL_16M25         (0 << 1)
+#define UART_RATE_FIX_ALL_16M25     (UART_RATE_FIX_16M25|UART_FREQ_SEL_16M25)
+
+
+/* Autobaud sample */
+#define UART_AUTOBADUSAM_13M         7
+#define UART_AUTOBADUSAM_26M        15
+#define UART_AUTOBADUSAM_52M        31
+//#define UART_AUTOBADUSAM_52M        29  /* 28 or 29 ? */
+#define UART_AUTOBAUDSAM_58_5M      31  /* 31 or 32 ? */
+
+static void mtk_set_current_uart(MTK_UART uart_base);
+
+#endif /* !__MT65XX_UART_H__ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_usbphy.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_usbphy.h
new file mode 100644
index 0000000..b7d9760
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mt_usbphy.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012 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 <platform/mt_typedefs.h>
+
+void mt_usb_phy_poweron(void);
+void mt_usb_phy_poweroff(void);
+
+void charger_detect_init(void);
+void charger_detect_release(void);
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_key.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_key.h
new file mode 100644
index 0000000..94a92f0
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_key.h
@@ -0,0 +1,41 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef ___MTK_KEY_H__
+#define ___MTK_KEY_H__
+
+extern bool check_download_key(void);
+
+#endif /* !__MT65XX_KEY_H__ */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_serial_key.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_serial_key.h
new file mode 100644
index 0000000..9ed8f16
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_serial_key.h
@@ -0,0 +1,33 @@
+/*
+ * 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
+/* serial key */
+#if WITH_KERNEL_VM
+#define SERIAL_KEY_HI    (0xfffffff011f10144UL)
+#define SERIAL_KEY_LO    (0xfffffff011f10140UL)
+#else
+#define SERIAL_KEY_HI    (0x11f10144UL)
+#define SERIAL_KEY_LO    (0x11f10140UL)
+#endif
+
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_timer.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_timer.h
new file mode 100644
index 0000000..a8bab97
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_timer.h
@@ -0,0 +1,32 @@
+/*
+ * 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
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <reg.h>
+
+void mdelay(unsigned long msec);
+void udelay(unsigned long usec);
+void gpt_busy_wait_us(u32 timeout_us);
+void gpt_busy_wait_ms(u32 timeout_ms);
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_wdt.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_wdt.h
new file mode 100644
index 0000000..8590390
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/mtk_wdt.h
@@ -0,0 +1,285 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2018
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+*  AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+*  NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+*  SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+*  SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+*  LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+*  AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+*  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+#ifndef __MTK_WDT_H__
+#define __MTK_WDT_H__
+
+#define CFG_APWDT_DISABLE		1
+
+
+#define MTK_WDT_BASE          TOP_RGU_BASE
+
+#define MTK_WDT_MODE            (MTK_WDT_BASE+0x0000)
+#define MTK_WDT_LENGTH            (MTK_WDT_BASE+0x0004)
+#define MTK_WDT_RESTART            (MTK_WDT_BASE+0x0008)
+#define MTK_WDT_STATUS            (MTK_WDT_BASE+0x000C)
+#define MTK_WDT_INTERVAL        (MTK_WDT_BASE+0x0010)
+#define MTK_WDT_SWRST            (MTK_WDT_BASE+0x0014)
+#define MTK_WDT_SWSYSRST        (MTK_WDT_BASE+0x0018)
+#define MTK_WDT_NONRST_REG        (MTK_WDT_BASE+0x0020)
+#define MTK_WDT_NONRST_REG2        (MTK_WDT_BASE+0x0024)
+#define MTK_WDT_REQ_MODE        (MTK_WDT_BASE+0x0030)
+#define MTK_WDT_REQ_IRQ_EN        (MTK_WDT_BASE+0x0034)
+#define MTK_WDT_DEBUG_CTL        (MTK_WDT_BASE+0x0040)
+#define MTK_WDT_LATCH_CTL        (MTK_WDT_BASE+0x0044)
+#define MTK_WDT_LATCH_CTL2        (MTK_WDT_BASE+0x0048)
+#define MTK_WDT_RSTDEG_EN1        (MTK_WDT_BASE+0x0080)
+#define MTK_WDT_RSTDEG_EN2        (MTK_WDT_BASE+0x0084)
+#define MTK_WDT_RESET_PROTECT    (MTK_WDT_BASE+0x0090)
+#define MTK_WDT_DEBUG_CTL2        (MTK_WDT_BASE+0x00A0)
+#define MTK_WDT_PWR_LATCH        (MTK_WDT_BASE+0x00A4)
+#define MTK_WDT_DEBUG_0_REG        (MTK_WDT_BASE+0x0500)
+#define MTK_WDT_DEBUG_1_REG        (MTK_WDT_BASE+0x0504)
+#define MTK_WDT_DEBUG_2_REG        (MTK_WDT_BASE+0x0508)
+#define MTK_WDT_DEBUG_3_REG        (MTK_WDT_BASE+0x050C)
+#define MTK_WDT_DEBUG_4_REG        (MTK_WDT_BASE+0x0510)
+#define MTK_WDT_DEBUG_5_REG        (MTK_WDT_BASE+0x0514)
+#define MTK_WDT_DEBUG_6_REG        (MTK_WDT_BASE+0x0518)
+
+/*WDT_MODE*/
+#define MTK_WDT_MODE_KEYMASK        (0xff00)
+#define MTK_WDT_MODE_KEY        (0x22000000)
+
+#define MTK_WDT_MODE_DDR_RESERVE  (0x0080)
+#define MTK_WDT_MODE_DUAL_MODE  (0x0040)
+#define MTK_WDT_MODE_IN_DIS        (0x0020) /* Reserved */
+#define MTK_WDT_MODE_AUTO_RESTART    (0x0010) /* Reserved */
+#define MTK_WDT_MODE_IRQ        (0x0008)
+#define MTK_WDT_MODE_EXTEN        (0x0004)
+#define MTK_WDT_MODE_EXT_POL        (0x0002)
+#define MTK_WDT_MODE_ENABLE        (0x0001)
+
+/*WDT_LENGTH*/
+#define MTK_WDT_LENGTH_TIME_OUT        (0xffe0)
+#define MTK_WDT_LENGTH_KEYMASK        (0x001f)
+#define MTK_WDT_LENGTH_KEY        (0x0008)
+#define MTK_WDT_LENGTH_CTL_KEY        (0x95<<24)
+
+/*WDT_RESTART*/
+#define MTK_WDT_RESTART_KEY        (0x1971)
+
+/*WDT_STATUS*/
+#define MTK_WDT_STATUS_HWWDT_RST    (0x80000000)
+#define MTK_WDT_STATUS_SWWDT_RST    (0x40000000)
+#define MTK_WDT_STATUS_IRQWDT_RST    (0x20000000)
+#define MTK_WDT_STATUS_DEBUGWDT_RST    (0x00080000)
+#define MTK_WDT_STATUS_SPMWDT_RST    (0x0002)
+#define MTK_WDT_STATUS_SPM_THERMAL_RST    (0x0001)
+#define MTK_WDT_STATUS_THERMAL_DIRECT_RST    (1<<18)
+#define MTK_WDT_STATUS_SECURITY_RST    (1<<28)
+#define MTK_WDT_STATUS_EINT_RST        (1<<2)
+#define MTK_WDT_STATUS_SYSRST_RST    (1<<3)
+#define MTK_WDT_STATUS_DVFSP_RST    (1<<4)
+#define MTK_WDT_STATUS_SSPM_RST        (1<<16)
+#define MTK_WDT_STATUS_MDDBG_RST    (1<<17)
+
+/*WDT_RST_DEGLITCH*/
+#define MTK_WDT_RSTDEG_EN1_KEY        (0xa357)
+#define MTK_WDT_RSTDEG_EN2_KEY        (0x67d2)
+#define MTK_WDT_RSTDEG_CLOCK_SELETC_SHIFT    (31)
+#define MTK_WDT_RSTDEG_CLOCK_SELECT_MASK    (0x1 << MTK_WDT_RSTDEG_CLOCK_SELETC_SHIFT)
+#define MTK_WDT_RSTDEG_CLOCK_26M            (0)
+#define MTK_WDT_RSTDEG_CLOCK_32K            (1)
+#define MTK_WDT_RSTDEG_LATENCY_SHIFT        (24)
+#define MTK_WDT_RSTDEG_LATENCY_MASK        (0xF << MTK_WDT_RSTDEG_LATENCY_SHIFT)
+#define MTK_WDT_RSTDEG_LATENCY_118US_93MS    (0x0)
+#define MTK_WDT_RSTDEG_LATENCY_59US_46MS    (0x1)
+#define MTK_WDT_RSTDEG_LATENCY_29US_23MS    (0x2)
+#define MTK_WDT_RSTDEG_LATENCY_14US_11MS    (0x3)
+#define MTK_WDT_RSTDEG_LATENCY_7US_5MS        (0x4)
+#define MTK_WDT_RSTDEG_LATENCY_3US_2MS        (0x5)
+#define MTK_WDT_RSTDEG_LATENCY_1US_1MS        (0x6)
+#define MTK_WDT_RSTDEG_LATENCY_923NS_732US    (0x7)
+#define MTK_WDT_RSTDEG_LATENCY_461NS_366US    (0x8)
+#define MTK_WDT_RSTDEG_LATENCY_230NS_183US    (0x9)
+#define MTK_WDT_RSTDEG_LATENCY_115NS_91US    (0xA)
+
+/*WDT_INTERVAL*/
+#define MTK_WDT_INTERVAL_KEY         (0x66000000)
+#define MTK_WDT_INTERVAL_MASK        (0x0FFF)
+
+/*WDT_SWRST*/
+#define MTK_WDT_SWRST_KEY        (0x1209)
+
+/*WDT_SWSYSRST*/
+#define MTK_WDT_SWSYS_RST_PWRAP_SPI_CTL_RST    (0x0800)
+#define MTK_WDT_SWSYS_RST_APMIXED_RST    (0x0400)
+#define MTK_WDT_SWSYS_RST_MD_LITE_RST    (0x0200)
+#define MTK_WDT_SWSYS_RST_INFRA_AO_RST    (0x0100)
+#define MTK_WDT_SWSYS_RST_MD_RST    (0x0080)
+#define MTK_WDT_SWSYS_RST_DDRPHY_RST    (0x0040)
+#define MTK_WDT_SWSYS_RST_IMG_RST    (0x0020)
+#define MTK_WDT_SWSYS_RST_VDEC_RST    (0x0010)
+#define MTK_WDT_SWSYS_RST_VENC_RST    (0x0008)
+#define MTK_WDT_SWSYS_RST_MFG_RST    (0x0004)
+#define MTK_WDT_SWSYS_RST_DISP_RST    (0x0002)
+#define MTK_WDT_SWSYS_RST_INFRA_RST    (0x0001)
+
+/* Reboot source */
+#define RGU_STAGE_MASK      (0x3)
+#define RGU_STAGE_PRELOADER (0x1)
+#define RGU_STAGE_LK        (0x2)
+#define RGU_STAGE_KERNEL    (0x3)
+
+/* WDT_NONRST_REG2 */
+#define MTK_WDT_NONRST2_SSPM_RESET     (1 << 0)
+#define MTK_WDT_NONRST2_STAGE_OFS      (30) /* 31:30: 2-bits for current stage */
+#define MTK_WDT_NONRST2_LAST_STAGE_OFS (28) /* 29:28: 2-bits for last stage */
+
+#define MTK_WDT_SWSYS_RST_KEY        (0x88000000)
+#define MTK_WDT_REQ_IRQ_KEY        (0x44000000)
+
+#define MTK_WDT_REQ_MODE_KEY    (0x33000000)
+
+/* WDT_NONRST_REG */
+#define MTK_WDT_NONRST_DL              (0x00008000)
+
+/* MTK_WDT_DEBUG_CTL */
+#define MTK_DEBUG_CTL_KEY              (0x59000000)
+#define MTK_RG_DRAMC_SREF              (0x00100)
+#define MTK_RG_DRAMC_ISO               (0x00200)
+#define MTK_RG_CONF_ISO                (0x00400)
+#define MTK_RGU_EMI_DCS_PAUSE          (0x00004000) /* bit 14: dcs_pause */
+#define MTK_RGU_DVFSRC_PAUSE           (0x00008000) /* bit 15: dvfsrc_pause */
+#define MTK_DDR_RESERVE_RTA            (0x10000)    /* bit 16: ddr_reserve_success */
+#define MTK_DDR_SREF_STA               (0x20000)    /* bit 17: ddr_sref_status */
+#define MTK_RGU_EMI_DCS_SUCCESS_OFFSET (18)         /* bit 18: emi_dcs_success */
+#define MTK_RGU_EMI_DCS_SUCCESS        (1 << MTK_RGU_EMI_DCS_SUCCESS_OFFSET)
+#define MTK_RGU_DVFSRC_SUCCESS_OFFSET  (20)         /* bit 20: dvfsrc_success */
+#define MTK_RGU_DVFSRC_SUCCESS         (1 << MTK_RGU_DVFSRC_SUCCESS_OFFSET)
+
+/* MTK_WDT_DEBUG_CTL2 */
+#define MTK_DEBUG_CTL2_KEY           (0x55000000)
+#define MTK_RGU_EMI_DCS_EN           (1 << 8) /* emi_dcs_en */
+#define MTK_RGU_DVFSRC_EN            (1 << 9) /* dvfsrc_en */
+
+/* MTK_WDT_LATCH_CTL */
+#define MTK_LATCH_CTL_KEY            (0x95000000)
+#define MTK_RG_LATH_EN               (1 << 0)
+#define MTK_RG_MCU_LATCH_SELECT      (1 << 1)
+#define MTK_RG_SPM_LATCH_SELECT      (1 << 2)
+#define MTK_RG_MCU_LATH_EN           (1 << 4)
+#define MTK_RG_SPM_LATH_EN           (1 << 5)
+#define MTK_RG_DRAMC_LATH_EN         (1 << 6)
+#define MTK_RG_MPO_EXT_OFF_EN        (1 << 8)
+#define MTK_RG_GPU_EXT_OFF_EN        (1 << 9)
+#define MTK_RG_MD_EXT_OFF_EN         (1 << 10)
+#define MTK_RG_DRAMC_RD_TEST_EN      (1 << 11)
+#define MTK_RG_DRAMC_RDWT_TEST_EN    (1 << 12)
+#define MTK_RG_DVFSRC_LATCH_EN       (1 << 13) /* obsolete */
+#define MTK_RG_EMI_LATCH_EN          (1 << 14)
+
+/* MTK_WDT_LATCH_CTL2 */
+#define MTK_LATCH_CTL2_KEY           (0x95000000)
+#define MTK_RG_MCU_DFD_EN            (1 << 17)
+#define MTK_RG_MCU_DFD_TIMEOUT_MASK  (0x1FFFF)
+#define MTK_RG_MCU_DFD_TIMEOUT_OFS   (0)
+#define MTK_RG_MCU_DFD_TIMEOUT_VALUE (0x30)
+
+/* Reboot reason */
+#define RE_BOOT_REASON_UNKNOW           (0x00)
+#define RE_BOOT_BY_WDT_HW               (0x01)
+#define RE_BOOT_BY_WDT_SW               (0x02)
+#define RE_BOOT_WITH_INTTERUPT          (0x04)
+#define RE_BOOT_BY_SPM_THERMAL          (0x08)
+#define RE_BOOT_BY_SPM                  (0x10)
+#define RE_BOOT_BY_THERMAL_DIRECT       (0x20)
+#define RE_BOOT_BY_DEBUG                (0x40)
+#define RE_BOOT_BY_SECURITY                (0x80)
+#define RE_BOOT_BY_EINT                (0x100)
+#define RE_BOOT_BY_SYSRST           (0x200)
+#define RE_BOOT_BY_SSPM_RST         (0x400)
+#define RE_BOOT_BY_PMIC_FULL_RST    (0x800)    /* PMIC full (cold) reset */
+#define RE_BOOT_ABNORMAL                (0xF0)
+
+/* Reboot from which stage */
+#define RE_BOOT_FROM_UNKNOW             (0x00)
+#define RE_BOOT_FROM_PRE_LOADER         (0x01)
+#define RE_BOOT_FROM_U_BOOT             (0x02)
+#define RE_BOOT_FROM_KERNEL             (0x03)
+#define RE_BOOT_FROM_POWER_ON           (0x04)
+
+#define WDT_NORMAL_REBOOT        (0x01)
+#define WDT_BY_PASS_PWK_REBOOT        (0x02)
+#define WDT_NOT_WDT_REBOOT        (0x00)
+
+typedef enum wd_swsys_reset_type {
+    WD_MD_RST,
+}WD_SYS_RST_TYPE;
+
+typedef enum wk_req_en {
+    WD_REQ_DIS,
+    WD_REQ_EN,
+} WD_REQ_CTL;
+
+typedef enum wk_req_mode {
+    WD_REQ_IRQ_MODE,
+    WD_REQ_RST_MODE,
+} WD_REQ_MODE;
+
+enum {
+    RGU_REG_CLR = 0,
+    RGU_REG_SET = 1
+};
+
+extern void mtk_wdt_init(void);
+void mtk_wdt_disable(void);
+extern void mtk_arch_reset(char mode);
+extern int  mtk_wdt_boot_check(void);
+int         mtk_wdt_request_en_set(int mark_bit, WD_REQ_CTL en);
+int         mtk_wdt_request_mode_set(int mark_bit, WD_REQ_MODE mode);
+int         rgu_dram_reserved(int enable);
+int         rgu_cfg_emi_dcs_en(int enable);
+int         rgu_is_dram_slf(void);
+int         rgu_is_dvfsrc_enable(void);
+int         rgu_is_dvfsrc_success(void);
+int         rgu_is_emi_dcs_enable(void);
+int         rgu_is_emi_dcs_success(void);
+int         rgu_is_reserve_ddr_enabled(void);
+int         rgu_is_reserve_ddr_mode_success(void);
+int         rgu_release_rg_dram_setting(void);
+int         rgu_release_rg_dramc_conf_iso(void);
+int         rgu_release_rg_dramc_iso(void);
+int         rgu_release_rg_dramc_sref(void);
+void        rgu_swsys_reset(WD_SYS_RST_TYPE reset_type);
+int         mtk_wdt_is_pmic_full_reset(void);
+void set_clr_fastboot_mode(bool flag);
+void set_clr_recovery_mode(bool flag);
+bool check_fastboot_mode(void);
+bool check_recovery_mode(void);
+
+extern unsigned g_rgu_status;
+
+#endif   /*__MTK_WDT_H__*/
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/panel.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/panel.h
new file mode 100644
index 0000000..8f3fd95
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/panel.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#ifndef __PANEL_H__
+#define __PANEL_H__
+
+#include <platform/dsi.h>
+#include <platform/dsi_common.h>
+#include <platform/ddp_debug.h>
+
+struct dsi_info {
+	u8 lanes;    /* interace lanes numeber */
+	u32 flag;
+	u32 format;
+};
+
+/*
+ * The data that to be serialized and put into CBFS.
+ * Note some fields, for example edid.mode.name, were actually pointers and
+ * cannot be really serialized.
+ */
+struct panel_serializable_data {
+	struct videomode vm;  /* edid info of this panel */
+	u8 init[2048]; /* A packed array of lcm_init_command */
+	u8 intf_mode;  /* interface mode,  dsi lvds or dpi */
+	struct dsi_info *dsi;
+};
+
+struct panel_description {
+	const char *name;  /* Panel name for constructing CBFS file name */
+	struct panel_serializable_data *s;
+	void (*power_on)(void);  /* Callback to turn on panel */
+	void (*backlight_enable)(void);
+};
+
+#define INIT_DCS_CMD(...) \
+	LCM_DCS_CMD, \
+	sizeof((u8[]){__VA_ARGS__}), \
+	__VA_ARGS__
+
+#define INIT_GENERIC_CMD(...) \
+	LCM_GENERIC_CMD, \
+	sizeof((u8[]){__VA_ARGS__}), \
+	__VA_ARGS__
+
+#define INIT_DELAY_CMD(delay) \
+	LCM_DELAY_CMD, \
+	delay
+
+#define INIT_END_CMD \
+	LCM_END_CMD
+
+#if WITH_PANEL_TPV_PH060PB16A
+	extern struct panel_description tpv_ph060pb16a_desc;
+#endif
+
+static inline struct panel_description *panel_get_desc(void)
+{
+	ddp_func();
+
+#if WITH_PANEL_TPV_PH060PB16A
+	return &tpv_ph060pb16a_desc;
+#endif
+	
+	return NULL;
+}
+#endif /* __PANEL_H__ */
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/pl_version.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/pl_version.h
new file mode 100644
index 0000000..6cbe869
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/pl_version.h
@@ -0,0 +1,38 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#define PL_VERSION    0x71067932
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/plat_dbg_info.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/plat_dbg_info.h
new file mode 100644
index 0000000..0bb658f
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/plat_dbg_info.h
@@ -0,0 +1,107 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2016. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("Media Tek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef MT_PLAT_DBG_INFO_H
+#define MT_PLAT_DBG_INFO_H
+
+/* here include the header declaring users' data structure */
+#include <platform/mt_reg_base.h>
+
+#define PLAT_DBG_INFO_BASE (SRAM_BASE_VIRT + 0x1D800)  //SRAM base + offset 0x1D800
+
+#define PLAT_DBG_INFO_SIZE 256
+
+#define INFO_TAIL_MAGIC 0x72590000
+
+#define INIT_DBG_HEAD(X) \
+	dbg_info->head[TYPE_##X]=(unsigned int)((KEY_##X<<16)|(sizeof(DEF_##X)&0xFFFF));
+#define INFO_ALIGN_CHECK(X) \
+	_Static_assert(sizeof(X)%4==0,#X" alignment is violated");
+
+typedef enum {
+	TYPE_LAST_DRAMC,
+	TYPE_LAST_EMI,
+	TYPE_END,
+	INFO_TYPE_MAX = 3,
+} DBG_INFO_TYPE;
+_Static_assert(TYPE_END <= INFO_TYPE_MAX, "TYPE_END is violated");
+
+#define LAST_EMI_MAGIC_PATTERN 0x19870611
+
+typedef struct {
+	unsigned int decs_magic;
+	unsigned int decs_ctrl;
+	unsigned int decs_dram_type;
+	unsigned int decs_diff_us;
+	unsigned int mbw_buf_l;
+	unsigned int mbw_buf_h;
+} LAST_EMI_INFO_T;
+#define DEF_LAST_EMI LAST_EMI_INFO_T
+
+typedef struct {
+	unsigned int head[INFO_TYPE_MAX];
+#ifdef DEF_LAST_DRAMC
+	LAST_DRAMC_INFO_T last_dramc_info;
+#endif
+#ifdef DEF_LAST_EMI
+	LAST_EMI_INFO_T last_emi;
+#endif
+	unsigned int tail;
+} top_dbg_info;
+_Static_assert(sizeof(top_dbg_info) <= PLAT_DBG_INFO_SIZE, "PLAT_DBG_INFO_SIZE is violated");
+
+#ifdef DEF_LAST_DRAMC
+#define KEY_LAST_DRAMC 0xD8A3
+INFO_ALIGN_CHECK(DEF_LAST_DRAMC)
+#endif
+#ifdef DEF_LAST_EMI
+#define KEY_LAST_EMI 0xE31C
+INFO_ALIGN_CHECK(DEF_LAST_EMI)
+#endif
+
+typedef struct {
+	unsigned int key;
+	unsigned int base;
+	unsigned int size;
+} dbg_info_in_bootargs;
+
+unsigned int get_dbg_info_key(DBG_INFO_TYPE info_type);
+u64 get_dbg_info_base(unsigned int key);
+unsigned int get_dbg_info_size(unsigned int key);
+
+#endif //MT_PLAT_DBG_INFO_H
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/pll.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/pll.h
new file mode 100644
index 0000000..8e87dfd
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/pll.h
@@ -0,0 +1,262 @@
+/*
+ * 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.
+ */
+
+#ifndef SOC_MEDIATEK_MT8183_PLL_H
+#define SOC_MEDIATEK_MT8183_PLL_H
+
+#include <platform/pll_common.h>
+
+struct mtk_topckgen_regs {
+    unsigned int clk_mode;
+    unsigned int clk_cfg_update;
+    unsigned int clk_cfg_update1;
+    unsigned int reserved1[13];
+    unsigned int clk_cfg_0;
+    unsigned int clk_cfg_0_set;
+    unsigned int clk_cfg_0_clr;
+    unsigned int reserved2[1];
+    unsigned int clk_cfg_1;
+    unsigned int clk_cfg_1_set;
+    unsigned int clk_cfg_1_clr;
+    unsigned int reserved3[1];
+    unsigned int clk_cfg_2;
+    unsigned int clk_cfg_2_set;
+    unsigned int clk_cfg_2_clr;
+    unsigned int reserved4[1];
+    unsigned int clk_cfg_3;
+    unsigned int clk_cfg_3_set;
+    unsigned int clk_cfg_3_clr;
+    unsigned int reserved5[1];
+    unsigned int clk_cfg_4;
+    unsigned int clk_cfg_4_set;
+    unsigned int clk_cfg_4_clr;
+    unsigned int reserved6[1];
+    unsigned int clk_cfg_5;
+    unsigned int clk_cfg_5_set;
+    unsigned int clk_cfg_5_clr;
+    unsigned int reserved7[1];
+    unsigned int clk_cfg_6;
+    unsigned int clk_cfg_6_set;
+    unsigned int clk_cfg_6_clr;
+    unsigned int reserved8[1];
+    unsigned int clk_cfg_7;
+    unsigned int clk_cfg_7_set;
+    unsigned int clk_cfg_7_clr;
+    unsigned int reserved9[1];
+    unsigned int clk_cfg_8;
+    unsigned int clk_cfg_8_set;
+    unsigned int clk_cfg_8_clr;
+    unsigned int reserved10[1];
+    unsigned int clk_cfg_9;
+    unsigned int clk_cfg_9_set;
+    unsigned int clk_cfg_9_clr;
+    unsigned int reserved11[1];
+    unsigned int clk_cfg_10;
+    unsigned int clk_cfg_10_set;
+    unsigned int clk_cfg_10_clr;
+    unsigned int reserved12[6];
+    unsigned int clk_misc_cfg_0;
+    unsigned int clk_misc_cfg_1;
+    unsigned int clk_dbg_cfg;
+    unsigned int reserved13[60];
+    unsigned int clk_scp_cfg_0;
+    unsigned int clk_scp_cfg_1;
+    unsigned int reserved14[6];
+    unsigned int clk26cali_0;
+    unsigned int clk26cali_1;
+    unsigned int reserved15[2];
+    unsigned int cksta_reg;
+    unsigned int cksta_reg1;
+    unsigned int reserved16[50];
+    unsigned int clkmon_clk_sel_reg;
+    unsigned int clkmon_k1_reg;
+    unsigned int reserved17[6];
+    unsigned int clk_auddiv_0;
+    unsigned int clk_auddiv_1;
+    unsigned int clk_auddiv_2;
+    unsigned int aud_top_cfg;
+    unsigned int aud_top_mon;
+    unsigned int clk_auddiv_3;
+    unsigned int reserved18[50];
+    unsigned int clk_pdn_reg;
+    unsigned int reserved19[63];
+    unsigned int clk_extck_reg;
+    unsigned int reserved20[79];
+    unsigned int clk_cfg_20;
+    unsigned int clk_cfg_20_set;
+    unsigned int clk_cfg_20_clr;
+};
+
+struct mtk_apmixed_regs {
+    unsigned int ap_pll_con0;
+    unsigned int ap_pll_con1;
+    unsigned int ap_pll_con2;
+    unsigned int ap_pll_con3;
+    unsigned int ap_pll_con4;
+    unsigned int ap_pll_con5;
+    unsigned int ap_pll_con6;
+    unsigned int ap_pll_con7;
+    unsigned int ap_pll_con8;
+    unsigned int clksq_stb_con0;
+    unsigned int pll_pwr_con0;
+    unsigned int pll_pwr_con1;
+    unsigned int pll_iso_con0;
+    unsigned int pll_iso_con1;
+    unsigned int pll_stb_con0;
+    unsigned int div_stb_con0;
+    unsigned int pll_chg_con0;
+    unsigned int pll_test_con0;
+    unsigned int pll_test_con1;
+    unsigned int reserved1[109];
+    unsigned int armpll_ll_con0;
+    unsigned int armpll_ll_con1;
+    unsigned int armpll_ll_con2;
+    unsigned int armpll_ll_pwr_con0;
+    unsigned int armpll_l_con0;
+    unsigned int armpll_l_con1;
+    unsigned int armpll_l_con2;
+    unsigned int armpll_l_pwr_con0;
+    unsigned int mainpll_con0;
+    unsigned int mainpll_con1;
+    unsigned int mainpll_con2;
+    unsigned int mainpll_pwr_con0;
+    unsigned int univpll_con0;
+    unsigned int univpll_con1;
+    unsigned int univpll_con2;
+    unsigned int univpll_pwr_con0;
+    unsigned int mfgpll_con0;
+    unsigned int mfgpll_con1;
+    unsigned int mfgpll_con2;
+    unsigned int mfgpll_pwr_con0;
+    unsigned int msdcpll_con0;
+    unsigned int msdcpll_con1;
+    unsigned int msdcpll_con2;
+    unsigned int msdcpll_pwr_con0;
+    unsigned int tvdpll_con0;
+    unsigned int tvdpll_con1;
+    unsigned int tvdpll_con2;
+    unsigned int tvdpll_pwr_con0;
+    unsigned int mmpll_con0;
+    unsigned int mmpll_con1;
+    unsigned int mmpll_con2;
+    unsigned int mmpll_pwr_con0;
+    unsigned int mpll_con0;
+    unsigned int mpll_con1;
+    unsigned int mpll_con2;
+    unsigned int mpll_pwr_con0;
+    unsigned int ccipll_con0;
+    unsigned int ccipll_con1;
+    unsigned int ccipll_con2;
+    unsigned int ccipll_pwr_con0;
+    unsigned int apll1_con0;
+    unsigned int apll1_con1;
+    unsigned int apll1_con2;
+    unsigned int apll1_con3;
+    unsigned int apll1_pwr_con0;
+    unsigned int apll2_con0;
+    unsigned int apll2_con1;
+    unsigned int apll2_con2;
+    unsigned int apll2_con3;
+    unsigned int apll2_pwr_con0;
+    unsigned int reserved2[78];
+    unsigned int ap_auxadc_con0;
+    unsigned int ap_auxadc_con1;
+    unsigned int ap_auxadc_con2;
+    unsigned int ap_auxadc_con3;
+    unsigned int ap_auxadc_con4;
+    unsigned int ap_auxadc_con5;
+    unsigned int reserved3[122];
+    unsigned int ts_con0;
+    unsigned int ts_con1;
+    unsigned int ts_con2;
+    unsigned int reserved4[61];
+    unsigned int ulposc_con0;
+    unsigned int ulposc_con1;
+    unsigned int ulposc2_con0;
+    unsigned int ulposc2_con1;
+    unsigned int reserved5[60];
+    unsigned int ap_abist_mon_con0;
+    unsigned int ap_abist_mon_con1;
+    unsigned int ap_abist_mon_con2;
+    unsigned int ap_abist_mon_con3;
+    unsigned int occscan_con0;
+    unsigned int clkdiv_con0;
+    unsigned int occscan_con1;
+    unsigned int occscan_con2;
+    unsigned int mcu_occscan_con0;
+    unsigned int reserved6[55];
+    unsigned int rsv_rw0_con0;
+    unsigned int rsv_rw1_con0;
+    unsigned int rsv_ro_con0;
+};
+
+enum {
+    DIV_MASK = 0x1f << 17,
+    DIV_1 = 0x8 << 17,
+    DIV_2 = 0xa << 17,
+
+    MUX_MASK = 0x3 << 9,
+    MUX_SRC_ARMPLL = 0x1 << 9,
+};
+
+enum {
+    PLL_PWR_ON_DELAY = 30,
+    PLL_ISO_DELAY = 1,
+    PLL_EN_DELAY = 20,
+};
+
+enum {
+    PCW_INTEGER_BITS = 8,
+};
+
+/* PLL rate */
+enum {
+    ARMPLL_LL_HZ = 1100 * MHz,
+    ARMPLL_L_HZ  = 1200 * MHz,
+    CCIPLL_HZ    = 598 * 2 * MHz,
+    MAINPLL_HZ   = 1092 * MHz,
+    UNIVPLL_HZ   = 1248UL * 2 * MHz,
+    MSDCPLL_HZ   = 384 * MHz,
+    MMPLL_HZ     = 3150UL * MHz,
+    MFGPLL_HZ    = 512 * MHz,
+    TVDPLL_HZ    = 594 * MHz,
+    APLL1_HZ     = 180633600,
+    APLL2_HZ     = 196608 * KHz,
+    MPLL_HZ      = 208 * MHz,
+};
+
+/* top_div rate */
+enum {
+    CLK26M_HZ        = 26 * MHz,
+    MAINPLL_D5_HZ    = MAINPLL_HZ / 5,
+    MAINPLL_D5_D2_HZ = MAINPLL_D5_HZ / 2,
+};
+
+/* top_mux rate */
+enum {
+    SPI_HZ = MAINPLL_D5_D2_HZ,
+};
+
+void mt_fmeter_dump(void);
+
+#endif /* SOC_MEDIATEK_MT8183_PLL_H */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/pmic_wrap.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/pmic_wrap.h
new file mode 100644
index 0000000..0d3a7c3
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/pmic_wrap.h
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+
+#ifndef __PMIC_WRAP_H
+#define __PMIC_WRAP_H
+
+#include <platform/mt_reg_base.h>
+#include <platform/pmic_wrap_common.h>
+
+struct mt8183_pwrap_regs {
+	u32 mux_sel;
+	u32 wrap_en;
+	u32 dio_en;
+	u32 si_sample_ctrl;
+	u32 si_sample_ctrl_ulposc;
+	u32 rddmy;
+	u32 cshext_write;
+	u32 cshext_read;
+	u32 cslext_write;
+	u32 cslext_read;
+	u32 ext_ck_write;
+	u32 ext_ck_read;
+	u32 staupd_ctrl;
+	u32 staupd_grpen;
+	u32 eint_sta0_adr;
+	u32 eint_sta1_adr;
+	u32 eint_sta;
+	u32 eint_clr;
+	u32 eint_ctrl;
+	u32 staupd_man_trig;
+	u32 staupd_sta;
+	u32 wrap_sta;
+	u32 harb_init;
+	u32 harb_hprio;
+	u32 hiprio_arb_en;
+	u32 harb_sta0;
+	u32 harb_sta1;
+	u32 harb_sta2;
+	u32 man_en;
+	u32 man_cmd;
+	u32 man_rdata;
+	u32 man_vldclr;
+	u32 wacs0_en;
+	u32 init_done0;
+	u32 wacs1_en;
+	u32 init_done1;
+	u32 wacs2_en;
+	u32 init_done2;
+	u32 wacs3_en;
+	u32 init_done3;
+	u32 wacs_p2p_en;
+	u32 init_done_p2p;
+	u32 wacs_md32_en;
+	u32 init_done_md32;
+	u32 int0_en;
+	u32 int0_flg_raw;
+	u32 int0_flg;
+	u32 int0_clr;
+	u32 int1_en;
+	u32 int1_flg_raw;
+	u32 int1_flg;
+	u32 int1_clr;
+	u32 sig_adr;
+	u32 sig_mode;
+	u32 sig_value;
+	u32 sig_errval;
+	u32 crc_en;
+	u32 timer_en;
+	u32 timer_sta;
+	u32 wdt_unit;
+	u32 wdt_src_en_0;
+	u32 wdt_src_en_1;
+	u32 wdt_flg_0;
+	u32 wdt_flg_1;
+	u32 debug_int_sel;
+	u32 dvfs_adr0;
+	u32 dvfs_wdata0;
+	u32 dvfs_adr1;
+	u32 dvfs_wdata1;
+	u32 dvfs_adr2;
+	u32 dvfs_wdata2;
+	u32 dvfs_adr3;
+	u32 dvfs_wdata3;
+	u32 dvfs_adr4;
+	u32 dvfs_wdata4;
+	u32 dvfs_adr5;
+	u32 dvfs_wdata5;
+	u32 dvfs_adr6;
+	u32 dvfs_wdata6;
+	u32 dvfs_adr7;
+	u32 dvfs_wdata7;
+	u32 dvfs_adr8;
+	u32 dvfs_wdata8;
+	u32 dvfs_adr9;
+	u32 dvfs_wdata9;
+	u32 dvfs_adr10;
+	u32 dvfs_wdata10;
+	u32 dvfs_adr11;
+	u32 dvfs_wdata11;
+	u32 dvfs_adr12;
+	u32 dvfs_wdata12;
+	u32 dvfs_adr13;
+	u32 dvfs_wdata13;
+	u32 dvfs_adr14;
+	u32 dvfs_wdata14;
+	u32 dvfs_adr15;
+	u32 dvfs_wdata15;
+	u32 dcxo_enable;
+	u32 dcxo_conn_adr0;
+	u32 dcxo_conn_wdata0;
+	u32 dcxo_conn_adr1;
+	u32 dcxo_conn_wdata1;
+	u32 dcxo_nfc_adr0;
+	u32 dcxo_nfc_wdata0;
+	u32 dcxo_nfc_adr1;
+	u32 dcxo_nfc_wdata1;
+	u32 spminf_sta_0;
+	u32 spminf_sta_1;
+	u32 spminf_backup_sta;
+	u32 scpinf_sta;
+	u32 cipher_key_sel;
+	u32 cipher_iv_sel;
+	u32 cipher_en;
+	u32 cipher_rdy;
+	u32 cipher_mode;
+	u32 cipher_swrst;
+	u32 dcm_en;
+	u32 dcm_spi_dbc_prd;
+	u32 dcm_dbc_prd;
+	u32 int_gps_auxadc_cmd_addr;
+	u32 int_gps_auxadc_cmd;
+	u32 int_gps_auxadc_rdata_addr;
+	u32 ext_gps_auxadc_rdata_addr;
+	u32 gpsinf_0_sta;
+	u32 gpsinf_1_sta;
+	u32 md_adcinf_ctrl;
+	u32 md_auxadc_rdata_latest_addr;
+	u32 md_auxadc_rdata_wp_addr;
+	u32 md_auxadc_rdata[32];
+	u32 md_adcinf_0_sta_0;
+	u32 md_adcinf_0_sta_1;
+	u32 md_adcinf_1_sta_0;
+	u32 md_adcinf_1_sta_1;
+	u32 swrst;
+	u32 spm_sleep_gating_ctrl;
+	u32 scp_sleep_gating_ctrl;
+	u32 priority_user_sel_0;
+	u32 priority_user_sel_1;
+	u32 priority_user_sel_2;
+	u32 priority_user_sel_3;
+	u32 priority_user_sel_4;
+	u32 arbiter_out_sel_0;
+	u32 arbiter_out_sel_1;
+	u32 arbiter_out_sel_2;
+	u32 arbiter_out_sel_3;
+	u32 arbiter_out_sel_4;
+	u32 starv_counter_0;
+	u32 starv_counter_1;
+	u32 starv_counter_2;
+	u32 starv_counter_3;
+	u32 starv_counter_4;
+	u32 starv_counter_5;
+	u32 starv_counter_6;
+	u32 starv_counter_7;
+	u32 starv_counter_8;
+	u32 starv_counter_9;
+	u32 starv_counter_10;
+	u32 starv_counter_11;
+	u32 starv_counter_12;
+	u32 starv_counter_13;
+	u32 starv_counter_14;
+	u32 starv_counter_15;
+	u32 starv_counter_16;
+	u32 starv_counter_0_status;
+	u32 starv_counter_1_status;
+	u32 starv_counter_2_status;
+	u32 starv_counter_3_status;
+	u32 starv_counter_4_status;
+	u32 starv_counter_5_status;
+	u32 starv_counter_6_status;
+	u32 starv_counter_7_status;
+	u32 starv_counter_8_status;
+	u32 starv_counter_9_status;
+	u32 starv_counter_10_status;
+	u32 starv_counter_11_status;
+	u32 starv_counter_12_status;
+	u32 starv_counter_13_status;
+	u32 starv_counter_14_status;
+	u32 starv_counter_15_status;
+	u32 starv_counter_16_status;
+	u32 starv_counter_clr;
+	u32 starv_prio_status;
+	u32 monitor_ctrl_0;
+	u32 monitor_ctrl_1;
+	u32 monitor_ctrl_2;
+	u32 monitor_ctrl_3;
+	u32 channel_sequence_0;
+	u32 channel_sequence_1;
+	u32 channel_sequence_2;
+	u32 channel_sequence_3;
+	u32 cmd_sequence_0;
+	u32 cmd_sequence_1;
+	u32 cmd_sequence_2;
+	u32 cmd_sequence_3;
+	u32 cmd_sequence_4;
+	u32 cmd_sequence_5;
+	u32 cmd_sequence_6;
+	u32 cmd_sequence_7;
+	u32 wdata_sequence_0;
+	u32 wdata_sequence_1;
+	u32 wdata_sequence_2;
+	u32 wdata_sequence_3;
+	u32 wdata_sequence_4;
+	u32 wdata_sequence_5;
+	u32 wdata_sequence_6;
+	u32 wdata_sequence_7;
+	u32 debug_sw_driver_0;
+	u32 debug_sw_driver_1;
+	u32 debug_sw_driver_2;
+	u32 debug_sw_driver_3;
+	u32 debug_sw_driver_4;
+	u32 debug_sw_driver_5;
+	u32 bwc_options;
+	u32 reserved1[524];
+	u32 wacs0_cmd;
+	u32 wacs0_rdata;
+	u32 wacs0_vldclr;
+	u32 reserved2;
+	u32 wacs1_cmd;
+	u32 wacs1_rdata;
+	u32 wacs1_vldclr;
+	u32 reserved3;
+	u32 wacs2_cmd;
+	u32 wacs2_rdata;
+	u32 wacs2_vldclr;
+	u32 reserved4;
+	u32 wacs3_cmd;
+	u32 wacs3_rdata;
+	u32 wacs3_vldclr;
+};
+
+static struct mt8183_pwrap_regs * const mtk_pwrap = (void *)PWRAP_BASE;
+
+enum {
+	WACS2 = 1 << 2
+};
+
+/* PMIC registers */
+enum {
+	PMIC_BASE                     = 0x0000,
+	PMIC_SMT_CON1                 = PMIC_BASE + 0x0030,
+	PMIC_DRV_CON1                 = PMIC_BASE + 0x0038,
+	PMIC_FILTER_CON0              = PMIC_BASE + 0x0040,
+	PMIC_GPIO_PULLEN0_CLR         = PMIC_BASE + 0x0098,
+	PMIC_RG_SPI_CON0              = PMIC_BASE + 0x0408,
+	PMIC_RG_SPI_RECORD0           = PMIC_BASE + 0x040A,
+	PMIC_DEW_DIO_EN               = PMIC_BASE + 0x040C,
+	PMIC_DEW_READ_TEST            = PMIC_BASE + 0x040E,
+	PMIC_DEW_WRITE_TEST           = PMIC_BASE + 0x0410,
+	PMIC_DEW_CRC_EN               = PMIC_BASE + 0x0414,
+	PMIC_DEW_CRC_VAL              = PMIC_BASE + 0x0416,
+	PMIC_DEW_RDDMY_NO             = PMIC_BASE + 0x0426,
+	PMIC_CPU_INT_STA              = PMIC_BASE + 0x042E,
+	PMIC_RG_SPI_CON2              = PMIC_BASE + 0x0432,
+	PMIC_RG_SPI_CON3              = PMIC_BASE + 0x0434,
+	PMIC_RG_SPI_CON4              = PMIC_BASE + 0x0436,
+	PMIC_RG_SPI_CON5              = PMIC_BASE + 0x0438,
+	PMIC_RG_SPI_CON6              = PMIC_BASE + 0x043A,
+	PMIC_RG_SPI_CON7              = PMIC_BASE + 0x043C,
+	PMIC_RG_SPI_CON8              = PMIC_BASE + 0x043E,
+	PMIC_RG_SPI_CON13             = PMIC_BASE + 0x0448,
+	PMIC_SPISLV_KEY               = PMIC_BASE + 0x044A,
+	PMIC_PPCCTL0                  = PMIC_BASE + 0x0A08,
+	PMIC_AUXADC_ADC17             = PMIC_BASE + 0x10AA,
+	PMIC_AUXADC_ADC31             = PMIC_BASE + 0x10C6,
+	PMIC_AUXADC_ADC32             = PMIC_BASE + 0x10C8,
+	PMIC_AUXADC_ADC35             = PMIC_BASE + 0x10CE,
+	PMIC_AUXADC_RQST0             = PMIC_BASE + 0x1108,
+	PMIC_AUXADC_RQST1             = PMIC_BASE + 0x110A,
+};
+
+enum {
+	E_CLK_EDGE = 1,
+	E_CLK_LAST_SETTING
+};
+
+enum {
+	GPS_MAIN = 0x40,
+	GPS_SUBSYS = 0x80
+};
+
+enum {
+	ULPOSC_CLK = 0x1 << 23
+};
+
+enum {
+	ULPOSC_OFF = 0x1 << 31,
+	ULPOSC_INV = 0x1 << 28,
+	ULPOSC_SEL_1 = 0x1 << 24,
+	ULPOSC_SEL_2 = 0x1 << 25,
+};
+
+enum {
+	TIMER_CG = 0x1,
+	AP_CG = 0x1 << 1,
+	MD_CG = 0x1 << 2,
+	CONN_CG = 0x1 << 3,
+};
+
+enum {
+	MODEM_TEMP_SHARE_CG = 0x1 << 8,
+};
+
+enum {
+	SIG_PMIC_0 = 0x1 << 0,
+	INT_STA_PMIC_0 = 0x1 << 2,
+	MD_ADC_DATA0 = 0x1 << 4,
+	MD_ADC_DATA1 = 0x1 << 5,
+	GPS_ADC_DATA0 = 0x1 << 6,
+	GPS_ADC_DATA1 = 0x1 << 7,
+};
+
+enum {
+	MD = 1,
+	MD_DVFS = 2,
+	POWER_HW = 4,
+	POWER_HW_BACKUP = 8,
+	ARB_PRIORITY = MD | MD_DVFS | POWER_HW | POWER_HW_BACKUP,
+};
+
+enum {
+	ARB_WACS0 = 0x1,
+	ARB_WACS2 = 0x1 << 2,
+	ARB_WACS_P2P = 0x1 << 4,
+	ARB_WACS_MD32 = 0x1 << 5,
+	ARB_MD = 0x1 << 6,
+	ARB_WACS_POWER_HW = 0x1 << 9,
+	ARB_DCXO_CONN = 0x1 << 11,
+	ARB_DCXO_NFC = 0x1 << 12,
+	ARB_MD_ADC0 = 0x1 << 13,
+	ARB_MD_ADC1 = 0x1 << 14,
+	ARB_GPS_0 = 0x1 << 15,
+	ARB_GPS_1 = 0x1 << 16,
+	STAUPD_HARB = 0x1 << 17,
+	ARB_USER_EN = ARB_WACS0 | ARB_WACS2 | ARB_WACS_P2P | ARB_WACS_MD32 |
+		ARB_MD | ARB_WACS_POWER_HW | ARB_DCXO_CONN | ARB_DCXO_NFC |
+		ARB_MD_ADC0 | ARB_MD_ADC1 | ARB_GPS_0 | ARB_GPS_1 | STAUPD_HARB,
+};
+
+enum {
+	STA_PD_98_5_US = 0X5,
+};
+
+enum {
+	WATCHDOG_TIMER_7_5_MS = 0XF,
+};
+
+enum {
+	WDT_MONITOR_ALL = 0XFFFF,
+};
+
+enum {
+	MONITOR_LATCH_MATCHED_TRANS = 0x1 << 28,
+	STARV_15 = 0x1 << 24,
+	DCXO = 0x1 << 19,
+	MONITOR_ALL_INT = 0XFFFFFFFF,
+	INT0_MONITOR = MONITOR_ALL_INT,
+	INT1_MONITOR = MONITOR_ALL_INT &
+		~MONITOR_LATCH_MATCHED_TRANS & ~STARV_15 & ~DCXO,
+};
+
+enum {
+	SPI_CLK = 0x1,
+	SPI_CSN = 0x1 << 1,
+	SPI_MOSI = 0x1 << 2,
+	SPI_MISO = 0x1 << 3,
+	SPI_FILTER = (SPI_CLK | SPI_CSN | SPI_MOSI | SPI_MISO) << 4,
+	SPI_SMT = (SPI_CLK | SPI_CSN | SPI_MOSI | SPI_MISO),
+	SPI_PULL_DISABLE = (SPI_CLK | SPI_CSN | SPI_MOSI | SPI_MISO) << 4,
+};
+
+enum {
+	IO_4_MA = 0x8,
+};
+
+enum {
+	SPI_CLK_SHIFT = 0,
+	SPI_CSN_SHIFT = 4,
+	SPI_MOSI_SHIFT = 8,
+	SPI_MISO_SHIFT = 12,
+	SPI_DRIVING = (IO_4_MA << SPI_CLK_SHIFT | IO_4_MA << SPI_CSN_SHIFT |
+		IO_4_MA << SPI_MOSI_SHIFT | IO_4_MA << SPI_MISO_SHIFT),
+};
+
+enum {
+	DUMMY_READ_CYCLES = 0X8,
+};
+#endif /* __PMIC_WRAP_H */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/regulator_core.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/regulator_core.h
new file mode 100644
index 0000000..bc5e4a9
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/regulator_core.h
@@ -0,0 +1,227 @@
+/*
+ * 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.
+ */
+
+#ifndef __REGULATOR_CORE_H
+#define __REGULATOR_CORE_H
+
+#include <compiler.h>
+#include <platform/regulator.h>
+
+#define vsram_others_vol_reg            0x1bf2
+#define vsram_others_vol_mask           0x7F
+#define vsram_others_vol_shift          0
+#define vsram_others_da_vol_reg         0x1bc0
+#define vsram_others_da_vol_mask        0x7F
+#define vsram_others_da_vol_shift       8
+#define vsram_others_enable_reg         0x1ba6
+#define vsram_others_enable_shift       0
+#define vsram_others_mode_reg           0
+#define vsram_others_mode_shift         0
+#define vsram_others_trim_reg           0
+#define vsram_others_trim_mask          0
+#define vsram_others_trim_shift         0
+#define vsram_others_min_uV             500000
+#define vsram_others_max_uV             1293750
+#define vsram_others_step_uV            6250
+#define vsram_others_volt_type          REGULAR_VOLTAGE
+#define vsram_others_stb                240
+
+#define vcore_vol_reg                   0x14aa
+#define vcore_vol_mask                  0x7F
+#define vcore_vol_shift                 0
+#define vcore_da_vol_reg                0x149e
+#define vcore_da_vol_mask               0x7F
+#define vcore_da_vol_shift              0
+#define vcore_enable_reg                0x1488
+#define vcore_enable_shift              0
+#define vcore_mode_reg                  0x1828
+#define vcore_mode_shift                1
+#define vcore_trim_reg                  0
+#define vcore_trim_mask                 0
+#define vcore_trim_shift                0
+#define vcore_min_uV                    500000
+#define vcore_max_uV                    1293750
+#define vcore_step_uV                   6250
+#define vcore_volt_type                 REGULAR_VOLTAGE
+#define vcore_stb                       1000
+
+#define vdram1_vol_reg                  0x1626
+#define vdram1_vol_mask                 0x7F
+#define vdram1_vol_shift                0
+#define vdram1_da_vol_reg               0x161e
+#define vdram1_da_vol_mask              0x7F
+#define vdram1_da_vol_shift             0
+#define vdram1_enable_reg               0x1608
+#define vdram1_enable_shift             0
+#define vdram1_mode_reg                 0x1896
+#define vdram1_mode_shift               8
+#define vdram1_trim_reg                 0
+#define vdram1_trim_mask                0
+#define vdram1_trim_shift               0
+#define vdram1_min_uV                   500000
+#define vdram1_max_uV                   2087500
+#define vdram1_step_uV                  12500
+#define vdram1_volt_type                REGULAR_VOLTAGE
+#define vdram1_stb                      1000
+
+#define vdram2_vol_reg                  0x1b78
+#define vdram2_vol_mask                 0xF
+#define vdram2_vol_shift                0
+#define vdram2_da_vol_reg               0
+#define vdram2_da_vol_mask              0
+#define vdram2_da_vol_shift             0
+#define vdram2_enable_reg               0x1b08
+#define vdram2_enable_shift             0
+#define vdram2_mode_reg                 0
+#define vdram2_mode_shift               0
+#define vdram2_trim_reg                 0x1ec4
+#define vdram2_trim_mask                0xF
+#define vdram2_trim_shift               0
+#define vdram2_min_uV                   600000
+#define vdram2_max_uV                   1800000
+#define vdram2_step_uV                  0
+#define vdram2_volt_type                NON_REGULAR_VOLTAGE
+#define vdram2_stb                      3300
+
+#define vio18_vol_reg                   0
+#define vio18_vol_mask                  0
+#define vio18_vol_shift                 0
+#define vio18_da_vol_reg                0
+#define vio18_da_vol_mask               0
+#define vio18_da_vol_shift              0
+#define vio18_enable_reg                0x1aec
+#define vio18_enable_shift              0
+#define vio18_mode_reg                  0
+#define vio18_mode_shift                0
+#define vio18_trim_reg                  0x1ebe
+#define vio18_trim_mask                 0xF
+#define vio18_trim_shift                0
+#define vio18_min_uV                    1800000
+#define vio18_max_uV                    1800000
+#define vio18_step_uV                   0
+#define vio18_volt_type                 FIXED_REGULAR_VOLTAGE
+#define vio18_stb                       2700
+
+#define vrf12_vol_reg                   0
+#define vrf12_vol_mask                  0
+#define vrf12_vol_shift                 0
+#define vrf12_da_vol_reg                0
+#define vrf12_da_vol_mask               0
+#define vrf12_da_vol_shift              0
+#define vrf12_enable_reg                0x1c30
+#define vrf12_enable_shift              0
+#define vrf12_mode_reg                  0
+#define vrf12_mode_shift                0
+#define vrf12_trim_reg                  0
+#define vrf12_trim_mask                 0
+#define vrf12_trim_shift                0
+#define vrf12_min_uV                    1200000
+#define vrf12_max_uV                    1200000
+#define vrf12_step_uV                   0
+#define vrf12_volt_type                 FIXED_REGULAR_VOLTAGE
+
+#define vcn18_vol_reg                   0
+#define vcn18_vol_mask                  0
+#define vcn18_vol_shift                 0
+#define vcn18_da_vol_reg                0
+#define vcn18_da_vol_mask               0
+#define vcn18_da_vol_shift              0
+#define vcn18_enable_reg                0x1c58
+#define vcn18_enable_shift              0
+#define vcn18_mode_reg                  0
+#define vcn18_mode_shift                0
+#define vcn18_trim_reg                  0
+#define vcn18_trim_mask                 0
+#define vcn18_trim_shift                0
+#define vcn18_min_uV                    1800000
+#define vcn18_max_uV                    1800000
+#define vcn18_step_uV                   0
+#define vcn18_volt_type                 FIXED_REGULAR_VOLTAGE
+
+#define vcn33_vol_reg                   0
+#define vcn33_vol_mask                  0
+#define vcn33_vol_shift                 0
+#define vcn33_da_vol_reg                0
+#define vcn33_da_vol_mask               0
+#define vcn33_da_vol_shift              0
+#define vcn33_enable_reg                0x1d1c
+#define vcn33_enable_shift              0
+#define vcn33_mode_reg                  0
+#define vcn33_mode_shift                0
+#define vcn33_trim_reg                  0
+#define vcn33_trim_mask                 0
+#define vcn33_trim_shift                0
+#define vcn33_min_uV                    3300000
+#define vcn33_max_uV                    3300000
+#define vcn33_step_uV                   0
+#define vcn33_volt_type                 FIXED_REGULAR_VOLTAGE
+
+#define mt6358_ldo_trim_decl(_name, trim_array)\
+{ \
+	.trim_reg = _name##_trim_reg, \
+	.trim_mask = _name##_trim_mask, \
+	.trim_shift = _name##_trim_shift, \
+	.trim_voltages = (void *)(trim_array), \
+	.trim_size = countof(trim_array),	\
+}
+
+#define mt6358_ldo_decl(volt_array, idx_array)\
+{ \
+	.pvoltages = (void *)(volt_array), \
+	.idxs = (void *)(idx_array), \
+	.n_size = countof(volt_array),	\
+}
+
+#define mt6358_decl(_name)\
+{ \
+	.min_uV = _name##_min_uV, \
+	.max_uV = _name##_max_uV, \
+	.vol_reg = _name##_vol_reg, \
+	.vol_mask = _name##_vol_mask, \
+	.vol_shift = _name##_vol_shift, \
+	.da_vol_reg = _name##_da_vol_reg, \
+	.da_vol_mask = _name##_da_vol_mask, \
+	.da_vol_shift = _name##_da_vol_shift, \
+	.enable_reg = _name##_enable_reg, \
+	.enable_shift = _name##_enable_shift, \
+	.mode_reg = _name##_mode_reg, \
+	.mode_shift = _name##_mode_shift, \
+	.step_uV = _name##_step_uV, \
+	.rtype = _name##_volt_type, \
+}
+
+struct regulator_ctrl {
+	int (*set_voltage)(unsigned char id, unsigned int min_vol, unsigned int max_vol);
+	int (*get_voltage)(unsigned char id);
+	int (*enable)(unsigned char id, unsigned char en);
+	int (*is_enabled)(unsigned char id);
+	int (*set_mode)(unsigned char id, unsigned char mode);
+	int (*get_mode)(unsigned char id);
+	int (*set_votrim)(unsigned char id, int trim_volt);
+	int (*get_votrim)(unsigned char id);
+};
+
+int mtk_simple_regulator_register(struct mtk_regulator *mreg);
+int mt6358_regulator_init(void);
+
+#endif /* __REGULATOR_CORE_H */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/rtc.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/rtc.h
new file mode 100644
index 0000000..e88a74f
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/rtc.h
@@ -0,0 +1,174 @@
+/*
+ * 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 <platform/rtc_common.h>
+
+/* RTC registers */
+enum {
+    RTC_BBPU = 0x0588,
+    RTC_IRQ_STA = 0x058A,
+    RTC_IRQ_EN = 0x058C,
+    RTC_CII_EN = 0x058E
+};
+
+enum {
+    RTC_TC_SEC = 0x0592,
+    RTC_TC_MIN = 0x0594,
+    RTC_TC_HOU = 0x0596,
+    RTC_TC_DOM = 0x0598,
+    RTC_TC_DOW = 0x059A,
+    RTC_TC_MTH = 0x059C,
+    RTC_TC_YEA = 0x059E
+};
+
+enum {
+    RTC_AL_SEC = 0x05A0,
+    RTC_AL_MIN = 0x05A2,
+    RTC_AL_HOU = 0x05A4,
+    RTC_AL_DOM = 0x05A6,
+    RTC_AL_DOW = 0x05A8,
+    RTC_AL_MTH = 0x05AA,
+    RTC_AL_YEA = 0x05AC,
+    RTC_AL_MASK = 0x0590
+};
+
+enum {
+    RTC_OSC32CON = 0x05AE,
+    RTC_CON = 0x05C4,
+    RTC_WRTGR = 0x05C2
+};
+
+enum {
+    RTC_POWERKEY1 = 0x05B0,
+    RTC_POWERKEY2 = 0x05B2
+};
+
+enum {
+    RTC_PDN1 = 0x05B4,
+    RTC_PDN2 = 0x05B6,
+    RTC_SPAR0 = 0x05B8,
+    RTC_SPAR1 = 0x05BA,
+    RTC_PROT = 0x05BC,
+    RTC_DIFF = 0x05BE,
+    RTC_CALI = 0x05C0
+};
+
+enum {
+    RTC_BBPU_PWREN = 1U << 0,
+    RTC_BBPU_CLR = 1U << 1,
+    RTC_BBPU_INIT = 1U << 2,
+    RTC_BBPU_AUTO = 1U << 3,
+    RTC_BBPU_CLRPKY = 1U << 4,
+    RTC_BBPU_RELOAD = 1U << 5,
+    RTC_BBPU_CBUSY = 1U << 6,
+
+    RTC_CBUSY_TIMEOUT_US = 8000
+};
+
+enum {
+    RTC_CON_VBAT_LPSTA_RAW = 1U << 0,
+    RTC_CON_EOSC32_LPEN = 1U << 1,
+    RTC_CON_XOSC32_LPEN = 1U << 2,
+    RTC_CON_LPRST = 1U << 3,
+    RTC_CON_CDBO = 1U << 4,
+    RTC_CON_F32KOB = 1U << 5,
+    RTC_CON_GPO = 1U << 6,
+    RTC_CON_GOE = 1U << 7,
+    RTC_CON_GSR = 1U << 8,
+    RTC_CON_GSMT = 1U << 9,
+    RTC_CON_GPEN = 1U << 10,
+    RTC_CON_GPU = 1U << 11,
+    RTC_CON_GE4 = 1U << 12,
+    RTC_CON_GE8 = 1U << 13,
+    RTC_CON_GPI = 1U << 14,
+    RTC_CON_LPSTA_RAW = 1U << 15
+};
+
+enum {
+    RTC_XOSCCALI_MASK = 0x1F << 0,
+    RTC_XOSC32_ENB = 1U << 5,
+    RTC_EMB_HW_MODE = 0U << 6,
+    RTC_EMB_K_EOSC32_MODE = 1U << 6,
+    RTC_EMB_SW_DCXO_MODE = 2U << 6,
+    RTC_EMB_SW_EOSC32_MODE = 3U << 6,
+    RTC_EMBCK_SEL_MODE_MASK = 3U << 6,
+    RTC_EMBCK_SRC_SEL = 1U << 8,
+    RTC_EMBCK_SEL_OPTION = 1U << 9,
+    RTC_GPS_CKOUT_EN = 1U << 10,
+    RTC_REG_XOSC32_ENB = 1U << 15
+};
+
+enum {
+    RTC_LPD_OPT_XOSC_AND_EOSC_LPD = 0U << 13,
+    RTC_LPD_OPT_EOSC_LPD = 1U << 13,
+    RTC_LPD_OPT_XOSC_LPD = 2U << 13,
+    RTC_LPD_OPT_F32K_CK_ALIVE = 3U << 13,
+    RTC_LPD_OPT_MASK = 3U << 13
+};
+
+enum {
+    RTC_PDN1_FAST_BOOT = 1 << 13
+};
+
+/* PMIC TOP Register Definition */
+enum {
+    PMIC_RG_SCK_TOP_CON0 = 0x050C
+};
+
+/* PMIC TOP Register Definition */
+enum {
+    PMIC_RG_TOP_CKPDN_CON1 = 0x0112,
+    PMIC_RG_TOP_CKPDN_CON1_SET = 0x0114,
+    PMIC_RG_TOP_CKPDN_CON1_CLR = 0x0116,
+    PMIC_RG_TOP_CKSEL_CON0 = 0x0118,
+    PMIC_RG_TOP_CKSEL_CON0_SET = 0x011A,
+    PMIC_RG_TOP_CKSEL_CON0_CLR = 0x011C
+};
+
+/* PMIC DCXO Register Definition */
+enum {
+    PMIC_RG_DCXO_CW00 = 0x0788,
+    PMIC_RG_DCXO_CW02 = 0x0790,
+    PMIC_RG_DCXO_CW07 = 0x079A,
+    PMIC_RG_DCXO_CW09 = 0x079E,
+    PMIC_RG_DCXO_CW11 = 0x07A2,
+    PMIC_RG_DCXO_CW13 = 0x07AA,
+    PMIC_RG_DCXO_CW15 = 0x07AE,
+    PMIC_RG_DCXO_CW16 = 0x07B0,
+    PMIC_RG_DCXO_CW21 = 0x07BA,
+    PMIC_RG_DCXO_ELR0 = 0x07C4
+};
+
+enum {
+    PMIC_RG_TOP_TMA_KEY = 0x03A8
+};
+
+/* external API */
+void rtc_bbpu_power_on(void);
+void rtc_osc_init(void);
+int rtc_init(u8 recover);
+void rtc_boot(void);
+/* get and set bootloader flag */
+bool rtc_bootloader_check(void);
+void rtc_bootloader_set_clr(bool value);
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/smi_common.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/smi_common.h
new file mode 100644
index 0000000..2f31589
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/smi_common.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#ifndef SOC_MEDIATEK_MT8183_SMI_COMMON_H
+#define SOC_MEDIATEK_MT8183_SMI_COMMON_H
+
+#include <platform/mt_reg_base.h>
+
+struct mt8183_smi_common_regs {
+    unsigned int reserved1[64];
+    unsigned int smi_l1len;
+    unsigned int smi_l1arb0;
+    unsigned int smi_l1arb1;
+    unsigned int smi_l1arb2;
+    unsigned int smi_l1arb3;
+    unsigned int smi_l1arb4;
+    unsigned int smi_l1arb5;
+    unsigned int smi_l1arb6;
+    unsigned int smi_l1arb7;
+    unsigned int reserved2[31];
+    unsigned int smi_mon_axi_ena;
+    unsigned int smi_mon_axi_clr;
+    unsigned int reserved3[1];
+    unsigned int smi_mon_axi_type;
+    unsigned int smi_mon_axi_con;
+    unsigned int reserved4[3];
+    unsigned int smi_mon_axi_act_cnt;
+    unsigned int smi_mon_axi_req_cnt;
+    unsigned int smi_mon_axi_ostd_cnt;
+    unsigned int smi_mon_axi_bea_cnt;
+    unsigned int smi_mon_axi_byt_cnt;
+    unsigned int smi_mon_axi_cp_cnt;
+    unsigned int smi_mon_axi_dp_cnt;
+    unsigned int smi_mon_axi_cp_max;
+    unsigned int smi_mon_axi_cos_max;
+    unsigned int reserved5[15];
+    unsigned int smi_bus_sel;
+    unsigned int reserved6[1];
+    unsigned int smi_wrr_reg0;
+    unsigned int smi_wrr_reg1;
+    unsigned int smi_read_fifo_th;
+    unsigned int smi_m4u_th;
+    unsigned int smi_fifo_th1;
+    unsigned int smi_fifo_th2;
+    unsigned int smi_preultra_mask0;
+    unsigned int smi_preultra_mask1;
+    unsigned int reserved7[46];
+    unsigned int smi_dcm;
+    unsigned int smi_ela;
+    unsigned int smi_m1_rultra_wrr0;
+    unsigned int smi_m1_rultra_wrr1;
+    unsigned int smi_m1_wultra_wrr0;
+    unsigned int smi_m1_wultra_wrr1;
+    unsigned int smi_m2_rultra_wrr0;
+    unsigned int smi_m2_rultra_wrr1;
+    unsigned int smi_m2_wultra_wrr0;
+    unsigned int smi_m2_wultra_wrr1;
+    unsigned int reserved8[38];
+    unsigned int smi_common_clamp_en;
+    unsigned int smi_common_clamp_en_set;
+    unsigned int smi_common_clamp_en_clr;
+    unsigned int reserved9[13];
+    unsigned int smi_debug_s0;
+    unsigned int smi_debug_s1;
+    unsigned int smi_debug_s2;
+    unsigned int smi_debug_s3;
+    unsigned int smi_debug_s4;
+    unsigned int smi_debug_s5;
+    unsigned int smi_debug_s6;
+    unsigned int smi_debug_s7;
+    unsigned int reserved10[4];
+    unsigned int smi_debug_m0;
+    unsigned int smi_debug_m1;
+    unsigned int reserved11[2];
+    unsigned int smi_debug_misc;
+    unsigned int smi_dummy;
+    unsigned int reserved12[46];
+    unsigned int smi_hist_rec0;
+    unsigned int smi_hist_rec_data0;
+    unsigned int smi_hist_rec_data1;
+    unsigned int smi_hist_rec_data2;
+    unsigned int smi_hist_rec_data3;
+    unsigned int smi_hist_rec_data4;
+    unsigned int smi_hist_rec_data5;
+    unsigned int smi_hist_rec_data6;
+    unsigned int smi_hist_rec_data7;
+    unsigned int smi_hist_rec_data8;
+    unsigned int smi_hist_rec_data9;
+};
+
+static struct mt8183_smi_common_regs *const mt8183_smi_common = (void *)SMI_COMMON_BASE;
+
+#endif  /* SOC_MEDIATEK_MT8183_SMI_COMMON_H */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/spm.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/spm.h
new file mode 100644
index 0000000..55228ae
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/spm.h
@@ -0,0 +1,485 @@
+/*
+ * 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.
+ */
+
+#ifndef SOC_MEDIATEK_MT8183_SPM_H
+#define SOC_MEDIATEK_MT8183_SPM_H
+
+#include <platform/mt_reg_base.h>
+
+enum {
+    SPM_PROJECT_CODE = 0xb16
+};
+
+enum {
+    DISP_SRAM_PDN_MASK  = 0x1 << 8,
+    DISP_SRAM_ACK_MASK  = 0x1 << 12,
+    AUDIO_SRAM_PDN_MASK = 0xf << 8,
+    AUDIO_SRAM_ACK_MASK = 0xf << 12,
+};
+
+struct mtk_spm_regs {
+    unsigned int poweron_config_set;
+    unsigned int spm_power_on_val0;
+    unsigned int spm_power_on_val1;
+    unsigned int spm_clk_con;
+    unsigned int spm_clk_settle;
+    unsigned int spm_ap_standby_con;
+    unsigned int pcm_con0;
+    unsigned int pcm_con1;
+    unsigned int pcm_im_ptr;
+    unsigned int pcm_im_len;
+    unsigned int pcm_reg_data_ini;
+    unsigned int pcm_pwr_io_en;
+    unsigned int pcm_timer_val;
+    unsigned int pcm_wdt_val;
+    unsigned int pcm_im_host_rw_ptr;
+    unsigned int pcm_im_host_rw_dat;
+    unsigned int pcm_event_vector0;
+    unsigned int pcm_event_vector1;
+    unsigned int pcm_event_vector2;
+    unsigned int pcm_event_vector3;
+    unsigned int pcm_event_vector4;
+    unsigned int pcm_event_vector5;
+    unsigned int pcm_event_vector6;
+    unsigned int pcm_event_vector7;
+    unsigned int pcm_event_vector8;
+    unsigned int pcm_event_vector9;
+    unsigned int pcm_event_vector10;
+    unsigned int pcm_event_vector11;
+    unsigned int pcm_event_vector12;
+    unsigned int pcm_event_vector13;
+    unsigned int pcm_event_vector14;
+    unsigned int pcm_event_vector15;
+    unsigned int pcm_event_vector_en;
+    unsigned int reserved1[1];
+    unsigned int spm_sram_rsv_con;
+    unsigned int spm_swint;
+    unsigned int spm_swint_set;
+    unsigned int spm_swint_clr;
+    unsigned int spm_scp_mailbox;
+    unsigned int scp_spm_mailbox;
+    unsigned int spm_twam_con;
+    unsigned int spm_twam_window_len;
+    unsigned int spm_twam_idle_sel;
+    unsigned int spm_scp_irq;
+    unsigned int spm_cpu_wakeup_event;
+    unsigned int spm_irq_mask;
+    unsigned int spm_src_req;
+    unsigned int spm_src_mask;
+    unsigned int spm_src2_mask;
+    unsigned int spm_wakeup_event_mask;
+    unsigned int spm_wakeup_event_ext_mask;
+    unsigned int spm_twam_event_clear;
+    unsigned int scp_clk_con;
+    unsigned int pcm_debug_con;
+    unsigned int ddr_en_dbc_len;
+    unsigned int ahb_bus_con;
+    unsigned int spm_src3_mask;
+    unsigned int ddr_en_emi_dbc_con;
+    unsigned int md32_clk_con;
+    unsigned int reserved2[5];
+    unsigned int pcm_reg0_data;
+    unsigned int pcm_reg1_data;
+    unsigned int pcm_reg2_data;
+    unsigned int pcm_reg3_data;
+    unsigned int pcm_reg4_data;
+    unsigned int pcm_reg5_data;
+    unsigned int pcm_reg6_data;
+    unsigned int pcm_reg7_data;
+    unsigned int pcm_reg8_data;
+    unsigned int pcm_reg9_data;
+    unsigned int pcm_reg10_data;
+    unsigned int pcm_reg11_data;
+    unsigned int pcm_reg12_data;
+    unsigned int pcm_reg13_data;
+    unsigned int pcm_reg14_data;
+    unsigned int pcm_reg15_data;
+    unsigned int pcm_reg12_mask_b_sta;
+    unsigned int pcm_reg12_ext_data;
+    unsigned int pcm_reg12_ext_mask_b_sta;
+    unsigned int pcm_event_reg_sta;
+    unsigned int pcm_timer_out;
+    unsigned int pcm_wdt_out;
+    unsigned int spm_irq_sta;
+    unsigned int spm_wakeup_sta;
+    unsigned int spm_wakeup_ext_sta;
+    unsigned int spm_wakeup_misc;
+    unsigned int bus_protect_rdy;
+    unsigned int bus_protect2_rdy;
+    unsigned int subsys_idle_sta;
+    unsigned int cpu_idle_sta;
+    unsigned int pcm_fsm_sta;
+    unsigned int src_req_sta;
+    unsigned int pwr_status;
+    unsigned int pwr_status_2nd;
+    unsigned int cpu_pwr_status;
+    unsigned int cpu_pwr_status_2nd;
+    unsigned int misc_sta;
+    unsigned int spm_src_rdy_sta;
+    unsigned int reserved3[1];
+    unsigned int dramc_dbg_latch;
+    unsigned int spm_twam_last_sta0;
+    unsigned int spm_twam_last_sta1;
+    unsigned int spm_twam_last_sta2;
+    unsigned int spm_twam_last_sta3;
+    unsigned int spm_twam_curr_sta0;
+    unsigned int spm_twam_curr_sta1;
+    unsigned int spm_twam_curr_sta2;
+    unsigned int spm_twam_curr_sta3;
+    unsigned int spm_twam_timer_out;
+    unsigned int reserved4[1];
+    unsigned int spm_dvfs_sta;
+    unsigned int bus_protect3_rdy;
+    unsigned int reserved5[4];
+    unsigned int src_ddren_sta;
+    unsigned int reserved6[7];
+    unsigned int mcu_pwr_con;
+    unsigned int mp0_cputop_pwr_con;
+    unsigned int mp0_cpu0_pwr_con;
+    unsigned int mp0_cpu1_pwr_con;
+    unsigned int mp0_cpu2_pwr_con;
+    unsigned int mp0_cpu3_pwr_con;
+    unsigned int mp1_cputop_pwr_con;
+    unsigned int mp1_cpu0_pwr_con;
+    unsigned int mp1_cpu1_pwr_con;
+    unsigned int mp1_cpu2_pwr_con;
+    unsigned int mp1_cpu3_pwr_con;
+    unsigned int reserved7[5];
+    unsigned int mp0_cputop_l2_pdn;
+    unsigned int mp0_cputop_l2_sleep_b;
+    unsigned int mp0_cpu0_l1_pdn;
+    unsigned int mp0_cpu1_l1_pdn;
+    unsigned int mp0_cpu2_l1_pdn;
+    unsigned int mp0_cpu3_l1_pdn;
+    unsigned int mp1_cputop_l2_pdn;
+    unsigned int mp1_cputop_l2_sleep_b;
+    unsigned int mp1_cpu0_l1_pdn;
+    unsigned int mp1_cpu1_l1_pdn;
+    unsigned int mp1_cpu2_l1_pdn;
+    unsigned int mp1_cpu3_l1_pdn;
+    unsigned int reserved8[8];
+    unsigned int cpu_ext_buck_iso;
+    unsigned int reserved9[7];
+    unsigned int dummy1_pwr_con;
+    unsigned int bypass_spmc;
+    unsigned int spmc_dormant_enable;
+    unsigned int armpll_clk_con;
+    unsigned int spmc_in_ret;
+    unsigned int reserved10[15];
+    unsigned int vde_pwr_con;
+    unsigned int ven_pwr_con;
+    unsigned int isp_pwr_con;
+    unsigned int dis_pwr_con;
+    unsigned int mfg_core1_pwr_con;
+    unsigned int audio_pwr_con;
+    unsigned int ifr_pwr_con;
+    unsigned int dpy_pwr_con;
+    unsigned int md1_pwr_con;
+    unsigned int vpu_top_pwr_con;
+    unsigned int reserved11[1];
+    unsigned int conn_pwr_con;
+    unsigned int vpu_core2_pwr_con;
+    unsigned int mfg_async_pwr_con;
+    unsigned int mfg_pwr_con;
+    unsigned int vpu_core0_pwr_con;
+    unsigned int vpu_core1_pwr_con;
+    unsigned int cam_pwr_con;
+    unsigned int mfg_2d_pwr_con;
+    unsigned int mfg_core0_pwr_con;
+    unsigned int sysram_con;
+    unsigned int sysrom_con;
+    unsigned int sspm_sram_con;
+    unsigned int scp_sram_con;
+    unsigned int reserved12[3];
+    unsigned int ufs_sram_con;
+    unsigned int reserved13[4];
+    unsigned int dummy_sram_con;
+    unsigned int reserved14[3];
+    unsigned int md_ext_buck_iso_con;
+    unsigned int md_sram_iso_con;
+    unsigned int md_extra_pwr_con;
+    unsigned int reserved15[1];
+    unsigned int ext_buck_con;
+    unsigned int reserved16[11];
+    unsigned int mbist_efuse_repair_ack_sta;
+    unsigned int reserved17[11];
+    unsigned int spm_dvfs_con;
+    unsigned int spm_mdbsi_con;
+    unsigned int spm_mas_pause_mask_b;
+    unsigned int spm_mas_pause2_mask_b;
+    unsigned int spm_bsi_gen;
+    unsigned int spm_bsi_en_sr;
+    unsigned int spm_bsi_clk_sr;
+    unsigned int spm_bsi_d0_sr;
+    unsigned int spm_bsi_d1_sr;
+    unsigned int spm_bsi_d2_sr;
+    unsigned int spm_ap_sema;
+    unsigned int spm_spm_sema;
+    unsigned int ap_mdsrc_req;
+    unsigned int reserved18[1];
+    unsigned int spm2md_dvfs_con;
+    unsigned int md2spm_dvfs_con;
+    unsigned int dramc_dpy_clk_sw_con_rsv;
+    unsigned int dpy_lp_con;
+    unsigned int cpu_dvfs_req;
+    unsigned int spm_pll_con;
+    unsigned int spm_emi_bw_mode;
+    unsigned int ap2md_peer_wakeup;
+    unsigned int ulposc_con;
+    unsigned int spm2mm_con;
+    unsigned int dramc_dpy_clk_sw_con_sel;
+    unsigned int dramc_dpy_clk_sw_con;
+    unsigned int spm_s1_mode_ch;
+    unsigned int emi_self_refresh_ch_sta;
+    unsigned int dramc_dpy_clk_sw_con_sel2;
+    unsigned int dramc_dpy_clk_sw_con2;
+    unsigned int dramc_dmyrd_con;
+    unsigned int spm_drs_con;
+    unsigned int spm_sema_m0;
+    unsigned int spm_sema_m1;
+    unsigned int spm_sema_m2;
+    unsigned int spm_sema_m3;
+    unsigned int spm_sema_m4;
+    unsigned int spm_sema_m5;
+    unsigned int spm_sema_m6;
+    unsigned int spm_sema_m7;
+    unsigned int spm_mas_pause_mm_mask_b;
+    unsigned int spm_mas_pause_mcu_mask_b;
+    unsigned int reserved19[1];
+    unsigned int sram_dreq_ack;
+    unsigned int sram_dreq_con;
+    unsigned int sram_dreq_con_set;
+    unsigned int sram_dreq_con_clr;
+    unsigned int spm2emi_enter_ulpm;
+    unsigned int spm_md32_irq;
+    unsigned int spm2pmcu_int;
+    unsigned int spm2pmcu_int_set;
+    unsigned int spm2pmcu_int_clr;
+    unsigned int spm2pmcu_mailbox_0;
+    unsigned int spm2pmcu_mailbox_1;
+    unsigned int spm2pmcu_mailbox_2;
+    unsigned int spm2pmcu_mailbox_3;
+    unsigned int pmcu2spm_int;
+    unsigned int pmcu2spm_int_set;
+    unsigned int pmcu2spm_int_clr;
+    unsigned int pmcu2spm_mailbox_0;
+    unsigned int pmcu2spm_mailbox_1;
+    unsigned int pmcu2spm_mailbox_2;
+    unsigned int pmcu2spm_mailbox_3;
+    unsigned int pmcu2spm_cfg;
+    unsigned int mp0_cpu0_irq_mask;
+    unsigned int mp0_cpu1_irq_mask;
+    unsigned int mp0_cpu2_irq_mask;
+    unsigned int mp0_cpu3_irq_mask;
+    unsigned int mp1_cpu0_irq_mask;
+    unsigned int mp1_cpu1_irq_mask;
+    unsigned int mp1_cpu2_irq_mask;
+    unsigned int mp1_cpu3_irq_mask;
+    unsigned int reserved20[4];
+    unsigned int mp0_cpu0_wfi_en;
+    unsigned int mp0_cpu1_wfi_en;
+    unsigned int mp0_cpu2_wfi_en;
+    unsigned int mp0_cpu3_wfi_en;
+    unsigned int mp1_cpu0_wfi_en;
+    unsigned int mp1_cpu1_wfi_en;
+    unsigned int mp1_cpu2_wfi_en;
+    unsigned int mp1_cpu3_wfi_en;
+    unsigned int reserved21[1];
+    unsigned int mp0_l2cflush;
+    unsigned int mp1_l2cflush;
+    unsigned int reserved22[1];
+    unsigned int cpu_ptpod2_con;
+    unsigned int reserved23[3];
+    unsigned int root_cputop_addr;
+    unsigned int root_core_addr;
+    unsigned int reserved24[2];
+    unsigned int cpu_spare_con;
+    unsigned int cpu_spare_con_set;
+    unsigned int cpu_spare_con_clr;
+    unsigned int reserved25[17];
+    unsigned int spm2sw_mailbox_0;
+    unsigned int spm2sw_mailbox_1;
+    unsigned int spm2sw_mailbox_2;
+    unsigned int spm2sw_mailbox_3;
+    unsigned int sw2spm_int;
+    unsigned int sw2spm_int_set;
+    unsigned int sw2spm_int_clr;
+    unsigned int sw2spm_mailbox_0;
+    unsigned int sw2spm_mailbox_1;
+    unsigned int sw2spm_mailbox_2;
+    unsigned int sw2spm_mailbox_3;
+    unsigned int sw2spm_cfg;
+    unsigned int spm_sw_flag;
+    unsigned int spm_sw_debug;
+    unsigned int spm_sw_rsv_0;
+    unsigned int spm_sw_rsv_1;
+    unsigned int spm_sw_rsv_2;
+    unsigned int spm_sw_rsv_3;
+    unsigned int spm_sw_rsv_4;
+    unsigned int spm_sw_rsv_5;
+    unsigned int spm_rsv_con;
+    unsigned int spm_rsv_sta;
+    unsigned int spm_rsv_con1;
+    unsigned int spm_rsv_sta1;
+    unsigned int spm_pasr_dpd_0;
+    unsigned int spm_pasr_dpd_1;
+    unsigned int spm_pasr_dpd_2;
+    unsigned int spm_pasr_dpd_3;
+    unsigned int spm_spare_con;
+    unsigned int spm_spare_con_set;
+    unsigned int spm_spare_con_clr;
+    unsigned int spm_sw_rsv_6;
+    unsigned int spm_sw_rsv_7;
+    unsigned int spm_sw_rsv_8;
+    unsigned int spm_sw_rsv_9;
+    unsigned int spm_sw_rsv_10;
+    unsigned int reserved26[7];
+    unsigned int spm_sw_rsv_18;
+    unsigned int spm_sw_rsv_19;
+    unsigned int reserved27[3];
+    unsigned int dvfsrc_event_mask_con;
+    unsigned int dvfsrc_event_force_on;
+    unsigned int dvfsrc_event_sel;
+    unsigned int spm_dvfs_event_sta;
+    unsigned int spm_dvfs_event_sta1;
+    unsigned int spm_dvfs_level;
+    unsigned int dvfs_abort_sta;
+    unsigned int dvfs_abort_others_mask;
+    unsigned int spm_dfs_level;
+    unsigned int spm_dvs_level;
+    unsigned int spm_dvfs_misc;
+    unsigned int reserved28[1];
+    unsigned int spare_src_req_mask;
+    unsigned int scp_vcore_level;
+    unsigned int sc_mm_ck_sel_con;
+    unsigned int reserved29[9];
+    unsigned int spare_ack_sta;
+    unsigned int spare_ack_mask;
+    unsigned int reserved30[2];
+    unsigned int spm_dvfs_con1;
+    unsigned int spm_dvfs_con1_sta;
+    unsigned int reserved31[2];
+    unsigned int spm_dvfs_cmd0;
+    unsigned int spm_dvfs_cmd1;
+    unsigned int spm_dvfs_cmd2;
+    unsigned int spm_dvfs_cmd3;
+    unsigned int spm_dvfs_cmd4;
+    unsigned int spm_dvfs_cmd5;
+    unsigned int spm_dvfs_cmd6;
+    unsigned int spm_dvfs_cmd7;
+    unsigned int spm_dvfs_cmd8;
+    unsigned int spm_dvfs_cmd9;
+    unsigned int spm_dvfs_cmd10;
+    unsigned int spm_dvfs_cmd11;
+    unsigned int spm_dvfs_cmd12;
+    unsigned int spm_dvfs_cmd13;
+    unsigned int spm_dvfs_cmd14;
+    unsigned int spm_dvfs_cmd15;
+    unsigned int reserved32[12];
+    unsigned int wdt_latch_spare0_fix;
+    unsigned int wdt_latch_spare1_fix;
+    unsigned int wdt_latch_spare2_fix;
+    unsigned int wdt_latch_spare3_fix;
+    unsigned int spare_ack_in_fix;
+    unsigned int dcha_latch_rsv0_fix;
+    unsigned int dchb_latch_rsv0_fix;
+    unsigned int reserved33[25];
+    unsigned int pcm_wdt_latch_0;
+    unsigned int pcm_wdt_latch_1;
+    unsigned int pcm_wdt_latch_2;
+    unsigned int pcm_wdt_latch_3;
+    unsigned int pcm_wdt_latch_4;
+    unsigned int pcm_wdt_latch_5;
+    unsigned int pcm_wdt_latch_6;
+    unsigned int pcm_wdt_latch_7;
+    unsigned int pcm_wdt_latch_8;
+    unsigned int pcm_wdt_latch_9;
+    unsigned int wdt_latch_spare0;
+    unsigned int wdt_latch_spare1;
+    unsigned int wdt_latch_spare2;
+    unsigned int wdt_latch_spare3;
+    unsigned int pcm_wdt_latch_10;
+    unsigned int pcm_wdt_latch_11;
+    unsigned int dcha_gating_latch_0;
+    unsigned int dcha_gating_latch_1;
+    unsigned int dcha_gating_latch_2;
+    unsigned int dcha_gating_latch_3;
+    unsigned int dcha_gating_latch_4;
+    unsigned int dcha_gating_latch_5;
+    unsigned int dcha_gating_latch_6;
+    unsigned int dcha_gating_latch_7;
+    unsigned int dchb_gating_latch_0;
+    unsigned int dchb_gating_latch_1;
+    unsigned int dchb_gating_latch_2;
+    unsigned int dchb_gating_latch_3;
+    unsigned int dchb_gating_latch_4;
+    unsigned int dchb_gating_latch_5;
+    unsigned int dchb_gating_latch_6;
+    unsigned int dchb_gating_latch_7;
+    unsigned int dcha_latch_rsv0;
+    unsigned int dchb_latch_rsv0;
+    unsigned int pcm_wdt_latch_12;
+    unsigned int pcm_wdt_latch_13;
+    unsigned int reserved34[12];
+    unsigned int spm_pc_trace_con;
+    unsigned int spm_pc_trace_g0;
+    unsigned int spm_pc_trace_g1;
+    unsigned int spm_pc_trace_g2;
+    unsigned int spm_pc_trace_g3;
+    unsigned int spm_pc_trace_g4;
+    unsigned int spm_pc_trace_g5;
+    unsigned int spm_pc_trace_g6;
+    unsigned int spm_pc_trace_g7;
+    unsigned int reserved35[7];
+    unsigned int spm_ack_chk_con;
+    unsigned int spm_ack_chk_pc;
+    unsigned int spm_ack_chk_sel;
+    unsigned int spm_ack_chk_timer;
+    unsigned int spm_ack_chk_sta;
+    unsigned int spm_ack_chk_latch;
+    unsigned int reserved36[2];
+    unsigned int spm_ack_chk_con2;
+    unsigned int spm_ack_chk_pc2;
+    unsigned int spm_ack_chk_sel2;
+    unsigned int spm_ack_chk_timer2;
+    unsigned int spm_ack_chk_sta2;
+    unsigned int spm_ack_chk_latch2;
+    unsigned int reserved37[2];
+    unsigned int spm_ack_chk_con3;
+    unsigned int spm_ack_chk_pc3;
+    unsigned int spm_ack_chk_sel3;
+    unsigned int spm_ack_chk_timer3;
+    unsigned int spm_ack_chk_sta3;
+    unsigned int spm_ack_chk_latch3;
+    unsigned int reserved38[2];
+    unsigned int spm_ack_chk_con4;
+    unsigned int spm_ack_chk_pc4;
+    unsigned int spm_ack_chk_sel4;
+    unsigned int spm_ack_chk_timer4;
+    unsigned int spm_ack_chk_sta4;
+    unsigned int spm_ack_chk_latch4;
+};
+
+static struct mtk_spm_regs *const mtk_spm = (void *)SPM_BASE;
+
+#endif  /* SOC_MEDIATEK_MT8183_SPM_H */
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/sspm.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/sspm.h
new file mode 100644
index 0000000..f733310
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/sspm.h
@@ -0,0 +1,80 @@
+/*
+ * 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 <debug.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mt_typedefs.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define SSPM_MEM_SIZE   0x00100000  // 768K -->1M
+#define SSPM_MEM_ALIGN  0x00010000  // 64K (minimal size for EMI MPU)
+#define SSPM_PART_SZ    0x000A0000  // 640K
+#define SSPM_RD_SZ      0x0000C000  // 48K
+
+#define PT_ID_SSPM_DM   0
+#define PT_ID_SSPM_PM   1
+#define PT_ID_SSPM_XFILE 99
+
+#if WITH_KERNEL_VM
+#define SSPM_VM_OFFSET 0xfffffff000000000
+#else
+#define SSPM_VM_OFFSET 0
+#endif
+#define SSPM_SW_RSTN        SSPM_VM_OFFSET + 0x10440000
+#define SSPM_CFGREG_GPR0    SSPM_SW_RSTN + 0x20
+#define SSPM_CFGREG_GPR1    SSPM_SW_RSTN + 0x24
+#define SSPM_CFGREG_GPR6    SSPM_SW_RSTN + 0x110
+#define CFG_SSPMP_MEMADDR   SSPM_VM_OFFSET + 0x10400000
+#define SSPM_UART_SET0      SSPM_VM_OFFSET + 0x102d0370
+#define SSPM_UART_SET1      SSPM_VM_OFFSET + 0x102d0380
+#define SSPM_JTAG_SET       SSPM_VM_OFFSET + 0x102d0440
+#define SSPM_LOAD_ADDR      SSPM_VM_OFFSET + 0x44000000
+#define SSPM_REAL_ADDR      SSPM_LOAD_ADDR + 0x200
+
+#define PT_MAGIC            0x58901690
+#define SSPM_DBG_MODE 0
+
+struct sspm_info_t {
+    unsigned int sspm_dm_ofs;   /*  for sspm data memory*/
+    unsigned int sspm_dm_sz;
+    unsigned int rd_ofs;        /* for sspm ramdump*/
+    unsigned int rd_sz;
+    uintptr_t xfile_addr;    /* for LKdump*/
+    unsigned int xfile_sz;
+};
+
+typedef enum {
+    CHIP_VER_E1 = 0x0,
+    CHIP_VER_E2 = 0x1,
+} chip_ver_t;
+
+typedef struct {
+    unsigned int magic;     /* magic */
+    unsigned int hdr_size;  /* data size */
+    unsigned int img_size;  /* img size */
+    unsigned int align;     /* align */
+    unsigned int id;        /* image id */
+    unsigned int addr;      /* memory addr */
+} ptimg_hdr_t;
\ No newline at end of file
diff --git a/src/bsp/lk/platform/mediatek/mt6771/include/platform/udc-common.h b/src/bsp/lk/platform/mediatek/mt6771/include/platform/udc-common.h
new file mode 100644
index 0000000..1347794
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/include/platform/udc-common.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#pragma once
+
+#define UDC_TYPE_BULK_IN    1
+#define UDC_TYPE_BULK_OUT   2
diff --git a/src/bsp/lk/platform/mediatek/mt6771/plat_dbg_info.c b/src/bsp/lk/platform/mediatek/mt6771/plat_dbg_info.c
new file mode 100644
index 0000000..b767bb0
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/plat_dbg_info.c
@@ -0,0 +1,132 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2016. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#include <platform/plat_dbg_info.h>
+
+static top_dbg_info *dbg_info;
+static int init = 0;
+
+static void init_dbg_info(void)
+{
+	unsigned int i;
+	unsigned int offset, size;
+
+	dbg_info = (top_dbg_info *) PLAT_DBG_INFO_BASE;
+
+	for (i = 0; i < INFO_TYPE_MAX; i++)
+		*((unsigned int *)dbg_info + i) = 0;
+
+#ifdef KEY_LAST_DRAMC
+	INIT_DBG_HEAD(LAST_DRAMC)
+#endif
+#ifdef KEY_LAST_EMI
+	INIT_DBG_HEAD(LAST_EMI)
+#endif
+
+	offset = 4 * INFO_TYPE_MAX;
+	for (i = 0; i < TYPE_END; i++) {
+		size = dbg_info->head[i];
+		if ((size >> 16) == 0)
+			continue;
+		dbg_info->head[i] = (dbg_info->head[i] & 0xffff0000) | offset;
+		offset += (size & 0xffff);
+	}
+
+	dbg_info->tail = INFO_TAIL_MAGIC | sizeof(top_dbg_info);
+
+	init = 1;
+}
+
+unsigned int get_dbg_info_key(DBG_INFO_TYPE info_type)
+{
+	if (init == 0)
+		init_dbg_info();
+
+	return (*((unsigned int *)dbg_info + info_type) >> 16);
+}
+
+u64 get_dbg_info_base(unsigned int key)
+{
+	unsigned int i;
+	unsigned int offset;
+
+	if (key == 0)
+		return 0;
+
+	if (init == 0)
+		init_dbg_info();
+
+	for (i = 0; i < TYPE_END; i++) {
+		offset = *((unsigned int *)dbg_info + i);
+		if ((offset >> 16) == key)
+			return ((u64)dbg_info + (offset & 0xffff));
+	}
+
+	return 0;
+}
+
+unsigned int get_dbg_info_size(unsigned int key)
+{
+	unsigned int offset_start, offset_end;
+	unsigned int i;
+
+	if (key == 0)
+		return 0;
+
+	if (init == 0)
+		init_dbg_info();
+
+	for (i = 0; i < TYPE_END; i++) {
+		offset_start = *((unsigned int *)dbg_info + i);
+		if ((offset_start >> 16) == key)
+			break;
+	}
+	offset_start &= 0xffff;
+
+	offset_end = dbg_info->tail - 4;
+	for (i++; i < TYPE_END; i++) {
+		if ((*((unsigned int *)dbg_info + i) >> 16) != 0) {
+			offset_end = *((unsigned int *)dbg_info + i);
+			break;
+		}
+	}
+
+	offset_end &= 0xffff;
+
+	return (offset_end - offset_start);
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt6771/platform.c b/src/bsp/lk/platform/mediatek/mt6771/platform.c
new file mode 100644
index 0000000..9c5c6b6
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/platform.c
@@ -0,0 +1,341 @@
+/*
+ * 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 <platform.h>
+#include <arch/arm64/mmu.h>
+#include <arch/ops.h>
+#include <assert.h>
+#include <boot_args.h>
+#include <debug.h>
+#include <dev/interrupt/arm_gic.h>
+#include <dev/timer/arm_generic.h>
+#include <dev/uart.h>
+#include <err.h>
+#include <kernel/vm.h>
+#include <platform/emi.h>
+#include <platform/mt6358.h>
+#include <platform/mt6771.h>
+#include <platform/mtk_wdt.h>
+#include <platform/memory.h>
+#include <platform/pll_common.h>
+#include <platform/i2c.h>
+#include <lib/mempool.h>
+#include <platform/mmc_core.h>
+#include <libfdt.h>
+
+u32 g_ddr_reserve_enable = 0;
+u32 g_ddr_reserve_success = 0;
+u32 g_ddr_reserve_ready = 0;
+u32 g_ddr_reserve_ta_err = 0;
+
+boot_reason_t g_boot_reason;
+
+#if WITH_KERNEL_VM
+#define L2C_MAPPING_IDX 0
+#define PERIPHERAL_MAPPING_IDX 1
+#define SRAM_MAPPING_IDX 2
+#define DRAM_MAPPING_IDX 3
+
+/* initial memory mappings. parsed by start.S */
+struct mmu_initial_mapping mmu_initial_mappings[] = {
+    {
+        .phys = MEMORY_BASE_PHYS,
+        .virt = MEMORY_BASE_VIRT,
+        .size = MEMORY_APERTURE_SIZE,
+        .flags = 0,
+        .name = "l2c"
+    },
+    {
+        .phys = GIC_PERIPHERAL_BASE_PHYS,
+        .virt = GIC_PERIPHERAL_BASE_VIRT,
+        .size = GIC_PERIPHERAL_BASE_SIZE,
+        .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
+        .name = "peripherals"
+    },
+    /* reserved for internal sram */
+    { 0 },
+
+    /* reserved for dram */
+    { 0 },
+
+    /* null entry to terminate the list */
+    { 0 }
+};
+
+static pmm_arena_t arena = {
+    .name = "sram",
+    .base = SRAM_BASE_PHYS,
+    .size = SRAM_BASE_SIZE,
+    .flags = PMM_ARENA_FLAG_KMAP,
+    .priority = 1,
+};
+
+
+/* only disable el1 dcache */
+void dcache_disable(void)
+{
+    uint32_t sctlr;
+
+    asm volatile("mrs %0, sctlr_el1" : "=r" (sctlr) : : "cc");
+
+    /* if cache isn't enabled no need to disable */
+    if (!(sctlr & (1 << 2)))
+        return;
+
+    asm volatile("msr sctlr_el1, %0" : : "r" (sctlr & ~(1 << 2)) : "cc");
+}
+
+/* only enable el1 dcache */
+static void dcache_enable(void)
+{
+    uint32_t sctlr;
+
+    asm volatile("mrs %0, sctlr_el1" : "=r" (sctlr) : : "cc");
+    asm volatile("msr sctlr_el1, %0" : : "r" (sctlr | (1 << 2)) : "cc");
+    asm volatile("isb");
+}
+
+void *dram_map(paddr_t pa)
+{
+    paddr_t dram_phy = DRAM_BASE_PHY;
+
+    u64 dram_sz = get_dram_size();
+
+    if (pa >= dram_phy && pa <= (dram_phy + dram_sz - 1)) {
+        return (void *)(DRAM_BASE_VIRT + (pa - dram_phy));
+    }
+
+    return NULL;
+}
+#endif /* WITH_KERNEL_VM */
+static void setup_plat_mem(void)
+{
+#if WITH_KERNEL_VM
+
+    arch_mmu_map(SRAM_BASE_VIRT, SRAM_BASE_PHYS,
+                 SRAM_BASE_SIZE >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+
+    /* add internal sram to mmu_initial_mappings struct for pa to va lookup */
+    mmu_initial_mappings[SRAM_MAPPING_IDX].phys = SRAM_BASE_PHYS;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].virt = SRAM_BASE_VIRT;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].size = SRAM_BASE_SIZE;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].flags = 0;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].name = "isram";
+
+    /* map dram may need new page tables, add internal sram to arena memory */
+    pmm_add_arena(&arena);
+
+	/* map register address*/
+	arch_mmu_map(REGISTER_BASE_VIRT, REGISTER_BASE_PHYS,
+					 REGISTER_BASE_SIZE >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+
+#endif /* WITH_KERNEL_VM */
+}
+
+static void dram_mmu_map_default(bool flag)
+{
+#if WITH_KERNEL_VM
+    size_t dram_sz, mem_sz;
+    size_t unmap_dram_start_pa, unmap_dram_start_va;
+
+    unmap_dram_start_pa = DRAM_BASE_PHY;
+    unmap_dram_start_va = DRAM_BASE_VIRT;
+
+    if (flag == true)//map default dram size
+    {
+    	dram_sz = 0x80000000;
+    }
+    else//map real dram size
+    {
+    	dram_sz = get_dram_size();
+    }
+
+    mem_sz = UNCACHED_MEMPOOL_ADDR - unmap_dram_start_va;
+
+    /* unmap_dram_start_pa ~  (unmap_dram_start_pa + mem_sz) = cached memory */
+    arch_mmu_map(unmap_dram_start_va, unmap_dram_start_pa,
+                 mem_sz >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_UNCACHED);
+
+    /*
+     * (unmap_dram_start_pa + mem_sz) ~  (unmap_dram_start_pa + mem_sz + UNCACHED_MEMPOOL_SIZE)=
+     * uncached memory
+     */
+    arch_mmu_map(UNCACHED_MEMPOOL_ADDR, unmap_dram_start_pa + mem_sz,
+                 UNCACHED_MEMPOOL_SIZE >> PAGE_SIZE_SHIFT,
+                 ARCH_MMU_FLAG_UNCACHED);
+
+    /*
+     * (unmap_dram_start_pa + mem_sz + UNCACHED_MEMPOOL_SIZE) ~  (dram_sz - mem_sz) =
+     * cached memory
+     */
+    mem_sz += UNCACHED_MEMPOOL_SIZE;
+    arch_mmu_map(UNCACHED_MEMPOOL_ADDR + UNCACHED_MEMPOOL_SIZE,
+                 unmap_dram_start_pa + mem_sz,
+                 (dram_sz - mem_sz) >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+
+    /* add dram to mmu_initial_mappings for pa to va lookup */
+    mmu_initial_mappings[DRAM_MAPPING_IDX].phys = DRAM_BASE_PHY;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].virt = DRAM_BASE_VIRT;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].size = dram_sz;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].flags = 0;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].name = "dram";
+
+#endif /* WITH_KERNEL_VM */
+}
+
+
+extern void rtc_boot(void);
+BOOT_ARGUMENT g_boot_arg;
+
+void platform_early_init(void)
+{
+    uart_init_early();
+
+#if WITH_KERNEL_VM
+	_dprintf("WITH_KERNEL_VM = 1, MMU enabled! \n");
+#endif
+
+    /* initialize the interrupt controller */
+    arm_gic_init();
+
+    arm_generic_timer_init(ARM_GENERIC_TIMER_PHYSICAL_INT, 13000000);
+
+    mt_pll_init();
+    mt6358_init();
+    rtc_boot();
+
+    /* check DDR-reserve mode */
+    check_ddr_reserve_status();
+
+    mtk_wdt_init();
+
+    setup_plat_mem();
+#if 0
+    /* map default dram size since dram is not ready */
+    dram_mmu_map_default(true);
+
+    mt_mem_init();
+    u64 dram_sz = get_dram_size();
+    _dprintf("after mt_mem_init,dram_size:%lld\n", dram_sz);
+
+    g_boot_arg.emi_info.dram_type = mt_get_dram_type();
+    g_boot_arg.emi_info.ch_num = get_dram_channel_nr();
+    g_boot_arg.emi_info.rk_num = get_dram_rank_nr();
+    get_dram_rank_size(g_boot_arg.emi_info.rank_size);
+    _dprintf("dram_type:%d,ch_num:%d,rk_num:%d,rank_size0:0x%x,rank_size1:0x%x\n", g_boot_arg.emi_info.dram_type,
+    	g_boot_arg.emi_info.ch_num, g_boot_arg.emi_info.rk_num,
+    	g_boot_arg.emi_info.rank_size[0], g_boot_arg.emi_info.rank_size[1]);
+
+    /* map real dram size since dram is ready */
+    dram_mmu_map_default(false);
+#endif
+    mtk_i2c_init();
+}
+
+
+void platform_init(void)
+{
+    int ret;
+	struct mmc_card *card;
+	bool retry_opcond;
+
+	/* emmc init */
+	card = emmc_init_stage1(&retry_opcond);
+    if (card) {
+        emmc_init_stage2(card, retry_opcond);
+    }
+
+    /* map default dram size since dram is not ready */
+    dram_mmu_map_default(true);
+
+    mt_mem_init();
+    u64 dram_sz = get_dram_size();
+    _dprintf("after mt_mem_init,dram_size:%lld\n", dram_sz);
+    
+    g_boot_arg.emi_info.dram_type = mt_get_dram_type();
+    g_boot_arg.emi_info.ch_num = get_dram_channel_nr();
+    g_boot_arg.emi_info.rk_num = get_dram_rank_nr();
+    get_dram_rank_size(g_boot_arg.emi_info.rank_size);
+    _dprintf("dram_type:%d,ch_num:%d,rk_num:%d,rank_size0:0x%x,rank_size1:0x%x\n", g_boot_arg.emi_info.dram_type,
+    	g_boot_arg.emi_info.ch_num, g_boot_arg.emi_info.rk_num, 
+    	g_boot_arg.emi_info.rank_size[0], g_boot_arg.emi_info.rank_size[1]);
+
+    /* map real dram size since dram is ready */
+    dram_mmu_map_default(false);
+
+    ret = mempool_init((void *)CACHED_MEMPOOL_ADDR, CACHED_MEMPOOL_SIZE,
+                       MEMPOOL_CACHE);
+    if (ret != NO_ERROR)
+        platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_PANIC);
+
+    ret = mempool_init((void *)(UNCACHED_MEMPOOL_ADDR), UNCACHED_MEMPOOL_SIZE,
+                   MEMPOOL_UNCACHE);
+
+}
+
+extern __WEAK bool plat_fixup_hook(void* bootimg_dtb_load, ...);
+bool plat_fixup_hook(void* bootimg_dtb_load, ...)
+{
+    int ret;
+
+    ret = fdt_open_into(bootimg_dtb_load, bootimg_dtb_load, MAX_DTB_SIZE);
+    if (ret) {
+        dprintf(CRITICAL, "open fdt failed\n");
+        return ret;
+    }
+    ret = fdt_check_header(bootimg_dtb_load);
+    if (ret) {
+        dprintf(CRITICAL, "check fdt failed\n");
+        return ret;
+    }
+
+    /* resize dram*/
+    ret = set_fdt_dram_size(bootimg_dtb_load);
+    if (ret < 0) {
+        dprintf(CRITICAL, "failed to set fdt emi info\n");
+    }
+
+    ret = fdt_pack(bootimg_dtb_load);
+    if (ret) {
+        dprintf(CRITICAL, "ft pack failed\n");
+        return ret;
+    }
+
+    return true;
+}
+
+typedef void (*jump_func_type)(uint64_t bl31_addr, uint64_t bl33_addr, uint64_t arg1) __attribute__ ((__noreturn__));
+
+void el3_mtk_sip(uint32_t smc_fid, uint64_t bl31_addr, uint64_t bl33_addr)
+{
+    jump_func_type jump_func;
+    jump_func = (jump_func_type)bl31_addr;
+    (*jump_func)(bl31_addr, bl33_addr, 0);
+}
+
+/* Initialization context in start.S before switching from EL3 to EL1.
+ * Note data/bss segment NOT initialized, i.e. No assumption on global variable initialization.*/
+void platform_el3_init(void)
+{
+    gic_setup();
+}
diff --git a/src/bsp/lk/platform/mediatek/mt6771/rules.mk b/src/bsp/lk/platform/mediatek/mt6771/rules.mk
new file mode 100644
index 0000000..22403e6
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt6771/rules.mk
@@ -0,0 +1,97 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+ARCH ?= arm64
+ARM_CPU ?= cortex-a53
+WITH_SMP ?= 0
+WITH_KERNEL_VM ?= 1
+WITH_MTK_PMIC_WRAP_AND_PMIC ?= 0
+AB_UPGRADE_APP := 1
+
+LK_HEAP_IMPLEMENTATION ?= miniheap
+
+GLOBAL_INCLUDES += -I$(LK_TOP_DIR)/include \
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/platform.c \
+    $(LOCAL_DIR)/plat_dbg_info.c \
+    $(LOCAL_DIR)/../common/debug.c \
+    $(LOCAL_DIR)/../common/interrupts.c \
+
+GLOBAL_INCLUDES += \
+    $(LOCAL_DIR)/../common/include \
+
+ifeq ($(WITH_KERNEL_VM),1)
+KERNEL_ASPACE_BASE ?= 0xfffffff000000000
+KERNEL_ASPACE_SIZE ?= 0x0000000180000000
+KERNEL_BASE ?= 0xfffffff000200000 # KERNEL_ASPACE_BASE + MEMBASE
+MMU_IDENT_SIZE_SHIFT ?= 32
+endif
+
+MEMBASE ?= 0x200000
+KERNEL_LOAD_OFFSET ?= 0x1000
+MEMSIZE ?= 0x00080000   # 512K
+MACH_TYPE := 6771
+
+ifeq ($(WITH_KERNEL_VM),1)
+GLOBAL_DEFINES += MMU_IDENT_SIZE_SHIFT=$(MMU_IDENT_SIZE_SHIFT)
+else
+GLOBAL_DEFINES += NOVM_MAX_ARENAS=2
+endif
+
+# LK build as BL2 or BL33 setting
+LK_AS_BL33 ?= 0
+MODULE_DEPS += \
+    dev/interrupt/arm_gic_v3 \
+    dev/timer/arm_generic \
+    lib/bio \
+    lib/cksum \
+    lib/partition \
+    lib/fdt \
+    lib/mempool \
+
+GLOBAL_DEFINES += \
+    MEMBASE=$(MEMBASE) \
+    MEMSIZE=$(MEMSIZE) \
+    RAMBASE=$(RAMBASE) \
+    MACH_TYPE=$(MACH_TYPE) \
+    PLATFORM_SUPPORTS_PANIC_SHELL=1 \
+    NOVM_MAX_ARENAS=2 \
+    WITH_NO_FP=1 \
+    AB_UPGRADE_APP=$(AB_UPGRADE_APP) \
+
+GLOBAL_CFLAGS += -fno-stack-protector -Wno-return-type\
+
+LINKER_SCRIPT += \
+    $(BUILDDIR)/system-onesegment.ld
+
+include make/module.mk $(LOCAL_DIR)/drivers/rules.mk
+
+WITH_DISPLAY ?= 0
+
+ifeq ($(WITH_DISPLAY),1)
+GLOBAL_DEFINES += WITH_DISPLAY=$(WITH_DISPLAY)
+endif
+
+HDMI_MAIN_PATH ?= 0
+
+ifeq ($(WITH_DISPLAY),1)
+GLOBAL_DEFINES += HDMI_MAIN_PATH=$(HDMI_MAIN_PATH)
+endif
+
+ifeq ($(WITH_PANEL_TPV_PH060PB16A),1)
+GLOBAL_DEFINES += WITH_PANEL_TPV_PH060PB16A=$(WITH_PANEL_TPV_PH060PB16A)
+endif
+
+TOOLCHAIN_PREFIX := $(ARCH_$(ARCH)_TOOLCHAIN_PREFIX)
+$(info TOOLCHAIN_PREFIX = $(TOOLCHAIN_PREFIX))
+ifneq ($(call TOBOOL,$(CLANGBUILD)),true)
+GCC_VER_GTE94 := $(shell echo `$(TOOLCHAIN_PREFIX)gcc -dumpfullversion | cut -f1-2 -d.` \>= 9.4 | bc )
+$(info GCC_VER = $(shell echo `$(TOOLCHAIN_PREFIX)gcc -dumpfullversion | cut -f1-2 -d.`))
+ifeq ($(GCC_VER_GTE94),1)
+ARCH_COMPILEFLAGS += -mno-outline-atomics
+endif
+endif
+$(info ARCH_COMPILEFLAGS = $(ARCH_COMPILEFLAGS))
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/bl2_bl33_options.mk b/src/bsp/lk/platform/mediatek/mt8133/bl2_bl33_options.mk
new file mode 100644
index 0000000..e009cab
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/bl2_bl33_options.mk
@@ -0,0 +1,75 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+ifeq ($(LK_AS_BL33),1)
+# LK build as BL33
+
+# memory setting
+MEMBASE ?= 0x43200000
+KERNEL_LOAD_OFFSET ?= 0x0
+MEMSIZE ?= 0x100000 # 1MB
+
+KERNEL_BASE ?= 0xfffffff043200000   # KERNEL_ASPACE_BASE + MEMBASE
+
+# dram size setting
+BL33_DRAM_SZ_MB ?= 512
+
+# image load options
+ENABLE_TZ_LOAD := 0                 # bl33 doesnt' load tz
+ENABLE_BL33_LOAD := 0               # bl33 doesn't load itself
+ENABLE_KERNEL_LOAD := 1             # loads kernel and dtbo
+
+# bl33 boot options
+BL33_BOOT_NEXT_64BITS ?= 0          # boot stage after bl33 is 32 bits
+
+# fastboot mode option
+OPTION_CLEAR_FASTBOOT_FLAG ?= 1
+
+# recovery mode option
+OPTION_CLEAR_RECOVERY_FLAG ?= 1
+
+MODULE_SRCS += $(LOCAL_DIR)/platform_bl33.c
+
+GLOBAL_DEFINES += \
+    BL33_DRAM_SZ_MB=$(BL33_DRAM_SZ_MB) \
+    BL33_BOOT_NEXT_64BITS=$(BL33_BOOT_NEXT_64BITS)
+
+else
+
+# LK build as BL2
+
+# memory setting
+MEMBASE ?= 0x200000
+KERNEL_LOAD_OFFSET ?= 0x1000
+MEMSIZE ?= 0x40000 # 256KB
+
+KERNEL_BASE ?= 0xfffffff000200000   # KERNEL_ASPACE_BASE + MEMBASE
+
+# image load options
+ENABLE_TZ_LOAD := 1                 # loads tz
+ENABLE_BL33_LOAD := 1
+ENABLE_BUILTIN_BL33 ?= 1            # default use builtin 'do-nothing-but-jump' bl33
+ifeq ($(ENABLE_BUILTIN_BL33),1)
+ENABLE_KERNEL_LOAD := 1             # if builtin bl33, bl2 also loads kernel (& dtbo)
+OPTION_CLEAR_FASTBOOT_FLAG ?= 1
+OPTION_CLEAR_RECOVERY_FLAG ?= 1
+else
+ENABLE_KERNEL_LOAD := 0
+OPTION_CLEAR_FASTBOOT_FLAG ?= 0
+OPTION_CLEAR_RECOVERY_FLAG ?= 0
+endif
+
+MODULE_SRCS += $(LOCAL_DIR)/platform_bl2.c
+
+GLOBAL_DEFINES += \
+    ENABLE_BUILTIN_BL33=$(ENABLE_BUILTIN_BL33)
+
+endif
+
+GLOBAL_DEFINES += \
+    MEMBASE=$(MEMBASE) \
+    MEMSIZE=$(MEMSIZE) \
+    ENABLE_TZ_LOAD=$(ENABLE_TZ_LOAD) \
+    ENABLE_BL33_LOAD=$(ENABLE_BL33_LOAD) \
+    ENABLE_KERNEL_LOAD=$(ENABLE_KERNEL_LOAD) \
+    OPTION_CLEAR_FASTBOOT_FLAG=$(OPTION_CLEAR_FASTBOOT_FLAG) \
+    OPTION_CLEAR_RECOVERY_FLAG=$(OPTION_CLEAR_RECOVERY_FLAG)
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/auxadc/mtk_auxadc.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/auxadc/mtk_auxadc.c
new file mode 100644
index 0000000..f28da93
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/auxadc/mtk_auxadc.c
@@ -0,0 +1,161 @@
+/*
+ * 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.
+*/
+#include <debug.h>
+#include <reg.h>
+
+#include "platform/mtk_auxadc_hw.h"
+#include "platform/mtk_auxadc_sw.h"
+
+#define udelay(x)       spin(x)
+#define mdelay(x)       udelay((x) * 1000)
+
+static void mt_auxadc_power_on(void)
+{
+    writel(readl(AUXADC_MISC) | (1 << 14), AUXADC_MISC);
+}
+
+static void mt_auxadc_power_off(void)
+{
+    writel(readl(AUXADC_MISC) & (~(1 << 14)), AUXADC_MISC);
+}
+
+/*
+ * step1 check con2 if auxadc is busy
+ * step2 clear bit
+ * step3  read channle and make sure old ready bit ==0
+ * step4 set bit  to trigger sample
+ * step5  read channle and make sure  ready bit ==1
+ * step6 read data
+ */
+//// Common API
+
+int IMM_GetOneChannelValue(int dwChannel, int data[4], int *rawdata)
+{
+    unsigned int channel[16] = {0};
+    int idle_count = 0;
+    int data_ready_count = 0;
+
+    if (readl(AUXADC_CLK_STA) & AUX_SW_CG_ADC) {
+        return -1;
+    }
+
+    mt_auxadc_power_on();
+
+    //step1 check con2 if auxadc is busy
+    while (readl(AUXADC_CON2) & 0x01) {
+        udelay(10000);
+        idle_count++;
+        if (idle_count > 30) {
+            dprintf(CRITICAL, "adc_lk: wait for auxadc idle time out\n");
+            return -2;
+        }
+    }
+
+    // step2 clear bit
+    writel(readl(AUXADC_CON1) & (~(1 << dwChannel)), AUXADC_CON1);
+
+    //step3  read channle and make sure old ready bit ==0
+    while (readl(AUXADC_DAT0 + dwChannel * 0x04) & (1<<12)) {
+        udelay(10000);
+        data_ready_count++;
+        if (data_ready_count > 30) {
+            dprintf(CRITICAL, "adc_lk: wait for ch[%d] ready bit clear timeout\n",
+                   dwChannel);
+            return -3;
+        }
+    }
+
+    //step4 set bit  to trigger sample
+    writel(readl(AUXADC_CON1) | (1 << dwChannel), AUXADC_CON1);
+    //step5  read channle and make sure  ready bit ==1
+    udelay(25000);//we must dealay here for hw sample channel data
+    while (0 == (readl(AUXADC_DAT0 + dwChannel * 0x04) & (1<<12))) {
+        udelay(10000);
+        data_ready_count++;
+        if (data_ready_count > 30) {
+            dprintf(CRITICAL, "adc_lk: wait for ch[%d] data ready timeout\n",
+                   dwChannel);
+            return -4;
+        }
+    }
+
+    //step6 read data
+    channel[dwChannel] = readl(AUXADC_DAT0 + dwChannel * 0x04) & 0x0FFF;
+    if (rawdata) {
+        *rawdata = channel[dwChannel];
+    }
+
+    data[0] = (channel[dwChannel] * 150 / 4096 / 100);
+    data[1] = ((channel[dwChannel] * 150 / 4096) % 100);
+
+    mt_auxadc_power_off();
+
+    return 0;
+}
+
+// this function voltage Unit is mv
+int IMM_GetOneChannelValue_Cali(int Channel, int *voltage)
+{
+    int ret = 0, data[4], rawvalue;
+
+    ret = IMM_GetOneChannelValue(Channel, data, &rawvalue);
+    if (ret) {
+        ret = IMM_GetOneChannelValue(Channel, data, &rawvalue);
+        if (ret) {
+            dprintf(CRITICAL, "adc_lk: get raw value error %d\n",ret);
+            return -1;
+        }
+    }
+
+    *voltage = rawvalue*1500 / 4096;
+
+    return 0;
+}
+
+int auxadc_test(void)
+{
+    int i = 0, data[4] = {0, 0, 0, 0};
+    int res = 0;
+    int rawdata = 0;
+    int Voltiage_cali = 0;
+
+    for (i = 0; i < 16; i++) {
+        res = IMM_GetOneChannelValue(i,data,&rawdata);
+        if (res < 0) {
+            dprintf(CRITICAL, "adc_lk: get data error\n");
+            break;
+        } else {
+            dprintf(SPEW, "adc_lk: channel[%d]raw =%d\n", i, rawdata);
+        }
+        res= IMM_GetOneChannelValue_Cali(i, &Voltiage_cali);
+        if (res < 0) {
+            dprintf(CRITICAL, "adc_lk: get cali voltage error\n");
+            break;
+        } else {
+            dprintf(SPEW, "adc_lk: channel[%d] cali_voltage =%d\n",
+                   i, Voltiage_cali);
+        }
+    }
+    return 0;
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/i2c/mtk_i2c.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/i2c/mtk_i2c.c
new file mode 100644
index 0000000..b7f521b
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/i2c/mtk_i2c.c
@@ -0,0 +1,1285 @@
+/*
+ * 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.
+*/
+
+/**
+ * @file mtk_i2c.c
+ * This i2c driver is used to control MediaTek I2C controller.\n
+ * It provides the interfaces which will be used in LK.
+ */
+
+/**
+ * @defgroup IP_group_i2c I2C
+ *
+ *   @{
+ *       @defgroup IP_group_i2c_external EXTERNAL
+ *         The external API document for I2C. \n
+ *
+ *         @{
+ *            @defgroup IP_group_i2c_external_function 1.function
+ *              External function in i2c driver.
+ *            @defgroup IP_group_i2c_external_struct 2.structure
+ *              none.
+ *            @defgroup IP_group_i2c_external_typedef 3.typedef
+ *              none.
+ *            @defgroup IP_group_i2c_external_enum 4.enumeration
+ *              none.
+ *            @defgroup IP_group_i2c_external_def 5.define
+ *              none.
+ *         @}
+ *
+ *       @defgroup IP_group_i2c_internal INTERNAL
+ *         The internal API document for I2C. \n
+ *
+ *         @{
+ *            @defgroup IP_group_i2c_internal_function 1.function
+ *              Internal function in i2c driver.
+ *            @defgroup IP_group_i2c_internal_struct 2.structure
+ *              Internal structure in i2c driver.
+ *            @defgroup IP_group_i2c_internal_typedef 3.typedef
+ *              none.
+ *            @defgroup IP_group_i2c_internal_enum 4.enumeration
+ *              Internal enumeration in i2c driver.
+ *            @defgroup IP_group_i2c_internal_def 5.define
+ *              Internal define in i2c driver.
+ *         @}
+ *   @}
+ */
+
+#include "platform/mtk_i2c.h"
+
+struct mtk_i2c *i2c_global;
+
+/**
+ * @brief i2c source clock.
+ */
+static uint32_t g_i2c_source_clock = MTK_I2C_SOURCE_CLK;
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Write data to i2c controller register.
+ * @param[in]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains register base\n
+ *     address.
+ * @param[in]
+ *     offset: register relative base offset value.
+ * @param[in]
+ *     value: The value set to register.
+ * @return
+ *     none.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     none.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static void i2c_writel(struct mtk_i2c *i2c, uint32_t offset,
+		 uint32_t value)
+{
+	writel(value, (i2c->base + offset));
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Read data from i2c controller register.
+ * @param[in]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains register base\n
+ *     address.
+ * @param[in]
+ *     offset: register relative base offset value.
+ * @return
+ *     i2c controller register value.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     none.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static uint32_t i2c_readl(struct mtk_i2c *i2c, uint32_t offset)
+{
+	return readl(i2c->base + offset);
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Write data to DMA controller register.
+ * @param[in]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains DMA register\n
+ *     base address.
+ * @param[in]
+ *     offset: register relative base offset value.
+ * @param[in]
+ *     value: The value set to register.
+ * @return
+ *     none.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     none.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static inline void i2c_dma_writel(struct mtk_i2c *i2c, uint32_t offset,
+				  uint32_t value)
+{
+	writel(value, (i2c->dmabase + offset));
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Read data from DMA controller register.
+ * @param[in]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains DMA register\n
+ *     base address.
+ * @param[in]
+ *     offset: register relative base offset value.
+ * @return
+ *     DMA controller register value.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     none.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static inline uint32_t i2c_dma_readl(struct mtk_i2c *i2c, uint32_t offset)
+{
+	return readl(i2c->dmabase + offset);
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Set gpio to i2c mode.
+ * @param[in]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains bus number\n
+ *     information.
+ * @return
+ *     0, set gpio to i2c mode successfully.\n
+ *     -EINVAL_I2C, invalid i2c bus id.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     1. Invalid i2c bus number, return -EINVAL_I2C.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static int i2c_gpio_pinmux(struct mtk_i2c *i2c)
+{
+#ifndef CONFIG_MTK_FPGA
+	uint32_t gpio_reg;
+
+	switch (i2c->id) {
+	case 0:
+		///* I2C0_SDA */
+		//mtk_pmx_set_mode(57, 1);
+		///* I2C0_SCL */
+		//mtk_pmx_set_mode(58, 1);
+		gpio_reg = (readl(MTK_GPIO_I2C_BASE0) &
+			   (~(0x7 << MTK_GPIO_SDA0))) | (0x1 << MTK_GPIO_SDA0);
+		writel(gpio_reg, MTK_GPIO_I2C_BASE0);
+        	gpio_reg = (readl(MTK_GPIO_I2C_BASE0) &
+			   (~(0x7 << MTK_GPIO_SCL0))) | (0x1 << MTK_GPIO_SCL0);
+        	writel(gpio_reg, MTK_GPIO_I2C_BASE0);
+		break;
+	case 1:
+		///* I2C1_SDA */
+		//mtk_pmx_set_mode(59, 1);
+		///* I2C1_SCL */
+		//mtk_pmx_set_mode(60, 1);
+		gpio_reg = (readl(MTK_GPIO_I2C_BASE0) &
+			   (~(0x7 << MTK_GPIO_SDA1))) | (0x1 << MTK_GPIO_SDA1);
+		writel(gpio_reg, MTK_GPIO_I2C_BASE0);
+        	gpio_reg = (readl(MTK_GPIO_I2C_BASE1) &
+			   (~(0x7 << MTK_GPIO_SCL1))) | (0x1 << MTK_GPIO_SCL1);
+        	writel(gpio_reg, MTK_GPIO_I2C_BASE1);
+		break;
+	case 2:
+		///* I2C2_SDA */
+		//mtk_pmx_set_mode(61, 1);
+		///* I2C2_SCL */
+		//mtk_pmx_set_mode(62, 1);
+		gpio_reg = (readl(MTK_GPIO_I2C_BASE1) &
+			   (~(0x7 << MTK_GPIO_SDA2))) | (0x1 << MTK_GPIO_SDA2);
+		writel(gpio_reg, MTK_GPIO_I2C_BASE1);
+        	gpio_reg = (readl(MTK_GPIO_I2C_BASE1) &
+			   (~(0x7 << MTK_GPIO_SCL2))) | (0x1 << MTK_GPIO_SCL2);
+        	writel(gpio_reg, MTK_GPIO_I2C_BASE1);
+		break;
+	case 3:
+		///* I2C3_SDA */
+		//mtk_pmx_set_mode(63, 1);
+		///* I2C3_SCL */
+		//mtk_pmx_set_mode(64, 1);
+		gpio_reg = (readl(MTK_GPIO_I2C_BASE1) &
+			   (~(0x7 << MTK_GPIO_SDA3))) | (0x1 << MTK_GPIO_SDA3);
+		writel(gpio_reg, MTK_GPIO_I2C_BASE1);
+        	gpio_reg = (readl(MTK_GPIO_I2C_BASE1) &
+			   (~(0x7 << MTK_GPIO_SCL3))) | (0x1 << MTK_GPIO_SCL3);
+        	writel(gpio_reg, MTK_GPIO_I2C_BASE1);
+		break;
+	default:
+		I2CERR("invalid para: i2c->id=%d\n", i2c->id);
+		return -EINVAL_I2C;
+	}
+#endif
+	return 0;
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Enable i2c clock.
+ * @param[in]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains i2c bus number.
+ * @return
+ *     none.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     none.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static void i2c_clock_enable(struct mtk_i2c *i2c)
+{
+#ifndef CONFIG_MTK_FPGA
+
+	switch (i2c->id) {
+	case 0:
+		writel(MTK_I2C0_CLK_OFFSET, MTK_I2C_CLK_CLR);
+		break;
+	case 1:
+		writel(MTK_I2C1_CLK_OFFSET, MTK_I2C_CLK_CLR);
+		break;
+	case 2:
+		writel(MTK_I2C2_CLK_OFFSET, MTK_I2C_CLK_CLR);
+		break;
+	case 3:
+		writel(MTK_I2C3_CLK_OFFSET, MTK_I2C_CLK_CLR);
+		break;
+	default:
+		I2CERR("i2c clk enable, invalid para: i2c->id=%d\n",i2c->id);
+	}
+
+	writel(MTK_APDMA_CLK_OFFSET, MTK_APDMA_CLK_CLR);
+#endif
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Disable i2c clock.
+ * @param[in]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains i2c bus number.
+ * @return
+ *     none.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     none.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static void i2c_clock_disable(struct mtk_i2c *i2c)
+{
+#ifndef CONFIG_MTK_FPGA
+
+	switch (i2c->id) {
+	case 0:
+		writel(MTK_I2C0_CLK_OFFSET, MTK_I2C_CLK_SET);
+		break;
+	case 1:
+		writel(MTK_I2C1_CLK_OFFSET, MTK_I2C_CLK_SET);
+		break;
+	case 2:
+		writel(MTK_I2C2_CLK_OFFSET, MTK_I2C_CLK_SET);
+		break;
+	case 3:
+		writel(MTK_I2C3_CLK_OFFSET, MTK_I2C_CLK_SET);
+		break;
+	default:
+		I2CERR("i2c clk disable, invalid para: i2c->id=%d\n",i2c->id);
+	}
+
+    writel(MTK_APDMA_CLK_OFFSET, MTK_APDMA_CLK_SET);
+#endif
+}
+
+#ifdef CONFIG_MTK_IRQ
+static static void mtk_i2c_irq(void)
+{
+	uint16_t restart_flag = 0;
+	uint16_t intr_stat;
+
+	if (i2c_global->auto_restart)
+		restart_flag = I2C_RS_TRANSFER;
+
+	intr_stat = i2c_readl(i2c_global, OFFSET_INTR_STAT);
+	i2c_writel(i2c_global, OFFSET_INTR_STAT, intr_stat);
+
+	/*
+	 * when occurs ack error, i2c controller generate two interrupts
+	 * first is the ack error interrupt, then the complete interrupt
+	 * i2c->irq_stat need keep the two interrupt value.
+	 */
+	i2c_global->irq_stat |= intr_stat;
+
+	if (i2c_global->irq_stat & (I2C_TRANSAC_COMP | restart_flag))
+		i2c_global->msg_complete = true;
+}
+
+static void mtk_irq_init(struct mtk_i2c *i2c)
+{
+	register_int_handler(i2c->irqnr, mtk_i2c_irq, "i2c irq handler");
+}
+#endif
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Get i2c bus base address, DMA base address and source clock.
+ * @param[out]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains register base\n
+ *     address, DMA base address and bus number information.
+ * @return
+ *     0, set base address successfully.\n
+ *     -EINVAL_I2C, invalid i2c bus id.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     1. Invalid i2c bus number, return -EINVAL_I2C.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static int mtk_i2c_init_base(struct mtk_i2c *i2c)
+{
+	switch (i2c->id) {
+	case 0:
+		i2c->base = MTK_I2C0_BASE;
+		i2c->dmabase = MTK_I2C0_DMA;
+		i2c->irqnr = MTK_I2C0_GIC_IRQ;
+		break;
+	case 1:
+		i2c->base = MTK_I2C1_BASE;
+		i2c->dmabase = MTK_I2C1_DMA;
+		i2c->irqnr = MTK_I2C1_GIC_IRQ;
+		break;
+	case 2:
+		i2c->base = MTK_I2C2_BASE;
+		i2c->dmabase = MTK_I2C2_DMA;
+		i2c->irqnr = MTK_I2C2_GIC_IRQ;
+		break;
+	case 3:
+		i2c->base = MTK_I2C3_BASE;
+		i2c->dmabase = MTK_I2C3_DMA;
+		i2c->irqnr = MTK_I2C3_GIC_IRQ;
+		break;
+	default:
+		I2CERR("invalid para: i2c->id=%d\n", i2c->id);
+		return -EINVAL_I2C;
+	}
+
+	i2c->clk = g_i2c_source_clock;
+	i2c->clk_src_div = MTK_I2C_CLK_DIV;
+
+	if(!i2c->poll_en) {
+#ifdef CONFIG_MTK_IRQ
+		i2c_global = i2c;
+		mtk_irq_init(i2c);
+#endif
+	}
+
+	return 0;
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Initialize i2c hardware, soft reset i2c controller, then\n
+ *     configure io mode and control registers.
+ * @param[in]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains register base\n
+ *     address, ioconfig and i2c hardware information.
+ * @return
+ *     none.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     none.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
+{
+	uint16_t control_reg;
+
+	if (!(i2c->mode & I2C_FIFO_FORCE))
+		i2c_writel(i2c, OFFSET_SOFTRESET, I2C_SOFT_RST);
+
+	/* set ioconfig */
+	if (i2c->pushpull)
+		i2c_writel(i2c, OFFSET_IO_CONFIG, I2C_IO_CONFIG_PUSH_PULL);
+	else
+		i2c_writel(i2c, OFFSET_IO_CONFIG, I2C_IO_CONFIG_OPEN_DRAIN);
+
+	control_reg = I2C_CONTROL_DEFAULT | I2C_CONTROL_ACKERR_DET_EN |
+		      I2C_CONTROL_CLK_EXT_EN;
+	i2c_writel(i2c, OFFSET_CONTROL, control_reg);
+
+	if (i2c->mode & I2C_DCM_ENABLE)
+		i2c_writel(i2c, OFFSET_DCM_EN, I2C_DCM_OPEN);
+
+	if (i2c->mode & I2C_CONTI_TRANS)
+		i2c_writel(i2c, OFFSET_DELAY_LEN, i2c->delay_len);
+	else
+		i2c_writel(i2c, OFFSET_DELAY_LEN, I2C_DELAY_LEN);
+
+	i2c_dma_writel(i2c, OFFSET_DMA_RST, I2C_DMA_HARD_RST);
+	i2c_dma_writel(i2c, OFFSET_DMA_RST, I2C_DMA_CLR_FLAG);
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Calculate i2c speed.\n
+ *     Hardware design:\n
+ *     i2c_bus_freq = source_clk / (2 * sample_cnt * step_cnt)\n
+ *     The calculation want to pick the highest bus frequency that\n
+ *     is still less than or equal to i2c->speed_hz. The\n
+ *     calculation try to get sample_cnt and step_cnt.
+ * @param[in]
+ *     clk_src: i2c module source clock.
+ * @param[in]
+ *     target_speed: i2c target speed.
+ * @param[out]
+ *     timing_step_cnt: i2c step_cnt value.
+ * @param[out]
+ *     timing_sample_cnt: i2c sample_cnt value.
+ * @return
+ *     0, calculate speed successfully.\n
+ *     -EINVAL_I2C, calculate speed fail.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     1. Target speed is too low, calculate speed fail, return\n
+ *     -EINVAL_I2C.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static int mtk_i2c_calculate_speed(unsigned int clk_src,
+				   unsigned int target_speed,
+				   unsigned int *timing_step_cnt,
+				   unsigned int *timing_sample_cnt)
+{
+	unsigned int step_cnt;
+	unsigned int sample_cnt;
+	unsigned int max_step_cnt;
+	unsigned int base_sample_cnt = MAX_SAMPLE_CNT_DIV;
+	unsigned int base_step_cnt;
+	unsigned int opt_div;
+	unsigned int best_mul;
+	unsigned int cnt_mul;
+
+	if (target_speed > MAX_FS_PLUS_SPEED)
+		max_step_cnt = MAX_HS_STEP_CNT_DIV;
+	else
+		max_step_cnt = MAX_STEP_CNT_DIV;
+
+	base_step_cnt = max_step_cnt;
+
+	/* find the best combination */
+	opt_div = DIV_ROUND_UP(clk_src >> 1, target_speed);
+	best_mul = MAX_SAMPLE_CNT_DIV * max_step_cnt;
+
+	/* Search for the best pair (sample_cnt, step_cnt) with
+	* 0 < sample_cnt < MAX_SAMPLE_CNT_DIV
+	* 0 < step_cnt < max_step_cnt
+	* sample_cnt * step_cnt >= opt_div
+	* optimizing for sample_cnt * step_cnt being minimal
+	*/
+	for (sample_cnt = 1; sample_cnt <= MAX_SAMPLE_CNT_DIV; sample_cnt++) {
+		step_cnt = DIV_ROUND_UP(opt_div, sample_cnt);
+		cnt_mul = step_cnt * sample_cnt;
+		if (step_cnt > max_step_cnt)
+			continue;
+
+		if (cnt_mul < best_mul) {
+			best_mul = cnt_mul;
+			base_sample_cnt = sample_cnt;
+			base_step_cnt = step_cnt;
+			if (best_mul == opt_div)
+				break;
+		}
+	}
+
+	sample_cnt = base_sample_cnt;
+	step_cnt = base_step_cnt;
+
+	if ((clk_src / (2 * sample_cnt * step_cnt)) > target_speed) {
+		I2CERR("Unsupported speed (%u KHz)\n", target_speed);
+		return -EINVAL_I2C;
+	}
+
+	*timing_step_cnt = step_cnt - 1;
+	*timing_sample_cnt = sample_cnt - 1;
+
+	return 0;
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Calculate i2c speed and write sample_cnt, step_cnt to TIMING register.
+ * @param[out]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains i2c source clock,
+ *     clock divide and speed.
+ * @return
+ *     0, set speed successfully.\n
+ *     error code from mtk_i2c_calculate_speed().
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     1. If mtk_i2c_calculate_speed() fails, return its error code.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static int mtk_i2c_set_speed(struct mtk_i2c *i2c)
+{
+	bool low_power_clk = false;
+	unsigned int clk_src;
+	unsigned int step_cnt;
+	unsigned int sample_cnt;
+	unsigned int target_speed;
+	int ret;
+
+	if ((i2c->clk == MTK_I2C_ULPOSC_DIV8) ||
+	    (i2c->clk == MTK_I2C_ULPOSC_DIV16) ||
+	    (i2c->clk == MTK_I2C_CLK_26M))
+		low_power_clk = true;
+
+	if (i2c->speed == 0)
+		i2c->speed = I2C_DEFAULT_SPEED;
+
+	if ((!low_power_clk) && (i2c->speed == I2C_DEFAULT_SPEED)) {
+		i2c->clock_div_reg = I2C_CLK_DIV_100K;
+		i2c->timing_reg = I2C_TIMING_100K;
+		i2c->high_speed_reg = 0;
+	} else if ((!low_power_clk) && (i2c->speed == MAX_FS_MODE_SPEED)) {
+		i2c->clock_div_reg = I2C_CLK_DIV_400K;
+		i2c->timing_reg = I2C_TIMING_400K;
+		i2c->high_speed_reg = 0;
+	} else if ((!low_power_clk) && (i2c->speed == MAX_FS_PLUS_SPEED)) {
+		i2c->clock_div_reg = I2C_CLK_DIV_1000K;
+		i2c->timing_reg = I2C_TIMING_1000K;
+		i2c->high_speed_reg = 0;
+	} else {
+		i2c->clock_div_reg = I2C_DEFAULT_CLK_DIV;
+
+		if (i2c->clk_src_div == 0)
+			i2c->clk_src_div = MTK_I2C_CLK_DIV;
+
+		i2c->clk_src_div *= i2c->clock_div_reg;
+
+		clk_src = (i2c->clk) / (i2c->clk_src_div);
+		target_speed = i2c->speed;
+
+		if (target_speed > MAX_FS_PLUS_SPEED) {
+			/* Set master code speed register */
+			i2c->timing_reg = I2C_TIMING_400K;
+
+			/* Set the high speed mode register */
+			ret = mtk_i2c_calculate_speed(clk_src, target_speed,
+						      &step_cnt, &sample_cnt);
+			if (ret < 0)
+				return ret;
+
+			i2c->high_speed_reg = I2C_TIME_DEFAULT_VALUE |
+					      (sample_cnt << 12) |
+					      (step_cnt << 8);
+		} else {
+			ret = mtk_i2c_calculate_speed(clk_src, target_speed,
+						      &step_cnt, &sample_cnt);
+			if (ret < 0)
+				return ret;
+
+			i2c->timing_reg = (sample_cnt << 8) | step_cnt;
+
+			/* Disable the high speed transaction */
+			i2c->high_speed_reg = 0;
+		}
+	}
+
+	i2c_writel(i2c, OFFSET_CLOCK_DIV, (i2c->clock_div_reg - 1));
+	i2c_writel(i2c, OFFSET_TIMING, i2c->timing_reg);
+	i2c_writel(i2c, OFFSET_HS, i2c->high_speed_reg);
+
+	return 0;
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Dump i2c controller registers and DMA registers value.
+ * @param[in]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains register base\n
+ *     address and DMA base address.
+ * @return
+ *     none.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     none.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static void i2c_dump_info(struct mtk_i2c *i2c)
+{
+	I2CERR("I2C structure:\n");
+	I2CERR("id=%d,dma_en=%x,auto_restart=%x,poll_en=%x,op=%x\n",
+	       i2c->id, i2c->dma_en, i2c->auto_restart, i2c->poll_en, i2c->op);
+	I2CERR("irq_stat=%x,source_clk=%d,clk_div=%d,speed=%d\n",
+	       i2c->irq_stat, i2c->clk, i2c->clk_src_div, i2c->speed);
+	I2CERR("filter_msg=%x,msg_complete=%x,addr=%x\n",
+		i2c->filter_msg, i2c->msg_complete, i2c->addr);
+	I2CERR("mode=%x,irqnr=%x,timing_reg=%x,high_speed_reg=%x\n",
+		i2c->mode, i2c->irqnr, i2c->timing_reg, i2c->high_speed_reg);
+	I2CERR("con_num=%d,delay_len=%x,ext_time=%x,scl_ratio=%x\n",
+		i2c->con_num, i2c->delay_len, i2c->ext_time, i2c->scl_ratio);
+	I2CERR("hs_scl_ratio=%x,scl_mis_comp=%x,sta_stop_time=%x\n",
+		i2c->hs_scl_ratio, i2c->scl_mis_comp, i2c->sta_stop_time);
+	I2CERR("hs_sta_stop_time=%x,sda_time=%x\n",
+		i2c->hs_sta_stop_time, i2c->sda_time);
+
+	I2CERR("I2C base address 0x%llx\n", i2c->base);
+	I2CERR("I2C register:\n");
+	I2CERR("SLAVE_ADDR=0x%x,INTR_MASK=0x%x,INTR_STAT=0x%x\n",
+		(i2c_readl(i2c, OFFSET_SLAVE_ADDR)),
+		(i2c_readl(i2c, OFFSET_INTR_MASK)),
+		(i2c_readl(i2c, OFFSET_INTR_STAT)));
+	I2CERR("CONTROL=0x%x,TIMING=0x%x\n",
+		(i2c_readl(i2c, OFFSET_CONTROL)),
+		(i2c_readl(i2c, OFFSET_TIMING)));
+	I2CERR("TRANSFER_LEN=0x%x,TRANSAC_LEN=0x%x,DELAY_LEN=0x%x\n",
+		(i2c_readl(i2c, OFFSET_TRANSFER_LEN)),
+		(i2c_readl(i2c, OFFSET_TRANSAC_LEN)),
+		(i2c_readl(i2c, OFFSET_DELAY_LEN)));
+	I2CERR("START=0x%x,EXT_CONF=0x%x,IO_CONFIG=0x%x\n",
+		(i2c_readl(i2c, OFFSET_START)),
+		(i2c_readl(i2c, OFFSET_EXT_CONF)),
+		(i2c_readl(i2c, OFFSET_IO_CONFIG)));
+	I2CERR("FIFO_STAT1=0x%x,FIFO_STAT=0x%x,FIFO_THRESH=0x%x\n",
+		(i2c_readl(i2c, OFFSET_FIFO_STAT1)),
+		(i2c_readl(i2c, OFFSET_FIFO_STAT)),
+		(i2c_readl(i2c, OFFSET_FIFO_THRESH)));
+	I2CERR("DEBUGSTAT=0x%x,TRANSFER_LEN_AUX=0x%x,CLOCK_DIV=0x%x\n",
+		(i2c_readl(i2c, OFFSET_DEBUGSTAT)),
+		(i2c_readl(i2c, OFFSET_TRANSFER_LEN_AUX)),
+		(i2c_readl(i2c, OFFSET_CLOCK_DIV)));
+	I2CERR("HS=0x%x,SCL_HL_RATIO=0x%x,HS_SCL_HL_RATIO=0x%x\n",
+		(i2c_readl(i2c, OFFSET_HS)),
+		(i2c_readl(i2c, OFFSET_SCL_HL_RATIO)),
+		(i2c_readl(i2c, OFFSET_HS_SCL_HL_RATIO)));
+	I2CERR("STA_STOP_AC_TIME=0x%x,HS_STA_STOP_AC_TIME=0x%x\n",
+		(i2c_readl(i2c, OFFSET_STA_STOP_AC_TIME)),
+		(i2c_readl(i2c, OFFSET_HS_STA_STOP_AC_TIME)));
+	I2CERR("SCL_MIS_COMP_POINT=0x%x,SDA_TIME=0x%x,FIFO_PAUSE=0x%x\n",
+		(i2c_readl(i2c, OFFSET_SCL_MIS_COMP_POINT)),
+		(i2c_readl(i2c, OFFSET_SDA_TIME)),
+		(i2c_readl(i2c, OFFSET_FIFO_PAUSE)));
+
+	I2CERR("DMA base address 0x%llx\n", i2c->dmabase);
+	I2CERR("I2C DMA register:\n");
+	I2CERR("OFFSET_DMA_TX_MEM_ADDR=0x%x,OFFSET_DMA_RX_MEM_ADDR=0x%x\n",
+	       (i2c_dma_readl(i2c, OFFSET_DMA_TX_MEM_ADDR)),
+	       (i2c_dma_readl(i2c, OFFSET_DMA_RX_MEM_ADDR)));
+	I2CERR("OFFSET_DMA_TX_LEN=0x%x,OFFSET_DMA_RX_LEN=0x%x\n",
+	       (i2c_dma_readl(i2c, OFFSET_DMA_TX_LEN)),
+	       (i2c_dma_readl(i2c, OFFSET_DMA_RX_LEN)));
+	I2CERR("OFFSET_DMA_CON=0x%x,OFFSET_DMA_EN=0x%x\n",
+	       (i2c_dma_readl(i2c, OFFSET_DMA_CON)),
+	       (i2c_dma_readl(i2c, OFFSET_DMA_EN)));
+	I2CERR("OFFSET_DMA_INT_EN=0x%x,OFFSET_DMA_INT_FLAG=0x%x\n",
+	       (i2c_dma_readl(i2c, OFFSET_DMA_INT_EN)),
+	       (i2c_dma_readl(i2c, OFFSET_DMA_INT_FLAG)));
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Configure i2c register and trigger transfer.
+ * @param[out]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains register base\n
+ *     address, operation mode, interrupt status and i2c driver data.
+ * @param[out]
+ *     msgs: i2c_msg pointer, struct i2c_msg contains slave\n
+ *     address, operation mode, msg length and data buffer.
+ * @param[in]
+ *     num: i2c_msg number.
+ * @param[in]
+ *     left_num: left i2c_msg number.
+ * @return
+ *     0, i2c transfer successfully.\n
+ *     -ETIMEDOUT_I2C, i2c transfer timeout.\n
+ *     -EREMOTEIO_I2C, i2c receive data length does not equal to request data\n
+ *     length.\n
+ *     -ENXIO_I2C, i2c transfer ack error.
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     1. i2c transfer timeout, return -ETIMEDOUT_I2C.\n
+ *     2. i2c receive data length does not equal to request data\n
+ *     length, return -EREMOTEIO_I2C.\n
+ *     3. i2c transfer ack error, return -ENXIO_I2C.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
+			       int num, int left_num)
+{
+	bool tmo = false;
+	bool trans_error = false;
+	uint8_t *data_buf = msgs->buf;
+	uint16_t data_len = msgs->len;
+	uint16_t read_len;
+	uint16_t addr_reg;
+	uint16_t start_reg;
+	uint16_t control_reg;
+	uint16_t restart_flag = 0;
+	uint32_t tmo_poll = I2C_POLL_VALUE;
+	int ret;
+
+	i2c->irq_stat = 0;
+
+	if (i2c->auto_restart)
+		restart_flag = I2C_RS_TRANSFER;
+
+	control_reg = i2c_readl(i2c, OFFSET_CONTROL) &
+		      ~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS);
+
+	if ((i2c->speed > MAX_FS_PLUS_SPEED) ||
+	    ((num > 1) && !(i2c->mode & I2C_MULTI_STOP)))
+		control_reg |= I2C_CONTROL_RS;
+
+	if (i2c->op == I2C_MASTER_WRRD)
+		control_reg |= I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS;
+
+	if (i2c->dma_en)
+		control_reg |= I2C_CONTROL_AYNCS_MODE | I2C_CONTROL_DMA_EN;
+
+	i2c_writel(i2c, OFFSET_CONTROL, control_reg);
+
+	/* set start condition */
+	if (i2c->mode & I2C_EXTEN_SET)
+		i2c_writel(i2c, OFFSET_EXT_CONF, i2c->ext_time);
+	else {
+		if (i2c->speed <= I2C_DEFAULT_SPEED)
+			i2c_writel(i2c, OFFSET_EXT_CONF, I2C_ST_START_CON);
+		else
+			i2c_writel(i2c, OFFSET_EXT_CONF, I2C_FS_START_CON);
+	}
+
+	/* set ac timing register */
+	if (i2c->mode & I2C_ACTIME_SET) {
+		i2c_writel(i2c, OFFSET_SCL_HL_RATIO, i2c->scl_ratio);
+		i2c_writel(i2c, OFFSET_HS_SCL_HL_RATIO, i2c->hs_scl_ratio);
+		i2c_writel(i2c, OFFSET_SCL_MIS_COMP_POINT, i2c->scl_mis_comp);
+		i2c_writel(i2c, OFFSET_STA_STOP_AC_TIME, i2c->sta_stop_time);
+		i2c_writel(i2c, OFFSET_HS_STA_STOP_AC_TIME,
+			   i2c->hs_sta_stop_time);
+		i2c_writel(i2c, OFFSET_SDA_TIME, i2c->sda_time);
+	}
+
+	addr_reg = msgs->addr << 1;
+	if (i2c->op == I2C_MASTER_RD)
+		addr_reg |= 0x1;
+
+	i2c_writel(i2c, OFFSET_SLAVE_ADDR, addr_reg);
+
+	/* clear interrupt status */
+	i2c_writel(i2c, OFFSET_INTR_STAT, I2C_RS_TRANSFER | I2C_ACKERR |
+		   I2C_TRANSAC_COMP);
+
+	if (!(i2c->mode & I2C_FIFO_FORCE))
+		i2c_writel(i2c, OFFSET_FIFO_ADDR_CLR, I2C_FIFO_ADDR_CLR);
+
+	if (i2c->poll_en)
+		i2c_writel(i2c, OFFSET_INTR_MASK, 0);
+	else
+		i2c_writel(i2c, OFFSET_INTR_MASK, restart_flag | I2C_ACKERR |
+			   I2C_TRANSAC_COMP);
+
+	/* set transfer and transaction len */
+	if (i2c->op == I2C_MASTER_WRRD) {
+		i2c_writel(i2c, OFFSET_TRANSFER_LEN, msgs->len);
+		i2c_writel(i2c, OFFSET_TRANSFER_LEN_AUX, (msgs + 1)->len);
+		i2c_writel(i2c, OFFSET_TRANSAC_LEN, I2C_WRRD_TRANAC_VALUE);
+	} else {
+		if (i2c->mode & I2C_CONTI_TRANS) {
+			i2c_writel(i2c, OFFSET_TRANSFER_LEN, msgs->len);
+			i2c_writel(i2c, OFFSET_TRANSAC_LEN, i2c->con_num);
+
+			msgs->len *= i2c->con_num;
+		} else {
+			i2c_writel(i2c, OFFSET_TRANSFER_LEN, msgs->len);
+			i2c_writel(i2c, OFFSET_TRANSAC_LEN, num);
+		}
+	}
+
+	if (i2c->dma_en) {
+		if (i2c->op == I2C_MASTER_WR) {
+			i2c_dma_writel(i2c, OFFSET_DMA_INT_FLAG,
+				       I2C_DMA_INT_FLAG_NONE);
+			i2c_dma_writel(i2c, OFFSET_DMA_CON,
+				       I2C_DMA_CON_TX);
+			i2c_dma_writel(i2c, OFFSET_DMA_TX_MEM_ADDR,
+				       (uint32_t)(uint64_t)(msgs->buf));
+			i2c_dma_writel(i2c, OFFSET_DMA_TX_LEN,
+				       (uint32_t)(msgs->len));
+		} else if (i2c->op == I2C_MASTER_RD) {
+			i2c_dma_writel(i2c, OFFSET_DMA_INT_FLAG,
+				       I2C_DMA_INT_FLAG_NONE);
+			i2c_dma_writel(i2c, OFFSET_DMA_CON,
+				       I2C_DMA_CON_RX);
+			i2c_dma_writel(i2c, OFFSET_DMA_RX_MEM_ADDR,
+				       (uint32_t)(uint64_t)(msgs->buf));
+			i2c_dma_writel(i2c, OFFSET_DMA_RX_LEN,
+				       (uint32_t)(msgs->len));
+		} else if (i2c->op == I2C_MASTER_WRRD) {
+			i2c_dma_writel(i2c, OFFSET_DMA_INT_FLAG,
+				       I2C_DMA_CLR_FLAG);
+			i2c_dma_writel(i2c, OFFSET_DMA_CON,
+				       I2C_DMA_CLR_FLAG);
+			i2c_dma_writel(i2c, OFFSET_DMA_TX_MEM_ADDR,
+				       (uint32_t)(uint64_t)(msgs->buf));
+			i2c_dma_writel(i2c, OFFSET_DMA_RX_MEM_ADDR,
+				       (uint32_t)(uint64_t)((msgs + 1)->buf));
+			i2c_dma_writel(i2c, OFFSET_DMA_TX_LEN,
+				       (uint32_t)(msgs->len));
+			i2c_dma_writel(i2c, OFFSET_DMA_RX_LEN,
+				       (uint32_t)((msgs + 1)->len));
+		}
+
+		i2c_dma_writel(i2c, OFFSET_DMA_EN, I2C_DMA_START_EN);
+	} else {
+		if (!(i2c->mode & I2C_FIFO_FORCE) &&
+		    (i2c->op != I2C_MASTER_RD)) {
+			data_buf = msgs->buf;
+			data_len = msgs->len;
+
+			while (data_len--)
+				i2c_writel(i2c, OFFSET_DATA_PORT,
+					   *(data_buf++));
+		}
+	}
+
+	if (!i2c->auto_restart) {
+		start_reg = I2C_TRANSAC_START;
+	} else {
+		start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG;
+		if (left_num >= 1)
+			start_reg |= I2C_RS_MUL_CNFG;
+	}
+
+	i2c_writel(i2c, OFFSET_START, start_reg);
+
+	if (i2c->poll_en) {
+		for (;;) {
+			i2c->irq_stat = i2c_readl(i2c, OFFSET_INTR_STAT);
+
+			if (i2c->irq_stat & (I2C_TRANSAC_COMP | restart_flag)) {
+				tmo = false;
+				if (i2c->irq_stat & I2C_ACKERR)
+					trans_error = true;
+				break;
+			}
+
+			tmo_poll--;
+			if (tmo_poll == 0) {
+				tmo = true;
+				break;
+			}
+		}
+	} else {
+		for (;;) {
+			if (i2c->msg_complete && (i2c->irq_stat &
+			    (I2C_TRANSAC_COMP | restart_flag))) {
+				tmo = false;
+				if (i2c->irq_stat & I2C_ACKERR)
+					trans_error = true;
+				break;
+			}
+
+			tmo_poll--;
+			if (tmo_poll == 0) {
+				tmo = true;
+				break;
+			}
+		}
+	}
+
+	/* clear interrupt mask */
+	i2c_writel(i2c, OFFSET_INTR_MASK, ~(restart_flag | I2C_ACKERR |
+					    I2C_TRANSAC_COMP));
+
+	if ((!tmo) && (!trans_error)) {
+		if (!i2c->dma_en && i2c->op != I2C_MASTER_WR &&
+		    !(i2c->mode & I2C_FIFO_FORCE)) {
+			data_buf = (i2c->op == I2C_MASTER_RD) ?
+				   msgs->buf : (msgs + 1)->buf;
+			data_len = (i2c->op == I2C_MASTER_RD) ?
+				   msgs->len : (msgs + 1)->len;
+				read_len = i2c_readl(i2c, OFFSET_FIFO_STAT1)
+					   & 0x1f;
+
+			if (read_len == data_len) {
+				while (data_len--)
+					*(data_buf++) = i2c_readl(i2c,
+							OFFSET_DATA_PORT);
+			} else {
+				I2CERR("fifo read error!\n");
+				I2CERR("data_len %x, read_len %x\n",
+					data_len, read_len);
+				if (i2c->filter_msg == false)
+					i2c_dump_info(i2c);
+				return -EREMOTEIO_I2C;
+			}
+		}
+	} else {
+		/* timeout or ACKERR */
+		if (tmo)
+			ret = -ETIMEDOUT_I2C;
+		else
+			ret = -ENXIO_I2C;
+
+		if (i2c->filter_msg == false) {
+			if (tmo) {
+				I2CERR("id=%d, addr: %x, transfer timeout\n",
+				       i2c->id, msgs->addr);
+			} else {
+				I2CERR("id=%d, addr: %x, I2C_ACKERR\n",
+				       i2c->id, msgs->addr);
+			}
+
+			i2c_dump_info(i2c);
+		}
+
+		return ret;
+	}
+
+	return 0;
+}
+
+/** @ingroup IP_group_i2c_internal_function
+ * @par Description
+ *     Common i2c transfer API. Set i2c transfer mode according to i2c_msg\n
+ *     information, then call mtk_i2c_do_transfer() to configure i2c register\n
+ *     and trigger transfer.
+ * @param[out]
+ *     i2c: mtk_i2c pointer, struct mtk_i2c contains register base\n
+ *     address, operation mode, interrupt status and i2c driver data.
+ * @param[out]
+ *     msgs: i2c_msg pointer, struct i2c_msg contains slave\n
+ *     address, operation mode, msg length and data buffer.
+ * @param[in]
+ *     num: i2c_msg number.
+ * @return
+ *     i2c_msg number, i2c transfer successfully.\n
+ *     -EINVAL_I2C, msg length is 0 or more than 16, msg data buffer is NULL,\n
+ *     use DMA MODE or slave address more than 0x7f.\n
+ *     error code from mtk_i2c_init_base().\n
+ *     error code from mtk_i2c_set_speed().\n
+ *     error code from mtk_i2c_do_transfer().
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     1. If msg length is 0 or more than 16, msg data buffer is NULL,\n
+ *     use DMA MODE or slave address more than 0x7f, return -EINVAL_I2C.
+ *     2. If mtk_i2c_init_base() fails, return its error code.\n
+ *     3. If mtk_i2c_set_speed() fails, return its error code.\n
+ *     4. If mtk_i2c_do_transfer() fails, return its error code.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+static int mtk_i2c_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, int num)
+{
+	uint8_t num_cnt;
+	int left_num = num;
+	int ret;
+
+	ret = mtk_i2c_init_base(i2c);
+	if (ret) {
+		I2CERR("Failed to init i2c base.\n");
+		return ret;
+	}
+
+	ret = i2c_gpio_pinmux(i2c);
+	if (ret) {
+		I2CERR("Failed to set gpio to i2c mode.\n");
+		return ret;
+	}
+
+	if (!(i2c->mode & I2C_FIFO_FORCE)) {
+
+		i2c_clock_enable(i2c);
+	}
+
+	mtk_i2c_init_hw(i2c);
+
+	ret = mtk_i2c_set_speed(i2c);
+	if (ret) {
+		I2CERR("Failed to set the speed.\n");
+		goto err_exit;
+	}
+
+	for (num_cnt = 0; num_cnt < num; num_cnt++) {
+		if (((msgs + num_cnt)->addr) > 0x7f) {
+			I2CERR("i2c addr: msgs[%d]->addr(%x) > 0x7f, error!\n",
+			       num_cnt, ((msgs + num_cnt)->addr));
+			ret = -EINVAL_I2C;
+			goto err_exit;
+		}
+
+		if (!(msgs + num_cnt)->buf) {
+			I2CERR("msgs[%d]->buf is NULL.\n", num_cnt);
+			ret = -EINVAL_I2C;
+			goto err_exit;
+		}
+
+		if ((msgs + num_cnt)->len == 0) {
+			I2CERR("msgs[%d]->len == 0, error!\n", num_cnt);
+			ret = -EINVAL_I2C;
+			goto err_exit;
+		}
+
+		if (!(i2c->mode & I2C_FIFO_FORCE) &&
+		    (msgs + num_cnt)->len > I2C_FIFO_SIZE)
+			i2c->dma_en = true;
+	}
+
+	if ((num == 1) || ((!i2c->dma_en) && (num == 2) &&
+	    (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
+	    (msgs[0].addr == msgs[1].addr)) && !(i2c->mode & I2C_MULTI_TRANS)))
+		i2c->auto_restart = false;
+	else
+		i2c->auto_restart = true;
+
+	while (left_num--) {
+		if (msgs->flags & I2C_M_RD)
+			i2c->op = I2C_MASTER_RD;
+		else
+			i2c->op = I2C_MASTER_WR;
+
+		if (!i2c->auto_restart) {
+			if (num == 2) {
+				/* combined two messages into one transaction */
+				i2c->op = I2C_MASTER_WRRD;
+				left_num--;
+			}
+		}
+
+		ret = mtk_i2c_do_transfer(i2c, msgs, num, left_num);
+		if (ret < 0)
+			goto err_exit;
+
+		msgs++;
+	}
+
+	ret = I2C_OK;
+
+err_exit:
+	if (!(i2c->mode & I2C_FIFO_FORCE))
+		i2c_clock_disable(i2c);
+
+	return ret;
+}
+
+/** @ingroup IP_group_i2c_external_function
+ * @par Description
+ *     Initialize struct mtk_i2c and i2c_msg, then read data from\n
+ *     slave device.
+ * @param[in]
+ *     bus_num: i2c bus number.
+ * @param[in]
+ *     device_addr: slave device 7bits address.
+ * @param[in]
+ *     speed_khz: i2c transfer speed.
+ * @param[out]
+ *     buffer: read data buffer pointer.
+ * @param[in]
+ *     len: read data length.
+ * @return
+ *     0, i2c transfer successfully.\n
+ *     error code from mtk_i2c_transfer().
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     If mtk_i2c_transfer() fails, return its error code.
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+int mtk_i2c_read(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,
+		 uint8_t *buffer, uint16_t len)
+{
+	int ret = I2C_OK;
+	struct i2c_msg msgs;
+	struct mtk_i2c i2c_mtk;
+	struct mtk_i2c *i2c = &i2c_mtk;
+
+	memset(i2c, 0, sizeof(struct mtk_i2c));
+
+	i2c->poll_en = true;
+	i2c->dma_en = false;
+	i2c->auto_restart = false;
+	i2c->pushpull = false;
+	i2c->filter_msg = false;
+	i2c->id = bus_num;
+	i2c->addr = device_addr;
+	i2c->speed = speed_khz;
+	i2c->mode = 0;
+
+	msgs.addr = i2c->addr;
+	msgs.flags = 1;
+	msgs.buf = buffer;
+	msgs.len = len;
+	ret = mtk_i2c_transfer(i2c, &msgs, 1);
+
+	if ((i2c->filter_msg == false) && (ret != I2C_OK))
+		I2CERR("mtk_i2c_read fails(%d).\n", ret);
+
+	return ret;
+}
+
+/** @ingroup IP_group_i2c_external_function
+ * @par Description
+ *     Initialize struct mtk_i2c and i2c_msg, then write data to\n
+ *     slave device.
+ * @param[in]
+ *     bus_num: i2c bus number.
+ * @param[in]
+ *     device_addr: slave device 7bits address.
+ * @param[in]
+ *     speed_khz: i2c transfer speed.
+ * @param[in]
+ *     buffer: write data buffer pointer.
+ * @param[in]
+ *     len: write data length.
+ * @return
+ *     0, i2c transfer successfully.\n
+ *     error code from mtk_i2c_transfer().
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     If mtk_i2c_transfer() fails, return its error code.\n
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+int mtk_i2c_write(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,
+		  uint8_t *buffer, uint16_t len)
+{
+	int ret = I2C_OK;
+	struct i2c_msg msgs;
+	struct mtk_i2c i2c_mtk;
+	struct mtk_i2c *i2c = &i2c_mtk;
+
+	memset(i2c, 0, sizeof(struct mtk_i2c));
+
+	i2c->poll_en = true;
+	i2c->dma_en = false;
+	i2c->auto_restart = false;
+	i2c->pushpull = false;
+	i2c->filter_msg = false;
+	i2c->id = bus_num;
+	i2c->addr = device_addr;
+	i2c->speed = speed_khz;
+	i2c->mode = 0;
+
+	msgs.addr = i2c->addr;
+	msgs.flags = 0;
+	msgs.buf = buffer;
+	msgs.len = len;
+	ret = mtk_i2c_transfer(i2c, &msgs, 1);
+
+	if ((i2c->filter_msg == false) && (ret != I2C_OK))
+		I2CERR("mtk_i2c_write fails(%d).\n", ret);
+
+	return ret;
+}
+
+/** @ingroup IP_group_i2c_external_function
+ * @par Description
+ *     Initialize struct mtk_i2c and i2c_msg, first write data to\n
+ *     slave device then read data from slave device.
+ * @param[in]
+ *     bus_num: i2c bus number.
+ * @param[in]
+ *     device_addr: slave device 7bits address.
+ * @param[in]
+ *     speed_khz: i2c transfer speed.
+ * @param[in]
+ *     write_buffer: write data buffer pointer.
+ * @param[out]
+ *     read_buffer: read data buffer pointer.
+ * @param[in]
+ *     write_len: write data length.
+ * @param[in]
+ *     read_len: read data length.
+ * @return
+ *     0, i2c transfer successfully.\n
+ *     error code from mtk_i2c_transfer().
+ * @par Boundary case and Limitation
+ *     none.
+ * @par Error case and Error handling
+ *     If mtk_i2c_transfer() fails, return its error code.\n
+ * @par Call graph and Caller graph
+ * @par Refer to the source code
+ */
+int mtk_i2c_write_read(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,
+		       uint8_t *write_buffer, uint8_t *read_buffer,
+		       uint16_t write_len, uint16_t read_len)
+{
+	int ret = I2C_OK;
+	struct i2c_msg msgs[2];
+	struct mtk_i2c i2c_mtk;
+	struct mtk_i2c *i2c = &i2c_mtk;
+
+	memset(i2c, 0, sizeof(struct mtk_i2c));
+
+	i2c->poll_en = true;
+	i2c->dma_en = false;
+	i2c->auto_restart = false;
+	i2c->pushpull = false;
+	i2c->filter_msg = false;
+	i2c->id = bus_num;
+	i2c->addr = device_addr;
+	i2c->speed = speed_khz;
+	i2c->mode = 0;
+
+	msgs[0].addr = i2c->addr;
+	msgs[0].flags = 0;
+	msgs[0].buf = write_buffer;
+	msgs[0].len = write_len;
+
+	msgs[1].addr = i2c->addr;
+	msgs[1].flags = 1;
+	msgs[1].buf = read_buffer;
+	msgs[1].len = read_len;
+	ret = mtk_i2c_transfer(i2c, msgs, 2);
+
+	if ((i2c->filter_msg == false) && (ret != I2C_OK))
+		I2CERR("mtk_i2c_write_read fails(%d).\n", ret);
+
+	return ret;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/key/mtk_key.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/key/mtk_key.c
new file mode 100644
index 0000000..fdff12b
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/key/mtk_key.c
@@ -0,0 +1,30 @@
+/*
+ * 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.
+*/
+
+#include <platform/mt_reg_base.h>
+#include <reg.h>
+
+bool check_download_key(void)
+{
+    return (readl(GPIO_BASE) & (1U << 22)) ? true : false;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/mmc_core.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/mmc_core.c
new file mode 100644
index 0000000..53fd00a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/mmc_core.c
@@ -0,0 +1,1894 @@
+/*
+ * 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.
+ */
+
+/*=======================================================================*/
+/* HEADER FILES                                                          */
+/*=======================================================================*/
+#include <config.h>
+#include <platform/msdc.h>
+#include <platform/mmc_core.h>
+#include <platform/mmc_rpmb.h>
+#include <platform/mmc_ioctl.h>
+//#include <platform/trapping.h>
+#include <lib/bio.h>
+#include <lib/heap.h>
+#include <lib/partition.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+#include <kernel/mutex.h>
+
+#define CMD_RETRIES        (5)
+#define CMD_TIMEOUT        (100)    /* 100ms */
+#define PAD_DELAY_MAX 32
+
+static int mmc_set_ext_csd(struct mmc_card *card, u8 addr, u8 value);
+/* before DRAM k, malloc() is not ready, so define it globally */
+struct mmc_host msdc_host0;
+struct mmc_card emmc_card;
+
+typedef struct {
+    bdev_t bdev;
+    u32 part_id;
+    struct mmc_host *host;
+    struct mmc_card *card;
+} mmc_dev_t;
+
+struct msdc_delay_phase {
+    u8 maxlen;
+    u8 start;
+    u8 final_phase;
+};
+
+static const unsigned int tran_exp[] = {
+    10000,      100000,     1000000,    10000000,
+    0,      0,      0,      0
+};
+
+static const unsigned char tran_mant[] = {
+    0,  10, 12, 13, 15, 20, 25, 30,
+    35, 40, 45, 50, 55, 60, 70, 80,
+};
+
+static const unsigned char mmc_tran_mant[] = {
+    0,  10, 12, 13, 15, 20, 26, 30,
+    35, 40, 45, 52, 55, 60, 70, 80,
+};
+
+static u32 unstuff_bits(u32 *resp, u32 start, u32 size)
+{
+    const u32 __mask = (1 << (size)) - 1;
+    const int __off = 3 - ((start) / 32);
+    const int __shft = (start) & 31;
+    u32 __res;
+
+    __res = resp[__off] >> __shft;
+    if ((size) + __shft >= 32)
+        __res |= resp[__off-1] << (32 - __shft);
+    return __res & __mask;
+}
+
+#define UNSTUFF_BITS(r,s,sz)    unstuff_bits(r,s,sz)
+
+static int mmc_switch_part(mmc_dev_t *dev)
+{
+    int err = MMC_ERR_NONE;
+    struct mmc_card *card;
+    struct mmc_host *host;
+    u8 cfg;
+
+    host = dev->host;
+    if (host->curr_part == dev->part_id)
+        /* already set to specific partition */
+        return MMC_ERR_NONE;
+
+    if (dev->part_id > EXT_CSD_PART_CFG_GP_PART_4) {
+        dprintf(CRITICAL, "[MSDC] Unsupported partid: %u\n", dev->part_id);
+        return MMC_ERR_INVALID;
+    }
+
+    card = dev->card;
+    ASSERT(card);
+
+    cfg = card->ext_csd.part_cfg;
+    cfg = (cfg & ~0x7) | dev->part_id;
+    err = mmc_set_ext_csd(card, EXT_CSD_PART_CFG, cfg);
+    if (err)
+        dprintf(CRITICAL, "[MSDC] switch to part %u failed!\n", dev->part_id);
+    else
+        card->ext_csd.part_cfg = cfg;
+
+    return err;
+}
+
+static int mmc_cmd(struct mmc_host *host, struct mmc_command *cmd)
+{
+    int err;
+    int retry = cmd->retries;
+
+    do {
+        err = msdc_cmd(host, cmd);
+	/* do not retry CMD21 */
+        if (err == MMC_ERR_NONE || cmd->opcode == MMC_CMD21)
+            break;
+    } while (retry--);
+
+    return err;
+}
+
+static int mmc_app_cmd(struct mmc_host *host, struct mmc_command *cmd,
+                       u32 rca, int retries)
+{
+    int err = MMC_ERR_FAILED;
+    struct mmc_command appcmd;
+
+    appcmd.opcode  = MMC_CMD_APP_CMD;
+    appcmd.arg     = rca << 16;
+    appcmd.rsptyp  = RESP_R1;
+    appcmd.retries = CMD_RETRIES;
+    appcmd.timeout = CMD_TIMEOUT;
+
+    do {
+        err = mmc_cmd(host, &appcmd);
+
+        if (err == MMC_ERR_NONE)
+            err = mmc_cmd(host, cmd);
+        if (err == MMC_ERR_NONE)
+            break;
+    } while (retries--);
+
+    return err;
+}
+
+static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
+{
+    int bit;
+
+    ocr &= host->ocr_avail;
+
+    bit = __builtin_ffs(ocr);
+    if (bit) {
+        bit -= 1;
+        ocr &= 3 << bit;
+    } else {
+        ocr = 0;
+    }
+    return ocr;
+}
+
+static inline int mmc_go_idle(struct mmc_host *host)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_GO_IDLE_STATE, 0, RESP_NONE, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+    return mmc_cmd(host, &cmd);
+}
+
+static int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
+{
+    struct mmc_command cmd;
+    int err;
+    static const u8 test_pattern = 0xAA;
+    u8 result_pattern;
+
+    /*
+     * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+     * before SD_APP_OP_COND. This command will harmlessly fail for
+     * SD 1.0 cards.
+     */
+
+    cmd.opcode  = SD_CMD_SEND_IF_COND;
+    cmd.arg     = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+    cmd.rsptyp  = RESP_R1;
+    cmd.retries = 0;
+    cmd.timeout = CMD_TIMEOUT;
+
+    err = mmc_cmd(host, &cmd);
+
+    if (err != MMC_ERR_NONE)
+        return err;
+
+    result_pattern = cmd.resp[0] & 0xFF;
+
+    if (result_pattern != test_pattern)
+        return MMC_ERR_INVALID;
+
+    return MMC_ERR_NONE;
+}
+
+/*
+ * return MMC_ERR_RETRY means that need re-send CMD1 in stage 2
+ */
+static int mmc_send_op_cond_once(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+    int i, err = 0;
+    struct mmc_command cmd = {
+        MMC_CMD_SEND_OP_COND, 0, RESP_R3, {0}, CMD_TIMEOUT, 0, 0
+    };
+
+    cmd.arg = ocr;
+
+    for (i = 1; i; i--) {
+        err = mmc_cmd(host, &cmd);
+        if (err)
+            break;
+
+        /* if we're just probing, do a single pass */
+        if (ocr == 0)
+            break;
+
+        if (cmd.resp[0] & MMC_CARD_BUSY)
+            break;
+
+        err = MMC_ERR_RETRY;
+    }
+
+    if (!err && rocr)
+        *rocr = cmd.resp[0];
+
+    return err;
+}
+
+static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+    int i, err = 0;
+    struct mmc_command cmd = {
+        MMC_CMD_SEND_OP_COND, 0, RESP_R3, {0}, CMD_TIMEOUT, 0, 0
+    };
+
+    cmd.arg = ocr;
+
+    for (i = 100; i; i--) {
+        err = mmc_cmd(host, &cmd);
+        if (err)
+            break;
+
+        /* if we're just probing, do a single pass */
+        if (ocr == 0)
+            break;
+
+        if (cmd.resp[0] & MMC_CARD_BUSY)
+            break;
+
+        err = MMC_ERR_TIMEOUT;
+
+        spin(10000);
+
+    }
+
+    if (!err && rocr)
+        *rocr = cmd.resp[0];
+
+    return err;
+}
+
+static int mmc_send_app_op_cond_once(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+    struct mmc_command cmd;
+    int i, err = 0;
+
+    cmd.opcode  = SD_ACMD_SEND_OP_COND;
+    cmd.arg     = ocr;
+    cmd.rsptyp  = RESP_R3;
+    cmd.retries = CMD_RETRIES;
+    cmd.timeout = CMD_TIMEOUT;
+
+    for (i = 1; i; i--) {
+        err = mmc_app_cmd(host, &cmd, 0, CMD_RETRIES);
+        if (err != MMC_ERR_NONE)
+            break;
+
+        if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+            break;
+
+        err = MMC_ERR_RETRY;
+    }
+
+    if (rocr)
+        *rocr = cmd.resp[0];
+
+    return err;
+}
+
+static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+    struct mmc_command cmd;
+    int i, err = 0;
+
+    cmd.opcode  = SD_ACMD_SEND_OP_COND;
+    cmd.arg     = ocr;
+    cmd.rsptyp  = RESP_R3;
+    cmd.retries = CMD_RETRIES;
+    cmd.timeout = CMD_TIMEOUT;
+
+    for (i = 100; i; i--) {
+        err = mmc_app_cmd(host, &cmd, 0, CMD_RETRIES);
+        if (err != MMC_ERR_NONE)
+            break;
+
+        if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+            break;
+
+        err = MMC_ERR_TIMEOUT;
+
+        spin(10000);
+    }
+
+    if (rocr)
+        *rocr = cmd.resp[0];
+
+    return err;
+}
+
+static int mmc_all_send_cid(struct mmc_host *host)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_ALL_SEND_CID, 0, RESP_R2, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+    return mmc_cmd(host, &cmd);
+}
+
+static int mmc_send_relative_addr(struct mmc_host *host,
+                                  struct mmc_card *card, unsigned int *rca)
+{
+    int err;
+    struct mmc_command cmd;
+
+    memset(&cmd, 0, sizeof(struct mmc_command));
+
+    if (mmc_card_mmc(card)) { /* set rca */
+        cmd.opcode  = MMC_CMD_SET_RELATIVE_ADDR;
+        cmd.arg     = *rca << 16;
+        cmd.rsptyp  = RESP_R1;
+        cmd.retries = CMD_RETRIES;
+        cmd.timeout = CMD_TIMEOUT;
+    } else {  /* send rca */
+        cmd.opcode  = SD_CMD_SEND_RELATIVE_ADDR;
+        cmd.arg     = 0;
+        cmd.rsptyp  = RESP_R6;
+        cmd.retries = CMD_RETRIES;
+        cmd.timeout = CMD_TIMEOUT;
+    }
+    err = mmc_cmd(host, &cmd);
+    if ((err == MMC_ERR_NONE) && !mmc_card_mmc(card))
+        *rca = cmd.resp[0] >> 16;
+
+    return err;
+}
+
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_SELECT_CARD, 0, RESP_R1B, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+    cmd.arg = card->rca << 16;
+    return mmc_cmd(host, &cmd);
+}
+
+static int mmc_send_status(struct mmc_host *host, struct mmc_card *card,
+                           u32 *status)
+{
+    int err;
+    struct mmc_command cmd = {
+        MMC_CMD_SEND_STATUS, 0, RESP_R1, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+    cmd.arg = card->rca << 16;
+
+    err = mmc_cmd(host, &cmd);
+    if (err == MMC_ERR_NONE)
+        *status = cmd.resp[0];
+    return err;
+}
+
+static int mmc_switch(struct mmc_host *host, struct mmc_card *card,
+                      u8 set, u8 index, u8 value)
+{
+    int err;
+    u32 status = 0, count = 0;
+    struct mmc_command cmd = {
+        MMC_CMD_SWITCH, 0, RESP_R1B, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+
+    cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) |
+              (value << 8) | set;
+
+    err = mmc_cmd(host, &cmd);
+    if (err != MMC_ERR_NONE)
+        return err;
+
+    do {
+        err = mmc_send_status(host, card, &status);
+        if (err) {
+            dprintf(CRITICAL, "[eMMC] Fail to send status %d\n", err);
+            break;
+        }
+        if (status & R1_SWITCH_ERROR) {
+            dprintf(CRITICAL, "[eMMC] switch error. arg(0x%x)\n", cmd.arg);
+            return MMC_ERR_FAILED;
+        }
+        if (count++ >= 600000) {
+            dprintf(CRITICAL, "[%s]: timeout happend, count=%d, status=0x%x\n",
+                    __func__, count, status);
+            break;
+        }
+    } while (!(status & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(status) == 7));
+
+    if (!err && (index == EXT_CSD_PART_CFG))
+        host->curr_part = value & 0x7;
+
+    return err;
+}
+
+static int mmc_read_csds(struct mmc_host *host, struct mmc_card *card)
+{
+    int err;
+    struct mmc_command cmd = {
+        MMC_CMD_SEND_CSD, 0, RESP_R2, {0}, CMD_TIMEOUT * 100, CMD_RETRIES, 0
+    };
+
+    cmd.arg = card->rca << 16;
+
+    err = mmc_cmd(host, &cmd);
+    if (err == MMC_ERR_NONE) {
+        unsigned int e, m;
+        card->csd.mmca_vsn = UNSTUFF_BITS(&cmd.resp[0], 122, 4);
+        m = UNSTUFF_BITS(&cmd.resp[0], 99, 4);
+        e = UNSTUFF_BITS(&cmd.resp[0], 96, 3);
+        card->csd.max_dtr = tran_exp[e] * mmc_tran_mant[m];
+        e = UNSTUFF_BITS(&cmd.resp[0], 47, 3);
+        m = UNSTUFF_BITS(&cmd.resp[0], 62, 12);
+        card->csd.capacity = (1 + m) << (e + 2);
+        card->csd.read_blkbits = UNSTUFF_BITS(&cmd.resp[0], 80, 4);
+        memcpy(&card->raw_csd, &cmd.resp[0], sizeof(u32) * 4);
+    }
+
+    return err;
+}
+
+static int mmc_decode_csd(struct mmc_card *card)
+{
+    struct mmc_csd *csd = &card->csd;
+    unsigned int e, m, csd_struct;
+    u32 *resp = card->raw_csd;
+
+    /* common part; some part are updated later according to spec. */
+    csd_struct = unstuff_bits(resp, 126, 2);
+    csd->csd_struct = csd_struct;
+
+    /* For MMC
+     * We only understand CSD structure v1.1 and v1.2.
+     * v1.2 has extra information in bits 15, 11 and 10.
+     */
+    if ( ( mmc_card_mmc(card) &&
+            ( csd_struct != CSD_STRUCT_VER_1_0 && csd_struct != CSD_STRUCT_VER_1_1
+              && csd_struct != CSD_STRUCT_VER_1_2 && csd_struct != CSD_STRUCT_EXT_CSD )
+         ) ||
+            ( mmc_card_sd(card) && ( csd_struct != 0 && csd_struct!=1 ) )
+       ) {
+        dprintf(ALWAYS, "Unknown CSD ver %d\n", csd_struct);
+        return MMC_ERR_INVALID;
+    }
+
+    m = unstuff_bits(resp, 99, 4);
+    e = unstuff_bits(resp, 96, 3);
+    csd->max_dtr      = tran_exp[e] * tran_mant[m];
+
+    /* update later according to spec. */
+    csd->read_blkbits = unstuff_bits(resp, 80, 4);
+
+    e = unstuff_bits(resp, 47, 3);
+    m = unstuff_bits(resp, 62, 12);
+    csd->capacity     = (1 + m) << (e + 2);
+
+    //Specific part
+    if (mmc_card_sd(card)) {
+        switch (csd_struct) {
+            case 0:
+                break;
+            case 1:
+                /*
+                 * This is a block-addressed SDHC card. Most
+                 * interesting fields are unused and have fixed
+                 * values. To avoid getting tripped by buggy cards,
+                 * we assume those fixed values ourselves.
+                 */
+                mmc_card_set_blockaddr(card);
+
+                m = unstuff_bits(resp, 48, 22);
+                csd->capacity     = (1 + m) << 10;
+
+                csd->read_blkbits = 9;
+                break;
+        }
+    } else {
+        csd->mmca_vsn    = unstuff_bits(resp, 122, 4);
+    }
+
+    return 0;
+}
+
+static void mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+    u32 caps = card->host->caps;
+    u8 card_type = ext_csd[EXT_CSD_CARD_TYPE];
+
+    card->ext_csd.sectors =
+        ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+        ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+        ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+        ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+
+    card->ext_csd.rev = ext_csd[EXT_CSD_REV];
+    card->ext_csd.boot_info   = ext_csd[EXT_CSD_BOOT_INFO];
+    card->ext_csd.boot_part_sz = ext_csd[EXT_CSD_BOOT_SIZE_MULT] * 128 * 1024;
+    card->ext_csd.rpmb_sz = ext_csd[EXT_CSD_RPMB_SIZE_MULT] * 128 * 1024;
+
+    if (card->ext_csd.sectors)
+        mmc_card_set_blockaddr(card);
+
+    if (caps & MMC_CAP_EMMC_HS400 &&
+            card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
+        card->ext_csd.hs400_support = 1;
+        card->ext_csd.hs_max_dtr = 200000000;
+    } else if (caps & MMC_CAP_EMMC_HS200 &&
+               card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
+        card->ext_csd.hs_max_dtr = 200000000;
+    } else if (caps & MMC_CAP_DDR &&
+               card_type & EXT_CSD_CARD_TYPE_DDR_52) {
+        card->ext_csd.ddr_support = 1;
+        card->ext_csd.hs_max_dtr = 52000000;
+    } else if (caps & MMC_CAP_MMC_HIGHSPEED &&
+               card_type & EXT_CSD_CARD_TYPE_52) {
+        card->ext_csd.hs_max_dtr = 52000000;
+    } else if (card_type & EXT_CSD_CARD_TYPE_26) {
+        card->ext_csd.hs_max_dtr = 26000000;
+    } else {
+        /* MMC v4 spec says this cannot happen */
+        dprintf(CRITICAL, "[eMMC] MMCv4 but HS unsupported\n");
+    }
+
+    card->ext_csd.part_cfg = ext_csd[EXT_CSD_PART_CFG];
+    card->ext_csd.sec_support = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
+    card->ext_csd.reset_en = ext_csd[EXT_CSD_RST_N_FUNC];
+
+    return;
+}
+
+/* Read and decode extended CSD. */
+static int mmc_read_ext_csd(struct mmc_host *host, struct mmc_card *card)
+{
+    int err = MMC_ERR_NONE;
+    u8 *ext_csd;
+    int result = MMC_ERR_NONE;
+    struct mmc_data data;
+    addr_t base = host->base;
+    struct mmc_command cmd = {
+        MMC_CMD_SEND_EXT_CSD, 0, RESP_R1, {0}, CMD_TIMEOUT, CMD_RETRIES, 0
+    };
+
+    if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
+        dprintf(CRITICAL, "[eMMC] MMCA_VSN: %d. Skip EXT_CSD\n",
+                card->csd.mmca_vsn);
+        return MMC_ERR_NONE;
+    }
+
+    /*
+     * As the ext_csd is so large and mostly unused, we don't store the
+     * raw block in mmc_card.
+     */
+    ext_csd = malloc(512);
+    ASSERT(ext_csd);
+    memset(ext_csd, 0, 512);
+
+    msdc_reset_tune_counter(host);
+
+    do {
+#ifdef MSDC_USE_DMA_MODE
+        MSDC_DMA_ON;
+#endif
+        MSDC_CLR_FIFO();
+        MSDC_WRITE32(SDC_BLK_NUM, 1);
+        host->blklen = 512;
+        msdc_set_timeout(host, 100000000, 0);
+        err = mmc_cmd(host, &cmd);
+        if (err != MMC_ERR_NONE)
+            goto out;
+
+        data.cmd = &cmd;
+        data.blks = 1;
+        data.buf = ext_csd;
+        data.timeout = 100;
+#ifdef MSDC_USE_DMA_MODE
+        err = msdc_dma_transfer(host, &data);
+        MSDC_DMA_OFF;
+#else
+        err = msdc_pio_read_word(host, ext_csd, 512);
+#endif
+        if (err != MMC_ERR_NONE) {
+            if (msdc_abort_handler(host, 1))
+                dprintf(CRITICAL, "[eMMC] data abort failed\n");
+            result = msdc_tune_read(host);
+        }
+    } while (err && result != MMC_ERR_READTUNEFAIL);
+    msdc_reset_tune_counter(host);
+    mmc_decode_ext_csd(card, ext_csd);
+
+out:
+    free(ext_csd);
+    return err;
+}
+
+static void mmc_set_clock(struct mmc_host *host, int state, unsigned int hz)
+{
+    if (hz >= host->f_max) {
+        hz = host->f_max;
+    } else if (hz < host->f_min) {
+        hz = host->f_min;
+    }
+    msdc_config_clock(host, state, hz);
+}
+
+static int mmc_set_bus_width(struct mmc_host *host, struct mmc_card *card, int width)
+{
+    int err = MMC_ERR_NONE;
+    u32 arg = 0;
+    struct mmc_command cmd;
+
+    if (mmc_card_sd(card)) {
+        if (width == HOST_BUS_WIDTH_8) {
+            arg = SD_BUS_WIDTH_4;
+            width = HOST_BUS_WIDTH_4;
+        }
+
+        if ((width == HOST_BUS_WIDTH_4) && (host->caps & MMC_CAP_4_BIT_DATA)) {
+            arg = SD_BUS_WIDTH_4;
+        } else {
+            arg = SD_BUS_WIDTH_1;
+            width = HOST_BUS_WIDTH_1;
+        }
+
+        cmd.opcode  = SD_ACMD_SET_BUSWIDTH;
+        cmd.arg     = arg;
+        cmd.rsptyp  = RESP_R1;
+        cmd.retries = CMD_RETRIES;
+        cmd.timeout = CMD_TIMEOUT;
+
+        err = mmc_app_cmd(host, &cmd, card->rca, 0);
+        if (err != MMC_ERR_NONE)
+            goto out;
+
+        msdc_config_bus(host, width);
+    } else if (mmc_card_mmc(card)) {
+
+        if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+            goto out;
+
+        if (width == HOST_BUS_WIDTH_8) {
+            if (host->caps & MMC_CAP_8_BIT_DATA) {
+                arg = EXT_CSD_BUS_WIDTH_8;
+            } else {
+                width = HOST_BUS_WIDTH_4;
+            }
+        }
+        if (width == HOST_BUS_WIDTH_4) {
+            if (host->caps & MMC_CAP_4_BIT_DATA) {
+                arg = EXT_CSD_BUS_WIDTH_4;
+            } else {
+                width = HOST_BUS_WIDTH_1;
+            }
+        }
+        if (width == HOST_BUS_WIDTH_1)
+            arg = EXT_CSD_BUS_WIDTH_1;
+
+        err = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, arg);
+        if (err != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "[eMMC] Switch to bus width(%d) failed\n", arg);
+            goto out;
+        }
+        mmc_card_clr_ddr(card);
+
+        msdc_config_bus(host, width);
+    }
+
+out:
+    return err;
+}
+
+static u32 test_delay_bit(u32 delay, u32 bit)
+{
+    bit %= PAD_DELAY_MAX;
+    return delay & (1 << bit);
+}
+
+static int get_delay_len(u32 delay, u32 start_bit)
+{
+    u32 i;
+
+    for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) {
+        if (test_delay_bit(delay, start_bit + i) == 0)
+            return i;
+    }
+    return PAD_DELAY_MAX - start_bit;
+}
+
+static struct msdc_delay_phase get_best_delay(u32 delay)
+{
+    int start = 0, len = 0;
+    int start_final = 0, len_final = 0;
+    u8 final_phase = 0xff;
+    struct msdc_delay_phase delay_phase = { 0, };
+
+    if (delay == 0) {
+        dprintf(CRITICAL, "phase error: [map:%x]\n", delay);
+        delay_phase.final_phase = final_phase;
+        return delay_phase;
+    }
+
+    while (start < PAD_DELAY_MAX) {
+        len = get_delay_len(delay, start);
+        if (len_final < len) {
+            start_final = start;
+            len_final = len;
+        }
+        start += len ? len : 1;
+        if (len >= 12 && start_final < 4)
+            break;
+    }
+
+    /* The rule is that to find the smallest delay cell */
+    if (start_final == 0)
+        final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX;
+    else
+        final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX;
+    dprintf(ALWAYS, "phase: [map:%x] [maxlen:%d] [final:%d]\n",
+            delay, len_final, final_phase);
+
+    delay_phase.maxlen = len_final;
+    delay_phase.start = start_final;
+    delay_phase.final_phase = final_phase;
+    return delay_phase;
+}
+
+static int mmc_hs200_tune_cmd(struct mmc_host *host, int *cmd_error)
+{
+    int err = MMC_ERR_NONE;
+    u8 *tune_data;
+    u16 data_len = host->caps &  MMC_CAP_8_BIT_DATA ? 128: 64;
+    struct mmc_data data;
+    addr_t base = host->base;
+    struct mmc_command cmd = {
+        MMC_CMD21, 0, RESP_R1, {0}, CMD_TIMEOUT, 0, 0
+    };
+
+    tune_data = malloc(data_len);
+    ASSERT(tune_data);
+    memset(tune_data, 0, data_len);
+    *cmd_error = MMC_ERR_NONE;
+
+    msdc_reset_tune_counter(host);
+
+#ifdef MSDC_USE_DMA_MODE
+    MSDC_DMA_ON;
+#endif
+    MSDC_CLR_FIFO();
+    MSDC_WRITE32(SDC_BLK_NUM, 1);
+    host->blklen = data_len;
+    msdc_set_timeout(host, 100000000, 0);
+    err = mmc_cmd(host, &cmd);
+    if (err != MMC_ERR_NONE)
+        *cmd_error = err; /* still need receive data, or will impact the next cmd21 */
+
+    data.cmd = &cmd;
+    data.blks = 1;
+    data.buf = tune_data;
+    data.timeout = 100;
+#ifdef MSDC_USE_DMA_MODE
+    err = msdc_dma_transfer(host, &data);
+    MSDC_DMA_OFF;
+#else
+    err = msdc_pio_read_word(host, data.buf, data_len);
+#endif
+
+    msdc_reset_tune_counter(host);
+
+out:
+    free(tune_data);
+    return err;
+}
+
+static int msdc_tune_together(struct mmc_host *host)
+{
+    addr_t base = host->base;
+    u32 rise_delay = 0, fall_delay = 0;
+    struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
+    u8 final_delay, final_maxlen;
+    int cmd_err;
+    int i;
+    int ret;
+
+    MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+    MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_D_SMPL);
+    for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+        MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY, i);
+        MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, i);
+            ret = mmc_hs200_tune_cmd(host, &cmd_err);
+            if (!ret && !cmd_err)
+                rise_delay |= (1 << i);
+    }
+    final_rise_delay = get_best_delay(rise_delay);
+    /* if rising edge has enough margin, then do not scan falling edge */
+    if (final_rise_delay.maxlen >= 12 ||
+            (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
+        goto skip_fall;
+
+    MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+    MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_D_SMPL);
+    for (i = 0; i < PAD_DELAY_MAX; i++) {
+        MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY, i);
+        MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, i);
+            ret = mmc_hs200_tune_cmd(host, &cmd_err);
+            if (!ret && !cmd_err)
+                fall_delay |= (1 << i);
+    }
+    final_fall_delay = get_best_delay(fall_delay);
+
+skip_fall:
+    final_maxlen = MAX(final_rise_delay.maxlen, final_fall_delay.maxlen);
+    if (final_maxlen == final_rise_delay.maxlen) {
+        final_delay = final_rise_delay.final_phase;
+        MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+        MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_D_SMPL);
+    } else {
+        final_delay = final_fall_delay.final_phase;
+        MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+        MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_D_SMPL);
+    }
+
+    MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY, final_delay);
+    MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, final_delay);
+    dprintf(ALWAYS, "Final cmd/data pad delay: %x\n", final_delay);
+    return final_delay == 0xff ? -EIO : 0;
+}
+
+static int mmc_select_hs200(struct mmc_card *card)
+{
+    struct mmc_host *host = card->host;
+    int ret;
+
+    ret = mmc_set_bus_width(host, card, HOST_BUS_WIDTH_8);
+    if (ret != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "failed to set bus width!\n");
+        return ret;
+    }
+
+    ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+                     EXT_CSD_HS_TIMEING_HS200);
+    if (ret != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "failed to switch to hs200 mode!\n");
+        return ret;
+    }
+
+    mmc_card_set_hs200(card);
+    mmc_set_clock(host, card->state, card->ext_csd.hs_max_dtr);
+
+    return 0;
+}
+
+static int mmc_select_hs400(struct mmc_card *card)
+{
+    struct mmc_host *host = card->host;
+    addr_t base = host->base;
+    int ret;
+
+    mmc_set_clock(host, card->state, 50000000);
+    ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+                     EXT_CSD_HS_TIMEING_HS);
+    if (ret != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "switch to high-speed from hs200 failed, err:%d\n", ret);
+        return ret;
+    }
+
+    ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8_DDR);
+    if (ret != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "switch to bus width for hs400 failed, err:%d\n", ret);
+        return ret;
+    }
+
+    ret = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+                     EXT_CSD_HS_TIMEING_HS400);
+    if (ret != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "switch to hs400 failed, err:%d\n", ret);
+        return ret;
+    }
+    mmc_card_set_hs400(card);
+    mmc_set_clock(host, card->state, card->ext_csd.hs_max_dtr);
+
+    /*
+     * Apply hs400 settings:
+     * set data tune to default value and apply ds delay setting
+     */
+
+    MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_D_SMPL);
+
+    MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, 0);
+    MSDC_CLR_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS);
+    MSDC_WRITE32(EMMC50_PAD_DS_TUNE, 0x12012);
+
+    return ret;
+}
+
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+    struct mmc_host *host = card->host;
+    int ret;
+
+    ret = msdc_tune_together(host);
+    if (ret == -EIO) {
+        dprintf(CRITICAL, "hs200 tuning cmd/data error!\n");
+        return ret;
+    }
+
+    return MMC_ERR_NONE;
+}
+
+static int mmc_erase_start(struct mmc_card *card, u32 blknr)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_ERASE_GROUP_START, 0, RESP_R1, {0}, CMD_TIMEOUT, 3, 0
+    };
+    if (mmc_card_sd(card))
+        cmd.opcode = MMC_CMD_ERASE_WR_BLK_START;
+    cmd.arg = blknr;
+    return mmc_cmd(card->host, &cmd);
+}
+
+static int mmc_erase_end(struct mmc_card *card, u32 blknr)
+{
+    struct mmc_command cmd = {
+        MMC_CMD_ERASE_GROUP_END, 0, RESP_R1, {0}, CMD_TIMEOUT, 3, 0
+    };
+    if (mmc_card_sd(card))
+        cmd.opcode = MMC_CMD_ERASE_WR_BLK_END;
+    cmd.arg = blknr;
+    return mmc_cmd(card->host, &cmd);
+}
+
+static int mmc_erase(struct mmc_card *card, u32 arg)
+{
+    int err;
+    u32 status;
+    struct mmc_command cmd = {
+        MMC_CMD_ERASE, 0, RESP_R1B, {0}, CMD_TIMEOUT, 3, 0
+    };
+    if (mmc_card_sd(card))
+        arg = 0;
+    cmd.arg = arg;
+
+    if (arg & MMC_ERASE_SECURE_REQ) {
+        if (!(card->ext_csd.sec_support & EXT_CSD_SEC_FEATURE_ER_EN))
+            return MMC_ERR_INVALID;
+    }
+    if ((arg & MMC_ERASE_GC_REQ) || (arg & MMC_ERASE_TRIM)) {
+        if (!(card->ext_csd.sec_support & EXT_CSD_SEC_FEATURE_GB_CL_EN))
+            return MMC_ERR_INVALID;
+    }
+
+    err = mmc_cmd(card->host, &cmd);
+    if (err)
+        return err;
+
+    do {
+        err = mmc_send_status(card->host, card, &status);
+        if (err)
+            break;
+        if (R1_STATUS(status) != 0)
+            break;
+    } while (R1_CURRENT_STATE(status) == 7);
+
+    return err;
+}
+
+static int mmc_do_trim(struct mmc_card *card, off_t start_addr, size_t len)
+{
+    int err = MMC_ERR_NONE;
+    off_t end_addr;
+
+    if (len < card->blklen) {
+        dprintf(CRITICAL, "%s: invalid len: %ld\n", __func__, len);
+        return MMC_ERR_INVALID;
+    }
+
+    end_addr =((start_addr + len) / card->blklen - 1) * card->blklen;
+
+    if (mmc_card_highcaps(card)) {
+        start_addr >>= MMC_BLOCK_BITS_SHFT;
+        end_addr >>= MMC_BLOCK_BITS_SHFT;
+    }
+
+    err = mmc_erase_start(card, start_addr);
+    if (err)
+        goto error;
+
+    err = mmc_erase_end(card, end_addr);
+    if (err)
+        goto error;
+
+    err = mmc_erase(card, MMC_ERASE_TRIM);
+
+error:
+    if (err)
+        dprintf(CRITICAL, "%s: erase range (0x%llx~0x%llx) failed,Err<%d>\n",
+                __func__, start_addr, end_addr, err);
+
+    return err;
+}
+
+static int mmc_set_ext_csd(struct mmc_card *card, u8 addr, u8 value)
+{
+    int err;
+
+    /* can't write */
+    if (192 <= addr || !card)
+        return MMC_ERR_INVALID;
+
+    err = mmc_switch(card->host, card, EXT_CSD_CMD_SET_NORMAL, addr, value);
+
+    if (err == MMC_ERR_NONE)
+        err = mmc_read_ext_csd(card->host, card);
+
+    return err;
+}
+
+static int mmc_set_reset_func(struct mmc_card *card, u8 enable)
+{
+    int err = MMC_ERR_FAILED;
+
+    if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+        goto out;
+
+    if (card->ext_csd.reset_en == 0) {
+        err = mmc_set_ext_csd(card, EXT_CSD_RST_N_FUNC, enable);
+        if (err == MMC_ERR_NONE)
+            card->ext_csd.reset_en = enable;
+    } else {
+        /* no need set */
+        return MMC_ERR_NONE;
+    }
+out:
+    return err;
+}
+
+static int mmc_set_boot_bus(struct mmc_card *card, u8 rst_bwidth, u8 mode, u8 bwidth)
+{
+    int err = MMC_ERR_FAILED;
+    u8 arg;
+
+    if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+        goto out;
+
+    arg = mode | rst_bwidth | bwidth;
+
+    err = mmc_set_ext_csd(card, EXT_CSD_BOOT_BUS_WIDTH, arg);
+out:
+    return err;
+}
+
+static int mmc_set_part_config(struct mmc_card *card, u8 cfg)
+{
+    int err = MMC_ERR_FAILED;
+
+    if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+        goto out;
+
+    err = mmc_set_ext_csd(card, EXT_CSD_PART_CFG, cfg);
+out:
+    return err;
+}
+
+static int mmc_boot_config(struct mmc_card *card, u8 acken, u8 enpart, u8 buswidth, u8 busmode)
+{
+    int err = MMC_ERR_FAILED;
+    u8 val;
+    u8 rst_bwidth = 0;
+    u8 cfg;
+
+    if (card->csd.mmca_vsn < CSD_SPEC_VER_4 ||
+            !card->ext_csd.boot_info || card->ext_csd.rev < 3)
+        goto out;
+
+    cfg = card->ext_csd.part_cfg;
+    /* configure boot partition */
+    val = acken | enpart | (cfg & 0x7);
+    err = mmc_set_part_config(card, val);
+    if (err != MMC_ERR_NONE)
+        goto out;
+    else
+        card->ext_csd.part_cfg = val;
+
+    /* configure boot bus mode and width */
+    rst_bwidth = (buswidth != EXT_CSD_BOOT_BUS_WIDTH_1 ? 1 : 0) << 2;
+    dprintf(INFO, " =====Set boot Bus Width<%d>=======\n", buswidth);
+    dprintf(INFO, " =====Set boot Bus mode<%d>=======\n", busmode);
+    err = mmc_set_boot_bus(card, rst_bwidth, busmode, buswidth);
+out:
+
+    return err;
+}
+
+static int emmc_boot_prepare(struct mmc_card *card)
+{
+    int err = MMC_ERR_NONE;
+    /* MT8133 BROM default use 8bit mode */
+    u8 buswidth = EXT_CSD_BOOT_BUS_WIDTH_8;
+
+#if 0
+    /* check EFUSE setting, to do... */
+	    buswidth = EXT_CSD_BOOT_BUS_WIDTH_1;
+#endif
+
+    err = mmc_boot_config(card, EXT_CSD_PART_CFG_EN_ACK,
+                          EXT_CSD_PART_CFG_EN_BOOT_PART_1,
+                          buswidth, EXT_CSD_BOOT_BUS_MODE_DEFT);
+    if (err)
+        goto exit;
+
+    err = mmc_set_reset_func(card, 1);
+exit:
+    return err;
+}
+
+static int mmc_dev_bread(struct mmc_card *card, unsigned long blknr, u32 blkcnt, u8 *dst)
+{
+    struct mmc_host *host = card->host;
+    u32 blksz = host->blklen;
+    int tune = 0;
+    int retry = 3;
+    int err;
+    unsigned long src;
+
+    src = mmc_card_highcaps(card) ? blknr : blknr * blksz;
+
+    do {
+        if (!tune) {
+            err = host->blk_read(host, (uchar *)dst, src, blkcnt);
+        } else {
+#ifdef FEATURE_MMC_RD_TUNING
+            err = msdc_tune_bread(host, (uchar *)dst, src, blkcnt);
+#endif
+            if (err && (host->sclk > (host->f_max >> 4)))
+                mmc_set_clock(host, card->state, host->sclk >> 1);
+        }
+        if (err == MMC_ERR_NONE) {
+            break;
+        }
+
+        if (err == MMC_ERR_BADCRC || err == MMC_ERR_ACMD_RSPCRC || err == MMC_ERR_CMD_RSPCRC) {
+            tune = 1;
+            retry++;
+        } else if (err == MMC_ERR_READTUNEFAIL || err == MMC_ERR_CMDTUNEFAIL) {
+            dprintf(CRITICAL, "[eMMC] Fail to tuning,%s",
+                    (err == MMC_ERR_CMDTUNEFAIL) ?
+                    "cmd tune failed!\n" : "read tune failed!\n");
+            break;
+        }
+    } while (retry--);
+
+    return err;
+}
+
+static int mmc_dev_bwrite(struct mmc_card *card, unsigned long blknr,
+                          u32 blkcnt, const u8 *src)
+{
+    struct mmc_host *host = card->host;
+    u32 blksz = host->blklen;
+    u32 status;
+    int tune = 0;
+    int retry = 3;
+    int err;
+    unsigned long dst;
+
+    dst = mmc_card_highcaps(card) ? blknr : blknr * blksz;
+
+    do {
+        if (!tune) {
+            err = host->blk_write(host, dst, (uchar *)src, blkcnt);
+        } else {
+#ifdef FEATURE_MMC_WR_TUNING
+            err = msdc_tune_bwrite(host, dst, (uchar *)src, blkcnt);
+#endif
+            if (err && (host->sclk > (host->f_max >> 4)))
+                mmc_set_clock(host, card->state, host->sclk >> 1);
+        }
+        if (err == MMC_ERR_NONE) {
+            do {
+                err = mmc_send_status(host, card, &status);
+                if (err) {
+                    dprintf(CRITICAL, "[eMMC] Fail to send status %d\n", err);
+                    break;
+                }
+            } while (!(status & R1_READY_FOR_DATA) ||
+                     (R1_CURRENT_STATE(status) == 7));
+            dprintf(INFO, "[eMMC] Write %d bytes (DONE)\n", blkcnt * blksz);
+            break;
+        }
+
+        if (err == MMC_ERR_BADCRC || err == MMC_ERR_ACMD_RSPCRC || err == MMC_ERR_CMD_RSPCRC) {
+            tune = 1;
+            retry++;
+        } else if (err == MMC_ERR_WRITETUNEFAIL || err == MMC_ERR_CMDTUNEFAIL) {
+            dprintf(CRITICAL, "[eMMC] Fail to tuning,%s",
+                    (err == MMC_ERR_CMDTUNEFAIL) ?
+                    "cmd tune failed!\n" : "write tune failed!\n");
+            break;
+        }
+    } while (retry--);
+
+    return err;
+}
+
+static ssize_t mmc_block_read(struct bdev *dev, void *buf, bnum_t block,
+                              uint count)
+{
+    mmc_dev_t *__dev = (mmc_dev_t *)dev;
+    struct mmc_host *host = __dev->host;
+    struct mmc_card *card = __dev->card;
+    u32 maxblks = host->max_phys_segs;
+    u32 leftblks, totalblks = count;
+    ssize_t ret = 0;
+
+    mutex_acquire(&host->lock);
+    if (mmc_switch_part(__dev)) {
+        ret = ERR_IO;
+        goto done;
+    }
+
+    do {
+        leftblks = ((count > maxblks) ? maxblks : count);
+        if (mmc_dev_bread(card, (unsigned long)block, leftblks, buf)) {
+            ret = ERR_IO;
+            goto done;
+        }
+        block += leftblks;
+        buf += maxblks * dev->block_size;
+        count -= leftblks;
+    } while (count);
+
+    if (dev->block_size * totalblks > 0x7fffffffU)
+        /* ssize_t is defined as signed, should take a look here */
+        dprintf(CRITICAL, "[MSDC] %s: WARN! The return size is overflow! 0x%lx\n",
+                __func__, dev->block_size * totalblks);
+
+done:
+    mutex_release(&host->lock);
+    return ret ? ret : (ssize_t)dev->block_size * totalblks;
+}
+
+static ssize_t mmc_block_write(struct bdev *dev, const void *buf, bnum_t block,
+                               uint count)
+{
+    mmc_dev_t *__dev = (mmc_dev_t *)dev;
+    struct mmc_host *host = __dev->host;
+    struct mmc_card *card = __dev->card;
+    u32 maxblks = host->max_phys_segs;
+    u32 leftblks, totalblks = count;
+    ssize_t ret = 0;
+
+    mutex_acquire(&host->lock);
+    if (mmc_switch_part(__dev)) {
+        ret = ERR_IO;
+        goto done;
+    }
+
+    do {
+        leftblks = ((count > maxblks) ? maxblks : count);
+        if (mmc_dev_bwrite(card, (unsigned long)block, leftblks, buf)) {
+            ret = ERR_IO;
+            goto done;
+        }
+        block += leftblks;
+        buf = (u8 *)buf + maxblks * dev->block_size;
+        count -= leftblks;
+    } while (count);
+
+    if (dev->block_size * totalblks > 0x7fffffffU)
+        /* ssize_t is defined as signed, should take a look here */
+        dprintf(CRITICAL, "[MSDC] %s: WARN! The return size is overflow! 0x%lx\n",
+                __func__, dev->block_size * totalblks);
+
+done:
+    mutex_release(&host->lock);
+    return ret ? ret: (ssize_t)dev->block_size * totalblks;
+}
+
+static ssize_t mmc_wrap_erase(struct bdev *bdev, off_t offset, size_t len)
+{
+    mmc_dev_t *dev = (mmc_dev_t *)bdev;
+    struct mmc_host *host = dev->host;
+    ssize_t ret = 0;
+
+    mutex_acquire(&host->lock);
+    if (mmc_switch_part(dev)) {
+        ret = ERR_IO;
+        goto done;
+    }
+
+    /* ATTENTION:
+     * We use TRIM here, which is block-based(512B) wipping,
+     * If using ERASE here, please ensure the offset & size are
+     * erase-group aligned,
+     * OTHERWISE, some valid data may be wiped. refer to JEDEC spec:
+     * The Device will ignore all LSB's below the Erase Group size,
+     * effectively ROUNDING the address DOWN to the Erase Group boundary. */
+    ASSERT(dev && len);
+    if ((offset % MMC_BLOCK_SIZE) || (len % MMC_BLOCK_SIZE)) {
+        dprintf(CRITICAL, "%s: offset(0x%llx)/len(%lu) is not block-aligned!\n",
+                __func__, offset, len);
+        ret = ERR_IO;
+        goto done;
+    }
+
+    ASSERT(dev->card);
+    if (mmc_do_trim(dev->card, offset, len)) {
+        ret = ERR_IO;
+        goto done;
+    }
+
+done:
+    mutex_release(&host->lock);
+    return ret ? ret: (ssize_t)len;
+}
+
+static ssize_t mmc_rpmb_dummy_read(struct bdev *dev, void *buf, bnum_t block,
+                                   uint count)
+{
+    return 0;
+}
+
+static ssize_t mmc_rpmb_dummy_write(struct bdev *dev, const void *buf, bnum_t block,
+                                    uint count)
+{
+    return 0;
+}
+
+static ssize_t mmc_rpmb_dummy_erase(struct bdev *bdev, off_t offset, size_t len)
+{
+    return 0;
+}
+
+static int mmc_set_block_count(struct mmc_host *host, unsigned int blockcount,
+                               bool is_rel_write)
+{
+    struct mmc_command cmd = {0};
+
+    cmd.opcode = MMC_CMD_SET_BLOCK_COUNT;
+    cmd.arg = blockcount & 0x0000FFFF;
+    if (is_rel_write)
+        cmd.arg |= 1 << 31;
+    cmd.rsptyp = RESP_R1;
+
+    return mmc_cmd(host, &cmd);
+}
+
+static int mmc_rpmb_ioctl_cmd(struct bdev *dev, struct mmc_ioc_cmd *arg)
+{
+    mmc_dev_t *__dev = (mmc_dev_t *)dev;
+    struct mmc_host *host = __dev->host;
+    //struct mmc_card *card = __dev->card;
+    struct mmc_command cmd = {0};
+    struct mmc_data data = {0};
+    addr_t base = host->base;
+    int ret = 0;
+    int old_autocmd = msdc_get_autocmd(host);
+
+    msdc_set_autocmd(host, 0);
+    cmd.opcode = arg->opcode;
+    cmd.arg = arg->arg;
+    cmd.rsptyp = arg->flags; /* arg->flags must be type of enum of RESP_NONE ~ RESP_R1B */
+
+    if (arg->blocks) {
+        ret = mmc_set_block_count(host, arg->blocks,
+                                  arg->write_flag & (1 << 31));
+        if (ret != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "mmc cmd23 failed!\n");
+            goto out;
+        }
+    }
+
+    if (arg->blocks) {
+#ifdef MSDC_USE_DMA_MODE
+        MSDC_DMA_ON;
+#endif
+        MSDC_CLR_FIFO();
+        MSDC_WRITE32(SDC_BLK_NUM, arg->blocks);
+        host->blklen = 512;
+        msdc_set_timeout(host, 100000000, 0);
+        ret = mmc_cmd(host, &cmd);
+        if (ret != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "mmc cmd failed\n");
+            goto out;
+        }
+
+        data.cmd = &cmd;
+        data.blks = arg->blocks;
+        data.buf = (uchar *)arg->data_ptr;
+        data.timeout = 100;
+#ifdef MSDC_USE_DMA_MODE
+        ret = msdc_dma_transfer(host, &data);
+        MSDC_DMA_OFF;
+#else
+	ret = msdc_pio_read_word(host, data.buf, data.blks * 512);
+#endif
+
+    } else {
+        ret = mmc_cmd(host, &cmd);
+    }
+
+out:
+    msdc_set_autocmd(host, old_autocmd);
+    return ret;
+}
+
+static int mmc_rpmb_ioctl(struct bdev *dev, int request, void *argp)
+{
+    mmc_dev_t *__dev = (mmc_dev_t *)dev;
+    struct mmc_host *host = __dev->host;
+    int ret = 0;
+
+    mutex_acquire(&host->lock);
+    if (mmc_switch_part(__dev)) {
+        ret = ERR_IO;
+        goto done;
+    }
+
+    switch (request) {
+        case MMC_IOC_CMD:
+            ret = mmc_rpmb_ioctl_cmd(dev, (struct mmc_ioc_cmd *)argp);
+            break;
+        default:
+            ret = ERR_INVALID_ARGS;
+            break;
+    }
+
+done:
+    mutex_release(&host->lock);
+    return ret;
+}
+
+static int mmc_init_mem_card_stage1(struct mmc_host *host,
+                                    struct mmc_card *card, u32 ocr)
+{
+    int err;
+
+    /*
+     * Sanity check the voltages that the card claims to
+     * support.
+     */
+    if (ocr & 0x7F)
+        ocr &= ~0x7F;
+
+    ocr = host->ocr = mmc_select_voltage(host, ocr);
+
+    /*
+     * Can we support the voltage(s) of the card(s)?
+     */
+    if (!host->ocr) {
+        err = MMC_ERR_FAILED;
+        goto out;
+    }
+
+    err = mmc_go_idle(host);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in GO_IDLE_STATE cmd\n");
+        goto out;
+    }
+
+    /* send interface condition */
+    if (mmc_card_sd(card))
+        err = mmc_send_if_cond(host, ocr);
+
+    /* host support HCS[30] */
+    ocr |= (1 << 30);
+
+    /* send operation condition */
+    if (mmc_card_sd(card)) {
+        err = mmc_send_app_op_cond_once(host, ocr, &card->ocr);
+    } else {
+        /* The extra bit indicates that we support high capacity */
+        err = mmc_send_op_cond_once(host, ocr, &card->ocr);
+    }
+
+out:
+    /* MMC_ERR_RETRY is not error */
+    return err;
+}
+
+static int mmc_init_mem_card_stage2(struct mmc_host *host,
+                                    struct mmc_card *card, bool retry_opcond)
+{
+    int err = MMC_ERR_NONE;
+    u32 ocr = host->ocr;
+
+    /* host support HCS[30] */
+    ocr |= (1 << 30);
+
+    if (retry_opcond) {
+        /* send operation condition */
+        if (mmc_card_sd(card)) {
+            err = mmc_send_app_op_cond(host, ocr, &card->ocr);
+        } else {
+            /* The extra bit indicates that we support high capacity */
+            err = mmc_send_op_cond(host, ocr, &card->ocr);
+        }
+    }
+
+    if (err != MMC_ERR_NONE) {
+        dprintf(INFO, "Fail in SEND_OP_COND cmd\n");
+        goto out;
+    }
+
+    /* set hcs bit if a high-capacity card */
+    card->state |= ((card->ocr >> 30) & 0x1) ? MMC_STATE_HIGHCAPS : 0;
+    /* send cid */
+    err = mmc_all_send_cid(host);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in SEND_CID cmd\n");
+        goto out;
+    }
+
+    /* assign a rca */
+    card->rca = 0x1;
+
+    /* set/send rca */
+    err = mmc_send_relative_addr(host, card, &card->rca);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in SEND_RCA cmd\n");
+        goto out;
+    }
+
+    /* send csd */
+    err = mmc_read_csds(host, card);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in SEND_CSD cmd\n");
+        goto out;
+    }
+    mmc_decode_csd(card);
+
+    /* select this card */
+    err = mmc_select_card(host, card);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in select card cmd\n");
+        goto out;
+    }
+
+    if (mmc_card_sd(card)) {
+        /* set bus width */
+        mmc_set_bus_width(host, card, HOST_BUS_WIDTH_4);
+        /* compute bus speed.  usd defalut speed */
+        card->maxhz = 26000000;
+        mmc_set_clock(host, card->state, card->maxhz);
+    } else {
+
+        /* send ext csd */
+        err = mmc_read_ext_csd(host, card);
+        if (err != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "[eMMC] Fail in SEND_EXT_CSD cmd\n");
+            goto out;
+        }
+        if (host->caps & MMC_CAP_EMMC_HS200 && host->caps & MMC_CAP_EMMC_HS400) {
+            if (card->ext_csd.hs400_support) {
+                err = mmc_select_hs200(card);
+                if (err != MMC_ERR_NONE)
+                    goto select_hs;
+                err = mmc_hs200_tuning(card);
+                if (err != MMC_ERR_NONE)
+                    goto select_hs;
+                err = mmc_select_hs400(card);
+                if (err != MMC_ERR_NONE)
+                    goto select_hs;
+                else
+                    goto card_init_done;
+            }
+        }
+
+select_hs:
+        /* activate high speed (if supported) */
+        if ((card->ext_csd.hs_max_dtr != 0) && (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
+            mmc_set_clock(host, 0, host->f_min);
+            err = mmc_switch(host, card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
+            if (err == MMC_ERR_NONE) {
+                dprintf(INFO, "[eMMC] Switched to High-Speed mode!\n");
+                mmc_card_clear_hs200(card);
+                mmc_card_clear_hs400(card);
+                mmc_card_clear_ddr(card);
+                mmc_card_set_highspeed(card);
+                mmc_set_clock(host, card->state, 50000000);
+                /* set bus width */
+                mmc_set_bus_width(host, card, HOST_BUS_WIDTH_8);
+            }
+        }
+
+card_init_done:
+        /* compute bus speed. */
+        card->maxhz = (unsigned int)-1;
+
+        if (mmc_card_highspeed(card) || mmc_card_hs400(card)) {
+            if (card->maxhz > card->ext_csd.hs_max_dtr)
+                card->maxhz = card->ext_csd.hs_max_dtr;
+        } else if (card->maxhz > card->csd.max_dtr) {
+            card->maxhz = card->csd.max_dtr;
+        }
+    }
+
+    if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
+        /* The EXT_CSD sector count is in number or 512 byte sectors. */
+        card->blklen = MMC_BLOCK_SIZE;
+        card->nblks  = card->ext_csd.sectors;
+    } else {
+        /* The CSD capacity field is in units of read_blkbits.
+         * set_capacity takes units of 512 bytes.
+         */
+        card->blklen = MMC_BLOCK_SIZE;
+        host->blklen = MMC_BLOCK_SIZE;
+        card->nblks  = card->csd.capacity << (card->csd.read_blkbits - 9);
+    }
+
+    dprintf(CRITICAL,"[eMMC/SD] Size: %d MB, Max.Speed: %d kHz, blklen(%d), nblks(%d), ro(%d)\n",
+            ((card->nblks / 1024) * card->blklen) / 1024 , card->maxhz / 1000,
+            card->blklen, card->nblks, mmc_card_readonly(card));
+
+    card->ready = 1;
+
+    dprintf(INFO, "[eMMC/SD] Initialized\n");
+out:
+    return err;
+}
+
+static int mmc_init_card_stage1(struct mmc_host *host, struct mmc_card *card)
+{
+    int err;
+    u32 ocr;
+
+    dprintf(INFO, "[%s]: start\n", __func__);
+    memset(card, 0, sizeof(struct mmc_card));
+
+    mmc_card_set_present(card);
+    mmc_card_set_host(card, host);
+    mmc_card_set_unknown(card);
+
+    err = mmc_go_idle(host);
+    if (err != MMC_ERR_NONE) {
+        dprintf(CRITICAL, "[eMMC] Fail in GO_IDLE_STATE cmd\n");
+        goto out;
+    }
+
+    /* send interface condition */
+    if (host->host_id)
+        mmc_send_if_cond(host, host->ocr_avail);
+
+    /* query operation condition */
+
+    if (host->host_id) {
+        err = mmc_send_app_op_cond(host, 0, &ocr);
+        if (err != MMC_ERR_NONE) {
+            err = mmc_send_op_cond(host, 0, &ocr);
+            if (err != MMC_ERR_NONE) {
+                dprintf(INFO, "Fail in MMC_CMD_SEND_OP_COND/SD_ACMD_SEND_OP_COND cmd\n");
+                goto out;
+            }
+            mmc_card_set_mmc(card);
+        } else {
+            mmc_card_set_sd(card);
+        }
+    } else {
+        err = mmc_send_op_cond(host, 0, &ocr);
+        if (err != MMC_ERR_NONE) {
+            dprintf(INFO, "Fail in MMC_CMD_SEND_OP_COND/SD_ACMD_SEND_OP_COND cmd\n");
+            goto out;
+        }
+        mmc_card_set_mmc(card);
+    }
+
+    host->card = card;
+    err = mmc_init_mem_card_stage1(host, card, ocr);
+
+out:
+    return err;
+}
+
+static int mmc_init_card_stage2(struct mmc_host *host, struct mmc_card *card,
+                                bool retry_opcond)
+{
+    int err;
+
+    err = mmc_init_mem_card_stage2(host, card, retry_opcond);
+    if (err) {
+        dprintf(CRITICAL, "[%s]: failed, err=%d\n", __func__, err);
+        return err;
+    }
+    host->card = card;
+    dprintf(INFO, "[%s]: finish successfully\n",__func__);
+    return 0;
+}
+
+static inline int mmc_init_host(struct mmc_host *host)
+{
+    mutex_init(&host->lock);
+    return msdc_init(host);
+}
+
+static void mmc_bio_ops(const void *name, const int part_id, const int nblks,
+                        struct mmc_host *host, struct mmc_card *card)
+{
+    mmc_dev_t *dev;
+
+    dev = malloc(sizeof(mmc_dev_t));
+    /* malloc fail */
+    ASSERT(dev);
+    /* construct the block device */
+    memset(dev, 0, sizeof(mmc_dev_t));
+
+    /* setup partition id*/
+    dev->part_id = part_id;
+    /* setup host */
+    dev->host = host;
+    /* setup card */
+    dev->card = card;
+    /* bio block device register */
+    bio_initialize_bdev(&dev->bdev, name,
+                        card->blklen, nblks,
+                        0, NULL, BIO_FLAGS_NONE);
+    /* override our block device hooks */
+    if (part_id == EXT_CSD_PART_CFG_RPMB_PART) {
+        dev->bdev.read_block = mmc_rpmb_dummy_read;
+        dev->bdev.write_block = mmc_rpmb_dummy_write;
+        dev->bdev.erase = mmc_rpmb_dummy_erase;
+        dev->bdev.ioctl = mmc_rpmb_ioctl;
+    } else {
+        dev->bdev.read_block = mmc_block_read;
+        dev->bdev.write_block = mmc_block_write;
+        dev->bdev.erase = mmc_wrap_erase;
+    }
+    bio_register_device(&dev->bdev);
+    partition_publish(dev->bdev.name, 0x0);
+}
+
+struct mmc_card *emmc_init_stage1(bool *retry_opcond)
+{
+    int err = MMC_ERR_NONE;
+    struct mmc_host *host;
+    struct mmc_card *card;
+
+    host = &msdc_host0;
+    /* construct the block device */
+    memset(host, 0, sizeof(struct mmc_host));
+    host->host_id = 0;
+
+    card = &emmc_card;
+    /* construct the block device */
+    memset(card, 0, sizeof(struct mmc_card));
+
+    err = mmc_init_host(host);
+
+    if (err == MMC_ERR_NONE)
+        err = mmc_init_card_stage1(host, card);
+
+    if (err && err != MMC_ERR_RETRY) {
+        dprintf(CRITICAL, "failed in %s \n", __func__);
+        return NULL;
+    } else if (err == MMC_ERR_RETRY) {
+        *retry_opcond = true;
+    } else {
+        *retry_opcond = false;
+    }
+
+    return card;
+}
+
+int emmc_init_stage2(struct mmc_card *card, bool retry_opcond)
+{
+    int err = MMC_ERR_NONE;
+    struct mmc_host *host;
+    int boot_part_nblks = 0;
+    int rpmb_part_nblks = 0;
+
+    host = card->host;
+    err = mmc_init_card_stage2(host, card, retry_opcond);
+    /* mmc init fail */
+    ASSERT(err == MMC_ERR_NONE);
+
+    err = emmc_boot_prepare(card);
+    ASSERT(err == MMC_ERR_NONE);
+
+    mmc_bio_ops("mmc0", EXT_CSD_PART_CFG_DEFT_PART, card->nblks, host, card);
+    boot_part_nblks = card->ext_csd.boot_part_sz/card->blklen;
+    mmc_bio_ops("mmc0boot0", EXT_CSD_PART_CFG_BOOT_PART_1, boot_part_nblks,
+                host, card);
+    mmc_bio_ops("mmc0boot1", EXT_CSD_PART_CFG_BOOT_PART_2, boot_part_nblks,
+                host, card);
+    rpmb_part_nblks = card->ext_csd.rpmb_sz/card->blklen;
+    mmc_bio_ops("mmc0rpmb", EXT_CSD_PART_CFG_RPMB_PART, rpmb_part_nblks,
+                host, card);
+
+    return err;
+}
+
+int sdmmc_init(u8 host_id)
+{
+    int err = MMC_ERR_NONE;
+    struct mmc_host *host;
+    struct mmc_card *card;
+    bool retry_opcond;
+
+    printf("%s enter\n", __func__);
+
+    host = malloc(sizeof(struct mmc_host));
+    /* malloc fail */
+    if (!host) {
+        dprintf(INFO, "Failed to malloc host!\n");
+        err = -ENOMEM;
+        goto end;
+    }
+    /* construct the block device */
+    memset(host, 0, sizeof(struct mmc_host));
+    host->host_id = host_id;
+
+    card = malloc(sizeof(struct mmc_card));
+    /* malloc fail */
+    if (!card) {
+        dprintf(INFO, "Failed to malloc card!\n");
+        free(host);
+        err = -ENOMEM;
+        goto end;
+    }
+    /* construct the block device */
+    memset(card, 0, sizeof(struct mmc_card));
+
+    err = mmc_init_host(host);
+
+    if (err == MMC_ERR_NONE)
+        err = mmc_init_card_stage1(host, card);
+    /* mmc init fail */
+    if (err && err != MMC_ERR_RETRY) {
+        dprintf(INFO, "mmc_init_card fail!\n");
+        free(host);
+        free(card);
+        goto end;
+    } else if (err == MMC_ERR_RETRY) {
+        retry_opcond = true;
+    } else {
+        retry_opcond = false;
+    }
+
+    err = mmc_init_card_stage2(host, card, retry_opcond);
+    if (err != MMC_ERR_NONE) {
+        dprintf(INFO, "mmc_init_card fail!\n");
+        free(host);
+        free(card);
+        goto end;
+    }
+    mmc_bio_ops("sdmmc1", EXT_CSD_PART_CFG_DEFT_PART, card->nblks, host, card);
+
+end:
+    return err;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/mmc_rpmb.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/mmc_rpmb.c
new file mode 100644
index 0000000..3f6f4c7
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/mmc_rpmb.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2017 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 <stdlib.h>
+#include <string.h>
+#include <lib/bio.h>
+#include <platform/mmc_ioctl.h>
+#include <platform/mmc_rpmb.h>
+#include <platform/mtk_trng.h>
+#include <rpmb_mac.h>
+#include <debug.h>
+
+static void reverse_endian(void *data, size_t size)
+{
+    unsigned int i;
+    char tmp;
+    char *swp = (char *)data;
+
+    for (i = 0 ; i< (size/2); ++i) {
+        tmp = swp[i];
+        swp[i] = swp[size-1-i];
+        swp[size-1-i] = tmp;
+    }
+}
+
+int mmc_rpmb_set_key(u8 *key)
+{
+    int ret;
+    bdev_t *rpdev;
+    struct mmc_ioc_cmd *idata;
+    unsigned char *rpmb_pkt;
+
+    idata = malloc(sizeof(struct mmc_ioc_cmd));
+    if (idata == NULL) {
+        return -2;
+    }
+    rpmb_pkt = malloc(512);
+    if (rpmb_pkt == NULL) {
+        free(idata);
+        return -2;
+    }
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+
+    rpdev = bio_open("mmc0rpmb");
+    if (rpdev == NULL) {
+        free(rpmb_pkt);
+        free(idata);
+        return -3;
+    }
+
+    /* get wc for status */
+    rpmb_pkt[0] = 2;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1;
+    reverse_endian(rpmb_pkt, 512);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_READ_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 0;
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    reverse_endian(rpmb_pkt, 512);
+    /* check result */
+    ret = *(unsigned short *)&rpmb_pkt[2];
+    if (ret != 7) /* 7 means not programmed yet */
+        goto rpmb_end;
+    dprintf(INFO, "ret=%d, key not programmed yet\n", ret);
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, sizeof(struct mmc_rpmb_cfg));
+
+    rpmb_pkt[0] = 1;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1 << 31;
+    reverse_endian(rpmb_pkt, 512);
+    memcpy(&rpmb_pkt[RPMB_MAC_BEG], key, 32);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, sizeof(struct mmc_rpmb_cfg));
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_READ_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 0;
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    reverse_endian(rpmb_pkt, 512);
+
+    ret = ((unsigned short *)&rpmb_pkt)[2];
+
+rpmb_end:
+    free(rpmb_pkt);
+    free(idata);
+    bio_close(rpdev);
+    return ret;
+}
+
+int mmc_rpmb_block_read(int blknr, unsigned char blk[256])
+{
+    int ret;
+    bdev_t *rpdev;
+    struct mmc_ioc_cmd *idata;
+    unsigned char *rpmb_pkt;
+    unsigned char mac[RPMB_SZ_MAC];
+    unsigned char nonce[RPMB_SZ_NONCE];
+    unsigned int mac_sz = RPMB_SZ_MAC;
+    int i;
+
+    idata = malloc(sizeof(struct mmc_ioc_cmd));
+    if (idata == NULL)
+        return -2;
+    rpmb_pkt = malloc(512);
+    if (rpmb_pkt == NULL) {
+        free(idata);
+        return -2;
+    }
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+
+    rpdev = bio_open("mmc0rpmb");
+    if (rpdev == NULL) {
+        free(rpmb_pkt);
+        free(idata);
+        return -3;
+    }
+
+    /* read */
+    rpmb_pkt[0] = 4;
+    rpmb_pkt[4] = 1;
+    rpmb_pkt[6] = blknr;
+    if (trng_drv_get_random_data(nonce, RPMB_SZ_NONCE) != RPMB_SZ_NONCE)
+        return -4;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1;
+    reverse_endian(rpmb_pkt, 512);
+    memcpy(rpmb_pkt + RPMB_NONCE_BEG, nonce, RPMB_SZ_NONCE);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_READ_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 0;
+    reverse_endian(rpmb_pkt, 512);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    ret = *(unsigned short *)&rpmb_pkt[RPMB_RES_BEG];
+    reverse_endian(&ret, sizeof(short));
+    if (ret != 0)
+        goto rpmb_end;
+
+    rpmb_hmac_init(rpmb_pkt + RPMB_DATA_BEG, 512 - RPMB_DATA_BEG);
+    rpmb_hmac_done(mac, &mac_sz);
+    ret = 0;
+    for (i = 0; i < RPMB_SZ_NONCE; i++)
+        ret |= nonce[i] ^ rpmb_pkt[RPMB_NONCE_BEG + i];
+
+    if (ret != 0) {
+        ret = -5;
+        goto rpmb_end;
+    }
+    for (i = 0; i < RPMB_SZ_MAC; i++)
+        ret |= mac[i] ^ rpmb_pkt[RPMB_MAC_BEG + i];
+
+    if (ret != 0) {
+        ret = -1;
+        goto rpmb_end;
+    }
+    memcpy(blk, rpmb_pkt + RPMB_DATA_BEG, RPMB_SZ_DATA);
+    reverse_endian(blk, RPMB_SZ_DATA);
+
+rpmb_end:
+    free(rpmb_pkt);
+    free(idata);
+    bio_close(rpdev);
+    return ret;
+}
+
+int mmc_rpmb_block_write(int blknr, unsigned char blk[256])
+{
+    int ret;
+    bdev_t *rpdev;
+    struct mmc_ioc_cmd *idata;
+    unsigned char *rpmb_pkt;
+    unsigned char nonce[RPMB_SZ_NONCE];
+    unsigned int wc, mac_sz = RPMB_SZ_MAC;
+
+    idata = malloc(sizeof(struct mmc_ioc_cmd));
+    if (idata == NULL) {
+        return -2;
+    }
+    rpmb_pkt = malloc(512);
+    if (rpmb_pkt == NULL) {
+        free(idata);
+        return -2;
+    }
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+
+    rpdev = bio_open("mmc0rpmb");
+    if (rpdev == NULL) {
+        free(rpmb_pkt);
+        free(idata);
+        return -3;
+    }
+
+    /* get wc */
+    rpmb_pkt[0] = 2;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1;
+    reverse_endian(rpmb_pkt, 512);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_READ_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 0;
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    reverse_endian(rpmb_pkt, 512);
+    /* check result */
+    ret = *(unsigned short *)&rpmb_pkt[2];
+    if (ret != 0) /* get success */
+        goto rpmb_end;
+    wc = *(unsigned int *)&rpmb_pkt[8];
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+    /* do write */
+    rpmb_pkt[0] = 0x3;
+    rpmb_pkt[4] = 1;
+    rpmb_pkt[6] = blknr;
+    *(unsigned int *)&rpmb_pkt[8] = wc;
+    memcpy(rpmb_pkt + 28, blk, RPMB_SZ_DATA);
+    if (trng_drv_get_random_data(nonce, RPMB_SZ_NONCE) != RPMB_SZ_NONCE)
+        return -4;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1<<31;
+    reverse_endian(rpmb_pkt, 512);
+    memcpy(rpmb_pkt + RPMB_NONCE_BEG, nonce, RPMB_SZ_NONCE);
+    rpmb_hmac_init(rpmb_pkt + RPMB_DATA_BEG, 512 - RPMB_DATA_BEG);
+    rpmb_hmac_done(rpmb_pkt + RPMB_MAC_BEG, &mac_sz);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+    /* request to read result back */
+    rpmb_pkt[0] = 0x5;
+
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 1;
+    reverse_endian(rpmb_pkt, 512);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    memset(idata, 0, sizeof(struct mmc_ioc_cmd));
+    memset(rpmb_pkt, 0, 512);
+    /* read result back */
+    idata->flags = RESP_R1;
+    idata->opcode = MMC_CMD_READ_MULTIPLE_BLOCK;
+    idata->blksz = 512;
+    idata->blocks = 1;
+    idata->write_flag = 0;
+    reverse_endian(rpmb_pkt, 512);
+    mmc_ioc_cmd_set_data((*idata), rpmb_pkt);
+
+    ret = bio_ioctl(rpdev, MMC_IOC_CMD, idata);
+    if (ret != 0)
+        goto rpmb_end;
+
+    reverse_endian(rpmb_pkt, 512);
+    /* get result */
+    ret = *(unsigned short *)&rpmb_pkt[2];
+
+rpmb_end:
+    free(rpmb_pkt);
+    free(idata);
+    bio_close(rpdev);
+    return ret;
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/msdc.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/msdc.c
new file mode 100644
index 0000000..ff3547c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/msdc.c
@@ -0,0 +1,2153 @@
+/*
+ * 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.
+ */
+#define MSDC_DEBUG_KICKOFF
+
+#include <platform/msdc.h>
+#include <platform/mmc_core.h>
+#include <kernel/event.h>
+#include <kernel/vm.h>
+#include <platform/interrupts.h>
+#include <platform/mt_irq.h>
+#include <string.h>
+#include <assert.h>
+
+#define CMD_RETRIES        (5)
+#define CMD_TIMEOUT        (100) /* 100ms */
+
+#define PERI_MSDC_SRCSEL   (0xc100000c)
+
+/* Tuning Parameter */
+#define DEFAULT_DEBOUNCE   (8)  /* 8 cycles */
+#define DEFAULT_DTOC       (40) /* data timeout counter. 65536x40 sclk. */
+#define DEFAULT_WDOD       (0)  /* write data output delay. no delay. */
+#define DEFAULT_BSYDLY     (8)  /* card busy delay. 8 extend sclk */
+
+#define MSDC_USE_PATCH_BIT2_TURNING_WITH_ASYNC 1
+/* Declarations */
+static int msdc_send_cmd(struct mmc_host *host, struct mmc_command *cmd);
+static int msdc_wait_cmd_done(struct mmc_host *host, struct mmc_command *cmd);
+static int msdc_tune_cmdrsp(struct mmc_host *host, struct mmc_command *cmd);
+
+typedef struct {
+    int    autocmd;
+    int    rdsmpl;
+    int    wdsmpl;
+    int    rsmpl;
+    int    start_bit;
+} msdc_priv_t;
+
+static int msdc_rsp[] = {
+    0,  /* RESP_NONE */
+    1,  /* RESP_R1 */
+    2,  /* RESP_R2 */
+    3,  /* RESP_R3 */
+    4,  /* RESP_R4 */
+    1,  /* RESP_R5 */
+    1,  /* RESP_R6 */
+    1,  /* RESP_R7 */
+    7,  /* RESP_R1b */
+};
+
+struct msdc_cust {
+    unsigned char  clk_src;           /* host clock source             */
+    unsigned char  hclk_src;           /* host clock source             */
+    unsigned char  cmd_edge;          /* command latch edge            */
+    unsigned char  data_edge;         /* data latch edge               */
+#define MSDC_SMPL_RISING        (0)
+#define MSDC_SMPL_FALLING       (1)
+#define MSDC_SMPL_SEPERATE      (2)
+    unsigned char  clk_drv;           /* clock pad driving             */
+    unsigned char  cmd_drv;           /* command pad driving           */
+    unsigned char  dat_drv;           /* data pad driving              */
+    unsigned char  rst_drv;           /* reset pin pad driving         */
+    unsigned char  ds_drv;            /* ds pad driving                */
+    unsigned char  data_pins;         /* data pins                     */
+    unsigned int   data_offset;       /* data address offset           */
+    unsigned int   flags;             /* hardware capability flags     */
+#define MSDC_CD_PIN_EN      (1 << 0)  /* card detection pin is wired   */
+#define MSDC_WP_PIN_EN      (1 << 1)  /* write protection pin is wired */
+#define MSDC_RST_PIN_EN     (1 << 2)  /* emmc reset pin is wired       */
+#define MSDC_SDIO_IRQ       (1 << 3)  /* use internal sdio irq (bus)   */
+#define MSDC_EXT_SDIO_IRQ   (1 << 4)  /* use external sdio irq         */
+#define MSDC_REMOVABLE      (1 << 5)  /* removable slot                */
+#define MSDC_SYS_SUSPEND    (1 << 6)  /* suspended by system           */
+#define MSDC_HIGHSPEED      (1 << 7)  /* high-speed mode support       */
+#define MSDC_UHS1           (1 << 8)  /* uhs-1 mode support            */
+#define MSDC_DDR            (1 << 9)  /* ddr mode support              */
+#define MSDC_HS200          (1 << 10) /* hs200 mode support(eMMC4.5)   */
+#define MSDC_HS400          (1 << 11) /* hs200 mode support(eMMC5.0)   */
+} msdc_cap[2] = {
+    {
+        MSDC50_CLKSRC_DEFAULT, /* host clock source          */
+        MSDC50_CLKSRC4HCLK_273MHZ, /* host clock source          */
+        MSDC_SMPL_RISING,   /* command latch edge            */
+        MSDC_SMPL_RISING,   /* data latch edge               */
+        MSDC_DRVN_GEAR2,    /* clock pad driving             */
+        MSDC_DRVN_GEAR2,    /* command pad driving           */
+        MSDC_DRVN_GEAR2,    /* data pad driving              */
+        MSDC_DRVN_GEAR2,    /* rst pad driving               */
+        MSDC_DRVN_GEAR2,    /* ds pad driving                */
+        8,                  /* data pins                     */
+        0,                  /* data address offset           */
+#ifndef FPGA_PLATFORM
+        MSDC_HIGHSPEED | MSDC_HS200 | MSDC_HS400
+#else
+	MSDC_HIGHSPEED
+#endif
+    },
+
+    {
+        MSDC50_CLKSRC_DEFAULT, /* host clock source          */
+        MSDC50_CLKSRC4HCLK_273MHZ, /* host clock source          */
+        MSDC_SMPL_RISING,   /* command latch edge            */
+        MSDC_SMPL_RISING,   /* data latch edge               */
+        MSDC_DRVN_GEAR2,    /* clock pad driving             */
+        MSDC_DRVN_GEAR2,    /* command pad driving           */
+        MSDC_DRVN_GEAR2,    /* data pad driving              */
+        MSDC_DRVN_GEAR2,    /* rst pad driving               */
+        MSDC_DRVN_GEAR2,    /* ds pad driving                */
+        4,                  /* data pins                     */
+        0,                  /* data address offset           */
+        MSDC_HIGHSPEED
+    },
+};
+
+static event_t msdc_int_event;
+static u32 g_int_status = 0;
+static msdc_priv_t msdc_priv;
+#ifndef FPGA_PLATFORM
+static u32 hclks_msdc30[] = { 26000000, 208000000, 200000000, 156000000,
+                              182000000, 156000000, 178280000
+                            };
+#endif
+
+/* add function for MSDC_PAD_CTL handle */
+#ifndef FPGA_PLATFORM
+static void msdc_set_pin_msdc_mode(struct mmc_host *host)
+{
+	switch(host->host_id){
+	case 0:
+		MSDC_SET_FIELD(GPIO_MODE9_ADDR_MSDC0, MSDC0_CLK_MODE_MASK, 1);
+		MSDC_SET_FIELD(GPIO_MODE9_ADDR_MSDC0, MSDC0_CMD_MODE_MASK, 1);
+		MSDC_SET_FIELD(GPIO_MODE9_ADDR_MSDC0, MSDC0_RSTB_MODE_MASK, 1);
+		MSDC_SET_FIELD(GPIO_MODE9_ADDR_MSDC0, MSDC0_DAT4_MODE_MASK, 1);
+		MSDC_SET_FIELD(GPIO_MODE9_ADDR_MSDC0, MSDC0_DAT5_MODE_MASK, 1);
+		MSDC_SET_FIELD(GPIO_MODE9_ADDR_MSDC0, MSDC0_DAT6_MODE_MASK, 1);
+		MSDC_SET_FIELD(GPIO_MODE9_ADDR_MSDC0, MSDC0_DAT7_MODE_MASK, 1);
+
+		MSDC_SET_FIELD(GPIO_MODEA_ADDR_MSDC0, MSDC0_DAT0_MODE_MASK, 1);
+		MSDC_SET_FIELD(GPIO_MODEA_ADDR_MSDC0, MSDC0_DAT1_MODE_MASK, 1);
+		MSDC_SET_FIELD(GPIO_MODEA_ADDR_MSDC0, MSDC0_DAT2_MODE_MASK, 1);
+		MSDC_SET_FIELD(GPIO_MODEA_ADDR_MSDC0, MSDC0_DAT3_MODE_MASK, 1);
+		MSDC_SET_FIELD(GPIO_MODEA_ADDR_MSDC0, MSDC0_DSL_MODE_MASK, 1);
+	break;
+
+	default:
+		break;
+	}
+}
+
+void msdc_set_smt(struct mmc_host *host, int smt)
+{
+	switch(host->host_id){
+	case 0:
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC0_SMT_CLK_MASK, smt);
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC0_SMT_CMD_MASK, smt);
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC0_SMT_DAT0_MASK, smt);
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC0_SMT_DAT1_MASK, smt);
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC0_SMT_DAT2_MASK, smt);
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC0_SMT_DAT3_MASK, smt);
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC0_SMT_DAT4_MASK, smt);
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC0_SMT_DAT5_MASK, smt);
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC0_SMT_DAT6_MASK, smt);
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC0_SMT_DAT7_MASK, smt);
+		break;
+	case 1:
+		MSDC_SET_FIELD(SMT0_CFG_ADDR, MSDC1_SMT_CLK_MASK, smt);
+		MSDC_SET_FIELD(SMT0_CFG_ADDR, MSDC1_SMT_CMD_MASK, smt);
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC1_SMT_DAT3_MASK, smt);
+		MSDC_SET_FIELD(SMT1_CFG_ADDR, MSDC1_SMT_DAT2_MASK, smt);
+		MSDC_SET_FIELD(SMT0_CFG_ADDR, MSDC1_SMT_DAT1_MASK, smt);
+		MSDC_SET_FIELD(SMT0_CFG_ADDR, MSDC1_SMT_DAT0_MASK, smt);
+		break;
+	default:
+		break;
+	}
+
+}
+
+/* pull up means that host driver the line to HIGH
+ * pull down means that host driver the line to LOW */
+static void msdc_pin_set(struct mmc_host *host, MSDC_PIN_STATE mode)
+{
+    /* driver CLK/DAT pin */
+	ASSERT(host);
+	ASSERT(mode < MSDC_PST_MAX);
+
+	switch(host->host_id){
+	case 0:
+		MSDC_SET_FIELD(PUPD_CFG2_ADDR, MSDC0_PUPD_CLK_MASK, MSDC_PST_PD_50KOHM);
+		MSDC_SET_FIELD(PUPD_CFG2_ADDR, MSDC0_PUPD_CMD_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG2_ADDR, MSDC0_PUPD_DAT0_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG2_ADDR, MSDC0_PUPD_DAT1_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG2_ADDR, MSDC0_PUPD_DAT2_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG2_ADDR, MSDC0_PUPD_DAT3_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG2_ADDR, MSDC0_PUPD_DAT4_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG1_ADDR, MSDC0_PUPD_DAT5_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG1_ADDR, MSDC0_PUPD_DAT6_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG1_ADDR, MSDC0_PUPD_DAT7_MASK, mode);
+		break;
+	case 1:
+		MSDC_SET_FIELD(PUPD_CFG1_ADDR, MSDC1_PUPD_CLK_MASK, MSDC_PST_PD_50KOHM);
+		MSDC_SET_FIELD(PUPD_CFG1_ADDR, MSDC1_PUPD_CMD_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG1_ADDR, MSDC1_PUPD_DAT0_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG1_ADDR, MSDC1_PUPD_DAT1_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG1_ADDR, MSDC1_PUPD_DAT2_MASK, mode);
+		MSDC_SET_FIELD(PUPD_CFG1_ADDR, MSDC1_PUPD_DAT3_MASK, mode);
+		break;
+	default:
+		break;
+		}
+}
+
+/* host can modify from 0-7 */
+static void msdc_set_driving(struct mmc_host *host, struct msdc_cust *msdc_cap)
+{
+	u32 clkdrv, cmddrv, datdrv, dsdrv;
+
+	ASSERT(host);
+	ASSERT(msdc_cap);
+
+	clkdrv = msdc_cap->clk_drv;
+	cmddrv = msdc_cap->cmd_drv;
+	datdrv = msdc_cap->dat_drv;
+	dsdrv = msdc_cap->ds_drv;
+	if(host && msdc_cap){
+
+		switch(host->host_id){
+		case 0:
+			MSDC_SET_FIELD(DRV5_CFG_ADDR, MSDC0_DRV_DSL_MASK, dsdrv);
+			MSDC_SET_FIELD(DRV5_CFG_ADDR, MSDC0_DRV_CLK_MASK, clkdrv);
+			MSDC_SET_FIELD(DRV4_CFG_ADDR, MSDC0_DRV_CMD_MASK, cmddrv);
+			MSDC_SET_FIELD(DRV4_CFG_ADDR, MSDC0_DRV_DAT_MASK, datdrv);
+			break;
+		case 1:
+			MSDC_SET_FIELD(DRV3_CFG_ADDR, MSDC1_DRV_CLK_MASK, clkdrv);
+			MSDC_SET_FIELD(DRV3_CFG_ADDR, MSDC1_DRV_CMD_MASK, cmddrv);
+			MSDC_SET_FIELD(DRV3_CFG_ADDR, MSDC1_DRV_DAT_MASK, datdrv);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+#endif
+
+#ifndef FPGA_PLATFORM /* don't power on/off device and use power-on default volt */
+/* set to 3.3V */
+static void sd_card_vccq_on(void)
+{
+	/* wait to implement on MT8133 EVB */
+}
+
+static int pmic_config_interface(int a, int b, int c, int d)
+{
+    return 0;
+}
+
+static void msdc_set_card_pwr(struct mmc_host *host, int on)
+{
+    unsigned int ret;
+
+    ret = pmic_config_interface(0xAB,0x7,0x7,4); /* VMCH=3.3V */
+
+    if (ret == 0) {
+        if (on) {
+            ret = pmic_config_interface(0xAB,0x1,0x1,0); /* VMCH_EN=1 */
+        } else {
+            ret = pmic_config_interface(0xAB,0x0,0x1,0); /* VMCH_EN=0 */
+        }
+    }
+
+    if (ret != 0) {
+        dprintf(CRITICAL, "PMIC: Set MSDC Host Power Fail\n");
+    } else {
+        spin(3000);
+    }
+}
+
+static void msdc_set_host_pwr(struct mmc_host *host, int on)
+{
+    unsigned int ret;
+
+    ret = pmic_config_interface(0xA7,0x7,0x7,4); /* VMC=3.3V */
+
+    if (ret == 0) {
+        if (on) {
+            ret = pmic_config_interface(0xA7,0x1,0x1,0); /* VMC_EN=1 */
+        } else {
+            ret = pmic_config_interface(0xA7,0x0,0x1,0); /* VMC_EN=0 */
+        }
+    }
+
+    if (ret != 0) {
+        dprintf(CRITICAL, "PMIC: Set MSDC Card Power Fail\n");
+    }
+}
+#else
+#define PWR_GPIO            (0x10001E84)
+#define PWR_GPIO_EO         (0x10001E88)
+
+#define PWR_MASK_EN         (0x1 << 8)
+#define PWR_MASK_VOL_18     (0x1 << 9)
+#define PWR_MASK_VOL_33     (0x1 << 10)
+#define PWR_MASK_L4         (0x1 << 11)
+#define PWR_MSDC_DIR        (PWR_MASK_EN | PWR_MASK_VOL_18 | PWR_MASK_VOL_33 | PWR_MASK_L4)
+
+#define MSDC0_PWR_MASK_EN         (0x1 << 12)
+#define MSDC0_PWR_MASK_VOL_18     (0x1 << 13)
+#define MSDC0_PWR_MASK_VOL_33     (0x1 << 14)
+#define MSDC0_PWR_MASK_L4         (0x1 << 15)
+#define MSDC0_PWR_MSDC_DIR        (MSDC0_PWR_MASK_EN | MSDC0_PWR_MASK_VOL_18 | MSDC0_PWR_MASK_VOL_33 | MSDC0_PWR_MASK_L4)
+
+static void msdc_clr_gpio(u32 bits)
+{
+    switch (bits) {
+        case MSDC0_PWR_MASK_EN:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_EN),0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_EN),0);
+            break;
+        case MSDC0_PWR_MASK_VOL_18:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+            break;
+        case MSDC0_PWR_MASK_VOL_33:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 0);
+            break;
+        case MSDC0_PWR_MASK_L4:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    MSDC0_PWR_MASK_L4, 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, MSDC0_PWR_MASK_L4, 0);
+            break;
+        case PWR_MASK_EN:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_EN,0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_EN,0);
+            break;
+        case PWR_MASK_VOL_18:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+            break;
+        case PWR_MASK_VOL_33:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 0);
+            break;
+        case PWR_MASK_L4:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_L4, 0);
+            MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_L4, 0);
+            break;
+        default:
+            dprintf(CRITICAL, "[%s:%d]invalid value: 0x%x\n", __FILE__, __LINE__, bits);
+            break;
+    }
+}
+
+static void msdc_set_gpio(u32 bits)
+{
+    switch (bits) {
+        case MSDC0_PWR_MASK_EN:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    MSDC0_PWR_MASK_EN,1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, MSDC0_PWR_MASK_EN,1);
+            break;
+        case MSDC0_PWR_MASK_VOL_18:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 1);
+            break;
+        case MSDC0_PWR_MASK_VOL_33:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 2);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (MSDC0_PWR_MASK_VOL_18|MSDC0_PWR_MASK_VOL_33), 2);
+            break;
+        case MSDC0_PWR_MASK_L4:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    MSDC0_PWR_MASK_L4, 1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, MSDC0_PWR_MASK_L4, 1);
+            break;
+        case PWR_MASK_EN:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_EN,1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_EN,1);
+            break;
+        case PWR_MASK_VOL_18:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 1);
+            break;
+        case PWR_MASK_VOL_33:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 2);
+            MSDC_SET_FIELD(PWR_GPIO_EO, (PWR_MASK_VOL_18|PWR_MASK_VOL_33), 2);
+            break;
+        case PWR_MASK_L4:
+            /* check for set before */
+            MSDC_SET_FIELD(PWR_GPIO,    PWR_MASK_L4, 1);
+            MSDC_SET_FIELD(PWR_GPIO_EO, PWR_MASK_L4, 1);
+            break;
+        default:
+            dprintf(CRITICAL, "[%s:%s]invalid value: 0x%x\n", __FILE__, __func__, bits);
+            break;
+    }
+}
+
+static void msdc_set_card_pwr(struct mmc_host *host, int on)
+{
+    if (on) {
+        msdc_set_gpio(MSDC0_PWR_MASK_VOL_18);
+        msdc_set_gpio(MSDC0_PWR_MASK_L4);
+        msdc_set_gpio(MSDC0_PWR_MASK_EN);
+    } else {
+        msdc_clr_gpio(MSDC0_PWR_MASK_EN);
+        msdc_clr_gpio(MSDC0_PWR_MASK_VOL_18);
+        msdc_clr_gpio(MSDC0_PWR_MASK_L4);
+    }
+    spin(10000);
+}
+
+static void msdc_set_host_level_pwr(struct mmc_host *host, u32 level)
+{
+    msdc_clr_gpio(PWR_MASK_VOL_18);
+    msdc_clr_gpio(PWR_MASK_VOL_33);
+
+    if (level) {
+        msdc_set_gpio(PWR_MASK_VOL_18);
+    } else {
+        msdc_set_gpio(PWR_MASK_VOL_33);
+    }
+    msdc_set_gpio(PWR_MASK_L4);
+}
+
+static void msdc_set_host_pwr(struct mmc_host *host, int on)
+{
+    msdc_set_host_level_pwr(host, 0);
+}
+#endif
+
+static void msdc_set_startbit(struct mmc_host *host, u8 start_bit)
+{
+    addr_t base = host->base;
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+
+    /* set start bit */
+    MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_START_BIT, start_bit);
+    priv->start_bit = start_bit;
+    dprintf(INFO, "start bit = %d, MSDC_CFG[0x%x]\n", start_bit, MSDC_READ32(MSDC_CFG));
+}
+
+#define TYPE_CMD_RESP_EDGE      (0)
+#define TYPE_WRITE_CRC_EDGE     (1)
+#define TYPE_READ_DATA_EDGE     (2)
+#define TYPE_WRITE_DATA_EDGE    (3)
+
+static void msdc_set_smpl(struct mmc_host *host, u8 HS400, u8 mode, u8 type)
+{
+    addr_t base = host->base;
+    int i=0;
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+    static u8 read_data_edge[8] = {MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING,
+                                   MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING
+                                  };
+    static u8 write_data_edge[4] = {MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING, MSDC_SMPL_RISING};
+
+    switch (type) {
+        case TYPE_CMD_RESP_EDGE:
+            if (HS400) {
+                // eMMC5.0 only output resp at CLK pin, so no need to select DS pin
+                MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_PADCMD_LATCHCK, 0); //latch cmd resp at CLK pin
+                MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CMD_RESP_SEL, 0);//latch cmd resp at CLK pin
+            }
+
+            if (mode == MSDC_SMPL_RISING || mode == MSDC_SMPL_FALLING) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, mode);
+                priv->rsmpl = mode;
+            } else {
+                dprintf(CRITICAL, "[%s]: invalid resp parameter: HS400=%d, type=%d, mode=%d\n", __func__, HS400, type, mode);
+            }
+            break;
+
+        case TYPE_WRITE_CRC_EDGE:
+            if (HS400) {
+                MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_SEL, 1);//latch write crc status at DS pin
+            } else {
+                MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_SEL, 0);//latch write crc status at CLK pin
+            }
+
+            if (mode == MSDC_SMPL_RISING || mode == MSDC_SMPL_FALLING) {
+                if (HS400) {
+                    MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_EDGE, mode);
+                } else {
+                    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL_SEL, 0);
+                    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL, mode);
+                }
+                priv->wdsmpl = mode;
+            } else if (mode == MSDC_SMPL_SEPERATE && !HS400) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D0SPL, write_data_edge[0]); //only dat0 is for write crc status.
+                priv->wdsmpl = mode;
+            } else {
+                dprintf(CRITICAL, "[%s]: invalid crc parameter: HS400=%d, type=%d, mode=%d\n", __func__, HS400, type, mode);
+            }
+            break;
+
+        case TYPE_READ_DATA_EDGE:
+            if (HS400) {
+                msdc_set_startbit(host, START_AT_RISING_AND_FALLING); //for HS400, start bit is output both on rising and falling edge
+                priv->start_bit = START_AT_RISING_AND_FALLING;
+            } else {
+                msdc_set_startbit(host, START_AT_RISING); //for the other mode, start bit is only output on rising edge. but DDR50 can try falling edge if error casued by pad delay
+                priv->start_bit = START_AT_RISING;
+            }
+            if (mode == MSDC_SMPL_RISING || mode == MSDC_SMPL_FALLING) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL_SEL, 0);
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL, mode);
+                priv->rdsmpl = mode;
+            } else if (mode == MSDC_SMPL_SEPERATE) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL_SEL, 1);
+                for (i=0; i<8; i++) {
+                    MSDC_SET_FIELD(MSDC_IOCON, (MSDC_IOCON_R_D0SPL << i), read_data_edge[i]);
+                }
+                priv->rdsmpl = mode;
+            } else {
+                dprintf(CRITICAL, "[%s]: invalid read parameter: HS400=%d, type=%d, mode=%d\n", __func__, HS400, type, mode);
+            }
+            break;
+
+        case TYPE_WRITE_DATA_EDGE:
+            MSDC_SET_FIELD(EMMC50_CFG0, MSDC_EMMC50_CFG_CRC_STS_SEL, 0);//latch write crc status at CLK pin
+
+            if (mode == MSDC_SMPL_RISING|| mode == MSDC_SMPL_FALLING) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL_SEL, 0);
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL, mode);
+                priv->wdsmpl = mode;
+            } else if (mode == MSDC_SMPL_SEPERATE) {
+                MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_W_D_SMPL_SEL, 1);
+                for (i=0; i<4; i++) {
+                    MSDC_SET_FIELD(MSDC_IOCON, (MSDC_IOCON_W_D0SPL << i), write_data_edge[i]);//dat0~4 is for SDIO card.
+                }
+                priv->wdsmpl = mode;
+            } else {
+                dprintf(CRITICAL, "[%s]: invalid write parameter: HS400=%d, type=%d, mode=%d\n", __func__, HS400, type, mode);
+            }
+            break;
+
+        default:
+            dprintf(CRITICAL, "[%s]: invalid parameter: HS400=%d, type=%d, mode=%d\n", __func__, HS400, type, mode);
+            break;
+    }
+}
+
+void msdc_set_timeout(struct mmc_host *host, u32 ns, u32 clks)
+{
+    addr_t base = host->base;
+    u32 timeout, clk_ns;
+    u32 mode = 0;
+
+    if (host->sclk == 0) {
+        timeout = 0;
+    } else {
+        clk_ns  = 1000000000UL / host->sclk;
+        timeout = (ns + clk_ns - 1) / clk_ns + clks;
+        timeout = (timeout + (1 << 20) - 1) >> 20; /* in 1048576 sclk cycle unit */
+        MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, mode);
+        timeout = mode >= 2 ? timeout * 2 : timeout; //DDR mode will double the clk cycles for data timeout
+        timeout = timeout > 1 ? timeout - 1 : 0;
+        timeout = timeout > 255 ? 255 : timeout;
+    }
+    MSDC_SET_FIELD(SDC_CFG, SDC_CFG_DTOC, timeout);
+    dprintf(INFO, "[MSDC] Set read data timeout: %dns %dclks -> %d (65536 sclk cycles)\n",
+            ns, clks, timeout + 1);
+}
+
+void msdc_set_autocmd(struct mmc_host *host, int cmd)
+{
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+
+    priv->autocmd = cmd;
+}
+
+int msdc_get_autocmd(struct mmc_host *host)
+{
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+
+    return priv->autocmd;
+}
+
+static void msdc_abort(struct mmc_host *host)
+{
+    addr_t base = host->base;
+
+    dprintf(CRITICAL, "[MSDC] Abort: MSDC_FIFOCS=%xh MSDC_PS=%xh SDC_STS=%xh\n",
+            MSDC_READ32(MSDC_FIFOCS), MSDC_READ32(MSDC_PS), MSDC_READ32(SDC_STS));
+    /* reset controller */
+    MSDC_RESET();
+
+    /* clear fifo */
+    MSDC_CLR_FIFO();
+
+    /* make sure txfifo and rxfifo are empty */
+    if (MSDC_TXFIFOCNT() != 0 || MSDC_RXFIFOCNT() != 0) {
+        dprintf(INFO, "[MSDC] Abort: TXFIFO(%d), RXFIFO(%d) != 0\n",
+                MSDC_TXFIFOCNT(), MSDC_RXFIFOCNT());
+    }
+
+    /* clear all interrupts */
+    MSDC_CLR_INT();
+}
+
+static int msdc_get_card_status(struct mmc_host *host, u32 *status)
+{
+    int err;
+    struct mmc_command cmd;
+
+    cmd.opcode  = MMC_CMD_SEND_STATUS;
+    cmd.arg     = host->card->rca << 16;
+    cmd.rsptyp  = RESP_R1;
+    cmd.retries = CMD_RETRIES;
+    cmd.timeout = CMD_TIMEOUT;
+
+    err = msdc_send_cmd(host, &cmd);
+    if (!err)
+        err = msdc_wait_cmd_done(host, &cmd);
+
+    if (err == MMC_ERR_NONE)
+        *status = cmd.resp[0];
+
+    return err;
+}
+
+int msdc_abort_handler(struct mmc_host *host, int abort_card)
+{
+    struct mmc_command stop;
+    u32 status = 0;
+    u32 state = 0;
+
+    while (state != 4) { // until status to "tran"
+        msdc_abort(host);
+        if (msdc_get_card_status(host, &status)) {
+            dprintf(CRITICAL, "Get card status failed\n");
+            return 1;
+        }
+        state = R1_CURRENT_STATE(status);
+        dprintf(INFO, "check card state<%d>\n", state);
+        if (state == 5 || state == 6) {
+            dprintf(INFO, "state<%d> need cmd12 to stop\n", state);
+            if (abort_card) {
+                stop.opcode  = MMC_CMD_STOP_TRANSMISSION;
+                stop.rsptyp  = RESP_R1B;
+                stop.arg     = 0;
+                stop.retries = CMD_RETRIES;
+                stop.timeout = CMD_TIMEOUT;
+                msdc_send_cmd(host, &stop);
+                msdc_wait_cmd_done(host, &stop); // don't tuning
+            } else if (state == 7) {  // busy in programing
+                dprintf(INFO, "state<%d> card is busy\n", state);
+                spin(100000);
+            } else if (state != 4) {
+                dprintf(INFO, "state<%d> ??? \n", state);
+                return 1;
+            }
+        }
+    }
+    msdc_abort(host);
+    return 0;
+}
+
+static u32 msdc_intr_wait(struct mmc_host *host, u32 intrs)
+{
+    u32 sts = 0;
+    u32 tmo = UINT_MAX;
+    int ret = 0;
+
+#if 1
+    /* warning that interrupts are not enabled */
+    ret = event_wait_timeout(&msdc_int_event, tmo);
+    if (ret != 0) {
+        addr_t base = host->base;
+        dprintf(CRITICAL, "[%s]: failed to get event INT=0x%x\n",
+                __func__, MSDC_READ32(MSDC_INT));
+        g_int_status = 0;
+        return 0;
+    }
+#else
+    /* use polling way */
+    addr_t base = host->base;
+    u32 int_en = MSDC_READ32(MSDC_INTEN);
+    while (1) {
+	g_int_status = MSDC_READ32(MSDC_INT);
+	if (g_int_status & int_en) {
+		MSDC_WRITE32(MSDC_INT, g_int_status & host->intr_mask);
+		MSDC_WRITE32(MSDC_INTEN, 0);
+		break;
+
+	}
+    }
+#endif
+
+    sts = g_int_status;
+    g_int_status = 0;
+
+    if (~intrs & sts)
+        dprintf(CRITICAL, "[MSDC]<CHECKME> Unexpected INT(0x%x)\n", ~intrs & sts);
+
+    return sts;
+}
+
+static enum handler_return msdc_interrupt_handler(void *arg)
+{
+    struct mmc_host *host = arg;
+    addr_t base = host->base;
+
+    /* Save & Clear the interrupt */
+    g_int_status = MSDC_READ32(MSDC_INT);
+    MSDC_WRITE32(MSDC_INT, g_int_status & host->intr_mask);
+    MSDC_WRITE32(MSDC_INTEN, 0);
+    host->intr_mask = 0;
+
+    /* MUST BE *false*! otherwise, schedule in interrupt */
+    event_signal(&msdc_int_event, false);
+
+    return INT_RESCHEDULE;
+}
+
+static int msdc_send_cmd(struct mmc_host *host, struct mmc_command *cmd)
+{
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+    addr_t base   = host->base;
+    u32 opcode = cmd->opcode;
+    u32 rsptyp = cmd->rsptyp;
+    u32 rawcmd;
+    u32 error = MMC_ERR_NONE;
+
+    /* rawcmd :
+     * vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 |
+     * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode
+     */
+    rawcmd = (opcode & ~(SD_CMD_BIT | SD_CMD_APP_BIT)) |
+             msdc_rsp[rsptyp] << 7 | host->blklen << 16;
+
+    if (opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
+        rawcmd |= ((2 << 11) | (1 << 13));
+        if (priv->autocmd & MSDC_AUTOCMD12) {
+            rawcmd |= (1 << 28);
+        } else if (priv->autocmd & MSDC_AUTOCMD23) {
+            rawcmd |= (2 << 28);
+        }
+    } else if (opcode == MMC_CMD_WRITE_BLOCK || opcode == MMC_CMD50) {
+        rawcmd |= ((1 << 11) | (1 << 13));
+    } else if (opcode == MMC_CMD_READ_MULTIPLE_BLOCK) {
+        rawcmd |= (2 << 11);
+        if (priv->autocmd & MSDC_AUTOCMD12) {
+            rawcmd |= (1 << 28);
+        } else if (priv->autocmd & MSDC_AUTOCMD23) {
+            rawcmd |= (2 << 28);
+        }
+    } else if (opcode == MMC_CMD_READ_SINGLE_BLOCK ||
+               opcode == SD_ACMD_SEND_SCR ||
+               opcode == SD_CMD_SWITCH ||
+               opcode == MMC_CMD_SEND_EXT_CSD ||
+               opcode == MMC_CMD_SEND_WRITE_PROT ||
+               opcode == MMC_CMD_SEND_WRITE_PROT_TYPE ||
+               opcode == MMC_CMD21) {
+        rawcmd |= (1 << 11);
+    } else if (opcode == MMC_CMD_STOP_TRANSMISSION) {
+        rawcmd |= (1 << 14);
+        rawcmd &= ~(0x0FFF << 16);
+    } else if (opcode == SD_IO_RW_EXTENDED) {
+        if (cmd->arg & 0x80000000)  /* R/W flag */
+            rawcmd |= (1 << 13);
+        if ((cmd->arg & 0x08000000) && ((cmd->arg & 0x1FF) > 1))
+            rawcmd |= (2 << 11); /* multiple block mode */
+        else
+            rawcmd |= (1 << 11);
+    } else if (opcode == SD_IO_RW_DIRECT) {
+        if ((cmd->arg & 0x80000000) && ((cmd->arg >> 9) & 0x1FFFF))/* I/O abt */
+            rawcmd |= (1 << 14);
+    } else if (opcode == SD_CMD_VOL_SWITCH) {
+        rawcmd |= (1 << 30);
+    } else if (opcode == SD_CMD_SEND_TUNING_BLOCK) {
+        rawcmd |= (1 << 11); /* CHECKME */
+        if (priv->autocmd & MSDC_AUTOCMD19)
+            rawcmd |= (3 << 28);
+    } else if (opcode == MMC_CMD_GO_IRQ_STATE) {
+        rawcmd |= (1 << 15);
+    } else if (opcode == MMC_CMD_WRITE_DAT_UNTIL_STOP) {
+        rawcmd |= ((1<< 13) | (3 << 11));
+    } else if (opcode == MMC_CMD_READ_DAT_UNTIL_STOP) {
+        rawcmd |= (3 << 11);
+    }
+
+    dprintf(INFO, "+[MSDC%d] CMD(%d): ARG(0x%x), RAW(0x%x), BLK_NUM(0x%x) RSP(%d)\n",host->host_id,
+            (opcode & ~(SD_CMD_BIT | SD_CMD_APP_BIT)), cmd->arg, rawcmd,
+            MSDC_READ32(SDC_BLK_NUM), rsptyp);
+
+    while (SDC_IS_CMD_BUSY());
+    if ((rsptyp == RESP_R1B) || (opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK) ||
+            opcode == MMC_CMD_WRITE_BLOCK || opcode == MMC_CMD_READ_MULTIPLE_BLOCK ||
+            opcode == MMC_CMD_READ_SINGLE_BLOCK)
+        while (SDC_IS_BUSY());
+
+    SDC_SEND_CMD(rawcmd, cmd->arg);
+
+end:
+    cmd->error = error;
+
+    return error;
+}
+
+static int msdc_wait_cmd_done(struct mmc_host *host, struct mmc_command *cmd)
+{
+    addr_t base   = host->base;
+    u32 rsptyp = cmd->rsptyp;
+    u32 status;
+    u32 opcode = (cmd->opcode & ~(SD_CMD_BIT | SD_CMD_APP_BIT));
+    u32 error = MMC_ERR_NONE;
+    u32 wints = MSDC_INT_CMDTMO | MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR |
+                MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO;
+    u32 *resp = &cmd->resp[0];
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+
+    while (1) {
+        /* Wait for interrupt coming */
+        while (((status = MSDC_READ32(MSDC_INT)) & wints) == 0);
+        MSDC_WRITE32(MSDC_INT, (status & wints));
+        if (~wints & status)
+            dprintf(CRITICAL, "[MSDC]<CHECKME> Unexpected INT(0x%x)\n",
+                    ~wints & status);
+
+        if (status & MSDC_INT_CMDRDY)
+            break;
+        else if (status & MSDC_INT_RSPCRCERR) {
+            if (opcode != MMC_CMD21)
+                dprintf(CRITICAL, "[MSDC] cmd%d CRCERR! (0x%x)\n", opcode, status);
+            error = MMC_ERR_BADCRC;
+            goto err;
+        } else if (status & MSDC_INT_CMDTMO) {
+            dprintf(CRITICAL, "[MSDC] cmd%d TMO! (0x%x)\n", opcode, status);
+            error = MMC_ERR_TIMEOUT;
+            goto err;
+        } else if (priv->autocmd & MSDC_AUTOCMD23) {
+            if (status & MSDC_INT_ACMDRDY)
+                /* Autocmd rdy is set prior to cmd rdy */
+                continue;
+            else if (status & MSDC_INT_ACMDCRCERR) {
+                dprintf(CRITICAL, "[MSDC] autocmd23 CRCERR! (0x%x)\n", status);
+                error = MMC_ERR_ACMD_RSPCRC;
+                goto err;
+            } else if (status & MSDC_INT_ACMDTMO) {
+                dprintf(CRITICAL, "[MSDC] autocmd23 TMO! (0x%x)\n", status);
+                error = MMC_ERR_ACMD_TIMEOUT;
+                goto err;
+            }
+        } else {
+            dprintf(CRITICAL, "[MSDC] cmd%d UNEXPECT status! (0x%x)\n",
+                    opcode, status);
+            error = MMC_ERR_UNEXPECT;
+            goto err;
+        }
+    }
+
+    switch (rsptyp) {
+        case RESP_NONE:
+            dprintf(INFO, "-[MSDC] CMD(%d): RSP(%d)\n",
+                    opcode, rsptyp);
+            break;
+        case RESP_R2:
+            *resp++ = MSDC_READ32(SDC_RESP3);
+            *resp++ = MSDC_READ32(SDC_RESP2);
+            *resp++ = MSDC_READ32(SDC_RESP1);
+            *resp++ = MSDC_READ32(SDC_RESP0);
+            dprintf(INFO, "-[MSDC] CMD(%d): RSP(%d) = 0x%x 0x%x 0x%x 0x%x\n",
+                    opcode, cmd->rsptyp, cmd->resp[0], cmd->resp[1],
+                    cmd->resp[2], cmd->resp[3]);
+            break;
+        default: /* Response types 1, 3, 4, 5, 6, 7(1b) */
+            cmd->resp[0] = MSDC_READ32(SDC_RESP0);
+            dprintf(INFO, "-[MSDC] CMD(%d): RSP(%d) = 0x%x\n",
+                    opcode, cmd->rsptyp, cmd->resp[0]);
+            break;
+    }
+
+err:
+    if (rsptyp == RESP_R1B)
+        while ((MSDC_READ32(MSDC_PS) & MSDC_PS_DAT0) != MSDC_PS_DAT0);
+
+    cmd->error = error;
+
+    return error;
+}
+
+int msdc_cmd(struct mmc_host *host, struct mmc_command *cmd)
+{
+    int err;
+
+    err = msdc_send_cmd(host, cmd);
+    if (err != MMC_ERR_NONE)
+        return err;
+
+    err = msdc_wait_cmd_done(host, cmd);
+
+    /*
+     * For CMD21 resp CRC error, sitll need receive data, so MUST not
+     * clear fifo or do host reset
+     */
+    if (err && cmd->opcode != MMC_CMD21) {
+        addr_t base = host->base;
+        u32 tmp = MSDC_READ32(SDC_CMD);
+
+        /* check if data is used by the command or not */
+        if (tmp & SDC_CMD_DTYP) {
+            if (msdc_abort_handler(host, 1)) {
+                dprintf(CRITICAL, "[MSDC] abort failed\n");
+            }
+        }
+
+        if (cmd->opcode == MMC_CMD_APP_CMD ||
+                cmd->opcode == SD_CMD_SEND_IF_COND) {
+            if (err ==  MMC_ERR_TIMEOUT)
+                return err;
+        }
+
+        err = msdc_tune_cmdrsp(host, cmd);
+    }
+
+    return err;
+}
+
+#ifdef MSDC_USE_DMA_MODE
+static void msdc_flush_membuf(void *buf, u32 len)
+{
+    arch_clean_invalidate_cache_range((addr_t)buf,len);
+}
+
+static int msdc_dma_wait_done(struct mmc_host *host, struct mmc_command *cmd)
+{
+    addr_t base = host->base;
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+    u32 status;
+    u32 error = MMC_ERR_NONE;
+    u32 wints = MSDC_INT_XFER_COMPL | MSDC_INT_DATTMO | MSDC_INT_DATCRCERR |
+                MSDC_INT_DXFER_DONE | MSDC_INT_DMAQ_EMPTY |
+                MSDC_INT_ACMDRDY | MSDC_INT_ACMDTMO | MSDC_INT_ACMDCRCERR |
+                MSDC_INT_CMDRDY | MSDC_INT_CMDTMO | MSDC_INT_RSPCRCERR;
+
+    /* Deliver it to irq handler */
+    host->intr_mask = wints;
+
+    do {
+        status = msdc_intr_wait(host, wints);
+
+        if (status & MSDC_INT_XFER_COMPL) {
+            if (mmc_op_multi(cmd->opcode) && (priv->autocmd & MSDC_AUTOCMD12)) {
+                /* acmd rdy should be checked after xfer_done been held */
+                if (status & MSDC_INT_ACMDRDY) {
+                    break;
+                } else if (status & MSDC_INT_ACMDTMO) {
+                    dprintf(CRITICAL, "[MSDC] ACMD12 timeout(%xh)\n", status);
+                    error = MMC_ERR_ACMD_TIMEOUT;
+                    goto end;
+                } else if (status & MSDC_INT_ACMDCRCERR) {
+                    dprintf(CRITICAL, "[MSDC] ACMD12 CRC error(%xh)\n", status);
+                    error = MMC_ERR_ACMD_RSPCRC;
+                    goto end;
+                }
+            } else
+                break;
+        }
+
+        if (status == 0 || status & MSDC_INT_DATTMO) {
+            dprintf(CRITICAL, "[MSDC] DMA DAT timeout(%xh)\n", status);
+            error = MMC_ERR_TIMEOUT;
+            goto end;
+        } else if (status & MSDC_INT_DATCRCERR) {
+		if (cmd->opcode != MMC_CMD21)
+			dprintf(CRITICAL, "[MSDC] DMA DAT CRC error(%xh)\n", status);
+            error = MMC_ERR_BADCRC;
+            goto end;
+        } else {
+            dprintf(CRITICAL, "[MSDC] Unexpect status(0x%x)\n", status);
+            error = MMC_ERR_UNEXPECT;
+            goto end;
+        }
+    } while (1);
+
+end:
+    if (error)
+        MSDC_RESET();
+
+    return error;
+}
+
+int msdc_dma_transfer(struct mmc_host *host, struct mmc_data *data)
+{
+    addr_t base = host->base;
+    int err;
+    paddr_t pa;
+
+    /* Set dma timeout */
+    msdc_set_timeout(host, data->timeout * 1000000, 0);
+    /* DRAM address */
+#if WITH_KERNEL_VM
+    pa = kvaddr_to_paddr(data->buf);
+#else
+    pa = (paddr_t)(data->buf);
+#endif
+    if (sizeof(pa) > 4)
+        dprintf(INFO, "[MSDC] WARN: 64bit physical address!\n");
+    MSDC_WRITE32(MSDC_DMA_SA, (u32)pa);
+    MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_BURSTSZ, MSDC_DMA_BURST_64B);
+    /* BASIC_DMA mode */
+    MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 0);
+    /* This is the last buffer */
+    MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_LASTBUF, 1);
+    /* Total transfer size */
+    MSDC_WRITE32(MSDC_DMA_LEN, data->blks * host->blklen);
+    /* Set interrupts bit */
+    MSDC_SET_BIT32(MSDC_INTEN,
+                   MSDC_INT_XFER_COMPL | MSDC_INT_DATTMO | MSDC_INT_DATCRCERR);
+    /* Clean & Invalidate cache */
+    msdc_flush_membuf(data->buf, data->blks * host->blklen);
+    /* Trigger DMA start */
+    MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1);
+    /* wait DMA transferring done */
+    err = msdc_dma_wait_done(host, data->cmd);
+    msdc_flush_membuf(data->buf, data->blks * host->blklen);
+    if (err) {
+	    /*
+	     * We do not want print out error logs of CMD21, As it may
+	     * let user confused.
+	     */
+	    if (data->cmd->opcode == MMC_CMD21) {
+		    /* reset controller */
+		    MSDC_RESET();
+
+		    /* clear fifo */
+		    MSDC_CLR_FIFO();
+
+		    /* make sure txfifo and rxfifo are empty */
+		    if (MSDC_TXFIFOCNT() != 0 || MSDC_RXFIFOCNT() != 0) {
+			    dprintf(INFO, "[MSDC] Abort: TXFIFO(%d), RXFIFO(%d) != 0\n",
+					    MSDC_TXFIFOCNT(), MSDC_RXFIFOCNT());
+		    }
+
+		    /* clear all interrupts */
+		    MSDC_CLR_INT();
+
+	    } else {
+		    dprintf(CRITICAL, "[MSDC] DMA failed! err(%d)\n", err);
+		    if (msdc_abort_handler(host, 1)) {
+			    dprintf(CRITICAL, "[MSDC] eMMC cannot back to TRANS mode!\n");
+			    return MMC_ERR_FAILED;
+		    }
+	    }
+    }
+
+    /* Check DMA status and stop DMA transfer */
+    MSDC_SET_FIELD(MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 1);
+    while (MSDC_READ32(MSDC_DMA_CFG) & MSDC_DMA_CFG_STS);
+
+    return err;
+}
+
+static int msdc_dma_rw(struct mmc_host *host, u8 *buf, u32 blkaddr, u32 nblks, bool rd)
+{
+    int multi, err;
+    struct mmc_command cmd;
+    struct mmc_data data;
+    addr_t base = host->base;
+
+    ASSERT(nblks <= host->max_phys_segs);
+
+    dprintf(INFO, "[MSDC] %s data %d blks %s 0x%x\n",
+            rd ? "Read" : "Write", nblks, rd ? "from" : "to", blkaddr);
+
+    multi = nblks > 1 ? 1 : 0;
+    /* DMA and block number _MUST_BE_ set prior to issuing command */
+    MSDC_DMA_ON;
+    MSDC_WRITE32(SDC_BLK_NUM, nblks);
+
+    /* send read command */
+    if (rd)
+        cmd.opcode =
+            multi ? MMC_CMD_READ_MULTIPLE_BLOCK : MMC_CMD_READ_SINGLE_BLOCK;
+    else
+        cmd.opcode = multi ? MMC_CMD_WRITE_MULTIPLE_BLOCK : MMC_CMD_WRITE_BLOCK;
+    cmd.arg = blkaddr;
+    cmd.rsptyp  = RESP_R1;
+    cmd.retries = 0;
+    cmd.timeout = CMD_TIMEOUT;
+
+    err = msdc_cmd(host, &cmd);
+    if (err != MMC_ERR_NONE)
+        return err;
+
+    data.cmd = &cmd;
+    data.blks = nblks;
+    data.buf = buf;
+    if (rd)
+        data.timeout = 100;
+    else
+        data.timeout = 250;
+
+    err = msdc_dma_transfer(host, &data);
+    MSDC_DMA_OFF;
+
+    return err;
+}
+
+static int msdc_dma_bread(struct mmc_host *host, u8 *dst, u32 src, u32 nblks)
+{
+    return msdc_dma_rw(host, dst, src, nblks, true);
+}
+
+static int msdc_dma_bwrite(struct mmc_host *host, u32 dst, u8 *src, u32 nblks)
+{
+    return msdc_dma_rw(host, src, dst, nblks, false);
+}
+#else
+int msdc_pio_read_word(struct mmc_host *host, u32 *ptr, u32 size)
+{
+    int err = MMC_ERR_NONE;
+    addr_t base = host->base;
+    u32 ints = MSDC_INT_DATCRCERR | MSDC_INT_DATTMO | MSDC_INT_XFER_COMPL;
+    //u32 timeout = 100000;
+    u32 status;
+    u32 totalsz = size;
+    u8  done = 0;
+    u8 *u8ptr;
+    u32 dcrc=0;
+
+    while (1) {
+        status = MSDC_READ32(MSDC_INT);
+        MSDC_WRITE32(MSDC_INT, status);
+        if (status & ~ints)
+            dprintf(CRITICAL, "[MSDC]<CHECKME> Unexpected INT(0x%x)\n", status);
+        if (status & MSDC_INT_DATCRCERR) {
+            MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+            dprintf(CRITICAL, "[MSDC] DAT CRC error (0x%x), Left:%d/%d bytes, RXFIFO:%d,dcrc:0x%x\n",
+                    status, size, totalsz, MSDC_RXFIFOCNT(),dcrc);
+            err = MMC_ERR_BADCRC;
+            break;
+        } else if (status & MSDC_INT_DATTMO) {
+            dprintf(CRITICAL, "[MSDC] DAT TMO error (0x%x), Left: %d/%d bytes, RXFIFO:%d\n",
+                    status, size, totalsz, MSDC_RXFIFOCNT());
+            err = MMC_ERR_TIMEOUT;
+            break;
+        } else if (status & MSDC_INT_ACMDCRCERR) {
+            MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+            dprintf(CRITICAL, "[MSDC] AUTOCMD CRC error (0x%x), Left:%d/%d bytes, RXFIFO:%d,dcrc:0x%x\n",
+                    status, size, totalsz, MSDC_RXFIFOCNT(),dcrc);
+            err = MMC_ERR_ACMD_RSPCRC;
+            break;
+        } else if (status & MSDC_INT_XFER_COMPL) {
+            done = 1;
+        }
+
+        if (size == 0 && done)
+            break;
+
+        /* Note. RXFIFO count would be aligned to 4-bytes alignment size */
+        if ((size >=  MSDC_FIFO_THD) && (MSDC_RXFIFOCNT() >= MSDC_FIFO_THD)) {
+            int left = MSDC_FIFO_THD >> 2;
+            do {
+                *ptr++ = MSDC_FIFO_READ32();
+            } while (--left);
+            size -= MSDC_FIFO_THD;
+            dprintf(INFO, "[MSDC] Read %d bytes, RXFIFOCNT: %d,  Left: %d/%d\n",
+                    MSDC_FIFO_THD, MSDC_RXFIFOCNT(), size, totalsz);
+        } else if ((size < MSDC_FIFO_THD) && MSDC_RXFIFOCNT() >= size) {
+            while (size) {
+                if (size > 3) {
+                    *ptr++ = MSDC_FIFO_READ32();
+                } else {
+                    u8ptr = (u8 *)ptr;
+                    while (size --)
+                        *u8ptr++ = MSDC_FIFO_READ8();
+                }
+            }
+            dprintf(INFO, "[MSDC] Read left bytes, RXFIFOCNT: %d, Left: %d/%d\n",
+                    MSDC_RXFIFOCNT(), size, totalsz);
+        }
+    }
+
+    return err;
+}
+
+static int msdc_pio_read(struct mmc_host *host, u32 *ptr, u32 size)
+{
+    int err = msdc_pio_read_word(host, (u32 *)ptr, size);
+
+    if (err != MMC_ERR_NONE) {
+        msdc_abort(host); /* reset internal fifo and state machine */
+        dprintf(CRITICAL, "[MSDC] %d-bit PIO Read Error (%d)\n", 32, err);
+    }
+
+    return err;
+}
+
+static int msdc_pio_write_word(struct mmc_host *host, u32 *ptr, u32 size)
+{
+    int err = MMC_ERR_NONE;
+    addr_t base = host->base;
+    u32 ints = MSDC_INT_DATCRCERR | MSDC_INT_DATTMO | MSDC_INT_XFER_COMPL;
+    //u32 timeout = 250000;
+    u32 status;
+    u8 *u8ptr;
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+
+    while (1) {
+        status = MSDC_READ32(MSDC_INT);
+        MSDC_WRITE32(MSDC_INT, status);
+        if (status & ~ints) {
+            dprintf(CRITICAL, "[MSDC]<CHECKME> Unexpected INT(0x%x)\n", status);
+        }
+        if (status & MSDC_INT_DATCRCERR) {
+            dprintf(CRITICAL, "[MSDC] DAT CRC error (0x%x), Left DAT: %d bytes\n",
+                    status, size);
+            err = MMC_ERR_BADCRC;
+            break;
+        } else if (status & MSDC_INT_DATTMO) {
+            dprintf(CRITICAL, "[MSDC] DAT TMO error (0x%x), Left DAT: %d bytes, MSDC_FIFOCS=%xh\n",
+                    status, size, MSDC_READ32(MSDC_FIFOCS));
+            err = MMC_ERR_TIMEOUT;
+            break;
+        } else if (status & MSDC_INT_ACMDCRCERR) {
+            dprintf(CRITICAL, "[MSDC] AUTO CMD CRC error (0x%x), Left DAT: %d bytes\n",
+                    status, size);
+            err = MMC_ERR_ACMD_RSPCRC;
+            break;
+        } else if (status & MSDC_INT_XFER_COMPL) {
+            if (size == 0) {
+                dprintf(INFO, "[MSDC] all data flushed to card\n");
+                break;
+            } else
+                dprintf(INFO, "[MSDC]<CHECKME> XFER_COMPL before all data written\n");
+        }
+
+        if (size == 0)
+            continue;
+
+        if (size >= MSDC_FIFO_SZ) {
+            if (MSDC_TXFIFOCNT() == 0) {
+                int left = MSDC_FIFO_SZ >> 2;
+                do {
+                    MSDC_FIFO_WRITE32(*ptr);
+                    ptr++;
+                } while (--left);
+                size -= MSDC_FIFO_SZ;
+            }
+        } else if (size < MSDC_FIFO_SZ && MSDC_TXFIFOCNT() == 0) {
+            while (size ) {
+                if (size > 3) {
+                    MSDC_FIFO_WRITE32(*ptr);
+                    ptr++;
+                    size -= 4;
+                } else {
+                    u8ptr = (u8 *)ptr;
+                    while (size --) {
+                        MSDC_FIFO_WRITE8(*u8ptr);
+                        u8ptr++;
+                    }
+                }
+            }
+        }
+    }
+
+    return err;
+}
+
+static int msdc_pio_write(struct mmc_host *host, u32 *ptr, u32 size)
+{
+    int err = msdc_pio_write_word(host, (u32 *)ptr, size);
+
+    if (err != MMC_ERR_NONE) {
+        msdc_abort(host); /* reset internal fifo and state machine */
+        dprintf(CRITICAL, "[MSDC] PIO Write Error (%d)\n", err);
+    }
+
+    return err;
+}
+
+static int msdc_pio_bread(struct mmc_host *host, u8 *dst, u32 src, u32 nblks)
+{
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+    addr_t base = host->base;
+    u32 blksz = host->blklen;
+    int err = MMC_ERR_NONE, derr = MMC_ERR_NONE;
+    int multi;
+    struct mmc_command cmd;
+    struct mmc_command stop;
+    u32 *ptr = (u32 *)dst;
+
+    dprintf(INFO, "[MSDC] Read data %d bytes from 0x%x\n", nblks * blksz, src);
+
+    multi = nblks > 1 ? 1 : 0;
+
+    MSDC_CLR_FIFO();
+    MSDC_WRITE32(SDC_BLK_NUM, nblks);
+    msdc_set_timeout(host, 100000000, 0);
+
+    /* send read command */
+    cmd.opcode  = multi ? MMC_CMD_READ_MULTIPLE_BLOCK : MMC_CMD_READ_SINGLE_BLOCK;
+    cmd.rsptyp  = RESP_R1;
+    cmd.arg     = src;
+    cmd.retries = 0;
+    cmd.timeout = CMD_TIMEOUT;
+    err = msdc_cmd(host, &cmd);
+
+    if (err != MMC_ERR_NONE)
+        goto done;
+
+    err = derr = msdc_pio_read(host, (u32 *)ptr, nblks * blksz);
+
+done:
+    if (err != MMC_ERR_NONE) {
+        if (derr != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "[MSDC] Read data error (%d)\n", derr);
+            if (msdc_abort_handler(host, 1))
+                dprintf(CRITICAL, "[MSDC] abort failed\n");
+        } else {
+            dprintf(CRITICAL, "[MSDC] Read error (%d)\n", err);
+        }
+    }
+    return (derr == MMC_ERR_NONE) ? err : derr;
+}
+
+static int msdc_pio_bwrite(struct mmc_host *host, u32 dst, u8 *src, u32 nblks)
+{
+    msdc_priv_t *priv = (msdc_priv_t *)host->priv;
+    addr_t base = host->base;
+    int err = MMC_ERR_NONE, derr = MMC_ERR_NONE;
+    int multi;
+    u32 blksz = host->blklen;
+    struct mmc_command cmd;
+    struct mmc_command stop;
+    u32 *ptr = (u32 *)src;
+
+    dprintf(CRITICAL, "[MSDC] Write data %d bytes to 0x%x\n", nblks * blksz, dst);
+
+    multi = nblks > 1 ? 1 : 0;
+
+    MSDC_CLR_FIFO();
+    MSDC_WRITE32(SDC_BLK_NUM, nblks);
+
+    /* No need since MSDC always waits 8 cycles for write data timeout */
+
+    /* send write command */
+    cmd.opcode  = multi ? MMC_CMD_WRITE_MULTIPLE_BLOCK : MMC_CMD_WRITE_BLOCK;
+    cmd.rsptyp  = RESP_R1;
+    cmd.arg     = dst;
+    cmd.retries = 0;
+    cmd.timeout = CMD_TIMEOUT;
+    err = msdc_cmd(host, &cmd);
+
+    if (err != MMC_ERR_NONE)
+        goto done;
+
+    err = derr = msdc_pio_write(host, (u32 *)ptr, nblks * blksz);
+
+done:
+    if (err != MMC_ERR_NONE) {
+        if (derr != MMC_ERR_NONE) {
+            dprintf(CRITICAL, "[MSDC] Write data error (%d)\n", derr);
+            if (msdc_abort_handler(host, 1))
+                dprintf(CRITICAL, "[MSDC] abort failed\n");
+        } else {
+            dprintf(CRITICAL, "[MSDC] Write error (%d)\n", err);
+        }
+    }
+    return (derr == MMC_ERR_NONE) ? err : derr;
+}
+#endif
+
+
+static void msdc_config_clksrc(struct mmc_host *host, u32 clksrc, u32 hclksrc)
+{
+    // modify the clock
+    ASSERT(host);
+    /*
+     * For MT2712, MSDC0 use 400Mhz(MSDCPLL) source clock
+     */
+    host->clksrc  = clksrc;
+    host->hclksrc = hclksrc;
+#ifndef FPGA_PLATFORM
+    if (host->host_id == 0)
+        host->clk     = 400 * 1000 * 1000;
+    else
+        host->clk     = 200 * 1000 * 1000;
+#else
+    host->clk = MSDC_OP_SCLK;
+#endif
+
+    /* Chaotian, may need update this part of code */
+    dprintf(INFO, "[info][%s] pll_clk %u (%uMHz), pll_hclk %u\n",
+            __func__, host->clksrc, host->clk/1000000, host->hclksrc);
+}
+
+void msdc_config_clock(struct mmc_host *host, int state, u32 hz)
+{
+    addr_t base = host->base;
+    u32 mode = 0;
+    u32 div;
+    u32 sclk;
+    u32 u4buswidth=0;
+
+    if (hz >= host->f_max) {
+        hz = host->f_max;
+    } else if (hz < host->f_min) {
+        hz = host->f_min;
+    }
+
+    msdc_config_clksrc(host, host->clksrc, host->hclksrc);
+    MSDC_CLR_BIT32(MSDC_CFG, MSDC_CFG_CKMOD_HS400);
+    MSDC_SET_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS);
+
+    if (state & MMC_STATE_HS400) {
+        mode = 0x3;
+        div = 0; /* we let hs400 mode fixed at 200Mhz */
+        sclk = host->clk >> 1;
+        MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_CKMOD_HS400);
+        MSDC_CLR_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS);
+    } else if (state&MMC_STATE_DDR) {
+        mode = 0x2; /* ddr mode and use divisor */
+        if (hz >= (host->clk >> 2)) {
+            div  = 0;              /* mean div = 1/2 */
+            sclk = host->clk >> 2; /* sclk = clk/div/2. 2: internal divisor */
+        } else {
+            div  = (host->clk + ((hz << 2) - 1)) / (hz << 2);
+            sclk = (host->clk >> 2) / div;
+            div  = (div >> 1);     /* since there is 1/2 internal divisor */
+        }
+    } else if (hz >= host->clk) {
+        mode = 0x1; /* no divisor and divisor is ignored */
+        div  = 0;
+        sclk = host->clk;
+    } else {
+        mode = 0x0; /* use divisor */
+        if (hz >= (host->clk >> 1)) {
+            div  = 0;              /* mean div = 1/2 */
+            sclk = host->clk >> 1; /* sclk = clk / 2 */
+        } else {
+            div  = (host->clk + ((hz << 2) - 1)) / (hz << 2);
+            sclk = (host->clk >> 2) / div;
+        }
+    }
+    host->sclk = sclk;
+
+    /* set clock mode and divisor */
+    MSDC_SET_FIELD(MSDC_CFG, (MSDC_CFG_CKMOD |MSDC_CFG_CKDIV),\
+                   (mode << 12) | div);
+    /* wait clock stable */
+    while (!(MSDC_READ32(MSDC_CFG) & MSDC_CFG_CKSTB));
+
+    MSDC_GET_FIELD(SDC_CFG,SDC_CFG_BUSWIDTH,u4buswidth);
+
+    dprintf(INFO,
+            "[MSDC] SET_CLK(%dkHz): SCLK(%dkHz) MODE(%d) DIV(%d) DS(%d) RS(%d) buswidth(%s)\n",
+            hz/1000, sclk/1000, mode, div, msdc_cap[host->host_id].data_edge,
+            msdc_cap[host->host_id].cmd_edge,
+            (u4buswidth == 0) ?
+            "1-bit" : (u4buswidth == 1) ?
+            "4-bits" : (u4buswidth == 2) ?
+            "8-bits" : "undefined");
+}
+
+void msdc_config_bus(struct mmc_host *host, u32 width)
+{
+    u32 val,mode, div;
+    addr_t base = host->base;
+
+    val = (width == HOST_BUS_WIDTH_8) ? 2 :
+          (width == HOST_BUS_WIDTH_4) ? 1 : 0;
+
+    MSDC_SET_FIELD(SDC_CFG, SDC_CFG_BUSWIDTH, val);
+    MSDC_GET_FIELD(MSDC_CFG,MSDC_CFG_CKMOD,mode);
+    MSDC_GET_FIELD(MSDC_CFG,MSDC_CFG_CKDIV,div);
+
+    dprintf(INFO, "CLK (%dMHz), SCLK(%dkHz) MODE(%d) DIV(%d) buswidth(%u-bits)\n",
+            host->clk/1000000, host->sclk/1000, mode, div, width);
+}
+
+static void msdc_config_pin(struct mmc_host *host, int mode)
+{
+    dprintf(INFO, "[MSDC] Pins mode(%d), none(0), down(1), up(2), keep(3)\n", mode);
+
+    switch (mode) {
+        case MSDC_PIN_PULL_UP:
+	    msdc_pin_set(host, MSDC_PST_PU_10KOHM);
+            break;
+        case MSDC_PIN_PULL_DOWN:
+	    msdc_pin_set(host, MSDC_PST_PD_50KOHM);
+            break;
+        case MSDC_PIN_PULL_NONE:
+	default:
+	    msdc_pin_set(host, MSDC_PST_PD_50KOHM);
+            break;
+    }
+}
+
+void msdc_clock(struct mmc_host *host, int on)
+{
+    /* Chaotian, may need update this part of code */
+    dprintf(INFO, "[MSDC] Turn %s %s clock \n", on ? "on" : "off", "host");
+}
+
+static void msdc_host_power(struct mmc_host *host, int on)
+{
+    dprintf(INFO, "[MSDC] Turn %s %s power \n", on ? "on" : "off", "host");
+    return; /* power always on, return directly */
+
+    if (on) {
+        msdc_config_pin(host, MSDC_PIN_PULL_UP);
+        msdc_set_host_pwr(host, 1);
+        msdc_clock(host, 1);
+    } else {
+        msdc_clock(host, 0);
+        msdc_set_host_pwr(host, 0);
+        msdc_config_pin(host, MSDC_PIN_PULL_DOWN);
+    }
+}
+
+static void msdc_card_power(struct mmc_host *host, int on)
+{
+    dprintf(INFO, "[MSDC] Turn %s %s power \n", on ? "on" : "off", "card");
+    return; /* power always on, return directly */
+
+    if (on) {
+        msdc_set_card_pwr(host, 1);
+    } else {
+        msdc_set_card_pwr(host, 0);
+    }
+}
+
+void msdc_power(struct mmc_host *host, u8 mode)
+{
+    if (mode == MMC_POWER_ON || mode == MMC_POWER_UP) {
+        msdc_host_power(host, 1);
+        msdc_card_power(host, 1);
+    } else {
+        msdc_card_power(host, 0);
+        msdc_host_power(host, 0);
+    }
+}
+
+void msdc_reset_tune_counter(struct mmc_host *host)
+{
+    host->time_read = 0;
+}
+
+#ifdef FEATURE_MMC_CM_TUNING
+#ifndef FPGA_PLATFORM
+int msdc_tune_cmdrsp(struct mmc_host *host, struct mmc_command *cmd)
+{
+	u32 base = host->base;
+	u32 rsmpl,cur_rsmpl, orig_rsmpl;
+	u32 rdly,cur_rdly, orig_rdly;
+	u8 hs400 = 0, orig_clkmode;
+	int result = MMC_ERR_CMDTUNEFAIL;
+
+	MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RD_RXDLY_SEL, 1);
+	MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, orig_rsmpl);
+	MSDC_GET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY, orig_rdly);
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+
+	hs400 = (orig_clkmode == 3) ? 1 : 0;
+	rdly = 0;
+
+	do {
+		for (rsmpl = 0; rsmpl < 2; rsmpl++) {
+			cur_rsmpl = (orig_rsmpl + rsmpl) % 2;
+			msdc_set_smpl(host, hs400, cur_rsmpl, TYPE_CMD_RESP_EDGE);
+			if (host->sclk <= 400000){
+				MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, 0);
+			}
+			if (cmd->opcode != MMC_CMD_STOP_TRANSMISSION) {
+				result = msdc_send_cmd(host, cmd);
+				if(result == MMC_ERR_TIMEOUT)
+					rsmpl--;
+				if (result != MMC_ERR_NONE && cmd->opcode != MMC_CMD_STOP_TRANSMISSION){
+					if(cmd->opcode == MMC_CMD_READ_MULTIPLE_BLOCK ||
+					   cmd->opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK ||
+					   cmd->opcode == MMC_CMD_READ_SINGLE_BLOCK ||
+					   cmd->opcode == MMC_CMD_WRITE_BLOCK)
+						msdc_abort_handler(host,1);
+					continue;
+				}
+				result = msdc_wait_cmd_done(host, cmd);
+			} else if (cmd->opcode == MMC_CMD_STOP_TRANSMISSION){
+				result = MMC_ERR_NONE;
+				goto done;
+			}
+			else
+				result = MMC_ERR_BADCRC;
+
+			if(cmd->opcode == MMC_CMD_READ_MULTIPLE_BLOCK ||
+			   cmd->opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK ||
+			   cmd->opcode == MMC_CMD_READ_SINGLE_BLOCK ||
+			   cmd->opcode == MMC_CMD_WRITE_BLOCK)
+				msdc_abort_handler(host,1);
+		}
+		cur_rdly = (orig_rdly + rdly + 1) % 32;
+		MSDC_SET_FIELD(EMMC_TOP_CMD, PAD_CMD_RXDLY, cur_rdly);
+	} while (++rdly < 32);
+
+done:
+    dprintf(ALWAYS, "[SD%d] <TUNE_CMD%d><%s>@msdc_tune_cmdrsp\n",
+            host->host_id, (cmd->opcode & (~(SD_CMD_BIT | SD_CMD_APP_BIT))), \
+            (result == MMC_ERR_NONE) ? "PASS" : "FAIL");
+    return result;
+}
+#else
+int msdc_tune_cmdrsp(struct mmc_host *host, struct mmc_command *cmd)
+{
+	u32 base = host->base;
+	u32 rsmpl,cur_rsmpl, orig_rsmpl;
+	u8 hs400 = 0, orig_clkmode;
+	int result = MMC_ERR_CMDTUNEFAIL;
+
+	MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, orig_rsmpl);
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+
+	hs400 = (orig_clkmode == 3) ? 1 : 0;
+
+	for (rsmpl = 0; rsmpl < 2; rsmpl++) {
+		cur_rsmpl = (orig_rsmpl + rsmpl) % 2;
+		msdc_set_smpl(host, hs400, cur_rsmpl, TYPE_CMD_RESP_EDGE);
+		if (host->sclk <= 400000){
+			MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, 0);
+		}
+		if (cmd->opcode != MMC_CMD_STOP_TRANSMISSION) {
+			result = msdc_send_cmd(host, cmd);
+			if(result == MMC_ERR_TIMEOUT)
+				rsmpl--;
+			if (result != MMC_ERR_NONE && cmd->opcode != MMC_CMD_STOP_TRANSMISSION){
+				if(cmd->opcode == MMC_CMD_READ_MULTIPLE_BLOCK ||
+				   cmd->opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK ||
+				   cmd->opcode == MMC_CMD_READ_SINGLE_BLOCK ||
+				   cmd->opcode == MMC_CMD_WRITE_BLOCK)
+					msdc_abort_handler(host,1);
+				continue;
+			}
+			result = msdc_wait_cmd_done(host, cmd);
+		} else if (cmd->opcode == MMC_CMD_STOP_TRANSMISSION){
+			result = MMC_ERR_NONE;
+			goto done;
+		}
+		else
+			result = MMC_ERR_BADCRC;
+
+		if(cmd->opcode == MMC_CMD_READ_MULTIPLE_BLOCK ||
+		   cmd->opcode == MMC_CMD_WRITE_MULTIPLE_BLOCK ||
+		   cmd->opcode == MMC_CMD_READ_SINGLE_BLOCK ||
+		   cmd->opcode == MMC_CMD_WRITE_BLOCK)
+			msdc_abort_handler(host,1);
+	}
+
+done:
+	dprintf(ALWAYS, "[SD%d] <TUNE_CMD%d><%s>@msdc_tune_cmdrsp\n",
+		host->host_id, (cmd->opcode & (~(SD_CMD_BIT | SD_CMD_APP_BIT))), \
+		(result == MMC_ERR_NONE) ? "PASS" : "FAIL");
+	return result;
+}
+#endif
+#endif
+
+#ifdef FEATURE_MMC_RD_TUNING
+#ifndef FPGA_PLATFORM
+int msdc_tune_bread(struct mmc_host *host, uchar *dst, u32 src, u32 nblks)
+{
+	u32 base = host->base;
+	u32 cur_rxdly0, org_rxdly0;
+	u32 rxdly = 0;
+	u32 rdsmpl, cur_rdsmpl, orig_rdsmpl;
+	u32 dcrc, ddr = 0;
+	u8 hs400 = 0;
+	u32 orig_clkmode;
+	int result = MMC_ERR_READTUNEFAIL;
+
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+	ddr = (orig_clkmode == 2) ? 1 : 0;
+	hs400 = (orig_clkmode == 3) ? 1 : 0;
+
+	MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL, orig_rdsmpl);
+	MSDC_SET_BIT32(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL);
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, org_rxdly0);
+
+	do {
+		for (rdsmpl = 0; rdsmpl < 2; rdsmpl++) {
+			cur_rdsmpl = (orig_rdsmpl + rdsmpl) % 2;
+			msdc_set_smpl(host, hs400, cur_rdsmpl, TYPE_READ_DATA_EDGE);
+
+			result = host->blk_read(host, dst, src, nblks);
+			if (result == MMC_ERR_CMDTUNEFAIL ||
+			    result == MMC_ERR_CMD_RSPCRC ||
+			    result == MMC_ERR_ACMD_RSPCRC)
+				goto done;
+
+			MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+			if (!ddr) dcrc &= ~SDC_DCRC_STS_NEG;
+
+			/* no crc error in this data line */
+			if (result == MMC_ERR_NONE && dcrc == 0) {
+				goto done;
+			} else {
+				result = MMC_ERR_BADCRC;
+			}
+		}
+
+		cur_rxdly0 = (org_rxdly0 + rxdly + 1) % 32;
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, cur_rxdly0);
+
+	} while (++rxdly < 32);
+
+done:
+	dprintf(ALWAYS, "[SD%d] <msdc_tune_bread<%s><cmd%d>@msdc_tune_bread\n",
+		host->host_id, (result == MMC_ERR_NONE && dcrc == 0) ?"PASS" : "FAIL", (nblks == 1 ? 17 : 18));
+
+	return result;
+}
+#else
+int msdc_tune_bread(struct mmc_host *host, uchar *dst, u32 src, u32 nblks)
+{
+	u32 base = host->base;
+	u32 rdsmpl, cur_rdsmpl, orig_rdsmpl;
+	u32 dcrc, ddr = 0;
+	u8 hs400 = 0;
+	u32 orig_clkmode;
+	int result = MMC_ERR_READTUNEFAIL;
+
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+	ddr = (orig_clkmode == 2) ? 1 : 0;
+	hs400 = (orig_clkmode == 3) ? 1 : 0;
+
+	MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL, orig_rdsmpl);
+
+	for (rdsmpl = 0; rdsmpl < 2; rdsmpl++) {
+		cur_rdsmpl = (orig_rdsmpl + rdsmpl) % 2;
+		msdc_set_smpl(host, hs400, cur_rdsmpl, TYPE_READ_DATA_EDGE);
+
+		result = host->blk_read(host, dst, src, nblks);
+		if (result == MMC_ERR_CMDTUNEFAIL ||
+		    result == MMC_ERR_CMD_RSPCRC ||
+		    result == MMC_ERR_ACMD_RSPCRC)
+			goto done;
+
+		MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+		if (!ddr) dcrc &= ~SDC_DCRC_STS_NEG;
+
+		/* no crc error in this data line */
+		if (result == MMC_ERR_NONE && dcrc == 0) {
+			goto done;
+		} else {
+			result = MMC_ERR_BADCRC;
+		}
+	}
+
+done:
+	dprintf(ALWAYS, "[SD%d] <msdc_tune_bread<%s><cmd%d>@msdc_tune_bread\n",
+		host->host_id, (result == MMC_ERR_NONE && dcrc == 0) ?"PASS" : "FAIL", (nblks == 1 ? 17 : 18));
+
+	return result;
+}
+#endif
+
+#define READ_TUNING_MAX_HS (2 * 32)
+#define READ_TUNING_MAX_UHS (2 * 32)
+#define READ_TUNING_MAX_UHS_CLKMOD1 (2 * 32)
+#ifndef FPGA_PLATFORM
+int msdc_tune_read(struct mmc_host *host)
+{
+	u32 base = host->base;
+	u32 cur_rxdly0;
+	u32 cur_dsmpl, orig_dsmpl;
+	u32 dcrc = 0;
+	u8 hs400 = 0;
+	u32 orig_clkmode;
+	int result = MMC_ERR_NONE;
+
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+	hs400 = (orig_clkmode == 3) ? 1 : 0;
+
+	MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL, orig_dsmpl);
+	MSDC_SET_BIT32(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL);
+
+	cur_dsmpl = (orig_dsmpl + 1) ;
+	msdc_set_smpl(host, hs400, (cur_dsmpl % 2), TYPE_READ_DATA_EDGE);
+	++(host->time_read);
+	if (cur_dsmpl >= 2){
+		cur_rxdly0++;
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, cur_rxdly0 % 32);
+		if (cur_rxdly0 > 32)
+			result = MMC_ERR_READTUNEFAIL;
+	}
+
+	dprintf(ALWAYS, "[SD%d] <msdc_tune_read <%s> @msdc_tune_bread\n",
+		host->host_id, (result == MMC_ERR_NONE && dcrc == 0) ?"PASS" : "FAIL");
+	return result;
+}
+#else
+int msdc_tune_read(struct mmc_host *host)
+{
+	u32 base = host->base;
+	u32 cur_dsmpl, orig_dsmpl;
+	u32 dcrc = 0;
+	u8 hs400 = 0;
+	u32 orig_clkmode;
+	int result = MMC_ERR_NONE;
+
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+	hs400 = (orig_clkmode == 3) ? 1 : 0;
+
+	MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL, orig_dsmpl);
+
+	cur_dsmpl = (orig_dsmpl + 1) ;
+	msdc_set_smpl(host, hs400, (cur_dsmpl % 2), TYPE_READ_DATA_EDGE);
+	++(host->time_read);
+	if (cur_dsmpl >= 2){
+		result = MMC_ERR_READTUNEFAIL;
+	}
+
+	dprintf(ALWAYS, "[SD%d] <msdc_tune_read><%s> @msdc_tune_bread\n",
+		host->host_id, (result == MMC_ERR_NONE && dcrc == 0) ? "PASS" : "FAIL");
+	return result;
+}
+#endif
+#endif
+
+#ifdef FEATURE_MMC_WR_TUNING
+#ifndef FPGA_PLATFORM
+/* Chaotian, make read/write tune flow the same */
+int msdc_tune_bwrite(struct mmc_host *host, u32 dst, u8 *src, u32 nblks)
+{
+	u32 base = host->base;
+	u32 cur_rxdly0, org_rxdly0;
+	u32 rxdly = 0;
+	u32 rdsmpl, cur_rdsmpl, orig_rdsmpl;
+	u32 dcrc, ddr = 0;
+	u8 hs400 = 0;
+	u32 orig_clkmode;
+	int result = MMC_ERR_READTUNEFAIL;
+
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+	ddr = (orig_clkmode == 2) ? 1 : 0;
+	hs400 = (orig_clkmode == 3) ? 1 : 0;
+
+	MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL, orig_rdsmpl);
+	MSDC_SET_BIT32(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL);
+	MSDC_GET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, org_rxdly0);
+
+	do {
+		for (rdsmpl = 0; rdsmpl < 2; rdsmpl++) {
+			cur_rdsmpl = (orig_rdsmpl + rdsmpl) % 2;
+			msdc_set_smpl(host, hs400, cur_rdsmpl, TYPE_READ_DATA_EDGE);
+
+			result = host->blk_write(host, dst, src, nblks);
+			if (result == MMC_ERR_CMDTUNEFAIL ||
+			    result == MMC_ERR_CMD_RSPCRC ||
+			    result == MMC_ERR_ACMD_RSPCRC)
+				goto done;
+
+			MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+			if (!ddr) dcrc &= ~SDC_DCRC_STS_NEG;
+
+			/* no crc error in this data line */
+			if (result == MMC_ERR_NONE && dcrc == 0) {
+				goto done;
+			} else {
+				result = MMC_ERR_BADCRC;
+			}
+		}
+
+		cur_rxdly0 = (org_rxdly0 + rxdly + 1) % 32;
+		MSDC_SET_FIELD(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY, cur_rxdly0);
+
+	} while (++rxdly < 32);
+
+done:
+	dprintf(ALWAYS, "[SD%d] <msdc_tune_bwrite><%s><cmd%d>@msdc_tune_bread\n",
+	       host->host_id, (result == MMC_ERR_NONE && dcrc == 0) ? "PASS" : "FAIL", (nblks == 1 ? 17 : 18));
+
+	return result;
+}
+#else
+int msdc_tune_bwrite(struct mmc_host *host, u32 dst, u8 *src, u32 nblks)
+{
+	u32 base = host->base;
+	u32 rdsmpl, cur_rdsmpl, orig_rdsmpl;
+	u32 dcrc, ddr = 0;
+	u8 hs400 = 0;
+	u32 orig_clkmode;
+	int result = MMC_ERR_READTUNEFAIL;
+
+	MSDC_GET_FIELD(MSDC_CFG, MSDC_CFG_CKMOD, orig_clkmode);
+	ddr = (orig_clkmode == 2) ? 1 : 0;
+	hs400 = (orig_clkmode == 3) ? 1 : 0;
+
+	MSDC_GET_FIELD(MSDC_IOCON, MSDC_IOCON_R_D_SMPL, orig_rdsmpl);
+
+	for (rdsmpl = 0; rdsmpl < 2; rdsmpl++) {
+		cur_rdsmpl = (orig_rdsmpl + rdsmpl) % 2;
+		msdc_set_smpl(host, hs400, cur_rdsmpl, TYPE_READ_DATA_EDGE);
+
+		result = host->blk_write(host, dst, src, nblks);
+		if (result == MMC_ERR_CMDTUNEFAIL ||
+		    result == MMC_ERR_CMD_RSPCRC ||
+		    result == MMC_ERR_ACMD_RSPCRC)
+			goto done;
+
+		MSDC_GET_FIELD(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc);
+		if (!ddr) dcrc &= ~SDC_DCRC_STS_NEG;
+
+		/* no crc error in this data line */
+		if (result == MMC_ERR_NONE && dcrc == 0) {
+			goto done;
+		} else {
+			result = MMC_ERR_BADCRC;
+		}
+	}
+
+done:
+	dprintf(ALWAYS, "[SD%d] <msdc_tune_bwrite<%s><cmd%d>@msdc_tune_bwrite\n",
+		host->host_id, (result == MMC_ERR_NONE && dcrc == 0) ? "PASS" : "FAIL", (nblks == 1 ? 17 : 18));
+
+	return result;
+}
+#endif
+#endif
+
+void msdc_emmc_boot_stop(struct mmc_host *host)
+{
+    addr_t base = host->base;
+    u32 count = 0;
+
+    /* Step5. stop the boot mode */
+    MSDC_WRITE32(SDC_ARG, 0x00000000);
+    MSDC_WRITE32(SDC_CMD, 0x00001000);
+
+    MSDC_SET_FIELD(EMMC_CFG0, EMMC_CFG0_BOOTWDLY, 2);
+    MSDC_SET_BIT32(EMMC_CFG0, EMMC_CFG0_BOOTSTOP);
+    while (MSDC_READ32(EMMC_STS) & EMMC_STS_BOOTUPSTATE) {
+        spin(1000);
+        count++;
+        if (count >= 1000) {
+            dprintf(ALWAYS, "Timeout to wait EMMC to leave boot state!\n");
+            break;
+        }
+    }
+
+    /* Step6. */
+    MSDC_CLR_BIT32(EMMC_CFG0, EMMC_CFG0_BOOTSUPP);
+
+    /* Step7. clear EMMC_STS bits */
+    MSDC_WRITE32(EMMC_STS, MSDC_READ32(EMMC_STS));
+}
+
+int msdc_init(struct mmc_host *host)
+{   /* only support MSDC0, MSDC1 */
+    addr_t base = host->host_id ? MSDC1_BASE: MSDC0_BASE;
+    addr_t top_base = host->host_id? MSDC1_TOP_BASE : MSDC0_TOP_BASE;
+    msdc_priv_t *priv;
+
+    dprintf(INFO, "[%s]: Host controller intialization start \n", __func__);
+
+    priv = &msdc_priv;
+    memset(priv, 0, sizeof(msdc_priv_t));
+
+    host->base   = base;
+    host->top_base = top_base;
+    host->clksrc = msdc_cap[host->host_id].clk_src;
+    host->hclksrc= msdc_cap[host->host_id].hclk_src;
+#ifndef FPGA_PLATFORM
+    host->f_max  = hclks_msdc30[host->clksrc];
+#else
+    host->f_max  = MSDC_MAX_SCLK;
+#endif
+
+    host->f_min  = MSDC_MIN_SCLK;
+    host->blklen = 0;
+    host->priv   = (void *)priv;
+    host->caps   = MMC_CAP_MULTIWRITE;
+
+    if (msdc_cap[host->host_id].flags & MSDC_HIGHSPEED)
+        host->caps |= (MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED);
+    if (msdc_cap[host->host_id].flags & MSDC_DDR)
+        host->caps |= MMC_CAP_DDR;
+    if (msdc_cap[host->host_id].data_pins == 4)
+        host->caps |= MMC_CAP_4_BIT_DATA;
+    if (msdc_cap[host->host_id].data_pins == 8)
+        host->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
+    if (msdc_cap[host->host_id].flags & MSDC_HS200)
+        host->caps |= MMC_CAP_EMMC_HS200;
+    if (msdc_cap[host->host_id].flags & MSDC_HS400)
+        host->caps |= MMC_CAP_EMMC_HS400;
+
+    host->ocr_avail = MMC_VDD_32_33;  /* TODO: To be customized */
+
+    /* Configure BASIC_DMA + AUTOCMD12 for better R/W performance
+     * NOTE: ACMD23 only support transferring size of up to 32M */
+    priv->autocmd = MSDC_AUTOCMD12;
+    if (priv->autocmd == MSDC_AUTOCMD23)
+        /* The maximal transferring size is size of *[15:0] number of blocks* */
+        host->max_phys_segs = 0xffff;
+    else
+        /* The maximal transferring size is size of DMA_LENGTH */
+        host->max_phys_segs = (UINT_MAX & ~511) >> MMC_BLOCK_BITS_SHFT;
+
+    priv->rdsmpl       = msdc_cap[host->host_id].data_edge;
+    priv->wdsmpl       = msdc_cap[host->host_id].data_edge;
+    priv->rsmpl       = msdc_cap[host->host_id].cmd_edge;
+
+#ifdef MSDC_USE_DMA_MODE
+    host->blk_read  = msdc_dma_bread;
+    host->blk_write = msdc_dma_bwrite;
+    dprintf(INFO, "Transfer method: DMA\n");
+#else
+    host->blk_read  = msdc_pio_bread;
+    host->blk_write = msdc_pio_bwrite;
+    dprintf(INFO, "Transfer method: PIO\n");
+#endif
+
+    priv->rdsmpl       = msdc_cap[host->host_id].data_edge;
+    priv->rsmpl       = msdc_cap[host->host_id].cmd_edge;
+
+#ifndef FPGA_PLATFORM
+    /* BROM may set wrong pin mux, eg. NFI mode */
+    msdc_set_pin_msdc_mode(host);
+#endif
+    /* disable EMMC boot mode */
+    msdc_emmc_boot_stop(host);
+
+    msdc_power(host, MMC_POWER_OFF);
+    msdc_power(host, MMC_POWER_ON);
+
+#ifndef FPGA_PLATFORM
+    if (host->host_id == 1)
+        sd_card_vccq_on();
+#endif
+
+    /* set to SD/MMC mode */
+    MSDC_SET_FIELD(MSDC_CFG, MSDC_CFG_MODE, MSDC_SDMMC);
+    MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_PIO);
+    MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_CKPDN);
+
+    MSDC_RESET();
+    MSDC_CLR_FIFO();
+    MSDC_CLR_INT();
+
+    /* reset tuning parameter */
+#ifndef FPGA_PLATFORM
+    /* FPGA platform do not have top registers */
+    MSDC_WRITE32(EMMC_TOP_CONTROL, 0);
+    MSDC_WRITE32(EMMC_TOP_CMD, 0);
+    /* enable enhance rx */
+    MSDC_SET_BIT32(EMMC_TOP_CONTROL, SDC_RX_ENHANCE_EN);
+    MSDC_CLR_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CRCSTSENSEL);
+    MSDC_CLR_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_RESPSTSENSEL);
+    MSDC_SET_BIT32(EMMC_TOP_CONTROL, PAD_DAT_RD_RXDLY_SEL);
+    MSDC_SET_BIT32(EMMC_TOP_CMD, PAD_CMD_RD_RXDLY_SEL);
+#endif
+
+    MSDC_WRITE32(MSDC_IOCON, 0x00000000);
+
+    MSDC_WRITE32(MSDC_PATCH_BIT0, 0x403c0046);
+    MSDC_WRITE32(MSDC_PATCH_BIT1, 0xFFFF4309);//High 16 bit = 0 mean Power KPI is on, enable ECO for write timeout issue
+    MSDC_SET_BIT32(EMMC50_CFG0, MSDC_EMMC50_CFG_CRCSTS_SEL);
+    MSDC_CLR_BIT32(SDC_FIFO_CFG, SDC_FIFO_CFG_WRVALIDSEL);
+    MSDC_CLR_BIT32(SDC_FIFO_CFG, SDC_FIFO_CFG_RDVALIDSEL);
+    MSDC_SET_BIT32(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS);
+    MSDC_CLR_BIT32(MSDC_PATCH_BIT1, MSDC_BUSY_CHECK_SEL); /* disable busy check */
+    //MSDC_PATCH_BIT1YD:WRDAT_CRCS_TA_CNTR need fix to 3'001 by default,(<50MHz) (>=50MHz set 3'001 as initial value is OK for tunning)
+    //YD:CMD_RSP_TA_CNTR need fix to 3'001 by default(<50MHz)(>=50MHz set 3'001as initial value is OK for tunning)
+    /* 2012-01-07 using internal clock instead of feedback clock */
+    //MSDC_SET_BIT32(MSDC_PATCH_BIT0, MSDC_CKGEN_MSDC_CK_SEL);
+
+#ifdef MSDC_USE_PATCH_BIT2_TURNING_WITH_ASYNC
+    MSDC_SET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS,1);
+    MSDC_SET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_CFGRESP,0);
+#else
+    MSDC_SET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTS,0);
+    MSDC_SET_FIELD(MSDC_PATCH_BIT2, MSDC_PB2_CFGRESP,1);
+#endif
+
+    /* enable wake up events */
+    //MSDC_SET_BIT32(SDC_CFG, SDC_CFG_INSWKUP);
+
+    /* eneable SMT for glitch filter */
+#ifndef FPGA_PLATFORM
+    msdc_set_smt(host,1);
+    /* set clk, cmd, dat pad driving */
+    msdc_set_driving(host, &msdc_cap[host->host_id]);
+#endif
+
+    /* set sampling edge */
+    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_RSPL, msdc_cap[host->host_id].cmd_edge);
+    MSDC_SET_FIELD(MSDC_IOCON, MSDC_IOCON_DSPL, msdc_cap[host->host_id].data_edge);
+
+    /* write crc timeout detection */
+    MSDC_SET_FIELD(MSDC_PATCH_BIT0, MSDC_PB0_DETWR_CRCTMO, 1);
+
+    msdc_set_startbit(host, START_AT_RISING);
+
+    msdc_config_bus(host, HOST_BUS_WIDTH_1);
+    msdc_config_clock(host, 0, MSDC_MIN_SCLK);
+    msdc_set_timeout(host, 100000000, 0);
+
+    /* disable SDIO func */
+    MSDC_SET_FIELD(SDC_CFG, SDC_CFG_SDIO, 0);
+    MSDC_SET_FIELD(SDC_CFG, SDC_CFG_SDIOIDE, 0);
+    MSDC_SET_FIELD(SDC_CFG, SDC_CFG_INSWKUP, 0);
+
+    /* Clear all interrupts first */
+    MSDC_CLR_INT();
+    MSDC_WRITE32(MSDC_INTEN, 0);
+
+#ifdef MSDC_USE_DMA_MODE
+    /* Register msdc irq */
+    mt_irq_set_sens(MSDC0_IRQ_BIT_ID + host->host_id, LEVEL_SENSITIVE);
+    mt_irq_set_polarity(MSDC0_IRQ_BIT_ID + host->host_id, MT65xx_POLARITY_LOW);
+    event_init(&msdc_int_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+    register_int_handler(MSDC0_IRQ_BIT_ID + host->host_id, msdc_interrupt_handler, host);
+    unmask_interrupt(MSDC0_IRQ_BIT_ID + host->host_id);
+#endif
+
+    dprintf(INFO, "[%s]: Host controller intialization done\n", __func__);
+    return 0;
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/rules.mk b/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/rules.mk
new file mode 100644
index 0000000..57330b8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/mmc/rules.mk
@@ -0,0 +1,12 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/msdc.c \
+    $(LOCAL_DIR)/mmc_core.c \
+    $(LOCAL_DIR)/mmc_rpmb.c \
+
+MODULE_DEPS += \
+    lib/rpmb \
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_ecc_hal.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_ecc_hal.c
new file mode 100644
index 0000000..b465e60
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_ecc_hal.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2017 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 <arch/ops.h>
+#include <errno.h>
+#include <kernel/event.h>
+#include <kernel/mutex.h>
+#include <kernel/vm.h>
+#include <malloc.h>
+#include <platform/interrupts.h>
+#include <platform/mt_irq.h>
+#include <platform/mt_reg_base.h>
+#include <platform/nand/mtk_ecc_hal.h>
+#include <platform/nand/mtk_nand_common.h>
+#include <reg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+static inline void mtk_ecc_wait_ioready(struct mtk_ecc *ecc)
+{
+    if (!check_with_timeout((readl(ecc->regs +  ECC_PIO_DIRDY) & PIO_DI_RDY), ECC_TIMEOUT))
+        dprintf(CRITICAL, "ecc io not ready\n");
+
+    return;
+}
+
+static void mtk_ecc_runtime_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+{
+    u32 ecc_bit = ECC_CNFG_4BIT, dec_sz, enc_sz;
+    u32 reg;
+
+    switch (config->strength) {
+        case 4:
+            ecc_bit = ECC_CNFG_4BIT;
+            break;
+        case 6:
+            ecc_bit = ECC_CNFG_6BIT;
+            break;
+        case 8:
+            ecc_bit = ECC_CNFG_8BIT;
+            break;
+        case 10:
+            ecc_bit = ECC_CNFG_10BIT;
+            break;
+        case 12:
+            ecc_bit = ECC_CNFG_12BIT;
+            break;
+        case 14:
+            ecc_bit = ECC_CNFG_14BIT;
+            break;
+        case 16:
+            ecc_bit = ECC_CNFG_16BIT;
+            break;
+        case 18:
+            ecc_bit = ECC_CNFG_18BIT;
+            break;
+        case 20:
+            ecc_bit = ECC_CNFG_20BIT;
+            break;
+        case 22:
+            ecc_bit = ECC_CNFG_22BIT;
+            break;
+        case 24:
+            ecc_bit = ECC_CNFG_24BIT;
+            break;
+        case 28:
+            ecc_bit = ECC_CNFG_28BIT;
+            break;
+        case 32:
+            ecc_bit = ECC_CNFG_32BIT;
+            break;
+        case 36:
+            ecc_bit = ECC_CNFG_36BIT;
+            break;
+        case 40:
+            ecc_bit = ECC_CNFG_40BIT;
+            break;
+        case 44:
+            ecc_bit = ECC_CNFG_44BIT;
+            break;
+        case 48:
+            ecc_bit = ECC_CNFG_48BIT;
+            break;
+        case 52:
+            ecc_bit = ECC_CNFG_52BIT;
+            break;
+        case 56:
+            ecc_bit = ECC_CNFG_56BIT;
+            break;
+        case 60:
+            ecc_bit = ECC_CNFG_60BIT;
+            break;
+        case 68:
+            ecc_bit = ECC_CNFG_68BIT;
+            break;
+        case 72:
+            ecc_bit = ECC_CNFG_72BIT;
+            break;
+        case 80:
+            ecc_bit = ECC_CNFG_80BIT;
+            break;
+        default:
+            dprintf(CRITICAL, "invalid strength %d, default to 4 bits\n",
+                    config->strength);
+            break;
+    }
+
+    if (config->op == ECC_ENCODE) {
+        /* configure ECC encoder (in bits) */
+        enc_sz = config->len << 3;
+
+        reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
+        reg |= (enc_sz << ECC_MS_SHIFT);
+        writel(reg, ecc->regs + ECC_ENCCNFG);
+
+        if (config->mode == ECC_DMA_MODE) {
+            if (config->addr & 0x3)
+                dprintf(CRITICAL, "ecc encode address(0x%x) is not 4B aligned !!\n", config->addr);
+            writel(config->addr, ecc->regs + ECC_ENCDIADDR);
+        }
+
+    } else {
+        /* configure ECC decoder (in bits) */
+        dec_sz = (config->len << 3) + config->strength * ECC_PARITY_BITS;
+
+        reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
+        reg |= (dec_sz << ECC_MS_SHIFT) | (config->deccon << DEC_CON_SHIFT);
+        reg |= DEC_EMPTY_EN;
+        writel(reg, ecc->regs + ECC_DECCNFG);
+
+        if (config->mode == ECC_DMA_MODE) {
+            if (config->addr & 0x3)
+                dprintf(CRITICAL, "ecc decode address(0x%x) is not 4B aligned !!\n", config->addr);
+            writel(config->addr, ecc->regs + ECC_DECDIADDR);
+        }
+
+        if (config->sectors)
+            ecc->sectors = 1 << (config->sectors - 1);
+    }
+
+    return;
+}
+
+static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
+                                     enum mtk_ecc_operation op)
+{
+    if (!check_with_timeout(readl(ecc->regs + ECC_IDLE_REG(op)) & ECC_IDLE_MASK, ECC_TIMEOUT))
+        dprintf(CRITICAL, "%s NOT idle\n", op == ECC_ENCODE ? "encoder" : "decoder");
+
+    return;
+}
+
+static int mtk_ecc_irq_wait(struct mtk_ecc *ecc, lk_time_t timeout)
+{
+    int ret;
+
+    ret = event_wait_timeout(&ecc->irq_event, timeout);
+    if (ret != 0) {
+        dprintf(CRITICAL, "[%s]: failed to get event\n", __func__);
+        return ret;
+    }
+
+    return 0;
+}
+
+static enum handler_return mtk_ecc_interrupt_handler(void *arg)
+{
+    struct mtk_ecc *ecc = arg;
+    enum mtk_ecc_operation op;
+    u32 dec, enc;
+
+    dec = readw(ecc->regs + ECC_DECIRQ_STA) & ECC_IRQ_EN;
+    if (dec) {
+        op = ECC_DECODE;
+        dec = readw(ecc->regs + ECC_DECDONE);
+        if (dec & ecc->sectors) {
+            ecc->sectors = 0;
+            event_signal(&ecc->irq_event, false);
+        } else {
+            return INT_NO_RESCHEDULE;
+        }
+    } else {
+        enc = readl(ecc->regs + ECC_ENCIRQ_STA) & ECC_IRQ_EN;
+        if (enc) {
+            op = ECC_ENCODE;
+            event_signal(&ecc->irq_event, false);
+        } else {
+            return INT_NO_RESCHEDULE;
+        }
+    }
+
+    writel(0, ecc->regs + ECC_IRQ_REG(op));
+
+    return INT_RESCHEDULE;
+}
+
+static int mtk_ecc_request_irq(struct mtk_ecc *ecc)
+{
+    mt_irq_set_sens(NFIECC_IRQ_BIT_ID, LEVEL_SENSITIVE);
+    mt_irq_set_polarity(NFIECC_IRQ_BIT_ID, MT65xx_POLARITY_LOW);
+    event_init(&ecc->irq_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+    register_int_handler(NFIECC_IRQ_BIT_ID, mtk_ecc_interrupt_handler, ecc);
+    unmask_interrupt(NFIECC_IRQ_BIT_ID);
+
+    return 0;
+}
+
+int mtk_ecc_hw_init(struct mtk_ecc **ext_ecc)
+{
+    struct mtk_ecc *ecc;
+
+    ecc = (struct mtk_ecc *)malloc(sizeof(*ecc));
+    if (!ecc)
+        return -ENOMEM;
+
+    memset(ecc, 0, sizeof(*ecc));
+
+    *ext_ecc = ecc;
+
+    ecc->regs = NFIECC_BASE;
+
+    mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+    writew(ECC_OP_DISABLE, ecc->regs + ECC_ENCCON);
+
+    mtk_ecc_wait_idle(ecc, ECC_DECODE);
+    writel(ECC_OP_DISABLE, ecc->regs + ECC_DECCON);
+
+    mutex_init(&ecc->lock);
+
+    /* register interrupt handler */
+    mtk_ecc_request_irq(ecc);
+
+    return 0;
+}
+
+
+int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config, int polling)
+{
+    enum mtk_ecc_operation op = config->op;
+
+    mutex_acquire(&ecc->lock);
+
+    mtk_ecc_wait_idle(ecc, op);
+    mtk_ecc_runtime_config(ecc, config);
+
+    if (!polling) {
+        writew(ECC_IRQ_EN, ecc->regs + ECC_IRQ_REG(op));
+    }
+
+    writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
+
+    return 0;
+}
+
+void mtk_ecc_disable(struct mtk_ecc *ecc)
+{
+    enum mtk_ecc_operation op = ECC_ENCODE;
+
+    /* find out the running operation */
+    if (readw(ecc->regs + ECC_CTL_REG(op)) != ECC_OP_ENABLE)
+        op = ECC_DECODE;
+
+    /* disable it */
+    mtk_ecc_wait_idle(ecc, op);
+    writew(0, ecc->regs + ECC_IRQ_REG(op));
+    writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op));
+
+    mutex_release(&ecc->lock);
+
+    return;
+}
+
+void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
+                       u32 sectors)
+{
+    u32 offset, i, err;
+    u32 bitflips = 0;
+
+    stats->corrected = 0;
+    stats->failed = 0;
+
+    for (i = 0; i < sectors; i++) {
+        offset = (i >> 2);
+        err = readl(ecc->regs + ECC_DECENUM(offset));
+        err = err >> ((i % 4) * 8);
+        err &= ERR_MASK;
+        if (err == ERR_MASK) {
+            /* uncorrectable errors */
+            stats->failed++;
+            dprintf(ALWAYS, "sector %d is uncorrect\n", i);
+            continue;
+        }
+
+        stats->corrected += err;
+        bitflips = MAX(bitflips, err);
+    }
+
+    stats->bitflips = bitflips;
+
+    return;
+}
+
+int mtk_ecc_wait_done(struct mtk_ecc *ecc, enum mtk_ecc_operation op, int polling)
+{
+    int ret = 0;
+
+    if (!polling) {
+        ret = mtk_ecc_irq_wait(ecc, ECC_TIMEOUT);
+        if (!ret) {
+            dprintf(CRITICAL, "mtk_ecc_wait_done timeout\n");
+            return -ETIMEDOUT;
+        }
+    } else {
+        if (op == ECC_ENCODE) {
+            if (!check_with_timeout((readl(ecc->regs + ECC_ENCSTA) & ENC_IDLE), ECC_TIMEOUT)) {
+                dprintf(CRITICAL, "encoder timeout\n");
+                return -ETIMEDOUT;
+            }
+        } else {
+            if (!check_with_timeout((readw(ecc->regs + ECC_DECDONE) & ecc->sectors), ECC_TIMEOUT)) {
+                dprintf(CRITICAL, "decoder timeout\n");
+                return -ETIMEDOUT;
+            }
+        }
+    }
+
+    return 0;
+}
+
+int mtk_ecc_wait_decode_fsm_idle(struct mtk_ecc *ecc)
+{
+    /* decode done does not stands for ecc all work done.
+     * we need check syn, bma, chien, autoc all idle.
+     * just check it when ECC_DECCNFG[13:12] is 3, which means auto correct.*/
+    if (!check_with_timeout(((readl(ecc->regs + ECC_DECFSM) & FSM_MASK) == FSM_IDLE), ECC_TIMEOUT)) {
+        dprintf(CRITICAL, "decode fsm(0x%x) is not idle\n", readl(ecc->regs + ECC_DECFSM));
+        return -ETIMEDOUT;
+    }
+
+    return 0;
+}
+
+int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+                   u8 *data, u32 bytes, int polling)
+{
+    uintptr_t addr;
+    u8 *p;
+    u8 *buf = data;
+    u32 len, i, val = 0;
+    int ret = 0;
+
+    /* encoder memory address should be 4B aligned */
+    if ((config->mode == ECC_DMA_MODE) && ((uintptr_t)buf & 0x3)) {
+        buf = memalign(4, bytes);
+        if (!buf)
+            return -ENOMEM;
+        memcpy(buf, data, bytes);
+    }
+#ifdef WITH_KERNEL_VM
+    addr = (uintptr_t)kvaddr_to_paddr(buf);
+#else
+    addr = (uintptr_t)buf;
+#endif
+    if (config->mode == ECC_DMA_MODE)
+        arch_clean_cache_range((addr_t)buf, (size_t)bytes);
+
+    config->op = ECC_ENCODE;
+    config->addr = (u32)addr;
+    config->len = bytes;
+
+    ret = mtk_ecc_enable(ecc, config, polling);
+    if (ret)
+        goto freebuf;
+
+    if (config->mode == ECC_PIO_MODE) {
+        for (i = 0; i < ((config->len + 3) >> 2); i++) {
+            mtk_ecc_wait_ioready(ecc);
+            writel(*((u32 *)data + i), ecc->regs + ECC_PIO_DI);
+        }
+    }
+
+    ret = mtk_ecc_wait_done(ecc, ECC_ENCODE, polling);
+    if (ret)
+        goto timeout;
+
+    mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+
+    /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
+    len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
+    p = data + bytes;
+
+    /* write the parity bytes generated by the ECC back to the OOB region */
+    for (i = 0; i < len; i++) {
+        if ((i % 4) == 0)
+            val = readl(ecc->regs + ECC_ENCPAR(i / 4));
+        p[i] = (val >> ((i % 4) * 8)) & 0xff;
+    }
+
+timeout:
+    mtk_ecc_disable(ecc);
+freebuf:
+    if (config->mode == ECC_DMA_MODE)
+        arch_invalidate_cache_range((addr_t)buf, (size_t)bytes);
+    if (buf != data)
+        free(buf);
+    return ret;
+}
+
+int mtk_ecc_decode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+                   u8 *data, u32 len, int polling)
+{
+    struct mtk_ecc_stats stats;
+    u8 *buf = data;
+    uintptr_t addr;
+    u32 decodesize, i;
+    int ret;
+
+    decodesize = len + ((config->strength * ECC_PARITY_BITS + 7) >> 3);
+    if ((decodesize & 0x3)
+            || ((config->mode == ECC_DMA_MODE) && ((uintptr_t)buf & 0x3))) {
+        decodesize += 4 - (decodesize & 0x3);
+        buf = memalign(4, decodesize);
+        if (!buf)
+            return -ENOMEM;
+    }
+    if (config->mode == ECC_DMA_MODE)
+        arch_invalidate_cache_range((addr_t)buf, (size_t)decodesize);
+#ifdef WITH_KERNEL_VM
+    addr = (uintptr_t)kvaddr_to_paddr(buf);
+#else
+    addr = (uintptr_t)buf;
+#endif
+    config->op = ECC_DECODE;
+    config->addr = (u32)addr;
+    config->len = len;
+    ret = mtk_ecc_enable(ecc, config, polling);
+    if (ret)
+        goto freebuf;
+
+    if (config->mode == ECC_PIO_MODE) {
+        for (i = 0; i < (decodesize >> 2); i++) {
+            mtk_ecc_wait_ioready(ecc);
+            writel(*((u32 *)buf + i), ecc->regs + ECC_PIO_DI);
+        }
+    }
+
+    stats.bitflips = 0;
+    ret = mtk_ecc_cpu_correct(ecc, &stats, buf, 0, polling);
+    if (ret)
+        goto disecc;
+
+    if (config->mode == ECC_DMA_MODE)
+        arch_invalidate_cache_range((addr_t)buf, (size_t)decodesize);
+    if (buf != data)
+        memcpy(data, buf, len);
+
+disecc:
+    mtk_ecc_disable(ecc);
+
+freebuf:
+    if (buf != data)
+        free(buf);
+
+    return ret;
+}
+
+int mtk_ecc_cpu_correct(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats, u8 *data, u32 sector, int polling)
+{
+    u32 err, offset, i;
+    u32 loc, byteloc, bitloc;
+    int ret;
+
+    ecc->sectors = 1 << sector;
+    ret = mtk_ecc_wait_done(ecc, ECC_DECODE, polling);
+    if (ret)
+        return ret;
+
+    stats->corrected = 0;
+    stats->failed = 0;
+
+    offset = (sector >> 2);
+    err = readl(ecc->regs + ECC_DECENUM(offset));
+    err = err >> ((sector % 4) * 8);
+    err &= ERR_MASK;
+    if (err == ERR_MASK) {
+        /* uncorrectable errors */
+        stats->failed++;
+        return 0;
+    }
+
+    stats->corrected += err;
+    stats->bitflips = MAX(stats->bitflips, err);
+
+    for (i = 0; i < err; i++) {
+        loc = readl(ecc->regs + ECC_DECEL(i >> 1));
+        loc >>= ((i & 0x1) << 4);
+        loc &= DECEL_MASK;
+        byteloc = loc >> 3;
+        bitloc = loc & 0x7;
+        data[byteloc] ^= (1 << bitloc);
+    }
+
+    return 0;
+}
+
+void mtk_ecc_adjust_strength(u32 *p)
+{
+    u32 ecc[] = {4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
+                 40, 44, 48, 52, 56, 60, 68, 72, 80
+                };
+    u32 i;
+
+    for (i = 0; i < sizeof(ecc) / sizeof(u32); i++) {
+        if (*p <= ecc[i]) {
+            if (!i)
+                *p = ecc[i];
+            else if (*p != ecc[i])
+                *p = ecc[i - 1];
+            return;
+        }
+    }
+
+    *p = ecc[sizeof(ecc) / sizeof(u32) - 1];
+
+    return;
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_bbt.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_bbt.c
new file mode 100644
index 0000000..91a89e8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_bbt.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2017 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 <errno.h>
+#include <malloc.h>
+#include <platform/nand/mtk_nand_nal.h>
+#include <platform/nand/mtk_nand_bbt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BBT_BLOCK_GOOD          0x03
+#define BBT_BLOCK_WORN          0x02
+#define BBT_BLOCK_RESERVED      0x01
+#define BBT_BLOCK_FACTORY_BAD   0x00
+
+#define BBT_ENTRY_MASK          0x03
+#define BBT_ENTRY_SHIFT         2
+
+#define BBT_PATTERN_LEN         4
+#define BBT_VERSION_LEN         1
+
+static int check_pattern(u8 *buf)
+{
+    uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
+    uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+    if (!memcmp(buf, bbt_pattern, BBT_PATTERN_LEN))
+        return 0;
+    if (!memcmp(buf, mirror_pattern, BBT_PATTERN_LEN))
+        return 0;
+
+    return 1;
+}
+
+static void bbt_mark_entry(struct mtk_nand_chip *chip, int block, u8 mask)
+{
+    u32 offset = BBT_PATTERN_LEN + BBT_VERSION_LEN;
+
+    mask = (mask & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
+    offset += block >> BBT_ENTRY_SHIFT;
+
+    chip->bbt[offset] &= ~(BBT_ENTRY_MASK << ((block & BBT_ENTRY_MASK) * 2));
+    chip->bbt[offset] |= mask;
+}
+
+static u8 bbt_get_entry(struct mtk_nand_chip *chip, int block)
+{
+    u32 offset = BBT_PATTERN_LEN + BBT_VERSION_LEN;
+    u8 entry;
+
+    offset += block >> BBT_ENTRY_SHIFT;
+    entry = chip->bbt[offset];
+    entry >>= (block & BBT_ENTRY_MASK) * 2;
+
+    return entry & BBT_ENTRY_MASK;
+}
+
+static int search_bbt(struct mtk_nand_chip *chip, int bbt_len)
+{
+    int block, i;
+    struct mtk_nand_ops ops;
+
+    memset(&ops, 0, sizeof(ops));
+
+    block = chip->totalsize / chip->blocksize;
+    block -= 1;
+
+    for (i = 0; i < SCAN_BBT_MAXBLOCKS; i++, block--) {
+        ops.mode = NAND_OPS_ECC_DMA_POLL;
+        ops.offset = (u64)block * chip->blocksize;
+        ops.len = (u64)bbt_len;
+        ops.readbuf = chip->bbt;
+        mtk_nand_read(chip, &ops);
+        if (!check_pattern(chip->bbt)) {
+            chip->bbt_block = block;
+            dprintf(CRITICAL, "found bbt at block %d, version 0x%02X\n",
+                    block, chip->bbt[BBT_PATTERN_LEN]);
+            return 0;
+        }
+    }
+
+    dprintf(CRITICAL, "failed to find bbt!\n");
+    return -1;
+}
+
+static int create_bbt(struct mtk_nand_chip *chip, int bbt_len)
+{
+    int i, blocks = chip->totalsize / chip->blocksize;
+
+    memset(chip->bbt, 0xff, bbt_len);
+
+    for (i = 0; i < blocks; i++) {
+        if (mtk_nand_block_checkbad(chip, i * chip->page_per_block)) {
+            bbt_mark_entry(chip, i, BBT_BLOCK_FACTORY_BAD);
+            dprintf(CRITICAL, "block %d is bad\n", i);
+        }
+    }
+
+    dprintf(ALWAYS, "create bbt done!\n");
+
+    return 0;
+}
+
+int mtk_nand_scan_bbt(struct mtk_nand_chip *chip)
+{
+    int len;
+    int ret = 0;
+
+    len = (chip->totalsize / chip->blocksize + 3) >> 2;
+    len += BBT_PATTERN_LEN + BBT_VERSION_LEN;
+    /* allocate bbt memory */
+    chip->bbt = malloc(len);
+    if (!chip->bbt)
+        return -ENOMEM;
+    memset(chip->bbt, 0xff, len);
+    chip->bbt_block = -1;
+
+    if (search_bbt(chip, len)) {
+        ret = create_bbt(chip, len);
+    }
+
+    return ret;
+}
+
+int mtk_nand_isbad_bbt(struct mtk_nand_chip *chip, u32 page)
+{
+    int block = page / chip->page_per_block;
+    u8 mask;
+
+    mask = bbt_get_entry(chip, block);
+
+    return mask != BBT_BLOCK_GOOD;
+}
+
+int mtk_nand_markbad_bbt(struct mtk_nand_chip *chip, u32 page)
+{
+    struct mtk_nand_ops ops;
+    int len, write_len;
+    int ret = 0, block = page / chip->page_per_block;
+
+    bbt_mark_entry(chip, block, BBT_BLOCK_WORN);
+
+    if (chip->bbt_block > 0) {
+        memset(&ops, 0, sizeof(struct mtk_nand_ops));
+        ops.mode = NAND_OPS_ERASE_POLL;
+        ops.offset = (u64)chip->bbt_block * chip->blocksize;
+        ops.len = chip->blocksize;
+        ret = mtk_nand_erase(chip, &ops);
+        if (ret)
+            goto err;
+
+        /* increase bbt version */
+        chip->bbt[BBT_PATTERN_LEN]++;
+
+        len = (chip->totalsize / chip->blocksize + 3) >> 2;
+        len += BBT_PATTERN_LEN + BBT_VERSION_LEN;
+        ops.mode = NAND_OPS_ECC_DMA_POLL;
+        ops.len = chip->pagesize;
+        ops.writebuf = chip->databuf;
+        while (len) {
+            write_len = MIN((u32)len, chip->pagesize);
+            memset(chip->databuf, 0, chip->pagesize);
+            memcpy(chip->databuf, chip->bbt, write_len);
+            ret = mtk_nand_write(chip, &ops);
+            if (ret)
+                goto err;
+            len -= write_len;
+            ops.offset += chip->pagesize;
+        }
+    }
+
+err:
+    return ret;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_device.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_device.c
new file mode 100644
index 0000000..4df5122
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_device.c
@@ -0,0 +1,35 @@
+/*
+* Copyright (c) 2017 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 <platform/nand/mtk_nand_common.h>
+#include <platform/nand/mtk_nand_nal.h>
+
+#define NAND_OPTIONS_NONE   (0)
+
+struct mtk_nand_flash_dev nand_flash_devs[] = {
+    {"W29N08GZSIBA", {0xef, 0xa3, 0x91, 0x15, 0x58, 0, 0, 0}, 5, KB(1024), KB(128), 2048, 64, 1, 1, 0x10804011, 1024, 12, NAND_OPTIONS_NONE, NAND_OPTIONS_NONE},
+    {"TC58NYG2S0HTA00", {0x98, 0xac, 0x90, 0x26, 0x76, 0, 0, 0}, 5, KB(512), KB(256), 4096, 256, 1, 1, 0x10804011, 1024, 32, NAND_OPTIONS_NONE, NAND_OPTIONS_NONE},
+    {"F59D4G81A-45TG-18V", {0xc8, 0xac, 0x90, 0x15, 0x54, 0, 0, 0}, 5, KB(512), KB(128), 2048, 64, 1, 1, 0x10804011, 1024, 12, NAND_OPTIONS_NONE, NAND_OPTIONS_NONE},
+    {"MT29F16G08ADBCA", {0x2c, 0xa5, 0xd1, 0x26, 0x68, 0, 0, 0}, 5, KB(2048), KB(256), 4096, 224, 1, 1, 0x10404011, 1024, 24, NAND_OPTIONS_NONE, NAND_CACHEREAD | NAND_CACHEPRG},
+    {NULL}
+};
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_nal.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_nal.c
new file mode 100644
index 0000000..85db42e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_nal.c
@@ -0,0 +1,923 @@
+/*
+ * Copyright (c) 2017 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 <errno.h>
+#include <kernel/mutex.h>
+#include <malloc.h>
+#include <platform/nand/mtk_nand_bbt.h>
+#include <platform/nand/mtk_nand_common.h>
+#include <platform/nand/mtk_nand_nal.h>
+#include <platform/nand/mtk_nfi_hal.h>
+#include <stdlib.h>
+#include <string.h>
+
+static struct mtk_nand_chip *nandchip;
+
+static int mtk_nand_do_read_ops(struct mtk_nand_chip *chip,
+                                struct mtk_nand_ops *ops);
+static int mtk_nand_do_erase_ops(struct mtk_nand_chip *chip,
+                                 struct mtk_nand_ops *ops);
+static int mtk_nand_do_write_ops(struct mtk_nand_chip *chip,
+                                 struct mtk_nand_ops *ops);
+
+static int mtk_nand_get_controller(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mutex_acquire(&nfc->lock);
+
+    return 0;
+}
+
+static int mtk_nand_release_controller(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mutex_release(&nfc->lock);
+
+    return 0;
+}
+
+static int mtk_nand_wait_func(struct mtk_nand_chip *chip, int polling)
+{
+    int status;
+    unsigned long timeo = 1000000;
+
+    chip->cmdfunc(chip, NAND_CMD_STATUS, -1, -1);
+
+    if (!polling) {
+        if (chip->wait_busy_irq(chip))
+            dprintf(CRITICAL, "nand dev ready timeout\n");
+    } else {
+        if (!check_with_timeout(chip->dev_ready(chip), timeo))
+            dprintf(CRITICAL, "nand dev ready timeout\n");
+    }
+
+    status = (int)chip->read_byte(chip);
+
+    return status;
+}
+
+void mtk_nand_wait_ready(struct mtk_nand_chip *chip)
+{
+    unsigned long timeo = 1000000;
+
+    if (!check_with_timeout(chip->dev_ready(chip), timeo))
+        dprintf(CRITICAL, "nand dev ready timeout\n");
+
+    return;
+}
+
+static int mtk_nand_check_wp(struct mtk_nand_chip *chip)
+{
+    /* Check the WP bit */
+    chip->cmdfunc(chip, NAND_CMD_STATUS, -1, -1);
+    return (chip->read_byte(chip) & NAND_STATUS_WP) ? 0 : 1;
+}
+
+static u8 mtk_nand_block_lock_status(struct mtk_nand_chip *chip, u32 row)
+{
+    u8 status;
+
+    chip->cmdfunc(chip, 0x7a, -1, row);
+    status = chip->read_byte(chip);
+    dprintf(INFO, "%s: row 0x%x, status 0x%x\n", __func__, row, status);
+
+    return status;
+}
+
+static int mtk_nand_block_bad(struct mtk_nand_chip *chip, u64 ofs)
+{
+    int page, res = 0, i = 0;
+    u16 bad;
+
+    if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+        ofs += chip->blocksize - chip->pagesize;
+
+    page = (int)(ofs / chip->pagesize) % chip->page_per_chip;
+
+    do {
+        chip->cmdfunc(chip, NAND_CMD_READOOB, chip->badblockpos, page);
+        bad = chip->read_byte(chip);
+
+        if (chip->badblockbits == 8)
+            res = bad != 0xFF;
+
+        ofs += chip->pagesize;
+        page = (int)(ofs / chip->pagesize) % chip->page_per_chip;
+        i++;
+    } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
+
+    return res;
+}
+
+int mtk_nand_block_checkbad(struct mtk_nand_chip *chip, u32 page)
+{
+    struct mtk_nand_ops ops;
+    int ret;
+
+    /* block align */
+    page = page / chip->page_per_block * chip->page_per_block;
+
+    if (!(chip->options & NAND_NEED_SCRAMBLING)) {
+        ret = chip->block_bad(chip, (u64)page * chip->pagesize);
+    } else {
+        /*
+         * The output data is randomized if randomizer is on,
+         * we will get a wrong result if just read one byte data.
+         * So, should read page directly.
+         */
+        memset(&ops, 0, sizeof(ops));
+        ops.mode = NAND_OPS_ECC_DMA_POLL;
+        ops.offset = (u64)page * chip->pagesize;
+        ops.len = chip->pagesize;
+        ops.readbuf = chip->databuf;
+        ret = mtk_nand_do_read_ops(chip, &ops);
+        if (ret < 0)
+            ret = 1;
+        else
+            ret = chip->oob_poi[chip->badblockpos] != 0xFF;
+    }
+
+    return ret;
+}
+
+static int mtk_nand_block_isbad_lowlevel(struct mtk_nand_chip *chip, u32 page)
+{
+    if (chip->bbt)
+        return mtk_nand_isbad_bbt(chip, page);
+    else
+        return mtk_nand_block_checkbad(chip, page);
+}
+
+int mtk_nand_block_isbad(struct mtk_nand_chip *chip, u32 page)
+{
+    int ret;
+
+    mtk_nand_get_controller(chip);
+    ret = mtk_nand_block_isbad_lowlevel(chip, page);
+    mtk_nand_release_controller(chip);
+
+    return ret;
+}
+
+int mtk_nand_block_markbad(struct mtk_nand_chip *chip, u32 page)
+{
+    struct mtk_nand_ops ops;
+    u32 i = 0;
+    int ret = 0;
+
+    mtk_nand_get_controller(chip);
+    /* block align */
+    page = page / chip->page_per_block * chip->page_per_block;
+
+    ops.mode = NAND_OPS_ERASE_POLL;
+    ops.offset = (u64)page * chip->pagesize;
+    ops.len = chip->blocksize;
+    mtk_nand_do_erase_ops(chip, &ops);
+
+    if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+        ops.offset += chip->blocksize - chip->pagesize;
+    ops.mode = NAND_OPS_ECC_DMA_POLL;
+    ops.writebuf = chip->databuf;
+    ops.len = chip->pagesize;
+    ops.oobeccbuf = &chip->oob_poi[chip->oob_free_ecc_size
+                                   + chip->oob_free_raw_size];
+    ops.oobecclen = chip->ecc_steps * chip->fdm_ecc_size;
+    ops.oobeccoffs = 0;
+    ops.oobrawbuf = NULL;
+    memset(chip->databuf, 0, chip->pagesize);
+    memset(ops.oobeccbuf, 0, ops.oobecclen);
+    do {
+        ops.offset += chip->pagesize;
+        mtk_nand_do_write_ops(chip, &ops);
+        i++;
+    } while (i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
+
+    mtk_nand_release_controller(chip);
+
+    if (chip->bbt)
+        ret = mtk_nand_markbad_bbt(chip, page);
+
+    return ret;
+}
+
+int nand_reset(struct mtk_nand_chip *chip, int chipnr)
+{
+    /* power on sequence delay */
+    spin(300);
+
+    /*
+     * The CS line has to be released before we can apply the new NAND
+     * interface settings, hence this weird ->select_chip() dance.
+     */
+    chip->select_chip(chip, chipnr);
+    chip->cmdfunc(chip, NAND_CMD_RESET, -1, -1);
+    chip->select_chip(chip, -1);
+
+    return 0;
+}
+
+static inline int mtk_nand_opcode_8bits(unsigned int command)
+{
+    switch (command) {
+        case NAND_CMD_READID:
+        case NAND_CMD_PARAM:
+        case NAND_CMD_GET_FEATURES:
+        case NAND_CMD_SET_FEATURES:
+            return 1;
+        default:
+            break;
+    }
+    return 0;
+}
+
+static void mtk_nand_command_lp(struct mtk_nand_chip *chip, unsigned int command,
+                                int column, int page_addr)
+{
+    /* Emulate NAND_CMD_READOOB */
+    if (command == NAND_CMD_READOOB) {
+        column += chip->pagesize;
+        command = NAND_CMD_READ0;
+    }
+
+    /* Command latch cycle */
+    chip->cmd_ctrl(chip, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+
+    if (column != -1 || page_addr != -1) {
+        int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
+
+        /* Serially input address */
+        if (column != -1) {
+            chip->cmd_ctrl(chip, column, ctrl);
+            ctrl &= ~NAND_CTRL_CHANGE;
+
+            /* Only output a single addr cycle for 8bits opcodes. */
+            if (!mtk_nand_opcode_8bits(command))
+                chip->cmd_ctrl(chip, column >> 8, ctrl);
+        }
+        if (page_addr != -1) {
+            chip->cmd_ctrl(chip, page_addr, ctrl);
+            chip->cmd_ctrl(chip, page_addr >> 8, NAND_NCE | NAND_ALE);
+            /* One more address cycle for devices > 128MiB */
+            if (chip->chipsize > (128 << 20))
+                chip->cmd_ctrl(chip, page_addr >> 16, NAND_NCE | NAND_ALE);
+        }
+    }
+    chip->cmd_ctrl(chip, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+    /*
+     * Program and erase have their own busy handlers status, sequential
+     * in and status need no delay.
+     */
+    switch (command) {
+        case NAND_CMD_CACHEDPROG:
+        case NAND_CMD_PAGEPROG:
+        case NAND_CMD_ERASE1:
+        case NAND_CMD_ERASE2:
+        case NAND_CMD_SEQIN:
+        case NAND_CMD_STATUS:
+            return;
+
+        case NAND_CMD_RNDOUT:
+            /* No ready / busy check necessary */
+            chip->cmd_ctrl(chip, NAND_CMD_RNDOUTSTART, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+            chip->cmd_ctrl(chip, NAND_CMD_NONE,
+                           NAND_NCE | NAND_CTRL_CHANGE);
+            return;
+
+        case NAND_CMD_READ0:
+            chip->cmd_ctrl(chip, NAND_CMD_READSTART, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+            chip->cmd_ctrl(chip, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+        /* This applies to read commands */
+        default:
+            break;
+    }
+
+    mtk_nand_wait_ready(chip);
+
+    return;
+}
+
+static void mtk_nand_set_defaults(struct mtk_nand_chip *chip)
+{
+    /* chip_delay setup set 20us if not */
+    chip->chip_delay = 20;
+
+    /* command function*/
+    chip->cmdfunc = mtk_nand_command_lp;
+
+    /* wait function */
+    chip->waitfunc = mtk_nand_wait_func;
+
+    /* bad block check */
+    chip->block_bad = mtk_nand_block_bad;
+
+    /* variable defalut value */
+    chip->badblockbits = 8;
+    chip->badblockpos = 0;
+
+    chip->activechip = -1;
+
+    return;
+}
+
+static int mtk_nand_onfi_set_features(struct mtk_nand_chip *chip,
+			int addr, u8 *subfeature_param)
+{
+    int status;
+    int i;
+
+    dprintf(INFO, "%s: addr 0x%x, f[0] 0x%x, f[1] 0x%x, f[2] 0x%x, f[3] 0x%x\n",
+            __func__, addr, subfeature_param[0], subfeature_param[1],
+            subfeature_param[2], subfeature_param[3]);
+    chip->cmdfunc(chip, NAND_CMD_SET_FEATURES, addr, -1);
+    for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+        chip->write_byte(chip, subfeature_param[i]);
+
+    status = chip->waitfunc(chip, chip);
+    if (status & NAND_STATUS_FAIL)
+        return -EIO;
+
+    return 0;
+}
+
+static int mtk_nand_onfi_get_features(struct mtk_nand_chip *chip,
+			int addr, u8 *subfeature_param)
+{
+    int i;
+
+    chip->cmdfunc(chip, NAND_CMD_GET_FEATURES, addr, -1);
+    for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+        *subfeature_param++ = chip->read_byte(chip);
+
+    dprintf(INFO, "%s: addr 0x%x, f[0] 0x%x, f[1] 0x%x, f[2] 0x%x, f[3] 0x%x\n",
+            __func__, addr, subfeature_param[0], subfeature_param[1],
+            subfeature_param[2], subfeature_param[3]);
+
+    return 0;
+}
+
+int mtk_nand_flash_get(struct mtk_nand_chip *chip, int maxchips)
+{
+    int i;
+    u8 id_data[8];
+    struct mtk_nand_flash_dev *type = nand_flash_devs;
+
+    nand_reset(chip, 0);
+
+    /* Select the device */
+    chip->select_chip(chip, 0);
+
+    /* Send the command for reading device ID */
+    chip->cmdfunc(chip, NAND_CMD_READID, 0x00, -1);
+
+    /* Read entire ID string */
+    for (i = 0; i < 8; i++) {
+        id_data[i] = chip->read_byte(chip);
+        dprintf(INFO, "nand id[%d] [%x] \n", i, id_data[i]);
+    }
+
+    for (; type->name != NULL; type++) {
+        if (!strncmp((char const*)type->id, (char const*)id_data, type->id_len)) {
+            dprintf(ALWAYS, "nand found [%s] \n", type->name);
+            break;
+        }
+    }
+
+    chip->select_chip(chip, -1);
+    if (!type->name) {
+        return -ENODEV;
+    }
+
+    chip->numchips = 1;
+
+    /* Check for a chip array */
+    for (i = 1; i < maxchips; i++) {
+        /* See comment in nand_get_flash_type for reset */
+        nand_reset(chip, i);
+
+        chip->select_chip(chip, i);
+        /* Send the command for reading device ID */
+        chip->cmdfunc(chip, NAND_CMD_READID, 0x00, -1);
+        /* Read manufacturer and device IDs */
+        if (id_data[0] != chip->read_byte(chip) ||
+                id_data[1] != chip->read_byte(chip)) {
+            chip->select_chip(chip, -1);
+            break;
+        }
+        dprintf(ALWAYS, "chip %d is found\n", i);
+        chip->select_chip(chip, -1);
+        chip->numchips++;
+    }
+
+    /* set nand chip parameters */
+    chip->pagesize = type->pagesize;
+    chip->oobsize = type->oobsize;
+    chip->bits_per_cell = type->bits_per_cell;
+    /* KB to B */
+    chip->chipsize = ((u64)type->chipsize) << 10;
+    chip->blocksize = type->erasesize;
+    chip->bbt_options |= type->bbt_options;
+    chip->options |= type->options;
+    chip->ecc_size = type->ecc_size;
+    chip->ecc_strength = type->ecc_strength;
+    chip->fdm_ecc_size = type->fdmeccsize;
+
+    chip->totalsize = i * chip->chipsize;
+
+    chip->ecc_steps = chip->pagesize / chip->ecc_size;
+    if (nand_is_slc(chip)) {
+        if (chip->ecc_steps == 2)
+            chip->subpagesize = chip->pagesize / 2;
+        else if (chip->ecc_steps > 2)
+            chip->subpagesize = chip->pagesize / 4;
+        else
+            chip->subpagesize = chip->pagesize;
+    }
+    chip->page_per_block = chip->blocksize / chip->pagesize;
+    chip->page_per_chip = chip->chipsize / chip->pagesize;
+
+    chip->databuf = (u8 *)memalign(16, chip->pagesize + chip->oobsize);
+    if (!chip->databuf)
+        return -ENOMEM;
+    chip->oob_poi = chip->databuf + chip->pagesize;
+
+    return 0;
+}
+
+int mtk_nand_scan(struct mtk_nand_chip *chip, int maxchips)
+{
+    int ret;
+
+    /* Set the defaults */
+    mtk_nand_set_defaults(chip);
+
+    ret = mtk_nand_flash_get(chip, maxchips);
+    if (ret) {
+        dprintf(CRITICAL, "no nand device found\n");
+        return ret;
+    }
+
+    return 0;
+}
+
+int mtk_nand_scan_tail(struct mtk_nand_chip *chip)
+{
+    int ret;
+
+    /* scan bad block table */
+    ret = mtk_nand_scan_bbt(chip);
+
+    return ret;
+}
+
+static int mtk_nand_transfer_oob(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int ret = 0;
+    u32 parity_size;
+
+    parity_size = chip->oobsize - chip->oob_free_raw_size
+                  - chip->oob_free_ecc_size;
+
+    if (ops->oobeccbuf && chip->transfer_oob_ecc) {
+        if (ops->oobeccoffs >= chip->oob_free_ecc_size
+            || ops->oobecclen > chip->oob_free_ecc_size - ops->oobeccoffs)
+            return -EINVAL;
+        ret = chip->transfer_oob_ecc(chip, ops->oobeccbuf, ops->oobeccoffs,
+                                     ops->oobecclen);
+        if (ret)
+            return ret;
+    }
+
+    if (ops->oobrawbuf && chip->transfer_oob_raw) {
+        if (ops->oobrawoffs >= chip->oob_free_raw_size
+            || ops->oobrawlen > chip->oob_free_raw_size - ops->oobrawoffs)
+            return -EINVAL;
+        ret = chip->transfer_oob_raw(chip, ops->oobrawbuf, ops->oobrawoffs,
+                                     ops->oobrawlen);
+    }
+
+    if (ops->oobparitybuf && chip->transfer_oob_parity) {
+        if (ops->oobparityoffs >= parity_size
+            || ops->oobparitylen > parity_size - ops->oobparityoffs)
+            return -EINVAL;
+        ret = chip->transfer_oob_parity(chip, ops->oobparitybuf, ops->oobparityoffs,
+                                        ops->oobparitylen);
+    }
+
+    return ret;
+}
+
+static int mtk_nand_do_read_ops(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int chipnr, page, realpage, col, aligned;
+    u8 *buf, *bufpoi;
+    u64 readlen = ops->len, from = ops->offset;
+    u32 bytes, ecc_failures = chip->stats.failed;
+    int ret = 0, ecc_fail = 0, max_bitflips = 0;
+    bool enable_cache = false;
+
+    chipnr = (int)(from / chip->chipsize);
+    chip->select_chip(chip, chipnr);
+
+    realpage = (int)(from / chip->pagesize);
+    page = realpage % chip->page_per_chip;
+    if (readlen == 0)
+        return 0;
+    if (NAND_HAS_CACHEREAD(chip) && (int)((from + readlen - 1) / chip->pagesize) > realpage)
+        enable_cache = true;
+
+    col = (int)(from & (chip->pagesize - 1));
+
+    buf = ops->readbuf;
+
+    while (1) {
+        bytes = MIN(chip->pagesize - col, readlen);
+        aligned = (bytes == chip->pagesize);
+        bufpoi = aligned ? buf : chip->databuf;
+
+        memset(chip->oob_poi, 0xff, chip->oobsize);
+
+        /* send read page command */
+        dprintf(INFO, "[nand] read page %d chip %d\n", page, chipnr);
+        chip->enable_randomizer(chip, page, RAND_DECODE, 0);
+
+        if (!enable_cache || realpage == (int)(from / chip->pagesize))
+            chip->cmdfunc(chip, NAND_CMD_READ0, 0x00, page);
+
+        if (enable_cache) {
+            if ((readlen - bytes) == 0)
+                chip->cmdfunc(chip, NAND_CMD_READCACHELAST, -1, -1);
+            else
+                chip->cmdfunc(chip, NAND_CMD_READCACHESEQ, -1, -1);
+        }
+
+        if (!aligned) {
+            if (ops->mode == NAND_OPS_ECC_DMA_IRQ)
+                ret = chip->read_subpage_ecc_dma_irq(chip, col, bytes, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_DMA_POLL)
+                ret = chip->read_subpage_ecc_dma_polling(chip, col, bytes, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_IRQ)
+                ret = chip->read_subpage_ecc_pio_irq(chip, col, bytes, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_POLL)
+                ret = chip->read_subpage_ecc_pio_polling(chip, col, bytes, bufpoi, page);
+        } else {
+            if (ops->mode == NAND_OPS_RAW_DMA_IRQ)
+                ret = chip->read_page_raw_dma_irq(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_RAW_DMA_POLL)
+                ret = chip->read_page_raw_dma_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_RAW_PIO_IRQ)
+                ret = chip->read_page_raw_pio_irq(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_RAW_PIO_POLL)
+                ret = chip->read_page_raw_pio_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_DMA_IRQ)
+                ret = chip->read_page_ecc_dma_irq(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_DMA_POLL)
+                ret = chip->read_page_ecc_dma_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_IRQ)
+                ret = chip->read_page_ecc_pio_irq(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_POLL)
+                ret = chip->read_page_ecc_pio_polling(chip, bufpoi, page);
+        }
+        chip->disable_randomizer(chip);
+        if (ret < 0)
+            break;
+
+        max_bitflips = MAX(max_bitflips, ret);
+
+        ret = mtk_nand_transfer_oob(chip, ops);
+        if (ret) {
+            max_bitflips = ret;
+            break;
+        }
+
+        if (chip->stats.failed - ecc_failures) {
+            ecc_fail = 1;
+            break;
+        }
+
+        if (!aligned)
+            memcpy(buf, chip->databuf + col, bytes);
+
+        readlen -= bytes;
+        buf += bytes;
+
+        if (!readlen)
+            break;
+
+        /* For subsequent reads align to page boundary */
+        col = 0;
+        /* Increment page address */
+        realpage++;
+
+        page = realpage % chip->page_per_chip;
+        /* Check, if we cross a chip boundary */
+        if (!page) {
+            chipnr++;
+            chip->select_chip(chip, -1);
+            chip->select_chip(chip, chipnr);
+        }
+    }
+    chip->select_chip(chip, -1);
+
+    if (ecc_fail)
+        return -EBADMSG;
+
+    return max_bitflips;
+}
+
+int mtk_nand_read(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int ret;
+
+    mtk_nand_get_controller(chip);
+    ret = mtk_nand_do_read_ops(chip, ops);
+    mtk_nand_release_controller(chip);
+
+    return ret;
+}
+
+static int mtk_nand_fill_oob(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int ret = 0;
+    u32 parity_size;
+
+    parity_size = chip->oobsize - chip->oob_free_raw_size
+                  - chip->oob_free_ecc_size;
+
+    memset(chip->oob_poi, 0xff, chip->oobsize);
+
+    if (ops->oobeccbuf && chip->fill_oob_ecc) {
+        if (ops->oobeccoffs >= chip->oob_free_ecc_size
+            || ops->oobecclen > chip->oob_free_ecc_size - ops->oobeccoffs)
+            return -EINVAL;
+        ret = chip->fill_oob_ecc(chip, ops->oobeccbuf, ops->oobeccoffs,
+                                 ops->oobecclen);
+        if (ret)
+            return ret;
+    }
+
+    if (ops->oobrawbuf && chip->fill_oob_raw) {
+        if (ops->oobrawoffs >= chip->oob_free_raw_size
+            || ops->oobrawlen > chip->oob_free_raw_size - ops->oobrawoffs)
+            return -EINVAL;
+        ret = chip->fill_oob_raw(chip, ops->oobrawbuf, ops->oobrawoffs,
+                                 ops->oobrawlen);
+    }
+
+    if (ops->oobparitybuf && chip->fill_oob_parity) {
+        if (ops->oobparityoffs >= parity_size
+            || ops->oobparitylen > parity_size - ops->oobparityoffs)
+            return -EINVAL;
+        ret = chip->fill_oob_parity(chip, ops->oobparitybuf, ops->oobparityoffs,
+                                    ops->oobparitylen);
+    }
+
+    return ret;
+}
+
+static int mtk_nand_do_write_ops(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int chipnr, realpage, page, col, aligned;
+    u32 bytes, writelen = ops->len;
+    u64 to = ops->offset;
+    const u8 *buf = ops->writebuf;
+    const u8 *bufpoi;
+    int ret = 0, status, polling_wait = 1;
+    bool enable_cache = false;
+
+    /* Reject writes, which are not subpage aligned */
+    if (!IS_ALIGNED(to, chip->subpagesize) || !IS_ALIGNED(ops->len, chip->subpagesize)) {
+        dprintf(CRITICAL, "attempt to write non page aligned data (offset 0x%llx, len 0x%llx)\n", to, ops->len);
+        return -EINVAL;
+    }
+
+    col = to & (chip->pagesize - 1);
+    chipnr = (int)(to / chip->chipsize);
+    chip->select_chip(chip, chipnr);
+
+    /* Check, if it is write protected */
+    if (mtk_nand_check_wp(chip)) {
+        ret = -EIO;
+        dprintf(CRITICAL, "write protected!\n");
+        goto err_out;
+    }
+
+    realpage = (int)(to / chip->pagesize);
+    page = realpage % chip->page_per_chip;
+    if (NAND_HAS_CACHEPROG(chip) && (int)((to + writelen) / chip->pagesize) > realpage)
+        enable_cache = true;
+
+    while (1) {
+        bytes = MIN(chip->pagesize - col, writelen);
+        aligned = (bytes == chip->pagesize);
+        bufpoi = aligned ? buf : chip->databuf;
+
+        if (!aligned) {
+            memset(chip->databuf, 0xff, chip->pagesize);
+            memcpy(chip->databuf + col, buf, bytes);
+        }
+
+        ret = mtk_nand_fill_oob(chip, ops);
+        if (ret)
+            break;
+
+        dprintf(INFO, "[nand] write page %d chip %d\n", page, chipnr);
+        chip->enable_randomizer(chip, page, RAND_ENCODE, 0);
+        chip->cmdfunc(chip, NAND_CMD_SEQIN, 0x00, page);
+
+        if (!aligned) {
+            if (ops->mode == NAND_OPS_ECC_DMA_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_subpage_ecc_dma_irq(chip, col, bytes, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_ECC_DMA_POLL)
+                ret = chip->write_subpage_ecc_dma_polling(chip, col, bytes, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_subpage_ecc_pio_irq(chip, col, bytes, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_ECC_PIO_POLL)
+                ret = chip->write_subpage_ecc_pio_polling(chip, col, bytes, bufpoi, page);
+        }
+        else {
+            if (ops->mode == NAND_OPS_RAW_DMA_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_page_raw_dma_irq(chip, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_RAW_DMA_POLL)
+                ret = chip->write_page_raw_dma_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_RAW_PIO_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_page_raw_pio_irq(chip, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_RAW_PIO_POLL)
+                ret = chip->write_page_raw_pio_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_DMA_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_page_ecc_dma_irq(chip, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_ECC_DMA_POLL)
+                ret = chip->write_page_ecc_dma_polling(chip, bufpoi, page);
+            else if (ops->mode == NAND_OPS_ECC_PIO_IRQ) {
+                polling_wait = 0;
+                ret = chip->write_page_ecc_pio_irq(chip, bufpoi, page);
+            }
+            else if (ops->mode == NAND_OPS_ECC_PIO_POLL)
+                ret = chip->write_page_ecc_pio_polling(chip, bufpoi, page);
+        }
+        chip->disable_randomizer(chip);
+        if (ret < 0)
+            break;
+
+        if (!enable_cache || (writelen - bytes) == 0)
+            chip->cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
+        else
+            chip->cmdfunc(chip, NAND_CMD_CACHEDPROG, -1, -1);
+        status = chip->waitfunc(chip, polling_wait);
+        if (status & NAND_STATUS_FAIL) {
+            ret = -EIO;
+            dprintf(CRITICAL, "write failed at page 0x%x\n", realpage);
+            goto err_out;
+        }
+
+        writelen -= bytes;
+        if (!writelen)
+            break;
+
+        col = 0;
+        buf += bytes;
+        realpage++;
+
+        page = realpage % chip->page_per_chip;
+        /* Check, if we cross a chip boundary */
+        if (!page) {
+            chipnr++;
+            chip->select_chip(chip, -1);
+            chip->select_chip(chip, chipnr);
+        }
+    }
+
+err_out:
+    chip->select_chip(chip, -1);
+
+    return ret;
+}
+
+int mtk_nand_write(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int ret;
+
+    mtk_nand_get_controller(chip);
+    ret = mtk_nand_do_write_ops(chip, ops);
+    mtk_nand_release_controller(chip);
+
+    return ret;
+}
+
+static int mtk_nand_do_erase_ops(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    u64 offset = ops->offset;
+    u64 eraselen = ops->len;
+    int page, status, ret = 0, chipnr, polling_wait = 0;
+
+    if ((offset % chip->blocksize) || (eraselen % chip->blocksize)) {
+        dprintf(CRITICAL, "erase is not aligned (off 0x%llx, len 0x%llx)\n", offset, eraselen);
+        return -EINVAL;
+    }
+
+    page = (int)(offset / chip->pagesize);
+    chipnr = (int)(offset / chip->chipsize);
+
+    chip->select_chip(chip, chipnr);
+
+    /* Check, if it is write protected */
+    if (mtk_nand_check_wp(chip)) {
+        ret = -EIO;
+        dprintf(CRITICAL, "write protected!\n");
+        goto err_out;
+    }
+
+    while (1) {
+        if (mtk_nand_block_isbad_lowlevel(chip, page)) {
+            ret = -EIO;
+            dprintf(CRITICAL, "attempt to erase bad block at page 0x%x\n",
+                    page);
+            goto err_out;
+        }
+
+        dprintf(INFO, "[nand] erase page %d chip %d\n", page, chipnr);
+        chip->cmdfunc(chip, NAND_CMD_ERASE1, -1, (page % chip->page_per_chip));
+        chip->cmdfunc(chip, NAND_CMD_ERASE2, -1, -1);
+        if (ops->mode == NAND_OPS_ERASE_IRQ)
+            polling_wait = 0;
+        else if (ops->mode == NAND_OPS_ERASE_POLL)
+            polling_wait = 1;
+        status = chip->waitfunc(chip, polling_wait);
+
+        if (status & NAND_STATUS_FAIL) {
+            ret = -EIO;
+            dprintf(CRITICAL, "erase failed at page 0x%x, status 0x%x\n",
+                    page, status);
+            goto err_out;
+        }
+
+        eraselen -= chip->blocksize;
+        if (!eraselen)
+            break;
+        page += chip->page_per_block;
+
+        if (eraselen && !(page % chip->page_per_chip)) {
+            chipnr++;
+            chip->select_chip(chip, -1);
+            chip->select_chip(chip, chipnr);
+        }
+    }
+err_out:
+    chip->select_chip(chip, -1);
+
+    return ret;
+}
+
+int mtk_nand_erase(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+    int ret;
+
+    mtk_nand_get_controller(chip);
+    ret = mtk_nand_do_erase_ops(chip, ops);
+    mtk_nand_release_controller(chip);
+
+    return ret;
+}
+
+int mtk_nand_init(void)
+{
+    return mtk_nfc_nand_chip_init(&nandchip);
+}
+
+struct mtk_nand_chip *mtk_get_nand_chip(void)
+{
+    return nandchip;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_nftl.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_nftl.c
new file mode 100644
index 0000000..306c6ed
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_nftl.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2018 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 <err.h>
+#include <errno.h>
+#include <lib/nftl.h>
+#include <malloc.h>
+#include <platform/nand/mtk_nand_nal.h>
+#include <pow2.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+struct mtk_nand_chip *chip;
+
+static ssize_t nand_write(struct nftl_info *info, const void *buf, off_t offset,
+                          ssize_t len)
+{
+    struct mtk_nand_ops ops;
+    int ret;
+
+    memset(&ops, 0, sizeof(ops));
+    ops.mode = NAND_OPS_ECC_DMA_POLL;
+    ops.offset = (u64)offset;
+    ops.len = (u64)len;
+    ops.writebuf = buf;
+
+    ret = mtk_nand_write(chip, &ops);
+
+    return (ret < 0) ? ret : len;
+}
+
+static ssize_t nand_read(struct nftl_info *info, void *buf, off_t offset,
+                         ssize_t len)
+{
+    struct mtk_nand_ops ops;
+    int ret;
+
+    memset(&ops, 0, sizeof(ops));
+    ops.mode = NAND_OPS_ECC_DMA_POLL;
+    ops.offset = (u64)offset;
+    ops.len = (u64)len;
+    ops.readbuf = buf;
+
+    ret = mtk_nand_read(chip, &ops);
+
+    return (ret < 0) ? ret : len;
+}
+
+static ssize_t nand_erase(struct nftl_info *info, off_t offset, ssize_t len)
+{
+    struct mtk_nand_ops ops;
+    int ret;
+
+    memset(&ops, 0, sizeof(ops));
+    ops.mode = NAND_OPS_ERASE_POLL;
+    ops.offset = (u64)offset;
+    ops.len = (u64)len;
+
+    ret = (ssize_t)mtk_nand_erase(chip, &ops);
+
+    return (ret < 0) ? ret : len;
+}
+
+static int nand_block_isbad(struct nftl_info *info, u32 page)
+{
+    return mtk_nand_block_isbad(chip, page);
+}
+
+int nand_init_device(void)
+{
+    struct nftl_info *info;
+    int ret;
+
+    ret = mtk_nand_init();
+    if (ret) {
+        dprintf(CRITICAL, "nand device init error (%d)!\n", ret);
+        return ret;
+    }
+
+    chip = mtk_get_nand_chip();
+
+    info = nftl_add_master("nand0");
+    if (!info)
+        return ERR_NO_MEMORY;
+
+    info->erase_size = chip->blocksize;
+    info->write_size = chip->pagesize;
+    info->total_size = chip->totalsize;
+    info->block_isbad = nand_block_isbad;
+    info->read = nand_read;
+    info->write = nand_write;
+    info->erase = nand_erase;
+
+    ret = nftl_mount_bdev(info);
+
+    return ret;
+}
+
+void nand_dump_device_info(void)
+{
+    dprintf(ALWAYS, "chip size: %#llx B\n", chip->chipsize);
+    dprintf(ALWAYS, "block size: %u B\n", chip->blocksize);
+    dprintf(ALWAYS, "page size: %u B\n", chip->pagesize);
+    dprintf(ALWAYS, "oob size: %u B\n", chip->oobsize);
+    dprintf(ALWAYS, "bits per cell: %d\n", chip->bits_per_cell);
+    dprintf(ALWAYS, "ecc size: %d\n", chip->ecc_size);
+    dprintf(ALWAYS, "ecc strength: %d\n", chip->ecc_strength);
+    dprintf(ALWAYS, "all fdm ecc size: %d\n", chip->oob_free_ecc_size);
+    dprintf(ALWAYS, "all fdm raw size: %d\n", chip->oob_free_raw_size);
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_test.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_test.c
new file mode 100644
index 0000000..3eefdab
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nand_test.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2018 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.
+ */
+#if WITH_LIB_CONSOLE
+
+#include <debug.h>
+#include <err.h>
+#include <lib/bio.h>
+#include <lib/console.h>
+#include <lib/mempool.h>
+#include <platform.h>
+#include <platform/nand/mtk_nand_nal.h>
+#include <platform/nand/mtk_nand_bbt.h>
+#include <platform/nand/nand.h>
+#include <rand.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define TEST_BUFFER_SIZE (0x80000)
+
+static void gen_rand_data(u8 *buf, size_t len)
+{
+    u32 i;
+
+    for (i = 0; i < len; i++)
+        buf[i] = (u8)rand();
+}
+
+static int compare_data(u8 *src, u8 *dest, size_t len)
+{
+    u32 i;
+
+    for (i = 0; i < len; i++) {
+        if (src[i] != dest[i]) {
+            printf("ERROR at %d: should be 0x%x, is 0x%x\n", i, src[i], dest[i]);
+            return ERR_IO;
+        }
+    }
+
+    return 0;
+}
+
+static int nand_speed_test(const char *device)
+{
+    int ret = 0;
+    u8 *wbuf, *rbuf;
+    bdev_t *dev;
+    ssize_t valid_total_size, left, test_size;
+    lk_bigtime_t delta_time, start_time;
+
+    dev = bio_open(device);
+    if (!dev) {
+        dev = bio_open_by_label(device);
+        if (!dev) {
+            printf("error opening block device: %s\n", device);
+            return ERR_NOT_FOUND;
+        }
+    }
+
+    wbuf = mempool_alloc(TEST_BUFFER_SIZE, MEMPOOL_ANY);
+    if (wbuf == NULL) {
+        ret = ERR_NO_MEMORY;
+        goto closedev;
+    }
+
+    rbuf = mempool_alloc(TEST_BUFFER_SIZE, MEMPOOL_ANY);
+    if (rbuf == NULL) {
+        ret = ERR_NO_MEMORY;
+        goto freewbuf;
+    }
+
+    gen_rand_data(wbuf, TEST_BUFFER_SIZE);
+
+    printf("begin erase test!\n");
+    delta_time = current_time_hires();
+    valid_total_size = bio_erase(dev, 0, dev->total_size);
+    delta_time = current_time_hires() - delta_time;
+    printf("erase speed is: %llu KB/s\n", (valid_total_size * 1000000) / (delta_time * 1024));
+
+    printf("begin write test!\n");
+    left = valid_total_size;
+    delta_time = current_time_hires();
+    while (left) {
+        test_size = MIN(TEST_BUFFER_SIZE, left);
+        ret = bio_write(dev, wbuf, valid_total_size - left, test_size);
+        if (ret < 0)
+            goto freerbuf;
+        left -= test_size;
+    };
+    delta_time = current_time_hires() - delta_time;
+    printf("write speed is: %llu KB/s\n", (valid_total_size * 1000000) / (delta_time * 1024));
+
+    printf("begin read test!\n");
+    left = valid_total_size;
+    delta_time = 0;
+    while (left) {
+        start_time = current_time_hires();
+        test_size = MIN(TEST_BUFFER_SIZE, left);
+        ret = bio_read(dev, rbuf, valid_total_size - left, test_size);
+        if (ret < 0)
+            goto freerbuf;
+        delta_time += current_time_hires() - start_time;
+        ret = compare_data(wbuf, rbuf, test_size);
+        if (ret < 0)
+            goto freerbuf;
+        left -= test_size;
+    }
+    printf("read speed is: %llu KB/s\n", (valid_total_size * 1000000) / (delta_time * 1024));
+
+freerbuf:
+    mempool_free(rbuf);
+freewbuf:
+    mempool_free(wbuf);
+closedev:
+    bio_close(dev);
+
+    return ret;
+}
+
+#define CBIT(v, n) ((v) & (1 << (n)))
+#define BCLR(v, n) ((v) = (v) & ~(1 << (n)))
+static u32 insert_biterrors(u32 byte, u32 boundary, u32 errors, u8 *buf)
+{
+    int bit;
+
+    while (byte < boundary && errors) {
+        for (bit = 7; bit >= 0; bit--) {
+            if (CBIT(buf[byte], bit)) {
+                BCLR(buf[byte], bit);
+                printf("%s: Inserted biterror @ %u/%u\n", __func__, byte, bit);
+                if (--errors == 0)
+                    break;
+            }
+        }
+        byte++;
+    }
+
+    return errors;
+}
+
+static int nand_bit_errors_test(u32 page, u32 error_num)
+{
+    struct mtk_nand_chip *chip = mtk_get_nand_chip();
+    struct mtk_nand_ops ops;
+    u8 *rbuf, *wbuf;
+    u32 buf_size, i, byte, parity_per_sector;
+    u32 parity_bytes = chip->ecc_strength * ECC_PARITY_BITS / 8 - 1;
+    u32 errs;
+    int ret;
+
+    /* error num 0 means full ecc strength */
+    if (error_num == 0)
+        error_num = chip->ecc_strength;
+    errs = error_num;
+
+    buf_size = chip->pagesize + chip->oobsize;
+
+    rbuf = mempool_alloc(buf_size, MEMPOOL_ANY);
+    if (rbuf == NULL)
+        return ERR_NO_MEMORY;
+    memset(rbuf, 0xff, buf_size);
+
+    wbuf = mempool_alloc(buf_size, MEMPOOL_ANY);
+    if (wbuf == NULL) {
+        ret = ERR_NO_MEMORY;
+        goto freerbuf;
+    }
+    memset(wbuf, 0xff, buf_size);
+
+    if (mtk_nand_block_isbad(chip, page)) {
+        printf("%s: page %u is bad!\n", __func__, page);
+        ret = ERR_FAULT;
+        goto freewbuf;
+    }
+
+    memset(&ops, 0, sizeof(ops));
+
+    ops.mode = NAND_OPS_ECC_DMA_POLL;
+    ops.offset = (u64)page * chip->pagesize;
+    ops.len = (u64)chip->pagesize;
+    ops.readbuf = rbuf;
+    ret = mtk_nand_read(chip, &ops);
+    if (ret < 0)
+        goto freewbuf;
+    printf("%s: max bit errors before rewrite: %d\n", __func__, ret);
+
+    memset(rbuf, 0xff, buf_size);
+    ops.mode = NAND_OPS_RAW_DMA_POLL;
+    ops.oobeccbuf = ops.readbuf + chip->pagesize;
+    ops.oobeccoffs = 0;
+    ops.oobecclen = chip->oob_free_ecc_size;
+    ops.oobrawbuf = ops.oobeccbuf + chip->oob_free_ecc_size;
+    ops.oobrawoffs = 0;
+    ops.oobrawlen = chip->oob_free_raw_size;
+    ops.oobparitybuf = ops.oobrawbuf + chip->oob_free_raw_size;
+    ops.oobparityoffs = 0;
+    ops.oobparitylen = chip->oobsize - chip->oob_free_ecc_size
+                       - chip->oob_free_raw_size;
+    parity_per_sector = ops.oobparitylen / chip->ecc_steps;
+    ret = mtk_nand_read(chip, &ops);
+    if (ret < 0)
+        goto freewbuf;
+    memcpy(wbuf, rbuf, chip->pagesize + chip->oobsize);
+
+    /* introduce deliberate bit errors */
+    for (i = 0; i < chip->ecc_steps; i++) {
+        errs = error_num;
+
+        /* one bit error in fdm data area */
+        printf("%s: sector %u insert fdm data area error\n", __func__, i);
+        byte = (u32)rand() % chip->fdm_ecc_size;
+        byte += i * chip->fdm_ecc_size;
+        ret = insert_biterrors(byte, (i + 1) * chip->fdm_ecc_size, 1,
+                               ops.oobeccbuf);
+        errs -= (1 - ret);
+
+        if (errs == 0)
+            continue;
+
+        /* one bit error in parity data area */
+        printf("%s: sector %u insert parity data area error\n", __func__, i);
+        byte = (u32)rand() % parity_bytes;
+        byte += i * parity_per_sector;
+        ret = insert_biterrors(byte, (i + 1) * parity_per_sector, 1,
+                               ops.oobparitybuf);
+
+        errs -= (1 - ret);
+
+        if (errs == 0)
+            continue;
+
+        /* error in main data area */
+        printf("%s: sector %u insert main data area error\n", __func__, i);
+        byte = (u32)rand() % chip->ecc_size;
+        byte += i * chip->ecc_size;
+        ret = insert_biterrors(byte, (i + 1) * chip->ecc_size, errs,
+                               ops.readbuf);
+        errs -= (errs - ret);
+
+        if (errs)
+            printf("%s: sector %d insert errors not enough, left %u\n",
+                   __func__, i, errs);
+    }
+
+    ops.writebuf = rbuf;
+    ret = mtk_nand_write(chip, &ops);
+    if (ret < 0)
+        goto freewbuf;
+
+    /* readback */
+    memset(rbuf, 0xff, chip->pagesize + chip->oobsize);
+    ops.mode = NAND_OPS_ECC_DMA_POLL;
+    ops.oobrawbuf = NULL;
+    ops.oobparitybuf = NULL;
+    ret = mtk_nand_read(chip, &ops);
+    if (ret < 0)
+        goto freewbuf;
+    else
+        printf("%s: max bit errors after rewrite: %d\n", __func__, ret);
+
+    /* verify data */
+    for (i = 0; i < chip->pagesize + chip->oob_free_ecc_size; i++) {
+        if (wbuf[i] != rbuf[i]) {
+            printf("%s: byte %d is different: 0x%x != 0x%x, %p %p\n",
+                   __func__, i, wbuf[i], rbuf[i], &wbuf[i], &rbuf[i]);
+            hexdump(rbuf, chip->pagesize + chip->oobsize);
+            ret = ERR_IO;
+            goto freewbuf;
+        }
+    }
+
+freewbuf:
+    mempool_free(wbuf);
+freerbuf:
+    mempool_free(rbuf);
+
+    printf("%s: %u bit errors test %s\n", __func__, error_num,
+           ret < 0 ? "Failed" : "OK");
+
+    return ret;
+}
+
+static int nand_create_bbt(void)
+{
+    struct mtk_nand_chip *chip = mtk_get_nand_chip();
+    struct mtk_nand_ops ops;
+    u32 i, page;
+    int ret;
+
+    /* Free BBT */
+    free(chip->bbt);
+    chip->bbt = NULL;
+    chip->bbt_block = -1;
+
+    /* Erase BBT area */
+    for (i = 1; i <= SCAN_BBT_MAXBLOCKS; i++) {
+        page = chip->totalsize - chip->blocksize * i;
+        page /= chip->pagesize;
+        if (mtk_nand_block_isbad(chip, page))
+            continue;
+        memset(&ops, 0, sizeof(ops));
+        ops.mode = NAND_OPS_ERASE_POLL;
+        ops.offset = (u64)page * chip->pagesize;
+        ops.len = chip->blocksize;
+        mtk_nand_erase(chip, &ops);
+    }
+
+    ret = mtk_nand_scan_bbt(chip);
+
+    return ret;
+}
+
+static int cmd_nand(int argc, const cmd_args *argv)
+{
+    int ret = 0;
+
+    if (argc < 2) {
+notenoughargs:
+        printf("not enough arguments:\n");
+usage:
+        printf("%s info\n", argv[0].str);
+        printf("%s list\n", argv[0].str);
+        printf("%s speedtest <device>\n", argv[0].str);
+        printf("%s biterrstest <page> <error num>\n", argv[0].str);
+        printf("%s createbbt\n", argv[0].str);
+        return -1;
+    }
+
+    if (!strcmp(argv[1].str, "info")) {
+        nand_dump_device_info();
+    } else if (!strcmp(argv[1].str, "list")) {
+        bio_dump_devices();
+    } else if (!strcmp(argv[1].str, "speedtest")) {
+        if (argc < 3) goto notenoughargs;
+
+        ret = nand_speed_test(argv[2].str);
+    } else if (!strcmp(argv[1].str, "biterrstest")) {
+        if (argc < 4) goto notenoughargs;
+
+        ret = nand_bit_errors_test(argv[2].u, argv[3].u);
+    } else if (!strcmp(argv[1].str, "createbbt")) {
+        ret = nand_create_bbt();
+    } else {
+        printf("error: command %s not support\n", argv[1].str);
+        goto usage;
+    }
+
+    return ret;
+}
+
+STATIC_COMMAND_START
+STATIC_COMMAND("nand", "nand driver test & debug commands", &cmd_nand)
+STATIC_COMMAND_END(nand);
+
+#endif /* WITH_LIB_CONSOLE */
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nfi_hal.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nfi_hal.c
new file mode 100644
index 0000000..a84f6f4
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/mtk_nfi_hal.c
@@ -0,0 +1,1850 @@
+/*
+ * Copyright (c) 2017 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 <arch/ops.h>
+#include <errno.h>
+#include <kernel/event.h>
+#include <kernel/mutex.h>
+#include <kernel/vm.h>
+#include <malloc.h>
+#include <platform/interrupts.h>
+#include <platform/mt_irq.h>
+#include <platform/mt_reg_base.h>
+#include <platform/nand/mtk_ecc_hal.h>
+#include <platform/nand/mtk_nand_common.h>
+#include <platform/nand/mtk_nand_nal.h>
+#include <platform/nand/mtk_nfi_hal.h>
+#include <reg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct mtk_nand_chip *chip)
+{
+    return containerof(chip, struct mtk_nfc_nand_chip, chip);
+}
+
+static inline u8 *data_ptr(struct mtk_nand_chip *chip, const u8 *p, int i)
+{
+    return (u8 *)p + i * chip->ecc_size;
+}
+
+static inline int mtk_data_len(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+
+    return chip->ecc_size + mtk_nand->spare_per_sector;
+}
+
+static inline u8 *mtk_data_ptr(struct mtk_nand_chip *chip,  int i)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    return nfc->buffer + i * mtk_data_len(chip);
+}
+
+static inline u8 *oob_ptr(struct mtk_nand_chip *chip, u32 i)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    u8 *poi;
+
+    /* map the sector's FDM data to free oob:
+     * the beginning of the oob area stores the FDM data of bad mark sectors
+     */
+    if (i < mtk_nand->bad_mark.sec)
+        poi = chip->oob_poi + (i + 1) * mtk_nand->fdm.reg_size;
+    else if (i == mtk_nand->bad_mark.sec)
+        poi = chip->oob_poi;
+    else
+        poi = chip->oob_poi + i * mtk_nand->fdm.reg_size;
+
+    return poi;
+}
+
+static inline u8 *oob_parity_ptr(struct mtk_nand_chip *chip, u32 i)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    u32 parity_size = mtk_nand->spare_per_sector - mtk_nand->fdm.reg_size;
+    u32 fdm_total_size = mtk_nand->fdm.reg_size * chip->ecc_steps;
+    u8 *poi;
+
+    poi = chip->oob_poi + fdm_total_size;
+
+    if (i < mtk_nand->bad_mark.sec)
+        poi += (i + 1) * parity_size;
+    else if (i > mtk_nand->bad_mark.sec)
+        poi += i * parity_size;
+
+    return poi;
+}
+
+static inline u8 *mtk_oob_ptr(struct mtk_nand_chip *chip, int i)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    return nfc->buffer + i * mtk_data_len(chip) + chip->ecc_size;
+}
+
+static inline u8 *mtk_oob_parity_ptr(struct mtk_nand_chip *chip, int i)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+
+    return mtk_oob_ptr(chip, i) + mtk_nand->fdm.reg_size; 
+}
+
+static inline void nfi_writel(struct mtk_nfc *nfc, u32 val, u32 reg)
+{
+    writel(val, nfc->regs + reg);
+
+    return;
+}
+
+static inline void nfi_writew(struct mtk_nfc *nfc, u16 val, u32 reg)
+{
+    (*REG16(nfc->regs + reg) = (val));
+
+    return;
+}
+
+static inline void nfi_writeb(struct mtk_nfc *nfc, u8 val, u32 reg)
+{
+    writeb(val, nfc->regs + reg);
+
+    return;
+}
+
+static inline u32 nfi_readl(struct mtk_nfc *nfc, u32 reg)
+{
+    return readl(nfc->regs + reg);
+}
+
+static inline u16 nfi_readw(struct mtk_nfc *nfc, u32 reg)
+{
+    return *REG16(nfc->regs + reg);
+}
+
+static inline u8 nfi_readb(struct mtk_nfc *nfc, u32 reg)
+{
+    return readb(nfc->regs + reg);
+}
+
+static void mtk_nfc_hw_reset(struct mtk_nfc *nfc)
+{
+    /* reset all registers and force the NFI master to terminate */
+    nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
+
+    /* wait for the master to finish the last transaction */
+    if (!check_with_timeout(!(nfi_readl(nfc, NFI_MASTER_STA) & MASTER_STA_MASK),
+                            MTK_RESET_TIMEOUT))
+        dprintf(CRITICAL, "NFI HW reset timeout!\n");
+
+    /* ensure any status register affected by the NFI master is reset */
+    nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
+    nfi_writew(nfc, STAR_DE, NFI_STRDATA);
+
+    return;
+}
+
+static int mtk_nfc_send_command(struct mtk_nfc *nfc, u8 command)
+{
+    nfi_writel(nfc, command, NFI_CMD);
+
+    if (!check_with_timeout(!(nfi_readl(nfc, NFI_STA) & STA_CMD), MTK_TIMEOUT))
+        dprintf(CRITICAL, "send cmd 0x%x timeout\n", command);
+
+    return 0;
+}
+
+static int mtk_nfc_send_address(struct mtk_nfc *nfc, int addr)
+{
+    nfi_writel(nfc, addr, NFI_COLADDR);
+    nfi_writel(nfc, 0, NFI_ROWADDR);
+    nfi_writew(nfc, 1, NFI_ADDRNOB);
+
+    if (!check_with_timeout(!(nfi_readl(nfc, NFI_STA) & STA_ADDR), MTK_TIMEOUT))
+        dprintf(CRITICAL, "send addr 0x%x timeout\n", addr);
+
+    return 0;
+}
+
+static int mtk_nfc_irq_wait(struct mtk_nfc *nfc, lk_time_t timeout)
+{
+    int ret;
+
+    ret = event_wait_timeout(&nfc->irq_event, timeout);
+    if (ret != 0) {
+        dprintf(CRITICAL, "[%s]: failed to get event INT=0x%x\n",
+                __func__, nfi_readw(nfc, NFI_INTR_EN));
+        return ret;
+    }
+
+    return 0;
+}
+
+static enum handler_return mtk_nfc_interrupt_handler(void *arg)
+{
+    struct mtk_nfc *nfc = arg;
+    u16 sta, ien;
+
+    sta = nfi_readw(nfc, NFI_INTR_STA);
+    ien = nfi_readw(nfc, NFI_INTR_EN);
+    if (!(sta & ien))
+        return INT_NO_RESCHEDULE;
+
+    nfi_writew(nfc, ~sta & ien, NFI_INTR_EN);
+
+    /* MUST BE *false*! otherwise, schedule in interrupt */
+    event_signal(&nfc->irq_event, false);
+
+    return INT_RESCHEDULE;
+}
+
+static int mtk_nfc_request_irq(struct mtk_nfc *nfc)
+{
+    mt_irq_set_sens(NFI_IRQ_BIT_ID, LEVEL_SENSITIVE);
+    mt_irq_set_polarity(NFI_IRQ_BIT_ID, MT65xx_POLARITY_LOW);
+    event_init(&nfc->irq_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+    register_int_handler(NFI_IRQ_BIT_ID, mtk_nfc_interrupt_handler, nfc);
+    unmask_interrupt(NFI_IRQ_BIT_ID);
+
+    return 0;
+}
+
+static int mtk_nfc_hw_runtime_config(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    u32 fmt, spare;
+
+    if (!chip->pagesize)
+        return -EINVAL;
+
+    spare = mtk_nand->spare_per_sector;
+
+    switch (chip->pagesize) {
+        case 512:
+            fmt = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512;
+            break;
+        case KB(2):
+            if (chip->ecc_size == 512)
+                fmt = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512;
+            else
+                fmt = PAGEFMT_512_2K;
+            break;
+        case KB(4):
+            if (chip->ecc_size == 512)
+                fmt = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512;
+            else
+                fmt = PAGEFMT_2K_4K;
+            break;
+        case KB(8):
+            if (chip->ecc_size == 512)
+                fmt = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512;
+            else
+                fmt = PAGEFMT_4K_8K;
+            break;
+        case KB(16):
+            fmt = PAGEFMT_8K_16K;
+            break;
+        default:
+            dprintf(CRITICAL, "invalid page len: %d\n", chip->pagesize);
+            return -EINVAL;
+    }
+
+    /*
+     * the hardware will double the value for this eccsize, so we need to
+     * halve it
+     */
+    if (chip->ecc_size == 1024)
+        spare >>= 1;
+
+    switch (spare) {
+        case 16:
+            fmt |= (PAGEFMT_SPARE_16 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 26:
+            fmt |= (PAGEFMT_SPARE_26 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 27:
+            fmt |= (PAGEFMT_SPARE_27 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 28:
+            fmt |= (PAGEFMT_SPARE_28 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 32:
+            fmt |= (PAGEFMT_SPARE_32 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 36:
+            fmt |= (PAGEFMT_SPARE_36 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 40:
+            fmt |= (PAGEFMT_SPARE_40 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 44:
+            fmt |= (PAGEFMT_SPARE_44 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 48:
+            fmt |= (PAGEFMT_SPARE_48 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 49:
+            fmt |= (PAGEFMT_SPARE_49 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 50:
+            fmt |= (PAGEFMT_SPARE_50 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 51:
+            fmt |= (PAGEFMT_SPARE_51 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 52:
+            fmt |= (PAGEFMT_SPARE_52 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 62:
+            fmt |= (PAGEFMT_SPARE_62 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 63:
+            fmt |= (PAGEFMT_SPARE_63 << PAGEFMT_SPARE_SHIFT);
+            break;
+        case 64:
+            fmt |= (PAGEFMT_SPARE_64 << PAGEFMT_SPARE_SHIFT);
+            break;
+        default:
+            dprintf(CRITICAL, "invalid spare per sector %d\n", spare);
+            return -EINVAL;
+    }
+
+    fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
+    fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_SHIFT;
+    nfi_writel(nfc, fmt, NFI_PAGEFMT);
+
+    nfc->ecc_cfg.strength = chip->ecc_strength;
+    nfc->ecc_cfg.len = chip->ecc_size + mtk_nand->fdm.ecc_size;
+
+    return 0;
+}
+
+static void mtk_nfc_select_chip(struct mtk_nand_chip *chip, int chip_num)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    if ((chip_num < 0) || (chip_num == chip->activechip))
+        return;
+
+    if (!mtk_nfc_hw_runtime_config(chip)) {
+        chip->activechip = chip_num;
+    }
+
+    nfi_writel(nfc, chip_num, NFI_CSEL);
+
+    return;
+}
+
+static int mtk_nfc_dev_ready(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
+        return 0;
+
+    return 1;
+}
+
+static int mtk_nfc_wait_busy_irq(struct mtk_nand_chip *chip)
+{
+    int ret;
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    /* set wait busy interrupt */
+    nfi_writew(nfc, INTR_BUSY_RETURN_EN, NFI_INTR_EN);
+
+    /* wait interrupt */
+    ret = mtk_nfc_irq_wait(nfc, MTK_TIMEOUT);
+    if (!ret) {
+        dprintf(CRITICAL, "wait busy interrupt timeout\n");
+        nfi_writew(nfc, 0, NFI_INTR_EN);
+        return -ETIMEDOUT;
+    }
+
+    return 0;
+}
+
+static void mtk_nfc_cmd_ctrl(struct mtk_nand_chip *chip, int dat, unsigned int ctrl)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    u16 reg;
+
+    if (ctrl & NAND_ALE) {
+        mtk_nfc_send_address(nfc, dat);
+    } else if (ctrl & NAND_CLE) {
+        mtk_nfc_hw_reset(nfc);
+
+        reg = nfi_readw(nfc, NFI_CNFG);
+        reg &= CNFG_RAND_MASK;
+        reg |= CNFG_OP_CUST;
+        nfi_writew(nfc, reg, NFI_CNFG);
+        mtk_nfc_send_command(nfc, dat);
+    }
+
+    return;
+}
+
+static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
+{
+    if (!check_with_timeout((nfi_readl(nfc, NFI_PIO_DIRDY) & PIO_DI_RDY), MTK_TIMEOUT)) {
+        dprintf(CRITICAL, "data not ready\n");
+        dprintf(CRITICAL, "cntr 0x%x cnfg 0x%x fmt 0x%x con 0x%x\n", nfi_readl(nfc, NFI_BYTELEN),
+                nfi_readl(nfc, NFI_CNFG), nfi_readl(nfc, NFI_PAGEFMT), nfi_readl(nfc, NFI_CON));
+    }
+
+    return;
+}
+
+static inline u8 mtk_nfc_read_byte(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    u32 reg;
+
+    /* after each byte read, the NFI_STA reg is reset by the hardware */
+    reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
+    if (reg != NFI_FSM_CUSTDATA) {
+        reg = nfi_readw(nfc, NFI_CNFG);
+        reg |= CNFG_BYTE_RW | CNFG_READ_EN;
+        nfi_writew(nfc, reg, NFI_CNFG);
+
+        /*
+         * set to max sector to allow the HW to continue reading over
+         * unaligned accesses
+         */
+        reg = (MTK_MAX_SECTOR << CON_SEC_SHIFT) | CON_BRD;
+        nfi_writel(nfc, reg, NFI_CON);
+
+        /* trigger to fetch data */
+        nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+    }
+
+    mtk_nfc_wait_ioready(nfc);
+
+    return nfi_readb(nfc, NFI_DATAR);
+}
+
+static void mtk_nfc_read_buf(struct mtk_nand_chip *chip, u8 *buf, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        buf[i] = mtk_nfc_read_byte(chip);
+
+    return;
+}
+
+static void mtk_nfc_write_byte(struct mtk_nand_chip *chip, u8 byte)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    u32 reg;
+
+    reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
+
+    if (reg != NFI_FSM_CUSTDATA) {
+        reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
+        nfi_writew(nfc, reg, NFI_CNFG);
+
+        reg = MTK_MAX_SECTOR << CON_SEC_SHIFT | CON_BWR;
+        nfi_writel(nfc, reg, NFI_CON);
+
+        nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+    }
+
+    mtk_nfc_wait_ioready(nfc);
+    nfi_writeb(nfc, byte, NFI_DATAW);
+
+    return;
+}
+
+static void mtk_nfc_write_buf(struct mtk_nand_chip *chip, const u8 *buf, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        mtk_nfc_write_byte(chip, buf[i]);
+
+    return;
+}
+
+static int mtk_nfc_sector_encode(struct mtk_nand_chip *chip, u8 *data, int dma, int polling)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    int size = chip->ecc_size + mtk_nand->fdm.reg_size;
+
+    if (dma)
+        nfc->ecc_cfg.mode = ECC_DMA_MODE;
+    else
+        nfc->ecc_cfg.mode = ECC_PIO_MODE;
+    nfc->ecc_cfg.op = ECC_ENCODE;
+
+    return mtk_ecc_encode(nfc->ecc, &nfc->ecc_cfg, data, size, polling);
+}
+
+static void mtk_nfc_no_bad_mark_swap(struct mtk_nand_chip *a, u8 *b, int c)
+{
+    /* nop */
+    return;
+}
+
+static void mtk_nfc_bad_mark_swap(struct mtk_nand_chip *chip, u8 *buf, int raw)
+{
+    struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
+    u32 bad_pos = nand->bad_mark.pos;
+
+    if (raw)
+        bad_pos += nand->bad_mark.sec * mtk_data_len(chip);
+    else
+        bad_pos += nand->bad_mark.sec * chip->ecc_size;
+
+    swap(chip->oob_poi[0], buf[bad_pos]);
+
+    return;
+}
+
+static int mtk_nfc_format_subpage(struct mtk_nand_chip *chip, u32 offset,
+                                  u32 len, const u8 *buf, int dma, int polling)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 start, end, i;
+    int ret;
+
+    start = offset / chip->ecc_size;
+    end = DIV_ROUND_UP(offset + len, chip->ecc_size);
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i), chip->ecc_size);
+
+        if (start > i || i >= end)
+            continue;
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
+
+        /* program the CRC back to the OOB */
+        ret = mtk_nfc_sector_encode(chip, mtk_data_ptr(chip, i), dma, polling);
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+static void mtk_nfc_format_page(struct mtk_nand_chip *chip, const u8 *buf)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 parity_size = mtk_nand->spare_per_sector - fdm->reg_size;
+    u32 i;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    for (i = 0; i < chip->ecc_steps; i++) {
+        if (buf)
+            memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
+                   chip->ecc_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
+        memcpy(mtk_oob_parity_ptr(chip, i), oob_parity_ptr(chip, i),
+               parity_size);
+    }
+
+    return;
+}
+
+static inline void mtk_nfc_read_fdm(struct mtk_nand_chip *chip, u32 start,
+                                    u32 sectors)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 vall, valm, i, j;
+    u8 *oobptr;
+
+    for (i = 0; i < sectors; i++) {
+        oobptr = oob_ptr(chip, start + i);
+        vall = nfi_readl(nfc, NFI_FDML(i));
+        valm = nfi_readl(nfc, NFI_FDMM(i));
+
+        for (j = 0; j < fdm->reg_size; j++)
+            oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8);
+    }
+
+    return;
+}
+
+static inline void mtk_nfc_write_fdm(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 vall, valm, i, j;
+    u8 *oobptr;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        oobptr = oob_ptr(chip, i);
+        vall = 0;
+        valm = 0;
+        for (j = 0; j < 8; j++) {
+            if (j < 4)
+                vall |= (j < fdm->reg_size ? oobptr[j] : 0xff)
+                        << (j * 8);
+            else
+                valm |= (j < fdm->reg_size ? oobptr[j] : 0xff)
+                        << ((j - 4) * 8);
+        }
+        nfi_writel(nfc, vall, NFI_FDML(i));
+        nfi_writel(nfc, valm, NFI_FDMM(i));
+    }
+
+    return;
+}
+
+static int mtk_nfc_do_write_page(struct mtk_nand_chip *chip,
+                                 const u8 *buf, int page, int len, int raw, int dma, int polling)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    u32 *buf32 = (u32 *)buf;
+    uintptr_t addr;
+    u32 reg, i;
+    u32 data_len = chip->ecc_size;
+    int ret = 0, byterw;
+
+#ifdef WITH_KERNEL_VM
+    addr = (uintptr_t)kvaddr_to_paddr((void *)buf);
+#else
+    addr = (uintptr_t)buf;
+#endif
+
+    if (dma) {
+        reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AHB | CNFG_DMA_BURST_EN;
+        nfi_writew(nfc, reg, NFI_CNFG);
+        arch_clean_cache_range((addr_t)buf, (size_t)len);
+    }
+    nfi_writel(nfc, chip->ecc_steps << CON_SEC_SHIFT, NFI_CON);
+    nfi_writel(nfc, (u32)addr, NFI_STRADDR);
+
+    if (dma && (!polling)) {
+        nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
+    }
+
+    reg = nfi_readl(nfc, NFI_CON) | CON_BWR;
+    nfi_writel(nfc, reg, NFI_CON);
+    nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+
+    if (!dma) {
+        if (raw)
+            data_len = mtk_data_len(chip);
+        data_len *= chip->ecc_steps;
+
+        if (data_len & 0x3) {
+            reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
+            nfi_writew(nfc, reg, NFI_CNFG);
+            byterw = 1;
+        } else {
+            data_len >>= 2;
+            byterw = 0;
+        }
+
+        for (i = 0; i < data_len; i++) {
+            mtk_nfc_wait_ioready(nfc);
+            if (!byterw)
+                nfi_writel(nfc, buf32[i],NFI_DATAW);
+            else
+                nfi_writeb(nfc, buf[i], NFI_DATAW);
+        }
+    }
+
+    if (dma && (!polling)) {
+        ret = mtk_nfc_irq_wait(nfc, MTK_TIMEOUT);
+        if (!ret) {
+            dprintf(CRITICAL, "program ahb done timeout\n");
+            nfi_writew(nfc, 0, NFI_INTR_EN);
+            ret = -ETIMEDOUT;
+            goto timeout;
+        }
+    }
+
+    if (!check_with_timeout(ADDRCNTR_SEC(nfi_readl(nfc, NFI_ADDRCNTR)) >= chip->ecc_steps, MTK_TIMEOUT))
+        dprintf(CRITICAL, "do page write timeout\n");
+
+timeout:
+    if (dma)
+        arch_invalidate_cache_range((addr_t)buf, (size_t)len);
+
+    nfi_writel(nfc, 0, NFI_CON);
+
+    return ret;
+}
+
+static int mtk_nfc_write_page(struct mtk_nand_chip *chip,
+                              const u8 *buf, int page, int raw, int dma, int polling)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    u32 len;
+    const u8 *bufpoi;
+    u32 reg;
+    int ret;
+
+    if (!raw) {
+        /* OOB => FDM: from register,  ECC: from HW */
+        reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AUTO_FMT_EN;
+        nfi_writew(nfc, reg | CNFG_HW_ECC_EN, NFI_CNFG);
+
+        nfc->ecc_cfg.op = ECC_ENCODE;
+        nfc->ecc_cfg.mode = ECC_NFI_MODE;
+        ret = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg, polling);
+        if (ret) {
+            /* clear NFI config */
+            reg = nfi_readw(nfc, NFI_CNFG);
+            reg &= ~(CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
+            nfi_writew(nfc, reg, NFI_CNFG);
+
+            return ret;
+        }
+
+        memcpy(nfc->buffer, buf, chip->pagesize);
+        mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, raw);
+        bufpoi = nfc->buffer;
+
+        /* write OOB into the FDM registers (OOB area in MTK NAND) */
+        mtk_nfc_write_fdm(chip);
+    } else {
+        bufpoi = buf;
+    }
+
+    len = chip->pagesize + (raw ? chip->oobsize : 0);
+    ret = mtk_nfc_do_write_page(chip, bufpoi, page, len, raw, dma, polling);
+
+    if (!raw)
+        mtk_ecc_disable(nfc->ecc);
+
+    return ret;
+}
+
+static int mtk_nfc_write_page_ecc_dma_polling(struct mtk_nand_chip *chip, const u8 *buf,
+        int page)
+{
+    return mtk_nfc_write_page(chip, buf, page, 0, 1, 1);
+}
+
+static int mtk_nfc_write_page_ecc_dma_irq(struct mtk_nand_chip *chip, const u8 *buf,
+        int page)
+{
+    return mtk_nfc_write_page(chip, buf, page, 0, 1, 0);
+}
+
+static int mtk_nfc_write_page_ecc_pio_polling(struct mtk_nand_chip *chip, const u8 *buf,
+        int page)
+{
+    return mtk_nfc_write_page(chip, buf, page, 0, 0, 1);
+}
+
+static int mtk_nfc_write_page_ecc_pio_irq(struct mtk_nand_chip *chip, const u8 *buf,
+        int page)
+{
+    return mtk_nfc_write_page(chip, buf, page, 0, 0, 0);
+}
+
+static int mtk_nfc_write_page_raw_dma_polling(struct mtk_nand_chip *chip,
+        const u8 *buf, int pg)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mtk_nfc_format_page(chip, buf);
+    return mtk_nfc_write_page(chip, nfc->buffer, pg, 1, 1, 1);
+}
+
+static int mtk_nfc_write_page_raw_dma_irq(struct mtk_nand_chip *chip,
+        const u8 *buf, int pg)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mtk_nfc_format_page(chip, buf);
+    return mtk_nfc_write_page(chip, nfc->buffer, pg, 1, 1, 0);
+}
+
+static int mtk_nfc_write_page_raw_pio_polling(struct mtk_nand_chip *chip,
+        const u8 *buf, int pg)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mtk_nfc_format_page(chip, buf);
+    return mtk_nfc_write_page(chip, nfc->buffer, pg, 1, 0, 1);
+}
+
+static int mtk_nfc_write_page_raw_pio_irq(struct mtk_nand_chip *chip,
+        const u8 *buf, int pg)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    mtk_nfc_format_page(chip, buf);
+    return mtk_nfc_write_page(chip, nfc->buffer, pg, 1, 0, 0);
+}
+
+static int mtk_nfc_write_subpage_ecc_dma_polling(struct mtk_nand_chip *chip, u32 offset,
+        u32 data_len, const u8 *buf, int page)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    int ret;
+
+    ret = mtk_nfc_format_subpage(chip, offset, data_len, buf, 1, 1);
+    if (ret < 0)
+        return ret;
+
+    /* use the data in the private buffer (now with FDM and CRC) */
+    return mtk_nfc_write_page(chip, nfc->buffer, page, 1, 1, 1);
+}
+
+static int mtk_nfc_write_subpage_ecc_dma_irq(struct mtk_nand_chip *chip, u32 offset,
+        u32 data_len, const u8 *buf, int page)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    int ret;
+
+    ret = mtk_nfc_format_subpage(chip, offset, data_len, buf, 1, 0);
+    if (ret < 0)
+        return ret;
+
+    /* use the data in the private buffer (now with FDM and CRC) */
+    return mtk_nfc_write_page(chip, nfc->buffer, page, 1, 1, 0);
+}
+
+static int mtk_nfc_write_subpage_ecc_pio_polling(struct mtk_nand_chip *chip, u32 offset,
+        u32 data_len, const u8 *buf, int page)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    int ret;
+
+    ret = mtk_nfc_format_subpage(chip, offset, data_len, buf, 0, 1);
+    if (ret < 0)
+        return ret;
+
+    /* use the data in the private buffer (now with FDM and CRC) */
+    return mtk_nfc_write_page(chip, nfc->buffer, page, 1, 0, 1);
+}
+
+static int mtk_nfc_write_subpage_ecc_pio_irq(struct mtk_nand_chip *chip, u32 offset,
+        u32 data_len, const u8 *buf, int page)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    int ret;
+
+    ret = mtk_nfc_format_subpage(chip, offset, data_len, buf, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    /* use the data in the private buffer (now with FDM and CRC) */
+    return mtk_nfc_write_page(chip, nfc->buffer, page, 1, 0, 0);
+}
+
+static int mtk_nfc_update_ecc_stats(struct mtk_nand_chip *chip, u8 *buf, u32 sectors)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_ecc_stats stats;
+    u32 rc, i;
+
+    rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
+    if (rc) {
+        memset(buf, 0xff, sectors * chip->ecc_size);
+        for (i = 0; i < sectors; i++)
+            memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size);
+        return 0;
+    }
+
+    mtk_ecc_get_stats(nfc->ecc, &stats, sectors);
+    chip->stats.corrected += stats.corrected;
+    chip->stats.failed += stats.failed;
+
+    return stats.bitflips;
+}
+
+static int mtk_nfc_read_subpage(struct mtk_nand_chip *chip,
+                                u32 data_offs, u32 readlen,
+                                u8 *bufpoi, int page, int raw, int dma, int polling)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_ecc_stats stats;
+    u32 spare = mtk_nand->spare_per_sector;
+    u32 column, sectors, start, end, reg;
+    uintptr_t addr;
+    u32 i, j;
+    int bitflips = 0;
+    u32 len, correct = 0, fail = 0;
+    u8 *buf;
+    u32 *buf32;
+    u32 data_len = chip->ecc_size;
+    int rc, byterw;
+
+    start = data_offs / chip->ecc_size;
+    end = DIV_ROUND_UP(data_offs + readlen, chip->ecc_size);
+
+    sectors = end - start;
+    column = start * (chip->ecc_size + spare);
+
+    len = sectors * chip->ecc_size + ((raw || !dma) ? sectors * spare : 0);
+    buf = bufpoi + start * (chip->ecc_size + ((raw || !dma) ? sectors * spare : 0));
+    buf32 = (u32 *)buf;
+
+    if (column != 0)
+        chip->cmdfunc(chip, NAND_CMD_RNDOUT, column, -1);
+
+#ifdef WITH_KERNEL_VM
+    addr = (uintptr_t)kvaddr_to_paddr(buf);
+#else
+    addr = (uintptr_t)buf;
+#endif
+
+    reg = nfi_readw(nfc, NFI_CNFG);
+    reg |= CNFG_READ_EN;
+    if (dma)
+        reg |= CNFG_DMA_BURST_EN | CNFG_AHB;
+    if (!raw) {
+        reg |= CNFG_HW_ECC_EN;
+        if (dma)
+            reg |= CNFG_AUTO_FMT_EN;
+        nfi_writew(nfc, reg, NFI_CNFG);
+
+        nfc->ecc_cfg.mode = ECC_NFI_MODE;
+        nfc->ecc_cfg.sectors = sectors;
+        nfc->ecc_cfg.op = ECC_DECODE;
+        if (dma) {
+            nfc->ecc_cfg.deccon = ECC_DEC_CORRECT;
+        } else {
+            nfc->ecc_cfg.deccon = ECC_DEC_LOCATE;
+        }
+        rc = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg, polling);
+        if (rc) {
+            dprintf(CRITICAL, "ecc enable failed\n");
+            /* clear NFI_CNFG */
+            reg &= ~(CNFG_DMA_BURST_EN | CNFG_AHB | CNFG_READ_EN |
+                     CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
+            nfi_writew(nfc, reg, NFI_CNFG);
+
+            return rc;
+        }
+    } else {
+        nfi_writew(nfc, reg, NFI_CNFG);
+    }
+
+    if (dma)
+        arch_invalidate_cache_range((addr_t)buf, (size_t)len);
+    nfi_writel(nfc, sectors << CON_SEC_SHIFT, NFI_CON);
+    nfi_writel(nfc, (u32)addr, NFI_STRADDR);
+
+    if (dma && (!polling)) {
+        nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
+    }
+    reg = nfi_readl(nfc, NFI_CON) | CON_BRD;
+    nfi_writel(nfc, reg, NFI_CON);
+    nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+
+    if (!dma) {
+        data_len = mtk_data_len(chip);
+
+        if (data_len & 0x3) {
+            reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
+            nfi_writew(nfc, reg, NFI_CNFG);
+            byterw = 1;
+        } else {
+            data_len >>= 2;
+            byterw = 0;
+        }
+        if (!raw) {
+            stats.bitflips = 0;
+            correct = chip->stats.corrected;
+            fail = chip->stats.failed;
+        }
+        for (i = 0; i < sectors; i++) {
+            for (j = 0; j < data_len; j++) {
+                mtk_nfc_wait_ioready(nfc);
+                if (!byterw)
+                    *(buf32 + (i * data_len) + j) = nfi_readl(nfc, NFI_DATAR);
+                else
+                    *(buf + (i * data_len) + j) = nfi_readb(nfc, NFI_DATAR);
+            }
+            if (!raw) {
+                rc = mtk_ecc_cpu_correct(nfc->ecc, &stats, buf + (i * (byterw ? data_len : (data_len << 2))), i, polling);
+                if (rc < 0)
+                    goto disecc;
+                chip->stats.corrected += stats.corrected;
+                chip->stats.failed += stats.failed;
+                if (stats.failed)
+                    dprintf(ALWAYS, "sectoer %d uncorrect\n", i);
+            }
+        }
+        if (!raw) {
+            bitflips = stats.bitflips;
+            rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
+            if (rc) {
+                dprintf(INFO, "page is empty\n");
+                memset(buf, 0xff, sectors * mtk_data_len(chip));
+                bitflips = 0;
+                chip->stats.corrected = correct;
+                chip->stats.failed = fail;
+            }
+        }
+    }
+
+    if (dma && (!polling)) {
+        rc = mtk_nfc_irq_wait(nfc, MTK_TIMEOUT);
+        if (!rc) {
+            dprintf(CRITICAL, "read ahb/dma done timeout\n");
+            nfi_writew(nfc, 0, NFI_INTR_EN);
+        }
+    }
+
+    rc = check_with_timeout(ADDRCNTR_SEC(nfi_readl(nfc, NFI_BYTELEN)) >= sectors, MTK_TIMEOUT);
+    if (rc && polling)
+        rc = check_with_timeout((nfi_readl(nfc, NFI_MASTER_STA) & MASTER_BUS_BUSY) == 0, MTK_TIMEOUT);
+    if (!rc) {
+        dprintf(CRITICAL, "subpage done timeout %d\n", nfi_readl(nfc, NFI_BYTELEN));
+        dprintf(CRITICAL, "cnfg 0x%x fmt 0x%x con 0x%x master_sta 0x%x\n",
+                nfi_readl(nfc, NFI_CNFG), nfi_readl(nfc, NFI_PAGEFMT), nfi_readl(nfc, NFI_CON),
+                nfi_readl(nfc, NFI_MASTER_STA));
+        bitflips = -EIO;
+    } else {
+        if ((!raw) && dma) {
+            bitflips = 0;
+            rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE, polling);
+            if (!rc)
+                rc = mtk_ecc_wait_decode_fsm_idle(nfc->ecc);
+            arch_invalidate_cache_range((addr_t)buf, (size_t)len);
+            mtk_nfc_read_fdm(chip, start, sectors);
+            bitflips = rc < 0 ? -ETIMEDOUT :
+                       mtk_nfc_update_ecc_stats(chip, buf, sectors);
+        }
+    }
+
+    if (raw)
+        goto done;
+
+disecc:
+    mtk_ecc_disable(nfc->ecc);
+
+    if (!dma)
+        goto done;
+
+    if (clamp(mtk_nand->bad_mark.sec, start, end) == mtk_nand->bad_mark.sec)
+        mtk_nand->bad_mark.bm_swap(chip, bufpoi, raw);
+done:
+    nfi_writel(nfc, 0, NFI_CON);
+
+    return bitflips;
+}
+
+static int mtk_nfc_read_subpage_ecc_dma_polling(struct mtk_nand_chip *chip, u32 off,
+        u32 len, u8 *p, int pg)
+{
+    return mtk_nfc_read_subpage(chip, off, len, p, pg, 0, 1, 1);
+}
+
+static int mtk_nfc_read_subpage_ecc_dma_irq(struct mtk_nand_chip *chip, u32 off,
+        u32 len, u8 *p, int pg)
+{
+    return mtk_nfc_read_subpage(chip, off, len, p, pg, 0, 1, 0);
+}
+
+static int mtk_nfc_read_subpage_ecc_pio_polling(struct mtk_nand_chip *chip, u32 off,
+        u32 len, u8 *p, int pg)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 start, end, i;
+    int ret;
+
+    start = off / chip->ecc_size;
+    end = DIV_ROUND_UP(off + len, chip->ecc_size);
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, off, len, nfc->buffer, pg, 0, 0, 1);
+    if (ret < 0)
+        return ret;
+
+    for (i = start; i < end; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (p)
+            memcpy(data_ptr(chip, p, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_subpage_ecc_pio_irq(struct mtk_nand_chip *chip, u32 off,
+        u32 len, u8 *p, int pg)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 start, end, i;
+    int ret;
+
+    start = off / chip->ecc_size;
+    end = DIV_ROUND_UP(off + len, chip->ecc_size);
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, off, len, nfc->buffer, pg, 0, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    for (i = start; i < end; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (p)
+            memcpy(data_ptr(chip, p, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_ecc_dma_polling(struct mtk_nand_chip *chip, u8 *p,
+        int pg)
+{
+    return mtk_nfc_read_subpage(chip, 0, chip->pagesize, p, pg, 0, 1, 1);
+}
+
+static int mtk_nfc_read_page_ecc_dma_irq(struct mtk_nand_chip *chip, u8 *p,
+        int pg)
+{
+    return mtk_nfc_read_subpage(chip, 0, chip->pagesize, p, pg, 0, 1, 0);
+}
+
+static int mtk_nfc_read_page_ecc_pio_polling(struct mtk_nand_chip *chip, u8 *p,
+        int pg)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 i;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer, pg, 0, 0, 1);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (p)
+            memcpy(data_ptr(chip, p, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_ecc_pio_irq(struct mtk_nand_chip *chip, u8 *p,
+        int pg)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 i;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer, pg, 0, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (p)
+            memcpy(data_ptr(chip, p, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_raw_dma_polling(struct mtk_nand_chip *chip,
+        u8 *buf, int page)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 i;
+    u32 parity_size = mtk_nand->spare_per_sector - fdm->reg_size;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer,
+                               page, 1, 1, 1);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+        memcpy(oob_parity_ptr(chip, i), mtk_oob_parity_ptr(chip, i),
+               parity_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (buf)
+            memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_raw_dma_irq(struct mtk_nand_chip *chip,
+        u8 *buf, int page)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 i;
+    u32 parity_size = mtk_nand->spare_per_sector - fdm->reg_size;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer,
+                               page, 1, 1, 0);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+        memcpy(oob_parity_ptr(chip, i), mtk_oob_parity_ptr(chip, i),
+               parity_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (buf)
+            memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_raw_pio_polling(struct mtk_nand_chip *chip,
+        u8 *buf, int page)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 i;
+    u32 parity_size = mtk_nand->spare_per_sector - fdm->reg_size;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer,
+                               page, 1, 0, 1);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+        memcpy(oob_parity_ptr(chip, i), mtk_oob_parity_ptr(chip, i),
+               parity_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (buf)
+            memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static int mtk_nfc_read_page_raw_pio_irq(struct mtk_nand_chip *chip,
+        u8 *buf, int page)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+    u32 parity_size = mtk_nand->spare_per_sector - fdm->reg_size;
+    u32 i;
+    int ret;
+
+    memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+    ret = mtk_nfc_read_subpage(chip, 0, chip->pagesize, nfc->buffer,
+                               page, 1, 0, 0);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < chip->ecc_steps; i++) {
+        memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+        memcpy(oob_parity_ptr(chip, i), mtk_oob_parity_ptr(chip, i),
+               parity_size);
+
+        if (i == mtk_nand->bad_mark.sec)
+            mtk_nand->bad_mark.bm_swap(chip, nfc->buffer, 1);
+
+        if (buf)
+            memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+                   chip->ecc_size);
+    }
+
+    return ret;
+}
+
+static void clrsetbits32(u32 clr, u32 set, uintptr_t reg)
+{
+    writel(readl(reg) & ~(clr) | (set), reg);
+}
+
+static int mtk_nfc_clock_init(void)
+{
+#define NFI_CLK_CFG_9           (CKSYS_BASE + 0x000000d0)
+#define	NFI2X_CLK_MASK          (0x7)
+#define	ECC_CLK_MASK            (0x700)
+#define	ECC_CLK_SHIFT           (8)
+
+#define NFI2X_26M               (0)
+#define NFI2X_SYSPLL2_D2_182M   (1)
+#define NFI2X_SYSPLL_D7_156M    (2)
+#define NFI2X_SYSPLL_D3_364M    (3)
+#define NFI2X_SYSPLL2_D4_91M    (4)
+
+/* clock configuration update register, it is write-only register */
+#define NFI_CLK_CFG_UPDATE1     (CKSYS_BASE + 0x00000008)
+#define NFI2X_CK_UPDATE         (1 << 4)
+#define ECC_CK_UPDATE           (1 << 5)
+
+    u32 reg;
+
+    reg = readl(NFI_CLK_CFG_9);
+    reg &= ~NFI2X_CLK_MASK;
+    reg |= NFI2X_SYSPLL_D7_156M;
+    writel(reg, NFI_CLK_CFG_9);
+    dprintf(ALWAYS, "%s: clock 156M!\n", __func__);
+
+    writel(NFI2X_CK_UPDATE, NFI_CLK_CFG_UPDATE1);
+
+    return 0;
+}
+
+static int mtk_nfc_gpio_init(void)
+{
+#define PUPU_CFG2_ADDR          (GPIO_BASE + 0x90)
+#define PUPU_CFG3_ADDR          (GPIO_BASE + 0xf0)
+#define GPIO_MODE8_ADDR_MSDC0   (GPIO_BASE + 0x260)
+#define GPIO_MODE9_ADDR_MSDC0   (GPIO_BASE + 0x270)
+#define GPIO_MODEA_ADDR_MSDC0   (GPIO_BASE + 0x280)
+
+#define DRV3_CFG_ADDR       (GPIO_BASE + 0x740)
+#define DRV4_CFG_ADDR       (GPIO_BASE + 0x750)
+#define DRV5_CFG_ADDR       (GPIO_BASE + 0x760)
+    /*
+     * mode setting
+     *
+     * NLD7 - GPIO93 - 0x270[11:9]=0x2
+     * NLD6 - GPIO94 - 0x270[14:12]=0x2
+     * NLD4 - GPIO95 - 0x270[17:15]=0x2
+     * NLD3 - GPIO96 - 0x270[20:18]=0x2
+     * NLD0 - GPIO97 - 0x270[23:21]=0x2
+     * NALE - GPIO98 - 0x270[26:24]=0x2
+     * NWEB - GPIO99 - 0x270[29:27]=0x2
+     * NLD1 - GPIO100 - 0x280[2:0]=0x2
+     * NLD5 - GPIO101 - 0x280[5:3]=0x2
+     * NDQS - GPIO102 - 0x280[8:6]=0x2
+     * NLD2 - GPIO103 - 0x280[11:9]=0x2
+     * NCLE, NCEB1, NCEB0, NREB, NRNB default on
+     */
+    clrsetbits32(0x3ffffe00, 0x12492400, GPIO_MODE9_ADDR_MSDC0);
+    clrsetbits32(0xfff, 0x492, GPIO_MODEA_ADDR_MSDC0);
+
+    /*
+     * PUPD setting
+     *
+     * 0x10005090[8:6]=0x6
+     * 0x10005090[11:9]=0x1
+     * 0x10005090[20:18]=0x6
+     * 0x10005090[29:27]=0x6
+     * 0x100050f0[8:6]=0x1
+     */
+    clrsetbits32(0x381c0fc0, 0x30180380, PUPU_CFG2_ADDR);
+    clrsetbits32(0x1c0, 0x40, PUPU_CFG3_ADDR);
+
+    /*
+     * driving setting
+     *
+     * 0x10005750[11:8]=0x1
+     * 0x10005750[27:24]=0x1
+     * 0x10005750[31:28]=0x1
+     * 0x10005760[3:0]=0x1
+     * 0x10005760[27:24]=0x1
+     */
+    clrsetbits32(0xff000f00, 0x11000100, DRV4_CFG_ADDR);
+    clrsetbits32(0xf00000f, 0x1000001, DRV5_CFG_ADDR);
+
+    return 0;
+}
+
+#define SS_SEED_NUM 128
+static u16 ss_randomizer_seed[SS_SEED_NUM] = {
+    0x576A, 0x05E8, 0x629D, 0x45A3, 0x649C, 0x4BF0, 0x2342, 0x272E,
+    0x7358, 0x4FF3, 0x73EC, 0x5F70, 0x7A60, 0x1AD8, 0x3472, 0x3612,
+    0x224F, 0x0454, 0x030E, 0x70A5, 0x7809, 0x2521, 0x48F4, 0x5A2D,
+    0x492A, 0x043D, 0x7F61, 0x3969, 0x517A, 0x3B42, 0x769D, 0x0647,
+    0x7E2A, 0x1383, 0x49D9, 0x07B8, 0x2578, 0x4EEC, 0x4423, 0x352F,
+    0x5B22, 0x72B9, 0x367B, 0x24B6, 0x7E8E, 0x2318, 0x6BD0, 0x5519,
+    0x1783, 0x18A7, 0x7B6E, 0x7602, 0x4B7F, 0x3648, 0x2C53, 0x6B99,
+    0x0C23, 0x67CF, 0x7E0E, 0x4D8C, 0x5079, 0x209D, 0x244A, 0x747B,
+    0x350B, 0x0E4D, 0x7004, 0x6AC3, 0x7F3E, 0x21F5, 0x7A15, 0x2379,
+    0x1517, 0x1ABA, 0x4E77, 0x15A1, 0x04FA, 0x2D61, 0x253A, 0x1302,
+    0x1F63, 0x5AB3, 0x049A, 0x5AE8, 0x1CD7, 0x4A00, 0x30C8, 0x3247,
+    0x729C, 0x5034, 0x2B0E, 0x57F2, 0x00E4, 0x575B, 0x6192, 0x38F8,
+    0x2F6A, 0x0C14, 0x45FC, 0x41DF, 0x38DA, 0x7AE1, 0x7322, 0x62DF,
+    0x5E39, 0x0E64, 0x6D85, 0x5951, 0x5937, 0x6281, 0x33A1, 0x6A32,
+    0x3A5A, 0x2BAC, 0x743A, 0x5E74, 0x3B2E, 0x7EC7, 0x4FD2, 0x5D28,
+    0x751F, 0x3EF8, 0x39B1, 0x4E49, 0x746B, 0x6EF6, 0x44BE, 0x6DB7
+};
+
+static void mtk_nfc_randomizer_init(struct mtk_nand_chip *chip)
+{
+    if (chip->bits_per_cell > 1) {
+        chip->options |= NAND_NEED_SCRAMBLING;
+        dprintf(ALWAYS, "nand randomizer trapping on!\n");
+    } else {
+        dprintf(ALWAYS, "nand randomizer trapping off!\n");
+    };
+}
+
+static void mtk_nfc_randomizer_enable(struct mtk_nand_chip *chip, int page,
+                               enum mtk_randomizer_operation rand, int repage)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+    u32 reg = 0, index;
+
+    if (!(chip->options & NAND_NEED_SCRAMBLING))
+        return;
+
+    /* randomizer type and reseed type setup */
+    reg = nfi_readl(nfc, NFI_CNFG) | CNFG_RAND_SEL;
+    if (repage)
+        reg &= ~CNFG_RESEED_SEC_EN;
+    else
+        reg |= CNFG_RESEED_SEC_EN;
+    nfi_writel(nfc, reg, NFI_CNFG);
+
+    /* randomizer seed and type setup */
+    index = page % chip->page_per_block;
+    index &= SS_SEED_NUM - 1;
+    reg = (ss_randomizer_seed[index] & RAN_SEED_MASK) << RAND_SEED_SHIFT(rand);
+    reg |= RAND_EN(rand);
+
+    nfi_writel(nfc, reg, NFI_RANDOM_CNFG);
+}
+
+static void mtk_nfc_randomizer_disable(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    if (!(chip->options & NAND_NEED_SCRAMBLING))
+        return;
+
+    nfi_writel(nfc, 0, NFI_RANDOM_CNFG);
+}
+
+static inline void mtk_nfc_hw_init(struct mtk_nand_chip *chip)
+{
+    struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+    struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+    /*
+     * ACCON: access timing control register
+     * -------------------------------------
+     * 31:28: minimum required time for CS post pulling down after accessing
+     *  the device
+     * 27:22: minimum required time for CS pre pulling down before accessing
+     *  the device
+     * 21:16: minimum required time from NCEB low to NREB low
+     * 15:12: minimum required time from NWEB high to NREB low.
+     * 11:08: write enable hold time
+     * 07:04: write wait states
+     * 03:00: read wait states
+     */
+    if (!mtk_nand->acctiming)
+        nfi_writel(nfc, mtk_nand->acctiming, NFI_ACCCON);
+    else
+        //nfi_writel(nfc, 0x10404011, NFI_ACCCON);
+        nfi_writel(nfc, 0x10403011, NFI_ACCCON);
+
+    /*
+     * CNRNB: nand ready/busy register
+     * -------------------------------
+     * 7:4: timeout register for polling the NAND busy/ready signal
+     * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
+     */
+    nfi_writew(nfc, 0xf1, NFI_CNRNB);
+    nfi_writew(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
+
+    mtk_nfc_hw_reset(nfc);
+
+    nfi_readl(nfc, NFI_INTR_STA);
+    nfi_writel(nfc, 0, NFI_INTR_EN);
+
+    return;
+}
+
+static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtk_nand_chip *nand)
+{
+    struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
+    u32 ecc_bytes;
+
+    ecc_bytes = DIV_ROUND_UP(nand->ecc_strength * ECC_PARITY_BITS, 8);
+
+    fdm->reg_size = chip->spare_per_sector - ecc_bytes;
+    if (fdm->reg_size > NFI_FDM_MAX_SIZE)
+        fdm->reg_size = NFI_FDM_MAX_SIZE;
+
+    /* bad block mark storage */
+    fdm->ecc_size = nand->fdm_ecc_size > NFI_FDM_MAX_SIZE ? NFI_FDM_MAX_SIZE : nand->fdm_ecc_size;
+
+    nand->fdm_ecc_size = fdm->ecc_size;
+    nand->oob_free_ecc_size = nand->fdm_ecc_size * nand->ecc_steps;
+    nand->oob_free_raw_size = (fdm->reg_size - fdm->ecc_size) * nand->ecc_steps;
+
+    return;
+}
+
+static int mtk_nfc_deal_oob_ecc(struct mtk_nand_chip *nand, u8 *buf, u32 offset,
+                                u32 len, bool fill_oob)
+{
+    struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
+    struct mtk_nfc_fdm *fdm = &chip->fdm;
+    u32 copy_len, done = 0, sector = offset / fdm->ecc_size;
+    u8 *to, *from;
+
+    while (len) {
+        offset %= fdm->ecc_size;
+        copy_len = MIN(len, fdm->ecc_size - offset);
+        if (fill_oob) {
+            to = oob_ptr(nand, sector) + offset;
+            from = buf + done;
+        } else {
+            to = buf + done;
+            from = oob_ptr(nand, sector) + offset;
+        }
+        memcpy(to, from, copy_len);
+        done += copy_len;
+        len -= copy_len;
+        sector++;
+        offset += copy_len;
+    };
+
+    return 0;
+}
+
+static int mtk_nfc_deal_oob_raw(struct mtk_nand_chip *nand, u8 *buf, u32 offset,
+                                u32 len, bool fill_oob)
+{
+    struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
+    struct mtk_nfc_fdm *fdm = &chip->fdm;
+    u32 copy_len, done = 0, sector;
+    u32 fdm_raw_size = fdm->reg_size - fdm->ecc_size;
+    u8 *to, *from;
+
+    sector = offset / fdm_raw_size;
+    while (len) {
+        offset %= fdm_raw_size;
+        copy_len = MIN(len, fdm_raw_size - offset);
+        if (fill_oob) {
+            to = oob_ptr(nand, sector) + fdm->ecc_size + offset;
+            from = buf + done;
+        } else {
+            to = buf + done;
+            from = oob_ptr(nand, sector) + fdm->ecc_size + offset;
+        }
+        memcpy(to, from, copy_len);
+        done += copy_len;
+        len -= copy_len;
+        sector++;
+        offset += copy_len;
+    };
+
+    return 0;
+}
+
+static int mtk_nfc_deal_oob_parity(struct mtk_nand_chip *nand, u8 *buf,
+                                   u32 offset, u32 len, bool fill_oob)
+{
+    struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
+    struct mtk_nfc_fdm *fdm = &chip->fdm;
+    u32 copy_len, done = 0, sector;
+    u32 parity_size = chip->spare_per_sector - fdm->reg_size;
+    u8 *to, *from;
+
+    sector = offset / parity_size;
+    while (len) {
+        offset %= parity_size;
+        copy_len = MIN(len, parity_size - offset);
+        if (fill_oob) {
+            to = oob_parity_ptr(nand, sector) + offset;
+            from = buf + done;
+        } else {
+            to = buf + done;
+            from = oob_parity_ptr(nand, sector) + offset;
+        }
+        memcpy(to, from, copy_len);
+        done += copy_len;
+        len -= copy_len;
+        sector++;
+        offset += copy_len;
+    };
+
+    return 0;
+}
+
+static int mtk_nfc_transfer_oob_ecc(struct mtk_nand_chip *nand, u8 *buf,
+                                    u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_ecc(nand, buf, offset, len, false);
+}
+
+static int mtk_nfc_transfer_oob_raw(struct mtk_nand_chip *nand, u8 *buf,
+                                    u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_raw(nand, buf, offset, len, false);
+}
+
+static int mtk_nfc_transfer_oob_parity(struct mtk_nand_chip *nand, u8 *buf,
+                                       u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_parity(nand, buf, offset, len, false);
+}
+
+static int mtk_nfc_fill_oob_ecc(struct mtk_nand_chip *nand, u8 *buf,
+                                u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_ecc(nand, buf, offset, len, true);
+}
+
+static int mtk_nfc_fill_oob_raw(struct mtk_nand_chip *nand, u8 *buf,
+                                u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_raw(nand, buf, offset, len, true);
+}
+
+static int mtk_nfc_fill_oob_parity(struct mtk_nand_chip *nand, u8 *buf,
+                                   u32 offset, u32 len)
+{
+    return mtk_nfc_deal_oob_parity(nand, buf, offset, len, true);
+}
+
+static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
+                                     struct mtk_nand_chip *nand)
+{
+    if (nand->pagesize == 512) {
+        bm_ctl->bm_swap = mtk_nfc_no_bad_mark_swap;
+    } else {
+        bm_ctl->bm_swap = mtk_nfc_bad_mark_swap;
+        bm_ctl->sec = nand->pagesize / mtk_data_len(nand);
+        bm_ctl->pos = nand->pagesize % mtk_data_len(nand);
+    }
+
+    return;
+}
+
+static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtk_nand_chip *nand)
+{
+    u32 spare[] = {16, 26, 27, 28, 32, 36, 40, 44,
+                   48, 49, 50, 51, 52, 62, 63, 64
+                  };
+    u32 eccsteps, i;
+
+    eccsteps = nand->pagesize / nand->ecc_size;
+    *sps = nand->oobsize / eccsteps;
+
+    if (nand->ecc_size == 1024)
+        *sps >>= 1;
+
+    for (i = 0; i < sizeof(spare) / sizeof(u32); i++) {
+        if (*sps <= spare[i]) {
+            if (*sps == spare[i])
+                *sps = spare[i];
+            else if (i != 0)
+                *sps = spare[i - 1];
+            break;
+        }
+    }
+
+    if (i >= sizeof(spare) / sizeof(u32))
+        *sps = spare[sizeof(spare) / sizeof(u32) - 1];
+
+    if (nand->ecc_size == 1024)
+        *sps <<= 1;
+
+    return;
+}
+
+int mtk_nfc_nand_chip_init(struct mtk_nand_chip **ext_nand)
+{
+    struct mtk_nfc *nfc;
+    struct mtk_nfc_nand_chip *chip;
+    struct mtk_nand_chip *nand;
+    int ret = 0;
+
+    nfc = (struct mtk_nfc *)malloc(sizeof(*nfc));
+    if (!nfc)
+        return -ENOMEM;
+    memset(nfc, 0, sizeof(*nfc));
+    nfc->regs = NFI_BASE;
+
+    chip = (struct mtk_nfc_nand_chip *)malloc(sizeof(*chip));
+    if (!chip) {
+        goto free_nfc;
+        ret = -ENOMEM;
+    }
+    memset(chip, 0, sizeof(*chip));
+
+    /* register interrupt handler */
+    mtk_nfc_request_irq(nfc);
+
+    nand = &chip->chip;
+    *ext_nand = nand;
+
+    nand_set_controller_data(nand, nfc);
+
+    nand->dev_ready = mtk_nfc_dev_ready;
+    nand->wait_busy_irq = mtk_nfc_wait_busy_irq;
+    nand->select_chip = mtk_nfc_select_chip;
+    nand->write_byte = mtk_nfc_write_byte;
+    nand->write_buf = mtk_nfc_write_buf;
+    nand->read_byte = mtk_nfc_read_byte;
+    nand->read_buf = mtk_nfc_read_buf;
+    nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
+
+    nand->write_page_ecc_dma_irq = mtk_nfc_write_page_ecc_dma_irq;
+    nand->write_page_ecc_dma_polling = mtk_nfc_write_page_ecc_dma_polling;
+    nand->write_page_ecc_pio_irq = mtk_nfc_write_page_ecc_pio_irq;
+    nand->write_page_ecc_pio_polling = mtk_nfc_write_page_ecc_pio_polling;
+    nand->write_page_raw_dma_irq = mtk_nfc_write_page_raw_dma_irq;
+    nand->write_page_raw_dma_polling = mtk_nfc_write_page_raw_dma_polling;
+    nand->write_page_raw_pio_irq = mtk_nfc_write_page_raw_pio_irq;
+    nand->write_page_raw_pio_polling = mtk_nfc_write_page_raw_pio_polling;
+    nand->write_subpage_ecc_dma_irq = mtk_nfc_write_subpage_ecc_dma_irq;
+    nand->write_subpage_ecc_dma_polling = mtk_nfc_write_subpage_ecc_dma_polling;
+    nand->write_subpage_ecc_pio_irq = mtk_nfc_write_subpage_ecc_pio_irq;
+    nand->write_subpage_ecc_pio_polling = mtk_nfc_write_subpage_ecc_pio_polling;
+
+    nand->read_subpage_ecc_dma_irq = mtk_nfc_read_subpage_ecc_dma_irq;
+    nand->read_subpage_ecc_dma_polling = mtk_nfc_read_subpage_ecc_dma_polling;
+    nand->read_subpage_ecc_pio_irq = mtk_nfc_read_subpage_ecc_pio_irq;
+    nand->read_subpage_ecc_pio_polling = mtk_nfc_read_subpage_ecc_pio_polling;
+    nand->read_page_ecc_dma_irq = mtk_nfc_read_page_ecc_dma_irq;
+    nand->read_page_ecc_dma_polling = mtk_nfc_read_page_ecc_dma_polling;
+    nand->read_page_ecc_pio_irq = mtk_nfc_read_page_ecc_pio_irq;
+    nand->read_page_ecc_pio_polling = mtk_nfc_read_page_ecc_pio_polling;
+    nand->read_page_raw_dma_irq = mtk_nfc_read_page_raw_dma_irq;
+    nand->read_page_raw_dma_polling = mtk_nfc_read_page_raw_dma_polling;
+    nand->read_page_raw_pio_irq = mtk_nfc_read_page_raw_pio_irq;
+    nand->read_page_raw_pio_polling = mtk_nfc_read_page_raw_pio_polling;
+
+    nand->enable_randomizer = mtk_nfc_randomizer_enable;
+    nand->disable_randomizer = mtk_nfc_randomizer_disable;
+
+    nand->fill_oob_ecc = mtk_nfc_fill_oob_ecc;
+    nand->fill_oob_raw = mtk_nfc_fill_oob_raw;
+    nand->fill_oob_parity = mtk_nfc_fill_oob_parity;
+    nand->transfer_oob_ecc = mtk_nfc_transfer_oob_ecc;
+    nand->transfer_oob_raw = mtk_nfc_transfer_oob_raw;
+    nand->transfer_oob_parity = mtk_nfc_transfer_oob_parity;
+
+    /* default acc timing */
+    chip->acctiming = 0x10404011;
+    mtk_nfc_gpio_init();
+    mtk_nfc_clock_init();
+    mtk_nfc_randomizer_init(nand);
+    mtk_nfc_hw_init(nand);
+
+    ret = mtk_ecc_hw_init(&nfc->ecc);
+    if (ret)
+        goto free_chip;
+
+    ret = mtk_nand_scan(nand, 1 /*MTK_NAND_MAX_NSELS*/);
+    if (ret)
+        goto free_ecc;
+
+    mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, nand);
+    mtk_nfc_set_fdm(&chip->fdm, nand);
+    mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, nand);
+
+    nfc->buffer = (u8 *)memalign(16, nand->pagesize + nand->oobsize);
+    if (!nfc->buffer) {
+        ret = -ENOMEM;
+        goto free_databuf;
+    }
+
+    mutex_init(&nfc->lock);
+
+    ret = mtk_nand_scan_tail(nand);
+    if (ret)
+        goto free_buffer;
+
+    dprintf(INFO, "nand chip init done\n");
+    return 0;
+
+free_buffer:
+    free(nfc->buffer);
+free_databuf:
+    free(nand->databuf);
+free_ecc:
+    free(nfc->ecc);
+free_chip:
+    free(chip);
+free_nfc:
+    free(nfc);
+
+    return ret;
+}
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/rules.mk b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/rules.mk
new file mode 100644
index 0000000..161e76c
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/nand/rules.mk
@@ -0,0 +1,18 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/mtk_ecc_hal.c \
+    $(LOCAL_DIR)/mtk_nfi_hal.c \
+    $(LOCAL_DIR)/mtk_nand_bbt.c \
+    $(LOCAL_DIR)/mtk_nand_device.c \
+    $(LOCAL_DIR)/mtk_nand_nal.c \
+    $(LOCAL_DIR)/mtk_nand_nftl.c \
+    $(LOCAL_DIR)/mtk_nand_test.c \
+
+MODULE_DEPS += \
+    lib/bio \
+    lib/nftl \
+    lib/partition \
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/pll/pll.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/pll/pll.c
new file mode 100644
index 0000000..822f793
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/pll/pll.c
@@ -0,0 +1,704 @@
+/*
+ * 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.
+ */
+
+#include <debug.h>
+#include <platform/mt_reg_base.h>
+#include <platform/pll.h>
+#include <platform/spm.h>
+#include <reg.h>
+
+#define RGU_KEY_CODE          (0x88 << 24)
+#define CONNSYS_CPU_SW_RST    (0x1 << 12)
+
+#define ALL_CLK_ON  1
+#define FMETER_EN   0
+
+#define udelay(x)       spin(x)
+#define mdelay(x)       udelay((x) * 1000)
+
+#define set_r(addr, val) \
+    write_r(addr, readl(addr) | (val))
+
+#define clr_r(addr, mask) \
+    write_r(addr, readl(addr) & ~(mask))
+
+#define clrset_r(addr, mask, val) \
+    write_r(addr, (readl(addr) & ~(mask)) | (val))
+
+#define ARRAY_SIZE(a)       (sizeof(a) / sizeof(a[0]))
+#define SET_ARMPLL_CLK_SRC
+
+unsigned int mt_get_abist_freq(unsigned int ID)
+{
+    int output = 0, i = 0;
+    unsigned int temp, clk26cali_0, clk_dbg_cfg, clk_misc_cfg_0, clk26cali_1;
+    clk_dbg_cfg = readl(CLK_DBG_CFG);
+    write_r(CLK_DBG_CFG, (clk_dbg_cfg & 0xFFC0FFFC)|(ID << 16));
+    clk_misc_cfg_0 = readl(CLK_MISC_CFG_0);
+    write_r(CLK_MISC_CFG_0, (clk_misc_cfg_0 & 0x00FFFFFF) | (0x3 << 24));
+    clk26cali_0 = readl(CLK26CALI_0);
+    clk26cali_1 = readl(CLK26CALI_1);
+    write_r(CLK26CALI_0, 0x1000);
+    write_r(CLK26CALI_0, 0x1010);
+    /* wait frequency meter finish */
+    while (readl(CLK26CALI_0) & 0x10) {
+        mdelay(10);
+        i++;
+        if (i > 10)
+            break;
+    }
+    temp = readl(CLK26CALI_1) & 0xFFFF;
+    output = ((temp * 26000) ) / 1024; // Khz
+    write_r(CLK_DBG_CFG, clk_dbg_cfg);
+    write_r(CLK_MISC_CFG_0, clk_misc_cfg_0);
+    write_r(CLK26CALI_0, clk26cali_0);
+    write_r(CLK26CALI_1, clk26cali_1);
+
+    return output * 4;
+}
+static unsigned int mt_get_ckgen_freq(unsigned int ID)
+{
+    int output = 0, i = 0;
+    unsigned int temp, clk26cali_0, clk_dbg_cfg, clk_misc_cfg_0, clk26cali_1;
+    clk_dbg_cfg = readl(CLK_DBG_CFG);
+    write_r(CLK_DBG_CFG, (clk_dbg_cfg & 0xFFFFC0FC)|(ID << 8)|(0x1)); //sel ckgen_cksw[22] and enable freq meter sel ckgen[21:16], 01:hd_faxi_ck
+    clk_misc_cfg_0 = readl(CLK_MISC_CFG_0);
+    write_r(CLK_MISC_CFG_0, (clk_misc_cfg_0 & 0x00FFFFFF)); // select divider?dvt set zero
+    clk26cali_0 = readl(CLK26CALI_0);
+    clk26cali_1 = readl(CLK26CALI_1);
+    write_r(CLK26CALI_0, 0x1000);
+    write_r(CLK26CALI_0, 0x1010);
+    /* wait frequency meter finish */
+    while (readl(CLK26CALI_0) & 0x10) {
+        mdelay(10);
+        i++;
+        if (i > 10)
+            break;
+    }
+    temp = readl(CLK26CALI_1) & 0xFFFF;
+    output = ((temp * 26000) ) / 1024; // Khz
+    write_r(CLK_DBG_CFG, clk_dbg_cfg);
+    write_r(CLK_MISC_CFG_0, clk_misc_cfg_0);
+    write_r(CLK26CALI_0, clk26cali_0);
+    write_r(CLK26CALI_1, clk26cali_1);
+
+    return output;
+}
+#define Range 1000
+const int ckgen_needCheck_array[] = {
+    /* 01 - 05*/ 1, 1, 1, 1, 1,
+    /* 06 - 10*/ 1, 1, 1, 1, 1,
+    /* 11 - 15*/ 1, 1, 1, 1, 1,
+    /* 16 - 20*/ 1, 1, 1, 1, 1,
+    /* 21 - 25*/ 1, 1, 1, 1, 1,
+    /* 26 - 30*/ 1, 1, 1, 1, 1,
+    /* 31 - 35*/ 1, 1, 1, 1, 1,
+    /* 36 - 40*/ 1, 1, 1, 1, 1,
+    /* 41 - 45*/ 1, 1, 1, 1, 1,
+    /* 46 - 50*/ 1, 1, 1, 0, 0,
+    /* 51 - 55*/ 0, 0, 0, 0, 0,
+    /* 56 - 58*/ 0, 0, 0,
+};
+
+
+const char *ckgen_array[] = {
+    "axi_ck",
+    "mem_ck",
+    "mm_ck",
+    "scp_ck",
+    "mfg_ck",
+    "atb_ck",
+    "camtg_ck",
+    "camtg1_ck",
+    "uart_ck",
+    "f_fspi_ck",
+    "msdc50_0_hclk_ck",
+    "fmsdc2_2_hclk_ck",
+    "msdc50_0_ck",
+    "msdc50_2_ck",
+    "msdc30_1_ck",
+    "audio_ck",
+    "aud_intbus_ck",
+    "aud_1_ck",
+    "aud_2_ck",
+    "aud_engen1_ck",
+    "aud_engen2_ck",
+    "hf_faud_spdif_ck",
+    "disp_pwm_ck",
+    "sspm_ck",
+    "dxcc_ck",
+    "ssusb_sys_ck",
+    "ssusb_xhci_ck",
+    "spm_ck",
+    "i2c_ck",
+    "pwm_ck",
+    "seninf_ck",
+    "aes_fde_ck",
+    "camtm_ck",
+    "dpi0_ck",
+    "dpi1_ck",
+    "dsp_ck",
+    "nfi2x_ck",
+    "nfiecc_ck",
+    "ecc_ck",
+    "eth_ck",
+    "gcpu_ck",
+    "gcpu_cpm_ck",
+    "apu_ck",
+    "apu_if_ck",
+    "mbist_diag_clk",
+    "f_ufs_mp_sap_cfg_ck",
+    "f_ufs_tick1us_ck",
+    "NULL",
+    "NULL",
+    "NULL",
+    "NULL",
+};
+
+const int abist_needCheck_array[] = {
+    /* 01 - 05*/    1, 0, 1, 1, 1,
+    /* 06 - 10*/    0, 1, 1, 1, 1,
+    /* 11 - 15*/    1, 1, 1, 1, 1,
+    /* 16 - 20*/    1, 1, 1, 1, 1,
+    /* 21 - 25*/    0, 1, 1, 1, 1,
+    /* 26 - 30*/    1, 1, 1, 1, 1,
+    /* 31 - 35*/    1, 1, 1, 1, 1,
+    /* 36 - 40*/    1, 1, 1, 0, 1,
+    /* 41 - 45*/    1, 1, 1, 1, 1,
+    /* 46 - 50*/    1, 1, 1, 1, 1,
+    /* 51 - 55*/    1, 1, 1, 1, 1,
+    /* 56 - 58*/    1, 1, 1, 1,
+};
+
+const char *abist_array[] = {
+    "AD_ARMPLL_CK",
+    "0",
+    "AD_MAINPLLCK",
+    "AD_CSI0A_CDPHY_DELAYCAL_CK",
+    "AD_CSI0B_CDPHY_DELAYCAL_CK",
+    "0",
+    "AD_USB20_CLK480M",
+    "AD_USB20_CLK480M_1P",
+    "AD_MADADC_26MCKO",
+    "AD_MAINPLL_H546M_CK",
+    "AD_MAINPLL_H364M_CK",
+    "AD_MAINPLL_H218P4M_CK",
+    "AD_MAINPLL_H156M_CK",
+    "AD_UNIVPLL_1248M_CK",
+    "AD_USB20_192M_CK",
+    "AD_UNIVPLL_624M_CK",
+    "AD_UNIVPLL_416M_CK",
+    "AD_UNIVPLL_249P6M_CK",
+    "AD_UNIVPLL_178P3M_CK",
+    "AD_SYS_26M_CK",
+    "AD_CSI1A_DPHY_DELAYCAL_CK",
+    "AD_CSI1B_DPHY_DELAYCAL_CK",
+    "AD_CSI2A_DPHY_DELAYCAL_CK",
+    "AD_CSI2B_DPHY_DELAYCAL_CK",
+    "RTC32K",
+    "AD_MMPLL_CK",
+    "AD_MFGPLL_CK",
+    "AD_MSDCPLL_CK",
+    "AD_DSI0_LNTC_DSICLK",
+    "AD_DSI0_MPPLL_TST_CK",
+    "AD_APPLLGP_TST_CK",
+    "AD_APLL1_180P6336M_CK",
+    "AD_APLL1_196P608M_CK",
+    "AD_MADCKO_TEST",
+    "AD_MPLL_208M_CK",
+    "Armpll_ll_mon_ck",
+    "vad_clk_i",
+    "msdc01_in_ck",
+    "0",
+    "msdc11_in_ck",
+    "msdc12_in_ck",
+    "AD_PLLGP_TST_CK",
+    "AD_LVDSTX_CLKDIG_CTS",
+    "AD_LVDSTX_CLKDIG",
+    "AD_VPLL_DPIX_CK",
+    "DA_USB20_48M_DIV_CK",
+    "DA_UNIV_48M_DIV_CK",
+    "DA_MPLL_104M_DIV_CK",
+    "DA_MPLL_52M_DIV_CK",
+    "DA_PLLGP_CPU_CK_MON",
+    "trng_freq_debug_out0",
+    "trng_freq_debug_out1",
+    "AD_LVDSTX_MONCLK",
+    "AD_VPLL_MONREF_CK",
+    "AD_VPLL_MONFBK_CK",
+    "AD_LVDSPLL_300M_CK",
+    "AD_DSPPLL_CK",
+    "AD_APUPLL_CK",
+};
+
+#define CKGEN_CHANNEL_CNT 58
+#define ABIST_CHANNEL_CNT 58
+unsigned int ret_feq_store[CKGEN_CHANNEL_CNT+ABIST_CHANNEL_CNT];
+unsigned int ret_feq_total=0;
+unsigned int pll_chk_is_fail = 0;
+//after pmic_init
+void mt_pll_post_init(void)
+{
+    /* need dram porting code */
+    /* mempll_init_main(); */
+#ifdef _FREQ_SCAN_
+    unsigned int temp, ret_feq;
+    dprintf(CRITICAL, "Pll post init start...\n");
+    dprintf(CRITICAL, "==============================\n");
+    dprintf(CRITICAL, "==      Parsing Start       ==\n");
+    dprintf(CRITICAL, "==============================\n");
+    for (temp=1; temp<=CKGEN_CHANNEL_CNT; temp++) {
+        if (!ckgen_needCheck_array[temp-1])
+            continue;
+        else
+            dprintf(CRITICAL,"%d:",temp);
+        ret_feq = 0;
+        ret_feq = mt_get_ckgen_freq(temp);
+        ret_feq_store[ret_feq_total] = ret_feq;
+        ret_feq_total++;
+        dprintf(CRITICAL,"%s:", ckgen_array[temp-1]);
+        dprintf(CRITICAL,"%d\n",ret_feq);
+    }
+    //abist
+    for (temp=1; temp<=ABIST_CHANNEL_CNT; temp++) {
+        if (!abist_needCheck_array[temp-1])
+            continue;
+        else
+            dprintf(CRITICAL,"%d:",temp);
+        ret_feq = mt_get_abist_freq(temp);
+        ret_feq_store[ret_feq_total] = ret_feq;
+        ret_feq_total++;
+        dprintf(CRITICAL,"%s:", abist_array[temp-1]);
+        dprintf(CRITICAL,"%d\n", ret_feq);
+    }
+
+    dprintf(CRITICAL, "Pll post init Done!\n");
+#endif // _FREQ_SCAN_
+}
+
+/* Setting got from USB */
+void usb_pll_init(void)
+{
+    unsigned int temp;
+
+    temp = readl(UNIVPLL_CON0);
+    write_r(UNIVPLL_CON0, temp | (0x1 << 8));
+
+    temp = readl(IO_PHYS + 0x0000c304);
+    temp = (temp & 0xFFFFFFC7);
+    write_r(IO_PHYS + 0x0000c304, temp);
+    udelay(20);
+    temp = readl(AP_PLLGP_CON1);
+    write_r(AP_PLLGP_CON1, temp | (0x1 << 0));
+
+    temp = readl(AP_PLLGP_CON1);
+    write_r(AP_PLLGP_CON1, temp | (0x1 << 1));
+}
+
+void mt_pll_prepare(void)
+{
+    unsigned int mainpll_en = readl(MAINPLL_CON0) & 1;
+    unsigned int univpll_en = readl(UNIVPLL_CON0) & 1;
+    unsigned int armpll_en = readl(ARMPLL_CON0) & 1;
+    unsigned int pllgp_en = readl(AP_PLLGP_CON1) & 3;
+
+    if (!pllgp_en) {
+        write_r(AP_PLLGP_CON1, readl(AP_PLLGP_CON1) | 0x3);
+        udelay(1);
+    }
+
+    if (!mainpll_en && !univpll_en && !armpll_en)
+        return;
+
+    /* Before PLL and div_macro disable, switch source clock to 26M */
+    write_r(CLK_CFG_0, (readl(CLK_CFG_0) & 0xFFFFFFF0));
+    write_r(CLK_CFG_UPDATE, 0x00000001);
+
+    write_r(INFRA_BUS_DCM_CTRL,
+        readl(INFRA_BUS_DCM_CTRL) & 0xFFFFFFFC);
+    write_r(PERI_BUS_DCM_CTRL,
+        readl(PERI_BUS_DCM_CTRL) & 0xFFFFFFFC);
+    /* [22]=1'b0: disable the pllck_sel bit in infrasys DCM */
+    write_r(INFRA_BUS_DCM_CTRL,
+        readl(INFRA_BUS_DCM_CTRL) & (~(0x1 << 22)));
+
+    /* switch back to 26m */
+    write_r(BUS_PLL_DIV_CFG,
+        readl(BUS_PLL_DIV_CFG) & (~(0x1 << 9)));
+    write_r(ACLKEN_DIV, 0x11);
+
+    write_r(UNIVPLL_CON0, readl(UNIVPLL_CON0) & 0xFF7FFFFF);
+    write_r(UNIVPLL_CON0, readl(UNIVPLL_CON0) & 0xFFFFFFFE);
+    write_r(MAINPLL_CON0, readl(MAINPLL_CON0) & 0xFF7FFFFF);
+    write_r(MAINPLL_CON0, readl(MAINPLL_CON0) & 0xFFFFFFFE);
+    write_r(ARMPLL_CON0, readl(ARMPLL_CON0) & 0xFFFFFFFE);
+
+    udelay(1);
+
+    write_r(UNIVPLL_CON3, readl(UNIVPLL_CON3) | 0x2);
+    write_r(MAINPLL_CON3, readl(MAINPLL_CON3) | 0x2);
+    write_r(ARMPLL_CON3, readl(ARMPLL_CON3) | 0x2);
+
+    write_r(UNIVPLL_CON3, readl(UNIVPLL_CON3) & 0xFFFFFFFE);
+    write_r(MAINPLL_CON3, readl(MAINPLL_CON3) & 0xFFFFFFFE);
+    write_r(ARMPLL_CON3, readl(ARMPLL_CON3) & 0xFFFFFFFE);
+}
+
+void mt_pll_init(void)
+{
+    unsigned int temp;
+
+    dprintf(CRITICAL, "Pll init start...\n");
+    mt_pll_prepare();
+    //step 0
+    write_r(ACLKEN_DIV, 0x12); // MCU Bus DIV2
+    //step 1
+    temp = readl(AP_PLL_CON0);
+    write_r(AP_PLL_CON0, temp | 0x01);// [0]=1 (CLKSQ_EN)
+    //step 2
+    udelay(100);
+    //step 3
+    temp = readl(AP_PLL_CON0);
+    write_r(AP_PLL_CON0, temp | 0x2); // [1]=1 (CLKSQ_LPF_EN)
+    temp = readl(AP_PLL_CON3);
+    write_r(AP_PLL_CON3, temp & ~0x2); // [1]=0 (LTECLKSQ_EN_SEL)
+    temp = readl(AP_PLL_CON4);
+    write_r(AP_PLL_CON4, temp & ~0x10); // [4]=0 (LTECLKSQ_BY_DLY)
+    /*************
+    * xPLL PWR ON
+    **************/
+    //step 4
+    temp = readl(ARMPLL_CON3);
+    write_r(ARMPLL_CON3, temp | 0x1); // [0]=1 (ARMPLL_PWR_ON)
+    //step 7
+    temp = readl(MFGPLL_CON3);
+    write_r(MFGPLL_CON3, temp | 0x1); // [0]=1 (GPUPLL_PWR_ON)
+    //step 8
+    temp = readl(MPLL_CON3);
+    write_r(MPLL_CON3, temp | 0x1); // [0]=1 (MPLL_PWR_ON)
+    //step 9
+    temp = readl(MAINPLL_CON3);
+    write_r(MAINPLL_CON3, temp | 0x1); // [0]=1 (MAINPLL_PWR_ON)
+    //step 10
+    temp = readl(UNIVPLL_CON3);
+    write_r(UNIVPLL_CON3, temp | 0x1); // [0]=1 (UNIVPLL_PWR_ON)
+    //step 11
+    temp = readl(MSDCPLL_CON3);
+    write_r(MSDCPLL_CON3, temp | 0x1); // [0]=1 (MSDCPLL_PWR_ON)
+    //step 12
+    temp = readl(MMPLL_CON3);
+    write_r(MMPLL_CON3, temp | 0x1); // [0]=1 (MMPLL_PWR_ON)
+    //step 13
+    temp = readl(APLL1_CON4);
+    write_r(APLL1_CON4, temp | 0x1); // [0]=1 (APLL1_PWR_ON)
+
+    /* mt8168 */
+    temp = readl(APLL2_CON4);
+    write_r(APLL2_CON4, temp | 0x1); // [0]=1 (APLL2_PWR_ON)
+
+    temp = readl(LVDSPLL_CON3);
+    write_r(LVDSPLL_CON3, temp | 0x1); // [0]=1 (LVDSPLL_PWR_ON)
+
+    temp = readl(DSPPLL_CON3);
+    write_r(DSPPLL_CON3, temp | 0x1); // [0]=1 (DSPPLL_PWR_ON)
+
+    //step 14
+    udelay(30); // Wait 30us
+    /******************
+    * xPLL ISO Eisable
+    *******************/
+    //step 15
+    temp = readl(ARMPLL_CON3);
+    write_r(ARMPLL_CON3, temp & 0xFFFFFFFD); // [1]=0 (ARMPLL_ISO_EN)
+    //step 18
+    temp = readl(MFGPLL_CON3);
+    write_r(MFGPLL_CON3, temp & 0xFFFFFFFD); // [1]=0 (MFGPLL_ISO_EN)
+    //step 19
+    temp = readl(MPLL_CON3);
+    write_r(MPLL_CON3, temp & 0xFFFFFFFD); // [1]=0 (MPLL_ISO_EN)
+    //step 20
+    temp = readl(MAINPLL_CON3);
+    write_r(MAINPLL_CON3, temp & 0xFFFFFFFD); // [1]=0 (MAINPLL_ISO_EN)
+    //step 21
+    temp = readl(UNIVPLL_CON3);
+    write_r(UNIVPLL_CON3, temp & 0xFFFFFFFD); // [1]=0 (UNIVPLL_ISO_EN)
+    //step 22
+    temp = readl(MSDCPLL_CON3);
+    write_r(MSDCPLL_CON3, temp & 0xFFFFFFFD); // [1]=0 (MSDCPLL_ISO_EN)
+    //step 23
+    temp = readl(MMPLL_CON3);
+    write_r(MMPLL_CON3, temp & 0xFFFFFFFD); // [1]=0 (MMPLL_ISO_EN)
+    //step 24
+    temp = readl(APLL1_CON4);
+    write_r(APLL1_CON4, temp & 0xFFFFFFFD); // [1]=0 (APLL1_ISO_EN)
+
+    /* mt8168 */
+    //step 25
+    temp = readl(APLL2_CON4);
+    write_r(APLL2_CON4, temp & 0xFFFFFFFD); // [1]=0 (APLL2_ISO_EN)
+
+    temp = readl(LVDSPLL_CON3);
+    write_r(LVDSPLL_CON3, temp & 0xFFFFFFFD); // [1]=0 (LVDSPLL_ISO_EN)
+
+    temp = readl(DSPPLL_CON3);
+    write_r(DSPPLL_CON3, temp & 0xFFFFFFFD); // [1]=0 (DSPPLL_ISO_EN)
+
+    temp = readl(APUPLL_CON3);
+    write_r(APUPLL_CON3, temp & 0xFFFFFFFD); // [1]=0 (APUPLL_ISO_EN)
+
+    udelay(1); // Wait 1us
+    /********************
+    * xPLL Frequency Set
+    *********************/
+    write_r(ARMPLL_CON1, 0x811aec4e); // [25:0] (ARMPLL_N_INFO, 1400MHz)
+    //step 27
+    write_r(MFGPLL_CON1, 0x810f6276); // [21:0] (GPUPLL_N_INFO, 800MHz)
+    //step 28
+    /* Keep MPLL as default 208Mhz */
+    //step 29
+    write_r(MMPLL_CON1, 0x821193b1); // [21:0] (MMPLL_N_INFO, 457MHz)
+    //step 30
+    write_r(APUPLL_CON1, 0x82180000); // [21:0] (APUPLL_N_INFO, 624MHz)
+    write_r(DSPPLL_CON1, 0x821713b1); // [21:0] (DSPPLL_N_INFO, 600MHz)
+
+    //step 31
+	temp = readl(CLK_MSDCCG_REG);
+	write_r(CLK_MSDCCG_REG, (temp | 0x00000e00)); // gate msdc module src clk
+	write_r(MSDCPLL_CON1, 0x820F0000); // [21:0] (MSDCPLL_N_INFO, 390MHz)
+	write_r(CLK_MSDCCG_REG, (temp & 0xfffff1ff)); // ungate msdc module src clk
+
+    /***********************
+    * xPLL Frequency Enable
+    ************************/
+    //step 36
+    temp = readl(ARMPLL_CON0);
+    write_r(ARMPLL_CON0, temp | 0x1); // [0]=1 (ARMPLL_EN)
+    //step 39
+    temp = readl(MFGPLL_CON0);
+    write_r(MFGPLL_CON0, temp | 0x1); // [0]=1 (GPUPLL_EN)
+    //step 40
+    temp = readl(MPLL_CON0);
+    write_r(MPLL_CON0, temp | 0x1); // [0]=1 (MPLL_EN)
+    //step 41
+    temp = readl(MAINPLL_CON0);
+    write_r(MAINPLL_CON0, temp | 0x1); // [0]=1 (MAINPLL_EN)
+    //step 42
+    temp = readl(UNIVPLL_CON0);
+    write_r(UNIVPLL_CON0, temp | 0x1); // [0]=1 (UNIVPLL_EN)
+    //step 43
+    temp = readl(MSDCPLL_CON0);
+    write_r(MSDCPLL_CON0, temp | 0x1); // [0]=1 (MSDCPLL_EN)
+    //step 44
+    temp = readl(MMPLL_CON0);
+    write_r(MMPLL_CON0, temp | 0x1); // [0]=1 (MMPLL_EN)
+    //step 45
+    temp = readl(APLL1_CON0);
+    write_r(APLL1_CON0, temp | 0x1); // [0]=1 (APLL1_EN)
+
+    /* mt8168 */
+    temp = readl(APLL2_CON0);
+    write_r(APLL2_CON0, temp | 0x1); // [1]=0 (APLL2_EN)
+
+    temp = readl(LVDSPLL_CON0);
+    write_r(LVDSPLL_CON0, temp | 0x1); // [1]=0 (LVDSPLL_EN)
+
+    temp = readl(DSPPLL_CON0);
+    write_r(DSPPLL_CON0, temp | 0x1); // [1]=0 (DSPPLL_EN)
+
+    temp = readl(APUPLL_CON0);
+    write_r(APUPLL_CON0, temp | 0x1); // [1]=0 (APUPLL_EN)
+
+    temp = readl(ULPLL_CON1);
+    write_r(ULPLL_CON1, temp | 0x4); // [2]=1 (ULPLL_HPM_EN)
+
+    /***************
+    * xPLL DIV Enable
+    ****************/
+    //step 46
+    temp = readl(MAINPLL_CON0);
+    write_r(MAINPLL_CON0, temp | 0xFF000180); // [31:24] (MAINPLL_DIV_EN)
+    //step 47
+    temp = readl(UNIVPLL_CON0);
+    write_r(UNIVPLL_CON0, temp | 0xFF000080); // [31:24] (UNIVPLL_DIV_EN)
+    // step 48
+    udelay(20); // Wait PLL stable (20us)
+    /***************
+    * xPLL DIV RSTB
+    ****************/
+    //step 49
+    temp = readl(MAINPLL_CON0);
+    write_r(MAINPLL_CON0, temp | 0x00800000); // [23]=1 (MAINPLL_DIV_RSTB)
+    //step 50
+    temp = readl(UNIVPLL_CON0);
+    write_r(UNIVPLL_CON0, temp | 0x00800000); // [23]=1 (UNIVPLL_DIV_RSTB)
+    // step 51
+    udelay(20); // Wait PLL stable (20us)
+    /*****************
+    * xPLL HW Control
+    ******************/
+    //step 52
+    temp = readl(PLLON_CON0);
+    // [29]= 0 MPLL_RSTB_SEL(spm), [30]=0 MAINPLL_RSTB_SEL(spm), [31]=0 ARMPLL_RSTB_SEL(spm)
+    write_r(PLLON_CON0, temp & 0x1111ffbf);
+    /**************
+    * INFRA CPU CLKMUX, CLK Div
+    ***************/
+#ifdef SET_ARMPLL_DIV_EN
+    /* 8: div1, A: div2, B: div4, 1D: div6 */
+    temp = readl(MP0_PLL_DIV_CFG) ;
+    write_r(MP0_PLL_DIV_CFG, (temp & 0xFFC1FFFF) | (0x08 << 17)); // [21:17] divsel: CPU clock divide by 1
+    temp = readl(MP1_PLL_DIV_CFG) ;
+    write_r(MP1_PLL_DIV_CFG, (temp & 0xFFC1FFFF) | (0x08 << 17)); // [21:17] divsel: CPU clock divide by 1
+    temp = readl(BUS_PLL_DIV_CFG) ;
+    write_r(BUS_PLL_DIV_CFG, (temp & 0xFFC1FFFF) | (0x0A << 17)); // [21:17] divsel: CPU clock divide by 1 ?
+#endif
+#ifdef SET_ARMPLL_CLK_SRC
+    /* 0: 26M,  1: armpll, 2:  Mainpll, 3:  Unipll */
+    /*
+    * if (MP_SYNC_DCM_CONFIG.mp0_sync_dcm_div_en==1) {
+    *   x==1;
+    * } else {
+    *   x inside {[0:1]};
+    *}
+    */
+    temp = readl(MP0_PLL_DIV_CFG);
+    write_r(MP0_PLL_DIV_CFG, (temp & 0xFFFFF9FF) | (0x01<<9)); // [10:9] muxsel: switch to PLL speed
+    /*
+    * if (MP_SYNC_DCM_CONFIG.mp1_sync_dcm_div_en==1) {
+    *   x==1;
+    * } else {
+    *   x inside {[0:1]};
+    *}
+    */
+    temp = readl(MP1_PLL_DIV_CFG);
+    write_r(MP1_PLL_DIV_CFG, (temp & 0xFFFFF9FF) | (0x01<<9)); // [10:9] muxsel: switch to PLL speed
+    /*
+    * if (MP_SYNC_DCM_CONFIG.cci_sync_dcm_div_en==1) {
+    *   x==1;
+    * } else if (gic_sync_dcm.gic_sync_dcm_en==1) {
+    *   x==1;
+    * } else {
+    *   x inside {[0:1]};
+    *}
+    */
+    temp = readl(BUS_PLL_DIV_CFG);
+    /* [10:9] muxsel: switch to PLL speed */
+    write_r(BUS_PLL_DIV_CFG, (temp & 0xFFFFF9FF) | (0x01 << 9));
+#endif
+    /************
+    * TOP CLKMUX
+    *************/
+    /* config AXI clock first, axi=syspll_d7 */
+    write_r(CLK_CFG_0, 0x00000001);
+    write_r(CLK_CFG_UPDATE, 0x00000001);
+
+   /* CLK_SCP_CFG_0: [0] = sc_26ck_off_en, [1] = sc_memck_off_en,
+    * [2] = sc_axick_off_en, [9] = sc_mac_26m_off_en
+    */
+    temp = readl(CLK_SCP_CFG_0);
+    write_r(CLK_SCP_CFG_0, (temp | 0x207));
+
+    /* CLK_SCP_CFG_1[22:20] => 1 */
+    /* CLK_SCP_CFG_1[16] => 0 */
+    temp = readl(CLK_SCP_CFG_1);
+    write_r(CLK_SCP_CFG_1, (temp & 0xFF8EFFFF) | (0x01 << 20) | (0x1));
+    /* config other clocks */
+    write_r(CLK_CFG_0, 0x06010101);
+    write_r(CLK_CFG_1, 0x02010201);	// [18:16] 0:26Mhz, 1:24Mhz, 2:54Mhz, 3:48Mhz
+    write_r(CLK_CFG_2, 0x01010100);
+    write_r(CLK_CFG_3, 0x01020101);
+    write_r(CLK_CFG_4, 0x03010101);
+    write_r(CLK_CFG_5, 0x02010103);
+    write_r(CLK_CFG_6, 0x01030301);
+    write_r(CLK_CFG_7, 0x01020202);
+    write_r(CLK_CFG_8, 0x02010003); /* clk_dpi0_sel -> clk26m_ck */
+    write_r(CLK_CFG_9, 0x04020403);
+    write_r(CLK_CFG_10, 0x01010103); /* clk_gcpu_sel -> syspll_d3 */
+    write_r(CLK_CFG_11, 0x00000000);
+
+    /* update all clocks except "fmem & axi"(dram) */
+    write_r(CLK_CFG_UPDATE, 0xFFFFFFFC);
+    write_r(CLK_CFG_UPDATE1, 0x00000FFF);
+
+    /* TOPCKGEN */
+    temp = readl(CLK_MISC_CFG_0);
+    write_r(CLK_MISC_CFG_0, temp | 0x00f13f78);
+    temp = readl(CLK_AUDDIV_0);
+    write_r(CLK_AUDDIV_0, temp & ~(0x3F9FF));
+
+    /* INFRA CG */
+    write_r(INFRA_TOPAXI_SI0_CTL,
+            readl(INFRA_TOPAXI_SI0_CTL) | (0x80000000));
+    write_r(PERI_BUS_DCM_CTRL,
+            readl(PERI_BUS_DCM_CTRL) & ~(0x00000004));
+    write_r(INFRA_BUS_DCM_CTRL,
+            readl(INFRA_BUS_DCM_CTRL) | 0x00400000);
+
+    write_r(MODULE_SW_CG_0_CLR, 0x9DFF877F);
+    write_r(MODULE_SW_CG_1_CLR, 0x879C7796);
+    write_r(MODULE_SW_CG_2_CLR, 0x3ffc87dd);
+    write_r(MODULE_SW_CG_3_CLR, 0x7FFFFFBF);
+    write_r(MODULE_SW_CG_4_CLR, 0x00000FFF);
+    write_r(MODULE_SW_CG_1_SET, 0x800);
+
+    spm_mtcmos_ctrl_dis(STA_POWER_ON);
+    spm_mtcmos_ctrl_cam(STA_POWER_ON);
+    spm_mtcmos_ctrl_ven(STA_POWER_ON);
+    spm_mtcmos_ctrl_vde(STA_POWER_ON);
+    spm_mtcmos_ctrl_audio(STA_POWER_ON);
+
+    /* PERICFG */
+    temp = readl(PERIAXI_SI0_CTL);
+    write_r(PERIAXI_SI0_CTL, temp | 0x80000000);
+
+    /* MFGCFG */
+    temp = readl(MFG_CG_CLR);
+    write_r(MFG_CG_CLR, temp & ~(0x1));
+    temp = readl(MFG_MBIST_CFG);
+    write_r(MFG_MBIST_CFG, temp & ~(0x1000000));
+
+    /* MMSYS */
+    write_r(MMSYS_CG_CLR0, 0xFFFFFFFF);
+    write_r(MMSYS_CG_CLR1, 0x0000000F);
+
+    /* CAMSYS */
+    write_r(CAMSYS_CG_CLR, 0x00001fc1);
+
+    /* VDEC */
+    temp = readl(VDEC_CKEN_SET);
+    write_r(VDEC_CKEN_SET, temp | 0x1);
+    temp = readl(VDEC_LARB3_CKEN_SET);
+    write_r(VDEC_LARB3_CKEN_SET, temp | 0x1);
+
+    /* VENC */
+    temp = readl(VENC_CG_CON);
+    write_r(VENC_CG_CON, temp | 0x110);
+    usb_pll_init();
+
+    /* CONNSYS MCU reset */
+    temp = readl(WDT_SWSYSRST);
+    write_r(WDT_SWSYSRST, (temp | CONNSYS_CPU_SW_RST | RGU_KEY_CODE));
+
+    dprintf(CRITICAL, "Pll init Done!\n");
+    mt_pll_post_init();
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/pmic/mt6357.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/pmic/mt6357.c
new file mode 100644
index 0000000..3129fe8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/pmic/mt6357.c
@@ -0,0 +1,596 @@
+/*
+ * 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.
+ */
+
+#include <compiler.h>
+#include <debug.h>
+#include <platform/mt6357.h>
+#include <platform/pmic_wrap.h>
+
+static struct pmic_setting init_setting[] = {
+	/* [15:0]: TMA_KEY */
+	{0x3AE, 0x9CA8, 0xFFFF, 0},
+	/* [1:1]: RG_SRCLKEN_IN0_HW_MODE */
+	/* [3:3]: RG_SRCLKEN_IN1_HW_MODE */
+	{0x1A, 0xA, 0xA, 0},
+	/* [12:8]: RG_MON_GRP_SEL */
+	{0x1E, 0x1F00, 0x1F00, 0},
+	/* [0:0]: RG_SMT_WDTRSTB_IN */
+	{0x2A, 0x1, 0x1, 0},
+	/* [0:0]: RG_SMT_SPI_CLK */
+	{0x2C, 0x1, 0x1, 0},
+	/* [3:0]: RG_OCTL_SRCLKEN_IN0 */
+	/* [7:4]: RG_OCTL_SRCLKEN_IN1 */
+	/* [11:8]: RG_OCTL_RTC_32K1V8_0 */
+	/* [15:12]: RG_OCTL_RTC_32K1V8_1 */
+	{0x32, 0x8888, 0xFFFF, 0},
+	/* [3:0]: RG_OCTL_AUD_CLK_MOSI */
+	/* [7:4]: RG_OCTL_AUD_DAT_MOSI0 */
+	/* [11:8]: RG_OCTL_AUD_DAT_MOSI1 */
+	/* [15:12]: RG_OCTL_AUD_SYNC_MOSI */
+	{0x36, 0x8888, 0xFFFF, 0},
+	/* [3:0]: RG_OCTL_AUD_CLK_MISO */
+	/* [7:4]: RG_OCTL_AUD_DAT_MISO0 */
+	/* [11:8]: RG_OCTL_AUD_DAT_MISO1 */
+	/* [15:12]: RG_OCTL_AUD_SYNC_MISO */
+	{0x38, 0x8888, 0xFFFF, 0},
+	/* [15:0]: GPIO_PULLEN0 */
+	{0x8E, 0x0, 0xFFFF, 0},
+	/* [3:3]: RG_INTRP_PRE_OC_CK_PDN */
+	/* [4:4]: RG_EFUSE_CK_PDN */
+	{0x10C, 0x18, 0x18, 0},
+	/* [2:2]: RG_TRIM_128K_CK_PDN */
+	{0x112, 0x4, 0x4, 0},
+	/* [3:3]: RG_RTC_32K1V8_SEL */
+	{0x118, 0x8, 0x8, 0},
+	/* [7:7]: RG_SRCLKEN2_LP_EN */
+	/* [11:11]: RG_BUCK_PFM_FLAG_SW_EN */
+	/* [13:13]: RG_DCXO26M_RDY_SW_EN */
+	{0x134, 0x80, 0x2880, 0},
+	/* [5:5]: RG_WDTRSTB_DEB */
+	{0x14C, 0x20, 0x20, 0},
+	/* [0:0]: RG_INT_MASK_BUCK_TOP */
+	/* [1:1]: RG_INT_MASK_LDO_TOP */
+	/* [2:2]: RG_INT_MASK_PSC_TOP */
+	/* [3:3]: RG_INT_MASK_SCK_TOP */
+	/* [4:4]: RG_INT_MASK_BM_TOP */
+	/* [5:5]: RG_INT_MASK_HK_TOP */
+	/* [6:6]: RG_INT_MASK_XPP_TOP */
+	/* [7:7]: RG_INT_MASK_AUD_TOP */
+	/* [8:8]: RG_INT_MASK_MISC_TOP */
+	{0x198, 0x0, 0x1FF, 0},
+	/* [0:0]: RG_SLP_RW_EN */
+	{0x408, 0x1, 0x1, 0},
+	/* [8:7]: XO_AAC_MODE_LPM */
+	/* [10:9]: XO_AAC_MODE_FPM */
+	{0x790, 0x280, 0x780, 0},
+	/* [7:0]: XO_CDAC_FPM */
+	{0x794, 0x88, 0xFF, 0},
+	/* [8:5]: XO_AAC_VSEL_LPM */
+	{0x79E, 0x80, 0x1E0, 0},
+	/* [13:13]: XO_AUDIO_EN_M */
+	{0x7AC, 0x0, 0x2000, 0},
+	/* [6:6]: RG_RST_DRVSEL */
+	{0x98A, 0x40, 0x40, 0},
+	/* [0:0]: RG_FCHR_PU_EN */
+	{0x98C, 0x1, 0x1, 0},
+	/* [0:0]: RG_PWRHOLD */
+	{0xA08, 0x1, 0x1, 0},
+	/* [3:3]: RG_STRUP_AUXADC_RSTB_SEL */
+	{0xA20, 0x8, 0x8, 0},
+	/* [5:5]: RG_STRUP_LONG_PRESS_EXT_CHR_CTRL */
+	/* [6:6]: RG_STRUP_LONG_PRESS_EXT_PWRKEY_CTRL */
+	/* [7:7]: RG_STRUP_LONG_PRESS_EXT_SPAR_CTRL */
+	/* [8:8]: RG_STRUP_LONG_PRESS_EXT_RTCA_CTRL */
+	/* [15:15]: RG_STRUP_ENVTEM_CTRL */
+	{0xA2C, 0x81E0, 0x81E0, 0},
+	/* [4:4]: RG_STRUP_EXT_PMIC_PG_H2L_EN */
+	/* [5:5]: RG_STRUP_VAUD28_PG_H2L_EN */
+	/* [6:6]: RG_STRUP_VUSB33_PG_H2L_EN */
+	/* [7:7]: RG_STRUP_VDRAM_PG_H2L_EN */
+	/* [8:8]: RG_STRUP_VEMC_PG_H2L_EN */
+	/* [9:9]: RG_STRUP_VSRAM_PROC_PG_H2L_EN */
+	/* [10:10]: RG_STRUP_VSRAM_OTHERS_PG_H2L_EN */
+	/* [11:11]: RG_STRUP_VAUX18_PG_H2L_EN */
+	/* [12:12]: RG_STRUP_VPROC_PG_H2L_EN */
+	/* [13:13]: RG_STRUP_VMODEM_PG_H2L_EN */
+	/* [14:14]: RG_STRUP_VCORE_PG_H2L_EN */
+	/* [15:15]: RG_STRUP_VS1_PG_H2L_EN */
+	{0xA30, 0xFFF0, 0xFFF0, 0},
+	/* [9:9]: RG_SDN_DLY_ENB */
+	{0xA3C, 0x200, 0x200, 0},
+	/* [6:4]: FG_AUTOCALRATE */
+	{0xD08, 0x20, 0x70, 0},
+	/* [0:0]: RG_AUXADC_AO_1M_CK_PDN */
+	/* [1:1]: RG_AUXADC_1M_CK_PDN_HWEN */
+	/* [2:2]: RG_AUXADC_1M_CK_PDN */
+	/* [3:3]: RG_AUXADC_CK_PDN_HWEN */
+	/* [4:4]: RG_AUXADC_CK_PDN */
+	/* [5:5]: RG_AUXADC_RNG_CK_PDN_HWEN */
+	/* [6:6]: RG_AUXADC_RNG_CK_PDN */
+	/* [7:7]: RG_AUXADC_32K_CK_PDN_HWEN */
+	/* [8:8]: RG_AUXADC_32K_CK_PDN */
+	/* [9:9]: RG_AUXADC_1K_CK_PDN */
+	{0xF8C, 0xAA, 0x3FF, 0},
+	/* [9:9]: RG_AUXADC_CK_DIVSEL */
+	{0xF8E, 0x0, 0x1, 0},
+	/* [3:0]: RG_AUXADC_CALI */
+	{0x1008, 0x1, 0xF, 0},
+	/* [15:15]: AUXADC_CK_AON */
+	{0x1120, 0x0, 0x8000, 0},
+	/* [15:6]: AUXADC_SPL_NUM */
+	{0x1126, 0x340, 0xFFC0, 0},
+	/* [11:0]: AUXADC_AVG_NUM_SEL */
+	/* [15:5]: AUXADC_AVG_NUM_SEL_WAKEUP */
+	{0x1128, 0x8083, 0x8FFF, 0},
+	/* [9:0]: AUXADC_SPL_NUM_LARGE */
+	{0x112A, 0x30, 0x3FF, 0},
+	/* [14:14]: AUXADC_SPL_NUM_SEL_BAT_TEMP */
+	{0x112E, 0x4000, 0x4000, 0},
+	/* [9:0]: AUXADC_SPL_NUM_CH0 */
+	{0x1130, 0xB, 0x3FF, 0},
+	/* [9:0]: AUXADC_SPL_NUM_CH3 */
+	{0x1132, 0x30, 0x3FF, 0},
+	/* [9:0]: AUXADC_SPL_NUM_CH7 */
+	{0x1134, 0xB, 0x3FF, 0},
+	/* [14:12]: AUXADC_AVG_NUM_CH0 */
+	{0x1136, 0x6000, 0x7000, 0},
+	/* [6:4]: AUXADC_AVG_NUM_DCXO */
+	{0x1138, 0x60, 0x70, 0},
+	/* [5:4]: AUXADC_TRIM_CH2_SEL */
+	/* [7:6]: AUXADC_TRIM_CH3_SEL */
+	/* [9:8]: AUXADC_TRIM_CH4_SEL */
+	/* [11:10]: AUXADC_TRIM_CH5_SEL */
+	/* [13:12]: AUXADC_TRIM_CH6_SEL */
+	/* [15:14]: AUXADC_TRIM_CH7_SEL */
+	{0x113A, 0x95D0, 0xFFF0, 0},
+	/* [1:0]: AUXADC_TRIM_CH8_SEL */
+	/* [3:2]: AUXADC_TRIM_CH9_SEL */
+	/* [5:4]: AUXADC_TRIM_CH10_SEL */
+	/* [7:6]: AUXADC_TRIM_CH11_SEL */
+	{0x113C, 0x55, 0xFF, 0},
+	/* [14:14]: AUXADC_START_SHADE_EN */
+	{0x1148, 0x4000, 0x4000, 0},
+	/* [1:0]: AUXADC_DATA_REUSE_SEL */
+	/* [8:8]: AUXADC_DATA_REUSE_EN */
+	{0x114C, 0x100, 0x103, 0},
+	/* [9:0]: AUXADC_MDRT_DET_PRD */
+	/* [15:15]: AUXADC_MDRT_DET_EN */
+	{0x1208, 0x8040, 0x83FF, 0},
+	/* [2:2]: AUXADC_MDRT_DET_WKUP_EN */
+	{0x120C, 0x4, 0x4, 0},
+	/* [0:0]: AUXADC_MDRT_DET_START_SEL */
+	{0x1210, 0x1, 0x1, 0},
+	/* [0:0]: RG_AUXADC_IMP_CK_SW_MODE */
+	{0x122E, 0x0, 0x1, 0},
+	/* [3:3]: RG_BUCK_DCM_MODE */
+	{0x1412, 0x8, 0x8, 0},
+	/* [1:0]: RG_BUCK_VPROC_FREQ_SEL */
+	/* [3:2]: RG_BUCK_VCORE_FREQ_SEL */
+	{0x1418, 0xF, 0xF, 0},
+	/* [4:4]: RG_BUCK_VPA_OC_SDN_EN */
+	{0x1444, 0x10, 0x10, 0},
+	/* [6:0]: RG_BUCK_VPROC_VOSEL_SLEEP */
+	{0x148A, 0x0, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VPROC_SFCHG_FRATE */
+	/* [14:8]: RG_BUCK_VPROC_SFCHG_RRATE */
+	{0x148C, 0xF0F, 0x7F7F, 0},
+	/* [5:4]: RG_BUCK_VPROC_DVS_EN_CTRL */
+	/* [13:12]: RG_BUCK_VPROC_DVS_DOWN_CTRL */
+	{0x148E, 0x1030, 0x3030, 0},
+	/* [6:0]: RG_BUCK_VCORE_VOSEL_SLEEP */
+	{0x150A, 0x15, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VCORE_SFCHG_FRATE */
+	/* [14:8]: RG_BUCK_VCORE_SFCHG_RRATE */
+	{0x150C, 0x1429, 0x7F7F, 0},
+	/* [5:4]: RG_BUCK_VCORE_DVS_EN_CTRL */
+	/* [13:12]: RG_BUCK_VCORE_DVS_DOWN_CTRL */
+	{0x150E, 0x1030, 0x3030, 0},
+	/* [0:0]: RG_BUCK_VMODEM_EN */
+	{0x1588, 0x0, 0x1, 0},
+	/* [6:0]: RG_BUCK_VMODEM_VOSEL_SLEEP */
+	{0x158A, 0x8, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VMODEM_SFCHG_FRATE */
+	/* [14:8]: RG_BUCK_VMODEM_SFCHG_RRATE */
+	{0x158C, 0x70F, 0x7F7F, 0},
+	/* [5:4]: RG_BUCK_VMODEM_DVS_EN_CTRL */
+	/* [6:6]: RG_BUCK_VMODEM_DVS_EN_ONCE */
+	/* [13:12]: RG_BUCK_VMODEM_DVS_DOWN_CTRL */
+	/* [14:14]: RG_BUCK_VMODEM_DVS_DOWN_ONCE */
+	{0x158E, 0x1010, 0x7070, 0},
+	/* [6:0]: RG_BUCK_VS1_VOSEL_SLEEP */
+	{0x160A, 0x35, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VS1_SFCHG_RRATE */
+	/* [14:8]: RG_BUCK_VS1_SFCHG_FRATE */
+	{0x160C, 0x1968, 0x7F7F, 0},
+	/* [5:4]: RG_BUCK_VS1_DVS_EN_CTRL */
+	/* [13:12]: RG_BUCK_VS1_DVS_DOWN_CTRL */
+	{0x160E, 0x2020, 0x3030, 0},
+	/* [6:0]: RG_BUCK_VS1_VOTER_VOSEL */
+	{0x162E, 0x40, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VS1_VOSEL */
+	{0x1632, 0x48, 0x7F, 0},
+	/* [6:0]: RG_BUCK_VPA_SFCHG_FRATE */
+	/* [14:8]: RG_BUCK_VPA_SFCHG_RRATE */
+	{0x168C, 0x202, 0x7F7F, 0},
+	/* [1:0]: RG_BUCK_VPA_DVS_TRANST_TD */
+	/* [5:4]: RG_BUCK_VPA_DVS_TRANST_CTRL */
+	/* [6:6]: RG_BUCK_VPA_DVS_TRANST_ONCE */
+	{0x168E, 0x70, 0x73, 0},
+	/* [1:1]: RG_BUCK_VPA_OC_DEG_EN */
+	/* [3:2]: RG_BUCK_VPA_OC_WND */
+	/* [7:6]: RG_BUCK_VPA_OC_THD */
+	{0x1690, 0xE, 0xCE, 0},
+	/* [5:0]: RG_BUCK_VPA_VOSEL_DLC011 */
+	/* [13:8]: RG_BUCK_VPA_VOSEL_DLC111 */
+	{0x1698, 0x2810, 0x3F3F, 0},
+	/* [13:8]: RG_BUCK_VPA_VOSEL_DLC001 */
+	{0x169A, 0x800, 0x3F00, 0},
+	/* [0:0]: RG_BUCK_VPA_MSFG_EN */
+	{0x169E, 0x1, 0x1, 0},
+	/* [13:12]: RG_VPA_BURSTH */
+	{0x1708, 0x2000, 0x3000, 0},
+	/* [7:5]: RG_VCORE_SLEEP_VOLTAGE */
+	/* [10:8]: RG_VMODEM_SLEEP_VOLTAGE */
+	{0x170A, 0x120, 0x7E0, 0},
+	/* [2:0]: RG_VPROC_SLEEP_VOLTAGE */
+	/* [5:3]: RG_VSRAM_PROC_SLEEP_VOLTAGE */
+	/* [8:6]: RG_VSRAM_OTHERS_SLEEP_VOLTAGE */
+	{0x170C, 0x190, 0x1FF, 0},
+	/* [5:5]: RG_VCORE_FCOT */
+	/* [6:6]: RG_VPROC_FCOT */
+	{0x170E, 0x60, 0x60, 0},
+	/* [3:0]: RG_VCORE_RCOMP0 */
+	/* [10:9]: RG_VCORE_CCOMP1 */
+	{0x1710, 0x209, 0x60F, 0},
+	/* [3:0]: RG_VPROC_RCOMP0 */
+	/* [10:9]: RG_VPROC_CCOMP1 */
+	{0x1712, 0x208, 0x60F, 0},
+	/* [5:4]: RG_VCORE_UG_SR */
+	/* [7:6]: RG_VCORE_LG_SR */
+	/* [9:8]: RG_VPROC_UG_SR */
+	/* [11:10]: RG_VPROC_LG_SR */
+	/* [14:12]: RG_VCORE_PFM_TON */
+	{0x1716, 0xFF0, 0x7FF0, 0},
+	/* [2:0]: RG_VPROC_PFM_TON */
+	{0x1718, 0x0, 0x7, 0},
+	/* [15:13]: RG_VCORE_COTRAMP_SLP */
+	{0x171C, 0x8000, 0xE000, 0},
+	/* [2:0]: RG_VPROC_COTRAMP_SLP */
+	/* [4:3]: RG_VCORE_SLEEP_TIME */
+	/* [6:5]: RG_VPROC_SLEEP_TIME */
+	/* [8:7]: RG_VCORE_VREFTB */
+	/* [10:9]: RG_VPROC_VREFTB */
+	{0x171E, 0x2AD, 0x7FF, 0},
+	/* [15:0]: RG_VCORE_RSV */
+	{0x1720, 0x327A, 0xFFFF, 0},
+	/* [15:0]: RG_VPROC_RSV */
+	{0x1722, 0x323A, 0xFFFF, 0},
+	/* [1:1]: RG_VMODEM_FCOT */
+	/* [5:2]: RG_VMODEM_RCOMP */
+	/* [6:6]: RG_VMODEM_TB_DIS */
+	/* [11:9]: RG_VMODEM_PFM_TON */
+	/* [14:12]: RG_VMODEM_PWMRAMP_SLP */
+	{0x1726, 0x304A, 0x7E7E, 0},
+	/* [11:10]: RG_VMODEM_VREFUP */
+	/* [13:12]: RG_VMODEM_TB_WIDTH */
+	{0x1728, 0x800, 0x3C00, 0},
+	/* [1:0]: RG_VMODEM_UG_SR */
+	/* [3:2]: RG_VMODEM_LG_SR */
+	/* [5:4]: RG_VMODEM_CCOMP */
+	{0x172A, 0x3F, 0x3F, 0},
+	/* [15:0]: RG_VMODEM_RSV */
+	{0x172C, 0x5258, 0xFFFF, 0},
+	/* [2:0]: RG_VS1_SLP */
+	{0x1734, 0x3, 0x7, 0},
+	/* [3:0]: RG_VS1_RSV_L */
+	{0x173A, 0x8, 0xF, 0},
+	/* [5:4]: RG_VPA_CSMIR */
+	/* [7:6]: RG_VPA_CSL */
+	/* [10:10]: RG_VPA_AZC_EN */
+	{0x1740, 0x50, 0x4F0, 0},
+	/* [3:2]: RG_VPA_SLEW */
+	/* [5:4]: RG_VPA_SLEW_NMOS */
+	/* [7:6]: RG_VPA_MIN_ON */
+	{0x1742, 0x3C, 0xFC, 0},
+	/* [9:8]: RG_VPA_MIN_PK */
+	{0x1744, 0x0, 0x300, 0},
+	/* [7:0]: RG_VPA_RSV1 */
+	/* [15:8]: RG_VPA_RSV2 */
+	{0x1746, 0x8886, 0xFFFF, 0},
+	/* [14:13]: RG_VS1_SLEEP_VOLTAGE */
+	{0x174C, 0x0, 0x6000, 0},
+	/* [1:0]: RG_VCORE_ZC_TRIM */
+	/* [5:2]: RG_VCORE_NLIM_TRIM */
+	{0x1758, 0x17, 0x3F, 0},
+	/* [9:8]: RG_VPROC_ZC_TRIM */
+	/* [13:10]: RG_VPROC_NLIM_TRIM */
+	{0x175C, 0x1700, 0x3F00, 0},
+	/* [11:8]: RG_VPA_NLIM_SEL */
+	{0x176C, 0x700, 0xF00, 0},
+	/* [0:0]: RG_LDO_DCM_MODE */
+	{0x188C, 0x1, 0x1, 0},
+	/* [0:0]: RG_LDO_VIO28_CK_SW_MODE */
+	{0x188E, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VIO18_CK_SW_MODE */
+	{0x1890, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VAUD28_CK_SW_MODE */
+	{0x1892, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VDRAM_CK_SW_MODE */
+	{0x1894, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VSRAM_PROC_CK_SW_MODE */
+	{0x1896, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VSRAM_OTHERS_CK_SW_MODE */
+	{0x1898, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VAUX18_CK_SW_MODE */
+	{0x189A, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VUSB33_CK_SW_MODE */
+	{0x189C, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VEMC_CK_SW_MODE */
+	{0x189E, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VXO22_CK_SW_MODE */
+	{0x18A0, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VSIM1_CK_SW_MODE */
+	{0x18A2, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VSIM2_CK_SW_MODE */
+	{0x18A4, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMD_CK_SW_MODE */
+	{0x18A6, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMIO_CK_SW_MODE */
+	{0x18A8, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VEFUSE_CK_SW_MODE */
+	{0x18AA, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN33_CK_SW_MODE */
+	{0x18AC, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN18_CK_SW_MODE */
+	{0x18AE, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCN28_CK_SW_MODE */
+	{0x18B0, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VIBR_CK_SW_MODE */
+	{0x18B2, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VFE28_CK_SW_MODE */
+	{0x18B4, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VMCH_CK_SW_MODE */
+	{0x18B6, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VMC_CK_SW_MODE */
+	{0x18B8, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VRF18_CK_SW_MODE */
+	{0x18BA, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VLDO28_CK_SW_MODE */
+	{0x18BC, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VRF12_CK_SW_MODE */
+	{0x18BE, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_VCAMA_CK_SW_MODE */
+	{0x18C0, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_TREF_CK_SW_MODE */
+	{0x18C2, 0x0, 0x1, 0},
+	/* [0:0]: RG_LDO_WDT_MODE */
+	{0x18E6, 0x1, 0x1, 0},
+	/* [6:0]: RG_LDO_VSRAM_PROC_VOSEL_SLEEP */
+	{0x19B4, 0x35, 0x7F, 0},
+	/* [6:0]: RG_LDO_VSRAM_PROC_SFCHG_FRATE */
+	/* [14:8]: RG_LDO_VSRAM_PROC_SFCHG_RRATE */
+	{0x19B6, 0x70F, 0x7F7F, 0},
+	/* [6:0]: RG_LDO_VSRAM_OTHERS_VOSEL_SLEEP */
+	{0x19D2, 0xD, 0x7F, 0},
+	/* [6:0]: RG_LDO_VSRAM_OTHERS_SFCHG_FRATE */
+	/* [14:8]: RG_LDO_VSRAM_OTHERS_SFCHG_RRATE */
+	{0x19D4, 0xF0F, 0x7F7F, 0},
+	/* [0:0]: RG_LDO_TREF_EN */
+	{0x1B9E, 0x1, 0x1, 0},
+	/* [15:0]: TMA_KEY */
+	{0x3AE, 0, 0xFFFF, 0},
+
+	/* Reset digital only,Enable WDT */
+	/* [15:0]: TOP_RST_MISC_SET */
+	{0x14E, 0x21, 0xFFFF, 0},
+	/* [15:0]: TOP_RST_MISC_CLR */
+	{0x150, 0x2, 0xFFFF, 0},
+
+	/* Enable VUSB33 */
+	/* [0:0]: RG_LDO_VUSB33_SW_OP_EN */
+	{0x199C, 0x1, 0x1, 0},
+};
+
+static void mt6357_init_setting(void)
+{
+	for (size_t i = 0; i < ARRAY_SIZE(init_setting); i++)
+		pwrap_write_field(
+			init_setting[i].addr, init_setting[i].val,
+			init_setting[i].mask, init_setting[i].shift);
+}
+
+static void pmic_dump_status(void)
+{
+	dprintf(CRITICAL, "[%s] TOP_RST_STATUS[0x%x]=0x%x\n", __func__,
+		PMIC_TOP_RST_STATUS, pwrap_read_field(PMIC_TOP_RST_STATUS, 0xFFFF, 0));
+	dprintf(CRITICAL, "[%s] PONSTS[0x%x]=0x%x\n", __func__,
+		PMIC_PONSTS, pwrap_read_field(PMIC_PONSTS, 0xFFFF, 0));
+	dprintf(CRITICAL, "[%s] PMIC_POFFSTS[0x%x]=0x%x\n", __func__,
+		PMIC_POFFSTS, pwrap_read_field(PMIC_POFFSTS, 0xFFFF, 0));
+	dprintf(CRITICAL, "[%s] PGSTATUS0[0x%x]=0x%x\n", __func__,
+		PMIC_PG_SDN_STS, pwrap_read_field(PMIC_PG_SDN_STS, 0xFFFF, 0));
+	dprintf(CRITICAL, "[%s] PSOCSTATUS[0x%x]=0x%x\n", __func__,
+		PMIC_OC_SDN_STS, pwrap_read_field(PMIC_OC_SDN_STS, 0xFFFF, 0));
+	dprintf(CRITICAL, "[%s] BUCK_OC_SDN_STATUS[0x%x]=0x%x\n", __func__,
+		PMIC_BUCK_TOP_OC_CON0, pwrap_read_field(PMIC_BUCK_TOP_OC_CON0, 0xFFFF, 0));
+	dprintf(CRITICAL, "[%s] BUCK_OC_SDN_EN[0x%x]=0x%x\n", __func__,
+		PMIC_BUCK_TOP_ELR0, pwrap_read_field(PMIC_BUCK_TOP_ELR0, 0xFFFF, 0));
+	dprintf(CRITICAL, "[%s] THERMALSTATUS[0x%x]=0x%x\n", __func__,
+		PMIC_THERMALSTATUS, pwrap_read_field(PMIC_THERMALSTATUS, 0xFFFF, 0));
+	dprintf(CRITICAL, "[%s] Long Press Shutdown(%d)\n", __func__,
+		pwrap_read_field(PMIC_STRUP_CON4, 0x1, 14));
+	dprintf(CRITICAL, "[%s] WDT, TOP_RST_MISC[0x%x]=0x%x\n", __func__,
+		PMIC_TOP_RST_MISC, pwrap_read_field(PMIC_TOP_RST_MISC, 0xFFFF, 0));
+	dprintf(CRITICAL, "[%s] TOP_CLK_TRIM[0x%x]=0x%x\n", __func__,
+		PMIC_TOP_CLK_TRIM, pwrap_read_field(PMIC_TOP_CLK_TRIM, 0xFFFF, 0));
+}
+
+static void pmic_clear_status(void)
+{
+	/* write 1 to clear status */
+	/* clear POFFSTS */
+	pwrap_write_field(PMIC_PSTSCTL, 0x1, 0x1, 0);
+	/* clear PONSTS */
+	pwrap_write_field(PMIC_PSTSCTL, 0x1, 0x1, 8);
+	/* clear OC_SDN_STATUS */
+	pwrap_write_field(PMIC_BUCK_TOP_OC_CON0, 0xFF, 0xFF, 0);
+	/* clear Thermal Shutdown */
+	pwrap_write_field(PMIC_STRUP_CON11, 0x1, 0x1, 0);
+	/* clear Long Press Shutdown */
+	pwrap_write_field(PMIC_STRUP_CON4, 0x1, 0x1, 4);
+
+	spin(70);
+
+	/* After writing 1, need to write 0 back */
+	/* set POFFSTS */
+	pwrap_write_field(PMIC_PSTSCTL, 0, 0x1, 0);
+	/* set PONSTS */
+	pwrap_write_field(PMIC_PSTSCTL, 0, 0x1, 8);
+	/* set Thermal Shutdown */
+	pwrap_write_field(PMIC_STRUP_CON11, 0, 0x1, 0);
+	/* set Long Press Shutdown */
+	pwrap_write_field(PMIC_STRUP_CON4, 0, 0x1, 4);
+}
+
+void pmic_set_power_hold(bool enable)
+{
+	pwrap_write_field(PMIC_PWRHOLD, (enable) ? 1 : 0, 0x1, 0);
+}
+
+void pmic_camera_sensor_init(void)
+{
+	/* VCAMIO (1.8V) -> VCAMA (2.8V) -> VCAMD (1.2V) */
+	/* Enable */
+	pwrap_write_field(PMIC_LDO_VCAMIO_CON0, 0x1, 0x1, 0);
+	pwrap_write_field(PMIC_LDO_VCAMA_CON0, 0x1, 0x1, 0);
+	pwrap_write_field(PMIC_LDO_VCAMD_CON0, 0x1, 0x1, 0);
+	dprintf(CRITICAL, "%s done\n", __func__);
+}
+
+int pmic_get_voltage(int power_id)
+{
+	int vol = 0;
+
+	switch (power_id)
+	{
+		case BUCK_PROC:
+			vol = pwrap_read_field(PMIC_BUCK_VPROC_DBG0, 0x7f, 0);
+			vol = 518750 + 6250 * vol;
+			break;
+		case LDO_SRAM_PROC:
+			vol = pwrap_read_field(PMIC_LDO_VSRAM_PROC_DBG0, 0x7f, 8);
+			vol = 518750 + 6250 * vol;
+			break;
+		default:
+			return 0;
+	}
+
+	return vol;
+}
+
+void pmic_set_voltage(int power_id, int target_uV)
+{
+	int vsel = 0, old_vol, delay_us;
+
+	old_vol = pmic_get_voltage(power_id);
+	switch (power_id)
+	{
+		case BUCK_PROC:
+			vsel = (target_uV - 518750) / 6250;
+			pwrap_write_field(PMIC_BUCK_VPROC_ELR0, vsel, 0x7f, 0);
+			delay_us = 30 + (target_uV - old_vol)/(10 * 1000);
+			break;
+		case LDO_SRAM_PROC:
+			vsel = (target_uV - 518750) / 6250;
+			pwrap_write_field(PMIC_LDO_VSRAM_CON0, vsel, 0x7f, 0);
+			delay_us = 30 + (target_uV - old_vol)/(10 * 1000);
+			break;
+		default:
+			return;
+	}
+	spin(delay_us);
+}
+
+int mt6357_init(void)
+{
+	if (pwrap_init()) {
+		dprintf(CRITICAL, "ERROR - Failed to initialize pmic wrap!");
+		return -1;
+	}
+
+	pmic_set_power_hold(true);
+	pmic_dump_status();
+	pmic_clear_status();
+	mt6357_init_setting();
+
+	return 0;
+}
+
+/* external api */
+/*
+ * PMIC Access APIs
+ */
+
+u16 pmic_read_interface (u16 RegNum, u16 *val, u16 MASK, u16 SHIFT)
+{
+	u16 return_value = 0;
+	u16 pmic_reg = 0;
+	u16 rdata;
+
+	return_value = pwrap_read(RegNum, &rdata);
+	pmic_reg = rdata;
+	if (return_value != 0) {
+		dprintf(CRITICAL, "[PMIC]Reg[0x%x] pmic_wrap read data fail\n", RegNum);
+		return return_value;
+	}
+
+	pmic_reg &= (MASK << SHIFT);
+	*val = (pmic_reg >> SHIFT);
+
+	return return_value;
+}
+
+u16 pmic_config_interface (u16 RegNum, u16 val, u16 MASK, u16 SHIFT)
+{
+	u16 return_value = 0;
+	u16 pmic_reg = 0;
+	u16 rdata;
+
+	return_value = pwrap_read(RegNum, &rdata);
+	pmic_reg = rdata;
+	if (return_value != 0) {
+		dprintf(CRITICAL, "[PMIC]Reg[0x%x] pmic_wrap read data fail\n", RegNum);
+		return return_value;
+	}
+
+	pmic_reg &= ~(MASK << SHIFT);
+	pmic_reg |= (val << SHIFT);
+
+	return_value = pwrap_write(RegNum, pmic_reg);
+	if (return_value != 0) {
+		dprintf(CRITICAL, "[PMIC]Reg[0x%x] pmic_wrap write 0x%x fail\n", RegNum, pmic_reg);
+		return return_value;
+	}
+
+	return return_value;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/pmic_wrap/pmic_wrap.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/pmic_wrap/pmic_wrap.c
new file mode 100644
index 0000000..ace92af
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/pmic_wrap/pmic_wrap.c
@@ -0,0 +1,319 @@
+/*
+ * 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.
+ */
+
+//#include <platform/infracfg.h>
+#include <platform/pll.h>
+#include <platform/pmic_wrap.h>
+#include <reg.h>
+
+#define PENDING_US(x) x
+enum {
+	STARVE_ENABLE = 0x1 << 10,
+	COUNTER0_PENDING_THRES = STARVE_ENABLE | PENDING_US(0),
+	COUNTER1_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x2),
+	COUNTER2_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x2),
+	COUNTER3_PENDING_THRES = STARVE_ENABLE | PENDING_US(0xe),
+	COUNTER4_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x2),
+	COUNTER5_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x27),
+	COUNTER6_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x27),
+	COUNTER7_PENDING_THRES = STARVE_ENABLE | PENDING_US(0xa4),
+	COUNTER8_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x13),
+	COUNTER9_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x17),
+	COUNTER10_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x17),
+	COUNTER11_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x7b),
+	COUNTER12_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x7b),
+	COUNTER13_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x45b),
+};
+
+
+static void pwrap_soft_reset(void)
+{
+	writel(0x1, INFRA_GLOBALCON_RST2_SET);
+	writel(0x1, INFRA_GLOBALCON_RST2_CLR);
+}
+
+static void pwrap_spi_clk_set(void)
+{
+	writel(TIMER_CG | AP_CG | MD_CG | CONN_CG, MODULE_SW_CG_0_SET);
+	writel(MODEM_TEMP_SHARE_CG, MODULE_SW_CG_2_SET);
+
+	/* Select ULPOSC/16 Clock as SYS, TMR and SPI Clocks in SODI-3.0 and Suspend Modes */
+	writel(0x00000097, CLK_CFG_7_CLR);
+	writel(0x00000003, CLK_CFG_7_SET);
+	writel((0x1 << 28), CLK_CFG_UPDATE);
+	writel((readl(PMICW_CLOCK_CTRL) & ~(0x1 << 2)), PMICW_CLOCK_CTRL);
+
+	pwrap_soft_reset();
+
+	writel(TIMER_CG | AP_CG | MD_CG | CONN_CG,
+		MODULE_SW_CG_0_CLR);
+	writel(MODEM_TEMP_SHARE_CG, MODULE_SW_CG_2_CLR);
+}
+
+static s32 pwrap_init_dio(u16 dio_en)
+{
+	writel(0x4, &mtk_pwrap->hiprio_arb_en);
+	if (wait_for_state_ready(wait_for_wrap_idle,
+		100, &mtk_pwrap->wrap_sta, 0))
+		return E_PWR_TIMEOUT;
+
+	pwrap_write_nochk(PMIC_DEW_DIO_EN, dio_en);
+
+	if (wait_for_state_ready(wait_for_idle_and_sync,
+		100, &mtk_pwrap->wacs2_rdata, 0))
+		return E_PWR_TIMEOUT;
+
+	writel(dio_en, &mtk_pwrap->dio_en);
+	return 0;
+}
+
+static void pwrap_initstaupd(void)
+{
+	writel(0xff, &mtk_pwrap->staupd_grpen);
+
+	/* CRC */
+	pwrap_write_nochk(PMIC_DEW_CRC_EN, 0x1);
+	writel(0x1, &mtk_pwrap->crc_en);
+	writel(PMIC_DEW_CRC_VAL, &mtk_pwrap->sig_adr);
+
+	writel(PMIC_CPU_INT_STA, &mtk_pwrap->eint_sta0_adr);
+
+	/* MD ADC Interface */
+	writel((PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31,
+		&mtk_pwrap->md_auxadc_rdata_latest_addr);
+	writel((PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31,
+		&mtk_pwrap->md_auxadc_rdata_wp_addr);
+	for (size_t i = 0; i < 32; i++)
+		writel((PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31,
+			&mtk_pwrap->md_auxadc_rdata[i]);
+
+	writel((PMIC_AUXADC_RQST1 << 16) + PMIC_AUXADC_RQST0,
+		&mtk_pwrap->int_gps_auxadc_cmd_addr);
+	writel((0x400 << 16) + GPS_SUBSYS, &mtk_pwrap->int_gps_auxadc_cmd);
+	writel((PMIC_AUXADC_ADC32 << 16) + PMIC_AUXADC_ADC17,
+		&mtk_pwrap->int_gps_auxadc_rdata_addr);
+
+	writel(PMIC_AUXADC_ADC31, &mtk_pwrap->ext_gps_auxadc_rdata_addr);
+}
+
+static void pwrap_starve_set(void)
+{
+	writel(ARB_PRIORITY, &mtk_pwrap->harb_hprio);
+	writel(COUNTER0_PENDING_THRES, &mtk_pwrap->starv_counter_0);
+	writel(COUNTER1_PENDING_THRES, &mtk_pwrap->starv_counter_1);
+	writel(COUNTER2_PENDING_THRES, &mtk_pwrap->starv_counter_2);
+	writel(COUNTER3_PENDING_THRES, &mtk_pwrap->starv_counter_3);
+	writel(COUNTER4_PENDING_THRES, &mtk_pwrap->starv_counter_4);
+	writel(COUNTER5_PENDING_THRES, &mtk_pwrap->starv_counter_5);
+	writel(COUNTER6_PENDING_THRES, &mtk_pwrap->starv_counter_6);
+	writel(COUNTER7_PENDING_THRES, &mtk_pwrap->starv_counter_7);
+	writel(COUNTER8_PENDING_THRES, &mtk_pwrap->starv_counter_8);
+	writel(COUNTER9_PENDING_THRES, &mtk_pwrap->starv_counter_9);
+	writel(COUNTER10_PENDING_THRES, &mtk_pwrap->starv_counter_10);
+	writel(COUNTER11_PENDING_THRES, &mtk_pwrap->starv_counter_11);
+	writel(COUNTER12_PENDING_THRES, &mtk_pwrap->starv_counter_12);
+	writel(COUNTER13_PENDING_THRES, &mtk_pwrap->starv_counter_13);
+}
+
+static void pwrap_enable(void)
+{
+	writel(0x3fd35, &mtk_pwrap->hiprio_arb_en);
+	writel(0x1, &mtk_pwrap->wacs0_en);
+	writel(0x1, &mtk_pwrap->wacs2_en);
+	writel(0x1, &mtk_pwrap->wacs_p2p_en);
+	writel(0x1, &mtk_pwrap->wacs_md32_en);
+	writel(STA_PD_98_5_US, &mtk_pwrap->staupd_ctrl);
+	writel(WATCHDOG_TIMER_7_5_MS, &mtk_pwrap->wdt_unit);
+	writel(WDT_MONITOR_ALL, &mtk_pwrap->wdt_src_en_0);
+	writel(WDT_MONITOR_ALL, &mtk_pwrap->wdt_src_en_1);
+	writel(0x1, &mtk_pwrap->timer_ctrl);
+	writel(0x3, &mtk_pwrap->int0_en);
+	writel(0xffffd800, &mtk_pwrap->int1_en);
+}
+
+static s32 pwrap_init_sistrobe(void)
+{
+	u16 rdata;
+	int si_sample_ctrl;
+	int test_data[30] = {
+		0x6996, 0x9669, 0x6996, 0x9669, 0x6996, 0x9669, 0x6996,
+		0x9669, 0x6996, 0x9669, 0x5AA5, 0xA55A, 0x5AA5, 0xA55A,
+		0x5AA5, 0xA55A, 0x5AA5, 0xA55A, 0x5AA5, 0xA55A, 0x1B27,
+		0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27,
+		0x1B27, 0x1B27};
+
+	for (si_sample_ctrl = 0; si_sample_ctrl < 16; si_sample_ctrl++) {
+		writel(si_sample_ctrl << 5, &mtk_pwrap->si_sample_ctrl);
+
+		pwrap_read_nochk(PMIC_DEW_READ_TEST, &rdata);
+		if (rdata == DEFAULT_VALUE_READ_TEST)
+			break;
+	}
+
+	if (si_sample_ctrl == 16)
+		return E_CLK_EDGE;
+
+	if (si_sample_ctrl == 15)
+		return E_CLK_LAST_SETTING;
+
+	/*
+	 * Add the delay time of SPI data from PMIC to align the start boundary
+	 * to current sampling clock edge.
+	 */
+	for (int si_dly = 0; si_dly < 10; si_dly++) {
+		pwrap_write_nochk(PMIC_RG_SPI_CON2, si_dly);
+
+		int start_boundary_found = 0;
+		for (size_t i = 0; i < 30; i++) {
+			pwrap_write_nochk(PMIC_DEW_WRITE_TEST, test_data[i]);
+			pwrap_read_nochk(PMIC_DEW_WRITE_TEST, &rdata);
+			if ((rdata & 0x7fff) != (test_data[i] & 0x7fff)) {
+				start_boundary_found = 1;
+				break;
+			}
+		}
+		if (start_boundary_found == 1)
+			break;
+	}
+
+	/*
+	 * Change the sampling clock edge to the next one which is the middle
+	 * of SPI data window.
+	 */
+	writel(++si_sample_ctrl << 5, &mtk_pwrap->si_sample_ctrl);
+
+	/* Read Test */
+	pwrap_read_nochk(PMIC_DEW_READ_TEST, &rdata);
+	if (rdata != DEFAULT_VALUE_READ_TEST) {
+		pwrap_err("rdata = %#x, exp = %#x\n", rdata,
+			  DEFAULT_VALUE_READ_TEST);
+		return E_PWR_READ_TEST_FAIL;
+	}
+
+	return 0;
+}
+
+static void pwrap_init_spislv(void)
+{
+	/* Turn on IO filter function MT6357_FILTER_CON0 */
+	pwrap_write_nochk(PMIC_FILTER_CON0, SPI_FILTER);
+	/* Turn on IO SMT function to improve noise immunity MT6357_SMT_CON1 */
+	pwrap_write_nochk(PMIC_SMT_CON1, SPI_SMT);
+	/* Turn off IO pull function for power saving MT6357_GPIO_PULLEN0_CLR */
+	pwrap_write_nochk(PMIC_GPIO_PULLEN0_CLR, SPI_PULL_DISABLE);
+	/* Enable SPI R/W in suspend mode MT6357_RG_SPI_CON0 */
+	pwrap_write_nochk(PMIC_RG_SPI_CON0, 0x1);
+	/* Set PMIC GPIO driving current to 4mA MT6357_DRV_CON1 */
+	pwrap_write_nochk(PMIC_DRV_CON1, SPI_DRIVING);
+}
+
+static void pwrap_init_reg_clock(void)
+{
+	writel(0x1, &mtk_pwrap->ext_ck_write);
+
+	pwrap_write_nochk(PMIC_DEW_RDDMY_NO, DUMMY_READ_CYCLES);
+	writel(DUMMY_READ_CYCLES, &mtk_pwrap->rddmy);
+
+	writel(0, &mtk_pwrap->cshext_write);
+	writel(0, &mtk_pwrap->cshext_read);
+	writel(0, &mtk_pwrap->cslext_write);
+	writel(0x200, &mtk_pwrap->cslext_read);
+}
+
+#define DRIVING (GPIO_BASE+0x720)
+s32 pwrap_init(void)
+{
+	s32 sub_return = 0, sub_return1 = 0;
+	u16 rdata;
+
+	/* Set SoC SPI IO Driving Strength to 4 mA */
+	writel(((readl(DRIVING) & ~(0xF << 16)) | (0x1 << 16)), DRIVING);
+
+	pwrap_spi_clk_set();
+
+	/* Reset spislv */
+	sub_return = pwrap_reset_spislv();
+	if (sub_return != 0) {
+		pwrap_err("reset_spislv fail, ret=%d\n", sub_return);
+		return E_PWR_INIT_RESET_SPI;
+	}
+
+	/* Enable WRAP */
+	writel(0x1, &mtk_pwrap->wrap_en);
+
+	/* Enable WACS2 */
+	writel(0x1, &mtk_pwrap->wacs2_en);
+	writel(WACS2, &mtk_pwrap->hiprio_arb_en); /* ONLY WACS2 */
+
+	/* SPI Waveform Configuration */
+	pwrap_init_reg_clock();
+
+	/* SPI Slave Configuration */
+	pwrap_init_spislv();
+
+	/* Enable DIO mode */
+	sub_return = pwrap_init_dio(1);
+	if (sub_return != 0) {
+		pwrap_err("dio test error, ret=%d\n", sub_return);
+		return E_PWR_INIT_DIO;
+	}
+
+	/* Input data calibration flow; */
+	sub_return = pwrap_init_sistrobe();
+	if (sub_return != 0) {
+		pwrap_err("InitSiStrobe fail,ret=%d\n", sub_return);
+		return E_PWR_INIT_SIDLY;
+	}
+
+	/*
+	 * Write test using WACS2,
+	 * make sure the read/write function ready.
+	 */
+	sub_return = pwrap_write_nochk(PMIC_DEW_WRITE_TEST, WRITE_TEST_VALUE);
+	sub_return1 = pwrap_read_nochk(PMIC_DEW_WRITE_TEST, &rdata);
+	if (rdata != WRITE_TEST_VALUE || sub_return || sub_return1) {
+		pwrap_err("write error, rdata=%#x, return=%d, return1=%d\n",
+			  rdata, sub_return, sub_return1);
+		return E_PWR_INIT_WRITE_TEST;
+	}
+
+	/*
+	 * Status update function initialization
+	 * 1. Signature Checking using CRC (CRC 0 only)
+	 * 2. EINT update
+	 * 3. Read back Auxadc thermal data for GPS
+	 */
+	pwrap_initstaupd();
+
+	pwrap_starve_set();
+
+	pwrap_enable();
+
+	/* Initialization Done */
+	writel(0x1, &mtk_pwrap->init_done0);
+	writel(0x1, &mtk_pwrap->init_done2);
+	writel(0x1, &mtk_pwrap->init_done_p2p);
+	writel(0x1, &mtk_pwrap->init_done_md32);
+
+	return 0;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/rtc/rtc.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/rtc/rtc.c
new file mode 100644
index 0000000..b580a25
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/rtc/rtc.c
@@ -0,0 +1,341 @@
+/*
+ * 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.
+ */
+
+#include <platform/rtc_common.h>
+#include <platform/rtc.h>
+#include <platform/mt6357.h>
+#include <platform/pmic_wrap.h>
+
+#define RTC_GPIO_USER_MASK    ((1 << 13) - (1 << 8))
+
+bool rtc_bootloader_check(void)
+{
+    u16 pdn1;
+
+    rtc_read(RTC_PDN1, &pdn1);
+    if (pdn1 & RTC_PDN1_FAST_BOOT)
+        return true;
+    else
+        return false;
+}
+
+void rtc_bootloader_set_clr(bool value)
+{
+    u16 pdn1;
+
+    if (!rtc_writeif_unlock()) { /* Unlock for reload */
+        rtc_info("rtc_writeif_unlock() fail\n");
+        return;
+    }
+    rtc_read(RTC_PDN1, &pdn1);
+    if (value)
+        pdn1 |= RTC_PDN1_FAST_BOOT;
+    else
+        pdn1 &= ~RTC_PDN1_FAST_BOOT;
+    rtc_write(RTC_PDN1, pdn1);
+    rtc_write_trigger();
+}
+
+/* initialize rtc setting of using dcxo clock */
+static int rtc_enable_dcxo(void)
+{
+    u16 bbpu, con, osc32con, sec;
+
+    rtc_read(RTC_BBPU, &bbpu);
+    rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
+    rtc_write_trigger();
+
+    mdelay(1);
+    if (!rtc_writeif_unlock()) { /* Unlock for reload */
+        rtc_info("rtc_writeif_unlock() failed\n");
+        return 0;
+    }
+
+    rtc_read(RTC_OSC32CON, &osc32con);
+    osc32con &= ~(RTC_EMBCK_SRC_SEL | RTC_EMBCK_SEL_MODE_MASK
+                | RTC_GPS_CKOUT_EN);
+    osc32con |= RTC_XOSC32_ENB | RTC_REG_XOSC32_ENB
+                | RTC_EMB_K_EOSC32_MODE | RTC_EMBCK_SEL_OPTION;
+    if (!rtc_xosc_write(osc32con)) {
+        rtc_info("rtc_xosc_write() failed\n");
+        return 0;
+    }
+
+    rtc_read(RTC_CON, &con);
+    rtc_read(RTC_OSC32CON, &osc32con);
+    rtc_read(RTC_AL_SEC, &sec);
+    rtc_info("con=0x%x, osc32con=0x%x, sec=0x%x\n", con, osc32con, sec);
+
+    return 1;
+}
+
+/* initialize rtc related gpio */
+static int rtc_gpio_init(void)
+{
+    u16 con;
+
+    /* RTC_32K1V8 clock change from 128k div 4 source
+     * to RTC 32k source
+     */
+    pwrap_write_field(PMIC_RG_TOP_CKSEL_CON0_SET, 0x1, 0x1, 3);
+
+    /* Export 32K clock RTC_32K1V8_1 */
+    pwrap_write_field(PMIC_RG_TOP_CKPDN_CON1_CLR, 0x1, 0x1, 1);
+
+    /* Export 32K clock RTC_32K2V8 */
+    rtc_read(RTC_CON, &con);
+    con &= (RTC_CON_LPSTA_RAW | RTC_CON_LPRST | RTC_CON_EOSC32_LPEN
+            | RTC_CON_XOSC32_LPEN);
+    con |= (RTC_CON_GPEN | RTC_CON_GOE);
+    con &= ~(RTC_CON_F32KOB);
+    rtc_write(RTC_CON, con);
+
+    return rtc_write_trigger();
+}
+
+/* set xosc mode */
+void rtc_osc_init(void)
+{
+    /* enable 32K export */
+    rtc_gpio_init();
+}
+
+/* enable lpd subroutine */
+static int rtc_lpen(u16 con)
+{
+    con &= ~RTC_CON_LPRST;
+    rtc_write(RTC_CON, con);
+    if (!rtc_write_trigger())
+        return 0;
+
+    con |= RTC_CON_LPRST;
+    rtc_write(RTC_CON, con);
+    if (!rtc_write_trigger())
+        return 0;
+
+    con &= ~RTC_CON_LPRST;
+    rtc_write(RTC_CON, con);
+    if (!rtc_write_trigger())
+        return 0;
+
+    return 1;
+}
+
+/* low power detect setting */
+static int rtc_lpd_init(void)
+{
+    u16 con, sec;
+
+    /* set RTC_LPD_OPT */
+    rtc_read(RTC_AL_SEC, &sec);
+    sec |= RTC_LPD_OPT_F32K_CK_ALIVE;
+    rtc_write(RTC_AL_SEC, sec);
+    if (!rtc_write_trigger())
+        return 0;
+
+    /* init XOSC32 to detect 32k clock stop */
+    rtc_read(RTC_CON, &con);
+    con |= RTC_CON_XOSC32_LPEN;
+    if (!rtc_lpen(con))
+        return 0;
+
+    /* init EOSC32 to detect rtc low power */
+    rtc_read(RTC_CON, &con);
+    con |= RTC_CON_EOSC32_LPEN;
+    if (!rtc_lpen(con))
+        return 0;
+
+    rtc_read(RTC_CON, &con);
+    con &= ~RTC_CON_XOSC32_LPEN;
+    rtc_write(RTC_CON, con);
+
+    /* set RTC_LPD_OPT */
+    rtc_read(RTC_AL_SEC, &sec);
+    sec &= ~RTC_LPD_OPT_MASK;
+    sec |= RTC_LPD_OPT_EOSC_LPD;
+    rtc_write(RTC_AL_SEC, sec);
+    if (!rtc_write_trigger())
+        return 0;
+
+    return 1;
+}
+
+static bool rtc_hw_init(void)
+{
+    u16 bbpu;
+
+    rtc_read(RTC_BBPU, &bbpu);
+    rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_INIT);
+    rtc_write_trigger();
+
+    udelay(500);
+
+    rtc_read(RTC_BBPU, &bbpu);
+    rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
+    rtc_write_trigger();
+
+    rtc_read(RTC_BBPU, &bbpu);
+    if (bbpu & RTC_BBPU_INIT) {
+        rtc_info("timeout\n");
+        return false;
+    }
+
+    return true;
+}
+
+/* write powerkeys to enable rtc functions */
+static int rtc_powerkey_init(void)
+{
+    rtc_write(RTC_POWERKEY1, RTC_POWERKEY1_KEY);
+    rtc_write(RTC_POWERKEY2, RTC_POWERKEY2_KEY);
+    return rtc_write_trigger();
+}
+
+/* rtc init check */
+int rtc_init(u8 recover)
+{
+    int ret;
+
+    rtc_info("recovery: %d\n", recover);
+
+    /* write powerkeys to enable rtc functions */
+    if (!rtc_powerkey_init()) {
+        ret = -RTC_STATUS_POWERKEY_INIT_FAIL;
+        goto err;
+    }
+
+    /* write interface unlock need to be set after powerkey match */
+    if (!rtc_writeif_unlock()) {
+        ret = -RTC_STATUS_WRITEIF_UNLOCK_FAIL;
+        goto err;
+    }
+
+    if (recover)
+        mdelay(20);
+
+    if (!rtc_gpio_init()) {
+        ret = -RTC_STATUS_GPIO_INIT_FAIL;
+        goto err;
+    }
+
+    if (!rtc_hw_init()) {
+        ret = -RTC_STATUS_HW_INIT_FAIL;
+        goto err;
+    }
+
+    if (!rtc_reg_init()) {
+        ret = -RTC_STATUS_REG_INIT_FAIL;
+        goto err;
+    }
+
+    if (!rtc_lpd_init()) {
+        ret = -RTC_STATUS_LPD_INIT_FAIL;
+        goto err;
+    }
+
+    /* After lpd init, powerkeys need to be written again to enable
+     * low power detect function.
+     */
+    if (!rtc_powerkey_init()) {
+        ret = -RTC_STATUS_POWERKEY_INIT_FAIL;
+        goto err;
+    }
+
+    return RTC_STATUS_OK;
+err:
+    rtc_info("init fail: ret=%d\n", ret);
+    return ret;
+}
+
+/* enable rtc bbpu */
+void rtc_bbpu_power_on(void)
+{
+    u16 bbpu;
+    int ret;
+
+    /* pull powerhold high, control by pmic */
+    pmic_set_power_hold(true);
+
+    /* pull PWRBB high */
+    bbpu = RTC_BBPU_KEY | RTC_BBPU_AUTO | RTC_BBPU_RELOAD | RTC_BBPU_PWREN;
+    rtc_write(RTC_BBPU, bbpu);
+    ret = rtc_write_trigger();
+    rtc_info("rtc_write_trigger=%d\n", ret);
+
+    rtc_read(RTC_BBPU, &bbpu);
+    rtc_info("done BBPU=%#x\n", bbpu);
+}
+
+void poweroff(void)
+{
+    u16 bbpu;
+
+    if (!rtc_writeif_unlock())
+        rtc_info("rtc_writeif_unlock() failed\n");
+    /* pull PWRBB low */
+    bbpu = RTC_BBPU_KEY | RTC_BBPU_RELOAD | RTC_BBPU_PWREN;
+    rtc_write(RTC_BBPU, bbpu);
+
+    pmic_set_power_hold(false);
+    mdelay(1);
+}
+
+static void dcxo_init(void)
+{
+    /* Buffer setting */
+    rtc_write(PMIC_RG_DCXO_CW15, 0xA2AA);
+    rtc_write(PMIC_RG_DCXO_CW13, 0x98E9);
+    rtc_write(PMIC_RG_DCXO_CW16, 0x9855);
+
+    /* 26M enable control */
+    /* Enable clock buffer XO_SOC, XO_CEL */
+    rtc_write(PMIC_RG_DCXO_CW00, 0x4E1D);
+    rtc_write(PMIC_RG_DCXO_CW11, 0x8000);
+
+    /* Adjust OSC FPM setting */
+    rtc_write(PMIC_RG_DCXO_CW07, 0x8FFE);
+
+    /* Re-Calibrate OSC current */
+    rtc_write(PMIC_RG_DCXO_CW09, 0x010F);
+    udelay(100);
+    rtc_write(PMIC_RG_DCXO_CW09, 0x410F);
+    mdelay(5);
+}
+
+/* the rtc boot flow entry */
+void rtc_boot(void)
+{
+    /* dcxo clock init settings */
+    dcxo_init();
+
+    /* dcxo 32k init settings */
+    pwrap_write_field(PMIC_RG_DCXO_CW02, 0xF, 0xF, 0);
+    pwrap_write_field(PMIC_RG_SCK_TOP_CON0, 0x1, 0x1, 0);
+
+    /* using dcxo 32K clock */
+    if (!rtc_enable_dcxo())
+        rtc_info("rtc_enable_dcxo() failed\n");
+
+    rtc_boot_common();
+    rtc_bbpu_power_on();
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/rules.mk b/src/bsp/lk/platform/mediatek/mt8133/drivers/rules.mk
new file mode 100644
index 0000000..c77a3f7
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/rules.mk
@@ -0,0 +1,38 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+    $(COMMON_PLAT)/drivers/pmic_wrap/pmic_wrap_common.c \
+    $(COMMON_PLAT)/drivers/rtc/rtc_common.c \
+    $(COMMON_PLAT)/drivers/uart/uart.c \
+    $(COMMON_PLAT)/drivers/usb/mtu3.c \
+    $(COMMON_PLAT)/drivers/usb/mtu3_qmu.c \
+    $(LOCAL_DIR)/auxadc/mtk_auxadc.c \
+    $(LOCAL_DIR)/i2c/mtk_i2c.c \
+    $(LOCAL_DIR)/key/mtk_key.c \
+    $(LOCAL_DIR)/pll/pll.c \
+    $(LOCAL_DIR)/spm/spm_mtcmos.c \
+    $(LOCAL_DIR)/pmic/mt6357.c \
+    $(LOCAL_DIR)/pmic_wrap/pmic_wrap.c \
+    $(LOCAL_DIR)/rtc/rtc.c \
+    $(LOCAL_DIR)/wdt/mtk_wdt.c \
+
+ifeq ($(strip $(USB_PHY)),fpga)
+MODULE_SRCS += \
+    $(COMMON_PLAT)/drivers/usb/u3phy-i2c.c \
+    $(COMMON_PLAT)/drivers/usb/md1122.c
+endif
+
+ifeq ($(strip $(USB_PHY)),realchip)
+MODULE_SRCS += \
+    $(LOCAL_DIR)/../../common/drivers/usb/usbphy.c
+endif
+
+MODULE_DEPS += \
+    lib/bio \
+    lib/cksum \
+    lib/fdt \
+    lib/mempool \
+    lib/partition \
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/spm/spm_mtcmos.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/spm/spm_mtcmos.c
new file mode 100644
index 0000000..30e3d52
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/spm/spm_mtcmos.c
@@ -0,0 +1,846 @@
+/*
+ * 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.
+ */
+
+#include <platform/pll.h>
+#include <platform/spm.h>
+
+/* for CPU MTCMOS */
+#define spm_mtcmos_cpu_lock(x)
+#define spm_mtcmos_cpu_unlock(x)
+#define spm_mtcmos_noncpu_lock(x)   (*(&x) = 0)
+#define spm_mtcmos_noncpu_unlock(x) (*(&x) = 0)
+
+#define udelay(x)       spin(x)
+#define mdelay(x)       udelay((x) * 1000)
+
+int spm_mtcmos_ctrl_dis(int state)
+{
+    int err = 0;
+
+    /* TINFO="enable SPM register control" */
+    spm_write(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | (0x1 << 0));
+
+    if (state == STA_POWER_DOWN) {
+        /* TINFO="Start to turn off DIS" */
+        /* TINFO="Set bus protect - step1 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_1_SET, DIS_PROT_STEP1_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        while ((spm_read(INFRA_TOPAXI_PROTECTEN_STA1_1) & DIS_PROT_STEP1_0_ACK_MASK) != DIS_PROT_STEP1_0_ACK_MASK) {
+        }
+#endif
+        /* TINFO="Set bus protect - step2 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_SET, DIS_PROT_STEP2_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        while ((spm_read(INFRA_TOPAXI_PROTECTEN_STA1) & DIS_PROT_STEP2_0_ACK_MASK) != DIS_PROT_STEP2_0_ACK_MASK) {
+        }
+#endif
+        /* TINFO="Set SRAM_PDN = 1" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) | DIS_SRAM_PDN);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until DIS_SRAM_PDN_ACK = 1" */
+        while ((spm_read(DIS_PWR_CON) & DIS_SRAM_PDN_ACK) != DIS_SRAM_PDN_ACK) {
+            /* Need hf_fmm_ck for SRAM PDN delay IP. */
+        }
+#endif
+        /* TINFO="Set PWR_ISO = 1" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) | PWR_ISO);
+        /* TINFO="Set PWR_CLK_DIS = 1" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) | PWR_CLK_DIS);
+        /* TINFO="Set PWR_RST_B = 0" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) & ~PWR_RST_B);
+        /* TINFO="Set PWR_ON = 0" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) & ~PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 0" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) & ~PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 0 and PWR_STATUS_2ND = 0" */
+        while ((spm_read(PWR_STATUS) & DIS_PWR_STA_MASK)
+                || (spm_read(PWR_STATUS_2ND) & DIS_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Finish to turn off DIS" */
+    } else {    /* STA_POWER_ON */
+        /* TINFO="Start to turn on DIS" */
+        /* TINFO="Set PWR_ON = 1" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) | PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 1" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) | PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 1 and PWR_STATUS_2ND = 1" */
+        while (((spm_read(PWR_STATUS) & DIS_PWR_STA_MASK) != DIS_PWR_STA_MASK)
+                || ((spm_read(PWR_STATUS_2ND) & DIS_PWR_STA_MASK) != DIS_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Set PWR_CLK_DIS = 0" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) & ~PWR_CLK_DIS);
+        /* TINFO="Set PWR_ISO = 0" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) & ~PWR_ISO);
+        /* TINFO="Set PWR_RST_B = 1" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) | PWR_RST_B);
+        /* TINFO="Set SRAM_PDN = 0" */
+        spm_write(DIS_PWR_CON, spm_read(DIS_PWR_CON) & ~(0x1 << 8));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until DIS_SRAM_PDN_ACK_BIT0 = 0" */
+        while (spm_read(DIS_PWR_CON) & DIS_SRAM_PDN_ACK_BIT0) {
+            /* Need hf_fmm_ck for SRAM PDN delay IP. */
+        }
+#endif
+        /* TINFO="Release bus protect - step2 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_CLR, DIS_PROT_STEP2_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* Note that this protect ack check after releasing protect has been ignored */
+#endif
+        /* TINFO="Release bus protect - step1 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_1_CLR, DIS_PROT_STEP1_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* Note that this protect ack check after releasing protect has been ignored */
+#endif
+        /* TINFO="Finish to turn on DIS" */
+    }
+    return err;
+}
+
+int spm_mtcmos_ctrl_conn(int state)
+{
+    int err = 0;
+
+    /* TINFO="enable SPM register control" */
+    spm_write(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | (0x1 << 0));
+
+    if (state == STA_POWER_DOWN) {
+        /* TINFO="Start to turn off CONN" */
+        /* TINFO="Set bus protect - step1 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_SET, CONN_PROT_STEP1_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        while ((spm_read(INFRA_TOPAXI_PROTECTEN_STA1) & CONN_PROT_STEP1_0_ACK_MASK) != CONN_PROT_STEP1_0_ACK_MASK) {
+        }
+#endif
+        /* TINFO="Set bus protect - step1 : 1" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_1_SET, CONN_PROT_STEP1_1_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        while ((spm_read(INFRA_TOPAXI_PROTECTEN_STA1_1) & CONN_PROT_STEP1_1_ACK_MASK) != CONN_PROT_STEP1_1_ACK_MASK) {
+        }
+#endif
+        /* TINFO="Set bus protect - step2 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_SET, CONN_PROT_STEP2_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        while ((spm_read(INFRA_TOPAXI_PROTECTEN_STA1) & CONN_PROT_STEP2_0_ACK_MASK) != CONN_PROT_STEP2_0_ACK_MASK) {
+        }
+#endif
+#ifndef IGNORE_MTCMOS_CHECK
+#endif
+        /* TINFO="Set PWR_ISO = 1" */
+        spm_write(CONN_PWR_CON, spm_read(CONN_PWR_CON) | PWR_ISO);
+        /* TINFO="Set PWR_CLK_DIS = 1" */
+        spm_write(CONN_PWR_CON, spm_read(CONN_PWR_CON) | PWR_CLK_DIS);
+        /* TINFO="Set PWR_RST_B = 0" */
+        spm_write(CONN_PWR_CON, spm_read(CONN_PWR_CON) & ~PWR_RST_B);
+        /* TINFO="Set PWR_ON = 0" */
+        spm_write(CONN_PWR_CON, spm_read(CONN_PWR_CON) & ~PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 0" */
+        spm_write(CONN_PWR_CON, spm_read(CONN_PWR_CON) & ~PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 0 and PWR_STATUS_2ND = 0" */
+        while ((spm_read(PWR_STATUS) & CONN_PWR_STA_MASK)
+                || (spm_read(PWR_STATUS_2ND) & CONN_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Finish to turn off CONN" */
+    } else {    /* STA_POWER_ON */
+        /* TINFO="Start to turn on CONN" */
+        /* TINFO="Set PWR_ON = 1" */
+        spm_write(CONN_PWR_CON, spm_read(CONN_PWR_CON) | PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 1" */
+        spm_write(CONN_PWR_CON, spm_read(CONN_PWR_CON) | PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 1 and PWR_STATUS_2ND = 1" */
+        while (((spm_read(PWR_STATUS) & CONN_PWR_STA_MASK) != CONN_PWR_STA_MASK)
+                || ((spm_read(PWR_STATUS_2ND) & CONN_PWR_STA_MASK) != CONN_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Set PWR_CLK_DIS = 0" */
+        spm_write(CONN_PWR_CON, spm_read(CONN_PWR_CON) & ~PWR_CLK_DIS);
+        /* TINFO="Set PWR_ISO = 0" */
+        spm_write(CONN_PWR_CON, spm_read(CONN_PWR_CON) & ~PWR_ISO);
+        /* TINFO="Set PWR_RST_B = 1" */
+        spm_write(CONN_PWR_CON, spm_read(CONN_PWR_CON) | PWR_RST_B);
+#ifndef IGNORE_MTCMOS_CHECK
+#endif
+        /* TINFO="Release bus protect - step2 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_CLR, CONN_PROT_STEP2_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* Note that this protect ack check after releasing protect has been ignored */
+#endif
+        /* TINFO="Release bus protect - step1 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_CLR, CONN_PROT_STEP1_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* Note that this protect ack check after releasing protect has been ignored */
+#endif
+        /* TINFO="Release bus protect - step1 : 1" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_1_CLR, CONN_PROT_STEP1_1_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* Note that this protect ack check after releasing protect has been ignored */
+#endif
+        /* TINFO="Finish to turn on CONN" */
+    }
+    return err;
+}
+
+int spm_mtcmos_ctrl_mfg(int state)
+{
+    int err = 0;
+
+    /* TINFO="enable SPM register control" */
+    spm_write(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | (0x1 << 0));
+
+    if (state == STA_POWER_DOWN) {
+        /* TINFO="Start to turn off MFG" */
+        /* TINFO="Set bus protect - step1 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_SET, MFG_PROT_STEP1_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        while ((spm_read(INFRA_TOPAXI_PROTECTEN_STA1) & MFG_PROT_STEP1_0_ACK_MASK) != MFG_PROT_STEP1_0_ACK_MASK) {
+        }
+#endif
+        /* TINFO="Set bus protect - step2 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_SET, MFG_PROT_STEP2_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        while ((spm_read(INFRA_TOPAXI_PROTECTEN_STA1) & MFG_PROT_STEP2_0_ACK_MASK) != MFG_PROT_STEP2_0_ACK_MASK) {
+        }
+#endif
+        /* TINFO="Set SRAM_PDN = 1" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) | MFG_SRAM_PDN);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until MFG_SRAM_PDN_ACK = 1" */
+        while ((spm_read(MFG_PWR_CON) & MFG_SRAM_PDN_ACK) != MFG_SRAM_PDN_ACK) {
+            /* Need f_fmfg_core_ck for SRAM PDN delay IP. */
+        }
+#endif
+        /* TINFO="Set PWR_ISO = 1" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) | PWR_ISO);
+        /* TINFO="Set PWR_CLK_DIS = 1" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) | PWR_CLK_DIS);
+        /* TINFO="Set PWR_RST_B = 0" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) & ~PWR_RST_B);
+        /* TINFO="Set PWR_ON = 0" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) & ~PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 0" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) & ~PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 0 and PWR_STATUS_2ND = 0" */
+        while ((spm_read(PWR_STATUS) & MFG_PWR_STA_MASK)
+                || (spm_read(PWR_STATUS_2ND) & MFG_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Finish to turn off MFG" */
+    } else {    /* STA_POWER_ON */
+        /* TINFO="Start to turn on MFG" */
+        /* TINFO="Set PWR_ON = 1" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) | PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 1" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) | PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 1 and PWR_STATUS_2ND = 1" */
+        while (((spm_read(PWR_STATUS) & MFG_PWR_STA_MASK) != MFG_PWR_STA_MASK)
+                || ((spm_read(PWR_STATUS_2ND) & MFG_PWR_STA_MASK) != MFG_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Set PWR_CLK_DIS = 0" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) & ~PWR_CLK_DIS);
+        /* TINFO="Set PWR_ISO = 0" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) & ~PWR_ISO);
+        /* TINFO="Set PWR_RST_B = 1" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) | PWR_RST_B);
+        /* TINFO="Set SRAM_PDN = 0" */
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) & ~(0x1 << 8));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until MFG_SRAM_PDN_ACK_BIT0 = 0" */
+        while (spm_read(MFG_PWR_CON) & MFG_SRAM_PDN_ACK_BIT0) {
+            /* Need f_fmfg_core_ck for SRAM PDN delay IP. */
+        }
+#endif
+        spm_write(MFG_PWR_CON, spm_read(MFG_PWR_CON) & ~(0x1 << 9));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until MFG_SRAM_PDN_ACK_BIT1 = 0" */
+        while (spm_read(MFG_PWR_CON) & MFG_SRAM_PDN_ACK_BIT1) {
+            /* Need f_fmfg_core_ck for SRAM PDN delay IP. */
+        }
+#endif
+        /* TINFO="Release bus protect - step2 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_CLR, MFG_PROT_STEP2_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* Note that this protect ack check after releasing protect has been ignored */
+#endif
+        /* TINFO="Release bus protect - step1 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_CLR, MFG_PROT_STEP1_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* Note that this protect ack check after releasing protect has been ignored */
+#endif
+        /* TINFO="Finish to turn on MFG" */
+    }
+    return err;
+}
+
+int spm_mtcmos_ctrl_apu_shut_down(int state)
+{
+    int err = 0;
+
+    /* TINFO="enable SPM register control" */
+    spm_write(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | (0x1 << 0));
+
+    if (state == STA_POWER_DOWN) {
+        /* TINFO="Start to turn off APU" */
+        /* TINFO="Set bus protect - step1 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_1_SET, APU_PROT_STEP1_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        while ((spm_read(INFRA_TOPAXI_PROTECTEN_STA1_1) & APU_PROT_STEP1_0_ACK_MASK) != APU_PROT_STEP1_0_ACK_MASK) {
+        }
+#endif
+        /* TINFO="Set bus protect - step2 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_1_SET, APU_PROT_STEP2_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        while ((spm_read(INFRA_TOPAXI_PROTECTEN_STA1_1) & APU_PROT_STEP2_0_ACK_MASK) != APU_PROT_STEP2_0_ACK_MASK) {
+        }
+#endif
+        spm_write(SMI_COMMON_CLAMP_EN_SET,(0x1 << 4));
+        /* TINFO="Set APU_PDN_BIT6 = 1" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) | APU_PDN_BIT6);
+        /* TINFO="Set APU_PDN_BIT5 = 1" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) | APU_PDN_BIT5);
+        /* TINFO="Set APU_PDN_BIT4 = 1" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) | APU_PDN_BIT4);
+        /* TINFO="Set APU_PDN_BIT3 = 1" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) | APU_PDN_BIT3);
+        /* TINFO="Set APU_PDN_BIT2 = 1" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) | APU_PDN_BIT2);
+        /* TINFO="Set SRAM_PDN = 1" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) | APU_SRAM_PDN);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until APU_SRAM_PDN_ACK = 1" */
+        while ((spm_read(APU_PWR_CON) & APU_SRAM_PDN_ACK) != APU_SRAM_PDN_ACK) {
+            /*  */
+        }
+#endif
+        /* TINFO="Set PWR_ISO = 1" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) | PWR_ISO);
+        /* TINFO="Set PWR_CLK_DIS = 1" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) | PWR_CLK_DIS);
+        /* TINFO="Set PWR_RST_B = 0" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~PWR_RST_B);
+        /* TINFO="Set PWR_ON = 0" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 0" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 0 and PWR_STATUS_2ND = 0" */
+        while ((spm_read(PWR_STATUS) & APU_PWR_STA_MASK)
+                || (spm_read(PWR_STATUS_2ND) & APU_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Finish to turn off APU" */
+    } else {    /* STA_POWER_ON */
+        /* TINFO="Start to turn on APU" */
+        /* TINFO="Set PWR_ON = 1" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) | PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 1" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) | PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 1 and PWR_STATUS_2ND = 1" */
+        while (((spm_read(PWR_STATUS) & APU_PWR_STA_MASK) != APU_PWR_STA_MASK)
+                || ((spm_read(PWR_STATUS_2ND) & APU_PWR_STA_MASK) != APU_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Set PWR_CLK_DIS = 0" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~PWR_CLK_DIS);
+        /* TINFO="Set PWR_ISO = 0" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~PWR_ISO);
+        /* TINFO="Set PWR_RST_B = 1" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) | PWR_RST_B);
+        /* TINFO="Set APU_PDN_BIT6 = 0" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~APU_PDN_BIT6);
+        /* TINFO="Set APU_PDN_BIT5 = 0" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~APU_PDN_BIT5);
+        /* TINFO="Set APU_PDN_BIT4 = 0" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~APU_PDN_BIT4);
+        /* TINFO="Set APU_PDN_BIT3 = 0" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~APU_PDN_BIT3);
+        /* TINFO="Set APU_PDN_BIT2 = 0" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~APU_PDN_BIT2);
+        /* TINFO="Set SRAM_PDN = 0" */
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~(0x1 << 8));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until APU_SRAM_PDN_ACK_BIT0 = 0" */
+        while (spm_read(APU_PWR_CON) & APU_SRAM_PDN_ACK_BIT0) {
+            /*  */
+        }
+#endif
+        spm_write(APU_PWR_CON, spm_read(APU_PWR_CON) & ~(0x1 << 9));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until APU_SRAM_PDN_ACK_BIT1 = 0" */
+        while (spm_read(APU_PWR_CON) & APU_SRAM_PDN_ACK_BIT1) {
+            /*  */
+        }
+#endif
+        spm_write(SMI_COMMON_CLAMP_EN_CLR,(0x1 << 4));
+        /* TINFO="Release bus protect - step2 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_1_CLR, APU_PROT_STEP2_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* Note that this protect ack check after releasing protect has been ignored */
+#endif
+        /* TINFO="Release bus protect - step1 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_1_CLR, APU_PROT_STEP1_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* Note that this protect ack check after releasing protect has been ignored */
+#endif
+        /* TINFO="Finish to turn on APU" */
+    }
+    return err;
+}
+
+int spm_mtcmos_ctrl_dsp_shut_down(int state)
+{
+    int err = 0;
+
+    /* TINFO="enable SPM register control" */
+    spm_write(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | (0x1 << 0));
+
+    if (state == STA_POWER_DOWN) {
+        /* TINFO="Start to turn off DSP" */
+        /* TINFO="AUDIO_BUS_AUD_SI0[0]=0"*/
+        spm_write(AUDIO_BUS_AUD_SI0, spm_read(AUDIO_BUS_AUD_SI0) & ~(0x1 << 0));
+        /* TINFO="AUDIO_BUS_INFRA_SI0[0]=0"*/
+        spm_write(AUDIO_BUS_INFRA_SI0, spm_read(AUDIO_BUS_INFRA_SI0) & ~(0x1 << 0));
+        /* TINFO="Set SRAM_PDN = 1" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) | DSP_SRAM_PDN);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until DSP_SRAM_PDN_ACK = 1" */
+        while ((spm_read(DSP_PWR_CON) & DSP_SRAM_PDN_ACK) != DSP_SRAM_PDN_ACK) {
+            /*  */
+        }
+#endif
+        /* TINFO="Set PWR_ISO = 1" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) | PWR_ISO);
+        /* TINFO="Set PWR_CLK_DIS = 1" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) | PWR_CLK_DIS);
+        /* TINFO="Set PWR_RST_B = 0" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) & ~PWR_RST_B);
+        /* TINFO="Set PWR_ON = 0" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) & ~PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 0" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) & ~PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 0 and PWR_STATUS_2ND = 0" */
+        while ((spm_read(PWR_STATUS) & DSP_PWR_STA_MASK)
+                || (spm_read(PWR_STATUS_2ND) & DSP_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Finish to turn off DSP" */
+    } else {    /* STA_POWER_ON */
+        /* TINFO="Start to turn on DSP" */
+        /* TINFO="Set PWR_ON = 1" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) | PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 1" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) | PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 1 and PWR_STATUS_2ND = 1" */
+        while (((spm_read(PWR_STATUS) & DSP_PWR_STA_MASK) != DSP_PWR_STA_MASK)
+                || ((spm_read(PWR_STATUS_2ND) & DSP_PWR_STA_MASK) != DSP_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Set PWR_CLK_DIS = 0" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) & ~PWR_CLK_DIS);
+        /* TINFO="Set PWR_ISO = 0" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) & ~PWR_ISO);
+        /* TINFO="Set PWR_RST_B = 1" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) | PWR_RST_B);
+        /* TINFO="Set SRAM_PDN = 0" */
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) & ~(0x1 << 8));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until DSP_SRAM_PDN_ACK_BIT0 = 0" */
+        while (spm_read(DSP_PWR_CON) & DSP_SRAM_PDN_ACK_BIT0) {
+            /*  */
+        }
+#endif
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) & ~(0x1 << 9));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until DSP_SRAM_PDN_ACK_BIT1 = 0" */
+        while (spm_read(DSP_PWR_CON) & DSP_SRAM_PDN_ACK_BIT1) {
+            /*  */
+        }
+#endif
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) & ~(0x1 << 10));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until DSP_SRAM_PDN_ACK_BIT2 = 0" */
+        while (spm_read(DSP_PWR_CON) & DSP_SRAM_PDN_ACK_BIT2) {
+            /*  */
+        }
+#endif
+        spm_write(DSP_PWR_CON, spm_read(DSP_PWR_CON) & ~(0x1 << 11));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until DSP_SRAM_PDN_ACK_BIT3 = 0" */
+        while (spm_read(DSP_PWR_CON) & DSP_SRAM_PDN_ACK_BIT3) {
+            /*  */
+        }
+#endif
+        /* TINFO="AUDIO_BUS_AUD_SI0[0]=1"*/
+        spm_write(AUDIO_BUS_AUD_SI0, spm_read(AUDIO_BUS_AUD_SI0) | (0x1 << 0));
+        /* TINFO="AUDIO_BUS_INFRA_SI0[0]=1"*/
+        spm_write(AUDIO_BUS_INFRA_SI0, spm_read(AUDIO_BUS_INFRA_SI0) | (0x1 << 0));
+        /* TINFO="Finish to turn on DSP" */
+    }
+    return err;
+}
+
+int spm_mtcmos_ctrl_ven(int state)
+{
+    int err = 0;
+
+    /* TINFO="enable SPM register control" */
+    spm_write(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | (0x1 << 0));
+
+    if (state == STA_POWER_DOWN) {
+        /* TINFO="Start to turn off VEN" */
+        /* TINFO="Set SRAM_PDN = 1" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) | VEN_SRAM_PDN);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until VEN_SRAM_PDN_ACK = 1" */
+        while ((spm_read(VEN_PWR_CON) & VEN_SRAM_PDN_ACK) != VEN_SRAM_PDN_ACK) {
+            /*  */
+        }
+#endif
+        /* TINFO="Set PWR_ISO = 1" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) | PWR_ISO);
+        /* TINFO="Set PWR_CLK_DIS = 1" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) | PWR_CLK_DIS);
+        /* TINFO="Set PWR_RST_B = 0" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) & ~PWR_RST_B);
+        /* TINFO="Set PWR_ON = 0" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) & ~PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 0" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) & ~PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 0 and PWR_STATUS_2ND = 0" */
+        while ((spm_read(PWR_STATUS) & VEN_PWR_STA_MASK)
+                || (spm_read(PWR_STATUS_2ND) & VEN_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Finish to turn off VEN" */
+    } else {    /* STA_POWER_ON */
+        /* TINFO="Start to turn on VEN" */
+        /* TINFO="Set PWR_ON = 1" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) | PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 1" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) | PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 1 and PWR_STATUS_2ND = 1" */
+        while (((spm_read(PWR_STATUS) & VEN_PWR_STA_MASK) != VEN_PWR_STA_MASK)
+                || ((spm_read(PWR_STATUS_2ND) & VEN_PWR_STA_MASK) != VEN_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Set PWR_CLK_DIS = 0" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) & ~PWR_CLK_DIS);
+        /* TINFO="Set PWR_ISO = 0" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) & ~PWR_ISO);
+        /* TINFO="Set PWR_RST_B = 1" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) | PWR_RST_B);
+        /* TINFO="Set SRAM_PDN = 0" */
+        spm_write(VEN_PWR_CON, spm_read(VEN_PWR_CON) & ~(0x1 << 8));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until VEN_SRAM_PDN_ACK_BIT0 = 0" */
+        while (spm_read(VEN_PWR_CON) & VEN_SRAM_PDN_ACK_BIT0) {
+            /*  */
+        }
+#endif
+        /* TINFO="Finish to turn on VEN" */
+    }
+    return err;
+}
+
+int spm_mtcmos_ctrl_audio(int state)
+{
+    int err = 0;
+
+    /* TINFO="enable SPM register control" */
+    spm_write(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | (0x1 << 0));
+
+    if (state == STA_POWER_DOWN) {
+        /* TINFO="Start to turn off AUDIO" */
+        /* TINFO="Set SRAM_PDN = 1" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) | AUDIO_SRAM_PDN);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until AUDIO_SRAM_PDN_ACK = 1" */
+        while ((spm_read(AUDIO_PWR_CON) & AUDIO_SRAM_PDN_ACK) != AUDIO_SRAM_PDN_ACK) {
+            /*  */
+        }
+#endif
+        /* TINFO="Set PWR_ISO = 1" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) | PWR_ISO);
+        /* TINFO="Set PWR_CLK_DIS = 1" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) | PWR_CLK_DIS);
+        /* TINFO="Set PWR_RST_B = 0" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) & ~PWR_RST_B);
+        /* TINFO="Set PWR_ON = 0" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) & ~PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 0" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) & ~PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 0 and PWR_STATUS_2ND = 0" */
+        while ((spm_read(PWR_STATUS) & AUDIO_PWR_STA_MASK)
+                || (spm_read(PWR_STATUS_2ND) & AUDIO_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Finish to turn off AUDIO" */
+    } else {    /* STA_POWER_ON */
+        /* TINFO="Start to turn on AUDIO" */
+        /* TINFO="Set PWR_ON = 1" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) | PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 1" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) | PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 1 and PWR_STATUS_2ND = 1" */
+        while (((spm_read(PWR_STATUS) & AUDIO_PWR_STA_MASK) != AUDIO_PWR_STA_MASK)
+                || ((spm_read(PWR_STATUS_2ND) & AUDIO_PWR_STA_MASK) != AUDIO_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Set PWR_CLK_DIS = 0" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) & ~PWR_CLK_DIS);
+        /* TINFO="Set PWR_ISO = 0" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) & ~PWR_ISO);
+        /* TINFO="Set PWR_RST_B = 1" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) | PWR_RST_B);
+        /* TINFO="Set SRAM_PDN = 0" */
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) & ~(0x1 << 8));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until AUDIO_SRAM_PDN_ACK_BIT0 = 0" */
+        while (spm_read(AUDIO_PWR_CON) & AUDIO_SRAM_PDN_ACK_BIT0) {
+            /*  */
+        }
+#endif
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) & ~(0x1 << 9));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until AUDIO_SRAM_PDN_ACK_BIT1 = 0" */
+        while (spm_read(AUDIO_PWR_CON) & AUDIO_SRAM_PDN_ACK_BIT1) {
+            /*  */
+        }
+#endif
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) & ~(0x1 << 10));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until AUDIO_SRAM_PDN_ACK_BIT2 = 0" */
+        while (spm_read(AUDIO_PWR_CON) & AUDIO_SRAM_PDN_ACK_BIT2) {
+            /*  */
+        }
+#endif
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) & ~(0x1 << 11));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until AUDIO_SRAM_PDN_ACK_BIT3 = 0" */
+        while (spm_read(AUDIO_PWR_CON) & AUDIO_SRAM_PDN_ACK_BIT3) {
+            /*  */
+        }
+#endif
+        spm_write(AUDIO_PWR_CON, spm_read(AUDIO_PWR_CON) & ~(0x1 << 12));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until AUDIO_SRAM_PDN_ACK_BIT4 = 0" */
+        while (spm_read(AUDIO_PWR_CON) & AUDIO_SRAM_PDN_ACK_BIT4) {
+            /*  */
+        }
+#endif
+        /* TINFO="Finish to turn on AUDIO" */
+    }
+    return err;
+}
+
+int spm_mtcmos_ctrl_cam(int state)
+{
+    int err = 0;
+
+    /* TINFO="enable SPM register control" */
+    spm_write(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | (0x1 << 0));
+
+    if (state == STA_POWER_DOWN) {
+        /* TINFO="Start to turn off CAM" */
+        /* TINFO="Set bus protect - step1 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_1_SET, CAM_PROT_STEP1_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        while ((spm_read(INFRA_TOPAXI_PROTECTEN_STA1_1) & CAM_PROT_STEP1_0_ACK_MASK) != CAM_PROT_STEP1_0_ACK_MASK) {
+        }
+#endif
+        /* TINFO="Set bus protect - step2 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_SET, CAM_PROT_STEP2_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        while ((spm_read(INFRA_TOPAXI_PROTECTEN_STA1) & CAM_PROT_STEP2_0_ACK_MASK) != CAM_PROT_STEP2_0_ACK_MASK) {
+        }
+#endif
+        /* TINFO="Set SRAM_PDN = 1" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) | CAM_SRAM_PDN);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until CAM_SRAM_PDN_ACK = 1" */
+        while ((spm_read(CAM_PWR_CON) & CAM_SRAM_PDN_ACK) != CAM_SRAM_PDN_ACK) {
+            /*  */
+        }
+#endif
+        /* TINFO="Set PWR_ISO = 1" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) | PWR_ISO);
+        /* TINFO="Set PWR_CLK_DIS = 1" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) | PWR_CLK_DIS);
+        /* TINFO="Set PWR_RST_B = 0" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) & ~PWR_RST_B);
+        /* TINFO="Set PWR_ON = 0" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) & ~PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 0" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) & ~PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 0 and PWR_STATUS_2ND = 0" */
+        while ((spm_read(PWR_STATUS) & CAM_PWR_STA_MASK)
+                || (spm_read(PWR_STATUS_2ND) & CAM_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Finish to turn off CAM" */
+    } else {    /* STA_POWER_ON */
+        /* TINFO="Start to turn on CAM" */
+        /* TINFO="Set PWR_ON = 1" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) | PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 1" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) | PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 1 and PWR_STATUS_2ND = 1" */
+        while (((spm_read(PWR_STATUS) & CAM_PWR_STA_MASK) != CAM_PWR_STA_MASK)
+                || ((spm_read(PWR_STATUS_2ND) & CAM_PWR_STA_MASK) != CAM_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Set PWR_CLK_DIS = 0" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) & ~PWR_CLK_DIS);
+        /* TINFO="Set PWR_ISO = 0" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) & ~PWR_ISO);
+        /* TINFO="Set PWR_RST_B = 1" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) | PWR_RST_B);
+        /* TINFO="Set SRAM_PDN = 0" */
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) & ~(0x1 << 8));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until CAM_SRAM_PDN_ACK_BIT0 = 0" */
+        while (spm_read(CAM_PWR_CON) & CAM_SRAM_PDN_ACK_BIT0) {
+            /*  */
+        }
+#endif
+        spm_write(CAM_PWR_CON, spm_read(CAM_PWR_CON) & ~(0x1 << 9));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until CAM_SRAM_PDN_ACK_BIT1 = 0" */
+        while (spm_read(CAM_PWR_CON) & CAM_SRAM_PDN_ACK_BIT1) {
+            /*  */
+        }
+#endif
+        /* TINFO="Release bus protect - step2 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_CLR, CAM_PROT_STEP2_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* Note that this protect ack check after releasing protect has been ignored */
+#endif
+        /* TINFO="Release bus protect - step1 : 0" */
+        spm_write(INFRA_TOPAXI_PROTECTEN_1_CLR, CAM_PROT_STEP1_0_MASK);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* Note that this protect ack check after releasing protect has been ignored */
+#endif
+        /* TINFO="Finish to turn on CAM" */
+    }
+    return err;
+}
+
+int spm_mtcmos_ctrl_vde(int state)
+{
+    int err = 0;
+
+    /* TINFO="enable SPM register control" */
+    spm_write(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | (0x1 << 0));
+
+    if (state == STA_POWER_DOWN) {
+        /* TINFO="Start to turn off VDE" */
+        /* TINFO="Set SRAM_PDN = 1" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) | VDE_SRAM_PDN);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until VDE_SRAM_PDN_ACK = 1" */
+        while ((spm_read(VDE_PWR_CON) & VDE_SRAM_PDN_ACK) != VDE_SRAM_PDN_ACK) {
+            /*  */
+        }
+#endif
+        /* TINFO="Set PWR_ISO = 1" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) | PWR_ISO);
+        /* TINFO="Set PWR_CLK_DIS = 1" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) | PWR_CLK_DIS);
+        /* TINFO="Set PWR_RST_B = 0" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) & ~PWR_RST_B);
+        /* TINFO="Set PWR_ON = 0" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) & ~PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 0" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) & ~PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 0 and PWR_STATUS_2ND = 0" */
+        while ((spm_read(PWR_STATUS) & VDE_PWR_STA_MASK)
+                || (spm_read(PWR_STATUS_2ND) & VDE_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Finish to turn off VDE" */
+    } else {    /* STA_POWER_ON */
+        /* TINFO="Start to turn on VDE" */
+        /* TINFO="Set PWR_ON = 1" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) | PWR_ON);
+        /* TINFO="Set PWR_ON_2ND = 1" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) | PWR_ON_2ND);
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until PWR_STATUS = 1 and PWR_STATUS_2ND = 1" */
+        while (((spm_read(PWR_STATUS) & VDE_PWR_STA_MASK) != VDE_PWR_STA_MASK)
+                || ((spm_read(PWR_STATUS_2ND) & VDE_PWR_STA_MASK) != VDE_PWR_STA_MASK)) {
+            /* No logic between pwr_on and pwr_ack. Print SRAM / MTCMOS control and PWR_ACK for debug. */
+        }
+#endif
+        /* TINFO="Set PWR_CLK_DIS = 0" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) & ~PWR_CLK_DIS);
+        /* TINFO="Set PWR_ISO = 0" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) & ~PWR_ISO);
+        /* TINFO="Set PWR_RST_B = 1" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) | PWR_RST_B);
+        /* TINFO="Set SRAM_PDN = 0" */
+        spm_write(VDE_PWR_CON, spm_read(VDE_PWR_CON) & ~(0x1 << 8));
+#ifndef IGNORE_MTCMOS_CHECK
+        /* TINFO="Wait until VDE_SRAM_PDN_ACK_BIT0 = 0" */
+        while (spm_read(VDE_PWR_CON) & VDE_SRAM_PDN_ACK_BIT0) {
+            /*  */
+        }
+#endif
+        /* TINFO="Finish to turn on VDE" */
+    }
+    return err;
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/drivers/wdt/mtk_wdt.c b/src/bsp/lk/platform/mediatek/mt8133/drivers/wdt/mtk_wdt.c
new file mode 100644
index 0000000..93b50f3
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/drivers/wdt/mtk_wdt.c
@@ -0,0 +1,357 @@
+/*
+ * 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.
+ */
+
+#include <debug.h>
+#include <platform/mtk_wdt.h>
+#include <reg.h>
+
+#define LK_WDT_DISABLE          (1)
+
+#define MTK_WDT_BASE            TOP_RGU_BASE
+
+#define MTK_WDT_MODE            (MTK_WDT_BASE+0x0000)
+#define MTK_WDT_LENGTH          (MTK_WDT_BASE+0x0004)
+#define MTK_WDT_RESTART         (MTK_WDT_BASE+0x0008)
+#define MTK_WDT_STATUS          (MTK_WDT_BASE+0x000C)
+#define MTK_WDT_INTERVAL        (MTK_WDT_BASE+0x0010)
+#define MTK_WDT_SWRST           (MTK_WDT_BASE+0x0014)
+#define MTK_WDT_SWSYSRST        (MTK_WDT_BASE+0x0018)
+#define MTK_WDT_NONRST_REG      (MTK_WDT_BASE+0x0020)
+#define MTK_WDT_NONRST_REG2     (MTK_WDT_BASE+0x0024)
+#define MTK_WDT_REQ_MODE        (MTK_WDT_BASE+0x0030)
+#define MTK_WDT_REQ_IRQ_EN      (MTK_WDT_BASE+0x0034)
+#define MTK_WDT_DRAMC_CTL       (MTK_WDT_BASE+0x0040)
+#define MTK_WDT_PWR_LATCH       (MTK_WDT_BASE+0x00a4)
+#define MTK_WDT_DEBUG_2_REG     (MTK_WDT_BASE+0x0508)
+
+/*WDT_MODE*/
+#define MTK_WDT_MODE_KEYMASK        (0xff00)
+#define MTK_WDT_MODE_KEY        (0x22000000)
+#define MTK_WDT_MODE_DDR_RESERVE  (0x0080)
+
+#define MTK_WDT_MODE_DUAL_MODE  (0x0040)
+#define MTK_WDT_MODE_IN_DIS     (0x0020) /* Reserved */
+#define MTK_WDT_MODE_AUTO_RESTART   (0x0010) /* Reserved */
+#define MTK_WDT_MODE_IRQ        (0x0008)
+#define MTK_WDT_MODE_EXTEN      (0x0004)
+#define MTK_WDT_MODE_EXT_POL        (0x0002)
+#define MTK_WDT_MODE_ENABLE     (0x0001)
+
+/*WDT_LENGTH*/
+#define MTK_WDT_LENGTH_TIME_OUT     (0xffe0)
+#define MTK_WDT_LENGTH_KEYMASK      (0x001f)
+#define MTK_WDT_LENGTH_KEY      (0x0008)
+
+/*WDT_RESTART*/
+#define MTK_WDT_RESTART_KEY     (0x1971)
+
+/*WDT_STATUS*/
+#define MTK_WDT_STATUS_HWWDT_RST_WITH_IRQ    (0xA0000000)
+#define MTK_WDT_STATUS_HWWDT_RST    (0x80000000)
+#define MTK_WDT_STATUS_SWWDT_RST    (0x40000000)
+#define MTK_WDT_STATUS_IRQWDT_RST   (0x20000000)
+#define MTK_WDT_STATUS_SECURITY_RST (1<<28)
+#define MTK_WDT_STATUS_DEBUGWDT_RST (0x00080000)
+#define MTK_WDT_STATUS_THERMAL_CTL_RST   (1<<18)
+#define MTK_WDT_STATUS_SPMWDT_RST          (0x0002)
+#define MTK_WDT_STATUS_SPM_THERMAL_RST     (0x0001)
+
+//MTK_WDT_DEBUG_CTL
+#define MTK_DEBUG_CTL_KEY           (0x59000000)
+#define MTK_RG_DDR_PROTECT_EN       (0x00001)
+#define MTK_RG_MCU_LATH_EN          (0x00002)
+#define MTK_RG_DRAMC_SREF           (0x00100)
+#define MTK_RG_DRAMC_ISO            (0x00200)
+#define MTK_RG_CONF_ISO             (0x00400)
+#define MTK_DDR_RESERVE_RTA         (0x10000)  //sta
+#define MTK_DDR_SREF_STA            (0x20000)  //sta
+
+/*WDT_INTERVAL*/
+#define MTK_WDT_INTERVAL_MASK       (0x0fff)
+
+/*WDT_SWRST*/
+#define MTK_WDT_SWRST_KEY       (0x1209)
+
+/*WDT_SWSYSRST*/
+#define MTK_WDT_SWSYS_RST_PWRAP_SPI_CTL_RST (0x0800)
+#define MTK_WDT_SWSYS_RST_APMIXED_RST   (0x0400)
+#define MTK_WDT_SWSYS_RST_MD_LITE_RST   (0x0200)
+#define MTK_WDT_SWSYS_RST_INFRA_AO_RST  (0x0100)
+#define MTK_WDT_SWSYS_RST_MD_RST    (0x0080)
+#define MTK_WDT_SWSYS_RST_DDRPHY_RST    (0x0040)
+#define MTK_WDT_SWSYS_RST_IMG_RST   (0x0020)
+#define MTK_WDT_SWSYS_RST_VDEC_RST  (0x0010)
+#define MTK_WDT_SWSYS_RST_VENC_RST  (0x0008)
+#define MTK_WDT_SWSYS_RST_MFG_RST   (0x0004)
+#define MTK_WDT_SWSYS_RST_DISP_RST  (0x0002)
+#define MTK_WDT_SWSYS_RST_INFRA_RST (0x0001)
+
+static bool mtk_wd_CheckNonResetReg2(unsigned int offset)
+{
+    u32 tmp;
+    tmp = readl(MTK_WDT_NONRST_REG2);
+    if (tmp & (1U << offset))
+        return true;
+    else
+        return false;
+}
+
+static void mtk_wd_SetNonResetReg2(unsigned int offset, bool value)
+{
+    u32 reg;
+
+    reg = readl(MTK_WDT_NONRST_REG2);
+    if (value)
+        reg |= (1U << offset);
+    else
+        reg &= ~(1U << offset);
+
+    writel(reg, MTK_WDT_NONRST_REG2);
+}
+
+void set_clr_fastboot_mode(bool flag)
+{
+    if (flag == true)
+        mtk_wd_SetNonResetReg2(0x2, 1);
+    else if (flag == false)
+        mtk_wd_SetNonResetReg2(0x2, 0);
+
+    dprintf(INFO, "set_clr_fastboot_mode\n");
+}
+
+void set_clr_recovery_mode(bool flag)
+{
+    if (flag == true)
+        mtk_wd_SetNonResetReg2(0x1, 1);
+    else if (flag == false)
+        mtk_wd_SetNonResetReg2(0x1, 0);
+
+    dprintf(INFO, "set_clr_recovery_mode\n");
+}
+
+bool check_fastboot_mode(void)
+{
+    return mtk_wd_CheckNonResetReg2(0x2);
+}
+
+bool check_recovery_mode(void)
+{
+    return mtk_wd_CheckNonResetReg2(0x1);
+}
+
+void mtk_wdt_disable(void)
+{
+    u32 tmp;
+
+    tmp = readl(MTK_WDT_MODE);
+    tmp &= ~MTK_WDT_MODE_ENABLE;       /* disable watchdog */
+    tmp |= (MTK_WDT_MODE_KEY);         /* need key then write is allowed */
+    writel(tmp, MTK_WDT_MODE);
+}
+
+static void mtk_wdt_reset(char mode)
+{
+    /* Watchdog Rest */
+    unsigned int wdt_mode_val;
+    writel(MTK_WDT_RESTART_KEY, MTK_WDT_RESTART);
+
+    wdt_mode_val = readl(MTK_WDT_MODE);
+    /* clear autorestart bit: autoretart: 1, bypass power key, 0: not bypass power key */
+    wdt_mode_val &=(~MTK_WDT_MODE_AUTO_RESTART);
+    /* make sure WDT mode is hw reboot mode, can not config isr mode  */
+    wdt_mode_val &= ~(MTK_WDT_MODE_IRQ | MTK_WDT_MODE_ENABLE | MTK_WDT_MODE_DUAL_MODE);
+
+    wdt_mode_val |= (MTK_WDT_MODE_KEY | MTK_WDT_MODE_EXTEN);
+
+    if (mode)  /* mode != 0 means by pass power key reboot, We using auto_restart bit as by pass power key flag */
+        wdt_mode_val |= MTK_WDT_MODE_AUTO_RESTART;
+
+    writel(wdt_mode_val, MTK_WDT_MODE);
+
+    spin(100);
+    writel(MTK_WDT_SWRST_KEY, MTK_WDT_SWRST);
+}
+
+static unsigned int mtk_wdt_check_status(void)
+{
+    static unsigned int status = 0;
+
+    /*
+     * Because WDT_STA register will be cleared after writing WDT_MODE,
+     * we use a static variable to store WDT_STA.
+     * After reset, static varialbe will always be clear to 0,
+     * so only read WDT_STA when static variable is 0 is OK
+     */
+    if (0 == status)
+        status = readl(MTK_WDT_STATUS);
+
+    return status;
+}
+
+static void mtk_wdt_mode_config(bool dual_mode_en,
+                                bool irq,
+                                bool ext_en,
+                                bool ext_pol,
+                                bool wdt_en)
+{
+    unsigned int tmp;
+
+    tmp = readl(MTK_WDT_MODE);
+    tmp |= MTK_WDT_MODE_KEY;
+
+    // Bit 0 : Whether enable watchdog or not
+    if (wdt_en == true)
+        tmp |= MTK_WDT_MODE_ENABLE;
+    else
+        tmp &= ~MTK_WDT_MODE_ENABLE;
+
+    // Bit 1 : Configure extern reset signal polarity.
+    if (ext_pol == true)
+        tmp |= MTK_WDT_MODE_EXT_POL;
+    else
+        tmp &= ~MTK_WDT_MODE_EXT_POL;
+
+    // Bit 2 : Whether enable external reset signal
+    if (ext_en == true)
+        tmp |= MTK_WDT_MODE_EXTEN;
+    else
+        tmp &= ~MTK_WDT_MODE_EXTEN;
+
+    // Bit 3 : Whether generating interrupt instead of reset signal
+    if (irq == true)
+        tmp |= MTK_WDT_MODE_IRQ;
+    else
+        tmp &= ~MTK_WDT_MODE_IRQ;
+
+    // Bit 6 : Whether enable debug module reset
+    if (dual_mode_en == true)
+        tmp |= MTK_WDT_MODE_DUAL_MODE;
+    else
+        tmp &= ~MTK_WDT_MODE_DUAL_MODE;
+
+    // Bit 4: WDT_Auto_restart, this is a reserved bit, we use it as bypass powerkey flag.
+    //      Because HW reboot always need reboot to kernel, we set it always.
+    tmp |= MTK_WDT_MODE_AUTO_RESTART;
+
+    writel(tmp, MTK_WDT_MODE);
+    //dual_mode(1); //always dual mode
+    //mdelay(100);
+    dprintf(INFO,"mtk_wdt_mode_config LK mode value=%x", readl(MTK_WDT_MODE));
+}
+
+static void mtk_wdt_set_time_out_value(uint32_t value)
+{
+    static unsigned int timeout;
+
+    /*
+    * TimeOut = BitField 15:5
+    * Key      = BitField  4:0 = 0x08
+    */
+
+    // sec * 32768 / 512 = sec * 64 = sec * 1 << 6
+    timeout = (unsigned int)(value * ( 1 << 6) );
+    timeout = timeout << 5;
+    writel((timeout | MTK_WDT_LENGTH_KEY), MTK_WDT_LENGTH);
+}
+
+static void mtk_wdt_restart(void)
+{
+    // Reset WatchDogTimer's counting value to time out value
+    // ie., keepalive()
+    writel(MTK_WDT_RESTART_KEY, MTK_WDT_RESTART);
+}
+
+static const char *parsing_reset_reason(unsigned int wdt_status)
+{
+    const char *rst_reason="normal";
+    switch (wdt_status) {
+        case MTK_WDT_STATUS_HWWDT_RST_WITH_IRQ:
+            rst_reason="hw_rst_with_irq";
+            break;
+
+        case MTK_WDT_STATUS_HWWDT_RST:
+            rst_reason="hw_rst";
+            break;
+
+        case MTK_WDT_STATUS_SWWDT_RST:
+            rst_reason="sw_rst";
+            break;
+
+        case MTK_WDT_STATUS_IRQWDT_RST:
+            rst_reason="irq_rst";
+            break;
+
+        case MTK_WDT_STATUS_SECURITY_RST:
+            rst_reason="security_rst";
+            break;
+
+        case MTK_WDT_STATUS_DEBUGWDT_RST:
+            rst_reason="debug_rst";
+            break;
+
+        case MTK_WDT_STATUS_THERMAL_CTL_RST:
+            rst_reason="thermal_ctl_rst";
+            break;
+
+        case MTK_WDT_STATUS_SPMWDT_RST:
+            rst_reason="spm_rst";
+            break;
+
+        case MTK_WDT_STATUS_SPM_THERMAL_RST:
+            rst_reason="spm_thermal_rst";
+            break;
+
+        default:
+            break;
+    }
+
+    return rst_reason;
+}
+
+void mtk_wdt_init(void)
+{
+    /* This function will store the reset reason: Time out/ SW trigger */
+    dprintf(ALWAYS, "Watchdog Status: %x , boot from %s\n", mtk_wdt_check_status(),parsing_reset_reason(mtk_wdt_check_status()));
+
+    mtk_wdt_mode_config(false, false, false, false, false);
+
+#if (!LK_WDT_DISABLE)
+    mtk_wdt_set_time_out_value(10);
+    mtk_wdt_mode_config(true, true, true, false, true);
+    mtk_wdt_restart();
+#endif
+}
+
+void mtk_arch_reset(char mode)
+{
+    dprintf(INFO,"UB mtk_arch_reset\n");
+
+    mtk_wdt_reset(mode);
+
+    while (1);
+}
+
+void mtk_wdt_pwr_latch(void)
+{
+    writel(0x66000001, MTK_WDT_PWR_LATCH);
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/fixup/plat_fixup.c b/src/bsp/lk/platform/mediatek/mt8133/fixup/plat_fixup.c
new file mode 100644
index 0000000..29ff81a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/fixup/plat_fixup.c
@@ -0,0 +1,130 @@
+/*

+ * Copyright (c) 2019 MediaTek Inc.

+ *

+ * Use of this source code is governed by MIT-style

+ * license that can be found in the LICENSE file or at

+ * https://opensource.org/licenses/MIT

+ */

+

+#include <assert.h>

+#include <compiler.h>

+#include <err.h>

+#include <lib/kcmdline.h>

+#if (LOG_STORE_SUPPORT == 1)

+#include <lib/log_store.h>

+#endif

+#include <lib/bio.h>

+#include <malloc.h>

+#include <stdlib.h>

+#include <string.h>

+#include <trace.h>

+

+#define LOCAL_TRACE 2

+

+extern __WEAK void mrdump_append_cmdline(void);

+

+#if defined(AB_UPGRADE_APP)

+static void ab_fixup(const char *ab_suffix)

+{

+    int rc __UNUSED;

+    char *suffix_arg;

+

+    if (!ab_suffix)

+        return;

+

+    suffix_arg = (char *)malloc(strlen("androidboot.slot_suffix=") +

+                                strlen(ab_suffix) + 1);

+    if (!suffix_arg) {

+        LTRACEF("Not enough memory for suffix cmdline\n");

+        return;

+    }

+

+    sprintf(suffix_arg, "androidboot.slot_suffix=%s", ab_suffix);

+    rc = kcmdline_append(suffix_arg);

+    assert(rc == NO_ERROR);

+    free(suffix_arg);

+}

+#endif

+

+static void project_fixup_hook(uint32_t boot_mode, const char *ab_suffix)

+{

+#if defined(AB_UPGRADE_APP)

+    bdev_t *bdev;

+    char *part_name;

+    char *part_uuid;

+    char *part_rootfs;    //for nand

+    const char *suffix = ab_suffix ? : "";

+

+    part_name = (char *)malloc(strlen(ROOTFS_PART_NAME) +

+                               strlen(suffix) + 1);

+    if (!part_name) {

+        LTRACEF("Not enough memory for part_name\n");

+        return;

+    }

+

+    sprintf(part_name, "%s%s", ROOTFS_PART_NAME, suffix);

+

+    bdev = bio_open_by_label(part_name);

+    if (!bdev) {

+        LTRACEF("Partition not exist: %s\n", part_name);

+        goto err;

+    }

+

+#if defined(MTK_NAND_PAGE_SIZE)

+    LTRACEF("This is nand, bdev->name == %s. \n", bdev->name);

+    //part_rootfs = (char *)malloc(strlen("ubi.mtd=") + strlen(bdev->name) - strlen("nand0p") + 1);

+

+    //sprintf(part_rootfs, "ubi.mtd=%d", atoi(bdev->name + strlen("nand0p"))-1);

+    part_rootfs = (char *)malloc(strlen("ubi.mtd=") + strlen(part_name) + 1);

+    sprintf(part_rootfs, "ubi.mtd=%s", part_name);

+    kcmdline_subst("ubi.mtd=system",part_rootfs);

+    LTRACEF("This is nand, part_rootfs == %s. \n", part_rootfs);

+

+    free(part_rootfs);

+#else

+    part_uuid = (char *)malloc(strlen("root=PARTUUID=") +

+                               strlen(bdev->unique_uuid) + 1);

+    if (!part_uuid) {

+        LTRACEF("Not enough memory for part_uuid\n");

+        goto err;

+    }

+

+    sprintf(part_uuid, "root=PARTUUID=%s", bdev->unique_uuid);

+    kcmdline_append(part_uuid);

+    free(part_uuid);

+#endif

+err:

+    free(part_name);

+    bio_close(bdev);

+#endif

+}

+

+

+

+/* need to do fixup when bl2 or bl33 lk will load kernel image */

+#if (defined(ENABLE_BUILTIN_BL33) && (ENABLE_BUILTIN_BL33 == 1)) || \

+    (defined(LK_AS_BL33) && (LK_AS_BL33 == 1))

+int plat_fixup_init(void)

+{

+    return kcmdline_init();

+}

+

+void plat_fixup_append(char *append_str)

+{

+    if (kcmdline_append(append_str) != NO_ERROR) {

+        LTRACEF("append str failed: %s\n", append_str);

+    }

+}

+

+void plat_fixup_hook(uint32_t boot_mode, const char *ab_suffix,

+                     void *dtb, size_t dtb_size)

+{

+    /* project specific fixup */

+    project_fixup_hook(boot_mode, ab_suffix);

+

+    /* finalized fixup */

+    if (kcmdline_finalized(dtb, dtb_size)) {

+        LTRACEF("kcmdline finalized failed.\n");

+    }

+}

+#endif

diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/generic_ioctl.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/generic_ioctl.h
new file mode 100644
index 0000000..84c2ec8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/generic_ioctl.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_ASM_GENERIC_IOCTL_H
+#define _UAPI_ASM_GENERIC_IOCTL_H
+#define _IOC_NRBITS 8
+#define _IOC_TYPEBITS 8
+#ifndef _IOC_SIZEBITS
+#define _IOC_SIZEBITS 14
+#endif
+#ifndef _IOC_DIRBITS
+#define _IOC_DIRBITS 2
+#endif
+#define _IOC_NRMASK ((1 << _IOC_NRBITS) - 1)
+#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS) - 1)
+#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS) - 1)
+#define _IOC_DIRMASK ((1 << _IOC_DIRBITS) - 1)
+#define _IOC_NRSHIFT 0
+#define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS)
+#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS)
+#define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS)
+#ifndef _IOC_NONE
+#define _IOC_NONE 0U
+#endif
+#ifndef _IOC_WRITE
+#define _IOC_WRITE 1U
+#endif
+#ifndef _IOC_READ
+#define _IOC_READ 2U
+#endif
+#define _IOC(dir,type,nr,size) (((dir) << _IOC_DIRSHIFT) | ((type) << _IOC_TYPESHIFT) | ((nr) << _IOC_NRSHIFT) | ((size) << _IOC_SIZESHIFT))
+#define _IOC_TYPECHECK(t) (sizeof(t))
+#define _IO(type,nr) _IOC(_IOC_NONE, (type), (nr), 0)
+#define _IOR(type,nr,size) _IOC(_IOC_READ, (type), (nr), (_IOC_TYPECHECK(size)))
+#define _IOW(type,nr,size) _IOC(_IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size)))
+#define _IOWR(type,nr,size) _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size)))
+#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ, (type), (nr), sizeof(size))
+#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE, (type), (nr), sizeof(size))
+#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), sizeof(size))
+#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT ((_IOC_WRITE | _IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/gic.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/gic.h
new file mode 100644
index 0000000..07f2a28
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/gic.h
@@ -0,0 +1,26 @@
+/*
+ * 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 <platform/mt8133.h>
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mmc_core.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mmc_core.h
new file mode 100644
index 0000000..599f39a
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mmc_core.h
@@ -0,0 +1,655 @@
+/*
+ * 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
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <kernel/mutex.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MMC_BLOCK_BITS_SHFT             (9)
+#define MMC_BLOCK_SIZE                  (1 << MMC_BLOCK_BITS_SHFT)
+#define MMC_MAX_BLOCK_SIZE              (1 << MMC_BLOCK_BITS_SHFT)
+
+#define SDIO_MAX_FUNCS                  (7)
+
+#define SD_CMD_BIT                      (1 << 7)
+#define SD_CMD_APP_BIT                  (1 << 8)
+#define SD_CMD_AUTO_BIT                 (1 << 9)
+
+/* MMC command numbers */
+#define MMC_CMD_GO_IDLE_STATE           (0)              /* bc.   no response */
+#define MMC_CMD_SEND_OP_COND            (1)              /* bcr.  R3          */
+#define MMC_CMD_ALL_SEND_CID            (2)              /* bcr.  R2          */
+#define MMC_CMD_SET_RELATIVE_ADDR       (3)              /* ac.   R1          */
+#define MMC_CMD_SET_DSR                 (4)              /* bc.   no response */
+#define MMC_CMD_SLEEP_AWAKE             (5)              /* ac.   R1b         */
+#define MMC_CMD_SWITCH                  (6)              /* ac.   R1b         */
+#define MMC_CMD_SELECT_CARD             (7)              /* ac.   R1/R1b      */
+#define MMC_CMD_SEND_EXT_CSD            (8)              /* adtc. R1          */
+#define MMC_CMD_SEND_CSD                (9)              /* ac.   R2          */
+#define MMC_CMD_SEND_CID                (10)             /* ac.   R2          */
+#define MMC_CMD_READ_DAT_UNTIL_STOP     (11)             /* adtc. R1          */
+#define MMC_CMD_STOP_TRANSMISSION       (12)             /* ac.   R1/R1b      */
+#define MMC_CMD_SEND_STATUS             (13)             /* ac.   R1          */
+#define MMC_CMD_BUSTEST_R               (14)             /* adtc. R1          */
+#define MMC_CMD_GO_INACTIVE_STATE       (15)             /* ac.   no response */
+#define MMC_CMD_SET_BLOCKLEN            (16)             /* ac.   R1          */
+#define MMC_CMD_READ_SINGLE_BLOCK       (17)             /* adtc. R1          */
+#define MMC_CMD_READ_MULTIPLE_BLOCK     (18)             /* adtc. R1          */
+#define MMC_CMD_BUSTEST_W               (19)             /* adtc. R1          */
+#define MMC_CMD_WRITE_DAT_UNTIL_STOP    (20)             /* adtc. R1          */
+#define MMC_CMD21                       (21)             /* adtc. R1  Sandisk  */
+#define MMC_CMD_SET_BLOCK_COUNT         (23)             /* ac.   R1          */
+#define MMC_CMD_WRITE_BLOCK             (24)             /* adtc. R1          */
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK    (25)             /* adtc. R1          */
+#define MMC_CMD_PROGRAM_CID             (26)             /* adtc. R1          */
+#define MMC_CMD_PROGRAM_CSD             (27)             /* adtc. R1          */
+
+#define MMC_CMD_SET_WRITE_PROT          (28)             /* ac.   R1b         */
+#define MMC_CMD_CLR_WRITE_PROT          (29)             /* ac.   R1b         */
+#define MMC_CMD_SEND_WRITE_PROT         (30)             /* adtc. R1          */
+#define MMC_CMD_SEND_WRITE_PROT_TYPE    (31)             /* adtc. R1          */
+#define MMC_CMD_ERASE_WR_BLK_START      (32)
+#define MMC_CMD_ERASE_WR_BLK_END        (33)
+#define MMC_CMD_ERASE_GROUP_START       (35)             /* ac.   R1          */
+#define MMC_CMD_ERASE_GROUP_END         (36)             /* ac.   R1          */
+#define MMC_CMD_ERASE                   (38)             /* ac.   R1b         */
+#define MMC_CMD_FAST_IO                 (39)             /* ac.   R4          */
+#define MMC_CMD_GO_IRQ_STATE            (40)             /* bcr.  R5          */
+#define MMC_CMD_LOCK_UNLOCK             (42)             /* adtc. R1          */
+#define MMC_CMD50                       (50)             /* adtc. R1 Sandisk */
+#define MMC_CMD_APP_CMD                 (55)             /* ac.   R1          */
+#define MMC_CMD_GEN_CMD                 (56)             /* adtc. R1          */
+
+/* SD Card command numbers */
+#define SD_CMD_SEND_RELATIVE_ADDR       (3 | SD_CMD_BIT)
+#define SD_CMD_SWITCH                   (6 | SD_CMD_BIT)
+#define SD_CMD_SEND_IF_COND             (8 | SD_CMD_BIT)
+#define SD_CMD_VOL_SWITCH               (11 | SD_CMD_BIT)
+#define SD_CMD_SEND_TUNING_BLOCK        (19 | SD_CMD_BIT)
+#define SD_CMD_SPEED_CLASS_CTRL         (20 | SD_CMD_BIT)
+
+#define SD_ACMD_SET_BUSWIDTH            (6  | SD_CMD_APP_BIT)
+#define SD_ACMD_SD_STATUS               (13 | SD_CMD_APP_BIT)
+#define SD_ACMD_SEND_NR_WR_BLOCKS       (22 | SD_CMD_APP_BIT)
+#define SD_ACMD_SET_WR_ERASE_CNT        (23 | SD_CMD_APP_BIT)
+#define SD_ACMD_SEND_OP_COND            (41 | SD_CMD_APP_BIT)
+#define SD_ACMD_SET_CLR_CD              (42 | SD_CMD_APP_BIT)
+#define SD_ACMD_SEND_SCR                (51 | SD_CMD_APP_BIT)
+
+/* SDIO Card command numbers */
+#define SD_IO_SEND_OP_COND              (5 | SD_CMD_BIT) /* bcr. R4           */
+#define SD_IO_RW_DIRECT                 (52 | SD_CMD_BIT)/* ac.  R5           */
+#define SD_IO_RW_EXTENDED               (53 | SD_CMD_BIT)/* adtc. R5          */
+
+/* platform dependent command */
+#define SD_ATOCMD_STOP_TRANSMISSION     (12 | SD_CMD_AUTO_BIT)
+#define SD_ATOCMD_SET_BLOCK_COUNT       (23 | SD_CMD_AUTO_BIT)
+
+#define MMC_VDD_145_150 0x00000001  /* VDD voltage 1.45 - 1.50 */
+#define MMC_VDD_150_155 0x00000002  /* VDD voltage 1.50 - 1.55 */
+#define MMC_VDD_155_160 0x00000004  /* VDD voltage 1.55 - 1.60 */
+#define MMC_VDD_160_165 0x00000008  /* VDD voltage 1.60 - 1.65 */
+#define MMC_VDD_165_170 0x00000010  /* VDD voltage 1.65 - 1.70 */
+#define MMC_VDD_17_18   0x00000020  /* VDD voltage 1.7 - 1.8 */
+#define MMC_VDD_18_19   0x00000040  /* VDD voltage 1.8 - 1.9 */
+#define MMC_VDD_19_20   0x00000080  /* VDD voltage 1.9 - 2.0 */
+#define MMC_VDD_20_21   0x00000100  /* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22   0x00000200  /* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23   0x00000400  /* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24   0x00000800  /* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25   0x00001000  /* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26   0x00002000  /* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27   0x00004000  /* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28   0x00008000  /* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29   0x00010000  /* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30   0x00020000  /* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31   0x00040000  /* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32   0x00080000  /* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33   0x00100000  /* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34   0x00200000  /* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35   0x00400000  /* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36   0x00800000  /* VDD voltage 3.5 ~ 3.6 */
+#define MMC_CARD_BUSY   0x80000000  /* Card Power up status bit */
+#define MMC_VDD_165_195     0x00000080  /* VDD voltage 1.65 - 1.95 */ //Add this line by reference to include/linux/mmc/host.h in linux kernel
+#define MMC_VDD_27_36       0x00FF8000
+
+#define EMMC_VER_50   (50)
+#define EMMC_VER_45   (45)
+#define EMMC_VER_44   (44)
+#define EMMC_VER_43   (43)
+#define EMMC_VER_42   (42)
+#define SD_VER_10     (10)
+#define SD_VER_20     (20)
+#define SD_VER_30     (30)
+
+#define MMC_ERR_NONE          0
+#define MMC_ERR_TIMEOUT       1
+#define MMC_ERR_BADCRC        2
+#define MMC_ERR_FIFO          3
+#define MMC_ERR_FAILED        4
+#define MMC_ERR_INVALID       5
+#define MMC_ERR_CMDTUNEFAIL   6
+#define MMC_ERR_READTUNEFAIL  7
+#define MMC_ERR_WRITETUNEFAIL 8
+#define MMC_ERR_CMD_TIMEOUT   9
+#define MMC_ERR_CMD_RSPCRC    10
+#define MMC_ERR_ACMD_TIMEOUT  11
+#define MMC_ERR_ACMD_RSPCRC   12
+#define MMC_ERR_AXI_RSPCRC    13
+#define MMC_ERR_UNEXPECT      14
+#define MMC_ERR_RETRY         15
+
+#define MMC_POWER_OFF       0
+#define MMC_POWER_UP        1
+#define MMC_POWER_ON        2
+
+#define MMC_BUS_WIDTH_1     0
+#define MMC_BUS_WIDTH_4     2
+
+#define SD_BUS_WIDTH_1      0
+#define SD_BUS_WIDTH_4      2
+
+#define MMC_STATE_PRESENT       (1<<0)      /* present in sysfs */
+#define MMC_STATE_READONLY      (1<<1)      /* card is read-only */
+#define MMC_STATE_HIGHSPEED     (1<<2)      /* card is in high speed mode */
+#define MMC_STATE_BLOCKADDR     (1<<3)      /* card uses block-addressing */
+#define MMC_STATE_HIGHCAPS      (1<<4)
+#define MMC_STATE_UHS1          (1<<5)      /* card is in ultra high speed mode */
+#define MMC_STATE_DDR           (1<<6)      /* card is in ddr mode */
+#define MMC_STATE_HS200         (1<<7)
+#define MMC_STATE_HS400         (1<<8)
+#define MMC_STATE_BACKYARD      (1<<9)
+
+#define R1_OUT_OF_RANGE         (1UL << 31) /* er, c */
+#define R1_ADDRESS_ERROR        (1 << 30)   /* erx, c */
+#define R1_BLOCK_LEN_ERROR      (1 << 29)   /* er, c */
+#define R1_ERASE_SEQ_ERROR      (1 << 28)   /* er, c */
+#define R1_ERASE_PARAM          (1 << 27)   /* ex, c */
+#define R1_WP_VIOLATION         (1 << 26)   /* erx, c */
+#define R1_CARD_IS_LOCKED       (1 << 25)   /* sx, a */
+#define R1_LOCK_UNLOCK_FAILED   (1 << 24)   /* erx, c */
+#define R1_COM_CRC_ERROR        (1 << 23)   /* er, b */
+#define R1_ILLEGAL_COMMAND      (1 << 22)   /* er, b */
+#define R1_CARD_ECC_FAILED      (1 << 21)   /* ex, c */
+#define R1_CC_ERROR             (1 << 20)   /* erx, c */
+#define R1_ERROR                (1 << 19)   /* erx, c */
+#define R1_UNDERRUN             (1 << 18)   /* ex, c */
+#define R1_OVERRUN              (1 << 17)   /* ex, c */
+#define R1_CID_CSD_OVERWRITE    (1 << 16)   /* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP        (1 << 15)   /* sx, c */
+#define R1_CARD_ECC_DISABLED    (1 << 14)   /* sx, a */
+#define R1_ERASE_RESET          (1 << 13)   /* sr, c */
+#define R1_STATUS(x)            (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x)     ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
+#define R1_READY_FOR_DATA       (1 << 8)    /* sx, a */
+#define R1_SWITCH_ERROR         (1 << 7)    /* ex, b */
+#define R1_URGENT_BKOPS         (1 << 6)    /* sr, a */
+#define R1_APP_CMD              (1 << 5)    /* sr, c */
+
+/*
+ * Card Command Classes (CCC)
+ */
+#define CCC_BASIC               (1<<0)  /* (0) Basic protocol functions */
+/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
+#define CCC_STREAM_READ         (1<<1)  /* (1) Stream read commands */
+/* (CMD11) */
+#define CCC_BLOCK_READ          (1<<2)  /* (2) Block read commands */
+/* (CMD16,17,18) */
+#define CCC_STREAM_WRITE        (1<<3)  /* (3) Stream write commands */
+/* (CMD20) */
+#define CCC_BLOCK_WRITE         (1<<4)  /* (4) Block write commands */
+/* (CMD16,24,25,26,27) */
+#define CCC_ERASE               (1<<5)  /* (5) Ability to erase blocks */
+/* (CMD32,33,34,35,36,37,38,39) */
+#define CCC_WRITE_PROT          (1<<6)  /* (6) Able to write protect blocks */
+/* (CMD28,29,30) */
+#define CCC_LOCK_CARD           (1<<7)  /* (7) Able to lock down card */
+/* (CMD16,CMD42) */
+#define CCC_APP_SPEC            (1<<8)  /* (8) Application specific */
+/* (CMD55,56,57,ACMD*) */
+#define CCC_IO_MODE             (1<<9)  /* (9) I/O mode */
+/* (CMD5,39,40,52,53) */
+#define CCC_SWITCH              (1<<10) /* (10) High speed switch */
+/* (CMD6,34,35,36,37,50) */
+/* (11) Reserved */
+/* (CMD?) */
+
+/*
+ * CSD field definitions
+ */
+
+#define CSD_STRUCT_VER_1_0  0   /* Valid for system specification 1.0 - 1.2 */
+#define CSD_STRUCT_VER_1_1  1   /* Valid for system specification 1.4 - 2.2 */
+#define CSD_STRUCT_VER_1_2  2   /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
+#define CSD_STRUCT_EXT_CSD  3   /* Version is coded in CSD_STRUCTURE in EXT_CSD */
+
+#define CSD_SPEC_VER_0      0   /* Implements system specification 1.0 - 1.2 */
+#define CSD_SPEC_VER_1      1   /* Implements system specification 1.4 */
+#define CSD_SPEC_VER_2      2   /* Implements system specification 2.0 - 2.2 */
+#define CSD_SPEC_VER_3      3   /* Implements system specification 3.1 - 3.2 - 3.31 */
+#define CSD_SPEC_VER_4      4   /* Implements system specification 4.0 - 4.1 */
+
+/*
+ * EXT_CSD fields
+ */
+
+#define EXT_CSD_BADBLK_MGMT             134 /* R/W */
+#define EXT_CSD_ENH_START_ADDR          136 /* R/W 4 bytes */
+#define EXT_CSD_ENH_SIZE_MULT           140 /* R/W 3 bytes */
+#define EXT_CSD_GP1_SIZE_MULT           143 /* R/W 3 bytes */
+#define EXT_CSD_GP2_SIZE_MULT           146 /* R/W 3 bytes */
+#define EXT_CSD_GP3_SIZE_MULT           149 /* R/W 3 bytes */
+#define EXT_CSD_GP4_SIZE_MULT           152 /* R/W 3 bytes */
+#define EXT_CSD_PART_SET_COMPL          155 /* R/W */
+#define EXT_CSD_PART_ATTR               156 /* R/W 3 bytes */
+#define EXT_CSD_MAX_ENH_SIZE_MULT       157 /* R/W 3 bytes */
+#define EXT_CSD_PART_SUPPORT            160 /* R */
+#define EXT_CSD_HPI_MGMT                161 /* R/W/E_P (4.41) */
+#define EXT_CSD_RST_N_FUNC              162 /* R/W */
+#define EXT_CSD_BKOPS_EN                163 /* R/W (4.41) */
+#define EXT_CSD_BKOPS_START             164 /* W/E_P (4.41) */
+#define EXT_CSD_WR_REL_PARAM            166 /* R (4.41) */
+#define EXT_CSD_WR_REL_SET              167 /* R/W (4.41) */
+#define EXT_CSD_RPMB_SIZE_MULT          168 /* R */
+#define EXT_CSD_FW_CONFIG               169 /* R/W */
+#define EXT_CSD_USR_WP                  171 /* R/W, R/W/C_P & R/W/E_P */
+#define EXT_CSD_BOOT_WP                 173 /* R/W, R/W/C_P */
+#define EXT_CSD_ERASE_GRP_DEF           175 /* R/W/E */
+#define EXT_CSD_BOOT_BUS_WIDTH          177 /* R/W/E */
+#define EXT_CSD_BOOT_CONFIG_PROT        178 /* R/W & R/W/C_P */
+#define EXT_CSD_PART_CFG                179 /* R/W/E & R/W/E_P */
+#define EXT_CSD_ERASED_MEM_CONT         181 /* R */
+#define EXT_CSD_BUS_WIDTH               183 /* R/W */
+#define EXT_CSD_HS_TIMING               185 /* R/W */
+#define EXT_CSD_PWR_CLASS               187 /* R/W/E_P */
+#define EXT_CSD_CMD_SET_REV             189 /* R */
+#define EXT_CSD_CMD_SET                 191 /* R/W/E_P */
+#define EXT_CSD_REV                     192 /* R */
+#define EXT_CSD_STRUCT                  194 /* R */
+#define EXT_CSD_CARD_TYPE               196 /* RO */
+#define EXT_CSD_OUT_OF_INTR_TIME        198 /* R (4.41) */
+#define EXT_CSD_PART_SWITCH_TIME        199 /* R (4.41) */
+#define EXT_CSD_PWR_CL_52_195           200 /* R */
+#define EXT_CSD_PWR_CL_26_195           201 /* R */
+#define EXT_CSD_PWR_CL_52_360           202 /* R */
+#define EXT_CSD_PWR_CL_26_360           203 /* R */
+#define EXT_CSD_MIN_PERF_R_4_26         205 /* R */
+#define EXT_CSD_MIN_PERF_W_4_26         206 /* R */
+#define EXT_CSD_MIN_PERF_R_8_26_4_25    207 /* R */
+#define EXT_CSD_MIN_PERF_W_8_26_4_25    208 /* R */
+#define EXT_CSD_MIN_PERF_R_8_52         209 /* R */
+#define EXT_CSD_MIN_PERF_W_8_52         210 /* R */
+#define EXT_CSD_SEC_CNT                 212 /* RO, 4 bytes */
+#define EXT_CSD_S_A_TIMEOUT             217 /* R */
+#define EXT_CSD_S_C_VCCQ                219 /* R */
+#define EXT_CSD_S_C_VCC                 220 /* R */
+#define EXT_CSD_HC_WP_GPR_SIZE          221 /* R */
+#define EXT_CSD_REL_WR_SEC_C            222 /* R */
+#define EXT_CSD_ERASE_TIMEOUT_MULT      223 /* R */
+#define EXT_CSD_HC_ERASE_GRP_SIZE       224 /* R */
+#define EXT_CSD_ACC_SIZE                225 /* R */
+#define EXT_CSD_BOOT_SIZE_MULT          226 /* R */
+#define EXT_CSD_BOOT_INFO               228 /* R */
+#define EXT_CSD_SEC_TRIM_MULT           229 /* R */
+#define EXT_CSD_SEC_ERASE_MULT          230 /* R */
+#define EXT_CSD_SEC_FEATURE_SUPPORT     231 /* R */
+#define EXT_CSD_TRIM_MULT               232 /* R */
+#define EXT_CSD_MIN_PERF_DDR_R_8_52     234 /* R */
+#define EXT_CSD_MIN_PERF_DDR_W_8_52     235 /* R */
+#define EXT_CSD_PWR_CL_DDR_52_195       238 /* R */
+#define EXT_CSD_PWR_CL_DDR_52_360       239 /* R */
+#define EXT_CSD_INI_TIMEOUT_AP          241 /* R */
+#define EXT_CSD_CORRECT_PRG_SECTS_NUM   242 /* R, 4 bytes (4.41) */
+#define EXT_CSD_BKOPS_STATUS            246 /* R (4.41) */
+#define EXT_CSD_BKOPS_SUPP              502 /* R (4.41) */
+#define EXT_CSD_HPI_FEATURE             503 /* R (4.41) */
+#define EXT_CSD_S_CMD_SET               504 /* R */
+
+/*
+ * EXT_CSD field definitions
+ */
+
+/* SEC_FEATURE_SUPPORT[231] */
+#define EXT_CSD_SEC_FEATURE_ER_EN       (1<<0)
+#define EXT_CSD_SEC_FEATURE_BD_BLK_EN   (1<<2)
+#define EXT_CSD_SEC_FEATURE_GB_CL_EN    (1<<4)
+
+/* BOOT_INFO[228] */
+#define EXT_CSD_BOOT_INFO_ALT_BOOT      (1<<0)
+#define EXT_CSD_BOOT_INFO_DDR_BOOT      (1<<1)
+#define EXT_CSD_BOOT_INFO_HS_BOOT       (1<<2)
+
+#define EXT_CSD_CMD_SET_NORMAL          (1<<0)
+#define EXT_CSD_CMD_SET_SECURE          (1<<1)
+#define EXT_CSD_CMD_SET_CPSECURE        (1<<2)
+
+#define EXT_CSD_CARD_TYPE_26            (1<<0)  /* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_52            (1<<1)  /* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_DDR_52        (1<<2)  /* Card can run at DDR 52MHz@1.8V or 3V */
+#define EXT_CSD_CARD_TYPE_DDR_52_1_2V   (1<<3)  /* Card can run at DDR 52MHz@1.2V */
+#define EXT_CSD_CARD_TYPE_HS200_1_8V    (1<<4)  /* Card can run at 200MHz@ 1.8V*/
+#define EXT_CSD_CARD_TYPE_HS200_1_2V    (1<<5)  /* Card can run at 200MHz@ 1.2V*/
+#define EXT_CSD_CARD_TYPE_HS400_1_8V    (1<<6)  /* Card can run at 200MHz@ 1.8V*/
+#define EXT_CSD_CARD_TYPE_HS400_1_2V    (1<<7)  /* Card can run at 200MHz@ 1.2V*/
+
+/* BUS_WIDTH[183] */
+#define EXT_CSD_BUS_WIDTH_1             (0) /* Card is in 1 bit mode */
+#define EXT_CSD_BUS_WIDTH_4             (1) /* Card is in 4 bit mode */
+#define EXT_CSD_BUS_WIDTH_8             (2) /* Card is in 8 bit mode */
+#define EXT_CSD_BUS_WIDTH_4_DDR         (5) /* Card is in 4 bit mode + DDR */
+#define EXT_CSD_BUS_WIDTH_8_DDR         (6) /* Card is in 8 bit mode + DDR */
+
+/* high speed timing */
+#define EXT_CSD_HS_TIMEING_BACKWARDS    (0) /* selecting backwards compatibility interface timing */
+#define EXT_CSD_HS_TIMEING_HS           (1) /* selecting high speed  interface timing */
+#define EXT_CSD_HS_TIMEING_HS200        (2) /* selecting hs200 interface timing */
+#define EXT_CSD_HS_TIMEING_HS400        (3) /* selecting hs400 interface timing */
+
+/* ERASED_MEM_CONT[181] */
+#define EXT_CSD_ERASED_MEM_CONT_0       (0)
+#define EXT_CSD_ERASED_MEM_CONT_1       (1)
+
+/* PARTITION CONFIG[179] */
+#define EXT_CSD_PART_CFG_DEFT_PART      (0)
+#define EXT_CSD_PART_CFG_BOOT_PART_1    (1)
+#define EXT_CSD_PART_CFG_BOOT_PART_2    (2)
+#define EXT_CSD_PART_CFG_RPMB_PART      (3)
+#define EXT_CSD_PART_CFG_GP_PART_1      (4)
+#define EXT_CSD_PART_CFG_GP_PART_2      (5)
+#define EXT_CSD_PART_CFG_GP_PART_3      (6)
+#define EXT_CSD_PART_CFG_GP_PART_4      (7)
+#define EXT_CSD_PART_CFG_EN_NO_BOOT     (0 << 3)
+#define EXT_CSD_PART_CFG_EN_BOOT_PART_1 (1 << 3)
+#define EXT_CSD_PART_CFG_EN_BOOT_PART_2 (2 << 3)
+#define EXT_CSD_PART_CFG_EN_USER_AREA   (7 << 3)
+#define EXT_CSD_PART_CFG_EN_NO_ACK      (0 << 6)
+#define EXT_CSD_PART_CFG_EN_ACK         (1 << 6)
+
+/* BOOT_CONFIG_PROT[178] */
+#define EXT_CSD_EN_PWR_BOOT_CFG_PROT    (1)
+#define EXT_CSD_EN_PERM_BOOT_CFG_PROT   (1<<4)  /* Carefully */
+
+/* BOOT_BUS_WIDTH[177] */
+#define EXT_CSD_BOOT_BUS_WIDTH_1        (0)
+#define EXT_CSD_BOOT_BUS_WIDTH_4        (1)
+#define EXT_CSD_BOOT_BUS_WIDTH_8        (2)
+#define EXT_CSD_BOOT_BUS_RESET          (1 << 2)
+
+#define EXT_CSD_BOOT_BUS_MODE_DEFT      (0 << 3)
+#define EXT_CSD_BOOT_BUS_MODE_HS        (1 << 3)
+#define EXT_CSD_BOOT_BUS_MODE_DDR       (2 << 3)
+
+/* ERASE_GROUP_DEF[175] */
+#define EXT_CSD_ERASE_GRP_DEF_EN        (1)
+
+/* BOOT_WP[173] */
+#define EXT_CSD_BOOT_WP_EN_PWR_WP       (1)
+#define EXT_CSD_BOOT_WP_EN_PERM_WP      (1 << 2)
+#define EXT_CSD_BOOT_WP_DIS_PERM_WP     (1 << 4)
+#define EXT_CSD_BOOT_WP_DIS_PWR_WP      (1 << 6)
+
+/* USER_WP[171] */
+#define EXT_CSD_USR_WP_EN_PWR_WP        (1)
+#define EXT_CSD_USR_WP_EN_PERM_WP       (1<<2)
+#define EXT_CSD_USR_WP_DIS_PWR_WP       (1<<3)
+#define EXT_CSD_USR_WP_DIS_PERM_WP      (1<<4)
+#define EXT_CSD_USR_WP_DIS_CD_PERM_WP   (1<<6)
+#define EXT_CSD_USR_WP_DIS_PERM_PWD     (1<<7)
+
+/* RST_n_FUNCTION[162] */
+#define EXT_CSD_RST_N_TEMP_DIS          (0)
+#define EXT_CSD_RST_N_PERM_EN           (1) /* carefully */
+#define EXT_CSD_RST_N_PERM_DIS          (2) /* carefully */
+
+/* PARTITIONING_SUPPORT[160] */
+#define EXT_CSD_PART_SUPPORT_PART_EN     (1)
+#define EXT_CSD_PART_SUPPORT_ENH_ATTR_EN (1<<1)
+
+/* PARTITIONS_ATTRIBUTE[156] */
+#define EXT_CSD_PART_ATTR_ENH_USR       (1<<0)
+#define EXT_CSD_PART_ATTR_ENH_1         (1<<1)
+#define EXT_CSD_PART_ATTR_ENH_2         (1<<2)
+#define EXT_CSD_PART_ATTR_ENH_3         (1<<3)
+#define EXT_CSD_PART_ATTR_ENH_4         (1<<4)
+
+/* PARTITION_SETTING_COMPLETED[156] */
+#define EXT_CSD_PART_SET_COMPL_BIT      (1<<0)
+
+/*
+ * MMC_SWITCH access modes
+ */
+
+#define MMC_SWITCH_MODE_CMD_SET     0x00    /* Change the command set */
+#define MMC_SWITCH_MODE_SET_BITS    0x01    /* Set bits which are 1 in value */
+#define MMC_SWITCH_MODE_CLEAR_BITS  0x02    /* Clear bits which are 1 in value */
+#define MMC_SWITCH_MODE_WRITE_BYTE  0x03    /* Set target to value */
+
+#define MMC_SWITCH_MODE_SDR12       0
+#define MMC_SWITCH_MODE_SDR25       1
+#define MMC_SWITCH_MODE_SDR50       2
+#define MMC_SWITCH_MODE_SDR104      3
+#define MMC_SWITCH_MODE_DDR50       4
+
+#define MMC_SWITCH_MODE_DRV_TYPE_B  0
+#define MMC_SWITCH_MODE_DRV_TYPE_A  1
+#define MMC_SWITCH_MODE_DRV_TYPE_C  2
+#define MMC_SWITCH_MODE_DRV_TYPE_D  3
+
+#define MMC_SWITCH_MODE_CL_200MA    0
+#define MMC_SWITCH_MODE_CL_400MA    1
+#define MMC_SWITCH_MODE_CL_600MA    2
+#define MMC_SWITCH_MODE_CL_800MA    3
+
+/*
+ * MMC_ERASE arguments
+ */
+#define MMC_ERASE_SECURE_REQ        (1 << 31)
+#define MMC_ERASE_GC_REQ            (1 << 15)
+#define MMC_ERASE_DISCARD           (3 << 0)
+#define MMC_ERASE_TRIM              (1 << 0)
+#define MMC_ERASE_NORMAL            (0)
+
+#define HOST_BUS_WIDTH_1            (1)
+#define HOST_BUS_WIDTH_4            (4)
+#define HOST_BUS_WIDTH_8            (8)
+
+#define EMMC_BOOT_PULL_CMD_MODE     (0)
+#define EMMC_BOOT_RST_CMD_MODE      (1)
+
+enum {
+    EMMC_BOOT_PWR_RESET = 0,
+    EMMC_BOOT_RST_N_SIG,
+    EMMC_BOOT_PRE_IDLE_CMD
+};
+
+enum {
+    RESP_NONE = 0,
+    RESP_R1,
+    RESP_R2,
+    RESP_R3,
+    RESP_R4,
+    RESP_R5,
+    RESP_R6,
+    RESP_R7,
+    RESP_R1B
+};
+
+struct mmc_csd {
+    unsigned char  csd_struct;
+    unsigned char  mmca_vsn;
+    unsigned int   max_dtr;             /* max. data transfer rate */
+    unsigned int   read_blkbits;        /* max. read data block length */
+    unsigned int   capacity;            /* card capacity */
+};
+
+struct mmc_ext_csd {
+    unsigned int    sectors;
+    unsigned int    hs_max_dtr;
+    unsigned char   rev;
+    unsigned char   boot_info;
+    unsigned int    boot_part_sz;
+    unsigned int    rpmb_sz;
+    unsigned char   ddr_support;
+    unsigned char   hs400_support;
+    unsigned char   part_cfg;
+    unsigned char   sec_support;
+    unsigned char   reset_en;
+};
+
+#define MMC_CAP_4_BIT_DATA      (1 << 0) /* Can the host do 4 bit transfers */
+#define MMC_CAP_MULTIWRITE      (1 << 1) /* Can accurately report bytes sent to card on error */
+#define MMC_CAP_BYTEBLOCK       (1 << 2) /* Can do non-log2 block sizes */
+#define MMC_CAP_MMC_HIGHSPEED   (1 << 3) /* Can do MMC high-speed timing */
+#define MMC_CAP_SD_HIGHSPEED    (1 << 4) /* Can do SD high-speed timing */
+#define MMC_CAP_8_BIT_DATA      (1 << 5) /* Can the host do 8 bit transfers */
+#define MMC_CAP_SD_UHS1         (1 << 6) /* Can do SD ultra-high-speed timing */
+#define MMC_CAP_DDR             (1 << 7) /* The host support dual data rate */
+#define MMC_CAP_EMMC_HS200      (1 << 8) /* The host support dual data rate */
+#define MMC_CAP_EMMC_HS400      (1 << 9) /* The host support dual data rate */
+
+struct mmc_host {
+    u8 host_id;
+    struct mmc_card *card;
+    u32 max_phys_segs;
+    addr_t base;      /* host base address */
+    addr_t top_base;  /* host top pad address */
+    u32 caps;         /* Host capabilities */
+    u32 f_min;        /* host min. frequency */
+    u32 f_max;        /* host max. frequency */
+    u32 clk;          /* host clock speed */
+    u32 sclk;         /* SD/MS clock speed */
+    u32 blklen;       /* block len */
+    u32 ocr;          /* current ocr */
+    u32 ocr_avail;    /* available ocr */
+    u32 timeout_ns;   /* data timeout ns */
+    u32 timeout_clks; /* data timeout clks */
+    u8  clksrc;       /* clock source */
+    u8  hclksrc;       /* clock source */
+    u8  curr_part;    /* host current working partition */
+    u32 intr_mask;    /* Interrupt mask */
+    u32  time_read;
+    void *priv;       /* private data */
+    mutex_t lock;    /* mutex lock for multi-thread */
+    int (*blk_read)(struct mmc_host *host, u8 *dst, u32 src, u32 nblks);
+    int (*blk_write)(struct mmc_host *host, u32 dst, u8 *src, u32 nblks);
+};
+
+#define MMC_TYPE_UNKNOWN    (0)          /* Unknown card */
+#define MMC_TYPE_MMC        (0x00000001) /* MMC card */
+#define MMC_TYPE_SD         (0x00000002) /* SD card */
+#define MMC_TYPE_SDIO       (0x00000004) /* SDIO card */
+
+/* MMC device */
+struct mmc_card {
+    struct mmc_host        *host;       /* the host this device belongs to */
+    unsigned int            nblks;
+    unsigned int            blklen;
+    unsigned int            ocr;
+    unsigned int            maxhz;
+    unsigned int            uhs_mode;
+    unsigned int            rca;        /* relative card address of device */
+    unsigned int            type;       /* card type */
+    unsigned int            sdio_funcs; /* number of SDIO functions */
+    unsigned short          state;      /* (our) card state */
+    unsigned short          ready;      /* card is ready or not */
+    u32                     raw_csd[4]; /* raw card CSD */
+    struct mmc_csd          csd;        /* card specific */
+    struct mmc_ext_csd      ext_csd;    /* mmc v4 extended card specific */
+    u8                      version;    /* the SD card version, 1.0, 2.0, or 3.0*/
+};
+
+struct mmc_command {
+    u32 opcode;
+    u32 arg;
+    u32 rsptyp;
+    u32 resp[4];
+    u32 timeout;
+    u32 retries;    /* max number of retries */
+    u32 error;      /* command error */
+};
+
+struct mmc_data {
+    u8  *buf;
+    struct mmc_command *cmd;
+    u32  blks;
+    u32  timeout;   /* ms */
+};
+
+#define mmc_card_mmc(c)             ((c)->type & MMC_TYPE_MMC)
+#define mmc_card_sd(c)              ((c)->type & MMC_TYPE_SD)
+
+#define mmc_card_set_host(c,h)      ((c)->host = (h))
+#define mmc_card_set_unknown(c)     ((c)->type = MMC_TYPE_UNKNOWN)
+#define mmc_card_set_mmc(c)         ((c)->type |= MMC_TYPE_MMC)
+#define mmc_card_set_sd(c)          ((c)->type |= MMC_TYPE_SD)
+
+#define mmc_card_present(c)         ((c)->state & MMC_STATE_PRESENT)
+#define mmc_card_readonly(c)        ((c)->state & MMC_STATE_READONLY)
+#define mmc_card_backyard(c)        ((c)->state & MMC_STATE_BACKYARD)
+#define mmc_card_highspeed(c)       ((c)->state & MMC_STATE_HIGHSPEED)
+#define mmc_card_uhs1(c)            ((c)->state & MMC_STATE_UHS1)
+#define mmc_card_hs200(c)           ((c)->state & MMC_STATE_HS200)
+#define mmc_card_hs400(c)           ((c)->state & MMC_STATE_HS400)
+#define mmc_card_ddr(c)             ((c)->state & MMC_STATE_DDR)
+#define mmc_card_blockaddr(c)       ((c)->state & MMC_STATE_BLOCKADDR)
+#define mmc_card_highcaps(c)        ((c)->state & MMC_STATE_HIGHCAPS)
+
+#define mmc_card_set_present(c)     ((c)->state |= MMC_STATE_PRESENT)
+#define mmc_card_set_readonly(c)    ((c)->state |= MMC_STATE_READONLY)
+#define mmc_card_set_backyard(c)    ((c)->state |= MMC_STATE_BACKYARD)
+#define mmc_card_set_highspeed(c)   ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_set_uhs1(c)        ((c)->state |= MMC_STATE_UHS1)
+#define mmc_card_set_hs200(c)       ((c)->state |= MMC_STATE_HS200)
+#define mmc_card_set_hs400(c)       ((c)->state |= MMC_STATE_HS400)
+#define mmc_card_set_ddr(c)         ((c)->state |= MMC_STATE_DDR)
+#define mmc_card_set_blockaddr(c)   ((c)->state |= MMC_STATE_BLOCKADDR)
+
+#define mmc_card_clear_present(c)     ((c)->state &= ~MMC_STATE_PRESENT)
+#define mmc_card_clear_readonly(c)    ((c)->state &= ~MMC_STATE_READONLY)
+#define mmc_card_clear_highspeed(c)   ((c)->state &= ~MMC_STATE_HIGHSPEED)
+#define mmc_card_clear_uhs1(c)        ((c)->state &= ~MMC_STATE_UHS1)
+#define mmc_card_clear_hs200(c)       ((c)->state &= ~MMC_STATE_HS200)
+#define mmc_card_clear_hs400(c)       ((c)->state &= ~MMC_STATE_HS400)
+#define mmc_card_clear_ddr(c)         ((c)->state &= ~MMC_STATE_DDR)
+#define mmc_card_clear_blockaddr(c)   ((c)->state &= ~MMC_STATE_BLOCKADDR)
+
+#define mmc_card_clr_ddr(c)         ((c)->state &= ~MMC_STATE_DDR)
+#define mmc_card_clr_speed_mode(c)  ((c)->state &= ~(MMC_STATE_HS400 | MMC_STATE_HS200 | MMC_STATE_UHS1 | MMC_STATE_HIGHSPEED | MMC_STATE_BACKYARD))
+
+#define mmc_card_name(c)            ((c)->cid.prod_name)
+
+#define mmc_op_multi(op)    (((op) == MMC_CMD_READ_MULTIPLE_BLOCK) || \
+        ((op) == MMC_CMD_WRITE_MULTIPLE_BLOCK))
+
+struct mmc_card *emmc_init_stage1(bool *retry_opcond);
+int emmc_init_stage2(struct mmc_card *card, bool retry_opcond);
+int sdmmc_init(u8 host_id);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mmc_ioctl.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mmc_ioctl.h
new file mode 100644
index 0000000..6afd29b
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mmc_ioctl.h
@@ -0,0 +1,76 @@
+#ifndef LINUX_MMC_IOCTL_H
+#define LINUX_MMC_IOCTL_H
+
+#include <sys/types.h>
+#include "generic_ioctl.h"
+
+struct mmc_ioc_cmd {
+	/* Implies direction of data.  true = write, false = read */
+	int write_flag;
+
+	/* Application-specific command.  true = precede with CMD55 */
+	int is_acmd;
+
+	u32 opcode;
+	u32 arg;
+	u32 response[4];  /* CMD response */
+	unsigned int flags;
+	unsigned int blksz;
+	unsigned int blocks;
+
+	/*
+	 * Sleep at least postsleep_min_us useconds, and at most
+	 * postsleep_max_us useconds *after* issuing command.  Needed for
+	 * some read commands for which cards have no other way of indicating
+	 * they're ready for the next command (i.e. there is no equivalent of
+	 * a "busy" indicator for read operations).
+	 */
+	unsigned int postsleep_min_us;
+	unsigned int postsleep_max_us;
+
+	/*
+	 * Override driver-computed timeouts.  Note the difference in units!
+	 */
+	unsigned int data_timeout_ns;
+	unsigned int cmd_timeout_ms;
+
+	/*
+	 * For 64-bit machines, the next member, ``u64 data_ptr``, wants to
+	 * be 8-byte aligned.  Make sure this struct is the same size when
+	 * built for 32-bit.
+	 */
+	u32 __pad;
+
+	/* DAT buffer */
+	u64 data_ptr;
+};
+#define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (u64)(unsigned long) ptr
+
+/**
+ * struct mmc_ioc_multi_cmd - multi command information
+ * @num_of_cmds: Number of commands to send. Must be equal to or less than
+ *	MMC_IOC_MAX_CMDS.
+ * @cmds: Array of commands with length equal to 'num_of_cmds'
+ */
+struct mmc_ioc_multi_cmd {
+	u64 num_of_cmds;
+	struct mmc_ioc_cmd cmds[0];
+};
+
+#define MMC_BLOCK_MAJOR 179
+#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd)
+/*
+ * MMC_IOC_MULTI_CMD: Used to send an array of MMC commands described by
+ *	the structure mmc_ioc_multi_cmd. The MMC driver will issue all
+ *	commands in array in sequence to card.
+ */
+#define MMC_IOC_MULTI_CMD _IOWR(MMC_BLOCK_MAJOR, 1, struct mmc_ioc_multi_cmd)
+/*
+ * Since this ioctl is only meant to enhance (and not replace) normal access
+ * to the mmc bus device, an upper data transfer limit of MMC_IOC_MAX_BYTES
+ * is enforced per ioctl call.  For larger data transfers, use the normal
+ * block device operations.
+ */
+#define MMC_IOC_MAX_BYTES  (512L * 1024)
+#define MMC_IOC_MAX_CMDS    255
+#endif /* LINUX_MMC_IOCTL_H */
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mmc_rpmb.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mmc_rpmb.h
new file mode 100755
index 0000000..237dff7
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mmc_rpmb.h
@@ -0,0 +1,59 @@
+
+
+#ifndef _MMC_RPMB_H
+#define _MMC_RPMB_H
+
+#include "mmc_core.h"
+
+/* ==================================================================================
+
+   RPMB definition
+
+====================================================================================*/
+#define RPMB_SZ_STUFF 196
+#define RPMB_SZ_MAC   32
+#define RPMB_SZ_DATA  256
+#define RPMB_SZ_NONCE 16
+
+#define RPMB_PROGRAM_KEY       1       /* Program RPMB Authentication Key */
+#define RPMB_GET_WRITE_COUNTER 2       /* Read RPMB write counter */
+#define RPMB_WRITE_DATA        3       /* Write data to RPMB partition */
+#define RPMB_READ_DATA         4       /* Read data from RPMB partition */
+#define RPMB_RESULT_READ       5       /* Read result request */
+#define RPMB_REQ               1       /* RPMB request mark */
+#define RPMB_RESP              (1 << 1)/* RPMB response mark */
+#define RPMB_AVALIABLE_SECTORS 8       /* 4K page size */
+
+#define RPMB_TYPE_BEG          510
+#define RPMB_RES_BEG           508
+#define RPMB_BLKS_BEG          506
+#define RPMB_ADDR_BEG          504
+#define RPMB_WCOUNTER_BEG      500
+
+#define RPMB_NONCE_BEG         484
+#define RPMB_DATA_BEG          228
+#define RPMB_MAC_BEG           196
+
+struct mmc_rpmb_cfg {
+    u16 type;                     /* RPMB request type */
+    u16 result;                  /* response or request result */
+    u16 blk_cnt;                  /* Number of blocks(half sector 256B) */
+    u16 addr;                     /* data address */
+    u32 *wc;                      /* write counter */
+    u8 *nonce;                    /* Ramdom number */
+    u8 *data;                     /* Buffer of the user data */
+    u8 *mac;                      /* Message Authentication Code */
+};
+
+struct mmc_rpmb_req {
+    struct mmc_rpmb_cfg *rpmb_cfg;
+    u8 *data_frame;
+};
+
+extern int mmc_rpmb_set_key(u8 *key);
+extern u32 mmc_rpmb_get_size(void);
+extern u32 mmc_rpmb_get_rel_wr_sec_c(void);
+
+extern int mmc_rpmb_block_read(int blknr, unsigned char blk[256]);
+extern int mmc_rpmb_block_write(int blknr, unsigned char blk[256]);
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/msdc.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/msdc.h
new file mode 100644
index 0000000..3f06a26
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/msdc.h
@@ -0,0 +1,1149 @@
+/*
+ * 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
+
+#include <reg.h>
+#include <platform/msdc_cfg.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mmc_core.h>
+
+/*--------------------------------------------------------------------------*/
+/* Common Macro                                                             */
+/*--------------------------------------------------------------------------*/
+#define REG_ADDR(x)             ((volatile uint32_t *)(uintptr_t)(base + OFFSET_##x))
+#define REG_TOP_ADDR(x)         ((volatile uint32_t *)(uintptr_t)(host->top_base + OFFSET_##x))
+
+/*--------------------------------------------------------------------------*/
+/* Common Definition                                                        */
+/*--------------------------------------------------------------------------*/
+#define MSDC_FIFO_SZ            (128)
+#define MSDC_FIFO_THD           (128)
+//#define MSDC_MAX_NUM            (2)
+
+#define MSDC_MS                 (0)
+#define MSDC_SDMMC              (1)
+
+#define MSDC_MODE_UNKNOWN       (0)
+#define MSDC_MODE_PIO           (1)
+#define MSDC_MODE_DMA_BASIC     (2)
+#define MSDC_MODE_DMA_DESC      (3)
+#define MSDC_MODE_DMA_ENHANCED  (4)
+#define MSDC_MODE_MMC_STREAM    (5)
+
+#define MSDC_BUS_1BITS          (0)
+#define MSDC_BUS_4BITS          (1)
+#define MSDC_BUS_8BITS          (2)
+
+#define MSDC_BURST_8B           (3)
+#define MSDC_BURST_16B          (4)
+#define MSDC_BURST_32B          (5)
+#define MSDC_BURST_64B          (6)
+
+#define MSDC_PIN_PULL_NONE      (0)
+#define MSDC_PIN_PULL_DOWN      (1)
+#define MSDC_PIN_PULL_UP        (2)
+#define MSDC_PIN_KEEP           (3)
+
+#ifdef FPGA_PLATFORM
+#define MSDC_OP_SCLK            (12000000)
+#define MSDC_MAX_SCLK           MSDC_OP_SCLK / 2
+#else
+#define MSDC_OP_SCLK            (200000000)
+#define MSDC_MAX_SCLK           (200000000)
+#endif
+
+#define MSDC_MIN_SCLK           (260000)
+
+#define MSDC_350K_SCLK          (350000)
+#define MSDC_400K_SCLK          (400000)
+#define MSDC_25M_SCLK           (25000000)
+#define MSDC_26M_SCLK           (26000000)
+#define MSDC_50M_SCLK           (50000000)
+#define MSDC_52M_SCLK           (52000000)
+#define MSDC_100M_SCLK          (100000000)
+#define MSDC_179M_SCLK          (179000000)
+#define MSDC_200M_SCLK          (200000000)
+#define MSDC_208M_SCLK          (208000000)
+#define MSDC_400M_SCLK          (400000000)
+#define MSDC_800M_SCLK          (800000000)
+
+#define MSDC_AUTOCMD12          (0x0001)
+#define MSDC_AUTOCMD23          (0x0002)
+#define MSDC_AUTOCMD19          (0x0003)
+
+#define TYPE_CMD_RESP_EDGE      (0)
+#define TYPE_WRITE_CRC_EDGE     (1)
+#define TYPE_READ_DATA_EDGE     (2)
+#define TYPE_WRITE_DATA_EDGE    (3)
+
+#define START_AT_RISING                 (0x0)
+#define START_AT_FALLING                (0x1)
+#define START_AT_RISING_AND_FALLING     (0x2)
+#define START_AT_RISING_OR_FALLING      (0x3)
+
+#define MSDC_DMA_BURST_8B       (3)
+#define MSDC_DMA_BURST_16B      (4)
+#define MSDC_DMA_BURST_32B      (5)
+#define MSDC_DMA_BURST_64B      (6)
+
+/*--------------------------------------------------------------------------*/
+/* Register Offset                                                          */
+/*--------------------------------------------------------------------------*/
+#define OFFSET_MSDC_CFG                  (0x00)
+#define OFFSET_MSDC_IOCON                (0x04)
+#define OFFSET_MSDC_PS                   (0x08)
+#define OFFSET_MSDC_INT                  (0x0c)
+#define OFFSET_MSDC_INTEN                (0x10)
+#define OFFSET_MSDC_FIFOCS               (0x14)
+#define OFFSET_MSDC_TXDATA               (0x18)
+#define OFFSET_MSDC_RXDATA               (0x1c)
+#define OFFSET_SDC_CFG                   (0x30)
+#define OFFSET_SDC_CMD                   (0x34)
+#define OFFSET_SDC_ARG                   (0x38)
+#define OFFSET_SDC_STS                   (0x3c)
+#define OFFSET_SDC_RESP0                 (0x40)
+#define OFFSET_SDC_RESP1                 (0x44)
+#define OFFSET_SDC_RESP2                 (0x48)
+#define OFFSET_SDC_RESP3                 (0x4c)
+#define OFFSET_SDC_BLK_NUM               (0x50)
+#define OFFSET_SDC_VOL_CHG               (0x54)
+#define OFFSET_SDC_CSTS                  (0x58)
+#define OFFSET_SDC_CSTS_EN               (0x5c)
+#define OFFSET_SDC_DCRC_STS              (0x60)
+#define OFFSET_SDC_AVG_CFG0              (0x64)
+
+/* Only for EMMC Controller 4 registers below */
+#define OFFSET_EMMC_CFG0                 (0x70)
+#define OFFSET_EMMC_CFG1                 (0x74)
+#define OFFSET_EMMC_STS                  (0x78)
+#define OFFSET_EMMC_IOCON                (0x7c)
+
+#define OFFSET_SDC_ACMD_RESP             (0x80)
+#define OFFSET_SDC_ACMD19_TRG            (0x84)
+#define OFFSET_SDC_ACMD19_STS            (0x88)
+#define OFFSET_MSDC_DMA_HIGH4BIT         (0x8C)
+#define OFFSET_MSDC_DMA_SA               (0x90)
+#define OFFSET_MSDC_DMA_CA               (0x94)
+#define OFFSET_MSDC_DMA_CTRL             (0x98)
+#define OFFSET_MSDC_DMA_CFG              (0x9c)
+#define OFFSET_MSDC_DBG_SEL              (0xa0)
+#define OFFSET_MSDC_DBG_OUT              (0xa4)
+#define OFFSET_MSDC_DMA_LEN              (0xa8)
+#define OFFSET_MSDC_PATCH_BIT0           (0xb0)
+#define OFFSET_MSDC_PATCH_BIT1           (0xb4)
+#define OFFSET_MSDC_PATCH_BIT2           (0xb8)
+
+/* Only for SD/SDIO Controller 6 registers below */
+#define OFFSET_DAT0_TUNE_CRC             (0xc0)
+#define OFFSET_DAT1_TUNE_CRC             (0xc4)
+#define OFFSET_DAT2_TUNE_CRC             (0xc8)
+#define OFFSET_DAT3_TUNE_CRC             (0xcc)
+#define OFFSET_CMD_TUNE_CRC              (0xd0)
+#define OFFSET_SDIO_TUNE_WIND            (0xd4)
+
+#define OFFSET_MSDC_PAD_TUNE             (0xF0)
+#define OFFSET_MSDC_PAD_TUNE0            (0xF0)
+
+#define OFFSET_MSDC_DAT_RDDLY2           (0x100)
+#define OFFSET_MSDC_DAT_RDDLY3           (0x104)
+
+#define OFFSET_MSDC_HW_DBG               (0x110)
+#define OFFSET_MSDC_VERSION              (0x114)
+#define OFFSET_MSDC_ECO_VER              (0x118)
+
+/* Only for EMMC 5.0 Controller 4 registers below */
+#define OFFSET_EMMC50_CFG0               (0x208)
+#define OFFSET_EMMC50_CFG1               (0x20c)
+#define OFFSET_EMMC50_CFG2               (0x21c)
+#define OFFSET_EMMC50_CFG3               (0x220)
+#define OFFSET_EMMC50_CFG4               (0x224)
+#define OFFSET_SDC_FIFO_CFG              (0x228)
+
+/* TOP registers */
+#define OFFSET_EMMC_TOP_CONTROL		 (0x0)
+#define OFFSET_EMMC_TOP_CMD		 (0x04)
+#define OFFSET_EMMC50_PAD_CTL0		 (0x08)
+#define OFFSET_EMMC50_PAD_DS_TUNE	 (0x0C)
+
+/* EMMC_TOP_CONTROL mask */
+#define PAD_RXDLY_SEL           (0x1 << 0)      /* RW */
+#define DELAY_EN                (0x1 << 1)      /* RW */
+#define PAD_DAT_RD_RXDLY2       (0x1F << 2)     /* RW */
+#define PAD_DAT_RD_RXDLY        (0x1F << 7)     /* RW */
+#define PAD_DAT_RD_RXDLY2_SEL   (0x1 << 12)     /* RW */
+#define PAD_DAT_RD_RXDLY_SEL    (0x1 << 13)     /* RW */
+#define DATA_K_VALUE_SEL        (0x1 << 14)     /* RW */
+#define SDC_RX_ENHANCE_EN       (0x1 << 15)     /* RW */
+
+/* EMMC_TOP_CMD mask */
+#define PAD_CMD_RXDLY2          (0x1F << 0)     /* RW */
+#define PAD_CMD_RXDLY           (0x1F << 5)     /* RW */
+#define PAD_CMD_RD_RXDLY2_SEL   (0x1 << 10)     /* RW */
+#define PAD_CMD_RD_RXDLY_SEL    (0x1 << 11)     /* RW */
+#define PAD_CMD_TX_DLY          (0x1F << 12)    /* RW */
+
+/* TOP_EMMC50_PAD_CTL0 mask */
+#define HL_SEL                  (0x1 << 0)      /* RW */
+#define DCC_SEL                 (0x1 << 1)      /* RW */
+#define DLN1                    (0x3 << 2)      /* RW */
+#define DLN0                    (0x3 << 4)      /* RW */
+#define DLP1                    (0x3 << 6)      /* RW */
+#define DLP0                    (0x3 << 8)      /* RW */
+#define PAD_CLK_TXDLY           (0x1F << 10)    /* RW */
+
+/* TOP_EMMC50_PAD_DS_TUNE mask */
+#define PAD_DS_DLY3             (0x1F << 0)     /* RW */
+#define PAD_DS_DLY2             (0x1F << 5)     /* RW */
+#define PAD_DS_DLY1             (0x1F << 10)    /* RW */
+#define PAD_DS_DLY2_SEL         (0x1 << 15)     /* RW */
+#define PAD_DS_DLY_SEL          (0x1 << 16)     /* RW */
+
+
+/*--------------------------------------------------------------------------*/
+/* Register Address                                                         */
+/*--------------------------------------------------------------------------*/
+/* common register */
+#define MSDC_CFG                         REG_ADDR(MSDC_CFG)
+#define MSDC_IOCON                       REG_ADDR(MSDC_IOCON)
+#define MSDC_PS                          REG_ADDR(MSDC_PS)
+#define MSDC_INT                         REG_ADDR(MSDC_INT)
+#define MSDC_INTEN                       REG_ADDR(MSDC_INTEN)
+#define MSDC_FIFOCS                      REG_ADDR(MSDC_FIFOCS)
+#define MSDC_TXDATA                      REG_ADDR(MSDC_TXDATA)
+#define MSDC_RXDATA                      REG_ADDR(MSDC_RXDATA)
+
+/* sdmmc register */
+#define SDC_CFG                          REG_ADDR(SDC_CFG)
+#define SDC_CMD                          REG_ADDR(SDC_CMD)
+#define SDC_ARG                          REG_ADDR(SDC_ARG)
+#define SDC_STS                          REG_ADDR(SDC_STS)
+#define SDC_RESP0                        REG_ADDR(SDC_RESP0)
+#define SDC_RESP1                        REG_ADDR(SDC_RESP1)
+#define SDC_RESP2                        REG_ADDR(SDC_RESP2)
+#define SDC_RESP3                        REG_ADDR(SDC_RESP3)
+#define SDC_BLK_NUM                      REG_ADDR(SDC_BLK_NUM)
+#define SDC_VOL_CHG                      REG_ADDR(SDC_VOL_CHG)
+#define SDC_CSTS                         REG_ADDR(SDC_CSTS)
+#define SDC_CSTS_EN                      REG_ADDR(SDC_CSTS_EN)
+#define SDC_DCRC_STS                     REG_ADDR(SDC_DCRC_STS)
+#define SDC_AVG_CFG0                     REG_ADDR(SDC_AVG_CFG0)
+
+/* emmc register*/
+#define EMMC_CFG0                        REG_ADDR(EMMC_CFG0)
+#define EMMC_CFG1                        REG_ADDR(EMMC_CFG1)
+#define EMMC_STS                         REG_ADDR(EMMC_STS)
+#define EMMC_IOCON                       REG_ADDR(EMMC_IOCON)
+
+/* auto command register */
+#define SDC_ACMD_RESP                    REG_ADDR(SDC_ACMD_RESP)
+#define SDC_ACMD19_TRG                   REG_ADDR(SDC_ACMD19_TRG)
+#define SDC_ACMD19_STS                   REG_ADDR(SDC_ACMD19_STS)
+
+/* dma register */
+#define MSDC_DMA_HIGH4BIT                REG_ADDR(MSDC_DMA_HIGH4BIT)
+#define MSDC_DMA_SA                      REG_ADDR(MSDC_DMA_SA)
+#define MSDC_DMA_CA                      REG_ADDR(MSDC_DMA_CA)
+#define MSDC_DMA_CTRL                    REG_ADDR(MSDC_DMA_CTRL)
+#define MSDC_DMA_CFG                     REG_ADDR(MSDC_DMA_CFG)
+
+/* debug register */
+#define MSDC_DBG_SEL                     REG_ADDR(MSDC_DBG_SEL)
+#define MSDC_DBG_OUT                     REG_ADDR(MSDC_DBG_OUT)
+#define MSDC_DMA_LEN                     REG_ADDR(MSDC_DMA_LEN)
+
+/* misc register */
+#define MSDC_PATCH_BIT0                  REG_ADDR(MSDC_PATCH_BIT0)
+#define MSDC_PATCH_BIT1                  REG_ADDR(MSDC_PATCH_BIT1)
+#define MSDC_PATCH_BIT2                  REG_ADDR(MSDC_PATCH_BIT2)
+#define DAT0_TUNE_CRC                    REG_ADDR(DAT0_TUNE_CRC)
+#define DAT1_TUNE_CRC                    REG_ADDR(DAT1_TUNE_CRC)
+#define DAT2_TUNE_CRC                    REG_ADDR(DAT2_TUNE_CRC)
+#define DAT3_TUNE_CRC                    REG_ADDR(DAT3_TUNE_CRC)
+#define CMD_TUNE_CRC                     REG_ADDR(CMD_TUNE_CRC)
+#define SDIO_TUNE_WIND                   REG_ADDR(SDIO_TUNE_WIND)
+#define MSDC_PAD_TUNE                    REG_ADDR(MSDC_PAD_TUNE)
+#define MSDC_PAD_TUNE0                   REG_ADDR(MSDC_PAD_TUNE0)
+#define MSDC_PAD_TUNE1                   REG_ADDR(MSDC_PAD_TUNE1)
+
+/* data read delay */
+#define MSDC_DAT_RDDLY0                  REG_ADDR(MSDC_DAT_RDDLY0)
+#define MSDC_DAT_RDDLY1                  REG_ADDR(MSDC_DAT_RDDLY1)
+#define MSDC_DAT_RDDLY2                  REG_ADDR(MSDC_DAT_RDDLY2)
+#define MSDC_DAT_RDDLY3                  REG_ADDR(MSDC_DAT_RDDLY3)
+
+#define MSDC_HW_DBG                      REG_ADDR(MSDC_HW_DBG)
+#define MSDC_VERSION                     REG_ADDR(MSDC_VERSION)
+#define MSDC_ECO_VER                     REG_ADDR(MSDC_ECO_VER)
+/* eMMC 5.0 register */
+#define EMMC50_CFG0                      REG_ADDR(EMMC50_CFG0)
+#define EMMC50_CFG1                      REG_ADDR(EMMC50_CFG1)
+#define EMMC50_CFG2                      REG_ADDR(EMMC50_CFG2)
+#define EMMC50_CFG3                      REG_ADDR(EMMC50_CFG3)
+#define EMMC50_CFG4                      REG_ADDR(EMMC50_CFG4)
+#define SDC_FIFO_CFG                     REG_ADDR(SDC_FIFO_CFG)
+
+#define EMMC_TOP_CONTROL		 REG_TOP_ADDR(EMMC_TOP_CONTROL)
+#define EMMC_TOP_CMD			 REG_TOP_ADDR(EMMC_TOP_CMD)
+#define EMMC50_PAD_CTL0			 REG_TOP_ADDR(EMMC50_PAD_CTL0)
+#define EMMC50_PAD_DS_TUNE		 REG_TOP_ADDR(EMMC50_PAD_DS_TUNE)
+/*--------------------------------------------------------------------------*/
+/* Register Mask                                                            */
+/*--------------------------------------------------------------------------*/
+
+/* MSDC_CFG mask */
+#define MSDC_CFG_MODE           (0x1   <<  0)     /* RW */
+#define MSDC_CFG_CKPDN          (0x1   <<  1)     /* RW */
+#define MSDC_CFG_RST            (0x1   <<  2)     /* A0 */
+#define MSDC_CFG_PIO            (0x1   <<  3)     /* RW */
+#define MSDC_CFG_CKDRVEN        (0x1   <<  4)     /* RW */
+#define MSDC_CFG_BV18SDT        (0x1   <<  5)     /* RW */
+#define MSDC_CFG_BV18PSS        (0x1   <<  6)     /* R  */
+#define MSDC_CFG_CKSTB          (0x1   <<  7)     /* R  */
+#define MSDC_CFG_CKDIV          (0xFFF <<  8)     /* RW   !!! MT2701 change 0xFF ->0xFFF*/
+#define MSDC_CFG_CKMOD          (0x3   << 20)     /* W1C  !!! MT2701 change 16 ->21 only for eMCC 5.0*/
+#define MSDC_CFG_CKMOD_HS400    (0x1   << 22)     /* RW   !!! MT2701 change 18 ->22 only for eMCC 5.0*/
+#define MSDC_CFG_START_BIT      (0x3   << 23)     /* RW   !!! MT2701 change 19 ->23 only for eMCC 5.0*/
+#define MSDC_CFG_SCLK_STOP_DDR  (0x1   << 25)     /* RW   !!! MT2701 change 21 ->25 */
+
+/* MSDC_IOCON mask */
+#define MSDC_IOCON_SDR104CKS    (0x1   <<  0)     /* RW */
+#define MSDC_IOCON_RSPL         (0x1   <<  1)     /* RW */
+#define MSDC_IOCON_R_D_SMPL     (0x1   <<  2)     /* RW */
+#define MSDC_IOCON_DSPL          MSDC_IOCON_R_D_SMPL /* alias */
+
+#define MSDC_IOCON_DDLSEL       (0x1   <<  3)     /* RW */
+#define MSDC_IOCON_DDR50CKD     (0x1   <<  4)     /* RW */
+#define MSDC_IOCON_R_D_SMPL_SEL (0x1   <<  5)     /* RW */
+#define MSDC_IOCON_W_D_SMPL     (0x1   <<  8)     /* RW */
+#define MSDC_IOCON_W_D_SMPL_SEL (0x1   <<  9)     /* RW */
+#define MSDC_IOCON_W_D0SPL      (0x1   << 10)     /* RW */
+#define MSDC_IOCON_W_D1SPL      (0x1   << 11)     /* RW */
+#define MSDC_IOCON_W_D2SPL      (0x1   << 12)     /* RW */
+#define MSDC_IOCON_W_D3SPL      (0x1   << 13)     /* RW */
+
+#define MSDC_IOCON_R_D0SPL      (0x1   << 16)     /* RW */
+#define MSDC_IOCON_R_D1SPL      (0x1   << 17)     /* RW */
+#define MSDC_IOCON_R_D2SPL      (0x1   << 18)     /* RW */
+#define MSDC_IOCON_R_D3SPL      (0x1   << 19)     /* RW */
+#define MSDC_IOCON_R_D4SPL      (0x1   << 20)     /* RW */
+#define MSDC_IOCON_R_D5SPL      (0x1   << 21)     /* RW */
+#define MSDC_IOCON_R_D6SPL      (0x1   << 22)     /* RW */
+#define MSDC_IOCON_R_D7SPL      (0x1   << 23)     /* RW */
+//#define MSDC_IOCON_RISCSZ       (0x3   << 24)     /* RW  !!! MT2701  remove*/
+
+/* MSDC_PS mask */
+#define MSDC_PS_CDEN            (0x1   <<  0)     /* RW */
+#define MSDC_PS_CDSTS           (0x1   <<  1)     /* RU  */
+
+#define MSDC_PS_CDDEBOUNCE      (0xF   << 12)     /* RW */
+#define MSDC_PS_DAT             (0xFF  << 16)     /* RU */
+#define MSDC_PS_DAT8PIN         (0xFF  << 16)     /* RU */
+#define MSDC_PS_DAT4PIN         (0xF   << 16)     /* RU */
+#define MSDC_PS_DAT0            (0x1   << 16)     /* RU */
+
+#define MSDC_PS_CMD             (0x1   << 24)     /* RU */
+
+#define MSDC_PS_WP              (0x1   << 31)     /* RU  */
+
+/* MSDC_INT mask */
+#define MSDC_INT_MMCIRQ         (0x1   <<  0)     /* W1C */
+#define MSDC_INT_CDSC           (0x1   <<  1)     /* W1C */
+
+#define MSDC_INT_ACMDRDY        (0x1   <<  3)     /* W1C */
+#define MSDC_INT_ACMDTMO        (0x1   <<  4)     /* W1C */
+#define MSDC_INT_ACMDCRCERR     (0x1   <<  5)     /* W1C */
+#define MSDC_INT_DMAQ_EMPTY     (0x1   <<  6)     /* W1C */
+#define MSDC_INT_SDIOIRQ        (0x1   <<  7)     /* W1C Only for SD/SDIO */
+#define MSDC_INT_CMDRDY         (0x1   <<  8)     /* W1C */
+#define MSDC_INT_CMDTMO         (0x1   <<  9)     /* W1C */
+#define MSDC_INT_RSPCRCERR      (0x1   << 10)     /* W1C */
+#define MSDC_INT_CSTA           (0x1   << 11)     /* R */
+#define MSDC_INT_XFER_COMPL     (0x1   << 12)     /* W1C */
+#define MSDC_INT_DXFER_DONE     (0x1   << 13)     /* W1C */
+#define MSDC_INT_DATTMO         (0x1   << 14)     /* W1C */
+#define MSDC_INT_DATCRCERR      (0x1   << 15)     /* W1C */
+#define MSDC_INT_ACMD19_DONE    (0x1   << 16)     /* W1C */
+#define MSDC_INT_BDCSERR        (0x1   << 17)     /* W1C */
+#define MSDC_INT_GPDCSERR       (0x1   << 18)     /* W1C */
+#define MSDC_INT_DMAPRO         (0x1   << 19)     /* W1C */
+#define MSDC_INT_GOBOUND        (0x1   << 20)     /* W1C Only for SD/SDIO ACMD 53*/
+#define MSDC_INT_ACMD53_DONE    (0x1   << 21)     /* W1C Only for SD/SDIO ACMD 53*/
+#define MSDC_INT_ACMD53_FAIL    (0x1   << 22)     /* W1C Only for SD/SDIO ACMD 53*/
+#define MSDC_INT_AXI_RESP_ERR   (0x1   << 23)     /* W1C Only for eMMC 5.0*/
+
+/* MSDC_INTEN mask */
+#define MSDC_INTEN_MMCIRQ       (0x1   <<  0)     /* RW */
+#define MSDC_INTEN_CDSC         (0x1   <<  1)     /* RW */
+
+#define MSDC_INTEN_ACMDRDY      (0x1   <<  3)     /* RW */
+#define MSDC_INTEN_ACMDTMO      (0x1   <<  4)     /* RW */
+#define MSDC_INTEN_ACMDCRCERR   (0x1   <<  5)     /* RW */
+#define MSDC_INTEN_DMAQ_EMPTY   (0x1   <<  6)     /* RW */
+#define MSDC_INTEN_SDIOIRQ      (0x1   <<  7)     /* RW Only for SDIO*/
+#define MSDC_INTEN_CMDRDY       (0x1   <<  8)     /* RW */
+#define MSDC_INTEN_CMDTMO       (0x1   <<  9)     /* RW */
+#define MSDC_INTEN_RSPCRCERR    (0x1   << 10)     /* RW */
+#define MSDC_INTEN_CSTA         (0x1   << 11)     /* RW */
+#define MSDC_INTEN_XFER_COMPL   (0x1   << 12)     /* RW */
+#define MSDC_INTEN_DXFER_DONE   (0x1   << 13)     /* RW */
+#define MSDC_INTEN_DATTMO       (0x1   << 14)     /* RW */
+#define MSDC_INTEN_DATCRCERR    (0x1   << 15)     /* RW */
+#define MSDC_INTEN_ACMD19_DONE  (0x1   << 16)     /* RW */
+#define MSDC_INTEN_BDCSERR      (0x1   << 17)     /* RW */
+#define MSDC_INTEN_GPDCSERR     (0x1   << 18)     /* RW */
+#define MSDC_INTEN_DMAPRO       (0x1   << 19)     /* RW */
+#define MSDC_INTEN_GOBOUND      (0x1   << 20)     /* RW  Only for SD/SDIO ACMD 53*/
+#define MSDC_INTEN_ACMD53_DONE  (0x1   << 21)     /* RW  Only for SD/SDIO ACMD 53*/
+#define MSDC_INTEN_ACMD53_FAIL  (0x1   << 22)     /* RW  Only for SD/SDIO ACMD 53*/
+#define MSDC_INTEN_AXI_RESP_ERR (0x1   << 23)     /* RW  Only for eMMC 5.0*/
+
+#define MSDC_INTEN_DFT       (  MSDC_INTEN_MMCIRQ        |MSDC_INTEN_CDSC        | MSDC_INTEN_ACMDRDY\
+                                |MSDC_INTEN_ACMDTMO      |MSDC_INTEN_ACMDCRCERR  | MSDC_INTEN_DMAQ_EMPTY /*|MSDC_INTEN_SDIOIRQ*/\
+                                |MSDC_INTEN_CMDRDY       |MSDC_INTEN_CMDTMO      | MSDC_INTEN_RSPCRCERR   |MSDC_INTEN_CSTA\
+                                |MSDC_INTEN_XFER_COMPL   |MSDC_INTEN_DXFER_DONE  | MSDC_INTEN_DATTMO      |MSDC_INTEN_DATCRCERR\
+                                |MSDC_INTEN_BDCSERR      |MSDC_INTEN_ACMD19_DONE | MSDC_INTEN_GPDCSERR     /*|MSDC_INTEN_DMAPRO*/\
+                                /*|MSDC_INTEN_GOBOUND   |MSDC_INTEN_ACMD53_DONE |MSDC_INTEN_ACMD53_FAIL |MSDC_INTEN_AXI_RESP_ERR*/)
+
+
+/* MSDC_FIFOCS mask */
+#define MSDC_FIFOCS_RXCNT       (0xFF  <<  0)     /* R */
+#define MSDC_FIFOCS_TXCNT       (0xFF  << 16)     /* R */
+#define MSDC_FIFOCS_CLR         (0x1   << 31)     /* RW */
+
+/* SDC_CFG mask */
+#define SDC_CFG_SDIOINTWKUP     (0x1   <<  0)     /* RW */
+#define SDC_CFG_INSWKUP         (0x1   <<  1)     /* RW */
+#define SDC_CFG_BUSWIDTH        (0x3   << 16)     /* RW */
+#define SDC_CFG_SDIO            (0x1   << 19)     /* RW */
+#define SDC_CFG_SDIOIDE         (0x1   << 20)     /* RW */
+#define SDC_CFG_INTATGAP        (0x1   << 21)     /* RW */
+#define SDC_CFG_DTOC            (0xFF  << 24)     /* RW */
+
+/* SDC_CMD mask */
+#define SDC_CMD_OPC             (0x3F  <<  0)     /* RW */
+#define SDC_CMD_BRK             (0x1   <<  6)     /* RW */
+#define SDC_CMD_RSPTYP          (0x7   <<  7)     /* RW */
+#define SDC_CMD_DTYP            (0x3   << 11)     /* RW */
+#define SDC_CMD_RW              (0x1   << 13)     /* RW */
+#define SDC_CMD_STOP            (0x1   << 14)     /* RW */
+#define SDC_CMD_GOIRQ           (0x1   << 15)     /* RW */
+#define SDC_CMD_BLKLEN          (0xFFF << 16)     /* RW */
+#define SDC_CMD_AUTOCMD         (0x3   << 28)     /* RW */
+#define SDC_CMD_VOLSWTH         (0x1   << 30)     /* RW */
+#define SDC_CMD_ACMD53          (0x1   << 31)     /* RW Only for SD/SDIO ACMD 53*/
+
+/* SDC_STS mask */
+#define SDC_STS_SDCBUSY         (0x1   <<  0)     /* RW */
+#define SDC_STS_CMDBUSY         (0x1   <<  1)     /* RW */
+#define SDC_STS_CMD_WR_BUSY     (0x1   << 16)     /* RW !!! MT2701  Add*/
+#define SDC_STS_SWR_COMPL       (0x1   << 31)     /* RW */
+
+/* SDC_VOL_CHG mask */
+#define SDC_VOL_CHG_VCHGCNT     (0xFFFF<<  0)     /* RW  !!! MT2701  Add*/
+/* SDC_DCRC_STS mask */
+#define SDC_DCRC_STS_POS        (0xFF  <<  0)     /* RO */
+#define SDC_DCRC_STS_NEG        (0xFF  <<  8)     /* RO */
+/* SDC_ADV_CFG0 mask */
+/* EMMC_CFG0 mask */
+#define EMMC_CFG0_BOOTSTART     (0x1   <<  0)     /* WO Only for eMMC */
+#define EMMC_CFG0_BOOTSTOP      (0x1   <<  1)     /* WO Only for eMMC */
+#define EMMC_CFG0_BOOTMODE      (0x1   <<  2)     /* RW Only for eMMC */
+#define EMMC_CFG0_BOOTACKDIS    (0x1   <<  3)     /* RW Only for eMMC */
+
+#define EMMC_CFG0_BOOTWDLY      (0x7   << 12)     /* RW Only for eMMC */
+#define EMMC_CFG0_BOOTSUPP      (0x1   << 15)     /* RW Only for eMMC */
+
+/* EMMC_CFG1 mask */
+#define EMMC_CFG1_BOOTDATTMC   (0xFFFFF<<  0)     /* RW Only for eMMC */
+#define EMMC_CFG1_BOOTACKTMC    (0xFFF << 20)     /* RW Only for eMMC */
+
+/* EMMC_STS mask */
+#define EMMC_STS_BOOTCRCERR     (0x1   <<  0)     /* W1C Only for eMMC */
+#define EMMC_STS_BOOTACKERR     (0x1   <<  1)     /* W1C Only for eMMC */
+#define EMMC_STS_BOOTDATTMO     (0x1   <<  2)     /* W1C Only for eMMC */
+#define EMMC_STS_BOOTACKTMO     (0x1   <<  3)     /* W1C Only for eMMC */
+#define EMMC_STS_BOOTUPSTATE    (0x1   <<  4)     /* RU Only for eMMC */
+#define EMMC_STS_BOOTACKRCV     (0x1   <<  5)     /* W1C Only for eMMC */
+#define EMMC_STS_BOOTDATRCV     (0x1   <<  6)     /* RU Only for eMMC */
+
+/* EMMC_IOCON mask */
+#define EMMC_IOCON_BOOTRST      (0x1   <<  0)     /* RW Only for eMMC */
+
+/* SDC_ACMD19_TRG mask */
+#define SDC_ACMD19_TRG_TUNESEL  (0xF   <<  0)     /* RW */
+
+/* DMA_SA_HIGH4BIT mask */
+#define DMA_SA_HIGH4BIT_L4BITS  (0xF   <<  0)     /* RW  !!! MT2701  Add*/
+/* MSDC_DMA_CTRL mask */
+#define MSDC_DMA_CTRL_START     (0x1   <<  0)     /* WO */
+#define MSDC_DMA_CTRL_STOP      (0x1   <<  1)     /* AO */
+#define MSDC_DMA_CTRL_RESUME    (0x1   <<  2)     /* WO */
+#define MSDC_DMA_CTRL_READYM    (0x1   <<  3)     /* RO  !!! MT2701  Add*/
+
+#define MSDC_DMA_CTRL_MODE      (0x1   <<  8)     /* RW */
+#define MSDC_DMA_CTRL_ALIGN     (0x1   <<  9)     /* RW !!! MT2701  Add*/
+#define MSDC_DMA_CTRL_LASTBUF   (0x1   << 10)     /* RW */
+#define MSDC_DMA_CTRL_SPLIT1K   (0x1   << 11)     /* RW !!! MT2701  Add*/
+#define MSDC_DMA_CTRL_BURSTSZ   (0x7   << 12)     /* RW */
+// #define MSDC_DMA_CTRL_XFERSZ    (0xffffUL << 16)/* RW */
+
+/* MSDC_DMA_CFG mask */
+#define MSDC_DMA_CFG_STS              (0x1  <<  0)     /* R */
+#define MSDC_DMA_CFG_DECSEN           (0x1  <<  1)     /* RW */
+#define MSDC_DMA_CFG_LOCKDISABLE      (0x1  <<  2)     /* RW !!! MT2701  Add*/
+//#define MSDC_DMA_CFG_BDCSERR        (0x1  <<  4)     /* R */
+//#define MSDC_DMA_CFG_GPDCSERR       (0x1  <<  5)     /* R */
+#define MSDC_DMA_CFG_AHBEN            (0x3  <<  8)     /* RW */
+#define MSDC_DMA_CFG_ACTEN            (0x3  << 12)     /* RW */
+
+#define MSDC_DMA_CFG_CS12B            (0x1  << 16)     /* RW */
+#define MSDC_DMA_CFG_OUTB_STOP        (0x1  << 17)     /* RW */
+
+/* MSDC_PATCH_BIT0 mask */
+//#define MSDC_PB0_RESV1              (0x1  <<  0)
+#define MSDC_PB0_EN_8BITSUP           (0x1  <<  1)    /* RW */
+#define MSDC_PB0_DIS_RECMDWR          (0x1  <<  2)    /* RW */
+//#define MSDC_PB0_RESV2                        (0x1  <<  3)
+#define MSDC_PB0_RDDATSEL             (0x1  <<  3)    /* RW !!! MT2701 Add for SD/SDIO/eMMC 4.5*/
+#define MSDC_PB0_ACMD53_CRCINTR       (0x1  <<  4)    /* RW !!! MT2701 Add only for SD/SDIO */
+#define MSDC_PB0_ACMD53_ONESHOT       (0x1  <<  5)    /* RW !!! MT2701 Add ony for SD/SDIO */
+//#define MSDC_PB0_RESV3                        (0x1  <<  6)
+#define MSDC_PB0_DESC_UP_SEL          (0x1  <<  6)    /* RW !!! MT2701  Add*/
+#define MSDC_PB0_INT_DAT_LATCH_CK_SEL (0x7  <<  7)    /* RW */
+#define MSDC_INT_DAT_LATCH_CK_SEL      MSDC_PB0_INT_DAT_LATCH_CK_SEL  /* alias */
+
+#define MSDC_PB0_CKGEN_MSDC_DLY_SEL   (0x1F << 10)    /* RW */
+#define MSDC_CKGEN_MSDC_DLY_SEL        MSDC_PB0_CKGEN_MSDC_DLY_SEL  /* alias */
+
+
+#define MSDC_PB0_FIFORD_DIS           (0x1  << 15)    /* RW */
+//#define MSDC_PB0_SDIO_DBSSEL                  (0x1  << 16)    /* RW !!! MT2701  change*/
+#define MSDC_PB0_MSDC_BLKNUMSEL       (0x1  << 16)    /* RW !!! MT2701  change ACMD23*/
+#define MSDC_PB0_BLKNUM_SEL           MSDC_PB0_MSDC_BLKNUMSEL /* alias */
+
+#define MSDC_PB0_SDIO_INTCSEL         (0x1  << 17)    /* RW */
+#define MSDC_PB0_SDIO_BSYDLY          (0xF  << 18)    /* RW */
+#define MSDC_PB0_SDC_WDOD             (0xF  << 22)    /* RW */
+#define MSDC_PB0_CMDIDRTSEL           (0x1  << 26)    /* RW */
+#define MSDC_PB0_CMDFAILSEL           (0x1  << 27)    /* RW */
+#define MSDC_PB0_SDIO_INTDLYSEL       (0x1  << 28)    /* RW */
+#define MSDC_PB0_SPCPUSH              (0x1  << 29)    /* RW */
+#define MSDC_PB0_DETWR_CRCTMO         (0x1  << 30)    /* RW */
+#define MSDC_PB0_EN_DRVRSP            (0x1  << 31)    /* RW */
+
+/* MSDC_PATCH_BIT1 mask */
+#define MSDC_PB1_WRDAT_CRCS_TA_CNTR   (0x7  <<  0)    /* RW */
+#define MSDC_PATCH_BIT1_WRDAT_CRCS    MSDC_PB1_WRDAT_CRCS_TA_CNTR /* alias */
+
+
+#define MSDC_PB1_CMD_RSP_TA_CNTR      (0x7  <<  3)    /* RW */
+#define MSDC_PATCH_BIT1_CMD_RSP       MSDC_PB1_CMD_RSP_TA_CNTR  /* alias */
+
+//#define MSDC_PB1_RESV3                        (0x3  <<  6)
+#define MSDC_PB1_GET_BUSY_MARGIN      (0x1  <<  6)    /* RW !!! MT2701  Add */
+#define MSDC_BUSY_CHECK_SEL           (0x1  <<  7)    /* RW !!! MT2712  Add */
+#define MSDC_PB1_BIAS_TUNE_28NM       (0xF  <<  8)    /* RW */
+#define MSDC_PB1_BIAS_EN18IO_28NM     (0x1  << 12)    /* RW */
+#define MSDC_PB1_BIAS_EXT_28NM        (0x1  << 13)    /* RW */
+
+//#define MSDC_PB1_RESV2                        (0x3  << 14)
+#define MSDC_PB1_RESET_GDMA           (0x1  << 15)    /* RW !!! MT2701  Add */
+//#define MSDC_PB1_RESV1                        (0x7F << 16)
+#define MSDC_PB1_EN_SINGLE_BURST      (0x1  << 16)    /* RW !!! MT2701  Add */
+#define MSDC_PB1_EN_FORCE_STOP_GDMA   (0x1  << 17)    /* RW !!! MT2701  Add  for eMMC 5.0 only*/
+#define MSDC_PB1_DCM_DIV_SEL2         (0x3  << 18)    /* RW !!! MT2701  Add  for eMMC 5.0 only*/
+#define MSDC_PB1_DCM_DIV_SEL1         (0x1  << 20)    /* RW !!! MT2701  Add */
+#define MSDC_PB1_DCM_EN               (0x1  << 21)    /* RW !!! MT2701  Add */
+#define MSDC_PB1_AXI_WRAP_CKEN        (0x1  << 22)    /* RW !!! MT2701  Add for eMMC 5.0 only*/
+#define MSDC_PB1_AHBCKEN              (0x1  << 23)    /* RW */
+#define MSDC_PB1_CKSPCEN              (0x1  << 24)    /* RW */
+#define MSDC_PB1_CKPSCEN              (0x1  << 25)    /* RW */
+#define MSDC_PB1_CKVOLDETEN           (0x1  << 26)    /* RW */
+#define MSDC_PB1_CKACMDEN             (0x1  << 27)    /* RW */
+#define MSDC_PB1_CKSDEN               (0x1  << 28)    /* RW */
+#define MSDC_PB1_CKWCTLEN             (0x1  << 29)    /* RW */
+#define MSDC_PB1_CKRCTLEN             (0x1  << 30)    /* RW */
+#define MSDC_PB1_CKSHBFFEN            (0x1  << 31)    /* RW */
+
+/* MSDC_PATCH_BIT2 mask */
+#define MSDC_PB2_ENHANCEGPD           (0x1  <<  0)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_SUPPORT64G           (0x1  <<  1)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_RESPWAIT             (0x3  <<  2)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGRDATCNT           (0x1F <<  4)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGRDAT              (0x1  <<  9)    /* RW !!! MT2701  Add */
+
+#define MSDC_PB2_INTCRESPSEL          (0x1  << 11)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGRESPCNT           (0x7  << 12)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGRESP              (0x1  << 15)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_RESPSTSENSEL         (0x7  << 16)    /* RW !!! MT2701  Add */
+
+#define MSDC_PB2_POPENCNT             (0xF  << 20)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGCRCSTSSEL         (0x1  << 24)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGCRCSTSEDGE        (0x1  << 25)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGCRCSTSCNT         (0x3  << 26)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CFGCRCSTS            (0x1  << 28)    /* RW !!! MT2701  Add */
+#define MSDC_PB2_CRCSTSENSEL          (0x7  << 29)    /* RW !!! MT2701  Add */
+
+
+/* SDIO_TUNE_WIND mask */
+#define SDIO_TUNE_WIND_TUNEWINDOW     (0x1F  <<  0)     /* RW !!! MT2701  Add for SD/SDIO only*/
+
+/* MSDC_PAD_TUNE/MSDC_PAD_TUNE0 mask */
+#define MSDC_PAD_TUNE_DATWRDLY        (0x1F  <<  0)     /* RW */
+
+#define MSDC_PAD_TUNE_DELAYEN         (0x1   <<  7)     /* RW !!! MT2701  Add*/
+#define MSDC_PAD_TUNE_DATRRDLY        (0x1F  <<  8)     /* RW */
+#define MSDC_PAD_TUNE_DATRRDLYSEL     (0x1   << 13)     /* RW !!! MT2701  Add*/
+
+#define MSDC_PAD_TUNE_RXDLYSEL        (0x1   << 15)     /* RW !!! MT2701  Add*/
+#define MSDC_PAD_TUNE_CMDRDLY         (0x1F  << 16)     /* RW */
+#define MSDC_PAD_TUNE_CMDRDLYSEL      (0x1   << 21)     /* RW !!! MT2701  Add*/
+#define MSDC_PAD_TUNE_CMDRRDLY        (0x1F  << 22)     /* RW */
+#define MSDC_PAD_TUNE_CLKTXDLY        (0x1F  << 27)     /* RW */
+
+/* MSDC_PAD_TUNE1 mask */
+
+#define MSDC_PAD_TUNE1_DATRRDLY2      (0x1F  <<  8)     /* RW  !!! MT2701  Add*/
+#define MSDC_PAD_TUNE1_DATRDLY2SEL    (0x1   << 13)     /* RW  !!! MT2701  Add*/
+
+#define MSDC_PAD_TUNE1_CMDRDLY2       (0x1F  << 16)     /* RW  !!! MT2701  Add*/
+#define MSDC_PAD_TUNE1_CMDRDLY2SEL    (0x1   << 21)     /* RW  !!! MT2701  Add*/
+
+
+/* MSDC_DAT_RDDLY0 mask */
+#define MSDC_DAT_RDDLY0_D3            (0x1F  <<  0)     /* RW */
+#define MSDC_DAT_RDDLY0_D2            (0x1F  <<  8)     /* RW */
+#define MSDC_DAT_RDDLY0_D1            (0x1F  << 16)     /* RW */
+#define MSDC_DAT_RDDLY0_D0            (0x1F  << 24)     /* RW */
+
+/* MSDC_DAT_RDDLY1 mask */
+#define MSDC_DAT_RDDLY1_D7            (0x1F  <<  0)     /* RW */
+
+#define MSDC_DAT_RDDLY1_D6            (0x1F  <<  8)     /* RW */
+
+#define MSDC_DAT_RDDLY1_D5            (0x1F  << 16)     /* RW */
+
+#define MSDC_DAT_RDDLY1_D4            (0x1F  << 24)     /* RW */
+
+/* MSDC_DAT_RDDLY2 mask */
+#define MSDC_DAT_RDDLY2_D3            (0x1F  <<  0)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY2_D2            (0x1F  <<  8)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY2_D1            (0x1F  << 16)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY2_D0            (0x1F  << 24)     /* RW !!! MT2701  Add*/
+
+/* MSDC_DAT_RDDLY3 mask */
+#define MSDC_DAT_RDDLY3_D7            (0x1F  <<  0)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY3_D6            (0x1F  <<  8)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY3_D5            (0x1F  << 16)     /* RW !!! MT2701  Add*/
+
+#define MSDC_DAT_RDDLY3_D4            (0x1F  << 24)     /* RW !!! MT2701  Add*/
+
+/* MSDC_HW_DBG_SEL mask */
+#define MSDC_HW_DBG0_SEL              (0xFF  <<  0)     /* RW DBG3->DBG0 !!! MT2701  Change*/
+#define MSDC_HW_DBG1_SEL              (0x3F  <<  8)     /* RW DBG2->DBG1 !!! MT2701  Add*/
+
+#define MSDC_HW_DBG2_SEL              (0xFF  << 16)     /* RW DBG1->DBG2 !!! MT2701  Add*/
+//#define MSDC_HW_DBG_WRAPTYPE_SEL    (0x3   << 22)           /* RW !!! MT2701  Removed*/
+#define MSDC_HW_DBG3_SEL              (0x3F  << 24)     /* RW DBG0->DBG3 !!! MT2701  Add*/
+#define MSDC_HW_DBG_WRAP_SEL          (0x1   << 30)     /* RW */
+
+
+/* MSDC_EMMC50_PAD_CTL0 mask*/
+#define MSDC_EMMC50_PAD_CTL0_DCCSEL   (0x1  <<  0)     /* RW */
+#define MSDC_EMMC50_PAD_CTL0_HLSEL    (0x1  <<  1)     /* RW */
+#define MSDC_EMMC50_PAD_CTL0_DLP0     (0x3  <<  2)     /* RW */
+#define MSDC_EMMC50_PAD_CTL0_DLN0     (0x3  <<  4)     /* RW */
+#define MSDC_EMMC50_PAD_CTL0_DLP1     (0x3  <<  6)     /* RW */
+#define MSDC_EMMC50_PAD_CTL0_DLN1     (0x3  <<  8)     /* RW */
+
+/* MSDC_EMMC50_PAD_DS_CTL0 mask */
+#define MSDC_EMMC50_PAD_DS_CTL0_SR    (0x1  <<  0)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_R0    (0x1  <<  1)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_R1    (0x1  <<  2)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_PUPD  (0x1  <<  3)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_IES   (0x1  <<  4)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_SMT   (0x1  <<  5)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_RDSEL (0x3F <<  6)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_TDSEL (0xF  << 12)     /* RW */
+#define MSDC_EMMC50_PAD_DS_CTL0_DRV   (0x7  << 16)     /* RW */
+
+
+/* EMMC50_PAD_DS_TUNE mask */
+#define MSDC_EMMC50_PAD_DS_TUNE_DLYSEL  (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_DS_TUNE_DLY2SEL (0x1  <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_DS_TUNE_DLY1    (0x1F <<  2)  /* RW */
+#define MSDC_EMMC50_PAD_DS_TUNE_DLY2    (0x1F <<  7)  /* RW */
+#define MSDC_EMMC50_PAD_DS_TUNE_DLY3    (0x1F << 12)  /* RW */
+
+/* EMMC50_PAD_CMD_TUNE mask */
+#define MSDC_EMMC50_PAD_CMD_TUNE_DLY3SEL (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_CMD_TUNE_RXDLY3  (0x1F <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_CMD_TUNE_TXDLY   (0x1F <<  6)  /* RW */
+
+/* EMMC50_PAD_DAT01_TUNE mask */
+#define MSDC_EMMC50_PAD_DAT0_RXDLY3SEL   (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_DAT0_RXDLY3      (0x1F <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_DAT0_TXDLY       (0x1F <<  6)  /* RW */
+#define MSDC_EMMC50_PAD_DAT1_RXDLY3SEL   (0x1  << 16)  /* RW */
+#define MSDC_EMMC50_PAD_DAT1_RXDLY3      (0x1F << 17)  /* RW */
+#define MSDC_EMMC50_PAD_DAT1_TXDLY       (0x1F << 22)  /* RW */
+
+/* EMMC50_PAD_DAT23_TUNE mask */
+#define MSDC_EMMC50_PAD_DAT2_RXDLY3SEL   (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_DAT2_RXDLY3      (0x1F <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_DAT2_TXDLY       (0x1F <<  6)  /* RW */
+#define MSDC_EMMC50_PAD_DAT3_RXDLY3SEL   (0x1  << 16)  /* RW */
+#define MSDC_EMMC50_PAD_DAT3_RXDLY3      (0x1F << 17)  /* RW */
+#define MSDC_EMMC50_PAD_DAT3_TXDLY       (0x1F << 22)  /* RW */
+
+/* EMMC50_PAD_DAT45_TUNE mask */
+#define MSDC_EMMC50_PAD_DAT4_RXDLY3SEL   (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_DAT4_RXDLY3      (0x1F <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_DAT4_TXDLY       (0x1F <<  6)  /* RW */
+#define MSDC_EMMC50_PAD_DAT5_RXDLY3SEL   (0x1  << 16)  /* RW */
+#define MSDC_EMMC50_PAD_DAT5_RXDLY3      (0x1F << 17)  /* RW */
+#define MSDC_EMMC50_PAD_DAT5_TXDLY       (0x1F << 22)  /* RW */
+
+/* EMMC50_PAD_DAT67_TUNE mask */
+#define MSDC_EMMC50_PAD_DAT6_RXDLY3SEL   (0x1  <<  0)  /* RW */
+#define MSDC_EMMC50_PAD_DAT6_RXDLY3      (0x1F <<  1)  /* RW */
+#define MSDC_EMMC50_PAD_DAT6_TXDLY       (0x1F <<  6)  /* RW */
+#define MSDC_EMMC50_PAD_DAT7_RXDLY3SEL   (0x1  << 16)  /* RW */
+#define MSDC_EMMC50_PAD_DAT7_RXDLY3      (0x1F << 17)  /* RW */
+#define MSDC_EMMC50_PAD_DAT7_TXDLY       (0x1F << 22)  /* RW */
+
+/* EMMC51_CFG0 mask */
+#define MSDC_EMMC51_CFG_CMDQ_EN          (0x1   <<  0) /* RW !!! MT2701  Add*/
+#define MSDC_EMMC51_CFG_WDAT_CNT         (0x3FF <<  1) /* RW !!! MT2701  Add*/
+#define MSDC_EMMC51_CFG_RDAT_CNT         (0x3FF << 11) /* RW !!! MT2701  Add*/
+#define MSDC_EMMC51_CFG_CMDQ_CMD_EN      (0x1   << 21) /* RW !!! MT2701  Add*/
+
+
+/* EMMC50_CFG0 mask */
+#define MSDC_EMMC50_CFG_PADCMD_LATCHCK         (0x1  <<  0)  /* RW*/
+#define MSDC_EMMC50_CFG_CRCSTS_CNT             (0x3  <<  1)  /* RW*/
+#define MSDC_EMMC50_CFG_CRCSTS_EDGE            (0x1  <<  3)  /* RW*/
+#define MSDC_EMMC50_CFG_CRC_STS_EDGE           MSDC_EMMC50_CFG_CRCSTS_EDGE /*alias */
+
+#define MSDC_EMMC50_CFG_CRCSTS_SEL             (0x1  <<  4)  /* RW*/
+#define MSDC_EMMC50_CFG_CRC_STS_SEL            MSDC_EMMC50_CFG_CRCSTS_SEL /*alias */
+
+#define MSDC_EMMC50_CFG_ENDBIT_CHKCNT          (0xF  <<  5)  /* RW*/
+#define MSDC_EMMC50_CFG_CMDRSP_SEL             (0x1  <<  9)  /* RW*/
+#define MSDC_EMMC50_CFG_CMD_RESP_SEL           MSDC_EMMC50_CFG_CMDRSP_SEL  /*alias */
+
+#define MSDC_EMMC50_CFG_CMDEDGE_SEL            (0x1  << 10)  /* RW*/
+#define MSDC_EMMC50_CFG_ENDBIT_CNT             (0x3FF<< 11)  /* RW*/
+#define MSDC_EMMC50_CFG_READDAT_CNT            (0x7  << 21)  /* RW*/
+#define MSDC_EMMC50_CFG_EMMC50_MONSEL          (0x1  << 24)  /* RW*/
+#define MSDC_EMMC50_CFG_MSDC_WRVALID           (0x1  << 25)  /* RW*/
+#define MSDC_EMMC50_CFG_MSDC_RDVALID           (0x1  << 26)  /* RW*/
+#define MSDC_EMMC50_CFG_MSDC_WRVALID_SEL       (0x1  << 27)  /* RW*/
+#define MSDC_EMMC50_CFG_MSDC_RDVALID_SEL       (0x1  << 28)  /* RW*/
+#define MSDC_EMMC50_CFG_MSDC_TXSKEW_SEL        (0x1  << 29)  /* RW*/
+//#define MSDC_EMMC50_CFG_MSDC_GDMA_RESET      (0x1  << 31)  /* RW !!! MT2701  Removed*/
+
+/* EMMC50_CFG1 mask */
+#define MSDC_EMMC50_CFG1_WRPTR_MARGIN          (0xFF <<  0)  /* RW*/
+#define MSDC_EMMC50_CFG1_CKSWITCH_CNT          (0x7  <<  8)  /* RW*/
+#define MSDC_EMMC50_CFG1_RDDAT_STOP            (0x1  << 11)  /* RW*/
+#define MSDC_EMMC50_CFG1_WAIT8CLK_CNT          (0xF  << 12)  /* RW*/
+#define MSDC_EMMC50_CFG1_EMMC50_DBG_SEL        (0xFF << 16)  /* RW*/
+#define MSDC_EMMC50_CFG1_PSH_CNT               (0x7  << 24)  /* RW !!! MT2701  Add*/
+#define MSDC_EMMC50_CFG1_PSH_PS_SEL            (0x1  << 27)  /* RW !!! MT2701  Add*/
+#define MSDC_EMMC50_CFG1_DS_CFG                (0x1  << 28)  /* RW !!! MT2701  Add*/
+
+/* EMMC50_CFG2 mask */
+//#define MSDC_EMMC50_CFG2_AXI_GPD_UP          (0x1  <<  0)  /* RW !!! MT2701  Removed*/
+#define MSDC_EMMC50_CFG2_AXI_IOMMU_WR_EMI      (0x1  <<  1) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_SHARE_EN_WR_EMI   (0x1  <<  2) /* RW*/
+
+#define MSDC_EMMC50_CFG2_AXI_IOMMU_RD_EMI      (0x1  <<  7) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_SHARE_EN_RD_EMI   (0x1  <<  8) /* RW*/
+
+#define MSDC_EMMC50_CFG2_AXI_BOUND_128B        (0x1  << 13) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BOUND_256B        (0x1  << 14) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BOUND_512B        (0x1  << 15) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BOUND_1K          (0x1  << 16) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BOUND_2K          (0x1  << 17) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BOUND_4K          (0x1  << 18) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_RD_OUTSTANDING_NUM (0x1F << 19) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_RD_OUTS_NUM       MSDC_EMMC50_CFG2_AXI_RD_OUTSTANDING_NUM /*alias */
+
+#define MSDC_EMMC50_CFG2_AXI_SET_LET           (0xF  << 24) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_SET_LEN           MSDC_EMMC50_CFG2_AXI_SET_LET /*alias */
+
+#define MSDC_EMMC50_CFG2_AXI_RESP_ERR_TYPE     (0x3  << 28) /* RW*/
+#define MSDC_EMMC50_CFG2_AXI_BUSY              (0x1  << 30) /* RW*/
+
+
+/* EMMC50_CFG3 mask */
+#define MSDC_EMMC50_CFG3_OUTSTANDING_WR        (0x1F <<  0) /* RW*/
+#define MSDC_EMMC50_CFG3_OUTS_WR               MSDC_EMMC50_CFG3_OUTSTANDING_WR /*alias */
+
+#define MSDC_EMMC50_CFG3_ULTRA_SET_WR          (0x3F <<  5) /* RW*/
+#define MSDC_EMMC50_CFG3_PREULTRA_SET_WR       (0x3F << 11) /* RW*/
+#define MSDC_EMMC50_CFG3_ULTRA_SET_RD          (0x3F << 17) /* RW*/
+#define MSDC_EMMC50_CFG3_PREULTRA_SET_RD       (0x3F << 23) /* RW*/
+
+/* EMMC50_CFG4 mask */
+#define MSDC_EMMC50_CFG4_IMPR_ULTRA_SET_WR     (0xFF <<  0) /* RW*/
+#define MSDC_EMMC50_CFG4_IMPR_ULTRA_SET_RD     (0xFF <<  8) /* RW*/
+#define MSDC_EMMC50_CFG4_ULTRA_EN              (0x3  << 16) /* RW*/
+#define MSDC_EMMC50_CFG4_WRAP_SEL              (0x1F << 18) /* RW !!! MT2701  Add*/
+
+/* SDC_FIFO_CFG mask */
+#define SDC_FIFO_CFG_WRVALIDSEL   (0x1 << 24)  /* RW */
+#define SDC_FIFO_CFG_RDVALIDSEL   (0x1 << 25)  /* RW */
+
+#if 1
+/* Chaotian Add GPIO top layer */
+#define MSDC_DRVN_GEAR0                       0
+#define MSDC_DRVN_GEAR1                       1
+#define MSDC_DRVN_GEAR2                       2
+#define MSDC_DRVN_GEAR3                       3
+#define MSDC_DRVN_GEAR4                       4
+#define MSDC_DRVN_GEAR5                       5
+#define MSDC_DRVN_GEAR6                       6
+#define MSDC_DRVN_GEAR7                       7
+#define MSDC_DRVN_DONT_CARE                   MSDC_DRVN_GEAR0
+/* for MT8133 */
+#define GPIO_REG_ADDR(x)        ((volatile u32*)(GPIO_BASE + x))
+
+/* MSDC0 related settings */
+#define GPIO_MODE9_ADDR_MSDC0	GPIO_REG_ADDR(0x270)
+#define GPIO_MODEA_ADDR_MSDC0	GPIO_REG_ADDR(0x280)
+
+#define MSDC0_DSL_MODE_MASK	(0x7 << 12)
+#define MSDC0_DAT0_MODE_MASK	(0x7 << 9)
+#define MSDC0_DAT1_MODE_MASK	(0x7 << 6)
+#define MSDC0_DAT2_MODE_MASK	(0x7 << 3)
+#define MSDC0_DAT3_MODE_MASK	(0x7 << 0)
+
+#define MSDC0_CLK_MODE_MASK	(0x7 << 27)
+#define MSDC0_CMD_MODE_MASK	(0x7 << 24)
+#define MSDC0_RSTB_MODE_MASK	(0x7 << 21)
+#define MSDC0_DAT4_MODE_MASK	(0x7 << 18)
+#define MSDC0_DAT5_MODE_MASK	(0x7 << 15)
+#define MSDC0_DAT6_MODE_MASK	(0x7 << 12)
+#define MSDC0_DAT7_MODE_MASK	(0x7 << 9)
+/*
+ * GPIO104---0x280[14:12]=1---MSDC0_DSL
+ * GPIO103---0x280[11:9]=1---MSDC0_DAT0
+ * GPIO102---0x280[8:6]=1---MSDC0_DAT1
+ * GPIO101---0x280[5:3]=1---MSDC0_DAT2
+ * GPIO100---0x280[2:0]=1---MSDC0_DAT3
+ * GPIO99---0x270[29:27]=1---MSDC0_CLK
+ * GPIO98---0x270[26:24]=1---MSDC0_CMD
+ * GPIO97---0x270[23:21]=1---MSDC0_RSTB
+ * GPIO96---0x270[20:18]=1---MSDC0_DAT4
+ * GPIO95---0x270[17:15]=1---MSDC0_DAT5
+ * GPIO94---0x270[14:12]=1---MSDC0_DAT6
+ * GPIO93---0x270[11:9]=1---MSDC0_DAT7
+ */
+
+#define DRV4_CFG_ADDR	GPIO_REG_ADDR(0x750)
+#define DRV5_CFG_ADDR	GPIO_REG_ADDR(0x760)
+
+/*
+ * 0x10005750[11:8] --> PAD_MSDC0_DAT
+ * 0x10005750[31:28] --> PAD_MSDC0_CMD
+ * 0x10005760[3:0] --> PAD_MSDC0_CLK
+ * 0x10005760[23:20] --> PAD_MSDC0_DSL
+ */
+#define MSDC0_DRV_CLK_MASK	(0x7 << 0)
+#define MSDC0_DRV_DSL_MASK	(0x7 << 20)
+#define MSDC0_DRV_CMD_MASK	(0x7 << 28)
+#define MSDC0_DRV_DAT_MASK	(0x7 << 8)
+
+/* MSDC1 related settings */
+#define DRV3_CFG_ADDR	GPIO_REG_ADDR(0x740)
+/*
+ * 0x10005740[27:24] --> PAD_MSDC1_DAT
+ * 0x10005740[19:16] --> PAD_MSDC1_CMD
+ * 0x10005740[23:20] --> PAD_MSDC1_CLK
+ */
+#define MSDC1_DRV_CLK_MASK	(0x7 << 20)
+#define MSDC1_DRV_CMD_MASK	(0x7 << 16)
+#define MSDC1_DRV_DAT_MASK	(0x7 << 24)
+
+/* SMT setting */
+#define SMT0_CFG_ADDR		GPIO_REG_ADDR(0x470)
+#define SMT1_CFG_ADDR		GPIO_REG_ADDR(0x480)
+
+/* MSDC0 SMT mask*/
+#define MSDC0_SMT_CLK_MASK             (0x1  << 8)
+#define MSDC0_SMT_CMD_MASK             (0x1  << 7)
+#define MSDC0_SMT_DAT0_MASK            (0x1  << 12)
+#define MSDC0_SMT_DAT1_MASK            (0x1  << 11)
+#define MSDC0_SMT_DAT2_MASK            (0x1  << 10)
+#define MSDC0_SMT_DAT3_MASK            (0x1  << 9)
+#define MSDC0_SMT_DAT4_MASK            (0x1  << 5)
+#define MSDC0_SMT_DAT5_MASK            (0x1  << 4)
+#define MSDC0_SMT_DAT6_MASK            (0x1  << 3)
+#define MSDC0_SMT_DAT7_MASK            (0x1  << 2)
+#define MSDC0_SMT_RSTB_MASK            (0x1  << 6)
+
+/* SMT0 */
+#define MSDC1_SMT_CLK_MASK              (0x1 <<  29)
+#define MSDC1_SMT_CMD_MASK              (0x1 <<  28)
+#define MSDC1_SMT_DAT1_MASK             (0x1 << 31)
+#define MSDC1_SMT_DAT0_MASK             (0x1 << 30)
+/* SMT1*/
+#define MSDC1_SMT_DAT3_MASK             (0x1 << 1)
+#define MSDC1_SMT_DAT2_MASK             (0x1 << 0)
+
+/* PUPD setting */
+#define PUPD_CFG1_ADDR		GPIO_REG_ADDR(0x80)
+#define PUPD_CFG2_ADDR		GPIO_REG_ADDR(0x90)
+
+/* MSDC0 PUPD mask*/
+#define MSDC0_PUPD_DAT0_MASK            (0x7 <<  21)
+#define MSDC0_PUPD_DAT1_MASK            (0x7 <<  18)
+#define MSDC0_PUPD_DAT2_MASK            (0x7 <<  15)
+#define MSDC0_PUPD_DAT3_MASK            (0x7 <<  12)
+#define MSDC0_PUPD_DAT4_MASK            (0x7 <<  0)
+
+/* PUPD_CFG1 */
+#define MSDC0_PUPD_DAT5_MASK            (0x7 <<  27)
+#define MSDC0_PUPD_DAT6_MASK            (0x7 <<  24)
+#define MSDC0_PUPD_DAT7_MASK            (0x7 <<  21)
+
+#define MSDC0_PUPD_CMD_MASK             (0x7  <<  6)
+#define MSDC0_PUPD_CLK_MASK             (0x7  <<  9)
+#define MSDC0_PUPD_DSL_MASK		(0x7  << 24)
+#define MSDC0_PUPD_RSTB_MASK            (0x7  << 3)
+
+/* MSDC1 PUPD mask */
+/* PUPD_CFG1 */
+#define MSDC1_PUPD_DAT0_MASK            (0x7  <<  9)
+#define MSDC1_PUPD_DAT1_MASK            (0x7  <<  12)
+#define MSDC1_PUPD_DAT2_MASK            (0x7  <<  15)
+#define MSDC1_PUPD_DAT3_MASK            (0x7  <<  18)
+#define MSDC1_PUPD_CLK_MASK             (0x7  <<  6)
+#define MSDC1_PUPD_CMD_MASK             (0x7  <<  3)
+
+
+#endif
+
+typedef enum __MSDC_PIN_STATE {
+	MSDC_PST_PU_HIGHZ = 0,
+	MSDC_PST_PU_10KOHM,
+	MSDC_PST_PU_50KOHM,
+	MSDC_PST_PU_08KOHM,
+	MSDC_PST_PD_HIGHZ,
+	MSDC_PST_PD_10KOHM,
+	MSDC_PST_PD_50KOHM,
+	MSDC_PST_PD_08KOHM,
+	MSDC_PST_MAX
+} MSDC_PIN_STATE;
+
+
+/* each PLL have different gears for select
+ * software can used mux interface from clock management module to select */
+enum {
+    MSDC50_CLKSRC4HCLK_26MHZ  = 0,
+    MSDC50_CLKSRC4HCLK_273MHZ,
+    MSDC50_CLKSRC4HCLK_182MHZ,
+    MSDC50_CLKSRC4HCLK_78MHZ,
+    MSDC_DONOTCARE_HCLK,
+    MSDC50_CLKSRC4HCLK_MAX
+};
+
+enum {
+    MSDC50_CLKSRC_26MHZ  = 0,
+    MSDC50_CLKSRC_400MHZ,  /* MSDCPLL_CK */
+    MSDC50_CLKSRC_182MHZ,  /*MSDCPLL_D2 */
+    MSDC50_CLKSRC_136MHZ,
+    MSDC50_CLKSRC_156MHZ,
+    MSDC50_CLKSRC_200MHZ,  /*MSDCPLL_D4 */
+    MSDC50_CLKSRC_100MHZ,
+    MSDC50_CLKSRC_50MHZ,
+    MSDC50_CLKSRC_MAX
+};
+
+/* MSDC0/1/2
+     PLL MUX SEL List */
+enum {
+    MSDC30_CLKSRC_26MHZ   = 0,
+    MSDC30_CLKSRC_200MHZ,
+    MSDC30_CLKSRC_182MHZ,
+    MSDC30_CLKSRC_91MHZ,
+    MSDC30_CLKSRC_156MHZ,
+    MSDC30_CLKSRC_104MHZ,
+    MSDC30_CLKSRC_MAX
+};
+
+#define MSDC50_CLKSRC_DEFAULT     MSDC50_CLKSRC_400MHZ
+#define MSDC30_CLKSRC_DEFAULT     MSDC30_CLKSRC_200MHZ
+
+typedef enum MT65XX_POWER_VOL_TAG {
+    VOL_DEFAULT,
+    VOL_0900 = 900,
+    VOL_1000 = 1000,
+    VOL_1100 = 1100,
+    VOL_1200 = 1200,
+    VOL_1300 = 1300,
+    VOL_1350 = 1350,
+    VOL_1500 = 1500,
+    VOL_1800 = 1800,
+    VOL_2000 = 2000,
+    VOL_2100 = 2100,
+    VOL_2500 = 2500,
+    VOL_2800 = 2800,
+    VOL_3000 = 3000,
+    VOL_3300 = 3300,
+    VOL_3400 = 3400,
+    VOL_3500 = 3500,
+    VOL_3600 = 3600
+} MT65XX_POWER_VOLTAGE;
+
+/*--------------------------------------------------------------------------*/
+/* Descriptor Structure                                                     */
+/*--------------------------------------------------------------------------*/
+#define DMA_FLAG_NONE       (0x00000000)
+#define DMA_FLAG_EN_CHKSUM  (0x00000001)
+#define DMA_FLAG_PAD_BLOCK  (0x00000002)
+#define DMA_FLAG_PAD_DWORD  (0x00000004)
+
+#define MSDC_WRITE32(addr, data)    writel(data, addr)
+#define MSDC_READ32(addr)           readl(addr)
+#define MSDC_WRITE8(addr, data)     writeb(data, addr)
+#define MSDC_READ8(addr)            readb(addr)
+
+#define MSDC_SET_BIT32(addr,mask) \
+    do {    \
+        unsigned int tv = MSDC_READ32(addr); \
+        tv |=((u32)(mask)); \
+        MSDC_WRITE32(addr,tv); \
+    } while (0)
+#define MSDC_CLR_BIT32(addr,mask) \
+    do {    \
+        unsigned int tv = MSDC_READ32(addr); \
+        tv &= ~((u32)(mask)); \
+        MSDC_WRITE32(addr,tv); \
+    } while (0)
+
+#define MSDC_SET_FIELD(reg,field,val) \
+    do { \
+        u32 tv = MSDC_READ32(reg); \
+        tv &= ~((u32)(field)); \
+        tv |= ((val) << (__builtin_ffs((u32)(field)) - 1)); \
+        MSDC_WRITE32(reg, tv); \
+    } while (0)
+
+#define MSDC_GET_FIELD(reg,field,val) \
+    do { \
+        u32 tv = MSDC_READ32(reg); \
+        val = ((tv & (field)) >> (__builtin_ffs((u32)(field)) - 1)); \
+    } while (0)
+
+#define MSDC_RETRY(expr,retry,cnt) \
+    do { \
+        uint32_t t = cnt; \
+        uint32_t r = retry; \
+        uint32_t c = cnt; \
+        while (r) { \
+            if (!(expr)) break; \
+            if (c-- == 0) { \
+                r--; spin(200); c = t; \
+            } \
+        } \
+        if (r == 0) \
+            dprintf(CRITICAL, "%s->%d: retry %d times failed!\n", __func__, \
+                    __LINE__, retry); \
+    } while (0)
+
+#define MSDC_RESET() \
+    do { \
+        MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_RST); \
+        MSDC_RETRY(MSDC_READ32(MSDC_CFG) & MSDC_CFG_RST, 5, 1000); \
+    } while (0)
+
+#define MSDC_CLR_INT() \
+    do { \
+        volatile uint32_t val = MSDC_READ32(MSDC_INT); \
+        MSDC_WRITE32(MSDC_INT, val); \
+    } while (0)
+
+#define MSDC_CLR_FIFO() \
+    do { \
+        MSDC_SET_BIT32(MSDC_FIFOCS, MSDC_FIFOCS_CLR); \
+        MSDC_RETRY(MSDC_READ32(MSDC_FIFOCS) & MSDC_FIFOCS_CLR, 5, 1000); \
+    } while (0)
+
+#define MSDC_FIFO_WRITE32(val)  MSDC_WRITE32(MSDC_TXDATA, val)
+#define MSDC_FIFO_READ32()      MSDC_READ32(MSDC_RXDATA)
+#define MSDC_FIFO_WRITE8(val)   MSDC_WRITE8(MSDC_TXDATA, val)
+#define MSDC_FIFO_READ8()       MSDC_READ8(MSDC_RXDATA)
+
+#define MSDC_TXFIFOCNT() \
+    ((MSDC_READ32(MSDC_FIFOCS) & MSDC_FIFOCS_TXCNT) >> 16)
+#define MSDC_RXFIFOCNT() \
+    ((MSDC_READ32(MSDC_FIFOCS) & MSDC_FIFOCS_RXCNT) >> 0)
+
+#define SDC_IS_BUSY()       (MSDC_READ32(SDC_STS) & SDC_STS_SDCBUSY)
+#define SDC_IS_CMD_BUSY()   (MSDC_READ32(SDC_STS) & SDC_STS_CMDBUSY)
+
+#define SDC_SEND_CMD(cmd,arg) \
+    do { \
+        MSDC_WRITE32(SDC_ARG, (arg)); \
+        MSDC_WRITE32(SDC_CMD, (cmd)); \
+    } while (0)
+
+#define MSDC_DMA_ON     MSDC_CLR_BIT32(MSDC_CFG, MSDC_CFG_PIO);
+#define MSDC_DMA_OFF    MSDC_SET_BIT32(MSDC_CFG, MSDC_CFG_PIO);
+
+#define MSDC_RELIABLE_WRITE     (0x1 << 0)
+#define MSDC_PACKED             (0x1 << 1)
+#define MSDC_TAG_REQUEST        (0x1 << 2)
+#define MSDC_CONTEXT_ID         (0x1 << 3)
+#define MSDC_FORCED_PROG        (0x1 << 4)
+
+#ifdef FPGA_PLATFORM
+#define msdc_pin_set(...)
+#define msdc_set_smt(...)
+#define msdc_set_driving(...)
+#endif
+
+int msdc_init(struct mmc_host *host);
+void msdc_config_bus(struct mmc_host *host, u32 width);
+int msdc_dma_transfer(struct mmc_host *host, struct mmc_data *data);
+#ifndef MSDC_USE_DMA_MODE
+int msdc_pio_read_word(struct mmc_host *host, u32 *ptr, u32 size);
+#endif
+int msdc_tune_bwrite(struct mmc_host *host, u32 dst, u8 *src, u32 nblks);
+int msdc_tune_bread(struct mmc_host *host, u8 *dst, u32 src, u32 nblks);
+void msdc_reset_tune_counter(struct mmc_host *host);
+int msdc_abort_handler(struct mmc_host *host, int abort_card);
+int msdc_tune_read(struct mmc_host *host);
+void msdc_config_clock(struct mmc_host *host, int state, u32 hz);
+int msdc_cmd(struct mmc_host *host, struct mmc_command *cmd);
+void msdc_set_timeout(struct mmc_host *host, u32 ns, u32 clks);
+void msdc_set_autocmd(struct mmc_host *host, int cmd);
+int msdc_get_autocmd(struct mmc_host *host);
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/msdc_cfg.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/msdc_cfg.h
new file mode 100644
index 0000000..0afd634
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/msdc_cfg.h
@@ -0,0 +1,48 @@
+/*
+ * 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
+
+/*--------------------------------------------------------------------------*/
+/* Common Definition                                                        */
+/*--------------------------------------------------------------------------*/
+#ifdef MACH_FPGA
+#define FPGA_PLATFORM
+#endif
+
+/* HW deal with the 2K DMA boundary limitation, SW do nothing with it */
+/* Most of eMMC request in lk are sequential access, so it's no need to
+ * use descript DMA mode, I just remove relevant codes. JieWu@20160607 */
+#define MSDC_USE_DMA_MODE
+
+#define FEATURE_MMC_WR_TUNING
+#define FEATURE_MMC_RD_TUNING
+#define FEATURE_MMC_CM_TUNING
+
+/* Maybe we discard these macro definition */
+//#define MSDC_USE_PATCH_BIT2_TURNING_WITH_ASYNC
+
+/*--------------------------------------------------------------------------*/
+/* Debug Definition                                                         */
+/*--------------------------------------------------------------------------*/
+//#define KEEP_SLIENT_BUILD
+//#define ___MSDC_DEBUG___
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt6357.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt6357.h
new file mode 100644
index 0000000..b0332a9
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt6357.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#ifndef __MT6357_H
+#define __MT6357_H
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+#define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))
+
+enum {
+	PMIC_PONSTS 			= 0xC,
+	PMIC_POFFSTS 			= 0xE,
+	PMIC_PSTSCTL			= 0x10,
+	PMIC_PG_SDN_STS 		= 0x14,
+	PMIC_OC_SDN_STS 		= 0x16,
+	PMIC_THERMALSTATUS		= 0x18,
+	PMIC_TOP_RST_MISC 		= 0x14C,
+	PMIC_TOP_RST_STATUS		= 0x152,
+	PMIC_TOP_CLK_TRIM		= 0x38E,
+	PMIC_PWRHOLD			= 0xA08,
+	PMIC_STRUP_CON4 		= 0xA1C,
+	PMIC_STRUP_CON11		= 0xA2A,
+	PMIC_BUCK_TOP_OC_CON0		= 0x1434,
+	PMIC_BUCK_TOP_ELR0		= 0x1444,
+	PMIC_BUCK_VPROC_DBG0		= 0x14A2,
+	PMIC_BUCK_VPROC_ELR0		= 0x14AA,
+	PMIC_LDO_VSRAM_PROC_DBG0	= 0x19CC,
+	PMIC_LDO_VSRAM_CON0		= 0x19FA,
+	PMIC_LDO_VCAMA_CON0 		= 0x1A6C,
+	PMIC_LDO_VCAMD_CON0		= 0x1A88,
+	PMIC_LDO_VCAMIO_CON0		= 0x1A9C,
+};
+
+struct pmic_setting {
+	unsigned short addr;
+	unsigned short val;
+	unsigned short mask;
+	unsigned char shift;
+};
+
+enum {
+	BUCK_PROC = 0,
+	LDO_SRAM_PROC,
+	REGULATOR_MAX,
+};
+
+int mt6357_init(void);
+void pmic_set_power_hold(bool enable);
+u16 pmic_read_interface (u16 RegNum, u16 *val, u16 MASK, u16 SHIFT);
+u16 pmic_config_interface (u16 RegNum, u16 val, u16 MASK, u16 SHIFT);
+
+int pmic_get_voltage(int power_id);
+void pmic_set_voltage(int power_id, int target_uV);
+
+#endif /* __MT6357_H */
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt8133.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt8133.h
new file mode 100644
index 0000000..1109099
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt8133.h
@@ -0,0 +1,79 @@
+/*
+ * 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 <compiler.h>
+#include <debug.h>
+
+#if LK_AS_BL33 == 0 /* LK as BL2 */
+/* program memory: L2C for BL2 */
+#define MEMORY_BASE_PHYS     (0x200000)
+#define MEMORY_APERTURE_SIZE (0x40000UL)
+
+/* internal SRAM */
+#define SRAM_BASE_PHYS (0x100000)
+#define SRAM_BASE_SIZE (0x12000UL)
+
+#else /* LK as BL33 */
+
+/* program memory and memory before mempool */
+#define MEMORY_BASE_PHYS        (0x40000000)
+#define MEMORY_APERTURE_SIZE    (0xC300000UL)
+
+/* non-secure accessible internal SRAM region */
+#define SRAM_BASE_PHYS          (0x118000)
+#define SRAM_BASE_SIZE          (0x12000UL)
+#endif
+
+/* peripheral */
+#define PERIPHERAL_BASE_PHYS (0x10000000)
+#define PERIPHERAL_BASE_SIZE (0x10000000UL)
+
+/* gic+peripheral */
+#define GIC_PERIPHERAL_BASE_PHYS (0xC000000)
+#define GIC_PERIPHERAL_BASE_SIZE (0x12000000UL)
+
+/* GIC */
+#define GIC_DIST_BASE       (KERNEL_ASPACE_BASE + 0x0C000000)
+#define GIC_REDIS_BASE      (KERNEL_ASPACE_BASE + 0x0C080000)
+#define GIC_REDIS_BASE_PHY  (0x0C080000)
+
+/* dram */
+#define DRAM_BASE_PHY  (0x40000000UL)
+
+#define MEMORY_BASE_VIRT        (KERNEL_ASPACE_BASE + MEMORY_BASE_PHYS)
+#define SRAM_BASE_VIRT          (KERNEL_ASPACE_BASE + SRAM_BASE_PHYS)
+#define PERIPHERAL_BASE_VIRT     (KERNEL_ASPACE_BASE + PERIPHERAL_BASE_PHYS)
+#define GIC_PERIPHERAL_BASE_VIRT (KERNEL_ASPACE_BASE + 0xC000000)
+#define DRAM_BASE_VIRT           (KERNEL_ASPACE_BASE + DRAM_BASE_PHY)
+
+#define SRAM_ARENA_BASE         SRAM_BASE_PHYS
+#define SRAM_ARENA_SIZE         SRAM_BASE_SIZE
+#define DRAM_ARENA_BASE         DRAM_BASE_PHY
+#define DRAM_ARENA_SIZE         SRAM_BASE_SIZE
+
+/* interrupts */
+#define ARM_GENERIC_TIMER_VIRTUAL_INT 27
+#define ARM_GENERIC_TIMER_PHYSICAL_INT 30
+
+#define MAX_INT 256
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt_irq.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt_irq.h
new file mode 100644
index 0000000..3a640e8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt_irq.h
@@ -0,0 +1,75 @@
+/*
+ * 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
+
+#define GIC_DIST_PENDING_SET            0x200
+#define GIC_DIST_ENABLE_SET             0x100
+#define GIC_DIST_ENABLE_CLEAR           0x180
+#define GIC_DIST_PENDING_CLEAR          0x280
+#define GIC_DIST_CTR                    0x004
+#define GIC_DIST_CTRL                   0x000
+#define GIC_DIST_TARGET                 0x800
+#define GIC_DIST_ACTIVE_BIT             0x300
+#define GIC_DIST_PRI                    0x400
+#define GIC_DIST_ICDISR                 0x80
+#define GIC_DIST_CONFIG                 0xc00
+#define GIC_DIST_SOFTINT                0xf00
+
+#define GIC_CPU_HIGHPRI                 0x18
+#define GIC_CPU_EOI                     0x10
+#define GIC_CPU_RUNNINGPRI              0x14
+#define GIC_CPU_BINPOINT                0x08
+#define GIC_CPU_INTACK                  0x0c
+#define GIC_CPU_CTRL                    0x00
+#define GIC_CPU_PRIMASK                 0x04
+
+/*
+ * Define IRQ code.
+ */
+#define GIC_PRIVATE_SIGNALS (32)
+
+#define GIC_PPI_OFFSET          (27)
+#define GIC_PPI_GLOBAL_TIMER    (GIC_PPI_OFFSET + 0)
+#define GIC_PPI_LEGACY_FIQ      (GIC_PPI_OFFSET + 1)
+#define GIC_PPI_PRIVATE_TIMER   (GIC_PPI_OFFSET + 2)
+#define GIC_PPI_WATCHDOG_TIMER  (GIC_PPI_OFFSET + 3)
+#define GIC_PPI_LEGACY_IRQ      (GIC_PPI_OFFSET + 4)
+
+#define SSUSB_DEV_INT_ID             48
+#define USB_MCU_IRQ_BIT1_ID          105
+#define MSDC0_IRQ_BIT_ID             55
+#define NFI_IRQ_BIT_ID               110
+#define NFIECC_IRQ_BIT_ID            111
+
+#define MT_NR_PPI   (5)
+#define MT_NR_SPI   (292)
+#define NR_IRQ_LINE  (GIC_PPI_OFFSET + MT_NR_PPI + MT_NR_SPI)
+
+#define EDGE_SENSITIVE 0
+#define LEVEL_SENSITIVE 1
+
+#define MT65xx_POLARITY_LOW   0
+#define MT65xx_POLARITY_HIGH  1
+
+void mt_irq_set_sens(unsigned int irq, unsigned int sens);
+void mt_irq_set_polarity(unsigned int irq, unsigned int polarity);
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt_reg_base.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt_reg_base.h
new file mode 100644
index 0000000..e178037
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mt_reg_base.h
@@ -0,0 +1,72 @@
+/*
+ * 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 <platform/mt8133.h>
+
+/* I/O mapping */
+#define IO_PHYS             PERIPHERAL_BASE_VIRT
+#define IO_SIZE             PERIPHERAL_BASE_SIZE
+
+/* IO register definitions */
+#define TOP_RGU_BASE        (IO_PHYS + 0x00007000)
+#define MCUSYS_CFGREG_BASE  (IO_PHYS + 0x00200000)
+#define INT_POL_CTL0        (MCUSYS_CFGREG_BASE + 0xA80)
+#define INT_POL_SECCTL0     (MCUSYS_CFGREG_BASE + 0xA00)
+#define SEC_POL_CTL_EN0     INT_POL_SECCTL0
+
+#define write_r(a, v) writel(v, a)
+
+#define CKSYS_BASE          (IO_PHYS + 0x00000000)
+#define SPM_BASE            (IO_PHYS + 0x00006000)
+#define APMIXED_BASE        (IO_PHYS + 0x0000C000)
+#define PWRAP_BASE          (IO_PHYS + 0x0000D000)
+#define AUDIO_BASE          (IO_PHYS + 0x01220000)
+#define MFGCFG_BASE         (IO_PHYS + 0x03000000)
+#define MMSYS_CONFIG_BASE   (IO_PHYS + 0x04000000)
+#define SMI_COMMON_BASE     (IO_PHYS + 0x04002000)
+#define CAMSYS_BASE         (IO_PHYS + 0x05000000)
+#define MCUCFG_BASE         (IO_PHYS + 0x00200000)
+#define GCE_BASE            (IO_PHYS + 0x0023C000)
+#define INFRACFG_AO_BASE    (IO_PHYS + 0x00001000)
+#define PERICFG_BASE        (IO_PHYS + 0x00003000)
+#define VDECSYS_BASE        (IO_PHYS + 0x06000000)
+#define VENCSYS_BASE        (IO_PHYS + 0x07000000)
+
+#define GPIO_BASE           (IO_PHYS + 0x00005000)
+#define AUXADC_BASE         (IO_PHYS + 0x01001000)
+#define UART0_BASE          (IO_PHYS + 0x01002000)
+#define UART1_BASE          (IO_PHYS + 0x01003000)
+#define UART2_BASE          (IO_PHYS + 0x01004000)
+#define UART3_BASE          (IO_PHYS + 0x01005000)
+#define NFI_BASE            (IO_PHYS + 0x01018000)
+#define NFIECC_BASE         (IO_PHYS + 0x01019000)
+#define MSDC0_BASE          (IO_PHYS + 0x01230000)
+#define MSDC1_BASE          (IO_PHYS + 0x01240000)
+#define MSDC0_TOP_BASE      (IO_PHYS + 0x01CD0000)
+#define MSDC1_TOP_BASE      (IO_PHYS + 0x01C90000)
+
+/* USB */
+#define USB3_BASE           (IO_PHYS + 0x01200000)
+#define USB3_SIF2_BASE      (IO_PHYS + 0x01CC0000)
+#define USB3_IPPC_BASE      (IO_PHYS + 0x01203e00)
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_auxadc_hw.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_auxadc_hw.h
new file mode 100644
index 0000000..6a9aa82
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_auxadc_hw.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+*/
+
+#ifndef _MTK_ADC_HW_H
+#define _MTK_ADC_HW_H
+
+#include <platform/mt_reg_base.h>
+
+#define AUXADC_CLK_STA          INFRACFG_AO_BASE + 0x094
+#define AUXADC_CLK_CLR          INFRACFG_AO_BASE + 0x08c
+#define AUXADC_CLK_SET          INFRACFG_AO_BASE + 0x088
+
+#define AUXADC1_SW_CG           (1 << 5)
+#define AUXADC2_SW_CG           (1 << 15)
+#define AUX_SW_CG_ADC           (1 << 14)   /*main clk*/
+#define AUX_SW_CG_TP            (1 << 31)
+
+#define AUXADC_CON0             (AUXADC_BASE + 0x000)
+#define AUXADC_CON1             (AUXADC_BASE + 0x004)
+#define AUXADC_CON1_SET         (AUXADC_BASE + 0x008)
+#define AUXADC_CON1_CLR         (AUXADC_BASE + 0x00C)
+#define AUXADC_CON2             (AUXADC_BASE + 0x010)
+#define AUXADC_DAT0             (AUXADC_BASE + 0x014)
+
+#define AUXADC_MISC             (AUXADC_BASE + 0x094)
+
+#endif   /*_MTK_ADC_HW_H*/
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_auxadc_sw.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_auxadc_sw.h
new file mode 100644
index 0000000..1256561
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_auxadc_sw.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+*/
+
+#ifndef _MTK_ADC_SW_H
+#define _MTK_ADC_SW_H
+
+extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int *rawdata);
+extern int IMM_GetOneChannelValue_Cali(int Channel, int *voltage);
+extern int auxadc_test(void);
+#endif   /*_MTK_ADC_SW_H*/
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_i2c.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_i2c.h
new file mode 100644
index 0000000..82723c1
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_i2c.h
@@ -0,0 +1,463 @@
+/*

+ * MediaTek Inc. (C) 2019. All rights reserved.

+ *

+ * Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+

+/**

+ * @file mt_i2c.h

+ * This i2c header file is used for i2c driver. It declares\n

+ * the external functions which will be used in LK.

+ */

+

+/**

+ * @defgroup IP_group_i2c I2C

+ *

+ *   @{

+ *       @defgroup IP_group_i2c_external EXTERNAL

+ *         The external API document for I2C. \n

+ *

+ *         @{

+ *            @defgroup IP_group_i2c_external_function 1.function

+ *              External function in i2c driver.

+ *            @defgroup IP_group_i2c_external_struct 2.structure

+ *              none.

+ *            @defgroup IP_group_i2c_external_typedef 3.typedef

+ *              none.

+ *            @defgroup IP_group_i2c_external_enum 4.enumeration

+ *              none.

+ *            @defgroup IP_group_i2c_external_def 5.define

+ *              none.

+ *         @}

+ *

+ *       @defgroup IP_group_i2c_internal INTERNAL

+ *         The internal API document for I2C. \n

+ *

+ *         @{

+ *            @defgroup IP_group_i2c_internal_function 1.function

+ *              none.

+ *            @defgroup IP_group_i2c_internal_struct 2.structure

+ *              Internal structure in i2c driver.

+ *            @defgroup IP_group_i2c_internal_typedef 3.typedef

+ *              none.

+ *            @defgroup IP_group_i2c_internal_enum 4.enumeration

+ *              Internal enumeration in i2c driver.

+ *            @defgroup IP_group_i2c_internal_def 5.define

+ *              Internal define in i2c driver.

+ *         @}

+ *   @}

+ */

+

+#ifndef __MTK_I2C_H__

+#define __MTK_I2C_H__

+

+#include <stdbool.h>

+#include <stdint.h>

+#include <string.h>

+#include <debug.h>

+#include <reg.h>

+#include <platform/mt_irq.h>

+#include "platform/mt_reg_base.h"

+//#include "platform/mt_typedefs.h"

+

+//#define CONFIG_MTK_FPGA

+

+/** @ingroup IP_group_i2c_internal_def

+ * @{

+ */

+#ifdef CONFIG_MTK_FPGA

+#define MTK_I2C_SOURCE_CLK 6000

+#define MTK_I2C_CLK_DIV 1

+#define I2C_DEFAULT_CLK_DIV 1

+#define I2C_CLK_DIV_100K I2C_DEFAULT_CLK_DIV

+#define I2C_TIMING_100K 0x1d

+#define I2C_CLK_DIV_400K I2C_DEFAULT_CLK_DIV

+#define I2C_TIMING_400K 0x7

+#define I2C_CLK_DIV_1000K I2C_DEFAULT_CLK_DIV

+#define I2C_TIMING_1000K 0x2

+#else

+#define MTK_I2C_SOURCE_CLK 156000

+#define MTK_I2C_CLK_DIV 1

+#define I2C_DEFAULT_CLK_DIV 2

+#define I2C_CLK_DIV_100K 10

+#define I2C_TIMING_100K 0x126

+#define I2C_CLK_DIV_400K I2C_DEFAULT_CLK_DIV

+#define I2C_TIMING_400K 0x637

+#define I2C_CLK_DIV_1000K I2C_DEFAULT_CLK_DIV

+#define I2C_TIMING_1000K 0x407

+#endif

+#define MTK_I2C_ULPOSC_DIV8 32750

+#define MTK_I2C_ULPOSC_DIV16 16375

+#define MTK_I2C_CLK_26M 26000

+

+#define I2CTAG "[I2C-LK] "

+#define I2CLOG(x...) printf(x)

+#define I2CERR(x...) printf(x)

+

+#ifndef DIV_ROUND_UP

+#define DIV_ROUND_UP(x, y) (((x) + ((y) - 1)) / (y))

+#endif

+

+#define I2CBIT(nr) (1UL << (nr))

+#define I2CBITMASK(a, b) (I2CBIT(a+1) - I2CBIT(b))

+

+#define I2C_POLL_VALUE 0xfffff

+

+#define MTK_I2C_NUM 4

+

+#define MTK_I2C0_BASE (IO_PHYS+0x01007000)

+#define MTK_I2C1_BASE (IO_PHYS+0x01008000)

+#define MTK_I2C2_BASE (IO_PHYS+0x01009000)

+#define MTK_I2C3_BASE (IO_PHYS+0x0000F000)

+

+#define MTK_I2C0_DMA (IO_PHYS+0x01000080)

+#define MTK_I2C1_DMA (IO_PHYS+0x01000100)

+#define MTK_I2C2_DMA (IO_PHYS+0x01000180)

+#define MTK_I2C3_DMA (IO_PHYS+0x01000200)

+

+#define MTK_I2C0_GIC_IRQ 60

+#define MTK_I2C1_GIC_IRQ 61

+#define MTK_I2C2_GIC_IRQ 62

+#define MTK_I2C3_GIC_IRQ 63

+

+#define MTK_I2C_CLK_SET  (IO_PHYS+0x000010C0)

+#define MTK_I2C_CLK_CLR  (IO_PHYS+0x000010C4)

+#define MTK_I2C_CLK_STA  (IO_PHYS+0x000010C8)

+#define MTK_APDMA_CLK_SET (IO_PHYS+0x00001088)

+#define MTK_APDMA_CLK_CLR (IO_PHYS+0x0000108C)

+#define MTK_APDMA_CLK_STA (IO_PHYS+0x00001094)

+#define MTK_I2C0_CLK_OFFSET  (0x1 << 24)

+#define MTK_I2C1_CLK_OFFSET  (0x1 << 25)

+#define MTK_I2C2_CLK_OFFSET  (0x1 << 26)

+#define MTK_I2C3_CLK_OFFSET  (0x1 << 27)

+#define MTK_APDMA_CLK_OFFSET (0x1 << 18)

+

+#define MTK_GPIO_I2C_BASE0 (IO_PHYS+0x00005230)//i2c0

+#define MTK_GPIO_I2C_BASE1 (IO_PHYS+0x00005240)//i2c1 i2c2 i2c3

+

+

+#define MTK_GPIO_SDA0 21

+#define MTK_GPIO_SCL0 24

+#define MTK_GPIO_SDA1 27

+#define MTK_GPIO_SCL1 0

+#define MTK_GPIO_SDA2 3

+#define MTK_GPIO_SCL2 6

+#define MTK_GPIO_SDA3 9

+#define MTK_GPIO_SCL3 12

+

+#define I2C_CONTROL_RS			I2CBIT(1)

+#define I2C_CONTROL_DMA_EN		I2CBIT(2)

+#define I2C_CONTROL_CLK_EXT_EN		I2CBIT(3)

+#define I2C_CONTROL_DIR_CHANGE		I2CBIT(4)

+#define I2C_CONTROL_ACKERR_DET_EN	I2CBIT(5)

+#define I2C_CONTROL_TRANSFER_LEN_CHANGE	I2CBIT(6)

+#define I2C_CONTROL_AYNCS_MODE		I2CBIT(9)

+

+#define I2C_RS_TRANSFER			I2CBIT(4)

+#define I2C_ARB_LOSE			I2CBIT(3)

+#define I2C_ACKERR			I2CBIT(1)

+#define I2C_TRANSAC_COMP		I2CBIT(0)

+#define I2C_TRANSAC_START		I2CBIT(0)

+#define I2C_RS_MUL_CNFG			I2CBIT(15)

+#define I2C_RS_MUL_TRIG			I2CBIT(14)

+#define I2C_SOFT_RST			0x0001

+#define I2C_FIFO_ADDR_CLR		0x0001

+

+#define I2C_IO_CONFIG_OPEN_DRAIN	0x0003

+#define I2C_IO_CONFIG_PUSH_PULL		0x0000

+#define I2C_CONTROL_DEFAULT		0x0d00

+#define I2C_DELAY_LEN			0x0002

+#define I2C_ST_START_CON		0x8001

+#define I2C_FS_START_CON		0x1800

+#define I2C_DCM_OPEN			0x0003

+#define I2C_WRRD_TRANAC_VALUE		0x0002

+#define I2C_M_RD			0x0001

+

+#define I2C_DMA_CON_TX			0x0000

+#define I2C_DMA_CON_RX			0x0001

+#define I2C_DMA_START_EN		0x0001

+#define I2C_DMA_INT_FLAG_NONE		0x0000

+#define I2C_DMA_CLR_FLAG		0x0000

+#define I2C_DMA_HARD_RST		0x0002

+

+#define I2C_FIFO_SIZE			16

+#define I2C_DEFAULT_SPEED		100

+#define MAX_FS_MODE_SPEED		400

+#define MAX_FS_PLUS_SPEED		1000

+#define MAX_SAMPLE_CNT_DIV		8

+#define MAX_STEP_CNT_DIV		64

+#define MAX_HS_STEP_CNT_DIV		8

+#define I2C_TIME_DEFAULT_VALUE		0x0003

+

+#define I2C_OK				0

+#define ENXIO_I2C			6

+#define EINVAL_I2C			22

+#define ETIMEDOUT_I2C			110

+#define EREMOTEIO_I2C			121

+

+#define I2C_FIFO_FORCE			I2CBIT(0)

+#define I2C_DCM_ENABLE			I2CBIT(1)

+#define I2C_CONTI_TRANS			I2CBIT(2)

+#define I2C_EXTEN_SET			I2CBIT(3)

+#define I2C_ACTIME_SET			I2CBIT(4)

+#define I2C_MULTI_TRANS			I2CBIT(5)

+#define I2C_MULTI_STOP			I2CBIT(6)

+#define I2C_CLOCK_STRETCH		I2CBIT(7)

+/** @}

+ */

+

+/** @ingroup IP_group_i2c_internal_enum

+ * @brief I2C controller register offset.

+ */

+enum I2C_REGS_OFFSET {

+	OFFSET_DATA_PORT = 0x0,

+	OFFSET_SLAVE_ADDR = 0x04,

+	OFFSET_INTR_MASK = 0x08,

+	OFFSET_INTR_STAT = 0x0c,

+	OFFSET_CONTROL = 0x10,

+	OFFSET_TRANSFER_LEN = 0x14,

+	OFFSET_TRANSAC_LEN = 0x18,

+	OFFSET_DELAY_LEN = 0x1c,

+	OFFSET_TIMING = 0x20,

+	OFFSET_START = 0x24,

+	OFFSET_EXT_CONF = 0x28,

+	OFFSET_FIFO_STAT1 = 0x2c,

+	OFFSET_FIFO_STAT = 0x30,

+	OFFSET_FIFO_THRESH = 0x34,

+	OFFSET_FIFO_ADDR_CLR = 0x38,

+	OFFSET_IO_CONFIG = 0x40,

+	OFFSET_MULTI_MASTER = 0x44,

+	OFFSET_HS = 0x48,

+	OFFSET_SOFTRESET = 0x50,

+	OFFSET_DCM_EN = 0x54,

+	OFFSET_DEBUGSTAT = 0x64,

+	OFFSET_DEBUGCTRL = 0x68,

+	OFFSET_TRANSFER_LEN_AUX = 0x6c,

+	OFFSET_CLOCK_DIV = 0x70,

+	OFFSET_SCL_HL_RATIO = 0x74,

+	OFFSET_HS_SCL_HL_RATIO = 0x78,

+	OFFSET_SCL_MIS_COMP_POINT = 0x7C,

+	OFFSET_STA_STOP_AC_TIME = 0x80,

+	OFFSET_HS_STA_STOP_AC_TIME = 0x84,

+	OFFSET_SDA_TIME = 0x88,

+	OFFSET_FIFO_PAUSE = 0x8C,

+};

+

+/** @ingroup IP_group_i2c_internal_enum

+ * @brief I2C transfer operation mode.

+ */

+enum mtk_trans_op {

+	I2C_MASTER_WR = 1,

+	I2C_MASTER_RD,

+	I2C_MASTER_WRRD,

+};

+

+/** @ingroup IP_group_i2c_internal_enum

+ * @brief I2C GDMA register offset.

+ */

+enum DMA_REGS_OFFSET {

+	OFFSET_DMA_INT_FLAG       = 0x0,

+	OFFSET_DMA_INT_EN         = 0x04,

+	OFFSET_DMA_EN             = 0x08,

+	OFFSET_DMA_RST            = 0x0C,

+	OFFSET_DMA_CON            = 0x18,

+	OFFSET_DMA_TX_MEM_ADDR    = 0x1C,

+	OFFSET_DMA_RX_MEM_ADDR    = 0x20,

+	OFFSET_DMA_TX_LEN         = 0x24,

+	OFFSET_DMA_RX_LEN         = 0x28,

+};

+

+/** @ingroup IP_group_i2c_internal_enum

+ * @brief I2C bus num.

+ */

+enum mtk_i2c_bus_num {

+	I2C0 = 0,

+	I2C1 = 1,

+	I2C2 = 2,

+	I2C3 = 3,

+};

+

+/** @ingroup IP_group_i2c_internal_struct

+ * @brief Struct keeping i2c message data.

+ */

+struct i2c_msg {

+	/** slave address */

+	uint16_t addr;

+	/** i2c transfer operation mode */

+	uint16_t flags;

+	/** msg length */

+	uint16_t len;

+	/** pointer to msg data */

+	uint8_t *buf;

+};

+

+/** @ingroup IP_group_i2c_internal_struct

+ * @brief Struct keeping i2c driver data.

+ */

+struct mtk_i2c {

+	/** dma mode flag */

+	bool dma_en;

+	/** polling mode flag */

+	bool poll_en;

+	/** IO config push-pull mode */

+	bool pushpull;

+	/** filter error message */

+	bool filter_msg;

+	/** multi-transfer repeated start enable */

+	bool auto_restart;

+	bool msg_complete;

+	/** slave device 7bits address */

+	uint8_t addr;

+	/** i2c bus number */

+	uint8_t id;

+	uint8_t mode;

+	uint16_t irqnr;

+	/** i2c interrupt status */

+	uint16_t irq_stat;

+	/** clock_div register value */

+	uint16_t clock_div_reg;

+	/** timing register value */

+	uint16_t timing_reg;

+	uint16_t high_speed_reg;

+	uint16_t con_num;

+	uint16_t delay_len;

+	uint16_t ext_time;

+	uint16_t scl_ratio;

+	uint16_t hs_scl_ratio;

+	uint16_t scl_mis_comp;

+	uint16_t sta_stop_time;

+	uint16_t hs_sta_stop_time;

+	uint16_t sda_time;

+	/** i2c base address */

+	uint64_t base;

+	/** i2c dma base address */

+	uint64_t dmabase;

+	/** source clock KHz */

+	uint32_t clk;

+	/** source clock divide */

+	uint32_t clk_src_div;

+	/** i2c transfer speed */

+	uint32_t speed;

+	/** i2c transfer operation mode */

+	enum mtk_trans_op op;

+};

+

+/** @ingroup IP_group_i2c_external_function

+ * @par Description

+ *     Initialize struct mtk_i2c and i2c_msg, then read data from\n

+ *     slave device.

+ * @param[in]

+ *     bus_num: i2c bus number.

+ * @param[in]

+ *     device_addr: slave device 7bits address.

+ * @param[in]

+ *     speed_khz: i2c transfer speed.

+ * @param[out]

+ *     buffer: read data buffer pointer.

+ * @param[in]

+ *     len: read data length.

+ * @return

+ *     0, i2c transfer successfully.\n

+ *     error code from mtk_i2c_transfer().

+ * @par Boundary case and Limitation

+ *     none.

+ * @par Error case and Error handling

+ *     If mtk_i2c_transfer() fails, return its error code.

+ * @par Call graph and Caller graph

+ * @par Refer to the source code

+ */

+int mtk_i2c_read(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,

+		 uint8_t *buffer, uint16_t len);

+

+/** @ingroup IP_group_i2c_external_function

+ * @par Description

+ *     Initialize struct mtk_i2c and i2c_msg, then write data to\n

+ *     slave device.

+ * @param[in]

+ *     bus_num: i2c bus number.

+ * @param[in]

+ *     device_addr: slave device 7bits address.

+ * @param[in]

+ *     speed_khz: i2c transfer speed.

+ * @param[in]

+ *     buffer: write data buffer pointer.

+ * @param[in]

+ *     len: write data length.

+ * @return

+ *     0, i2c transfer successfully.\n

+ *     error code from mtk_i2c_transfer().

+ * @par Boundary case and Limitation

+ *     none.

+ * @par Error case and Error handling

+ *     If mtk_i2c_transfer() fails, return its error code.\n

+ * @par Call graph and Caller graph

+ * @par Refer to the source code

+ */

+int mtk_i2c_write(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,

+		  uint8_t *buffer, uint16_t len);

+

+/** @ingroup IP_group_i2c_external_function

+ * @par Description

+ *     Initialize struct mtk_i2c and i2c_msg, first write data to\n

+ *     slave device then read data from slave device.

+ * @param[in]

+ *     bus_num: i2c bus number.

+ * @param[in]

+ *     device_addr: slave device 7bits address.

+ * @param[in]

+ *     speed_khz: i2c transfer speed.

+ * @param[in]

+ *     write_buffer: write data buffer pointer.

+ * @param[out]

+ *     read_buffer: read data buffer pointer.

+ * @param[in]

+ *     write_len: write data length.

+ * @param[in]

+ *     read_len: read data length.

+ * @return

+ *     0, i2c transfer successfully.\n

+ *     error code from mtk_i2c_transfer().

+ * @par Boundary case and Limitation

+ *     none.

+ * @par Error case and Error handling

+ *     If mtk_i2c_transfer() fails, return its error code.\n

+ * @par Call graph and Caller graph

+ * @par Refer to the source code

+ */

+int mtk_i2c_write_read(uint8_t bus_num, uint8_t device_addr, uint32_t speed_khz,

+		       uint8_t *write_buffer, uint8_t *read_buffer,

+		       uint16_t write_len, uint16_t read_len);

+

+#endif /* __I2C_TEST_H__ */

diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_serial_key.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_serial_key.h
new file mode 100644
index 0000000..21be4d8
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_serial_key.h
@@ -0,0 +1,29 @@
+/*
+ * 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
+
+/* serial key */
+#define SERIAL_KEY_HI    (18446744005260632388UL)
+#define SERIAL_KEY_LO    (18446744005260632384UL)
+#define SERIAL_KEY_2_HI  (18446744005260632396UL)
+#define SERIAL_KEY_2_LO  (18446744005260632392UL)
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_trng.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_trng.h
new file mode 100644
index 0000000..ce762ce
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_trng.h
@@ -0,0 +1,40 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*
+* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek Software")
+* have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+* applicable license agreements with MediaTek Inc.
+*/
+
+#ifndef __MTK_TRNG_H__
+#define __MTK_TRNG_H__
+s32 trng_drv_get_random_data(u8 *buf, u32 len);
+
+#endif  /* !defined __MTK_TRNG_H__ */
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_wdt.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_wdt.h
new file mode 100644
index 0000000..98bdfc0
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/mtk_wdt.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <platform/mt_reg_base.h>
+#include <stdbool.h>
+
+void set_clr_fastboot_mode(bool flag);
+void set_clr_recovery_mode(bool flag);
+bool check_fastboot_mode(void);
+bool check_recovery_mode(void);
+void mtk_wdt_init(void);
+void mtk_wdt_disable(void);
+void mtk_arch_reset(char mode);
+/* To inform PMIC that system is ready */
+void mtk_wdt_pwr_latch(void);
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_ecc_hal.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_ecc_hal.h
new file mode 100644
index 0000000..220a55e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_ecc_hal.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2017 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 <kernel/event.h>
+#include <kernel/mutex.h>
+#include <sys/types.h>
+
+#define     ECC_IDLE_MASK       NAND_BIT(0)
+#define     ECC_IRQ_EN          NAND_BIT(0)
+#define     ECC_OP_ENABLE       (1)
+#define     ECC_OP_DISABLE      (0)
+
+#define     ECC_ENCCON          (0x00)
+#define     ECC_ENCCNFG         (0x04)
+#define     ECC_CNFG_4BIT       (0)
+#define     ECC_CNFG_6BIT       (1)
+#define     ECC_CNFG_8BIT       (2)
+#define     ECC_CNFG_10BIT      (3)
+#define     ECC_CNFG_12BIT      (4)
+#define     ECC_CNFG_14BIT      (5)
+#define     ECC_CNFG_16BIT      (6)
+#define     ECC_CNFG_18BIT      (7)
+#define     ECC_CNFG_20BIT      (8)
+#define     ECC_CNFG_22BIT      (9)
+#define     ECC_CNFG_24BIT      (0xa)
+#define     ECC_CNFG_28BIT      (0xb)
+#define     ECC_CNFG_32BIT      (0xc)
+#define     ECC_CNFG_36BIT      (0xd)
+#define     ECC_CNFG_40BIT      (0xe)
+#define     ECC_CNFG_44BIT      (0xf)
+#define     ECC_CNFG_48BIT      (0x10)
+#define     ECC_CNFG_52BIT      (0x11)
+#define     ECC_CNFG_56BIT      (0x12)
+#define     ECC_CNFG_60BIT      (0x13)
+#define     ECC_CNFG_68BIT      (0x14)
+#define     ECC_CNFG_72BIT      (0x15)
+#define     ECC_CNFG_80BIT      (0x16)
+#define     ECC_MODE_SHIFT      (5)
+#define     ECC_MS_SHIFT        (16)
+#define     ECC_ENCDIADDR       (0x08)
+#define     ECC_ENCIDLE         (0x0c)
+#define     ECC_ENCSTA          (0x7c)
+#define     ENC_IDLE            NAND_BIT(0)
+#define     ECC_ENCIRQ_EN       (0x80)
+#define     ECC_ENCIRQ_STA      (0x84)
+#define     PG_IRQ_SEL          NAND_BIT(1)
+#define     ECC_PIO_DIRDY       (0x90)
+#define     PIO_DI_RDY          (0x01)
+#define     ECC_PIO_DI          (0x94)
+#define     ECC_DECCON          (0x100)
+#define     ECC_DECCNFG         (0x104)
+#define     DEC_EMPTY_EN        NAND_BIT(31)
+#define     DEC_CON_SHIFT       (12)
+#define     ECC_DECDIADDR       (0x108)
+#define     ECC_DECIDLE         (0x10c)
+#define     ECC_DECENUM(x)      (0x114 + (x) * sizeof(u32))
+#define     ERR_MASK            (0x7f)
+#define     ECC_DECDONE         (0x124)
+#define     ECC_DECIRQ_EN       (0x200)
+#define     ECC_DECIRQ_STA      (0x204)
+#define     ECC_DECFSM          (0x208)
+#define     FSM_MASK            (0x3f3fff0f)
+#define     FSM_IDLE            (0x01011101)
+
+#define     ECC_ENCPAR(x)       (0x300 + (x) * sizeof(u32))
+#define     ECC_DECEL(x)        (0x500 + (x) * sizeof(u32))
+#define     DECEL_MASK          (0x3fff)
+#define     ECC_TIMEOUT         (500000)
+
+#define     ECC_IDLE_REG(op)    ((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE)
+#define     ECC_CTL_REG(op)     ((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON)
+#define     ECC_IRQ_REG(op)     ((op) == ECC_ENCODE ? ECC_ENCIRQ_EN : ECC_DECIRQ_EN)
+#define     ECC_PARITY_BITS     (14)
+#define     MAX_ECC_STRENGTH    (80)
+
+#define     writew(v, a)        (*REG16(a) = (v))
+#define     readw(a)            (*REG16(a))
+
+struct mtk_ecc {
+    mutex_t lock;
+    event_t irq_event;
+    uintptr_t regs;
+    u32 sectors;
+};
+
+enum mtk_ecc_mode {
+    ECC_DMA_MODE = 0,
+    ECC_NFI_MODE = 1,
+    ECC_PIO_MODE = 2
+};
+
+enum mtk_ecc_operation {
+    ECC_ENCODE,
+    ECC_DECODE
+};
+
+enum mtk_ecc_deccon {
+    ECC_DEC_FER = 1,
+    ECC_DEC_LOCATE = 2,
+    ECC_DEC_CORRECT = 3
+};
+
+struct mtk_ecc_stats {
+    u32 corrected;
+    u32 bitflips;
+    u32 failed;
+};
+
+struct mtk_ecc_config {
+    enum mtk_ecc_operation op;
+    enum mtk_ecc_mode mode;
+    enum mtk_ecc_deccon deccon;
+    u32 addr;
+    u32 strength;
+    u32 sectors;
+    u32 len;
+};
+
+int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+                          u8 *data, u32 bytes, int polling);
+int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config, int polling);
+void mtk_ecc_disable(struct mtk_ecc *ecc);
+void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats, u32 sectors);
+int mtk_ecc_cpu_correct(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats, u8 *data, u32 sector, int polling);
+int mtk_ecc_wait_done(struct mtk_ecc *ecc, enum mtk_ecc_operation op, int polling);
+int mtk_ecc_hw_init(struct mtk_ecc **ext_ecc);
+int mtk_ecc_wait_decode_fsm_idle(struct mtk_ecc *ecc);
+int mtk_ecc_decode(struct mtk_ecc *ecc, struct mtk_ecc_config *config, u8 *data, u32 len, int polling);
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nand_bbt.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nand_bbt.h
new file mode 100644
index 0000000..3fdb9fb
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nand_bbt.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 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 <platform/nand/mtk_nand_nal.h>
+
+#define SCAN_BBT_MAXBLOCKS      4
+
+int mtk_nand_isbad_bbt(struct mtk_nand_chip *chip, u32 page);
+int mtk_nand_scan_bbt(struct mtk_nand_chip *chip);
+int mtk_nand_markbad_bbt(struct mtk_nand_chip *chip, u32 page);
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nand_common.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nand_common.h
new file mode 100644
index 0000000..f2bf4ac
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nand_common.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017 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 <platform.h>
+
+#define NAND_BIT(nr)        (1UL << (nr))
+#define NAND_GENMASK(h, l)  (((~0UL) << (l)) & (~0UL >> ((sizeof(unsigned long) * 8) - 1 - (h))))
+#define DIV_ROUND_UP(n,d)   (((n) + (d) - 1) / (d))
+#define clamp(val, lo, hi)  MIN((typeof(val))MAX(val, lo), hi)
+
+#define MTK_TIMEOUT         (500000)
+
+#define KB(x)               ((x) * 1024UL)
+#define MB(x)               (KB(x) * 1024UL)
+
+#define swap(a, b) \
+    do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while(0)
+
+/*
+ * wait until cond gets true or timeout.
+ *
+ * cond : C expression to wait
+ * timeout : usecs
+ *
+ * Returns:
+ * 0 : if cond = false after timeout elapsed.
+ * 1 : if cond = true after timeout elapsed,
+ * or the remain usecs if cond = true before timeout elapsed.
+ */
+#define check_with_timeout(cond, timeout)                      \
+({                                                             \
+    lk_bigtime_t __ret;                                        \
+    if (cond) {                                                \
+        __ret = timeout;                                       \
+    } else {                                                   \
+        lk_bigtime_t __end = current_time_hires() + timeout;   \
+                                                               \
+        for (;;) {                                             \
+            lk_bigtime_t __now = current_time_hires();         \
+                                                               \
+            if (cond) {                                        \
+                __ret = (__end > __now) ? (__end - __now) : 1; \
+                    break;                                     \
+            }                                                  \
+                                                               \
+            if (__end <= __now) {                              \
+                __ret = 0;                                     \
+                break;                                         \
+            }                                                  \
+        }                                                      \
+    }                                                          \
+    __ret;                                                     \
+})
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nand_nal.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nand_nal.h
new file mode 100644
index 0000000..a4d4723
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nand_nal.h
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2017 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 <platform/nand/mtk_ecc_hal.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+/* Select the chip by setting nCE to low */
+#define NAND_NCE                    0x01
+/* Select the command latch by setting CLE to high */
+#define NAND_CLE                    0x02
+/* Select the address latch by setting ALE to high */
+#define NAND_ALE                    0x04
+
+#define NAND_CTRL_CLE               (NAND_NCE | NAND_CLE)
+#define NAND_CTRL_ALE               (NAND_NCE | NAND_ALE)
+#define NAND_CTRL_CHANGE            0x80
+
+/*
+ * Standard NAND flash commands
+ */
+#define NAND_CMD_READ0              0
+#define NAND_CMD_READ1              1
+#define NAND_CMD_RNDOUT             5
+#define NAND_CMD_PAGEPROG           0x10
+#define NAND_CMD_READOOB            0x50
+#define NAND_CMD_ERASE1             0x60
+#define NAND_CMD_STATUS             0x70
+#define NAND_CMD_SEQIN              0x80
+#define NAND_CMD_RNDIN              0x85
+#define NAND_CMD_READID             0x90
+#define NAND_CMD_ERASE2             0xd0
+#define NAND_CMD_PARAM              0xec
+#define NAND_CMD_GET_FEATURES       0xee
+#define NAND_CMD_SET_FEATURES       0xef
+#define NAND_CMD_RESET              0xff
+#define NAND_CMD_LOCK               0x2a
+#define NAND_CMD_UNLOCK1            0x23
+#define NAND_CMD_UNLOCK2            0x24
+
+/* Extended commands for large page devices */
+#define NAND_CMD_READSTART          0x30
+#define NAND_CMD_READCACHESEQ       0x31
+#define NAND_CMD_READCACHELAST      0x3f
+#define NAND_CMD_RNDOUTSTART        0xE0
+#define NAND_CMD_CACHEDPROG         0x15
+#define NAND_CMD_NONE               -1
+
+#define ONFI_SUBFEATURE_PARAM_LEN   4
+
+/* Status bits */
+#define NAND_STATUS_FAIL            0x01
+#define NAND_STATUS_FAIL_N1         0x02
+#define NAND_STATUS_TRUE_READY      0x20
+#define NAND_STATUS_READY           0x40
+#define NAND_STATUS_WP              0x80
+
+/* Search good / bad pattern on the first and the second page */
+#define NAND_BBT_SCAN2NDPAGE        0x00008000
+/* Search good / bad pattern on the last page of the eraseblock */
+#define NAND_BBT_SCANLASTPAGE       0x00010000
+
+/* Chip has cache read function */
+#define NAND_CACHEREAD              0x00000004
+/* Chip has cache program function */
+#define NAND_CACHEPRG               0x00000008
+
+/*
+ * Some MLC NANDs need data scrambling to limit bitflips caused by repeated
+ * patterns.
+ */
+#define NAND_NEED_SCRAMBLING        0x00002000
+
+#define NAND_HAS_CACHEPROG(chip)    ((chip->options & NAND_CACHEPRG))
+#define NAND_HAS_CACHEREAD(chip)    ((chip->options & NAND_CACHEREAD))
+
+/* Max NAND ID length */
+#define NAND_MAX_ID_LEN             8
+
+struct mtk_nand_flash_dev {
+    const char *name;
+    u8 id[NAND_MAX_ID_LEN];
+    u8 id_len;
+
+    /* unit: KByte */
+    u32 chipsize;
+    u32 erasesize;
+    u32 pagesize;
+    u16 oobsize;
+    u32 fdmeccsize;
+    u8 bits_per_cell;
+
+    /* customized setting if need */
+    u32 acctiming;
+    u32 ecc_size;
+    u32 ecc_strength;
+    u32 bbt_options;
+    u32 options;
+};
+
+enum {
+    NAND_OPS_RAW_DMA_POLL = 0,
+    NAND_OPS_RAW_DMA_IRQ,
+    NAND_OPS_RAW_PIO_POLL,
+    NAND_OPS_RAW_PIO_IRQ,
+    NAND_OPS_ECC_DMA_POLL,
+    NAND_OPS_ECC_DMA_IRQ,
+    NAND_OPS_ECC_PIO_POLL,
+    NAND_OPS_ECC_PIO_IRQ,
+    NAND_OPS_ERASE_POLL,
+    NAND_OPS_ERASE_IRQ,
+};
+
+enum mtk_randomizer_operation {RAND_ENCODE, RAND_DECODE};
+
+struct mtk_nand_ops {
+    u32 mode;
+    u64 offset;
+    u64 len;
+    const u8 *writebuf;
+    u8 *readbuf;
+    /* ecc protected oob data */
+    u8 *oobeccbuf;
+    u32 oobeccoffs;
+    u32 oobecclen;
+    /* ecc unprotected oob data */
+    u8 *oobrawbuf;
+    u32 oobrawoffs;
+    u32 oobrawlen;
+    /* ecc parity data */
+    u8 *oobparitybuf;
+    u32 oobparityoffs;
+    u32 oobparitylen;
+};
+
+struct mtk_nand_chip {
+    u8 (*read_byte)(struct mtk_nand_chip *nand);
+    void (*write_byte)(struct mtk_nand_chip *nand, u8 byte);
+    void (*write_buf)(struct mtk_nand_chip *nand, const u8 *buf, int len);
+    void (*read_buf)(struct mtk_nand_chip *nand, u8 *buf, int len);
+    void (*select_chip)(struct mtk_nand_chip *nand, int chip);
+    void (*cmd_ctrl)(struct mtk_nand_chip *nand, int dat, unsigned int ctrl);
+    int (*dev_ready)(struct mtk_nand_chip *nand);
+    int (*wait_busy_irq)(struct mtk_nand_chip *nand);
+    void (*cmdfunc)(struct mtk_nand_chip *nand, unsigned command, int column,
+                    int page_addr);
+    int(*waitfunc)(struct mtk_nand_chip *this, int polling);
+
+    int (*block_bad)(struct mtk_nand_chip *nand, u64 ofs);
+    int (*block_markbad)(struct mtk_nand_chip *nand, u64 ofs);
+
+    int (*write_page_ecc_dma_polling)(struct mtk_nand_chip *chip, const u8 *buf,
+                                      int page);
+    int (*write_page_ecc_dma_irq)(struct mtk_nand_chip *chip, const u8 *buf,
+                                  int page);
+    int (*write_page_ecc_pio_polling)(struct mtk_nand_chip *chip, const u8 *buf,
+                                      int page);
+    int (*write_page_ecc_pio_irq)(struct mtk_nand_chip *chip, const u8 *buf,
+                                  int page);
+    int (*write_page_raw_dma_polling)(struct mtk_nand_chip *chip, const u8 *buf,
+                                      int page);
+    int (*write_page_raw_dma_irq)(struct mtk_nand_chip *chip, const u8 *buf,
+                                  int page);
+    int (*write_page_raw_pio_polling)(struct mtk_nand_chip *chip, const u8 *buf,
+                                      int page);
+    int (*write_page_raw_pio_irq)(struct mtk_nand_chip *chip, const u8 *buf,
+                                  int page);
+    int (*write_subpage_ecc_dma_polling)(struct mtk_nand_chip *chip, u32 offset,
+                                         u32 data_len, const u8 *buf, int page);
+    int (*write_subpage_ecc_dma_irq)(struct mtk_nand_chip *chip, u32 offset,
+                                     u32 data_len, const u8 *buf, int page);
+    int (*write_subpage_ecc_pio_polling)(struct mtk_nand_chip *chip, u32 offset,
+                                         u32 data_len, const u8 *buf, int page);
+    int (*write_subpage_ecc_pio_irq)(struct mtk_nand_chip *chip, u32 offset,
+                                     u32 data_len, const u8 *buf, int page);
+
+    int (*read_subpage_ecc_dma_polling)(struct mtk_nand_chip *chip, u32 off,
+                                        u32 len, u8 *p, int pg);
+    int (*read_subpage_ecc_dma_irq)(struct mtk_nand_chip *chip, u32 off,
+                                    u32 len, u8 *p, int pg);
+    int (*read_subpage_ecc_pio_polling)(struct mtk_nand_chip *chip, u32 off,
+                                        u32 len, u8 *p, int pg);
+    int (*read_subpage_ecc_pio_irq)(struct mtk_nand_chip *chip, u32 off,
+                                    u32 len, u8 *p, int pg);
+    int (*read_page_ecc_dma_polling)(struct mtk_nand_chip *chip, u8 *p, int pg);
+    int (*read_page_ecc_dma_irq)(struct mtk_nand_chip *chip, u8 *p, int pg);
+    int (*read_page_ecc_pio_polling)(struct mtk_nand_chip *chip, u8 *p, int pg);
+    int (*read_page_ecc_pio_irq)(struct mtk_nand_chip *chip, u8 *p, int pg);
+    int (*read_page_raw_dma_polling)(struct mtk_nand_chip *chip, u8 *buf, int page);
+    int (*read_page_raw_dma_irq)(struct mtk_nand_chip *chip, u8 *buf, int page);
+    int (*read_page_raw_pio_polling)(struct mtk_nand_chip *chip, u8 *buf, int page);
+    int (*read_page_raw_pio_irq)(struct mtk_nand_chip *chip, u8 *buf, int page);
+    void (*enable_randomizer)(struct mtk_nand_chip *chip, int page,
+                              enum mtk_randomizer_operation rand, int repage);
+    void (*disable_randomizer)(struct mtk_nand_chip *chip);
+    int (*fill_oob_ecc)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+    int (*fill_oob_raw)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+    int (*fill_oob_parity)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+    int (*transfer_oob_ecc)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+    int (*transfer_oob_raw)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+    int (*transfer_oob_parity)(struct mtk_nand_chip *chip, u8* buf, u32 offset, u32 len);
+
+    /* nand device information */
+    u64 totalsize;
+    /* unit: Byte */
+    u64 chipsize;
+    u32 pagesize;
+    u32 oobsize;
+    u32 blocksize;
+    u32 ecc_size;
+    u32 ecc_strength;
+    u32 ecc_steps;
+    u32 subpagesize;
+    u32 fdm_ecc_size;
+    u32 oob_free_ecc_size;
+    u32 oob_free_raw_size;
+    u8 bits_per_cell;
+    u32 page_per_chip;
+    u32 page_per_block;
+    int chip_delay;
+    u32 options;
+    u8 numchips;
+    int activechip;
+
+    u8 *databuf;
+    u8 *oob_poi;
+
+    u8 *bbt;
+    u32 bbt_options;
+    int bbt_block;
+    int badblockpos;
+    int badblockbits;
+
+    struct mtk_ecc_stats stats;
+
+    void *priv;
+};
+
+static inline void *nand_get_controller_data(struct mtk_nand_chip *chip)
+{
+    return chip->priv;
+}
+
+static inline void nand_set_controller_data(struct mtk_nand_chip *chip, void *priv)
+{
+    chip->priv = priv;
+}
+
+static inline bool nand_is_slc(struct mtk_nand_chip *chip)
+{
+    return chip->bits_per_cell == 1;
+}
+
+extern struct mtk_nand_flash_dev nand_flash_devs[];
+int mtk_nand_erase(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops);
+int mtk_nand_write(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops);
+int mtk_nand_read(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops);
+int mtk_nand_block_isbad(struct mtk_nand_chip *chip, u32 page);
+int mtk_nand_block_markbad(struct mtk_nand_chip *chip, u32 page);
+int mtk_nand_init(void);
+int mtk_nand_scan(struct mtk_nand_chip *chip, int maxchips);
+int mtk_nand_scan_tail(struct mtk_nand_chip *chip);
+int nand_reset(struct mtk_nand_chip *chip, int chipnr);
+struct mtk_nand_chip *mtk_get_nand_chip(void);
+int mtk_nand_block_checkbad(struct mtk_nand_chip *chip, u32 page);
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nfi_hal.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nfi_hal.h
new file mode 100644
index 0000000..ccb39a0
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/mtk_nfi_hal.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2017 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 <platform/nand/mtk_nand_nal.h>
+#include <kernel/mutex.h>
+#include <kernel/event.h>
+
+#define     NFI_CNFG                (0x00)
+#define     CNFG_AHB                NAND_BIT(0)
+#define     CNFG_READ_EN            NAND_BIT(1)
+#define     CNFG_DMA_BURST_EN       NAND_BIT(2)
+#define     CNFG_RESEED_SEC_EN      NAND_BIT(4)
+#define     CNFG_RAND_SEL           NAND_BIT(5)
+#define     CNFG_RAND_MASK          (3 << 4)
+#define     CNFG_BYTE_RW            NAND_BIT(6)
+#define     CNFG_HW_ECC_EN          NAND_BIT(8)
+#define     CNFG_AUTO_FMT_EN        NAND_BIT(9)
+#define     CNFG_OP_CUST            (6 << 12)
+#define     NFI_PAGEFMT             (0x04)
+#define     PAGEFMT_FDM_ECC_SHIFT   (12)
+#define     PAGEFMT_FDM_SHIFT       (8)
+#define     PAGEFMT_SPARE_16        (0)
+#define     PAGEFMT_SPARE_26        (1)
+#define     PAGEFMT_SPARE_27        (2)
+#define     PAGEFMT_SPARE_28        (3)
+#define     PAGEFMT_SPARE_32        (4)
+#define     PAGEFMT_SPARE_36        (5)
+#define     PAGEFMT_SPARE_40        (6)
+#define     PAGEFMT_SPARE_44        (7)
+#define     PAGEFMT_SPARE_48        (8)
+#define     PAGEFMT_SPARE_49        (9)
+#define     PAGEFMT_SPARE_50        (0xa)
+#define     PAGEFMT_SPARE_51        (0xb)
+#define     PAGEFMT_SPARE_52        (0xc)
+#define     PAGEFMT_SPARE_62        (0xd)
+#define     PAGEFMT_SPARE_61        (0xe)
+#define     PAGEFMT_SPARE_63        (0xf)
+#define     PAGEFMT_SPARE_64        (0x10)
+#define     PAGEFMT_SPARE_67        (0x11)
+#define     PAGEFMT_SPARE_74        (0x12)
+#define     PAGEFMT_SPARE_SHIFT     (16)
+#define     PAGEFMT_SEC_SEL_512     NAND_BIT(2)
+#define     PAGEFMT_512_2K          (0)
+#define     PAGEFMT_2K_4K           (1)
+#define     PAGEFMT_4K_8K           (2)
+#define     PAGEFMT_8K_16K          (3)
+#define     NFI_CON                 (0x08)
+#define     CON_FIFO_FLUSH          NAND_BIT(0)
+#define     CON_NFI_RST             NAND_BIT(1)
+#define     CON_BRD                 NAND_BIT(8)  /* burst  read */
+#define     CON_BWR                 NAND_BIT(9) /* burst  write */
+#define     CON_SEC_SHIFT           (12)
+#define     NFI_ACCCON              (0x0c)
+#define     NFI_INTR_EN             (0x10)
+#define     INTR_BUSY_RETURN_EN     NAND_BIT(4)
+#define     INTR_AHB_DONE_EN        NAND_BIT(6)
+#define     NFI_INTR_STA            (0x14)
+#define     NFI_CMD                 (0x20)
+#define     NFI_ADDRNOB             (0x30)
+#define     NFI_COLADDR             (0x34)
+#define     NFI_ROWADDR             (0x38)
+#define     NFI_STRDATA             (0x40)
+#define     STAR_EN                 (1)
+#define     STAR_DE                 (0)
+#define     NFI_CNRNB               (0x44)
+#define     NFI_DATAW               (0x50)
+#define     NFI_DATAR               (0x54)
+#define     NFI_PIO_DIRDY           (0x58)
+#define     PIO_DI_RDY              (0x01)
+#define     NFI_STA                 (0x60)
+#define     STA_CMD                 NAND_BIT(0)
+#define     STA_ADDR                NAND_BIT(1)
+#define     STA_BUSY                NAND_BIT(8)
+#define     STA_EMP_PAGE            NAND_BIT(12)
+#define     NFI_FSM_CUSTDATA        (0xe << 16)
+#define     NFI_FSM_MASK            (0xf << 16)
+#define     NFI_ADDRCNTR            (0x70)
+#define     CNTR_MASK               NAND_GENMASK(16, 12)
+#define     ADDRCNTR_SEC_SHIFT      (12)
+#define     ADDRCNTR_SEC(val)       (((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT)
+#define     NFI_STRADDR             (0x80)
+#define     NFI_BYTELEN             (0x84)
+#define     NFI_CSEL                (0x90)
+#define     NFI_FDML(x)             (0xa0 + (x) * sizeof(u32) * 2)
+#define     NFI_FDMM(x)             (0xa4 + (x) * sizeof(u32) * 2)
+#define     NFI_FDM_MAX_SIZE        (8)
+#define     NFI_FDM_MIN_SIZE        (1)
+#define     NFI_MASTER_STA          (0x224)
+#define     MASTER_STA_MASK         (0x3)
+#define     MASTER_BUS_BUSY         (0x3)
+#define     NFI_RANDOM_CNFG         (0x238)
+#define     RAN_ENCODE_EN           NAND_BIT(0)
+#define     ENCODE_SEED_SHIFT       (1)
+#define     RAN_DECODE_EN           NAND_BIT(16)
+#define     DECODE_SEED_SHIFT       (17)
+#define     RAN_SEED_MASK           (0x7fff)
+#define     RAND_SEED_SHIFT(op)     \
+    ((op) == RAND_ENCODE ? ENCODE_SEED_SHIFT : DECODE_SEED_SHIFT)
+#define     RAND_EN(op)             \
+    ((op) == RAND_ENCODE ? RAN_ENCODE_EN : RAN_DECODE_EN)
+#define     NFI_EMPTY_THRESH        (0x23c)
+
+#define     MTK_RESET_TIMEOUT       (1000000)
+#define     MTK_MAX_SECTOR          (16)
+#define     MTK_NAND_MAX_NSELS      (2)
+
+struct mtk_nfc_bad_mark_ctl {
+    void (*bm_swap)(struct mtk_nand_chip *chip, u8 *buf, int raw);
+    u32 sec;
+    u32 pos;
+};
+
+/*
+ * FDM: region used to store free OOB data
+ */
+struct mtk_nfc_fdm {
+    u32 reg_size;
+    u32 ecc_size;
+};
+
+struct mtk_nfc {
+    mutex_t lock;
+    event_t irq_event;
+    struct mtk_ecc_config ecc_cfg;
+    struct mtk_ecc *ecc;
+    uintptr_t regs;
+    u8 *buffer;
+};
+
+struct mtk_nfc_nand_chip {
+    struct mtk_nand_chip chip;
+    struct mtk_nfc_bad_mark_ctl bad_mark;
+    struct mtk_nfc_fdm fdm;
+    u32 spare_per_sector;
+    u32 acctiming;
+};
+
+int mtk_nfc_nand_chip_init(struct mtk_nand_chip **ext_nand);
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/nand.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/nand.h
new file mode 100644
index 0000000..adbaf69
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/nand/nand.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 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
+
+int nand_init_device(void);
+void nand_dump_device_info(void);
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/platform_blx.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/platform_blx.h
new file mode 100644
index 0000000..930b6a4
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/platform_blx.h
@@ -0,0 +1,28 @@
+/*
+ * 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 <compiler.h>
+#include <debug.h>
+
+void platform_memory_init(void);
+void platform_early_init_blx(void);
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/pll.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/pll.h
new file mode 100644
index 0000000..8b06870
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/pll.h
@@ -0,0 +1,239 @@
+#ifndef PLL_H
+#define PLL_H
+
+/* MCUCFG Register */
+#define MP0_PLL_DIV_CFG     (MCUSYS_CFGREG_BASE + 0x7A0) //ARMPLL_LL
+#define MP1_PLL_DIV_CFG     (MCUSYS_CFGREG_BASE + 0x7A4) //ARMPLL_L
+#define BUS_PLL_DIV_CFG     (MCUSYS_CFGREG_BASE + 0x7C0) //CCIPLL
+
+/* APMIXEDSYS Register */
+#define AP_PLL_CON0     (APMIXED_BASE + 0x00)
+#define AP_PLL_CON1     (APMIXED_BASE + 0x04)
+#define AP_PLL_CON2     (APMIXED_BASE + 0x08)
+#define AP_PLL_CON3     (APMIXED_BASE + 0x0C)
+#define AP_PLL_CON4     (APMIXED_BASE + 0x10)
+#define AP_PLL_CON5     (APMIXED_BASE + 0x14)
+#define CLKSQ_STB_CON0      (APMIXED_BASE + 0x18)
+#define PLL_PWR_CON0        (APMIXED_BASE + 0x1C)
+#define PLL_PWR_CON1        (APMIXED_BASE + 0x20)
+#define PLL_ISO_CON0        (APMIXED_BASE + 0x24)
+#define PLL_ISO_CON1        (APMIXED_BASE + 0x28)
+#define PLL_STB_CON0        (APMIXED_BASE + 0x2C)
+#define DIV_STB_CON0        (APMIXED_BASE + 0x30)
+#define PLL_CHG_CON0        (APMIXED_BASE + 0x34)
+#define PLL_TEST_CON0       (APMIXED_BASE + 0x38)
+#define PLL_TEST_CON1       (APMIXED_BASE + 0x3C)
+#define APLL1_TUNER_CON0    (APMIXED_BASE + 0x40)
+#define PLLON_CON0      (APMIXED_BASE + 0x44)
+#define PLLON_CON1      (APMIXED_BASE + 0x48)
+
+#define AP_PLLGP_CON0       (APMIXED_BASE + 0x200)
+#define AP_PLLGP_CON1       (APMIXED_BASE + 0x204)
+#define AP_PLLGP2_CON0      (APMIXED_BASE + 0x300)
+#define AP_PLLGP2_CON1      (APMIXED_BASE + 0x304)
+#define AP_PLLGP2_CON2      (APMIXED_BASE + 0x308)
+
+#define UNIVPLL_CON0        (APMIXED_BASE + 0x208)
+#define UNIVPLL_CON1        (APMIXED_BASE + 0x20C)
+#define UNIVPLL_CON2        (APMIXED_BASE + 0x210)
+#define UNIVPLL_CON3        (APMIXED_BASE + 0x214)
+
+#define MFGPLL_CON0     (APMIXED_BASE + 0x218)
+#define MFGPLL_CON1     (APMIXED_BASE + 0x21C)
+#define MFGPLL_CON2     (APMIXED_BASE + 0x220)
+#define MFGPLL_CON3     (APMIXED_BASE + 0x224)
+
+#define MAINPLL_CON0        (APMIXED_BASE + 0x228)
+#define MAINPLL_CON1        (APMIXED_BASE + 0x22c)
+#define MAINPLL_CON2        (APMIXED_BASE + 0x230)
+#define MAINPLL_CON3        (APMIXED_BASE + 0x234)
+
+#define ARMPLL_CON0     (APMIXED_BASE + 0x30C)
+#define ARMPLL_CON1     (APMIXED_BASE + 0x310)
+#define ARMPLL_CON2     (APMIXED_BASE + 0x314)
+#define ARMPLL_CON3     (APMIXED_BASE + 0x318)
+
+#define APLL1_CON0      (APMIXED_BASE + 0x31C)
+#define APLL1_CON1      (APMIXED_BASE + 0x320)
+#define APLL1_CON2      (APMIXED_BASE + 0x324)
+#define APLL1_CON3      (APMIXED_BASE + 0x328)
+#define APLL1_CON4      (APMIXED_BASE + 0x32C)
+
+#define MMPLL_CON0      (APMIXED_BASE + 0x330)
+#define MMPLL_CON1      (APMIXED_BASE + 0x334)
+#define MMPLL_CON2      (APMIXED_BASE + 0x338)
+#define MMPLL_CON3      (APMIXED_BASE + 0x33C)
+
+#define MPLL_CON0       (APMIXED_BASE + 0x340)
+#define MPLL_CON1       (APMIXED_BASE + 0x344)
+#define MPLL_CON2       (APMIXED_BASE + 0x348)
+#define MPLL_CON3       (APMIXED_BASE + 0x34C)
+
+#define MSDCPLL_CON0        (APMIXED_BASE + 0x350)
+#define MSDCPLL_CON1        (APMIXED_BASE + 0x354)
+#define MSDCPLL_CON2        (APMIXED_BASE + 0x358)
+#define MSDCPLL_CON3        (APMIXED_BASE + 0x35C)
+
+#define APLL2_CON0      (APMIXED_BASE + 0x360)
+#define APLL2_CON1      (APMIXED_BASE + 0x364)
+#define APLL2_CON2      (APMIXED_BASE + 0x368)
+#define APLL2_CON3      (APMIXED_BASE + 0x36C)
+#define APLL2_CON4      (APMIXED_BASE + 0x370)
+
+#define LVDSPLL_CON0        (APMIXED_BASE + 0x374)
+#define LVDSPLL_CON1        (APMIXED_BASE + 0x378)
+#define LVDSPLL_CON2        (APMIXED_BASE + 0x37C)
+#define LVDSPLL_CON3        (APMIXED_BASE + 0x380)
+
+#define DSPPLL_CON0     (APMIXED_BASE + 0x390)
+#define DSPPLL_CON1     (APMIXED_BASE + 0x394)
+#define DSPPLL_CON2     (APMIXED_BASE + 0x398)
+#define DSPPLL_CON3     (APMIXED_BASE + 0x39C)
+
+#define APUPLL_CON0     (APMIXED_BASE + 0x3A0)
+#define APUPLL_CON1     (APMIXED_BASE + 0x3A4)
+#define APUPLL_CON2     (APMIXED_BASE + 0x3A8)
+#define APUPLL_CON3     (APMIXED_BASE + 0x3AC)
+#define ULPLL_CON1      (APMIXED_BASE + 0x3B4)
+
+/* MCUCFG Register */
+#define ACLKEN_DIV      (MCUCFG_BASE + 0x640)
+
+/* TOPCKGEN Register */
+#define CLK_MODE        (CKSYS_BASE + 0x000)
+#define CLK_CFG_UPDATE      (CKSYS_BASE + 0x004)
+#define CLK_CFG_UPDATE1     (CKSYS_BASE + 0x008)
+#define CLK_CFG_0       (CKSYS_BASE + 0x040)
+#define CLK_CFG_0_SET       (CKSYS_BASE + 0x044)
+#define CLK_CFG_0_CLR       (CKSYS_BASE + 0x048)
+#define CLK_CFG_1       (CKSYS_BASE + 0x050)
+#define CLK_CFG_1_SET       (CKSYS_BASE + 0x054)
+#define CLK_CFG_1_CLR       (CKSYS_BASE + 0x058)
+#define CLK_CFG_2       (CKSYS_BASE + 0x060)
+#define CLK_CFG_2_SET       (CKSYS_BASE + 0x064)
+#define CLK_CFG_2_CLR       (CKSYS_BASE + 0x068)
+#define CLK_CFG_3       (CKSYS_BASE + 0x070)
+#define CLK_CFG_3_SET       (CKSYS_BASE + 0x074)
+#define CLK_CFG_3_CLR       (CKSYS_BASE + 0x078)
+#define CLK_CFG_4       (CKSYS_BASE + 0x080)
+#define CLK_CFG_4_SET       (CKSYS_BASE + 0x084)
+#define CLK_CFG_4_CLR       (CKSYS_BASE + 0x088)
+#define CLK_CFG_5       (CKSYS_BASE + 0x090)
+#define CLK_CFG_5_SET       (CKSYS_BASE + 0x094)
+#define CLK_CFG_5_CLR       (CKSYS_BASE + 0x098)
+#define CLK_CFG_6       (CKSYS_BASE + 0x0A0)
+#define CLK_CFG_6_SET       (CKSYS_BASE + 0x0A4)
+#define CLK_CFG_6_CLR       (CKSYS_BASE + 0x0A8)
+#define CLK_CFG_7       (CKSYS_BASE + 0x0B0)
+#define CLK_CFG_7_SET       (CKSYS_BASE + 0x0B4)
+#define CLK_CFG_7_CLR       (CKSYS_BASE + 0x0B8)
+#define CLK_CFG_8       (CKSYS_BASE + 0x0C0)
+#define CLK_CFG_8_SET       (CKSYS_BASE + 0x0C4)
+#define CLK_CFG_8_CLR       (CKSYS_BASE + 0x0C8)
+#define CLK_CFG_9       (CKSYS_BASE + 0x0D0)
+#define CLK_CFG_9_SET       (CKSYS_BASE + 0x0D4)
+#define CLK_CFG_9_CLR       (CKSYS_BASE + 0x0D8)
+#define CLK_CFG_10      (CKSYS_BASE + 0x0E0)
+#define CLK_CFG_10_SET      (CKSYS_BASE + 0x0E4)
+#define CLK_CFG_10_CLR      (CKSYS_BASE + 0x0E8)
+#define CLK_CFG_11      (CKSYS_BASE + 0x0EC)
+#define CLK_CFG_11_SET      (CKSYS_BASE + 0x0F0)
+#define CLK_CFG_11_CLR      (CKSYS_BASE + 0x0F4)
+
+#define CLK_MISC_CFG_0      (CKSYS_BASE + 0x104)
+#define CLK_MISC_CFG_1      (CKSYS_BASE + 0x108)
+#define CLK_DBG_CFG     (CKSYS_BASE + 0x10C)
+#define CLK_SCP_CFG_0       (CKSYS_BASE + 0x200)
+#define CLK_SCP_CFG_1       (CKSYS_BASE + 0x204)
+#define CLK26CALI_0     (CKSYS_BASE + 0x220)
+#define CLK26CALI_1     (CKSYS_BASE + 0x224)
+#define CKSTA_REG       (CKSYS_BASE + 0x230)
+#define CKSTA1_REG      (CKSYS_BASE + 0x234)
+#define CLKMON_CLK_SEL_REG  (CKSYS_BASE + 0x300)
+#define CLKMON_K1_REG       (CKSYS_BASE + 0x304)
+#define CLK_AUDDIV_0        (CKSYS_BASE + 0x320)
+#define CLK_AUDDIV_1        (CKSYS_BASE + 0x324)
+#define CLK_AUDDIV_2        (CKSYS_BASE + 0x328)
+#define CLK_AUDDIV_3        (CKSYS_BASE + 0x32C)
+#define AUD_TOP_CFG     (CKSYS_BASE + 0x330)
+#define AUD_TOP_MON     (CKSYS_BASE + 0x334)
+#define CLK_PDN_REG     (CKSYS_BASE + 0x400)
+#define CLK_EXTCK_REG       (CKSYS_BASE + 0x500)
+
+#define CLK_MSDCCG_REG       (CKSYS_BASE + 0x10C0)
+
+/* INFRASYS Register */
+#define INFRA_GLOBALCON_DCMCTL      (INFRACFG_AO_BASE + 0x50)
+#define INFRA_BUS_DCM_CTRL      (INFRACFG_AO_BASE + 0x70)
+#define PERI_BUS_DCM_CTRL       (INFRACFG_AO_BASE + 0x74)
+#define MODULE_SW_CG_0_SET      (INFRACFG_AO_BASE + 0x80)
+#define MODULE_SW_CG_0_CLR      (INFRACFG_AO_BASE + 0x84)
+#define MODULE_SW_CG_1_SET      (INFRACFG_AO_BASE + 0x88)
+#define MODULE_SW_CG_1_CLR      (INFRACFG_AO_BASE + 0x8C)
+#define MODULE_SW_CG_0_STA      (INFRACFG_AO_BASE + 0x90)
+#define MODULE_SW_CG_1_STA      (INFRACFG_AO_BASE + 0x94)
+#define MODULE_CLK_SEL          (INFRACFG_AO_BASE + 0x98)
+#define MODULE_SW_CG_2_SET      (INFRACFG_AO_BASE + 0xA4)
+#define MODULE_SW_CG_2_CLR      (INFRACFG_AO_BASE + 0xA8)
+#define MODULE_SW_CG_2_STA      (INFRACFG_AO_BASE + 0xAC)
+#define MODULE_SW_CG_3_SET      (INFRACFG_AO_BASE + 0xC0)
+#define MODULE_SW_CG_3_CLR      (INFRACFG_AO_BASE + 0xC4)
+#define MODULE_SW_CG_3_STA      (INFRACFG_AO_BASE + 0xC8)
+#define MODULE_SW_CG_4_SET      (INFRACFG_AO_BASE + 0xD0)
+#define MODULE_SW_CG_4_CLR      (INFRACFG_AO_BASE + 0xD4)
+#define MODULE_SW_CG_4_STA      (INFRACFG_AO_BASE + 0xD8)
+#define INFRA_TOPAXI_SI0_CTL        (INFRACFG_AO_BASE + 0x0200)
+#define INFRA_TOPAXI_SI1_CTL        (INFRACFG_AO_BASE + 0x0204)
+#define INFRA_TOPAXI_PROTECTEN      (INFRACFG_AO_BASE + 0x0220)
+#define INFRA_TOPAXI_PROTECTEN_STA0 (INFRACFG_AO_BASE + 0x0224)
+#define INFRA_TOPAXI_PROTECTEN_STA1 (INFRACFG_AO_BASE + 0x0228)
+#define INFRA_TOPAXI_PROTECTEN_1    (INFRACFG_AO_BASE + 0x0250)
+#define INFRA_TOPAXI_PROTECTEN_STA0_1   (INFRACFG_AO_BASE + 0x0254)
+#define INFRA_TOPAXI_PROTECTEN_STA1_1   (INFRACFG_AO_BASE + 0x0258)
+#define INFRA_TOPAXI_PROTECTEN_SET  (INFRACFG_AO_BASE + 0x02A0)
+#define INFRA_TOPAXI_PROTECTEN_CLR  (INFRACFG_AO_BASE + 0x02A4)
+#define INFRA_TOPAXI_PROTECTEN_1_SET    (INFRACFG_AO_BASE + 0x02A8)
+#define INFRA_TOPAXI_PROTECTEN_1_CLR    (INFRACFG_AO_BASE + 0x02AC)
+#define INFRA_PLL_ULPOSC_CON0       (INFRACFG_AO_BASE + 0x0B00)
+#define INFRA_PLL_ULPOSC_CON1       (INFRACFG_AO_BASE + 0x0B04)
+
+/* Pericfg Register*/
+#define PERIAXI_SI0_CTL         (PERICFG_BASE + 0x20C)
+#define PERIAXI_SI1_CTL         (PERICFG_BASE + 0x210)
+
+/* Audio Register*/
+#define AUDIO_TOP_CON0          (AUDIO_BASE + 0x0000)
+#define AUDIO_TOP_CON1          (AUDIO_BASE + 0x0004)
+#define AUDIO_TOP_CON2          (AUDIO_BASE + 0x0008)
+#define AUDIO_TOP_CON3          (AUDIO_BASE + 0x000C)
+
+/* MFGCFG Register*/
+#define MFG_CG_CON          (MFGCFG_BASE + 0x000)
+#define MFG_CG_SET          (MFGCFG_BASE + 0x004)
+#define MFG_CG_CLR          (MFGCFG_BASE + 0x008)
+#define MFG_MBIST_CFG           (MFGCFG_BASE + 0x280)
+
+/* MMSYS Register*/
+#define MMSYS_CG_CON0           (MMSYS_CONFIG_BASE + 0x100)
+#define MMSYS_CG_SET0           (MMSYS_CONFIG_BASE + 0x104)
+#define MMSYS_CG_CLR0           (MMSYS_CONFIG_BASE + 0x108)
+#define MMSYS_CG_CON1           (MMSYS_CONFIG_BASE + 0x110)
+#define MMSYS_CG_SET1           (MMSYS_CONFIG_BASE + 0x114)
+#define MMSYS_CG_CLR1           (MMSYS_CONFIG_BASE + 0x118)
+
+/* CAMSYS */
+#define CAMSYS_CG_CLR           (CAMSYS_BASE + 0x008)
+
+/* VDECSYS */
+#define VDEC_CKEN_SET           (VDECSYS_BASE)
+#define VDEC_LARB3_CKEN_SET     (VDECSYS_BASE + 0x008)
+
+/* VENCSYS */
+#define VENC_CG_CON         (VENCSYS_BASE + 0x004)
+
+#define WDT_SWSYSRST		(TOP_RGU_BASE + 0x018)
+
+void mt_pll_init(void);
+void mt_pll_post_init(void);
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/pmic_wrap.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/pmic_wrap.h
new file mode 100644
index 0000000..184b4aa
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/pmic_wrap.h
@@ -0,0 +1,423 @@
+/*
+ * 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.
+ */
+
+#ifndef __PMIC_WRAP_H
+#define __PMIC_WRAP_H
+
+#include <platform/mt_reg_base.h>
+#include <platform/pmic_wrap_common.h>
+
+struct mt8168_pwrap_regs {
+	u32	mux_sel;
+	u32	wrap_en;
+	u32	dio_en;
+	u32	si_sample_ctrl;
+	u32	si_sample_ctrl_1;
+	u32	si_sample_ctrl_2;
+	u32	si_sample_ctrl_3;
+	u32	si_sample_ctrl_ulposc;
+	u32	rddmy;
+	u32	cshext_write;
+	u32	cshext_read;
+	u32	cslext_write;
+	u32	cslext_read;
+	u32	ext_ck_write;
+	u32	ext_ck_read;
+	u32	staupd_ctrl;
+	u32	staupd_grpen;
+	u32	eint_sta0_adr;
+	u32	eint_sta1_adr;
+	u32	eint_sta;
+	u32	eint_clr;
+	u32	eint_ctrl;
+	u32	staupd_man_trig;
+	u32	staupd_sta;
+	u32	wrap_sta;
+	u32	harb_init;
+	u32	harb_hprio;
+	u32	hiprio_arb_en;
+	u32	harb_sta0;
+	u32	harb_sta1;
+	u32	harb_sta2;
+	u32	man_en;
+	u32	man_cmd;
+	u32	man_rdata;
+	u32	man_vldclr;
+	u32	wacs0_en;
+	u32	init_done0;
+	u32	wacs1_en;
+	u32	init_done1;
+	u32	wacs2_en;
+	u32	init_done2;
+	u32	wacs_p2p_en;
+	u32	init_done_p2p;
+	u32	wacs_md32_en;
+	u32	init_done_md32;
+	u32	int0_en;
+	u32	int0_flg_raw;
+	u32	int0_flg;
+	u32	int0_clr;
+	u32	int1_en;
+	u32	int1_flg_raw;
+	u32	int1_flg;
+	u32	int1_clr;
+	u32	sig_adr;
+	u32	sig_mode;
+	u32	sig_value;
+	u32	sig_errval;
+	u32	crc_en;
+	u32	timer_ctrl;
+	u32	timer_sta;
+	u32	wdt_unit;
+	u32	wdt_src_en_0;
+	u32	wdt_src_en_1;
+	u32	wdt_flg_0;
+	u32	wdt_flg_1;
+	u32	debug_int_sel;
+	u32	dvfs_adr0;
+	u32	dvfs_wdata0;
+	u32	dvfs_adr1;
+	u32	dvfs_wdata1;
+	u32	dvfs_adr2;
+	u32	dvfs_wdata2;
+	u32	dvfs_adr3;
+	u32	dvfs_wdata3;
+	u32	dvfs_adr4;
+	u32	dvfs_wdata4;
+	u32	dvfs_adr5;
+	u32	dvfs_wdata5;
+	u32	dvfs_adr6;
+	u32	dvfs_wdata6;
+	u32	dvfs_adr7;
+	u32	dvfs_wdata7;
+	u32	dvfs_adr8;
+	u32	dvfs_wdata8;
+	u32	dvfs_adr9;
+	u32	dvfs_wdata9;
+	u32	dvfs_adr10;
+	u32	dvfs_wdata10;
+	u32	dvfs_adr11;
+	u32	dvfs_wdata11;
+	u32	dvfs_adr12;
+	u32	dvfs_wdata12;
+	u32	dvfs_adr13;
+	u32	dvfs_wdata13;
+	u32	dvfs_adr14;
+	u32	dvfs_wdata14;
+	u32	dvfs_adr15;
+	u32	dvfs_wdata15;
+	u32	dcxo_enable;
+	u32	dcxo_conn_adr0;
+	u32	dcxo_conn_wdata0;
+	u32	dcxo_conn_adr1;
+	u32	dcxo_conn_wdata1;
+	u32	dcxo_nfc_adr0;
+	u32	dcxo_nfc_wdata0;
+	u32	dcxo_nfc_adr1;
+	u32	dcxo_nfc_wdata1;
+	u32	spminf_sta_0;
+	u32	spminf_sta_1;
+	u32	spminf_backup_sta;
+	u32	mcu_pminf_sta_0;
+	u32	mcu_pminf_sta_1;
+	u32	scpinf_sta;
+	u32	cipher_key_sel;
+	u32	cipher_iv_sel;
+	u32	cipher_en;
+	u32	cipher_rdy;
+	u32	cipher_mode;
+	u32	cipher_swrst;
+	u32	dcm_en;
+	u32	dcm_dbc_prd;
+	u32	int_gps_auxadc_cmd_addr;
+	u32	int_gps_auxadc_cmd;
+	u32	int_gps_auxadc_rdata_addr;
+	u32	ext_gps_auxadc_rdata_addr;
+	u32	gpsinf_0_sta;
+	u32	gpsinf_1_sta;
+	u32	md_adcinf_ctrl;
+	u32	md_auxadc_rdata_latest_addr;
+	u32	md_auxadc_rdata_wp_addr;
+	u32 md_auxadc_rdata[32];
+	u32	md_adcinf_0_sta_0;
+	u32	md_adcinf_0_sta_1;
+	u32	md_adcinf_1_sta_0;
+	u32	md_adcinf_1_sta_1;
+	u32	swrst;
+	u32	sleep_protection_ctrl;
+	u32	spm_sleep_gating_ctrl;
+	u32	scp_sleep_gating_ctrl;
+	u32	priority_user_sel_0;
+	u32	priority_user_sel_1;
+	u32	priority_user_sel_2;
+	u32	priority_user_sel_3;
+	u32	priority_user_sel_4;
+	u32	arbiter_out_sel_0;
+	u32	arbiter_out_sel_1;
+	u32	arbiter_out_sel_2;
+	u32	arbiter_out_sel_3;
+	u32	arbiter_out_sel_4;
+	u32	starv_counter_0;
+	u32	starv_counter_1;
+	u32	starv_counter_2;
+	u32	starv_counter_3;
+	u32	starv_counter_4;
+	u32	starv_counter_5;
+	u32	starv_counter_6;
+	u32	starv_counter_7;
+	u32	starv_counter_8;
+	u32	starv_counter_9;
+	u32	starv_counter_10;
+	u32	starv_counter_11;
+	u32	starv_counter_12;
+	u32	starv_counter_13;
+	u32	starv_counter_14;
+	u32	starv_counter_15;
+	u32	starv_counter_16;
+	u32	starv_int_en;
+	u32	starv_counter_0_status;
+	u32	starv_counter_1_status;
+	u32	starv_counter_2_status;
+	u32	starv_counter_3_status;
+	u32	starv_counter_4_status;
+	u32	starv_counter_5_status;
+	u32	starv_counter_6_status;
+	u32	starv_counter_7_status;
+	u32	starv_counter_8_status;
+	u32	starv_counter_9_status;
+	u32	starv_counter_10_status;
+	u32	starv_counter_11_status;
+	u32	starv_counter_12_status;
+	u32	starv_counter_13_status;
+	u32	starv_counter_14_status;
+	u32	starv_counter_15_status;
+	u32	starv_counter_16_status;
+	u32	starv_counter_clr;
+	u32	starv_prio_status;
+	u32	monitor_ctrl_0;
+	u32	monitor_ctrl_1;
+	u32	monitor_ctrl_2;
+	u32	monitor_ctrl_3;
+	u32	channel_sequence_0;
+	u32	channel_sequence_1;
+	u32	channel_sequence_2;
+	u32	channel_sequence_3;
+	u32	cmd_sequence_0;
+	u32	cmd_sequence_1;
+	u32	cmd_sequence_2;
+	u32	cmd_sequence_3;
+	u32	cmd_sequence_4;
+	u32	cmd_sequence_5;
+	u32	cmd_sequence_6;
+	u32	cmd_sequence_7;
+	u32	wdata_sequence_0;
+	u32	wdata_sequence_1;
+	u32	wdata_sequence_2;
+	u32	wdata_sequence_3;
+	u32	wdata_sequence_4;
+	u32	wdata_sequence_5;
+	u32	wdata_sequence_6;
+	u32	wdata_sequence_7;
+	u32	debug_reg_for_sw_0;
+	u32	debug_reg_for_sw_1;
+	u32	debug_reg_for_sw_2;
+	u32	debug_reg_for_sw_3;
+	u32	debug_reg_for_sw_4;
+	u32	debug_reg_for_sw_5;
+	u32	bwc_options;
+	u32	reserved[520];
+	u32	wacs0_cmd;
+	u32	wacs0_rdata;
+	u32	wacs0_vldclr;
+	u32	reserved1[5];
+	u32	wacs2_cmd;
+	u32	wacs2_rdata;
+	u32	wacs2_vldclr;
+};
+
+static struct mt8168_pwrap_regs * const mtk_pwrap = (void *)PWRAP_BASE;
+
+enum {
+	WACS2 = 1 << 2
+};
+
+/* PMIC registers */
+enum {
+	PMIC_BASE                     = 0x0000,
+	PMIC_SMT_CON1                 = PMIC_BASE + 0x002c,
+	PMIC_DRV_CON1                 = PMIC_BASE + 0x0034,
+	PMIC_FILTER_CON0              = PMIC_BASE + 0x003a,
+	PMIC_GPIO_PULLEN0_CLR         = PMIC_BASE + 0x0092,
+	PMIC_RG_SPI_CON0              = PMIC_BASE + 0x0408,
+	PMIC_DEW_DIO_EN               = PMIC_BASE + 0x040a,
+	PMIC_DEW_READ_TEST            = PMIC_BASE + 0x040c,
+	PMIC_DEW_WRITE_TEST           = PMIC_BASE + 0x040e,
+	PMIC_DEW_CRC_EN               = PMIC_BASE + 0x0412,
+	PMIC_DEW_CRC_VAL              = PMIC_BASE + 0x0414,
+	PMIC_DEW_RDDMY_NO             = PMIC_BASE + 0x0424,
+	PMIC_CPU_INT_STA              = PMIC_BASE + 0x042c,
+	PMIC_RG_SPI_CON2              = PMIC_BASE + 0x0430,
+	PMIC_RG_SPI_CON3              = PMIC_BASE + 0x0432,
+	PMIC_RG_SPI_CON4              = PMIC_BASE + 0x0434,
+	PMIC_RG_SPI_CON5              = PMIC_BASE + 0x0436,
+	PMIC_RG_SPI_CON6              = PMIC_BASE + 0x0438,
+	PMIC_RG_SPI_CON7              = PMIC_BASE + 0x043a,
+	PMIC_RG_SPI_CON8              = PMIC_BASE + 0x043c,
+	PMIC_RG_SPI_CON13             = PMIC_BASE + 0x0446,
+	PMIC_AUXADC_ADC17             = PMIC_BASE + 0x10a6,
+	PMIC_AUXADC_ADC31             = PMIC_BASE + 0x10C0,
+	PMIC_AUXADC_ADC32             = PMIC_BASE + 0x10C2,
+	PMIC_AUXADC_ADC35             = PMIC_BASE + 0x10C8,
+	PMIC_AUXADC_RQST0             = PMIC_BASE + 0x110e,
+	PMIC_AUXADC_RQST1             = PMIC_BASE + 0x111A,
+};
+
+enum {
+	E_CLK_EDGE = 1,
+	E_CLK_LAST_SETTING
+};
+
+enum {
+	GPS_MAIN = 0x40,
+	GPS_SUBSYS = 0x80
+};
+
+enum {
+	ULPOSC_CLK = 0x1 << 23
+};
+
+enum {
+	ULPOSC_OFF = 0x1 << 31,
+	ULPOSC_INV = 0x1 << 28,
+	ULPOSC_SEL_1 = 0x1 << 24,
+	ULPOSC_SEL_2 = 0x1 << 25,
+};
+
+enum {
+	TIMER_CG = 0x1,
+	AP_CG = 0x1 << 1,
+	MD_CG = 0x1 << 2,
+	CONN_CG = 0x1 << 3,
+};
+
+enum {
+	MODEM_TEMP_SHARE_CG = 0x1 << 8,
+};
+
+enum {
+	SIG_PMIC_0 = 0x1 << 0,
+	INT_STA_PMIC_0 = 0x1 << 2,
+	MD_ADC_DATA0 = 0x1 << 4,
+	MD_ADC_DATA1 = 0x1 << 5,
+	GPS_ADC_DATA0 = 0x1 << 6,
+	GPS_ADC_DATA1 = 0x1 << 7,
+};
+
+enum {
+	MD = 1,
+	MD_DVFS = 2,
+	POWER_HW = 4,
+	POWER_HW_BACKUP = 8,
+	ARB_PRIORITY = MD | MD_DVFS | POWER_HW | POWER_HW_BACKUP,
+};
+
+enum {
+	ARB_WACS0 = 0x1,
+	ARB_WACS2 = 0x1 << 2,
+	ARB_WACS_P2P = 0x1 << 4,
+	ARB_WACS_MD32 = 0x1 << 5,
+	ARB_MD = 0x1 << 6,
+	ARB_WACS_POWER_HW = 0x1 << 9,
+	ARB_DCXO_CONN = 0x1 << 11,
+	ARB_DCXO_NFC = 0x1 << 12,
+	ARB_MD_ADC0 = 0x1 << 13,
+	ARB_MD_ADC1 = 0x1 << 14,
+	ARB_GPS_0 = 0x1 << 15,
+	ARB_GPS_1 = 0x1 << 16,
+	STAUPD_HARB = 0x1 << 17,
+	ARB_USER_EN = ARB_WACS0 | ARB_WACS2 | ARB_WACS_P2P | ARB_WACS_MD32 |
+		ARB_MD | ARB_WACS_POWER_HW | ARB_DCXO_CONN | ARB_DCXO_NFC |
+		ARB_MD_ADC0 | ARB_MD_ADC1 | ARB_GPS_0 | ARB_GPS_1 | STAUPD_HARB,
+};
+
+enum {
+	STA_PD_98_5_US = 0X5,
+};
+
+enum {
+	WATCHDOG_TIMER_7_5_MS = 0XF,
+};
+
+enum {
+	WDT_MONITOR_ALL = 0XFFFF,
+};
+
+enum {
+	MONITOR_LATCH_MATCHED_TRANS = 0x1 << 28,
+	STARV_15 = 0x1 << 24,
+	DCXO = 0x1 << 19,
+	MONITOR_ALL_INT = 0XFFFFFFFF,
+	INT0_MONITOR = MONITOR_ALL_INT,
+	INT1_MONITOR = MONITOR_ALL_INT &
+		~MONITOR_LATCH_MATCHED_TRANS & ~STARV_15 & ~DCXO,
+};
+
+enum {
+	SPI_CLK = 0x1,
+	SPI_CSN = 0x1 << 1,
+	SPI_MOSI = 0x1 << 2,
+	SPI_MISO = 0x1 << 3,
+	SPI_FILTER = (SPI_CLK | SPI_CSN | SPI_MOSI | SPI_MISO) << 4,
+	SPI_SMT = (SPI_CLK | SPI_CSN | SPI_MOSI | SPI_MISO),
+	SPI_PULL_DISABLE = (SPI_CLK | SPI_CSN | SPI_MOSI | SPI_MISO) << 4,
+};
+
+enum {
+	IO_4_MA = 0x8,
+};
+
+enum {
+	SPI_CLK_SHIFT = 0,
+	SPI_CSN_SHIFT = 4,
+	SPI_MOSI_SHIFT = 8,
+	SPI_MISO_SHIFT = 12,
+	SPI_DRIVING = (IO_4_MA << SPI_CLK_SHIFT | IO_4_MA << SPI_CSN_SHIFT |
+		IO_4_MA << SPI_MOSI_SHIFT | IO_4_MA << SPI_MISO_SHIFT),
+};
+
+enum {
+	DUMMY_READ_CYCLES = 0X8,
+};
+
+/************* macro for spi clock config ******************************/
+#define CLK_SPI_CK_26M						0x1
+#define INFRA_GLOBALCON_RST0					(INFRACFG_AO_BASE+0x140)
+#define INFRA_GLOBALCON_RST1					(INFRACFG_AO_BASE+0x144)
+#define PMIC_CLOCK_DCM						(INFRACFG_AO_BASE+0x074)
+#define PMICW_CLOCK_CTRL					(INFRACFG_AO_BASE+0x108)
+#define INFRA_GLOBALCON_RST2_SET				(INFRACFG_AO_BASE+0x140)
+#define INFRA_GLOBALCON_RST2_CLR				(INFRACFG_AO_BASE+0x144)
+#define INFRA_GLOBALCON_RST2_STA				(INFRACFG_AO_BASE+0x148)
+#define APB_CLOCK_GATING					(INFRACFG_AO_BASE+0xF0C)
+
+#endif /* __PMIC_WRAP_H */
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/rtc.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/rtc.h
new file mode 100644
index 0000000..d0c21d0
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/rtc.h
@@ -0,0 +1,174 @@
+/*
+ * 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 <platform/rtc_common.h>
+
+/* RTC registers */
+enum {
+    RTC_BBPU = 0x0588,
+    RTC_IRQ_STA = 0x058A,
+    RTC_IRQ_EN = 0x058C,
+    RTC_CII_EN = 0x058E
+};
+
+enum {
+    RTC_TC_SEC = 0x0592,
+    RTC_TC_MIN = 0x0594,
+    RTC_TC_HOU = 0x0596,
+    RTC_TC_DOM = 0x0598,
+    RTC_TC_DOW = 0x059A,
+    RTC_TC_MTH = 0x059C,
+    RTC_TC_YEA = 0x059E
+};
+
+enum {
+    RTC_AL_SEC = 0x05A0,
+    RTC_AL_MIN = 0x05A2,
+    RTC_AL_HOU = 0x05A4,
+    RTC_AL_DOM = 0x05A6,
+    RTC_AL_DOW = 0x05A8,
+    RTC_AL_MTH = 0x05AA,
+    RTC_AL_YEA = 0x05AC,
+    RTC_AL_MASK = 0x0590
+};
+
+enum {
+    RTC_OSC32CON = 0x05AE,
+    RTC_CON = 0x05C4,
+    RTC_WRTGR = 0x05C2
+};
+
+enum {
+    RTC_POWERKEY1 = 0x05B0,
+    RTC_POWERKEY2 = 0x05B2
+};
+
+enum {
+    RTC_PDN1 = 0x05B4,
+    RTC_PDN2 = 0x05B6,
+    RTC_SPAR0 = 0x05B8,
+    RTC_SPAR1 = 0x05BA,
+    RTC_PROT = 0x05BC,
+    RTC_DIFF = 0x05BE,
+    RTC_CALI = 0x05C0
+};
+
+enum {
+    RTC_BBPU_PWREN = 1U << 0,
+    RTC_BBPU_CLR = 1U << 1,
+    RTC_BBPU_INIT = 1U << 2,
+    RTC_BBPU_AUTO = 1U << 3,
+    RTC_BBPU_CLRPKY = 1U << 4,
+    RTC_BBPU_RELOAD = 1U << 5,
+    RTC_BBPU_CBUSY = 1U << 6,
+
+    RTC_CBUSY_TIMEOUT_US = 8000
+};
+
+enum {
+    RTC_CON_VBAT_LPSTA_RAW = 1U << 0,
+    RTC_CON_EOSC32_LPEN = 1U << 1,
+    RTC_CON_XOSC32_LPEN = 1U << 2,
+    RTC_CON_LPRST = 1U << 3,
+    RTC_CON_CDBO = 1U << 4,
+    RTC_CON_F32KOB = 1U << 5,
+    RTC_CON_GPO = 1U << 6,
+    RTC_CON_GOE = 1U << 7,
+    RTC_CON_GSR = 1U << 8,
+    RTC_CON_GSMT = 1U << 9,
+    RTC_CON_GPEN = 1U << 10,
+    RTC_CON_GPU = 1U << 11,
+    RTC_CON_GE4 = 1U << 12,
+    RTC_CON_GE8 = 1U << 13,
+    RTC_CON_GPI = 1U << 14,
+    RTC_CON_LPSTA_RAW = 1U << 15
+};
+
+enum {
+    RTC_XOSCCALI_MASK = 0x1F << 0,
+    RTC_XOSC32_ENB = 1U << 5,
+    RTC_EMB_HW_MODE = 0U << 6,
+    RTC_EMB_K_EOSC32_MODE = 1U << 6,
+    RTC_EMB_SW_DCXO_MODE = 2U << 6,
+    RTC_EMB_SW_EOSC32_MODE = 3U << 6,
+    RTC_EMBCK_SEL_MODE_MASK = 3U << 6,
+    RTC_EMBCK_SRC_SEL = 1U << 8,
+    RTC_EMBCK_SEL_OPTION = 1U << 9,
+    RTC_GPS_CKOUT_EN = 1U << 10,
+    RTC_REG_XOSC32_ENB = 1U << 15
+};
+
+enum {
+    RTC_LPD_OPT_XOSC_AND_EOSC_LPD = 0U << 13,
+    RTC_LPD_OPT_EOSC_LPD = 1U << 13,
+    RTC_LPD_OPT_XOSC_LPD = 2U << 13,
+    RTC_LPD_OPT_F32K_CK_ALIVE = 3U << 13,
+    RTC_LPD_OPT_MASK = 3U << 13
+};
+
+enum {
+    RTC_PDN1_FAST_BOOT = 1 << 13
+};
+
+/* PMIC TOP Register Definition */
+enum {
+    PMIC_RG_SCK_TOP_CON0 = 0x050C
+};
+
+/* PMIC TOP Register Definition */
+enum {
+    PMIC_RG_TOP_CKPDN_CON1 = 0x0112,
+    PMIC_RG_TOP_CKPDN_CON1_SET = 0x0114,
+    PMIC_RG_TOP_CKPDN_CON1_CLR = 0x0116,
+    PMIC_RG_TOP_CKSEL_CON0 = 0x0118,
+    PMIC_RG_TOP_CKSEL_CON0_SET = 0x011A,
+    PMIC_RG_TOP_CKSEL_CON0_CLR = 0x011C
+};
+
+/* PMIC DCXO Register Definition */
+enum {
+    PMIC_RG_DCXO_CW00 = 0x0788,
+    PMIC_RG_DCXO_CW02 = 0x0790,
+    PMIC_RG_DCXO_CW07 = 0x079A,
+    PMIC_RG_DCXO_CW09 = 0x079E,
+    PMIC_RG_DCXO_CW11 = 0x07A2,
+    PMIC_RG_DCXO_CW13 = 0x07AA,
+    PMIC_RG_DCXO_CW15 = 0x07AE,
+    PMIC_RG_DCXO_CW16 = 0x07B0,
+    PMIC_RG_DCXO_CW21 = 0x07BA,
+    PMIC_RG_DCXO_ELR0 = 0x07C0
+};
+
+enum {
+    PMIC_RG_TOP_TMA_KEY = 0x03AE
+};
+
+/* external API */
+void rtc_bbpu_power_on(void);
+void rtc_osc_init(void);
+int rtc_init(u8 recover);
+void rtc_boot(void);
+/* get and set bootloader flag */
+bool rtc_bootloader_check(void);
+void rtc_bootloader_set_clr(bool value);
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/spm.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/spm.h
new file mode 100644
index 0000000..1d45b06
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/spm.h
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+
+#ifndef _SPM_
+#define _SPM_
+
+#include <arch/arm64.h>
+#include <platform/mt_reg_base.h>
+#include <reg.h>
+
+#define SPM_REG(offset)             (SPM_BASE + offset)
+#define SPM_PROJECT_CODE            0xB16
+#define POWERON_CONFIG_EN           SPM_REG(0x0000)
+#define PWR_STATUS              SPM_REG(0x0180)
+#define PWR_STATUS_2ND              SPM_REG(0x0184)
+
+#define DIS_PWR_CON             SPM_REG(0x030C)
+#define VEN_PWR_CON             SPM_REG(0x0304)
+#define ISP_PWR_CON             SPM_REG(0x0308)
+#define AUDIO_PWR_CON               SPM_REG(0x0314)
+#define VPU_TOP_PWR_CON             SPM_REG(0x0324)
+#define CONN_PWR_CON                SPM_REG(0x032C)
+#define MFG_PWR_CON             SPM_REG(0x0338)
+#define CAM_PWR_CON             SPM_REG(0x0344)
+#define VDE_PWR_CON             SPM_REG(0x0370)
+#define APU_PWR_CON             SPM_REG(0x0378)
+#define DSP_PWR_CON             SPM_REG(0x037C)
+
+#define INFRACFG_REG(offset)            (INFRACFG_AO_BASE + offset)
+#define AUDIO_BUS_AUD_SI0           INFRACFG_REG(0x0800)
+#define AUDIO_BUS_INFRA_SI0         INFRACFG_REG(0x0808)
+#define SMI_COMMON_REG(offset)          (SMI_COMMON_BASE + offset)
+#define SMI_COMMON_CLAMP_EN_SET         SMI_COMMON_REG(0x03C4)
+#define SMI_COMMON_CLAMP_EN_CLR         SMI_COMMON_REG(0x03C8)
+
+/* Macro and Inline */
+#define spm_read(addr)              (*(volatile u32 *)(addr))
+
+#define sync_writel(v, a) \
+            do {    \
+                writel(v, a); \
+                DSB; \
+            } while (0)
+
+#define spm_write(addr, val)        sync_writel(val, addr)
+
+/* Define MTCMOS power control */
+#define PWR_RST_B                        (0x1 << 0)
+#define PWR_ISO                          (0x1 << 1)
+#define PWR_ON                           (0x1 << 2)
+#define PWR_ON_2ND                       (0x1 << 3)
+#define PWR_CLK_DIS                      (0x1 << 4)
+#define SRAM_CKISO                       (0x1 << 5)
+#define SRAM_ISOINT_B                    (0x1 << 6)
+#define SLPB_CLAMP                       (0x1 << 7)
+#define APU_PDN_BIT0                     (0x1 << 8)
+#define APU_PDN_BIT1                     (0x1 << 9)
+#define APU_PDN_BIT2                     (0x1 << 10)
+#define pwrdnreqn_mp0_adb                (0x1 << 10)
+#define APU_PDN_BIT3                     (0x1 << 11)
+#define pwrdnreqn_mp1_adb                (0x1 << 11)
+#define pwrdnreqn_icc_mp0_adb            (0x1 << 12)
+#define APU_PDN_BIT4                     (0x1 << 12)
+#define APU_PDN_BIT5                     (0x1 << 13)
+#define pwrdnreqn_icd_mp0_adb            (0x1 << 13)
+#define APU_PDN_BIT6                     (0x1 << 14)
+#define pwrdnreqn_icc_mp1_adb            (0x1 << 14)
+#define pwrdnreqn_icd_mp1_adb            (0x1 << 15)
+#define DSP_SLPB_BIT0                    (0x1 << 16)
+#define DSP_SLPB_BIT1                    (0x1 << 17)
+#define DSP_SLPB_BIT2                    (0x1 << 18)
+#define DSP_SLPB_BIT3                    (0x1 << 19)
+#define DSP_SRAM_SLEEP_B_ACK             (0x1 << 20)
+#define APU_SLPB_BIT0                    (0x1 << 22)
+#define APU_SLPB_BIT1                    (0x1 << 23)
+#define APU_SLPB_BIT2                    (0x1 << 24)
+#define APU_SLPB_BIT3                    (0x1 << 25)
+#define pwrdnreqn_l2c_mp0_adb            (0x1 << 26)
+#define APU_SLPB_BIT4                    (0x1 << 26)
+#define pwrdnreqn_l2c_mp1_adb            (0x1 << 27)
+
+/* Define MTCMOS Bus Protect Mask */
+#define MD1_PROT_STEP1_0_MASK            ((0x1 << 7))
+#define MD1_PROT_STEP1_0_ACK_MASK        ((0x1 << 7))
+#define MD1_PROT_STEP2_0_MASK            ((0x1 << 3) \
+                      |(0x1 << 4))
+#define MD1_PROT_STEP2_0_ACK_MASK        ((0x1 << 3) \
+                      |(0x1 << 4))
+#define MD1_PROT_STEP2_1_MASK            ((0x1 << 6))
+#define MD1_PROT_STEP2_1_ACK_MASK        ((0x1 << 6))
+#define CONN_PROT_STEP1_0_MASK           ((0x1 << 13))
+#define CONN_PROT_STEP1_0_ACK_MASK       ((0x1 << 13))
+#define CONN_PROT_STEP1_1_MASK           ((0x1 << 18))
+#define CONN_PROT_STEP1_1_ACK_MASK       ((0x1 << 18))
+#define CONN_PROT_STEP2_0_MASK           ((0x1 << 14))
+#define CONN_PROT_STEP2_0_ACK_MASK       ((0x1 << 14))
+#define DPY_PROT_STEP1_0_MASK            ((0x1 << 0) \
+                      |(0x1 << 23) \
+                      |(0x1 << 26))
+#define DPY_PROT_STEP1_0_ACK_MASK        ((0x1 << 0) \
+                      |(0x1 << 23) \
+                      |(0x1 << 26))
+#define DPY_PROT_STEP1_1_MASK            ((0x1 << 10) \
+                      |(0x1 << 11) \
+                      |(0x1 << 12) \
+                      |(0x1 << 13) \
+                      |(0x1 << 14) \
+                      |(0x1 << 15) \
+                      |(0x1 << 16) \
+                      |(0x1 << 17))
+#define DPY_PROT_STEP1_1_ACK_MASK        ((0x1 << 10) \
+                      |(0x1 << 11) \
+                      |(0x1 << 12) \
+                      |(0x1 << 13) \
+                      |(0x1 << 14) \
+                      |(0x1 << 15) \
+                      |(0x1 << 16) \
+                      |(0x1 << 17))
+#define DPY_PROT_STEP2_0_MASK            ((0x1 << 1) \
+                      |(0x1 << 2) \
+                      |(0x1 << 3) \
+                      |(0x1 << 4) \
+                      |(0x1 << 10) \
+                      |(0x1 << 11) \
+                      |(0x1 << 21) \
+                      |(0x1 << 22))
+#define DPY_PROT_STEP2_0_ACK_MASK        ((0x1 << 1) \
+                      |(0x1 << 2) \
+                      |(0x1 << 3) \
+                      |(0x1 << 4) \
+                      |(0x1 << 10) \
+                      |(0x1 << 11) \
+                      |(0x1 << 21) \
+                      |(0x1 << 22))
+#define DIS_PROT_STEP1_0_MASK            ((0x1 << 16) \
+                      |(0x1 << 17))
+#define DIS_PROT_STEP1_0_ACK_MASK        ((0x1 << 16) \
+                      |(0x1 << 17))
+#define DIS_PROT_STEP2_0_MASK            ((0x1 << 1) \
+                      |(0x1 << 2) \
+                      |(0x1 << 10) \
+                      |(0x1 << 11))
+#define DIS_PROT_STEP2_0_ACK_MASK        ((0x1 << 1) \
+                      |(0x1 << 2) \
+                      |(0x1 << 10) \
+                      |(0x1 << 11))
+#define MFG_PROT_STEP1_0_MASK            ((0x1 << 25))
+#define MFG_PROT_STEP1_0_ACK_MASK        ((0x1 << 25))
+#define MFG_PROT_STEP2_0_MASK            ((0x1 << 21) \
+                      |(0x1 << 22))
+#define MFG_PROT_STEP2_0_ACK_MASK        ((0x1 << 21) \
+                      |(0x1 << 22))
+#define MCU_PROT_STEP1_0_MASK            ((0x1 << 0) \
+                      |(0x1 << 9))
+#define MCU_PROT_STEP1_0_ACK_MASK        ((0x1 << 0) \
+                      |(0x1 << 9))
+#define MCU_PROT_STEP2_0_MASK            ((0x1 << 12))
+#define MCU_PROT_STEP2_0_ACK_MASK        ((0x1 << 12))
+#define APU_PROT_STEP1_0_MASK            ((0x1 << 2))
+#define APU_PROT_STEP1_0_ACK_MASK        ((0x1 << 2))
+#define APU_PROT_STEP2_0_MASK            ((0x1 << 20))
+#define APU_PROT_STEP2_0_ACK_MASK        ((0x1 << 20))
+#define CAM_PROT_STEP1_0_MASK            ((0x1 << 19))
+#define CAM_PROT_STEP1_0_ACK_MASK        ((0x1 << 19))
+#define CAM_PROT_STEP2_0_MASK            ((0x1 << 20))
+#define CAM_PROT_STEP2_0_ACK_MASK        ((0x1 << 20))
+
+/* Define MTCMOS Power Status Mask */
+
+#define MD1_PWR_STA_MASK                 (0x1 << 0)
+#define CONN_PWR_STA_MASK                (0x1 << 1)
+#define DPY_PWR_STA_MASK                 (0x1 << 2)
+#define DIS_PWR_STA_MASK                 (0x1 << 3)
+#define MFG_PWR_STA_MASK                 (0x1 << 4)
+#define IFR_PWR_STA_MASK                 (0x1 << 6)
+#define MFG_CORE0_PWR_STA_MASK           (0x1 << 7)
+#define MP0_CPUTOP_PWR_STA_MASK          (0x1 << 8)
+#define MP0_CPU0_PWR_STA_MASK            (0x1 << 9)
+#define MP0_CPU1_PWR_STA_MASK            (0x1 << 10)
+#define MP0_CPU2_PWR_STA_MASK            (0x1 << 11)
+#define MP0_CPU3_PWR_STA_MASK            (0x1 << 12)
+#define MCU_PWR_STA_MASK                 (0x1 << 14)
+#define MM_PWR_STA_MASK                  (0x1 << 15)
+#define APU_PWR_STA_MASK                 (0x1 << 16)
+#define DSP_PWR_STA_MASK                 (0x1 << 17)
+#define VEN_PWR_STA_MASK                 (0x1 << 21)
+#define MFG_ASYNC_PWR_STA_MASK           (0x1 << 23)
+#define AUDIO_PWR_STA_MASK               (0x1 << 24)
+#define CAM_PWR_STA_MASK                 (0x1 << 25)
+#define VCODEC_PWR_STA_MASK              (0x1 << 26)
+#define VDE_PWR_STA_MASK                 (0x1 << 31)
+
+/* Define Non-CPU SRAM Mask */
+#define MD1_SRAM_PDN                     (0x1 << 8)
+#define MD1_SRAM_PDN_ACK                 (0x0 << 12)
+#define MD1_SRAM_PDN_ACK_BIT0            (0x1 << 12)
+#define DPY_SRAM_PDN                     (0xF << 8)
+#define DPY_SRAM_PDN_ACK                 (0xF << 12)
+#define DPY_SRAM_PDN_ACK_BIT0            (0x1 << 12)
+#define DPY_SRAM_PDN_ACK_BIT1            (0x1 << 13)
+#define DPY_SRAM_PDN_ACK_BIT2            (0x1 << 14)
+#define DPY_SRAM_PDN_ACK_BIT3            (0x1 << 15)
+#define DIS_SRAM_PDN                     (0x1 << 8)
+#define DIS_SRAM_PDN_ACK                 (0x1 << 12)
+#define DIS_SRAM_PDN_ACK_BIT0            (0x1 << 12)
+#define MFG_SRAM_PDN                     (0x3 << 8)
+#define MFG_SRAM_PDN_ACK                 (0x3 << 12)
+#define MFG_SRAM_PDN_ACK_BIT0            (0x1 << 12)
+#define MFG_SRAM_PDN_ACK_BIT1            (0x1 << 13)
+#define IFR_SRAM_PDN                     (0x1 << 8)
+#define IFR_SRAM_PDN_ACK                 (0x1 << 12)
+#define IFR_SRAM_PDN_ACK_BIT0            (0x1 << 12)
+#define MFG_CORE0_SRAM_PDN               (0x1 << 8)
+#define MFG_CORE0_SRAM_PDN_ACK           (0x1 << 12)
+#define MFG_CORE0_SRAM_PDN_ACK_BIT0      (0x1 << 12)
+#define MM_SRAM_PDN                      (0xF << 8)
+#define MM_SRAM_PDN_ACK                  (0xF << 12)
+#define MM_SRAM_PDN_ACK_BIT0             (0x1 << 12)
+#define MM_SRAM_PDN_ACK_BIT1             (0x1 << 13)
+#define MM_SRAM_PDN_ACK_BIT2             (0x1 << 14)
+#define MM_SRAM_PDN_ACK_BIT3             (0x1 << 15)
+#define APU_SRAM_PDN                     (0x3 << 8)
+#define APU_SRAM_PDN_ACK                 (0x3 << 15)
+#define APU_SRAM_PDN_ACK_BIT0            (0x1 << 15)
+#define APU_SRAM_PDN_ACK_BIT1            (0x1 << 16)
+#define DSP_SRAM_PDN                     (0xF << 8)
+#define DSP_SRAM_PDN_ACK                 (0xF << 12)
+#define DSP_SRAM_PDN_ACK_BIT0            (0x1 << 12)
+#define DSP_SRAM_PDN_ACK_BIT1            (0x1 << 13)
+#define DSP_SRAM_PDN_ACK_BIT2            (0x1 << 14)
+#define DSP_SRAM_PDN_ACK_BIT3            (0x1 << 15)
+#define VEN_SRAM_PDN                     (0x1 << 8)
+#define VEN_SRAM_PDN_ACK                 (0x1 << 12)
+#define VEN_SRAM_PDN_ACK_BIT0            (0x1 << 12)
+#define AUDIO_SRAM_PDN                   (0x1F << 8)
+#define AUDIO_SRAM_PDN_ACK               (0x1F << 13)
+#define AUDIO_SRAM_PDN_ACK_BIT0          (0x1 << 13)
+#define AUDIO_SRAM_PDN_ACK_BIT1          (0x1 << 14)
+#define AUDIO_SRAM_PDN_ACK_BIT2          (0x1 << 15)
+#define AUDIO_SRAM_PDN_ACK_BIT3          (0x1 << 16)
+#define AUDIO_SRAM_PDN_ACK_BIT4          (0x1 << 17)
+#define CAM_SRAM_PDN                     (0x3 << 8)
+#define CAM_SRAM_PDN_ACK                 (0x3 << 12)
+#define CAM_SRAM_PDN_ACK_BIT0            (0x1 << 12)
+#define CAM_SRAM_PDN_ACK_BIT1            (0x1 << 13)
+#define VCODEC_SRAM_PDN                  (0x1 << 8)
+#define VCODEC_SRAM_PDN_ACK              (0x1 << 12)
+#define VCODEC_SRAM_PDN_ACK_BIT0         (0x1 << 12)
+#define VDE_SRAM_PDN                     (0x1 << 8)
+#define VDE_SRAM_PDN_ACK                 (0x1 << 12)
+#define VDE_SRAM_PDN_ACK_BIT0            (0x1 << 12)
+
+#define STA_POWER_DOWN          0
+#define STA_POWER_ON            1
+
+extern int spm_mtcmos_ctrl_dis(int state);
+extern int spm_mtcmos_ctrl_conn(int state);
+extern int spm_mtcmos_ctrl_mfg(int state);
+extern int spm_mtcmos_ctrl_apu_shut_down(int state);
+extern int spm_mtcmos_ctrl_dsp_shut_down(int state);
+extern int spm_mtcmos_ctrl_ven(int state);
+extern int spm_mtcmos_ctrl_audio(int state);
+extern int spm_mtcmos_ctrl_cam(int state);
+extern int spm_mtcmos_ctrl_vde(int state);
+
+#endif
diff --git a/src/bsp/lk/platform/mediatek/mt8133/include/platform/udc-common.h b/src/bsp/lk/platform/mediatek/mt8133/include/platform/udc-common.h
new file mode 100644
index 0000000..1347794
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/include/platform/udc-common.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#pragma once
+
+#define UDC_TYPE_BULK_IN    1
+#define UDC_TYPE_BULK_OUT   2
diff --git a/src/bsp/lk/platform/mediatek/mt8133/lib/storage/mtk_storage_operation.c b/src/bsp/lk/platform/mediatek/mt8133/lib/storage/mtk_storage_operation.c
new file mode 100644
index 0000000..f37be86
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/lib/storage/mtk_storage_operation.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <debug.h>
+#include <err.h>
+#include <lib/bio.h>
+#include <lib/console.h>
+#include <lib/mempool.h>
+#include <platform.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define STORAGE_BLOCK_SIZE (0x20000)
+
+static void show_buf(u8 *buf, u32 len)
+{
+    u32 i;
+
+    dprintf(ALWAYS, "memory content: ");
+
+    for (i = 0 ; i < len ; i++)
+    {
+        dprintf(ALWAYS, " %02X ", buf[i]);
+    }
+
+    dprintf(ALWAYS, "\n");
+}
+
+static int storage_read(const char *device, u32 offset, u32 len)
+{
+    int ret = 0;
+    int buf_offset = (offset % STORAGE_BLOCK_SIZE);
+    u8 *rbuf;
+    bdev_t *dev;
+
+    // check if args are valid
+    if (len >= STORAGE_BLOCK_SIZE){
+        dprintf(ALWAYS, "invalid argument value. \n");
+        return ERR_INVALID_ARGS;
+    }
+
+    // open device
+    dev = bio_open(device);
+    if (!dev) {
+        dev = bio_open_by_label(device);
+        if (!dev) {
+            dprintf(ALWAYS, "error opening block device: %s\n", device);
+            return ERR_NOT_FOUND;
+        }
+    }
+
+    // alloc rbuf
+    rbuf = mempool_alloc(STORAGE_BLOCK_SIZE, MEMPOOL_ANY);
+    if (rbuf == NULL) {
+        ret = ERR_NO_MEMORY;
+        bio_close(dev);
+        return ret;
+    }
+
+    // read nand
+    ret = bio_read(dev, rbuf, offset, len);
+    if (ret > 0) {
+        show_buf(rbuf, len);
+    }
+
+    mempool_free(rbuf);
+    bio_close(dev);
+    return ret;
+}
+
+static int storage_write(const char *device, u32 offset, const char *w_byte)
+{
+    int ret = 0;
+    int buf_offset = (offset % STORAGE_BLOCK_SIZE);
+    int block_start_addr = ROUNDDOWN(offset, STORAGE_BLOCK_SIZE);
+    u8 w_num = (u8)strtol(w_byte, NULL, 16);
+    u8 *wbuf;
+    bdev_t *dev;
+
+    // open device
+    dev = bio_open(device);
+    if (!dev) {
+        dev = bio_open_by_label(device);
+        if (!dev) {
+            dprintf(ALWAYS, "error opening block device: %s\n", device);
+            return ERR_NOT_FOUND;
+        }
+    }
+
+    // alloc wbuf
+    wbuf = mempool_alloc(STORAGE_BLOCK_SIZE, MEMPOOL_ANY);
+    if (wbuf == NULL) {
+        ret = ERR_NO_MEMORY;
+        bio_close(dev);
+        return ret;
+    }
+
+    // set wbuf
+    ret = bio_read(dev, wbuf, block_start_addr, STORAGE_BLOCK_SIZE);
+    if(ret < 0){
+        mempool_free(wbuf);
+        bio_close(dev);
+        return ret;
+    }
+    wbuf[buf_offset] = w_num;
+
+    // erase nand
+    bio_erase(dev, block_start_addr, STORAGE_BLOCK_SIZE);
+    if(ret < 0){
+        mempool_free(wbuf);
+        bio_close(dev);
+        return ret;
+    }
+
+    // write nand
+    ret = bio_write(dev, wbuf, block_start_addr, STORAGE_BLOCK_SIZE);
+
+    mempool_free(wbuf);
+    bio_close(dev);
+    return ret;
+}
+
+static int cmd_storage(int argc, const cmd_args *argv)
+{
+    int ret = 0;
+
+    if (argc < 2) {
+notenoughargs:
+        printf("not enough arguments:\n");
+usage:
+        printf("%s read <device> <offset> <read len>\n", argv[0].str);
+        printf("%s write <device> <offset> <write byte>\n", argv[0].str);
+        return -1;
+    }
+
+    if (!strcmp(argv[1].str, "read")){
+        if (argc < 5) goto notenoughargs;
+        ret = storage_read(argv[2].str, argv[3].u, argv[4].u);
+    } else if (!strcmp(argv[1].str, "write")){
+        if (argc < 5) goto notenoughargs;
+        ret = storage_write(argv[2].str, argv[3].u, argv[4].str);
+    } else {
+        printf("error: command %s not support\n", argv[1].str);
+        goto usage;
+    }
+
+    return ret;
+}
+
+STATIC_COMMAND_START
+STATIC_COMMAND("storage", "storage read/write commands", &cmd_storage)
+STATIC_COMMAND_END(storage);
+
+
+
diff --git a/src/bsp/lk/platform/mediatek/mt8133/lib/storage/rules.mk b/src/bsp/lk/platform/mediatek/mt8133/lib/storage/rules.mk
new file mode 100644
index 0000000..82e8c98
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/lib/storage/rules.mk
@@ -0,0 +1,10 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)

+MODULE := $(LOCAL_DIR)

+

+MODULE_SRCS += \

+    $(LOCAL_DIR)/mtk_storage_operation.c \

+

+MODULE_DEPS += \

+    lib/bio \

+

+include make/module.mk
\ No newline at end of file
diff --git a/src/bsp/lk/platform/mediatek/mt8133/platform.c b/src/bsp/lk/platform/mediatek/mt8133/platform.c
new file mode 100644
index 0000000..7bdfd1f
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/platform.c
@@ -0,0 +1,74 @@
+/*
+ * 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.
+*/
+#include <debug.h>
+#include <dev/interrupt/arm_gic.h>
+#include <dev/timer/arm_generic.h>
+#include <dev/uart.h>
+#include <err.h>
+#include <lib/mempool.h>
+#include <platform.h>
+#include <platform/mt8133.h>
+#include <platform/mtk_wdt.h>
+#include <platform/platform_blx.h>
+
+void platform_early_init(void)
+{
+    /* To inform PMIC that system is ready */
+    mtk_wdt_pwr_latch();
+
+    uart_init_early();
+
+    /* initialize the interrupt controller */
+    arm_gic_init();
+
+    arm_generic_timer_init(ARM_GENERIC_TIMER_PHYSICAL_INT, 13000000);
+
+    /* init AP watchdog and set timeout to 10 secs */
+    mtk_wdt_init();
+
+    /* bl2 or bl33 specific platform early init */
+    platform_early_init_blx();
+}
+
+void platform_init(void)
+{
+    int cache_ret = NO_ERROR, uncache_ret = NO_ERROR;
+
+    if (CACHED_MEMPOOL_ADDR && CACHED_MEMPOOL_SIZE)
+        cache_ret = mempool_init((void *)CACHED_MEMPOOL_ADDR,
+                                 CACHED_MEMPOOL_SIZE, MEMPOOL_CACHE);
+
+    if (UNCACHED_MEMPOOL_ADDR && UNCACHED_MEMPOOL_SIZE)
+        uncache_ret = mempool_init((void *)UNCACHED_MEMPOOL_ADDR,
+                                   UNCACHED_MEMPOOL_SIZE, MEMPOOL_UNCACHE);
+
+    if ((cache_ret != NO_ERROR) || (uncache_ret != NO_ERROR))
+        platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_PANIC);
+}
+
+/* Initialization context in start.S before switching from EL3 to EL1.
+ * Note data/bss segment NOT initialized, i.e. No assumption on global variable initialization.*/
+void platform_el3_init(void)
+{
+    gic_setup();
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/platform_bl2.c b/src/bsp/lk/platform/mediatek/mt8133/platform_bl2.c
new file mode 100644
index 0000000..33809e0
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/platform_bl2.c
@@ -0,0 +1,168 @@
+/*
+ * 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.
+*/
+
+#include <arch/ops.h>
+#include <debug.h>
+#include <err.h>
+#include <kernel/vm.h>
+#include <platform.h>
+#include <platform/mt6357.h>
+#include <platform/mt8133.h>
+#include <platform/pll.h>
+#include <platform/rtc.h>
+
+#define PROG_MEM_MAPPING_IDX        0
+#define GIC_PERIPHERAL_MAPPING_IDX  1
+#define DRAM_MAPPING_IDX        2
+
+#define MMU_LEVEL_2_ENTRY_MAP_SIZE  (0x200000) /* 2MB for 4K page size */
+
+/* initial memory mappings. parsed by start.S */
+struct mmu_initial_mapping mmu_initial_mappings[] = {
+    {
+        /*
+         * internal sram  : 0x10_0000 ~ 0x12_ffff ==> 1st 2MB range in L2 table
+         * l2c shared sram: 0x20_0000 ~ 0x23_ffff ==> 2nd 2MB range in L2 table
+         * For 4K page size, an entry in level 2 mmu table can map to 2MB range.
+         *
+         * We use internal sram as arena memory to map dram to mmu, the internal
+         * sram should be mapped before dram mmu mmapping. Add internal sram
+         * to mmu initial mappings, so we don't need to carefully map the
+         * internal sram on existing mmu table (new page table is not available
+         * since the arena memory is not set yet).
+         */
+        .phys = ROUNDDOWN(SRAM_BASE_PHYS, MMU_LEVEL_2_ENTRY_MAP_SIZE),
+        .virt = ROUNDDOWN(SRAM_BASE_VIRT, MMU_LEVEL_2_ENTRY_MAP_SIZE),
+        .size = (MMU_LEVEL_2_ENTRY_MAP_SIZE * 2),
+        .flags = 0,
+        .name = "prog"
+    },
+    {
+        .phys = GIC_PERIPHERAL_BASE_PHYS,
+        .virt = GIC_PERIPHERAL_BASE_VIRT,
+        .size = GIC_PERIPHERAL_BASE_SIZE,
+        .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE
+    },
+
+    /* reserved for dram */
+    { 0 },
+    /* null entry to terminate the list */
+    { 0 }
+};
+
+static inline size_t query_plat_dram_sz(void)
+{
+    extern size_t mt_mem_size(void) __attribute__((weak));
+
+    if (mt_mem_size)
+        return mt_mem_size();
+    else
+        /* default memory size for FPGA platform */
+        return 0x40000000;
+}
+
+static void setup_plat_mem(void)
+{
+    size_t dram_sz, mem_sz;
+    size_t unmap_dram_start_pa, unmap_dram_start_va;
+
+    /*
+     * Except the dram range for uncached memory pool, all other dram ranges
+     * are all mapped as cacheable memory.
+     */
+    unmap_dram_start_pa = DRAM_BASE_PHY;
+    unmap_dram_start_va = DRAM_BASE_VIRT;
+
+    dram_sz = query_plat_dram_sz();
+    mem_sz = UNCACHED_MEMPOOL_ADDR - unmap_dram_start_va;
+
+    /* unmap_dram_start_pa ~  (unmap_dram_start_pa + mem_sz) = cached memory */
+    arch_mmu_map(unmap_dram_start_va, unmap_dram_start_pa,
+                 mem_sz >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+
+    /*
+     * (unmap_dram_start_pa + mem_sz) ~  (unmap_dram_start_pa + mem_sz + UNCACHED_MEMPOOL_SIZE)=
+     * uncached memory
+     */
+    arch_mmu_map(UNCACHED_MEMPOOL_ADDR, unmap_dram_start_pa + mem_sz,
+                 UNCACHED_MEMPOOL_SIZE >> PAGE_SIZE_SHIFT,
+                 ARCH_MMU_FLAG_UNCACHED);
+
+    /*
+     * (unmap_dram_start_pa + mem_sz + UNCACHED_MEMPOOL_SIZE) ~  (dram_sz - mem_sz) =
+     * cached memory
+     */
+    mem_sz += UNCACHED_MEMPOOL_SIZE;
+    arch_mmu_map(UNCACHED_MEMPOOL_ADDR + UNCACHED_MEMPOOL_SIZE,
+                 unmap_dram_start_pa + mem_sz,
+                 (dram_sz - mem_sz) >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+
+    /* add dram to mmu_initial_mappings for pa to va lookup */
+    mmu_initial_mappings[DRAM_MAPPING_IDX].phys = DRAM_BASE_PHY;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].virt = DRAM_BASE_VIRT;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].size = dram_sz;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].flags = 0;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].name = "dram";
+}
+
+static void dcache_enable(void)
+{
+    uint32_t sctlr;
+
+    asm volatile("mrs %0, sctlr_el1" : "=r" (sctlr) : : "cc");
+    asm volatile("msr sctlr_el1, %0" : : "r" (sctlr | (1 << 2)) : "cc");
+    asm volatile("isb");
+}
+
+void platform_memory_init(void)
+{
+    extern void mt_mem_init(void) __attribute__((weak));
+    extern void mt_mem_test(void) __attribute__((weak));
+
+    mt_mem_init();
+    setup_plat_mem();
+    arch_disable_ints();
+    arch_disable_cache(DCACHE);
+    arch_enable_ints();
+    mt_mem_test();
+    dcache_enable();
+}
+
+static pmm_arena_t arena = {
+    .name = "sram",
+    .base = SRAM_ARENA_BASE,
+    .size = SRAM_ARENA_SIZE,
+    .flags = PMM_ARENA_FLAG_KMAP,
+};
+
+void platform_early_init_blx(void)
+{
+    dprintf(INFO, "BL2 Build Time: %s %s\n", __DATE__, __TIME__);
+
+    mt_pll_init();
+    mt6357_init();
+    rtc_boot();
+
+    /* map dram may need new page tables, add internal sram to arena memory */
+    pmm_add_arena(&arena);
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/platform_bl33.c b/src/bsp/lk/platform/mediatek/mt8133/platform_bl33.c
new file mode 100644
index 0000000..ebf3bb0
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/platform_bl33.c
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#include <arch/ops.h>
+#include <debug.h>
+#include <err.h>
+#include <kernel/vm.h>
+#include <platform.h>
+#include <platform/mt8133.h>
+
+#define PROG_MEM_MAPPING_IDX    0
+#define GIC_PERIPHERAL_MAPPING_IDX     1
+#define SRAM_MAPPING_IDX               2
+#define DRAM_MAPPING_IDX               3
+
+/* initial memory mappings. parsed by start.S */
+struct mmu_initial_mapping mmu_initial_mappings[] = {
+    {
+        .phys = MEMORY_BASE_PHYS,
+        .virt = MEMORY_BASE_VIRT,
+        .size = MEMORY_APERTURE_SIZE,
+        .flags = 0,
+        .name = "prog"
+    },
+    {
+        .phys = GIC_PERIPHERAL_BASE_PHYS,
+        .virt = GIC_PERIPHERAL_BASE_VIRT,
+        .size = GIC_PERIPHERAL_BASE_SIZE,
+        .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE
+    },
+
+    /* reserved for internal sram */
+    { 0 },
+    /* reserved for dram */
+    { 0 },
+    /* null entry to terminate the list */
+    { 0 }
+};
+
+static pmm_arena_t dram_arena = {
+    .name = "dram",
+    .base = DRAM_ARENA_BASE,
+    .size = DRAM_ARENA_SIZE,
+    .flags = PMM_ARENA_FLAG_KMAP,
+    .priority = 0,
+};
+
+static inline size_t query_plat_dram_sz(void)
+{
+    return BL33_DRAM_SZ_MB * 0x100000UL;
+}
+
+static void setup_plat_mem(void)
+{
+    size_t unmap_dram_sz, mapped_mem_sz;
+    size_t unmap_dram_start_pa, unmap_dram_start_va;
+
+    /* dram arena memory are already mapped in mmu initial mappings */
+    pmm_add_arena(&dram_arena);
+
+    arch_mmu_map(SRAM_BASE_VIRT, SRAM_BASE_PHYS,
+                 SRAM_BASE_SIZE >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+
+    /* add internal sram to mmu_initial_mappings for pa to va lookup */
+    mmu_initial_mappings[SRAM_MAPPING_IDX].phys = SRAM_BASE_PHYS;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].virt = SRAM_BASE_VIRT;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].size = SRAM_BASE_SIZE;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].flags = 0;
+    mmu_initial_mappings[SRAM_MAPPING_IDX].name = "sram";
+
+    /*
+     * Except the dram range for uncached memory pool, all other dram ranges
+     * are all mapped as cacheable memory.
+     */
+
+    /* BL33 initial mapping already maps a portion of dram, map the rest here */
+    unmap_dram_start_pa = MEMORY_BASE_PHYS + MEMORY_APERTURE_SIZE;
+    unmap_dram_start_va = MEMORY_BASE_VIRT + MEMORY_APERTURE_SIZE;
+
+    mapped_mem_sz = UNCACHED_MEMPOOL_ADDR - unmap_dram_start_va;
+    arch_mmu_map(unmap_dram_start_va, unmap_dram_start_pa,
+                 mapped_mem_sz >> PAGE_SIZE_SHIFT, ARCH_MMU_FLAG_CACHED);
+    arch_mmu_map(UNCACHED_MEMPOOL_ADDR, unmap_dram_start_pa + mapped_mem_sz,
+                 UNCACHED_MEMPOOL_SIZE >> PAGE_SIZE_SHIFT,
+                 ARCH_MMU_FLAG_UNCACHED);
+
+    unmap_dram_sz = query_plat_dram_sz() - MEMORY_APERTURE_SIZE;
+    mapped_mem_sz += UNCACHED_MEMPOOL_SIZE;
+    arch_mmu_map(UNCACHED_MEMPOOL_ADDR + UNCACHED_MEMPOOL_SIZE,
+                 unmap_dram_start_pa + mapped_mem_sz,
+                 (unmap_dram_sz - mapped_mem_sz) >> PAGE_SIZE_SHIFT,
+                 ARCH_MMU_FLAG_CACHED);
+
+    /* add dram to mmu_initial_mappings for pa to va lookup */
+    mmu_initial_mappings[DRAM_MAPPING_IDX].phys = unmap_dram_start_pa;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].virt = unmap_dram_start_va;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].size = unmap_dram_sz;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].flags = 0;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].name = "dram";
+}
+
+void platform_memory_init(void)
+{
+    setup_plat_mem();
+}
+
+void platform_early_init_blx(void)
+{
+    dprintf(CRITICAL, "BL33 Build Time: %s %s\n", __DATE__, __TIME__);
+}
diff --git a/src/bsp/lk/platform/mediatek/mt8133/rules.mk b/src/bsp/lk/platform/mediatek/mt8133/rules.mk
new file mode 100644
index 0000000..a42533e
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/mt8133/rules.mk
@@ -0,0 +1,89 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+COMMON_PLAT := $(LOCAL_DIR)/../common
+
+ARCH ?= arm64
+ARM_CPU ?= cortex-a53
+WITH_SMP ?= 0
+
+LK_HEAP_IMPLEMENTATION ?= miniheap
+
+GLOBAL_INCLUDES += -I$(LK_TOP_DIR)/include
+GLOBAL_CFLAGS += -fno-stack-protector
+MODULE_SRCS += \
+    $(LOCAL_DIR)/platform.c \
+    $(LOCAL_DIR)/../common/debug.c \
+    $(LOCAL_DIR)/../common/interrupts.c \
+    $(LOCAL_DIR)/../common/boot_mode.c \
+    $(LOCAL_DIR)/fixup/plat_fixup.c \
+
+GLOBAL_INCLUDES += \
+    $(LOCAL_DIR)/../common/include
+
+MACH_TYPE := 8133
+
+KERNEL_ASPACE_BASE ?= 0xfffffff000000000
+KERNEL_ASPACE_SIZE ?= 0x0000000180000000
+MMU_IDENT_SIZE_SHIFT ?= 32
+
+CACHED_MEMPOOL_ADDR ?= 0xfffffff04c500000
+CACHED_MEMPOOL_SIZE ?= 0x03A00000 # 58MB
+UNCACHED_MEMPOOL_ADDR ?= 0xfffffff04c300000
+UNCACHED_MEMPOOL_SIZE ?= 0x200000 # 2MB
+BL33_ADDR ?= 0xfffffff043200000
+
+# LK build as BL2 or BL33 setting
+LK_AS_BL33 ?= 0
+
+MODULE_DEPS += \
+    dev/interrupt/arm_gic_v3 \
+    dev/timer/arm_generic \
+    lib/bio \
+    lib/partition \
+    lib/fdt \
+    lib/mempool \
+    lib/kcmdline
+
+# if BOOTAPP is not specified elsewhere, and AVB is required, choose 'avbboot'
+ifeq ($(strip $(SECURE_BOOT_ENABLE)),yes)
+ifeq ($(strip $(SECURE_BOOT_TYPE)),avb)
+BOOTAPP ?= avbboot
+endif
+endif
+
+# otherwise, choose 'fitboot'
+BOOTAPP ?= fitboot
+
+MODULES += app/$(BOOTAPP)
+
+GLOBAL_DEFINES += MMU_IDENT_SIZE_SHIFT=$(MMU_IDENT_SIZE_SHIFT)
+
+GLOBAL_DEFINES += \
+    RAMBASE=$(RAMBASE) \
+    MACH_TYPE=$(MACH_TYPE) \
+    PLATFORM_SUPPORTS_PANIC_SHELL=1 \
+    WITH_NO_FP=1 \
+    CACHED_MEMPOOL_ADDR=$(CACHED_MEMPOOL_ADDR) \
+    CACHED_MEMPOOL_SIZE=$(CACHED_MEMPOOL_SIZE) \
+    UNCACHED_MEMPOOL_ADDR=$(UNCACHED_MEMPOOL_ADDR) \
+    UNCACHED_MEMPOOL_SIZE=$(UNCACHED_MEMPOOL_SIZE) \
+    BL33_ADDR=$(BL33_ADDR) \
+    LK_AS_BL33=$(LK_AS_BL33)
+
+TOOLCHAIN_PREFIX := $(ARCH_$(ARCH)_TOOLCHAIN_PREFIX)
+$(info TOOLCHAIN_PREFIX = $(TOOLCHAIN_PREFIX))
+ifneq ($(call TOBOOL,$(CLANGBUILD)),true)
+GCC_VER_GTE94 := $(shell echo `$(TOOLCHAIN_PREFIX)gcc -dumpfullversion | cut -f1-2 -d.` \>= 9.4 | bc )
+$(info GCC_VER = $(shell echo `$(TOOLCHAIN_PREFIX)gcc -dumpfullversion | cut -f1-2 -d.`))
+ifeq ($(GCC_VER_GTE94),1)
+ARCH_COMPILEFLAGS += -mno-outline-atomics
+endif
+endif
+$(info ARCH_COMPILEFLAGS = $(ARCH_COMPILEFLAGS))
+
+LINKER_SCRIPT += \
+    $(BUILDDIR)/system-onesegment.ld
+
+include $(LOCAL_DIR)/bl2_bl33_options.mk
+include make/module.mk $(LOCAL_DIR)/drivers/rules.mk
diff --git a/src/bsp/lk/platform/mediatek/rules.mk b/src/bsp/lk/platform/mediatek/rules.mk
new file mode 100644
index 0000000..29f47e2
--- /dev/null
+++ b/src/bsp/lk/platform/mediatek/rules.mk
@@ -0,0 +1,3 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+include $(LOCAL_DIR)/$(MTK_PLATFORM)/rules.mk