[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, ®_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, ®_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, ®_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, ®_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, ®_val, 0xFFFF, 0);
+ printf("Reg[0x%x]=0x0222\n", reg_val);
+ pmic_read_interface(0x0248, ®_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, ®_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,
+ ®_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*)¶m.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*)¶m.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*)¶m.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);
+}