[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/platform/mt8518/debug.c b/src/bsp/lk/platform/mt8518/debug.c
new file mode 100644
index 0000000..cbe1ea6
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/debug.c
@@ -0,0 +1,74 @@
+/*
+ * 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 <stdarg.h>
+#include <reg.h>
+#include <stdio.h>
+#include <kernel/thread.h>
+#include <dev/uart.h>
+#include <platform/debug.h>
+#include <platform/mt_uart.h>
+#include <platform/mt8518.h>
+#include <target/debugconfig.h>
+#include <reg.h>
+
+/* DEBUG_UART must be defined to 0 or 1 */
+#if defined(DEBUG_UART) && DEBUG_UART == 0
+#define DEBUG_UART_BASE UART0_BASE
+#elif defined(DEBUG_UART) && DEBUG_UART == 1
+#define DEBUG_UART_BASE UART1_BASE
+#else
+#error define DEBUG_UART to something valid
+#endif
+
+void platform_dputc(char c)
+{
+    if (c == '\n')
+        uart_putc(DEBUG_UART, '\r');
+    uart_putc(DEBUG_UART, c);
+}
+
+int platform_dgetc(char *c, bool wait)
+{
+    bool ret = check_uart_enter();
+    if (ret == false)
+        return -1;
+    *c = 13;
+    return 0;
+}
+
+void platform_pputc(char c)
+{
+    if (c == '\n')
+        uart_pputc(DEBUG_UART, '\r');
+    uart_pputc(DEBUG_UART, c);
+}
+
+int platform_pgetc(char *c, bool wait)
+{
+    int ret = uart_pgetc(DEBUG_UART);
+    if (ret < 0)
+        return ret;
+    *c = ret;
+    return 0;
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/charger/rt9460.c b/src/bsp/lk/platform/mt8518/drivers/charger/rt9460.c
new file mode 100644
index 0000000..91ce256
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/charger/rt9460.c
@@ -0,0 +1,114 @@
+/* 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.
+ */
+#include <platform/mt_i2c.h>
+#include <platform/rt9460.h>
+/**********************************************************
+  *   I2C Slave Setting
+  *********************************************************/
+#define rt9460_SLAVE_ADDR   0x25
+/**********************************************************
+  *   Global Variable
+  *********************************************************/
+#define rt9460_I2C_ID        0
+/*********************************************************/
+/***********************************************************
+  *   [I2C Function For Read/Write rt9460]  *
+  *********************************************************/
+u32 rt9460_write_byte(u8 addr, u8 value)
+{
+    int ret_code = 0;
+    u8 write_data[2];
+    u16 len;
+
+    write_data[0]= addr;
+    write_data[1] = value;
+    len = 2;
+
+    ret_code = mtk_i2c_write(rt9460_I2C_ID, rt9460_SLAVE_ADDR, 100, write_data, len);
+
+    if(ret_code == 0)
+        return 0; // ok
+    else
+        return -1; // fail
+}
+
+u32 rt9460_read_byte (u8 addr, u8 *dataBuffer)
+{
+    int ret_code = 0;
+    u16 len;
+    *dataBuffer = addr;
+    len = 1;
+
+    ret_code = mtk_i2c_write_read(rt9460_I2C_ID,
+                    rt9460_SLAVE_ADDR,
+                    100,
+                    dataBuffer,
+                     dataBuffer,
+                    len,
+                    len);
+
+    if(ret_code == 0)
+        return 0; // ok
+    else
+        return -1; // fail
+}
+/***********************************************/
+int rt9460IsCableIn(void)
+{
+    u8 val=0;
+    rt9460_read_byte(RT9460_REG_CTRL1,&val);
+    if(val & RT9460_PWRRDY_MASK) return 1; // usb cable in
+    return 0;    //no usb in
+}
+
+unsigned int rt9460TypeDetection(void)
+{
+    uint8_t val=RT9460_REG_CTRLDPDM;
+    rt9460_read_byte(RT9460_REG_CTRLDPDM,&val);
+    val = (val & RT9460_CHGTYP_MASK) >> RT9460_CHGTYP_SHFT;
+
+    switch(val){
+        case 0x00:    //standard usb charger
+            return     1;    //STANDARD_HOST;
+        case 0x01:    //sony charger 1
+        case 0x02:    //sony charger 2
+        case 0x03:    //apple 0.5A
+        case 0x04:    //apple 1A
+        case 0x05:    //nikon charger 1A
+            return     3;    //NONSTANDARD_CHARGER;
+        case 0x06:    //cdp
+            return     2;    //CHARGING_HOST;
+        case 0x07:    //DCP
+            return     4;    //STANDARD_CHARGER;
+        default:
+            return 0;
+    }
+}
diff --git a/src/bsp/lk/platform/mt8518/drivers/gic/mt_gic.S b/src/bsp/lk/platform/mt8518/drivers/gic/mt_gic.S
new file mode 100644
index 0000000..647299a
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/gic/mt_gic.S
@@ -0,0 +1,64 @@
+#include <asm.h>
+#include <arch/arm64/mmu.h>
+#include <arch/asm_macros.h>
+#include <kernel/vm.h>
+
+/*
+ * Register use:
+ *  x0-x3   Arguments
+ *  x9-x15  Scratch
+ *  x19-x28 Globals
+ */
+
+#define GIC_DIST_BASE	0x0c000000
+#define GIC_RDIST_BASE	0x0c100000
+
+FUNCTION(mt_gic_el3_setup)
+	/* GIC V3 redistributor initialization (all CPUs) */
+	ldr x2, =GIC_RDIST_BASE
+	ldr w4, [x2, #0x14]       // GICR_WAKER
+	bic w4, w4, #(1 << 1)     // clear ProcessorSleep
+	str w4, [x2, #0x14]       // GICR_WAKER
+
+1:
+	ldr	w4, [x2, #0x14]       // GICR_WAKER
+	tst w4, #(1 << 2)         // test ChildrenAsleep
+	b.ne	1b
+
+	/*
+	 * We need to set SCR_EL3.NS in order to see GICv3 non-secure state.
+	 * Restore SCR_EL3.NS again before exit.
+	 */
+	mov	x0, #0x30				// RES1
+	orr	x0, x0, #1				// Non-secure EL1
+	msr	scr_el3, x0	            /* ensure NS=1 takes effect before accessing ICC_SRE_EL2 */
+
+	/*GIC V3 CPU interface initialization (all CPUs)*/
+	mrs	x0, S3_6_C12_C12_5    // ICC_SRE_EL3
+	orr     x0, x0, #1        // SRE
+	orr     x0, x0, #(1<<3)   // EN
+	msr	S3_6_C12_C12_5, x0
+
+	mov x0, #0x1
+	msr S3_6_C12_C12_7, x0    // ICC_GRPEN1_EL3
+
+	mrs	x0, S3_4_C12_C9_5     // ICC_SRE_EL2
+	orr     x0, x0, #1        // SRE
+	orr     x0, x0, #(1<<3)   // EN
+	msr	S3_4_C12_C9_5, x0
+
+	mov x0, #0xff
+	msr S3_0_C4_C6_0, x0      // ICC_PMR_EL1
+
+	/* Restore SCR_EL3 */
+	mrs	x0, scr_el3
+	bic x0, x0, #1
+	msr	scr_el3, x0	          /* ensure NS=0 takes effect immediately */
+
+	mov x0, #0x1
+	msr S3_0_C12_C12_7, x0    // ICC_GRPEN1_EL1
+
+	mov x0, #0x1
+	msr	S3_0_C12_C12_5, x0    //Write the secure ICC_SRE_EL1 register
+
+    ret
diff --git a/src/bsp/lk/platform/mt8518/drivers/gic/mt_gic_v3.c b/src/bsp/lk/platform/mt8518/drivers/gic/mt_gic_v3.c
new file mode 100644
index 0000000..e8d255d
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/gic/mt_gic_v3.c
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 2012-2015 Travis Geiselbrecht
+ *
+ * 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 <err.h>
+#include <reg.h>
+#include <kernel/thread.h>
+#include <kernel/debug.h>
+#include <lk/init.h>
+#include <platform/interrupts.h>
+#include <platform/mt_irq.h>
+#include <platform/mt_gic_v3.h>
+#include <platform/mt_reg_base.h>
+#include <arch/ops.h>
+#include <platform/gic.h>
+#include <trace.h>
+
+#if WITH_LIB_SM
+#include <lib/sm.h>
+#include <lib/sm/sm_err.h>
+#endif
+
+#define LOCAL_TRACE 0
+
+#if ARCH_ARM
+#include <arch/arm.h>
+#define iframe arm_iframe
+#define IFRAME_PC(frame) ((frame)->pc)
+#endif
+#if ARCH_ARM64
+#include <arch/arm64.h>
+#define iframe arm64_iframe_short
+#define IFRAME_PC(frame) ((frame)->elr)
+#endif
+
+/* helpers for later ICC encode macros
+ * Indirect stringification.  Doing two levels allows the parameter to be a
+ * macro itself.  For example, compile with -DFOO=bar, __stringify(FOO)
+ * converts to "bar".
+ */
+#define __stringify_1(x)     #x
+#define __stringify(x)       __stringify_1(x)
+
+#define GIC_READ(a) readl(a)
+#define GIC_WRITE(a, v) writel(v, a)
+
+static status_t arm_gic_set_secure_locked(u_int irq, bool secure);
+static spin_lock_t gicd_lock;
+
+#if WITH_LIB_SM
+#define GICD_LOCK_FLAGS SPIN_LOCK_FLAG_IRQ_FIQ
+#else
+#define GICD_LOCK_FLAGS SPIN_LOCK_FLAG_INTERRUPTS
+#endif
+
+#define GIC_MAX_PER_CPU_INT 32
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#define GIC_REG_COUNT(bit_per_reg) DIV_ROUND_UP(MAX_INT, (bit_per_reg))
+#define DEFINE_GIC_SHADOW_REG(name, bit_per_reg, init_val, init_from) \
+	uint32_t (name)[GIC_REG_COUNT(bit_per_reg)] = { \
+		[(init_from / bit_per_reg) ... \
+		 (GIC_REG_COUNT(bit_per_reg) - 1)] = (init_val) \
+	}
+
+__asm__ (
+"       .irp    num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n"
+"       .equ    __reg_num_x\\num, \\num\n"
+"       .endr\n"
+"       .equ    __reg_num_xzr, 31\n"
+"\n"
+"       .macro  mrs_s, rt, sreg\n"
+"       .inst   0xd5300000|(\\sreg)|(__reg_num_\\rt)\n"
+"       .endm\n"
+"\n"
+"       .macro  msr_s, sreg, rt\n"
+"       .inst   0xd5100000|(\\sreg)|(__reg_num_\\rt)\n"
+"       .endm\n"
+);
+
+/* since gcc not support most ARMv8 ICC sysreg in asm,
+ * we learn Linux's way to encode them */
+#define sys_reg(op0, op1, crn, crm, op2) \
+        ((((op0)-2)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5))
+
+#if WITH_LIB_SM
+static bool arm_gic_non_secure_interrupts_frozen;
+
+static bool arm_gic_interrupt_change_allowed(int irq)
+{
+	if (!arm_gic_non_secure_interrupts_frozen)
+		return true;
+
+	TRACEF("change to interrupt %d ignored after booting ns\n", irq);
+	return false;
+}
+
+static void suspend_resume_fiq(bool resume_gicc, bool resume_gicd);
+#else
+static bool arm_gic_interrupt_change_allowed(int irq)
+{
+	return true;
+}
+
+static void suspend_resume_fiq(bool resume_gicc, bool resume_gicd)
+{
+}
+#endif
+
+/*******************************************************************************
+ * This function does some minimal GICv3 configuration. The Firmware itself does
+ * not fully support GICv3 at this time and relies on GICv2 emulation as
+ * provided by GICv3. This function allows software (like Linux) in later stages
+ * to use full GICv3 features.
+ ******************************************************************************/
+static void gicv3_cpuif_setup(void)
+{
+	/* set all SGI/PPI as non-secure GROUP1 by default.
+	   rdist_base + 64K == SGI_base */
+	GIC_WRITE(GIC_REDIS_BASE+SZ_64K+GICE_V3_IGROUP0, 0xffffffff);
+	GIC_WRITE(GIC_REDIS_BASE+SZ_64K+GICE_V3_IGRPMOD0, 0x0);
+}
+
+
+static void mt_git_dist_rwp(void)
+{
+	/*
+	 * check GICD_CTLR.RWP for done check
+	 */
+	while (GIC_READ(GIC_DIST_BASE + GICD_CTLR) & GICD_CTLR_RWP) {
+
+	}
+}
+
+struct int_handler_struct {
+	int_handler handler;
+	void *arg;
+};
+
+static struct int_handler_struct int_handler_table_per_cpu[GIC_MAX_PER_CPU_INT][SMP_MAX_CPUS];
+static struct int_handler_struct int_handler_table_shared[MAX_INT-GIC_MAX_PER_CPU_INT];
+
+static struct int_handler_struct *get_int_handler(unsigned int vector, uint cpu)
+{
+	if (vector < GIC_MAX_PER_CPU_INT)
+		return &int_handler_table_per_cpu[vector][cpu];
+	else
+		return &int_handler_table_shared[vector - GIC_MAX_PER_CPU_INT];
+}
+
+void register_int_handler(unsigned int vector, int_handler handler, void *arg)
+{
+	struct int_handler_struct *h;
+	uint cpu = arch_curr_cpu_num();
+
+	spin_lock_saved_state_t state;
+
+	if (vector >= MAX_INT)
+		panic("register_int_handler: vector out of range %d\n", vector);
+
+	spin_lock_save(&gicd_lock, &state, GICD_LOCK_FLAGS);
+
+	if (arm_gic_interrupt_change_allowed(vector)) {
+		h = get_int_handler(vector, cpu);
+		h->handler = handler;
+		h->arg = arg;
+	}
+
+	spin_unlock_restore(&gicd_lock, state, GICD_LOCK_FLAGS);
+}
+
+#if WITH_LIB_SM
+static DEFINE_GIC_SHADOW_REG(gicd_igroupr, 32, ~0U, 0);
+#endif
+static DEFINE_GIC_SHADOW_REG(gicd_itargetsr, 4, 0x01010101, 32);
+
+static void gic_set_enable(uint vector, bool enable)
+{
+	int reg = vector / 32;
+	uint32_t mask = 1ULL << (vector % 32);
+
+	if (enable)
+		GIC_READ(GIC_DIST_BASE + GICD_ISENABLER + reg * 4) = mask;
+	else
+		GIC_READ(GIC_DIST_BASE + GICD_ICENABLER + reg * 4) = mask;
+}
+
+static void arm_gic_init_percpu(uint level)
+{
+#if WITH_LIB_SM
+	GIC_READ(GIC_REDIS_BASE + GICC_CTLR) = 0xb; // enable GIC0 and select fiq mode for secure
+	GIC_READ(GIC_DIST_BASE + GICD_IGROUPR) = ~0U; /* GICD_IGROUPR0 is banked */
+#else
+	GIC_READ(GIC_REDIS_BASE + GICC_CTLR) = 1; // enable GIC0
+#endif
+	GIC_READ(GIC_REDIS_BASE + GICC_PMR) = 0xFF; // unmask interrupts at all priority levels
+}
+
+LK_INIT_HOOK_FLAGS(arm_gic_init_percpu,
+       arm_gic_init_percpu,
+       LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_FLAG_SECONDARY_CPUS);
+
+static void arm_gic_suspend_cpu(uint level)
+{
+	suspend_resume_fiq(false, false);
+}
+
+LK_INIT_HOOK_FLAGS(arm_gic_suspend_cpu, arm_gic_suspend_cpu,
+		LK_INIT_LEVEL_PLATFORM, LK_INIT_FLAG_CPU_SUSPEND);
+
+static void arm_gic_resume_cpu(uint level)
+{
+	spin_lock_saved_state_t state;
+	bool resume_gicd = false;
+
+	spin_lock_save(&gicd_lock, &state, GICD_LOCK_FLAGS);
+	if (!(GIC_READ(GIC_DIST_BASE + GICD_CTLR) & 1)) {
+		dprintf(SPEW, "%s: distibutor is off, calling arm_gic_init instead\n", __func__);
+		arm_gic_init();
+		resume_gicd = true;
+	} else {
+		arm_gic_init_percpu(0);
+	}
+	spin_unlock_restore(&gicd_lock, state, GICD_LOCK_FLAGS);
+	suspend_resume_fiq(true, resume_gicd);
+}
+
+LK_INIT_HOOK_FLAGS(arm_gic_resume_cpu, arm_gic_resume_cpu,
+		LK_INIT_LEVEL_PLATFORM, LK_INIT_FLAG_CPU_RESUME);
+
+static int arm_gic_max_cpu(void)
+{
+	return (GIC_READ(GIC_DIST_BASE + GICD_TYPER) >> 5) & 0x7;
+}
+
+/*******************************************************************************
+ * Enable secure interrupts and use FIQs to route them. Disable legacy bypass
+ * and set the priority mask register to allow all interrupts to trickle in.
+ ******************************************************************************/
+void arm_gic_redist_init(void)
+{
+	/* set all SGI/PPI as non-secure GROUP1 by default.
+	   rdist_base + 64K == SGI_base */
+	GIC_WRITE(GIC_REDIS_BASE+SZ_64K+GICE_V3_IGROUP0, 0xffffffff);
+	GIC_WRITE(GIC_REDIS_BASE+SZ_64K+GICE_V3_IGRPMOD0, 0x0);
+}
+
+static void arm_gic_distif_init(void)
+{
+	unsigned int i, ctrl, irq_set;
+
+	/* Disable the distributor before going further */
+	ctrl = GIC_READ(GIC_DIST_BASE + GICD_CTLR);
+	ctrl &= ~(GICD_CTLR_ENABLE_GRP0 | GICD_CTLR_ENGRP1NS | GICD_CTLR_ENGRP1S);
+	GIC_WRITE(GIC_DIST_BASE + GICD_CTLR, ctrl);
+
+	mt_git_dist_rwp();
+
+	/*
+	 * Mark out non-secure SPI interrupts. The number of interrupts is
+	 * calculated as 32 * (IT_LINES + 1). We do 32 at a time.
+	 */
+	irq_set = (GIC_READ(GIC_DIST_BASE + GICD_TYPER)&IT_LINES_NO_MASK) + 1;
+	irq_set = irq_set * 32;
+
+	/* set all SPI as non-secure group1 by default,
+	 * index from 1, because GICE_V3_IGROUP0, GICE_V3_IGRPMOD0 are RES0,
+	 * equivalent function is provided by GICR_IGROUPR0, GICE_V3_IGRPMOD0,
+	 * which are both initialized in gic_cpuif_init() */
+	for (i = 32; i < irq_set; i += 32) {
+		GIC_WRITE(GIC_DIST_BASE+GICD_IGROUPR + i * 4 / 32, 0x0);
+		GIC_WRITE(GIC_DIST_BASE+GICD_IGRPMODR + i * 4 / 32, 0xffffffff);
+	}
+
+	/*
+	 * Set all global interrupts to be level triggered, active low.
+	 */
+	for (i = 32; i < irq_set; i += 16) {
+		GIC_WRITE(GIC_DIST_BASE + GICD_ICFGR + i * 4 / 16, 0);
+	}
+
+	/*
+	 * Set all global interrupts to this CPU only.
+	 */
+	if (arm_gic_max_cpu() > 0) {
+		/* Set external interrupts to target cpu 0 */
+		for (i = 32; i < irq_set; i += 4) {
+			GIC_READ(GIC_DIST_BASE + GICD_ITARGETSR + (i / 4) * 4) = gicd_itargetsr[i / 4];
+		}
+	}
+
+	/*
+	 * Set priority on all interrupts.
+	 */
+	for (i = 0; i < irq_set; i += 4) {
+		GIC_WRITE(GIC_DIST_BASE + GICD_IPRIORITYR + i * 4 / 4, 0xA0A0A0A0);
+	}
+
+	/*
+	 * Disable all interrupts.
+	 */
+	for (i = 0; i < irq_set; i += 32) {
+		GIC_WRITE(GIC_DIST_BASE + GICD_ICENABLER + i * 4 / 32, 0xFFFFFFFF);
+	}
+
+	/*
+	 * Clear all active status
+	 */
+	for (i = 0; i < irq_set; i += 32) {
+		GIC_WRITE(GIC_DIST_BASE + GICD_ICACTIVER + i * 4 / 32, 0xFFFFFFFF);
+	}
+
+	/*
+	 * Clear all pending status
+	 */
+	for (i = 0; i < irq_set; i += 32) {
+		GIC_WRITE(GIC_DIST_BASE + GICD_ICPENDR + i * 4 / 32, 0xFFFFFFFF);
+	}
+
+	/* enable all groups & ARE */
+	ctrl = GICD_CTLR_ENABLE_GRP0 | GICD_CTLR_ENGRP1NS | GICD_CTLR_ENGRP1S |
+		GICD_CTLR_ARE | GICD_CTLR_ARE_NS;
+	GIC_WRITE(GIC_DIST_BASE + GICD_CTLR, ctrl);
+
+	mt_git_dist_rwp();
+}
+
+void clear_sec_pol_ctl_en(void)
+{
+	unsigned int i;
+
+	/* total 19 polarity ctrl registers */
+	for (i = 0; i <= NR_INT_POL_CTL-1; i++) {
+		GIC_WRITE((SEC_POL_CTL_EN0 + (i * 4)), 0);
+	}
+}
+
+void arm_gic_init(void)
+{
+	LTRACEF("[LK GIC] before arm_gic_cpuif_setup\n");
+	arm_gic_redist_init();
+
+	LTRACEF("[LK GIC] before arm_gic_distif_init\n");
+	arm_gic_distif_init();
+
+#if WITH_LIB_SM
+	GIC_READ(GIC_DIST_BASE + GICD_CTLR) = 3; // enable GIC0 ns interrupts
+	/*
+	 * Iterate through all IRQs and set them to non-secure
+	 * mode. This will allow the non-secure side to handle
+	 * all the interrupts we don't explicitly claim.
+	 */
+	for (i = 32; i < MAX_INT; i += 32) {
+		u_int reg = i / 32;
+		GIC_READ(GIC_DIST_BASE + GICD_IGROUPR + reg * 4) = gicd_igroupr[reg];
+	}
+#endif
+	arm_gic_init_percpu(0);
+
+	LTRACEF("[LK GIC] before clear_sec_pol_ctl_en\n");
+	clear_sec_pol_ctl_en();
+
+}
+
+static status_t arm_gic_set_secure_locked(u_int irq, bool secure)
+{
+#if WITH_LIB_SM
+	int reg = irq / 32;
+	uint32_t mask = 1ULL << (irq % 32);
+
+	if (irq >= MAX_INT)
+		return ERR_INVALID_ARGS;
+
+	if (secure)
+		GIC_READ(GIC_DIST_BASE + GICD_IGROUPR + reg * 4) = (gicd_igroupr[reg] &= ~mask);
+	else
+		GIC_READ(GIC_DIST_BASE + GICD_IGROUPR + reg * 4) = (gicd_igroupr[reg] |= mask);
+	LTRACEF("irq %d, secure %d, GICD_IGROUP%d = %x\n",
+		irq, secure, reg, GIC_READ(GIC_DIST_BASE + GICD_IGROUPR + reg * 4);
+#endif
+	return NO_ERROR;
+}
+
+static status_t arm_gic_set_target_locked(u_int irq, u_int cpu_mask, u_int enable_mask)
+{
+	u_int reg = irq / 4;
+	u_int shift = 8 * (irq % 4);
+	u_int old_val;
+	u_int new_val;
+
+	cpu_mask = (cpu_mask & 0xff) << shift;
+	enable_mask = (enable_mask << shift) & cpu_mask;
+
+	old_val = GIC_READ(GIC_DIST_BASE + GICD_ITARGETSR + reg * 4);
+	new_val = (gicd_itargetsr[reg] & ~cpu_mask) | enable_mask;
+	GIC_READ(GIC_DIST_BASE + GICD_ITARGETSR + reg * 4) = gicd_itargetsr[reg] = new_val;
+	LTRACEF("irq %i, GICD_ITARGETSR%d %x => %x (got %x)\n",
+		irq, reg, old_val, new_val, GIC_READ(GIC_DIST_BASE + GICD_ITARGETSR + reg));
+
+	return NO_ERROR;
+}
+
+static status_t arm_gic_get_priority(u_int irq)
+{
+	u_int reg = irq / 4;
+	u_int shift = 8 * (irq % 4);
+	return (GIC_READ(GIC_DIST_BASE + GICD_IPRIORITYR + reg * 4) >> shift) & 0xff;
+}
+
+static status_t arm_gic_set_priority_locked(u_int irq, uint8_t priority)
+{
+	u_int reg = irq / 4;
+	u_int shift = 8 * (irq % 4);
+	u_int mask = 0xff << shift;
+	uint32_t regval;
+
+	regval = GIC_READ(GIC_DIST_BASE + GICD_IPRIORITYR + reg);
+	LTRACEF("irq %i, old GICD_IPRIORITYR%d = %x\n", irq, reg, regval);
+	regval = (regval & ~mask) | ((uint32_t)priority << shift);
+	GIC_READ(GIC_DIST_BASE + GICD_IPRIORITYR + reg * 4) = regval;
+	LTRACEF("irq %i, new GICD_IPRIORITYR%d = %x, req %x\n",
+		irq, reg, GIC_READ(GIC_DIST_BASE + GICD_IPRIORITYR + reg * 4), regval);
+
+	return 0;
+}
+
+status_t arm_gic_sgi(u_int irq, u_int flags, u_int cpu_mask)
+{
+	u_int val =
+		((flags & ARM_GIC_SGI_FLAG_TARGET_FILTER_MASK) << 24) |
+		((cpu_mask & 0xff) << 16) |
+		((flags & ARM_GIC_SGI_FLAG_NS) ? (1U << 15) : 0) |
+		(irq & 0xf);
+
+	if (irq >= 16)
+		return ERR_INVALID_ARGS;
+
+	LTRACEF("GICD_SGIR: %x\n", val);
+
+	GIC_READ(GIC_DIST_BASE + GICD_SGIR) = val;
+
+	return NO_ERROR;
+}
+
+status_t mask_interrupt(unsigned int vector)
+{
+	if (vector >= MAX_INT)
+		return ERR_INVALID_ARGS;
+
+	if (arm_gic_interrupt_change_allowed(vector))
+		gic_set_enable(vector, false);
+
+	return NO_ERROR;
+}
+
+status_t unmask_interrupt(unsigned int vector)
+{
+	if (vector >= MAX_INT)
+		return ERR_INVALID_ARGS;
+
+	if (arm_gic_interrupt_change_allowed(vector))
+		gic_set_enable(vector, true);
+
+	return NO_ERROR;
+}
+
+static uint64_t gicc_read_hppir1_el1(void)
+{
+	uint64_t val = 0;
+
+	__asm__ volatile("mrs_s %0, " __stringify(ICC_HPPIR1_EL1) : "=r" (val));
+
+	return val;
+}
+
+uint32_t arm_gic_get_pending_interrupt_id(void)
+{
+	return gicc_read_hppir1_el1();
+}
+
+uint64_t gicc_read_iar1_el1(void)
+{
+	u64 irqstat;
+	__asm__ volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat));
+	return irqstat;
+}
+
+uint64_t arm_gic_acknowledge_irq(void)
+{
+	return gicc_read_iar1_el1();
+}
+
+static void gicc_write_eoi1_el1(uint32_t irq)
+{
+	__asm__ volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" (irq));
+}
+
+static void arm_gic_end_of_irq(uint32_t id)
+{
+	gicc_write_eoi1_el1(id);
+}
+
+uint64_t gicc_read_iar0_el1(void)
+{
+	u64 irqstat;
+	__asm__ volatile("mrs_s %0, " __stringify(ICC_IAR0_EL1) : "=r" (irqstat));
+	return irqstat;
+}
+
+uint64_t arm_gic_acknowledge_fiq(void)
+{
+	return gicc_read_iar0_el1();
+}
+
+static void gicc_write_eoi0_el1(uint32_t irq)
+{
+	__asm__ volatile("msr_s " __stringify(ICC_EOIR0_EL1) ", %0" : : "r" (irq));
+}
+
+static void arm_gic_end_of_fiq(uint32_t id)
+{
+	gicc_write_eoi0_el1(id);
+}
+
+static
+enum handler_return __platform_irq(struct iframe *frame)
+{
+	// get the current vector
+	uint32_t iar = arm_gic_acknowledge_irq();
+	unsigned int vector = iar & 0x3ff;
+
+	if (vector >= 0x3fe) {
+		// spurious
+		return INT_NO_RESCHEDULE;
+	}
+
+	THREAD_STATS_INC(interrupts);
+	KEVLOG_IRQ_ENTER(vector);
+
+	uint cpu = arch_curr_cpu_num();
+
+	LTRACEF_LEVEL(2, "iar 0x%x cpu %u currthread %p vector %d pc 0x%lx\n", iar, cpu,
+	       get_current_thread(), vector, (uintptr_t)IFRAME_PC(frame));
+
+	// deliver the interrupt
+	enum handler_return ret;
+
+	ret = INT_NO_RESCHEDULE;
+	struct int_handler_struct *handler = get_int_handler(vector, cpu);
+	if (handler->handler)
+		ret = handler->handler(handler->arg);
+
+	arm_gic_end_of_irq(iar);
+
+	LTRACEF_LEVEL(2, "cpu %u exit %d\n", cpu, ret);
+
+	KEVLOG_IRQ_EXIT(vector);
+
+	return ret;
+}
+
+enum handler_return platform_irq(struct iframe *frame)
+{
+#if WITH_LIB_SM
+	uint32_t ahppir = arm_gic_get_pending_interrupt_id();
+	uint32_t pending_irq = ahppir & 0x3ff;
+	struct int_handler_struct *h;
+	uint cpu = arch_curr_cpu_num();
+
+	LTRACEF("ahppir %d\n", ahppir);
+	if (pending_irq < MAX_INT && get_int_handler(pending_irq, cpu)->handler) {
+		enum handler_return ret = 0;
+		uint32_t irq;
+		uint8_t old_priority;
+		spin_lock_saved_state_t state;
+
+		spin_lock_save(&gicd_lock, &state, GICD_LOCK_FLAGS);
+
+		/* Temporarily raise the priority of the interrupt we want to
+		 * handle so another interrupt does not take its place before
+		 * we can acknowledge it.
+		 */
+		old_priority = arm_gic_get_priority(pending_irq);
+		arm_gic_set_priority_locked(pending_irq, 0);
+		DSB;
+		irq = arm_gic_acknowledge_irq() & 0x3ff;
+		arm_gic_set_priority_locked(pending_irq, old_priority);
+
+		spin_unlock_restore(&gicd_lock, state, GICD_LOCK_FLAGS);
+
+		LTRACEF("irq %d\n", irq);
+		if (irq < MAX_INT && (h = get_int_handler(pending_irq, cpu))->handler)
+			ret = h->handler(h->arg);
+		else
+			TRACEF("unexpected irq %d != %d may get lost\n", irq, pending_irq);
+		arm_gic_end_of_fiq(irq);
+
+		return ret;
+	}
+	return sm_handle_irq();
+#else
+	return __platform_irq(frame);
+#endif
+}
+
+void platform_fiq(struct iframe *frame)
+{
+#if WITH_LIB_SM
+	sm_handle_fiq();
+#else
+	PANIC_UNIMPLEMENTED;
+#endif
+}
+
+#if WITH_LIB_SM
+static status_t arm_gic_get_next_irq_locked(u_int min_irq, bool per_cpu)
+{
+	u_int irq;
+	u_int max_irq = per_cpu ? GIC_MAX_PER_CPU_INT : MAX_INT;
+	uint cpu = arch_curr_cpu_num();
+
+	if (!per_cpu && min_irq < GIC_MAX_PER_CPU_INT)
+		min_irq = GIC_MAX_PER_CPU_INT;
+
+	for (irq = min_irq; irq < max_irq; irq++)
+		if (get_int_handler(irq, cpu)->handler)
+			return irq;
+
+	return SM_ERR_END_OF_INPUT;
+}
+
+long smc_intc_get_next_irq(smc32_args_t *args)
+{
+	status_t ret;
+	spin_lock_saved_state_t state;
+
+	spin_lock_save(&gicd_lock, &state, GICD_LOCK_FLAGS);
+
+	arm_gic_non_secure_interrupts_frozen = true;
+	ret = arm_gic_get_next_irq_locked(args->params[0], args->params[1]);
+	LTRACEF("min_irq %d, per_cpu %d, ret %d\n",
+		args->params[0], args->params[1], ret);
+
+	spin_unlock_restore(&gicd_lock, state, GICD_LOCK_FLAGS);
+
+	return ret;
+}
+
+static u_long enabled_fiq_mask[BITMAP_NUM_WORDS(MAX_INT)];
+
+static void bitmap_update_locked(u_long *bitmap, u_int bit, bool set)
+{
+	u_long mask = 1UL << BITMAP_BIT_IN_WORD(bit);
+
+	bitmap += BITMAP_WORD(bit);
+	if (set)
+		*bitmap |= mask;
+	else
+		*bitmap &= ~mask;
+}
+
+long smc_intc_request_fiq(smc32_args_t *args)
+{
+	u_int fiq = args->params[0];
+	bool enable = args->params[1];
+	spin_lock_saved_state_t state;
+
+	dprintf(SPEW, "%s: fiq %d, enable %d\n", __func__, fiq, enable);
+	spin_lock_save(&gicd_lock, &state, GICD_LOCK_FLAGS);
+
+	arm_gic_set_secure_locked(fiq, true);
+	arm_gic_set_target_locked(fiq, ~0, ~0);
+	arm_gic_set_priority_locked(fiq, 0);
+
+	gic_set_enable(fiq, enable);
+	bitmap_update_locked(enabled_fiq_mask, fiq, enable);
+
+	dprintf(SPEW, "%s: fiq %d, enable %d done\n", __func__, fiq, enable);
+
+	spin_unlock_restore(&gicd_lock, state, GICD_LOCK_FLAGS);
+
+	return NO_ERROR;
+}
+
+static u_int current_fiq[8] = { 0x3ff, 0x3ff, 0x3ff, 0x3ff, 0x3ff, 0x3ff, 0x3ff, 0x3ff };
+
+static bool update_fiq_targets(u_int cpu, bool enable, u_int triggered_fiq, bool resume_gicd)
+{
+	u_int i, j;
+	u_long mask;
+	u_int fiq;
+	bool smp = arm_gic_max_cpu() > 0;
+	bool ret = false;
+
+	spin_lock(&gicd_lock); /* IRQs and FIQs are already masked */
+	for (i = 0; i < BITMAP_NUM_WORDS(MAX_INT); i++) {
+		mask = enabled_fiq_mask[i];
+		while (mask) {
+			j = _ffz(~mask);
+			mask &= ~(1UL << j);
+			fiq = i * BITMAP_BITS_PER_WORD + j;
+			if (fiq == triggered_fiq)
+				ret = true;
+			LTRACEF("cpu %d, irq %i, enable %d\n", cpu, fiq, enable);
+			if (smp)
+				arm_gic_set_target_locked(fiq, 1U << cpu, enable ? ~0 : 0);
+			if (!smp || resume_gicd)
+				gic_set_enable(fiq, enable);
+		}
+	}
+	spin_unlock(&gicd_lock);
+	return ret;
+}
+
+static void suspend_resume_fiq(bool resume_gicc, bool resume_gicd)
+{
+	u_int cpu = arch_curr_cpu_num();
+
+	ASSERT(cpu < 8);
+
+	update_fiq_targets(cpu, resume_gicc, ~0, resume_gicd);
+}
+
+status_t sm_intc_fiq_enter(void)
+{
+	u_int cpu = arch_curr_cpu_num();
+	u_int irq = arm_gic_acknowledge_fiq() & 0x3ff;
+	bool fiq_enabled;
+
+	ASSERT(cpu < 8);
+
+	LTRACEF("cpu %d, irq %i\n", cpu, irq);
+
+	if (irq >= 1020) {
+		LTRACEF("spurious fiq: cpu %d, old %d, new %d\n", cpu, current_fiq[cpu], irq);
+		return ERR_NO_MSG;
+	}
+
+	fiq_enabled = update_fiq_targets(cpu, false, irq, false);
+	arm_gic_end_of_fiq(irq);
+
+	if (current_fiq[cpu] != 0x3ff) {
+		dprintf(INFO, "more than one fiq active: cpu %d, old %d, new %d\n", cpu, current_fiq[cpu], irq);
+		return ERR_ALREADY_STARTED;
+	}
+
+	if (!fiq_enabled) {
+		dprintf(INFO, "got disabled fiq: cpu %d, new %d\n", cpu, irq);
+		return ERR_NOT_READY;
+	}
+
+	current_fiq[cpu] = irq;
+
+	return 0;
+}
+
+void sm_intc_fiq_exit(void)
+{
+	u_int cpu = arch_curr_cpu_num();
+
+	ASSERT(cpu < 8);
+
+	LTRACEF("cpu %d, irq %i\n", cpu, current_fiq[cpu]);
+	if (current_fiq[cpu] == 0x3ff) {
+		dprintf(INFO, "%s: no fiq active, cpu %d\n", __func__, cpu);
+		return;
+	}
+	update_fiq_targets(cpu, true, current_fiq[cpu], false);
+	current_fiq[cpu] = 0x3ff;
+}
+#endif
+
+/* vim: set ts=4 sw=4 noexpandtab: */
diff --git a/src/bsp/lk/platform/mt8518/drivers/i2c/mt_i2c.c b/src/bsp/lk/platform/mt8518/drivers/i2c/mt_i2c.c
new file mode 100644
index 0000000..2381918
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/i2c/mt_i2c.c
@@ -0,0 +1,1287 @@
+/*
+ * 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.
+*/
+
+/**
+ * @file mt_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/mt_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(110, 1);
+		///* I2C0_SCL */
+		//mtk_pmx_set_mode(111, 1);
+		gpio_reg = (readl(MTK_GPIO_I2C_BASE1) &
+			   (~(0x7 << MTK_GPIO_SDA0))) | (0x1 << MTK_GPIO_SDA0);
+		writel(gpio_reg, MTK_GPIO_I2C_BASE1);
+        	gpio_reg = (readl(MTK_GPIO_I2C_BASE1) &
+			   (~(0x7 << MTK_GPIO_SCL0))) | (0x1 << MTK_GPIO_SCL0);
+        	writel(gpio_reg, MTK_GPIO_I2C_BASE1);
+		break;
+	case 1:
+		///* I2C1_SDA */
+		//mtk_pmx_set_mode(108, 1);
+		///* I2C1_SCL */
+		//mtk_pmx_set_mode(109, 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_BASE0) &
+			   (~(0x7 << MTK_GPIO_SCL1))) | (0x1 << MTK_GPIO_SCL1);
+        	writel(gpio_reg, MTK_GPIO_I2C_BASE0);
+		break;
+	case 2:
+		///* I2C1_SDA */
+		//mtk_pmx_set_mode(112, 1);
+		///* I2C1_SCL */
+		//mtk_pmx_set_mode(113, 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:
+		///* I2C1_SDA */
+		//mtk_pmx_set_mode(21, 1);
+		///* I2C1_SCL */
+		//mtk_pmx_set_mode(22, 1);
+		gpio_reg = (readl(MTK_GPIO_I2C_BASE2) &
+			   (~(0x7 << MTK_GPIO_SDA3))) | (0x1 << MTK_GPIO_SDA3);
+		writel(gpio_reg, MTK_GPIO_I2C_BASE2);
+        	gpio_reg = (readl(MTK_GPIO_I2C_BASE2) &
+			   (~(0x7 << MTK_GPIO_SCL3))) | (0x1 << MTK_GPIO_SCL3);
+        	writel(gpio_reg, MTK_GPIO_I2C_BASE2);
+		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
+	writel(MTK_I2C_CLK_OFFSET, MTK_I2C_CLK_CLR);
+
+	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_CLR1);
+		break;
+	default:
+		I2CERR("i2c clk enable, invalid para: i2c->id=%d\n",i2c->id);
+	}
+
+	writel(MTK_APDMA_CLK_OFFSET, MTK_I2C_CLK_CLR0);
+#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
+	writel(MTK_I2C_CLK_OFFSET, MTK_I2C_CLK_SET);
+
+	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_SET1);
+		break;
+	default:
+		I2CERR("i2c clk disable, invalid para: i2c->id=%d\n",i2c->id);
+	}
+
+    writel(MTK_APDMA_CLK_OFFSET, MTK_I2C_CLK_SET0);
+#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/mt8518/drivers/key/mtk_key.c b/src/bsp/lk/platform/mt8518/drivers/key/mtk_key.c
new file mode 100644
index 0000000..2c3066b
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/key/mtk_key.c
@@ -0,0 +1,39 @@
+/*
+ * 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 <platform/mtk_key.h>
+
+bool check_download_key(void)
+{
+    if ((readl(SEJ_BASE)&0xF) == 0x3)
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
diff --git a/src/bsp/lk/platform/mt8518/drivers/led/mtk_led.c b/src/bsp/lk/platform/mt8518/drivers/led/mtk_led.c
new file mode 100644
index 0000000..42b7f14
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/led/mtk_led.c
@@ -0,0 +1,202 @@
+#include <stdio.h>

+#include <platform/mt_i2c.h>

+#include <platform/mtk_timer.h>

+

+u16 busnum = 1 ;

+u8 dev_addr[4] = {0x32,0x33,0x34,0x35};

+u8 wr_buf_2[2];

+u8 wr_buf_1 = 0;

+u32 wr_len_2 = 2;

+u32 wr_len_1 = 1;

+u32 speed = 400;

+u32 rd_len = 1;

+u8 rd_buf = 0;

+static unsigned int reg[3] = {0};

+

+#define LP5523_REG_ENABLE		    0x00

+#define LP5523_REG_OP_MODE		    0x01

+#define LP5523_REG_ENABLE_LEDS_MSB	0x04

+#define LP5523_REG_ENABLE_LEDS_LSB	0x05

+#define LP5523_REG_LED_PWM_BASE		0x16

+#define LP5523_REG_LED_CURRENT_BASE	0x26

+#define LP5523_REG_CONFIG		    0x36

+#define LP5523_ENABLE			    0x40

+#define LP5523_AUTO_INC			    0x40

+#define LP5523_PWR_SAVE			    0x20

+#define LP5523_PWM_PWR_SAVE		    0x04

+#define LP5523_CP_AUTO			    0x18

+#define LP5523_AUTO_CLK			    0x02

+#define LP5523_MAX_LEDS			    9

+#define DEVICE_NUM                  4

+#define led_cur                     0x20

+#define max_chan                    0x09

+

+/**********************************************/

+//MODE:     GPIO_BASE+0X3D0[14:12] //000 gpio mode

+//DIR:        GPIO_BASE+0X040[5]

+//DATAOUT:GPIO_BASE+0X140[5]

+/**********************************************/

+static void gpio117_set_enable(void)

+{

+  unsigned int tmp = (unsigned int)(*(volatile unsigned int *)(IO_PHYS + 0x0005470));

+  reg[0] = tmp;

+  tmp &= ~(0x1c0);

+  (*(volatile unsigned int *)(IO_PHYS + 0x0005470)) = (unsigned int)tmp;

+

+  tmp = (unsigned int)(*(volatile unsigned int *)( IO_PHYS + 0x0005070));

+  reg[1] = tmp;

+  tmp |= 0x20;

+  (*(volatile unsigned int *)( IO_PHYS + 0x0005070)) = (unsigned int)tmp;

+

+  tmp = (unsigned int)(*(volatile unsigned int *)( IO_PHYS + 0x0005170));

+  tmp &= ~(0x20);

+  (*(volatile unsigned int *)( IO_PHYS + 0x0005170)) = (unsigned int)tmp;

+  udelay(2000);

+

+  tmp = (unsigned int)(*(volatile unsigned int *)( IO_PHYS + 0x0005170));

+  reg[2] = tmp;

+  tmp |= 0x20;

+  (*(volatile unsigned int *)( IO_PHYS + 0x0005170)) = (unsigned int)tmp;

+  udelay(2000);

+}

+

+static void gpio117_set_disable(void)

+{

+  unsigned int tmp = (unsigned int)(*(volatile unsigned int *)(IO_PHYS + 0x0005470));

+  tmp |= reg[0];

+  (*(volatile unsigned int *)(IO_PHYS + 0x0005470)) = (unsigned int)tmp;

+

+  tmp = (unsigned int)(*(volatile unsigned int *)( IO_PHYS + 0x0005070));

+  tmp &= reg[1];

+  (*(volatile unsigned int *)( IO_PHYS + 0x0005070)) = (unsigned int)tmp;

+

+  tmp = (unsigned int)(*(volatile unsigned int *)( IO_PHYS + 0x0005170));

+  tmp &= reg[2];

+  (*(volatile unsigned int *)( IO_PHYS + 0x0005170)) = (unsigned int)tmp;

+}

+

+static int lp55xx_detect_device(int device_idx)

+{

+  int ret;

+  wr_buf_2[0] = LP5523_REG_ENABLE;

+  wr_buf_2[1] = LP5523_ENABLE;

+  ret = mtk_i2c_write(busnum,dev_addr[device_idx],speed,wr_buf_2,wr_len_2);

+  if (ret)

+    return ret;

+  udelay(2000);

+  wr_buf_1 = LP5523_REG_ENABLE;

+  ret = mtk_i2c_write_read(busnum,dev_addr[device_idx],speed,&wr_buf_1,&rd_buf,wr_len_1,rd_len);

+  if (ret)

+  	return ret;

+  if(rd_buf != LP5523_ENABLE)

+  {

+    return -1;

+  }

+  return 0;

+}

+

+static inline void lp5523_wait_opmode_done(void)

+{

+  udelay(2000);

+}

+

+static void lp5523_set_led_current(int device_idx)

+{

+  int i=0;

+  for(i=0;i<max_chan;i++)

+  {

+    wr_buf_2[0] = LP5523_REG_LED_CURRENT_BASE + i;

+	wr_buf_2[1] = led_cur;

+	mtk_i2c_write(busnum,dev_addr[device_idx],speed,wr_buf_2,wr_len_2);

+  }

+}

+

+static void lp5523_stop_all_engines(int device_idx)

+{

+  wr_buf_2[0] = LP5523_REG_OP_MODE;

+  wr_buf_2[1] = 0;

+  mtk_i2c_write(busnum,dev_addr[device_idx],speed,wr_buf_2,wr_len_2);

+  lp5523_wait_opmode_done();

+}

+

+static int lp55xx_init(int device_idx)

+{

+  int ret;

+  wr_buf_2[0] = LP5523_REG_ENABLE;

+  wr_buf_2[1] = LP5523_ENABLE;

+  ret = mtk_i2c_write(busnum,dev_addr[device_idx],speed,wr_buf_2,wr_len_2);

+  if (ret)

+    return ret;

+  udelay(2000);

+  wr_buf_2[0] = LP5523_REG_CONFIG;

+  wr_buf_2[1] = LP5523_AUTO_INC | LP5523_PWR_SAVE | LP5523_CP_AUTO | LP5523_AUTO_CLK | LP5523_PWM_PWR_SAVE;

+  ret = mtk_i2c_write(busnum,dev_addr[device_idx],speed,wr_buf_2,wr_len_2);

+  if (ret)

+  	return ret;

+  wr_buf_2[0] = LP5523_REG_ENABLE_LEDS_MSB;

+  wr_buf_2[1] = 0x01;

+  ret = mtk_i2c_write(busnum,dev_addr[device_idx],speed,wr_buf_2,wr_len_2);

+  if (ret)

+	return ret;

+  wr_buf_2[0] = LP5523_REG_ENABLE_LEDS_LSB;

+  wr_buf_2[1] = 0xff;

+  ret = mtk_i2c_write(busnum,dev_addr[device_idx],speed,wr_buf_2,wr_len_2);

+  if (ret)

+	return ret;

+  return 0;

+}

+

+static int lp5523_pwm_light(int device_idx)

+{

+  int i = 0;

+  int ret;

+  lp5523_stop_all_engines(device_idx);

+  wr_buf_2[0] = LP5523_REG_ENABLE_LEDS_MSB;

+  wr_buf_2[1] = 0x01;

+  ret = mtk_i2c_write(busnum,dev_addr[device_idx],speed,wr_buf_2,wr_len_2);

+  if (ret)

+  	return ret;

+  wr_buf_2[0] = LP5523_REG_ENABLE_LEDS_LSB;

+  wr_buf_2[1] = 0xFF;

+  ret = mtk_i2c_write(busnum,dev_addr[device_idx],speed,wr_buf_2,wr_len_2);

+  if (ret)

+  	return ret;

+  for (i = 0; i < LP5523_MAX_LEDS; i++)

+  {

+    wr_buf_2[0] = LP5523_REG_LED_PWM_BASE + i;

+    wr_buf_2[1] = 0xff;

+	ret = mtk_i2c_write(busnum,dev_addr[device_idx],speed,wr_buf_2,wr_len_2);

+	if (ret)

+		return ret;

+	udelay(1000);

+  }

+  return ret;

+}

+

+int led_init(void)

+{

+  int ret;

+  int i=0;

+

+  gpio117_set_enable();

+  for(i=0;i<DEVICE_NUM;i++)

+  {

+	ret = lp55xx_detect_device(i);

+	if(ret)

+	{

+      return -1;

+	}

+    ret = lp55xx_init(i);

+	if(ret)

+	{

+      return -2;

+	}

+	lp5523_set_led_current(i);

+  }

+  for(i=0;i<DEVICE_NUM;i++)

+  {

+    lp5523_pwm_light(i);

+  }

+  gpio117_set_disable();

+  return ret;

+}

diff --git a/src/bsp/lk/platform/mt8518/drivers/mmc/mmc_core.c b/src/bsp/lk/platform/mt8518/drivers/mmc/mmc_core.c
new file mode 100644
index 0000000..b8bf10b
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/mmc/mmc_core.c
@@ -0,0 +1,1869 @@
+/*
+ * 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_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>
+#include <lib/mempool.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);
+        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)
+{
+    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 {
+        MSDC_DMA_ON;
+        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 = { 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_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_response(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 = { 0,};
+    u8 final_delay, final_maxlen;
+    int cmd_err;
+    int i, j;
+
+    MSDC_CLR_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+    for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+        MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY, i);
+        for (j = 0; j < 3; j++) {
+            mmc_hs200_tune_cmd(mmc, &cmd_err);
+            if (!cmd_err) {
+                rise_delay |= (1 << i);
+            } else {
+                rise_delay &= ~(1 << i);
+                break;
+            }
+        }
+    }
+    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);
+    for (i = 0; i < PAD_DELAY_MAX; i++) {
+        MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY, i);
+        for (j = 0; j < 3; j++) {
+            mmc_hs200_tune_cmd(mmc, &cmd_err);
+            if (!cmd_err) {
+                fall_delay |= (1 << i);
+            } else {
+                fall_delay &= ~(1 << i);
+                break;
+            }
+        }
+    }
+    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_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+                       final_rise_delay.final_phase);
+        final_delay = final_rise_delay.final_phase;
+    } else {
+        MSDC_SET_BIT32(MSDC_IOCON, MSDC_IOCON_RSPL);
+        MSDC_SET_FIELD(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+                       final_fall_delay.final_phase);
+        final_delay = final_fall_delay.final_phase;
+    }
+
+    dprintf(ALWAYS, "Final cmd 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;
+    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);
+
+    return ret;
+}
+
+static int mmc_hs200_tuning(struct mmc_card *card)
+{
+    struct mmc_host *host = card->host;
+    addr_t base = host->base;
+    int ret;
+
+    ret = msdc_tune_response(host);
+    if (ret == -EIO) {
+        dprintf(CRITICAL, "hs200 tuning cmd error!\n");
+        return ret;
+    }
+
+    if (host->caps & MMC_CAP_EMMC_HS400 && card->ext_csd.hs400_support) {
+        MSDC_WRITE32(EMMC50_PAD_DS_TUNE, 0x14029);
+        return MMC_ERR_NONE;
+    }
+
+    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;
+    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 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) {
+        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;
+}
+
+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:
+    if (host)
+        free(host);
+    if (card)
+        free(card);
+    return err;
+}
diff --git a/src/bsp/lk/platform/mt8518/drivers/mmc/msdc.c b/src/bsp/lk/platform/mt8518/drivers/mmc/msdc.c
new file mode 100644
index 0000000..806df68
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/mmc/msdc.c
@@ -0,0 +1,1928 @@
+/*
+ * 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 */
+
+/* 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
+    },
+
+    {
+        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
+                            };
+/* 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, 0x7FF);
+	else
+		MSDC_SET_FIELD(MSDC0_SMT_ADDR, MSDC0_SMT_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_PUPD0_ADDR, MSDC0_DAT0_3_PUPD_MASK, 0x1111);
+    MSDC_SET_FIELD(MSDC0_PUPD1_ADDR, MSDC0_DAT4_7_PUPD_MASK, 0x1111);
+    MSDC_SET_FIELD(MSDC0_PUPD2_ADDR, MSDC0_CMD_PUPD_MASK, 1);
+    MSDC_SET_FIELD(MSDC0_PUPD2_ADDR, MSDC0_CLK_PUPD_MASK, 6);
+    MSDC_SET_FIELD(MSDC0_PUPD2_ADDR, MSDC0_RST_PUPD_MASK, 1);
+    MSDC_SET_FIELD(MSDC0_PUPD6_ADDR, MSDC0_DSL_PUPD_MASK, 6);
+}
+
+/* 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_DRV6_ADDR, MSDC0_CLK_DRV_MASK, msdc_cap->clk_drv);
+        MSDC_SET_FIELD(MSDC0_DRV6_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_MODE1_ADDR, MSDC0_DAT6_MODE_MASK, 1);
+	MSDC_SET_FIELD(MSDC0_GPIO_MODE1_ADDR, MSDC0_DAT7_MODE_MASK, 1);
+	MSDC_SET_FIELD(MSDC0_GPIO_MODE1_ADDR, MSDC0_DS_MODE_MASK, 2);
+	MSDC_SET_FIELD(MSDC0_GPIO_MODE2_ADDR, MSDC0_CLK_CMD_DAT4_5_MASK, 0x1249);
+	MSDC_SET_FIELD(MSDC0_GPIO_MODE3_ADDR, MSDC0_DAT0_3_MODE_MASK, 0x249);
+}
+
+static void msdc_set_tdsel(struct mmc_host *host)
+{
+	ASSERT(host);
+	MSDC_SET_FIELD(MSDC0_TDSEL6_ADDR, MSDC0_CLK_TDSEL_MASK, 0xa);
+	MSDC_SET_FIELD(MSDC0_TDSEL6_ADDR, MSDC0_CMD_TDSEL_MASK, 0xa);
+	MSDC_SET_FIELD(MSDC0_TDSEL7_ADDR, MSDC0_DAT_TDSEL_MASK, 0xa);
+	MSDC_SET_FIELD(MSDC0_TDSEL7_ADDR, MSDC0_RST_TDSEL_MASK, 0xa);
+}
+
+static void msdc_set_rdsel(struct mmc_host *host)
+{
+	ASSERT(host);
+	MSDC_SET_FIELD(MSDC0_RDSELE_ADDR, MSDC0_CLK_RDSEL_MASK, 0);
+	MSDC_SET_FIELD(MSDC0_RDSELE_ADDR, MSDC0_CMD_RDSEL_MASK, 0);
+	MSDC_SET_FIELD(MSDC0_RDSELF_ADDR, MSDC0_DAT_RDSEL_MASK, 0);
+	MSDC_SET_FIELD(MSDC0_RDSELF_ADDR, MSDC0_RST_RDSEL_MASK, 0);
+}
+
+
+static void msdc_gpio_and_pad_init(struct mmc_host *host)
+{
+	/*set smt enable*/
+	msdc_set_smt(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]);
+
+	/*set tdsel and rdsel*/
+	msdc_set_tdsel(host);
+	msdc_set_rdsel(host);
+}
+#endif
+
+#ifndef FPGA_PLATFORM
+
+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:%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)
+{
+    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;
+
+    /* 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_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;
+    addr_t base = host->base;
+
+    /* Save & Clear the interrupt */
+    g_int_status = MSDC_READ32(MSDC_INT);
+    MSDC_WRITE32(MSDC_INT, g_int_status);
+    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_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;
+
+    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) {
+        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) {
+            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) {
+        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
+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_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;
+    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_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)
+{
+    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_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_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);
+}
+
+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
+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;
+}
+#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;
+
+    dprintf(INFO, "[%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;
+    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();
+
+    /* 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);
+
+#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_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(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;
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/mmc/rules.mk b/src/bsp/lk/platform/mt8518/drivers/mmc/rules.mk
new file mode 100644
index 0000000..bb46477
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/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/mt8518/drivers/nand/mtk_ecc_hal.c b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_ecc_hal.c
new file mode 100644
index 0000000..66fa13f
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_ecc_hal.c
@@ -0,0 +1,632 @@
+/*
+ * 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 "mtk_ecc_hal.h"
+#include "mtk_nand_sys.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        (0x1f)
+#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_BYPASS      (0x20c)
+#define     ECC_BYPASS_EN       NAND_BIT(0)
+#ifdef MT8518_NFI
+#define ECC_ENCPAR(x)      (0x300 + (x) * sizeof(u32))
+#define ECC_DECEL(x)        (0x500 + (x) * sizeof(u32))
+#else
+#define ECC_ENCPAR(x)       (0x10 + (x) * sizeof(u32))
+#define ECC_ENCPAR_EXT(x)   (0x300 + (x) * sizeof(u32))
+
+#define ECC_DECEL(x)        (0x128 + (x) * sizeof(u32))
+#define ECC_DECEL_EXT(x)    (0x400 + (x) * sizeof(u32))
+#endif
+
+#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)
+
+
+struct mtk_ecc {
+	nand_lock_t lock;
+	nand_completion_t done;
+
+	u64 regs;
+	u32 sectors;
+	u8 *buffer; /* for buffer not aligned issue */
+};
+
+static inline void mtk_ecc_wait_ioready(struct mtk_ecc *ecc)
+{
+	if (!check_with_timeout((nand_readl(ecc->regs +  ECC_PIO_DIRDY) & PIO_DI_RDY), ECC_TIMEOUT))
+		nand_err("ecc io not ready");
+}
+
+static void mtk_ecc_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:
+			nand_err("invalid strength %d, default to 4 bits",
+			         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);
+		nand_writel(reg, ecc->regs + ECC_ENCCNFG);
+
+		if (config->mode == ECC_DMA_MODE) {
+			if (config->addr & 0x3)
+				nand_err("ecc encode address is not 4B aligned !!", config->addr);
+			nand_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;
+		nand_writel(reg, ecc->regs + ECC_DECCNFG);
+
+		if (config->mode == ECC_DMA_MODE) {
+			if (config->addr & 0x3)
+				nand_err("ecc decode address is not 4B aligned !!", config->addr);
+			nand_writel(config->addr, ecc->regs + ECC_DECDIADDR);
+		}
+
+		if (config->sectors)
+			ecc->sectors = 1 << (config->sectors - 1);
+	}
+}
+
+static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
+                                     enum mtk_ecc_operation op)
+{
+	if (!check_with_timeout(nand_readl(ecc->regs + ECC_IDLE_REG(op)) & ECC_IDLE_MASK,
+	                        ECC_TIMEOUT))
+		nand_err("%s NOT idle", op == ECC_ENCODE ? "encoder" : "decoder");
+}
+
+#ifdef MTK_NAND_IRQ_EN
+static int mtk_ecc_irq_wait(struct mtk_ecc *ecc, u32 timeout)
+{
+	int ret;
+
+	ret = nand_wait_for_completion_timeout(&ecc->done, timeout);
+	if (ret != 0) {
+		nand_err("failed to get completion timeout");
+		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 = nand_readw(ecc->regs + ECC_DECIRQ_STA) & ECC_IRQ_EN;
+	if (dec) {
+		op = ECC_DECODE;
+		dec = nand_readw(ecc->regs + ECC_DECDONE);
+		if (dec & ecc->sectors) {
+			ecc->sectors = 0;
+			nand_complete(&ecc->done);
+		} else {
+			return NAND_IRQ_NONE;
+		}
+	} else {
+		enc = nand_readl(ecc->regs + ECC_ENCIRQ_STA) & ECC_IRQ_EN;
+		if (enc) {
+			op = ECC_ENCODE;
+			nand_complete(&ecc->done);
+		} else {
+			return NAND_IRQ_NONE;
+		}
+	}
+
+	nand_writel(0, ecc->regs + ECC_IRQ_REG(op));
+
+	return NAND_IRQ_HANDLED;
+}
+
+static int mtk_ecc_request_irq(struct mtk_ecc *ecc)
+{
+	nand_init_completion(&ecc->done);
+	mtk_nand_request_irq(NAND_NFIECC_IRQ_BIT_ID, &mtk_ecc_interrupt_handler, ecc);
+
+	return 0;
+}
+#endif
+
+int mtk_ecc_hw_init(struct mtk_ecc **ext_ecc)
+{
+	struct mtk_ecc *ecc;
+	u32 reg;
+	int ret = 0;
+
+	ecc = (struct mtk_ecc *)nand_malloc(sizeof(*ecc));
+	if (!ecc)
+		return -ENOMEM;
+
+	nand_memset(ecc, 0, sizeof(*ecc));
+#if 1
+	ecc->buffer = (u8 *)nand_memalign(4, ECC_MAX_CODESIZE);
+	if (!ecc->buffer) {
+		ret = -ENOMEM;
+		nand_err("failed to malloc ecc temp buffer %d", ECC_MAX_CODESIZE);
+		goto free_ecc;
+	}
+#endif
+	*ext_ecc = ecc;
+
+	ecc->regs = NAND_NFIECC_BASE;
+
+	mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+	nand_writew(ECC_OP_DISABLE, ecc->regs + ECC_ENCCON);
+
+	mtk_ecc_wait_idle(ecc, ECC_DECODE);
+	nand_writel(ECC_OP_DISABLE, ecc->regs + ECC_DECCON);
+
+	nand_lock_init(&ecc->lock);
+
+#ifdef MTK_NAND_IRQ_EN
+	/* register interrupt handler */
+	mtk_ecc_request_irq(ecc);
+#endif
+	/* disable ecc bypass */
+	reg = nand_readl(ecc->regs + ECC_BYPASS);
+	reg &= ~ECC_BYPASS_EN;
+	nand_writel(reg, ecc->regs + ECC_BYPASS);
+
+	return 0;
+
+free_ecc:
+	nand_free(ecc);
+	return ret;
+}
+
+
+int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config, int polling)
+{
+	enum mtk_ecc_operation op = config->op;
+
+	nand_lock(&ecc->lock);
+
+	mtk_ecc_wait_idle(ecc, op);
+	mtk_ecc_config(ecc, config);
+	nand_writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
+
+	if (!polling) {
+		nand_writew(ECC_IRQ_EN, ecc->regs + ECC_IRQ_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 (nand_readw(ecc->regs + ECC_CTL_REG(op)) != ECC_OP_ENABLE)
+		op = ECC_DECODE;
+
+	/* disable it */
+	mtk_ecc_wait_idle(ecc, op);
+	nand_writew(0, ecc->regs + ECC_IRQ_REG(op));
+	nand_writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op));
+
+	nand_unlock(&ecc->lock);
+}
+
+void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
+                       int sectors)
+{
+	u32 offset, i, err;
+	u32 bitflips = 0;
+
+	stats->corrected = 0;
+	stats->failed = 0;
+
+	for (i = 0; i < sectors; i++) {
+		offset = (i >> 2);
+		err = nand_readl(ecc->regs + ECC_DECENUM(offset));
+		err = err >> ((i % 4) * 8);
+		err &= ERR_MASK;
+		if (err == ERR_MASK) {
+			/* uncorrectable errors */
+			stats->failed++;
+			nand_err("sector %d is uncorrect", i);
+			continue;
+		}
+
+		stats->corrected += err;
+		bitflips = max(bitflips, err);
+	}
+
+	stats->bitflips = bitflips;
+}
+
+int mtk_ecc_wait_done(struct mtk_ecc *ecc, enum mtk_ecc_operation op, int polling)
+{
+	int ret = 0;
+
+	if (!polling) {
+#ifdef MTK_NAND_IRQ_EN
+		ret = mtk_ecc_irq_wait(ecc, ECC_TIMEOUT);
+		if (!ret)
+			nand_err("mtk_ecc_wait_done timeout");
+#endif
+		return -ETIMEDOUT;
+	} else {
+		if (op == ECC_ENCODE) {
+			if (!check_with_timeout((nand_readl(ecc->regs + ECC_ENCSTA) & ENC_IDLE), ECC_TIMEOUT)) {
+				nand_err("encoder timeout");
+				return -ETIMEDOUT;
+			}
+		} else {
+			if (!check_with_timeout((nand_readw(ecc->regs + ECC_DECDONE) & ecc->sectors), ECC_TIMEOUT)) {
+				nand_err("decoder timeout");
+				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(((nand_readl(ecc->regs + ECC_DECFSM) & FSM_MASK) == FSM_IDLE), ECC_TIMEOUT)) {
+		nand_err("decode fsm(0x%x) is not idle", nand_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)
+{
+	u32 addr = (u32)data;
+	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) && (addr & 0x3)) {
+		/* buf =(u8 *)NAND_DRAM_BUF_ECCDE_ADDR; */
+		buf = ecc->buffer;
+		nand_memcpy(buf, data, bytes);
+	}
+
+	addr = nand_kvaddr_to_paddr(buf);
+
+	if (config->mode == ECC_DMA_MODE)
+		nand_dma_map(buf, bytes, true, NULL);
+
+	config->op = ECC_ENCODE;
+	config->addr = 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);
+			nand_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) {
+#ifdef MT8518_NFI
+			val = nand_readl(ecc->regs + ECC_ENCPAR(i / 4));
+#else
+			if (i < 108)
+				val = nand_readl(ecc->regs + ECC_ENCPAR(i / 4));
+			else
+				val = nand_readl(ecc->regs + ECC_ENCPAR_EXT((i / 4) - 27));
+#endif
+		}
+		p[i] = (val >> ((i % 4) * 8)) & 0xff;
+	}
+timeout:
+	mtk_ecc_disable(ecc);
+freebuf:
+	if (config->mode == ECC_DMA_MODE) {
+		nand_dma_unmap(buf, bytes, false, NULL);
+	}
+
+	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;
+	u32 addr = (u32)data, decodesize, i;
+	int ret;
+
+	decodesize = len + ((config->strength * ECC_PARITY_BITS + 7) >> 3);
+	if ((decodesize & 0x3)
+	        || ((config->mode == ECC_DMA_MODE) && (addr & 0x3))) {
+		decodesize += 4 - (decodesize & 0x3);
+		/* buf = (u8 *)NAND_DRAM_BUF_ECCEN_ADDR; */
+		buf = ecc->buffer;
+	}
+	if (config->mode == ECC_DMA_MODE)
+		nand_dma_map(buf, decodesize, false, NULL);
+
+	addr = nand_kvaddr_to_paddr(buf);
+
+	config->op = ECC_DECODE;
+	config->addr = 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);
+			*((u32 *)buf + i) = nand_readl(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)
+		nand_dma_unmap(buf, decodesize, false, NULL);
+
+	if (buf != data)
+		nand_memcpy(data, buf, len);
+
+disecc:
+	mtk_ecc_disable(ecc);
+
+freebuf:
+
+	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 = nand_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++) {
+#ifdef MT8518_NFI
+		loc = nand_readl(ecc->regs + ECC_DECEL(i >> 1));
+#else
+		if (i < 60)
+			loc = nand_readl(ecc->regs + ECC_DECEL(i >> 1));
+		else
+			loc = nand_readl(ecc->regs + ECC_DECEL_EXT((i >> 1) - 30));
+#endif
+		loc >>= ((i & 0x1) << 4);
+		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
+	            };
+	int 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];
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_ecc_hal.h b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_ecc_hal.h
new file mode 100644
index 0000000..400ebed
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_ecc_hal.h
@@ -0,0 +1,66 @@
+/*
+ * 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 _MTK_ECC_HAL_H_
+#define _MTK_ECC_HAL_H_
+
+#include "mtk_nand_sys.h"
+
+#define ECC_PARITY_BITS     (14)
+/* for SLC */
+#define ECC_MAX_CODESIZE    (1024+128)
+
+struct mtk_ecc;
+
+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;
+	u8 empty;
+};
+
+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;
+};
+
+extern int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+                          u8 *data, u32 bytes, int polling);
+extern int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config, int polling);
+extern void mtk_ecc_disable(struct mtk_ecc *ecc);
+extern void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats, int sectors);
+extern int mtk_ecc_cpu_correct(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats, u8 *data, u32 sector, int polling);
+extern int mtk_ecc_wait_done(struct mtk_ecc *ecc, enum mtk_ecc_operation op, int polling);
+extern int mtk_ecc_hw_init(struct mtk_ecc **ext_ecc);
+extern int mtk_ecc_wait_decode_fsm_idle(struct mtk_ecc *ecc);
+extern int mtk_ecc_decode(struct mtk_ecc *ecc, struct mtk_ecc_config *config, u8 *data, u32 len, int polling);
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_api.c b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_api.c
new file mode 100644
index 0000000..90ed78a
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_api.c
@@ -0,0 +1,658 @@
+/*
+ * 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 <lib/mempool.h>
+#include "mtk_nand_nal.h"
+#include "mtk_nand_bbt.h"
+#include "mtk_nand_sys.h"
+#include "mtk_nand_test.h"
+#include <lib/partition.h>
+
+extern struct mtk_nand_chip *g_nand_chip;
+
+#if MTK_NAND_ERASE_ALL
+int nand_erase_all(void)
+{
+	struct mtk_nand_ops ops;
+	u32 i, blocks = g_nand_chip->chipsize / g_nand_chip->blocksize;
+
+	nand_memset(&ops, 0, sizeof(ops));
+	ops.mode = NAND_OPS_ERASE_POLL;
+	ops.len = g_nand_chip->blocksize;
+	ops.offset = 0;
+
+	for (i = 0; i < blocks; i++) {
+		mtk_nand_erase_block(g_nand_chip, &ops, 1);
+		ops.offset += g_nand_chip->blocksize;
+	}
+
+	return 0;
+}
+#else
+int nand_erase_all(void)
+{
+	return -EINVAL;
+}
+#endif
+
+#if MTK_NAND_CREATE_BBT_TEST
+/**
+ * nand_create_bbt - Create bbt with simulated bad block required
+ * @arg: arg from fastboot command
+ *
+ * arg format:
+ * <mode> <block> <block> ...
+ * mode: Optional. "mark" - simulate bad block, "unmark" - unmark simulated
+ *       bad block.
+ * block: Optional. Block number in BBT space.
+ *
+ * Return 0 if create bbt done or negative if occurs error.
+ */
+int nand_create_bbt(const char *arg)
+{
+	struct mtk_nand_ops ops;
+	u32 len = strlen(arg) + 1, page;
+	char *buf, *temp;
+	int ret = 0, mode = 0;
+
+	if (g_nand_chip->scan_bbt == NULL) {
+		nand_err("not support bbt!");
+		return -EINVAL;
+	}
+
+	buf = nand_malloc(len);
+	if (!buf) {
+		nand_err("no enough memory!");
+		return -ENOMEM;
+	}
+	memset(buf, 0, len);
+	strncpy(buf, arg, len);
+
+	temp = strtok(buf, " ");
+	if (!strcmp(temp, "mark")) {
+		/* Simulate bad block in BBT space */
+		mode = 1;
+	} else if (!strcmp(temp, "unmark")) {
+		/* Remove simulated bad block in BBT space */
+		mode = 2;
+	}
+
+	temp = strtok(NULL, " ");
+	nand_memset(&ops, 0, sizeof(ops));
+	ops.mode = NAND_OPS_ERASE_POLL;
+	ops.len = g_nand_chip->blocksize;
+	while (mode && temp) {
+		page = atoi(temp);
+		if (page >= NAND_BBT_SCAN_MAXBLOCKS) {
+			nand_err("block %d is not in BBT space (0 ~ %d)",
+				page, NAND_BBT_SCAN_MAXBLOCKS - 1);
+			ret = -EINVAL;
+			goto free_buf;
+		}
+		page += (g_nand_chip->totalsize / g_nand_chip->blocksize);
+		page -= NAND_BBT_SCAN_MAXBLOCKS;
+		nand_info("%s block %d", mode == 1 ? "mark" : "unmark", page);
+		page *= g_nand_chip->page_per_block;
+		ops.offset = (u64)page * g_nand_chip->pagesize;
+		mtk_nand_force_erase(g_nand_chip, &ops);
+		if (mode == 1)
+			g_nand_chip->block_markbad(g_nand_chip, page);
+		temp = strtok(NULL, " ");
+	}
+
+	/* Create BBT */
+	nand_free(g_nand_chip->bbt);
+	g_nand_chip->bbt = NULL;
+	ret = g_nand_chip->scan_bbt(g_nand_chip);
+
+free_buf:
+	nand_free(buf);
+
+	return ret;
+}
+#else
+int nand_create_bbt(const char *arg)
+{
+	return -EINVAL;
+}
+#endif
+
+#if MTK_NAND_READ_BBT_TEST
+int nand_is_bbt_valid(void)
+{
+	return g_nand_chip->bbt ? 1 : 0;
+}
+
+int nand_is_bad_block(u32 block)
+{
+	u32 page, total;
+
+	total = g_nand_chip->totalsize / g_nand_chip->pagesize;
+	page = block * g_nand_chip->page_per_block;
+	if (page >= total)
+		return -1;
+
+	return mtk_nand_block_isbad_allowbbt(g_nand_chip, page) ? 1 : 0;
+}
+#else
+int nand_is_bbt_valid(void)
+{
+	return 0;
+}
+int nand_is_bad_block(u32 block)
+{
+	return -1;
+}
+#endif
+
+#if MTK_NAND_WORN_BAD_TEST
+u32 *erase_test_block;
+u32 erase_test_block_cnt;
+u32 *program_test_page;
+u32 program_test_page_cnt;
+
+static int nand_set_test_pattern(const char *arg, char *buf, char *test_case)
+{
+	char *temp;
+	int index;
+	u32 start_chunk, total_chunk, chunk_size;
+	u32 **pattern, *pattern_cnt;
+	u32 i;
+
+	if (!strcmp(test_case, "erase")) {
+		pattern = &erase_test_block;
+		pattern_cnt = &erase_test_block_cnt;
+		chunk_size = g_nand_chip->blocksize;
+	} else if (!strcmp(test_case, "program")) {
+		pattern = &program_test_page;
+		pattern_cnt = &program_test_page_cnt;
+		chunk_size = g_nand_chip->pagesize;
+	} else {
+		nand_err("invalid case %s", test_case);
+		return -EINVAL;
+	}
+
+	/* Fetch partition name */
+	temp = strtok(NULL, " ");
+	if (!temp) {
+		nand_err("no partition specified!");
+		return -EINVAL;
+	}
+
+	if (!strcmp(temp, "bbt")) {
+		i = NAND_BBT_SCAN_MAXBLOCKS * g_nand_chip->blocksize;
+		start_chunk = (g_nand_chip->totalsize - i) / chunk_size;
+		total_chunk = i / chunk_size;
+	} else {
+		start_chunk = partition_get_offset(temp) / chunk_size;
+		total_chunk = partition_get_size(temp) / chunk_size;
+	}
+
+	/* Fetch test pattern count */
+	temp = strtok(NULL, " ");
+	while (temp) {
+		*pattern_cnt += 1;
+		temp = strtok(NULL, " ");
+	}
+
+	if (*pattern_cnt == 0) {
+		nand_err("no test pattern specified!");
+		return -EINVAL;
+	} else {
+		*pattern = nand_malloc(*pattern_cnt * sizeof(u32));
+		if (!*pattern) {
+			nand_err("no enough memory!");
+			return -ENOMEM;
+		}
+	}
+
+	/* buf has been modified by strtok, so copy arg again */
+	strncpy(buf, arg, strlen(arg));
+	/* Skip mode */
+	temp = strtok(buf, " ");
+	/* Skip test_case */
+	temp = strtok(NULL, " ");
+	/* Skip partition */
+	temp = strtok(NULL, " ");
+
+	/* Fetch test pattern */
+	temp = strtok(NULL, " ");
+	i = 0;
+	while (temp) {
+		**pattern = atoi(temp);
+		if (**pattern >= total_chunk) {
+			nand_err("test pattern %u out of range!", **pattern);
+			*pattern -= i;
+			nand_free(*pattern);
+			return -EINVAL;
+		} else {
+			/* Transfer pattern to NAND physical address */
+			**pattern += start_chunk;
+		}
+		*pattern += 1;
+		i++;
+		temp = strtok(NULL, " ");
+	}
+
+	*pattern -= *pattern_cnt;
+	for (i = 0; i < *pattern_cnt; i++) {
+		nand_info("[%u] %u", i, **pattern);
+		*pattern += 1;
+	}
+	*pattern -= *pattern_cnt;
+
+	return 0;
+}
+
+static int nand_clear_test_pattern(char *test_case)
+{
+	if (!test_case)
+		return -EINVAL;
+
+	if (!strcmp(test_case, "erase")) {
+		if (erase_test_block)
+			nand_free(erase_test_block);
+		erase_test_block = NULL;
+		erase_test_block_cnt = 0;
+	} else if (!strcmp(test_case, "program")) {
+		if (program_test_page)
+			nand_free(program_test_page);
+		program_test_page = NULL;
+		program_test_page_cnt = 0;
+	} else {
+		nand_err("invalid case %s\n", test_case);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * nand_receive_worn_test_pattern - receive pattern from fastboot command
+ * @arg: arg from fastboot command
+ *
+ * arg format:
+ * mode + test_case + partition + number0 + number1 + ...
+ * mode: "set" - setup test pattern, "clear" - clear test pattern
+ * test_case: "erase" - test pattern for erase, "program" - test pattern for
+ *            program
+ * number{x}: block number for erase test or page number for program test
+ *
+ * Return 0 if arg parameters are valid or error code if not valid.
+ */
+int nand_receive_worn_test_pattern(const char *arg)
+{
+	u32 len = strlen(arg) + 1;
+	char *buf, *mode, *test_case;
+	int ret = 0;
+
+	buf = nand_malloc(len);
+	if (!buf) {
+		nand_err("no enough memory!");
+		return -ENOMEM;
+	}
+	memset(buf, 0, len);
+	strncpy(buf, arg, strlen(arg));
+
+	/* Fetch mode */
+	mode = strtok(buf, " ");
+	if (!mode) {
+		nand_err("no mode specified!");
+		ret = -EINVAL;
+		goto freebuf;
+	}
+
+	test_case = strtok(NULL, " ");
+
+	if (!strcmp(mode, "set")) {
+		ret = nand_set_test_pattern(arg, buf, test_case);
+	} else if (!strcmp(mode, "clear")) {
+		ret = nand_clear_test_pattern(test_case);
+	} else {
+		nand_err("invalid mode %s", mode);
+		ret = -EINVAL;
+	}
+
+freebuf:
+	nand_free(buf);
+
+	return ret;
+}
+
+int nand_check_erase_test_block(u32 block)
+{
+	u32 i;
+
+	if (!erase_test_block || !erase_test_block_cnt)
+		return 0;
+
+	for (i = 0; i < erase_test_block_cnt; i++) {
+		if (erase_test_block[i] == block)
+			return 1;
+	}
+
+	return 0;
+}
+
+int nand_check_program_test_page(u32 page)
+{
+	u32 i;
+
+	if (!program_test_page || !program_test_page_cnt)
+		return 0;
+
+	for (i = 0; i < program_test_page_cnt; i++) {
+		if (program_test_page[i] == page)
+			return 1;
+	}
+
+	return 0;
+}
+#else
+int nand_receive_worn_test_pattern(const char *arg)
+{
+	return -EINVAL;
+}
+int nand_check_erase_test_block(u32 block)
+{
+	return -EINVAL;
+}
+
+int nand_check_program_test_page(u32 page)
+{
+	return -EINVAL;
+}
+
+#endif
+
+#if MTK_NAND_BIT_ERROR_TEST
+static int get_bit_one(u32 *bit_one, u8 *data, int len)
+{
+	int i = 0, j = 0;
+	int count = 0;
+
+	do {
+		if (data[i] & (1 << j)) {
+			bit_one[count++] = i * 8 + j;
+		}
+		j++;
+		if (j == 8) {
+			j = 0;
+			i++;
+		}
+	} while (i < len);
+
+	return count;
+}
+
+int nand_inject_biterrs(u32 block, u32 page, u32 sector, u32 err_bits, bool force)
+{
+	struct mtk_nand_chip *chip = g_nand_chip;
+	struct mtk_nand_ops ops;
+	u8 *wr_buf = NULL;
+	u8 *rd_buf = NULL;
+	u8 *sector_buf = NULL;
+	u32 *bit_one = NULL;
+	u32 bit_one_count, err;
+	int ret;
+
+	nand_info("pagesize:%d, oobsize:%d, ecc_size:%d, ecc_steps:%d, ecc_strength:%d",
+		chip->pagesize, chip->oobsize, chip->ecc_size, chip->ecc_steps, chip->ecc_strength);
+
+	if (block >= chip->totalsize / chip->blocksize) {
+		nand_err("block should be from 0~%lld!!!",
+			chip->totalsize / chip->blocksize - 1);
+		return -EINVAL;
+	}
+
+	if (sector >= chip->ecc_steps) {
+		nand_err("sector should be from 0~%d!!!", chip->ecc_steps - 1);
+		return -EINVAL;
+	}
+
+	if (page >= chip->page_per_block) {
+		nand_err("sector should be from 0~%d!!!", chip->page_per_block - 1);
+		return -EINVAL;
+	}
+
+	if (err_bits == 0) {
+		nand_err("The input error bit number is 0");
+		return -EINVAL;
+	}
+
+	wr_buf = mempool_alloc(chip->pagesize + chip->oobsize, MEMPOOL_ANY);
+	if (wr_buf == NULL) {
+		nand_err("malloc fail!!!");
+		return -ENOMEM;
+	}
+	nand_memset(wr_buf, 0, chip->pagesize + chip->oobsize);
+	nand_memset(&ops, 0, sizeof(ops));
+	ops.offset = block * chip->blocksize + page * chip->pagesize;
+	ops.datbuf = wr_buf;
+	ops.len = chip->pagesize;
+	ops.oobeccbuf = NULL;
+	ops.oobecclen = 0;
+	ops.oobfreebuf = NULL;
+	ops.oobfreelen = 0;
+
+	ops.mode = NAND_OPS_RAW_DMA_POLL;
+	nand_info("Step1: Read page --no-ecc");
+	ret = mtk_nand_read(chip, &ops);
+	if (ret < 0) {
+		nand_err("read fail!!! ret:%d\n", ret);
+		goto __exit;
+	}
+
+	nand_info("Step2: Verify step1 data by writting and reading"
+			" with ecc on");
+	ret = mtk_nand_write(chip, &ops);
+	if (ret < 0) {
+		nand_err("write fail!!! ret:%d\n", ret);
+		goto __exit;
+	}
+
+	rd_buf = mempool_alloc(chip->pagesize + chip->oobsize, MEMPOOL_ANY);
+	if (rd_buf == NULL) {
+		nand_err("malloc fail!!!");
+		ret = -ENOMEM;
+		goto __exit;
+	}
+
+	nand_memset(rd_buf, 0, chip->pagesize + chip->oobsize);
+	ops.datbuf = rd_buf;
+	ops.mode = NAND_OPS_ECC_DMA_POLL;
+	ret = mtk_nand_read(chip, &ops);
+	if (ret < 0) {
+		nand_err("read fail!!!");
+		goto __exit;
+	}
+
+	if (ret > 0 && (!force)) {
+		nand_err("nandbiterrs command exit due to pre-existing bit errors.");
+		goto __exit;
+	}
+
+	if (ret > 0 && force)
+		nand_info("WARNING:There are pre-existing %d bits error", ret);
+
+
+	nand_info("Step3:Inject bit errors");
+	err = 0;
+	sector_buf = wr_buf + chip->ecc_size * sector;
+	bit_one = mempool_alloc(chip->ecc_size * 8 * sizeof(u32), MEMPOOL_ANY);
+	if (bit_one == NULL) {
+		nand_err("malloc fail!!!");
+		ret = -ENOMEM;
+		goto __exit;
+	}
+
+	bit_one_count = get_bit_one(bit_one, sector_buf, chip->ecc_size);
+	if (bit_one_count < err_bits) {
+		nand_err("Data has not enough 1 bits");
+		ret = -EINVAL;
+		goto __exit;
+	}
+
+	/*
+	* All bit-1 in the target ecc_zone(sector) have been collected in array
+	* bit_one, now we choose the specified number of bit-1 and set them as
+	* bit-0. The position of bit-1 is random.
+	*/
+	do {
+		int bit;
+
+		bit = bit_one[rand()%bit_one_count];
+		sector_buf[bit / 8] &= ~(1 << (bit % 8));
+		nand_info("Set %d byte %d bit as 0", bit / 8, bit % 8);
+		err++;
+	} while(err < err_bits);
+
+	nand_info("Step4:Write page --no-ecc");
+	ops.mode = NAND_OPS_RAW_DMA_POLL;
+	ops.datbuf = wr_buf;
+	ret = mtk_nand_write(chip, &ops);
+	if (ret < 0) {
+		nand_err("write fail!!!");
+		goto __exit;
+	}
+
+	nand_info("Step5:Read page --ecc");
+	nand_memset(rd_buf, 0, chip->pagesize + chip->oobsize);
+	ops.datbuf = rd_buf;
+	ops.mode = NAND_OPS_ECC_DMA_POLL;
+	ret = mtk_nand_read(chip, &ops);
+	if (ret < 0) {
+		nand_err("read fail!!!");
+		goto __exit;
+	}
+
+	nand_info("There are %d bits error after inject bit errors", ret);
+	ret = 0;
+
+__exit:
+	mempool_free(wr_buf);
+	mempool_free(rd_buf);
+	mempool_free(bit_one);
+	return ret;
+}
+
+int nand_clear_biterrs(u32 block)
+{
+	struct mtk_nand_chip *chip = g_nand_chip;
+	struct mtk_nand_ops ops, erase_ops;
+	u8 *rd_buf;
+	int raw_page_len = 0;
+	u32 i;
+	int ret;
+
+	nand_info("block:%d", block);
+	if (block >= chip->totalsize/chip->blocksize) {
+		nand_err("block should be from 0~%lld!!!",
+			chip->totalsize / chip->blocksize - 1);
+		return -1;
+	}
+
+	raw_page_len = chip->pagesize + chip->oobsize;
+	rd_buf = mempool_alloc(raw_page_len * chip->page_per_block, MEMPOOL_ANY);
+	if (rd_buf == NULL) {
+		nand_err("malloc fail!!!");
+		return -1;
+	}
+
+	nand_memset(rd_buf, 0, raw_page_len * chip->page_per_block);
+	ops.len = chip->pagesize;
+	ops.oobeccbuf = NULL;
+	ops.oobecclen = 0;
+	ops.oobfreebuf = NULL;
+	ops.oobfreelen = 0;
+	ops.mode = NAND_OPS_ECC_DMA_POLL;
+
+	nand_info("Step1: Read the block's all page");
+	ops.offset = block * chip->blocksize;
+	ops.datbuf = rd_buf;
+	for (i = 0; i < chip->page_per_block; i++) {
+		ret = mtk_nand_read(chip, &ops);
+		if (ret < 0) {
+			nand_err("read fail!!! ret:%d\n", ret);
+			goto __exit;
+		}
+		ops.offset += chip->pagesize;
+		ops.datbuf += raw_page_len;
+	}
+
+	nand_info("Step2: Erase the block");
+	nand_memset(&erase_ops, 0, sizeof(erase_ops));
+	erase_ops.mode = NAND_OPS_ERASE_POLL;
+	erase_ops.offset = block * chip->blocksize;
+	erase_ops.len = chip->blocksize;
+	ret = mtk_nand_erase(chip, &erase_ops);
+	if (ret < 0) {
+		nand_err("erase fail!!! ret:%d\n", ret);
+		goto __exit;
+	}
+
+	nand_info("Step3: Rewrite the block");
+	ops.mode = NAND_OPS_ECC_DMA_POLL;
+	ops.offset = block * chip->blocksize;
+	ops.datbuf = rd_buf;
+	for (i = 0; i < chip->page_per_block; i++) {
+		ret = mtk_nand_write(chip, &ops);
+		if (ret < 0) {
+			nand_err("write fail!!! ret:%d\n", ret);
+			goto __exit;
+		}
+		ops.offset += chip->pagesize;
+		ops.datbuf += raw_page_len;
+	}
+
+	nand_info("Step4: Read again to verify clear result");
+	ops.offset = block * chip->blocksize;
+	ops.datbuf = rd_buf;
+	for (i = 0; i < chip->page_per_block; i++) {
+		ret = mtk_nand_read(chip, &ops);
+		if (ret < 0)
+			nand_err("read page:%d fail!!! ret:%d\n", i, ret);
+		else if (ret)
+			nand_err("There are still %d bits error on page :%d",
+				ret, i);
+
+		ops.offset += chip->pagesize;
+		ops.datbuf += raw_page_len;
+	}
+__exit:
+	nand_free(rd_buf);
+	return ret;
+}
+#else
+int nand_inject_biterrs(u32 block, u32 page, u32 sector, u32 err_bits, bool force)
+{
+	return -EINVAL;
+}
+
+int nand_clear_biterrs(u32 block)
+{
+	return -EINVAL;
+}
+#endif
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_bbt.c b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_bbt.c
new file mode 100644
index 0000000..2c5c6ed
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_bbt.c
@@ -0,0 +1,434 @@
+#include "mtk_nand_sys.h"

+#include "mtk_nand_nal.h"

+#include "mtk_nand_bbt.h"

+#include "mtk_nand_test.h"

+

+/*Not support: multi-chip*/

+static u8 main_bbt_pattern[] = {'B', 'b', 't', '0' };

+static u8 mirror_bbt_pattern[] = {'1', 't', 'b', 'B' };

+

+static struct mtk_bbt g_mtk_bbt =

+{

+	{{{main_bbt_pattern, 4}, 0, BBT_INVALID_PAGE},

+	{{mirror_bbt_pattern, 4}, 0, BBT_INVALID_PAGE}},

+	NAND_BBT_SCAN_MAXBLOCKS

+};

+

+static int mtk_bbt_read_pages(struct mtk_nand_chip *chip, u8 *buf, u32 offs, u32 len)

+{

+	struct mtk_nand_ops ops;

+

+	nand_debug("len:0x%x, offs:0x%lx", len, offs);

+	nand_memset(&ops, 0, sizeof(ops));

+	ops.mode = NAND_OPS_ECC_DMA_POLL;

+	ops.offset = (u64) offs;

+	ops.len = (u64) len;

+	ops.datbuf = buf;

+

+	return mtk_nand_read(chip, &ops);

+}

+

+static int mtk_bbt_program_pages(struct mtk_nand_chip *chip, u8 *buf, u32 offs, u32 len)

+{

+	struct mtk_nand_ops ops;

+

+	nand_debug("len:0x%x", len);

+

+	nand_memset(&ops, 0, sizeof(ops));

+	ops.mode = NAND_OPS_ECC_DMA_POLL;

+	ops.offset = (u64) offs;

+	ops.len = (u64) len;

+	ops.datbuf = buf;

+	ops.oobeccbuf = NULL;

+

+	return mtk_nand_write(chip, &ops);

+}

+

+static int mtk_bbt_erase_block(struct mtk_nand_chip *chip, u32 block)

+{

+	struct mtk_nand_ops ops;

+

+	nand_memset(&ops, 0, sizeof(ops));

+	ops.mode = NAND_OPS_ERASE_POLL;

+	ops.offset = (u64) (block * chip->blocksize);

+	ops.len = chip->blocksize;

+

+	return mtk_nand_erase_block(chip, &ops, 1);

+}

+

+static inline void mtk_set_bbt_mark(u8 *bbt, int block, u8 mark)

+{

+	bbt[GET_ENTRY(block)] |= GET_MARK_VALUE(block, mark);

+}

+

+static inline u8 mtk_get_bbt_mark(u8 *bbt, int block)

+{

+	int index = GET_ENTRY(block);

+	int offset = GET_POSITION(block);

+	u8 value = bbt[index];

+

+	return (value >> offset) & BBT_ENTRY_MASK;

+}

+

+static void mtk_bbt_to_buf(u8 *bbt, u8 *buf, int blocks)

+{

+	int i, bit_pos;

+	uint8_t mark;

+

+	/* Walk through the memory table */

+	for (i = 0; i < blocks; i++) {

+		bit_pos = (i & 3) << 1;

+		mark = mtk_get_bbt_mark(bbt, i);

+                /*

+		 * In flash the block bad information are:

+		 * BBT_BLOCK_GOOD, BBT_BLOCK_WORN, BBT_BLOCK_FACTORY_BAD,

+                 * and in dram, they are: BBT_BLOCK_GOOD, BBT_BLOCK_WORN,

+		 * BBT_BLOCK_RESERVED, BBT_BLOCK_FACTORY_BAD.

+                 * BBT_BLOCK_RESERVED is not stored in flash, and if a block is

+                 * reserved, it is stored as BBT_BLOCK_GOOD

+	         */

+		if (mark == BBT_BLOCK_RESERVED)

+			mark = BBT_BLOCK_GOOD;

+		buf[i >> 2] &= ~(mark << bit_pos);

+	}

+}

+

+static void mtk_buf_to_bbt(u8 *bbt, u8 *buf, int len)

+{

+	u8 data, mark;

+	int i, j;

+

+	for (i = 0; i < len; i++) {

+		data = ~buf[i];

+		if (buf[i] != 0xFF)

+			nand_info("buf[%d]=(0x%x)", i, buf[i]);

+		if (!data)

+			continue;

+

+		for (j = 0; j * 2 < 8; j++) {

+			mark = (data >> j * 2) & 0x3;

+			if (!mark)

+				continue;

+			mtk_set_bbt_mark(bbt, (i << 2) + j, mark);

+		}

+	}

+}

+

+static inline bool mtk_is_bbt_data(u8 *buf, struct mtk_bbt_pattern *pattern)

+{

+	if (nand_memcmp(buf, pattern->data, pattern->len))

+		return FALSE;

+	return TRUE;

+}

+static int mtk_get_bbt_page(struct mtk_nand_chip *chip,

+			int mirror_page)

+{

+	int i = 0, total_block, block, page;

+	u8 mark;

+

+	total_block = chip->totalsize / chip->blocksize;

+

+	while (i < g_mtk_bbt.max_blocks) {

+		block = total_block - 1 - i;

+		mark = mtk_get_bbt_mark(chip->bbt, block);

+		nand_info("block %d, mark %d, mirror_page %d",

+			block, mark, mirror_page);

+		if (mark == BBT_BLOCK_WORN || mark == BBT_BLOCK_FACTORY_BAD) {

+			i++;

+			continue;

+		}

+		page = block * chip->page_per_block;

+		if (page != mirror_page)

+			return page;

+		i++;

+	}

+

+	return BBT_INVALID_PAGE;

+}

+

+static int mtk_read_bbt(struct mtk_nand_chip *chip, u32 bbt_len, struct mtk_bbt_desc *desc)

+{

+	u32 offset = 0;

+	u32 label_len;

+	int ret;

+	u8 *buf = NAND_DRAM_BUF_DATABUF_ADDR;

+

+	nand_info("page:%d", desc->page);

+	label_len = desc->pattern.len + 1;

+	offset = (desc->page * chip->pagesize) + label_len;

+	ret = mtk_bbt_read_pages(chip, buf, offset, bbt_len);

+	if (ret < 0) {

+		nand_info("nand_bbt: error reading BBT page, ret:-%x", ret);

+		desc->page = BBT_INVALID_PAGE;

+		desc->version = 0;

+		return ret;

+	}

+

+	mtk_buf_to_bbt(chip->bbt, buf, bbt_len);

+

+	return 0;

+}

+

+static void mtk_create_bbt(struct mtk_nand_chip *chip, u32 max_block)

+{

+	u32 block = 0;

+

+	nand_info("max_block %d", max_block);

+	while (block < max_block) {

+		if (chip->block_bad(chip, (u64)block * chip->blocksize)) {

+			nand_info("bad block is found, block %d", block);

+			mtk_set_bbt_mark(chip->bbt, block, BBT_BLOCK_FACTORY_BAD);

+		}

+		block++;

+	}

+}

+

+/*search bbt by given pattern defined in desc and if find, update desc->page*/

+static int mtk_search_bbt(struct mtk_nand_chip *chip, struct mtk_bbt_desc *desc)

+{

+	struct mtk_bbt *bbt = &g_mtk_bbt;

+	u8 *buf = NAND_DRAM_BUF_DATABUF_ADDR;

+	int i = 0, page, total_block;

+	int ret;

+

+	total_block = chip->totalsize / chip->blocksize;

+	while ((++i) <= bbt->max_blocks) {

+		page = (total_block - i) * chip->page_per_block;

+

+		ret = mtk_bbt_read_pages(chip, buf, page * chip->pagesize, chip->pagesize);

+		if (ret) {

+			nand_err("read page (%d) error, ret %d", page, ret);

+			continue;

+		}

+

+		if (mtk_is_bbt_data(buf, &desc->pattern))

+		{

+			desc->page = page;

+			desc->version = buf[desc->pattern.len];

+			nand_info("Bad block table found at page %d, version %d, i %d",

+				desc->page, desc->version, i);

+			ret = 0;

+			break;

+		}

+	}

+

+	if (i > bbt->max_blocks) {

+		nand_err("Bad block table not found for pattern %s",

+			desc->pattern.data);

+		ret = -EFAULT;

+	}

+

+	return ret;

+}

+

+static int mtk_save_bbt(struct mtk_nand_chip *chip, struct mtk_bbt_desc *desc)

+{

+	int block, write_len;

+	u32 page_size_mask, total_block;

+	u8 *buf;

+	int ret;

+

+	nand_info("page %d", desc->page);

+	total_block = chip->totalsize / chip->blocksize;

+	block = desc->page / chip->page_per_block;

+	ret = mtk_bbt_erase_block(chip, block);

+#if MTK_NAND_WORN_BAD_TEST

+	nand_info("MTK_NAND_WORN_BAD_TEST");

+	if (nand_check_erase_test_block(block)) {

+		nand_info("Simulate erase fail case on block %d", block);

+		ret = -EIO;

+	}

+#endif

+	if (ret) {

+		nand_err("erase block %d fail !!!, ret %d", block, ret);

+		return ret;

+	}

+

+	write_len= GET_BBT_LENGTH(total_block) + desc->pattern.len + 1;

+	page_size_mask = chip->pagesize - 1;

+	write_len = (write_len + page_size_mask) & (~page_size_mask);

+

+	buf = NAND_DRAM_BUF_DATABUF_ADDR;

+	nand_memset(buf, 0xFF, write_len);

+

+	nand_memcpy(buf, desc->pattern.data, desc->pattern.len);

+	buf[desc->pattern.len] = desc->version;

+

+	mtk_bbt_to_buf(chip->bbt, buf + desc->pattern.len + 1, total_block);

+

+	ret = mtk_bbt_program_pages(chip, buf, desc->page * chip->pagesize, write_len);

+#if MTK_NAND_WORN_BAD_TEST

+	if (nand_check_program_test_page(desc->page)) {

+		nand_info("Simulate program fail case at page %u", desc->page);

+		ret = -EIO;

+	}

+#endif

+

+	return ret;

+}

+

+static int mtk_write_bbt(struct mtk_nand_chip *chip,

+			struct mtk_bbt_desc *main,

+			struct mtk_bbt_desc *mirror)

+{

+	do {

+		if (main->page == BBT_INVALID_PAGE) {

+			main->page = mtk_get_bbt_page(chip, mirror->page);

+			if (main->page == BBT_INVALID_PAGE)

+				return -ENOSPC;

+		}

+

+		if (!mtk_save_bbt(chip, main))

+			break;

+

+		mtk_set_bbt_mark(chip->bbt, main->page / chip->page_per_block,

+				BBT_BLOCK_WORN);

+		chip->block_markbad(chip, main->page);

+		main->page = BBT_INVALID_PAGE;

+	} while (1);

+

+	return 0;

+}

+

+static int mtk_update_bbt(struct mtk_nand_chip *chip)

+{

+	struct mtk_bbt_desc *desc = g_mtk_bbt.bbt_desc;

+	int ret, i;

+

+	for (i = 0; i < 2; i++) {

+		desc[i].version++;

+		ret = mtk_write_bbt(chip, &desc[i], &desc[1-i]);

+		if (ret)

+			return ret;

+	}

+

+	return 0;

+}

+static void mtk_mark_bbt_region(struct mtk_nand_chip *chip)

+{

+	int block, total_block;

+

+	total_block = (int)(chip->totalsize >> chip->bbt_erase_shift);

+	block = total_block - g_mtk_bbt.max_blocks;

+

+	do {

+		mtk_set_bbt_mark(chip->bbt, block, BBT_BLOCK_RESERVED);

+	} while ((++block) < total_block);

+}

+

+void mtk_nand_set_bbt_options(struct mtk_nand_chip *chip, u8 maf_id)

+{

+	if ((maf_id == NAND_MFR_SAMSUNG ||

+	           maf_id == NAND_MFR_HYNIX ||

+	           maf_id == NAND_MFR_TOSHIBA ||

+	           maf_id == NAND_MFR_AMD ||

+	           maf_id == NAND_MFR_MACRONIX) ||

+	         (maf_id == NAND_MFR_MICRON &&

+	          chip->pagesize == 2048))

+		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;

+}

+

+int mtk_nand_default_bbt(struct mtk_nand_chip *chip)

+{

+	struct mtk_bbt *bbt = &g_mtk_bbt;

+	struct mtk_bbt_desc *pdesc;

+	int valid_desc = 0;/*bit0: desc0; bit1: desc1*/

+	int total_block, len, i;

+	int ret = 0;

+

+	total_block = chip->totalsize / chip->blocksize;

+	len = GET_BBT_LENGTH(total_block);

+

+	chip->bbt = nand_malloc(len);

+	if (NULL == chip->bbt) {

+		nand_err("malloc bbt buf fail!!! len:%d", len);

+		return -ENOMEM;

+	}

+	nand_memset(chip->bbt, 0, len);

+

+	/*scan bbt*/

+	for (i = 0; i < 2; i++) {

+		pdesc = &bbt->bbt_desc[i];

+		pdesc->page = BBT_INVALID_PAGE;

+		pdesc->version = 0;

+		ret = mtk_search_bbt(chip, pdesc);

+		if (!ret && (pdesc->page != BBT_INVALID_PAGE))

+			valid_desc += 1 << i;

+	}

+

+	pdesc = &bbt->bbt_desc[0];

+	if ((valid_desc == 0x3) && (pdesc[0].version != pdesc[1].version))

+		valid_desc = (pdesc[0].version > pdesc[1].version) ? 1 : 2;

+

+	/* read bbt */

+	for (i = 0; i < 2; i++) {

+		if (!(valid_desc & (1 << i)))

+			continue;

+		ret = mtk_read_bbt(chip, len, &pdesc[i]);

+		if (ret)

+			valid_desc &= ~(1 << i);

+	}

+

+	if (!valid_desc) {

+		mtk_create_bbt(chip, total_block);

+		pdesc[0].version = 1;

+		pdesc[1].version = 1;

+	}

+

+	pdesc[0].version = max(pdesc[0].version, pdesc[1].version);

+	pdesc[1].version = pdesc[0].version;

+

+	for (i = 0; i < 2; i++) {

+		if (valid_desc & (1 << i))

+			continue;

+

+		ret = mtk_write_bbt(chip, &pdesc[i], &pdesc[1 - i]);

+		if (ret) {

+			nand_err("save bbt(%d) fail, ret:%d", i, ret);

+			nand_free(chip->bbt);

+			chip->bbt = NULL;

+			return ret;

+		}

+	}

+	/* Prevent the bbt regions from erasing / writing */

+	mtk_mark_bbt_region(chip);

+

+	nand_info("BBT check total block:%d", total_block);

+	for (i = 0; i < total_block; i++) {

+		if (mtk_get_bbt_mark(chip->bbt, i) == BBT_BLOCK_WORN)

+			nand_info("Checked WORN bad blk: %d", i);

+		else if (mtk_get_bbt_mark(chip->bbt, i) == BBT_BLOCK_FACTORY_BAD)

+			nand_info("Checked Factory bad blk: %d", i);

+		else if (mtk_get_bbt_mark(chip->bbt, i) != BBT_BLOCK_GOOD)

+			nand_debug("Checked Reserved blk: %d", i);

+	}

+	return 0;

+}

+

+int mtk_nand_markbad_bbt(struct mtk_nand_chip *this, loff_t offs)

+{

+	u8 *bbt_buf = this->bbt;

+	int block, ret;

+

+	block = (int)(offs >> this->bbt_erase_shift);

+	mtk_set_bbt_mark(bbt_buf, block, BBT_BLOCK_WORN);

+

+	/* Update flash-based bad block table */

+	ret = mtk_update_bbt(this);

+	nand_info("block %d, update result %d.", block, ret);

+

+	return ret;

+}

+

+int mtk_nand_isbad_bbt(struct mtk_nand_chip *this, int block, int allowbbt)

+{

+	u8 mark = mtk_get_bbt_mark(this->bbt, block);

+

+	if (mark == BBT_BLOCK_GOOD)

+		return 0;

+

+	if ((mark == BBT_BLOCK_RESERVED) && allowbbt)

+		return 0;

+

+	return 1;

+}

diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_bbt.h b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_bbt.h
new file mode 100644
index 0000000..d295bab
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_bbt.h
@@ -0,0 +1,52 @@
+#ifndef __MTK_NAND_BBT_H__

+#define __MTK_NAND_BBT_H__

+

+#define BBT_BLOCK_GOOD      0x00

+#define BBT_BLOCK_WORN      0x01

+#define BBT_BLOCK_RESERVED      0x02

+#define BBT_BLOCK_FACTORY_BAD   0x03

+

+#define BBT_INVALID_PAGE (-1)

+/* The maximum number of blocks to scan for a bbt */

+#define NAND_BBT_SCAN_MAXBLOCKS 4

+#define NAND_BBT_USE_FLASH  0x00020000

+#define NAND_BBT_NO_OOB     0x00040000

+#define NAND_BBT_NO_OOB_BBM	0x00080000

+

+/* 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

+

+struct mtk_bbt_pattern {

+	u8 *data;

+	int len;

+};

+

+struct mtk_bbt_desc{

+	struct mtk_bbt_pattern pattern;

+	u8 version;

+	int page;/*-1: invalid value; >=0, valid value*/

+};

+

+struct mtk_bbt {

+	/* main bbt descriptor and mirror descriptor */

+	struct mtk_bbt_desc bbt_desc[2];/* 0: main bbt; 1: mirror bbt */

+	int max_blocks;

+};

+

+#define BBT_ENTRY_MASK      0x03

+#define BBT_ENTRY_SHIFT     2

+

+#define GET_BBT_LENGTH(blocks) (blocks >> 2)

+#define GET_ENTRY(block) ((block) >> BBT_ENTRY_SHIFT)

+#define GET_POSITION(block) (((block) & BBT_ENTRY_MASK) * 2)

+#define GET_MARK_VALUE(block, mark) \

+	(((mark) & BBT_ENTRY_MASK) << GET_POSITION(block))

+void mtk_nand_set_bbt_options(struct mtk_nand_chip *chip, u8 maf_id);

+int mtk_nand_default_bbt(struct mtk_nand_chip *chip);

+

+int mtk_nand_markbad_bbt(struct mtk_nand_chip *this, loff_t offs);

+int mtk_nand_isbad_bbt(struct mtk_nand_chip *this, int block, int allowbbt);

+

+#endif /*__MTK_NAND_BBT_H__*/

diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_device.c b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_device.c
new file mode 100644
index 0000000..e45fc02
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_device.c
@@ -0,0 +1,112 @@
+/*
+* 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 "mtk_nand_nal.h"
+
+#define NAND_OPTIONS_NONE    0
+#define NFI_DEFAULT_ACTIMING 0x10804111
+
+struct mtk_nand_flash_dev nand_flash_devs[] = {
+	/* MXIC */
+	{
+		"MX30LF2G18AC", {0xc2, 0xda, 0x90, 0x95, 0x6, 0, 0, 0},
+		5, KB(256), KB(128), 2048, 64, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 12,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	{
+		"MX30LF4G28AD", {0xc2, 0xdc, 0x90, 0xa2, 0x57, 0x03},
+		6, KB(512), KB(256), 4096, 256, 1, 1, 0x10804111, 1024, 24,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	{
+		"MX30LF4G18AC", {0xc2, 0xdc, 0x90, 0x95, 0x56, 0, 0, 0},
+		5, KB(512), KB(128), 2048, 64, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 12,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	{
+		"MX60LF8G18AC", {0xc2, 0xd3, 0xd1, 0x95, 0x5a, 0x00},
+		5, KB(1024), KB(128), 2048, 64, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 12,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	/* Micron */
+	{
+		"MT29F2G08ABAEA", {0x2c, 0xda, 0x90, 0x95, 0x06, 0, 0, 0},
+		5, KB(256), KB(128), 2048, 64, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 12,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	{
+		"MT29F4G08ABAEA", {0x2c, 0xdc, 0x90, 0xa6, 0x54, 0x00},
+		5, KB(512), KB(512), 4096, 224, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 24,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	{
+		"MT29F4G08ABAFA", {0x2c, 0xdc, 0x80, 0xa6, 0x62, 0x00},
+		5, KB(512), KB(256), 4096, 256, 1, 1, 0x10804111, 1024, 24,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	{
+		"MT29F8G08ABABA", {0x2C, 0x38, 0x00, 0x26, 0x85, 0x0, 0},
+		5, KB(1024), KB(512), 4096, 224, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 24,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	{
+		"MT29F8G08ABACA", {0x2c, 0xd3, 0x90, 0xa6, 0x64, 0x00},
+		5, KB(256), KB(256), 4096, 224, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 24,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	{
+		"MT29F16G08ADBCA", {0x2c, 0xa5, 0xd1, 0x26, 0x68, 0, 0, 0},
+		5, KB(2048), KB(256), 4096, 224, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 24,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	/* Toshiba */
+	{
+		"TC58NYG1S3HBAI6", {0x98, 0xaa, 0x90, 0x15, 0x76, 0x16, 0, 0},
+		6, KB(256), KB(128), 2048, 128, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 24,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	{
+		"TC58BVG1S3HTA00", {0x98, 0xda, 0x90, 0x15, 0xf6, 0x00, 0, 0},
+		5, KB(256), KB(128), 2048, 64, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 12,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	{
+		"TC58NVG2S0HTA00", {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0, 0},
+		6, KB(512), KB(256), 4096, 256, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 24,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	/* Samsung */
+	{
+		"K9F2G08U0D", {0xec, 0xda, 0x10, 0x95, 0x46, 0, 0, 0},
+		5, KB(256), KB(128), 2048, 64, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 12,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+	/* MXIC */
+	{
+		"F59D4G81A-45TG-18V", {0xc8, 0xac, 0x90, 0x15, 0x54, 0, 0, 0},
+		5, KB(512), KB(128), 2048, 64, 1, 1, NFI_DEFAULT_ACTIMING, 1024, 4,
+		NAND_OPTIONS_NONE, NAND_OPTIONS_NONE
+	},
+
+	{NULL}
+};
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_nal.c b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_nal.c
new file mode 100644
index 0000000..f4f1900
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_nal.c
@@ -0,0 +1,962 @@
+/*
+ * 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 "mtk_nand_nal.h"
+#include "mtk_nfi_hal.h"
+#include "mtk_nand_bbt.h"
+#include "mtk_nand_sys.h"
+#include "mtk_nfi_hal.h"
+#include "mtk_nand_test.h"
+
+#define NOTALIGNED(x)   ((x & (chip->subpagesize - 1)) != 0)
+
+u64 g_nand_size = 0;
+
+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,
+				int allowbbt, int force_erase);
+
+static int mtk_nand_is_dram_buf(u8* buf)
+{
+	//return (buf < NAND_DRAM_BASE_VIRT) ? 0 : 1;
+	return 1;
+}
+
+static int mtk_nand_get_controller(struct mtk_nand_chip *chip)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+	nand_lock(&nfc->lock);
+
+	return 0;
+}
+
+static int mtk_nand_release_controller(struct mtk_nand_chip *chip)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+	nand_unlock(&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))
+			nand_err("nand dev ready timeout");
+	} else {
+		if (!check_with_timeout(chip->dev_ready(chip), timeo))
+			nand_err("nand dev ready timeout");
+	}
+
+	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))
+		nand_err("nand dev ready timeout");
+
+}
+
+
+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)
+{
+	struct mtk_nand_ops ops;
+	int page, res = 0, i = 0;
+	u16 bad;
+	int ret = 0;
+
+	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+		ofs += chip->blocksize - chip->pagesize;
+
+	page = (int)(ofs / chip->pagesize) % chip->page_per_chip;
+
+	nand_memset(&ops, 0, sizeof(ops));
+	ops.mode = NAND_OPS_ECC_DMA_POLL;
+	ops.offset = (u64)page * chip->pagesize;
+	ops.len = chip->pagesize;
+	ops.datbuf = chip->databuf;
+	ret = mtk_nand_do_read_ops(chip, &ops);
+
+	if (chip->oob_poi[chip->badblockpos] != 0xFF) {
+		nand_err("bad block:%d", ofs / chip->blocksize);
+		return -EBADMSG;
+	}
+
+	if ((ret < 0) || chip->stats.empty) {
+		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;
+}
+
+static int mtk_nand_block_checkbad(struct mtk_nand_chip *chip, u32 page, int allowbbt)
+{
+	struct mtk_nand_ops ops;
+	int ret = 0;
+
+	if (chip->bbt)
+		return mtk_nand_isbad_bbt(chip, page / chip->page_per_block, allowbbt);
+
+	ret = chip->block_bad(chip, (u32)page * chip->pagesize);
+	if(ret)
+		nand_err("bad blk at page:0x%x", page);
+
+	return ret;
+}
+
+int mtk_nand_block_isbad_allowbbt(struct mtk_nand_chip *nand, u32 page)
+{
+	int ret = 0;
+
+	mtk_nand_get_controller(nand);
+
+	/* Make page be block aligned */
+	page = page / nand->page_per_block * nand->page_per_block;
+
+	ret = mtk_nand_block_checkbad(nand, page, 1);
+
+	mtk_nand_release_controller(nand);
+
+	return ret;
+}
+
+int mtk_nand_block_isbad(struct mtk_nand_chip *nand, u32 page)
+{
+	int ret = 0;
+
+	mtk_nand_get_controller(nand);
+
+	/* Make page be block aligned */
+	page = page / nand->page_per_block * nand->page_per_block;
+
+	ret = mtk_nand_block_checkbad(nand, page, 0);
+
+	mtk_nand_release_controller(nand);
+
+	return ret;
+}
+
+int nand_reset(struct mtk_nand_chip *chip, int chipnr)
+{
+	/* power on sequence delay */
+	mtk_nand_udelay(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 cmd, int col, int row)
+{
+	int ctrl;
+
+	if (NAND_CMD_READOOB == cmd) {
+		col += chip->pagesize;
+		cmd = NAND_CMD_READ0;
+	}
+
+	/* send command */
+	chip->cmd_ctrl(chip, cmd, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+
+	ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
+
+	/* input column address then row address */
+	if (col != -1) {
+		chip->cmd_ctrl(chip, col, ctrl);
+		ctrl &= ~NAND_CTRL_CHANGE;
+
+		/* if it is 8bits opcodes, only output a single addr cycle. */
+		if (!mtk_nand_opcode_8bits(cmd))
+			chip->cmd_ctrl(chip, col >> 8, ctrl);
+	}
+	if (row != -1) {
+		chip->cmd_ctrl(chip, row, ctrl);
+		chip->cmd_ctrl(chip, row >> 8, NAND_NCE | NAND_ALE);
+		/* One more address cycle for devices > 128MiB */
+		if (chip->chipsize > (128 << 20))
+			chip->cmd_ctrl(chip, row >> 16, NAND_NCE | NAND_ALE);
+	}
+	chip->cmd_ctrl(chip, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+	if ((cmd == NAND_CMD_CACHEDPROG) || (cmd == NAND_CMD_PAGEPROG)
+		|| (cmd == NAND_CMD_ERASE1) || (cmd == NAND_CMD_ERASE2)
+		|| (cmd == NAND_CMD_SEQIN)|| (cmd == NAND_CMD_STATUS))
+		return;
+
+	if (cmd == NAND_CMD_RNDOUT) {
+		/* No need to check ready / busy */
+		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;
+	}
+
+	if (cmd == 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);
+	}
+
+	mtk_nand_wait_ready(chip);
+
+}
+
+int mtk_nand_block_markbad(struct mtk_nand_chip *chip, u32 page)
+{
+	struct mtk_nand_ops ops;
+	int ret_bbm, ret = 0;
+
+	nand_info("page:%d", page);
+
+	/* Make page be block aligned */
+	page = page / chip->page_per_block * chip->page_per_block;
+
+	if (mtk_nand_block_isbad(chip, page)) {
+		return 0;
+	} else {
+		/* Mark block bad in BBT */
+		if (chip->bbt) {
+			ret = mtk_nand_markbad_bbt(chip, (u64)(page*chip->pagesize));
+		}
+
+		/* Only update OOB BBM if needed */
+		if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
+			mtk_nand_get_controller(chip);
+			/* Attempt erase befor marking OOB */
+			nand_memset(&ops, 0, sizeof(ops));
+			ops.mode = NAND_OPS_ERASE_POLL;
+			ops.offset = (u64)page * chip->pagesize;
+			ops.len = chip->blocksize;
+			mtk_nand_do_erase_ops(chip, &ops, 0, 0);
+			/* Write bad marker to OOB */
+			ret_bbm = chip->block_markbad(chip, page);
+			mtk_nand_release_controller(chip);
+
+			/* Update the return value only if needed */
+			if (!ret) {
+				ret = ret_bbm;
+			}
+		}
+	}
+
+	return ret;
+}
+
+void lk_nand_irq_handler(unsigned int irq)
+{
+	/* no need irq handler for lk, we use polling */
+	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;
+
+	/* scan bbt, set scan_bbt to NULL if disable bbt */
+	chip->scan_bbt = mtk_nand_default_bbt;
+
+	/* variable defalut value */
+	chip->badblockbits = 8;
+	chip->badblockpos = 0;
+
+	chip->activechip = -1;
+
+	/* BBT options setting, must align for all drivers */
+	chip->bbt_options |= (NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB | NAND_BBT_NO_OOB_BBM);
+}
+
+/**
+ * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ */
+static int nand_onfi_set_features(struct mtk_nand_chip *chip,
+			int addr, u8 *subfeature_param)
+{
+	int status;
+	int i;
+
+	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, 1);
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return 0;
+}
+
+/**
+ * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ */
+static void 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);
+
+}
+
+static void nand_IO_strength_adjust(struct mtk_nand_chip *chip)
+{
+	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {0};
+
+	/* Try ONFI for unknown chip or LP */
+	chip->cmdfunc(chip, NAND_CMD_READID, 0x20, -1);
+	if (chip->read_byte(chip) != 'O' || chip->read_byte(chip) != 'N' ||
+		chip->read_byte(chip) != 'F' || chip->read_byte(chip) != 'I') {
+		nand_info("Not ONFI CHIP");
+		return;
+	}
+
+	/* Add I/O Strength adjustment for Micron nand chip */
+	nand_onfi_get_features(chip, 0x80, feature);
+	nand_info("Check IO strength 80H before setting: %x %x %x %x",
+		feature[0], feature[1], feature[2], feature[3]);
+
+	if (feature[IO_STR_MICRON_ADDR] != IO_STR_MICRON_THREE_QUARTER) {
+		/*
+		 * Feature Address 80h: Prgogrammable I/O Drive Strength
+		 * -------------------------------------
+		 * P1: IO drive strength.
+		 *	00h: Full(default)
+		 *	01h: Three-quarters
+		 *	02h: One-half
+		 *	03h: One-quarter
+		 * p2 ~ P4: 00h: Reserved
+		 */
+		memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN);
+		feature[IO_STR_MICRON_ADDR] = IO_STR_MICRON_THREE_QUARTER;
+		nand_onfi_set_features(chip, 0x80, feature);
+
+		memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN);
+		nand_onfi_get_features(chip, 0x80, feature);
+		if (feature[IO_STR_MICRON_ADDR] != IO_STR_MICRON_THREE_QUARTER) {
+			nand_info("Check IO strength 80H failed: %x %x %x %x",
+				feature[0], feature[1], feature[2], feature[3]);
+		}
+	}
+}
+
+int mtk_nand_flash_get(struct mtk_nand_chip *chip, int maxchips)
+{
+	u32 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);
+	}
+	nand_info("nand id: %x %x %x %x %x %x",
+	          id_data[0], id_data[1], id_data[2],id_data[3], id_data[4],  id_data[5]);
+
+
+	for (; type->name != NULL; type++) {
+		if (!nand_strncmp(type->id, id_data, type->id_len)) {
+			nand_info("nand found [%s]", 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;
+		}
+		nand_info("chip %d is found", 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;
+	g_nand_size = chip->chipsize;
+	chip->blocksize = type->erasesize;
+	chip->bbt_erase_shift = nand_ffs(type->erasesize) - 1;
+	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->acctiming = type->acctiming;
+
+	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 *)nand_memalign(4, chip->pagesize + chip->oobsize);
+	if (!chip->databuf)
+		return -ENOMEM;
+	chip->oob_poi = chip->databuf + chip->pagesize;
+
+	mtk_nand_set_bbt_options(chip, id_data[0]);
+
+	if (id_data[NAND_ID_VENDOR] == NAND_MFR_MICRON)
+		nand_IO_strength_adjust(chip);
+
+	nand_info("pagesize:%d, oobsize:%d, blocksize:0x%x totalsize:0x%x",
+		chip->pagesize, chip->oobsize, chip->blocksize, chip->totalsize);
+
+	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) {
+		nand_err("no nand device found");
+		return ret;
+	}
+
+	/* ret = chip->scan_bbt(chip); */
+
+	return ret;
+}
+
+static int mtk_nand_fill_ecc_oob()
+{
+	return 0;
+}
+
+static int mtk_nand_fill_free_oob()
+{
+	return 0;
+}
+
+static int mtk_nand_transfer_ecc_oob()
+{
+	return 0;
+}
+
+static int mtk_nand_transfer_free_oob()
+{
+	return 0;
+}
+
+static int mtk_nand_do_read_ops(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+	int chipnr, page, realpage, col, bytes, aligned;
+	u8 *buf, *oob_ecc, *oob_free, *bufpoi;
+	u64 readlen = ops->len, from = ops->offset;
+	u32 max_bitflips = 0;
+	u32 ecc_failures = chip->stats.failed;
+	int ret = 0, ecc_fail = 0;
+
+	chipnr = (int)(from / chip->chipsize);
+	chip->select_chip(chip, chipnr);
+
+	realpage = (int)(from / chip->pagesize);
+	page = realpage % chip->page_per_chip;
+
+	col = (int)(from & (chip->pagesize - 1));
+
+	buf = ops->datbuf;
+	oob_ecc = ops->oobeccbuf;
+	oob_free = ops->oobfreebuf;
+
+	nand_debug("page:0x%x data[0~7] %2x %2x %2x %2x  %2x %2x %2x %2x",
+		page, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+
+	while (1) {
+		bytes = min(chip->pagesize - col, readlen);
+		aligned = (bytes == chip->pagesize);
+		/* workaround for dma to sram */
+		if (!mtk_nand_is_dram_buf(buf))
+			aligned = 0;
+		bufpoi = aligned ? buf : chip->databuf;
+
+		/* send read page command */
+		nand_debug("[nand] read page %d chip %d", page, chipnr);
+		#ifndef MT8518_NFI
+		mtk_nfc_randomizer_enable(chip, page, RAND_DECODE, 0);
+		#endif
+		chip->cmdfunc(chip, NAND_CMD_READ0, 0x00, page);
+
+		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);
+		}
+		#ifndef MT8518_NFI
+		mtk_nfc_randomizer_disable(chip);
+		#endif
+		if (ret < 0)
+			break;
+
+		max_bitflips = max(max_bitflips, ret);
+
+		if (chip->stats.failed - ecc_failures) {
+			ecc_fail = 1;
+			break;
+		}
+
+		if (!aligned)
+			nand_memcpy(buf, chip->databuf + col, bytes);
+		if (!oob_ecc)
+			mtk_nand_transfer_ecc_oob();
+		else if (!oob_free)
+			mtk_nand_transfer_free_oob();
+
+		nand_debug("page:0x%x data[0~7] %2x %2x %2x %2x  %2x %2x %2x %2x",
+			page, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+
+		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) {
+		nand_info("uncorrect error at page:0x%x", page);
+		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_do_write_ops(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+	int chipnr, realpage, page, col, bytes, aligned;
+	u32 writelen = ops->len;
+	u64 to = ops->offset;
+	u8 *buf = ops->datbuf;
+	u8 *oob_ecc = ops->oobeccbuf;
+	u8 *oob_free = ops->oobfreebuf;
+	u8 *bufpoi;
+	int ret = 0, status, polling_wait = 1;
+
+	/* Reject writes, which are not subpage aligned */
+	if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
+		nand_err("attempt to write non page aligned data (offset 0x%llx, len 0x%llx)", 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;
+		nand_err("write protected!");
+		goto err_out;
+	}
+
+	realpage = (int)(to / chip->pagesize);
+	page = realpage % chip->page_per_chip;
+
+	nand_debug("page:0x%x data[0~7] %2x %2x %2x %2x  %2x %2x %2x %2x",
+		page, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+
+	while (1) {
+		bytes = min(chip->pagesize - col, writelen);
+		aligned = (bytes == chip->pagesize);
+		/* workaround for dma to sram */
+		if (!mtk_nand_is_dram_buf(buf))
+			aligned = 0;
+		bufpoi = aligned ? buf : chip->databuf;
+
+		if (!aligned) {
+			nand_memset(chip->databuf, 0xff, chip->pagesize);
+			nand_memcpy(chip->databuf + col, buf, bytes);
+		}
+		nand_memset(chip->oob_poi, 0xff, chip->oobsize);
+		if (!oob_ecc)
+			mtk_nand_fill_ecc_oob();
+		else if (!oob_free)
+			mtk_nand_fill_free_oob();
+
+		/* nand_debug("[nand] write page %d chip %d", page, chipnr); */
+		#ifndef MT8518_NFI
+
+		mtk_nfc_randomizer_enable(chip, page, RAND_ENCODE, 0);
+		#endif
+		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);
+		}
+		#ifndef MT8518_NFI
+		mtk_nfc_randomizer_disable(chip);
+		#endif
+		if (ret < 0)
+			break;
+
+		chip->cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
+		status = chip->waitfunc(chip, polling_wait);
+#if MTK_NAND_WORN_BAD_TEST
+		if (nand_check_program_test_page(page)) {
+			nand_err("Simulate program fail case at page %u", page);
+			status |= NAND_STATUS_FAIL;
+		}
+#endif
+		if (status & NAND_STATUS_FAIL) {
+			ret = -EIO;
+			nand_err("write failed at page 0x%x status:0x%x", realpage, status);
+			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,
+				int allowbbt, int force_erase)
+{
+	u64 offset = ops->offset;
+	u64 eraselen = ops->len;
+	int page, status, ret = 0, chipnr, polling_wait = 0;
+
+	if ((offset % chip->blocksize) || (eraselen % chip->blocksize)) {
+		nand_err("erase is not aligned (off 0x%llx, len 0x%llx)", offset, eraselen);
+		return -EINVAL;
+	}
+
+	page = (int)(offset / chip->pagesize);
+	chipnr = (int)(offset / chip->chipsize);
+
+	nand_debug("page:0x%x, chipnr:0x%x", page, chipnr);
+
+	chip->select_chip(chip, chipnr);
+
+	/* Check, if it is write protected */
+	if (mtk_nand_check_wp(chip)) {
+		ret = -EIO;
+		nand_err("write protected!");
+		goto err_out;
+	}
+
+	while (1) {
+		if (!force_erase && mtk_nand_block_checkbad(chip, page, allowbbt)) {
+			nand_err("attempt to erase bad block at page 0x%x", page);
+			ret = -EIO;
+			goto err_out;
+		}
+
+		nand_debug("[nand] erase page %d chip %d", 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 MTK_NAND_WORN_BAD_TEST
+		if (nand_check_erase_test_block((u32)offset / chip->blocksize)) {
+			nand_info("Simulate erase fail case at offset %x", (u32)offset);
+			ret = -EIO;
+		}
+#endif
+
+		if (status & NAND_STATUS_FAIL) {
+			ret = -EIO;
+			nand_err("erase failed at page 0x%x status:0x%x", 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_block(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops, int allowbbt)
+{
+	int ret;
+
+	mtk_nand_get_controller(chip);
+	ret = mtk_nand_do_erase_ops(chip, ops, allowbbt, 0);
+	mtk_nand_release_controller(chip);
+
+	return ret;
+}
+
+int mtk_nand_force_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, 1, 1);
+	mtk_nand_release_controller(chip);
+
+	return ret;
+}
+
+int mtk_nand_erase(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops)
+{
+	return mtk_nand_erase_block(chip, ops, 0);
+}
+
+int mtk_nand_init(struct mtk_nand_chip **ext_nand)
+{
+	struct mtk_nand_chip *chip;
+	int ret;
+
+	ret = mtk_nfc_nand_chip_init(ext_nand);
+
+	chip = *ext_nand;
+
+#if MTK_NAND_UNIT_TEST
+	mtk_nand_chip_test(chip);
+#endif
+	if (chip->scan_bbt)
+		ret = chip->scan_bbt(chip);
+
+	return ret;
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_nal.h b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_nal.h
new file mode 100644
index 0000000..6964f6f
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_nal.h
@@ -0,0 +1,298 @@
+/*
+ * 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 _MTK_NAND_NAL_H
+#define _MTK_NAND_NAL_H
+
+#include "mtk_nand_sys.h"
+#include "mtk_ecc_hal.h"
+
+/* Set nCE to low  to select the chip*/
+#define NAND_NCE        (1 << 0)
+/* Set CLE to high to select the command latch*/
+#define NAND_CLE        (1 << 1)
+/* Set ALE to high to select the address latch*/
+#define NAND_ALE        (1 << 2)
+
+#define NAND_CTRL_CLE       (NAND_CLE | NAND_NCE)
+#define NAND_CTRL_ALE       (NAND_ALE | NAND_NCE)
+#define NAND_CTRL_CHANGE    0x80
+
+/*
+ * NAND commands definition
+ */
+#define NAND_CMD_NONE       -1
+
+#define NAND_CMD_RESET      0xFF
+#define NAND_CMD_READID     0x90
+#define NAND_CMD_GET_FEATURES   0xEE
+#define NAND_CMD_SET_FEATURES   0xEF
+#define NAND_CMD_PARAM      0xEC
+
+#define NAND_CMD_ERASE1     0x60
+#define NAND_CMD_ERASE2     0xD0
+
+#define NAND_CMD_PAGEPROG   0x10
+#define NAND_CMD_CACHEDPROG 0x15
+
+#define NAND_CMD_READSTART  0x30
+#define NAND_CMD_READ0      0
+#define NAND_CMD_READ1      1
+#define NAND_CMD_READOOB    0x50
+
+#define NAND_CMD_STATUS     0x70
+
+#define NAND_CMD_RNDOUTSTART    0xE0
+#define NAND_CMD_RNDOUT     5
+
+#define NAND_CMD_SEQIN      0x80
+#define NAND_CMD_RNDIN      0x85
+
+#define NAND_CMD_LOCK       0x2A
+#define NAND_CMD_UNLOCK1    0x23
+#define NAND_CMD_UNLOCK2    0x24
+
+/*NAND status bit */
+#define NAND_STATUS_FAIL        (1 << 0)
+#define NAND_STATUS_FAIL_N1     (1 << 1)
+#define NAND_STATUS_TRUE_READY  (1 << 5)
+#define NAND_STATUS_READY       (1 << 6)
+#define NAND_STATUS_WP		(1 << 7)
+
+/* The length of ONFI subfeature parameters */
+#define ONFI_SUBFEATURE_PARAM_LEN	4
+
+/* MICRON IO Strength */
+#define IO_STR_MICRON_ADDR	0
+#define IO_STR_MICRON_FULL			0
+#define IO_STR_MICRON_THREE_QUARTER		1
+#define IO_STR_MICRON_ONE_HALF		2
+#define IO_STR_MICRON_ONE_QUARTER		3
+
+/* chip options definition */
+/*
+ * Some MLC NANDs need data scrambling to limit bitflips caused by repeated
+ * patterns.
+ */
+#define NAND_NEED_SCRAMBLING    0x00002000
+
+#define NAND_MAX_ID_LEN 8
+#define NAND_ID_VENDOR 0
+
+/*
+ * Definition for NAND Manufacturer ID Codes, ordered by their value
+ */
+#define NAND_MFR_AMD        0x01
+#define NAND_MFR_FUJITSU    0x04
+#define NAND_MFR_RENESAS    0x07
+#define NAND_MFR_STMICRO    0x20
+#define NAND_MFR_MICRON		0x2C
+#define NAND_MFR_SANDISK    0x45
+#define NAND_MFR_INTEL      0x89
+#define NAND_MFR_NATIONAL   0x8F
+#define NAND_MFR_EON        0x92
+#define NAND_MFR_TOSHIBA    0x98
+#define NAND_MFR_ATO        0x9B
+#define NAND_MFR_HYNIX      0xAD
+#define NAND_MFR_MACRONIX   0xC2
+#define NAND_MFR_SAMSUNG    0xEC
+#define NAND_MFR_WINBOND    0xEF
+
+struct mtk_nand_flash_dev {
+	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,
+};
+
+struct mtk_nand_ops {
+	u32 mode;
+	u64 offset;
+	u64 len;
+	u8 *datbuf;
+	/* ecc protected oob data */
+	u8 *oobeccbuf;
+	u32 oobecclen;
+	/* ecc unprotected oob data */
+	u8 *oobfreebuf;
+	u32 oobfreelen;
+};
+
+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 (*scan_bbt)(struct mtk_nand_chip *chip);
+
+	int (*block_bad)(struct mtk_nand_chip *chip, u64 ofs);
+	int (*block_markbad)(struct mtk_nand_chip *chip, u32 page);
+
+	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);
+
+	/* 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;
+	u8 bits_per_cell;
+	u32 page_per_chip;
+	u32 page_per_block;
+	int chip_delay;
+	u32 acctiming;
+	u32 options;
+	u8 numchips;
+	int activechip;
+
+	u8 *databuf;
+	u8 *oob_poi;
+
+	/* BBT related */
+	u32 bbt_options;
+	int badblockpos;
+	int badblockbits;
+	u32 bbt_erase_shift;
+
+	u8 *bbt;
+	struct mtk_nand_bbt_descr *bbt_td;
+	struct mtk_nand_bbt_descr *bbt_md;
+	struct mtk_nand_bbt_descr *badblock_pattern;
+
+	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[];
+
+extern int mtk_nand_erase(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops);
+extern int mtk_nand_erase_block(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops,
+				int allowbbt);
+extern int mtk_nand_force_erase(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops);
+extern int mtk_nand_write(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops);
+extern int mtk_nand_read(struct mtk_nand_chip *chip, struct mtk_nand_ops *ops);
+extern int mtk_nand_block_isbad(struct mtk_nand_chip *nand, u32 page);
+extern int mtk_nand_block_isbad_allowbbt(struct mtk_nand_chip *nand, u32 page);
+extern int mtk_nand_scan(struct mtk_nand_chip *chip, int maxchips);
+extern void lk_nand_irq_handler(unsigned int irq);
+extern int nand_get_alignment(void);
+extern int mtk_nand_init(struct mtk_nand_chip **ext_nand);
+extern int nand_check_erase_test_block(u32 block);
+extern int nand_check_program_test_page(u32 page);
+#endif
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_nftl.c b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_nftl.c
new file mode 100644
index 0000000..d11c668
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_nftl.c
@@ -0,0 +1,127 @@
+/*
+ * 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 <pow2.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "mtk_nand_nal.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.datbuf = 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.datbuf = 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(&chip);
+    if (ret) {
+        dprintf(CRITICAL, "nand device init error (%d)!\n", ret);
+        return ret;
+    }
+
+    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);
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_sys.c b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_sys.c
new file mode 100644
index 0000000..4b73135
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_sys.c
@@ -0,0 +1,319 @@
+/*
+ * 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 "mtk_nand_sys.h"
+
+/**
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+int nand_ffs(int x)
+{
+	int r = 1;
+
+	if (!x)
+		return 0;
+	if (!(x & 0xffff)) {
+		x >>= 16;
+		r += 16;
+	}
+	if (!(x & 0xff)) {
+		x >>= 8;
+		r += 8;
+	}
+	if (!(x & 0xf)) {
+		x >>= 4;
+		r += 4;
+	}
+	if (!(x & 3)) {
+		x >>= 2;
+		r += 2;
+	}
+	if (!(x & 1)) {
+		x >>= 1;
+		r += 1;
+	}
+	return r;
+}
+
+nand_time nand_current_time(void)
+{
+	return current_time();
+}
+
+void *nand_memalign(size_t boundary, size_t size)
+{
+	return memalign(boundary, size);
+}
+
+/*
+ * allocate memory and memset zero, see calloc
+ * @nmemb:  Number of element to allocate
+ * @size:   Size of each element
+ */
+void *nand_malloc(size_t size)
+{
+	return calloc(1, size);
+}
+
+/*
+ * Free a buffer allocated by os_calloc
+ * @buf:  Buffer to free. os_free will just return if it is NULL.
+ */
+void nand_free(void *buf)
+{
+	free(buf);
+}
+
+/* see memcpy */
+void *nand_memcpy(void *dest, const void *src, u64 n)
+{
+	return memcpy(dest, src, n);
+}
+
+/* see strncmp */
+int nand_strncmp(char const *cs, char const *ct, size_t count)
+{
+	return strncmp(cs, ct, count);
+}
+
+int nand_memcmp(const void *cs, const void *ct, size_t count)
+{
+	return memcmp(cs, ct, count);
+}
+
+/* see memset */
+void *nand_memset(void *s, int c, u64 n)
+{
+	return memset(s, c, n);
+}
+
+/* Abort the system. Should only be used when debug. */
+void nand_abort(char *s)
+{
+	panic("Nand abort: %s\n", s);
+}
+
+void nand_lock_init(nand_lock_t *m)
+{
+	mutex_init(m);
+}
+
+status_t nand_lock(nand_lock_t *m)
+{
+	return mutex_acquire(m);
+}
+
+status_t nand_unlock(nand_lock_t *m)
+{
+	return mutex_release(m);
+}
+
+void nand_init_completion(nand_completion_t *x)
+{
+	event_init(x, false, EVENT_FLAG_AUTOUNSIGNAL);
+}
+
+void nand_complete(nand_completion_t *x)
+{
+	event_signal(x, false);
+}
+
+status_t  nand_wait_for_completion_timeout(nand_completion_t *x, nand_time t)
+{
+	return event_wait_timeout(x, t);
+}
+
+u32 nand_kvaddr_to_paddr(const u8 *buf)
+{
+	u32 addr;
+
+#ifdef WITH_KERNEL_VM
+	addr = (u32)kvaddr_to_paddr(buf);
+#else
+	addr = (u32)buf;
+#endif
+	return addr;
+}
+
+u32 nand_dma_map(const u8 *buf, size_t len, bool flag, void *arg)
+{
+	if (flag)
+		arch_clean_cache_range((addr_t)buf, (size_t)len);
+	else
+		arch_clean_invalidate_cache_range((addr_t)buf, (size_t)len);
+	return 0;
+}
+
+void nand_dma_unmap(const u8 *buf, size_t len, bool flag, void *arg)
+{
+	if (flag)
+		arch_clean_cache_range((addr_t)buf, (size_t)len);
+	else
+		arch_clean_invalidate_cache_range((addr_t)buf, (size_t)len);
+}
+#if 1
+void nand_gpio_cfg_bit32(u64 addr, u32 field , u32 val)
+{
+	u32 tv = (unsigned int)(*(volatile u32*)(addr));
+	tv &= ~(field);	tv |= val;
+	(*(volatile u32*)(addr) = (u32)(tv));
+}
+
+#define NFI_GPIO_CFG_BIT32(reg,field,val)   nand_gpio_cfg_bit32(reg, field, val)
+
+void mtk_nfc_gpio_init(void)
+{
+/* Nand GPIO register define */
+#define NFI_GPIO_BASE               (IO_PHYS+0x5000)
+/* For NFI GPIO setting *//* NCLE */
+#define NFI_GPIO_MODE1              (NFI_GPIO_BASE + 0x300)
+/* NCEB1/NCEB0/NREB */
+#define NFI_GPIO_MODE2              (NFI_GPIO_BASE + 0x310)
+/* NRNB/NREB_C/NDQS_C */
+#define NFI_GPIO_MODE3              (NFI_GPIO_BASE + 0x320)
+#define NFI_GPIO_PUPD_CTRL0         (NFI_GPIO_BASE + 0xE00)
+#define NFI_GPIO_PUPD_CTRL1         (NFI_GPIO_BASE + 0xE10)
+#define NFI_GPIO_PUPD_CTRL2         (NFI_GPIO_BASE + 0xE20)
+#define NFI_GPIO_PUPD_CTRL6         (NFI_GPIO_BASE + 0xE60)
+/* Drving */
+#define NFI_GPIO_DRV_MODE0          (NFI_GPIO_BASE + 0xD00)
+#define NFI_GPIO_DRV_MODE6          (NFI_GPIO_BASE + 0xD60)
+#define NFI_GPIO_DRV_MODE7          (NFI_GPIO_BASE + 0xD70)
+//TDSEL,
+#define NFI_GPIO_TDSEL6_EN          (NFI_GPIO_BASE + 0xB60)
+#define NFI_GPIO_TDSEL7_EN          (NFI_GPIO_BASE + 0xB70)
+//RDSEL, no need for 1.8V
+#define NFI_GPIO_RDSEL1_EN          (NFI_GPIO_BASE + 0xC10)
+#define NFI_GPIO_RDSELE_EN          (NFI_GPIO_BASE + 0xCE0)
+#define NFI_GPIO_RDSELF_EN          (NFI_GPIO_BASE + 0xCF0)
+
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_MODE1, 0x7FFF,
+		(1 << 0) | (1 << 3) | (1 << 6) | (2 << 9) | (2  << 12));
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_MODE2, 0x7FFF,
+		(2 << 0) | (2 << 3) | (2 << 6) | (2 << 9) | (2 << 12));
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_MODE3, 0xFFF,
+		(2 << 0) | (2 << 3) | (2 << 6) | (2 << 9));
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_PUPD_CTRL6, (0xFFF << 4), (0x111 << 4));
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_PUPD_CTRL1, 0xFFFF, 0x6666);
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_PUPD_CTRL2, 0xFFF, 0x616);
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_PUPD_CTRL0, 0xFFFF, 0x6666);
+	/*only for 3.3V */
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_DRV_MODE6, (0xFF << 8), (0x11 << 8));
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_DRV_MODE7, 0xFFF, 0x111);
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_TDSEL6_EN, (0xFF << 8), (0xAA << 8));
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_TDSEL7_EN, 0xFFF, 0xAAA);
+	/*only for 3.3v */
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_RDSEL1_EN, (0x3F << 6), (0xC << 6));
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_RDSELE_EN, 0x3F3F, 0xC0C);
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_RDSELF_EN, 0x3F3F, 0xC0C);
+}
+#else
+void nand_gpio_cfg_bit32(u32 addr, u32 field , u32 val)
+{
+	u32 tv = (unsigned int)(*(volatile u32*)(addr));
+	tv &= ~(field);
+	tv |= val;
+	(*(volatile u32*)(addr) = (u32)(tv));
+}
+
+void nand_gpio_set_field(u32 reg, u32 field, u32 val)
+{
+	u32 tv = (u32)(*(volatile u32*)(reg));
+	tv &= ~(field);
+	tv |= ((val) << (uffs((unsigned short)(field)) - 1));
+	(*(volatile u32*)(reg) = (u32)(tv));
+}
+
+#define NFI_GPIO_CFG_BIT32(reg,field,val)   nand_gpio_cfg_bit32(reg, field, val)
+
+int mtk_nfc_gpio_init(void)
+{
+	/* Enable Pinmux Function setting */
+	/* NCLE */
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_MODE3, (0x7 << 12), (0x6 << 12));
+	/* NCEB1/NCEB0/NREB */
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_MODE4, (0x1FF << 0), (0x1B6 << 0));
+	/* NRNB/NREB_C/NDQS_C */
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_MODE5, (0x1FF << 3), (0x1B1 << 3));
+	/* NLD7/NLD6/NLD4/NLD3/NLD0 */
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_MODE17, (0x7FFF << 0), (0x4924 << 0));
+	/* NALE/NWEB/NLD1/NLD5/NLD8, NLD8 for NDQS */
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_MODE18, (0x7FFF << 0), (0x4924 << 0));
+	/* NLD2 */
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_MODE19, (0x7 << 0), (0x5 << 0));
+
+	/* PULL UP setting */
+	/* PD, NCEB0, NCEB1, NRNB
+	NFI_GPIO_CFG_BIT32(NFI_GPIO_PULLUP, (0xF0FF << 0), (0x1011 << 0));
+
+	/* Driving setting */
+	if (NFI_EFUSE_Is_IO_33V()) {
+		NFI_GPIO_CFG_BIT32(NFI_GPIO_DRV_MODE0, (0xF << 12), (0x2 << 12));
+		NFI_GPIO_CFG_BIT32(NFI_GPIO_DRV_MODE6, (0xFF << 8), (0x22 << 8));
+		NFI_GPIO_CFG_BIT32(NFI_GPIO_DRV_MODE7, (0xFF << 0), (0x22 << 0));
+	} else {
+		NFI_GPIO_CFG_BIT32(NFI_GPIO_DRV_MODE0, (0xF << 12), (0x4 << 12));
+		NFI_GPIO_CFG_BIT32(NFI_GPIO_DRV_MODE6, (0xFF << 8), (0x44 << 8));
+		NFI_GPIO_CFG_BIT32(NFI_GPIO_DRV_MODE7, (0xFF << 0), (0x44 << 0));
+	}
+
+	/* TDSEL, No need */
+
+	/* RDSEL, only need for 3.3V */
+	if (NFI_EFUSE_Is_IO_33V()) {
+		NFI_GPIO_CFG_BIT32(NFI_GPIO_RDSEL1_EN, (0x3F << 6), (0xC << 6));
+		NFI_GPIO_CFG_BIT32(NFI_GPIO_RDSEL6_EN, (0xFFF << 0), (0x30C << 0));
+		NFI_GPIO_CFG_BIT32(NFI_GPIO_RDSEL7_EN, (0xFFF << 0), (0x30C << 0));
+	}
+
+	return 0;
+}
+#endif
+
+int mtk_nfc_clock_init(void)
+{
+	u32 reg;
+
+	reg = *((volatile u32*)NFC_CLOCK_ADDR);
+	reg &= 0xffffff00;
+	reg |= 0x00000052;
+	*((volatile u32*)NFC_CLOCK_ADDR) = reg;
+
+	return 0;
+}
+
+/*
+int mtk_nand_request_irq(unsigned int vector, int_handler handler, void *arg)
+{
+	mt_irq_set_sens(vector, LEVEL_SENSITIVE);
+	mt_irq_set_polarity(vector, MT65xx_POLARITY_LOW);
+	register_int_handler(vector, handler, arg);
+	unmask_interrupt(vector);
+
+	return 0;
+}*/
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_sys.h b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_sys.h
new file mode 100644
index 0000000..9c3e0f2
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_sys.h
@@ -0,0 +1,294 @@
+/*
+ * 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 _MTK_NAND_SYS_H_
+#define _MTK_NAND_SYS_H_
+
+/* System related head file*/
+#include <platform/mt_irq.h>
+#include <platform/interrupts.h>
+#include <platform/mt_reg_base.h>
+#include <platform/timer.h>
+#include <platform/mtk_timer.h>
+#include <kernel/mutex.h>
+#include <kernel/event.h>
+#include <arch/ops.h>
+#include <sys/types.h>
+#include <platform.h>
+#include <reg.h>
+#include <string.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <kernel/vm.h>
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#include <partition.h>
+#endif
+#include <debug.h>
+
+#define MT8518_NFI
+
+/* Error codes */
+#ifndef EIO
+#define EIO      5  /* I/O error */
+#define ENOMEM      12  /* Out of memory */
+#define EFAULT      14  /* Bad address */
+#define EBUSY       16  /* Device or resource busy */
+#define EINVAL      22  /* Invalid argument */
+#define ENOSPC      28  /* No space left on device */
+#define EBADMSG     77  /* Trying to read unreadable message */
+#define ETIMEDOUT   110 /* Connection timed out */
+#endif
+
+/* Data types define */
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+#ifndef loff_t
+typedef u64 loff_t;
+#endif
+#ifndef status_t
+typedef int status_t;
+#endif
+#ifndef bool
+typedef char bool;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef false
+#define false 0
+#define true 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+
+#ifndef BUG_ON
+#define BUG_ON(cond)    assert(!(cond))
+#endif
+
+/* Common define */
+#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 ALIGN(S,A) ((S + A) & ~(A))
+
+#define max(a, b)       (a > b ? a : b)
+#define min(a, b)       (a > b ? b : a)
+//#define clamp(val, lo, hi)  min((typeof(val))max(val, lo), hi)
+
+#if 0//ndef containerof
+#define containerof(ptr, type, member) \
+    ((type *)((unsigned long)(ptr) - __builtin_offsetof(type, member)))
+#endif
+
+#define MTK_NAND_TIMEOUT        (500000)
+
+#define KB(x)           ((x) * 1024UL)
+#define MB(x)           (KB(x) * 1024UL)
+
+/*
+ * 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 nand_time size_t
+nand_time nand_current_time(void);
+
+#define check_with_timeout(cond, timeout)                   \
+({                                  \
+    nand_time __ret;                            \
+    if (cond) {                         \
+         __ret = timeout;                       \
+    } else {                                \
+        nand_time __end = nand_current_time() + timeout;        \
+                                    \
+        for (;;) {                          \
+            nand_time __now = nand_current_time();      \
+                                    \
+            if (cond) {                 \
+                __ret = (__end > __now) ? (__end - __now) : 1;  \
+                break;                  \
+            }                       \
+                                    \
+            if (__end <= __now) {               \
+                __ret = 0;              \
+                break;                  \
+            }                       \
+        }                           \
+    }                               \
+    __ret;                              \
+})
+
+//#define swap(a, b) \
+ //   do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while(0)
+
+/* system API related, need porting for different system, such as PL/LK/kernel, etc. */
+extern int nand_ffs(int x);
+extern void *nand_memalign(size_t boundary, size_t size);
+extern void *nand_malloc(size_t size);
+extern void nand_free(void *buf);
+extern int nand_strncmp(char const *cs, char const *ct, size_t count);
+extern int nand_memcmp(const void *cs, const void *ct, size_t count);
+extern void *nand_memcpy(void *dest, const void *src, u64 n);
+extern void *nand_memset(void *s, int c, u64 n);
+extern void nand_abort(char *s);
+
+/* Mutex/lock related */
+#define nand_lock_t mutex_t
+extern void nand_lock_init(nand_lock_t *m);
+extern status_t nand_lock(nand_lock_t *m);
+extern status_t nand_unlock(nand_lock_t *m);
+
+/* completion related */
+#define nand_completion_t   event_t
+extern void nand_init_completion(nand_completion_t *x);
+extern void nand_complete(nand_completion_t *x);
+extern status_t  nand_wait_for_completion_timeout(nand_completion_t *x, nand_time t);
+
+/* DMA related */
+extern u32 nand_kvaddr_to_paddr(const u8 *buf);
+extern u32 nand_dma_map(const u8 *buf, size_t len, bool flag, void *arg);
+extern void nand_dma_unmap(const u8 *buf, size_t len, bool flag, void *arg);
+#define mtk_nand_udelay(a)      udelay(a)
+#define mtk_nand_mdelay(a)  mdelay(a)
+
+/* Nand print info related */
+#define NAND_DEBUG_FLAG 0
+/* Nand debug messages */
+#if NAND_DEBUG_FLAG
+#define nand_debug(fmt, ...) dprintf(INFO, "NAND debug::%s %d: " fmt "\n",      \
+    __func__, __LINE__,  ##__VA_ARGS__)
+#else
+#define nand_debug(fmt, ...)    do {} while (0)
+#endif
+/* Nand info messages */
+#define nand_info(fmt, ...) dprintf(INFO, "NAND INFO:%s %d: " fmt "\n",      \
+    __func__, __LINE__,  ##__VA_ARGS__)
+/* Nand error messages */
+#define nand_err(fmt, ...) dprintf(INFO, "NAND ERROR:%s %d: " fmt "\n",      \
+    __func__, __LINE__,  ##__VA_ARGS__)
+
+/* Nand register RW function re-define */
+#define nand_readb(a)   (*(volatile u8 * const)(a))
+#define nand_readw(a)   (*(volatile u16 * const)(a))
+#define nand_readl(a)   (*(volatile u32 * const)(a))
+
+#define nand_writeb(v, a)   (*(volatile u8 * const)(a)) = (v)
+#define nand_writew(v, a)  (*(volatile u16 * const)(a)) = (v)
+#define nand_writel(v, a)   (*(volatile u32 * const)(a)) = (v)
+
+/* Nand Base register define */
+#define NAND_NFI_BASE       NFI_BASE
+#define NAND_NFIECC_BASE    NFIECC_BASE
+//#define NAND_DRAM_BASE_VIRT DRAM_BASE_VIRT
+//#define NAND_NFI_IRQ_BIT_ID NFI_IRQ_BIT_ID
+//#define NAND_NFIECC_IRQ_BIT_ID  NFIECC_IRQ_BIT_ID
+
+#define NAND_IRQ_NONE       INT_NO_RESCHEDULE
+#define NAND_IRQ_HANDLED    INT_RESCHEDULE
+
+/* reserve 1M dram buffer for system memory issue */
+#define NAND_DRAM_BUF_DATABUF_ADDR  (NAND_BUF_ADDR)
+#define NAND_DRAM_BUF_DATABUF_SIZE  (4096+256)
+#define NAND_DRAM_BUF_NFCBUF_ADDR   (NAND_DRAM_BUF_DATABUF_ADDR + NAND_DRAM_BUF_DATABUF_SIZE)
+#define NAND_DRAM_BUF_NFCBUF_SIZE   (4096+256)
+#define NAND_DRAM_BUF_ECCDE_ADDR    (NAND_DRAM_BUF_NFCBUF_ADDR + NAND_DRAM_BUF_NFCBUF_SIZE)
+#define NAND_DRAM_BUF_ECCDE_SIZE    (4096+256)
+#define NAND_DRAM_BUF_ECCEN_ADDR    (NAND_DRAM_BUF_ECCDE_ADDR + NAND_DRAM_BUF_ECCDE_SIZE)
+#define NAND_DRAM_BUF_ECCEN_SIZE    (4096+256)
+#define NAND_DRAM_BUF_BAD_MAP_ADDR  (NAND_DRAM_BUF_ECCEN_ADDR + NAND_DRAM_BUF_ECCEN_SIZE)
+#define NAND_DRAM_BUF_BAD_MAP_SIZE  (16384)
+
+/* Nand EFUSE register define */
+#define EFUSE_RANDOM_CFG    ((volatile u32 *)(IO_PHYS+0x9020))
+#define EFUSE_RANDOM_ENABLE 0x00001000
+
+#if 0
+#define NFI_EFUSE_M_SW_RES  ((volatile u32 *)(IO_PHYS+0x9000 + 0x0120))
+#define NFI_EFUSE_IO_33V    0x00000100
+#define NFI_EFUSE_Is_IO_33V()   (((*NFI_EFUSE_M_SW_RES)&NFI_EFUSE_IO_33V)?FALSE:TRUE)
+
+/* Nand GPIO register define */
+#define NFI_GPIO_BASE               (IO_PHYS+0x5000)
+
+
+/*******************************************************************************
+ * GPIO(PinMux) register definition
+ *******************************************************************************/
+/* For NFI GPIO setting */
+/* NCLE */
+#define NFI_GPIO_MODE3              (NFI_GPIO_BASE + 0x320)
+/* NCEB1/NCEB0/NREB */
+#define NFI_GPIO_MODE4              (NFI_GPIO_BASE + 0x330)
+/* NRNB/NREB_C/NDQS_C */
+#define NFI_GPIO_MODE5              (NFI_GPIO_BASE + 0x340)
+/* NLD7/NLD6/NLD4/NLD3/NLD0 */
+#define NFI_GPIO_MODE17             (NFI_GPIO_BASE + 0x460)
+/* NALE/NWEB/NLD1/NLD5/NLD8    (NLD8--->NDQS) */
+#define NFI_GPIO_MODE18             (NFI_GPIO_BASE + 0x470)
+/* NLD2 */
+#define NFI_GPIO_MODE19             (NFI_GPIO_BASE + 0x480)
+
+/* PD, NCEB0/NCEB1/NRNB */
+#define NFI_GPIO_PULLUP             (NFI_GPIO_BASE + 0xE60)
+
+/* Drving */
+#define NFI_GPIO_DRV_MODE0      (NFI_GPIO_BASE + 0xD00)
+#define NFI_GPIO_DRV_MODE6      (NFI_GPIO_BASE + 0xD60)
+#define NFI_GPIO_DRV_MODE7      (NFI_GPIO_BASE + 0xD70)
+
+/* TDSEL, no need */
+
+/* RDSEL, no need for 1.8V */
+#define NFI_GPIO_RDSEL1_EN      (NFI_GPIO_BASE + 0xC10)
+#define NFI_GPIO_RDSEL6_EN      (NFI_GPIO_BASE + 0xC60)
+#define NFI_GPIO_RDSEL7_EN      (NFI_GPIO_BASE + 0xC70)
+#endif
+
+extern void mtk_nfc_gpio_init(void);
+
+/* Nand CLK register define */
+#define NFC_CLOCK_ADDR (IO_PHYS + 0x4)
+extern int mtk_nfc_clock_init(void);
+//extern int mtk_nand_request_irq(unsigned int vector, int_handler handler, void *arg);
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_test.c b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_test.c
new file mode 100644
index 0000000..5fc2abb
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_test.c
@@ -0,0 +1,132 @@
+/*
+ * 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 "mtk_nand_nal.h"
+#include "mtk_nand_sys.h"
+#include "mtk_nand_test.h"
+
+#if MTK_NAND_UNIT_TEST
+void mtk_nand_chip_test(struct mtk_nand_chip *chip)
+{
+	struct mtk_nand_ops ops;
+	u8 *buf_w, *buf_r;
+	int total_block, i, j;
+	int ret = 0;
+
+	total_block = chip->totalsize/chip->blocksize;
+	nand_info("mtk_nand_unit_test start total_block: %d", total_block);
+
+	buf_w = nand_malloc(chip->pagesize * 2);
+	if (buf_w == NULL) {
+		nand_err("malloc buf_w failed: %d \n", chip->pagesize);
+		return;
+	}
+
+	buf_r = nand_malloc(chip->pagesize * 2);
+	if (buf_r == NULL) {
+		nand_err("malloc buf_r failed: %d \n", chip->pagesize);
+		return;
+	}
+
+	for (i = 0; i < chip->pagesize*2; i++)
+		buf_w[i] = i;
+
+	for (i = 0; i < 10; i++) {
+	//for (i = total_block-1; ; i--) {
+
+		if (mtk_nand_block_isbad(chip, i*chip->page_per_block)) {
+			nand_info("check bad blk: %d", i);
+			//continue;
+		}
+
+		nand_info("test blk: %d", i);
+		nand_memset(&ops, 0, sizeof(ops));
+		ops.mode = NAND_OPS_ERASE_POLL;
+		ops.offset = (u64)(i * chip->blocksize);
+		ops.len = chip->blocksize;
+
+		ret = mtk_nand_erase(chip, &ops);
+		if (ret) {
+			nand_err("Erase failed at blk: %d", i);
+			continue;
+		}
+#if MTK_NAND_ERASE_TEST
+		for (j = i*chip->page_per_block;
+		        j < i*chip->page_per_block+ chip->page_per_block; j++) {
+
+			nand_memset(&ops, 0, sizeof(ops));
+			ops.mode = NAND_OPS_ECC_DMA_POLL;
+			ops.offset = (u64)(j * chip->pagesize);
+			ops.len = (u64)chip->pagesize;
+			ops.datbuf = buf_w;
+
+			ret = mtk_nand_write(chip, &ops);
+			if (ret) {
+				nand_err("Write failed at blk:%d, page:%d", i, j);
+				break;
+			}
+
+			nand_memset(&ops, 0, sizeof(ops));
+			nand_memset(buf_r, 0x5A, chip->pagesize);
+			ops.mode = NAND_OPS_ECC_DMA_POLL;
+			ops.offset = (u64)(j * chip->pagesize);
+			ops.len = (u64)chip->pagesize;
+			ops.datbuf = buf_r;
+
+			ret = mtk_nand_read(chip, &ops);
+			if (ret) {
+				nand_err("Read failed at blk:%d page:%d", i, j);
+				break;
+			}
+
+			/* compare the read buf and write buf */
+			if (nand_memcmp(buf_r, buf_w, chip->pagesize)) {
+				nand_err("compare failed! addr:0x%x, buf_r:0x%x, %x, %x, %x, %x buf_w:0x%x, %x, %x, %x, %x", 
+				(int)ops.offset, buf_r[0], buf_r[1], buf_r[2], buf_r[3], buf_r[4]
+				, buf_w[0], buf_w[1], buf_w[2], buf_w[3], buf_w[4]);
+			}
+		}
+
+		nand_memset(&ops, 0, sizeof(ops));
+		ops.mode = NAND_OPS_ERASE_POLL;
+		ops.offset = (u64)(i * chip->blocksize);
+		ops.len = chip->blocksize;			
+		ret = mtk_nand_erase(chip, &ops);
+		if (ret) {
+			nand_err("Erase failed at blk: %d", i);
+			continue;
+		}			
+#endif
+		//if(i == 0)
+		//	break;
+	}
+
+	nand_info("mtk_nand_chip_test start end");
+
+	if (buf_r != NULL)
+		nand_free(buf_r);
+	if (buf_w != NULL)
+		nand_free(buf_w);
+
+}
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_test.h b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_test.h
new file mode 100644
index 0000000..72a5673
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nand_test.h
@@ -0,0 +1,55 @@
+/*
+ * 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 _MTK_NAND_TEST_H_
+#define _MTK_NAND_TEST_H_
+
+#define MTK_NAND_UNIT_TEST  0
+
+/*
+ * Code for runtime worn bad block test will be built in
+ * if enable this config
+*/
+#define MTK_NAND_WORN_BAD_TEST 0
+
+/*
+ * For NAND erase all include BBT blocks
+ */
+#define MTK_NAND_ERASE_ALL 1
+
+/* Test to create BBT */
+#define MTK_NAND_CREATE_BBT_TEST 1
+
+/* Read BBT test */
+#define MTK_NAND_READ_BBT_TEST 1
+
+/* Bit error test */
+#define MTK_NAND_BIT_ERROR_TEST 1
+
+#if MTK_NAND_UNIT_TEST
+#define MTK_NAND_ERASE_TEST 1
+
+extern void mtk_nand_chip_test(struct mtk_nand_chip *chip);
+#endif
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nfi_hal.c b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nfi_hal.c
new file mode 100644
index 0000000..e2ef790
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nfi_hal.c
@@ -0,0 +1,1853 @@
+/*
+ * 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 "mtk_nfi_hal.h"
+#include "mtk_nand_bbt.h"
+#include "mtk_nand_sys.h"
+
+/* NAND controller register definition */
+#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_READ        (1 << 12)
+#define     CNFG_OP_PROGRAM     (3 << 12)
+#define     CNFG_OP_CUST        (6 << 12)
+#define     CNFG_OP_MASK        (7 << 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)
+/* NFI control */
+#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)
+/* Timming control register */
+#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_DEBUG_CON1      (0x220)
+#define     BYPASS_MASTER_EN    NAND_BIT(15)
+#define     STROBE_SEL_SHIFT	(3)
+#define     STROBE_SEL_MASK	(0x7 << STROBE_SEL_SHIFT)
+#define NFI_MASTER_STA      (0x224)
+#define     MASTER_STA_MASK     (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 NFI_EMPTY_THRESH    (0x23c)
+#define NFI_SNAND_CNFG      (0x55c)
+
+#define MTK_RESET_TIMEOUT   (1000000)
+#define MTK_MAX_SECTOR      (16)
+#define MTK_NAND_MAX_NSELS  (2)
+
+void swap(char *x, char *y)
+{
+        char tmp;
+        tmp = *x;
+        *x = *y;
+        *y = tmp;
+}
+
+u32 clamp(u32 fValue, u32 fMin, u32 fMax)
+{
+        return fValue > fMax ? fMax : (fValue < fMin ? fMin : fValue);
+}
+
+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, int 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 *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 void nfi_writel(struct mtk_nfc *nfc, u32 val, u32 reg)
+{
+	//nand_debug("val:0x%x, reg:0x%x nfc->regs:%x", val, reg, nfc->regs);
+	nand_writel(val, nfc->regs + reg);
+	//nand_debug("val:0x%x, reg:0x%x", val, reg);
+}
+
+static inline void nfi_writew(struct mtk_nfc *nfc, u16 val, u32 reg)
+{
+	//nand_debug("val:0x%x, reg:0x%x nfc->regs:%x", val, reg, nfc->regs);
+	nand_writew(val, nfc->regs + reg);
+	//nand_debug("val:0x%x, reg:0x%x nfc->regs:%x", val, reg, nfc->regs);	
+}
+
+static inline void nfi_writeb(struct mtk_nfc *nfc, u8 val, u32 reg)
+{
+	//nand_debug("val:0x%x, reg:0x%x nfc->regs:%x", val, reg, nfc->regs);
+	nand_writeb(val, nfc->regs + reg);
+}
+
+static inline u32 nfi_readl(struct mtk_nfc *nfc, u32 reg)
+{
+	//nand_debug("reg:0x%x nfc->regs:%x", reg, nfc->regs);
+
+	return nand_readl(nfc->regs + reg);
+}
+
+static inline u16 nfi_readw(struct mtk_nfc *nfc, u32 reg)
+{
+	//nand_debug("reg:0x%x nfc->regs:%x", reg, nfc->regs);
+	return nand_readw(nfc->regs + reg);
+}
+
+static inline u8 nfi_readb(struct mtk_nfc *nfc, u32 reg)
+{
+	//nand_debug("reg:0x%x nfc->regs:%x", reg, nfc->regs);
+	return nand_readb(nfc->regs + reg);
+}
+
+static void mtk_nfc_dump_reg(struct mtk_nfc *nfc)
+{
+	u32 i;
+
+	nand_info("nfi and nfiecc registers");
+	for (i = 0; i < 0x2000; i+=4) {
+		if (!(i % 16))
+			nand_info("\n0x%x: ", i);
+		nand_info("%x", nfi_readl(nfc, i));
+	}
+
+	nand_info("nfi clock setting");
+	nand_info("0x10000004 = 0x%x", *((volatile u32*)0x10000004));
+	nand_info("0x1000007c = 0x%x", *((volatile u32*)0x1000007c));
+	nand_info("0x10000024 = 0x%x", *((volatile u32*)0x10000024));
+	nand_info("0x1000003c = 0x%x", *((volatile u32*)0x1000003c));
+	nand_info("0x10000070 = 0x%x", *((volatile u32*)0x10000070));
+
+	nand_info("nfi gpio setting");
+	nand_info("0x10005320 = 0x%x", *((volatile u32*)0x10005320));
+	nand_info("0x10005330 = 0x%x", *((volatile u32*)0x10005330));
+	nand_info("0x10005340 = 0x%x", *((volatile u32*)0x10005340));
+	nand_info("0x10005460 = 0x%x", *((volatile u32*)0x10005460));
+	nand_info("0x10005470 = 0x%x", *((volatile u32*)0x10005470));
+	nand_info("0x10005480 = 0x%x", *((volatile u32*)0x10005480));
+	nand_info("0x10005e60 = 0x%x", *((volatile u32*)0x10005e60));
+	nand_info("0x10005d00 = 0x%x", *((volatile u32*)0x10005d00));
+	nand_info("0x10005d60 = 0x%x", *((volatile u32*)0x10005d60));
+	nand_info("0x10005d70 = 0x%x", *((volatile u32*)0x10005d70));
+	nand_info("0x10005c10 = 0x%x", *((volatile u32*)0x10005c10));
+	nand_info("0x10005c60 = 0x%x", *((volatile u32*)0x10005c60));
+	nand_info("0x10005c70 = 0x%x", *((volatile u32*)0x10005c70));
+
+}
+
+static void mtk_nfc_hw_reset(struct mtk_nfc *nfc)
+{
+	//nand_debug("enter");
+
+	/* 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))
+		nand_err("NFI HW reset timeout!");
+
+	/* 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);
+
+	//nand_debug("end");
+
+}
+
+/* Randomizer define */
+#define SS_SEED_NUM     128
+#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)
+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, 0x484F, 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)
+{
+	#ifdef MT8518_NFI
+	chip->options &= ~(NAND_NEED_SCRAMBLING);
+	#else
+	/* check whether randomizer efuse is on */
+	if ((*EFUSE_RANDOM_CFG) & EFUSE_RANDOM_ENABLE)
+		chip->options |= NAND_NEED_SCRAMBLING;
+	#endif
+}
+
+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;
+	u32 loop = SS_SEED_NUM;
+
+	if (!(chip->options & NAND_NEED_SCRAMBLING))
+		return;
+
+	/* nand_debug("page:0x%x repage %d", page, repage); */
+
+	mtk_nfc_hw_reset(nfc);
+
+	/* 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 */
+	if (chip->page_per_block <= SS_SEED_NUM)
+		loop = chip->page_per_block;
+	reg = (ss_randomizer_seed[page % loop] & RAN_SEED_MASK) << RAND_SEED_SHIFT(rand);
+	reg |= RAND_EN(rand);
+
+	nfi_writel(nfc, reg, NFI_RANDOM_CNFG);
+}
+
+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);
+
+	mtk_nfc_hw_reset(nfc);
+}
+
+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_NAND_TIMEOUT))
+		nand_err("send cmd 0x%x timeout", 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_NAND_TIMEOUT))
+		nand_err("send cmd 0x%x timeout", addr);
+
+	return 0;
+}
+
+static int mtk_nfc_irq_wait(struct mtk_nfc *nfc, u32 timeout)
+{
+	int ret;
+
+	ret = nand_wait_for_completion_timeout(&nfc->done, timeout);
+	if (ret != 0) {
+		nand_err("failed to get event INT=0x%x",
+		         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 NAND_IRQ_NONE;
+
+	nfi_writew(nfc, ~sta & ien, NFI_INTR_EN);
+
+	/* MUST BE *false*! otherwise, schedule in interrupt */
+	nand_complete(&nfc->done);
+
+	return NAND_IRQ_HANDLED;
+}
+
+static int mtk_nfc_request_irq(struct mtk_nfc *nfc)
+{
+	nand_init_completion(&nfc->done);
+	//mtk_nand_request_irq(NAND_NFI_IRQ_BIT_ID, &mtk_nfc_interrupt_handler, nfc);
+	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;
+
+	/* nand_debug("spare_per_sector:%d, ecc_size:%d, acctiming:0x%x",
+		mtk_nand->spare_per_sector, mtk_nand->fdm.ecc_size, mtk_nand->acctiming); */
+
+	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:
+			nand_err("invalid page len: %d", 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:
+			nand_err("invalid spare per sector %d", 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(chip_num > 0)
+		nand_info("chip_num:%d", chip_num);
+
+	if (!mtk_nfc_hw_runtime_config(chip)) {
+		chip->activechip = chip_num;
+	}
+
+	nfi_writel(nfc, chip_num, NFI_CSEL);
+}
+
+static int mtk_nfc_dev_ready(struct mtk_nand_chip *chip)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+	//nand_debug("0x%x", nfi_readl(nfc, NFI_STA));
+
+	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_NAND_TIMEOUT);
+	if (!ret) {
+		nand_err("wait busy interrupt timeout");
+		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;
+
+	//nand_debug("ctrl:0x%x dat:0x%x", ctrl, dat);
+	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);
+	}
+
+	//nand_debug("ctrl:0x%x dat:0x%x", ctrl, dat);
+
+}
+
+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_NAND_TIMEOUT)) {
+		nand_err("data not ready");
+		nand_err("cntr 0x%x cnfg 0x%x fmt 0x%x con 0x%x",
+		         nfi_readl(nfc, NFI_BYTELEN), nfi_readl(nfc, NFI_CNFG),
+		         nfi_readl(nfc, NFI_PAGEFMT), nfi_readl(nfc, NFI_CON));
+	}
+}
+
+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);
+}
+
+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);
+}
+
+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]);
+}
+
+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 */
+}
+
+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, buf + bad_pos);
+}
+
+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;
+	int i, ret;
+
+	start = offset / chip->ecc_size;
+	end = DIV_ROUND_UP(offset + len, chip->ecc_size);
+
+	nand_memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+	for (i = 0; i < chip->ecc_steps; i++) {
+		nand_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);
+
+		nand_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 i;
+
+	nand_memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+	for (i = 0; i < chip->ecc_steps; i++) {
+		if (buf)
+			nand_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);
+
+		nand_memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
+	}
+}
+
+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;
+	u8 *oobptr;
+	u32 i, j;
+
+	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);
+	}
+}
+
+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;
+	u8 *oobptr;
+	u32 i, j;
+
+	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));
+	}
+}
+
+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;
+	u32 addr, reg, i;
+	u32 data_len = chip->ecc_size;
+	int ret = 0, byterw;
+
+	addr = nand_kvaddr_to_paddr(buf);
+	if (dma) {
+		reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AHB | CNFG_DMA_BURST_EN;
+		nfi_writew(nfc, reg, NFI_CNFG);
+		nand_dma_map(buf, len, true, NULL);
+	}
+
+	nfi_writel(nfc, chip->ecc_steps << CON_SEC_SHIFT, NFI_CON);
+	nfi_writel(nfc, 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)) {
+#ifdef MTK_NAND_IRQ_EN
+		ret = mtk_nfc_irq_wait(nfc, MTK_NAND_TIMEOUT);
+#endif
+		if (!ret) {
+			nand_err("program ahb done timeout");
+			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_NAND_TIMEOUT))
+		nand_err("do page write timeout");
+
+timeout:
+	if (dma)
+		nand_dma_unmap(buf, len, false, NULL);
+
+	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;
+		}
+
+		nand_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;
+	int rc, i;
+
+	rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
+	if (rc) {
+		chip->stats.empty = 1;
+		nand_memset(buf, 0xff, sectors * chip->ecc_size);
+		for (i = 0; i < sectors; i++)
+			nand_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;
+	u32 addr, 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);
+
+	addr = nand_kvaddr_to_paddr(buf);
+
+	chip->stats.empty = 0;
+
+	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) {
+			nand_err("ecc enable failed");
+			/* 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);
+			/* error handle */
+			return rc;
+		}
+	} else {
+		nfi_writew(nfc, reg, NFI_CNFG);
+	}
+
+	if (dma)
+		nand_dma_map(buf, len, false, NULL);
+
+	nfi_writel(nfc, sectors << CON_SEC_SHIFT, NFI_CON);
+	nfi_writel(nfc, 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) {
+					nand_info("sectoer %d uncorrect", i);
+				}
+			}
+		}
+		if (!raw) {
+			bitflips = stats.bitflips;
+			rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
+			if (rc) {
+				nand_info("page %d is empty", page);
+				nand_memset(buf, 0xff, sectors * mtk_data_len(chip));
+				bitflips = 0;
+				chip->stats.corrected = correct;
+				chip->stats.failed = fail;
+				chip->stats.empty = 1;
+			}
+		}
+	}
+
+	if (dma && (!polling)) {
+		rc = mtk_nfc_irq_wait(nfc, MTK_NAND_TIMEOUT);
+		if (!rc) {
+			nand_err("read ahb/dma done timeout");
+		}
+	}
+
+	if (!check_with_timeout(ADDRCNTR_SEC(nfi_readl(nfc, NFI_BYTELEN)) >= sectors,
+	                        MTK_NAND_TIMEOUT)) {
+		nand_err("subpage done timeout %d", nfi_readl(nfc, NFI_BYTELEN));
+		nand_err("cnfg 0x%x fmt 0x%x\n con 0x%x", nfi_readl(nfc, NFI_CNFG),
+		         nfi_readl(nfc, NFI_PAGEFMT), nfi_readl(nfc, NFI_CON));
+		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);
+			nand_dma_unmap(buf, len, false, NULL);
+			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 sectors, start, end;
+	int i, ret;
+
+	start = off / chip->ecc_size;
+	end = DIV_ROUND_UP(off + len, chip->ecc_size);
+	sectors = end - start;
+
+	nand_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++) {
+		nand_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)
+			nand_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 sectors, start, end;
+	int i, ret;
+
+	start = off / chip->ecc_size;
+	end = DIV_ROUND_UP(off + len, chip->ecc_size);
+	sectors = end - start;
+
+	nand_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++) {
+		nand_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)
+			nand_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;
+	int i, ret;
+
+	nand_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++) {
+		nand_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)
+			nand_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;
+	int i, ret;
+
+	nand_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++) {
+		nand_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)
+			nand_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;
+	int i, ret;
+
+	nand_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++) {
+		nand_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 (buf)
+			nand_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;
+	int i, ret;
+
+	nand_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++) {
+		nand_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 (buf)
+			nand_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;
+	int i, ret;
+
+	nand_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++) {
+		nand_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 (buf)
+			nand_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;
+	int i, ret;
+
+	nand_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++) {
+		nand_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 (buf)
+			nand_memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+			            chip->ecc_size);
+	}
+
+	return ret;
+}
+
+static void mtk_nfc_set_timing(struct mtk_nand_chip *chip)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	u32 reg;
+
+	/*
+	 * 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 (chip->acctiming) {
+		nfi_writel(nfc, chip->acctiming, NFI_ACCCON);
+	/*
+	 * DEBUG_CON1: debug register
+	 * -------------------------------------
+	 * 15: bypass master async circuit.
+	 * 14:05: write enable hold time
+	 * 04:03: strobe sel, internal sample delay n cycles as rising edge of NREB
+	 * 02:00: reserved
+	 */
+		if ((chip->acctiming == 0x10804111)
+			|| (chip->acctiming == 0x10804122)) {
+			/* Set strobe_sel to delay 1 cycle for NRE */
+			reg = nfi_readl(nfc, NFI_DEBUG_CON1);
+			reg &= ~STROBE_SEL_MASK;
+			reg |= (0x1 << STROBE_SEL_SHIFT);
+			nfi_writel(nfc, reg, NFI_DEBUG_CON1);
+		}
+	} else
+		nfi_writel(nfc, 0x10804222, NFI_ACCCON);
+}
+
+static 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);
+	u32 reg;
+
+	/* Change to NFI mode */
+	nfi_writel(nfc, 0, NFI_SNAND_CNFG);
+
+	nfi_writel(nfc, 0, NFI_CSEL);
+
+	/* disable bypass_master_en */
+	reg = nfi_readl(nfc, NFI_DEBUG_CON1);
+	reg &= ~BYPASS_MASTER_EN;
+	nfi_writel(nfc, reg, NFI_DEBUG_CON1);
+	/*
+	 * 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 (chip->acctiming)
+		nfi_writel(nfc, chip->acctiming, NFI_ACCCON);
+	else
+		nfi_writel(nfc, 0x30C77FFF, 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);
+}
+
+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;
+}
+
+static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
+                                     struct mtk_nand_chip *nand)
+{
+	/* mt8561 no swap */
+	if (0) { /*(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);
+	}
+}
+
+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;
+
+	nand_debug("pagesize:%d, oobsize:%d, ecc_size:%d",
+		nand->pagesize, nand->oobsize, nand->ecc_size);
+	
+	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;
+}
+
+static int mtk_nfc_markbad(struct mtk_nand_chip *chip, u32 page)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	int ret = 0, res, chipnr, i = 0;
+
+	/* Write to first/last page(s) if necessary */
+	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+		page += chip->page_per_block - 1;
+
+	memset(nfc->buffer, 0xff, chip->pagesize + chip->oobsize);
+	/* Set bad marker at chip->badblockpos */
+	nfc->buffer[chip->pagesize + chip->badblockpos] = 0;
+
+	chipnr = (int)(page / chip->page_per_chip);
+	chip->select_chip(chip, chipnr);
+
+	do {
+		chip->cmdfunc(chip, NAND_CMD_SEQIN, 0x00, page);
+
+		res = mtk_nfc_write_page(chip, nfc->buffer, page, 1, 1, 1);
+		if (res < 0) {
+			nand_err("markbad failed at page %d\n", page);
+			return -EIO;
+		}
+
+		chip->cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
+		res = chip->waitfunc(chip, 1);
+		res = res & NAND_STATUS_FAIL ? -EIO : 0;
+		if (!ret)
+			ret = res;
+
+		i++;
+		page++;
+	} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
+
+	chip->select_chip(chip, -1);
+
+	return ret;
+}
+
+static void dump_nand_info(struct mtk_nand_chip *chip)
+{
+	nand_info("------------dump nand info ------------\n");
+	nand_info("totalsize 			0x%llx\n", chip->totalsize);
+	nand_info("chipsize 			0x%llx\n", chip->chipsize);
+	nand_info("pagesize 			0x%x\n", chip->pagesize);
+	nand_info("oobsize 			0x%x\n", chip->oobsize);
+	nand_info("blocksize 			0x%x\n", chip->blocksize);
+	nand_info("ecc_size 			0x%x\n", chip->ecc_size);
+	nand_info("ecc_strength 		0x%x\n", chip->ecc_strength);
+	nand_info("ecc_steps 			0x%x\n", chip->ecc_steps);
+	nand_info("subpagesize 			0x%x\n", chip->subpagesize);
+	nand_info("fdm_ecc_size 		0x%x\n", chip->fdm_ecc_size);
+	nand_info("bits_per_cell 		0x%x\n", chip->bits_per_cell);
+	nand_info("page_per_chip 		0x%x\n", chip->page_per_chip);
+	nand_info("page_per_block 		0x%x\n", chip->page_per_block);
+	nand_info("chip_delay 			0x%x\n", chip->chip_delay);
+	nand_info("acctiming 			0x%x\n", chip->acctiming);
+	nand_info("options 			0x%x\n", chip->options);
+	nand_info("numchips 			0x%x\n", chip->numchips);
+	nand_info("activechip			0x%x\n", chip->activechip);
+	nand_info("bbt_options 			0x%x\n", chip->bbt_options);
+	nand_info("badblockpos 			0x%x\n", chip->badblockpos);
+	nand_info("badblockbits 		0x%x\n", chip->badblockbits);
+	nand_info("bbt_erase_shift 		0x%x\n", chip->bbt_erase_shift);
+}
+
+static void mtk_nfc_clk_init(void)
+{
+	u32 reg;
+/* Nand clock select register define */
+#define NFI_CLK_SEL1               (IO_PHYS+0x4)
+
+	reg = (unsigned int)(*(volatile u32*)(NFI_CLK_SEL1));
+	reg &= ~(0x7);
+	/* 250.25MHz */
+	reg |= 0x3;
+	(*(volatile u32*)(NFI_CLK_SEL1) = (u32)(reg));
+}
+
+struct mtk_nand_chip *g_nand_chip;
+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 *)nand_malloc(sizeof(*nfc));
+	if (!nfc)
+		return -ENOMEM;
+	nand_memset(nfc, 0, sizeof(*nfc));
+	nfc->regs = NAND_NFI_BASE;
+
+	chip = (struct mtk_nfc_nand_chip *)nand_malloc(sizeof(*chip));
+	if (!chip) {
+		goto free_nfc;
+		ret = -ENOMEM;
+	}
+	nand_memset(chip, 0, sizeof(*chip));
+	
+	nand_debug("nfc->regs:0x%lx nfc:0x%x chip:0x%x NAND_NFI_BASE:0x%x NFI_BASE:0x%x IO_PHYS:0x%x\n", 
+		(u32)nfc->regs, (u32)nfc, (u32)chip, NAND_NFI_BASE, NFI_BASE, IO_PHYS);
+
+#if 0
+	/* register interrupt handler */
+	mtk_nfc_request_irq(nfc);
+#endif
+
+	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->block_markbad = mtk_nfc_markbad;
+
+	mtk_nfc_gpio_init();
+	mtk_nfc_clk_init();
+
+#ifndef MT8518_NFI
+	mtk_nfc_randomizer_init(nand);
+#endif
+
+	mtk_nfc_hw_init(nand);
+
+	//nand_debug("chip->acctiming:%x", chip->acctiming);
+
+	ret = mtk_nand_scan(nand, 1 /*MTK_NAND_MAX_NSELS*/);
+	if (ret)
+		goto free_chip;
+
+	nand_debug("chip->acctiming:%x", chip->acctiming);
+	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);
+	mtk_nfc_set_timing(nand);
+
+	ret = mtk_ecc_hw_init(&nfc->ecc);
+	if (ret)
+		goto free_chip;
+
+	/* nfc->buffer = (u8 *)NAND_DRAM_BUF_NFCBUF_ADDR; */
+	nfc->buffer = (u8 *)nand_memalign(4, nand->pagesize + nand->oobsize);
+	if (!nfc->buffer) {
+		ret = -ENOMEM;
+		goto free_chip;
+	}
+
+	nand_lock_init(&nfc->lock);
+	g_nand_chip = nand;
+	nand_debug("nand chip init done");
+
+	dump_nand_info(nand);
+
+	return 0;
+
+free_chip:
+	nand_free(chip);
+free_nfc:
+	nand_free(nfc);
+
+	return ret;
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nfi_hal.h b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nfi_hal.h
new file mode 100644
index 0000000..7c4b934
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/mtk_nfi_hal.h
@@ -0,0 +1,70 @@
+/*
+ * 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 _MTK_NFI_HAL_H_
+#define _MTK_NFI_HAL_H_
+
+#include "mtk_nand_sys.h"
+#include "mtk_nand_nal.h"
+
+/*
+ * used to do bad mark byte swap
+ */
+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 {
+	nand_lock_t lock;
+	nand_completion_t done;
+	struct mtk_ecc_config ecc_cfg;
+	struct mtk_ecc *ecc;
+
+	void *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;
+};
+
+extern int mtk_nfc_nand_chip_init(struct mtk_nand_chip **ext_nand);
+
+enum mtk_randomizer_operation {RAND_ENCODE, RAND_DECODE};
+extern void mtk_nfc_randomizer_disable(struct mtk_nand_chip *chip);
+extern void mtk_nfc_randomizer_enable(struct mtk_nand_chip *chip, int page,
+                                      enum mtk_randomizer_operation rand, int repage);
+#endif
diff --git a/src/bsp/lk/platform/mt8518/drivers/nand/rules.mk b/src/bsp/lk/platform/mt8518/drivers/nand/rules.mk
new file mode 100644
index 0000000..a93b43a
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/nand/rules.mk
@@ -0,0 +1,30 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+CFLAGS := $(filter-out -Werror, $(CFLAGS))
+GLOBAL_CFLAGS := $(filter-out -Werror, $(GLOBAL_CFLAGS))
+
+CFLAGS := $(filter-out -Werror=return-type, $(CFLAGS))
+GLOBAL_CFLAGS := $(filter-out -Werror=return-type, $(GLOBAL_CFLAGS))
+
+CFLAGS := $(filter-out -Werror=implicit-function-declaration, $(CFLAGS))
+GLOBAL_CFLAGS := $(filter-out -Werror=implicit-function-declaration, $(GLOBAL_CFLAGS))
+
+MODULE_DEPS += \
+    lib/bio \
+    lib/nftl \
+    lib/partition \
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/mtk_nand_nftl.c \
+    $(LOCAL_DIR)/mtk_nand_nal.c \
+    $(LOCAL_DIR)/mtk_nand_device.c \
+    $(LOCAL_DIR)/mtk_ecc_hal.c \
+    $(LOCAL_DIR)/mtk_nand_bbt.c \
+    $(LOCAL_DIR)/mtk_nfi_hal.c \
+    $(LOCAL_DIR)/mtk_nand_test.c \
+    $(LOCAL_DIR)/mtk_nand_sys.c \
+    $(LOCAL_DIR)/mtk_nand_api.c \
+
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mt8518/drivers/pll/pll.c b/src/bsp/lk/platform/mt8518/drivers/pll/pll.c
new file mode 100644
index 0000000..5269a82
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/pll/pll.c
@@ -0,0 +1,579 @@
+/* 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.
+ */
+
+#include <debug.h>
+#include <reg.h>
+#include <platform/mt8518.h>
+#include <platform/pll.h>
+#include <platform/spm.h>
+#include <platform/spm_mtcmos.h>
+#include <platform/sec_devinfo.h>
+
+typedef volatile unsigned int *V_UINT32P;
+
+#define ALL_CLK_ON      1
+#define DEBUG_FQMTR     0
+
+#define udelay(x)       spin(x)
+#define mdelay(x)       udelay((x) * 1000)
+
+#define DRV_WriteReg32(addr, data)  writel(data, addr)
+#define DRV_Reg32(addr) readl(addr)
+
+#define FREQ_MTR_CTRL_REG       (CKSYS_BASE + 0x10)
+#define FREQ_MTR_CTRL_RDATA     (CKSYS_BASE + 0x14)
+
+#define RG_FQMTR_CKDIV_GET(x)           (((x) >> 28) & 0x3)
+#define RG_FQMTR_CKDIV_SET(x)           (((x)& 0x3) << 28)
+#define RG_FQMTR_FIXCLK_SEL_GET(x)      (((x) >> 24) & 0x3)
+#define RG_FQMTR_FIXCLK_SEL_SET(x)      (((x)& 0x3) << 24)
+#define RG_FQMTR_MONCLK_SEL_GET(x)      (((x) >> 16) & 0x7f)
+#define RG_FQMTR_MONCLK_SEL_SET(x)      (((x)& 0x7f) << 16)
+#define RG_FQMTR_MONCLK_EN_GET(x)       (((x) >> 15) & 0x1)
+#define RG_FQMTR_MONCLK_EN_SET(x)       (((x)& 0x1) << 15)
+#define RG_FQMTR_MONCLK_RST_GET(x)      (((x) >> 14) & 0x1)
+#define RG_FQMTR_MONCLK_RST_SET(x)      (((x)& 0x1) << 14)
+#define RG_FQMTR_MONCLK_WINDOW_GET(x)   (((x) >> 0) & 0xfff)
+#define RG_FQMTR_MONCLK_WINDOW_SET(x)   (((x)& 0xfff) << 0)
+
+#define RG_FQMTR_CKDIV_DIV_2    0
+#define RG_FQMTR_CKDIV_DIV_4    1
+#define RG_FQMTR_CKDIV_DIV_8    2
+#define RG_FQMTR_CKDIV_DIV_16   3
+
+#define RG_FQMTR_FIXCLK_26MHZ   0
+#define RG_FQMTR_FIXCLK_32KHZ   2
+
+enum rg_fqmtr_monclk {
+	FM_CLK_NULL			=  0,
+
+	FM_G_MAINPLL_D8_188M_CK		=  1,
+	FM_G_MAINPLL_D11_137M_CK	=  2,
+	FM_G_MAINPLL_D12_126M_CK	=  3,
+	FM_G_MAINPLL_D20_76M_CK		=  4,
+	FM_G_MAINPLL_D7_215M_CK		=  5,
+	FM_G_UNIVPLL_D16_78M_CK		=  6,
+	FM_G_UNIVPLL_D24_52M_CK		=  7,
+	FM_CSW_MUX_NFI2X_CK		=  8,
+	FM_AD_SYS_26M_CK		= 11,
+	FM_AD_USB_F48M_CK		= 12,
+	FM_CSW_GFMUX_EMI1X_CK		= 13,
+	FM_CSW_GFMUX_AXIBUS_CK		= 14,
+	FM_CSW_MUX_SMI_CK		= 15,
+	FM_CSW_GFMUX_UART0_CK		= 16,
+	FM_CSW_GFMUX_UART1_CK		= 17,
+	FM_HF_FAUD_INTBUS_CK		= 18,
+	FM_CSW_MUX_MSDC0_CK		= 19,
+	FM_CSW_MUX_MSDC1_CK		= 20,
+	FM_AD_MPPLL_TST_CK		= 22,
+	FM_AD_PLLGP_TST_CK		= 23,
+	FM_CSW_52M_CK			= 24,
+	FM_MCUSYS_DEBUG_MON0		= 25,
+	FM_CSW_32K_CK			= 26,
+	FM_AD_MEMPLL_MONCLK		= 27,
+	FM_AD_MEMPLL2_MONCLK		= 28,
+	FM_AD_MEMPLL3_MONCLK		= 29,
+	FM_AD_MEMPLL4_MONCLK		= 30,
+	FM_HF_SPIS_CK			= 32,
+	FM_HF_GCPU_CK			= 33,
+	FM_CSW_MUX_PWM_MM_CK		= 34,
+	FM_CSW_MUX_DDRPHYCFG_CK		= 35,
+	FM_CSW_MUX_PMICSPI_CK		= 36,
+	FM_CSW_MUX_SPI_CK1		= 37,
+	FM_CSW_104M_CK			= 38,
+	FM_CSW_78M_CK			= 39,
+	FM_CSW_MUX_SPINOR_CK		= 40,
+	FM_CSW_MUX_ETH_CK		= 41,
+	FM_CSW_MUX_AUDIO_CK		= 42,
+	FM_CSW_MUX_IMGRZ_SYS_CK		= 43,
+	FM_CSW_MUX_PNG_SYS_CK		= 44,
+	FM_CSW_MUX_GRAPH_ECLK		= 45,
+	FM_CSW_MUX_FDBI_CK		= 46,
+	FM_CSW_MUX_AUD1_CK		= 47,
+	FM_CSW_MUX_AUD2_CK		= 48,
+	FM_CSW_MUX_FA2SYS_CK		= 49,
+	FM_CSW_MUX_FA1SYS_CK		= 50,
+	FM_CSW_MUX_SPINFI_BCLK_CK	= 51,
+	FM_CSW_MUX_PWM_INFRA_CK		= 52,
+	FM_CSW_MUX_AUD_SPDIF_IN_CK	= 53,
+	FM_CSW_GFMUX_UART2_CK		= 54,
+	FM_CSW_MUX_DBG_ATCLK_CK		= 56,
+	FM_CSW_MUX_FASM_M_CK		= 57,
+	FM_CSW_MUX_FECC_CK		= 58,
+	FM_FQ_TRNG_FREQ_DEBUG_OUT0	= 59,
+	FM_FQ_TRNG_FREQ_DEBUG_OUT1	= 60,
+	FM_FQ_USB20_CLK480M		= 61,
+	FM_CSW_MUX_HF_PE2_MAC_CK	= 62,
+	FM_CSW_MUX_HF_CMSYS_CK		= 63,
+	FM_AD_ARMPLL_650M_CK		= 64,
+	FM_AD_MAINPLL_1501P5M_CK	= 65,
+	FM_AD_UNIVPLL_1248M_CK		= 66,
+	FM_AD_MMPLL_380M_CK		= 67,
+	FM_AD_TVDPLL_594M_CK		= 68,
+	FM_AD_AUD1PLL_180P6336M_CK	= 69,
+	FM_AD_AUD2PLL_196P608M_CK	= 70,
+	FM_AD_ARMPLL_650M_VPROC_CK	= 71,
+	FM_AD_USB20_48M_CK		= 72,
+	FM_AD_UNIV_48M_CK		= 73,
+	FM_AD_TPHY_26M_CK		= 74,
+	FM_FQ_HF_FASM_L_CK		= 75,
+	FM_AD_MEM_26M_CK		= 77,
+	FM_AD_MEMPLL5_MONCLK		= 78,
+	FM_AD_MEMPLL6_MONCLK		= 79,
+	FM_CSW_MUX_MSDC2_CK		= 80,
+	FM_CSW_MUX_MSDC0_HCLK50_CK	= 81,
+	FM_CSW_MUX_MSDC2_HCLK50_CK	= 82,
+	FM_CSW_MUX_DISP_DPI_CK		= 83,
+	FM_CSW_MUX_SPI_CK2		= 84,
+	FM_CSW_MUX_SPI_CK3		= 85,
+	FM_CSW_MUX_HAPLL1_CK		= 86,
+	FM_CSW_MUX_HAPLL2_CK		= 87,
+	FM_CSW_MUX_I2C_CK		= 88,
+	FM_CSW_SEJ_13M_CK		= 89,
+
+	FM_CLK_END			= 90,
+};
+
+const char* rg_fqmtr_monclk_name[] = {
+	[FM_G_MAINPLL_D8_188M_CK]	= "g_mainpll_d8_188m_ck",
+	[FM_G_MAINPLL_D11_137M_CK]	= "g_mainpll_d11_137m_ck",
+	[FM_G_MAINPLL_D12_126M_CK]	= "g_mainpll_d12_126m_ck",
+	[FM_G_MAINPLL_D20_76M_CK]	= "g_mainpll_d20_76m_ck",
+	[FM_G_MAINPLL_D7_215M_CK]	= "g_mainpll_d7_215m_ck",
+	[FM_G_UNIVPLL_D16_78M_CK]	= "g_univpll_d16_78m_ck",
+	[FM_G_UNIVPLL_D24_52M_CK]	= "g_univpll_d24_52m_ck",
+	[FM_CSW_MUX_NFI2X_CK]		= "csw_mux_nfi2x_ck",
+	[FM_AD_SYS_26M_CK]		= "AD_SYS_26M_CK",
+	[FM_AD_USB_F48M_CK]		= "AD_USB_F48M_CK",
+	[FM_CSW_GFMUX_EMI1X_CK]		= "csw_gfmux_emi1x_ck",
+	[FM_CSW_GFMUX_AXIBUS_CK]	= "csw_gfmux_axibus_ck",
+	[FM_CSW_MUX_SMI_CK]		= "csw_mux_smi_ck",
+	[FM_CSW_GFMUX_UART0_CK]		= "csw_gfmux_uart0_ck",
+	[FM_CSW_GFMUX_UART1_CK]		= "csw_gfmux_uart1_ck",
+	[FM_HF_FAUD_INTBUS_CK]		= "hf_faud_intbus_ck",
+	[FM_CSW_MUX_MSDC0_CK]		= "csw_mux_msdc0_ck",
+	[FM_CSW_MUX_MSDC1_CK]		= "csw_mux_msdc1_ck",
+	[FM_AD_MPPLL_TST_CK]		= "AD_MPPLL_TST_CK",
+	[FM_AD_PLLGP_TST_CK]		= "AD_PLLGP_TST_CK",
+	[FM_CSW_52M_CK]			= "csw_52m_ck",
+	[FM_MCUSYS_DEBUG_MON0]		= "mcusys_debug_mon0",
+	[FM_CSW_32K_CK]			= "csw_32k_ck",
+	[FM_AD_MEMPLL_MONCLK]		= "AD_MEMPLL_MONCLK",
+	[FM_AD_MEMPLL2_MONCLK]		= "AD_MEMPLL2_MONCLK",
+	[FM_AD_MEMPLL3_MONCLK]		= "AD_MEMPLL3_MONCLK",
+	[FM_AD_MEMPLL4_MONCLK]		= "AD_MEMPLL4_MONCLK",
+	[FM_HF_SPIS_CK]			= "hf_spis_ck",
+	[FM_HF_GCPU_CK]			= "hf_gcpu_ck",
+	[FM_CSW_MUX_PWM_MM_CK]		= "csw_mux_pwm_mm_ck",
+	[FM_CSW_MUX_DDRPHYCFG_CK]	= "csw_mux_ddrphycfg_ck",
+	[FM_CSW_MUX_PMICSPI_CK]		= "csw_mux_pmicspi_ck",
+	[FM_CSW_MUX_SPI_CK1]		= "csw_mux_spi_ck1",
+	[FM_CSW_104M_CK]		= "csw_104m_ck",
+	[FM_CSW_78M_CK]			= "csw_78m_ck",
+	[FM_CSW_MUX_SPINOR_CK]		= "csw_mux_spinor_ck",
+	[FM_CSW_MUX_ETH_CK]		= "csw_mux_eth_ck",
+	[FM_CSW_MUX_AUDIO_CK]		= "csw_mux_audio_ck",
+	[FM_CSW_MUX_IMGRZ_SYS_CK]	= "csw_mux_imgrz_sys_ck",
+	[FM_CSW_MUX_PNG_SYS_CK]		= "csw_mux_png_sys_ck",
+	[FM_CSW_MUX_GRAPH_ECLK]		= "csw_mux_graph_eclk",
+	[FM_CSW_MUX_FDBI_CK]		= "csw_mux_fdbi_ck",
+	[FM_CSW_MUX_AUD1_CK]		= "csw_mux_aud1_ck",
+	[FM_CSW_MUX_AUD2_CK]		= "csw_mux_aud2_ck",
+	[FM_CSW_MUX_FA2SYS_CK]		= "csw_mux_fa2sys_ck",
+	[FM_CSW_MUX_FA1SYS_CK]		= "csw_mux_fa1sys_ck",
+	[FM_CSW_MUX_SPINFI_BCLK_CK]	= "csw_mux_spinfi_bclk_ck",
+	[FM_CSW_MUX_PWM_INFRA_CK]	= "csw_mux_pwm_infra_ck",
+	[FM_CSW_MUX_AUD_SPDIF_IN_CK]	= "csw_mux_aud_spdif_in_ck",
+	[FM_CSW_GFMUX_UART2_CK]		= "csw_gfmux_uart2_ck",
+	[FM_CSW_MUX_DBG_ATCLK_CK]	= "csw_mux_dbg_atclk_ck",
+	[FM_CSW_MUX_FASM_M_CK]		= "csw_mux_fasm_m_ck",
+	[FM_CSW_MUX_FECC_CK]		= "csw_mux_fecc_ck",
+	[FM_FQ_TRNG_FREQ_DEBUG_OUT0]	= "fq_trng_freq_debug_out0",
+	[FM_FQ_TRNG_FREQ_DEBUG_OUT1]	= "fq_trng_freq_debug_out1",
+	[FM_FQ_USB20_CLK480M]		= "fq_usb20_clk480m",
+	[FM_CSW_MUX_HF_PE2_MAC_CK]	= "csw_mux_hf_pe2_mac_ck",
+	[FM_CSW_MUX_HF_CMSYS_CK]	= "csw_mux_hf_cmsys_ck",
+	[FM_AD_ARMPLL_650M_CK]		= "AD_ARMPLL_650M_CK",
+	[FM_AD_MAINPLL_1501P5M_CK]	= "AD_MAINPLL_1501P5M_CK",
+	[FM_AD_UNIVPLL_1248M_CK]	= "AD_UNIVPLL_1248M_CK",
+	[FM_AD_MMPLL_380M_CK]		= "AD_MMPLL_380M_CK",
+	[FM_AD_TVDPLL_594M_CK]		= "AD_TVDPLL_594M_CK",
+	[FM_AD_AUD1PLL_180P6336M_CK]	= "AD_AUD1PLL_180P6336M_CK",
+	[FM_AD_AUD2PLL_196P608M_CK]	= "AD_AUD2PLL_196P608M_CK",
+	[FM_AD_ARMPLL_650M_VPROC_CK]	= "AD_ARMPLL_650M_VPROC_CK",
+	[FM_AD_USB20_48M_CK]		= "AD_USB20_48M_CK",
+	[FM_AD_UNIV_48M_CK]		= "AD_UNIV_48M_CK",
+	[FM_AD_TPHY_26M_CK]		= "AD_TPHY_26M_CK",
+	[FM_FQ_HF_FASM_L_CK]		= "fq_hf_fasm_l_ck",
+	[FM_AD_MEM_26M_CK]		= "AD_MEM_26M_CK",
+	[FM_AD_MEMPLL5_MONCLK]		= "AD_MEMPLL5_MONCLK",
+	[FM_AD_MEMPLL6_MONCLK]		= "AD_MEMPLL6_MONCLK",
+	[FM_CSW_MUX_MSDC2_CK]		= "csw_mux_msdc2_ck",
+	[FM_CSW_MUX_MSDC0_HCLK50_CK]	= "csw_mux_msdc0_hclk50_ck",
+	[FM_CSW_MUX_MSDC2_HCLK50_CK]	= "csw_mux_msdc2_hclk50_ck",
+	[FM_CSW_MUX_DISP_DPI_CK]	= "csw_mux_disp_dpi_ck",
+	[FM_CSW_MUX_SPI_CK2]		= "csw_mux_spi_ck2",
+	[FM_CSW_MUX_SPI_CK3]		= "csw_mux_spi_ck3",
+	[FM_CSW_MUX_HAPLL1_CK]		= "csw_mux_hapll1_ck",
+	[FM_CSW_MUX_HAPLL2_CK]		= "csw_mux_hapll2_ck",
+	[FM_CSW_MUX_I2C_CK]		= "csw_mux_i2c_ck",
+	[FM_CSW_SEJ_13M_CK]		= "csw_sej_13m_ck",
+};
+
+#define RG_FQMTR_EN     1
+#define RG_FQMTR_RST    1
+
+#define RG_FRMTR_WINDOW     1023
+
+unsigned int do_fqmtr_ctrl(int fixclk, int monclk_sel)
+{
+    u32 value = 0;
+
+    if(!((fixclk == RG_FQMTR_FIXCLK_26MHZ) | (fixclk == RG_FQMTR_FIXCLK_32KHZ))) {
+		dprintf(CRITICAL, "do_fqmtr_ctrl: clock source wrong!\n");
+		return 0;
+    }
+    // reset
+    DRV_WriteReg32(FREQ_MTR_CTRL_REG, RG_FQMTR_MONCLK_RST_SET(RG_FQMTR_RST));
+    // reset deassert
+    DRV_WriteReg32(FREQ_MTR_CTRL_REG, RG_FQMTR_MONCLK_RST_SET(!RG_FQMTR_RST));
+    // set window and target
+    DRV_WriteReg32(FREQ_MTR_CTRL_REG, RG_FQMTR_MONCLK_WINDOW_SET(RG_FRMTR_WINDOW) |
+                RG_FQMTR_MONCLK_SEL_SET(monclk_sel) |
+                RG_FQMTR_FIXCLK_SEL_SET(fixclk) |
+                RG_FQMTR_MONCLK_EN_SET(RG_FQMTR_EN));
+    udelay(100);
+    value = DRV_Reg32(FREQ_MTR_CTRL_RDATA);
+    // reset
+    DRV_WriteReg32(FREQ_MTR_CTRL_REG, RG_FQMTR_MONCLK_RST_SET(RG_FQMTR_RST));
+    // reset deassert
+    DRV_WriteReg32(FREQ_MTR_CTRL_REG, RG_FQMTR_MONCLK_RST_SET(!RG_FQMTR_RST));
+    if (fixclk == RG_FQMTR_FIXCLK_26MHZ)
+        return ((26000 * value) / (RG_FRMTR_WINDOW + 1));
+    else
+        return ((32 * value) / (RG_FRMTR_WINDOW + 1));
+
+}
+
+void dump_fqmtr(void)
+{
+    int i = 0;
+    unsigned int ret;
+
+    // fixclk = RG_FQMTR_FIXCLK_26MHZ
+    for (i = 0; i < FM_CLK_END; i++)
+    {
+		if (!rg_fqmtr_monclk_name[i])
+            continue;
+
+        ret = do_fqmtr_ctrl(RG_FQMTR_FIXCLK_26MHZ, i);
+        dprintf(CRITICAL, "%s - %d KHz\n", rg_fqmtr_monclk_name[i], ret);
+    }
+}
+
+unsigned int mt_get_cpu_freq(void)
+{
+#if FPGA_PLATFORM
+    return 0;
+#else
+    return do_fqmtr_ctrl(RG_FQMTR_FIXCLK_26MHZ, FM_AD_ARMPLL_650M_CK);
+#endif
+}
+
+unsigned int mt_get_mem_freq(void)
+{
+#if FPGA_PLATFORM
+    return 0;
+#else
+    return do_fqmtr_ctrl(RG_FQMTR_FIXCLK_26MHZ, FM_AD_MEMPLL6_MONCLK);
+#endif
+}
+
+unsigned int mt_get_bus_freq(void)
+{
+#if FPGA_PLATFORM
+    return 0;
+#else
+    return do_fqmtr_ctrl(RG_FQMTR_FIXCLK_26MHZ, FM_CSW_GFMUX_AXIBUS_CK);
+#endif
+}
+
+/* mt_pll_post_init() should be invoked after pmic_init */
+void mt_pll_post_init(void)
+{
+    unsigned int temp;
+
+/*****************
+ * xPLL HW Control
+ ******************/
+    // TBD (mem init)
+    DRV_WriteReg32(AP_PLL_CON1, (DRV_Reg32(AP_PLL_CON1) & 0xFCFCEFCC)); // Main, ARM PLL HW Control
+    DRV_WriteReg32(AP_PLL_CON2, (DRV_Reg32(AP_PLL_CON2) & 0xFFFFFFFC)); // Main, ARM PLL HW Control
+
+/*****************
+ * switch CPU clock to ARMPLL
+ ******************/
+    temp = DRV_Reg32(MCU_BUS_MUX) & ~0x600;
+    DRV_WriteReg32(MCU_BUS_MUX, temp | 0x200);
+
+#if DEBUG_FQMTR
+    dump_fqmtr();
+
+    dprintf(CRITICAL, "AP_PLL_CON1= 0x%x\n", DRV_Reg32(AP_PLL_CON1));
+    dprintf(CRITICAL, "AP_PLL_CON2= 0x%x\n", DRV_Reg32(AP_PLL_CON2));
+    dprintf(CRITICAL, "CLKSQ_STB_CON0= 0x%x\n", DRV_Reg32(CLKSQ_STB_CON0));
+    dprintf(CRITICAL, "PLL_ISO_CON0= 0x%x\n", DRV_Reg32(PLL_ISO_CON0));
+    dprintf(CRITICAL, "ARMPLL_CON0= 0x%x\n", DRV_Reg32(ARMPLL_CON0));
+    dprintf(CRITICAL, "ARMPLL_CON1= 0x%x\n", DRV_Reg32(ARMPLL_CON1));
+    dprintf(CRITICAL, "ARMPLL_PWR_CON0= 0x%x\n", DRV_Reg32(ARMPLL_PWR_CON0));
+    dprintf(CRITICAL, "MPLL_CON0= 0x%x\n", DRV_Reg32(MAINPLL_CON0));
+    dprintf(CRITICAL, "MPLL_CON1= 0x%x\n", DRV_Reg32(MAINPLL_CON1));
+    dprintf(CRITICAL, "MPLL_PWR_CON0= 0x%x\n", DRV_Reg32(MAINPLL_PWR_CON0));
+    dprintf(CRITICAL, "UPLL_CON0= 0x%x\n", DRV_Reg32(UNIVPLL_CON0));
+    dprintf(CRITICAL, "UPLL_CON1= 0x%x\n", DRV_Reg32(UNIVPLL_CON1));
+    dprintf(CRITICAL, "UPLL_PWR_CON0= 0x%x", DRV_Reg32(UNIVPLL_PWR_CON0));
+    dprintf(CRITICAL, "MMSYS_CG_CON0= 0x%x, \n", DRV_Reg32(MMSYS_CG_CON0));
+#endif /* DEBUG_FQMTR */
+    dprintf(CRITICAL, "cpu_freq = %d KHz\n", mt_get_cpu_freq());
+    dprintf(CRITICAL, "bus_freq = %d KHz\n", mt_get_bus_freq());
+}
+
+void mt_pll_prepare(void)
+{
+    unsigned int mainpll_en = DRV_Reg32(MAINPLL_CON0) & 1;
+    unsigned int univpll_en = DRV_Reg32(UNIVPLL_CON0) & 1;
+    unsigned int armpll_en = DRV_Reg32(ARMPLL_CON0) & 1;
+    unsigned int mmpll_en = DRV_Reg32(MMPLL_CON0) & 1;
+
+    if (!mainpll_en && !univpll_en && !armpll_en && !mmpll_en)
+        return;
+
+    DRV_WriteReg32(MCU_BUS_MUX, (DRV_Reg32(MCU_BUS_MUX) & ~0x600) | 0x0);
+    DRV_WriteReg32(ACLKEN_DIV, 0x1);
+    DRV_WriteReg32(ACLKEN_DIV, DRV_Reg32(ACLKEN_DIV) & 0xFFFFFFE0);	//[4:0]=5'b00000: CPU BUS clock freq is divided by 1
+    DRV_WriteReg32(CLK_MUX_SEL19, (DRV_Reg32(CLK_MUX_SEL19) & ~0xff00ff00) | 0x01000100);
+    DRV_WriteReg32(INFRABUS_DCMCTL1, DRV_Reg32(INFRABUS_DCMCTL1) & 0x7FFFFFFF); //[31]=1'b1: INFRABUS_DCMCTL1
+
+    DRV_WriteReg32(CLK_MUX_SEL1, (DRV_Reg32(CLK_MUX_SEL1) & 0xFF8FFFFF) | 0x100000);
+    DRV_WriteReg32(CLK_GATING_CTRL7, DRV_Reg32(CLK_GATING_CTRL7) | (0x1 << 31)); //[31]=1 disable 78M clk
+    DRV_WriteReg32(CLK_GATING_CTRL1, DRV_Reg32(CLK_GATING_CTRL1) | (0x1 << 13)); //[13]=1 disable hf_qaxi_usb_bclk_ck
+    DRV_WriteReg32(CLK_GATING_CTRL7, DRV_Reg32(CLK_GATING_CTRL7) | (0x1 << 24)); //[24]=1 disable hf_qaxi_usbsif_mcu_bclk_ck
+
+    DRV_WriteReg32(MAINPLL_CON0, DRV_Reg32(MAINPLL_CON0) & 0xF7FFFFFF);
+    DRV_WriteReg32(MAINPLL_CON0, DRV_Reg32(MAINPLL_CON0) & 0xFFFFFFFE);
+    DRV_WriteReg32(ARMPLL_CON0, DRV_Reg32(ARMPLL_CON0) & 0xFFFFFFFE);
+    DRV_WriteReg32(MMPLL_CON0, DRV_Reg32(MMPLL_CON0) & 0xFFFFFFFE);
+
+    DRV_WriteReg32(UNIVPLL_CON0, DRV_Reg32(UNIVPLL_CON0) & 0xF7FFFFFF);
+    DRV_WriteReg32(UNIVPLL_CON0, DRV_Reg32(UNIVPLL_CON0) & 0xFFFFFFFE);
+
+    udelay(1);
+
+    DRV_WriteReg32(MAINPLL_PWR_CON0, DRV_Reg32(MAINPLL_PWR_CON0) | 0x2);
+    DRV_WriteReg32(ARMPLL_PWR_CON0, DRV_Reg32(ARMPLL_PWR_CON0) | 0x2);
+    DRV_WriteReg32(MMPLL_PWR_CON0, DRV_Reg32(MMPLL_PWR_CON0) | 0x2);
+    DRV_WriteReg32(UNIVPLL_PWR_CON0, DRV_Reg32(UNIVPLL_PWR_CON0) | 0x2);
+
+    udelay(1);
+
+    DRV_WriteReg32(MAINPLL_PWR_CON0, DRV_Reg32(MAINPLL_PWR_CON0) & 0xFFFFFFFE);
+    DRV_WriteReg32(ARMPLL_PWR_CON0, DRV_Reg32(ARMPLL_PWR_CON0) & 0xFFFFFFFE);
+    DRV_WriteReg32(MMPLL_PWR_CON0, DRV_Reg32(MMPLL_PWR_CON0) & 0xFFFFFFFE);
+    DRV_WriteReg32(UNIVPLL_PWR_CON0, DRV_Reg32(UNIVPLL_PWR_CON0) & 0xFFFFFFFE);
+}
+
+void mt_pll_init(void)
+{
+  dprintf(CRITICAL, "mt_pll_init +\n");
+  unsigned int devinfo;
+
+    mt_pll_prepare();
+
+/*************
+ * CLKSQ
+ * ***********/
+    DRV_WriteReg32(AP_PLL_CON0, (DRV_Reg32(AP_PLL_CON0) | 0x1)); // [0] CLKSQ_EN = 1
+    udelay(100);  // wait 100us
+    DRV_WriteReg32(AP_PLL_CON0, (DRV_Reg32(AP_PLL_CON0) | 0x2)); // [1] CLKSQ_LPF_EN =1
+
+/*************
+ * xPLL PWR ON
+ **************/
+    DRV_WriteReg32(ARMPLL_PWR_CON0, (DRV_Reg32(ARMPLL_PWR_CON0) | 0x1));    // [0]ARMPLL_PWR_ON = 1
+    DRV_WriteReg32(MAINPLL_PWR_CON0, (DRV_Reg32(MAINPLL_PWR_CON0) | 0x1));  // [0]MAINPLL_PWR_ON = 1
+    DRV_WriteReg32(UNIVPLL_PWR_CON0, (DRV_Reg32(UNIVPLL_PWR_CON0) | 0x1));  // [0]UNIVPLL_PWR_ON = 1
+    DRV_WriteReg32(MMPLL_PWR_CON0, (DRV_Reg32(MMPLL_PWR_CON0) | 0x1));      // [0]MMPLL_PWR_ON = 1
+    DRV_WriteReg32(APLL1_PWR_CON0, (DRV_Reg32(APLL1_PWR_CON0) | 0x1));      // [0]APLL1_PWR_ON = 1
+    DRV_WriteReg32(APLL2_PWR_CON0, (DRV_Reg32(APLL2_PWR_CON0) | 0x1));      // [0]APLL2_PWR_ON = 1
+    DRV_WriteReg32(TVDPLL_PWR_CON0, (DRV_Reg32(TVDPLL_PWR_CON0) | 0x1));    // [0]TVDPLL_PWR_ON = 1
+
+/*************
+ * Wait PWR ready(30ns)
+ **************/
+    udelay(30);
+
+/******************
+* xPLL ISO Disable
+*******************/
+    DRV_WriteReg32(ARMPLL_PWR_CON0, (DRV_Reg32(ARMPLL_PWR_CON0) & 0xFFFFFFFD));   // [2]ARMPLL_ISO_EN = 0
+    DRV_WriteReg32(MAINPLL_PWR_CON0, (DRV_Reg32(MAINPLL_PWR_CON0) & 0xFFFFFFFD)); // [2]MAINPLL_ISO_EN = 0
+    DRV_WriteReg32(UNIVPLL_PWR_CON0, (DRV_Reg32(UNIVPLL_PWR_CON0) & 0xFFFFFFFD)); // [2]UNIVPLL_ISO_EN = 0
+    DRV_WriteReg32(MMPLL_PWR_CON0, (DRV_Reg32(MMPLL_PWR_CON0) & 0xFFFFFFFD));     // [2]MMPLL_ISO_EN = 0
+    DRV_WriteReg32(APLL1_PWR_CON0, (DRV_Reg32(APLL1_PWR_CON0) & 0xFFFFFFFD));     // [2]APLL1_ISO_EN = 0
+    DRV_WriteReg32(APLL2_PWR_CON0, (DRV_Reg32(APLL2_PWR_CON0) & 0xFFFFFFFD));     // [2]APLL2_ISO_EN = 0
+    DRV_WriteReg32(TVDPLL_PWR_CON0, (DRV_Reg32(TVDPLL_PWR_CON0) & 0xFFFFFFFD));   // [2]TVDPLL_ISO_EN = 0
+
+/********************
+ * xPLL Frequency Set
+ *********************/
+    DRV_WriteReg32(ARMPLL_CON1, 0x810d7627);  // 700 MHz
+
+    DRV_WriteReg32(MAINPLL_CON1, 0x800e7000); // 1501 MHz
+
+    DRV_WriteReg32(UNIVPLL_CON1, 0x81000060); // 1248 MHz
+
+	DRV_WriteReg32(MMPLL_CON1, 0x820F0000);   // 390 MHz
+
+    DRV_WriteReg32(APLL1_CON1, 0xb7945ea6);   // 180.6 MHz
+    DRV_WriteReg32(APLL1_CON0, 0x16);
+    DRV_WriteReg32(APLL1_CON_TUNER, 0x37945ea7); // 180.6MHz + 1
+
+    DRV_WriteReg32(APLL2_CON1, 0xbc7ea932);   // 196.6 MHz
+    DRV_WriteReg32(APLL2_CON0, 0x16);
+    DRV_WriteReg32(APLL2_CON_TUNER, 0x3c7ea933); // 196.6 MHz + 1
+
+    DRV_WriteReg32(TVDPLL_CON1, 0x8216d89e);  // 594 MHz
+
+/***********************
+ * xPLL Frequency Enable
+ ************************/
+    DRV_WriteReg32(ARMPLL_CON0, (DRV_Reg32(ARMPLL_CON0) | 0x1));   // [0]ARMPLL_EN = 1
+    DRV_WriteReg32(MAINPLL_CON0, (DRV_Reg32(MAINPLL_CON0) | 0x1)); // [0]MAINPLL_EN = 1
+    DRV_WriteReg32(UNIVPLL_CON0, (DRV_Reg32(UNIVPLL_CON0) | 0x1)); // [0]UNIVPLL_EN = 1
+    DRV_WriteReg32(MMPLL_CON0, (DRV_Reg32(MMPLL_CON0) | 0x1));     // [0]MMPLL_EN = 1
+    DRV_WriteReg32(APLL1_CON0, (DRV_Reg32(APLL1_CON0) | 0x1));     // [0]APLL1_EN = 1
+    DRV_WriteReg32(APLL2_CON0, (DRV_Reg32(APLL2_CON0) | 0x1));     // [0]APLL2_EN = 1
+    DRV_WriteReg32(TVDPLL_CON0, (DRV_Reg32(TVDPLL_CON0) | 0x1D));  // [0]TVDPLL_EN = 1
+
+/*************
+ * Wait PWR ready(20ns)
+ **************/
+    udelay(20); // wait for PLL stable (min delay is 20us)
+
+/***************
+ * xPLL DIV RSTB
+ ****************/
+    DRV_WriteReg32(MAINPLL_CON0, (DRV_Reg32(MAINPLL_CON0) | 0x08000000)); // [27]MAINPLL_DIV_RSTB = 1
+    DRV_WriteReg32(UNIVPLL_CON0, (DRV_Reg32(UNIVPLL_CON0) | 0x08000000)); // ]27]UNIVPLL_DIV_RSTB = 1
+
+
+/**************
+ * INFRA CLKMUX
+ ***************/
+    DRV_WriteReg32(ACLKEN_DIV, 0x12); // CPU BUS clock freq is divided by 2
+    DRV_WriteReg32(INFRA_CLKSEL, (DRV_Reg32(INFRA_CLKSEL) | 0x1E)); // i2c_bclk_sel bit[4:1] = 1
+
+/*****************
+ * AXI BUS DCM Setting
+ ******************/
+    DRV_WriteReg32(INFRABUS_DCMCTL1, 0x80000000);
+    if (readl(VERSION_BASE_VIRT+0x08) == 0xCB00)
+        DRV_WriteReg32(INFRABUS_DCMCTL0, (DRV_Reg32(INFRABUS_DCMCTL0) & ~0xC000C00) | 0x4000400);
+
+/*****************
+ * Enable SPM bus control
+ * bit6: Enable SPM sc_26m_ck_sel signal to control bus clock 26MHz selection
+ * bit8: Enable SPM sc_axi_ck_off signal to control AXI clock gating off
+ ******************/
+    DRV_WriteReg32(CLK_GATING_CTRL0_SET, 0x140);
+
+/************
+ * TOP CLKMUX
+ *************/
+	DRV_WriteReg32(CLK_MUX_SEL15, (DRV_Reg32(CLK_MUX_SEL15) & ~0x77fc000f) | 0x3380000a);
+	DRV_WriteReg32(CLK_MUX_SEL16, (DRV_Reg32(CLK_MUX_SEL16) & ~0x00000ff7) | 0x00000081);
+#if WITH_32K_OSC
+	DRV_WriteReg32(CLK_MUX_SEL17, (DRV_Reg32(CLK_MUX_SEL17) & ~0x0001ffc0) | 0x00000200);
+#else
+	DRV_WriteReg32(CLK_MUX_SEL17, (DRV_Reg32(CLK_MUX_SEL17) & ~0x0001ffc0) | 0x00001200);
+#endif
+	DRV_WriteReg32(CLK_MUX_SEL19, (DRV_Reg32(CLK_MUX_SEL19) & ~0xff00ff00) | 0x02000200);
+	DRV_WriteReg32(CLK_MUX_SEL21, (DRV_Reg32(CLK_MUX_SEL21) & ~0x00000fff) | 0x00000133);
+	DRV_WriteReg32(CLK_MUX_SEL22, (DRV_Reg32(CLK_MUX_SEL22) & ~0x1fffbfff) | 0x06400c40);
+	DRV_WriteReg32(CLK_MUX_SEL23, (DRV_Reg32(CLK_MUX_SEL23) & ~0x3fffffff) | 0x02020209);
+	DRV_WriteReg32(CLK_MUX_SEL0, (DRV_Reg32(CLK_MUX_SEL0) & ~0x03cc0ff7) | 0x01c00206);
+	DRV_WriteReg32(CLK_MUX_SEL1, (DRV_Reg32(CLK_MUX_SEL1) & ~0x007f8007) | 0x00298000);
+	DRV_WriteReg32(CLK_MUX_SEL8, (DRV_Reg32(CLK_MUX_SEL8) & ~0x70c001c7) | 0x40c00001);
+	DRV_WriteReg32(CLK_SEL_9, (DRV_Reg32(CLK_SEL_9) & ~0x00059000) | 0x00000000);
+	DRV_WriteReg32(CLK_MUX_SEL13, (DRV_Reg32(CLK_MUX_SEL13) & ~0x0047039d) | 0x00450104);
+	DRV_WriteReg32(CLK_MUX_SEL14, (DRV_Reg32(CLK_MUX_SEL14) & ~0xff03ff07) | 0x9b000104);
+
+#if ALL_CLK_ON
+/************
+ * TOP CG
+ *************/
+	DRV_WriteReg32(CLK_GATING_CTRL0_CLR, 0x000f1e09);
+	DRV_WriteReg32(CLK_GATING_CTRL1_CLR, 0xfdcfeffe);
+	DRV_WriteReg32(CLK_GATING_CTRL7_CLR, 0x8b9abf36);
+	DRV_WriteReg32(CLK_GATING_CTRL7_SET, 0x70000000);
+	DRV_WriteReg32(CLK_SEL_9, (DRV_Reg32(CLK_SEL_9) & ~0x00000119));
+	DRV_WriteReg32(CLK_GATING_CTRL8_CLR, 0x0002f307);
+	DRV_WriteReg32(CLK_GATING_CTRL10_SET, 0x07801fff);
+	DRV_WriteReg32(CLK_GATING_CTRL10_CLR, 0x08000000);
+	DRV_WriteReg32(CLK_GATING_CTRL12_CLR, 0x000000ff);
+	DRV_WriteReg32(CLK_GATING_CTRL13_SET, 0x00000001);
+
+/*************
+ * for MTCMOS
+ *************/
+    spm_write(SPM_POWERON_CONFIG_SET, (SPM_PROJECT_CODE << 16) | (1U << 0));
+
+    spm_mtcmos_ctrl_disp(STA_POWER_ON);
+    spm_mtcmos_ctrl_audafe(STA_POWER_ON);
+
+    devinfo = seclib_get_devinfo_with_index(3);
+    if (!(devinfo & 0x1000))
+        spm_mtcmos_ctrl_cm4(STA_POWER_ON);
+
+/*************
+ * for Subsys CG
+ *************/
+    DRV_WriteReg32(MMSYS_CG_CON0, (DRV_Reg32(MMSYS_CG_CON0) & ~0x000c8007));
+#endif /* ALL_CLK_ON */
+
+	dprintf(CRITICAL, "mt_pll_init done\n");
+}
diff --git a/src/bsp/lk/platform/mt8518/drivers/pmic/pmic.c b/src/bsp/lk/platform/mt8518/drivers/pmic/pmic.c
new file mode 100644
index 0000000..2c3743e
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/pmic/pmic.c
@@ -0,0 +1,275 @@
+
+#include <platform/mt8518.h>
+#include <reg.h>
+#include <platform/pmic_wrap_init.h>
+#include <platform/mtk_timer.h>
+#include <platform/pmic.h>
+
+//flag to indicate ca15 related power is ready
+volatile int g_ca15_ready __attribute__ ((section (".data"))) = 0;
+
+extern CHARGER_TYPE hw_charger_type_detection(void);
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// PMIC access API
+//////////////////////////////////////////////////////////////////////////////////////////
+u32 pmic_read_interface (u32 RegNum, u32 *val, u32 MASK, u32 SHIFT)
+{
+    u32 return_value = 0;
+    u32 pmic_reg = 0;
+    u32 rdata;
+
+    return_value= pwrap_wacs2(0, (RegNum), 0, &rdata);
+    pmic_reg=rdata;
+    if(return_value!=0)
+    {
+        printf("[pmic_read_interface] Reg[%x]= pmic_wrap read data fail\n", RegNum);
+        return return_value;
+    }
+    printf("[pmic_read_interface] Reg[%x]=0x%x\n", RegNum, pmic_reg);
+
+    pmic_reg &= (MASK << SHIFT);
+    *val = (pmic_reg >> SHIFT);
+    printf("[pmic_read_interface] val=0x%x\n", *val);
+
+    return return_value;
+}
+
+u32 pmic_config_interface (u32 RegNum, u32 val, u32 MASK, u32 SHIFT)
+{
+    u32 return_value = 0;
+    u32 pmic_reg = 0;
+    u32 rdata;
+
+    //1. mt_read_byte(RegNum, &pmic_reg);
+    return_value= pwrap_wacs2(0, (RegNum), 0, &rdata);
+    pmic_reg=rdata;
+    if(return_value!=0)
+    {
+        printf("[pmic_config_interface] Reg[%x]= pmic_wrap read data fail\n", RegNum);
+        return return_value;
+    }
+    printf("[pmic_config_interface] Reg[%x]=0x%x\n", RegNum, pmic_reg);
+
+    pmic_reg &= ~(MASK << SHIFT);
+    pmic_reg |= (val << SHIFT);
+
+    //2. mt_write_byte(RegNum, pmic_reg);
+    return_value= pwrap_wacs2(1, (RegNum), pmic_reg, &rdata);
+    if(return_value!=0)
+    {
+        printf("[pmic_config_interface] Reg[%x]= pmic_wrap read data fail\n", RegNum);
+        return return_value;
+    }
+    printf("[pmic_config_interface] write Reg[%x]=0x%x\n", RegNum, pmic_reg);
+
+    return return_value;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// PMIC-Charger Type Detection
+//////////////////////////////////////////////////////////////////////////////////////////
+CHARGER_TYPE g_ret = CHARGER_UNKNOWN;
+int g_charger_in_flag = 0;
+int g_first_check=0;
+
+CHARGER_TYPE mt_charger_type_detection(void)
+{
+    if( g_first_check == 0 )
+    {
+        g_first_check = 1;
+        g_ret = hw_charger_type_detection();
+    }
+    else
+    {
+        printf("[mt_charger_type_detection] Got data !!, %d, %d\r\n", g_charger_in_flag, g_first_check);
+    }
+
+    printf("[mt_charger_type_detection] chr_type: %d.\r\n", g_ret);
+    return g_ret;
+}
+
+//==============================================================================
+// PMIC Usage APIs
+//==============================================================================
+u32 get_pmic6397_chip_version (void)
+{
+    u32 eco_version = 0;
+
+    pmic_read_interface(0x0100, &eco_version, 0xFFFF, 0);
+
+    return eco_version;
+}
+
+u32 pmic_IsUsbCableIn (void)
+{
+    u32 val=0;
+
+    pmic_read_interface(0x0000, &val, 0x1, 5);
+
+    if(val)
+        return PMIC_CHRDET_EXIST;
+    else
+        return PMIC_CHRDET_NOT_EXIST;
+}
+
+int pmic_detect_powerkey(void)
+{
+    u32 val=0;
+
+    pmic_read_interface(0x0144, &val, 0x1, 3);
+    if (val==1){
+        printf("[pmic_detect_powerkey_PL] Release\n");
+        return 0;
+    }else{
+        printf("[pmic_detect_powerkey_PL] Press\n");
+        return 1;
+    }
+}
+
+int pmic_detect_homekey(void)
+{
+    u32 val=0;
+
+    pmic_read_interface(0x014A, &val, 0x1, 4);
+    return val;
+}
+
+//==============================================================================
+// PMIC Init Code
+//==============================================================================
+void PMIC_INIT_SETTING_V1(void)
+{
+	u32 chip_version = 0;
+    /* put init setting from DE/SA */
+
+	pmic_config_interface(0x0, 0x0, 0x1, 0);	/* [0:0]: RG_VCDT_HV_EN; Disable HV. Only compare LV threshold. */
+
+	chip_version = get_pmic6397_chip_version();
+	switch (chip_version) {
+	/* [7:4]: RG_VCDT_HV_VTH; 7V OVP */
+	case PMIC6391_E1_CID_CODE:
+	case PMIC6391_E2_CID_CODE:
+	case PMIC6391_E3_CID_CODE:
+		pmic_config_interface(0x2, 0xC, 0xF, 4);
+		break;
+	case PMIC6397_E2_CID_CODE:
+	case PMIC6397_E3_CID_CODE:
+	case PMIC6397_E4_CID_CODE:
+		pmic_config_interface(0x2, 0xB, 0xF, 4);
+		break;
+	default:
+		printf("[Power/PMIC] Error chip ID %d\r\n", chip_version);
+		pmic_config_interface(0x2, 0xB, 0xF, 4);
+		break;
+	}
+}
+
+static void pmic_default_buck_voltage(void)
+{
+	u32 reg_val=0;
+	u32 buck_val=0;
+	pmic_read_interface(0x01F2, &reg_val, 0xFFFF, 0);
+	if ((reg_val &0x01) == 0x01) {
+		printf("[EFUSE_DOUT_288_303] FUSE 288=0x%x\n", reg_val);
+
+		/* VCORE */
+		pmic_read_interface(0x01EE, &reg_val, 0xF, 12);
+		pmic_read_interface(0x0278, &buck_val, 0x7F, 0);
+		buck_val = (buck_val&0x07)|(reg_val<<3);
+		pmic_config_interface(0x0278, buck_val, 0x7F, 0);
+		pmic_config_interface(0x027A, buck_val, 0x7F, 0);
+
+		pmic_read_interface(0x01F0, &reg_val, 0xFFFF, 0);
+		/* VCA15 */
+		buck_val = 0;
+		pmic_read_interface(0x0226, &buck_val, 0x7F, 0);
+		buck_val = (buck_val&0x07)|((reg_val&0x0F)<<3);
+		pmic_config_interface(0x0226, buck_val, 0x7F, 0);
+		pmic_config_interface(0x0228, buck_val, 0x7F, 0);
+
+		/* VSAMRCA15 */
+		buck_val = 0;
+		pmic_read_interface(0x024C, &buck_val, 0x7F, 0);
+		buck_val = (buck_val&0x07)|((reg_val&0xF0)>>1);
+		pmic_config_interface(0x024C, buck_val, 0x7F, 0);
+		pmic_config_interface(0x024E, buck_val, 0x7F, 0);
+
+		/* VCA7 */
+		buck_val = 0;
+		pmic_read_interface(0x0338, &buck_val, 0x7F, 0);
+		buck_val = (buck_val&0x07)|((reg_val&0xF00)>>5);
+		pmic_config_interface(0x0338, buck_val, 0x7F, 0);
+		pmic_config_interface(0x033A, buck_val, 0x7F, 0);
+
+		/* VSAMRCA7 */
+		buck_val = 0;
+		pmic_read_interface(0x035E, &buck_val, 0x7F, 0);
+		buck_val = (buck_val&0x07)|((reg_val&0xF000)>>9);
+		pmic_config_interface(0x035E, buck_val, 0x7F, 0);
+		pmic_config_interface(0x0360, buck_val, 0x7F, 0);
+
+		//set the power control by register(use original)
+		pmic_config_interface(0x0206, 0x1, 0x1, 12);
+	}
+}
+
+u32 pmic_init (void)
+{
+    u32 ret_code = PMIC_TEST_PASS;
+    u32 reg_val=0;
+
+    printf("[pmic_init] Start..................\n");
+
+    /* Adjust default BUCK voltage */
+    pmic_default_buck_voltage();
+
+    pmic_config_interface(0x0126,  0x1, 0x1, 1);
+    pmic_config_interface(0x0126,  0x0, 0x1, 2);
+    pmic_config_interface(0x0126,  0x1, 0x1, 4);
+    pmic_config_interface(0x0126,  0x0, 0x1, 6);
+    pmic_read_interface(0x0126, &reg_val, 0xFFFF, 0);
+    printf("[pmic_init] Enable PMIC RST function (depends on main chip RST function) Reg[0x%x]=0x126\n", reg_val);
+
+    //Enable CA15 by default for different PMIC behavior
+    pmic_config_interface(0x0222, 0x1, 0x1, 0);
+    pmic_config_interface(0x0248, 0x1, 0x1, 0);
+	/*Disable CA7/SRCMA7/VDRM by default for no user*/
+    pmic_config_interface(0x0334, 0x0, 0x1, 0);
+    pmic_config_interface(0x035A, 0x0, 0x1, 0);
+    pmic_config_interface(0x0386, 0x0, 0x1, 0);
+    gpt_busy_wait_us(200);
+    g_ca15_ready = 1;
+
+    pmic_read_interface(0x0222, &reg_val, 0xFFFF, 0);
+    printf("Reg[0x%x]=0x0222\n", reg_val);
+    pmic_read_interface(0x0248, &reg_val, 0xFFFF, 0);
+    printf("Reg[0x%x]=0x0248\n", reg_val);
+
+    //pmic initial setting
+    PMIC_INIT_SETTING_V1();
+    printf("[PMIC_INIT_SETTING_V1] Done\n");
+
+    //26M clock amplitute adjust
+    pmic_config_interface(0x084A, 0x0, 0x3, 2);
+    pmic_config_interface(0x084A, 0x1, 0x3, 11);
+
+    pmic_read_interface(0x01F4, &reg_val, 0xFFFF, 0);
+    if ((reg_val & 0x8000) == 0)
+    {
+        pmic_config_interface(0x039E, 0x0041, 0xFFFF, 0);
+        pmic_config_interface(0x039E, 0x0040, 0xFFFF, 0);
+        pmic_config_interface(0x039E, 0x0050, 0xFFFF, 0);
+    }
+
+    //BC11_RST=1
+    pmic_config_interface(0x0024, 0x1, 0x1, 1);
+    //RG_BC11_BB_CTRL=1
+    pmic_config_interface(0x0024, 0x1, 0x1, 0);
+    pmic_config_interface(0x001A, 0x0, 0x1, 4);
+
+    printf("[pmic_init] Done...................\n");
+
+    return ret_code;
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/pmic/pmic_6395.c b/src/bsp/lk/platform/mt8518/drivers/pmic/pmic_6395.c
new file mode 100644
index 0000000..76664a5
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/pmic/pmic_6395.c
@@ -0,0 +1,174 @@
+/* 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.
+ */
+
+#include <platform/mt_i2c.h>
+#include <platform/pmic_6395.h>
+
+/**********************************************************
+  *   I2C Slave Setting
+  *********************************************************/
+#define mt6393_SLAVE_ADDR   0x61
+
+/**********************************************************
+  *   Global Variable
+  *********************************************************/
+#if PMIC_MT6395_I2C0
+    #define mt6393_I2C_ID       0
+#else
+    #define mt6393_I2C_ID       3
+#endif
+
+/**********************************************************
+  *
+  *   [I2C Function For Read/Write mt6393]
+  *
+  *********************************************************/
+u32 mt6393_write_byte(u8 addr, u8 value)
+{
+	int ret_code = 0;
+	u8 write_data[2];
+	u16 len;
+
+	write_data[0]= addr;
+	write_data[1] = value;
+	len = 2;
+
+	ret_code = mtk_i2c_write(mt6393_I2C_ID, mt6393_SLAVE_ADDR, 100, write_data, len);
+
+	if(ret_code == 0)
+		return 0; // ok
+	else
+		return -1; // fail
+}
+
+u32 mt6393_read_byte (u8 addr, u8 *dataBuffer)
+{
+	int ret_code = 0;
+	u16 len;
+	*dataBuffer = addr;
+
+	len = 1;
+
+	ret_code = mtk_i2c_write_read(mt6393_I2C_ID, mt6393_SLAVE_ADDR, 100,
+								dataBuffer, dataBuffer, len, len);
+
+	if(ret_code == 0)
+		return 0; // ok
+	else
+		return -1; // fail
+}
+
+/**********************************************************
+  *
+  *   [Read / Write Function]
+  *
+  *********************************************************/
+u32 pmic_read_interface (u8 RegNum, u8 *val, u8 MASK, u8 SHIFT)
+{
+	u8 mt6393_reg = 0;
+	u32 ret = 0;
+
+	ret = mt6393_read_byte(RegNum, &mt6393_reg);
+
+	mt6393_reg &= (MASK << SHIFT);
+	*val = (mt6393_reg >> SHIFT);
+
+	return ret;
+}
+
+u32 pmic_config_interface (u8 RegNum, u8 val, u8 MASK, u8 SHIFT)
+{
+	u8 mt6393_reg = 0;
+	u32 ret = 0;
+
+	ret = mt6393_read_byte(RegNum, &mt6393_reg);
+
+	mt6393_reg &= ~(MASK << SHIFT);
+	mt6393_reg |= (val << SHIFT);
+
+	ret = mt6393_write_byte(RegNum, mt6393_reg);
+
+	return ret;
+}
+
+int pmic_detect_powerkey(void)
+{
+	u8 val=0;
+
+	pmic_read_interface(0x1E, &val, 0x01, 7);
+
+	if (val==1) {
+		printf("pl pmic powerkey Release\n");
+		return 0;
+	} else {
+		printf("pl pmic powerkey Press\n");
+		return 1;
+	}
+}
+
+void PMIC_INIT_SETTING_V1(void)
+{
+	unsigned int ret = 0;
+
+	ret = pmic_config_interface(0x40, 0x98, 0xFF, 0); //enter test mode
+	ret = pmic_config_interface(0x4C, 0x1, 0xFF, 0); //disable reset i2c slave function
+
+	ret = pmic_config_interface(0x0B, 0x1, 0x01, 3); //WDOG_RST_EN  enable watchdog reset
+	ret = pmic_config_interface(0x45, 0x0, 0x03, 6); //CH1_SR set slew rate to 20mV/us
+
+	/*low power setting*/
+	ret = pmic_config_interface(0x0C, 0x1, 0x01, 7); //SLEEP_SEL enter sleep mode control by pin SUSPEND
+
+	/*HW chip ID E1 IC set 0x06, E2 IC set 0x07*/
+	if (readl(VERSION_BASE_VIRT+0x08) == 0xCA00)   //E1 IC
+		ret = pmic_config_interface(0x06, 0x0, 0x7F, 0);  //set vproc suspend mode 0.6V
+	else
+		ret = pmic_config_interface(0x0C, 0x0, 0x01, 1);  //set vproc poweroff when enter suspend mode
+
+	if (ret)
+		printf("[pmic6395_init] PMIC MT6395 init setting fail\n");
+	else
+		printf("[pmic6395_init] PMIC MT6395 init setting success\n");
+}
+
+//==============================================================================
+// PMIC6395 Init Code
+//==============================================================================
+void pmic_init_mt6395 (void)
+{
+	printf("[pmic6395_init] Preloader INIT Start..................\n");
+
+	/* pmic initial setting */
+	PMIC_INIT_SETTING_V1();
+
+	printf("[pmic6395_init] Preloader INIT Done...................\n");
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/pmic/pwm_buck.c b/src/bsp/lk/platform/mt8518/drivers/pmic/pwm_buck.c
new file mode 100644
index 0000000..aacc7a3
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/pmic/pwm_buck.c
@@ -0,0 +1,245 @@
+/* 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) 2018. 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.

+ */

+#include <platform/pwm-buck.h>

+#include <platform/pwm_buck_property.h>

+#include <platform/pwm.h>

+#include <stdbool.h>

+#include <stdint.h>

+#include <string.h>

+#include <reg.h>

+

+struct pwm_buck pwm_buck_prop[2];

+

+/*actually when voltage is adjusted, pwm is enabled*/

+static int pwm_is_enabled(void)

+{

+	return 1;

+}

+

+static int _regulator_get_voltage(unsigned int n, struct pwm_volt_map *table, unsigned int pwm_num)

+{

+	unsigned int pwm_period;

+	unsigned int duty_cycle_period;

+	unsigned int duty_cycle;

+	unsigned int i;

+

+	pwm_period = pwm_get_period(pwm_num);   //pwm_period is the clk number in one period

+

+	duty_cycle_period = pwm_get_duty_cycle(pwm_num);   //duty_cycle_period is the clk number in one period for the high level

+

+	duty_cycle = ((duty_cycle_period * 100) +  pwm_period - 1) / pwm_period;

+

+	for (i = 0; i < n; i++) {

+		if (table[i].duty_cycle == duty_cycle)

+			return table[i].volt;

+	}

+

+	BUCKERR("Do not recognize the duty_cycle and voltage mapping relation!\n");

+

+	return -BUCK_EINVAL;

+}

+

+static int _regulator_set_voltage(unsigned int n, struct pwm_volt_map *table, unsigned int volt, unsigned int pwm_num)

+{

+	unsigned int pwm_period;

+	unsigned int duty_cycle_period;

+	unsigned int duty_cycle;

+	unsigned int i;

+

+	pwm_period = pwm_get_period(pwm_num);

+

+	if (table[0].volt >= volt) {

+		duty_cycle = table[0].duty_cycle;

+		goto set_volt;

+	}

+

+	if (table[n-1].volt <= volt) {

+		duty_cycle = table[n-1].duty_cycle;

+		goto set_volt;

+	}

+

+	for (i = 0; i < n-1; i++) {

+		if ((table[i].volt < volt) && (table[i+1].volt >= volt)) {

+			duty_cycle = table[i+1].duty_cycle;

+			goto set_volt;

+		}

+	}

+

+	return -BUCK_EINVAL;

+

+set_volt:

+	duty_cycle_period = pwm_period * duty_cycle / 100;

+

+	pwm_set_duty(pwm_num, duty_cycle_period);

+	pwm_enable(pwm_num);

+

+	return BUCK_OK;

+}

+

+static int _regulator_is_enabled(void)

+{

+	return pwm_is_enabled();

+}

+

+static int _regulator_enable(unsigned int enable, unsigned int pwm_num)

+{

+	int ret = 0;

+

+	pwm_enable(pwm_num);

+

+	return ret;

+}

+

+int regulator_get_voltage()

+{

+	int ret = 0;

+

+	ret = _regulator_get_voltage(pwm_buck_prop[0].n_table, pwm_buck_prop[0].table, PWM_NUM_VCORE);

+	if (ret < 0)

+	{

+		BUCKERR("[regulator_get_voltage] _regulator_get_voltage fail, ret = %d!\n", ret);

+		return ret;

+	}

+

+	return ret;

+}

+

+int regulator_set_voltage(unsigned int volt)

+{

+	int ret = 0;

+

+	ret = _regulator_set_voltage(pwm_buck_prop[0].n_table, pwm_buck_prop[0].table, volt, PWM_NUM_VCORE);

+	if (ret < 0)

+	{

+		BUCKERR("[regulator_set_voltage] _regulator_set_voltage fail, ret = %d!\n", ret);

+		return ret;

+	}

+

+	return ret;

+}

+

+

+int regulator_is_enabled()

+{

+	int ret = 0;

+

+	ret = _regulator_is_enabled();

+	if (ret < 0)

+	{

+		BUCKERR("[regulator_is_enabled] _regulator_is_enabled fail, ret = %d!\n", ret);

+		return ret;

+	}

+

+	return ret;

+}

+

+

+int regulator_enable(int enable)

+{

+	int is_enabled = 0;

+	int ret = 0;

+

+	is_enabled = regulator_is_enabled();

+

+	if (is_enabled < 0)

+	{

+		BUCKERR("[regulator_enable] regulator_is_enabled fail, ret = %d!\n", is_enabled);

+		return is_enabled;

+	}

+

+	if (is_enabled == enable)

+	{

+		BUCKERR("[regulator_enable] regulator is already %d!\n", enable);

+		return BUCK_OK;

+	}

+

+	ret = _regulator_enable(enable, PWM_NUM_VCORE);

+	if (ret < 0)

+	{

+		BUCKERR("[regulator_enable] _regulator_enable fail, ret = %d!\n", ret);

+		return ret;

+	}

+

+	return ret;

+}

+

+

+static int PWM_BUCK_VCORE_INIT_SETTING(void)

+{

+	uint32_t gpio_reg;

+

+	pwm_buck_prop[0].table = vcore_map;

+	pwm_buck_prop[0].n_table = sizeof(vcore_map) / sizeof(struct pwm_volt_map);

+

+	/* set pwm period*/

+	pwm_buck_prop[0].pwm_period = PWM_PERIOD_INIT;

+	if (!pwm_buck_prop[0].pwm_period) {

+		BUCKERR("There is no vcore pwm buck period!\n");

+		goto err;

+	}

+	pwm_config_freq(PWM_NUM_VCORE, pwm_buck_prop[0].pwm_period);

+

+	gpio_reg = (readl(GPIO_VCORE_BASE) &

+			   (~(0x7 << GPIO_VCORE_PWM_OFFSET))) |

+			   (GPIO_VCORE_PWM_MODE << GPIO_VCORE_PWM_OFFSET);

+	writel(gpio_reg, GPIO_VCORE_BASE);

+

+	pwm_set_duty(PWM_NUM_VCORE, 0);  //for 1.1V

+	pwm_enable(PWM_NUM_VCORE);

+

+	return BUCK_OK;

+err:

+	return -BUCK_EINVAL;

+}

+

+

+//==============================================================================

+// BUCK RT5748 Init Code

+//==============================================================================

+int pwm_buck_init (void)

+{

+	int ret;

+

+	printf("[pwm_buck_init] Init Start..................\n");

+

+	/*Do the initial setting for struct pwm_buck*/

+	//memset(pwm_buck_prop, 0, sizeof(struct pwm_buck)*2);

+

+	ret = PWM_BUCK_VCORE_INIT_SETTING();

+	if (ret)

+		goto err1;

+

+	return BUCK_OK;

+

+err1:

+	return -BUCK_EINVAL;

+}

+

diff --git a/src/bsp/lk/platform/mt8518/drivers/pmic/rt5748.c b/src/bsp/lk/platform/mt8518/drivers/pmic/rt5748.c
new file mode 100644
index 0000000..195b647
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/pmic/rt5748.c
@@ -0,0 +1,128 @@
+/* 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.

+ */

+

+#include <platform/mt_i2c.h>

+#include <platform/rt5748.h>

+

+/**********************************************************

+  *

+  *   [I2C Function For Read/Write rt5748]

+  *

+  *********************************************************/

+u32 rt5748_write_byte(u8 addr, u8 value, u8 i2c_bus)

+{

+    int ret_code = 0;

+    u8 write_data[2];

+    u8 len;

+

+    write_data[0]= addr;

+    write_data[1] = value;

+

+    len = 2;

+

+    ret_code = mtk_i2c_write(i2c_bus, rt5748_SLAVE_ADDR, 100, write_data, len);

+

+    if(ret_code == 0)

+        return 0; // ok

+    else

+        return -1; // fail

+}

+

+u32 rt5748_read_byte (u8 addr, u8 *dataBuffer, u8 i2c_bus)

+{

+    int ret_code = 0;

+    u8 len;

+    *dataBuffer = addr;

+

+    len = 1;

+

+    ret_code = mtk_i2c_write_read(i2c_bus, rt5748_SLAVE_ADDR, 100,

+               dataBuffer, dataBuffer, len, len);

+

+    if(ret_code == 0)

+        return 0; // ok

+    else

+        return -1; // fail

+}

+

+/**********************************************************

+  *

+  *   [Read / Write Function]

+  *

+  *********************************************************/

+u32 rt5748_read_interface (u8 RegNum, u8 *val, u8 MASK, u8 SHIFT, u8 i2c_bus)

+{

+    u8 rt5748_reg = 0;

+    u32 ret = 0;

+

+    ret = rt5748_read_byte(RegNum, &rt5748_reg, i2c_bus);

+

+    rt5748_reg &= (MASK << SHIFT);

+    *val = (rt5748_reg >> SHIFT);

+

+    return ret;

+}

+

+u32 rt5748_config_interface (u8 RegNum, u8 val, u8 MASK, u8 SHIFT, u8 i2c_bus)

+{

+    u8 rt5748_reg = 0;

+    u32 ret = 0;

+

+    ret = rt5748_read_byte(RegNum, &rt5748_reg, i2c_bus);

+

+    rt5748_reg &= ~(MASK << SHIFT);

+    rt5748_reg |= (val << SHIFT);

+

+    ret = rt5748_write_byte(RegNum, rt5748_reg, i2c_bus);

+

+    return ret;

+}

+

+

+void RT5748_INIT_SETTING_V1(void)

+{

+	rt5748_config_interface(0x02, 0, 0x1, 1, rt5748_I2C_ID_P1);

+	rt5748_config_interface(0x02, 0, 0x1, 1, rt5748_I2C_ID_M2);

+}

+

+//==============================================================================

+// BUCK RT5748 Init Code

+//==============================================================================

+void rt5748_init (void)

+{

+    printf("[buck5748_init] Preloader Start..................\n");

+

+    /* buck initial setting */

+    RT5748_INIT_SETTING_V1();

+

+    printf("[buck5748_init] Done...................\n");

+}

+

diff --git a/src/bsp/lk/platform/mt8518/drivers/pwm/pwm.c b/src/bsp/lk/platform/mt8518/drivers/pwm/pwm.c
new file mode 100644
index 0000000..c94f973
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/pwm/pwm.c
@@ -0,0 +1,524 @@
+#include <platform/mt8518.h>
+#include <platform/pwm.h>
+#include <platform/mt_reg_base.h>
+#include <platform/pll.h>
+#include <reg.h>
+
+void pwm_dump(int pwm_no);
+
+#define u32		unsigned int
+
+#define PRINTF_I	printf
+#define PRINTF_W	printf
+#define PRINTF_E	printf
+
+#ifndef BIT
+#define BIT(_bit_)		(u32)(1U << (_bit_))
+#endif
+
+#if 0
+#define DRV_Reg32(addr)			(*(volatile u32 *)(addr))
+#define DRV_WriteReg32(addr,data)	((*(volatile u32 *)(addr)) = (u32)data)
+#define DRV_SetReg32(REG,BS)		((*(volatile u32*)(REG)) |= (u32)(BS))
+#define DRV_ClrReg32(REG,BS)		((*(volatile u32*)(REG)) &= ~((u32)(BS)))
+#else
+#define DRV_Reg32(addr)			readl(addr)
+#define DRV_WriteReg32(addr,data)	writel(data, addr)
+#define DRV_SetReg32(addr,BS)		writel((readl(addr)) | (BS), addr)
+#define DRV_ClrReg32(addr,BS)		writel((readl(addr)) & ~(BS), addr)
+#endif
+
+#define PWM_EN_REG          	0x0000
+#define PWMCON              	0x00
+#define PWMGDUR             	0x0c
+#define PWMWAVENUM          	0x28
+#define PWMDWIDTH           	0x2c
+#define PWMTHRES            	0x30
+#define PWM_SEND_WAVENUM	0x34
+#define PWM_CK_SEL		0x210
+
+#define PWM_BASE_ADDR		PWM_BASE
+#define CLK_BASE_ADDR		CKSYS_BASE
+
+#define PWM_CLK_DIV_MAX     	7
+#define PWM_NUM_MAX         	4
+
+#define PWM_CLK_NAME_MAIN   "main"
+
+#define ENOMEM          12    /* Out of memory */
+#define ENODEV          19    /* No such device */
+#define EINVAL          22      /* Invalid argument */
+
+#define CLK_API_IS_READY	0
+
+/*
+static const char * const pwm_clk_name[PWM_NUM_MAX] = {
+	"pwm0", "pwm1", "pwm2", "pwm3",
+};
+*/
+
+/*==========================================*/
+static const unsigned long pwm_com_register[] = {
+	0x0010, 0x0050, 0x0090, 0x00d0,
+};
+/*==========================================*/
+
+static int pwm_duties[PWM_NUM_MAX];
+static int pwm_periods[PWM_NUM_MAX];
+
+static int pwm_flag;
+
+static int pwm_get_clk_rate(int pwm_no)
+{
+	return 26000000;
+}
+
+static void pwm_enable_main_clock(void)
+{
+#if CLK_API_IS_READY
+#else
+	DRV_SetReg32(CLK_BASE_ADDR + 0x84, BIT(9));
+	DRV_SetReg32(CLK_BASE_ADDR + 0x9C, BIT(8));
+#endif
+}
+
+static void pwm_disable_main_clock(void)
+{
+#if CLK_API_IS_READY
+#else
+	DRV_SetReg32(CLK_BASE_ADDR + 0x6C, BIT(8));
+	DRV_SetReg32(CLK_BASE_ADDR + 0x54, BIT(9));
+#endif
+}
+
+static void pwm_enable_fbclk(int pwm_no)
+{
+#if CLK_API_IS_READY
+#else
+	switch(pwm_no) {
+		case 0:
+			DRV_SetReg32(CLK_BASE_ADDR + 0x9C, BIT(9));
+			break;
+
+		case 1:
+			DRV_SetReg32(CLK_BASE_ADDR + 0x9C, BIT(10));
+			break;
+
+		case 2:
+			DRV_SetReg32(CLK_BASE_ADDR + 0x9C, BIT(11));
+			break;
+
+		case 3:
+			DRV_SetReg32(CLK_BASE_ADDR + 0x9C, BIT(12));
+			break;
+
+		default:
+			break;
+	}
+#endif
+}
+
+static void pwm_disable_fbclk(int pwm_no)
+{
+#if CLK_API_IS_READY
+#else
+	switch(pwm_no) {
+		case 0:
+			DRV_SetReg32(CLK_BASE_ADDR + 0x6C, BIT(9));
+			break;
+
+		case 1:
+			DRV_SetReg32(CLK_BASE_ADDR + 0x6C, BIT(10));
+			break;
+
+		case 2:
+			DRV_SetReg32(CLK_BASE_ADDR + 0x6C, BIT(11));
+			break;
+
+		case 3:
+			DRV_SetReg32(CLK_BASE_ADDR + 0x6C, BIT(12));
+			break;
+
+		default:
+			break;
+	}
+#endif
+}
+
+static int pwm_clk_enable(int pwm_no)
+{
+	int ret = 0;
+
+	pwm_enable_main_clock();
+	pwm_enable_fbclk(pwm_no);
+	pwm_flag |= BIT(pwm_no);
+
+	PRINTF_I("pwm_clk_enable:main:0x%x, top:0x%x, fbclk0:0x%x, fbclk1:0x%x, fbclk2:0x%x, fbclk3:0x%x\n",
+		DRV_Reg32(CLK_BASE_ADDR + 0x24) & BIT(9), 
+		DRV_Reg32(CLK_BASE_ADDR + 0x3C) & BIT(8),
+		DRV_Reg32(CLK_BASE_ADDR + 0x3C) & BIT(9),
+		DRV_Reg32(CLK_BASE_ADDR + 0x3C) & BIT(10),
+		DRV_Reg32(CLK_BASE_ADDR + 0x3C) & BIT(11),
+		DRV_Reg32(CLK_BASE_ADDR + 0x3C) & BIT(12));
+	return ret;
+}
+
+static void pwm_clk_disable(int pwm_no)
+{
+	pwm_disable_fbclk(pwm_no);
+	pwm_flag &= (~ BIT(pwm_no));
+
+	if(pwm_flag == 0)
+		pwm_disable_main_clock();
+
+	PRINTF_I("pwm_clk_enable:main:0x%x, top:0x%x, fbclk0:0x%x, fbclk1:0x%x, fbclk2:0x%x, fbclk3:0x%x\n",
+		DRV_Reg32(CLK_BASE_ADDR + 0x24) & BIT(9), 
+		DRV_Reg32(CLK_BASE_ADDR + 0x3C) & BIT(8),
+		DRV_Reg32(CLK_BASE_ADDR + 0x3C) & BIT(9),
+		DRV_Reg32(CLK_BASE_ADDR + 0x3C) & BIT(10),
+		DRV_Reg32(CLK_BASE_ADDR + 0x3C) & BIT(11),
+		DRV_Reg32(CLK_BASE_ADDR + 0x3C) & BIT(12));
+}
+
+static inline u32 pwm_readl(int pwm_no, unsigned long offset)
+{
+	void  *reg = (void *)(PWM_BASE_ADDR + pwm_com_register[pwm_no] + offset);
+
+	return DRV_Reg32(reg);
+}
+
+static inline void pwm_writel(int pwm_no, unsigned long offset, unsigned int val)
+{
+	void  *reg = (void *)(PWM_BASE_ADDR + pwm_com_register[pwm_no] + offset);
+
+	DRV_WriteReg32(reg, val);
+}
+
+#if 0
+static int pwm_config(int pwm_no, int duty_ns, int period_ns)
+{
+	u32 value;
+	int resolution;
+	u32 clkdiv = 0;
+	u32 clksrc_rate;
+
+	int data_width, thresh;
+
+	pwm_clk_enable(pwm_no);
+
+	/* this use pwm clock, not fixed 26M: so the period_ns and duty_ns is not as what you want from 26M clock...*/
+	clksrc_rate = pwm_get_clk_rate(pwm_no);
+	resolution = 1000000000 / clksrc_rate;
+
+	while (period_ns / resolution  > 8191) {
+		clkdiv++;
+		resolution *= 2;
+	}
+
+	if (clkdiv > PWM_CLK_DIV_MAX) {
+		PRINTF_E("period %d not supported\n", period_ns);
+		return -EINVAL;
+	}
+
+	data_width = period_ns / resolution;
+	thresh = duty_ns / resolution;
+
+	if(data_width > 1)
+		--data_width;
+	if(thresh >= 1)
+		--thresh;
+
+	value = pwm_readl(pwm_no, PWMCON);
+	value = value | BIT(15) | clkdiv;
+	pwm_writel(pwm_no, PWMCON, value);
+
+	pwm_writel(pwm_no, PWMDWIDTH, data_width);
+	pwm_writel(pwm_no, PWMTHRES, thresh);
+
+	pwm_dump(pwm_no);
+
+	pwm_clk_disable(pwm_no);
+
+	return 0;
+}
+#endif
+
+int pwm_config_freq(int pwm_no, int freq)
+{
+	u32 value;
+	u32 resolution = 1;
+	u32 clkdiv = 0;
+	u32 clksrc_rate;
+
+	u32 data_width, thresh;
+
+	if (freq <= 0 || freq > 26000000) {
+		PRINTF_E("freq %d not supported\n", freq);
+		return -EINVAL;
+	}
+
+	pwm_clk_enable(pwm_no);
+
+	/* currently: fixed 26M */
+	clksrc_rate = pwm_get_clk_rate(pwm_no);
+	data_width = clksrc_rate / freq;
+
+	while (data_width > 8191) {
+		clkdiv++;
+		resolution *= 2;
+		data_width = data_width / resolution;
+	}
+
+	if (clkdiv > PWM_CLK_DIV_MAX) {
+		PRINTF_E("clkdiv %d not supported\n", clkdiv);
+		return -EINVAL;
+	}
+
+	thresh = 0;
+
+	pwm_periods[pwm_no] = data_width;
+	pwm_duties[pwm_no] = 1;
+
+	if(data_width > 1)
+		--data_width;
+
+	value = pwm_readl(pwm_no, PWMCON);
+	value = value | BIT(15) | clkdiv;
+	pwm_writel(pwm_no, PWMCON, value);
+
+	pwm_writel(pwm_no, PWMDWIDTH, data_width);
+	pwm_writel(pwm_no, PWMTHRES, thresh);
+
+	pwm_dump(pwm_no);
+
+	pwm_clk_disable(pwm_no);
+
+	return 0;
+}
+
+int pwm_set_duty(int pwm_no, int duty)
+{
+	if (duty < 0 || duty > 8191 || (pwm_periods[pwm_no] > 0 && duty > pwm_periods[pwm_no])) {
+		PRINTF_E("duty %d not supported(period:%u)\n", duty, pwm_periods[pwm_no]);
+		return -EINVAL;
+	}
+
+	pwm_clk_enable(pwm_no);
+
+	pwm_duties[pwm_no] = duty;
+	if(duty >= 1)
+		--duty;
+
+	PRINTF_E("pwm%d: set duty:%d\n", pwm_no, duty);
+	pwm_writel(pwm_no, PWMTHRES, duty);
+
+	pwm_dump(pwm_no);
+
+	pwm_disable(pwm_no);
+
+	return 0;
+}
+
+int pwm_get_period(int pwm_no)
+{
+	if(pwm_no < 0 || pwm_no >= PWM_NUM_MAX) {
+		PRINTF_E("pwm_no: %d is too big!\n", pwm_no);
+		return -1;
+	}
+	return pwm_periods[pwm_no];
+}
+
+int pwm_get_duty_cycle(int pwm_no)
+{
+	if(pwm_no < 0 || pwm_no >= PWM_NUM_MAX) {
+		PRINTF_E("pwm_no: %d is too big!\n", pwm_no);
+		return -1;
+	}
+
+	return pwm_duties[pwm_no];
+}
+
+int pwm_enable(int pwm_no)
+{
+	u32 val;
+
+	if(pwm_no < 0 || pwm_no >= PWM_NUM_MAX) {
+		PRINTF_E("pwm_no: %d is too big!\n", pwm_no);
+		return -1;
+	}
+
+	pwm_clk_enable(pwm_no);
+
+	val = DRV_Reg32(PWM_BASE_ADDR + PWM_EN_REG);
+	val |= BIT(pwm_no);
+	DRV_WriteReg32(PWM_BASE_ADDR + PWM_EN_REG, val);
+
+	return 0;
+}
+
+int pwm_disable(int pwm_no)
+{
+	u32 val;
+
+	if(pwm_no < 0 || pwm_no >= PWM_NUM_MAX) {
+		PRINTF_E("pwm_no: %d is too big!\n", pwm_no);
+		return -1;
+	}
+
+	val = DRV_Reg32(PWM_BASE_ADDR + PWM_EN_REG);
+	val &= ~ BIT(pwm_no);
+	DRV_WriteReg32(PWM_BASE_ADDR + PWM_EN_REG, val);
+
+	pwm_clk_disable(pwm_no);
+	
+	return 0;
+}
+
+int pwm_get_send_wavenums(int pwm_no)
+{
+	u32 val;
+
+	if(pwm_no < 0 || pwm_no >= PWM_NUM_MAX) {
+		PRINTF_E("pwm_no: %d is too big!\n", pwm_no);
+		return -1;
+	}
+
+	val = pwm_readl(pwm_no, PWM_SEND_WAVENUM);
+	PRINTF_I("pwm%d: send wavenum:%u\n", pwm_no, val);
+
+	return (int)val;
+}
+
+void pwm_dump(int pwm_no)
+{
+	u32 value;
+
+	if(pwm_no < 0 || pwm_no >= PWM_NUM_MAX) {
+		PRINTF_E("pwm_no: %d is too big!\n", pwm_no);
+		return;
+	}
+
+	value = pwm_readl(pwm_no, PWM_SEND_WAVENUM);
+
+	PRINTF_I("pwm%d: send wavenum:%u, duty/period:%d%%\n", pwm_no, value,
+		(pwm_readl(pwm_no, PWMTHRES) + 1) * 100 / (pwm_readl(pwm_no, PWMDWIDTH) + 1));
+	PRINTF_I("\tDATA_WIDTH:%u, THRESH:%u, CON:0x%x, EN:0x%x, CLK_SEL:0x%x\n",
+		pwm_readl(pwm_no, PWMDWIDTH),
+		pwm_readl(pwm_no, PWMTHRES),
+		pwm_readl(pwm_no, PWMCON),
+		DRV_Reg32(PWM_BASE_ADDR + PWM_EN_REG),
+		DRV_Reg32(PWM_BASE_ADDR + PWM_CK_SEL));
+}
+
+void pwm_dump_all(void)
+{
+	u32 value;
+	int i;
+
+	for(i = 0; i < PWM_NUM_MAX; ++i) {
+		value = pwm_readl(i, PWM_SEND_WAVENUM);
+		if(value > 0) {
+			pwm_dump(i);
+		} else
+			PRINTF_W("pwm %d: no waves!\n", i);
+	}
+}
+
+// set gpio_no to mode
+// return value: if return 0, means set susscessful, if return is not 0, means failed
+static int pwm_set_gpio_mode(int gpio_no, int mode)
+{
+	u32 uval;
+	PRINTF_I("pwm_set_gpio_mode +: sizeof(uintptr_t):%zu\n", sizeof(uintptr_t));
+	if(gpio_no == 88 && mode == 5) {
+		PRINTF_I("pwm_set_gpio_mode 88 5\n");
+		// switch GPIO88 to pwm mode 5:  bit[11~9]: value: 5
+		uval = DRV_Reg32(GPIO_BASE + 0x410);
+		PRINTF_I("0x10005410: 0x%x\n", uval);
+		
+		DRV_WriteReg32(GPIO_BASE + 0x410, (uval & 0xFFFFF1FF) | 0xA00);
+
+		uval = DRV_Reg32(GPIO_BASE + 0x410);
+		PRINTF_I("after set to gpio%d to pwm mode %d: 0x10005410: 0x%x\n", gpio_no, mode, uval);
+
+		// verify gpio88 is mode 5
+		if((uval & 0xA00) != 0xA00) {
+			PRINTF_E("gpio 88 is not mode 5!\n");
+			return -1;
+		}
+		return 0;
+	}
+	return -2;
+}
+
+// set the specified pwm to specified freq: eg: 0, 32000 means: pwm0, 32K
+// return value: if return 0, means set susscessful, if return is not 0, means failed
+static int pwm_set_pwm_freq(int pwm_no, int freq)
+{
+	int ret;
+	int val;
+	
+	PRINTF_I("pwm_set_pwm_freq: pwm_no:%d, freq:%d\n", pwm_no, freq);
+	
+	ret = pwm_config_freq(pwm_no, freq);
+	if(ret == 0) {
+		val = pwm_get_period(pwm_no);
+		ret = pwm_set_duty(pwm_no, val / 2);	// duty is set to period / 2
+		if(ret == 0)
+			ret = pwm_enable(0);
+		else {
+			PRINTF_E("set duty failed!\n");
+			goto error;
+		}
+
+		if(ret == 0) {
+			PRINTF_I("enable pwm %d successfully!\n", 0);
+ 		} else {
+			PRINTF_E("enable pwm %d failed!\n", 0);
+			goto error;
+		}
+	} else {
+		PRINTF_E("config freq failed!\n");
+		goto error;
+	}
+
+	return 0;
+	
+error:
+	return -1;
+}
+
+// #define PWM_TEST
+void pwm_init (void)
+{
+#ifdef PWM_TEST
+	int ret;
+#endif
+
+	PRINTF_I("[pwm_init] Init Start..................\n");
+
+	#if CLK_API_IS_READY
+		// get clock here
+	#endif
+
+#ifdef PWM_TEST
+	ret = pwm_set_gpio_mode(88, 5);
+	if (ret != 0) {
+		PRINTF_E("set gpio 88 to mode 5 failed!\n");
+		return;
+	}
+	ret = pwm_set_pwm_freq(0, 1000000);
+	if (ret != 0) {
+		PRINTF_E("pwm_set_pwm_freq: set pwm_no:%d to freq:%d failed!\n", 0, 1000000);
+		return;
+	}
+	
+	PRINTF_I("Now, we stop here to let you check: the pwm wave should be working!\n");
+
+	#if 0
+		while(1)
+			;
+	#endif
+#endif	
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/pwrap/pmic_wrap_init.c b/src/bsp/lk/platform/mt8518/drivers/pwrap/pmic_wrap_init.c
new file mode 100644
index 0000000..ce0513a
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/pwrap/pmic_wrap_init.c
@@ -0,0 +1,655 @@
+/* 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.
+ */
+#include <reg.h>
+#include <platform/pmic_wrap_init.h>
+#include <platform/mtk_timer.h>
+#include <platform/pmic.h>
+#include "platform/mt_reg_base.h"
+
+#define PWRAP_INT_GPIO_BASE (IO_PHYS+0x00005610)
+
+#define pwrap_log(fmt, arg ...)   printf("[PWRAP] " fmt, ## arg)
+#define pwrap_err(fmt, arg ...)	  printf("[PWRAP] ERROR,line=%d" fmt, \
+					__LINE__, ## arg)
+
+static s32 pwrap_read_nochk(u32 adr, u32 *rdata);
+static s32 pwrap_write_nochk(u32 adr, u32 wdata);
+
+extern lk_bigtime_t current_time_hires(void);
+
+/* define macro and inline function (for do while loop) */
+
+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_cipher_ready(u32 x)
+{
+	return x != 3;
+}
+
+static inline 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_time = 0, timeout_time = 0;
+
+	start_time = current_time_hires();
+	timeout_time = start_time + timeout_us;
+
+	do {
+		reg_rdata = read32((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:
+			write32(wacs_vldclr_register, 1);
+			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() >= timeout_time)
+			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;
+}
+
+static inline 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_time = 0, timeout_time = 0;
+
+	start_time = current_time_hires();
+	timeout_time = start_time + timeout_us;
+
+	do {
+		reg_rdata = read32((wacs_register));
+
+		if (current_time_hires() >= timeout_time) {
+			pwrap_err("timeout when waiting for idle\n");
+			return E_PWR_WAIT_IDLE_TIMEOUT;
+		}
+	} while (fp(reg_rdata));        /* IDLE State */
+	if (read_reg)
+		*read_reg = reg_rdata;
+	return 0;
+}
+
+static s32 pwrap_wacs(u32 write, u32 adr, u32 wdata, u32 *rdata, u32 init_check)
+{
+	u32 reg_rdata = 0;
+	u32 wacs_write = 0;
+	u32 wacs_adr = 0;
+	u32 wacs_cmd = 0;
+	u32 return_value = 0;
+
+	if (init_check) {
+		reg_rdata = read32(&mt8518_pwrap->wacs2_rdata);
+		/* Prevent someone to used pwrap before pwrap init */
+		if (((reg_rdata >> RDATA_INIT_DONE_SHIFT) &
+		    RDATA_INIT_DONE_MASK) != WACS_INIT_DONE) {
+			pwrap_err("initialization isn't finished \n");
+			return E_PWR_NOT_INIT_DONE;
+		}
+	}
+	reg_rdata = 0;
+	/* Check IDLE in advance */
+	return_value = wait_for_state_idle(TIMEOUT_WAIT_IDLE_US,
+					   &mt8518_pwrap->wacs2_rdata,
+					   &mt8518_pwrap->wacs2_vldclr,
+					   0);
+	if (return_value != 0) {
+		pwrap_err("wait_for_fsm_idle fail,return_value=%d\n",
+			  return_value);
+		return E_PWR_WAIT_IDLE_TIMEOUT;
+	}
+	wacs_write = write << 31;
+	wacs_adr = (adr >> 1) << 16;
+	wacs_cmd = wacs_write | wacs_adr | wdata;
+
+	write32(&mt8518_pwrap->wacs2_cmd, wacs_cmd);
+	if (write == 0) {
+		if (NULL == rdata) {
+			pwrap_err("rdata is a NULL pointer\n");
+			return E_PWR_INVALID_ARG;
+		}
+		return_value = wait_for_state_ready(wait_for_fsm_vldclr,
+						    TIMEOUT_READ_US,
+						    &mt8518_pwrap->wacs2_rdata,
+						    &reg_rdata);
+		if (return_value != 0) {
+			pwrap_err("wait_for_fsm_vldclr fail,return_value=%d\n",
+				  return_value);
+			return E_PWR_WAIT_IDLE_TIMEOUT_READ;
+		}
+		*rdata = ((reg_rdata >> RDATA_WACS_RDATA_SHIFT)
+			  & RDATA_WACS_RDATA_MASK);
+		write32(&mt8518_pwrap->wacs2_vldclr, 1);
+	}
+
+	return 0;
+}
+
+/* external API for pmic_wrap user */
+
+s32 pwrap_wacs2(u32 write, u32 adr, u32 wdata, u32 *rdata)
+{
+	return pwrap_wacs(write, adr, wdata, rdata, 1);
+}
+
+s32 pwrap_read(u32 adr, u32 *rdata)
+{
+	return pwrap_wacs(0, adr, 0, rdata, 1);
+}
+
+s32 pwrap_write(u32 adr, u32 wdata)
+{
+	return pwrap_wacs(1, adr, wdata, 0, 1);
+}
+
+static s32 pwrap_read_nochk(u32 adr, u32 *rdata)
+{
+	return pwrap_wacs(0, adr, 0, rdata, 0);
+}
+
+static s32 pwrap_write_nochk(u32 adr, u32 wdata)
+{
+	return pwrap_wacs(1, adr, wdata, 0, 0);
+}
+
+/* call it in pwrap_init,mustn't check init done */
+static s32 pwrap_init_dio( u32 dio_en )
+{
+  u32 arb_en_backup=0x0;
+  u32 rdata=0x0;
+  u32 return_value=0;
+
+  arb_en_backup = read32(&mt8518_pwrap->hiprio_arb_en);
+
+  write32(&mt8518_pwrap->hiprio_arb_en , WACS2); // only WACS2
+
+  pwrap_write_nochk(DEW_DIO_EN, dio_en);
+
+  // Check IDLE & INIT_DONE in advance
+  return_value =
+  wait_for_state_ready(wait_for_idle_and_sync,
+  				TIMEOUT_WAIT_IDLE_US,
+  				&mt8518_pwrap->wacs2_rdata,
+  				0);
+  if(return_value!=0)
+  {
+    pwrap_err("pwrap_init_dio fail,return_value=%d\n", return_value);
+    return return_value;
+  }
+
+  write32(&mt8518_pwrap->dio_en, dio_en);
+  // Read Test
+  pwrap_read_nochk(DEW_READ_TEST,&rdata);
+  if( rdata != DEFAULT_VALUE_READ_TEST )
+  {
+    pwrap_err("[Dio_mode][Read Test] fail,dio_en = %x, READ_TEST rdata=%x, exp=0x5aa5\n", dio_en, rdata);
+    return E_PWR_READ_TEST_FAIL;
+  }
+
+  write32(&mt8518_pwrap->hiprio_arb_en , arb_en_backup);
+
+  return 0;
+}
+
+
+static int pwrap_init_cipher(void)
+{
+	u32 rdata = 0;
+	u32 return_value = 0;
+	lk_bigtime_t start_time = 0, timeout_time = 0;
+	u32 arb_en_backup = 0;
+
+	arb_en_backup = read32(&mt8518_pwrap->hiprio_arb_en);
+
+	write32(&mt8518_pwrap->hiprio_arb_en, WACS2);	/* only WACS2 */
+
+	/* Config cipher mode @AP */
+	write32(&mt8518_pwrap->cipher_swrst, 0x1);
+	write32(&mt8518_pwrap->cipher_swrst, 0x0);
+	write32(&mt8518_pwrap->cipher_key_sel, 0x1);
+	write32(&mt8518_pwrap->cipher_iv_sel, 0x2);
+	write32(&mt8518_pwrap->cipher_en, 0x1);
+
+	/* Config cipher mode @PMIC */
+	pwrap_write_nochk(DEW_CIPHER_SWRST,   0x1);
+	pwrap_write_nochk(DEW_CIPHER_SWRST,   0x0);
+	pwrap_write_nochk(DEW_CIPHER_KEY_SEL, 0x1);
+	pwrap_write_nochk(DEW_CIPHER_IV_SEL,  0x2);
+	pwrap_write_nochk(DEW_CIPHER_LOAD,    0x1);
+	pwrap_write_nochk(DEW_CIPHER_START,   0x1);
+
+	/* wait for cipher data ready@AP */
+	return_value = wait_for_state_ready(wait_for_cipher_ready,
+			     TIMEOUT_WAIT_IDLE_US,
+			     &mt8518_pwrap->cipher_rdy,
+			     0);
+	if (return_value != 0) {
+		pwrap_err("pwrap_init_cipher fail,return_value=%d\n", return_value);
+		return return_value;
+	}
+
+	/* wait for cipher data ready@PMIC */
+	start_time = current_time_hires();
+	timeout_time = start_time + 0xFFFFFF;
+	do
+	{
+		if (current_time_hires() >= timeout_time)
+		{
+			pwrap_err("timeout when waiting for cipher data ready@PMIC\n");
+			return E_PWR_WAIT_IDLE_TIMEOUT;
+		}
+		pwrap_read_nochk(DEW_CIPHER_RDY,&rdata);
+	} while( rdata != 0x1 ); /* cipher_ready */
+
+	pwrap_write_nochk(DEW_CIPHER_MODE, 0x1);
+
+	/* wait for cipher mode idle */
+	return_value = wait_for_state_ready(wait_for_idle_and_sync,
+			     TIMEOUT_WAIT_IDLE_US,
+			     &mt8518_pwrap->wacs2_rdata,
+			     0);
+	if (return_value != 0) {
+		pwrap_err("pwrap_init_cipher fail,return_value=%d\n", return_value);
+		return return_value;
+	}
+
+	write32(&mt8518_pwrap->cipher_mode, 0x1);
+
+	/* Read Test */
+	pwrap_read_nochk(DEW_READ_TEST, &rdata);
+	if (rdata != DEFAULT_VALUE_READ_TEST) {
+		pwrap_err("pwrap_init_cipher fail, READ_TEST rdata=%x\n", rdata);
+		return E_PWR_READ_TEST_FAIL;
+	}
+
+	write32(&mt8518_pwrap->hiprio_arb_en, arb_en_backup);
+
+	return 0;
+}
+
+/*
+ * pwrap_init_sidly - configure serial input delay
+ *
+ * This configures the serial input delay. We can configure 0, 2, 4 or 6ns
+ * delay. Do a read test with all possible values and chose the best delay.
+ */
+static s32 pwrap_init_sidly(void)
+{
+	u32 arb_en_backup = 0;
+	u32 rdata = 0;
+	s32 ind = 0;
+	u32 tmp1 = 0;
+	u32 tmp2 = 0;
+	u32 result_faulty = 0;
+	u32 result = 0;
+	u32 leading_one, tailing_one;
+
+	arb_en_backup = read32(&mt8518_pwrap->hiprio_arb_en);
+
+	write32(&mt8518_pwrap->hiprio_arb_en, WACS2);	/* only WACS2 */
+
+	/* --------------------------------------------------------------------- */
+	/* Scan all possible input strobe by READ_TEST */
+	/* --------------------------------------------------------------------- */
+	/* 24 sampling clock edge */
+	for (ind = 0; ind < 24; ind++)	/* 24 sampling clock edge */
+	{
+		write32(&mt8518_pwrap->si_ck_con, (ind >> 2) & 0x7);
+		write32(&mt8518_pwrap->sidly, 0x3 - (ind & 0x3));
+		pwrap_read_nochk(DEW_READ_TEST, &rdata);
+		if( rdata == DEFAULT_VALUE_READ_TEST )
+		{
+			pwrap_log("_pwrap_init_sidly [Read Test] pass,index=%d rdata=%x\n", ind,rdata);
+			result |= (0x1 << ind);
+		}
+		else
+			pwrap_log("_pwrap_init_sidly [Read Test] fail,index=%d,rdata=%x\n", ind,rdata);
+	}
+	/* --------------------------------------------------------------------- */
+	/* Locate the leading one and trailing one of PMIC 1/2 */
+	/* --------------------------------------------------------------------- */
+	for( ind=23 ; ind>=0 ; ind-- )
+	{
+		if( result & (0x1 << ind) ) break;
+	}
+	leading_one = ind;
+	
+	for( ind=0 ; ind<24 ; ind++ )
+	{
+		if( result & (0x1 << ind) ) break;
+	}
+	tailing_one = ind;
+
+	/* --------------------------------------------------------------------- */
+	/* Check the continuity of pass range */
+	/* --------------------------------------------------------------------- */
+	tmp1 = (0x1 << (leading_one+1)) - 1;
+	tmp2 = (0x1 << tailing_one) - 1;
+	if( (tmp1 - tmp2) != result )
+	{
+		/*TERR = "[DrvPWRAP_InitSiStrobe] Fail, tmp1:%d, tmp2:%d", tmp1, tmp2*/
+		pwrap_err("_pwrap_init_sidly Fail,tmp1=%x,tmp2=%x\n", tmp1,tmp2);
+		result_faulty = 0x1;
+	}
+
+	/* --------------------------------------------------------------------- */
+	/* Config SICK and SIDLY to the middle point of pass range */
+	/* --------------------------------------------------------------------- */
+	ind = (leading_one + tailing_one)/2;
+	write32(&mt8518_pwrap->si_ck_con , (ind >> 2) & 0x7);
+	write32(&mt8518_pwrap->sidly , 0x3 - (ind & 0x3));
+
+	/* --------------------------------------------------------------------- */
+	/* Restore */
+	/* --------------------------------------------------------------------- */
+	write32(&mt8518_pwrap->hiprio_arb_en, arb_en_backup);
+
+	if( result_faulty == 0 )
+		return 0;
+	else
+	{
+		pwrap_err("_pwrap_init_sidly Fail,result=%x\n", result);
+		return result_faulty;
+	}
+}
+
+
+static s32 pwrap_reset_spislv(void)
+{
+	u32 ret = 0;
+	u32 return_value = 0;
+
+	write32(&mt8518_pwrap->hiprio_arb_en, 0);
+	write32(&mt8518_pwrap->wrap_en, 0);
+	write32(&mt8518_pwrap->mux_sel, 1);
+	write32(&mt8518_pwrap->man_en, 1);
+	write32(&mt8518_pwrap->dio_en, 0);
+
+	write32(&mt8518_pwrap->man_cmd, (OP_WR << 13) | (OP_CSL << 8));
+	/* to reset counter */
+	write32(&mt8518_pwrap->man_cmd, (OP_WR << 13) | (OP_OUTS << 8));
+	write32(&mt8518_pwrap->man_cmd, (OP_WR << 13) | (OP_CSH << 8));
+	/*
+	 * In order to pull CSN signal to PMIC,
+	 * PMIC will count it then reset spi slave
+	*/
+	write32(&mt8518_pwrap->man_cmd, (OP_WR << 13) | (OP_OUTS << 8));
+	write32(&mt8518_pwrap->man_cmd, (OP_WR << 13) | (OP_OUTS << 8));
+	write32(&mt8518_pwrap->man_cmd, (OP_WR << 13) | (OP_OUTS << 8));
+	write32(&mt8518_pwrap->man_cmd, (OP_WR << 13) | (OP_OUTS << 8));
+
+	return_value = wait_for_state_ready(wait_for_sync,
+					    TIMEOUT_WAIT_IDLE_US,
+					    &mt8518_pwrap->wacs2_rdata, 0);
+	if (return_value != 0) {
+		pwrap_err("pwrap_reset_spislv fail,return_value=%d\n", return_value);
+		ret = E_PWR_TIMEOUT;
+	}
+
+	write32(&mt8518_pwrap->man_en, 0);
+	write32(&mt8518_pwrap->mux_sel, 0);
+
+	return ret;
+}
+
+static s32 pwrap_init_reg_clock(enum pmic_regck regck_sel)
+{
+	u32 wdata = 0;
+	u32 rdata = 0;
+
+	/* Set reg clk freq */
+	pwrap_read_nochk(PMIC_TOP_CKCON2, &rdata); 
+	if (regck_sel == 1)
+		wdata = (rdata & (~(0x3 << 10))) | (0x1 << 10);
+	else
+		wdata = rdata & (~(0x3 << 10));
+
+	pwrap_write_nochk(PMIC_TOP_CKCON2, wdata);
+	pwrap_read_nochk(PMIC_TOP_CKCON2, &rdata);
+	if (rdata != wdata) {
+		pwrap_err("pwrap_init_reg_clock,PMIC_TOP_CKCON2 Write [15]=1 Fail, rdata=%x\n",
+				rdata);
+	return E_PWR_INIT_REG_CLOCK;
+	}
+
+	/* Config SPI Waveform according to reg clk */
+	switch (regck_sel) {
+	case REG_CLOCK_12MHZ:
+		write32(&mt8518_pwrap->rddmy, 0xc);
+		write32(&mt8518_pwrap->cshext_write, 0x0);
+		write32(&mt8518_pwrap->cshext_read, 0x4);
+		write32(&mt8518_pwrap->cslext_start, 0x0);
+		write32(&mt8518_pwrap->cslext_end, 0x4);
+		break;
+	case REG_CLOCK_24MHZ:
+		write32(&mt8518_pwrap->rddmy, 0x2);
+		write32(&mt8518_pwrap->cshext_write, 0x5);
+		write32(&mt8518_pwrap->cshext_read, 0x5);
+		write32(&mt8518_pwrap->cslext_start, 0xf);
+		write32(&mt8518_pwrap->cslext_end, 0xf);
+		break;
+	default:
+		write32(&mt8518_pwrap->rddmy, 0xf);
+		write32(&mt8518_pwrap->cshext_write, 0xf);
+		write32(&mt8518_pwrap->cshext_read, 0xf);
+		write32(&mt8518_pwrap->cslext_start, 0xf);
+		write32(&mt8518_pwrap->cslext_end, 0xf);
+		break;
+	}
+
+	return 0;
+}
+
+s32 pwrap_init(void)
+{
+	s32 sub_return = 0;
+	s32 sub_return1 = 0;
+	u32 rdata = 0x0;
+	u32 cg_mask = 0;
+	u32 gpio_val;
+
+	/* Turn off module clock */
+	cg_mask = PWRAP_CG_TMR| PWRAP_CG_SPI| PWRAP_CG_SYS;
+	write32(MODULE_SW_CG_1_SET, cg_mask);
+
+	/* dummy read to add latency (to wait clock turning off) */
+	rdata = read32(&mt8518_pwrap->swrst);
+
+	/* Toggle module reset */
+	write32(&mt8518_pwrap->swrst, 1);
+
+	/*reset pwrap_spictrl config swrst register in toprgu*/
+	/*rdata = read32(MODULE_SW_WDT_RST);
+
+	write32(MODULE_SW_WDT_RST, (rdata | 0x00004000) | (0x88 << 24));
+	write32(MODULE_SW_WDT_RST, (rdata & 0xffffbfff) | (0x88 << 24));*/
+
+	write32(&mt8518_pwrap->swrst, 0);
+
+	/* Turn on module clock */
+	write32(MODULE_SW_CG_1_CLR, cg_mask);
+
+	/* Turn on module clock dcm (in global_con) CHECK ME*/
+	/*write32(MODULE_SW_CG_3_SET, read32(MODULE_SW_CG_3_SET) | PMIC_B_DCM_EN | PMIC_SPI_DCM_EN);*/
+
+	/*set 0x1000F0AC[30]=1 for CK pin normal work*/
+	rdata = read32(&mt8518_pwrap->int_en);
+	write32(&mt8518_pwrap->int_en, (rdata | (0x1 << 30)));
+
+	/* Enable DCM */
+	write32(&mt8518_pwrap->dcm_en, 3);
+	write32(&mt8518_pwrap->dcm_dbc_prd, 0);
+
+	/*Set slave to MT6397/MT6391*/
+	write32(&mt8518_pwrap->op_type, 1);
+	write32(&mt8518_pwrap->msb_first, 0);
+
+	/* Reset SPISLV */
+	sub_return = pwrap_reset_spislv();
+	if (sub_return != 0) {
+		pwrap_err("error,pwrap_reset_spislv fail,sub_return=%x\n",
+			  sub_return);
+		return E_PWR_INIT_RESET_SPI;
+	}
+	/* Enable WACS2 */
+	write32(&mt8518_pwrap->wrap_en, 1);
+	write32(&mt8518_pwrap->hiprio_arb_en, WACS2);
+	write32(&mt8518_pwrap->wacs2_en, 1);
+
+	/*According to MT6391*/
+	write32(&mt8518_pwrap->rddmy, 0x8);
+
+	/* SIDLY setting */
+	sub_return = pwrap_init_sidly();
+	if (sub_return != 0) {
+		pwrap_err("error,pwrap_init_sidly fail,sub_return=%x\n",
+			  sub_return);
+		return E_PWR_INIT_SIDLY;
+	}
+	/*
+	 * SPI Waveform Configuration
+	 * safe mode/12MHz/24MHz/
+	 */
+	sub_return = pwrap_init_reg_clock(REG_CLOCK_24MHZ);
+	if (sub_return != 0) {
+		pwrap_err("error,pwrap_init_reg_clock fail,sub_return=%x\n",
+			  sub_return);
+		return E_PWR_INIT_REG_CLOCK;
+	}
+
+	/*PMIC MT6391 settings*/
+	sub_return = pwrap_write_nochk(PMIC_WRP_CKPDN, 0);
+	sub_return = pwrap_write_nochk(PMIC_WRP_RST_CON, 0);
+
+	/* Enable DIO mode */
+	sub_return = pwrap_init_dio(1);
+	if (sub_return != 0) {
+		pwrap_err("pwrap_init_dio fail, sub_return=%x\n", sub_return);
+		return E_PWR_INIT_DIO;
+	}
+
+	/* Enable Encryption */
+	sub_return = pwrap_init_cipher();
+	if (sub_return != 0) {
+		pwrap_err("pwrap_init_cipher fail, sub_return=%x\n", sub_return);
+		return E_PWR_INIT_CIPHER;
+	}
+
+	/*
+	 * Write test using WACS2,
+	 * make sure the read/write function ready
+	 */
+	sub_return = pwrap_write_nochk(DEW_WRITE_TEST, WRITE_TEST_VALUE);
+	sub_return1 = pwrap_read_nochk(DEW_WRITE_TEST, &rdata);
+	if ((rdata != WRITE_TEST_VALUE) || (sub_return != 0)
+	    || (sub_return1 != 0)) {
+		pwrap_err("write error, rdata=%x, return=%x, return1=%x\n",
+			  rdata, sub_return, sub_return1);
+		return E_PWR_INIT_WRITE_TEST;
+	}
+
+	/* Signature Checking - Using CRC
+	 * should be the last to modify WRITE_TEST
+	 */
+	sub_return = pwrap_write_nochk(DEW_CRC_EN, 0x1);
+	if (sub_return != 0) {
+		pwrap_err("enable CRC fail,sub_return=%x\n", sub_return);
+		return E_PWR_INIT_ENABLE_CRC;
+	}
+	write32(&mt8518_pwrap->crc_en, 0x1);
+	write32(&mt8518_pwrap->sig_mode, 0x0);
+	write32(&mt8518_pwrap->sig_adr, read32(&mt8518_pwrap->sig_adr) | DEW_CRC_VAL);
+
+	/* PMIC_WRAP enables */
+	write32(&mt8518_pwrap->hiprio_arb_en, 0x7f);
+	write32(&mt8518_pwrap->wacs0_en, 0x1);
+	write32(&mt8518_pwrap->wacs1_en, 0x1);
+	write32(&mt8518_pwrap->staupd_prd, 0x5);
+
+	/*initial settings for wachdod and interrupts*/
+	/*write32(&mt8518_pwrap->wdt_unit, 0xf);
+	write32(&mt8518_pwrap->wdt_src_en, 0xffffffff);
+	write32(&mt8518_pwrap->timer_en, 0x1);
+	write32(&mt8518_pwrap->int_en, 0x7ffffff9);*/
+
+	/* Initialization Done */
+	write32(&mt8518_pwrap->init_done2, 0x1);
+	write32(&mt8518_pwrap->init_done0, 0x1);
+	write32(&mt8518_pwrap->init_done1, 0x1);
+
+	/*set gpio27 PMIC_INT to pull down cause the default state is pull up and wrong in E1 IC*/
+	gpio_val = (read32(PWRAP_INT_GPIO_BASE) & (~(0x1 << 11))) | (0x0 << 11);
+	write32(PWRAP_INT_GPIO_BASE, gpio_val);
+
+	return 0;
+}
diff --git a/src/bsp/lk/platform/mt8518/drivers/rules.mk b/src/bsp/lk/platform/mt8518/drivers/rules.mk
new file mode 100644
index 0000000..1c70862
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/rules.mk
@@ -0,0 +1,54 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/uart/uart.c    \
+    $(LOCAL_DIR)/pll/pll.c \
+    $(LOCAL_DIR)/spm/spm_mtcmos.c \
+    $(LOCAL_DIR)/wdt/mtk_wdt.c \
+    $(LOCAL_DIR)/i2c/mt_i2c.c \
+    $(LOCAL_DIR)/usb/mt_usb.c \
+    $(LOCAL_DIR)/usb/usbtty.c \
+    $(LOCAL_DIR)/usb/handshake_usb.c \
+    $(LOCAL_DIR)/usb/platform_usb.c \
+    $(LOCAL_DIR)/usb/usb_toolhandler.c \
+    $(LOCAL_DIR)/gic/mt_gic_v3.c \
+    $(LOCAL_DIR)/gic/mt_gic.S \
+    $(LOCAL_DIR)/key/mtk_key.c \
+    $(LOCAL_DIR)/trng/mtk_trng.c \
+    $(LOCAL_DIR)/pwm/pwm.c \
+
+ifeq ($(WITH_LP5523_LED),1)
+MODULE_SRCS += $(LOCAL_DIR)/led/mtk_led.c
+endif
+MODULE_SRCS += $(LOCAL_DIR)/charger/rt9460.c
+
+ifeq ($(WITH_MTK_PMIC_WRAP_AND_PMIC), 1)
+    MODULE_SRCS += $(LOCAL_DIR)/pwrap/pmic_wrap_init.c
+    MODULE_SRCS += $(LOCAL_DIR)/pmic/pmic.c
+endif
+
+ifeq ($(WITH_PMIC_MT6395), 1)
+    MODULE_SRCS += $(LOCAL_DIR)/pmic/pmic_6395.c
+endif
+
+ifeq ($(WITH_VCORE_I2C_BUCK), 1)
+    MODULE_SRCS += $(LOCAL_DIR)/pmic/rt5748.c
+endif
+
+ifeq ($(WITH_VCORE_PWM_BUCK), 1)
+    MODULE_SRCS += $(LOCAL_DIR)/pmic/pwm_buck.c
+endif
+
+ifeq ($(FPGA_PLATFORM), 1)
+    MODULE_SRCS += $(LOCAL_DIR)/usb/md1122.c
+endif
+
+MODULE_EXTRA_OBJS += \
+    $(LOCAL_DIR)/../lib/libdevinfo.o
+
+MODULE_DEPS += \
+    ../dramk_8518/dram
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mt8518/drivers/scp/mt_scp.c b/src/bsp/lk/platform/mt8518/drivers/scp/mt_scp.c
new file mode 100644
index 0000000..1fb8a8e
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/scp/mt_scp.c
@@ -0,0 +1,116 @@
+/*
+ * 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 <app.h>
+#include <reg.h>
+#include <errno.h>
+#include <string.h>
+#include <lib/bio.h>
+#include <lib/mempool.h>
+#include <platform/mt8518.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mt_scp.h>
+
+void start_scpsys(void)
+{
+	u32 reg;
+	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);
+}
+
+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);
+
+}
+
+static int get_scpsys(const char *name, union fm_hdr_t *fm_hdr, void *buf)
+{
+    bdev_t *bdev;
+    size_t totalsize; //sram size
+
+    bdev = bio_open_by_label(name);
+    if (!bdev) {
+        dprintf(CRITICAL, "Partition [%s] is not exist.\n", name);
+        return -ENODEV;
+    }
+
+    totalsize = bio_read(bdev, fm_hdr, 0, sizeof(union fm_hdr_t));
+    if (totalsize <= 0) {
+        dprintf(CRITICAL, "error reading scp header\n");
+        return totalsize;
+    }
+
+    if (fm_hdr->info.magic != PART_MAGIC || fm_hdr->info.dsize > MAX_SCPSYS_SIZE) {
+	printf("scp: firmware information incorrect!\n");
+			return -EINVAL;
+    }
+
+    totalsize = bio_read(bdev, buf, sizeof(union fm_hdr_t),
+                         fm_hdr->info.dsize);
+    if (totalsize <= 0) {
+        dprintf(CRITICAL, "error reading scp data\n");
+        return totalsize;
+    }
+
+    dprintf(CRITICAL, "scp: load scp image success!\n");
+    return 0;
+}
+
+int load_scpsys(void)
+{
+    int err = 0;
+    void *buf = mempool_alloc(MAX_SCPSYS_SIZE, MEMPOOL_ANY);
+    union fm_hdr_t *fm_hdr = mempool_alloc(sizeof(union fm_hdr_t), MEMPOOL_ANY);
+
+    if (!buf || !fm_hdr)
+    {
+        dprintf(CRITICAL, "scp: fail to alloc memory!\n");
+    }
+
+    //load cmsys from flash to fit_data->buf.
+    err = get_scpsys(SCPSYS_PART_NAME, fm_hdr, buf);
+    if (err) {
+        dprintf(CRITICAL, "scp: fail to load scp image!\n");
+        goto done;
+    }
+    memcpy(SCP_BASE_SRAM, buf, fm_hdr->info.dsize);
+
+done:
+    mempool_free(buf);
+    mempool_free(fm_hdr);
+    return err;
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/scp/rules.mk b/src/bsp/lk/platform/mt8518/drivers/scp/rules.mk
new file mode 100644
index 0000000..88d5a5d
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/scp/rules.mk
@@ -0,0 +1,20 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+
+CFLAGS := $(filter-out -Werror, $(CFLAGS))
+GLOBAL_CFLAGS := $(filter-out -Werror, $(GLOBAL_CFLAGS))
+
+CFLAGS := $(filter-out -Werror=return-type, $(CFLAGS))
+GLOBAL_CFLAGS := $(filter-out -Werror=return-type, $(GLOBAL_CFLAGS))
+
+CFLAGS := $(filter-out -Werror=implicit-function-declaration, $(CFLAGS))
+GLOBAL_CFLAGS := $(filter-out -Werror=implicit-function-declaration, $(GLOBAL_CFLAGS))
+
+MODULE_DEPS += \
+    lib/bio \
+    lib/partition \
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/mt_scp.c
+
+include make/module.mk
diff --git a/src/bsp/lk/platform/mt8518/drivers/spm/spm_mtcmos.c b/src/bsp/lk/platform/mt8518/drivers/spm/spm_mtcmos.c
new file mode 100644
index 0000000..bb0a785
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/spm/spm_mtcmos.c
@@ -0,0 +1,335 @@
+#include <reg.h>
+#include <platform/mt8518.h>
+#include <platform/spm.h>
+#include <platform/spm_mtcmos.h>
+#include <platform/pll.h>
+
+#define USE_SPIN    0
+
+#define spm_mtcmos_noncpu_lock(x)   (*(&x) = 0)
+#define spm_mtcmos_noncpu_unlock(x) (*(&x) = 0)
+
+#if USE_SPIN
+
+#define udelay(x)       spin(x)
+#define mdelay(x)       udelay((x) * 1000)
+
+#else /* !USE_SPIN */
+
+#define my_delay(count) \
+    do { \
+        volatile unsigned int i = count * 26; \
+        for (; i != 0; i--); \
+    } while (0)
+
+#define udelay(x)       my_delay(x)
+#define mdelay(x)       udelay((x) * 1000)
+
+#endif              /* USE_SPIN */
+
+/**************************************
+ * for non-CPU MTCMOS
+ **************************************/
+#define DIS_PWR_STA_MASK    (0x1 << 3)
+#define CM4_PWR_STA_MASK   (0x1 << 16)
+#define AUDAFE_PWR_STA_MASK    (0x1 << 21)
+#define AUDSRC_PWR_STA_MASK    (0x1 << 20)
+
+#define DIS_SRAM_PDN        (0xf << 8)
+#define CM4_SRAM_PDN        (0x1 << 8)
+#define AUDAFE_SRAM_PDN        (0xf << 8)
+#define AUDSRC_SRAM_PDN        (0x1 << 8)
+
+#define DIS_SRAM_ACK        (0x1 << 12)
+#define CM4_SRAM_ACK        (0x1 << 9)
+#define AUDAFE_SRAM_ACK        (0xf << 12)
+#define AUDSRC_SRAM_ACK        (0x1 << 9)
+
+#define DISP_PROT_MASK       ((0x1 << 1))   /* bit 1 */
+#define CM4_PROT_MASK       ((0x1 << 7) | (0x1 << 8)| (0x1 << 9))   /* bit 7, 8 ,9 */
+#define AUDAFE_PROT_MASK       ((0x1 << 25) | (0x1 << 26)| (0x1 << 28))   /* bit 25, 26 ,28 */
+#define AUDSRC_PROT_MASK       ((0x1 << 27))   /* bit 27 */
+
+#define PWR_CLK_DIS             (1U << 4)
+#define PWR_ON_2ND              (1U << 3)
+#define PWR_ON                  (1U << 2)
+#define PWR_ISO                 (1U << 1)
+#define PWR_RST_B               (1U << 0)
+#define SRAM_CKISO              (1U << 5)
+#define SRAM_ISOINT_B           (1U << 6)
+
+int spm_mtcmos_ctrl_disp(int state)
+{
+    int err = 0;
+    unsigned int val;
+    unsigned long flags;
+
+    spm_mtcmos_noncpu_lock(flags);
+
+    if (state == STA_POWER_DOWN) {
+        spm_write(TOPAXI_PROT_EN,
+                  spm_read(TOPAXI_PROT_EN) | DISP_PROT_MASK);
+        while ((spm_read(TOPAXI_PROT_STA1) & DISP_PROT_MASK) !=
+                DISP_PROT_MASK) {
+        }
+
+        spm_write(SPM_DIS_PWR_CON,
+                  spm_read(SPM_DIS_PWR_CON) | DIS_SRAM_PDN);
+
+        while ((spm_read(SPM_DIS_PWR_CON) & DIS_SRAM_ACK) !=
+                DIS_SRAM_ACK) {
+        }
+
+        spm_write(SPM_DIS_PWR_CON, spm_read(SPM_DIS_PWR_CON) | PWR_ISO);
+
+        val = spm_read(SPM_DIS_PWR_CON);
+        val = (val & ~PWR_RST_B) | PWR_CLK_DIS;
+        spm_write(SPM_DIS_PWR_CON, val);
+
+        spm_write(SPM_DIS_PWR_CON,
+                  spm_read(SPM_DIS_PWR_CON) & ~(PWR_ON | PWR_ON_2ND));
+
+        while ((spm_read(SPM_PWR_STATUS) & DIS_PWR_STA_MASK)
+                || (spm_read(SPM_PWR_STATUS_2ND) & DIS_PWR_STA_MASK)) {
+        }
+    } else {    /* STA_POWER_ON */
+        spm_write(SPM_DIS_PWR_CON, spm_read(SPM_DIS_PWR_CON) | PWR_ON);
+        spm_write(SPM_DIS_PWR_CON,
+                  spm_read(SPM_DIS_PWR_CON) | PWR_ON_2ND);
+
+        while (!(spm_read(SPM_PWR_STATUS) & DIS_PWR_STA_MASK)
+                || !(spm_read(SPM_PWR_STATUS_2ND) & DIS_PWR_STA_MASK)) {
+        }
+
+        spm_write(SPM_DIS_PWR_CON,
+                  spm_read(SPM_DIS_PWR_CON) & ~PWR_CLK_DIS);
+        spm_write(SPM_DIS_PWR_CON,
+                  spm_read(SPM_DIS_PWR_CON) & ~PWR_ISO);
+        spm_write(SPM_DIS_PWR_CON,
+                  spm_read(SPM_DIS_PWR_CON) | PWR_RST_B);
+
+        spm_write(SPM_DIS_PWR_CON,
+                  spm_read(SPM_DIS_PWR_CON) & ~DIS_SRAM_PDN);
+
+        while ((spm_read(SPM_DIS_PWR_CON) & DIS_SRAM_ACK)) {
+        }
+
+        spm_write(TOPAXI_PROT_EN,
+                  spm_read(TOPAXI_PROT_EN) & ~DISP_PROT_MASK);
+        while (spm_read(TOPAXI_PROT_STA1) & DISP_PROT_MASK) {
+        }
+    }
+
+    spm_mtcmos_noncpu_unlock(flags);
+
+    return err;
+}
+
+int spm_mtcmos_ctrl_cm4(int state)
+{
+    int err = 0;
+    unsigned int val;
+    unsigned long flags;
+
+    spm_mtcmos_noncpu_lock(flags);
+
+    if (state == STA_POWER_DOWN) {
+        spm_write(TOPAXI_PROT_EN,
+                  spm_read(TOPAXI_PROT_EN) | CM4_PROT_MASK);
+        while ((spm_read(TOPAXI_PROT_STA1) & CM4_PROT_MASK) !=
+                CM4_PROT_MASK) {
+        }
+
+        spm_write(SPM_CM4_PWR_CON,
+                  spm_read(SPM_CM4_PWR_CON) | CM4_SRAM_PDN);
+
+        while ((spm_read(SPM_CM4_PWR_CON) & CM4_SRAM_ACK) !=
+                CM4_SRAM_ACK) {
+        }
+
+        spm_write(SPM_CM4_PWR_CON, spm_read(SPM_CM4_PWR_CON) | PWR_ISO);
+
+        val = spm_read(SPM_CM4_PWR_CON);
+        val = (val & ~PWR_RST_B) | PWR_CLK_DIS;
+        spm_write(SPM_CM4_PWR_CON, val);
+
+        spm_write(SPM_CM4_PWR_CON,
+                  spm_read(SPM_CM4_PWR_CON) & ~(PWR_ON | PWR_ON_2ND));
+
+        while ((spm_read(SPM_PWR_STATUS) & CM4_PWR_STA_MASK)
+                || (spm_read(SPM_PWR_STATUS_2ND) & CM4_PWR_STA_MASK)) {
+        }
+    } else {    /* STA_POWER_ON */
+        spm_write(SPM_CM4_PWR_CON, spm_read(SPM_CM4_PWR_CON) | PWR_ON);
+        spm_write(SPM_CM4_PWR_CON,
+                  spm_read(SPM_CM4_PWR_CON) | PWR_ON_2ND);
+
+        while (!(spm_read(SPM_PWR_STATUS) & CM4_PWR_STA_MASK)
+                || !(spm_read(SPM_PWR_STATUS_2ND) & CM4_PWR_STA_MASK)) {
+        }
+
+        spm_write(SPM_CM4_PWR_CON,
+                  spm_read(SPM_CM4_PWR_CON) & ~PWR_CLK_DIS);
+        spm_write(SPM_CM4_PWR_CON,
+                  spm_read(SPM_CM4_PWR_CON) & ~PWR_ISO);
+        spm_write(SPM_CM4_PWR_CON,
+                  spm_read(SPM_CM4_PWR_CON) | PWR_RST_B);
+
+        spm_write(SPM_CM4_PWR_CON,
+                  spm_read(SPM_CM4_PWR_CON) & ~CM4_SRAM_PDN);
+
+        while ((spm_read(SPM_CM4_PWR_CON) & CM4_SRAM_ACK)) {
+        }
+
+        spm_write(SPM_CM4_PWR_CON,
+                  spm_read(SPM_CM4_PWR_CON) | SRAM_ISOINT_B);
+
+        udelay(20);
+
+        spm_write(SPM_CM4_PWR_CON,
+                 spm_read(SPM_CM4_PWR_CON) & ~SRAM_CKISO);
+
+        spm_write(TOPAXI_PROT_EN,
+                  spm_read(TOPAXI_PROT_EN) & ~CM4_PROT_MASK);
+        while (spm_read(TOPAXI_PROT_STA1) & CM4_PROT_MASK) {
+        }
+    }
+
+    spm_mtcmos_noncpu_unlock(flags);
+
+    return err;
+}
+
+int spm_mtcmos_ctrl_audafe(int state)
+{
+    int err = 0;
+    unsigned int val;
+    unsigned long flags;
+
+    spm_mtcmos_noncpu_lock(flags);
+
+    if (state == STA_POWER_DOWN) {
+        spm_write(TOPAXI_PROT_EN,
+                  spm_read(TOPAXI_PROT_EN) | AUDAFE_PROT_MASK);
+        while ((spm_read(TOPAXI_PROT_STA1) & AUDAFE_PROT_MASK) !=
+                AUDAFE_PROT_MASK) {
+        }
+
+        spm_write(SPM_AUDAFE_PWR_CON,
+                  spm_read(SPM_AUDAFE_PWR_CON) | AUDAFE_SRAM_PDN);
+
+        while ((spm_read(SPM_AUDAFE_PWR_CON) & AUDAFE_SRAM_ACK) !=
+                AUDAFE_SRAM_ACK) {
+        }
+
+        spm_write(SPM_AUDAFE_PWR_CON, spm_read(SPM_AUDAFE_PWR_CON) | PWR_ISO);
+
+        val = spm_read(SPM_AUDAFE_PWR_CON);
+        val = (val & ~PWR_RST_B) | PWR_CLK_DIS;
+        spm_write(SPM_AUDAFE_PWR_CON, val);
+
+        spm_write(SPM_AUDAFE_PWR_CON,
+                  spm_read(SPM_AUDAFE_PWR_CON) & ~(PWR_ON | PWR_ON_2ND));
+
+        while ((spm_read(SPM_PWR_STATUS) & AUDAFE_PWR_STA_MASK)
+                || (spm_read(SPM_PWR_STATUS_2ND) & AUDAFE_PWR_STA_MASK)) {
+        }
+    } else {    /* STA_POWER_ON */
+        spm_write(SPM_AUDAFE_PWR_CON, spm_read(SPM_AUDAFE_PWR_CON) | PWR_ON);
+        spm_write(SPM_AUDAFE_PWR_CON,
+                  spm_read(SPM_AUDAFE_PWR_CON) | PWR_ON_2ND);
+
+        while (!(spm_read(SPM_PWR_STATUS) & AUDAFE_PWR_STA_MASK)
+                || !(spm_read(SPM_PWR_STATUS_2ND) & AUDAFE_PWR_STA_MASK)) {
+        }
+
+        spm_write(SPM_AUDAFE_PWR_CON,
+                  spm_read(SPM_AUDAFE_PWR_CON) & ~PWR_CLK_DIS);
+        spm_write(SPM_AUDAFE_PWR_CON,
+                  spm_read(SPM_AUDAFE_PWR_CON) & ~PWR_ISO);
+        spm_write(SPM_AUDAFE_PWR_CON,
+                  spm_read(SPM_AUDAFE_PWR_CON) | PWR_RST_B);
+
+        spm_write(SPM_AUDAFE_PWR_CON,
+                  spm_read(SPM_AUDAFE_PWR_CON) & ~AUDAFE_SRAM_PDN);
+
+        while ((spm_read(SPM_AUDAFE_PWR_CON) & AUDAFE_SRAM_ACK)) {
+        }
+
+        spm_write(TOPAXI_PROT_EN,
+                  spm_read(TOPAXI_PROT_EN) & ~AUDAFE_PROT_MASK);
+        while (spm_read(TOPAXI_PROT_STA1) & AUDAFE_PROT_MASK) {
+        }
+    }
+
+    spm_mtcmos_noncpu_unlock(flags);
+
+    return err;
+}
+
+int spm_mtcmos_ctrl_audsrc(int state)
+{
+    int err = 0;
+    unsigned int val;
+    unsigned long flags;
+
+    spm_mtcmos_noncpu_lock(flags);
+
+    if (state == STA_POWER_DOWN) {
+        spm_write(TOPAXI_PROT_EN,
+                  spm_read(TOPAXI_PROT_EN) | AUDSRC_PROT_MASK);
+        while ((spm_read(TOPAXI_PROT_STA1) & AUDSRC_PROT_MASK) !=
+                AUDSRC_PROT_MASK) {
+        }
+
+        spm_write(SPM_AUDSRC_PWR_CON,
+                  spm_read(SPM_AUDSRC_PWR_CON) | AUDSRC_SRAM_PDN);
+
+        while ((spm_read(SPM_AUDSRC_PWR_CON) & AUDSRC_SRAM_ACK) !=
+                AUDSRC_SRAM_ACK) {
+        }
+
+        spm_write(SPM_AUDSRC_PWR_CON, spm_read(SPM_AUDSRC_PWR_CON) | PWR_ISO);
+
+        val = spm_read(SPM_AUDSRC_PWR_CON);
+        val = (val & ~PWR_RST_B) | PWR_CLK_DIS;
+        spm_write(SPM_AUDSRC_PWR_CON, val);
+
+        spm_write(SPM_AUDSRC_PWR_CON,
+                  spm_read(SPM_AUDSRC_PWR_CON) & ~(PWR_ON | PWR_ON_2ND));
+
+        while ((spm_read(SPM_PWR_STATUS) & AUDSRC_PWR_STA_MASK)
+                || (spm_read(SPM_PWR_STATUS_2ND) & AUDSRC_PWR_STA_MASK)) {
+        }
+    } else {    /* STA_POWER_ON */
+        spm_write(SPM_AUDSRC_PWR_CON, spm_read(SPM_AUDSRC_PWR_CON) | PWR_ON);
+        spm_write(SPM_AUDSRC_PWR_CON,
+                  spm_read(SPM_AUDSRC_PWR_CON) | PWR_ON_2ND);
+
+        while (!(spm_read(SPM_PWR_STATUS) & AUDSRC_PWR_STA_MASK)
+                || !(spm_read(SPM_PWR_STATUS_2ND) & AUDSRC_PWR_STA_MASK)) {
+        }
+
+        spm_write(SPM_AUDSRC_PWR_CON,
+                  spm_read(SPM_AUDSRC_PWR_CON) & ~PWR_CLK_DIS);
+        spm_write(SPM_AUDSRC_PWR_CON,
+                  spm_read(SPM_AUDSRC_PWR_CON) & ~PWR_ISO);
+        spm_write(SPM_AUDSRC_PWR_CON,
+                  spm_read(SPM_AUDSRC_PWR_CON) | PWR_RST_B);
+
+        spm_write(SPM_AUDSRC_PWR_CON,
+                  spm_read(SPM_AUDSRC_PWR_CON) & ~AUDSRC_SRAM_PDN);
+
+        while ((spm_read(SPM_AUDSRC_PWR_CON) & AUDSRC_SRAM_ACK)) {
+        }
+
+        spm_write(TOPAXI_PROT_EN,
+                  spm_read(TOPAXI_PROT_EN) & ~AUDSRC_PROT_MASK);
+        while (spm_read(TOPAXI_PROT_STA1) & AUDSRC_PROT_MASK) {
+        }
+    }
+
+    spm_mtcmos_noncpu_unlock(flags);
+
+    return err;
+}
diff --git a/src/bsp/lk/platform/mt8518/drivers/trng/mtk_trng.c b/src/bsp/lk/platform/mt8518/drivers/trng/mtk_trng.c
new file mode 100644
index 0000000..24aaed4
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/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/mt8518/drivers/uart/uart.c b/src/bsp/lk/platform/mt8518/drivers/uart/uart.c
new file mode 100644
index 0000000..dc0bfba
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/uart/uart.c
@@ -0,0 +1,278 @@
+/*
+ * 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 <reg.h>
+#include <dev/uart.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mt_uart.h>
+#include <string.h>
+
+typedef enum {
+    UART1 = UART0_BASE,
+    UART2 = UART1_BASE,
+    UART3 = UART2_BASE,
+    UART4 = UART3_BASE
+} MTK_UART;
+
+/* 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)
+
+#define CONFIG_BAUDRATE         921600
+
+#define UART_BASE(uart)                   (uart)
+
+#define UART_RBR(uart)                    (UART_BASE(uart)+0x0)  /* Read only */
+#define UART_THR(uart)                    (UART_BASE(uart)+0x0)  /* Write only */
+#define UART_IER(uart)                    (UART_BASE(uart)+0x4)
+#define UART_IIR(uart)                    (UART_BASE(uart)+0x8)  /* Read only */
+#define UART_FCR(uart)                    (UART_BASE(uart)+0x8)  /* Write only */
+#define UART_LCR(uart)                    (UART_BASE(uart)+0xc)
+#define UART_MCR(uart)                    (UART_BASE(uart)+0x10)
+#define UART_LSR(uart)                    (UART_BASE(uart)+0x14)
+#define UART_MSR(uart)                    (UART_BASE(uart)+0x18)
+#define UART_SCR(uart)                    (UART_BASE(uart)+0x1c)
+#define UART_DLL(uart)                    (UART_BASE(uart)+0x0)  /* Only when LCR.DLAB = 1 */
+#define UART_DLH(uart)                    (UART_BASE(uart)+0x4)  /* Only when LCR.DLAB = 1 */
+#define UART_EFR(uart)                    (UART_BASE(uart)+0x8)  /* Only when LCR = 0xbf */
+#define UART_XON1(uart)                   (UART_BASE(uart)+0x10) /* Only when LCR = 0xbf */
+#define UART_XON2(uart)                   (UART_BASE(uart)+0x14) /* Only when LCR = 0xbf */
+#define UART_XOFF1(uart)                  (UART_BASE(uart)+0x18) /* Only when LCR = 0xbf */
+#define UART_XOFF2(uart)                  (UART_BASE(uart)+0x1c) /* Only when LCR = 0xbf */
+#define UART_AUTOBAUD_EN(uart)            (UART_BASE(uart)+0x20)
+#define UART_HIGHSPEED(uart)              (UART_BASE(uart)+0x24)
+#define UART_SAMPLE_COUNT(uart)           (UART_BASE(uart)+0x28)
+#define UART_SAMPLE_POINT(uart)           (UART_BASE(uart)+0x2c)
+#define UART_AUTOBAUD_REG(uart)           (UART_BASE(uart)+0x30)
+#define UART_RATE_FIX_AD(uart)            (UART_BASE(uart)+0x34)
+#define UART_AUTOBAUD_SAMPLE(uart)        (UART_BASE(uart)+0x38)
+#define UART_GUARD(uart)                  (UART_BASE(uart)+0x3c)
+#define UART_ESCAPE_DAT(uart)             (UART_BASE(uart)+0x40)
+#define UART_ESCAPE_EN(uart)              (UART_BASE(uart)+0x44)
+#define UART_SLEEP_EN(uart)               (UART_BASE(uart)+0x48)
+#define UART_VFIFO_EN(uart)               (UART_BASE(uart)+0x4c)
+#define UART_RXTRI_AD(uart)               (UART_BASE(uart)+0x50)
+
+#define INVAL_UART_BASE 0xFFFFFFFF
+
+// output uart port
+volatile addr_t g_uart = INVAL_UART_BASE;
+
+//extern unsigned int mtk_get_bus_freq(void);
+#if FPGA_PLATFORM
+#define UART_SRC_CLK 12000000
+#else
+#define UART_SRC_CLK 26000000
+#endif
+
+static void uart_setbrg(unsigned int baud)
+{
+    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 = baud;
+    uartclk = UART_SRC_CLK;
+    //uartclk = (unsigned int)(mtk_get_bus_freq()*1000/4);
+    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(g_uart));
+        byte = readl(UART_LCR(g_uart));   /* DLAB start */
+        writel((byte | UART_LCR_DLAB), UART_LCR(g_uart));
+        writel((divisor & 0x00ff), UART_DLL(g_uart));
+        writel(((divisor >> 8)&0x00ff), UART_DLH(g_uart));
+        writel(byte, UART_LCR(g_uart));   /* 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(g_uart));
+
+        byte = readl(UART_LCR(g_uart));    /* DLAB start */
+        writel((byte | UART_LCR_DLAB), UART_LCR(g_uart));
+        writel((high_speed_div & 0x00ff), UART_DLL(g_uart));
+        writel(((high_speed_div >> 8)&0x00ff), UART_DLH(g_uart));
+        writel(sample_count, UART_SAMPLE_COUNT(g_uart));
+        writel(sample_point, UART_SAMPLE_POINT(g_uart));
+        writel(byte, UART_LCR(g_uart));   /* DLAB end */
+    }
+}
+
+static void mtk_set_current_uart(MTK_UART uart_base)
+{
+    g_uart = uart_base;
+}
+
+void uart_init_early(void)
+{
+    unsigned int baud = CONFIG_BAUDRATE;
+    mtk_set_current_uart(UART1);
+    /* clear fifo */
+    writel(readl(UART_FCR(g_uart)) + UART_FCR_FIFO_INIT, UART_FCR(g_uart));
+    writel(UART_NONE_PARITY | UART_WLS_8 | UART_1_STOP, UART_LCR(g_uart));
+    uart_setbrg(baud);
+}
+
+#define UART_LSR_TX_READY (UART_LSR_THRE | UART_LSR_TEMT)
+int uart_putc(int port, char ch)
+{
+    if (g_uart == INVAL_UART_BASE) {
+        return -1;
+    }
+
+    while(1) {
+        if ((readl(UART_LSR(g_uart)) & UART_LSR_TX_READY) == UART_LSR_TX_READY) {
+            if (ch == '\n')
+                writel((unsigned int)'\r', UART_THR(g_uart));
+
+            writel((unsigned int)ch, UART_THR(g_uart));
+            break;
+        }
+    }
+
+    return 0;
+}
+
+int uart_getc(int port, bool wait)  /* returns -1 if no data available */
+{
+    while (!(readl(UART_LSR(g_uart)) & UART_LSR_DR));
+    return (int)readl(UART_RBR(g_uart));
+}
+
+int uart_pputc(int port, char c)
+{
+    return uart_putc(port, c);
+}
+
+int uart_pgetc(int port)
+{
+    return uart_getc(port, 0);
+}
+
+bool check_uart_enter(void)
+{
+    if ((int)readl(UART_RBR(g_uart)) == 13)
+        return true;
+    else
+        return false;
+}
diff --git a/src/bsp/lk/platform/mt8518/drivers/usb/handshake_usb.c b/src/bsp/lk/platform/mt8518/drivers/usb/handshake_usb.c
new file mode 100644
index 0000000..ccf869c
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/usb/handshake_usb.c
@@ -0,0 +1,432 @@
+/* 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.
+ */
+
+#include <string.h>
+#include <debug.h>
+#include <platform/platform_usb.h>
+#include <platform/usbbldr.h>
+#include <platform/usbtty.h>
+#include <platform/pmic.h>
+#include <platform/mtk_timer.h>
+#include <platform.h>
+#include <platform/rt9460.h>
+
+#define HSHK_COM_READY          "READY"       /* com ready for communication */
+
+/*============================================================================*/
+/* CONSTAND DEFINITIONS                                                       */
+/*============================================================================*/
+#define CFG_USB_HANDSHAKE_TIMEOUT_EN    (1)
+#define CFG_USB_ENUM_TIMEOUT_EN         (1)
+
+#define MOD                 "[TOOL]"
+#define CFG_USB_HANDSHAKE_TIMEOUT       (2500)       /* 2.5s */
+#define READ_USBTTY_TIMEOUT             (100)
+#define USB_SYNC_TIME                   (CFG_USB_HANDSHAKE_TIMEOUT)
+#define USB_PORT_DOWN_TIME              1000
+#define CDC_DTR_MASK                    0x01
+#define HSHK_TOKEN_SZ                   (8)          /* handshake token size */
+#define CFG_USB_ENUM_TIMEOUT            (8000)       /* 8s */
+#define USB_ENUM_TIMEOUT                (CFG_USB_ENUM_TIMEOUT)
+
+/*============================================================================*/
+/* EXTERNAL FUNCTIONS DECLARATION                                             */
+/*============================================================================*/
+extern int usbdl_init(void);
+extern int usbdl_configured(void);
+extern void mt_usb_connect_internal(void);
+extern void mt_usb_disconnect_internal(void);
+extern void mt_usb_phy_savecurrent(void);
+
+/*============================================================================*/
+/* GLOBAL VARIABLES                                                           */
+/*============================================================================*/
+
+extern int g_usbphy_ok;
+
+static void usb_service_offline (void)
+{
+
+    mt_usb_disconnect_internal ();
+    mt_usb_phy_savecurrent ();
+
+    return;
+}
+
+
+//extern u32 pmic_IsUsbCableIn (void);
+static int usb_accessory_in(void)
+{
+#if !CFG_FPGA_PLATFORM
+    int exist = 0;
+    //if (PMIC_CHRDET_EXIST == pmic_IsUsbCableIn()) {
+    if (1 == rt9460IsCableIn()) {
+        exist = 1;
+#if !CFG_USBIF_COMPLIANCE
+        /* enable charging current as early as possible to avoid can't enter
+         * following battery charging flow when low battery
+         */
+        platform_set_chrg_cur(450);
+#endif
+    }
+    return exist;
+#else
+    return 1;
+#endif
+}
+
+static int usb_cable_in(void)
+{
+#if !CFG_FPGA_PLATFORM
+    int exist = 0;
+    CHARGER_TYPE ret;
+    if (usb_accessory_in()) {
+        //ret = mt_charger_type_detection();
+        ret = rt9460TypeDetection();
+        dprintf(ALWAYS, " rt9460TypeDetection ret= %d\n",ret);
+        if (ret == STANDARD_HOST || ret == CHARGING_HOST) {
+            dprintf(ALWAYS, "\n[TOOL] USB cable in\n");
+
+            exist = 1;
+        } else if (ret == NONSTANDARD_CHARGER || ret == STANDARD_CHARGER) {
+#if CFG_USBIF_COMPLIANCE
+            platform_set_chrg_cur(450);
+#endif
+        }
+    }
+
+    return exist;
+#else
+    dprintf(ALWAYS, "\n[TOOL] USB cable in\n");
+    mt_usb_phy_poweron();
+    mt_usb_phy_savecurrent();
+
+    return 1;
+#endif
+}
+
+/*============================================================================*/
+/* INTERNAL FUNCTIONS                                                         */
+/*============================================================================*/
+static u8 usb_connect(u32 tmo)
+{
+    dprintf(ALWAYS, "usb_connect enter \n");
+    lk_bigtime_t start_time = 0, timeout_time = 0, tmp = 0;
+    u8 result = 0;
+    u32 i = 1;
+
+    tmp = start_time = current_time();
+    timeout_time = start_time + tmo;
+
+    mt_usb_disconnect_internal();
+    //mt_usb_connect_internal();
+    config_usbtty();
+
+#if CFG_USBIF_COMPLIANCE
+    /* USB compliance test: 100mA charging current when USB is unconfigured. */
+    platform_set_chrg_cur(70);
+#endif
+
+    dprintf(ALWAYS, "%s Enumeration(Start)\n", MOD);
+
+    do {
+        /* kick wdt to avoid cpu reset during usb driver installation if not present */
+        platform_wdt_all_kick();
+        //service_interrupts();
+
+        if (usbdl_configured()) {
+#if CFG_USBIF_COMPLIANCE
+            /* USB compliance test: 500mA charging current when USB is configured but
+             * we set the charging current to 450mA since 500mA doesn't support in the
+             * platform.
+             */
+            platform_set_chrg_cur(450);
+#endif
+            result = 1;
+            break;
+        }
+
+        if (tmo) {
+            tmp = current_time();
+            /* enable timeout mechanism */
+            if (tmp > timeout_time)
+                break;
+#if !CFG_FPGA_PLATFORM
+            /* cable plugged-out and power key detection each 1 second */
+            if (tmp > i * 1000) {
+                //if (!usb_accessory_in() && !pmic_detect_powerkey())
+                    //pl_power_off();
+
+#if !CFG_EVB_PLATFORM
+                /* check bypass power key from the 2nd second */
+                if (i > 1 && pmic_detect_powerkey()) {
+                    dprintf(ALWAYS, "%s Enumeration(Skip): powerkey pressed\n", MOD);
+                    break;
+                }
+                i++;
+#endif
+            }
+#endif
+        }
+    } while(1);
+
+    dprintf(ALWAYS, "%s Enumeration(End): %s %lldms \n", MOD, result == 1 ? "OK" : "TMO",(tmp - start_time));
+
+    return result;
+}
+
+static void usb_disconnect(void)
+{
+    mt_usb_disconnect_internal();
+}
+
+static int usb_send(u8 *buf, u32 len)
+{
+    return usbtty_write(buf, len);
+}
+
+static int usb_recv(u8 *buf, u32 size, u32 tmo_ms)
+{
+    lk_bigtime_t start_time = 0, timeout_time = 0;
+    int dsz;
+    u32 tmo_en = (tmo_ms) ? 1 : 0;
+    u8 *ptr = buf;
+
+    if (!size)
+        return 0;
+
+    start_time = current_time();
+    timeout_time = start_time + tmo_ms;
+
+    while (1) {
+        if (tmo_en && (current_time() > timeout_time)){
+            dprintf(ALWAYS, "%s : usb receive timeout\n", MOD);
+            return -1;
+        }
+
+        if (!tmo_en) {
+            /* kick watchdog to avoid cpu reset but don't kick pmic wdt since
+             * it could use i2c operations during a communication command protocl
+             * that could break the atomic operation of 2 pmic i2c communication
+             * commands. i2c operations should be not used during usb send or recv.
+             * for example:
+             *
+             * i2c_write(pmic_addr) -> usb_recv() -> i2c_read(&pmic_data).
+             */
+            platform_wdt_kick();
+        }
+
+        dsz = usbtty_read(ptr, size, READ_USBTTY_TIMEOUT);
+        if (dsz) {
+            ptr  += dsz;
+            size -= dsz;
+        }
+        if (size == 0)
+            break;
+    }
+
+    return 0;
+}
+
+static u8 usb_listen(struct bldr_comport *comport, uint8_t *data, uint32_t size, uint32_t tmo_ms)
+{
+    dprintf(ALWAYS, "enter usb_listen \n");
+    lk_bigtime_t start_time = 0, timeout_time = 0;
+    uint32_t dsz;
+    uint32_t tmo_en = (tmo_ms) ? 1 : 0;
+    uint8_t *ptr = data;
+
+    if (!size)
+        return 0;
+
+    start_time = current_time();
+    timeout_time = start_time + tmo_ms;
+
+    while (1) {
+        if (tool_is_present())
+            usbtty_write(HSHK_COM_READY, strlen(HSHK_COM_READY)); /* "READY" */
+
+        if (tmo_en && (current_time() > timeout_time)){
+            dprintf(ALWAYS, "%s : usb listen timeout\n", MOD);
+            return 0;
+         }
+
+        if (!tmo_en) {
+            /* kick watchdog to avoid cpu reset */
+            platform_wdt_all_kick();
+        }
+        dsz = usbtty_read(ptr, size, READ_USBTTY_TIMEOUT);
+        if (dsz) {
+            dsz = dsz < size ? dsz : size;
+#if CFG_USB_DOWNLOAD
+            if (*ptr == 0xa0) {
+                dprintf(INFO, "%s sync time %dms\n", MOD, (current_time() - start_time));
+                //usbdl_handler(comport, 300);
+                dprintf(INFO, "%s : ignore %d bytes garbage data\n", MOD, dsz);
+                continue; /* ingore received data */
+            }
+#endif
+            ptr  += dsz;
+            size -= dsz;
+        }
+        if (size == 0)
+            break;
+
+        udelay(20000); /* 20ms */
+    }
+
+    dprintf(INFO, "%s sync time %dms\n", MOD, (current_time() - start_time));
+
+    return 1;
+}
+
+static u8 usb_port_down(uint32_t tmo_ms)
+{
+    lk_bigtime_t start_time = 0, timeout_time = 0;
+    usbtty_stop();
+
+    start_time = current_time();
+    timeout_time = start_time + tmo_ms;
+
+#if 0
+    while (1) {
+        if (current_time() > timeout_time)
+            return 0;
+
+        /* kick watchdog to avoid cpu reset */
+        platform_wdt_all_kick();
+        //mt_usbtty_query_data_size();
+        /* check if usb comport close */
+        //if (!(g_usb_port_state & CDC_DTR_MASK))
+           //break;
+        udelay(20000); /* 20ms */
+    }
+
+#endif
+
+    dprintf(ALWAYS, "%s usb port down: %dms\n", MOD, (current_time() - start_time));
+
+    return 1;
+}
+
+static u8 usb_handshake_handler(struct bldr_command_handler *handler, uint32_t tmo)
+{
+    dprintf(ALWAYS, " enter usb_handshake_handler \n");
+    uint8_t buf[HSHK_TOKEN_SZ + 1] = {'\0'};
+    struct bldr_comport comport;
+    struct bldr_command cmd;
+    struct comport_ops usb_ops = {usb_send, usb_recv};
+
+    //comport.type = COM_USB;
+    comport.tmo  = tmo;
+    comport.ops  = &usb_ops;
+
+    if (0 == usb_listen(&comport, buf, HSHK_TOKEN_SZ, tmo)) {
+        dprintf(ALWAYS, "%s <USB> cannot detect tools!\n",MOD);
+        return 0;
+    }
+    cmd.data = &buf[0];
+    //cmd.len  = HSHK_TOKEN_SZ;
+
+    dprintf(ALWAYS, " enter handler->cb \n");
+    return handler->cb(handler, &cmd, &comport);
+}
+
+/*============================================================================*/
+/* GLOBAL FUNCTIONS                                                           */
+/*============================================================================*/
+u8 usb_handshake(struct bldr_command_handler *handler)
+{
+    dprintf(ALWAYS, "usb_handshake  enter  \n"); 
+    uint32_t enum_tmo = CFG_USB_ENUM_TIMEOUT_EN ? USB_ENUM_TIMEOUT : 0;
+    uint32_t handshake_tmo = CFG_USB_HANDSHAKE_TIMEOUT_EN ? USB_SYNC_TIME : 0;
+    bool result = 0;
+    bool force_download = 0;
+
+    platform_vusb_on();
+
+    force_download = platform_com_wait_forever_check();
+
+    if (1 == force_download) {
+        enum_tmo = 0;
+        handshake_tmo = 0;
+        usb_cable_in();
+    } else if (!usb_cable_in()) {
+        dprintf(ALWAYS, "%s PMIC not dectect usb cable!\n", MOD);
+        return 0;
+    }
+
+#if CFG_USB_AUTO_DETECT
+    platform_usb_auto_detect_flow();
+#endif
+
+    dprintf(INFO, "%s USB enum timeout (%s), handshake timeout(%s)\n", MOD,
+        enum_tmo ? "Yes" : "No",
+        handshake_tmo ? "Yes" : "No");
+
+    usbdl_init();
+    udelay(1000);
+    usb_disconnect();
+
+    if (usb_connect(enum_tmo) == 0) {
+        dprintf(ALWAYS, "%s USB enum timeout!\n", MOD);
+        /* USB enum fail when connecting to a standby PC, remove ASSERT */
+        /* ASSERT(g_usbphy_ok); */
+        goto end;
+    }
+
+    mdelay(2500);
+    if (0 == usb_handshake_handler(handler, handshake_tmo)) {
+        goto end;
+    }
+
+    result = 1;
+end:
+    if (0 == usb_port_down(USB_PORT_DOWN_TIME)) {
+        dprintf(ALWAYS, "%s USB port down timeout!\n", MOD);
+    }
+
+    usb_service_offline();
+
+#if CFG_USBIF_COMPLIANCE
+    /* USB compliance test: 100mA charging current when USB is unconfigured. */
+    //platform_set_chrg_cur(70);
+
+#endif
+
+    return result;
+}
diff --git a/src/bsp/lk/platform/mt8518/drivers/usb/md1122.c b/src/bsp/lk/platform/mt8518/drivers/usb/md1122.c
new file mode 100644
index 0000000..db6ea17
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/usb/md1122.c
@@ -0,0 +1,176 @@
+/*
+ * MD1122 usb2.0 phy board for FPGA
+ *
+ * Copyright 2016 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#include <debug.h>
+#include <platform/mt_i2c.h>
+
+#define MD1122_I2C_ADDR 0x60
+#define PHY_VERSION_BANK 0x20
+#define PHY_VERSION_ADDR 0xe4
+
+int USB_PHY_Write_Register8(unsigned char data, unsigned char addr)
+{
+    unsigned char buffer[2];
+
+    buffer[0] = addr;
+    buffer[1] = data;
+    mtk_i2c_write(0, MD1122_I2C_ADDR, 100, buffer, 2);
+
+    return 0;
+}
+
+unsigned char USB_PHY_Read_Register8(unsigned char addr)
+{
+    unsigned char data;
+
+    mtk_i2c_write_read(0, MD1122_I2C_ADDR, 100, &addr, &data, 1, 1);
+
+    return data;
+}
+
+unsigned int USB_PHY_Read_Register32(unsigned char addr)
+{
+    unsigned char data[4];
+    unsigned int ret;
+
+    mtk_i2c_write_read(0, MD1122_I2C_ADDR, 100, &addr, data, 1, 4);
+    ret = data[0];
+    ret |= data[1] << 8;
+    ret |= data[2] << 16;
+    ret |= data[3] << 24;
+
+    return ret;
+}
+
+#if 0
+unsigned int get_phy_verison(void)
+{
+    unsigned int version = 0;
+
+    USB_PHY_Write_Register8(0xff, PHY_VERSION_BANK);
+
+    version = USB_PHY_Read_Register32(PHY_VERSION_ADDR);
+    dprintf(ALWAYS, "ssusb phy version: %x\n", version);
+
+    return version;
+}
+#endif
+
+int md1122_u2phy_init(void)
+{
+#if 0
+    if (get_phy_verison() != 0xa60810a) {
+        dprintf(ALWAYS,"get phy version failed\n");
+        //return -1;
+    }
+#endif
+
+    /* usb phy initial sequence */
+    USB_PHY_Write_Register8(0x00, 0xFF);
+    dprintf(ALWAYS,"****************before bank 0x00*************************\n");
+    dprintf(ALWAYS,"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(ALWAYS,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(ALWAYS,"[U2P]addr: 0x05, value: %x\n", USB_PHY_Read_Register8(0x05));
+    dprintf(ALWAYS,"[U2P]addr: 0x18, value: %x\n", USB_PHY_Read_Register8(0x18));
+    dprintf(ALWAYS,"*****************after **********************************\n");
+    USB_PHY_Write_Register8(0x55, 0x05);
+    USB_PHY_Write_Register8(0x84, 0x18);
+
+
+    dprintf(ALWAYS,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(ALWAYS,"[U2P]addr: 0x05, value: %x\n", USB_PHY_Read_Register8(0x05));
+    dprintf(ALWAYS,"[U2P]addr: 0x18, value: %x\n", USB_PHY_Read_Register8(0x18));
+    dprintf(ALWAYS,"****************before bank 0x10*************************\n");
+    USB_PHY_Write_Register8(0x10, 0xFF);
+    dprintf(ALWAYS,"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(ALWAYS,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(ALWAYS,"[U2P]addr: 0x0A, value: %x\n", USB_PHY_Read_Register8(0x0A));
+    dprintf(ALWAYS,"*****************after **********************************\n");
+
+    USB_PHY_Write_Register8(0x84, 0x0A);
+
+    dprintf(ALWAYS,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(ALWAYS,"[U2P]addr: 0x0A, value: %x\n", USB_PHY_Read_Register8(0x0A));
+    dprintf(ALWAYS,"****************before bank 0x40*************************\n");
+    USB_PHY_Write_Register8(0x40, 0xFF);
+    dprintf(ALWAYS,"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(ALWAYS,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(ALWAYS,"[U2P]addr: 0x38, value: %x\n", USB_PHY_Read_Register8(0x38));
+    dprintf(ALWAYS,"[U2P]addr: 0x42, value: %x\n", USB_PHY_Read_Register8(0x42));
+    dprintf(ALWAYS,"[U2P]addr: 0x08, value: %x\n", USB_PHY_Read_Register8(0x08));
+    dprintf(ALWAYS,"[U2P]addr: 0x09, value: %x\n", USB_PHY_Read_Register8(0x09));
+    dprintf(ALWAYS,"[U2P]addr: 0x0C, value: %x\n", USB_PHY_Read_Register8(0x0C));
+    dprintf(ALWAYS,"[U2P]addr: 0x0E, value: %x\n", USB_PHY_Read_Register8(0x0E));
+    dprintf(ALWAYS,"[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x10));
+    dprintf(ALWAYS,"[U2P]addr: 0x14, value: %x\n", USB_PHY_Read_Register8(0x14));
+    dprintf(ALWAYS,"*****************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(ALWAYS,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(ALWAYS,"[U2P]addr: 0x38, value: %x\n", USB_PHY_Read_Register8(0x38));
+    dprintf(ALWAYS,"[U2P]addr: 0x42, value: %x\n", USB_PHY_Read_Register8(0x42));
+    dprintf(ALWAYS,"[U2P]addr: 0x08, value: %x\n", USB_PHY_Read_Register8(0x08));
+    dprintf(ALWAYS,"[U2P]addr: 0x09, value: %x\n", USB_PHY_Read_Register8(0x09));
+    dprintf(ALWAYS,"[U2P]addr: 0x0C, value: %x\n", USB_PHY_Read_Register8(0x0C));
+    dprintf(ALWAYS,"[U2P]addr: 0x0E, value: %x\n", USB_PHY_Read_Register8(0x0E));
+    dprintf(ALWAYS,"[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x10));
+    dprintf(ALWAYS,"[U2P]addr: 0x14, value: %x\n", USB_PHY_Read_Register8(0x14));
+    dprintf(ALWAYS,"****************before bank 0x60*************************\n");
+    USB_PHY_Write_Register8(0x60, 0xFF);
+    dprintf(ALWAYS,"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(ALWAYS,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(ALWAYS,"[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x14));
+    dprintf(ALWAYS,"*****************after **********************************\n");
+
+    USB_PHY_Write_Register8(0x03, 0x14);
+    dprintf(ALWAYS,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(ALWAYS,"[U2P]addr: 0x10, value: %x\n", USB_PHY_Read_Register8(0x14));
+    dprintf(ALWAYS,"****************before bank 0x00*************************\n");
+    USB_PHY_Write_Register8(0x00, 0xFF);
+    dprintf(ALWAYS,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(ALWAYS,"[U2P]addr: 0x6A, value: %x\n", USB_PHY_Read_Register8(0x6A));
+    dprintf(ALWAYS,"[U2P]addr: 0x68, value: %x\n", USB_PHY_Read_Register8(0x68));
+    dprintf(ALWAYS,"[U2P]addr: 0x6C, value: %x\n", USB_PHY_Read_Register8(0x6C));
+    dprintf(ALWAYS,"[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(0x2E, 0x6C);
+    USB_PHY_Write_Register8(0x3E, 0x6D);
+    dprintf(ALWAYS,"*****************after **********************************\n");
+    dprintf(ALWAYS,"[U2P]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
+    dprintf(ALWAYS,"[U2P]addr: 0x6A, value: %x\n", USB_PHY_Read_Register8(0x6A));
+    dprintf(ALWAYS,"[U2P]addr: 0x68, value: %x\n", USB_PHY_Read_Register8(0x68));
+    dprintf(ALWAYS,"[U2P]addr: 0x6C, value: %x\n", USB_PHY_Read_Register8(0x6C));
+    dprintf(ALWAYS,"[U2P]addr: 0x6D, value: %x\n", USB_PHY_Read_Register8(0x6D));
+
+    dprintf(ALWAYS,"[U2P]%s, end\n", __func__);
+    return 0;
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/usb/mt_usb.c b/src/bsp/lk/platform/mt8518/drivers/usb/mt_usb.c
new file mode 100644
index 0000000..52dcd0b
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/usb/mt_usb.c
@@ -0,0 +1,2152 @@
+/*
+ * Copyright (c) 2012 MediaTek Inc.
+ *
+ * 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 <dev/udc.h>
+#include <err.h>
+#include <kernel/thread.h>
+#include <kernel/vm.h>
+#include <platform/interrupts.h>
+#include <platform/mt_irq.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mt_usb.h>
+#if FPGA_PLATFORM
+#include <platform/md1122.h>
+#endif
+#include <platform/udc-common.h>
+#include <platform/usbtty.h>
+#include <reg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <lib/mempool.h>
+
+#define writew(v, a) (*REG16(a) = (v))
+#define readw(a) (*REG16(a))
+
+#define USB_DOUBLE_BUF
+
+#define USB_GINTR
+
+/*
+ * to use it during early integarate usb driver just
+ * #define USB_BYPASS_SPIN_AND_THREAD_SLEEP
+ */
+#define USB_BYPASS_SPIN_AND_THREAD_SLEEP
+#ifdef USB_BYPASS_SPIN_AND_THREAD_SLEEP
+#define usb_delay(count) \
+    do { \
+        volatile unsigned int i = count * 26; \
+        for (; i != 0; i--); \
+    } while (0)
+
+#define udelay(x)       usb_delay(x)
+#define mdelay(x)       usb_delay((x) * 1000)
+
+#define spin(x)         usb_delay(x)
+#define thread_sleep(x) usb_delay((x) * 1000)
+#endif
+
+//#define USB_DEBUG
+#ifdef USB_DEBUG
+/* DEBUG INFO Sections */
+#define DBG_USB_DUMP_DESC 0
+#define DBG_USB_DUMP_DATA 0
+#define DBG_USB_DUMP_SETUP 1
+#define DBG_USB_FIFO 0
+#define DBG_USB_GENERAL 1
+#define DBG_PHY_CALIBRATION 0
+#endif
+
+#define DBG_C(x...) dprintf(CRITICAL, x)
+#define DBG_I(x...) dprintf(INFO, x)
+//#define DBG_I(x...) dprintf(CRITICAL, x)
+#define DBG_S(x...) dprintf(SPEW, x)
+
+#if DBG_USB_GENERAL
+#define DBG_IRQ(x...) dprintf(INFO, x)
+#else
+#define DBG_IRQ(x...) do{} while(0)
+#endif
+
+/* bits used in all the endpoint status registers */
+#define EPT_TX(n) (1 << ((n) + 16))
+#define EPT_RX(n) (1 << (n))
+
+/* udc.h wrapper for usbdcore */
+
+static unsigned char usb_config_value = 0;
+EP0_STATE ep0_state = EP0_IDLE;
+int set_address = 0;
+u32 fifo_addr = FIFO_ADDR_START;
+
+#define EP0 0
+
+/* USB transfer directions */
+#define USB_DIR_IN  DEVICE_WRITE    /* val: 0x80 */
+#define USB_DIR_OUT DEVICE_READ /* val: 0x00 */
+
+#define EP0_MAX_PACKET_SIZE 64
+
+/* 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
+
+#define CDCACM_REQ_SET_LINE_CODING          0x20
+#define CDCACM_REQ_GET_LINE_CODING          0x21
+#define CDCACM_REQ_SET_CONTROL_LINE_STATE   0x22
+#define CDCACM_REQ_SEND_BREAK               0x23
+
+#define URB_BUF_SIZE 512
+
+struct urb {
+    struct udc_endpoint *endpoint;
+    struct udc_device *device;
+    struct setup_packet device_request;
+
+    u8 *buffer;
+    unsigned int actual_length;
+};
+
+struct usb_acm_line_coding
+{
+    u32 dwDTERate;
+    u8 bCharFormat;
+    u8 bParityType;
+    u8 bDataBits;
+} __attribute__ ((packed));
+
+static struct usb_acm_line_coding g_line_coding = {
+    921600, 0, 0, 8,
+};
+
+static struct udc_endpoint *ep0in, *ep0out;
+static struct udc_request *ep0req;
+struct urb mt_ep0_urb;
+struct urb mt_tx_urb;
+struct urb mt_rx_urb;
+struct urb *ep0_urb = &mt_ep0_urb;
+struct urb *tx_urb = &mt_tx_urb;
+struct urb *rx_urb = &mt_rx_urb;
+
+/* endpoint data - mt_ep */
+struct udc_endpoint {
+    /* rx side */
+    struct urb *rcv_urb;    /* active urb */
+
+    /* tx side */
+    struct urb *tx_urb; /* active urb */
+
+    /* info from hsusb */
+    struct udc_request *req;
+    unsigned int bit;   /* EPT_TX/EPT_RX */
+    unsigned char num;
+    unsigned char in;
+    unsigned short maxpkt;
+    int status; /* status for error handling */
+
+    unsigned int sent;      /* data already sent */
+    unsigned int last;      /* data sent in last packet XXX do we need this */
+    unsigned char mode; /* double buffer */
+};
+
+/* from mt_usbtty.h */
+#define NUM_ENDPOINTS   3
+
+/* origin endpoint_array */
+struct udc_endpoint ep_list[NUM_ENDPOINTS + 1]; /* one extra for control endpoint */
+
+static int usb_online = 0;
+
+static u8 dev_address = 0;
+
+static struct udc_device *the_device;
+static struct udc_gadget *the_gadget;
+static struct udc_gadget *the_gadget_1;
+/* end from hsusb.c */
+
+/* declare ept_complete handle */
+static void handle_ept_complete(struct udc_endpoint *ept);
+
+/* use mt_typedefs.h */
+#define USBPHY_READ8(offset)        readb(USB20_PHY_BASE+offset)
+#define USBPHY_WRITE8(offset, value)    writeb(value, USB20_PHY_BASE+offset)
+#define USBPHY_SET8(offset, mask)   USBPHY_WRITE8(offset, (USBPHY_READ8(offset)) | (mask))
+#define USBPHY_CLR8(offset, mask)   USBPHY_WRITE8(offset, (USBPHY_READ8(offset)) & (~mask))
+
+#define USB11PHY_READ8(offset)      readb(USB11_PHY_BASE+offset)
+#define USB11PHY_WRITE8(offset, value)  writeb(value, USB11_PHY_BASE+offset)
+#define USB11PHY_SET8(offset, mask) USB11PHY_WRITE8(offset, (USB11PHY_READ8(offset)) | (mask))
+#define USB11PHY_CLR8(offset, mask) USB11PHY_WRITE8(offset, (USB11PHY_READ8(offset)) & (~mask))
+
+static void mt_usb_phy_poweron(void)
+{
+#if (!FPGA_PLATFORM)
+  /*
+     * swtich to USB function.
+     * (system register, force ip into usb mode).
+     */
+    USBPHY_CLR8(0x6b, 0x04);
+    USBPHY_CLR8(0x6e, 0x01);
+    USBPHY_CLR8(0x21, 0x03);
+
+    /* RG_USB20_BC11_SW_EN = 1'b0 */
+    USBPHY_SET8(0x22, 0x04);
+    USBPHY_CLR8(0x1a, 0x80);
+
+    /* RG_USB20_DP_100K_EN = 1'b0 */
+    /* RG_USB20_DP_100K_EN = 1'b0 */
+    USBPHY_CLR8(0x22, 0x03);
+
+    /*OTG enable*/
+    USBPHY_SET8(0x20, 0x10);
+    /* release force suspendm */
+    USBPHY_CLR8(0x6a, 0x04);
+
+    spin(800);
+
+    /* force enter device mode */
+    USBPHY_CLR8(0x6c, 0x10);
+    USBPHY_SET8(0x6c, 0x2E);
+    USBPHY_SET8(0x6d, 0x3E);
+
+    return;
+#else
+    md1122_u2phy_init();
+#endif
+}
+
+void mt_usb_phy_savecurrent(void)
+{
+#if (!FPGA_PLATFORM)
+    /*
+     * swtich to USB function.
+     * (system register, force ip into usb mode).
+     */
+    USBPHY_CLR8(0x6b, 0x04);
+    USBPHY_CLR8(0x6e, 0x01);
+    USBPHY_CLR8(0x21, 0x03);
+
+    /* release force suspendm */
+    USBPHY_CLR8(0x6a, 0x04);
+    USBPHY_SET8(0x68, 0x04);
+    /* RG_DPPULLDOWN./RG_DMPULLDOWN. */
+    USBPHY_SET8(0x68, 0xc0);
+    /* RG_XCVRSEL[1:0] = 2'b01 */
+    USBPHY_CLR8(0x68, 0x30);
+    USBPHY_SET8(0x68, 0x10);
+    /* RG_TERMSEL = 1'b1 */
+    USBPHY_SET8(0x68, 0x04);
+    /* RG_DATAIN[3:0] = 4'b0000 */
+    USBPHY_CLR8(0x69, 0x3c);
+
+    /*
+     * force_dp_pulldown, force_dm_pulldown,
+     * force_xcversel, force_termsel.
+     */
+    USBPHY_SET8(0x6a, 0xba);
+
+    /* RG_USB20_BC11_SW_EN = 1'b0 */
+    USBPHY_CLR8(0x1a, 0x80);
+    /* RG_USB20_OTG_VBUSSCMP_EN = 1'b0 */
+    USBPHY_CLR8(0x1a, 0x10);
+
+    spin(800);
+
+    USBPHY_CLR8(0x6a, 0x04);
+    /* rg_usb20_pll_stable = 1 */
+    //USBPHY_SET8(0x63, 0x02);
+
+    spin(1);
+
+    /* force suspendm = 1 */
+    //USBPHY_SET8(0x6a, 0x04);
+
+    //udelay(1);
+
+    return;
+#endif
+}
+
+static void mt_usb_phy_recover(void)
+{
+#if (!FPGA_PLATFORM)
+    /* clean PUPD_BIST_EN */
+    /* PUPD_BIST_EN = 1'b0 */
+    /* PMIC will use it to detect charger type */
+    USBPHY_CLR8(0x1d, 0x10);
+
+    /* force_uart_en = 1'b0 */
+    USBPHY_CLR8(0x6b, 0x04);
+    /* RG_UART_EN = 1'b0 */
+    USBPHY_CLR8(0x6e, 0x01);
+    /* force_uart_en = 1'b0 */
+    USBPHY_CLR8(0x6a, 0x04);
+
+    USBPHY_CLR8(0x21, 0x03);
+    USBPHY_CLR8(0x68, 0xf4);
+
+    /* RG_DATAIN[3:0] = 4'b0000 */
+    USBPHY_CLR8(0x69, 0x3c);
+
+    USBPHY_CLR8(0x6a, 0xba);
+
+    /* RG_USB20_BC11_SW_EN = 1'b0 */
+    USBPHY_CLR8(0x1a, 0x80);
+    /* RG_USB20_OTG_VBUSSCMP_EN = 1'b1 */
+    USBPHY_SET8(0x1a, 0x10);
+
+    //HQA adjustment
+    USBPHY_CLR8(0x18, 0x08);
+    USBPHY_SET8(0x18, 0x06);
+    spin(800);
+
+    /* force enter device mode */
+    //USBPHY_CLR8(0x6c, 0x10);
+    //USBPHY_SET8(0x6c, 0x2E);
+    //USBPHY_SET8(0x6d, 0x3E);
+
+    /* enable VRT internal R architecture */
+    /* RG_USB20_INTR_EN = 1'b1 */
+    USBPHY_SET8(0x00, 0x20);
+#endif
+}
+
+static void Charger_Detect_Init(void)
+{
+    /* RG_USB20_BC11_SW_EN = 1'b1 */
+    USBPHY_SET8(0x1a, 0x80);
+}
+
+static void Charger_Detect_Release(void)
+{
+    /* RG_USB20_BC11_SW_EN = 1'b0 */
+    USBPHY_CLR8(0x1a, 0x80);
+}
+
+static void board_usb_init(void)
+{
+    mt_usb_phy_poweron();
+}
+
+struct udc_descriptor {
+    struct udc_descriptor *next;
+    unsigned short tag; /* ((TYPE << 8) | NUM) */
+    unsigned short len; /* total length */
+    unsigned char data[0];
+};
+
+#if DBG_USB_DUMP_SETUP
+static void dump_setup_packet(const char *str, struct setup_packet *sp)
+{
+    DBG_I("\n");
+    DBG_I(str);
+    DBG_I("       bmRequestType = %x\n", sp->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);
+}
+#else
+static void dump_setup_packet(const char *str, struct setup_packet *sp) {}
+#endif
+
+static void copy_desc(struct urb *urb, void *data, int length)
+{
+
+#if DBG_USB_FIFO
+    DBG_I("%s: urb: %x, data %x, length: %d, actual_length: %d\n",
+          __func__, urb->buffer, data, length, urb->actual_length);
+#endif
+
+    //memcpy(urb->buffer + urb->actual_length, data, length);
+    memcpy(urb->buffer, data, length);
+    //urb->actual_length += length;
+    urb->actual_length = length;
+#if DBG_USB_FIFO
+    DBG_I("%s: urb: %x, data %x, length: %d, actual_length: %d\n",
+          __func__, urb, data, length, urb->actual_length);
+#endif
+}
+
+
+static struct udc_descriptor *udc_descriptor_alloc(unsigned type, unsigned num,
+        unsigned len)
+{
+    struct udc_descriptor *desc;
+    if ((len > 255) || (len < 2) || (num > 255) || (type > 255))
+        return 0;
+
+    if (!(desc = malloc(sizeof(struct udc_descriptor) + len)))
+        return 0;
+
+    desc->next = 0;
+    desc->tag = (type << 8) | num;
+    desc->len = len;
+    desc->data[0] = len;
+    desc->data[1] = type;
+
+    return desc;
+}
+
+static struct udc_descriptor *desc_list = 0;
+static unsigned next_string_id = 1;
+
+static void udc_descriptor_register(struct udc_descriptor *desc)
+{
+    desc->next = desc_list;
+    desc_list = desc;
+}
+
+static unsigned udc_string_desc_alloc(const char *str)
+{
+    unsigned len;
+    struct udc_descriptor *desc;
+    unsigned char *data;
+
+    if (next_string_id > 255)
+        return 0;
+
+    if (!str)
+        return 0;
+
+    len = strlen(str);
+    desc = udc_descriptor_alloc(TYPE_STRING, next_string_id, len * 2 + 2);
+    if (!desc)
+        return 0;
+    next_string_id++;
+
+    /* expand ascii string to utf16 */
+    data = desc->data + 2;
+    while (len-- > 0) {
+        *data++ = *str++;
+        *data++ = 0;
+    }
+
+    udc_descriptor_register(desc);
+    return desc->tag & 0xff;
+}
+
+static int mt_read_fifo(struct udc_endpoint *endpoint)
+{
+
+    struct urb *urb = endpoint->rcv_urb;
+    int len = 0, count = 0;
+    int ep_num = endpoint->num;
+    int index;
+    unsigned char *cp;
+    u32 *wp;
+#if !FPGA_PLATFORM
+    u16 dma_cntl = 0;
+#endif
+
+    if (ep_num == EP0)
+        urb = ep0_urb;
+
+    if (urb) {
+        index = readb(INDEX);
+        writeb(ep_num, INDEX);
+
+        cp = (u8 *) (urb->buffer + urb->actual_length);
+        wp = (u32 *) cp;
+#if DBG_USB_FIFO
+        DBG_I("%s: ep_num: %d, urb: %x, urb->buffer: %x, urb->actual_length = %d\n",
+              __func__, ep_num, urb, urb->buffer, urb->actual_length);
+#endif
+
+        count = len = readw(IECSR + RXCOUNT);
+        if (ep_num != 0) {
+#if DBG_USB_FIFO
+            DBG_I("%s: ep_num: %d count = %d\n",
+                  __func__, ep_num, count);
+#endif
+        }
+
+        /* FIX: DMA has problem write now */
+
+#if !FPGA_PLATFORM
+        arch_clean_invalidate_cache_range((addr_t) cp, count);
+
+        if (ep_num != 0) {
+#if WITH_KERNEL_VM
+            paddr_t wp_dma_addr = kvaddr_to_paddr(wp);
+#else
+            paddr_t wp_dma_addr = (paddr_t)wp;
+#endif
+
+            if (wp_dma_addr >> 32)
+                dprintf(CRITICAL, "[USB] WARN: 64bit physical address!\n");
+            writel((u32)wp_dma_addr, USB_DMA_ADDR (ep_num));
+            writel(count, USB_DMA_COUNT (ep_num));
+            dma_cntl =
+                USB_DMA_BURST_MODE_3 | (ep_num << USB_DMA_ENDPNT_OFFSET) |
+                USB_DMA_EN;
+            writew(dma_cntl, USB_DMA_CNTL (ep_num));
+            while (readw(USB_DMA_CNTL (ep_num)) & USB_DMA_EN);
+        } else
+
+#endif
+        {
+            while (len > 0) {
+                if (len >= 4) {
+                    *wp++ = readl(FIFO(ep_num));
+                    cp = (unsigned char *) wp;
+                    //DBG_I("USB READ FIFO: wp = %lu, cp = %lu\n", wp, cp);
+                    len -= 4;
+                } else {
+                    *cp++ = readb(FIFO(ep_num));
+                    //DBG_I("USB READ FIFO: wp = %lu, cp = %lu\n", wp, cp);
+                    len--;
+                }
+            }
+        }
+
+#if DBG_USB_DUMP_DATA
+        if (ep_num != 0) {
+            DBG_I("%s: &urb->buffer: %x\n", __func__, urb->buffer);
+            DBG_I("[USB] dump data:\n");
+            hexdump8(urb->buffer, count);
+        }
+#endif
+
+        urb->actual_length += count;
+
+        writeb(index, INDEX);
+    }
+
+    return count;
+}
+
+static int mt_write_fifo(struct udc_endpoint *endpoint)
+{
+    struct urb *urb = endpoint->tx_urb;
+    int last = 0, count = 0;
+    int ep_num = endpoint->num;
+    int index;
+    unsigned char *cp = NULL;
+#ifdef USB_TX_DMA_MODE_0
+    u32 *wp;
+    u16 dma_cntl = 0;
+#endif
+
+    if (ep_num == EP0)
+        urb = ep0_urb;
+
+    if (urb) {
+        index = readb(INDEX);
+        writeb(ep_num, INDEX);
+
+#if DBG_USB_DUMP_DESC
+        DBG_I("%s: dump desc\n", __func__);
+        hexdump8(urb->buffer, urb->actual_length);
+#endif
+
+
+#if DBG_USB_FIFO
+        DBG_I("%s: ep_num: %d urb: %x, actual_length: %d\n",
+              __func__, ep_num, urb, urb->actual_length);
+        DBG_I("%s: sent: %d, tx_pkt_size: %d\n", __func__, endpoint->sent, endpoint->maxpkt);
+#endif
+
+        count = last = MIN (urb->actual_length - endpoint->sent,  endpoint->maxpkt);
+        //count = last = urb->actual_length;
+
+#if DBG_USB_FIFO
+        DBG_I("%s: count: %d\n", __func__, count);
+        DBG_I("%s: urb->actual_length = %d\n", __func__, urb->actual_length);
+        DBG_I("%s: endpoint->sent = %d\n", __func__, endpoint->sent);
+#endif
+
+        if (count < 0) {
+            DBG_C("%s: something is wrong, count < 0", __func__);
+        }
+
+        if (count) {
+            cp = urb->buffer + endpoint->sent;
+#ifdef USB_TX_DMA_MODE_0
+            wp = (u32 *)cp;
+
+            arch_clean_invalidate_cache_range((addr_t) cp, count);
+
+            if (ep_num != 0) {
+                writel(wp, USB_DMA_ADDR(ep_num));
+                writel(count, USB_DMA_COUNT(ep_num));
+                dma_cntl =
+                    USB_DMA_BURST_MODE_3 | (ep_num << USB_DMA_ENDPNT_OFFSET) |
+                    USB_DMA_EN | USB_DMA_DIR;
+                writew(dma_cntl, USB_DMA_CNTL(ep_num));
+                while (readw(USB_DMA_CNTL (ep_num)) & USB_DMA_EN);
+            } else
+#endif
+            {
+                //DBG("---------write USB fifo---------\n");
+                while (count > 0) {
+                    //hexdump8(cp, 1);
+                    writeb(*cp, FIFO (ep_num));
+                    cp++;
+                    count--;
+                }
+            }
+        }
+
+        endpoint->last = last;
+        endpoint->sent += last;
+
+        writeb(index, INDEX);
+    }
+
+    return last;
+}
+
+static struct udc_endpoint *mt_find_ep(int ep_num, u8 dir)
+{
+    int i;
+    u8 in = 0;
+
+    /* convert dir to in */
+    if (dir == USB_DIR_IN) /* dir == USB_DIR_IN */
+        in = 1;
+
+    /* for (i = 0; i < udc_device->max_endpoints; i++) */
+    /* for (i = 0; i < the_gadget->ifc_endpoints; i++) */
+    for (i = 0; i < MT_EP_NUM; i++) {
+        if ((ep_list[i].num == ep_num) && (ep_list[i].in == in)) {
+#if DBG_USB_GENERAL
+            DBG_I("%s: find ep!\n", __func__);
+#endif
+            return &ep_list[i];
+        }
+    }
+    return NULL;
+}
+
+static void mt_udc_flush_fifo(u8 ep_num, u8 dir)
+{
+    u16 tmpReg16;
+    u8 index;
+    struct udc_endpoint *endpoint;
+
+    index = readb(INDEX);
+    writeb(ep_num, INDEX);
+
+    if (ep_num == 0) {
+        tmpReg16 = readw(IECSR + CSR0);
+        tmpReg16 |= EP0_FLUSH_FIFO;
+        writew(tmpReg16, IECSR + CSR0);
+        writew(tmpReg16, IECSR + CSR0);
+    } else {
+        endpoint = mt_find_ep(ep_num, dir);
+        if (endpoint->in == 0) { /* USB_DIR_OUT */
+            tmpReg16 = readw(IECSR + RXCSR);
+            tmpReg16 |= EPX_RX_FLUSHFIFO;
+            writew(tmpReg16, IECSR + RXCSR);
+            writew(tmpReg16, IECSR + RXCSR);
+        } else {
+            tmpReg16 = readw(IECSR + TXCSR);
+            tmpReg16 |= EPX_TX_FLUSHFIFO;
+            writew(tmpReg16, IECSR + TXCSR);
+            writew(tmpReg16, IECSR + TXCSR);
+        }
+    }
+
+    /* recover index register */
+    writeb(index, INDEX);
+}
+
+/* the endpoint does not support the received command, stall it!! */
+static void udc_stall_ep(unsigned int ep_num, u8 dir)
+{
+    struct udc_endpoint *endpoint = mt_find_ep(ep_num, dir);
+    u8 index;
+    u16 csr;
+
+    DBG_C("[USB] %s\n", __func__);
+
+    index = readb(INDEX);
+    writeb(ep_num, INDEX);
+
+    if (ep_num == 0) {
+        csr = readw(IECSR + CSR0);
+        csr |= EP0_SENDSTALL;
+        writew(csr, IECSR + CSR0);
+        mt_udc_flush_fifo(ep_num, USB_DIR_OUT);
+    } else {
+        if (endpoint->in == 0) { /* USB_DIR_OUT */
+            csr = readb(IECSR + RXCSR);
+            csr |= EPX_RX_SENDSTALL;
+            writew(csr, IECSR + RXCSR);
+            mt_udc_flush_fifo(ep_num, USB_DIR_OUT);
+        } else {
+            csr = readb(IECSR + TXCSR);
+            csr |= EPX_TX_SENDSTALL;
+            writew(csr, IECSR + TXCSR);
+            mt_udc_flush_fifo(ep_num, USB_DIR_IN);
+        }
+    }
+    //mt_udc_flush_fifo (ep_num, USB_DIR_OUT);
+    //mt_udc_flush_fifo (ep_num, USB_DIR_IN);
+
+    ep0_state = EP0_IDLE;
+
+    writeb(index, INDEX);
+
+    return;
+}
+
+/*
+ * If abnormal DATA transfer happened, like USB unplugged,
+ * we cannot fix this after mt_udc_reset().
+ * Because sometimes there will come reset twice.
+ */
+static void mt_udc_suspend(void)
+{
+    /* handle abnormal DATA transfer if we had any */
+    struct udc_endpoint *endpoint;
+    int i;
+
+    /* deal with flags */
+    usb_online = 0;
+    usb_config_value = 0;
+    the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
+
+    /* error out any pending reqs */
+    for (i = 1; i < MT_EP_NUM; i++) {
+        /* ensure that ept_complete considers
+         * this to be an error state
+         */
+#if DBG_USB_GENERAL
+        DBG_I("%s: ep: %i, in: %s, req: %p\n",
+              __func__, ep_list[i].num, ep_list[i].in ? "IN" : "OUT", ep_list[i].req);
+#endif
+        if ((ep_list[i].req && (ep_list[i].in == 0)) || /* USB_DIR_OUT */
+                (ep_list[i].req && (ep_list[i].in == 1))) { /* USB_DIR_IN */
+            ep_list[i].status = -1; /* HALT */
+            endpoint = &ep_list[i];
+            handle_ept_complete(endpoint);
+        }
+    }
+}
+
+static void mt_udc_rxtxmap_recover(void)
+{
+    int i;
+
+    for (i = 1; i < MT_EP_NUM; i++) {
+        if (ep_list[i].num != 0) { /* allocated */
+
+            writeb(ep_list[i].num, INDEX);
+
+            if (ep_list[i].in == 0) /* USB_DIR_OUT */
+                writel(ep_list[i].maxpkt, (IECSR + RXMAP));
+            else
+                writel(ep_list[i].maxpkt, (IECSR + TXMAP));
+        }
+    }
+}
+
+static void mt_udc_reset(void)
+{
+
+    /* MUSBHDRC automatically does the following when reset signal is detected */
+    /* 1. Sets FAddr to 0
+     * 2. Sets Index to 0
+     * 3. Flush all endpoint FIFOs
+     * 4. Clears all control/status registers
+     * 5. Enables all endpoint interrupts
+     * 6. Generates a Rest interrupt
+     */
+
+    DBG_I("[USB] %s\n", __func__);
+
+    /* disable all endpoint interrupts */
+    writeb(0, INTRTXE);
+    writeb(0, INTRRXE);
+    writeb(0, INTRUSBE);
+
+    writew(SWRST_SWRST | SWRST_DISUSBRESET, SWRST);
+
+    dev_address = 0;
+
+    /* flush FIFO */
+    mt_udc_flush_fifo(0, USB_DIR_OUT);
+    mt_udc_flush_fifo(1, USB_DIR_OUT);
+    mt_udc_flush_fifo(1, USB_DIR_IN);
+    //mt_udc_flush_fifo (2, USB_DIR_IN);
+
+    /* detect USB speed */
+    if (readb(POWER) & PWR_HS_MODE) {
+        DBG_I("[USB] USB High Speed\n");
+//      enable_highspeed();
+    } else {
+        DBG_I("[USB] USB Full Speed\n");
+    }
+
+    /* restore RXMAP and TXMAP if the endpoint has been configured */
+    mt_udc_rxtxmap_recover();
+
+    /* enable suspend */
+    writeb((INTRUSB_SUSPEND | INTRUSB_RESUME | INTRUSB_RESET |INTRUSB_DISCON), INTRUSBE);
+
+}
+
+static void mt_udc_ep0_write(void)
+{
+
+    struct udc_endpoint *endpoint = &ep_list[EP0];
+    int count = 0;
+    u16 csr0 = 0;
+    u8 index = 0;
+
+    index = readb(INDEX);
+    writeb(0, INDEX);
+
+    csr0 = readw(IECSR + CSR0);
+    if (csr0 & EP0_TXPKTRDY) {
+        DBG_I("mt_udc_ep0_write: ep0 is not ready to be written\n");
+        return;
+    }
+
+    count = mt_write_fifo(endpoint);
+
+#if DBG_USB_GENERAL
+    DBG_I("%s: count = %d\n", __func__, count);
+#endif
+
+    if (count < EP0_MAX_PACKET_SIZE) {
+        /* last packet */
+        csr0 |= (EP0_TXPKTRDY | EP0_DATAEND);
+        ep0_urb->actual_length = 0;
+        endpoint->sent = 0;
+        ep0_state = EP0_IDLE;
+    } else {
+        /* more packets are waiting to be transferred */
+        csr0 |= EP0_TXPKTRDY;
+    }
+
+    writew(csr0, IECSR + CSR0);
+    writeb(index, INDEX);
+
+    return;
+}
+
+static void mt_udc_ep0_read(void)
+{
+
+    struct udc_endpoint *endpoint = &ep_list[EP0];
+    int count = 0;
+    u16 csr0 = 0;
+    u8 index = 0;
+
+    index = readb(INDEX);
+    writeb(EP0, INDEX);
+
+    csr0 = readw(IECSR + CSR0);
+
+    /* erroneous ep0 interrupt */
+    if (!(csr0 & EP0_RXPKTRDY)) {
+        return;
+    }
+
+    count = mt_read_fifo(endpoint);
+
+    if (count <= EP0_MAX_PACKET_SIZE) {
+        /* last packet */
+        csr0 |= (EP0_SERVICED_RXPKTRDY | EP0_DATAEND);
+        ep0_state = EP0_IDLE;
+    } else {
+        /* more packets are waiting to be transferred */
+        csr0 |= EP0_SERVICED_RXPKTRDY;
+    }
+
+    writew(csr0, IECSR + CSR0);
+
+    writeb(index, INDEX);
+
+    return;
+}
+
+/*
+ * udc_setup_ep - setup endpoint
+ *
+ * Associate a physical endpoint with endpoint_instance and initialize FIFO
+ */
+static void mt_setup_ep(unsigned int ep, struct udc_endpoint *endpoint)
+{
+    u8 index;
+    u16 csr;
+    u16 csr0;
+    u16 max_packet_size;
+    u8 fifosz = 0;
+
+    /* EP table records in bits hence bit 1 is ep0 */
+    index = readb(INDEX);
+    writeb(ep, INDEX);
+
+    if (ep == EP0) {
+        /* Read control status register for endpiont 0 */
+        csr0 = readw(IECSR + CSR0);
+
+        /* check whether RxPktRdy is set? */
+        if (!(csr0 & EP0_RXPKTRDY))
+            return;
+    }
+
+    /* Configure endpoint fifo */
+    /* Set fifo address, fifo size, and fifo max packet size */
+#if DBG_USB_GENERAL
+    DBG_I("%s: endpoint->in: %d, maxpkt: %d\n",
+          __func__, endpoint->in, endpoint->maxpkt);
+#endif
+    if (endpoint->in == 0) { /* USB_DIR_OUT */
+        /* Clear data toggle to 0 */
+        csr = readw(IECSR + RXCSR);
+        /* pangyen 20090911 */
+        csr |= EPX_RX_CLRDATATOG | EPX_RX_FLUSHFIFO;
+        writew(csr, IECSR + RXCSR);
+        /* Set fifo address */
+        writew(fifo_addr >> 3, RXFIFOADD);
+        /* Set fifo max packet size */
+        max_packet_size = endpoint->maxpkt;
+        writew(max_packet_size, IECSR + RXMAP);
+        /* Set fifo size (double buffering is currently not enabled) */
+        switch (max_packet_size) {
+            case 8:
+            case 16:
+            case 32:
+            case 64:
+            case 128:
+            case 256:
+            case 512:
+            case 1024:
+            case 2048:
+                if (endpoint->mode == DOUBLE_BUF)
+                    fifosz |= FIFOSZ_DPB;
+                fifosz |= __builtin_ffs(max_packet_size >> 4);
+                writeb(fifosz, RXFIFOSZ);
+                break;
+            case 4096:
+                fifosz |= __builtin_ffs(max_packet_size >> 4);
+                writeb(fifosz, RXFIFOSZ);
+                break;
+            case 3072:
+                fifosz = __builtin_ffs(4096 >> 4);
+                writeb(fifosz, RXFIFOSZ);
+                break;
+
+            default:
+                DBG_C("The max_packet_size for ep %d is not supported\n", ep);
+        }
+    } else {
+        /* Clear data toggle to 0 */
+        csr = readw(IECSR + TXCSR);
+        /* pangyen 20090911 */
+        csr |= EPX_TX_CLRDATATOG | EPX_TX_FLUSHFIFO;
+        writew(csr, IECSR + TXCSR);
+        /* Set fifo address */
+        writew(fifo_addr >> 3, TXFIFOADD);
+        /* Set fifo max packet size */
+        max_packet_size = endpoint->maxpkt;
+        writew(max_packet_size, IECSR + TXMAP);
+        /* Set fifo size(double buffering is currently not enabled) */
+        switch (max_packet_size) {
+            case 8:
+            case 16:
+            case 32:
+            case 64:
+            case 128:
+            case 256:
+            case 512:
+            case 1024:
+            case 2048:
+                if (endpoint->mode == DOUBLE_BUF)
+                    fifosz |= FIFOSZ_DPB;
+                /* Add for resolve issue reported by Coverity */
+                fifosz |= __builtin_ffs(max_packet_size >> 4);
+                writeb(fifosz, TXFIFOSZ);
+                break;
+            case 4096:
+                fifosz |= __builtin_ffs(max_packet_size >> 4);
+                writeb(fifosz, TXFIFOSZ);
+                break;
+            case 3072:
+                fifosz = __builtin_ffs(4096 >> 4);
+                writeb(fifosz, TXFIFOSZ);
+                break;
+
+            default:
+                DBG_C("The max_packet_size for ep %d is not supported\n", ep);
+        }
+    }
+
+    if (endpoint->mode == DOUBLE_BUF)
+        fifo_addr += (max_packet_size << 1);
+    else
+        fifo_addr += max_packet_size;
+
+    /* recover INDEX register */
+    writeb(index, INDEX);
+}
+
+static int ep0_standard_setup(struct urb *urb)
+{
+    struct setup_packet *request;
+    struct udc_descriptor *desc;
+    //struct udc_device *device;
+    u8 *cp = urb->buffer;
+
+    u8 ep_num;  /* ep number */
+    u8 dir; /* DIR */
+    struct udc_endpoint *endpoint;
+
+#if 0
+    if (!urb || !urb->device) {
+        DBG ("\n!urb || !urb->device\n");
+        return false;
+    }
+#endif
+
+    request = &urb->device_request;
+    //device = urb->device;
+
+    dump_setup_packet("[USB] Device Request\n", request);
+
+    if ((request->type & USB_TYPE_MASK) != 0) {
+        return false;           /* Class-specific requests are handled elsewhere */
+    }
+
+    /* handle all requests that return data (direction bit set on bm RequestType) */
+    if ((request->type & USB_EP_DIR_MASK)) {
+        /* send the descriptor */
+        ep0_state = EP0_TX;
+
+        switch (request->request) {
+                /* data stage: from device to host */
+            case GET_STATUS:
+#if DBG_USB_GENERAL
+                DBG_I("GET_STATUS\n");
+#endif
+                urb->actual_length = 2;
+                cp[0] = cp[1] = 0;
+                switch (request->type & USB_RECIP_MASK) {
+                    case USB_RECIP_DEVICE:
+                        cp[0] = USB_STAT_SELFPOWERED;
+                        break;
+                    case USB_RECIP_OTHER:
+                        urb->actual_length = 0;
+                        break;
+                    default:
+                        break;
+                }
+
+                return 0;
+
+            case GET_DESCRIPTOR:
+#if DBG_USB_GENERAL
+                DBG_I("GET_DESCRIPTOR\n");
+#endif
+                /* usb_highspeed? */
+
+                for (desc = desc_list; desc; desc = desc->next) {
+#if DBG_USB_DUMP_DESC
+                    DBG_I("desc->tag: %x: request->value: %x\n", desc->tag, request->value);
+#endif
+                    if (desc->tag == request->value) {
+
+#if DBG_USB_DUMP_DESC
+                        DBG_I("Find packet!\n");
+#endif
+                        unsigned len = desc->len;
+                        if (len > request->length)
+                            len = request->length;
+
+#if DBG_USB_GENERAL
+                        DBG_I("%s: urb: %p, cp: %p\n", __func__, urb, cp);
+#endif
+                        copy_desc(urb, desc->data, len);
+                        //DBG_I("GET_DESCRIPTOR done:");
+                        return 0;
+                    }
+                }
+                /* descriptor lookup failed */
+                return false;
+
+            case GET_CONFIGURATION:
+#if DBG_USB_GENERAL
+                DBG_I("GET_CONFIGURATION\n");
+                DBG_I("USB_EP_DIR_MASK\n");
+#endif
+                urb->actual_length = 1;
+#if 0
+                urb->actual_length = 1;
+                ((char *) urb->buffer)[0] = device->configuration;
+#endif
+                cp[0] = 1;
+                return 0;
+                //break;
+
+            case GET_INTERFACE:
+#if DBG_USB_GENERAL
+                DBG_I("GET_INTERFACE\n");
+#endif
+
+#if 0
+                urb->actual_length = 1;
+                ((char *) urb->buffer)[0] = device->alternate;
+                return 0;
+#endif
+            default:
+                DBG_C("Unsupported command with TX data stage\n");
+                break;
+        }
+    } else {
+
+        switch (request->request) {
+
+            case SET_ADDRESS:
+#if DBG_USB_GENERAL
+                DBG_I("SET_ADDRESS\n");
+#endif
+
+                dev_address = (request->value);
+                set_address = 1;
+                return 0;
+
+            case SET_CONFIGURATION:
+#if DBG_USB_GENERAL
+                DBG_I("SET_CONFIGURATION\n");
+#endif
+#if 0
+                device->configuration = (request->value) & 0x7f;
+                device->interface = device->alternate = 0;
+#endif
+                if (request->value == 1) {
+                    usb_config_value = 1;
+                    the_gadget->notify(the_gadget, UDC_EVENT_ONLINE);
+                } else {
+                    usb_config_value = 0;
+                    the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
+                }
+
+                usb_online = request->value ? 1 : 0;
+                //usb_status(request->value ? 1 : 0, usb_highspeed);
+
+                return 0;
+            case CLEAR_FEATURE:
+#if DBG_USB_GENERAL
+                DBG_I("CLEAR_FEATURE\n");
+#endif
+                ep_num = request->index & 0xf;
+                dir = request->index & 0x80;
+                if ((request->value == 0) && (request->length == 0)) {
+#if DBG_USB_GENERAL
+                    DBG_I("Clear Feature: ep: %d dir: %d\n", ep_num, dir);
+#endif
+                    endpoint = mt_find_ep(ep_num, dir);
+                    mt_setup_ep((unsigned int)ep_num, endpoint);
+                    return 0;
+                }
+                DBG_C("clear feature can't match, value[%d], len[%d]\n",
+                      request->value, request->length);
+                break;
+            default:
+                DBG_C("Unsupported command with RX data stage\n");
+                break;
+
+        }
+    }
+    return false;
+}
+
+static int ep0_class_setup (struct urb *urb)
+{
+
+    struct setup_packet *request;
+
+    request = &urb->device_request;
+
+    switch (request->request) {
+        case CDCACM_REQ_SET_LINE_CODING:
+            DBG_I("CDC ACM Request: SET_LINE_CODING\n");
+            ep0_state = EP0_RX;
+            tool_state_update(1);
+            break;
+        case CDCACM_REQ_GET_LINE_CODING:
+            DBG_I("CDC ACM Request: GET_LINE_CODING\n");
+            memcpy(urb->buffer, &g_line_coding,
+                   sizeof(struct usb_acm_line_coding));
+            urb->actual_length = sizeof(struct usb_acm_line_coding);
+            //DBG_I("urb->actual_length = %d\n", urb->actual_length);
+            //DBG_I("sizeof(struct USB_ACM_LINE_CODING = %d\n)", sizeof(struct USB_ACM_LINE_CODING));
+            ep0_state = EP0_TX;
+            break;
+        case CDCACM_REQ_SET_CONTROL_LINE_STATE:
+            DBG_I("CDC ACM Request: SET_CONTROL_LINE_STATE, request->wValue=%x\n",
+                  request->value);
+            break;
+        case CDCACM_REQ_SEND_BREAK:
+            /* do nothing */
+            DBG_I("CDC ACM Request: SEND_BREAK\n");
+            break;
+        default:
+            return -1;
+    }
+
+    return 0;
+}
+
+static void mt_udc_ep0_setup(void)
+{
+    struct udc_endpoint *endpoint = &ep_list[0];
+    u8 index;
+    u8 stall = 0;
+    u16 csr0;
+    struct setup_packet *request;
+
+#ifdef USB_DEBUG
+    u16 count;
+#endif
+
+    index = readb(INDEX);
+    writeb(0, INDEX);
+    /* Read control status register for endpiont 0 */
+    csr0 = readw(IECSR + CSR0);
+
+    /* check whether RxPktRdy is set? */
+    if (!(csr0 & EP0_RXPKTRDY))
+        return;
+
+    /* unload fifo */
+    ep0_urb->actual_length = 0;
+
+#ifndef USB_DEBUG
+    mt_read_fifo(endpoint);
+#else
+    count = mt_read_fifo(endpoint);
+
+//#if DBG_USB_FIFO
+    DBG_I("%s: mt_read_fifo count = %d\n", __func__, count);
+//#endif
+#endif
+    /* decode command */
+    request = &ep0_urb->device_request;
+    memcpy(request, ep0_urb->buffer, sizeof(struct setup_packet));
+
+    if (((request->type) & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+#if DBG_USB_GENERAL
+        DBG_I("[USB] Standard Request\n");
+#endif
+        stall = ep0_standard_setup(ep0_urb);
+        if (stall) {
+            dump_setup_packet("[USB] STANDARD REQUEST NOT SUPPORTED\n", request);
+        }
+    } else if (((request->type) & USB_TYPE_MASK) == USB_TYPE_CLASS) {
+#if DBG_USB_GENERAL
+        DBG_I("[USB] Class-Specific Request\n");
+#endif
+        if(usbtty_init_done()) {
+            stall = ep0_class_setup(ep0_urb);
+            if (stall) {
+                dump_setup_packet("[USB] CLASS REQUEST NOT SUPPORTED\n", request);
+            }
+        }
+    } else if (((request->type) & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
+#if DBG_USB_GENERAL
+        DBG_I("[USB] Vendor-Specific Request\n");
+        /* do nothing now */
+        DBG_I("[USB] ALL VENDOR-SPECIFIC REQUESTS ARE NOT SUPPORTED!!\n");
+#endif
+    }
+
+    if (stall) {
+        /* the received command is not supported */
+        udc_stall_ep(0, USB_DIR_OUT);
+        return;
+    }
+
+    switch (ep0_state) {
+        case EP0_TX:
+            /* data stage: from device to host */
+#if DBG_USB_GENERAL
+            DBG_I("%s: EP0_TX\n", __func__);
+#endif
+            csr0 = readw(IECSR + CSR0);
+            csr0 |= (EP0_SERVICED_RXPKTRDY);
+            writew(csr0, IECSR + CSR0);
+
+            mt_udc_ep0_write();
+
+            break;
+        case EP0_RX:
+            /* data stage: from host to device */
+#if DBG_USB_GENERAL
+            DBG_I("%s: EP0_RX\n", __func__);
+#endif
+            csr0 = readw(IECSR + CSR0);
+            csr0 |= (EP0_SERVICED_RXPKTRDY);
+            writew(csr0, IECSR + CSR0);
+
+            break;
+        case EP0_IDLE:
+            /* no data stage */
+#if DBG_USB_GENERAL
+            DBG_I("%s: EP0_IDLE\n", __func__);
+#endif
+            csr0 = readw(IECSR + CSR0);
+            csr0 |= (EP0_SERVICED_RXPKTRDY | EP0_DATAEND);
+
+            writew(csr0, IECSR + CSR0);
+            writew(csr0, IECSR + CSR0);
+
+            break;
+        default:
+            break;
+    }
+
+    writeb(index, INDEX);
+    return;
+
+}
+
+static void mt_udc_ep0_handler(void)
+{
+
+    u16 csr0;
+    u8 index = 0;
+
+    index = readb(INDEX);
+    writeb(0, INDEX);
+
+    csr0 = readw(IECSR + CSR0);
+
+    if (csr0 & EP0_SENTSTALL) {
+#if DBG_USB_GENERAL
+        DBG_I("USB: [EP0] SENTSTALL\n");
+#endif
+        /* needs implementation for exception handling here */
+        ep0_state = EP0_IDLE;
+    }
+
+    if (csr0 & EP0_SETUPEND) {
+#if DBG_USB_GENERAL
+        DBG_I("USB: [EP0] SETUPEND\n");
+#endif
+        csr0 |= EP0_SERVICE_SETUP_END;
+        writew(csr0, IECSR + CSR0);
+
+        ep0_state = EP0_IDLE;
+    }
+
+    switch (ep0_state) {
+        case EP0_IDLE:
+#if DBG_USB_GENERAL
+            DBG_I("%s: EP0_IDLE\n", __func__);
+#endif
+            if (set_address) {
+                writeb(dev_address, FADDR);
+                set_address = 0;
+            }
+            mt_udc_ep0_setup();
+            break;
+        case EP0_TX:
+#if DBG_USB_GENERAL
+            DBG_I("%s: EP0_TX\n", __func__);
+#endif
+            mt_udc_ep0_write();
+            break;
+        case EP0_RX:
+#if DBG_USB_GENERAL
+            DBG_I("%s: EP0_RX\n", __func__);
+#endif
+            mt_udc_ep0_read();
+            break;
+        default:
+            break;
+    }
+
+    writeb(index, INDEX);
+
+    return;
+}
+
+struct udc_endpoint *_udc_endpoint_alloc(unsigned char num, unsigned char in,
+        unsigned short max_pkt)
+{
+    int i;
+
+    /*
+     * find an unused slot in ep_list from EP1 to MAX_EP
+     * for example, EP1 will use 2 slot one for IN and the other for OUT
+     */
+    if (num != EP0) {
+        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;
+
+        if (in) { /* usb EP1 tx */
+            ep_list[i].tx_urb = tx_urb;
+#ifdef USB_DOUBLE_BUF
+            ep_list[i].mode = DOUBLE_BUF;
+#endif
+        } else {    /* usb EP1 rx */
+            ep_list[i].rcv_urb = rx_urb;
+#ifdef USB_DOUBLE_BUF
+            ep_list[i].mode = DOUBLE_BUF;
+#endif
+        }
+    } else {
+        i = EP0;    /* EP0 */
+    }
+
+    ep_list[i].maxpkt = max_pkt;
+    ep_list[i].num = num;
+    ep_list[i].in = in;
+    ep_list[i].req = NULL;
+
+    /* store EPT_TX/RX info */
+    if (ep_list[i].in) {
+        ep_list[i].bit = EPT_TX(num);
+    } else {
+        ep_list[i].bit = EPT_RX(num);
+    }
+
+    /* write parameters to this ep (write to hardware) */
+    mt_setup_ep(num, &ep_list[i]);
+
+    DBG_I("[USB] ept%d %s @%p/%p max=%d bit=%x\n",
+          num, in ? "in" : "out", &ep_list[i], &ep_list, max_pkt, ep_list[i].bit);
+
+    return &ep_list[i];
+}
+
+#define SETUP(type,request) (((type) << 8) | (request))
+
+static unsigned long ept_alloc_table = EPT_TX(0) | EPT_RX(0);
+
+struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt)
+{
+    struct udc_endpoint *ept;
+    unsigned n;
+    unsigned in;
+
+    if (type == UDC_BULK_IN) {
+        in = 1;
+    } else if (type == UDC_BULK_OUT) {
+        in = 0;
+    } else {
+        return 0;
+    }
+
+    /* udc_endpoint_alloc is used for EPx except EP0 */
+    for (n = 1; n < 16; n++) {
+        unsigned long bit = in ? EPT_TX(n) : EPT_RX(n);
+        if (ept_alloc_table & bit)
+            continue;
+        ept = _udc_endpoint_alloc(n, in, maxpkt);
+        if (ept)
+            ept_alloc_table |= bit;
+        return ept;
+    }
+
+    return 0;
+}
+
+static void handle_ept_complete(struct udc_endpoint *ept)
+{
+    unsigned int actual;
+    int status;
+    struct udc_request *req;
+
+    req = ept->req;
+    if (req) {
+#if DBG_USB_GENERAL
+        DBG_I("%s: req: %p: req->length: %d: status: %d\n", __func__, req, req->length, ept->status);
+#endif
+        /* release this request for processing next */
+        ept->req = NULL;
+
+        if (ept->status == -1) {
+            actual = 0;
+            status = -1;
+            DBG_C("%s: EP%d/%s FAIL status: %x\n",
+                  __func__, ept->num, ept->in ? "in" : "out", status);
+        } else {
+            actual = req->length;
+            status = 0;
+        }
+        if (req->complete)
+            req->complete(req, actual, status);
+    }
+
+}
+
+static void mt_udc_epx_handler(u8 ep_num, u8 dir)
+{
+    u8 index;
+    u16 csr;
+    u32 count;
+    struct udc_endpoint *endpoint;
+    struct urb *urb;
+    struct udc_request *req;    /* for event signaling */
+    u8 intrrxe;
+
+    endpoint = mt_find_ep(ep_num, dir);
+
+    index = readb(INDEX);
+    writeb(ep_num, INDEX);
+
+#if DBG_USB_GENERAL
+    DBG_I("EP%d Interrupt\n", ep_num);
+    DBG_I("dir: %x\n", dir);
+#endif
+
+    switch (dir) {
+        case USB_DIR_OUT:
+            /* transfer direction is from host to device */
+            /* from the view of usb device, it's RX */
+            csr = readw(IECSR + RXCSR);
+
+            if (csr & EPX_RX_SENTSTALL) {
+                DBG_C("EP %d(RX): STALL\n", ep_num);
+                /* exception handling: implement this!! */
+                return;
+            }
+
+            if (!(csr & EPX_RX_RXPKTRDY)) {
+#if DBG_USB_GENERAL
+                DBG_I("EP %d: ERRONEOUS INTERRUPT\n", ep_num); // normal
+#endif
+                return;
+            }
+
+            //DBG_C("mt_read_fifo, start\n");
+            count = mt_read_fifo(endpoint);
+            //DBG_C("mt_read_fifo, end\n");
+
+#if DBG_USB_GENERAL
+            DBG_I("EP%d(RX), count = %d\n", ep_num, count);
+#endif
+
+            csr &= ~EPX_RX_RXPKTRDY;
+            writew(csr, IECSR + RXCSR);
+            if (readw(IECSR + RXCSR) & EPX_RX_RXPKTRDY) {
+#if DBG_USB_GENERAL
+                DBG_I("%s: rxpktrdy clear failed\n", __func__);
+#endif
+            }
+
+            /* do signaling */
+            req = endpoint->req;
+            /* workaround: if req->lenth == 64 bytes (not huge data transmission)
+             * do normal return */
+#if DBG_USB_GENERAL
+            DBG_I("%s: req->length: %x, endpoint->rcv_urb->actual_length: %x\n",
+                  __func__, req->length, endpoint->rcv_urb->actual_length);
+#endif
+
+            /* Deal with FASTBOOT command */
+            if ((req->length >= endpoint->rcv_urb->actual_length) && req->length == 64) {
+                req->length = count;
+
+                /* mask EPx INTRRXE */
+                /* The buffer is passed from the AP caller.
+                 * It happens that AP is dealing with the buffer filled data by driver,
+                 * but the driver is still receiving the next data packets onto the buffer.
+                 * Data corrupted happens if the every request use the same buffer.
+                 * Mask the EPx to ensure that AP and driver are not accessing the buffer parallely.
+                 */
+                intrrxe = readb(INTRRXE);
+                writeb((intrrxe &= ~(1 << ep_num)), INTRRXE);
+            }
+
+            /* Deal with DATA transfer */
+            if ((req->length == endpoint->rcv_urb->actual_length) ||
+                    ((req->length >= endpoint->rcv_urb->actual_length) && req->length == 64)) {
+                handle_ept_complete(endpoint);
+
+                /* mask EPx INTRRXE */
+                /* The buffer is passed from the AP caller.
+                 * It happens that AP is dealing with the buffer filled data by driver,
+                 * but the driver is still receiving the next data packets onto the buffer.
+                 * Data corrupted happens if the every request use the same buffer.
+                 * Mask the EPx to ensure that AP and driver are not accessing the buffer parallely.
+                 */
+                intrrxe = readb(INTRRXE);
+                writeb((intrrxe &= ~(1 << ep_num)), INTRRXE);
+            }
+            break;
+        case USB_DIR_IN:
+            /* transfer direction is from device to host */
+            /* from the view of usb device, it's tx */
+            csr = readw(IECSR + TXCSR);
+
+            if (csr & EPX_TX_SENTSTALL) {
+                DBG_C("EP %d(TX): STALL\n", ep_num);
+                endpoint->status = -1;
+                handle_ept_complete(endpoint);
+                /* exception handling: implement this!! */
+                return;
+            }
+
+            if (csr & EPX_TX_TXPKTRDY) {
+                DBG_C
+                ("mt_udc_epx_handler: ep%d is not ready to be written\n",
+                 ep_num);
+                return;
+            }
+
+            urb = endpoint->tx_urb;
+            if (endpoint->sent == urb->actual_length) {
+                /* do signaling */
+                handle_ept_complete(endpoint);
+                break;
+            }
+
+            /* send next packet of the same urb */
+            count = mt_write_fifo(endpoint);
+#if DBG_USB_GENERAL
+            DBG_I("EP%d(TX), count = %d\n", ep_num, endpoint->sent);
+#endif
+
+            if (count != 0) {
+                /* not the interrupt generated by the last tx packet of the transfer */
+                csr |= EPX_TX_TXPKTRDY;
+                writew(csr, IECSR + TXCSR);
+            }
+
+            break;
+        default:
+            break;
+    }
+
+    writeb(index, INDEX);
+
+    return;
+}
+
+static void mt_udc_irq(u8 intrtx, u8 intrrx, u8 intrusb)
+{
+
+    int i;
+
+    DBG_IRQ("[USB] INTERRUPT\n");
+
+    if (intrusb) {
+        if (intrusb & INTRUSB_RESUME) {
+            DBG_IRQ("[USB] INTRUSB: RESUME\n");
+        }
+
+        if (intrusb & INTRUSB_SESS_REQ) {
+            DBG_IRQ("[USB] INTRUSB: SESSION REQUEST\n");
+        }
+
+        if (intrusb & INTRUSB_VBUS_ERROR) {
+            DBG_IRQ("[USB] INTRUSB: VBUS ERROR\n");
+        }
+
+        if (intrusb & INTRUSB_SUSPEND) {
+            DBG_IRQ("[USB] INTRUSB: SUSPEND\n");
+            mt_udc_suspend();
+        }
+
+        if (intrusb & INTRUSB_CONN) {
+            DBG_IRQ("[USB] INTRUSB: CONNECT\n");
+        }
+
+        if (intrusb & INTRUSB_DISCON) {
+            DBG_IRQ("[USB] INTRUSB: DISCONNECT\n");
+        }
+
+        if (intrusb & INTRUSB_RESET) {
+            DBG_IRQ("[USB] INTRUSB: RESET\n");
+            DBG_C("[USB] INTRUSB: RESET\n");
+            mt_udc_reset();
+        }
+
+        if (intrusb & INTRUSB_SOF) {
+            DBG_IRQ("[USB] INTRUSB: SOF\n");
+        }
+    }
+
+    /* endpoint 0 interrupt? */
+    if (intrtx & EPMASK (0)) {
+        mt_udc_ep0_handler();
+        intrtx &= ~0x1;
+    }
+
+    if (intrtx) {
+        for (i = 1; i < MT_EP_NUM; i++) {
+            if (intrtx & EPMASK (i)) {
+                mt_udc_epx_handler(i, USB_DIR_IN);
+            }
+        }
+    }
+
+    if (intrrx) {
+        for (i = 1; i < MT_EP_NUM; i++) {
+            if (intrrx & EPMASK (i)) {
+                mt_udc_epx_handler(i, USB_DIR_OUT);
+            }
+        }
+    }
+
+}
+
+static enum handler_return service_interrupts(void *arg)
+{
+
+    volatile u8 intrtx, intrrx, intrusb;
+    /* polling interrupt status for incoming interrupts and service it */
+    intrtx = readb(INTRTX) & readb(INTRTXE);
+    intrrx = readb(INTRRX) & readb(INTRRXE);
+    intrusb = readb(INTRUSB) & readb(INTRUSBE);
+
+    writeb(intrtx, INTRTX);
+    writeb(intrrx, INTRRX);
+    writeb(intrusb, INTRUSB);
+
+    intrusb &= ~INTRUSB_SOF;
+
+    if (intrtx | intrrx | intrusb) {
+        mt_udc_irq(intrtx, intrrx, intrusb);
+    }
+
+    return INT_RESCHEDULE;
+}
+
+static int mt_usb_irq_init(void)
+{
+    /* disable all endpoint interrupts */
+    writeb(0, INTRTXE);
+    writeb(0, INTRRXE);
+    writeb(0, INTRUSBE);
+
+    /* 2. Ack all gpt irq if needed */
+    //writel(0x3F, GPT_IRQ_ACK);
+
+    /* 3. Register usb irq */
+    mt_irq_set_sens(MT_USB0_IRQ_ID, LEVEL_SENSITIVE);
+    mt_irq_set_polarity(MT_USB0_IRQ_ID, MT65xx_POLARITY_LOW);
+
+    return 0;
+}
+
+/* Turn on the USB connection by enabling the pullup resistor */
+void mt_usb_connect_internal(void)
+{
+    u8 tmpReg8;
+
+    /* connect */
+    tmpReg8 = readb(POWER);
+    tmpReg8 |= PWR_SOFT_CONN;
+    tmpReg8 |= PWR_ENABLE_SUSPENDM;
+
+#ifdef USB_FORCE_FULL_SPEED
+    tmpReg8 &= ~PWR_HS_ENAB;
+#else
+    tmpReg8 |= PWR_HS_ENAB;
+#endif
+    writeb(tmpReg8, POWER);
+}
+
+/* Turn off the USB connection by disabling the pullup resistor */
+void mt_usb_disconnect_internal(void)
+{
+    u8 tmpReg8;
+
+    /* connect */
+    tmpReg8 = readb(POWER);
+    tmpReg8 &= ~PWR_SOFT_CONN;
+    writeb(tmpReg8, POWER);
+}
+
+int udc_init(struct udc_device *dev)
+{
+    struct udc_descriptor *desc = NULL;
+#ifdef USB_GINTR
+#ifdef USB_HSDMA_ISR
+    u32 usb_dmaintr;
+#endif
+    u32 usb_l1intm;
+#endif
+
+    DBG_I("[USB] %s:\n", __func__);
+
+    DBG_I("[USB] ep0_urb: %p\n", ep0_urb);
+    /* RESET */
+    mt_usb_disconnect_internal();
+    thread_sleep(20);
+    /*mt_usb_connect_internal();*/
+    /*thread_sleep(20);*/
+
+    /* usb phy init */
+    board_usb_init();
+    mt_usb_phy_recover();
+    thread_sleep(20);
+    /* allocate ep0 */
+    ep0out = _udc_endpoint_alloc(EP0, 0, EP0_MAX_PACKET_SIZE);
+    ep0in = _udc_endpoint_alloc(EP0, 1, EP0_MAX_PACKET_SIZE);
+    ep0req = udc_request_alloc();
+    ep0req->buffer = mempool_alloc(4096, MEMPOOL_ANY);
+    ep0_urb->buffer = (u8 *)mempool_alloc(4096, MEMPOOL_ANY);
+    if (!ep0req->buffer) {
+        dprintf(CRITICAL, "[USB] allocate buffer failed\n");
+        return ERR_NO_MEMORY;
+    }
+
+    {
+        /* create and register a language table descriptor */
+        /* language 0x0409 is US English */
+        desc = udc_descriptor_alloc(TYPE_STRING, EP0, 4);
+        desc->data[2] = 0x09;
+        desc->data[3] = 0x04;
+        udc_descriptor_register(desc);
+    }
+#ifdef USB_HSDMA_ISR
+    /* setting HSDMA interrupt register */
+    usb_dmaintr = (0xff | 0xff << USB_DMA_INTR_UNMASK_SET_OFFSET);
+    writel(usb_dmaintr, USB_DMA_INTR);
+#endif
+
+#ifdef USB_GINTR
+    usb_l1intm = (TX_INT_STATUS | RX_INT_STATUS | USBCOM_INT_STATUS | DMA_INT_STATUS);
+    writel(usb_l1intm, USB_L1INTM);
+#endif
+    the_device = dev;
+
+#if DBG_USB_GENERAL
+    DBG_I("[USB] devctl: 0x%x, hwcaps: 0x%x\n", readb(DEVCTL), readb(HWVERS));
+#endif
+
+    return 0;
+}
+
+void udc_endpoint_free(struct udc_endpoint *ept)
+{
+    /* todo */
+}
+
+struct udc_request *udc_request_alloc(void)
+{
+    struct udc_request *req;
+    req = malloc(sizeof(*req));
+    req->buffer = NULL;
+    req->length = 0;
+    return req;
+}
+
+
+void udc_request_free(struct udc_request *req)
+{
+    free(req);
+}
+
+/* Called to start packet transmission. */
+/* It must be applied in udc_request_queue when polling mode is used.
+ * (When USB_GINTR is undefined).
+ * If interrupt mode is used, you can use
+ * mt_udc_epx_handler(ept->num, USB_DIR_IN); to replace mt_ep_write make ISR
+ * do it for you.
+ */
+static int mt_ep_write(struct udc_endpoint *endpoint)
+{
+    int ep_num = endpoint->num;
+    int count;
+    u8 index;
+    u16 csr;
+
+    index = readb(INDEX);
+    writeb(ep_num, INDEX);
+
+    /* udc_endpoint_write: cannot write ep0 */
+    if (ep_num == 0)
+        return false;
+
+    /* udc_endpoint_write: cannot write USB_DIR_OUT */
+    if (endpoint->in == 0)
+        return false;
+
+    csr = readw(IECSR + TXCSR);
+    if (csr & EPX_TX_TXPKTRDY) {
+#if DBG_USB_GENERAL
+        DBG_I("[USB]: udc_endpoint_write: ep%d is not ready to be written\n",
+              ep_num);
+
+#endif
+        return false;
+    }
+    count = mt_write_fifo(endpoint);
+
+    csr |= EPX_TX_TXPKTRDY;
+    writew(csr, IECSR + TXCSR);
+
+    writeb(index, INDEX);
+
+    return count;
+}
+
+int udc_request_queue(struct udc_endpoint *ept, struct udc_request *req)
+{
+    u8 intrrxe;
+
+#if DBG_USB_GENERAL
+    DBG_I("[USB] %s: ept%d %s queue req=%p, req->length=%x\n",
+          __func__, ept->num, ept->in ? "in" : "out", req, req->length);
+    DBG_I("[USB] %s: ept%d: %p, ept->in: %s, ept->rcv_urb->buffer: %p, req->buffer: %p\n",
+          __func__, ept->num, ept, ept->in ? "IN" : "OUT" , ept->rcv_urb->buffer, req->buffer);
+#endif
+
+    THREAD_LOCK(state); /* enter_critical_section */
+    ept->req = req;
+    ept->status = 0;    /* ACTIVE */
+
+    ept->sent = 0;
+    ept->last = 0;
+
+    /* read */
+    if (!ept->in) {
+        ept->rcv_urb->buffer = req->buffer;
+        ept->rcv_urb->actual_length = 0;
+
+        /* unmask EPx INTRRXE */
+        /*
+         * To avoid the parallely access the buffer,
+         * it is umasked here and umask at complete.
+         */
+        intrrxe = readb(INTRRXE);
+        intrrxe |= (1 << ept->num);
+        writeb(intrrxe, INTRRXE);
+    }
+
+    /* write */
+    if (ept->in) {
+        ept->tx_urb->buffer = req->buffer;
+        ept->tx_urb->actual_length = req->length;
+
+        mt_ep_write(ept);
+    }
+    THREAD_UNLOCK(state); /* exit_critical_section */
+    return 0;
+}
+
+int udc_register_gadget(struct udc_gadget *gadget)
+{
+    if (the_gadget) {
+        DBG_C("only one gadget supported\n");
+        return false;
+    }
+    the_gadget = gadget;
+    return 0;
+}
+
+static void udc_ept_desc_fill(struct udc_endpoint *ept, unsigned char *data)
+{
+    data[0] = 7;
+    data[1] = TYPE_ENDPOINT;
+    data[2] = ept->num | (ept->in ? USB_DIR_IN : USB_DIR_OUT);
+    data[3] = 0x02;     /* bulk -- the only kind we support */
+    data[4] = ept->maxpkt;
+    data[5] = ept->maxpkt >> 8;
+    data[6] = ept->in ? 0x00 : 0x01;
+}
+
+static unsigned udc_ifc_desc_size(struct udc_gadget *g)
+{
+    return 9 + g->ifc_endpoints * 7;
+}
+
+static unsigned char *udc_ifc_desc_fill(struct udc_gadget *g, unsigned char *data)
+{
+    unsigned n;
+
+    data[0] = 0x09;
+    data[1] = TYPE_INTERFACE;
+    data[2] = 0x00;     /* ifc number */
+    data[3] = 0x00;     /* alt number */
+    data[4] = g->ifc_endpoints;
+    data[5] = g->ifc_class;
+    data[6] = g->ifc_subclass;
+    data[7] = g->ifc_protocol;
+    data[8] = udc_string_desc_alloc(g->ifc_string);
+
+    data += 9;
+    for (n = 0; n < g->ifc_endpoints; n++) {
+        udc_ept_desc_fill(g->ept[n], data);
+        data += 7;
+    }
+
+    return data;
+}
+
+static int udc_start_cond(bool (*cond_func)(void *), void *cond_data)
+{
+    struct udc_descriptor *desc;
+    unsigned char *data;
+    unsigned size;
+
+    DBG_C("[USB] %s\n", __func__);
+
+    if (!the_device) {
+        DBG_C("udc cannot start before init\n");
+        return false;
+    }
+    if (!the_gadget) {
+        DBG_C("udc has no gadget registered\n");
+        return false;
+    }
+
+    /* create our device descriptor */
+    desc = udc_descriptor_alloc(TYPE_DEVICE, EP0, 18);
+    data = desc->data;
+    data[2] = 0x00;     /* usb spec minor rev */
+    data[3] = 0x02;     /* usb spec major rev */
+    data[4] = 0x00;     /* class */
+    data[5] = 0x00;     /* subclass */
+    data[6] = 0x00;     /* protocol */
+    data[7] = 0x40;     /* max packet size on ept 0 */
+    memcpy(data + 8, &the_device->vendor_id, sizeof(short));
+    memcpy(data + 10, &the_device->product_id, sizeof(short));
+    memcpy(data + 12, &the_device->version_id, sizeof(short));
+    data[14] = udc_string_desc_alloc(the_device->manufacturer);
+    data[15] = udc_string_desc_alloc(the_device->product);
+    data[16] = udc_string_desc_alloc(the_device->serialno);
+    data[17] = 1;       /* number of configurations */
+    udc_descriptor_register(desc);
+
+    /* create our configuration descriptor */
+    size = 9 + udc_ifc_desc_size(the_gadget);
+
+    if(usbtty_init_done()) {
+        the_gadget_1 = usbtty_interface_1();
+        size += udc_ifc_desc_size(the_gadget_1);
+    }
+
+    desc = udc_descriptor_alloc(TYPE_CONFIGURATION, EP0, size);
+    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 */
+    data[8] = 0x80;     /* max power (250ma) -- todo fix this */
+
+    if(usbtty_init_done()) {
+        data[4] = 0x02;     /* number of interfaces */
+    }
+
+    data = udc_ifc_desc_fill(the_gadget, data + 9);
+
+    if(usbtty_init_done()) {
+        udc_ifc_desc_fill(the_gadget_1, data);
+        data[2] = 0x01;
+        data[12] = 0x03;
+    }
+
+    udc_descriptor_register(desc);
+
+#if DBG_USB_DUMP_DESC
+    DBG_I("%s: dump desc_list\n", __func__);
+    for (desc = 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);
+    }
+#endif
+
+    /* register interrupt handler */
+    dprintf(CRITICAL, "MT_USB0_IRQ_ID: %u\n", MT_USB0_IRQ_ID);
+    mt_usb_irq_init();
+    register_int_handler(MT_USB0_IRQ_ID, service_interrupts, NULL);
+
+    /* go to RUN mode */
+    mt_usb_phy_recover();
+
+    /* clear INTRTX, INTRRX and INTRUSB */
+    writew(0xffff, INTRTX); /* writew */
+    writew(0xffff, INTRRX); /* writew */
+    writeb(0xff, INTRUSB); /* writeb */
+
+    /* unmask usb irq */
+#ifdef USB_GINTR
+    unmask_interrupt(MT_USB0_IRQ_ID);
+#endif
+    writeb((INTRUSB_SUSPEND | INTRUSB_RESUME | INTRUSB_RESET |INTRUSB_DISCON), INTRUSBE);
+
+    /* enable the pullup resistor */
+    mt_usb_connect_internal();
+
+#if 0 /* FPGA_PLATFORM */
+    while ((!cond_func || cond_func(cond_data))) {
+#ifdef USB_GINTR
+        thread_sleep(1);
+#else
+        service_interrupts(NULL);
+#endif
+    }
+#endif
+
+    return 0;
+}
+
+int udc_start(void)
+{
+    return udc_start_cond(NULL,NULL);
+}
+
+int udc_stop(void)
+{
+    thread_sleep(10);
+    mt_usb_disconnect_internal();
+    mt_usb_phy_savecurrent();
+    mempool_free(ep0_urb->buffer);
+    return 0;
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/usb/platform_usb.c b/src/bsp/lk/platform/mt8518/drivers/usb/platform_usb.c
new file mode 100644
index 0000000..ace3b79
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/usb/platform_usb.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2012 MediaTek Inc.
+ *
+ * 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_typedefs.h>
+#include <platform/pmic.h>
+
+/*=======================================================================*/
+/* USB download control                                                  */
+/*=======================================================================*/
+#define SRAMROM_USBDL        (SRAMROM_BASE + 0x0050)
+
+#define USBDL_BIT_EN         (0x00000001) /* 1: download bit enabled */
+#define USBDL_BROM           (0x00000002) /* 0: usbdl by brom; 1: usbdl by bootloader */
+#define USBDL_TIMEOUT_MASK   (0x0000FFFC) /* 14-bit timeout: 0x0000~0x3FFE: second; 0x3FFFF: no timeout */
+#define USBDL_TIMEOUT_MAX    (USBDL_TIMEOUT_MASK >> 2) /* maximum timeout indicates no timeout */
+#define USBDL_MAGIC          (0x444C0000) /* Brom will check this magic number */
+
+
+#define SRAMROM_USBDL_TO_DIS (SRAMROM_BASE + 0x0054)
+#define USBDL_TO_DIS         (0x00000001)
+
+void platform_vusb_on(void)
+{
+#if 0
+#if !CFG_FPGA_PLATFORM
+    U32 ret = 0;
+
+    ret = pmic_config_interface((kal_uint32)(MT6392_DIGLDO_CON2),
+                                (kal_uint32)(1),
+                                (kal_uint32)(MT6392_PMIC_RG_VUSB_EN_MASK),
+                                (kal_uint32)(MT6392_PMIC_RG_VUSB_EN_SHIFT));
+
+    if (ret == 0)
+        dprintf(INFO, "[platform_vusb_on] VUSB33 is on\n");
+    else
+        dprintf(INFO, "[platform_vusb_on] Failed to turn on VUSB33!\n");
+#endif
+#endif
+    return;
+}
+
+bool platform_com_wait_forever_check(void)
+{
+#if 0
+#ifdef USBDL_DETECT_VIA_KEY
+    /* check download key */
+    if (true == mtk_detect_key(COM_WAIT_KEY)) {
+        dprintf(INFO, "[TOOL] COM handshake timeout force disable: Key\n");
+        return true;
+    }
+#endif
+#endif
+
+#ifdef USBDL_DETECT_VIA_AT_COMMAND
+    dprintf(INFO, "platform_com_wait_forever_check\n");
+    /* check SRAMROM_USBDL_TO_DIS */
+    if (USBDL_TO_DIS == (INREG32(SRAMROM_USBDL_TO_DIS) & USBDL_TO_DIS)) {
+    dprintf(INFO, "[TOOL] COM handshake timeout force disable: AT Cmd\n");
+    CLRREG32(SRAMROM_USBDL_TO_DIS, USBDL_TO_DIS);
+    return true;
+    }
+#endif
+
+    return false;
+}
+
+void platform_set_chrg_cur(int ma)
+{
+    //hw_set_cc(ma);
+}
+
+void pl_kick_chr_wdt(void)
+{
+// FIXME
+#if 0
+    //upmu_chr_chrwdt_td(0x0);                // CHRWDT_TD
+    pmic_config_interface(MT6392_CHR_CON13, 0x03, MT6392_PMIC_RG_CHRWDT_TD_MASK, MT6392_PMIC_RG_CHRWDT_TD_SHIFT);
+    //upmu_set_rg_chrwdt_wr(1);            // CHRWDT_FLAG
+    pmic_config_interface(MT6392_CHR_CON15, 0x01, MT6392_PMIC_RG_CHRWDT_WR_MASK, MT6392_PMIC_RG_CHRWDT_WR_SHIFT);
+    //upmu_chr_chrwdt_int_en(1);             // CHRWDT_INT_EN
+    pmic_config_interface(MT6392_CHR_CON15, 0x01, MT6392_PMIC_RG_CHRWDT_INT_EN_MASK, MT6392_PMIC_RG_CHRWDT_INT_EN_SHIFT);
+    //upmu_chr_chrwdt_en(1);                   // CHRWDT_EN
+    pmic_config_interface(MT6392_CHR_CON13, 0x01, MT6392_PMIC_RG_CHRWDT_EN_MASK, MT6392_PMIC_RG_CHRWDT_EN_SHIFT);
+    //upmu_chr_chrwdt_flag_wr(1);            // CHRWDT_FLAG_WR
+    pmic_config_interface(MT6392_CHR_CON15, 0x01, MT6392_PMIC_RG_CHRWDT_FLAG_WR_MASK, MT6392_PMIC_RG_CHRWDT_FLAG_WR_SHIFT);
+
+    //printf("[pl_kick_chr_wdt] done\n");
+#endif
+}
+
+extern void mtk_wdt_disable(void);
+void platform_wdt_all_kick(void)
+{
+    /* kick watchdog to avoid cpu reset */
+    //mtk_wdt_restart();
+
+    /* debugerr, for test*/
+    mtk_wdt_disable();
+
+#if !CFG_FPGA_PLATFORM
+    /* kick PMIC watchdog to keep charging */
+    pl_kick_chr_wdt();
+#endif
+}
+
+#if CFG_USB_AUTO_DETECT
+void platform_usb_auto_detect_flow()
+{
+
+    dprintf(INFO, "USB DL Flag is %d when enter preloader  \n",g_usbdl_flag);
+
+    /*usb download flag haven't set */
+    if(g_usbdl_flag == 0 && g_boot_reason != BR_RTC){
+        /*set up usbdl flag*/
+        platform_safe_mode(1,CFG_USB_AUTO_DETECT_TIMEOUT_MS);
+        dprintf(INFO, "Preloader going reset and trigger BROM usb auto detectiton!!\n");
+
+        /*WDT by pass powerkey reboot*/
+        mtk_arch_reset(1);
+
+    }else{
+    /*usb download flag have been set*/
+    }
+}
+#endif
+
+#if 0
+int pmic_detect_powerkey(void)
+{
+    U32 ret = 0;
+    U32 val = 0;
+
+    ret = pmic_read_interface((kal_uint32)(MT6392_CHRSTATUS),
+                              (&val),
+                              (kal_uint32)(MT6392_PMIC_PWRKEY_DEB_MASK),
+                              (kal_uint32)(MT6392_PMIC_PWRKEY_DEB_SHIFT));
+
+    if (val == 1) {
+        printf("pl pmic powerkey Release\n");
+        return 0;
+    } else {
+        printf("pl pmic powerkey Press\n");
+        return 1;
+    }
+}
+#endif
+
+void platform_wdt_kick(void)
+{
+    /* kick hardware watchdog */
+    //mtk_wdt_restart();
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/usb/usb_toolhandler.c b/src/bsp/lk/platform/mt8518/drivers/usb/usb_toolhandler.c
new file mode 100644
index 0000000..d170fcf
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/usb/usb_toolhandler.c
@@ -0,0 +1,255 @@
+/*

+ * 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 <assert.h>

+#include <errno.h>

+#include <libfdt.h>

+

+#include <platform/usbbldr.h>

+#include <platform/meta.h>

+#include <platform/boot_mode.h>

+//#include <platform/pmic.h>

+#define TMPBUF_SIZE 13

+

+#define  TRUE 1

+#define  FALSE 0

+#define  true 1

+#define  false 0

+#define  NO_ERROR 0

+

+#if MT8518

+#if WITH_BOOTMODE_HANDSHAKE

+//add for  handshake

+

+/*============================================================================*/

+/* CONSTAND DEFINITIONS                                                       */

+/*============================================================================*/

+#define MOD "[BLDR]"

+#define CMD_HNDL_ATTR_COM_FORBIDDEN               (1<<0)

+#define min(x,y) ((x) < (y) ? (x):(y))

+BOOTMODE g_boot_mode = NORMAL_BOOT;

+u32 g_meta_com_id=0;

+

+/*============================================================================*/

+/* MACROS DEFINITIONS                                                         */

+/*============================================================================*/

+#define CMD_MATCH(cmd1,cmd2)  \

+    (!strncmp((const char*)(cmd1->data), (cmd2), min(strlen(cmd2), cmd1->len)))

+

+static int extract_fdt(void *fdt, int size)

+{

+    int ret = 0;

+    /* DTB maximum size is 2MB */

+    ret = fdt_open_into(fdt, fdt, size);

+    if (ret) {

+        dprintf(CRITICAL, "open fdt failed\n");

+        return ret;

+    }

+    ret = fdt_check_header(fdt);

+    if (ret) {

+        dprintf(CRITICAL, "check fdt failed\n");

+        return ret;

+    }

+    return ret;

+}

+

+static bool wait_for_discon(struct comport_ops *comm, u32 tmo_ms)

+{

+    bool ret;

+    u8 discon[HSHK_DISCON_SZ];

+    memset(discon, 0x0, HSHK_DISCON_SZ);

+    dprintf(ALWAYS,"[BLDR] DISCON...");

+    if (ret = comm->recv(discon, HSHK_DISCON_SZ, tmo_ms)) {

+    dprintf(ALWAYS,"timeout\n");

+    return ret;

+    }

+

+    if (0 == memcmp(discon, HSHK_DISCON, HSHK_DISCON_SZ))

+    dprintf(ALWAYS,"OK\n");

+    else

+    dprintf(ALWAYS,"protocol mispatch\n");

+    return ret;

+}

+

+static int cmdlineoverlay_usbhandler(void* boot_dtb, char* cmdline, int len)

+{

+    dprintf(CRITICAL, "enter cmdlineoverlay_usbhandler\n");

+    int chosen_node_offset = 0;

+    int ret = -1;

+    ret = extract_fdt(boot_dtb, MAX_DTB_SIZE);

+    if (ret != 0) {

+        dprintf(CRITICAL, "extract_fdt error.\n");

+        return -1;

+    }

+

+    chosen_node_offset = fdt_path_offset(boot_dtb, "/chosen");

+    char *cmdline_read;

+    int lenth;

+    cmdline_read = fdt_getprop(boot_dtb, chosen_node_offset, "bootargs", &lenth);

+    //dprintf(CRITICAL, "dtsi cmdline: %s ,lenth:%d\n", cmdline_read, strlen(cmdline_read));

+    char *pos1;

+

+    pos1 = strstr(cmdline_read,"bootmode=");

+        if( pos1 == NULL) {

+            dprintf(CRITICAL, "no bootmode= in cmdline, error!\n");

+            return -1;

+        }

+    strncpy(pos1,cmdline,10);

+    //dprintf("cmdline new: %s , length: %d\n", cmdline_read, strlen(cmdline_read));

+    ret = fdt_setprop(boot_dtb, chosen_node_offset, "bootargs", cmdline_read, strlen(cmdline_read) + 1);

+

+    if (ret != 0) {

+        dprintf(CRITICAL, "fdt_setprop error.\n");

+        return -1;

+    }

+    ret = fdt_pack(boot_dtb);

+    if (ret != 0) {

+        dprintf(CRITICAL, "fdt_pack error.\n");

+        return -1;

+    }

+    dprintf(CRITICAL, "leave  cmdlineoverlay_usbhandler\n");

+    return 0;

+}

+

+

+extern bool usb_handshake(struct bldr_command_handler *handler );

+bool bldr_cmd_handler(struct bldr_command_handler *handler,struct bldr_command *cmd, struct bldr_comport *comport)

+{

+    dprintf(CRITICAL, "enter bldr_cmd_handler\n");

+    char tmpbuf[TMPBUF_SIZE]={};

+    struct comport_ops *comm = comport->ops;

+    u32 attr = handler->attr;

+

+#if CFG_DT_MD_DOWNLOAD

+        if (CMD_MATCH(cmd, SWITCH_MD_REQ)) {

+            /* SWITCHMD */

+            if (attr & CMD_HNDL_ATTR_COM_FORBIDDEN)

+                goto forbidden;

+            comm->send((u8*)SWITCH_MD_ACK, strlen(SWITCH_MD_ACK));

+            platform_modem_download();

+            return TRUE;

+        }

+#endif

+        if (CMD_MATCH(cmd, ATCMD_PREFIX)) {

+            /* "AT+XXX" */

+            if (CMD_MATCH(cmd, ATCMD_NBOOT_REQ)) {

+                /* return "AT+OK" to tool */

+                comm->send((u8*)ATCMD_OK, strlen(ATCMD_OK));

+                g_boot_mode = NORMAL_BOOT;

+                //g_boot_reason = BR_TOOL_BY_PASS_PWK;

+            } else {

+                /* return "AT+UNKONWN" to ack tool */

+                comm->send((u8*)ATCMD_UNKNOWN, strlen(ATCMD_UNKNOWN));

+                return FALSE;

+            }

+        } else if (CMD_MATCH(cmd, META_STR_REQ)) {

+            para_t param;

+            dprintf(CRITICAL, "CMD_MATCH(cmd, META_STR_REQ\n");

+#if CFG_BOOT_ARGUMENT

+            bootarg.md_type[0] = 0;

+            bootarg.md_type[1] = 0;

+#endif

+            /* "METAMETA" */

+            if (attr & CMD_HNDL_ATTR_COM_FORBIDDEN)

+                goto forbidden;

+        /* for backward compatibility */

+        comm->recv((u8*)&param.v0001, sizeof(param.v0001), 2000);

+#if CFG_WORLD_PHONE_SUPPORT

+            comm->send((u8*)META_ARG_VER_STR, strlen(META_ARG_VER_STR));

+            if (0 == comm->recv((u8*)&param.v0001, sizeof(param.v0001), 5000)) {

+                g_meta_com_id = param.v0001.usb_type;

+            //print("md_type[0] = %d \n", param.v0001.md0_type);

+            //print("md_type[1] = %d \n", param.v0001.md1_type);

+#if CFG_BOOT_ARGUMENT

+            bootarg.md_type[0] = param.v0001.md0_type;

+            bootarg.md_type[1] = param.v0001.md1_type;

+#endif

+            }

+#endif

+            comm->send((u8*)META_STR_ACK, strlen(META_STR_ACK));

+#if CFG_WORLD_PHONE_SUPPORT

+            wait_for_discon(comm, 1000);

+#endif

+            g_boot_mode = META_BOOT;

+            dprintf(CRITICAL, "g_boot_mode= %d \n", g_boot_mode);

+

+        if (g_boot_mode == META_BOOT ) {

+            snprintf(tmpbuf, TMPBUF_SIZE, "bootmode=%d", g_boot_mode);

+             cmdlineoverlay_usbhandler(handler->dtb, tmpbuf, strlen(tmpbuf));

+            }

+        dprintf(CRITICAL, "[meta] bootmode is 1\n");

+        } else if (CMD_MATCH(cmd, FACTORY_STR_REQ)) {

+            para_t param;

+            /* "FACTFACT" */

+            if (attr & CMD_HNDL_ATTR_COM_FORBIDDEN)

+                goto forbidden;

+

+            if (0 == comm->recv((u8*)&param.v0001, sizeof(param.v0001), 5)) {

+                g_meta_com_id = param.v0001.usb_type;

+            }

+            comm->send((u8*)FACTORY_STR_ACK, strlen(FACTORY_STR_ACK));

+            g_boot_mode = FACTORY_BOOT;

+            if (g_boot_mode == FACTORY_BOOT ) {

+                        snprintf(tmpbuf, TMPBUF_SIZE, "bootmode=%d", g_boot_mode);

+                        cmdlineoverlay_usbhandler(handler->dtb, tmpbuf, strlen(tmpbuf));

+                        }

+            dprintf(CRITICAL, "[factory] bootmode is 4\n");

+        }else {

+            dprintf(ALWAYS,"%s unknown received: \'%s\'\n", MOD, cmd->data);

+            return FALSE;

+        }

+        dprintf(ALWAYS,"%s '%s' received!\n", MOD, cmd->data);

+        dprintf(ALWAYS,"leave return ture !\n");

+        return TRUE;

+    forbidden:

+        comm->send((u8*)META_FORBIDDEN_ACK, strlen(META_FORBIDDEN_ACK));

+        dprintf(ALWAYS,"%s '%s' is forbidden!\n", MOD, cmd->data);

+        return FALSE;

+        return TRUE;

+}

+

+//bool tool_usb_handshake ( void* bootimg_dtb_load, ... )

+bool tool_usb_handshake(void *bootimg_dtb_load)

+{

+    // get  bootimg_dtb_load from variable parameter

+/*

+    void *bootimg_dtb_load;

+    __builtin_va_list vaptr;

+    __builtin_va_start(vaptr,arg_cnt);

+    for( int i=0; i<arg_cnt; i++)

+    {

+        bootimg_dtb_load = __builtin_va_arg(vaptr,void*);

+    }

+*/

+    bool ret = false;

+    dprintf(ALWAYS, " fitboot handshake entr \n");

+    struct bldr_command_handler handler;

+    handler.priv = NULL;

+    handler.attr = 0;

+    handler.dtb = (void *)bootimg_dtb_load;

+    handler.cb = bldr_cmd_handler;

+    ret = usb_handshake(&handler);

+    dprintf(ALWAYS, " fitboot handshake leave \n");

+    return ret;

+}

+#endif

+#endif
\ No newline at end of file
diff --git a/src/bsp/lk/platform/mt8518/drivers/usb/usbtty.c b/src/bsp/lk/platform/mt8518/drivers/usb/usbtty.c
new file mode 100644
index 0000000..b141f2c
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/usb/usbtty.c
@@ -0,0 +1,298 @@
+#include <debug.h>
+#include <dev/udc.h>
+#include <kernel/event.h>
+#include <kernel/thread.h>
+#include <platform/udc-common.h>
+#include <platform.h>
+#include <platform/mtk_timer.h>
+
+static struct udc_endpoint *in, *out, *out_1;
+static struct udc_request *req;
+
+static event_t txn_done;
+
+static int usbtty_txn;
+
+int tool_exists = 0;
+int usb_configured = 0;
+int usbdl_tty = 0;
+
+#define MAX_USBFS_BULK_SIZE (16 * 1024)
+
+int tool_is_present (void)
+{
+    return tool_exists;
+}
+
+void tool_state_update (int state)
+{
+    tool_exists = state;
+
+    return;
+}
+
+static void req_complete(struct udc_request *req, unsigned actual, int status)
+{
+    usbtty_txn = status;
+    req->length = actual;
+    event_signal(&txn_done, 0);
+}
+
+/**
+ * @brief  Wait for event to be signaled
+ *
+ * If the event has already been signaled, this function
+ * returns immediately.  Otherwise, the current thread
+ * goes to sleep until the event object is signaled,
+ * the timeout is reached, or the event object is destroyed
+ * by another thread.
+ *
+ * @param e        Event object
+ * @param timeout  Timeout value, in ms
+ *
+ * @return  0 on success, ERR_TIMED_OUT on timeout,
+ *         other values on other errors.
+ */
+int event_wait_timeout_usb(event_t *e, lk_time_t timeout)
+{
+#if 0
+        status_t ret = NO_ERROR;
+
+        DEBUG_ASSERT(e->magic == EVENT_MAGIC);
+
+        THREAD_LOCK(state);
+
+        if (e->signalled) {
+                /* signalled, we're going to fall through */
+                if (e->flags & EVENT_FLAG_AUTOUNSIGNAL) {
+                        /* autounsignal flag lets one thread fall through before unsignalling */
+                        e->signalled = false;
+                }
+        } else {
+                /* unsignalled, block here */
+                 printf("before  wait_queue_block\n");
+                 ret = wait_queue_block(&e->wait, timeout);
+                 printf("after  wait_queue_block\n");
+        }
+
+        THREAD_UNLOCK(state);
+#endif
+    lk_bigtime_t timeout_time = 0, tmp = 0;
+    timeout_time = current_time() + timeout;
+
+    do {
+        if (e->signalled) {
+                          /* signalled, we're going to fall through */
+                         if (e->flags & EVENT_FLAG_AUTOUNSIGNAL) {
+                            /* autounsignal flag lets one thread fall through before unsignalling */
+                             e->signalled = false;
+                           }
+                           break;
+                         }
+      if (timeout) {
+                    tmp = current_time();
+                    /* enable timeout mechanism */
+                    if (tmp > timeout_time)
+                                break;
+                     mdelay(1);
+                   }
+       } while (1);
+       return 0;
+}
+
+int usbtty_read(void *_buf, unsigned len, lk_time_t timeout)
+{
+    dprintf(ALWAYS, "enter usb_read\n");
+    int r;
+    unsigned xfer;
+    unsigned char *buf = _buf;
+    int count = 0;
+
+    while (len > 0) {
+        xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
+        req->buffer = buf;
+        req->length = xfer;
+        req->complete = req_complete;
+        r = udc_request_queue(out, req);
+        if (r < 0) {
+            dprintf(ALWAYS, "usb_read() queue failed\n");
+            count = -1;
+            goto oops;
+        }
+
+        dprintf(ALWAYS, "before  event_wait_timeout\n");
+        dprintf(ALWAYS, "before  event_wait_timeout:timeout:%d\n",timeout);
+        r = event_wait_timeout_usb(&txn_done, timeout);
+        dprintf(ALWAYS, "after  event_wait_timeout\n");
+
+        if (r < 0) {
+            count = 0;
+            goto oops;
+        }
+
+        if (usbtty_txn < 0) {
+            dprintf(ALWAYS, "usb_read() transaction failed\n");
+            count = -1;
+            goto oops;
+        }
+
+        count += req->length;
+        buf += req->length;
+        len -= req->length;
+
+        /* short transfer? */
+        if (req->length != xfer) break;
+    }
+
+oops:
+    return count;
+}
+
+int usbtty_write(void *buf, unsigned len)
+{
+    int r;
+
+    req->buffer = buf;
+    req->length = len;
+    req->complete = req_complete;
+    r = udc_request_queue(in, req);
+    if (r < 0) {
+        dprintf(ALWAYS, "usb_write() queue failed\n");
+        goto oops;
+    }
+    event_wait(&txn_done);
+    if (usbtty_txn < 0) {
+        dprintf(ALWAYS, "usb_write() transaction failed\n");
+        goto oops;
+    }
+    return req->length;
+
+oops:
+    return -1;
+}
+
+static void usbtty_notify(struct udc_gadget *gadget, unsigned event)
+{
+    if (event == UDC_EVENT_ONLINE) {
+        usb_configured = 1;
+    } else if (event == UDC_EVENT_OFFLINE) {
+        usb_configured = 0;
+    }
+}
+
+static struct udc_endpoint *usbtty_endpoints[2];
+static struct udc_endpoint *usbtty_endpoints_1[1];
+
+static struct udc_gadget usbtty_gadget = {
+    .notify        = usbtty_notify,
+    .ifc_class     = 0x0a,
+    .ifc_subclass  = 0x00,
+    .ifc_protocol  = 0x00,
+    .ifc_endpoints = 2,
+    .ifc_string    = "CDC ACM Data Interface",
+    .ept           = usbtty_endpoints,
+};
+
+static struct udc_gadget usbtty_gadget_1 = {
+    .notify        = usbtty_notify,
+    .ifc_class     = 0x02,
+    .ifc_subclass  = 0x02,
+    .ifc_protocol  = 0x01,
+    .ifc_endpoints = 1,
+    .ifc_string    = "CDC ACM Communication Interface",
+    .ept           = usbtty_endpoints_1,
+};
+
+static udc_device_t usbtty_device = {
+    .vendor_id     = 0x0E8D,
+    .product_id    = 0x2000,
+    .version_id    = 0x0100,
+};
+
+int usbdl_init(void)
+{
+
+    dprintf(ALWAYS, "usbdl_init()\n");
+
+    tool_exists = 0;
+    usb_configured = 0;
+
+    udc_init(&usbtty_device);
+
+    event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);
+
+    in = udc_endpoint_alloc(UDC_BULK_IN, 512);
+    if (!in) {
+        dprintf(ALWAYS, "usbdl_init() fail 1\n");
+        goto fail_alloc_in;
+    }
+
+    out = udc_endpoint_alloc(UDC_BULK_OUT, 512);
+    if (!out) {
+        dprintf(ALWAYS, "usbdl_init() fail 2\n");
+        goto fail_alloc_out;
+    }
+
+    out_1 = udc_endpoint_alloc(UDC_BULK_OUT, 64);
+    if (!out_1) {
+        dprintf(ALWAYS, "usbdl_init() fail 3\n");
+        goto fail_alloc_out1;
+    }
+
+    usbtty_endpoints[0] = in;
+    usbtty_endpoints[1] = out;
+
+    usbtty_endpoints_1[0] = out_1;
+
+    req = udc_request_alloc();
+    if (!req) {
+        dprintf(ALWAYS, "usbdl_init() fail 4\n");
+        goto fail_alloc_req;
+    }
+
+    if (udc_register_gadget(&usbtty_gadget)) {
+        dprintf(ALWAYS, "usbdl_init() fail 5\n");
+        goto fail_udc_register;
+    }
+
+    return 0;
+
+fail_udc_register:
+    udc_request_free(req);
+fail_alloc_req:
+    udc_endpoint_free(out_1);
+fail_alloc_out1:
+    udc_endpoint_free(out);
+fail_alloc_out:
+    udc_endpoint_free(in);
+fail_alloc_in:
+    return -1;
+}
+
+void config_usbtty (void)
+{
+    usbdl_tty = 1;
+    udc_start();
+}
+
+int usbdl_configured (void)
+{
+    return usb_configured;
+}
+
+void usbtty_stop(void)
+{
+    udc_stop();
+    usbdl_tty = 0;
+}
+
+int usbtty_init_done(void)
+{
+    return usbdl_tty;
+}
+
+struct udc_gadget *usbtty_interface_1(void)
+{
+    return &usbtty_gadget_1;
+}
+
diff --git a/src/bsp/lk/platform/mt8518/drivers/wdt/mtk_wdt.c b/src/bsp/lk/platform/mt8518/drivers/wdt/mtk_wdt.c
new file mode 100644
index 0000000..b912559
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/drivers/wdt/mtk_wdt.c
@@ -0,0 +1,411 @@
+#include <debug.h>
+#include <platform/mtk_wdt.h>
+#include <reg.h>
+
+#if ENABLE_WDT_MODULE
+
+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);
+#else
+	return false;
+#endif
+}
+
+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 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)
+{
+    dprintf(INFO,"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);
+}
+
+void mtk_wdt_init(void)
+{
+    /* This function will store the reset reason: Time out/ SW trigger */
+    dprintf(ALWAYS, "RGU STA: %x\n", 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)
+{
+    dprintf(INFO,"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);
+        dprintf(INFO,"rgu pl md reset\n");
+    }
+}
+
+int rgu_dram_reserved(int enable)
+{
+    volatile unsigned int tmp = 0, ret = 0;
+    if(1 == 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 if(0 == enable)
+    {
+        /* 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
+    {
+        dprintf(CRITICAL,"Wrong input %d, should be 1(enable) or 0(disable) in %s\n", enable, __func__);
+        ret = -1;
+    }
+	dprintf(CRITICAL,"RGU %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_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)
+{
+    dprintf(INFO,"UB WDT Dummy init called\n");
+}
+
+static bool mtk_is_rgu_trigger_reset()
+{
+    dprintf(INFO,"UB Dummy mtk_is_rgu_trigger_reset called\n");
+    return FALSE;
+}
+
+void mtk_arch_reset(char mode)
+{
+    dprintf(INFO,"UB WDT Dummy arch reset called\n");
+}
+
+int mtk_wdt_boot_check(void)
+{
+    dprintf(INFO,"UB WDT Dummy mtk_wdt_boot_check called\n");
+    return WDT_NOT_WDT_REBOOT;
+}
+
+void mtk_wdt_disable(void)
+{
+    dprintf(INFO,"UB WDT Dummy mtk_wdt_disable called\n");
+}
+
+static void mtk_wdt_restart(void)
+{
+    dprintf(INFO,"UB WDT Dummy mtk_wdt_restart called\n");
+}
+static void mtk_wdt_sw_reset(void)
+{
+    dprintf(INFO,"UB WDT Dummy mtk_wdt_sw_reset called\n");
+}
+
+static void mtk_wdt_hw_reset(void)
+{
+    dprintf(INFO,"UB WDT Dummy mtk_wdt_hw_reset called\n");
+}
+
+static void rgu_swsys_reset(WD_SYS_RST_TYPE reset_type)
+{
+    dprintf(INFO,"UB WDT Dummy rgu_swsys_reset called\n");
+}
+#endif
diff --git a/src/bsp/lk/platform/mt8518/include/platform/boot_mode.h b/src/bsp/lk/platform/mt8518/include/platform/boot_mode.h
new file mode 100644
index 0000000..31a89e4
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/boot_mode.h
@@ -0,0 +1,49 @@
+/*
+ * 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 _MT_BOOT_MODE_H_
+#define _MT_BOOT_MODE_H_
+
+#include <stdint.h>
+
+/*
+ *uint32_t get_boot_mode() - determine which boot mode to boot
+ *
+ * return:
+ *     code of boot_mode which represent normal, recovery or fastboot mode.
+ *
+ */
+uint32_t get_boot_mode(void);
+
+/* boot type definitions */
+typedef enum {
+    NORMAL_BOOT = 0,
+    META_BOOT = 1,
+    RECOVERY_BOOT = 2,
+    FACTORY_BOOT = 4,
+    FASTBOOT_BOOT,
+    UNKNOWN_BOOT
+} BOOTMODE;
+
+extern BOOTMODE g_boot_mode;
+#endif
diff --git a/src/bsp/lk/platform/mt8518/include/platform/generic_ioctl.h b/src/bsp/lk/platform/mt8518/include/platform/generic_ioctl.h
new file mode 100644
index 0000000..84c2ec8
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/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/mt8518/include/platform/gic.h b/src/bsp/lk/platform/mt8518/include/platform/gic.h
new file mode 100644
index 0000000..b1072af
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/gic.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
+#include <platform/mt8518.h>
+
+#define GICBASE(n)  (MEMORY_BASE_VIRT+0x0c000000)
+#define GICD_OFFSET (0x1000)
+#define GICC_OFFSET (0x2000)
+
diff --git a/src/bsp/lk/platform/mt8518/include/platform/led.h b/src/bsp/lk/platform/mt8518/include/platform/led.h
new file mode 100644
index 0000000..b85fada
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/led.h
@@ -0,0 +1,6 @@
+#ifndef _LED_H_

+#define _LED_H_

+

+extern int led_init(void);

+

+#endif

diff --git a/src/bsp/lk/platform/mt8518/include/platform/md1122.h b/src/bsp/lk/platform/mt8518/include/platform/md1122.h
new file mode 100644
index 0000000..e1ec1e0
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/md1122.h
@@ -0,0 +1,7 @@
+#ifndef __MUSB_PHY_H__
+#define __MUSB_PHY_H__
+
+int md1122_u2phy_init(void);
+unsigned int get_phy_verison(void);
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/include/platform/meta.h b/src/bsp/lk/platform/mt8518/include/platform/meta.h
new file mode 100644
index 0000000..861d077
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/meta.h
@@ -0,0 +1,97 @@
+/* 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 META_H
+#define META_H
+
+#define HSHK_TOKEN_SZ           (8)             /* handshake token size */
+#define HSHK_COM_READY          "READY"         /* com ready for communication */
+#define HSHK_DISCON_SZ          (10)
+#define HSHK_DISCON             "DISCONNECT"    /* com disconnect for communication */
+
+#define    META_STR_REQ            "METAMETA"      /* META request */
+
+#if CFG_WORLD_PHONE_SUPPORT
+#define META_STR_ACK            "ATEMATEX"      /* META ack Response */
+#else
+#define META_STR_ACK            "ATEMATEM"      /* META ack Response */
+#endif
+
+#define META_LOCK               "LOCK"          /* META lock */
+#define META_FORBIDDEN_ACK      "METAFORB"
+#define META_ARG_VER_STR        "ATEM0001"
+
+#define META_ADV_REQ            "ADVEMETA"
+#define META_ADV_ACK            "ATEMEVDX"
+
+#define FACTORY_STR_REQ         "FACTFACT"
+#define FACTORY_STR_ACK         "TCAFTCAF"
+
+#define ATE_STR_REQ             "FACTORYM"      /* ATE request */
+#define ATE_STR_ACK             "MYROTCAF"      /* ATE ack response */
+
+#define SWITCH_MD_REQ           "SWITCHMD"      /* switch MD request */
+#define SWITCH_MD_ACK           "DMHCTIWS"      /* switch MD ack response */
+
+#define ATCMD_PREFIX            "AT+"
+#define ATCMD_NBOOT_REQ         ATCMD_PREFIX"NBOOT"    /* AT command to trigger normal boot */
+#define ATCMD_OK                ATCMD_PREFIX"OK"
+#define ATCMD_UNKNOWN           ATCMD_PREFIX"UNKONWN"
+
+#define FB_STR_REQ              "FASTBOOT"
+#define FB_STR_ACK              "TOOBTSAF"
+
+typedef struct {
+    unsigned int len;           /* the length of parameter */
+    unsigned int ver;           /* the version of parameter */
+} para_header_t;
+
+typedef struct {
+    para_header_t header;       /* the header of parameter */
+    unsigned char usb_type;     /* 0: single interface device, 1: composite device */
+    unsigned char usb_num;      /* usb com port number */
+    unsigned char md0_type;     /* md image type for md1 */
+    unsigned char md1_type;     /* md image type for md1 */
+} para_v1_t;
+
+typedef union {
+    para_header_t header;
+    para_v1_t     v0001;
+} para_t;
+
+#endif /* META_H */
+
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mmc_core.h b/src/bsp/lk/platform/mt8518/include/platform/mmc_core.h
new file mode 100644
index 0000000..a614108
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mmc_core.h
@@ -0,0 +1,654 @@
+/*
+ * 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 */
+    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/mt8518/include/platform/mmc_ioctl.h b/src/bsp/lk/platform/mt8518/include/platform/mmc_ioctl.h
new file mode 100644
index 0000000..6afd29b
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/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/mt8518/include/platform/mmc_rpmb.h b/src/bsp/lk/platform/mt8518/include/platform/mmc_rpmb.h
new file mode 100644
index 0000000..5ebaa54
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/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/mt8518/include/platform/msdc.h b/src/bsp/lk/platform/mt8518/include/platform/msdc.h
new file mode 100644
index 0000000..ed2d9fd
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/msdc.h
@@ -0,0 +1,1053 @@
+/*
+ * 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 MT8518 */
+#define MSDC0_GPIO_BASE			(IO_PHYS+0x0005000)
+#define MSDC0_IES_ADDR		(MSDC0_GPIO_BASE + 0x920)
+#define MSDC0_SMT_ADDR		(MSDC0_GPIO_BASE + 0xA20)
+#define MSDC0_SMT_MASK		(0x7FF)
+
+#define MSDC0_PUPD0_ADDR		(MSDC0_GPIO_BASE + 0xE00)
+#define MSDC0_PUPD1_ADDR		(MSDC0_GPIO_BASE + 0xE10)
+#define MSDC0_PUPD2_ADDR		(MSDC0_GPIO_BASE + 0xE20)
+#define MSDC0_PUPD6_ADDR		(MSDC0_GPIO_BASE + 0xE60)
+/*MSDC0_PUPD_CTRL0 for MSDC0_DAT0~MSDC0_DAT3*/
+#define MSDC0_DAT0_3_PUPD_MASK	(0xFFFF)
+/*MSDC0_PUPD_CTRL1 for MSDC0_DAT4~MSDC0_DAT7*/
+#define MSDC0_DAT4_7_PUPD_MASK	(0xFFFF)
+/*MSDC0_PUPD_CTRL2 for MSDC0_CMD/CLK/RST*/
+#define MSDC0_CMD_PUPD_MASK		(0xF)
+#define MSDC0_CLK_PUPD_MASK		(0xF << 4)
+#define MSDC0_RST_PUPD_MASK		(0xF << 8)
+/*MSDC0_PUPD_CTRL6 for MSDC0_DSL*/
+#define MSDC0_DSL_PUPD_MASK		(0xF << 12)
+
+#define MSDC0_DRV6_ADDR		(MSDC0_GPIO_BASE + 0xD60)
+#define MSDC0_DRV7_ADDR		(MSDC0_GPIO_BASE + 0xD70)
+
+#define MSDC0_CMD_DRV_MASK	(0xF << 8)
+#define MSDC0_CLK_DRV_MASK	(0xF << 12)
+#define MSDC0_DAT_DRV_MASK	(0xF)
+#define MSDC0_DSL_DRV_MASK	(0xF << 8)
+
+#define MSDC0_GPIO_MODE1_ADDR	(MSDC0_GPIO_BASE + 0x300)
+#define MSDC0_DAT6_MODE_MASK	(0x7 << 12)
+#define MSDC0_DAT7_MODE_MASK	(0x7 << 9)
+#define MSDC0_DS_MODE_MASK	(0x7 << 6)
+
+/*msdc0 clk,cmd, rst, data4, data5*/
+#define MSDC0_GPIO_MODE2_ADDR	(MSDC0_GPIO_BASE + 0x310)
+#define MSDC0_CLK_CMD_DAT4_5_MASK	(0x7FFF)
+/*msdc data0, data1, data2, data3*/
+#define MSDC0_GPIO_MODE3_ADDR	(MSDC0_GPIO_BASE + 0x320)
+#define MSDC0_DAT0_3_MODE_MASK	(0xFFF)
+
+#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
+
+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)
+
+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/mt8518/include/platform/msdc_cfg.h b/src/bsp/lk/platform/mt8518/include/platform/msdc_cfg.h
new file mode 100644
index 0000000..0afd634
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/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/mt8518/include/platform/mt8518.h b/src/bsp/lk/platform/mt8518/include/platform/mt8518.h
new file mode 100644
index 0000000..1cc520a
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mt8518.h
@@ -0,0 +1,73 @@
+/*
+ * 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 <debug.h>
+
+/* L2C */
+#define MEMORY_BASE_PHYS     (0x200000)
+#define MEMORY_BASE_VIRT     (KERNEL_BASE)
+#define MEMORY_APERTURE_SIZE (0x40000UL)
+
+/* Internal SRAM */
+#define SRAM_BASE_PHYS (0x100000)
+#define SRAM_BASE_SIZE (0x10000L)
+#define SRAM_BASE_VIRT (MEMORY_BASE_VIRT + 0x100000UL)
+
+
+/* IC VERSION */
+#define VERSION_BASE_PHYS (0x08000000)
+#define VERSION_BASE_SIZE (0x0200000L)
+#define VERSION_BASE_VIRT (MEMORY_BASE_VIRT + 0x08000000UL)
+
+/* GIC */
+#define GIC_BASE_PHYS (0x0c000000)
+#define GIC_BASE_SIZE (0x0200000L)
+#define GIC_BASE_VIRT (MEMORY_BASE_VIRT + 0x0c000000UL)
+/* map all of 0-1GB into kernel space in one shot */
+#define PERIPHERAL_BASE_PHYS (0x10000000)
+#define PERIPHERAL_BASE_SIZE (0x0d000000UL)
+#if WITH_KERNEL_VM
+#define PERIPHERAL_BASE_VIRT (SRAM_BASE_VIRT + 0x300000UL)
+#else
+#define PERIPHERAL_BASE_VIRT PERIPHERAL_BASE_PHYS
+#endif
+
+#define DRAM_BASE_PHY  (0x40000000U)
+#if WITH_KERNEL_VM
+#define DRAM_BASE_VIRT (PERIPHERAL_BASE_VIRT + PERIPHERAL_BASE_SIZE)
+#else
+#define DRAM_BASE_VIRT DRAM_BASE_PHY
+#endif
+
+/* individual peripherals in this mapping */
+#define CPUPRIV_BASE_VIRT   (PERIPHERAL_BASE_VIRT + 0x08000000)
+#define CPUPRIV_BASE_PHYS   (PERIPHERAL_BASE_PHYS + 0x08000000)
+#define CPUPRIV_SIZE        (0x00020000)
+
+/* interrupts */
+#define ARM_GENERIC_TIMER_VIRTUAL_INT 27
+#define ARM_GENERIC_TIMER_PHYSICAL_INT 30
+
+#define MAX_INT 236
+
+#define SRAMROM_BASE        (PERIPHERAL_BASE_VIRT + 0x202000)
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mt_gic_v3.h b/src/bsp/lk/platform/mt8518/include/platform/mt_gic_v3.h
new file mode 100644
index 0000000..23461b4
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mt_gic_v3.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2013, Google Inc. All rights reserved.
+ *
+ * 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 __DEV_INTERRUPT_ARM_GIC_H
+#define __DEV_INTERRUPT_ARM_GIC_H
+
+#include <sys/types.h>
+
+#define ICC_IAR1_EL1	sys_reg(3, 0, 12, 12, 0)
+#define ICC_EOIR1_EL1	sys_reg(3, 0, 12, 12, 1)
+#define ICC_IAR0_EL1	sys_reg(3, 0, 12,  8, 0)
+#define ICC_EOIR0_EL1	sys_reg(3, 0, 12,  8, 1)
+#define ICC_HPPIR1_EL1	sys_reg(3, 0, 12, 12, 2)
+
+#define GICD_CTLR_ENABLE_GRP0		(1 << 0)
+#define GICD_CTLR_ENGRP1NS      	(1 << 1)
+#define GICD_CTLR_ENGRP1S   		(1 << 2)
+#define GICD_CTLR_ARE       		(1 << 4)
+#define GICD_CTLR_ARE_NS                (1 << 5)
+#define GICD_CTLR_DS			(1 << 6)
+#define GICD_CTLR_E1NWF			(1 << 7)
+#define GICD_CTLR_RWP       		(1 << 31)
+
+#define GICR_WAKER_ProcessorSleep	(1 << 1)
+#define GICR_WAKER_ChildrenAsleep	(1 << 2)
+
+/* GICD_TYPER bit definitions */
+#define IT_LINES_NO_MASK    (0x1f)
+
+#define ENABLE_GRP0		(1 << 0)
+#define ENABLE_GRP1		(1 << 1)
+
+/* Mask for the priority field common to all GIC interfaces */
+#define GIC_PRI_MASK    0xff
+
+/* GICC_CTLR bit definitions */
+#define EOI_MODE_NS		(1 << 10)
+#define EOI_MODE_S		(1 << 9)
+#define IRQ_BYP_DIS_GRP1	(1 << 8)
+#define FIQ_BYP_DIS_GRP1	(1 << 7)
+#define IRQ_BYP_DIS_GRP0	(1 << 6)
+#define FIQ_BYP_DIS_GRP0	(1 << 5)
+#define CBPR			(1 << 4)
+#define FIQ_EN			(1 << 3)
+#define ACK_CTL			(1 << 2)
+
+/* GICv3 ICC_SRE register bit definitions*/
+#define ICC_SRE_EN		(1 << 3)
+#define ICC_SRE_SRE		(1 << 0)
+
+/* GICC_IIDR bit masks and shifts */
+#define GICC_IIDR_PID_SHIFT 20
+#define GICC_IIDR_ARCH_SHIFT 16
+#define GICC_IIDR_REV_SHIFT 12
+#define GICC_IIDR_IMP_SHIFT	0
+
+#define GICC_IIDR_PID_MASK	0xfff
+#define GICC_IIDR_ARCH_MASK	0xf
+#define GICC_IIDR_REV_MASK	0xf
+#define GICC_IIDR_IMP_MASK	0xfff
+
+#define SZ_64K			(0x00010000)
+#define INT_POL_SECCTL_NUM	20
+#define NR_INT_POL_CTL		(20)
+
+/* main cpu regs */
+#define GICC_CTLR               0x0000
+#define GICC_PMR                0x0004
+#define GICC_BPR                0x0008
+#define GICC_IAR                0x000c
+#define GICC_EOIR               0x0010
+#define GICC_RPR                0x0014
+#define GICC_HPPIR              0x0018
+#define GICC_APBR               0x001c
+#define GICC_AIAR               0x0020
+#define GICC_AEOIR              0x0024
+#define GICC_AHPPIR            	0x0028
+#define GICC_APR                0x00d0
+#define GICC_NSAPR              0x00e0
+#define GICC_IIDR               0x00fc
+#define GICC_DIR                0x1000
+
+/* distribution regs */
+#define GICD_CTLR               0x000
+#define GICD_TYPER              0x004
+#define GICD_IIDR               0x008
+#define GICD_STATUSR      	0x010
+#define GICD_SEIR		0x068
+#define GICD_IGROUPR            0x080
+#define GICD_ISENABLER		0x100
+#define GICD_ICENABLER		0x180
+#define GICD_ISPENDR		0x200
+#define GICD_ICPENDR		0x280
+#define GICD_ISACTIVER		0x300
+#define GICD_ICACTIVER		0x380
+#define GICD_IPRIORITYR		0x400
+#define GICD_ITARGETSR		0x800
+#define GICD_ICFGR		0xc00
+#define GICD_IGRPMODR		0xd00
+#define GICD_NSACR		0xe00
+#define GICD_SGIR               0xf00
+#define GICD_CPENDSGIR		0xf10
+#define GICD_SPENDSGIR		0xf20
+#define GICD_PIDR2		0xFFE8
+
+/*
+ * Re-Distributor registers, offsets from RD_base
+ */
+#define GICR_V3_CTLR                       GICD_CTLR
+#define GICR_V3_IIDR                       0x0004
+#define GICR_V3_TYPER                      0x0008
+#define GICR_V3_STATUSR                    GICD_STATUSR
+#define GICR_V3_WAKER                      0x0014
+#define GICR_V3_SETLPIR                    0x0040
+#define GICR_V3_CLRLPIR                    0x0048
+#define GICR_V3_SEIR                       GICD_SEIR
+#define GICR_V3_PROPBASER                  0x0070
+#define GICR_V3_PENDBASER                  0x0078
+#define GICE_V3_IGROUP0			   		   0x0080
+#define GICR_V3_INVLPIR                    0x00A0
+#define GICR_V3_INVALLR                    0x00B0
+#define GICR_V3_SYNCR                      0x00C0
+#define GICR_V3_MOVLPIR                    0x0100
+#define GICR_V3_MOVALLR                    0x0110
+#define GICE_V3_IGRPMOD0		           0x0d00
+#define GICR_V3_PIDR2                      GICD_PIDR2
+
+#define GIC_V3_PIDR2_ARCH_MASK             0xf0
+#define GIC_V3_PIDR2_ARCH_GICv3            0x30
+#define GIC_V3_PIDR2_ARCH_GICv4            0x40
+
+#define INT_POL_CTL0		(MCUCFG_BASE + 0xA80)
+#define INT_POL_SECCTL0		(MCUCFG_BASE + 0xA00)
+#define SEC_POL_CTL_EN0		INT_POL_SECCTL0
+
+enum {
+	/* Ignore cpu_mask and forward interrupt to all CPUs other than the current cpu */
+	ARM_GIC_SGI_FLAG_TARGET_FILTER_NOT_SENDER = 0x1,
+	/* Ignore cpu_mask and forward interrupt to current CPU only */
+	ARM_GIC_SGI_FLAG_TARGET_FILTER_SENDER = 0x2,
+	ARM_GIC_SGI_FLAG_TARGET_FILTER_MASK = 0x3,
+
+	/* Only forward the interrupt to CPUs that has the interrupt configured as group 1 (non-secure) */
+	ARM_GIC_SGI_FLAG_NS = 0x4,
+};
+status_t arm_gic_sgi(u_int irq, u_int flags, u_int cpu_mask);
+
+void arm_gic_init(void);
+
+void mt_gic_el3_setup(void);
+#endif
+
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mt_i2c.h b/src/bsp/lk/platform/mt8518/include/platform/mt_i2c.h
new file mode 100644
index 0000000..4324161
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mt_i2c.h
@@ -0,0 +1,467 @@
+/*
+ * MediaTek Inc. (C) 2018. 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 136500
+#define MTK_I2C_CLK_DIV 2
+#define I2C_DEFAULT_CLK_DIV 2
+#define I2C_CLK_DIV_100K 10
+#define I2C_TIMING_100K 0x22
+#define I2C_CLK_DIV_400K I2C_DEFAULT_CLK_DIV
+#define I2C_TIMING_400K 0x2a
+#define I2C_CLK_DIV_1000K I2C_DEFAULT_CLK_DIV
+#define I2C_TIMING_1000K 0x11
+#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+0x01009000)
+#define MTK_I2C1_BASE (IO_PHYS+0x0100A000)
+#define MTK_I2C2_BASE (IO_PHYS+0x0100B000)
+#define MTK_I2C3_BASE (IO_PHYS+0x00014000)
+
+#define MTK_I2C0_DMA (IO_PHYS+0x01000180)
+#define MTK_I2C1_DMA (IO_PHYS+0x01000200)
+#define MTK_I2C2_DMA (IO_PHYS+0x01000280)
+#define MTK_I2C3_DMA (IO_PHYS+0x01000300)
+
+#define MTK_I2C0_GIC_IRQ 112
+#define MTK_I2C1_GIC_IRQ 113
+#define MTK_I2C2_GIC_IRQ 114
+#define MTK_I2C3_GIC_IRQ 203
+
+#define MTK_I2C_CLK_SET  (IO_PHYS+0x000000A0)
+#define MTK_I2C_CLK_CLR  (IO_PHYS+0x000000B0)
+#define MTK_I2C_CLK_STA  (IO_PHYS+0x00000070)
+#define MTK_I2C_CLK_SET0 (IO_PHYS+0x00000054)
+#define MTK_I2C_CLK_CLR0 (IO_PHYS+0x00000084)
+#define MTK_I2C_CLK_STA0 (IO_PHYS+0x00000024)
+#define MTK_I2C_CLK_SET1 (IO_PHYS+0x00000128)
+#define MTK_I2C_CLK_CLR1 (IO_PHYS+0x00000148)
+#define MTK_I2C_CLK_STA1 (IO_PHYS+0x000000E8)
+#define MTK_I2C_CLK_OFFSET   (0x1 << 12)
+#define MTK_I2C0_CLK_OFFSET  (0x1 << 3)
+#define MTK_I2C1_CLK_OFFSET  (0x1 << 4)
+#define MTK_I2C2_CLK_OFFSET  (0x1 << 16)
+#define MTK_I2C3_CLK_OFFSET  (0x1 << 0)
+#define MTK_APDMA_CLK_OFFSET (0x1 << 2)
+
+#define MTK_GPIO_I2C_BASE0 (IO_PHYS+0x00005450)//i2c1
+#define MTK_GPIO_I2C_BASE1 (IO_PHYS+0x00005460)//i2c0 i2c2
+#define MTK_GPIO_I2C_BASE2 (IO_PHYS+0x00005340)//i2c3
+
+#define MTK_GPIO_SDA0 0
+#define MTK_GPIO_SCL0 3
+#define MTK_GPIO_SDA1 9
+#define MTK_GPIO_SCL1 12
+#define MTK_GPIO_SDA2 6
+#define MTK_GPIO_SCL2 9
+#define MTK_GPIO_SDA3 3
+#define MTK_GPIO_SCL3 6
+
+#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/mt8518/include/platform/mt_irq.h b/src/bsp/lk/platform/mt8518/include/platform/mt_irq.h
new file mode 100644
index 0000000..94a0d08
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mt_irq.h
@@ -0,0 +1,109 @@
+/*
+ * 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 __MT_IRQ_H__
+#define __MT_IRQ_H__
+
+#define GIC_CPU_CTRL            0x00
+#define GIC_CPU_PRIMASK         0x04
+#define GIC_CPU_BINPOINT        0x08
+#define GIC_CPU_INTACK          0x0c
+#define GIC_CPU_EOI             0x10
+#define GIC_CPU_RUNNINGPRI      0x14
+#define GIC_CPU_HIGHPRI         0x18
+
+#define GIC_DIST_CTRL           0x000
+#define GIC_DIST_CTR            0x004
+#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_BIT     0x300
+#define GIC_DIST_PRI            0x400
+#define GIC_DIST_TARGET         0x800
+#define GIC_DIST_CONFIG         0xc00
+#define GIC_DIST_SOFTINT        0xf00
+#define GIC_DIST_ICDISR         0x80
+enum {IRQ_MASK_HEADER = 0xF1F1F1F1, IRQ_MASK_FOOTER = 0xF2F2F2F2};
+
+struct mtk_irq_mask {
+    unsigned int header;   /* for error checking */
+    unsigned int mask0;
+    unsigned int mask1;
+    unsigned int mask2;
+    unsigned int mask3;
+    unsigned int mask4;
+    unsigned int mask5;
+    unsigned int mask6;
+    unsigned int mask7;
+    unsigned int footer;   /* for error checking */
+};
+
+
+/*
+ * 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 ARM_GENERIC_TIMER_NONSECURE_PHYSICAL_INT   30
+
+#define MT_GPT_IRQ_ID   184
+#define MT_USB0_IRQ_ID  104
+#define MT_MSDC0_IRQ_ID 110
+#define MT_MSDC1_IRQ_ID 111
+
+#define MT_NR_PPI   (5)
+#define MT_NR_SPI   (221)
+#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
+
+
+int mt_irq_mask_all(struct mtk_irq_mask *mask); //(This is ONLY used for the sleep driver)
+int mt_irq_mask_restore(struct mtk_irq_mask *mask); //(This is ONLY used for the sleep driver)
+void mt_irq_set_sens(unsigned int irq, unsigned int sens);
+void mt_irq_set_polarity(unsigned int irq, unsigned int polarity);
+int mt_irq_mask_restore(struct mtk_irq_mask *mask);
+void mt_irq_unmask(unsigned int irq);
+void mt_irq_ack(unsigned int irq);
+
+void platform_init_interrupts(void);
+
+#endif  /* !__MT_IRQ_H__ */
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mt_partition.h b/src/bsp/lk/platform/mt8518/include/platform/mt_partition.h
new file mode 100644
index 0000000..169547a
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mt_partition.h
@@ -0,0 +1,168 @@
+/* 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) 2012. 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 __MT_PARTITION_H__
+#define __MT_PARTITION_H__
+
+
+#include <platform/part.h>
+#include "partition_define.h"
+#include <platform/mt_typedefs.h>
+
+#define PMT
+
+#define NAND_WRITE_SIZE  2048
+
+#define BIMG_HEADER_SZ              (0x800)
+#define MKIMG_HEADER_SZ             (0x200)
+
+#define BLK_BITS         (9)
+#define BLK_SIZE         (1 << BLK_BITS)
+#define BLK_NUM(size)    ((unsigned long long)(size) / BLK_SIZE)
+#define PART_KERNEL     "KERNEL"
+#define PART_ROOTFS     "ROOTFS"
+
+#define FRP_NAME        "frp"
+
+enum partition_type {
+    TYPE_LOW,
+    TYPE_FULL,
+    TYPE_SLC,
+    TYPE_TLC,
+};
+
+#define PART_BLKS_PRELOADER   BLK_NUM(PART_SIZE_PRELOADER)
+#define PART_BLKS_MBR   BLK_NUM(PART_SIZE_MBR)
+#define PART_BLKS_EBR1   BLK_NUM(PART_SIZE_EBR1)
+#define PART_BLKS_PRO_INFO   BLK_NUM(PART_SIZE_PRO_INFO)
+#define PART_BLKS_NVRAM   BLK_NUM(PART_SIZE_NVRAM)
+#define PART_BLKS_PROTECT_F   BLK_NUM(PART_SIZE_PROTECT_F)
+#define PART_BLKS_PROTECT_S   BLK_NUM(PART_SIZE_PROTECT_S)
+#define PART_BLKS_SECURE   BLK_NUM(PART_SIZE_SECCFG)
+#define PART_BLKS_UBOOT   BLK_NUM(PART_SIZE_UBOOT)
+#define PART_BLKS_BOOTIMG   BLK_NUM(PART_SIZE_BOOTIMG)
+#define PART_BLKS_RECOVERY   BLK_NUM(PART_SIZE_RECOVERY)
+#define PART_BLKS_SECSTATIC   BLK_NUM(PART_SIZE_SEC_RO)
+#define PART_BLKS_MISC   BLK_NUM(PART_SIZE_MISC)
+#define PART_BLKS_LOGO   BLK_NUM(PART_SIZE_LOGO)
+#define PART_BLKS_APANIC   BLK_NUM(PART_SIZE_EXPDB)
+#define PART_BLKS_TEE1   BLK_NUM(PART_SIZE_TEE1)
+#define PART_BLKS_TEE2   BLK_NUM(PART_SIZE_TEE2)
+#define PART_BLKS_KB   BLK_NUM(PART_SIZE_KB)
+#define PART_BLKS_DKB   BLK_NUM(PART_SIZE_DKB)
+#define PART_BLKS_ANDSYSIMG   BLK_NUM(PART_SIZE_ANDROID)
+#define PART_BLKS_CACHE   BLK_NUM(PART_SIZE_CACHE)
+#define PART_BLKS_USER   BLK_NUM(PART_SIZE_USRDATA)
+
+
+#define PMT_END_NAME "USRDATA"
+
+struct NAND_CMD {
+    u32 u4ColAddr;
+    u32 u4RowAddr;
+    u32 u4OOBRowAddr;
+    u8  au1OOB[64];
+    u8* pDataBuf;
+};
+
+typedef union {
+    struct {
+        unsigned int magic;        /* partition magic */
+        unsigned int dsize;        /* partition data size */
+        char         name[32];     /* partition name */
+        unsigned int maddr;        /* partition memory address */
+    } info;
+    unsigned char data[BLK_SIZE];
+} part_hdr_t;
+
+typedef struct {
+    const char *name;        /* partition name */
+    unsigned long  nr_sects;      /* partition blks */
+    unsigned long  flags;       /* partition flags */
+    unsigned long  start_sect;    /* partition start blk */
+    unsigned int part_id;        /* partition region */
+    enum partition_type type;
+} part_t;
+
+struct part_name_map {
+    char fb_name[32];   /*partition name used by fastboot*/
+    char r_name[32];    /*real partition name*/
+    char *partition_type;   /*partition_type*/
+    int partition_idx;  /*partition index*/
+    int is_support_erase;   /*partition support erase in fastboot*/
+    int is_support_dl;  /*partition support download in fastboot*/
+};
+
+typedef struct part_dev part_dev_t;
+
+struct part_dev {
+    int init;
+    int id;
+    void *priv;
+    block_dev_desc_t *blkdev;
+    int (*init_dev) (int id);
+    int (*read)  (part_dev_t *dev, u64 src, uchar *dst, u32 size, unsigned int part_id);
+    int (*write) (part_dev_t *dev, uchar *src, u64 dst, u32 size, unsigned int part_id);
+};
+enum {
+    RAW_DATA_IMG,
+    YFFS2_IMG,
+    UBIFS_IMG,
+    EXT4_IMG,
+    FAT_IMG,
+    UNKOWN_IMG,
+};
+
+extern struct part_name_map g_part_name_map[PART_MAX_COUNT];
+
+
+extern void mt_part_init(unsigned long totalblks);
+extern void part_init_pmt(unsigned long totalblks, part_dev_t *dev);
+
+extern int mt_part_register_device(part_dev_t *dev);
+extern part_t* mt_part_get_partition(char *name);
+extern part_dev_t* mt_part_get_device(void);
+extern void mt_part_dump(void);
+extern int partition_get_index(const char * name);
+extern u32 partition_get_region(int index);
+extern u64 partition_get_offset(int index);
+extern u64 partition_get_size(int index);
+extern int partition_get_type(int index, char **p_type);
+extern int partition_get_name(int index, char **p_name);
+extern int is_support_erase(int index);
+extern int is_support_flash(int index);
+extern unsigned long long partition_reserve_size(void);
+#endif /* __MT_PARTITION_H__ */
+    
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mt_reg_base.h b/src/bsp/lk/platform/mt8518/include/platform/mt_reg_base.h
new file mode 100644
index 0000000..79fdb82
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mt_reg_base.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 <platform/mt8518.h>
+
+/* I/O mapping */
+#define IO_PHYS             PERIPHERAL_BASE_VIRT
+#define IO_SIZE             PERIPHERAL_BASE_SIZE
+
+/* IO register definitions */
+#define EMI_BASE            (IO_PHYS + 0x00205000)
+#define GPIO_BASE           (IO_PHYS + 0x00005000)
+#define MCUSYS_CFGREG_BASE  (IO_PHYS + 0x00200000)
+#define TRNG_BASE           (IO_PHYS + 0x0020C000)
+
+// gic
+#define GIC_DIST_BASE   (MEMORY_BASE_VIRT+0x0C000000)
+#define GIC_REDIS_BASE  (MEMORY_BASE_VIRT+0x0C100000)
+
+// APB Module mcucfg
+#define MCUCFG_BASE         (IO_PHYS + 0x00200000)
+
+#define UART0_BASE          (IO_PHYS + 0x01005000)
+#define UART1_BASE          (IO_PHYS + 0x0001A000)
+#define UART2_BASE          (IO_PHYS + 0x01007000)
+#define UART3_BASE          (IO_PHYS + 0x01007500)
+
+#define MSDC0_BASE          (IO_PHYS + 0x01120000)
+#define MSDC1_BASE          (IO_PHYS + 0x01130000)
+
+#define USB0_BASE           (IO_PHYS + 0x01100000)
+#define USBSIF_BASE         (IO_PHYS + 0x01110000)
+#define USB_BASE            (USB0_BASE)
+#define RGU_BASE            (IO_PHYS + 0x7000)
+
+#define NFI_BASE            (IO_PHYS + 0x1001000)
+#define NFIECC_BASE         (IO_PHYS + 0x1002000)
+
+#define SEJ_BASE            (IO_PHYS + 0x000A000)
+#define SCP_BASE_SRAM       (IO_PHYS + 0x1800000)
+#define SCP_BASE_CFG        (IO_PHYS + 0x1820000)
+
+#define PWM_BASE            (IO_PHYS + 0x00015000)
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mt_scp.h b/src/bsp/lk/platform/mt8518/include/platform/mt_scp.h
new file mode 100644
index 0000000..9932153
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mt_scp.h
@@ -0,0 +1,42 @@
+#ifndef __MT_SCP_H__
+#define __MT_SCP_H__
+
+#define SCPSYS_PART_NAME	"scpsys"
+#define CMSYS_RESET_CTL		0x0
+#define CPU_RST_SW		0x1
+
+#define CMSYS_CLKGAT_CTL	0x8
+#define CPUCK_EN		0x1
+
+#define MAX_SCPSYS_SIZE         0x20000
+/* scp firmware information */
+#define PART_HDR_DATA_SIZE	512
+#define PART_MAGIC		0x58881688
+#define PART_EXT_MAGIC		0x58891689
+union  fm_hdr_t {
+	struct {
+		unsigned int magic;        /* partition magic */
+		unsigned int dsize;        /* partition data size */
+		char         name[32];     /* partition name */
+		unsigned int maddr;        /* partition memory address */
+		unsigned int mode;
+		/* extension */
+		unsigned int ext_magic;    /* always EXT_MAGIC */
+		/* header size: 512 bytes currently,may extend in the future */
+		unsigned int hdr_size;
+		unsigned int hdr_version;  /* see HDR_VERSION */
+		unsigned int img_type;
+		unsigned int img_list_end;
+		unsigned int align_size;
+		unsigned int dsize_extend;
+		unsigned int maddr_extend;
+	} info;
+	unsigned char data[PART_HDR_DATA_SIZE];
+};
+
+void start_scpsys(void);
+void stop_scpsys(void);
+int load_scpsys(void);
+
+#endif
+
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mt_typedefs.h b/src/bsp/lk/platform/mt8518/include/platform/mt_typedefs.h
new file mode 100644
index 0000000..2216539
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mt_typedefs.h
@@ -0,0 +1,196 @@
+/* ------------
+ *   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 volatile unsigned short *UINT16P;
+typedef volatile unsigned char *UINT8P;
+typedef unsigned char *U8P;
+
+
+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 volatile unsigned char *P_kal_uint8;
+typedef volatile unsigned short *P_kal_uint16;
+typedef volatile unsigned int *P_kal_uint32;
+typedef long LONG;
+typedef unsigned char UBYTE;
+typedef short SHORT;
+typedef long long kal_int64;
+typedef unsigned long long kal_uint64;
+typedef char kal_char;
+
+typedef volatile unsigned char *P_U8;
+typedef volatile signed char *P_S8;
+typedef volatile unsigned short *P_U16;
+typedef volatile signed short *P_S16;
+typedef volatile unsigned int *P_U32;
+typedef volatile signed int *P_S32;
+typedef unsigned long long *P_U64;
+typedef signed long long *P_S64;
+
+
+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/mt8518/include/platform/mt_uart.h b/src/bsp/lk/platform/mt8518/include/platform/mt_uart.h
new file mode 100644
index 0000000..3a9f0e8
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mt_uart.h
@@ -0,0 +1,25 @@
+/*
+ * 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
+
+bool check_uart_enter(void);
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mt_usb.h b/src/bsp/lk/platform/mt8518/include/platform/mt_usb.h
new file mode 100644
index 0000000..1742f05
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mt_usb.h
@@ -0,0 +1,273 @@
+/*
+ * 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
+
+/* USB PHY registers */
+#define USB20_PHY_BASE  (USBSIF_BASE + 0x0800)
+#define USB11_PHY_BASE  (USBSIF_BASE + 0x0900)
+
+/* hardware spec */
+#define MT_EP_NUM 4
+#define MT_CHAN_NUM 4
+#define MT_EP0_FIFOSIZE 64
+
+#define FIFO_ADDR_START  512
+
+#define MT_BULK_MAXP 512
+#define MT_INT_MAXP  1024
+
+/* USB common registers */
+#define FADDR    (USB_BASE + 0x0000)    /* Function Address Register */
+#define POWER    (USB_BASE + 0x0001)    /* Power Management Register */
+#define INTRTX   (USB_BASE + 0x0002)    /* TX Interrupt Status Register */
+#define INTRRX   (USB_BASE + 0x0004)    /* RX Interrupt Status Register */
+#define INTRTXE  (USB_BASE + 0x0006)    /* TX Interrupt Status Enable Register */
+#define INTRRXE  (USB_BASE + 0x0008)    /* RX Interrupt Status Enable Register */
+#define INTRUSB  (USB_BASE + 0x000a)    /* Common USB Interrupt Register */
+#define INTRUSBE (USB_BASE + 0x000b)    /* Common USB Interrupt Enable Register */
+#define FRAME    (USB_BASE + 0x000c)    /* Frame Number Register */
+#define INDEX    (USB_BASE + 0x000e)    /* Endpoint Selecting Index Register */
+#define TESTMODE (USB_BASE + 0x000f)    /* Test Mode Enable Register */
+
+/* POWER fields */
+#define PWR_ISO_UPDATE       (1<<7)
+#define PWR_SOFT_CONN        (1<<6)
+#define PWR_HS_ENAB          (1<<5)
+#define PWR_HS_MODE          (1<<4)
+#define PWR_RESET            (1<<3)
+#define PWR_RESUME           (1<<2)
+#define PWR_SUSPEND_MODE     (1<<1)
+#define PWR_ENABLE_SUSPENDM  (1<<0)
+
+/* INTRUSB fields */
+#define INTRUSB_VBUS_ERROR (1<<7)
+#define INTRUSB_SESS_REQ   (1<<6)
+#define INTRUSB_DISCON     (1<<5)
+#define INTRUSB_CONN       (1<<4)
+#define INTRUSB_SOF        (1<<3)
+#define INTRUSB_RESET      (1<<2)
+#define INTRUSB_RESUME     (1<<1)
+#define INTRUSB_SUSPEND    (1<<0)
+
+/* DMA control registers */
+#define USB_DMA_INTR (USB_BASE + 0x0200)
+#define USB_DMA_INTR_UNMASK_SET_OFFSET (24)
+
+#define USB_DMA_CNTL(chan)  (USB_BASE + 0x0204 + 0x10*(chan-1))
+#define USB_DMA_ADDR(chan)  (USB_BASE + 0x0208 + 0x10*(chan-1))
+#define USB_DMA_COUNT(chan) (USB_BASE + 0x020c + 0x10*(chan-1))
+
+/* Endpoint Control/Status Registers */
+#define IECSR (USB_BASE + 0x0010)
+/* for EP0 */
+#define CSR0         0x2        /* EP0 Control Status Register */
+/* For Host Mode, it would be 0x2 */
+#define COUNT0       0x8        /* EP0 Received Bytes Register */
+#define NAKLIMIT0    0xB        /* NAK Limit Register */
+#define CONFIGDATA   0xF        /* Core Configuration Register */
+/* for other endpoints */
+#define TXMAP        0x0        /* TXMAP Register: Max Packet Size for TX */
+#define TXCSR        0x2        /* TXCSR Register: TX Control Status Register */
+#define RXMAP        0x4        /* RXMAP Register: Max Packet Size for RX */
+#define RXCSR        0x6        /* RXCSR Register: RX Control Status Register */
+#define RXCOUNT      0x8        /* RXCOUNT Register */
+#define TXTYPE       0xa        /* TX Type Register */
+#define TXINTERVAL   0xb        /* TX Interval Register */
+#define RXTYPE       0xc        /* RX Type Register */
+#define RXINTERVAL   0xd        /* RX Interval Register */
+#define FIFOSIZE     0xf        /* configured FIFO size register */
+
+/* control status register fields */
+/* CSR0_DEV */
+#define EP0_FLUSH_FIFO           (1<<8)
+#define EP0_SERVICE_SETUP_END    (1<<7)
+#define EP0_SERVICED_RXPKTRDY    (1<<6)
+#define EP0_SENDSTALL            (1<<5)
+#define EP0_SETUPEND             (1<<4)
+#define EP0_DATAEND              (1<<3)
+#define EP0_SENTSTALL            (1<<2)
+#define EP0_TXPKTRDY             (1<<1)
+#define EP0_RXPKTRDY             (1<<0)
+
+/* TXCSR_DEV */
+#define EPX_TX_AUTOSET           (1<<15)
+#define EPX_TX_ISO               (1<<14)
+#define EPX_TX_MODE              (1<<13)
+#define EPX_TX_DMAREQEN          (1<<12)
+#define EPX_TX_FRCDATATOG        (1<<11)
+#define EPX_TX_DMAREQMODE        (1<<10)
+#define EPX_TX_AUTOSETEN_SPKT    (1<<9)
+#define EPX_TX_INCOMPTX          (1<<7)
+#define EPX_TX_CLRDATATOG        (1<<6)
+#define EPX_TX_SENTSTALL         (1<<5)
+#define EPX_TX_SENDSTALL         (1<<4)
+#define EPX_TX_FLUSHFIFO         (1<<3)
+#define EPX_TX_UNDERRUN          (1<<2)
+#define EPX_TX_FIFONOTEMPTY      (1<<1)
+#define EPX_TX_TXPKTRDY          (1<<0)
+
+/* RXCSR_DEV */
+#define EPX_RX_AUTOCLEAR         (1<<15)
+#define EPX_RX_ISO               (1<<14)
+#define EPX_RX_DMAREQEN          (1<<13)
+#define EPX_RX_DISNYET           (1<<12)
+#define EPX_RX_PIDERR            (1<<12)
+#define EPX_RX_DMAREQMODE        (1<<11)
+#define EPX_RX_AUTOCLRENSPKT     (1<<10)
+#define EPX_RX_INCOMPRXINTREN    (1<<9)
+#define EPX_RX_INCOMPRX          (1<<8)
+#define EPX_RX_CLRDATATOG        (1<<7)
+#define EPX_RX_SENTSTALL         (1<<6)
+#define EPX_RX_SENDSTALL         (1<<5)
+#define EPX_RX_FLUSHFIFO         (1<<4)
+#define EPX_RX_DATAERR           (1<<3)
+#define EPX_RX_OVERRUN           (1<<2)
+#define EPX_RX_FIFOFULL          (1<<1)
+#define EPX_RX_RXPKTRDY          (1<<0)
+
+/* CONFIGDATA fields */
+#define MP_RXE         (1<<7)
+#define MP_TXE         (1<<6)
+#define BIGENDIAN      (1<<5)
+#define HBRXE          (1<<4)
+#define HBTXE          (1<<3)
+#define DYNFIFOSIZING  (1<<2)
+#define SOFTCONE       (1<<1)
+#define UTMIDATAWIDTH  (1<<0)
+
+/* FIFO register */
+/*
+ * for endpint 1 ~ 4, writing to these addresses = writing to the
+ * corresponding TX FIFO, reading from these addresses = reading from
+ * corresponding RX FIFO
+ */
+
+#define FIFO(ep_num)     (USB_BASE + 0x0020 + ep_num*0x0004)
+
+/* ============================ */
+/* additional control registers */
+/* ============================ */
+
+#define DEVCTL       (USB_BASE + 0x0060)        /* OTG Device Control Register */
+#define PWRUPCNT     (USB_BASE + 0x0061)        /* Power Up Counter Register */
+#define TXFIFOSZ     (USB_BASE + 0x0062)        /* TX FIFO Size Register */
+#define RXFIFOSZ     (USB_BASE + 0x0063)        /* RX FIFO Size Register */
+#define TXFIFOADD    (USB_BASE + 0x0064)        /* TX FIFO Address Register */
+#define RXFIFOADD    (USB_BASE + 0x0066)        /* RX FIFO Address Register */
+#define HWVERS       (USB_BASE + 0x006c)        /* H/W Version Register */
+#define SWRST        (USB_BASE + 0x0074)        /* Software Reset Register */
+#define EPINFO       (USB_BASE + 0x0078)        /* TX and RX Information Register */
+#define RAM_DMAINFO  (USB_BASE + 0x0079)        /* RAM and DMA Information Register */
+#define LINKINFO     (USB_BASE + 0x007a)        /* Delay Time Information Register */
+#define VPLEN        (USB_BASE + 0x007b)        /* VBUS Pulse Charge Time Register */
+#define HSEOF1       (USB_BASE + 0x007c)        /* High Speed EOF1 Register */
+#define FSEOF1       (USB_BASE + 0x007d)        /* Full Speed EOF1 Register */
+#define LSEOF1       (USB_BASE + 0x007e)        /* Low Speed EOF1 Register */
+#define RSTINFO      (USB_BASE + 0x007f)        /* Reset Information Register */
+
+/* FIFO size register fields and available packet size values */
+#define DOUBLE_BUF  1
+#define FIFOSZ_DPB  (1 << 4)
+#define PKTSZ       0x0f
+
+#define PKTSZ_8     (1<<3)
+#define PKTSZ_16    (1<<4)
+#define PKTSZ_32    (1<<5)
+#define PKTSZ_64    (1<<6)
+#define PKTSZ_128   (1<<7)
+#define PKTSZ_256   (1<<8)
+#define PKTSZ_512   (1<<9)
+#define PKTSZ_1024  (1<<10)
+
+#define FIFOSZ_8    (0x0)
+#define FIFOSZ_16   (0x1)
+#define FIFOSZ_32   (0x2)
+#define FIFOSZ_64   (0x3)
+#define FIFOSZ_128  (0x4)
+#define FIFOSZ_256  (0x5)
+#define FIFOSZ_512  (0x6)
+#define FIFOSZ_1024 (0x7)
+#define FIFOSZ_2048 (0x8)
+#define FIFOSZ_4096 (0x9)
+#define FIFOSZ_3072 (0xF)
+
+/* SWRST fields */
+#define SWRST_PHY_RST         (1<<7)
+#define SWRST_PHYSIG_GATE_HS  (1<<6)
+#define SWRST_PHYSIG_GATE_EN  (1<<5)
+#define SWRST_REDUCE_DLY      (1<<4)
+#define SWRST_UNDO_SRPFIX     (1<<3)
+#define SWRST_FRC_VBUSVALID   (1<<2)
+#define SWRST_SWRST           (1<<1)
+#define SWRST_DISUSBRESET     (1<<0)
+
+/* DMA_CNTL */
+#define USB_DMA_CNTL_ENDMAMODE2            (1 << 13)
+#define USB_DMA_CNTL_PP_RST                (1 << 12)
+#define USB_DMA_CNTL_PP_EN                 (1 << 11)
+#define USB_DMA_BURST_MODE_MASK            (3 << 9)
+#define USB_DMA_BURST_MODE_0               (0 << 9)
+#define USB_DMA_BURST_MODE_1               (0x1 << 9)
+#define USB_DMA_BURST_MODE_2               (0x2 << 9)
+#define USB_DMA_BURST_MODE_3               (0x3 << 9)
+#define USB_DMA_BUS_ERROR                  (0x1 << 8)
+#define USB_DMA_ENDPNT_MASK                (0xf << 4)
+#define USB_DMA_ENDPNT_OFFSET              (4)
+#define USB_DMA_INTEN                      (1 << 3)
+#define USB_DMA_DMAMODE                    (1 << 2)
+#define USB_DMA_DIR                        (1 << 1)
+#define USB_DMA_EN                         (1 << 0)
+
+/* USB level 1 interrupt registers */
+
+#define USB_L1INTS (USB_BASE + 0xa0)  /* USB level 1 interrupt status register */
+#define USB_L1INTM (USB_BASE + 0xa4)  /* USB level 1 interrupt mask register  */
+#define USB_L1INTP (USB_BASE + 0xa8)  /* USB level 1 interrupt polarity register  */
+
+#define TX_INT_STATUS       (1 << 0)
+#define RX_INT_STATUS       (1 << 1)
+#define USBCOM_INT_STATUS   (1 << 2)
+#define DMA_INT_STATUS      (1 << 3)
+#define PSR_INT_STATUS      (1 << 4)
+#define QINT_STATUS     (1 << 5)
+#define QHIF_INT_STATUS     (1 << 6)
+#define DPDM_INT_STATUS     (1 << 7)
+#define VBUSVALID_INT_STATUS    (1 << 8)
+#define IDDIG_INT_STATUS    (1 << 9)
+#define DRVVBUS_INT_STATUS  (1 << 10)
+#define POWERDWN_INT_STATUS (1 << 11)
+
+#define VBUSVALID_INT_POL   (1 << 8)
+#define IDDIG_INT_POL       (1 << 9)
+#define DRVVBUS_INT_POL     (1 << 10)
+
+/* mt_usb defines */
+typedef enum {
+    EP0_IDLE = 0,
+    EP0_RX,
+    EP0_TX,
+} EP0_STATE;
+
+/* some macros */
+#define EPMASK(X)   (1 << X)
+#define CHANMASK(X) (1 << X)
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mtk_key.h b/src/bsp/lk/platform/mt8518/include/platform/mtk_key.h
new file mode 100644
index 0000000..082e95f
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mtk_key.h
@@ -0,0 +1,26 @@
+/*
+ * 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
+
+bool check_download_key(void);
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mtk_serial_key.h b/src/bsp/lk/platform/mt8518/include/platform/mtk_serial_key.h
new file mode 100644
index 0000000..2a87f45
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mtk_serial_key.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.
+ */
+#pragma once
+
+/* serial key */
+#if WITH_KERNEL_VM
+#define SERIAL_KEY_HI    (0xffff000000609254UL)
+#define SERIAL_KEY_LO    (0xffff000000609250UL)
+#else
+#define SERIAL_KEY_HI    (0x10009254UL)
+#define SERIAL_KEY_LO    (0x10009250UL)
+#endif
+
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mtk_timer.h b/src/bsp/lk/platform/mt8518/include/platform/mtk_timer.h
new file mode 100644
index 0000000..7986128
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mtk_timer.h
@@ -0,0 +1,34 @@
+/*
+ * 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>
+#include <stdbool.h>
+#include <reg.h>
+
+void gpt_busy_wait_us(u32 timeout_us);
+void gpt_busy_wait_ms(u32 timeout_ms);
+
+void mdelay(unsigned long msec);
+void udelay(unsigned long usec);
+void mtk_timer_init(void);
diff --git a/src/bsp/lk/platform/mt8518/include/platform/mtk_wdt.h b/src/bsp/lk/platform/mt8518/include/platform/mtk_wdt.h
new file mode 100644
index 0000000..45ac4b1
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/mtk_wdt.h
@@ -0,0 +1,132 @@
+/*
+ * 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>
+#include <stdbool.h>
+#include <platform/mt8518.h>
+
+#define ENABLE_WDT_MODULE       (1) /* Module switch */
+#define LK_WDT_DISABLE          (0)
+
+#define MTK_WDT_BASE            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    (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_DIRECT_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)
+
+#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_recovery_mode(bool flag);
+bool check_fastboot_mode(void);
+bool check_recovery_mode(void);
+void mtk_wdt_init(void);
+void mtk_wdt_disable(void);
+int rgu_dram_reserved(int 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/mt8518/include/platform/nand.h b/src/bsp/lk/platform/mt8518/include/platform/nand.h
new file mode 100644
index 0000000..6074fec
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/nand.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
+
+extern int nand_init_device(void);
+
+/* nand ioctls, nand does not support generic bio ioctls(mapping),
+ * so just use the same value
+ */
+enum nand_ioctl_num {
+	NAND_IOCTL_GET_ERASE_SIZE = 0x100,
+	NAND_IOCTL_REGISTER_SUBDEV,
+	NAND_IOCTL_UNREGISTER_SUBDEV,
+	NAND_IOCTL_CHECK_BAD_BLOCK,
+	NAND_IOCTL_IS_BAD_BLOCK,
+	NAND_IOCTL_FORCE_FORMAT_ALL,
+	NAND_IOCTL_FORCE_TEST_ALL,
+};
+
diff --git a/src/bsp/lk/platform/mt8518/include/platform/nand_device_list.h b/src/bsp/lk/platform/mt8518/include/platform/nand_device_list.h
new file mode 100644
index 0000000..1a62aa8
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/nand_device_list.h
@@ -0,0 +1,374 @@
+/* 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 __NAND_DEVICE_LIST_H__
+#define __NAND_DEVICE_LIST_H__
+
+#define NAND_MAX_ID     6
+#define CHIP_CNT        10
+#define P_SIZE      16384
+#define P_PER_BLK       256
+#define C_SIZE      8192
+#define RAMDOM_READ     (1<<0)
+#define CACHE_READ      (1<<1)
+#define RAND_TYPE_SAMSUNG 0
+#define RAND_TYPE_TOSHIBA 1
+#define RAND_TYPE_NONE 2
+
+#define MAX_FLASH 20 //modify this define if device list is more than 20 later .xiaolei
+
+
+#define READ_RETRY_MAX 10
+struct gFeature {
+    u32 address;
+    u32 feature;
+};
+
+enum readRetryType {
+    RTYPE_MICRON,
+    RTYPE_SANDISK,
+    RTYPE_SANDISK_19NM,
+    RTYPE_TOSHIBA,
+    RTYPE_HYNIX,
+    RTYPE_HYNIX_16NM,
+#if defined(MTK_TLC_NAND_SUPPORT)
+    RTYPE_SANDISK_TLC_1YNM,
+#endif
+    RTYPE_HYNIX_FDIE,
+#if defined(MTK_TLC_NAND_SUPPORT)
+    RTYPE_TOSHIBA_TLC_A19NM,
+    RTYPE_SANDISK_TLC_1ZNM
+#endif
+};
+
+struct gFeatureSet {
+    u8 sfeatureCmd;
+    u8 gfeatureCmd;
+    u8 readRetryPreCmd;
+    u8 readRetryCnt;
+    u32 readRetryAddress;
+    u32 readRetryDefault;
+    u32 readRetryStart;
+    enum readRetryType rtype;
+    struct gFeature Interface;
+    struct gFeature Async_timing;
+};
+
+struct gRandConfig {
+    u8 type;
+    u32 seed[6];
+};
+
+enum pptbl {
+    MICRON_8K,
+    HYNIX_8K,
+    SANDISK_16K,
+    PPTBL_NONE,
+};
+
+struct MLC_feature_set {
+    enum pptbl ptbl_idx;
+    struct gFeatureSet   FeatureSet;
+    struct gRandConfig   randConfig;
+};
+
+enum flashdev_vendor {
+    VEND_SAMSUNG,
+    VEND_MICRON,
+    VEND_TOSHIBA,
+    VEND_HYNIX,
+    VEND_SANDISK,
+    VEND_BIWIN,
+    VEND_MXIC,
+    VEND_NONE,
+};
+
+enum flashdev_IOWidth {
+    IO_8BIT = 8,
+    IO_16BIT = 16,
+    IO_TOGGLEDDR = 9,
+    IO_TOGGLESDR = 10,
+    IO_ONFI = 12,
+};
+
+#if defined(MTK_TLC_NAND_SUPPORT)
+#define NAND_FLASH_SLC   (0x0000)
+#define NAND_FLASH_MLC   (0x0001)
+#define NAND_FLASH_TLC   (0x0002)
+#define NAND_FLASH_MASK   (0x00FF)
+
+typedef struct {
+    bool         slcopmodeEn;                  //TRUE: slc mode   FALSE: tlc mode
+    bool         pPlaneEn;                     //this chip has pseudo plane
+    bool         needchangecolumn;             //read page with change column address command
+    bool         normaltlc;                    //whether need 09/0d 01/02/03 tlc command, whether need wl and page exchange.  micron no need
+    u16          en_slc_mode_cmd;              //enable slc mode cmd
+    u16          dis_slc_mode_cmd;             //disable slc mode cmd: 0xff is invalid
+    bool         ecc_recalculate_en;           //for nfi config
+    u8           ecc_required;                 //required ecc bit
+    u8           block_bit;                    //block address start bit;
+    u8           pPlane_bit;                   //pesudo plane bit;
+} NFI_TLC_CTRL;
+
+typedef enum {
+    PROGRAM_1ST_CYCLE = 1,
+    PROGRAM_2ND_CYCLE = 2,
+    PROGRAM_3RD_CYCLE = 3
+} NFI_TLC_PG_CYCLE;
+
+typedef enum {
+    WL_LOW_PAGE = 0,
+    WL_MID_PAGE = 1,
+    WL_HIGH_PAGE = 2,
+} NFI_TLC_WL_PRE;
+
+typedef struct {
+    u32 word_line_idx;
+    NFI_TLC_WL_PRE wl_pre;
+} NFI_TLC_WL_INFO;
+#endif
+
+typedef struct {
+    u8 id[NAND_MAX_ID];
+    u8 id_length;
+    u8 addr_cycle;
+    u32 iowidth;
+    u32 totalsize;
+    u16 blocksize;
+    u16 pagesize;
+    u16 sparesize;
+    u32 timmingsetting;
+    u32 s_acccon;
+    u32 s_acccon1;
+    u32 freq;
+    enum flashdev_vendor vendor;
+    u16 sectorsize;
+    u8 devciename[30];
+    u32 advancedmode;
+    struct MLC_feature_set feature_set;
+#if defined(MTK_TLC_NAND_SUPPORT)
+    u16 NAND_FLASH_TYPE;
+    NFI_TLC_CTRL tlcControl;
+    bool two_phyplane; //whether have two physical plane.
+#endif
+} flashdev_info,*pflashdev_info;
+
+#if defined(MTK_TLC_NAND_SUPPORT)
+static const flashdev_info gen_FlashTable_p[]= {
+    {    {0x45,0x4C,0x98,0xA3,0x76,0x00}, 5,5,IO_8BIT,0x10F2000,6144,16384,1952,0x10401011, 0xC03222,0x101,80,VEND_SANDISK,1024, "SDTNSIAMA016G",0 ,
+        {
+            PPTBL_NONE, {0xEF,0xEE,0x5D,46,0x11,0,0,RTYPE_SANDISK_TLC_1ZNM,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_TLC, {FALSE, FALSE, TRUE, TRUE, 0xA2, 0xFF, TRUE, 68, 8, 0}, false
+    },
+    {    {0x45,0xDE,0x98,0x92,0x72,0x00}, 5,5,IO_8BIT,0x83C580,4128,16384,1952,0x10401011, 0xC03222,0x101,80,VEND_SANDISK,1024, "SDTNRCAMAOO8G",0 ,
+        {
+            PPTBL_NONE, {0xEF,0xEE,0x5D,39,0x11,0,0,RTYPE_SANDISK_TLC_1YNM,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_TLC, {FALSE, TRUE, TRUE, TRUE, 0xA2, 0xFF, TRUE, 68, 9, 8}, false
+    },
+    {    {0x45,0xDE,0xA8,0x92,0x76,0x00}, 5,5,IO_8BIT,0x884E80,8256,32768,3904,0x10401011, 0xC03222,0x101,80,VEND_SANDISK,1024, "SDTNRIAMAOO8G",0 ,
+        {
+            PPTBL_NONE, {0xEF,0xEE,0x5D,39,0x11,0,0,RTYPE_SANDISK_TLC_1YNM,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_TLC, {false, true, true, true, 0xA2, 0xFF, true, 68, 9, 8}, true
+    },
+    {    {0x98,0xDE,0x98,0x92,0x72,0x00}, 5,5,IO_8BIT,0x83C580,4128,16384,1952,0x10401011, 0xC03222,0x101,80,VEND_TOSHIBA,1024, "TC58TEG6TCKTA00",0 ,
+        {
+            PPTBL_NONE, {0xEF,0xEE,0x5D,31,0x11,31,0,RTYPE_TOSHIBA_TLC_A19NM,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_TLC, {false, true, true, true, 0xA2, 0xFF, true, 68, 9, 8}, false
+    },
+    {    {0x45,0xDE,0x94,0x93,0x76,0x57}, 6,5,IO_8BIT,0x800000,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_SANDISK,1024, "SDTNQGAMA008G ",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0xFF,16,0x11,0,1,RTYPE_SANDISK_19NM,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_MLC, {FALSE,FALSE,FALSE,FALSE, 0xFF, 0xFF,FALSE, 0xFF, 8, 0xFF}, false
+    },
+    {    {0x98,0xD7,0x84,0x93,0x72,0x00}, 5,5,IO_8BIT,0x400000,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_TOSHIBA,1024, "TC58TEG5DCKTA00",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0xFF,7,0xFF,7,0,RTYPE_TOSHIBA,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_MLC, {FALSE,FALSE,FALSE,FALSE, 0xFF, 0xFF,FALSE, 0xFF, 8, 0xFF}, false
+    },
+    {    {0x45,0xDE,0x94,0x93,0x76,0x00}, 5,5,IO_8BIT,0x800000,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_SANDISK,1024, "SDTNRGAMA008GK ",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0x5D,36,0x11,0,0xFFFFFFFF,RTYPE_SANDISK,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_MLC, {FALSE,FALSE,FALSE,FALSE, 0xFF, 0xFF,FALSE, 0xFF, 8, 0xFF}, false
+    },
+    {    {0xAD,0xDE,0x14,0xA7,0x42,0x00}, 5,5,IO_8BIT,0x800000,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_HYNIX,1024, "H27UCG8T2ETR",0 ,
+        {
+            SANDISK_16K, {0xFF,0xFF,0xFF,7,0xFF,0,1,RTYPE_HYNIX_16NM,{0xFF, 0xFF},{0xFF, 0xFF}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_MLC, {FALSE,FALSE,FALSE,FALSE, 0xFF, 0xFF,FALSE, 0xFF, 8, 0xFF}, false
+    },
+    {    {0x2C,0x44,0x44,0x4B,0xA9,0x00}, 5,5,IO_8BIT,0x400000,2048,8192,640,0x10401011, 0xC03222,0x101,80,VEND_MICRON,1024, "MT29F32G08CBADB ",0 ,
+        {
+            MICRON_8K, {0xEF,0xEE,0xFF,7,0x89,0,1,RTYPE_MICRON,{0x1, 0x14},{0x1, 0x5}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_MLC, {FALSE,FALSE,FALSE,FALSE, 0xFF, 0xFF,FALSE, 0xFF, 8, 0xFF}, false
+    },
+    {    {0xAD,0xDE,0x94,0xA7,0x42,0x00}, 5,5,IO_8BIT,0x800000,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_BIWIN,1024, "BW27UCG8T2ETR",0 ,
+        {
+            SANDISK_16K, {0xFF,0xFF,0xFF,7,0xFF,0,1,RTYPE_HYNIX_16NM,{0xFF, 0xFF},{0xFF, 0xFF}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_MLC, {FALSE,FALSE,FALSE,FALSE, 0xFF, 0xFF,FALSE, 0xFF, 8, 0xFF}, false
+    },
+    {    {0x45,0xD7,0x84,0x93,0x72,0x00}, 5,5,IO_8BIT,0x400000,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_SANDISK,1024, "SDTNRGAMA004GK ",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0x5D,36,0x11,0,0xFFFFFFFF,RTYPE_SANDISK,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_MLC, {FALSE,FALSE,FALSE,FALSE, 0xFF, 0xFF,FALSE, 0xFF, 8, 0xFF}, false
+    },
+    {    {0x2C,0x64,0x44,0x4B,0xA9,0x00}, 5,5,IO_8BIT,0x800000,2048,8192,640,0x10401011, 0xC03222,0x101,80,VEND_MICRON,1024, "MT29F128G08CFABA ",0 ,
+        {
+            MICRON_8K, {0xEF,0xEE,0xFF,7,0x89,0,1,RTYPE_MICRON,{0x1, 0x14},{0x1, 0x5}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_MLC, {FALSE,FALSE,FALSE,FALSE, 0xFF, 0xFF,FALSE, 0xFF, 8, 0xFF}, false
+    },
+    {    {0xAD,0xD7,0x94,0x91,0x60,0x00}, 5,5,IO_8BIT,0x400000,2048,8192,640,0x10401011, 0xC03222,0x101,80,VEND_HYNIX,1024, "H27UBG8T2CTR",0 ,
+        {
+            HYNIX_8K, {0xFF,0xFF,0xFF,7,0xFF,0,1,RTYPE_HYNIX,{0xFF, 0xFF},{0xFF, 0xFF}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_MLC, {FALSE,FALSE,FALSE,FALSE, 0xFF, 0xFF,FALSE, 0xFF, 8, 0xFF}, false
+    },
+    {    {0x98,0xDE,0x94,0x93,0x76,0x00}, 5,5,IO_8BIT,0x800000,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_TOSHIBA,1024, "TC58TEG6DDKTA00",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0xFF,7,0xFF,7,0,RTYPE_TOSHIBA,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        },
+        NAND_FLASH_MLC, {FALSE,FALSE,FALSE,FALSE, 0xFF, 0xFF,FALSE, 0xFF, 8, 0xFF}, false
+    },
+};
+#else
+static const flashdev_info gen_FlashTable_p[]= {
+    {    {0x45,0xDE,0x94,0x93,0x76,0x57}, 6,5,IO_8BIT,8192,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_SANDISK,1024, "SDTNQGAMA008G ",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0xFF,16,0x11,0,1,RTYPE_SANDISK_19NM,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0x98,0xD7,0x84,0x93,0x72,0x00}, 5,5,IO_8BIT,4096,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_TOSHIBA,1024, "TC58TEG5DCKTA00",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0xFF,7,0xFF,7,0,RTYPE_TOSHIBA,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0x45,0xDE,0x94,0x93,0x76,0x00}, 5,5,IO_8BIT,8192,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_SANDISK,1024, "SDTNRGAMA008GK ",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0x5D,36,0x11,0,0xFFFFFFFF,RTYPE_SANDISK,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0xAD,0xDE,0x14,0xA7,0x42,0x00}, 5,5,IO_8BIT,8192,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_HYNIX,1024, "H27UCG8T2ETR",0 ,
+        {
+            SANDISK_16K, {0xFF,0xFF,0xFF,7,0xFF,0,1,RTYPE_HYNIX_16NM,{0xFF, 0xFF},{0xFF, 0xFF}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0x2C,0x44,0x44,0x4B,0xA9,0x00}, 5,5,IO_8BIT,4096,2048,8192,640,0x10401011, 0xC03222,0x101,80,VEND_MICRON,1024, "MT29F32G08CBADB ",0 ,
+        {
+            MICRON_8K, {0xEF,0xEE,0xFF,7,0x89,0,1,RTYPE_MICRON,{0x1, 0x14},{0x1, 0x5}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0xAD,0xDE,0x94,0xA7,0x42,0x00}, 5,5,IO_8BIT,8192,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_BIWIN,1024, "BW27UCG8T2ETR",0 ,
+        {
+            SANDISK_16K, {0xFF,0xFF,0xFF,7,0xFF,0,1,RTYPE_HYNIX_16NM,{0xFF, 0xFF},{0xFF, 0xFF}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0x45,0xD7,0x84,0x93,0x72,0x00}, 5,5,IO_8BIT,4096,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_SANDISK,1024, "SDTNRGAMA004GK ",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0x5D,36,0x11,0,0xFFFFFFFF,RTYPE_SANDISK,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0x2C,0x64,0x44,0x4B,0xA9,0x00}, 5,5,IO_8BIT,8192,2048,8192,640,0x10401011, 0xC03222,0x101,80,VEND_MICRON,1024, "MT29F128G08CFABA ",0 ,
+        {
+            MICRON_8K, {0xEF,0xEE,0xFF,7,0x89,0,1,RTYPE_MICRON,{0x1, 0x14},{0x1, 0x5}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0xAD,0xD7,0x94,0x91,0x60,0x00}, 5,5,IO_8BIT,4096,2048,8192,640,0x10401011, 0xC03222,0x101,80,VEND_HYNIX,1024, "H27UBG8T2CTR",0 ,
+        {
+            HYNIX_8K, {0xFF,0xFF,0xFF,7,0xFF,0,1,RTYPE_HYNIX,{0xFF, 0xFF},{0xFF, 0xFF}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0x98,0xDE,0x94,0x93,0x76,0x00}, 5,5,IO_8BIT,8192,4096,16384,1280,0x10401011, 0xC03222,0x101,80,VEND_TOSHIBA,1024, "TC58TEG6DDKTA00",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0xFF,7,0xFF,7,0,RTYPE_TOSHIBA,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0xC2,0xDC,0x90,0x95,0x56,0x00}, 5,5,IO_8BIT,512,128,2048,64,0x10401011, 0x10818011,0x101,80,VEND_MXIC,1024, "MX30LF4G18AC",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0xFF,7,0xFF,7,0,RTYPE_TOSHIBA,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0x98,0xDC,0x90,0x26,0x76,0x00}, 5,5,IO_8BIT,512,256,4096,256,0x10401011, 0x10818011,0x101,80,VEND_TOSHIBA,1024, "TC58NVG2S0HTA00",0 ,
+        {
+            SANDISK_16K, {0xEF,0xEE,0xFF,7,0xFF,7,0,RTYPE_TOSHIBA,{0x80, 0x00},{0x80, 0x01}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0x2C,0x38,0x00,0x26,0x85,0x00}, 5,5,IO_8BIT,1024,512,4096,224,0x10401011, 0x10818011,0x101,80,VEND_MICRON,1024, "MT29F8G08ABABA",0 ,
+        {
+            MICRON_8K, {0xEF,0xEE,0xFF,7,0x89,0,1,RTYPE_MICRON,{0x1, 0x14},{0x1, 0x5}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+    {    {0x2C,0xDA,0x90,0x95,0x06,0x00}, 5,5,IO_8BIT,256,128,2048,64,0x10401011, 0x10818011,0x101,80,VEND_MICRON,1024, "MT29F2G08ABAEA",0 ,
+        {
+            MICRON_8K, {0xEF,0xEE,0xFF,7,0x89,0,1,RTYPE_MICRON,{0x1, 0x14},{0x1, 0x5}},
+            {RAND_TYPE_SAMSUNG,{0x2D2D,1,1,1,1,1}}
+        }
+    },
+};
+#endif
+static unsigned int flash_number = sizeof(gen_FlashTable_p) / sizeof(flashdev_info);
+#endif
diff --git a/src/bsp/lk/platform/mt8518/include/platform/part.h b/src/bsp/lk/platform/mt8518/include/platform/part.h
new file mode 100644
index 0000000..5706e97
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/part.h
@@ -0,0 +1,89 @@
+/* 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 _PART_H
+#define _PART_H
+
+#include <sys/types.h>
+#include <stdint.h>
+
+
+typedef ulong lbaint_t; //Hong-Rong: Add for lk porting
+
+typedef struct block_dev_desc {
+    int     if_type;    /* type of the interface */
+    int     dev;        /* device number */
+    unsigned char   part_type;  /* partition type */
+    unsigned char   target;     /* target SCSI ID */
+    unsigned char   lun;        /* target LUN */
+    unsigned char   type;       /* device type */
+    unsigned char   removable;  /* removable device */
+#ifdef CONFIG_LBA48
+    unsigned char   lba48;      /* device can use 48bit addr (ATA/ATAPI v7) */
+#endif
+    lbaint_t        lba;        /* number of blocks */
+    unsigned long   blksz;      /* block size */
+#ifdef MTK_SPI_NOR_SUPPORT
+    unsigned long   blksz512;   /* block size 512 bytes */
+#endif
+    unsigned char   blk_bits;
+    unsigned char    part_boot1;
+    unsigned char    part_boot2;
+    unsigned char    part_user;
+    char        vendor [40+1];  /* IDE model, SCSI Vendor */
+    char        product[20+1];  /* IDE Serial no, SCSI product */
+    char        revision[8+1];  /* firmware revision */
+#if defined(PART_DEV_API_V2) || defined(PART_DEV_API_V3)
+    unsigned long   (*block_read)(int dev,
+                                  unsigned long start,
+                                  lbaint_t blkcnt,
+                                  void *buffer,
+                                  unsigned int part_id);
+    unsigned long   (*block_write)(int dev,
+                                   unsigned long start,
+                                   lbaint_t blkcnt,
+                                   const void *buffer,
+                                   unsigned int part_id);
+#elif defined PART_DEV_API_V1
+    unsigned long   (*block_read)(int dev,
+                    unsigned long start,
+                    lbaint_t blkcnt,
+                    void *buffer);
+    unsigned long   (*block_write)(int dev,
+                    unsigned long start,
+                    lbaint_t blkcnt,
+                    const void *buffer);
+#endif
+    void        *priv;      /* driver private struct pointer */
+} block_dev_desc_t;
+
+
+#endif /* _PART_H */
diff --git a/src/bsp/lk/platform/mt8518/include/platform/partition_define.h b/src/bsp/lk/platform/mt8518/include/platform/partition_define.h
new file mode 100644
index 0000000..de95bb6
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/partition_define.h
@@ -0,0 +1,142 @@
+/* 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) 2012. 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 __PARTITION_DEFINE_H__
+#define __PARTITION_DEFINE_H__
+
+
+
+
+#define KB  (1024ULL)
+#define MB  (1024 * KB)
+#define GB  (1024 * MB)
+
+#define PART_PRELOADER "PRELOADER"
+#define PART_MBR "MBR"
+#define PART_EBR1 "EBR1"
+#define PART_PRO_INFO "PRO_INFO"
+#define PART_NVRAM "NVRAM"
+#define PART_PROTECT_F "PROTECT_F"
+#define PART_PROTECT_S "PROTECT_S"
+#define PART_SECCFG "SECCFG"
+#define PART_UBOOT "UBOOT"
+#define PART_BOOTIMG "BOOTIMG"
+#define PART_RECOVERY "RECOVERY"
+#define PART_SEC_RO "SEC_RO"
+#define PART_MISC "MISC"
+#define PART_LOGO "LOGO"
+#define PART_EXPDB "EXPDB"
+#define PART_TEE1 "TEE1"
+#define PART_TEE2 "TEE2"
+#define PART_KB "KB"
+#define PART_DKB "DKB"
+#define PART_ANDROID "ANDROID"
+#define PART_CACHE "CACHE"
+#define PART_USRDATA "USRDATA"
+#define PART_BMTPOOL "BMTPOOL"
+/*preloader re-name*/
+#define PART_SECURE "SECURE"
+#define PART_SECSTATIC "SECSTATIC"
+#define PART_ANDSYSIMG "ANDSYSIMG"
+#define PART_USER "USER"
+#define PART_OTP  "OTP"
+/*Uboot re-name*/
+#define PART_APANIC "APANIC"
+
+#define PART_FLAG_NONE              0
+#define PART_FLAG_LEFT             0x1
+#define PART_FLAG_END              0x2
+#define PART_MAGIC              0x58881688
+
+#define PART_SIZE_PRELOADER         (256*KB)
+#define PART_SIZE_MBR           (512*KB)
+#define PART_SIZE_EBR1          (512*KB)
+#define PART_SIZE_PRO_INFO          (3072*KB)
+#define PART_SIZE_NVRAM         (5120*KB)
+#define PART_SIZE_PROTECT_F         (10240*KB)
+#define PART_SIZE_PROTECT_S         (10240*KB)
+#define PART_SIZE_SECCFG            (128*KB)
+#define PART_OFFSET_SECCFG          (0x1d00000)
+#define PART_SIZE_UBOOT         (384*KB)
+#define PART_SIZE_BOOTIMG           (16384*KB)
+#define PART_SIZE_RECOVERY          (16384*KB)
+#define PART_SIZE_SEC_RO            (6144*KB)
+#define PART_OFFSET_SEC_RO          (0x3d80000)
+#define PART_SIZE_MISC          (512*KB)
+#define PART_SIZE_LOGO          (3072*KB)
+#define PART_SIZE_EXPDB         (10240*KB)
+#define PART_SIZE_TEE1          (5120*KB)
+#define PART_SIZE_TEE2          (5120*KB)
+#define PART_SIZE_KB            (1024*KB)
+#define PART_SIZE_DKB           (1024*KB)
+#define PART_SIZE_ANDROID           (1048576*KB)
+#define PART_SIZE_CACHE         (129024*KB)
+#define PART_SIZE_USRDATA           (2097152*KB)
+#define PART_SIZE_BMTPOOL           (0)//(0xa8)
+#ifndef RAND_START_ADDR
+#define RAND_START_ADDR   1024
+#endif
+
+#define PART_NUM            23
+
+
+
+#define PART_MAX_COUNT           40
+
+#define MBR_START_ADDRESS_BYTE          (20480*KB)
+
+#define WRITE_SIZE_Byte     512
+typedef enum  {
+    EMMC = 1,
+    NAND = 2,
+} dev_type;
+
+typedef enum {
+    NAND_PART_UNKNOWN=0
+    ,NAND_PART_USER
+} NAND_Region;
+struct excel_info {
+    char * name;
+    unsigned long long size;
+    unsigned long long start_address;
+    dev_type type ;
+    unsigned int partition_idx;
+    NAND_Region region;
+};
+
+extern struct excel_info *PartInfo;
+
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/include/platform/platform_usb.h b/src/bsp/lk/platform/mt8518/include/platform/platform_usb.h
new file mode 100644
index 0000000..446dc9a
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/platform_usb.h
@@ -0,0 +1,11 @@
+#ifndef __PLATFORM_USB_H__
+#define __PLATFORM_USB_H__
+
+void platform_wdt_all_kick(void);
+void platform_wdt_kick(void);
+void platform_set_chrg_cur(int ma);
+void platform_vusb_on(void);
+bool platform_com_wait_forever_check(void);
+int pmic_detect_powerkey(void);
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/include/platform/pll.h b/src/bsp/lk/platform/mt8518/include/platform/pll.h
new file mode 100644
index 0000000..05f6569
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/pll.h
@@ -0,0 +1,248 @@
+/* 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 PLL_H
+#define PLL_H
+#include <platform/mt8518.h>
+#include <platform/mt_reg_base.h>
+
+#define CKSYS_BASE        	(IO_PHYS + 0x00000000)
+#define INFRACFG_AO_BASE	(IO_PHYS + 0x00001000)
+#define APMIXED_BASE      	(IO_PHYS + 0x00018000)
+#define MCUSYS_CONFIG_BASE	(IO_PHYS + 0x00200000)
+#define MMSYS_CONFIG_BASE 	(IO_PHYS + 0x04000000)
+
+/***********************/
+/* APMIXEDSYS Register */
+/***********************/
+#define AP_PLL_CON0          (APMIXED_BASE + 0x0000)
+#define AP_PLL_CON1          (APMIXED_BASE + 0x0004)
+#define AP_PLL_CON2          (APMIXED_BASE + 0x0008)
+#define AP_PLL_CON3          (APMIXED_BASE + 0x000C)
+#define AP_PLL_CON4          (APMIXED_BASE + 0x0010)
+#define PLL_HP_CON0          (APMIXED_BASE + 0x0014)
+#define PLL_HP_CON1          (APMIXED_BASE + 0x0018)
+#define CLKSQ_STB_CON0       (APMIXED_BASE + 0x001C)
+#define PLL_PWR_CON0         (APMIXED_BASE + 0x0020)
+#define PLL_PWR_CON1         (APMIXED_BASE + 0x0024)
+#define PLL_PWR_CON2         (APMIXED_BASE + 0x0028)
+#define PLL_PWR_CON3         (APMIXED_BASE + 0x002C)
+#define PLL_PWR_CON4         (APMIXED_BASE + 0x0070)
+#define PLL_PWR_CON5         (APMIXED_BASE + 0x0074)
+#define PLL_PWR_CON6         (APMIXED_BASE + 0x0078)
+#define PLL_PWR_CON7         (APMIXED_BASE + 0x007C)
+#define PLL_ISO_CON0         (APMIXED_BASE + 0x0030)
+#define PLL_ISO_CON1         (APMIXED_BASE + 0x0034)
+#define PLL_ISO_CON2         (APMIXED_BASE + 0x0038)
+#define PLL_ISO_CON3         (APMIXED_BASE + 0x003C)
+#define PLL_ISO_CON4         (APMIXED_BASE + 0x0080)
+#define PLL_ISO_CON5         (APMIXED_BASE + 0x0084)
+#define PLL_ISO_CON6         (APMIXED_BASE + 0x0088)
+#define PLL_ISO_CON7         (APMIXED_BASE + 0x008C)
+#define PLL_EN_CON0          (APMIXED_BASE + 0x0040)
+#define PLL_EN_CON1          (APMIXED_BASE + 0x0044)
+#define PLL_EN_CON2          (APMIXED_BASE + 0x0090)
+#define PLL_EN_CON3          (APMIXED_BASE + 0x0094)
+#define PLL_STB_CON0         (APMIXED_BASE + 0x0048)
+#define PLL_STB_CON1         (APMIXED_BASE + 0x004C)
+#define PLL_STB_CON2         (APMIXED_BASE + 0x0050)
+#define PLL_STB_CON3         (APMIXED_BASE + 0x0098)
+#define PLL_STB_CON4         (APMIXED_BASE + 0x009C)
+#define PLL_STB_CON5         (APMIXED_BASE + 0x00A0)
+#define DIV_STB_CON0         (APMIXED_BASE + 0x0054)
+#define PLL_CHG_CON0         (APMIXED_BASE + 0x0058)
+#define PLL_CHG_CON1         (APMIXED_BASE + 0x005C)
+#define PLL_CHG_CON2         (APMIXED_BASE + 0x00A4)
+#define PLL_CHG_CON3         (APMIXED_BASE + 0x00A8)
+#define PLL_TEST_CON0        (APMIXED_BASE + 0x0060)
+#define PLL_TEST_CON1        (APMIXED_BASE + 0x0064)
+#define PLL_INT_CON0         (APMIXED_BASE + 0x0068)
+#define PLL_INT_CON1         (APMIXED_BASE + 0x006C)
+#define XTAL_CON0            (APMIXED_BASE + 0x00D0)
+#define ARMPLL_CON0          (APMIXED_BASE + 0x0100)
+#define ARMPLL_CON1          (APMIXED_BASE + 0x0104)
+#define ARMPLL_CON2          (APMIXED_BASE + 0x0108)
+#define ARMPLL_CON3          (APMIXED_BASE + 0x010C)
+#define ARMPLL_PWR_CON0      (APMIXED_BASE + 0x0110)
+#define MAINPLL_CON0         (APMIXED_BASE + 0x0120)
+#define MAINPLL_CON1         (APMIXED_BASE + 0x0124)
+#define MAINPLL_CON2         (APMIXED_BASE + 0x0128)
+#define MAINPLL_CON3         (APMIXED_BASE + 0x012C)
+#define MAINPLL_PWR_CON0     (APMIXED_BASE + 0x0130)
+#define UNIVPLL_CON0         (APMIXED_BASE + 0x0140)
+#define UNIVPLL_CON1         (APMIXED_BASE + 0x0144)
+#define UNIVPLL_CON2         (APMIXED_BASE + 0x0148)
+#define UNIVPLL_CON3         (APMIXED_BASE + 0x014C)
+#define UNIVPLL_PWR_CON0     (APMIXED_BASE + 0x0150)
+#define MMPLL_CON0           (APMIXED_BASE + 0x0160)
+#define MMPLL_CON1           (APMIXED_BASE + 0x0164)
+#define MMPLL_CON2           (APMIXED_BASE + 0x0168)
+#define MMPLL_CON3           (APMIXED_BASE + 0x016C)
+#define MMPLL_PWR_CON0       (APMIXED_BASE + 0x0170)
+#define APLL1_CON0           (APMIXED_BASE + 0x0180)
+#define APLL1_CON1           (APMIXED_BASE + 0x0184)
+#define APLL1_CON2           (APMIXED_BASE + 0x0188)
+#define APLL1_CON3           (APMIXED_BASE + 0x018C)
+#define APLL1_PWR_CON0       (APMIXED_BASE + 0x0190)
+#define APLL1_CON_TUNER      (APMIXED_BASE + 0x0194)
+#define APLL2_CON0           (APMIXED_BASE + 0x01A0)
+#define APLL2_CON1           (APMIXED_BASE + 0x01A4)
+#define APLL2_CON2           (APMIXED_BASE + 0x01A8)
+#define APLL2_CON3           (APMIXED_BASE + 0x01AC)
+#define APLL2_PWR_CON0       (APMIXED_BASE + 0x01B0)
+#define APLL2_CON_TUNER      (APMIXED_BASE + 0x01B4)
+#define TVDPLL_CON0          (APMIXED_BASE + 0x01C0)
+#define TVDPLL_CON1          (APMIXED_BASE + 0x01C4)
+#define TVDPLL_CON2          (APMIXED_BASE + 0x01C8)
+#define TVDPLL_CON3          (APMIXED_BASE + 0x01CC)
+#define TVDPLL_PWR_CON0      (APMIXED_BASE + 0x01D0)
+#define AP_AUXADC_CON0       (APMIXED_BASE + 0x0400)
+#define TS_CON0              (APMIXED_BASE + 0x0600)
+#define TS_CON1              (APMIXED_BASE + 0x0604)
+#define AP_ABIST_MON_CON0    (APMIXED_BASE + 0x0E00)
+#define AP_ABIST_MON_CON1    (APMIXED_BASE + 0x0E04)
+#define AP_ABIST_MON_CON2    (APMIXED_BASE + 0x0E08)
+#define AP_ABIST_MON_CON3    (APMIXED_BASE + 0x0E0C)
+#define OCCSCAN_CON0         (APMIXED_BASE + 0x0E1C)
+#define CLKDIV_CON0          (APMIXED_BASE + 0x0E20)
+#define RSV_RW0_CON0         (APMIXED_BASE + 0x0B00)
+#define RSV_RW0_CON1         (APMIXED_BASE + 0x0B04)
+#define RSV_RW1_CON0         (APMIXED_BASE + 0x0B08)
+#define RSV_RW1_CON1         (APMIXED_BASE + 0x0B0C)
+#define RSV_RO_CON0          (APMIXED_BASE + 0x0B10)
+#define RSV_RO_CON1          (APMIXED_BASE + 0x0B14)
+#define RSV_ATPG_CON0        (APMIXED_BASE + 0x0B18)
+#define ZCD_RO_CON0          (APMIXED_BASE + 0x0C00)
+#define ANA_FIFO_RO_CON0     (APMIXED_BASE + 0x0C10)
+
+/***********************/
+/* TOPCKGEN Register   */
+/***********************/
+#define CLK_MUX_SEL0           (CKSYS_BASE + 0x000)
+#define CLK_MUX_SEL1           (CKSYS_BASE + 0x004)
+#define TOPBUS_DCMCTL          (CKSYS_BASE + 0x008)
+#define TOPEMI_DCMCTL          (CKSYS_BASE + 0x00C)
+#define FREQ_MTR_CTRL          (CKSYS_BASE + 0x010)
+#define FREQ_MTR_DAT           (CKSYS_BASE + 0x014)
+#define CLK_GATING_CTRL0       (CKSYS_BASE + 0x020)
+#define CLK_GATING_CTRL1       (CKSYS_BASE + 0x024)
+#define INFRABUS_DCMCTL0       (CKSYS_BASE + 0x028)
+#define INFRABUS_DCMCTL1       (CKSYS_BASE + 0x02C)
+#define MPLL_FREDIV_EN         (CKSYS_BASE + 0x030)
+#define UPLL_FREDIV_EN         (CKSYS_BASE + 0x034)
+#define TEST_DBG_CTRL          (CKSYS_BASE + 0x038)
+#define CLK_GATING_CTRL7       (CKSYS_BASE + 0x03C)
+#define CLK_MUX_SEL8           (CKSYS_BASE + 0x040)
+#define CLK_SEL_9              (CKSYS_BASE + 0x044)
+#define CLK_SEL_10             (CKSYS_BASE + 0x048)
+#define CLK_SEL_11             (CKSYS_BASE + 0x04C)
+#define CLK_GATING_CTRL0_SET   (CKSYS_BASE + 0x050)
+#define CLK_GATING_CTRL1_SET   (CKSYS_BASE + 0x054)
+#define INFRABUS_DCMCTL0_SET   (CKSYS_BASE + 0x058)
+#define INFRABUS_DCMCTL1_SET   (CKSYS_BASE + 0x05C)
+#define SET_MPLL_FREDIV_EN     (CKSYS_BASE + 0x060)
+#define SET_UPLL_FREDIV_EN     (CKSYS_BASE + 0x064)
+#define TEST_DBG_CTRL_SET      (CKSYS_BASE + 0x068)
+#define CLK_GATING_CTRL7_SET   (CKSYS_BASE + 0x06C)
+#define CLK_GATING_CTRL8       (CKSYS_BASE + 0x070)
+#define CLK_GATING_CTRL9       (CKSYS_BASE + 0x074)
+#define CLK_SEL_12             (CKSYS_BASE + 0x078)
+#define CLK_MUX_SEL13          (CKSYS_BASE + 0x07c)
+#define CLK_GATING_CTRL0_CLR   (CKSYS_BASE + 0x080)
+#define CLK_GATING_CTRL1_CLR   (CKSYS_BASE + 0x084)
+#define INFRABUS_DCMCTL0_CLR   (CKSYS_BASE + 0x088)
+#define INFRABUS_DCMCTL1_CLR   (CKSYS_BASE + 0x08C)
+#define CLR_MPLL_FREDIV_EN     (CKSYS_BASE + 0x090)
+#define CLR_UPLL_FREDIV_EN     (CKSYS_BASE + 0x094)
+#define TEST_DBG_CTRL_CLR      (CKSYS_BASE + 0x098)
+#define CLK_GATING_CTRL7_CLR   (CKSYS_BASE + 0x09C)
+#define CLK_GATING_CTRL8_SET   (CKSYS_BASE + 0x0A0)
+#define SET_CLK_GATING_CTRL9   (CKSYS_BASE + 0x0A4)
+#define CLK_GATING_CTRL8_CLR   (CKSYS_BASE + 0x0B0)
+#define CLR_CLK_GATING_CTRL9   (CKSYS_BASE + 0x0B4)
+#define CLK_MUX_SEL14          (CKSYS_BASE + 0x0c0)
+#define CLK_MUX_SEL15          (CKSYS_BASE + 0x0c4)
+#define CLK_MUX_SEL16          (CKSYS_BASE + 0x0c8)
+#define CLK_MUX_SEL17          (CKSYS_BASE + 0x0cc)
+#define CLK_MUX_SEL19          (CKSYS_BASE + 0x0d4)
+#define CLK_MUX_SEL20          (CKSYS_BASE + 0x0d8)
+#define CLK_MUX_SEL21          (CKSYS_BASE + 0x0dc)
+#define CLK_GATING_CTRL10      (CKSYS_BASE + 0x0e0)
+#define CLK_GATING_CTRL11      (CKSYS_BASE + 0x0e4)
+#define CLK_GATING_CTRL12      (CKSYS_BASE + 0x0e8)
+#define CLK_GATING_CTRL13      (CKSYS_BASE + 0x0ec)
+#define CLK_MUX_SEL22          (CKSYS_BASE + 0x0f4)
+#define CLK_MUX_SEL23          (CKSYS_BASE + 0x0f8)
+#define LPM_CTRL               (CKSYS_BASE + 0x100)
+#define LPM_TOTAL_TIME         (CKSYS_BASE + 0x104)
+#define LPM_LOW2HIGH_COUNT     (CKSYS_BASE + 0x108)
+#define LPM_HIGH_DUR_TIME      (CKSYS_BASE + 0x10C)
+#define LPM_LONGEST_HIGHTIME   (CKSYS_BASE + 0x110)
+#define LPM_GOODDUR_COUNT      (CKSYS_BASE + 0x114)
+#define CLK_GATING_CTRL10_SET  (CKSYS_BASE + 0x120)
+#define CLK_GATING_CTRL12_SET  (CKSYS_BASE + 0x128)
+#define CLK_GATING_CTRL13_SET  (CKSYS_BASE + 0x12c)
+#define CLK_GATING_CTRL10_CLR  (CKSYS_BASE + 0x140)
+#define CLK_GATING_CTRL12_CLR  (CKSYS_BASE + 0x148)
+#define CLK_GATING_CTRL13_CLR  (CKSYS_BASE + 0x14c)
+
+/***********************/
+/* INFRASYS Register   */
+/***********************/
+#define INFRA_CLKSEL            (INFRACFG_AO_BASE + 0x80)
+#define TOPAXI_PROT_EN          (INFRACFG_AO_BASE + 0x220)
+#define TOPAXI_PROT_STA0        (INFRACFG_AO_BASE + 0x224)
+#define TOPAXI_PROT_STA1        (INFRACFG_AO_BASE + 0x228)
+
+/***********************/
+/* MMSYS Register      */
+/***********************/
+#define MMSYS_CG_CON0		(MMSYS_CONFIG_BASE + 0x100)
+#define MMSYS_HW_DCM_DIS0		(MMSYS_CONFIG_BASE + 0x120)
+
+/***********************/
+/* MCUSYS Register      */
+/***********************/
+#define ACLKEN_DIV          	(MCUSYS_CONFIG_BASE + 0x640)
+#define PCLKEN_DIV          	(MCUSYS_CONFIG_BASE + 0x644)
+#define MCU_BUS_MUX             (MCUSYS_CONFIG_BASE + 0x7C0)
+
+void mt_pll_init(void);
+void mt_pll_post_init(void);
+//====================================================
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/include/platform/pmic.h b/src/bsp/lk/platform/mt8518/include/platform/pmic.h
new file mode 100644
index 0000000..76537fe
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/pmic.h
@@ -0,0 +1,43 @@
+
+#ifndef _PL_MT_PMIC_H_
+#define _PL_MT_PMIC_H_
+
+//==============================================================================
+// PMIC define
+//==============================================================================
+#define PMIC6391_E1_CID_CODE    0x1091
+#define PMIC6391_E2_CID_CODE    0x2091
+#define PMIC6391_E3_CID_CODE    0x3091
+#define PMIC6397_E1_CID_CODE    0x1097
+#define PMIC6397_E2_CID_CODE    0x2097
+#define PMIC6397_E3_CID_CODE    0x3097
+#define PMIC6397_E4_CID_CODE    0x4097
+
+typedef enum {
+    CHARGER_UNKNOWN = 0,
+    STANDARD_HOST,
+    CHARGING_HOST,
+    NONSTANDARD_CHARGER,
+    STANDARD_CHARGER,
+} CHARGER_TYPE;
+
+//==============================================================================
+// PMIC Status Code
+//==============================================================================
+#define PMIC_TEST_PASS               0x0000
+#define PMIC_TEST_FAIL               0xB001
+#define PMIC_EXCEED_I2C_FIFO_LENGTH  0xB002
+#define PMIC_CHRDET_EXIST            0xB003
+#define PMIC_CHRDET_NOT_EXIST        0xB004
+
+//==============================================================================
+// PMIC Exported Function
+//==============================================================================
+extern CHARGER_TYPE mt_charger_type_detection(void);
+extern int pmic_detect_powerkey(void);
+extern u32 pmic_read_interface (u32 RegNum, u32 *val, u32 MASK, u32 SHIFT);
+extern u32 pmic_config_interface (u32 RegNum, u32 val, u32 MASK, u32 SHIFT);
+extern u32 pmic_init (void);
+
+#endif // _PL_MT_PMIC_H_
+
diff --git a/src/bsp/lk/platform/mt8518/include/platform/pmic_6395.h b/src/bsp/lk/platform/mt8518/include/platform/pmic_6395.h
new file mode 100644
index 0000000..2053d1b
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/pmic_6395.h
@@ -0,0 +1,11 @@
+#ifndef _mt6395_SW_H_

+#define _mt6395_SW_H_

+

+//---------------------- EXPORT API ---------------------------

+extern u32 pmic_read_interface (u8 RegNum, u8 *val, u8 MASK, u8 SHIFT);

+extern u32 pmic_config_interface (u8 RegNum, u8 val, u8 MASK, u8 SHIFT);

+extern void pmic_init_mt6395 (void);

+extern int pmic_detect_powerkey(void);

+

+#endif

+

diff --git a/src/bsp/lk/platform/mt8518/include/platform/pmic_wrap_init.h b/src/bsp/lk/platform/mt8518/include/platform/pmic_wrap_init.h
new file mode 100644
index 0000000..28a1d1f
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/pmic_wrap_init.h
@@ -0,0 +1,266 @@
+#ifndef SOC_MEDIATEK_MT8518_PMIC_WRAP_H
+#define SOC_MEDIATEK_MT8518_PMIC_WRAP_H
+
+#include <platform/pll.h>
+#include <platform/mt8518.h>
+#include <platform/mt_reg_base.h>
+
+/* external API */
+s32 pwrap_read(u32 adr, u32 *rdata);
+s32 pwrap_write(u32 adr, u32 wdata);
+s32 pwrap_wacs2(u32 write, u32 adr, u32 wdata, u32 *rdata);
+s32 pwrap_init_preloader(void);
+
+#define read32(addr)		readl(addr)
+#define write32(addr,val)	writel((val), (addr))
+
+#define MUDI
+
+#define MODULE_SW_CG_1_SET	(CKSYS_BASE+0x054)
+#define MODULE_SW_CG_1_CLR	(CKSYS_BASE+0x084)
+
+#define MODULE_SW_WDT_RST	(INFRACFG_AO_BASE+0x02C)
+
+#define PWRAP_CG_TMR	(1 << 27)
+#define PWRAP_CG_SPI	(1 << 28)
+#define PWRAP_CG_SYS	(1 << 29)
+
+#define PMIC_B_DCM_EN	(1 << 1)
+#define PMIC_SPI_DCM_EN	(1 << 2)
+
+#define CLK_CFG_5_CLR		(CKSYS_BASE+0x098)
+#define CLK_SPI_CK_26M		0x1
+
+#define PWRAP_BASE          (IO_PHYS + 0xF000)
+#define PMIC_WRAP_BASE		(PWRAP_BASE)//0x1000F000
+static struct MT8518_pwrap_regs * const mt8518_pwrap = (void *)PMIC_WRAP_BASE;
+
+enum {
+	WACS2 = 1 << 3
+};
+
+/* timeout setting */
+enum {
+	TIMEOUT_READ_US        = 255,
+	TIMEOUT_WAIT_IDLE_US   = 255
+};
+
+/* PMIC_WRAP registers */
+struct MT8518_pwrap_regs {
+	u32 mux_sel;
+	u32 wrap_en;
+	u32 dio_en;
+	u32 sidly;
+	u32 rddmy;
+	u32 si_ck_con;
+	u32 cshext_write;
+	u32 cshext_read;
+	u32 cslext_start;
+	u32 cslext_end;
+	u32 staupd_prd;
+	u32 staupd_grpen;
+	u32 reserved[4];
+	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 man_en;
+	u32 man_cmd;
+	u32 man_rdata;
+	u32 man_vldclr;
+	u32 wacs0_en;
+	u32 init_done0;
+	u32 wacs0_cmd;
+	u32 wacs0_rdata;
+	u32 wacs0_vldclr;
+	u32 wacs1_en;
+	u32 init_done1;
+	u32 wacs1_cmd;
+	u32 wacs1_rdata;
+	u32 wacs1_vldclr;
+	u32 wacs2_en;
+	u32 init_done2;
+	u32 wacs2_cmd;
+	u32 wacs2_rdata;
+	u32 wacs2_vldclr;
+	u32 int_en;
+	u32 int_flg_raw;
+	u32 int_flg;
+	u32 int_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;
+	u32 wdt_flg;
+	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 spminf_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 ext_ck;
+	u32 adc_cmd_addr;
+	u32 adc_cmd;
+	u32 adc_rdy_addr;
+	u32 adc_rdata_addr1;
+	u32 adc_rdata_addr2;
+	u32 gps_sta;
+	u32 swrst;
+	u32 op_type;
+	u32 msb_first;
+};
+
+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
+};
+
+#define DEW_BASE  (0xBC00)
+//-------macro for pmic register--------------------------------
+#define PMIC_BASE (0x0000)
+#define PMIC_WRP_CKPDN            (PMIC_BASE+0x011A) //0x0056
+#define PMIC_WRP_RST_CON          (PMIC_BASE+0x0120)//0x005C
+#define PMIC_TOP_CKCON2           (PMIC_BASE+0x012A)
+#define PMIC_TOP_CKCON3           (PMIC_BASE+0x01D4)
+//-----macro for dewrapper regsister--------------------------------------------------------
+#define DEW_EVENT_OUT_EN   (DEW_BASE+0x0)
+#define DEW_DIO_EN         (DEW_BASE+0x2)
+#define DEW_EVENT_SRC_EN   (DEW_BASE+0x4)
+#define DEW_EVENT_SRC      (DEW_BASE+0x6)
+#define DEW_EVENT_FLAG     (DEW_BASE+0x8)
+#define DEW_READ_TEST      (DEW_BASE+0xA)
+#define DEW_WRITE_TEST     (DEW_BASE+0xC)
+#define DEW_CRC_EN         (DEW_BASE+0xE)
+#define DEW_CRC_VAL        (DEW_BASE+0x10)
+#define DEW_MON_GRP_SEL    (DEW_BASE+0x12)
+#define DEW_MON_FLAG_SEL   (DEW_BASE+0x14)
+#define DEW_EVENT_TEST     (DEW_BASE+0x16)
+#define DEW_CIPHER_KEY_SEL (DEW_BASE+0x18)
+#define DEW_CIPHER_IV_SEL  (DEW_BASE+0x1A)
+#define DEW_CIPHER_LOAD    (DEW_BASE+0x1C)
+#define DEW_CIPHER_START   (DEW_BASE+0x1E)
+#define DEW_CIPHER_RDY     (DEW_BASE+0x20)
+#define DEW_CIPHER_MODE    (DEW_BASE+0x22)
+#define DEW_CIPHER_SWRST   (DEW_BASE+0x24)
+#define DEW_CIPHER_IV0     (DEW_BASE+0x26)
+#define DEW_CIPHER_IV1     (DEW_BASE+0x28)
+#define DEW_CIPHER_IV2     (DEW_BASE+0x2A)
+#define DEW_CIPHER_IV3     (DEW_BASE+0x2C)
+#define DEW_CIPHER_IV4     (DEW_BASE+0x2E)
+#define DEW_CIPHER_IV5     (DEW_BASE+0x30)
+
+/* dewrapper defaule value */
+enum {
+	DEFAULT_VALUE_READ_TEST  = 0x5aa5,
+	WRITE_TEST_VALUE         = 0xa55a
+};
+
+enum pmic_regck {
+	REG_CLOCK_SAFE_MODE,
+	REG_CLOCK_12MHZ,
+	REG_CLOCK_24MHZ
+};
+
+/* manual commnd */
+enum {
+	OP_WR    = 0x1,
+	OP_CSH   = 0x0,
+	OP_CSL   = 0x1,
+	OP_OUTS  = 0x8,
+	OP_OUTD  = 0x9,
+	OP_INS   = 0xC,
+	OP_IND   = 0xE
+};
+
+/* 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,
+	E_PWR_INVALID_DATA            = 33
+};
+
+/* external API */
+extern s32 pwrap_read(u32 adr, u32 *rdata);
+extern s32 pwrap_write(u32 adr, u32 wdata);
+extern s32 pwrap_wacs2(u32 write, u32 adr, u32 wdata, u32 *rdata);
+extern s32 pwrap_init(void);
+
+#endif /* SOC_MEDIATEK_MT8518_PMIC_WRAP_H */
diff --git a/src/bsp/lk/platform/mt8518/include/platform/pwm-buck.h b/src/bsp/lk/platform/mt8518/include/platform/pwm-buck.h
new file mode 100644
index 0000000..79d9e7d
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/pwm-buck.h
@@ -0,0 +1,32 @@
+#ifndef _pwm_buck_SW_H_

+#define _pwm_buck_SW_H_

+

+struct pwm_volt_map {

+	unsigned int volt;

+	unsigned int duty_cycle;

+};

+

+#define PWM_VOLT_MAP struct pwm_volt_map

+

+struct pwm_buck {

+	unsigned int pwm_period;

+	unsigned int n_table;

+	struct pwm_volt_map *table;

+	unsigned int pwm_gpio;

+};

+

+#define BUCK_OK			0

+#define BUCK_EINVAL		22

+

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

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

+

+//---------------------- EXPORT API ---------------------------

+extern int regulator_get_voltage(void);

+extern int regulator_set_voltage(unsigned int volt);

+extern int regulator_is_enabled(void);

+extern int regulator_enable(int enable);

+extern int pwm_buck_init(void);

+

+#endif

+

diff --git a/src/bsp/lk/platform/mt8518/include/platform/pwm.h b/src/bsp/lk/platform/mt8518/include/platform/pwm.h
new file mode 100644
index 0000000..5904ce3
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/pwm.h
@@ -0,0 +1,54 @@
+#ifndef _PWM_H_
+#define _PWM_H_
+
+/*
+  pwm_no: 0/1/2/3
+  freq:   eg: 32K: 32000
+  returns: 0 means successful, < 0 means failed.
+*/
+extern int pwm_config_freq(int pwm_no, int freq);
+
+/*
+  pwm_no: 0/1/2/3
+  returns: >= 0 means successfully, return value is period, < 0 means failed.
+*/
+extern int pwm_get_period(int pwm_no);
+
+/*
+  pwm_no: 0/1/2/3
+  returns: >= 0 means successful, return value is duty, < 0 means failed.
+*/
+extern int pwm_get_duty_cycle(int pwm_no);
+
+/*
+  pwm_no: 0/1/2/3
+  returns:  0 means successful, < 0 means failed.
+*/
+extern int pwm_set_duty(int pwm_no, int duty);
+
+/*
+  pwm_no: 0/1/2/3
+  returns:  0 means successful, < 0 means failed.
+*/
+extern int pwm_enable(int pwm_no);
+
+
+/*
+  pwm_no: 0/1/2/3
+  returns:  0 means successful, < 0 means failed.
+*/
+extern int pwm_disable(int pwm_no);
+
+/*
+  pwm_no: 0/1/2/3
+  returns:   >= 0 means successful, return value is the wave numbers already been sent, < 0 means failed.
+*/
+int pwm_get_send_wavenums(int pwm_no);
+
+void pwm_dump(int pwm_no);
+void pwm_dump_all(void);
+
+extern void pwm_init (void);
+
+#endif
+
diff --git a/src/bsp/lk/platform/mt8518/include/platform/pwm_buck_property.h b/src/bsp/lk/platform/mt8518/include/platform/pwm_buck_property.h
new file mode 100644
index 0000000..c8fac15
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/pwm_buck_property.h
@@ -0,0 +1,37 @@
+#ifndef _pwm_buck_property_SW_H_

+#define _pwm_buck_property_SW_H_

+

+#include <platform/pwm-buck.h>

+#include <platform/mt_reg_base.h>

+

+#define PWM_1V8	1

+

+#define PWM_NUM_VCORE	0

+

+#define GPIO_VCORE_BASE (IO_PHYS+0x00005350)

+#define GPIO_VCORE_PWM_OFFSET 9

+#define GPIO_VCORE_PWM_MODE 0x2

+

+/*define pwm period or frequency*/

+#define PWM_PERIOD_INIT	32000

+

+#if defined(PWM_3V3)

+PWM_VOLT_MAP vcore_map[] = {

+	{700000, 93},

+	{800000, 65},

+	{900000, 35},

+	{1000000, 0},

+};

+#endif

+

+#if defined(PWM_1V8)

+PWM_VOLT_MAP vcore_map[] = {

+	{700000, 84},

+	{800000, 58},

+	{900000, 31},

+	{1000000, 0},

+};

+#endif

+

+#endif

+

diff --git a/src/bsp/lk/platform/mt8518/include/platform/reg_emi_reg.h b/src/bsp/lk/platform/mt8518/include/platform/reg_emi_reg.h
new file mode 100644
index 0000000..21fd4bb
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/reg_emi_reg.h
@@ -0,0 +1,1451 @@
+/* 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 ("Media Tek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+ #ifndef __EMI_REG_REGS_H__
+#define __EMI_REG_REGS_H__
+
+/* ----------------- Register Definitions ------------------- */
+#define EMI_CONA					0x00000000
+	#define EMI_CONA_DW32_EN			BIT(1)
+	#define EMI_CONA_CHN_POS			GENMASK(3, 2)
+	#define EMI_CONA_COL				GENMASK(5, 4)
+	#define EMI_CONA_COL2ND				GENMASK(7, 6)
+	#define EMI_CONA_CHN_EN				GENMASK(9, 8)
+	#define EMI_CONA_CHN_LOC			GENMASK(11, 10)
+	#define EMI_CONA_ROW				GENMASK(13, 12)
+	#define EMI_CONA_ROW2ND				GENMASK(15, 14)
+	#define EMI_CONA_DUAL_RANK_EN_CHN1		BIT(16)
+	#define EMI_CONA_DUAL_RANK_EN			BIT(17)
+	#define EMI_CONA_CHN1_COL			GENMASK(21, 20)
+	#define EMI_CONA_CHN1_COL2ND			GENMASK(23, 22)
+	#define EMI_CONA_ROW_EXT0			BIT(24)
+	#define EMI_CONA_ROW2ND_EXT0			BIT(25)
+	#define EMI_CONA_RANK_POS			BIT(27)
+	#define EMI_CONA_CHN1_ROW			GENMASK(29, 28)
+	#define EMI_CONA_CHN1_ROW2ND			GENMASK(31, 30)
+#define EMI_CONB					0x00000008
+	#define EMI_CONB_ONE				GENMASK(7, 0)
+	#define EMI_CONB_TWO				GENMASK(15, 8)
+	#define EMI_CONB_THREE				GENMASK(23, 16)
+	#define EMI_CONB_FOUR				GENMASK(31, 24)
+#define EMI_CONC					0x00000010
+	#define EMI_CONC_FIVE				GENMASK(7, 0)
+	#define EMI_CONC_SIX				GENMASK(15, 8)
+	#define EMI_CONC_SEVEN				GENMASK(23, 16)
+	#define EMI_CONC_EIGHT				GENMASK(31, 24)
+#define EMI_COND					0x00000018
+	#define EMI_COND_RFF_EMPTY_LOW			GENMASK(3, 0)
+	#define EMI_COND_RFF_EMPTY_HIGH			GENMASK(7, 4)
+	#define EMI_COND_WFF_EMPTY_LOW			GENMASK(11, 8)
+	#define EMI_COND_WFF_EMPTY_HIGH			GENMASK(15, 12)
+	#define EMI_COND_RFF_BUSY_LOW			GENMASK(19, 16)
+	#define EMI_COND_RFF_BUSY_HIGH			GENMASK(23, 20)
+	#define EMI_COND_WFF_BUSY_LOW			GENMASK(27, 24)
+	#define EMI_COND_WFF_BUSY_HIGH			GENMASK(31, 28)
+#define EMI_CONE					0x00000020
+	#define EMI_CONE_RCMD_LO_THR			GENMASK(3, 1)
+	#define EMI_CONE_RCMD_OO_THR			GENMASK(7, 4)
+	#define EMI_CONE_AP_BUSY_THR			GENMASK(11, 8)
+	#define EMI_CONE_AFF_GATED_DLY			GENMASK(14, 12)
+	#define EMI_CONE_AFF_ASYNC_HALF_EN		BIT(15)
+	#define EMI_CONE_AP_BUSY_RD_LAT			GENMASK(23, 16)
+	#define EMI_CONE_AP_BUSY_WR_LAT			GENMASK(31, 24)
+#define EMI_CONF					0x00000028
+#define EMI_CONG					0x00000030
+	#define EMI_CONG_TWO				GENMASK(7, 0)
+	#define EMI_CONG_FOUR				GENMASK(15, 8)
+	#define EMI_CONG_SIX				GENMASK(23, 16)
+	#define EMI_CONG_EIGHT				GENMASK(31, 24)
+#define EMI_CONH					0x00000038
+	#define EMI_CONH_CHN1_ROW_EXT0			BIT(4)
+	#define EMI_CONH_CHN1_ROW2ND_EXT0		BIT(5)
+	#define EMI_CONH_CHNAB_RANK0_SIZE		GENMASK(19, 16)
+	#define EMI_CONH_CHNAB_RANK1_SIZE		GENMASK(23, 20)
+	#define EMI_CONH_CHNCD_RANK0_SIZE		GENMASK(27, 24)
+	#define EMI_CONH_CHNCD_RANK1_SIZE		GENMASK(31, 28)
+#define EMI_CONM					0x00000060
+	#define EMI_CONM_PAGE_HIT_HIGH_PRIO_M0		BIT(0)
+	#define EMI_CONM_PAGE_HIT_HIGH_PRIO_M1		BIT(1)
+	#define EMI_CONM_PAGE_HIT_HIGH_PRIO_M2		BIT(2)
+	#define EMI_CONM_PAGE_HIT_HIGH_PRIO_M3		BIT(3)
+	#define EMI_CONM_PAGE_HIT_HIGH_PRIO_M4		BIT(4)
+	#define EMI_CONM_PAGE_HIT_HIGH_PRIO_M5		BIT(5)
+	#define EMI_CONM_PAGE_HIT_HIGH_PRIO_M6		BIT(6)
+	#define EMI_CONM_PAGE_HIT_HIGH_PRIO_M7		BIT(7)
+	#define EMI_CONM_AGE_SPEED			GENMASK(9, 8)
+	#define EMI_CONM_EMI_ENABLE			BIT(10)
+#define EMI_CONN					0x00000068
+	#define EMI_CONN_CH0_AFF_SLEEP_PRO		BIT(4)
+	#define EMI_CONN_CH1_AFF_SLEEP_PRO		BIT(5)
+	#define EMI_CONN_CH2_AFF_SLEEP_PRO		BIT(6)
+	#define EMI_CONN_CH3_AFF_SLEEP_PRO		BIT(7)
+	#define EMI_CONN_RCF_CNDT_CMPRSR_ACT		BIT(20)
+	#define EMI_CONN_CEN_BSEC_ACT			BIT(21)
+#define EMI_MDCT					0x00000078
+	#define EMI_MDCT_R_A_ULT_EN			BIT(0)
+	#define EMI_MDCT_W_A_ULT_EN			BIT(1)
+	#define EMI_MDCT_W_S_ULT_EN			BIT(3)
+	#define EMI_MDCT_W_S_AGE_EN			BIT(5)
+	#define EMI_MDCT_SBR_WRAP_MODE			BIT(15)
+	#define EMI_MDCT_RD_ULTRA_RSV_NUM		GENMASK(18, 16)
+	#define EMI_MDCT_WR_ULTRA_RSV_NUM		GENMASK(22, 20)
+	#define EMI_MDCT_RD_AP_RSV_NUM			GENMASK(26, 24)
+	#define EMI_MDCT_WR_AP_RSV_NUM			GENMASK(30, 28)
+#define EMI_MDCT_2ND					0x0000007c
+	#define EMI_MDCT_2ND_RD_HI_RSV_NUM		GENMASK(10, 8)
+	#define EMI_MDCT_2ND_WR_HI_RSV_NUM		GENMASK(14, 12)
+#define EMI_IOCL					0x000000d0
+	#define EMI_IOCL_M0_RD_OUTSTANDING		GENMASK(3, 0)
+	#define EMI_IOCL_M0_WR_OUTSTANDING		GENMASK(7, 4)
+	#define EMI_IOCL_M1_RD_OUTSTANDING		GENMASK(11, 8)
+	#define EMI_IOCL_M1_WR_OUTSTANDING		GENMASK(15, 12)
+	#define EMI_IOCL_M2_RD_OUTSTANDING		GENMASK(19, 16)
+	#define EMI_IOCL_M2_WR_OUTSTANDING		GENMASK(23, 20)
+	#define EMI_IOCL_M3_RD_OUTSTANDING		GENMASK(27, 24)
+	#define EMI_IOCL_M3_WR_OUTSTANDING		GENMASK(31, 28)
+#define EMI_IOCL_2ND					0x000000d4
+	#define EMI_IOCL_2ND_M0_RD_OUTSTANDING		GENMASK(3, 0)
+	#define EMI_IOCL_2ND_M0_WR_OUTSTANDING		GENMASK(7, 4)
+	#define EMI_IOCL_2ND_M1_RD_OUTSTANDING		GENMASK(11, 8)
+	#define EMI_IOCL_2ND_M1_WR_OUTSTANDING		GENMASK(15, 12)
+	#define EMI_IOCL_2ND_M2_RD_OUTSTANDING		GENMASK(19, 16)
+	#define EMI_IOCL_2ND_M2_WR_OUTSTANDING		GENMASK(23, 20)
+	#define EMI_IOCL_2ND_M3_RD_OUTSTANDING		GENMASK(27, 24)
+	#define EMI_IOCL_2ND_M3_WR_OUTSTANDING		GENMASK(31, 28)
+#define EMI_IOCM					0x000000d8
+	#define EMI_IOCM_M4_RD_OUTSTANDING		GENMASK(3, 0)
+	#define EMI_IOCM_M4_WR_OUTSTANDING		GENMASK(7, 4)
+	#define EMI_IOCM_M5_RD_OUTSTANDING		GENMASK(11, 8)
+	#define EMI_IOCM_M5_WR_OUTSTANDING		GENMASK(15, 12)
+	#define EMI_IOCM_M6_RD_OUTSTANDING		GENMASK(19, 16)
+	#define EMI_IOCM_M6_WR_OUTSTANDING		GENMASK(23, 20)
+	#define EMI_IOCM_M7_RD_OUTSTANDING		GENMASK(27, 24)
+	#define EMI_IOCM_M7_WR_OUTSTANDING		GENMASK(31, 28)
+#define EMI_IOCM_2ND					0x000000dc
+	#define EMI_IOCM_2ND_M4_RD_OUTSTANDING		GENMASK(3, 0)
+	#define EMI_IOCM_2ND_M4_WR_OUTSTANDING		GENMASK(7, 4)
+	#define EMI_IOCM_2ND_M5_RD_OUTSTANDING		GENMASK(11, 8)
+	#define EMI_IOCM_2ND_M5_WR_OUTSTANDING		GENMASK(15, 12)
+	#define EMI_IOCM_2ND_M6_RD_OUTSTANDING		GENMASK(19, 16)
+	#define EMI_IOCM_2ND_M6_WR_OUTSTANDING		GENMASK(23, 20)
+	#define EMI_IOCM_2ND_M7_RD_OUTSTANDING		GENMASK(27, 24)
+	#define EMI_IOCM_2ND_M7_WR_OUTSTANDING		GENMASK(31, 28)
+#define EMI_TESTB					0x000000e8
+	#define EMI_TESTB_PREULTRA_PRO			BIT(0)
+	#define EMI_TESTB_HALF_AGE_EN			BIT(4)
+	#define EMI_TESTB_BYTE32_WRAP_EN		BIT(5)
+#define EMI_ARBA					0x00000100
+	#define EMI_ARBA_M0_BANDWIDTH			GENMASK(5, 0)
+	#define EMI_ARBA_M0_ULTRA_DOM_BW		BIT(6)
+	#define EMI_ARBA_M0_DOUBLE_HALF_BW		GENMASK(9, 8)
+	#define EMI_ARBA_M0_BW_FILTER_LEN		GENMASK(11, 10)
+	#define EMI_ARBA_M0_BW_FILTER_EN		BIT(12)
+	#define EMI_ARBA_M0_PRE_ULTRA_DOM_BW		BIT(13)
+	#define EMI_ARBA_M0_MODE			BIT(14)
+	#define EMI_ARBA_M0_RD_LATENCY			GENMASK(23, 16)
+	#define EMI_ARBA_M0_WR_LATENCY			GENMASK(31, 24)
+#define EMI_ARBC					0x00000110
+	#define EMI_ARBC_M2_BANDWIDTH			GENMASK(5, 0)
+	#define EMI_ARBC_M2_ULTRA_DOM_BW		BIT(6)
+	#define EMI_ARBC_M2_BW_FILTER_EN		BIT(12)
+	#define EMI_ARBC_M2_PRE_ULTRA_DOM_BW		BIT(13)
+	#define EMI_ARBC_M2_MODE			BIT(14)
+	#define EMI_ARBC_M2_RD_LATENCY			GENMASK(23, 16)
+	#define EMI_ARBC_M2_WR_LATENCY			GENMASK(31, 24)
+#define EMI_ARBD					0x00000118
+	#define EMI_ARBD_M3_BANDWIDTH			GENMASK(5, 0)
+	#define EMI_ARBD_M3_ULTRA_DOM_BW		BIT(6)
+	#define EMI_ARBD_M3_BW_FILTER_EN		BIT(12)
+	#define EMI_ARBD_M3_PRE_ULTRA_DOM_BW		BIT(13)
+	#define EMI_ARBD_M3_MODE			BIT(14)
+	#define EMI_ARBD_M3_RD_LATENCY			GENMASK(23, 16)
+	#define EMI_ARBD_M3_WR_LATENCY			GENMASK(31, 24)
+#define EMI_ARBE					0x00000120
+	#define EMI_ARBE_M4_BANDWIDTH			GENMASK(5, 0)
+	#define EMI_ARBE_M4_ULTRA_DOM_BW		BIT(6)
+	#define EMI_ARBE_M4_BW_FILTER_EN		BIT(12)
+	#define EMI_ARBE_M4_PRE_ULTRA_DOM_BW		BIT(13)
+	#define EMI_ARBE_M4_MODE			BIT(14)
+	#define EMI_ARBE_M4_RD_LATENCY			GENMASK(23, 16)
+	#define EMI_ARBE_M4_WD_LATENCY			GENMASK(31, 24)
+#define EMI_ARBF					0x00000128
+	#define EMI_ARBF_M5_BANDWIDTH			GENMASK(5, 0)
+	#define EMI_ARBF_M5_ULTRA_DOM_BW		BIT(6)
+	#define EMI_ARBF_M5_BW_FILTER_EN		BIT(12)
+	#define EMI_ARBF_M5_PRE_ULTRA_DOM_BW		BIT(13)
+	#define EMI_ARBF_M5_MODE			BIT(14)
+	#define EMI_ARBF_M5_RD_LATENCY			GENMASK(23, 16)
+	#define EMI_ARBF_M5_WR_LATENCY			GENMASK(31, 24)
+#define EMI_ARBG					0x00000130
+	#define EMI_ARBG_M6_BANDWIDTH			GENMASK(5, 0)
+	#define EMI_ARBG_M6_ULTRA_DOM_BW		BIT(6)
+	#define EMI_ARBG_M6_BW_FILTER_EN		BIT(12)
+	#define EMI_ARBG_M6_PRE_ULTRA_DOM_BW		BIT(13)
+	#define EMI_ARBG_M6_MODE			BIT(14)
+	#define EMI_ARBG_M6_RD_LATENCY			GENMASK(23, 16)
+	#define EMI_ARBG_M6_WR_LATENCY			GENMASK(31, 24)
+#define EMI_ARBH					0x00000138
+	#define EMI_ARBH_M7_BANDWIDTH			GENMASK(5, 0)
+	#define EMI_ARBH_M7_ULTRA_DOM_BW		BIT(6)
+	#define EMI_ARBH_M7_BW_FILTER_EN		BIT(12)
+	#define EMI_ARBH_M7_PRE_ULTRA_DOM_BW		BIT(13)
+	#define EMI_ARBH_M7_MODE			BIT(14)
+	#define EMI_ARBH_M7_RD_LATENCY			GENMASK(23, 16)
+	#define EMI_ARBH_M7_WR_LATENCY			GENMASK(31, 24)
+#define EMI_ARBI					0x00000140
+	#define EMI_ARBI_ULTRA				GENMASK(3, 0)
+	#define EMI_ARBI_LIMIT				GENMASK(11, 8)
+	#define EMI_ARBI_PCIE				GENMASK(15, 12)
+#define EMI_SLCT					0x00000158
+	#define EMI_SLCT_HI_PRIO_EN_M0			BIT(8)
+	#define EMI_SLCT_HI_PRIO_EN_M1			BIT(9)
+	#define EMI_SLCT_HI_PRIO_EN_M2			BIT(10)
+	#define EMI_SLCT_HI_PRIO_EN_M3			BIT(11)
+	#define EMI_SLCT_HI_PRIO_EN_M4			BIT(12)
+	#define EMI_SLCT_HI_PRIO_EN_M5			BIT(13)
+	#define EMI_SLCT_HI_PRIO_EN_M6			BIT(14)
+	#define EMI_SLCT_HI_PRIO_EN_M7			BIT(15)
+	#define EMI_SLCT_M0_LLAT_EN			BIT(16)
+	#define EMI_SLCT_M1_LLAT_EN			BIT(17)
+	#define EMI_SLCT_M2_LLAT_EN			BIT(18)
+	#define EMI_SLCT_M3_LLAT_EN			BIT(19)
+	#define EMI_SLCT_M4_LLAT_EN			BIT(20)
+	#define EMI_SLCT_M5_LLAT_EN			BIT(21)
+	#define EMI_SLCT_M6_LLAT_EN			BIT(22)
+	#define EMI_SLCT_M7_LLAT_EN			BIT(23)
+#define EMI_MPUD0_ST					0x00000160
+	#define EMI_MPUD0_ST_D0_R0_VIO			BIT(0)
+	#define EMI_MPUD0_ST_D0_R1_VIO			BIT(1)
+	#define EMI_MPUD0_ST_D0_R2_VIO			BIT(2)
+	#define EMI_MPUD0_ST_D0_R3_VIO			BIT(3)
+	#define EMI_MPUD0_ST_D0_R4_VIO			BIT(4)
+	#define EMI_MPUD0_ST_D0_R5_VIO			BIT(5)
+	#define EMI_MPUD0_ST_D0_R6_VIO			BIT(6)
+	#define EMI_MPUD0_ST_D0_R7_VIO			BIT(7)
+	#define EMI_MPUD0_ST_D0_R8_VIO			BIT(8)
+	#define EMI_MPUD0_ST_D0_R9_VIO			BIT(9)
+	#define EMI_MPUD0_ST_D0_R10_VIO			BIT(10)
+	#define EMI_MPUD0_ST_D0_R11_VIO			BIT(11)
+	#define EMI_MPUD0_ST_D0_R12_VIO			BIT(12)
+	#define EMI_MPUD0_ST_D0_R13_VIO			BIT(13)
+	#define EMI_MPUD0_ST_D0_R14_VIO			BIT(14)
+	#define EMI_MPUD0_ST_D0_R15_VIO			BIT(15)
+	#define EMI_MPUD0_ST_D0_R16_VIO			BIT(16)
+	#define EMI_MPUD0_ST_D0_R17_VIO			BIT(17)
+	#define EMI_MPUD0_ST_D0_R18_VIO			BIT(18)
+	#define EMI_MPUD0_ST_D0_R19_VIO			BIT(19)
+	#define EMI_MPUD0_ST_D0_R20_VIO			BIT(20)
+	#define EMI_MPUD0_ST_D0_R21_VIO			BIT(21)
+	#define EMI_MPUD0_ST_D0_R22_VIO			BIT(22)
+	#define EMI_MPUD0_ST_D0_R23_VIO			BIT(23)
+	#define EMI_MPUD0_ST_D0_R24_VIO			BIT(24)
+	#define EMI_MPUD0_ST_D0_R25_VIO			BIT(25)
+	#define EMI_MPUD0_ST_D0_R26_VIO			BIT(26)
+	#define EMI_MPUD0_ST_D0_R27_VIO			BIT(27)
+	#define EMI_MPUD0_ST_D0_R28_VIO			BIT(28)
+	#define EMI_MPUD0_ST_D0_R29_VIO			BIT(29)
+	#define EMI_MPUD0_ST_D0_R30_VIO			BIT(30)
+	#define EMI_MPUD0_ST_D0_R31_VIO			BIT(31)
+#define EMI_MPUD1_ST					0x00000164
+	#define EMI_MPUD1_ST_D1_R0_VIO			BIT(0)
+	#define EMI_MPUD1_ST_D1_R1_VIO			BIT(1)
+	#define EMI_MPUD1_ST_D1_R2_VIO			BIT(2)
+	#define EMI_MPUD1_ST_D1_R3_VIO			BIT(3)
+	#define EMI_MPUD1_ST_D1_R4_VIO			BIT(4)
+	#define EMI_MPUD1_ST_D1_R5_VIO			BIT(5)
+	#define EMI_MPUD1_ST_D1_R6_VIO			BIT(6)
+	#define EMI_MPUD1_ST_D1_R7_VIO			BIT(7)
+	#define EMI_MPUD1_ST_D1_R8_VIO			BIT(8)
+	#define EMI_MPUD1_ST_D1_R9_VIO			BIT(9)
+	#define EMI_MPUD1_ST_D1_R10_VIO			BIT(10)
+	#define EMI_MPUD1_ST_D1_R11_VIO			BIT(11)
+	#define EMI_MPUD1_ST_D1_R12_VIO			BIT(12)
+	#define EMI_MPUD1_ST_D1_R13_VIO			BIT(13)
+	#define EMI_MPUD1_ST_D1_R14_VIO			BIT(14)
+	#define EMI_MPUD1_ST_D1_R15_VIO			BIT(15)
+	#define EMI_MPUD1_ST_D1_R16_VIO			BIT(16)
+	#define EMI_MPUD1_ST_D1_R17_VIO			BIT(17)
+	#define EMI_MPUD1_ST_D1_R18_VIO			BIT(18)
+	#define EMI_MPUD1_ST_D1_R19_VIO			BIT(19)
+	#define EMI_MPUD1_ST_D1_R20_VIO			BIT(20)
+	#define EMI_MPUD1_ST_D1_R21_VIO			BIT(21)
+	#define EMI_MPUD1_ST_D1_R22_VIO			BIT(22)
+	#define EMI_MPUD1_ST_D1_R23_VIO			BIT(23)
+	#define EMI_MPUD1_ST_D1_R24_VIO			BIT(24)
+	#define EMI_MPUD1_ST_D1_R25_VIO			BIT(25)
+	#define EMI_MPUD1_ST_D1_R26_VIO			BIT(26)
+	#define EMI_MPUD1_ST_D1_R27_VIO			BIT(27)
+	#define EMI_MPUD1_ST_D1_R28_VIO			BIT(28)
+	#define EMI_MPUD1_ST_D1_R29_VIO			BIT(29)
+	#define EMI_MPUD1_ST_D1_R30_VIO			BIT(30)
+	#define EMI_MPUD1_ST_D1_R31_VIO			BIT(31)
+#define EMI_MPUD2_ST					0x00000168
+	#define EMI_MPUD2_ST_D2_R0_VIO			BIT(0)
+	#define EMI_MPUD2_ST_D2_R1_VIO			BIT(1)
+	#define EMI_MPUD2_ST_D2_R2_VIO			BIT(2)
+	#define EMI_MPUD2_ST_D2_R3_VIO			BIT(3)
+	#define EMI_MPUD2_ST_D2_R4_VIO			BIT(4)
+	#define EMI_MPUD2_ST_D2_R5_VIO			BIT(5)
+	#define EMI_MPUD2_ST_D2_R6_VIO			BIT(6)
+	#define EMI_MPUD2_ST_D2_R7_VIO			BIT(7)
+	#define EMI_MPUD2_ST_D2_R8_VIO			BIT(8)
+	#define EMI_MPUD2_ST_D2_R9_VIO			BIT(9)
+	#define EMI_MPUD2_ST_D2_R10_VIO			BIT(10)
+	#define EMI_MPUD2_ST_D2_R11_VIO			BIT(11)
+	#define EMI_MPUD2_ST_D2_R12_VIO			BIT(12)
+	#define EMI_MPUD2_ST_D2_R13_VIO			BIT(13)
+	#define EMI_MPUD2_ST_D2_R14_VIO			BIT(14)
+	#define EMI_MPUD2_ST_D2_R15_VIO			BIT(15)
+	#define EMI_MPUD2_ST_D2_R16_VIO			BIT(16)
+	#define EMI_MPUD2_ST_D2_R17_VIO			BIT(17)
+	#define EMI_MPUD2_ST_D2_R18_VIO			BIT(18)
+	#define EMI_MPUD2_ST_D2_R19_VIO			BIT(19)
+	#define EMI_MPUD2_ST_D2_R20_VIO			BIT(20)
+	#define EMI_MPUD2_ST_D2_R21_VIO			BIT(21)
+	#define EMI_MPUD2_ST_D2_R22_VIO			BIT(22)
+	#define EMI_MPUD2_ST_D2_R23_VIO			BIT(23)
+	#define EMI_MPUD2_ST_D2_R24_VIO			BIT(24)
+	#define EMI_MPUD2_ST_D2_R25_VIO			BIT(25)
+	#define EMI_MPUD2_ST_D2_R26_VIO			BIT(26)
+	#define EMI_MPUD2_ST_D2_R27_VIO			BIT(27)
+	#define EMI_MPUD2_ST_D2_R28_VIO			BIT(28)
+	#define EMI_MPUD2_ST_D2_R29_VIO			BIT(29)
+	#define EMI_MPUD2_ST_D2_R30_VIO			BIT(30)
+	#define EMI_MPUD2_ST_D2_R31_VIO			BIT(31)
+#define EMI_MPUD3_ST					0x0000016c
+	#define EMI_MPUD3_ST_D3_R0_VIO			BIT(0)
+	#define EMI_MPUD3_ST_D3_R1_VIO			BIT(1)
+	#define EMI_MPUD3_ST_D3_R2_VIO			BIT(2)
+	#define EMI_MPUD3_ST_D3_R3_VIO			BIT(3)
+	#define EMI_MPUD3_ST_D3_R4_VIO			BIT(4)
+	#define EMI_MPUD3_ST_D3_R5_VIO			BIT(5)
+	#define EMI_MPUD3_ST_D3_R6_VIO			BIT(6)
+	#define EMI_MPUD3_ST_D3_R7_VIO			BIT(7)
+	#define EMI_MPUD3_ST_D3_R8_VIO			BIT(8)
+	#define EMI_MPUD3_ST_D3_R9_VIO			BIT(9)
+	#define EMI_MPUD3_ST_D3_R10_VIO			BIT(10)
+	#define EMI_MPUD3_ST_D3_R11_VIO			BIT(11)
+	#define EMI_MPUD3_ST_D3_R12_VIO			BIT(12)
+	#define EMI_MPUD3_ST_D3_R13_VIO			BIT(13)
+	#define EMI_MPUD3_ST_D3_R14_VIO			BIT(14)
+	#define EMI_MPUD3_ST_D3_R15_VIO			BIT(15)
+	#define EMI_MPUD3_ST_D3_R16_VIO			BIT(16)
+	#define EMI_MPUD3_ST_D3_R17_VIO			BIT(17)
+	#define EMI_MPUD3_ST_D3_R18_VIO			BIT(18)
+	#define EMI_MPUD3_ST_D3_R19_VIO			BIT(19)
+	#define EMI_MPUD3_ST_D3_R20_VIO			BIT(20)
+	#define EMI_MPUD3_ST_D3_R21_VIO			BIT(21)
+	#define EMI_MPUD3_ST_D3_R22_VIO			BIT(22)
+	#define EMI_MPUD3_ST_D3_R23_VIO			BIT(23)
+	#define EMI_MPUD3_ST_D3_R24_VIO			BIT(24)
+	#define EMI_MPUD3_ST_D3_R25_VIO			BIT(25)
+	#define EMI_MPUD3_ST_D3_R26_VIO			BIT(26)
+	#define EMI_MPUD3_ST_D3_R27_VIO			BIT(27)
+	#define EMI_MPUD3_ST_D3_R28_VIO			BIT(28)
+	#define EMI_MPUD3_ST_D3_R29_VIO			BIT(29)
+	#define EMI_MPUD3_ST_D3_R30_VIO			BIT(30)
+	#define EMI_MPUD3_ST_D3_R31_VIO			BIT(31)
+#define EMI_MPUD4_ST					0x00000170
+	#define EMI_MPUD4_ST_D4_R0_VIO			BIT(0)
+	#define EMI_MPUD4_ST_D4_R1_VIO			BIT(1)
+	#define EMI_MPUD4_ST_D4_R2_VIO			BIT(2)
+	#define EMI_MPUD4_ST_D4_R3_VIO			BIT(3)
+	#define EMI_MPUD4_ST_D4_R4_VIO			BIT(4)
+	#define EMI_MPUD4_ST_D4_R5_VIO			BIT(5)
+	#define EMI_MPUD4_ST_D4_R6_VIO			BIT(6)
+	#define EMI_MPUD4_ST_D4_R7_VIO			BIT(7)
+	#define EMI_MPUD4_ST_D4_R8_VIO			BIT(8)
+	#define EMI_MPUD4_ST_D4_R9_VIO			BIT(9)
+	#define EMI_MPUD4_ST_D4_R10_VIO			BIT(10)
+	#define EMI_MPUD4_ST_D4_R11_VIO			BIT(11)
+	#define EMI_MPUD4_ST_D4_R12_VIO			BIT(12)
+	#define EMI_MPUD4_ST_D4_R13_VIO			BIT(13)
+	#define EMI_MPUD4_ST_D4_R14_VIO			BIT(14)
+	#define EMI_MPUD4_ST_D4_R15_VIO			BIT(15)
+	#define EMI_MPUD4_ST_D4_R16_VIO			BIT(16)
+	#define EMI_MPUD4_ST_D4_R17_VIO			BIT(17)
+	#define EMI_MPUD4_ST_D4_R18_VIO			BIT(18)
+	#define EMI_MPUD4_ST_D4_R19_VIO			BIT(19)
+	#define EMI_MPUD4_ST_D4_R20_VIO			BIT(20)
+	#define EMI_MPUD4_ST_D4_R21_VIO			BIT(21)
+	#define EMI_MPUD4_ST_D4_R22_VIO			BIT(22)
+	#define EMI_MPUD4_ST_D4_R23_VIO			BIT(23)
+	#define EMI_MPUD4_ST_D4_R24_VIO			BIT(24)
+	#define EMI_MPUD4_ST_D4_R25_VIO			BIT(25)
+	#define EMI_MPUD4_ST_D4_R26_VIO			BIT(26)
+	#define EMI_MPUD4_ST_D4_R27_VIO			BIT(27)
+	#define EMI_MPUD4_ST_D4_R28_VIO			BIT(28)
+	#define EMI_MPUD4_ST_D4_R29_VIO			BIT(29)
+	#define EMI_MPUD4_ST_D4_R30_VIO			BIT(30)
+	#define EMI_MPUD4_ST_D4_R31_VIO			BIT(31)
+#define EMI_MPUD5_ST					0x00000174
+	#define EMI_MPUD5_ST_D5_R0_VIO			BIT(0)
+	#define EMI_MPUD5_ST_D5_R1_VIO			BIT(1)
+	#define EMI_MPUD5_ST_D5_R2_VIO			BIT(2)
+	#define EMI_MPUD5_ST_D5_R3_VIO			BIT(3)
+	#define EMI_MPUD5_ST_D5_R4_VIO			BIT(4)
+	#define EMI_MPUD5_ST_D5_R5_VIO			BIT(5)
+	#define EMI_MPUD5_ST_D5_R6_VIO			BIT(6)
+	#define EMI_MPUD5_ST_D5_R7_VIO			BIT(7)
+	#define EMI_MPUD5_ST_D5_R8_VIO			BIT(8)
+	#define EMI_MPUD5_ST_D5_R9_VIO			BIT(9)
+	#define EMI_MPUD5_ST_D5_R10_VIO			BIT(10)
+	#define EMI_MPUD5_ST_D5_R11_VIO			BIT(11)
+	#define EMI_MPUD5_ST_D5_R12_VIO			BIT(12)
+	#define EMI_MPUD5_ST_D5_R13_VIO			BIT(13)
+	#define EMI_MPUD5_ST_D5_R14_VIO			BIT(14)
+	#define EMI_MPUD5_ST_D5_R15_VIO			BIT(15)
+	#define EMI_MPUD5_ST_D5_R16_VIO			BIT(16)
+	#define EMI_MPUD5_ST_D5_R17_VIO			BIT(17)
+	#define EMI_MPUD5_ST_D5_R18_VIO			BIT(18)
+	#define EMI_MPUD5_ST_D5_R19_VIO			BIT(19)
+	#define EMI_MPUD5_ST_D5_R20_VIO			BIT(20)
+	#define EMI_MPUD5_ST_D5_R21_VIO			BIT(21)
+	#define EMI_MPUD5_ST_D5_R22_VIO			BIT(22)
+	#define EMI_MPUD5_ST_D5_R23_VIO			BIT(23)
+	#define EMI_MPUD5_ST_D5_R24_VIO			BIT(24)
+	#define EMI_MPUD5_ST_D5_R25_VIO			BIT(25)
+	#define EMI_MPUD5_ST_D5_R26_VIO			BIT(26)
+	#define EMI_MPUD5_ST_D5_R27_VIO			BIT(27)
+	#define EMI_MPUD5_ST_D5_R28_VIO			BIT(28)
+	#define EMI_MPUD5_ST_D5_R29_VIO			BIT(29)
+	#define EMI_MPUD5_ST_D5_R30_VIO			BIT(30)
+	#define EMI_MPUD5_ST_D5_R31_VIO			BIT(31)
+#define EMI_MPUD6_ST					0x00000178
+	#define EMI_MPUD6_ST_D6_R0_VIO			BIT(0)
+	#define EMI_MPUD6_ST_D6_R1_VIO			BIT(1)
+	#define EMI_MPUD6_ST_D6_R2_VIO			BIT(2)
+	#define EMI_MPUD6_ST_D6_R3_VIO			BIT(3)
+	#define EMI_MPUD6_ST_D6_R4_VIO			BIT(4)
+	#define EMI_MPUD6_ST_D6_R5_VIO			BIT(5)
+	#define EMI_MPUD6_ST_D6_R6_VIO			BIT(6)
+	#define EMI_MPUD6_ST_D6_R7_VIO			BIT(7)
+	#define EMI_MPUD6_ST_D6_R8_VIO			BIT(8)
+	#define EMI_MPUD6_ST_D6_R9_VIO			BIT(9)
+	#define EMI_MPUD6_ST_D6_R10_VIO			BIT(10)
+	#define EMI_MPUD6_ST_D6_R11_VIO			BIT(11)
+	#define EMI_MPUD6_ST_D6_R12_VIO			BIT(12)
+	#define EMI_MPUD6_ST_D6_R13_VIO			BIT(13)
+	#define EMI_MPUD6_ST_D6_R14_VIO			BIT(14)
+	#define EMI_MPUD6_ST_D6_R15_VIO			BIT(15)
+	#define EMI_MPUD6_ST_D6_R16_VIO			BIT(16)
+	#define EMI_MPUD6_ST_D6_R17_VIO			BIT(17)
+	#define EMI_MPUD6_ST_D6_R18_VIO			BIT(18)
+	#define EMI_MPUD6_ST_D6_R19_VIO			BIT(19)
+	#define EMI_MPUD6_ST_D6_R20_VIO			BIT(20)
+	#define EMI_MPUD6_ST_D6_R21_VIO			BIT(21)
+	#define EMI_MPUD6_ST_D6_R22_VIO			BIT(22)
+	#define EMI_MPUD6_ST_D6_R23_VIO			BIT(23)
+	#define EMI_MPUD6_ST_D6_R24_VIO			BIT(24)
+	#define EMI_MPUD6_ST_D6_R25_VIO			BIT(25)
+	#define EMI_MPUD6_ST_D6_R26_VIO			BIT(26)
+	#define EMI_MPUD6_ST_D6_R27_VIO			BIT(27)
+	#define EMI_MPUD6_ST_D6_R28_VIO			BIT(28)
+	#define EMI_MPUD6_ST_D6_R29_VIO			BIT(29)
+	#define EMI_MPUD6_ST_D6_R30_VIO			BIT(30)
+	#define EMI_MPUD6_ST_D6_R31_VIO			BIT(31)
+#define EMI_MPUD7_ST					0x0000017c
+	#define EMI_MPUD7_ST_D7_R0_VIO			BIT(0)
+	#define EMI_MPUD7_ST_D7_R1_VIO			BIT(1)
+	#define EMI_MPUD7_ST_D7_R2_VIO			BIT(2)
+	#define EMI_MPUD7_ST_D7_R3_VIO			BIT(3)
+	#define EMI_MPUD7_ST_D7_R4_VIO			BIT(4)
+	#define EMI_MPUD7_ST_D7_R5_VIO			BIT(5)
+	#define EMI_MPUD7_ST_D7_R6_VIO			BIT(6)
+	#define EMI_MPUD7_ST_D7_R7_VIO			BIT(7)
+	#define EMI_MPUD7_ST_D7_R8_VIO			BIT(8)
+	#define EMI_MPUD7_ST_D7_R9_VIO			BIT(9)
+	#define EMI_MPUD7_ST_D7_R10_VIO			BIT(10)
+	#define EMI_MPUD7_ST_D7_R11_VIO			BIT(11)
+	#define EMI_MPUD7_ST_D7_R12_VIO			BIT(12)
+	#define EMI_MPUD7_ST_D7_R13_VIO			BIT(13)
+	#define EMI_MPUD7_ST_D7_R14_VIO			BIT(14)
+	#define EMI_MPUD7_ST_D7_R15_VIO			BIT(15)
+	#define EMI_MPUD7_ST_D7_R16_VIO			BIT(16)
+	#define EMI_MPUD7_ST_D7_R17_VIO			BIT(17)
+	#define EMI_MPUD7_ST_D7_R18_VIO			BIT(18)
+	#define EMI_MPUD7_ST_D7_R19_VIO			BIT(19)
+	#define EMI_MPUD7_ST_D7_R20_VIO			BIT(20)
+	#define EMI_MPUD7_ST_D7_R21_VIO			BIT(21)
+	#define EMI_MPUD7_ST_D7_R22_VIO			BIT(22)
+	#define EMI_MPUD7_ST_D7_R23_VIO			BIT(23)
+	#define EMI_MPUD7_ST_D7_R24_VIO			BIT(24)
+	#define EMI_MPUD7_ST_D7_R25_VIO			BIT(25)
+	#define EMI_MPUD7_ST_D7_R26_VIO			BIT(26)
+	#define EMI_MPUD7_ST_D7_R27_VIO			BIT(27)
+	#define EMI_MPUD7_ST_D7_R28_VIO			BIT(28)
+	#define EMI_MPUD7_ST_D7_R29_VIO			BIT(29)
+	#define EMI_MPUD7_ST_D7_R30_VIO			BIT(30)
+	#define EMI_MPUD7_ST_D7_R31_VIO			BIT(31)
+#define EMI_MPUD8_ST					0x00000180
+	#define EMI_MPUD8_ST_D8_R0_VIO			BIT(0)
+	#define EMI_MPUD8_ST_D8_R1_VIO			BIT(1)
+	#define EMI_MPUD8_ST_D8_R2_VIO			BIT(2)
+	#define EMI_MPUD8_ST_D8_R3_VIO			BIT(3)
+	#define EMI_MPUD8_ST_D8_R4_VIO			BIT(4)
+	#define EMI_MPUD8_ST_D8_R5_VIO			BIT(5)
+	#define EMI_MPUD8_ST_D8_R6_VIO			BIT(6)
+	#define EMI_MPUD8_ST_D8_R7_VIO			BIT(7)
+	#define EMI_MPUD8_ST_D8_R8_VIO			BIT(8)
+	#define EMI_MPUD8_ST_D8_R9_VIO			BIT(9)
+	#define EMI_MPUD8_ST_D8_R10_VIO			BIT(10)
+	#define EMI_MPUD8_ST_D8_R11_VIO			BIT(11)
+	#define EMI_MPUD8_ST_D8_R12_VIO			BIT(12)
+	#define EMI_MPUD8_ST_D8_R13_VIO			BIT(13)
+	#define EMI_MPUD8_ST_D8_R14_VIO			BIT(14)
+	#define EMI_MPUD8_ST_D8_R15_VIO			BIT(15)
+	#define EMI_MPUD8_ST_D8_R16_VIO			BIT(16)
+	#define EMI_MPUD8_ST_D8_R17_VIO			BIT(17)
+	#define EMI_MPUD8_ST_D8_R18_VIO			BIT(18)
+	#define EMI_MPUD8_ST_D8_R19_VIO			BIT(19)
+	#define EMI_MPUD8_ST_D8_R20_VIO			BIT(20)
+	#define EMI_MPUD8_ST_D8_R21_VIO			BIT(21)
+	#define EMI_MPUD8_ST_D8_R22_VIO			BIT(22)
+	#define EMI_MPUD8_ST_D8_R23_VIO			BIT(23)
+	#define EMI_MPUD8_ST_D8_R24_VIO			BIT(24)
+	#define EMI_MPUD8_ST_D8_R25_VIO			BIT(25)
+	#define EMI_MPUD8_ST_D8_R26_VIO			BIT(26)
+	#define EMI_MPUD8_ST_D8_R27_VIO			BIT(27)
+	#define EMI_MPUD8_ST_D8_R28_VIO			BIT(28)
+	#define EMI_MPUD8_ST_D8_R29_VIO			BIT(29)
+	#define EMI_MPUD8_ST_D8_R30_VIO			BIT(30)
+	#define EMI_MPUD8_ST_D8_R31_VIO			BIT(31)
+#define EMI_MPUD9_ST					0x00000184
+	#define EMI_MPUD9_ST_D9_R0_VIO			BIT(0)
+	#define EMI_MPUD9_ST_D9_R1_VIO			BIT(1)
+	#define EMI_MPUD9_ST_D9_R2_VIO			BIT(2)
+	#define EMI_MPUD9_ST_D9_R3_VIO			BIT(3)
+	#define EMI_MPUD9_ST_D9_R4_VIO			BIT(4)
+	#define EMI_MPUD9_ST_D9_R5_VIO			BIT(5)
+	#define EMI_MPUD9_ST_D9_R6_VIO			BIT(6)
+	#define EMI_MPUD9_ST_D9_R7_VIO			BIT(7)
+	#define EMI_MPUD9_ST_D9_R8_VIO			BIT(8)
+	#define EMI_MPUD9_ST_D9_R9_VIO			BIT(9)
+	#define EMI_MPUD9_ST_D9_R10_VIO			BIT(10)
+	#define EMI_MPUD9_ST_D9_R11_VIO			BIT(11)
+	#define EMI_MPUD9_ST_D9_R12_VIO			BIT(12)
+	#define EMI_MPUD9_ST_D9_R13_VIO			BIT(13)
+	#define EMI_MPUD9_ST_D9_R14_VIO			BIT(14)
+	#define EMI_MPUD9_ST_D9_R15_VIO			BIT(15)
+	#define EMI_MPUD9_ST_D9_R16_VIO			BIT(16)
+	#define EMI_MPUD9_ST_D9_R17_VIO			BIT(17)
+	#define EMI_MPUD9_ST_D9_R18_VIO			BIT(18)
+	#define EMI_MPUD9_ST_D9_R19_VIO			BIT(19)
+	#define EMI_MPUD9_ST_D9_R20_VIO			BIT(20)
+	#define EMI_MPUD9_ST_D9_R21_VIO			BIT(21)
+	#define EMI_MPUD9_ST_D9_R22_VIO			BIT(22)
+	#define EMI_MPUD9_ST_D9_R23_VIO			BIT(23)
+	#define EMI_MPUD9_ST_D9_R24_VIO			BIT(24)
+	#define EMI_MPUD9_ST_D9_R25_VIO			BIT(25)
+	#define EMI_MPUD9_ST_D9_R26_VIO			BIT(26)
+	#define EMI_MPUD9_ST_D9_R27_VIO			BIT(27)
+	#define EMI_MPUD9_ST_D9_R28_VIO			BIT(28)
+	#define EMI_MPUD9_ST_D9_R29_VIO			BIT(29)
+	#define EMI_MPUD9_ST_D9_R30_VIO			BIT(30)
+	#define EMI_MPUD9_ST_D9_R31_VIO			BIT(31)
+#define EMI_MPUD10_ST					0x00000188
+	#define EMI_MPUD10_ST_D10_R0_VIO		BIT(0)
+	#define EMI_MPUD10_ST_D10_R1_VIO		BIT(1)
+	#define EMI_MPUD10_ST_D10_R2_VIO		BIT(2)
+	#define EMI_MPUD10_ST_D10_R3_VIO		BIT(3)
+	#define EMI_MPUD10_ST_D10_R4_VIO		BIT(4)
+	#define EMI_MPUD10_ST_D10_R5_VIO		BIT(5)
+	#define EMI_MPUD10_ST_D10_R6_VIO		BIT(6)
+	#define EMI_MPUD10_ST_D10_R7_VIO		BIT(7)
+	#define EMI_MPUD10_ST_D10_R8_VIO		BIT(8)
+	#define EMI_MPUD10_ST_D10_R9_VIO		BIT(9)
+	#define EMI_MPUD10_ST_D10_R10_VIO		BIT(10)
+	#define EMI_MPUD10_ST_D10_R11_VIO		BIT(11)
+	#define EMI_MPUD10_ST_D10_R12_VIO		BIT(12)
+	#define EMI_MPUD10_ST_D10_R13_VIO		BIT(13)
+	#define EMI_MPUD10_ST_D10_R14_VIO		BIT(14)
+	#define EMI_MPUD10_ST_D10_R15_VIO		BIT(15)
+	#define EMI_MPUD10_ST_D10_R16_VIO		BIT(16)
+	#define EMI_MPUD10_ST_D10_R17_VIO		BIT(17)
+	#define EMI_MPUD10_ST_D10_R18_VIO		BIT(18)
+	#define EMI_MPUD10_ST_D10_R19_VIO		BIT(19)
+	#define EMI_MPUD10_ST_D10_R20_VIO		BIT(20)
+	#define EMI_MPUD10_ST_D10_R21_VIO		BIT(21)
+	#define EMI_MPUD10_ST_D10_R22_VIO		BIT(22)
+	#define EMI_MPUD10_ST_D10_R23_VIO		BIT(23)
+	#define EMI_MPUD10_ST_D10_R24_VIO		BIT(24)
+	#define EMI_MPUD10_ST_D10_R25_VIO		BIT(25)
+	#define EMI_MPUD10_ST_D10_R26_VIO		BIT(26)
+	#define EMI_MPUD10_ST_D10_R27_VIO		BIT(27)
+	#define EMI_MPUD10_ST_D10_R28_VIO		BIT(28)
+	#define EMI_MPUD10_ST_D10_R29_VIO		BIT(29)
+	#define EMI_MPUD10_ST_D10_R30_VIO		BIT(30)
+	#define EMI_MPUD10_ST_D10_R31_VIO		BIT(31)
+#define EMI_MPUD11_ST					0x0000018c
+	#define EMI_MPUD11_ST_D11_R0_VIO		BIT(0)
+	#define EMI_MPUD11_ST_D11_R1_VIO		BIT(1)
+	#define EMI_MPUD11_ST_D11_R2_VIO		BIT(2)
+	#define EMI_MPUD11_ST_D11_R3_VIO		BIT(3)
+	#define EMI_MPUD11_ST_D11_R4_VIO		BIT(4)
+	#define EMI_MPUD11_ST_D11_R5_VIO		BIT(5)
+	#define EMI_MPUD11_ST_D11_R6_VIO		BIT(6)
+	#define EMI_MPUD11_ST_D11_R7_VIO		BIT(7)
+	#define EMI_MPUD11_ST_D11_R8_VIO		BIT(8)
+	#define EMI_MPUD11_ST_D11_R9_VIO		BIT(9)
+	#define EMI_MPUD11_ST_D11_R10_VIO		BIT(10)
+	#define EMI_MPUD11_ST_D11_R11_VIO		BIT(11)
+	#define EMI_MPUD11_ST_D11_R12_VIO		BIT(12)
+	#define EMI_MPUD11_ST_D11_R13_VIO		BIT(13)
+	#define EMI_MPUD11_ST_D11_R14_VIO		BIT(14)
+	#define EMI_MPUD11_ST_D11_R15_VIO		BIT(15)
+	#define EMI_MPUD11_ST_D11_R16_VIO		BIT(16)
+	#define EMI_MPUD11_ST_D11_R17_VIO		BIT(17)
+	#define EMI_MPUD11_ST_D11_R18_VIO		BIT(18)
+	#define EMI_MPUD11_ST_D11_R19_VIO		BIT(19)
+	#define EMI_MPUD11_ST_D11_R20_VIO		BIT(20)
+	#define EMI_MPUD11_ST_D11_R21_VIO		BIT(21)
+	#define EMI_MPUD11_ST_D11_R22_VIO		BIT(22)
+	#define EMI_MPUD11_ST_D11_R23_VIO		BIT(23)
+	#define EMI_MPUD11_ST_D11_R24_VIO		BIT(24)
+	#define EMI_MPUD11_ST_D11_R25_VIO		BIT(25)
+	#define EMI_MPUD11_ST_D11_R26_VIO		BIT(26)
+	#define EMI_MPUD11_ST_D11_R27_VIO		BIT(27)
+	#define EMI_MPUD11_ST_D11_R28_VIO		BIT(28)
+	#define EMI_MPUD11_ST_D11_R29_VIO		BIT(29)
+	#define EMI_MPUD11_ST_D11_R30_VIO		BIT(30)
+	#define EMI_MPUD11_ST_D11_R31_VIO		BIT(31)
+#define EMI_MPUD12_ST					0x00000190
+	#define EMI_MPUD12_ST_D12_R0_VIO		BIT(0)
+	#define EMI_MPUD12_ST_D12_R1_VIO		BIT(1)
+	#define EMI_MPUD12_ST_D12_R2_VIO		BIT(2)
+	#define EMI_MPUD12_ST_D12_R3_VIO		BIT(3)
+	#define EMI_MPUD12_ST_D12_R4_VIO		BIT(4)
+	#define EMI_MPUD12_ST_D12_R5_VIO		BIT(5)
+	#define EMI_MPUD12_ST_D12_R6_VIO		BIT(6)
+	#define EMI_MPUD12_ST_D12_R7_VIO		BIT(7)
+	#define EMI_MPUD12_ST_D12_R8_VIO		BIT(8)
+	#define EMI_MPUD12_ST_D12_R9_VIO		BIT(9)
+	#define EMI_MPUD12_ST_D12_R10_VIO		BIT(10)
+	#define EMI_MPUD12_ST_D12_R11_VIO		BIT(11)
+	#define EMI_MPUD12_ST_D12_R12_VIO		BIT(12)
+	#define EMI_MPUD12_ST_D12_R13_VIO		BIT(13)
+	#define EMI_MPUD12_ST_D12_R14_VIO		BIT(14)
+	#define EMI_MPUD12_ST_D12_R15_VIO		BIT(15)
+	#define EMI_MPUD12_ST_D12_R16_VIO		BIT(16)
+	#define EMI_MPUD12_ST_D12_R17_VIO		BIT(17)
+	#define EMI_MPUD12_ST_D12_R18_VIO		BIT(18)
+	#define EMI_MPUD12_ST_D12_R19_VIO		BIT(19)
+	#define EMI_MPUD12_ST_D12_R20_VIO		BIT(20)
+	#define EMI_MPUD12_ST_D12_R21_VIO		BIT(21)
+	#define EMI_MPUD12_ST_D12_R22_VIO		BIT(22)
+	#define EMI_MPUD12_ST_D12_R23_VIO		BIT(23)
+	#define EMI_MPUD12_ST_D12_R24_VIO		BIT(24)
+	#define EMI_MPUD12_ST_D12_R25_VIO		BIT(25)
+	#define EMI_MPUD12_ST_D12_R26_VIO		BIT(26)
+	#define EMI_MPUD12_ST_D12_R27_VIO		BIT(27)
+	#define EMI_MPUD12_ST_D12_R28_VIO		BIT(28)
+	#define EMI_MPUD12_ST_D12_R29_VIO		BIT(29)
+	#define EMI_MPUD12_ST_D12_R30_VIO		BIT(30)
+	#define EMI_MPUD12_ST_D12_R31_VIO		BIT(31)
+#define EMI_MPUD13_ST					0x00000194
+	#define EMI_MPUD13_ST_D13_R0_VIO		BIT(0)
+	#define EMI_MPUD13_ST_D13_R1_VIO		BIT(1)
+	#define EMI_MPUD13_ST_D13_R2_VIO		BIT(2)
+	#define EMI_MPUD13_ST_D13_R3_VIO		BIT(3)
+	#define EMI_MPUD13_ST_D13_R4_VIO		BIT(4)
+	#define EMI_MPUD13_ST_D13_R5_VIO		BIT(5)
+	#define EMI_MPUD13_ST_D13_R6_VIO		BIT(6)
+	#define EMI_MPUD13_ST_D13_R7_VIO		BIT(7)
+	#define EMI_MPUD13_ST_D13_R8_VIO		BIT(8)
+	#define EMI_MPUD13_ST_D13_R9_VIO		BIT(9)
+	#define EMI_MPUD13_ST_D13_R10_VIO		BIT(10)
+	#define EMI_MPUD13_ST_D13_R11_VIO		BIT(11)
+	#define EMI_MPUD13_ST_D13_R12_VIO		BIT(12)
+	#define EMI_MPUD13_ST_D13_R13_VIO		BIT(13)
+	#define EMI_MPUD13_ST_D13_R14_VIO		BIT(14)
+	#define EMI_MPUD13_ST_D13_R15_VIO		BIT(15)
+	#define EMI_MPUD13_ST_D13_R16_VIO		BIT(16)
+	#define EMI_MPUD13_ST_D13_R17_VIO		BIT(17)
+	#define EMI_MPUD13_ST_D13_R18_VIO		BIT(18)
+	#define EMI_MPUD13_ST_D13_R19_VIO		BIT(19)
+	#define EMI_MPUD13_ST_D13_R20_VIO		BIT(20)
+	#define EMI_MPUD13_ST_D13_R21_VIO		BIT(21)
+	#define EMI_MPUD13_ST_D13_R22_VIO		BIT(22)
+	#define EMI_MPUD13_ST_D13_R23_VIO		BIT(23)
+	#define EMI_MPUD13_ST_D13_R24_VIO		BIT(24)
+	#define EMI_MPUD13_ST_D13_R25_VIO		BIT(25)
+	#define EMI_MPUD13_ST_D13_R26_VIO		BIT(26)
+	#define EMI_MPUD13_ST_D13_R27_VIO		BIT(27)
+	#define EMI_MPUD13_ST_D13_R28_VIO		BIT(28)
+	#define EMI_MPUD13_ST_D13_R29_VIO		BIT(29)
+	#define EMI_MPUD13_ST_D13_R30_VIO		BIT(30)
+	#define EMI_MPUD13_ST_D13_R31_VIO		BIT(31)
+#define EMI_MPUD14_ST					0x00000198
+	#define EMI_MPUD14_ST_D14_R0_VIO		BIT(0)
+	#define EMI_MPUD14_ST_D14_R1_VIO		BIT(1)
+	#define EMI_MPUD14_ST_D14_R2_VIO		BIT(2)
+	#define EMI_MPUD14_ST_D14_R3_VIO		BIT(3)
+	#define EMI_MPUD14_ST_D14_R4_VIO		BIT(4)
+	#define EMI_MPUD14_ST_D14_R5_VIO		BIT(5)
+	#define EMI_MPUD14_ST_D14_R6_VIO		BIT(6)
+	#define EMI_MPUD14_ST_D14_R7_VIO		BIT(7)
+	#define EMI_MPUD14_ST_D14_R8_VIO		BIT(8)
+	#define EMI_MPUD14_ST_D14_R9_VIO		BIT(9)
+	#define EMI_MPUD14_ST_D14_R10_VIO		BIT(10)
+	#define EMI_MPUD14_ST_D14_R11_VIO		BIT(11)
+	#define EMI_MPUD14_ST_D14_R12_VIO		BIT(12)
+	#define EMI_MPUD14_ST_D14_R13_VIO		BIT(13)
+	#define EMI_MPUD14_ST_D14_R14_VIO		BIT(14)
+	#define EMI_MPUD14_ST_D14_R15_VIO		BIT(15)
+	#define EMI_MPUD14_ST_D14_R16_VIO		BIT(16)
+	#define EMI_MPUD14_ST_D14_R17_VIO		BIT(17)
+	#define EMI_MPUD14_ST_D14_R18_VIO		BIT(18)
+	#define EMI_MPUD14_ST_D14_R19_VIO		BIT(19)
+	#define EMI_MPUD14_ST_D14_R20_VIO		BIT(20)
+	#define EMI_MPUD14_ST_D14_R21_VIO		BIT(21)
+	#define EMI_MPUD14_ST_D14_R22_VIO		BIT(22)
+	#define EMI_MPUD14_ST_D14_R23_VIO		BIT(23)
+	#define EMI_MPUD14_ST_D14_R24_VIO		BIT(24)
+	#define EMI_MPUD14_ST_D14_R25_VIO		BIT(25)
+	#define EMI_MPUD14_ST_D14_R26_VIO		BIT(26)
+	#define EMI_MPUD14_ST_D14_R27_VIO		BIT(27)
+	#define EMI_MPUD14_ST_D14_R28_VIO		BIT(28)
+	#define EMI_MPUD14_ST_D14_R29_VIO		BIT(29)
+	#define EMI_MPUD14_ST_D14_R30_VIO		BIT(30)
+	#define EMI_MPUD14_ST_D14_R31_VIO		BIT(31)
+#define EMI_MPUD15_ST					0x0000019c
+	#define EMI_MPUD15_ST_D15_R0_VIO		BIT(0)
+	#define EMI_MPUD15_ST_D15_R1_VIO		BIT(1)
+	#define EMI_MPUD15_ST_D15_R2_VIO		BIT(2)
+	#define EMI_MPUD15_ST_D15_R3_VIO		BIT(3)
+	#define EMI_MPUD15_ST_D15_R4_VIO		BIT(4)
+	#define EMI_MPUD15_ST_D15_R5_VIO		BIT(5)
+	#define EMI_MPUD15_ST_D15_R6_VIO		BIT(6)
+	#define EMI_MPUD15_ST_D15_R7_VIO		BIT(7)
+	#define EMI_MPUD15_ST_D15_R8_VIO		BIT(8)
+	#define EMI_MPUD15_ST_D15_R9_VIO		BIT(9)
+	#define EMI_MPUD15_ST_D15_R10_VIO		BIT(10)
+	#define EMI_MPUD15_ST_D15_R11_VIO		BIT(11)
+	#define EMI_MPUD15_ST_D15_R12_VIO		BIT(12)
+	#define EMI_MPUD15_ST_D15_R13_VIO		BIT(13)
+	#define EMI_MPUD15_ST_D15_R14_VIO		BIT(14)
+	#define EMI_MPUD15_ST_D15_R15_VIO		BIT(15)
+	#define EMI_MPUD15_ST_D15_R16_VIO		BIT(16)
+	#define EMI_MPUD15_ST_D15_R17_VIO		BIT(17)
+	#define EMI_MPUD15_ST_D15_R18_VIO		BIT(18)
+	#define EMI_MPUD15_ST_D15_R19_VIO		BIT(19)
+	#define EMI_MPUD15_ST_D15_R20_VIO		BIT(20)
+	#define EMI_MPUD15_ST_D15_R21_VIO		BIT(21)
+	#define EMI_MPUD15_ST_D15_R22_VIO		BIT(22)
+	#define EMI_MPUD15_ST_D15_R23_VIO		BIT(23)
+	#define EMI_MPUD15_ST_D15_R24_VIO		BIT(24)
+	#define EMI_MPUD15_ST_D15_R25_VIO		BIT(25)
+	#define EMI_MPUD15_ST_D15_R26_VIO		BIT(26)
+	#define EMI_MPUD15_ST_D15_R27_VIO		BIT(27)
+	#define EMI_MPUD15_ST_D15_R28_VIO		BIT(28)
+	#define EMI_MPUD15_ST_D15_R29_VIO		BIT(29)
+	#define EMI_MPUD15_ST_D15_R30_VIO		BIT(30)
+	#define EMI_MPUD15_ST_D15_R31_VIO		BIT(31)
+#define EMI_MPUD16_ST					0x000001a0
+	#define EMI_MPUD16_ST_D16_R0_VIO		BIT(0)
+	#define EMI_MPUD16_ST_D16_R1_VIO		BIT(1)
+	#define EMI_MPUD16_ST_D16_R2_VIO		BIT(2)
+	#define EMI_MPUD16_ST_D16_R3_VIO		BIT(3)
+	#define EMI_MPUD16_ST_D16_R4_VIO		BIT(4)
+	#define EMI_MPUD16_ST_D16_R5_VIO		BIT(5)
+	#define EMI_MPUD16_ST_D16_R6_VIO		BIT(6)
+	#define EMI_MPUD16_ST_D16_R7_VIO		BIT(7)
+	#define EMI_MPUD16_ST_D16_R8_VIO		BIT(8)
+	#define EMI_MPUD16_ST_D16_R9_VIO		BIT(9)
+	#define EMI_MPUD16_ST_D16_R10_VIO		BIT(10)
+	#define EMI_MPUD16_ST_D16_R11_VIO		BIT(11)
+	#define EMI_MPUD16_ST_D16_R12_VIO		BIT(12)
+	#define EMI_MPUD16_ST_D16_R13_VIO		BIT(13)
+	#define EMI_MPUD16_ST_D16_R14_VIO		BIT(14)
+	#define EMI_MPUD16_ST_D16_R15_VIO		BIT(15)
+	#define EMI_MPUD16_ST_D16_R16_VIO		BIT(16)
+	#define EMI_MPUD16_ST_D16_R17_VIO		BIT(17)
+	#define EMI_MPUD16_ST_D16_R18_VIO		BIT(18)
+	#define EMI_MPUD16_ST_D16_R19_VIO		BIT(19)
+	#define EMI_MPUD16_ST_D16_R20_VIO		BIT(20)
+	#define EMI_MPUD16_ST_D16_R21_VIO		BIT(21)
+	#define EMI_MPUD16_ST_D16_R22_VIO		BIT(22)
+	#define EMI_MPUD16_ST_D16_R23_VIO		BIT(23)
+	#define EMI_MPUD16_ST_D16_R24_VIO		BIT(24)
+	#define EMI_MPUD16_ST_D16_R25_VIO		BIT(25)
+	#define EMI_MPUD16_ST_D16_R26_VIO		BIT(26)
+	#define EMI_MPUD16_ST_D16_R27_VIO		BIT(27)
+	#define EMI_MPUD16_ST_D16_R28_VIO		BIT(28)
+	#define EMI_MPUD16_ST_D16_R29_VIO		BIT(29)
+	#define EMI_MPUD16_ST_D16_R30_VIO		BIT(30)
+	#define EMI_MPUD16_ST_D16_R31_VIO		BIT(31)
+#define EMI_MPUD17_ST					0x000001a4
+	#define EMI_MPUD17_ST_D17_R0_VIO		BIT(0)
+	#define EMI_MPUD17_ST_D17_R1_VIO		BIT(1)
+	#define EMI_MPUD17_ST_D17_R2_VIO		BIT(2)
+	#define EMI_MPUD17_ST_D17_R3_VIO		BIT(3)
+	#define EMI_MPUD17_ST_D17_R4_VIO		BIT(4)
+	#define EMI_MPUD17_ST_D17_R5_VIO		BIT(5)
+	#define EMI_MPUD17_ST_D17_R6_VIO		BIT(6)
+	#define EMI_MPUD17_ST_D17_R7_VIO		BIT(7)
+	#define EMI_MPUD17_ST_D17_R8_VIO		BIT(8)
+	#define EMI_MPUD17_ST_D17_R9_VIO		BIT(9)
+	#define EMI_MPUD17_ST_D17_R10_VIO		BIT(10)
+	#define EMI_MPUD17_ST_D17_R11_VIO		BIT(11)
+	#define EMI_MPUD17_ST_D17_R12_VIO		BIT(12)
+	#define EMI_MPUD17_ST_D17_R13_VIO		BIT(13)
+	#define EMI_MPUD17_ST_D17_R14_VIO		BIT(14)
+	#define EMI_MPUD17_ST_D17_R15_VIO		BIT(15)
+	#define EMI_MPUD17_ST_D17_R16_VIO		BIT(16)
+	#define EMI_MPUD17_ST_D17_R17_VIO		BIT(17)
+	#define EMI_MPUD17_ST_D17_R18_VIO		BIT(18)
+	#define EMI_MPUD17_ST_D17_R19_VIO		BIT(19)
+	#define EMI_MPUD17_ST_D17_R20_VIO		BIT(20)
+	#define EMI_MPUD17_ST_D17_R21_VIO		BIT(21)
+	#define EMI_MPUD17_ST_D17_R22_VIO		BIT(22)
+	#define EMI_MPUD17_ST_D17_R23_VIO		BIT(23)
+	#define EMI_MPUD17_ST_D17_R24_VIO		BIT(24)
+	#define EMI_MPUD17_ST_D17_R25_VIO		BIT(25)
+	#define EMI_MPUD17_ST_D17_R26_VIO		BIT(26)
+	#define EMI_MPUD17_ST_D17_R27_VIO		BIT(27)
+	#define EMI_MPUD17_ST_D17_R28_VIO		BIT(28)
+	#define EMI_MPUD17_ST_D17_R29_VIO		BIT(29)
+	#define EMI_MPUD17_ST_D17_R30_VIO		BIT(30)
+	#define EMI_MPUD17_ST_D17_R31_VIO		BIT(31)
+#define EMI_MPUD18_ST					0x000001a8
+	#define EMI_MPUD18_ST_D18_R0_VIO		BIT(0)
+	#define EMI_MPUD18_ST_D18_R1_VIO		BIT(1)
+	#define EMI_MPUD18_ST_D18_R2_VIO		BIT(2)
+	#define EMI_MPUD18_ST_D18_R3_VIO		BIT(3)
+	#define EMI_MPUD18_ST_D18_R4_VIO		BIT(4)
+	#define EMI_MPUD18_ST_D18_R5_VIO		BIT(5)
+	#define EMI_MPUD18_ST_D18_R6_VIO		BIT(6)
+	#define EMI_MPUD18_ST_D18_R7_VIO		BIT(7)
+	#define EMI_MPUD18_ST_D18_R8_VIO		BIT(8)
+	#define EMI_MPUD18_ST_D18_R9_VIO		BIT(9)
+	#define EMI_MPUD18_ST_D18_R10_VIO		BIT(10)
+	#define EMI_MPUD18_ST_D18_R11_VIO		BIT(11)
+	#define EMI_MPUD18_ST_D18_R12_VIO		BIT(12)
+	#define EMI_MPUD18_ST_D18_R13_VIO		BIT(13)
+	#define EMI_MPUD18_ST_D18_R14_VIO		BIT(14)
+	#define EMI_MPUD18_ST_D18_R15_VIO		BIT(15)
+	#define EMI_MPUD18_ST_D18_R16_VIO		BIT(16)
+	#define EMI_MPUD18_ST_D18_R17_VIO		BIT(17)
+	#define EMI_MPUD18_ST_D18_R18_VIO		BIT(18)
+	#define EMI_MPUD18_ST_D18_R19_VIO		BIT(19)
+	#define EMI_MPUD18_ST_D18_R20_VIO		BIT(20)
+	#define EMI_MPUD18_ST_D18_R21_VIO		BIT(21)
+	#define EMI_MPUD18_ST_D18_R22_VIO		BIT(22)
+	#define EMI_MPUD18_ST_D18_R23_VIO		BIT(23)
+	#define EMI_MPUD18_ST_D18_R24_VIO		BIT(24)
+	#define EMI_MPUD18_ST_D18_R25_VIO		BIT(25)
+	#define EMI_MPUD18_ST_D18_R26_VIO		BIT(26)
+	#define EMI_MPUD18_ST_D18_R27_VIO		BIT(27)
+	#define EMI_MPUD18_ST_D18_R28_VIO		BIT(28)
+	#define EMI_MPUD18_ST_D18_R29_VIO		BIT(29)
+	#define EMI_MPUD18_ST_D18_R30_VIO		BIT(30)
+	#define EMI_MPUD18_ST_D18_R31_VIO		BIT(31)
+#define EMI_MPUD19_ST					0x000001ac
+	#define EMI_MPUD19_ST_D19_R0_VIO		BIT(0)
+	#define EMI_MPUD19_ST_D19_R1_VIO		BIT(1)
+	#define EMI_MPUD19_ST_D19_R2_VIO		BIT(2)
+	#define EMI_MPUD19_ST_D19_R3_VIO		BIT(3)
+	#define EMI_MPUD19_ST_D19_R4_VIO		BIT(4)
+	#define EMI_MPUD19_ST_D19_R5_VIO		BIT(5)
+	#define EMI_MPUD19_ST_D19_R6_VIO		BIT(6)
+	#define EMI_MPUD19_ST_D19_R7_VIO		BIT(7)
+	#define EMI_MPUD19_ST_D19_R8_VIO		BIT(8)
+	#define EMI_MPUD19_ST_D19_R9_VIO		BIT(9)
+	#define EMI_MPUD19_ST_D19_R10_VIO		BIT(10)
+	#define EMI_MPUD19_ST_D19_R11_VIO		BIT(11)
+	#define EMI_MPUD19_ST_D19_R12_VIO		BIT(12)
+	#define EMI_MPUD19_ST_D19_R13_VIO		BIT(13)
+	#define EMI_MPUD19_ST_D19_R14_VIO		BIT(14)
+	#define EMI_MPUD19_ST_D19_R15_VIO		BIT(15)
+	#define EMI_MPUD19_ST_D19_R16_VIO		BIT(16)
+	#define EMI_MPUD19_ST_D19_R17_VIO		BIT(17)
+	#define EMI_MPUD19_ST_D19_R18_VIO		BIT(18)
+	#define EMI_MPUD19_ST_D19_R19_VIO		BIT(19)
+	#define EMI_MPUD19_ST_D19_R20_VIO		BIT(20)
+	#define EMI_MPUD19_ST_D19_R21_VIO		BIT(21)
+	#define EMI_MPUD19_ST_D19_R22_VIO		BIT(22)
+	#define EMI_MPUD19_ST_D19_R23_VIO		BIT(23)
+	#define EMI_MPUD19_ST_D19_R24_VIO		BIT(24)
+	#define EMI_MPUD19_ST_D19_R25_VIO		BIT(25)
+	#define EMI_MPUD19_ST_D19_R26_VIO		BIT(26)
+	#define EMI_MPUD19_ST_D19_R27_VIO		BIT(27)
+	#define EMI_MPUD19_ST_D19_R28_VIO		BIT(28)
+	#define EMI_MPUD19_ST_D19_R29_VIO		BIT(29)
+	#define EMI_MPUD19_ST_D19_R30_VIO		BIT(30)
+	#define EMI_MPUD19_ST_D19_R31_VIO		BIT(31)
+#define EMI_MPUD20_ST					0x000001b0
+	#define EMI_MPUD20_ST_D20_R0_VIO		BIT(0)
+	#define EMI_MPUD20_ST_D20_R1_VIO		BIT(1)
+	#define EMI_MPUD20_ST_D20_R2_VIO		BIT(2)
+	#define EMI_MPUD20_ST_D20_R3_VIO		BIT(3)
+	#define EMI_MPUD20_ST_D20_R4_VIO		BIT(4)
+	#define EMI_MPUD20_ST_D20_R5_VIO		BIT(5)
+	#define EMI_MPUD20_ST_D20_R6_VIO		BIT(6)
+	#define EMI_MPUD20_ST_D20_R7_VIO		BIT(7)
+	#define EMI_MPUD20_ST_D20_R8_VIO		BIT(8)
+	#define EMI_MPUD20_ST_D20_R9_VIO		BIT(9)
+	#define EMI_MPUD20_ST_D20_R10_VIO		BIT(10)
+	#define EMI_MPUD20_ST_D20_R11_VIO		BIT(11)
+	#define EMI_MPUD20_ST_D20_R12_VIO		BIT(12)
+	#define EMI_MPUD20_ST_D20_R13_VIO		BIT(13)
+	#define EMI_MPUD20_ST_D20_R14_VIO		BIT(14)
+	#define EMI_MPUD20_ST_D20_R15_VIO		BIT(15)
+	#define EMI_MPUD20_ST_D20_R16_VIO		BIT(16)
+	#define EMI_MPUD20_ST_D20_R17_VIO		BIT(17)
+	#define EMI_MPUD20_ST_D20_R18_VIO		BIT(18)
+	#define EMI_MPUD20_ST_D20_R19_VIO		BIT(19)
+	#define EMI_MPUD20_ST_D20_R20_VIO		BIT(20)
+	#define EMI_MPUD20_ST_D20_R21_VIO		BIT(21)
+	#define EMI_MPUD20_ST_D20_R22_VIO		BIT(22)
+	#define EMI_MPUD20_ST_D20_R23_VIO		BIT(23)
+	#define EMI_MPUD20_ST_D20_R24_VIO		BIT(24)
+	#define EMI_MPUD20_ST_D20_R25_VIO		BIT(25)
+	#define EMI_MPUD20_ST_D20_R26_VIO		BIT(26)
+	#define EMI_MPUD20_ST_D20_R27_VIO		BIT(27)
+	#define EMI_MPUD20_ST_D20_R28_VIO		BIT(28)
+	#define EMI_MPUD20_ST_D20_R29_VIO		BIT(29)
+	#define EMI_MPUD20_ST_D20_R30_VIO		BIT(30)
+	#define EMI_MPUD20_ST_D20_R31_VIO		BIT(31)
+#define EMI_MPUD21_ST					0x000001b4
+	#define EMI_MPUD21_ST_D21_R0_VIO		BIT(0)
+	#define EMI_MPUD21_ST_D21_R1_VIO		BIT(1)
+	#define EMI_MPUD21_ST_D21_R2_VIO		BIT(2)
+	#define EMI_MPUD21_ST_D21_R3_VIO		BIT(3)
+	#define EMI_MPUD21_ST_D21_R4_VIO		BIT(4)
+	#define EMI_MPUD21_ST_D21_R5_VIO		BIT(5)
+	#define EMI_MPUD21_ST_D21_R6_VIO		BIT(6)
+	#define EMI_MPUD21_ST_D21_R7_VIO		BIT(7)
+	#define EMI_MPUD21_ST_D21_R8_VIO		BIT(8)
+	#define EMI_MPUD21_ST_D21_R9_VIO		BIT(9)
+	#define EMI_MPUD21_ST_D21_R10_VIO		BIT(10)
+	#define EMI_MPUD21_ST_D21_R11_VIO		BIT(11)
+	#define EMI_MPUD21_ST_D21_R12_VIO		BIT(12)
+	#define EMI_MPUD21_ST_D21_R13_VIO		BIT(13)
+	#define EMI_MPUD21_ST_D21_R14_VIO		BIT(14)
+	#define EMI_MPUD21_ST_D21_R15_VIO		BIT(15)
+	#define EMI_MPUD21_ST_D21_R16_VIO		BIT(16)
+	#define EMI_MPUD21_ST_D21_R17_VIO		BIT(17)
+	#define EMI_MPUD21_ST_D21_R18_VIO		BIT(18)
+	#define EMI_MPUD21_ST_D21_R19_VIO		BIT(19)
+	#define EMI_MPUD21_ST_D21_R20_VIO		BIT(20)
+	#define EMI_MPUD21_ST_D21_R21_VIO		BIT(21)
+	#define EMI_MPUD21_ST_D21_R22_VIO		BIT(22)
+	#define EMI_MPUD21_ST_D21_R23_VIO		BIT(23)
+	#define EMI_MPUD21_ST_D21_R24_VIO		BIT(24)
+	#define EMI_MPUD21_ST_D21_R25_VIO		BIT(25)
+	#define EMI_MPUD21_ST_D21_R26_VIO		BIT(26)
+	#define EMI_MPUD21_ST_D21_R27_VIO		BIT(27)
+	#define EMI_MPUD21_ST_D21_R28_VIO		BIT(28)
+	#define EMI_MPUD21_ST_D21_R29_VIO		BIT(29)
+	#define EMI_MPUD21_ST_D21_R30_VIO		BIT(30)
+	#define EMI_MPUD21_ST_D21_R31_VIO		BIT(31)
+#define EMI_MPUD22_ST					0x000001b8
+	#define EMI_MPUD22_ST_D22_R0_VIO		BIT(0)
+	#define EMI_MPUD22_ST_D22_R1_VIO		BIT(1)
+	#define EMI_MPUD22_ST_D22_R2_VIO		BIT(2)
+	#define EMI_MPUD22_ST_D22_R3_VIO		BIT(3)
+	#define EMI_MPUD22_ST_D22_R4_VIO		BIT(4)
+	#define EMI_MPUD22_ST_D22_R5_VIO		BIT(5)
+	#define EMI_MPUD22_ST_D22_R6_VIO		BIT(6)
+	#define EMI_MPUD22_ST_D22_R7_VIO		BIT(7)
+	#define EMI_MPUD22_ST_D22_R8_VIO		BIT(8)
+	#define EMI_MPUD22_ST_D22_R9_VIO		BIT(9)
+	#define EMI_MPUD22_ST_D22_R10_VIO		BIT(10)
+	#define EMI_MPUD22_ST_D22_R11_VIO		BIT(11)
+	#define EMI_MPUD22_ST_D22_R12_VIO		BIT(12)
+	#define EMI_MPUD22_ST_D22_R13_VIO		BIT(13)
+	#define EMI_MPUD22_ST_D22_R14_VIO		BIT(14)
+	#define EMI_MPUD22_ST_D22_R15_VIO		BIT(15)
+	#define EMI_MPUD22_ST_D22_R16_VIO		BIT(16)
+	#define EMI_MPUD22_ST_D22_R17_VIO		BIT(17)
+	#define EMI_MPUD22_ST_D22_R18_VIO		BIT(18)
+	#define EMI_MPUD22_ST_D22_R19_VIO		BIT(19)
+	#define EMI_MPUD22_ST_D22_R20_VIO		BIT(20)
+	#define EMI_MPUD22_ST_D22_R21_VIO		BIT(21)
+	#define EMI_MPUD22_ST_D22_R22_VIO		BIT(22)
+	#define EMI_MPUD22_ST_D22_R23_VIO		BIT(23)
+	#define EMI_MPUD22_ST_D22_R24_VIO		BIT(24)
+	#define EMI_MPUD22_ST_D22_R25_VIO		BIT(25)
+	#define EMI_MPUD22_ST_D22_R26_VIO		BIT(26)
+	#define EMI_MPUD22_ST_D22_R27_VIO		BIT(27)
+	#define EMI_MPUD22_ST_D22_R28_VIO		BIT(28)
+	#define EMI_MPUD22_ST_D22_R29_VIO		BIT(29)
+	#define EMI_MPUD22_ST_D22_R30_VIO		BIT(30)
+	#define EMI_MPUD22_ST_D22_R31_VIO		BIT(31)
+#define EMI_MPUD23_ST					0x000001bc
+	#define EMI_MPUD23_ST_D23_R0_VIO		BIT(0)
+	#define EMI_MPUD23_ST_D23_R1_VIO		BIT(1)
+	#define EMI_MPUD23_ST_D23_R2_VIO		BIT(2)
+	#define EMI_MPUD23_ST_D23_R3_VIO		BIT(3)
+	#define EMI_MPUD23_ST_D23_R4_VIO		BIT(4)
+	#define EMI_MPUD23_ST_D23_R5_VIO		BIT(5)
+	#define EMI_MPUD23_ST_D23_R6_VIO		BIT(6)
+	#define EMI_MPUD23_ST_D23_R7_VIO		BIT(7)
+	#define EMI_MPUD23_ST_D23_R8_VIO		BIT(8)
+	#define EMI_MPUD23_ST_D23_R9_VIO		BIT(9)
+	#define EMI_MPUD23_ST_D23_R10_VIO		BIT(10)
+	#define EMI_MPUD23_ST_D23_R11_VIO		BIT(11)
+	#define EMI_MPUD23_ST_D23_R12_VIO		BIT(12)
+	#define EMI_MPUD23_ST_D23_R13_VIO		BIT(13)
+	#define EMI_MPUD23_ST_D23_R14_VIO		BIT(14)
+	#define EMI_MPUD23_ST_D23_R15_VIO		BIT(15)
+	#define EMI_MPUD23_ST_D23_R16_VIO		BIT(16)
+	#define EMI_MPUD23_ST_D23_R17_VIO		BIT(17)
+	#define EMI_MPUD23_ST_D23_R18_VIO		BIT(18)
+	#define EMI_MPUD23_ST_D23_R19_VIO		BIT(19)
+	#define EMI_MPUD23_ST_D23_R20_VIO		BIT(20)
+	#define EMI_MPUD23_ST_D23_R21_VIO		BIT(21)
+	#define EMI_MPUD23_ST_D23_R22_VIO		BIT(22)
+	#define EMI_MPUD23_ST_D23_R23_VIO		BIT(23)
+	#define EMI_MPUD23_ST_D23_R24_VIO		BIT(24)
+	#define EMI_MPUD23_ST_D23_R25_VIO		BIT(25)
+	#define EMI_MPUD23_ST_D23_R26_VIO		BIT(26)
+	#define EMI_MPUD23_ST_D23_R27_VIO		BIT(27)
+	#define EMI_MPUD23_ST_D23_R28_VIO		BIT(28)
+	#define EMI_MPUD23_ST_D23_R29_VIO		BIT(29)
+	#define EMI_MPUD23_ST_D23_R30_VIO		BIT(30)
+	#define EMI_MPUD23_ST_D23_R31_VIO		BIT(31)
+#define EMI_MPUD24_ST					0x000001c0
+	#define EMI_MPUD24_ST_D24_R0_VIO		BIT(0)
+	#define EMI_MPUD24_ST_D24_R1_VIO		BIT(1)
+	#define EMI_MPUD24_ST_D24_R2_VIO		BIT(2)
+	#define EMI_MPUD24_ST_D24_R3_VIO		BIT(3)
+	#define EMI_MPUD24_ST_D24_R4_VIO		BIT(4)
+	#define EMI_MPUD24_ST_D24_R5_VIO		BIT(5)
+	#define EMI_MPUD24_ST_D24_R6_VIO		BIT(6)
+	#define EMI_MPUD24_ST_D24_R7_VIO		BIT(7)
+	#define EMI_MPUD24_ST_D24_R8_VIO		BIT(8)
+	#define EMI_MPUD24_ST_D24_R9_VIO		BIT(9)
+	#define EMI_MPUD24_ST_D24_R10_VIO		BIT(10)
+	#define EMI_MPUD24_ST_D24_R11_VIO		BIT(11)
+	#define EMI_MPUD24_ST_D24_R12_VIO		BIT(12)
+	#define EMI_MPUD24_ST_D24_R13_VIO		BIT(13)
+	#define EMI_MPUD24_ST_D24_R14_VIO		BIT(14)
+	#define EMI_MPUD24_ST_D24_R15_VIO		BIT(15)
+	#define EMI_MPUD24_ST_D24_R16_VIO		BIT(16)
+	#define EMI_MPUD24_ST_D24_R17_VIO		BIT(17)
+	#define EMI_MPUD24_ST_D24_R18_VIO		BIT(18)
+	#define EMI_MPUD24_ST_D24_R19_VIO		BIT(19)
+	#define EMI_MPUD24_ST_D24_R20_VIO		BIT(20)
+	#define EMI_MPUD24_ST_D24_R21_VIO		BIT(21)
+	#define EMI_MPUD24_ST_D24_R22_VIO		BIT(22)
+	#define EMI_MPUD24_ST_D24_R23_VIO		BIT(23)
+	#define EMI_MPUD24_ST_D24_R24_VIO		BIT(24)
+	#define EMI_MPUD24_ST_D24_R25_VIO		BIT(25)
+	#define EMI_MPUD24_ST_D24_R26_VIO		BIT(26)
+	#define EMI_MPUD24_ST_D24_R27_VIO		BIT(27)
+	#define EMI_MPUD24_ST_D24_R28_VIO		BIT(28)
+	#define EMI_MPUD24_ST_D24_R29_VIO		BIT(29)
+	#define EMI_MPUD24_ST_D24_R30_VIO		BIT(30)
+	#define EMI_MPUD24_ST_D24_R31_VIO		BIT(31)
+#define EMI_MPUD25_ST					0x000001c4
+	#define EMI_MPUD25_ST_D25_R0_VIO		BIT(0)
+	#define EMI_MPUD25_ST_D25_R1_VIO		BIT(1)
+	#define EMI_MPUD25_ST_D25_R2_VIO		BIT(2)
+	#define EMI_MPUD25_ST_D25_R3_VIO		BIT(3)
+	#define EMI_MPUD25_ST_D25_R4_VIO		BIT(4)
+	#define EMI_MPUD25_ST_D25_R5_VIO		BIT(5)
+	#define EMI_MPUD25_ST_D25_R6_VIO		BIT(6)
+	#define EMI_MPUD25_ST_D25_R7_VIO		BIT(7)
+	#define EMI_MPUD25_ST_D25_R8_VIO		BIT(8)
+	#define EMI_MPUD25_ST_D25_R9_VIO		BIT(9)
+	#define EMI_MPUD25_ST_D25_R10_VIO		BIT(10)
+	#define EMI_MPUD25_ST_D25_R11_VIO		BIT(11)
+	#define EMI_MPUD25_ST_D25_R12_VIO		BIT(12)
+	#define EMI_MPUD25_ST_D25_R13_VIO		BIT(13)
+	#define EMI_MPUD25_ST_D25_R14_VIO		BIT(14)
+	#define EMI_MPUD25_ST_D25_R15_VIO		BIT(15)
+	#define EMI_MPUD25_ST_D25_R16_VIO		BIT(16)
+	#define EMI_MPUD25_ST_D25_R17_VIO		BIT(17)
+	#define EMI_MPUD25_ST_D25_R18_VIO		BIT(18)
+	#define EMI_MPUD25_ST_D25_R19_VIO		BIT(19)
+	#define EMI_MPUD25_ST_D25_R20_VIO		BIT(20)
+	#define EMI_MPUD25_ST_D25_R21_VIO		BIT(21)
+	#define EMI_MPUD25_ST_D25_R22_VIO		BIT(22)
+	#define EMI_MPUD25_ST_D25_R23_VIO		BIT(23)
+	#define EMI_MPUD25_ST_D25_R24_VIO		BIT(24)
+	#define EMI_MPUD25_ST_D25_R25_VIO		BIT(25)
+	#define EMI_MPUD25_ST_D25_R26_VIO		BIT(26)
+	#define EMI_MPUD25_ST_D25_R27_VIO		BIT(27)
+	#define EMI_MPUD25_ST_D25_R28_VIO		BIT(28)
+	#define EMI_MPUD25_ST_D25_R29_VIO		BIT(29)
+	#define EMI_MPUD25_ST_D25_R30_VIO		BIT(30)
+	#define EMI_MPUD25_ST_D25_R31_VIO		BIT(31)
+#define EMI_MPUD26_ST					0x000001c8
+	#define EMI_MPUD26_ST_D26_R0_VIO		BIT(0)
+	#define EMI_MPUD26_ST_D26_R1_VIO		BIT(1)
+	#define EMI_MPUD26_ST_D26_R2_VIO		BIT(2)
+	#define EMI_MPUD26_ST_D26_R3_VIO		BIT(3)
+	#define EMI_MPUD26_ST_D26_R4_VIO		BIT(4)
+	#define EMI_MPUD26_ST_D26_R5_VIO		BIT(5)
+	#define EMI_MPUD26_ST_D26_R6_VIO		BIT(6)
+	#define EMI_MPUD26_ST_D26_R7_VIO		BIT(7)
+	#define EMI_MPUD26_ST_D26_R8_VIO		BIT(8)
+	#define EMI_MPUD26_ST_D26_R9_VIO		BIT(9)
+	#define EMI_MPUD26_ST_D26_R10_VIO		BIT(10)
+	#define EMI_MPUD26_ST_D26_R11_VIO		BIT(11)
+	#define EMI_MPUD26_ST_D26_R12_VIO		BIT(12)
+	#define EMI_MPUD26_ST_D26_R13_VIO		BIT(13)
+	#define EMI_MPUD26_ST_D26_R14_VIO		BIT(14)
+	#define EMI_MPUD26_ST_D26_R15_VIO		BIT(15)
+	#define EMI_MPUD26_ST_D26_R16_VIO		BIT(16)
+	#define EMI_MPUD26_ST_D26_R17_VIO		BIT(17)
+	#define EMI_MPUD26_ST_D26_R18_VIO		BIT(18)
+	#define EMI_MPUD26_ST_D26_R19_VIO		BIT(19)
+	#define EMI_MPUD26_ST_D26_R20_VIO		BIT(20)
+	#define EMI_MPUD26_ST_D26_R21_VIO		BIT(21)
+	#define EMI_MPUD26_ST_D26_R22_VIO		BIT(22)
+	#define EMI_MPUD26_ST_D26_R23_VIO		BIT(23)
+	#define EMI_MPUD26_ST_D26_R24_VIO		BIT(24)
+	#define EMI_MPUD26_ST_D26_R25_VIO		BIT(25)
+	#define EMI_MPUD26_ST_D26_R26_VIO		BIT(26)
+	#define EMI_MPUD26_ST_D26_R27_VIO		BIT(27)
+	#define EMI_MPUD26_ST_D26_R28_VIO		BIT(28)
+	#define EMI_MPUD26_ST_D26_R29_VIO		BIT(29)
+	#define EMI_MPUD26_ST_D26_R30_VIO		BIT(30)
+	#define EMI_MPUD26_ST_D26_R31_VIO		BIT(31)
+#define EMI_MPUD27_ST					0x000001cc
+	#define EMI_MPUD27_ST_D27_R0_VIO		BIT(0)
+	#define EMI_MPUD27_ST_D27_R1_VIO		BIT(1)
+	#define EMI_MPUD27_ST_D27_R2_VIO		BIT(2)
+	#define EMI_MPUD27_ST_D27_R3_VIO		BIT(3)
+	#define EMI_MPUD27_ST_D27_R4_VIO		BIT(4)
+	#define EMI_MPUD27_ST_D27_R5_VIO		BIT(5)
+	#define EMI_MPUD27_ST_D27_R6_VIO		BIT(6)
+	#define EMI_MPUD27_ST_D27_R7_VIO		BIT(7)
+	#define EMI_MPUD27_ST_D27_R8_VIO		BIT(8)
+	#define EMI_MPUD27_ST_D27_R9_VIO		BIT(9)
+	#define EMI_MPUD27_ST_D27_R10_VIO		BIT(10)
+	#define EMI_MPUD27_ST_D27_R11_VIO		BIT(11)
+	#define EMI_MPUD27_ST_D27_R12_VIO		BIT(12)
+	#define EMI_MPUD27_ST_D27_R13_VIO		BIT(13)
+	#define EMI_MPUD27_ST_D27_R14_VIO		BIT(14)
+	#define EMI_MPUD27_ST_D27_R15_VIO		BIT(15)
+	#define EMI_MPUD27_ST_D27_R16_VIO		BIT(16)
+	#define EMI_MPUD27_ST_D27_R17_VIO		BIT(17)
+	#define EMI_MPUD27_ST_D27_R18_VIO		BIT(18)
+	#define EMI_MPUD27_ST_D27_R19_VIO		BIT(19)
+	#define EMI_MPUD27_ST_D27_R20_VIO		BIT(20)
+	#define EMI_MPUD27_ST_D27_R21_VIO		BIT(21)
+	#define EMI_MPUD27_ST_D27_R22_VIO		BIT(22)
+	#define EMI_MPUD27_ST_D27_R23_VIO		BIT(23)
+	#define EMI_MPUD27_ST_D27_R24_VIO		BIT(24)
+	#define EMI_MPUD27_ST_D27_R25_VIO		BIT(25)
+	#define EMI_MPUD27_ST_D27_R26_VIO		BIT(26)
+	#define EMI_MPUD27_ST_D27_R27_VIO		BIT(27)
+	#define EMI_MPUD27_ST_D27_R28_VIO		BIT(28)
+	#define EMI_MPUD27_ST_D27_R29_VIO		BIT(29)
+	#define EMI_MPUD27_ST_D27_R30_VIO		BIT(30)
+	#define EMI_MPUD27_ST_D27_R31_VIO		BIT(31)
+#define EMI_MPUD28_ST					0x000001d0
+	#define EMI_MPUD28_ST_D28_R0_VIO		BIT(0)
+	#define EMI_MPUD28_ST_D28_R1_VIO		BIT(1)
+	#define EMI_MPUD28_ST_D28_R2_VIO		BIT(2)
+	#define EMI_MPUD28_ST_D28_R3_VIO		BIT(3)
+	#define EMI_MPUD28_ST_D28_R4_VIO		BIT(4)
+	#define EMI_MPUD28_ST_D28_R5_VIO		BIT(5)
+	#define EMI_MPUD28_ST_D28_R6_VIO		BIT(6)
+	#define EMI_MPUD28_ST_D28_R7_VIO		BIT(7)
+	#define EMI_MPUD28_ST_D28_R8_VIO		BIT(8)
+	#define EMI_MPUD28_ST_D28_R9_VIO		BIT(9)
+	#define EMI_MPUD28_ST_D28_R10_VIO		BIT(10)
+	#define EMI_MPUD28_ST_D28_R11_VIO		BIT(11)
+	#define EMI_MPUD28_ST_D28_R12_VIO		BIT(12)
+	#define EMI_MPUD28_ST_D28_R13_VIO		BIT(13)
+	#define EMI_MPUD28_ST_D28_R14_VIO		BIT(14)
+	#define EMI_MPUD28_ST_D28_R15_VIO		BIT(15)
+	#define EMI_MPUD28_ST_D28_R16_VIO		BIT(16)
+	#define EMI_MPUD28_ST_D28_R17_VIO		BIT(17)
+	#define EMI_MPUD28_ST_D28_R18_VIO		BIT(18)
+	#define EMI_MPUD28_ST_D28_R19_VIO		BIT(19)
+	#define EMI_MPUD28_ST_D28_R20_VIO		BIT(20)
+	#define EMI_MPUD28_ST_D28_R21_VIO		BIT(21)
+	#define EMI_MPUD28_ST_D28_R22_VIO		BIT(22)
+	#define EMI_MPUD28_ST_D28_R23_VIO		BIT(23)
+	#define EMI_MPUD28_ST_D28_R24_VIO		BIT(24)
+	#define EMI_MPUD28_ST_D28_R25_VIO		BIT(25)
+	#define EMI_MPUD28_ST_D28_R26_VIO		BIT(26)
+	#define EMI_MPUD28_ST_D28_R27_VIO		BIT(27)
+	#define EMI_MPUD28_ST_D28_R28_VIO		BIT(28)
+	#define EMI_MPUD28_ST_D28_R29_VIO		BIT(29)
+	#define EMI_MPUD28_ST_D28_R30_VIO		BIT(30)
+	#define EMI_MPUD28_ST_D28_R31_VIO		BIT(31)
+#define EMI_MPUD29_ST					0x000001d4
+	#define EMI_MPUD29_ST_D29_R0_VIO		BIT(0)
+	#define EMI_MPUD29_ST_D29_R1_VIO		BIT(1)
+	#define EMI_MPUD29_ST_D29_R2_VIO		BIT(2)
+	#define EMI_MPUD29_ST_D29_R3_VIO		BIT(3)
+	#define EMI_MPUD29_ST_D29_R4_VIO		BIT(4)
+	#define EMI_MPUD29_ST_D29_R5_VIO		BIT(5)
+	#define EMI_MPUD29_ST_D29_R6_VIO		BIT(6)
+	#define EMI_MPUD29_ST_D29_R7_VIO		BIT(7)
+	#define EMI_MPUD29_ST_D29_R8_VIO		BIT(8)
+	#define EMI_MPUD29_ST_D29_R9_VIO		BIT(9)
+	#define EMI_MPUD29_ST_D29_R10_VIO		BIT(10)
+	#define EMI_MPUD29_ST_D29_R11_VIO		BIT(11)
+	#define EMI_MPUD29_ST_D29_R12_VIO		BIT(12)
+	#define EMI_MPUD29_ST_D29_R13_VIO		BIT(13)
+	#define EMI_MPUD29_ST_D29_R14_VIO		BIT(14)
+	#define EMI_MPUD29_ST_D29_R15_VIO		BIT(15)
+	#define EMI_MPUD29_ST_D29_R16_VIO		BIT(16)
+	#define EMI_MPUD29_ST_D29_R17_VIO		BIT(17)
+	#define EMI_MPUD29_ST_D29_R18_VIO		BIT(18)
+	#define EMI_MPUD29_ST_D29_R19_VIO		BIT(19)
+	#define EMI_MPUD29_ST_D29_R20_VIO		BIT(20)
+	#define EMI_MPUD29_ST_D29_R21_VIO		BIT(21)
+	#define EMI_MPUD29_ST_D29_R22_VIO		BIT(22)
+	#define EMI_MPUD29_ST_D29_R23_VIO		BIT(23)
+	#define EMI_MPUD29_ST_D29_R24_VIO		BIT(24)
+	#define EMI_MPUD29_ST_D29_R25_VIO		BIT(25)
+	#define EMI_MPUD29_ST_D29_R26_VIO		BIT(26)
+	#define EMI_MPUD29_ST_D29_R27_VIO		BIT(27)
+	#define EMI_MPUD29_ST_D29_R28_VIO		BIT(28)
+	#define EMI_MPUD29_ST_D29_R29_VIO		BIT(29)
+	#define EMI_MPUD29_ST_D29_R30_VIO		BIT(30)
+	#define EMI_MPUD29_ST_D29_R31_VIO		BIT(31)
+#define EMI_MPUD30_ST					0x000001d8
+	#define EMI_MPUD30_ST_D30_R0_VIO		BIT(0)
+	#define EMI_MPUD30_ST_D30_R1_VIO		BIT(1)
+	#define EMI_MPUD30_ST_D30_R2_VIO		BIT(2)
+	#define EMI_MPUD30_ST_D30_R3_VIO		BIT(3)
+	#define EMI_MPUD30_ST_D30_R4_VIO		BIT(4)
+	#define EMI_MPUD30_ST_D30_R5_VIO		BIT(5)
+	#define EMI_MPUD30_ST_D30_R6_VIO		BIT(6)
+	#define EMI_MPUD30_ST_D30_R7_VIO		BIT(7)
+	#define EMI_MPUD30_ST_D30_R8_VIO		BIT(8)
+	#define EMI_MPUD30_ST_D30_R9_VIO		BIT(9)
+	#define EMI_MPUD30_ST_D30_R10_VIO		BIT(10)
+	#define EMI_MPUD30_ST_D30_R11_VIO		BIT(11)
+	#define EMI_MPUD30_ST_D30_R12_VIO		BIT(12)
+	#define EMI_MPUD30_ST_D30_R13_VIO		BIT(13)
+	#define EMI_MPUD30_ST_D30_R14_VIO		BIT(14)
+	#define EMI_MPUD30_ST_D30_R15_VIO		BIT(15)
+	#define EMI_MPUD30_ST_D30_R16_VIO		BIT(16)
+	#define EMI_MPUD30_ST_D30_R17_VIO		BIT(17)
+	#define EMI_MPUD30_ST_D30_R18_VIO		BIT(18)
+	#define EMI_MPUD30_ST_D30_R19_VIO		BIT(19)
+	#define EMI_MPUD30_ST_D30_R20_VIO		BIT(20)
+	#define EMI_MPUD30_ST_D30_R21_VIO		BIT(21)
+	#define EMI_MPUD30_ST_D30_R22_VIO		BIT(22)
+	#define EMI_MPUD30_ST_D30_R23_VIO		BIT(23)
+	#define EMI_MPUD30_ST_D30_R24_VIO		BIT(24)
+	#define EMI_MPUD30_ST_D30_R25_VIO		BIT(25)
+	#define EMI_MPUD30_ST_D30_R26_VIO		BIT(26)
+	#define EMI_MPUD30_ST_D30_R27_VIO		BIT(27)
+	#define EMI_MPUD30_ST_D30_R28_VIO		BIT(28)
+	#define EMI_MPUD30_ST_D30_R29_VIO		BIT(29)
+	#define EMI_MPUD30_ST_D30_R30_VIO		BIT(30)
+	#define EMI_MPUD30_ST_D30_R31_VIO		BIT(31)
+#define EMI_MPUD31_ST					0x000001dc
+	#define EMI_MPUD31_ST_D31_R0_VIO		BIT(0)
+	#define EMI_MPUD31_ST_D31_R1_VIO		BIT(1)
+	#define EMI_MPUD31_ST_D31_R2_VIO		BIT(2)
+	#define EMI_MPUD31_ST_D31_R3_VIO		BIT(3)
+	#define EMI_MPUD31_ST_D31_R4_VIO		BIT(4)
+	#define EMI_MPUD31_ST_D31_R5_VIO		BIT(5)
+	#define EMI_MPUD31_ST_D31_R6_VIO		BIT(6)
+	#define EMI_MPUD31_ST_D31_R7_VIO		BIT(7)
+	#define EMI_MPUD31_ST_D31_R8_VIO		BIT(8)
+	#define EMI_MPUD31_ST_D31_R9_VIO		BIT(9)
+	#define EMI_MPUD31_ST_D31_R10_VIO		BIT(10)
+	#define EMI_MPUD31_ST_D31_R11_VIO		BIT(11)
+	#define EMI_MPUD31_ST_D31_R12_VIO		BIT(12)
+	#define EMI_MPUD31_ST_D31_R13_VIO		BIT(13)
+	#define EMI_MPUD31_ST_D31_R14_VIO		BIT(14)
+	#define EMI_MPUD31_ST_D31_R15_VIO		BIT(15)
+	#define EMI_MPUD31_ST_D31_R16_VIO		BIT(16)
+	#define EMI_MPUD31_ST_D31_R17_VIO		BIT(17)
+	#define EMI_MPUD31_ST_D31_R18_VIO		BIT(18)
+	#define EMI_MPUD31_ST_D31_R19_VIO		BIT(19)
+	#define EMI_MPUD31_ST_D31_R20_VIO		BIT(20)
+	#define EMI_MPUD31_ST_D31_R21_VIO		BIT(21)
+	#define EMI_MPUD31_ST_D31_R22_VIO		BIT(22)
+	#define EMI_MPUD31_ST_D31_R23_VIO		BIT(23)
+	#define EMI_MPUD31_ST_D31_R24_VIO		BIT(24)
+	#define EMI_MPUD31_ST_D31_R25_VIO		BIT(25)
+	#define EMI_MPUD31_ST_D31_R26_VIO		BIT(26)
+	#define EMI_MPUD31_ST_D31_R27_VIO		BIT(27)
+	#define EMI_MPUD31_ST_D31_R28_VIO		BIT(28)
+	#define EMI_MPUD31_ST_D31_R29_VIO		BIT(29)
+	#define EMI_MPUD31_ST_D31_R30_VIO		BIT(30)
+	#define EMI_MPUD31_ST_D31_R31_VIO		BIT(31)
+#define EMI_MPUS					0x000001f0
+	#define EMI_MPUS_MASTER_ID			GENMASK(15, 0)
+	#define EMI_MPUS_REGION_ABORT			GENMASK(20, 16)
+	#define EMI_MPUS_DOMAIN_ID			GENMASK(24, 21)
+	#define EMI_MPUS_W_OO_VIO			BIT(27)
+	#define EMI_MPUS_R_OO_VIO			BIT(28)
+	#define EMI_MPUS_W_VIO				BIT(29)
+	#define EMI_MPUS_R_VIO				BIT(30)
+	#define EMI_MPUS_CLR				BIT(31)
+#define EMI_MPUT					0x000001f8
+	#define EMI_MPUT_MPU_ERROR_ADDR			GENMASK(31, 0)
+#define EMI_MPUT_2ND					0x000001fc
+	#define EMI_MPUT_2ND_MPU_ERROR_ADDR_EXT		GENMASK(3, 0)
+	#define EMI_MPUT_2ND_MASTER_ID_EXT		GENMASK(7, 4)
+	#define EMI_MPUT_2ND_DOMAIN_ID			BIT(16)
+#define EMI_D0_ST2					0x00000200
+	#define EMI_D0_ST2_D0_OO_VIO			BIT(0)
+	#define EMI_D0_ST2_D0_APB_VIO			BIT(1)
+#define EMI_D1_ST2					0x00000204
+	#define EMI_D1_ST2_D1_OO_VIO			BIT(0)
+	#define EMI_D1_ST2_D1_APB_VIO			BIT(1)
+#define EMI_D2_ST2					0x00000208
+	#define EMI_D2_ST2_D2_OO_VIO			BIT(0)
+	#define EMI_D2_ST2_D2_APB_VIO			BIT(1)
+#define EMI_D3_ST2					0x0000020c
+	#define EMI_D3_ST2_D3_OO_VIO			BIT(0)
+	#define EMI_D3_ST2_D3_APB_VIO			BIT(1)
+#define EMI_D4_ST2					0x00000210
+	#define EMI_D4_ST2_D4_OO_VIO			BIT(0)
+	#define EMI_D4_ST2_D4_APB_VIO			BIT(1)
+#define EMI_D5_ST2					0x00000214
+	#define EMI_D5_ST2_D5_OO_VIO			BIT(0)
+	#define EMI_D5_ST2_D5_APB_VIO			BIT(1)
+#define EMI_D6_ST2					0x00000218
+	#define EMI_D6_ST2_D6_OO_VIO			BIT(0)
+	#define EMI_D6_ST2_D6_APB_VIO			BIT(1)
+#define EMI_D7_ST2					0x0000021c
+	#define EMI_D7_ST2_D7_OO_VIO			BIT(0)
+	#define EMI_D7_ST2_D7_APB_VIO			BIT(1)
+#define EMI_D8_ST2					0x00000220
+	#define EMI_D8_ST2_D8_OO_VIO			BIT(0)
+	#define EMI_D8_ST2_D8_APB_VIO			BIT(1)
+#define EMI_D9_ST2					0x00000224
+	#define EMI_D9_ST2_D9_OO_VIO			BIT(0)
+	#define EMI_D9_ST2_D9_APB_VIO			BIT(1)
+#define EMI_D10_ST2					0x00000228
+	#define EMI_D10_ST2_D10_OO_VIO			BIT(0)
+	#define EMI_D10_ST2_D10_APB_VIO			BIT(1)
+#define EMI_D11_ST2					0x0000022c
+	#define EMI_D11_ST2_D11_OO_VIO			BIT(0)
+	#define EMI_D11_ST2_D11_APB_VIO			BIT(1)
+#define EMI_D12_ST2					0x00000230
+	#define EMI_D12_ST2_D12_OO_VIO			BIT(0)
+	#define EMI_D12_ST2_D12_APB_VIO			BIT(1)
+#define EMI_D13_ST2					0x00000234
+	#define EMI_D13_ST2_D13_OO_VIO			BIT(0)
+	#define EMI_D13_ST2_D13_APB_VIO			BIT(1)
+#define EMI_D14_ST2					0x00000238
+	#define EMI_D14_ST2_D14_OO_VIO			BIT(0)
+	#define EMI_D14_ST2_D14_APB_VIO			BIT(1)
+#define EMI_D15_ST2					0x0000023c
+	#define EMI_D15_ST2_D15_OO_VIO			BIT(0)
+	#define EMI_D15_ST2_D15_APB_VIO			BIT(1)
+#define EMI_D16_ST2					0x00000240
+	#define EMI_D16_ST2_D16_OO_VIO			BIT(0)
+	#define EMI_D16_ST2_D16_APB_VIO			BIT(1)
+#define EMI_D17_ST2					0x00000244
+	#define EMI_D17_ST2_D17_OO_VIO			BIT(0)
+	#define EMI_D17_ST2_D17_APB_VIO			BIT(1)
+#define EMI_D18_ST2					0x00000248
+	#define EMI_D18_ST2_D18_OO_VIO			BIT(0)
+	#define EMI_D18_ST2_D18_APB_VIO			BIT(1)
+#define EMI_D19_ST2					0x0000024c
+	#define EMI_D19_ST2_D19_OO_VIO			BIT(0)
+	#define EMI_D19_ST2_D19_APB_VIO			BIT(1)
+#define EMI_D20_ST2					0x00000250
+	#define EMI_D20_ST2_D20_OO_VIO			BIT(0)
+	#define EMI_D20_ST2_D20_APB_VIO			BIT(1)
+#define EMI_D21_ST2					0x00000254
+	#define EMI_D21_ST2_D21_OO_VIO			BIT(0)
+	#define EMI_D21_ST2_D21_APB_VIO			BIT(1)
+#define EMI_D22_ST2					0x00000258
+	#define EMI_D22_ST2_D22_OO_VIO			BIT(0)
+	#define EMI_D22_ST2_D22_APB_VIO			BIT(1)
+#define EMI_D23_ST2					0x0000025c
+	#define EMI_D23_ST2_D23_OO_VIO			BIT(0)
+	#define EMI_D23_ST2_D23_APB_VIO			BIT(1)
+#define EMI_D24_ST2					0x00000260
+	#define EMI_D24_ST2_D24_OO_VIO			BIT(0)
+	#define EMI_D24_ST2_D24_APB_VIO			BIT(1)
+#define EMI_D25_ST2					0x00000264
+	#define EMI_D25_ST2_D25_OO_VIO			BIT(0)
+	#define EMI_D25_ST2_D25_APB_VIO			BIT(1)
+#define EMI_D26_ST2					0x00000268
+	#define EMI_D26_ST2_D26_OO_VIO			BIT(0)
+	#define EMI_D26_ST2_D26_APB_VIO			BIT(1)
+#define EMI_D27_ST2					0x0000026c
+	#define EMI_D27_ST2_D27_OO_VIO			BIT(0)
+	#define EMI_D27_ST2_D27_APB_VIO			BIT(1)
+#define EMI_D28_ST2					0x00000270
+	#define EMI_D28_ST2_D28_OO_VIO			BIT(0)
+	#define EMI_D28_ST2_D28_APB_VIO			BIT(1)
+#define EMI_D29_ST2					0x00000274
+	#define EMI_D29_ST2_D29_OO_VIO			BIT(0)
+	#define EMI_D29_ST2_D29_APB_VIO			BIT(1)
+#define EMI_D30_ST2					0x00000278
+	#define EMI_D30_ST2_D30_OO_VIO			BIT(0)
+	#define EMI_D30_ST2_D30_APB_VIO			BIT(1)
+#define EMI_D31_ST2					0x0000027c
+	#define EMI_D31_ST2_D31_OO_VIO			BIT(0)
+	#define EMI_D31_ST2_D31_APB_VIO			BIT(1)
+#define EMI_BMEN					0x00000400
+	#define EMI_BMEN_BUS_MON_EN			BIT(0)
+	#define EMI_BMEN_BUS_MON_PAUSE			BIT(1)
+	#define EMI_BMEN_BUS_MON_STP			BIT(2)
+	#define EMI_BMEN_BUS_MON_RW			GENMASK(5, 4)
+	#define EMI_BMEN_BC_OVERRUN			BIT(8)
+	#define EMI_BMEN_SEL_MASTER			GENMASK(23, 16)
+#define EMI_BSTP					0x00000404
+	#define EMI_BSTP_BUSCYC_STOP			GENMASK(31, 0)
+#define EMI_BCNT					0x00000408
+	#define EMI_BCNT_BUSCYC_CNT			GENMASK(31, 0)
+#define EMI_TACT					0x00000410
+	#define EMI_TACT_TRANS_ALL_CNT			GENMASK(31, 0)
+#define EMI_TSCT					0x00000418
+	#define EMI_TSCT_TRANS_CNT			GENMASK(31, 0)
+#define EMI_WACT					0x00000420
+	#define EMI_WACT_WORD_ALL_CNT			GENMASK(31, 0)
+#define EMI_WSCT					0x00000428
+	#define EMI_WSCT_WORD_CNT			GENMASK(31, 0)
+#define EMI_BACT					0x00000430
+	#define EMI_BACT_BAND_WORD_CNT			GENMASK(31, 0)
+#define EMI_MSEL					0x00000440
+	#define EMI_MSEL_SEL2_MASTER			GENMASK(7, 0)
+	#define EMI_MSEL_SEL3_MASTER			GENMASK(23, 16)
+#define EMI_TSCT2					0x00000448
+	#define EMI_TSCT2_TRANS2_CNT			GENMASK(31, 0)
+#define EMI_TSCT3					0x00000450
+	#define EMI_TSCT3_TRANS3_CNT			GENMASK(31, 0)
+#define EMI_WSCT2					0x00000458
+	#define EMI_WSCT2_WORD2_CNT			GENMASK(31, 0)
+#define EMI_WSCT3					0x00000460
+	#define EMI_WSCT3_WORD3_CNT			GENMASK(31, 0)
+
+
+#endif /*__EMI_REG_REGS_H__*/
diff --git a/src/bsp/lk/platform/mt8518/include/platform/rt5748.h b/src/bsp/lk/platform/mt8518/include/platform/rt5748.h
new file mode 100644
index 0000000..8ace204
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/rt5748.h
@@ -0,0 +1,52 @@
+#ifndef _rt5748_SW_H_

+#define _rt5748_SW_H_

+

+//---------------------- AUTO GEN ---------------------------

+/* BUCK Registers */

+#define RT5748_REG_VSEL0	(0x00)

+#define RT5748_REG_VSEL1	(0x01)

+#define RT5748_REG_CTRL1	(0x02)

+#define RT5748_REG_ID1		(0x03)

+#define RT5748_REG_ID2		(0x04)

+#define RT5748_REG_MONITOR	(0x05)

+#define RT5748_REG_CTRL2	(0x06)

+#define RT5748_REG_CTRL3	(0x07)

+#define RT5748_REG_CTRL4	(0x08)

+

+/* PMIC Registers mask and shift,mask is HEX;shift is Integer*/

+#define rt5748_vsell_vol_mask	    0xff

+#define rt5748_vsell_vol_shift	    0

+#define rt5748_vsell_enable_mask	0x01

+#define rt5748_vsell_enable_shift	0

+#define rt5748_vsell_mode_mask	    0x01

+#define rt5748_vsell_mode_shift	    0x00

+

+#define rt5748_vselh_vol_mask	    0xff

+#define rt5748_vselh_vol_shift	    0

+#define rt5748_vselh_enable_mask    0x02

+#define rt5748_vselh_enable_shift   1

+#define rt5748_vselh_mode_mask	    0x02

+#define rt5748_vselh_mode_shift	    1

+

+#define rt5748_rampup_rate_mask	    0x07

+#define rt5748_rampup_rate_shift    4

+#define rt5748_rampdown_rate_mask	0x07

+#define rt5748_rampdown_rate_shift  5

+#define rt5748_softstart_rate_mask	0x03

+#define rt5748_softstart_rate_shift 2

+

+#define rt5748_discharge_func_mask	0x01

+#define rt5748_discharge_func_shift 7

+

+/*************************** I2C Slave Setting*********************************************/

+#define rt5748_SLAVE_ADDR   0x50

+#define rt5748_I2C_ID_P1    3

+#define rt5748_I2C_ID_M2    2

+

+//---------------------- EXPORT API ---------------------------

+extern u32 rt5748_config_interface (u8 RegNum, u8 val, u8 MASK, u8 SHIFT, u8 i2c_bus);

+extern u32 rt5748_read_interface (u8 RegNum, u8 *val, u8 MASK, u8 SHIFT, u8 i2c_bus);

+extern void rt5748_init(void);

+

+#endif

+

diff --git a/src/bsp/lk/platform/mt8518/include/platform/rt9460.h b/src/bsp/lk/platform/mt8518/include/platform/rt9460.h
new file mode 100644
index 0000000..94f1240
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/rt9460.h
@@ -0,0 +1,164 @@
+/*
+ * Richtek RT9460 Charger Header File
+ *
+ * Copyright (C) 2017, Richtek Technology Corp.
+ * Author: CY Hunag <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __I2C_CHARGER_RT9460_H
+#define __I2C_CHARGER_RT9460_H
+
+#define RT9460_REG_CTRL1    (0x00)
+#define RT9460_REG_CTRL2    (0x01)
+#define RT9460_REG_CTRL3    (0x02)
+#define RT9460_REG_DEVID    (0x03)
+#define RT9460_REG_CTRL4    (0x04)
+#define RT9460_REG_CTRL5    (0x05)
+#define RT9460_REG_CTRL6    (0x06)
+#define RT9460_REG_CTRL7    (0x07)
+#define RT9460_REG_IRQ1        (0x08)
+#define RT9460_REG_IRQ2        (0x09)
+#define RT9460_REG_IRQ3        (0x0A)
+#define RT9460_REG_MASK1    (0x0B)
+#define RT9460_REG_MASK2    (0x0C)
+#define RT9460_REG_MASK3    (0x0D)
+#define RT9460_REG_CTRLDPDM    (0x0E)
+#define RT9460_REG_CTRL8    (0x1C)
+#define RT9460_REG_CTRL9    (0x21)
+#define RT9460_REG_CTRL10    (0x22)
+#define RT9460_REG_CTRL11    (0x23)
+#define RT9460_REG_CTRL12    (0x24)
+#define RT9460_REG_CTRL13    (0x25)
+#define RT9460_REG_STATIRQ    (0x26)
+#define RT9460_REG_STATMASK    (0x27)
+#define RT9460_REG_HIDDEN1    (0x31)
+
+/* RT9460_REG_IRQ1 ~ IRQ3 + RT9460_REG_STATIRQ */
+#define RT9460_IRQ_REGNUM (4)
+enum {
+    RT9460_IRQ_BATABI = 0,
+    RT9460_IRQ_SYSUVPI,
+    RT9460_IRQ_CHTERM_TMRI,
+    RT9460_IRQ_WATCHDOGI = 4,
+    RT9460_IRQ_WAKEUPI,
+    RT9460_IRQ_VINOVPI = 6,
+    RT9460_IRQ_TSDI,
+    RT9460_IRQ_SYSWAKEUPI = 8,
+    RT9460_IRQ_CHTREGI,
+    RT9460_IRQ_CHTMRI,
+    RT9460_IRQ_CHRCHGI,
+    RT9460_IRQ_CHTERMI,
+    RT9460_IRQ_CHBATOVI,
+    RT9460_IRQ_CHBADI,
+    RT9460_IRQ_CHRVPI,
+    RT9460_IRQ_BSTLOWVI = 21,
+    RT9460_IRQ_BSTOLI,
+    RT9460_IRQ_BSTVINOVI,
+    RT9460_IRQ_MIVRI = 26,
+    RT9460_IRQ_PWR_RDYI,
+    RT9460_IRQ_TSCOLDI,
+    RT9460_IRQ_TSCOOLI,
+    RT9460_IRQ_TSWARMI,
+    RT9460_IRQ_TSHOTI,
+    RT9460_IRQ_MAXNUM,
+};
+
+/* RT9460_REG_CTRL1 : 0x00 */
+#define RT9460_STATEN_MASK    (0x40)
+#define RT9460_STAT_MASK    (0x30)
+#define RT9460_STAT_SHFT    (4)
+#define RT9460_STAT_MAX        (3)
+#define RT9460_PWRRDY_MASK    (0x04)
+
+/* RT9460_REG_CTRL2 : 0x01 */
+#define RT9460_IEOC_MASK    (0xe0)
+#define RT9460_IEOC_SHFT    (5)
+#define RT9460_IEOC_MAX        (0x7)
+#define RT9460_TEEN_MASK    (0x08)
+#define RT9460_IININT_MASK    (0x04)
+#define RT9460_HZ_MASK        (0x02)
+#define RT9460_OPAMODE_MASK    (0x01)
+
+/* RT9460_REG_CTRL3 : 0x02 */
+#define RT9460_VOREG_MASK    (0xfc)
+#define RT9460_VOREG_SHFT    (2)
+#define RT9460_VOREG_MAX    (0x38)
+
+/* RT9460_REG_CTRL5 : 0x05 */
+#define RT9460_OTGOC_MASK    (0x40)
+#define RT9460_IPREC_MASK    (0x0f)
+#define RT9460_IPREC_SHFT    (0)
+#define RT9460_IPREC_MAX    (0x0f)
+
+/* RT9460_REG_CTRL6 : 0x06 */
+#define RT9460_ICHG_MASK    (0xf0)
+#define RT9460_ICHG_SHFT    (4)
+#define RT9460_ICHG_MAX        (0xf)
+#define RT9460_VPREC_MASK    (0x07)
+#define RT9460_VPREC_SHFT    (0)
+#define RT9460_VPREC_MAX    (0x05)
+
+/* RT9460_REG_CTRL7 : 0x07 */
+#define RT9460_CCJEITAEN_MASK    (0x80)
+#define RT9460_BATDEN_MASK    (0x40)
+#define RT9460_TSHOT_MASK    (0x08)
+#define RT9460_TSWARM_MASK    (0x04)
+#define RT9460_TSCOOL_MASK    (0x02)
+#define RT9460_TSCOLD_MASK    (0x01)
+/* MTK proprietary ++ */
+/* MTK power path mean rt chipen, charger enable mean rt power path_en */
+#define RT9460_CHIPEN_MASK    (0x20)
+#define RT9460_CHGEN_MASK    (0x10)
+/* MTK proprietary -- */
+
+/* RT9460_REG_CTRLDPDM : 0x0E */
+#define RT9460_IINLMTSEL_MASK    (0x18)
+#define RT9460_IINLMTSEL_SHFT    (3)
+#define RT9460_CHGRUN_MASK    (0x01)
+#define RT9460_CHGTYP_SHFT    (5)
+#define RT9460_CHGTYP_MASK    (0xE0)
+#define RT9460_CHGDET_MASK    (0x06)
+
+
+/* RT9460_REG_CTRL9 : 0x21 */
+#define RT9460_MIVRDIS_MASK    (0x10)
+#define RT9460_MIVRLVL_MASK    (0x0F)
+#define RT9460_MIVRLVL_SHFT    (0)
+#define RT9460_MIVRLVL_MAX    (0x0b)
+
+/* RT9460_REG_CTRL10 : 0x22 */
+#define RT9460_WTFC_MASK    (0x38)
+#define RT9460_WTFC_SHFT    (3)
+#define RT9460_WTFC_MAX        (0x7)
+#define RT9460_WTPRC_MASK    (0x06)
+#define RT9460_WTPRC_SHFT    (1)
+#define RT9460_WTPRC_MAX    (0x3)
+#define RT9460_TMRPAUSE_MASK    (0x01)
+
+/* RT9460_REG_CTRL11 : 0x23 */
+#define RT9460_IAICR_MASK    (0xf8)
+#define RT9460_IAICR_SHFT    (3)
+#define RT9460_IAICR_MAX    (0x1f)
+
+/* RT9460_REG_CTRL12 : 0x24 */
+#define RT9460_EOCTIMER_MASK    (0xc0)
+#define RT9460_EOCTIMER_SHFT    (6)
+#define RT9460_EOCTIMER_MAX    (0x3)
+#define RT9460_WKTMREN_MASK    (0x04)
+#define RT9460_IRQPULSE_MASK    (0x02)
+#define RT9460_IRQREZ_MASK    (0x01)
+
+/* RT9460_REG_CTRL13 : 0x25 */
+#define RT9460_WDTEN_MASK    (0x80)
+#define RT9460_TWDT_MASK    (0x03)
+#define RT9460_TWDT_SHFT    (0)
+#define RT9460_TWDT_MAX        (0x3)
+
+extern int rt9460IsCableIn(void);
+extern unsigned int rt9460TypeDetection(void);
+
+#endif /* #ifndef __I2C_CHARGER_RT9460_H */
diff --git a/src/bsp/lk/platform/mt8518/include/platform/sec_devinfo.h b/src/bsp/lk/platform/mt8518/include/platform/sec_devinfo.h
new file mode 100644
index 0000000..ab82ce2
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/sec_devinfo.h
@@ -0,0 +1,37 @@
+/* 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) 2018. 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.
+*/
+#pragma once
+
+extern unsigned int seclib_get_devinfo_with_index(unsigned int index);
\ No newline at end of file
diff --git a/src/bsp/lk/platform/mt8518/include/platform/spm.h b/src/bsp/lk/platform/mt8518/include/platform/spm.h
new file mode 100644
index 0000000..40aa0e0
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/spm.h
@@ -0,0 +1,193 @@
+#ifndef _SPM_
+#define _SPM_
+
+#include <platform.h>
+#include <platform/mt8518.h>
+#include <platform/mt_reg_base.h>
+
+#define SPM_BASE        	(IO_PHYS + 0x00006000)
+
+/**************************************
+ * Define and Declare
+ **************************************/
+#define	SPM_POWERON_CONFIG_SET                (SPM_BASE + 0x000)
+#define	SPM_POWER_ON_VAL0                     (SPM_BASE + 0x010)
+#define	SPM_POWER_ON_VAL1                     (SPM_BASE + 0x014)
+#define	SPM_CLK_SETTLE                        (SPM_BASE + 0x100)
+#define	SPM_MP0_CPU0_PWR_CON                  (SPM_BASE + 0x200)
+#define	SPM_MP0_CPUTOP_PWR_CON                (SPM_BASE + 0x208)
+#define	SPM_MP0_CPU1_PWR_CON                  (SPM_BASE + 0x218)
+#define	SPM_MP0_CPU2_PWR_CON                  (SPM_BASE + 0x21C)
+#define	SPM_MP0_CPU3_PWR_CON                  (SPM_BASE + 0x220)
+#define	SPM_IFR_PWR_CON                       (SPM_BASE + 0x234)
+#define	SPM_DIS_PWR_CON                       (SPM_BASE + 0x23C)
+#define	SPM_DPY_PWR_CON                       (SPM_BASE + 0x240)
+#define	SPM_MP0_CPUTOP_L2_PDN                 (SPM_BASE + 0x244)
+#define	SPM_MP0_CPUTOP_L2_SLEEP               (SPM_BASE + 0x248)
+#define	SPM_MP0_CPU0_L1_PDN                   (SPM_BASE + 0x25C)
+#define	SPM_MP0_CPU1_L1_PDN                   (SPM_BASE + 0x264)
+#define	SPM_MP0_CPU2_L1_PDN                   (SPM_BASE + 0x26C)
+#define	SPM_MP0_CPU3_L1_PDN                   (SPM_BASE + 0x274)
+#define	SPM_CONN_PWR_CON                      (SPM_BASE + 0x280)
+#define	SPM_MCU_PWR_CON                       (SPM_BASE + 0x290)
+#define	SPM_IFR_SRAMROM_CON                   (SPM_BASE + 0x294)
+#define	SPM_CPU_EXT_ISO                       (SPM_BASE + 0x2DC)
+#define	SPM_SLEEP_IFR_PWR_MASK                (SPM_BASE + 0x2E0)
+#define	SPM_SLEEP_ISP_PWR_MASK                (SPM_BASE + 0x2E4)
+#define	SPM_SLEEP_MFG_3D_PWR_MASK             (SPM_BASE + 0x2E8)
+#define	SPM_SLEEP_DIS_PWR_MASK                (SPM_BASE + 0x2EC)
+#define	SPM_SLEEP_DPY_PWR_MASK                (SPM_BASE + 0x2F0)
+#define	SPM_SLEEP_CONN_PWR_MASK               (SPM_BASE + 0x2F4)
+#define	SPM_SLEEP_MFG_2D_PWR_MASK             (SPM_BASE + 0x300)
+#define	SPM_SLEEP_MFG_ASYNC_PWR_MASK          (SPM_BASE + 0x304)
+#define	SPM_CLK_CON                           (SPM_BASE + 0x400)
+#define	SPM_APMCU_PWRCTL                      (SPM_BASE + 0x600)
+#define	SPM_AP_DVFS_CON_SET                   (SPM_BASE + 0x604)
+#define	SPM_SLEEP_STNBY_CON                   (SPM_BASE + 0x608)
+#define	SPM_PWR_STATUS                        (SPM_BASE + 0x60C)
+#define	SPM_PWR_STATUS_2ND                    (SPM_BASE + 0x610)
+#define	SPM_RF_CLK_CFG                        (SPM_BASE + 0x620)
+#define	SPM_RF_CLK_CFG_SET                    (SPM_BASE + 0x624)
+#define	SPM_RF_CLK_CFG_CLR                    (SPM_BASE + 0x628)
+#define	SPM_SPM_AP_SEMA                       (SPM_BASE + 0x638)
+#define	SPM_SPM_SPM_SEMA                      (SPM_BASE + 0x63C)
+#define	SPM_SLEEP_TIMER_STA                   (SPM_BASE + 0x720)
+#define	SPM_SLEEP_TWAM_CON                    (SPM_BASE + 0x760)
+#define	SPM_SLEEP_TWAM_LAST_STATUS0           (SPM_BASE + 0x764)
+#define	SPM_SLEEP_TWAM_LAST_STATUS1           (SPM_BASE + 0x768)
+#define	SPM_SLEEP_TWAM_LAST_STATUS2           (SPM_BASE + 0x76C)
+#define	SPM_SLEEP_TWAM_LAST_STATUS3           (SPM_BASE + 0x770)
+#define	SPM_SLEEP_TWAM_CURR_STATUS0           (SPM_BASE + 0x774)
+#define	SPM_SLEEP_TWAM_CURR_STATUS1           (SPM_BASE + 0x778)
+#define	SPM_SLEEP_TWAM_CURR_STATUS2           (SPM_BASE + 0x77C)
+#define	SPM_SLEEP_TWAM_CURR_STATUS3           (SPM_BASE + 0x780)
+#define	SPM_SLEEP_TWAM_TIMER_OUT              (SPM_BASE + 0x784)
+#define	SPM_SLEEP_TWAM_WINDOW_LEN             (SPM_BASE + 0x788)
+#define	SPM_SLEEP_WAKEUP_EVENT_MASK           (SPM_BASE + 0x810)
+#define	SPM_SLEEP_CPU_WAKEUP_EVENT            (SPM_BASE + 0x814)
+#define	SPM_PCM_WDT_TIMER_VAL                 (SPM_BASE + 0x824)
+#define	SPM_PCM_WDT_TIMER_OUT                 (SPM_BASE + 0x828)
+#define	SPM_SLEEP_ISR_MASK                    (SPM_BASE + 0x900)
+#define	SPM_SLEEP_ISR_STATUS                  (SPM_BASE + 0x904)
+#define	SPM_SLEEP_ISR_RAW_STA                 (SPM_BASE + 0x910)
+#define	SPM_SLEEP_WAKEUP_MISC                 (SPM_BASE + 0x918)
+#define	SPM_SLEEP_BUS_PROTECT_RDY             (SPM_BASE + 0x91C)
+#define	SPM_SLEEP_SUBSYS_IDLE_STA             (SPM_BASE + 0x920)
+#define	SPM_PCM_CON0                          (SPM_BASE + 0x310)
+#define	SPM_PCM_EVENT_EN                      (SPM_BASE + 0xC00)
+#define	SPM_PCM_CON1                          (SPM_BASE + 0x314)
+#define	SPM_PCM_IM_PTR                        (SPM_BASE + 0x318)
+#define	SPM_PCM_IM_LEN                        (SPM_BASE + 0x31C)
+#define	SPM_PCM_REG_DATA_INI                  (SPM_BASE + 0x320)
+#define	SPM_PCM_REG0_DATA                     (SPM_BASE + 0x380)
+#define	SPM_PCM_REG1_DATA                     (SPM_BASE + 0x384)
+#define	SPM_PCM_REG2_DATA                     (SPM_BASE + 0x388)
+#define	SPM_PCM_REG3_DATA                     (SPM_BASE + 0x38C)
+#define	SPM_PCM_REG4_DATA                     (SPM_BASE + 0x390)
+#define	SPM_PCM_REG5_DATA                     (SPM_BASE + 0x394)
+#define	SPM_PCM_REG6_DATA                     (SPM_BASE + 0x398)
+#define	SPM_PCM_REG7_DATA                     (SPM_BASE + 0x39C)
+#define	SPM_PCM_REG8_DATA                     (SPM_BASE + 0x3A0)
+#define	SPM_PCM_REG9_DATA                     (SPM_BASE + 0x3A4)
+#define	SPM_PCM_REG10_DATA                    (SPM_BASE + 0x3A8)
+#define	SPM_PCM_REG11_DATA                    (SPM_BASE + 0x3AC)
+#define	SPM_PCM_REG12_DATA                    (SPM_BASE + 0x3B0)
+#define	SPM_PCM_REG13_DATA                    (SPM_BASE + 0x3B4)
+#define	SPM_PCM_REG14_DATA                    (SPM_BASE + 0x3B8)
+#define	SPM_PCM_REG15_DATA                    (SPM_BASE + 0x3BC)
+#define	SPM_PCM_EVENT_REG_STA                 (SPM_BASE + 0x3C0)
+#define	SPM_PCM_FSM_STA                       (SPM_BASE + 0x3C4)
+#define	SPM_PCM_IM_HOST_RW_PTR                (SPM_BASE + 0x3C8)
+#define	SPM_PCM_IM_HOST_RW_DAT                (SPM_BASE + 0x3CC)
+#define	SPM_PCM_EVENT_VECTOR0                 (SPM_BASE + 0x340)
+#define	SPM_PCM_EVENT_VECTOR1                 (SPM_BASE + 0x344)
+#define	SPM_PCM_EVENT_VECTOR2                 (SPM_BASE + 0x348)
+#define	SPM_PCM_EVENT_VECTOR3                 (SPM_BASE + 0x34C)
+#define	SPM_PCM_EVENT_VECTOR4                 (SPM_BASE + 0x3D0)
+#define	SPM_PCM_EVENT_VECTOR5                 (SPM_BASE + 0x3D4)
+#define	SPM_PCM_EVENT_VECTOR6                 (SPM_BASE + 0x3D8)
+#define	SPM_PCM_EVENT_VECTOR7                 (SPM_BASE + 0x3DC)
+#define	SPM_PCM_EVENT_VECTOR8                 (SPM_BASE + 0xC04)
+#define	SPM_PCM_EVENT_VECTOR9                 (SPM_BASE + 0xC08)
+#define	SPM_PCM_EVENT_VECTORA                 (SPM_BASE + 0xC0C)
+#define	SPM_PCM_EVENT_VECTORB                 (SPM_BASE + 0xC10)
+#define	SPM_PCM_EVENT_VECTORC                 (SPM_BASE + 0xC14)
+#define	SPM_PCM_EVENT_VECTORD                 (SPM_BASE + 0xC18)
+#define	SPM_PCM_EVENT_VECTORE                 (SPM_BASE + 0xC1C)
+#define	SPM_PCM_EVENT_VECTORF                 (SPM_BASE + 0xC20)
+#define	SPM_PCM_MAS_PAUSE_MASK                (SPM_BASE + 0x354)
+#define	SPM_PCM_PWR_IO_EN                     (SPM_BASE + 0x358)
+#define	SPM_PCM_TIMER_VAL                     (SPM_BASE + 0x35C)
+#define	SPM_PCM_TIMER_OUT                     (SPM_BASE + 0x360)
+#define	SPM_PCM_SW_INT_SET                    (SPM_BASE + 0x3E0)
+#define	SPM_PCM_SW_INT_CLEAR                  (SPM_BASE + 0x3E4)
+#define	SPM_PCM_REGC_WAKEUP_MASK              (SPM_BASE + 0x3E8)
+#define	SPM_SLEEP_MP0_CPU0_PWR_MASK           (SPM_BASE + 0x4E0)
+#define	SPM_SLEEP_MP0_CPU1_PWR_MASK           (SPM_BASE + 0x4E4)
+#define	SPM_SLEEP_MP0_CPU2_PWR_MASK           (SPM_BASE + 0x4E8)
+#define	SPM_SLEEP_MP0_CPU3_PWR_MASK           (SPM_BASE + 0x4EC)
+#define	SPM_SLEEP_MP0_CPUTOP_PWR_MASK         (SPM_BASE + 0x4F0)
+#define	SPM_SLEEP_MCU_PWR_MASK                (SPM_BASE + 0x4F4)
+#define	SPM_SLEEP_MP0_WFI0_EN                 (SPM_BASE + 0xF00)
+#define	SPM_SLEEP_MP0_WFI1_EN                 (SPM_BASE + 0xF04)
+#define	SPM_SLEEP_MP0_WFI2_EN                 (SPM_BASE + 0xF08)
+#define	SPM_SLEEP_MP0_WFI3_EN                 (SPM_BASE + 0xF0C)
+#define	SPM_PCM_RESERVE                       (SPM_BASE + 0xB00)
+#define	SPM_PCM_RESERVE2                      (SPM_BASE + 0xB04)
+#define	SPM_PCM_FLAGS                         (SPM_BASE + 0xB08)
+#define	SPM_PCM_SRC_REQ                       (SPM_BASE + 0xB0C)
+#define	SPM_PCM_RESERVE3                      (SPM_BASE + 0xB14)
+#define	SPM_PCM_RESERVE4                      (SPM_BASE + 0xB18)
+#define	SPM_PCM_RESERVE5                      (SPM_BASE + 0xC24)
+#define	SPM_PCM_RESERVE6                      (SPM_BASE + 0xC28)
+#define	SPM_PCM_RESERVE7                      (SPM_BASE + 0xC2C)
+#define	SPM_PCM_RESERVE8                      (SPM_BASE + 0xC30)
+#define	SPM_PCM_MMDDR_MASK                    (SPM_BASE + 0xB1C)
+#define	SPM_PCM_DEBUG_CON                     (SPM_BASE + 0xB20)
+#define	SPM_PCM_WDT_LATCH                     (SPM_BASE + 0xB24)
+#define	SPM_MP0_CPU0_IRQ_MASK                 (SPM_BASE + 0xB30)
+#define	SPM_MP0_CPU1_IRQ_MASK                 (SPM_BASE + 0xB34)
+#define	SPM_MP0_CPU2_IRQ_MASK                 (SPM_BASE + 0xB38)
+#define	SPM_MP0_CPU3_IRQ_MASK                 (SPM_BASE + 0xB3C)
+#define	SPM_PCM_PASR_DPD_0                    (SPM_BASE + 0xB60)
+#define	SPM_PCM_PASR_DPD_1                    (SPM_BASE + 0xB64)
+#define	SPM_PCM_PASR_DPD_2                    (SPM_BASE + 0xB68)
+#define	SPM_PCM_PASR_DPD_3                    (SPM_BASE + 0xB6C)
+#define	SPM_SLEEP_GCPU_SRAM_CON               (SPM_BASE + 0xC34)
+#define	SPM_SLEEP_NFI_SRAM_CON                (SPM_BASE + 0xC38)
+#define	SPM_SLEEP_DPY_MISC                    (SPM_BASE + 0xC60)
+#define	SPM_L2_FLUSH                          (SPM_BASE + 0xD00)
+#define	SPM_GIC_SRAM_CON                      (SPM_BASE + 0xD04)
+#define	SPM_MP0_VPROC_SUS                     (SPM_BASE + 0xD08)
+#define	SPM_AUDAFE_PWR_CON                    (SPM_BASE + 0xD10)
+#define	SPM_AUDSRC_PWR_CON                    (SPM_BASE + 0xD14)
+#define	SPM_CM4_PWR_CON                       (SPM_BASE + 0xD30)
+#define	SPM_CM4_SRAM_SLEEP                    (SPM_BASE + 0xD38)
+#define	SPM_SLEEP_SPMC_MP0_CPU0_PWR_CON       (SPM_BASE + 0xC40)
+#define	SPM_SLEEP_SPMC_MP0_CPU1_PWR_CON       (SPM_BASE + 0xC44)
+#define	SPM_SLEEP_SPMC_MP0_CPU2_PWR_CON       (SPM_BASE + 0xC48)
+#define	SPM_SLEEP_SPMC_MP0_CPU3_PWR_CON       (SPM_BASE + 0xC4C)
+#define	SPM_SLEEP_SPMC_MP0_CPUTOP_PWR_CON     (SPM_BASE + 0xC50)
+#define	SPM_SLEEP_SPMC_MP0_SRAM_SLP           (SPM_BASE + 0xC54)
+#define	SPM_SLEEP_SPMC_MP0_CPUTOP_CLK_DIS     (SPM_BASE + 0xC58)
+#define	SPM_SLEEP_SPMC_BYPASS                 (SPM_BASE + 0xC5C)
+#define	SPM_MP0_CPU0_SRAM_SLEEP               (SPM_BASE + 0xD60)
+#define	SPM_MP0_CPU1_SRAM_SLEEP               (SPM_BASE + 0xD64)
+#define	SPM_MP0_CPU2_SRAM_SLEEP               (SPM_BASE + 0xD68)
+#define	SPM_MP0_CPU3_SRAM_SLEEP               (SPM_BASE + 0xD6C)
+#define	SPM_MP_TOP_SRAM_SLEEP                 (SPM_BASE + 0xD70)
+#define	SPM_MP_TOP_VPROC_OFF                  (SPM_BASE + 0xD74)
+#define	SPM_DEBUG_TOP_SRAM_PD                 (SPM_BASE + 0xD78)
+#define	SPM_SLEEP_ACAO_INT_SET                (SPM_BASE + 0xD80)
+#define	SPM_SLEEP_ACAO_INT_CLR                (SPM_BASE + 0xD84)
+#define	SPM_SLEEP_ACAO_INT_STA                (SPM_BASE + 0xD88)
+
+#define SPM_PROJECT_CODE    0xb16
+
+#define SPM_REGWR_EN        (1U << 0)
+#define SPM_REGWR_CFG_KEY   (SPM_PROJECT_CODE << 16)
+
+#define spm_read(addr)          readl(addr)
+#define spm_write(addr, val)        writel(val, addr)
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/include/platform/spm_mtcmos.h b/src/bsp/lk/platform/mt8518/include/platform/spm_mtcmos.h
new file mode 100644
index 0000000..963579d
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/spm_mtcmos.h
@@ -0,0 +1,16 @@
+#ifndef _SPM_MTCMOS_
+#define _SPM_MTCMOS_
+
+#define STA_POWER_DOWN  0
+#define STA_POWER_ON    1
+
+/*
+ * 1. for non-CPU MTCMOS: DISP, CM4, AUDAFE, AUDSRC
+ * 2. call spm_mtcmos_noncpu_lock/unlock() before/after any operations
+ */
+extern int spm_mtcmos_ctrl_disp(int state);
+extern int spm_mtcmos_ctrl_cm4(int state);
+extern int spm_mtcmos_ctrl_audafe(int state);
+extern int spm_mtcmos_ctrl_audsrc(int state);
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/include/platform/typedefs.h b/src/bsp/lk/platform/mt8518/include/platform/typedefs.h
new file mode 100644
index 0000000..c9c8803
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/typedefs.h
@@ -0,0 +1,134 @@
+/*****************************************************************************
+*  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) 2001
+*
+*****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Filename:
+ * ---------
+ *   Error_code.h
+ *
+ * Project:
+ * --------
+ *   Device Test
+ *
+ * Description:
+ * ------------
+ *   Type definition.
+ *
+ * Author:
+ * -------
+ *   Shalyn Chua  (mtk00576)
+ *
+ *============================================================================
+ *             HISTORY
+ * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *------------------------------------------------------------------------------
+ *
+ ****************************************************************************/
+
+
+#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
+
+enum {RX, TX, NONE};
+
+/*==== TYPES ======================================================*/
+
+typedef unsigned char   kal_uint8;
+typedef unsigned short  kal_uint16;
+typedef unsigned int    kal_uint32;
+
+typedef unsigned long long  kal_uint64;
+
+typedef unsigned char   US8;
+typedef unsigned short  US16;
+typedef unsigned int    US32;
+
+typedef volatile unsigned char  *P_kal_uint8;
+typedef volatile signed char    *P_S8;
+typedef volatile unsigned short *P_kal_uint16;
+typedef volatile signed short   *P_S16;
+typedef volatile unsigned int   *P_kal_uint32;
+typedef volatile signed int     *P_S32;
+
+typedef long            LONG;
+typedef unsigned char   UBYTE;
+typedef short           SHORT;
+
+typedef signed char     kal_int8;
+typedef signed short    kal_int16;
+typedef signed int      kal_int32;
+typedef long long       kal_int64;
+typedef char            kal_char;
+
+typedef unsigned int            *UINT32P;
+typedef volatile unsigned short *UINT16P;
+typedef volatile unsigned char  *UINT8P;
+typedef unsigned char           *U8P;
+
+typedef signed long long        *P_S64;
+
+typedef unsigned char       U8;
+typedef unsigned short      U16;
+typedef unsigned int        U32;
+typedef unsigned long long  U64;
+typedef signed long long    S64;
+
+typedef enum {
+   KAL_FALSE = 0,
+   KAL_TRUE  = 1,
+   kal_false = KAL_FALSE,
+   kal_true  = KAL_TRUE,
+} kal_bool;
+
+typedef unsigned int    UINT32;
+typedef unsigned short  USHORT;
+typedef signed int      DWORD;
+typedef void            VOID;
+typedef unsigned char   BYTE;
+typedef float           FLOAT;
+
+typedef char           *LPCSTR;
+typedef short          *LPWSTR;
+
+#endif
+
diff --git a/src/bsp/lk/platform/mt8518/include/platform/udc-common.h b/src/bsp/lk/platform/mt8518/include/platform/udc-common.h
new file mode 100644
index 0000000..45c5ce8
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/udc-common.h
@@ -0,0 +1,83 @@
+/*
+ * 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 GET_STATUS           0
+#define CLEAR_FEATURE        1
+#define SET_FEATURE          3
+#define SET_ADDRESS          5
+#define GET_DESCRIPTOR       6
+#define SET_DESCRIPTOR       7
+#define GET_CONFIGURATION    8
+#define SET_CONFIGURATION    9
+#define GET_INTERFACE        10
+#define SET_INTERFACE        11
+#define SYNCH_FRAME          12
+#define SET_SEL              48
+
+#define TYPE_DEVICE          1
+#define TYPE_CONFIGURATION   2
+#define TYPE_STRING          3
+#define TYPE_INTERFACE       4
+#define TYPE_ENDPOINT        5
+#define TYPE_DEV_QUALIFIER   6
+#define TYPE_OTHER_SPEEDCONF 7
+#define TYPE_IFACE_POWER     8
+#define TYPE_OTG             9
+#define TYPE_DEBUG           10
+#define TYPE_IFACE_ASSOC     11
+#define TYPE_BOS             15
+#define TYPE_DEVICE_CAP      16
+#define TYPE_SS_EP_COMP      48
+
+#define DEVICE_READ          0x80
+#define DEVICE_WRITE         0x00
+#define INTERFACE_READ       0x81
+#define INTERFACE_WRITE      0x01
+#define ENDPOINT_READ        0x82
+#define ENDPOINT_WRITE       0x02
+
+#define TEST_SE0_NAK         0x0300
+#define TEST_PACKET          0x0400
+#define PORTSC_PTC           (0xF << 16)
+#define PORTSC_PTC_SE0_NAK   (0x03 << 16)
+#define PORTSC_PTC_TST_PKT   (0x4 << 16)
+
+#define USB3_U1_ENABLE       48
+#define USB3_U2_ENABLE       49
+
+#define UDC_TYPE_BULK_IN    1
+#define UDC_TYPE_BULK_OUT   2
+
+struct setup_packet {
+    unsigned char type;
+    unsigned char request;
+    unsigned short value;
+    unsigned short index;
+    unsigned short length;
+} __attribute__ ((packed));
diff --git a/src/bsp/lk/platform/mt8518/include/platform/usb_toolhandler.h b/src/bsp/lk/platform/mt8518/include/platform/usb_toolhandler.h
new file mode 100644
index 0000000..eb253bd
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/usb_toolhandler.h
@@ -0,0 +1,6 @@
+#ifndef __USB_TOOLHANDLER_H__

+#define __USB_TOOLHANDLER_H__

+

+bool tool_usb_handshake(void *bootimg_dtb_load);

+

+#endif
\ No newline at end of file
diff --git a/src/bsp/lk/platform/mt8518/include/platform/usbbldr.h b/src/bsp/lk/platform/mt8518/include/platform/usbbldr.h
new file mode 100644
index 0000000..9ca92ff
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/usbbldr.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008-2012 Travis Geiselbrecht
+ *
+ * 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_TEST_H
+#define __DEBUG_TEST_H
+
+struct comport_ops {
+    int (*send)(u8 *buf, u32 len);
+    int (*recv)(u8 *buf, u32 len, u32 tmo);
+};
+
+struct bldr_comport {
+    u32 type;
+    u32 tmo;
+    struct comport_ops *ops;
+};
+
+struct bldr_command {
+    u8  *data;
+    u32  len;
+};
+
+struct bldr_command_handler;
+
+typedef int (*bldr_cmd_handler_t)(struct bldr_command_handler *handler, struct bldr_command *cmd, struct bldr_comport *comm);
+
+struct bldr_command_handler {
+    void *priv;
+    u32   attr;
+    void * dtb;
+    bldr_cmd_handler_t  cb;
+};
+#endif
diff --git a/src/bsp/lk/platform/mt8518/include/platform/usbtty.h b/src/bsp/lk/platform/mt8518/include/platform/usbtty.h
new file mode 100644
index 0000000..56d0009
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/usbtty.h
@@ -0,0 +1,14 @@
+#ifndef __USB_TTY_H__
+#define __USB_TTY_H__
+
+void tool_state_update (int);
+void config_usbtty (void);
+int usbdl_configured (void);
+void usbtty_stop(void);
+int usbtty_write(void *buf, unsigned len);
+int usbtty_read(void *_buf, unsigned len, lk_time_t timeout);
+int tool_is_present (void);
+int usbtty_init_done(void);
+struct udc_gadget *usbtty_interface_1(void);
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/include/platform/x_hal_io.h b/src/bsp/lk/platform/mt8518/include/platform/x_hal_io.h
new file mode 100644
index 0000000..2ccdece
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/include/platform/x_hal_io.h
@@ -0,0 +1,160 @@
+/* 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 ("Media Tek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef X_HAL_IO_H
+#define X_HAL_IO_H
+
+#include <platform/dramc_api.h>
+#include <reg.h>
+#include <platform/typedefs.h>
+
+
+/* field access macro---------------------------------------------------------*/
+
+/* 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
+
+/* cc add. Used to generate bit mask for bits definition.
+ * for example, for XXX[4:3], this will generate 0x18 as the mask for it.
+ */
+#define MSB_POS		(sizeof(unsigned long) * 8 - 1)
+#define GENMASK(msb, lsb) \
+	(((~0UL) << (lsb)) & ((~0UL) >> (MSB_POS - (msb))))
+#define BIT(nr)		(1 << (nr))
+
+/* NEW_CODA comment old code*/
+/* #define Fld2Msk32(fld) ... */
+
+extern unsigned int dram_register_read(DRAMC_CTX_T *p, U64 u4reg_addr);
+extern unsigned char dram_register_write(DRAMC_CTX_T *p,
+	U64 u4reg_addr, unsigned int u4reg_value);
+
+extern void io32_write_4b_msk2(DRAMC_CTX_T *p, U64 reg32,
+	unsigned int val32, unsigned int msk32);
+extern void io32_write_4b_msk_all2(DRAMC_CTX_T *p, U64 reg32,
+	unsigned int val32, unsigned int msk32);
+extern void io32_write_4b_all2(DRAMC_CTX_T *p, U64 reg32,
+	unsigned int val32);
+
+/* public Macro for general use. */
+#define io32_read_4b(reg32) dram_register_read(p, reg32)
+#define io32_write_4b(reg32, val32) dram_register_write(p, reg32, val32)
+#define io32_write_4b_all(reg32, val32) io32_write_4b_all2(p, reg32, val32)
+#define io32_write_4b_msk(reg32, val32, msk32) \
+	io32_write_4b_msk2(p, reg32, val32, msk32)
+#define io32_write_4b_msk_all(reg32, val32, msk32) \
+	io32_write_4b_msk_all2(p, reg32, val32, msk32)
+
+#define ffld(wid, shft, ac)	GENMASK(shft + wid - 1, shft)
+#define fld_wid(fld) (unsigned char)(__builtin_popcount(fld))
+
+/*
+ * This macro should be used with "io_32_write_fld_multi"
+ * or "io_32_write_fld_multi_all"
+ * where "upk" variable is declared by these two functions.
+*/
+#define p_fld(val, msk) \
+	((sizeof(upk) > 1) ? ((unsigned int)msk) : ((unsigned int)msk & \
+	((unsigned int)(val) << (__builtin_ffsl((unsigned int)msk) - 1))))
+
+#define io_32_read_fld_align(reg32, msk) \
+	((((unsigned int)msk) == 0xffffffff) ? io32_read_4b(reg32) : \
+	((io32_read_4b(reg32) & ((unsigned int)msk)) >> \
+	(__builtin_ffsl((unsigned int)msk) - 1)))
+
+#define io_32_write_fld_align(reg32, val, msk) \
+	((((unsigned int)msk) == 0xffffffff) ? \
+	(io32_write_4b((reg32), (val))) : \
+	(io32_write_4b_msk((reg32), ((unsigned int)(val) << \
+	(__builtin_ffsl((unsigned int)msk) - 1)), ((unsigned int)msk))))
+
+/* The "upk" variable is used in the "p_fld" macro. */
+#define io_32_write_fld_multi(reg32, list) \
+{ \
+	unsigned short upk; \
+	signed int msk = (signed int)(list); \
+	{ \
+		unsigned char upk; \
+		((unsigned int)msk == 0xffffffff) ? \
+		(io32_write_4b(reg32, (list))) : (((unsigned int)msk) ? \
+		io32_write_4b_msk((reg32), (list), ((unsigned int)msk)) : 0); \
+	} \
+}
+
+#define io_32_write_fld_align_all(reg32, val, msk) \
+	((((unsigned int)msk) == 0xffffffff) ? \
+	(io32_write_4b_all((reg32), (val))) : \
+	(io32_write_4b_msk_all((reg32), \
+	((unsigned int)(val) << (__builtin_ffsl((unsigned int)msk) - 1)), \
+	((unsigned int)msk))))
+
+/* The "upk" variable is used in the "p_fld" macro. */
+#define io_32_write_fld_multi_all(reg32, list) \
+{ \
+	unsigned short upk; \
+	signed int msk = (signed int)(list); \
+	{ \
+		unsigned char upk; \
+		((unsigned int)msk == 0xffffffff) ? \
+		(io32_write_4b_all(reg32, (list))) : (((unsigned int)msk) ? \
+		io32_write_4b_msk_all((reg32), (list), \
+		((unsigned int)msk)) : 0); \
+	} \
+}
+
+void io_set_sw_broadcast(unsigned int value);
+unsigned int io_get_sw_broadcast(void);
+unsigned int io_get_set_sw_broadcast(unsigned int value);
+
+/* NEW_CODA end */
+
+#endif
diff --git a/src/bsp/lk/platform/mt8518/interrupts.c b/src/bsp/lk/platform/mt8518/interrupts.c
new file mode 100644
index 0000000..59f8e23
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/interrupts.c
@@ -0,0 +1,74 @@
+/*
+ * 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 <reg.h>
+#include <debug.h>
+#include <kernel/thread.h>
+#include <platform/gic.h>
+#include <platform/mt_irq.h>
+#include <platform/mt_gic_v3.h>
+#include <platform/interrupts.h>
+#include <platform/mt_reg_base.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(value, (INT_POL_CTL0 + (reg_index * 4)));
+    } else {
+        value = readl(INT_POL_CTL0 + (reg_index * 4));
+        value &= ~(0x1 << offset);
+        writel(value, INT_POL_CTL0 + (reg_index * 4));
+    }
+}
+
+/* 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(config, GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
+    } else {
+        config = readl(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
+        config &= ~(0x2 << (irq % 16) * 2);
+        writel(config,  GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
+    }
+    DSB;
+}
diff --git a/src/bsp/lk/platform/mt8518/lib/libdevinfo.o b/src/bsp/lk/platform/mt8518/lib/libdevinfo.o
new file mode 100644
index 0000000..0dbc118
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/lib/libdevinfo.o
Binary files differ
diff --git a/src/bsp/lk/platform/mt8518/platform.c b/src/bsp/lk/platform/mt8518/platform.c
new file mode 100644
index 0000000..a4d3cfe
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/platform.c
@@ -0,0 +1,259 @@
+/*
+ * 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.h>
+#include <arch/arm64/mmu.h>
+#include <arch/ops.h>
+#include <assert.h>
+#include <debug.h>
+#include <dev/timer/arm_generic.h>
+#include <dev/uart.h>
+#include <err.h>
+#include <kernel/vm.h>
+#include <platform.h>
+#include <platform/mt8518.h>
+#include <platform/mt_gic_v3.h>
+#include <platform/pll.h>
+#include <platform/dramc_api.h>
+#include <lib/mempool.h>
+#if WITH_MTK_PMIC_WRAP_AND_PMIC
+#include <platform/pmic_wrap_init.h>
+#include <platform/pmic.h>
+#endif
+#if WITH_PMIC_MT6395
+#include <platform/pmic_6395.h>
+#endif
+#if WITH_VCORE_PWM_BUCK
+#include <platform/pwm-buck.h>
+#endif
+#if WITH_VCORE_I2C_BUCK
+#include <platform/rt5748.h>
+#endif
+#ifdef MTK_TINYSYS_SCP_SUPPORT
+#include <platform/mt_scp.h>
+#endif
+#ifdef WITH_BOOTMODE_HANDSHAKE
+#include <platform/usb_toolhandler.h>
+#endif
+#include <platform/pwm.h>
+
+#if WITH_KERNEL_VM
+#define L2C_MAPPING_IDX 0
+#define PERIPHERAL_MAPPING_IDX 1
+#define ICVERSION_MAPPING_IDX 2
+#define GIC_MAPPING_IDX 3
+#define SRAM_MAPPING_IDX 4
+#define DRAM_MAPPING_IDX 5
+
+#include <platform/mtk_wdt.h>
+
+/* 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 = PERIPHERAL_BASE_PHYS,
+        .virt = PERIPHERAL_BASE_VIRT,
+        .size = PERIPHERAL_BASE_SIZE,
+        .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
+        .name = "peripherals"
+    },
+    {
+        .phys = VERSION_BASE_PHYS,
+        .virt = VERSION_BASE_VIRT,
+        .size = VERSION_BASE_SIZE,
+        .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
+        .name = "icversion"
+    },
+    {
+        .phys = GIC_BASE_PHYS,
+        .virt = GIC_BASE_VIRT,
+        .size = GIC_BASE_SIZE,
+        .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE,
+        .name = "gic"
+    },
+    /* reserved for internal sram */
+    { 0 },
+    /* reserved for dram */
+    { 0 },
+    /* null entry to terminate the list */
+    { 0 }
+};
+
+static pmm_arena_t arena = {
+    .name = "sdram",
+    .base = SRAM_BASE_PHYS,
+    .size = SRAM_BASE_SIZE,
+    .flags = PMM_ARENA_FLAG_KMAP,
+};
+
+/* 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");
+}
+
+uint32_t lk_dram_sz =  0x10000000; //get_dram_size();;
+void *dram_map(paddr_t pa)
+{
+    paddr_t dram_phy = DRAM_BASE_PHY;
+
+    if (pa >= dram_phy && pa <= (dram_phy + lk_dram_sz - 1)) {
+        return (void *)(DRAM_BASE_VIRT + (pa - dram_phy));
+    }
+
+    return NULL;
+}
+
+#endif /* WITH_KERNEL_VM */
+
+void platform_early_init(void)
+{
+    uart_init_early();
+
+    /* initialize the interrupt controller */
+    arm_gic_init();
+
+    arm_generic_timer_init(ARM_GENERIC_TIMER_PHYSICAL_INT, 13000000);
+
+    mtk_wdt_init();
+
+#if WITH_KERNEL_VM
+    arch_disable_cache(DCACHE);
+#endif
+
+#if !(FPGA_PLATFORM)
+    mt_pll_init();
+#endif
+
+    pwm_init();
+
+#if WITH_MTK_PMIC_WRAP_AND_PMIC
+    pwrap_init();
+    pmic_init();
+#endif
+
+#if WITH_PMIC_MT6395
+    pmic_init_mt6395();
+#endif
+
+#if WITH_VCORE_PWM_BUCK
+    pwm_buck_init();
+#endif
+
+#if WITH_VCORE_I2C_BUCK
+    rt5748_init();
+#endif
+
+#if !(FPGA_PLATFORM)
+    /* mt_pll_post_init should be invoked after pmic_init */
+    mt_pll_post_init();
+#endif
+
+    /* check DDR-reserve mode */
+    check_ddr_reserve_status();
+
+#if !(FPGA_PLATFORM)
+    mt_mem_init();
+#endif
+
+#if WITH_KERNEL_VM
+    dcache_enable();
+
+/* mapping dram to cacheable memory */
+#if FPGA_PLATFORM
+    arch_mmu_map(DRAM_BASE_VIRT, DRAM_BASE_PHY,  0x10000000 >> PAGE_SIZE_SHIFT, 0);
+#else
+    arch_mmu_map(DRAM_BASE_VIRT, DRAM_BASE_PHY,  0x20000000 >> PAGE_SIZE_SHIFT, 0);
+#endif
+    /* add DRAM to mmu_initial_mappings for physical-to-virtual translation */
+    mmu_initial_mappings[DRAM_MAPPING_IDX].phys = DRAM_BASE_PHY;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].virt = DRAM_BASE_VIRT;
+#if FPGA_PLATFORM
+    mmu_initial_mappings[DRAM_MAPPING_IDX].size = 0x10000000;
+#else
+    mmu_initial_mappings[DRAM_MAPPING_IDX].size = 0x20000000;//get_dram_size();
+#endif
+    mmu_initial_mappings[DRAM_MAPPING_IDX].flags = 0;
+    mmu_initial_mappings[DRAM_MAPPING_IDX].name = "dram";
+
+    /* mapping internel sram to cacheable memory */
+    arch_mmu_map(SRAM_BASE_VIRT, SRAM_BASE_PHYS,  SRAM_BASE_SIZE >> PAGE_SIZE_SHIFT, 0);
+    /* add intrenal sram to mmu_initial_mappings for heap */
+    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";
+
+    pmm_add_arena(&arena);
+#endif
+    /* set all gpio smt enabled */
+    writel(0xffff, GPIO_BASE + 0Xa00);
+    writel(0xffff, GPIO_BASE + 0xa10);
+    writel(0xffff, GPIO_BASE + 0xa20);
+    writel(0xffff, GPIO_BASE + 0xa30);
+}
+
+void platform_init(void)
+{
+    int ret;
+    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);
+
+}
+
+extern __WEAK bool plat_fixup_hook(void* bootimg_dtb_load, ...);
+bool plat_fixup_hook(void* bootimg_dtb_load, ...)
+{
+#ifdef MTK_TINYSYS_SCP_SUPPORT
+    if (load_scpsys() < 0)
+        dprintf(ALWAYS, "load scp fail\n");
+#endif
+
+#ifdef WITH_BOOTMODE_HANDSHAKE
+    bool ret=  tool_usb_handshake( bootimg_dtb_load );
+    return ret;
+#endif
+
+    return true;
+}
+
+/* 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.*/
+extern void mt_clear_sec_pol_ctl_en(void);
+void platform_el3_init(void)
+{
+    mt_gic_el3_setup();
+}
diff --git a/src/bsp/lk/platform/mt8518/rules.mk b/src/bsp/lk/platform/mt8518/rules.mk
new file mode 100644
index 0000000..6bae6f6
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/rules.mk
@@ -0,0 +1,113 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+ARCH ?= arm64
+ARM_CPU ?= cortex-a53
+WITH_SMP ?= 0
+WITH_KERNEL_VM ?= 0
+WITH_EL3_EXCEPTIONS ?= 1
+AB_UPGRADE_APP := 1
+
+LK_HEAP_IMPLEMENTATION ?= miniheap
+
+GLOBAL_INCLUDES += -I$(LK_TOP_DIR)/include \
+
+MT8518 :=1
+
+GLOBAL_DEFINES += \
+       MT8518=1
+
+MODULE_SRCS += \
+    $(LOCAL_DIR)/platform.c \
+    $(LOCAL_DIR)/debug.c \
+    $(LOCAL_DIR)/interrupts.c \
+    $(LOCAL_DIR)/timer.c \
+
+ifeq ($(WITH_KERNEL_VM),1)
+KERNEL_ASPACE_BASE ?= 0xffff000000200000
+KERNEL_ASPACE_SIZE ?= 0x00000000f0000000
+MMU_IDENT_SIZE_SHIFT ?= 32
+endif
+MEMBASE ?= 0x200000
+KERNEL_LOAD_OFFSET ?= 0x1000
+MEMSIZE ?= 0x00040000   # 256K
+MACH_TYPE := 8518
+
+MODULE_DEPS += \
+    dev/timer/arm_generic \
+    lib/cksum \
+    lib/mempool \
+
+ifeq ($(WITH_KERNEL_VM),1)
+GLOBAL_DEFINES += MMU_IDENT_SIZE_SHIFT=$(MMU_IDENT_SIZE_SHIFT)
+endif
+
+ifeq ($(WITH_MTK_PMIC_WRAP_AND_PMIC),1)
+GLOBAL_DEFINES += WITH_MTK_PMIC_WRAP_AND_PMIC=$(WITH_MTK_PMIC_WRAP_AND_PMIC)
+endif
+
+ifeq ($(WITH_PMIC_MT6395),1)
+    GLOBAL_DEFINES += WITH_PMIC_MT6395=$(WITH_PMIC_MT6395)
+endif
+
+ifeq ($(PMIC_MT6395_I2C0),1)
+    GLOBAL_DEFINES += PMIC_MT6395_I2C0=$(PMIC_MT6395_I2C0)
+endif
+
+ifeq ($(MTK_TINYSYS_SCP_SUPPORT), yes)
+MODULE_DEPS += $(LOCAL_DIR)/drivers/scp
+GLOBAL_DEFINES += MTK_TINYSYS_SCP_SUPPORT
+endif
+ifeq ($(WITH_VCORE_I2C_BUCK),1)
+    GLOBAL_DEFINES += WITH_VCORE_I2C_BUCK=$(WITH_VCORE_I2C_BUCK)
+endif
+
+ifeq ($(WITH_VCORE_PWM_BUCK),1)
+    GLOBAL_DEFINES += WITH_VCORE_PWM_BUCK=$(WITH_VCORE_PWM_BUCK)
+endif
+
+ifeq ($(WITH_32K_OSC),1)
+    GLOBAL_DEFINES += WITH_32K_OSC=$(WITH_32K_OSC)
+endif
+
+ifeq ($(WITH_UBOOT),1)
+GLOBAL_DEFINES += WITH_UBOOT=$(WITH_UBOOT)
+endif
+
+ifeq ($(UBOOT_ARCH64),1)
+GLOBAL_DEFINES += UBOOT_ARCH64=$(UBOOT_ARCH64)
+endif
+
+ifeq ($(SUPPORT_SLC_GPT_BACKUP), 1)
+GLOBAL_DEFINES += SUPPORT_SLC_GPT_BACKUP=1
+endif
+
+ifeq ($(WITH_BOOTMODE_HANDSHAKE),1)
+GLOBAL_DEFINES += WITH_BOOTMODE_HANDSHAKE=$(WITH_BOOTMODE_HANDSHAKE)
+endif
+
+GLOBAL_DEFINES += \
+    MEMBASE=$(MEMBASE) \
+    MEMSIZE=$(MEMSIZE) \
+    RAMBASE=$(RAMBASE) \
+    MACH_TYPE=$(MACH_TYPE) \
+    PLATFORM_SUPPORTS_PANIC_SHELL=1 \
+    WITH_NO_FP=1 \
+    AB_UPGRADE_APP=$(AB_UPGRADE_APP) \
+
+LINKER_SCRIPT += \
+    $(BUILDDIR)/system-onesegment.ld
+
+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))
+
+include make/module.mk $(LOCAL_DIR)/drivers/rules.mk
diff --git a/src/bsp/lk/platform/mt8518/timer.c b/src/bsp/lk/platform/mt8518/timer.c
new file mode 100644
index 0000000..b4e0970
--- /dev/null
+++ b/src/bsp/lk/platform/mt8518/timer.c
@@ -0,0 +1,65 @@
+/*
+ * 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>
+#include <platform/mt_reg_base.h>
+
+void set_cntfrq(unsigned long freq)
+{
+#if ARCH_ARM64
+
+#else
+    __asm__ volatile("mcr p15, 0, %0, c14, c0, 0\n" :: "r"(freq));
+#endif
+}
+
+/* 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);
+}