Merge "[BugFix][API-1441]add MTK patch to lk to get reboot info" into GSW3.0-No-Connman-2CoreT
diff --git a/src/bsp/lk/lib/aee/mrdump_setup.c b/src/bsp/lk/lib/aee/mrdump_setup.c
old mode 100644
new mode 100755
index 59088b3..649812a
--- a/src/bsp/lk/lib/aee/mrdump_setup.c
+++ b/src/bsp/lk/lib/aee/mrdump_setup.c
@@ -152,7 +152,8 @@
 {
     unsigned int g_rgu_status = 0;
 
-    if (wdt_status & MTK_WDT_STATUS_HWWDT_RST) {
+    if ((wdt_status & MTK_WDT_STATUS_HWWDT_RST) &&
+        !(wdt_status & MTK_WDT_STATUS_SWWDT_RST)) {
         /* For E1 bug, that SW reset value is 0xC000, we using "==" to check */
         /* Time out reboot always by pass power key */
         g_rgu_status = RE_BOOT_BY_WDT_HW;
@@ -182,6 +183,12 @@
     if (wdt_status & MTK_WDT_STATUS_SECURITY_RST) {
         g_rgu_status |= RE_BOOT_BY_SECURITY;
     }
+    if (wdt_status & MTK_WDT_STATUS_SYSRST_RST)
+        g_rgu_status |= RE_BOOT_BY_SYSRST;
+    if (wdt_status & MTK_WDT_STATUS_SSPM_RST)
+        g_rgu_status |= RE_BOOT_BY_SSPM_RST;
+    if (wdt_status & MTK_WDT_STATUS_MCUPM_RST)
+        g_rgu_status |= RE_BOOT_BY_MCUPM_RST;
 
 #ifdef MTK_PMIC_FULL_RESET
     if (mtk_wdt_is_pmic_full_reset())
diff --git a/src/bsp/lk/platform/mt2735/drivers/atf/atf_ramdump.c b/src/bsp/lk/platform/mt2735/drivers/atf/atf_ramdump.c
new file mode 100755
index 0000000..6e8de53
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/atf/atf_ramdump.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: MIT
+
+/*
+ * Copyright (c) 2021 MediaTek Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <arch/ops.h>
+#include <debug.h>
+#include <err.h>
+#include <kernel/vm.h>
+#include <platform/mboot_expdb.h>
+#include <reg.h>
+//#include <platform/smc.h>
+
+#define ATF_CRASH_MAGIC_NO                    0xdead1abf
+#define ATF_LAST_LOG_MAGIC_NO                 0x41544641
+#define ATF_DUMP_DONE_MAGIC_NO      0xd07ed07e
+
+#define MAX_ATF_LOG_SIZE            0x40000
+#define ATF_SMC_UNK 0xffffffff
+#define MTK_SIP_LK_DUMP_ATF_LOG_INFO 0x8200010A
+
+static u64 atf_log_buf_addr = 0x61000000;
+static u64 atf_log_buf_size = MAX_ATF_LOG_SIZE;
+static u64 atf_crash_flag_addr = 0;
+static void *atf_log_buf_addr_va;
+static void *atf_crash_flag_addr_va;
+
+struct __smccc_res {
+    ulong a0;
+    ulong a1;
+    ulong a2;
+    ulong a3;
+};
+
+extern  void __smc_pipe(size_t smc_id, ulong arg0, ulong arg1, ulong arg2, ulong arg3,
+               struct __smccc_res *res);
+
+#if 1
+void atf_log_init(void)
+{
+    uint32_t smc_id = 0;
+    //uint32_t op_id = 0;
+    struct __smccc_res res;
+    int ret;
+
+    /* reserve ramdump memory and pass to ATF*/
+
+    /* get log buffer and footprint buffer from ATF */
+    smc_id = MTK_SIP_LK_DUMP_ATF_LOG_INFO;
+    //__smc_conduit(smc_id, 0, 0, 0, 0, 0, 0, 0, &res);
+    __smc_pipe(smc_id, 0, 0, 0, 0, &res);
+    atf_log_buf_addr = res.a0;
+    atf_log_buf_size = res.a1;
+    atf_crash_flag_addr = res.a2;
+    dprintf(CRITICAL, "ATF: log_buf_addr = 0x%llx, size = 0x%llx, crash_flag_addr = 0x%llx\n",
+                atf_log_buf_addr, atf_log_buf_size, atf_crash_flag_addr);
+
+    if ((atf_log_buf_addr >> 32) == ATF_SMC_UNK) {
+          dprintf(CRITICAL, "LK Dump: ATF LOG INIT not supported\n");
+    } else {
+        ret = vmm_alloc_physical(vmm_get_kernel_aspace(),
+            "vm-atf-crashflag",
+            PAGE_SIZE,
+            &atf_crash_flag_addr_va,
+            PAGE_SIZE_SHIFT,
+            ROUNDDOWN((paddr_t)atf_crash_flag_addr, PAGE_SIZE),
+            0,
+            ARCH_MMU_FLAG_CACHED);
+
+        if (ret != NO_ERROR)
+            dprintf(CRITICAL, "ATF: vmm_alloc_physical failed\n");
+
+        /* round down */
+        atf_crash_flag_addr_va += (atf_crash_flag_addr & (PAGE_SIZE - 1));
+
+        /* backward compatible for legacy chips */
+        if (readl(atf_crash_flag_addr_va) == ATF_CRASH_MAGIC_NO)
+            dprintf(CRITICAL, "ATF: CRASH BUFF\n");
+        else if (readl(atf_crash_flag_addr_va) == ATF_LAST_LOG_MAGIC_NO)
+            dprintf(CRITICAL, "ATF: LAST BUFF\n");
+        else
+            dprintf(CRITICAL, "ATF: RAW BUFF\n");
+    }
+}
+#endif
+
+static void save_atf_log(AEE_DUMP_CALLBACK dev_write)
+{
+    uint32_t datasize = 0;
+    int ret;
+
+    atf_log_init();
+    /* ATF log is located in DRAM, we must allocate it first */
+    ret = vmm_alloc_physical(vmm_get_kernel_aspace(),
+                             "vm-atf-log",
+                             ROUNDUP(atf_log_buf_size, PAGE_SIZE),
+                             &atf_log_buf_addr_va,
+                             PAGE_SIZE_SHIFT,
+                             ROUNDDOWN((paddr_t)atf_log_buf_addr, PAGE_SIZE),
+                             0,
+                             ARCH_MMU_FLAG_CACHED);
+
+    if (ret != NO_ERROR)
+        dprintf(CRITICAL, "ATF: vmm_alloc_physical failed\n");
+
+    datasize = dev_write((uint64_t)atf_log_buf_addr_va, atf_log_buf_size);
+
+#if 1
+    /* Clear ATF crash flag */
+    writel(ATF_DUMP_DONE_MAGIC_NO, atf_crash_flag_addr_va);
+    arch_clean_cache_range(ROUNDDOWN((paddr_t)atf_crash_flag_addr_va, PAGE_SIZE), PAGE_SIZE);
+
+    if (!datasize)
+        dprintf(CRITICAL, "ATF: Log dump FAIL\n");
+    else
+        dprintf(INFO, "ATF: dev_w:%u, log_buf pa:0x%llx va:0x%p, size:%llx, crash_flag:0x%x\n",
+                datasize, atf_log_buf_addr, atf_log_buf_addr_va,
+                atf_log_buf_size, readl(atf_crash_flag_addr_va));
+#else
+    if (!datasize)
+        dprintf(CRITICAL, "ATF: Log dump FAIL\n");
+    else
+        dprintf(INFO, "ATF: dev_w:%u, log_buf pa:0x%llx va:0x%p, size:%llx\n",
+                datasize, atf_log_buf_addr, atf_log_buf_addr_va,
+                atf_log_buf_size);
+#endif
+}
+AEE_EXPDB_INIT_HOOK(SYS_ATF_LOG, MAX_ATF_LOG_SIZE, save_atf_log);
diff --git a/src/bsp/lk/platform/mt2735/drivers/rules.mk b/src/bsp/lk/platform/mt2735/drivers/rules.mk
old mode 100644
new mode 100755
index 46708a5..74703cc
--- a/src/bsp/lk/platform/mt2735/drivers/rules.mk
+++ b/src/bsp/lk/platform/mt2735/drivers/rules.mk
@@ -118,7 +118,12 @@
 MODULE_SRCS += \
 	$(LOCAL_DIR)/dpm/dpm_aee_dump.c \
 	$(LOCAL_DIR)/spm/spm_aee_dump.c \
-	$(LOCAL_DIR)/sspm/sspm_expdb.c
+	$(LOCAL_DIR)/sspm/sspm_expdb.c \
+    $(LOCAL_DIR)/sda/lastbus.c \
+    $(LOCAL_DIR)/sda/lastpc.c \
+    $(LOCAL_DIR)/sda/plat_debug.c \
+    $(LOCAL_DIR)/sda/tracker.c \
+    $(LOCAL_DIR)/atf/atf_ramdump.c
 endif
 
 MODULE_DEPS += $(LOCAL_DIR)/auxadc
diff --git a/src/bsp/lk/platform/mt2735/drivers/sda/init.c b/src/bsp/lk/platform/mt2735/drivers/sda/init.c
new file mode 100755
index 0000000..7304877
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/sda/init.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <arch/ops.h>
+#include <reg.h>
+
+// last_pc init
+#define CPC_FLOW_CTRL_CFG     (0x0C53A814)
+#define RESET_ON_KEEP_EN      (1 << 17)
+void lastpc_init(void)
+{
+    unsigned int ctrl = readl(CPC_FLOW_CTRL_CFG);
+    writel(CPC_FLOW_CTRL_CFG, (ctrl|RESET_ON_KEEP_EN));
+    DSB;
+}
+
+// systracker init
+//#define SYSTRACKER_CTRL   (0xFFFFFFF000000000 + 0x100012FC)
+#define SYSTRACKER_CTRL     (0x100012FC)
+
+void systracker_init(void)
+{
+    writel(SYSTRACKER_CTRL, 0x00006007);
+}
\ No newline at end of file
diff --git a/src/bsp/lk/platform/mt2735/drivers/sda/lastbus.c b/src/bsp/lk/platform/mt2735/drivers/sda/lastbus.c
new file mode 100755
index 0000000..4931c48
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/sda/lastbus.c
@@ -0,0 +1,412 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <debug.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <lib/mempool.h>
+#include "lastbus.h"
+#include <reg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "utils.h"
+
+static struct cfg_lastbus my_cfg_lastbus;
+
+const char *lastbus_compatible[] = {
+    "/lastbus",
+    "/lastbus/monitors",
+    NULL
+};
+
+static int get_lastbus_setting_from_fdt(void *fdt)
+{
+    int len, offset, value, node;
+    int num = 0;
+    int num_idle_mask;
+    u32 *data;
+
+    if (!fdt)
+        return -ENODATA;
+
+    offset = fdt_path_offset(fdt, lastbus_compatible[0]);
+    if (offset < 0) {
+        dprintf(CRITICAL, "%s: couldn't find the lastbus node\n", __func__);
+        return -ENODATA;
+    }
+
+    /* get enabled */
+    data = (u32 *)fdt_getprop(fdt, offset, "enabled", &len);
+    if (!data || !len) {
+        dprintf(CRITICAL, "%s: couldn't find property enabled\n", __func__);
+        my_cfg_lastbus.enabled = 0;
+        return -ENODATA;
+    } else {
+        value = fdt32_to_cpu(data[0]);
+        dprintf(INFO, "%s: enabled = %d\n", __func__, value);
+        my_cfg_lastbus.enabled = value;
+    }
+
+    /* get sw_version */
+    data = (u32 *)fdt_getprop(fdt, offset, "sw_version", &len);
+    if (!data || !len) {
+        dprintf(CRITICAL, "%s: couldn't find property sw_version\n", __func__);
+        my_cfg_lastbus.sw_version = LASTBUS_SW_V1;
+    } else {
+        value = fdt32_to_cpu(data[0]);
+        dprintf(INFO, "%s: sw_version = %d\n", __func__, value);
+        my_cfg_lastbus.sw_version = value;
+    }
+
+    /* get timeout_ms */
+    data = (u32 *)fdt_getprop(fdt, offset, "timeout_ms", &len);
+    if (!data || !len) {
+        dprintf(CRITICAL, "%s: couldn't find property timeout_ms\n", __func__);
+        my_cfg_lastbus.timeout_ms = 0xFFFFFFFF;
+    } else {
+        value = fdt32_to_cpu(data[0]);
+        dprintf(INFO, "%s: timeout_ms = %d\n", __func__, value);
+        my_cfg_lastbus.timeout_ms = value;
+    }
+
+    /* get timeout_type */
+    data = (u32 *)fdt_getprop(fdt, offset, "timeout_type", &len);
+    if (!data || !len) {
+        dprintf(CRITICAL, "%s: couldn't find property timeout_type\n", __func__);
+        my_cfg_lastbus.timeout_type = LASTBUS_TIMEOUT_FIRST;
+    } else {
+        value = fdt32_to_cpu(data[0]);
+        dprintf(INFO, "%s: timeout_type = %d (0:first/1:last)\n", __func__, value);
+        if ((value != LASTBUS_TIMEOUT_FIRST) && (value != LASTBUS_TIMEOUT_LAST)) {
+            dprintf(CRITICAL, "%s: timeout_type(%d) is invalid!\n", __func__, value);
+            return -EINVAL;
+        }
+        my_cfg_lastbus.timeout_type = value;
+    }
+
+    offset = fdt_subnode_offset(fdt, offset, "monitors");
+    if (offset < 0) {
+        dprintf(CRITICAL, "%s: couldn't find the monitors subnode\n", __func__);
+        return -ENODATA;
+    }
+
+    /* get monitors */
+    fdt_for_each_subnode(node, fdt, offset) {
+        if (node >= 0) {
+            /* get monitor name */
+            data = (u32 *)fdt_getprop(fdt, node, "monitor_name", &len);
+            if (!data || !len) {
+                dprintf(CRITICAL, "%s: couldn't find property monitor name\n", __func__);
+                return -ENODATA;
+            }
+
+            if (len <= MAX_MONITOR_NAME_LEN) {
+                strncpy(my_cfg_lastbus.monitors[num].name, (char const *)data, len);
+            } else {
+                strncpy(my_cfg_lastbus.monitors[num].name, (char const *)data,
+                        MAX_MONITOR_NAME_LEN);
+                my_cfg_lastbus.monitors[num].name[MAX_MONITOR_NAME_LEN-1] = '\0';
+            }
+
+            dprintf(INFO, "%s: name = %s\n", __func__, my_cfg_lastbus.monitors[num].name);
+
+            /* get monitor base */
+            data = (u32 *)fdt_getprop(fdt, node, "base", &len);
+            if (!data || !len) {
+                dprintf(CRITICAL, "%s: couldn't find property monitor base\n", __func__);
+                return -ENODATA;
+            } else {
+                value = fdt32_to_cpu(data[0]);
+                if (!value) {
+                    dprintf(CRITICAL, "%s: fail to get base\n", __func__);
+                    return -ENODATA;
+                } else {
+                    dprintf(INFO, "%s: base = 0x%x\n", __func__, value);
+                    my_cfg_lastbus.monitors[num].base = (value + KERNEL_ASPACE_BASE);
+                }
+            }
+
+            /* get monitor num_ports */
+            data = (u32 *)fdt_getprop(fdt, node, "num_ports", &len);
+            if (!data || !len) {
+                dprintf(CRITICAL, "%s: couldn't find property num_ports\n", __func__);
+                return -ENODATA;
+            } else {
+                value = fdt32_to_cpu(data[0]);
+                dprintf(INFO, "%s: num_ports = %d\n", __func__, value);
+                my_cfg_lastbus.monitors[num].num_ports = value;
+            }
+
+            /* get monitor idle_mask */
+            num_idle_mask = 0;
+            data = (u32 *)fdt_getprop(fdt, node, "idle_masks", &len);
+            if (!data || !len) {
+                my_cfg_lastbus.monitors[num].idle_mask_en = 0;
+            } else {
+                my_cfg_lastbus.monitors[num].idle_mask_en = 1;
+
+                while (len >= (sizeof(unsigned int) * 2)) {
+                    value = fdt32_to_cpu(*data++);
+                    if (value == 0x0) {
+                        dprintf(CRITICAL, "%s: invalid idle_mask offset (0x%x)\n", __func__, value);
+                        return -EINVAL;
+                    }
+                    my_cfg_lastbus.monitors[num].idle_masks[num_idle_mask].reg_offset = value;
+                    dprintf(INFO, "%s: idle_masks[%d].reg_offset = 0x%x\n",
+                            __func__, num_idle_mask, value);
+                    value = fdt32_to_cpu(*data++);
+                    my_cfg_lastbus.monitors[num].idle_masks[num_idle_mask].reg_value = value;
+                    dprintf(INFO, "%s: idle_masks[%d].reg_value  = 0x%x\n",
+                            __func__, num_idle_mask, value);
+                    num_idle_mask++;
+                    len -= (sizeof(unsigned int) * 2);
+                }
+
+                if (num_idle_mask > NR_MAX_LASTBUS_IDLE_MASK) {
+                    dprintf(CRITICAL, "%s: Error: number of idle_masks(%d) is great than %d!\n",
+                    __func__, num_idle_mask, NR_MAX_LASTBUS_IDLE_MASK);
+                    return -EINVAL;
+                } else {
+                    dprintf(INFO, "%s: num_idle_mask = %d\n", __func__, num_idle_mask);
+                    my_cfg_lastbus.monitors[num].num_idle_mask = num_idle_mask;
+                }
+            }
+
+            /* get monitor bus_freq_mhz */
+            data = (u32 *)fdt_getprop(fdt, node, "bus_freq_mhz", &len);
+            if (!data || !len) {
+                dprintf(CRITICAL, "%s: couldn't find property bus_freq_mhz\n", __func__);
+                return -ENODATA;
+            } else {
+                value = fdt32_to_cpu(data[0]);
+                dprintf(INFO, "%s: bus_freq_mhz = %d\n", __func__, value);
+                dprintf(INFO, "================================================\n");
+                my_cfg_lastbus.monitors[num].bus_freq_mhz = value;
+            }
+
+            num++;
+        }
+    }
+
+    if (num == 0) {
+        dprintf(CRITICAL, "%s: there is no lastbus monitor node\n", __func__);
+        return -ENODATA;
+    } else {
+        my_cfg_lastbus.num_used_monitors = num;
+        if (num > NR_MAX_LASTBUS_MONITOR) {
+            dprintf(CRITICAL, "%s: Error: number of monitors(%d) is great than %d!\n",
+                    __func__, num, NR_MAX_LASTBUS_MONITOR);
+            return -EINVAL;
+        } else {
+            dprintf(INFO, "%s: num_used_monitors = %d\n", __func__, num);
+        }
+    }
+    return 0;
+}
+
+static unsigned int calculate_timeout_setting(unsigned int bus_freq_mhz, unsigned int timeout_ms)
+{
+    unsigned int value;
+
+    value = ((timeout_ms * 1000 * bus_freq_mhz) >> 10) - 1;
+    //dprintf(INFO, "%s: bus_freq_mhz = %d, timeout_ms = %d, timeout_threshold = 0x%x\n",
+    //        __func__, bus_freq_mhz, timeout_ms, value);
+    return value;
+}
+
+static void lastbus_init_monitor_v1(struct lastbus_monitor *m, unsigned int timeout_ms,
+                                    unsigned int timeout_type)
+{
+    unsigned int bus_freq_mhz, timeout_setting;
+    unsigned int i, reg_offset, reg_value;
+
+    if (m->idle_mask_en == 1) {
+        for (i = 0; i < m->num_idle_mask; i++) {
+            reg_offset = m->idle_masks[i].reg_offset;
+            reg_value = m->idle_masks[i].reg_value;
+            writel(reg_value, m->base + reg_offset);
+            dprintf(INFO, "%s: set idle_mask 0x%x = 0x%x\n",
+                    __func__, m->base + reg_offset, reg_value);
+        }
+    }
+
+    /* clear timeout status with DBG_CKEN */
+    writel((LASTBUS_TIMEOUT_CLR | LASTBUS_DEBUG_CKEN), m->base);
+
+    /* de-assert clear bit with DBG_CKEN */
+    writel(LASTBUS_DEBUG_CKEN, m->base);
+
+    if (timeout_ms == 0xFFFFFFFF) {
+        /* set maximum timeout for 1st edition*/
+        writel(((0xFFFF << TIMEOUT_THRES_SHIFT) | LASTBUS_DEBUG_CKEN |
+               (timeout_type << TIMEOUT_TYPE_SHIFT)), m->base);
+        writel(((0xFFFF << TIMEOUT_THRES_SHIFT) | LASTBUS_DEBUG_CKEN | LASTBUS_DEBUG_EN |
+               (timeout_type << TIMEOUT_TYPE_SHIFT)), m->base);
+    } else {
+        bus_freq_mhz = m->bus_freq_mhz;
+        timeout_setting = calculate_timeout_setting(bus_freq_mhz, timeout_ms);
+        if (timeout_setting > 0xFFFF)
+            timeout_setting = 0xFFFF;
+        writel(((timeout_setting << TIMEOUT_THRES_SHIFT) | LASTBUS_DEBUG_CKEN |
+               (timeout_type << TIMEOUT_TYPE_SHIFT)), m->base);
+        writel(((timeout_setting << TIMEOUT_THRES_SHIFT) | LASTBUS_DEBUG_CKEN |
+               LASTBUS_DEBUG_EN | (timeout_type << TIMEOUT_TYPE_SHIFT)), m->base);
+    }
+    dprintf(INFO, "%s: base setting = 0x%x\n", __func__, readl(m->base));
+}
+
+static void lastbus_init_v1(void)
+{
+    struct lastbus_monitor *m;
+    unsigned int num_used_monitors, timeout_ms, timeout_type;
+    unsigned int i;
+
+    num_used_monitors = my_cfg_lastbus.num_used_monitors;
+    timeout_ms = my_cfg_lastbus.timeout_ms;
+    timeout_type = my_cfg_lastbus.timeout_type;
+
+    for (i = 0; i < num_used_monitors; i++) {
+        m = &my_cfg_lastbus.monitors[i];
+        lastbus_init_monitor_v1(m, timeout_ms, timeout_type);
+    }
+}
+
+void lastbus_init(void *fdt)
+{
+    if (get_lastbus_setting_from_fdt(fdt) < 0)
+        return;
+
+    if (my_cfg_lastbus.enabled == 0)
+        return;
+
+    if (my_cfg_lastbus.sw_version == LASTBUS_SW_V1) {
+        lastbus_init_v1();
+        return;
+    }
+}
+
+void lastbus_init_aee(void *fdt)
+{
+    /* get lastbus setting from fdt to initialize my_cfg_lastbus */
+    get_lastbus_setting_from_fdt(fdt);
+}
+
+static bool lastbus_is_timeout_v1(const struct lastbus_monitor *m)
+{
+#if 0
+    /* XXX
+     * workaround for timeout loss.
+     * debug_ctrl_ao*: infrabus_clk_detect [7:5] != 0
+     */
+    if (readl(m->base) & 0xe0)
+        return 1;
+#endif
+
+    return (readl(m->base) & LASTBUS_TIMEOUT);
+}
+
+static unsigned long long gray_code_to_binary_convert(const unsigned long long gray_code)
+{
+    unsigned int gray_array[64], binary_array[64];
+    int i;
+    unsigned long long value = 0;
+
+    for (i = 0; i < 64; i++)
+        gray_array[i] = ((gray_code >> i) & 0x1);
+
+    binary_array[63] = gray_array[63];
+    for (i = 62; i >= 0; i--)
+        binary_array[i] = gray_array[i] ^ binary_array[i+1];
+
+    for (i = 0; i < 64; i++)
+       value |= (binary_array[i] << i);
+
+    return value;
+}
+
+static void lastbus_dump_monitor_v1(const struct lastbus_monitor *m, char *buf, int *wp)
+{
+    unsigned int i;
+    unsigned long long grad_code, bin_code;
+
+    *wp += snprintf(buf + *wp, LASTBUS_BUF_LENGTH - *wp, "--- ");
+    *wp += snprintf(buf + *wp, LASTBUS_BUF_LENGTH - *wp, "%s %p %d",
+                    m->name, (void *)(m->base - KERNEL_ASPACE_BASE), m->num_ports);
+    *wp += snprintf(buf + *wp, LASTBUS_BUF_LENGTH - *wp, " ---\n");
+
+    for (i = 0; i < m->num_ports; i++) {
+        *wp += snprintf(buf + *wp, LASTBUS_BUF_LENGTH - *wp, "%08x\n",
+                        readl(m->base + 0x408 + (i * 4)));
+    }
+
+    grad_code = readl(m->base + 0x404);
+    grad_code = (grad_code << 32) | readl(m->base + 0x400);
+    bin_code = gray_code_to_binary_convert(grad_code);
+    dprintf(INFO, "%s: gray_code = 0x%llx, binary = 0x%llx\n", __func__, grad_code, bin_code);
+
+    *wp += snprintf(buf + *wp, LASTBUS_BUF_LENGTH - *wp, "timestamp: 0x%llx\n", bin_code);
+}
+
+static int lastbus_dump_v1(char *buf, int *wp)
+{
+    struct lastbus_monitor *m;
+    unsigned int num_used_monitors;
+    unsigned int i;
+    bool is_timeout, timeout_occurred = false;
+
+    *wp += snprintf(buf + *wp, LASTBUS_BUF_LENGTH - *wp,
+            "\n*********************** %s lastbus ***********************\n", PLATFORM);
+
+    num_used_monitors = my_cfg_lastbus.num_used_monitors;
+
+    for (i = 0; i < num_used_monitors; i++) {
+        is_timeout = false;
+
+        m = &my_cfg_lastbus.monitors[i];
+
+        is_timeout = lastbus_is_timeout_v1(m);
+
+        if (is_timeout) {
+            dprintf(INFO, "%s: lastbus timeout happened (%s)\n", __func__, m->name);
+            lastbus_dump_monitor_v1(m, buf, wp);
+        }
+
+        timeout_occurred |= is_timeout;
+    }
+
+    *wp += snprintf(buf + *wp, LASTBUS_BUF_LENGTH - *wp,
+                    "\n#lastbus timeout = %s\n",
+                    timeout_occurred ? "True" : "False");
+
+    return 1;
+}
+
+int lastbus_get(void **data, int *len)
+{
+    int ret;
+    *len = 0;
+    *data = mempool_alloc(LASTBUS_BUF_LENGTH, MEMPOOL_ANY);
+    if (*data == NULL)
+        return 0;
+
+    ret = lastbus_dump_v1(*data, len);
+
+    if (ret < 0 || *len > LASTBUS_BUF_LENGTH) {
+        *len = (*len > LASTBUS_BUF_LENGTH) ? LASTBUS_BUF_LENGTH : *len;
+        return ret;
+    }
+
+    return 1;
+}
+
+void lastbus_put(void **data)
+{
+    mempool_free(*data);
+}
diff --git a/src/bsp/lk/platform/mt2735/drivers/sda/lastbus.h b/src/bsp/lk/platform/mt2735/drivers/sda/lastbus.h
new file mode 100755
index 0000000..4a6e409
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/sda/lastbus.h
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#pragma once
+
+#define LASTBUS_BUF_LENGTH        0x4000
+#define NR_MAX_LASTBUS_MONITOR    16
+#define MAX_MONITOR_NAME_LEN      32
+#define NR_MAX_LASTBUS_IDLE_MASK  8
+
+#define TIMEOUT_THRES_SHIFT       16
+#define TIMEOUT_TYPE_SHIFT        1
+
+#define LASTBUS_TIMEOUT_CLR       0x0200
+#define LASTBUS_DEBUG_CKEN        0x0008
+#define LASTBUS_DEBUG_EN          0x0004
+#define LASTBUS_TIMEOUT           0x0001
+
+enum LASTBUS_SW_VERSION {
+    LASTBUS_SW_V1 = 1,
+    LASTBUS_SW_V2 = 2,
+};
+
+enum LASTBUS_TIMEOUT_TYPE {
+    LASTBUS_TIMEOUT_FIRST = 0,
+    LASTBUS_TIMEOUT_LAST = 1
+};
+
+struct lastbus_idle_mask {
+    unsigned int reg_offset;
+    unsigned int reg_value;
+};
+
+struct lastbus_monitor {
+    char name[MAX_MONITOR_NAME_LEN];
+    vaddr_t base;
+    unsigned int num_ports;
+    int bus_freq_mhz;
+    unsigned int idle_mask_en;
+    unsigned int num_idle_mask;
+    struct lastbus_idle_mask idle_masks[NR_MAX_LASTBUS_IDLE_MASK];
+};
+
+struct cfg_lastbus {
+    unsigned int sw_version;
+    unsigned int enabled;
+    unsigned int timeout_ms;
+    unsigned int timeout_type;
+    unsigned int num_used_monitors;
+    struct lastbus_monitor monitors[NR_MAX_LASTBUS_MONITOR];
+};
+
+void lastbus_init(void *fdt);
+void lastbus_init_aee(void *fdt);
+int lastbus_get(void **data, int *len);
+void lastbus_put(void **data);
diff --git a/src/bsp/lk/platform/mt2735/drivers/sda/lastpc.c b/src/bsp/lk/platform/mt2735/drivers/sda/lastpc.c
new file mode 100755
index 0000000..b162c08
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/sda/lastpc.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <debug.h>
+#include <errno.h>
+#include "lastpc.h"
+#include <lib/mempool.h>
+#include <platform/plat_lastpc.h>
+#include <reg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "utils.h"
+
+unsigned long plt_get_cpu_power_status_at_wdt(void)
+{
+    unsigned long bitmask = 0xff, ret;
+
+    ret = readl(SPM_PWR_STS_ADDR);
+    bitmask = (ret & SPM_PWR_STS_MASK) >> SPM_PWR_STS_OFFSET;
+
+    return bitmask;
+}
+
+int default_lastpc_dump(const struct plt_cfg_pc_latch *self, char *buf, int *wp)
+{
+    unsigned int i;
+    unsigned long long pc_value_h, fp_value_h, sp_value_h;
+    unsigned long long pc_value, fp_value, sp_value;
+    unsigned long core_dbg_sel, core_dbg_mon;
+    unsigned long cpu_power_status = 0;
+
+    int is_64bit_kernel = 1;
+
+#if 0 //mark it due to DFD on LK2 is not ready now
+    /* mcusys registers would be corrupted by DFD */
+    if (dfd_internal_dump_before_reboot()) {
+        *wp += dfd_internal_dump_get_decoded_lastpc(buf + *wp, LASTPC_BUF_LENGTH - *wp);
+        return 1;
+    }
+#endif
+
+    /* get the power status information */
+    cpu_power_status = plt_get_cpu_power_status_at_wdt();
+
+    for (i = 0; i < self->nr_max_core; ++i) {
+        /* if CPUX is not powered on before reboot --> skip */
+        if (extract_n2mbits(cpu_power_status, i, i) == 0) {
+            *wp += snprintf(buf + *wp, LASTPC_BUF_LENGTH - *wp,
+                       "[LAST PC] CORE_%d PC = 0x0, FP = 0x0, SP = 0x0\n", i);
+            continue;
+        }
+
+        core_dbg_sel = self->core_dbg_sel[i];
+        core_dbg_mon = self->core_dbg_mon[i];
+        if ((core_dbg_sel == 0) || (core_dbg_mon == 0))
+            continue;
+
+        if (i < (self->nr_max_core - self->nr_max_big_core)) { /* for little core */
+            writel(LCORE_PC_H, core_dbg_sel);
+            pc_value_h = readl(core_dbg_mon);
+            writel(LCORE_PC_L, core_dbg_sel);
+            pc_value = (pc_value_h << 32) | readl(core_dbg_mon);
+        } else { /* for big core */
+            writel(BCORE_PC_H, core_dbg_sel);
+            pc_value_h = readl(core_dbg_mon);
+            writel(BCORE_PC_L, core_dbg_sel);
+            pc_value = (pc_value_h << 32) | readl(core_dbg_mon);
+        }
+
+        if (self->dump_pc_only) {
+            *wp += snprintf(buf + *wp, LASTPC_BUF_LENGTH - *wp,
+                       "[LAST PC] CORE_%d PC = 0x%016llx\n", i, pc_value);
+            continue;
+        }
+
+        /* get the 64bit/32bit kernel information from bootopt */
+        if (is_64bit_kernel) {
+            if (i < (self->nr_max_core - self->nr_max_big_core)) {
+                writel(LCORE_LR_H, core_dbg_sel);
+                fp_value_h = readl(core_dbg_mon);
+                writel(LCORE_LR_L, core_dbg_sel);
+                fp_value = (fp_value_h << 32) | readl(core_dbg_mon);
+
+                writel(LCORE_SP_H, core_dbg_sel);
+                sp_value_h = readl(core_dbg_mon);
+                writel(LCORE_SP_L, core_dbg_sel);
+                sp_value = (sp_value_h << 32) | readl(core_dbg_mon);
+            } else {
+#if 0 //what value for core_dbg_sel to select FP and SP?
+                writel(BCORE_FP_H, core_dbg_sel);
+                fp_value_h = readl(core_dbg_mon);
+                writel(BCORE_FP_L, core_dbg_sel);
+                fp_value = (fp_value_h << 32) | readl(core_dbg_mon);
+
+                writel(BCORE_SP_H, core_dbg_sel);
+                sp_value_h = readl(core_dbg_mon);
+                writel(BCORE_SP_L, core_dbg_sel);
+                sp_value = (sp_value_h << 32) | readl(core_dbg_mon);
+#else
+                fp_value = 0;
+                sp_value = 0;
+#endif
+            }
+            *wp += snprintf(buf + *wp, LASTPC_BUF_LENGTH - *wp,
+                       "[LAST PC] CORE_%d PC = 0x%016llx, FP = 0x%016llx, SP = 0x%016llx\n",
+                       i, pc_value, fp_value, sp_value);
+        } else {
+            if (i < (self->nr_max_core - self->nr_max_big_core)) {
+                writel(LCORE_LR_L, core_dbg_sel);
+                fp_value = readl(core_dbg_mon);
+
+                writel(LCORE_SP_L, core_dbg_sel);
+                sp_value = readl(core_dbg_mon);
+            } else {
+#if 0
+                writel(BCORE_FP_L, core_dbg_sel);
+                fp_value = readl(core_dbg_mon);
+
+                writel(BCORE_SP_L, core_dbg_sel);
+                sp_value = readl(core_dbg_mon);
+#else
+                fp_value = 0;
+                sp_value = 0;
+#endif
+            }
+            *wp += snprintf(buf + *wp, LASTPC_BUF_LENGTH - *wp,
+                       "[LAST PC] CORE_%d PC = 0x%016llx, FP = 0x%08llx, SP = 0x%08llx\n",
+                       i, pc_value, fp_value, sp_value);
+        }
+    }
+
+    *wp += snprintf(buf + *wp, LASTPC_BUF_LENGTH - *wp, "\n");
+    return 1;
+}
+
+static int lastpc_dump(char *buf, int *wp)
+{
+    if (buf == NULL || wp == NULL)
+        return -1;
+
+    *wp += snprintf(buf + *wp, LASTPC_BUF_LENGTH - *wp,
+               "\n*************************** lastpc ***************************\n");
+
+    if (cfg_pc_latch.dump)
+        cfg_pc_latch.dump(&cfg_pc_latch, buf, wp);
+    else
+        default_lastpc_dump(&cfg_pc_latch, buf, wp);
+
+    return 1;
+}
+
+int lastpc_get(void **data, int *len)
+{
+    int ret;
+    *len = 0;
+    *data = mempool_alloc(LASTPC_BUF_LENGTH, MEMPOOL_ANY);
+    if (*data == NULL)
+        return 0;
+
+    ret = lastpc_dump(*data, len);
+    if (ret < 0 || *len > LASTPC_BUF_LENGTH) {
+        *len = (*len > LASTPC_BUF_LENGTH) ? LASTPC_BUF_LENGTH : *len;
+        return ret;
+    }
+
+    return 1;
+}
+
+void lastpc_put(void **data)
+{
+    mempool_free(*data);
+}
\ No newline at end of file
diff --git a/src/bsp/lk/platform/mt2735/drivers/sda/lastpc.h b/src/bsp/lk/platform/mt2735/drivers/sda/lastpc.h
new file mode 100755
index 0000000..b29492f
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/sda/lastpc.h
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#pragma once
+
+#define LASTPC_BUF_LENGTH          (2000)
+
+enum {
+    LASTPC_V1 = 0,
+    LASTPC_V2,
+    LASTPC_V3,
+};
+
+/* platform-dependent configs for lastpc */
+struct plt_cfg_pc_latch {
+    unsigned int nr_max_core;
+    unsigned int nr_max_big_core;
+    unsigned long *core_dbg_sel;
+    unsigned long *core_dbg_mon;
+    int (*dump)(const struct plt_cfg_pc_latch *self, char *buf, int *wp);
+    unsigned int dump_pc_only;
+    unsigned int version;
+};
+
+int lastpc_get(void **data, int *len);
+void lastpc_put(void **data);
diff --git a/src/bsp/lk/platform/mt2735/drivers/sda/plat_debug.c b/src/bsp/lk/platform/mt2735/drivers/sda/plat_debug.c
new file mode 100755
index 0000000..070ee0a
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/sda/plat_debug.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <debug.h>
+#include <errno.h>
+#include "lastpc.h"
+#include <kernel/vm.h>
+#include "lastbus.h"
+#include <platform/mboot_expdb.h>
+#include <platform/plat_debug.h>
+#include "tracker.h"
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+static void save_cpu_bus_data(AEE_DUMP_CALLBACK dev_write)
+{
+    char *buf = NULL;
+    int ret;
+    int len = 0;
+    unsigned int datasize = 0;
+    /* Save latch buffer */
+
+    ret = lastpc_get((void **)&buf, &len);
+    if (ret && (buf != NULL)) {
+        LTRACEF("In lastpc dump\n");
+        if (len > 0)
+            datasize = dev_write(buf, len);
+        lastpc_put((void **)&buf);
+    }
+    dprintf(CRITICAL, "lastpc done\n");
+
+    ret = tracker_get((void **)&buf, &len, SYS_TRACK_ENTRY);
+    if (ret && (buf != NULL)) {
+        LTRACEF("In tracker dump\n");
+        if (len > 0)
+            datasize = dev_write(buf, len);
+        tracker_put((void **)&buf);
+    } else {
+        tracker_put((void **)&buf);
+    }
+    dprintf(CRITICAL, "tracker done\n");
+
+    ret = lastbus_get((void **)&buf, &len);
+    if (ret && (buf != NULL)) {
+        LTRACEF("In lastbus dump\n");
+        if (len > 0)
+            datasize = dev_write(buf, len);
+        lastbus_put((void **)&buf);
+    }
+    dprintf(CRITICAL, "lastbus done\n");
+
+    return;
+}
+
+AEE_EXPDB_INIT_HOOK(SYS_LAST_CPU_BUS, LAST_DUMP_SIZE, save_cpu_bus_data);
diff --git a/src/bsp/lk/platform/mt2735/drivers/sda/tracker.c b/src/bsp/lk/platform/mt2735/drivers/sda/tracker.c
new file mode 100755
index 0000000..f1106cb
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/sda/tracker.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <debug.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <lib/mempool.h>
+#include "tracker.h"
+#include <reg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+static int systracker_dump(char *buf, int *wp, unsigned int entry_num)
+{
+    unsigned int i;
+    unsigned int reg_value;
+    unsigned int entry_valid;
+    unsigned int entry_secure;
+    unsigned int entry_id;
+    unsigned int entry_address;
+    unsigned int entry_data_size;
+    unsigned int entry_burst_length;
+
+    if (buf == NULL || wp == NULL)
+        return -1;
+
+    /* Get tracker info and save to buf */
+    /* check if we got AP tracker timeout */
+    if (readl(BUS_DBG_CON) & BUS_DBG_CON_TIMEOUT) {
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+               "\n*************************** systracker ***************************\n");
+
+        for (i = 0; i < entry_num; i++) {
+            entry_address      = readl(AR_TRACK_L(BUS_DBG_BASE, i));
+            reg_value          = readl(AR_TRACK_H(BUS_DBG_BASE, i));
+            entry_valid        = extract_n2mbits(reg_value, TRACKER_VALID_S, TRACKER_VALID_E);
+            entry_secure       = extract_n2mbits(reg_value, TRACKER_SECURE_S, TRACKER_SECURE_E);
+            entry_id           = extract_n2mbits(reg_value, TRACKER_ID_S, TRACKER_ID_E);
+            entry_data_size    = extract_n2mbits(reg_value,
+                                                 TRACKER_DATA_SIZE_S, TRACKER_DATA_SIZE_E);
+            entry_burst_length = extract_n2mbits(reg_value,
+                                                 TRACKER_BURST_LEN_S, TRACKER_BURST_LEN_E);
+
+            *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                       "read entry = %d, valid = 0x%x, non-secure = 0x%x, read id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
+                                       i, entry_valid, entry_secure, entry_id,
+                                       entry_address, entry_data_size, entry_burst_length);
+            }
+
+        for (i = 0; i < entry_num; i++) {
+            entry_address      = readl(AW_TRACK_L(BUS_DBG_BASE, i));
+            reg_value          = readl(AW_TRACK_H(BUS_DBG_BASE, i));
+            entry_valid        = extract_n2mbits(reg_value, TRACKER_VALID_S, TRACKER_VALID_E);
+            entry_secure       = extract_n2mbits(reg_value, TRACKER_SECURE_S, TRACKER_SECURE_E);
+            entry_id           = extract_n2mbits(reg_value, TRACKER_ID_S, TRACKER_ID_E);
+            entry_data_size    = extract_n2mbits(reg_value,
+                                                 TRACKER_DATA_SIZE_S, TRACKER_DATA_SIZE_E);
+            entry_burst_length = extract_n2mbits(reg_value,
+                                                 TRACKER_BURST_LEN_S, TRACKER_BURST_LEN_E);
+
+            *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                       "write entry = %d, valid = 0x%x, non-secure = 0x%x, write id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
+                                       i, entry_valid, entry_secure, entry_id, entry_address,
+                                       entry_data_size, entry_burst_length);
+        }
+
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "write entry ~ %d, valid = 0x%x, data = 0x%x\n", entry_num - 2,
+                                   ((readl(BUS_DBG_W_TRACK_DATA_VALID)&(0x1<<6))>>6),
+                                     readl(BUS_DBG_W_TRACK_DATA62));
+
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "write entry ~ %d, valid = 0x%x, data = 0x%x\n\n", entry_num - 1,
+                                   ((readl(BUS_DBG_W_TRACK_DATA_VALID)&(0x1<<7))>>7),
+                                     readl(BUS_DBG_W_TRACK_DATA63));
+    }
+
+#ifdef HAS_INFA_TRACKER
+    /* check if we got infra tracker timeout */
+    *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                    "\n*************************** INFRA ***************************\n");
+    if (readl(INFRA_TRACKER_CON) & BUSTRACKER_TIMEOUT) {
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "infra tracker timeout (0x%08x)\n", readl(INFRA_TRACKER_CON));
+        for (i = 0; i < INFRA_ENTRY_NUM; i++) {
+            entry_address = readl(AR_TRACK_L(INFRA_TRACKER_CON, i));
+            reg_value = readl(AR_TRACK_H(INFRA_TRACKER_CON, i));
+            *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                       "read entry = %d, address = 0x%x, attribute = 0x%x\n",
+                                       i, entry_address, reg_value);
+        }
+        for (i = 0; i < INFRA_ENTRY_NUM; i++) {
+            entry_address = readl(AW_TRACK_L(INFRA_TRACKER_CON, i));
+            reg_value = readl(AW_TRACK_H(INFRA_TRACKER_CON, i));
+            *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                       "write entry = %d, address = 0x%x, attribute = 0x%x\n",
+                                       i, entry_address, reg_value);
+        }
+    }
+#endif
+
+#ifdef HAS_PERI_TRACKER
+    /* check if we got peri tracker timeout */
+    if (readl(PERI_TRACKER_BASE) & BUSTRACKER_TIMEOUT) {
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                "peri tracker timeout (0x%08x)\n", readl(PERI_TRACKER_BASE));
+        for (i = 0; i < PERI_ENTRY_NUM; i++) {
+            entry_address = readl(AR_TRACK_L(PERI_TRACKER_BASE, i));
+            reg_value = readl(AR_TRACK_H(PERI_TRACKER_BASE, i));
+            *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                    "read entry = %d, address = 0x%x, attribute = 0x%x\n",
+                         i, entry_address, reg_value);
+        }
+        for (i = 0; i < PERI_ENTRY_NUM; i++) {
+            entry_address = readl(AW_TRACK_L(PERI_TRACKER_BASE, i));
+            reg_value = readl(AW_TRACK_H(PERI_TRACKER_BASE, i));
+            *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                    "write entry = %d, address = 0x%x, attribute = 0x%x\n",
+                        i, entry_address, reg_value);
+        }
+    }
+#endif
+
+#ifdef HAS_SLV
+    reg_value = readl(BUS_DBG_CON);
+    if (SLV_ERR == (reg_value & AR_RESP_ERR_TYPE_MASK) >> AR_RESP_ERR_TYPE_OFFSET)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n AP tracker detects AR slave error.");
+    if (DEC_ERR == (reg_value & AR_RESP_ERR_TYPE_MASK) >> AR_RESP_ERR_TYPE_OFFSET)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n AP tracker detects AR decode error.");
+    if (SLV_ERR == (reg_value & AW_RESP_ERR_TYPE_MASK) >> AW_RESP_ERR_TYPE_OFFSET)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n AP tracker detects AW slave error.");
+    if (DEC_ERR == (reg_value & AW_RESP_ERR_TYPE_MASK) >> AW_RESP_ERR_TYPE_OFFSET)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n AP tracker detects AW decode error.");
+
+    reg_value = readl(BUS_DBG_TIMEOUT_INFO);
+    if (reg_value & AR_STALL_TIMEOUT)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n AP tracker detects AR stall timeout.");
+    if (reg_value & AW_STALL_TIMEOUT)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n AP tracker detects AW stall timeout.");
+
+    reg_value = readl(INFRA_TRACKER_BASE);
+    if (SLV_ERR == (reg_value & AR_RESP_ERR_TYPE_MASK) >> AR_RESP_ERR_TYPE_OFFSET)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n Infra tracker detects AR slave error.");
+    if (DEC_ERR == (reg_value & AR_RESP_ERR_TYPE_MASK) >> AR_RESP_ERR_TYPE_OFFSET)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n Infra tracker detects AR decode error.");
+    if (SLV_ERR == (reg_value & AW_RESP_ERR_TYPE_MASK) >> AW_RESP_ERR_TYPE_OFFSET)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n Infra tracker detects AW slave error.");
+    if (DEC_ERR == (reg_value & AW_RESP_ERR_TYPE_MASK) >> AW_RESP_ERR_TYPE_OFFSET)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n Infra tracker detects AW decode error.");
+
+    reg_value = readl(INFRA_TRACKER_TIMEOUT_INFO);
+    if (reg_value & AR_STALL_TIMEOUT)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n Infra tracker detects AR stall timeout.");
+    if (reg_value & AW_STALL_TIMEOUT)
+        *wp += snprintf(buf + *wp, TRACKER_BUF_LENGTH - *wp,
+                                   "\n Infra tracker detects AW stall timeout.\n");
+#endif
+
+    LTRACEF("wp: %d\n", *wp);
+
+    return strlen(buf);
+}
+
+int tracker_get(void **data, int *len, unsigned int entry_num)
+{
+    int ret;
+
+    *len = 0;
+    *data = mempool_alloc(TRACKER_BUF_LENGTH, MEMPOOL_ANY);
+    if (*data == NULL)
+        return 0;
+
+    ret = systracker_dump(*data, len, entry_num);
+    if (ret < 0 || *len > TRACKER_BUF_LENGTH) {
+        *len = (*len > TRACKER_BUF_LENGTH) ? TRACKER_BUF_LENGTH : *len;
+        return ret;
+    }
+
+    return 1;
+}
+
+void tracker_put(void **data)
+{
+    mempool_free(*data);
+}
diff --git a/src/bsp/lk/platform/mt2735/drivers/sda/tracker.h b/src/bsp/lk/platform/mt2735/drivers/sda/tracker.h
new file mode 100755
index 0000000..9a966e6
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/sda/tracker.h
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#pragma once
+
+#include <platform/mt_reg_base.h>
+#include <platform/plat_debug.h>
+
+#define BUS_DBG_CON                 (BUS_DBG_BASE + 0x0000)
+#define INFRA_TRACKER_CON           (INFRA_TRACKER_BASE + 0x0000)
+#define BUS_DBG_TIMEOUT_INFO        (BUS_DBG_BASE + 0x0028)
+#define INFRA_TRACKER_TIMEOUT_INFO  (INFRA_TRACKER_BASE + 0x0028)
+#define AR_TRACK_L(__base, __n)     (__base + AR_TRACK_L_OFFSET + 8 * (__n))
+#define AR_TRACK_H(__base, __n)     (__base + AR_TRACK_H_OFFSET + 8 * (__n))
+#define AW_TRACK_L(__base, __n)     (__base + AW_TRACK_L_OFFSET + 8 * (__n))
+#define AW_TRACK_H(__base, __n)     (__base + AW_TRACK_H_OFFSET + 8 * (__n))
+#define BUS_DBG_W_TRACK_DATA_VALID  (BUS_DBG_BASE + W_TRACK_DATA_VALID_OFFSET)
+#define BUS_DBG_W_TRACK_DATA62      (BUS_DBG_BASE + 0x0EF8)
+#define BUS_DBG_W_TRACK_DATA63      (BUS_DBG_BASE + 0x0EFC)
+
+#define BUS_DBG_CON_IRQ_AR_STA0     (0x00000100)
+#define BUS_DBG_CON_IRQ_AW_STA0     (0x00000200)
+#define BUS_DBG_CON_IRQ_AR_STA1     (0x00100000)
+#define BUS_DBG_CON_IRQ_AW_STA1     (0x00200000)
+#define BUS_DBG_CON_TIMEOUT         (BUS_DBG_CON_IRQ_AR_STA0|BUS_DBG_CON_IRQ_AW_STA0| \
+                                     BUS_DBG_CON_IRQ_AR_STA1|BUS_DBG_CON_IRQ_AW_STA1)
+
+/* 8KB buffer is sufficient for tracker */
+#define TRACKER_BUF_LENGTH          (32000)
+
+/* INFRA BUS TRACKER */
+#define INFRA_ENTRY_NUM             (32)
+#define BUSTRACKER_TIMEOUT          (0x300)
+
+#define AR_STALL_TIMEOUT            (0x00000080)
+#define AW_STALL_TIMEOUT            (0x00008000)
+#define AR_RESP_ERR_TYPE_OFFSET     (24)
+#define AW_RESP_ERR_TYPE_OFFSET     (26)
+#define AR_RESP_ERR_TYPE_MASK       (0x03000000)
+#define AW_RESP_ERR_TYPE_MASK       (0x0C000000)
+#define SLV_ERR                     (2)
+#define DEC_ERR                     (3)
+
+int tracker_get(void **data, int *len, unsigned int entry_num);
+void tracker_put(void **data);
+
+static inline unsigned int extract_n2mbits(unsigned int input, unsigned int n, unsigned int m)
+{
+    /*
+     * 1. ~0 = 1111 1111 1111 1111 1111 1111 1111 1111
+     * 2. ~0 << (m - n + 1) = 1111 1111 1111 1111 1100 0000 0000 0000
+     * // assuming we are extracting 14 bits, the +1 is added for inclusive selection
+     * 3. ~(~0 << (m - n + 1)) = 0000 0000 0000 0000 0011 1111 1111 1111
+     */
+    int mask;
+
+    if (n > m) {
+        n = n + m;
+        m = n - m;
+        n = n - m;
+    }
+    mask = ~(~0 << (m - n + 1));
+    return (input >> n) & mask;
+}
diff --git a/src/bsp/lk/platform/mt2735/drivers/sda/utils.h b/src/bsp/lk/platform/mt2735/drivers/sda/utils.h
new file mode 100755
index 0000000..3a2f1c4
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/drivers/sda/utils.h
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#pragma once
+
+static inline unsigned int extract_n2mbits(unsigned int input, unsigned int n, unsigned int m)
+{
+    /*
+     * 1. ~0 = 1111 1111 1111 1111 1111 1111 1111 1111
+     * 2. ~0 << (m - n + 1) = 1111 1111 1111 1111 1100 0000 0000 0000
+     * // assuming we are extracting 14 bits, the +1 is added for inclusive selection
+     * 3. ~(~0 << (m - n + 1)) = 0000 0000 0000 0000 0011 1111 1111 1111
+     */
+    int mask;
+
+    if (n > m) {
+        n = n + m;
+        m = n - m;
+        n = n - m;
+    }
+    mask = ~(~0U << (m - n + 1));
+    return (input >> n) & mask;
+}
diff --git a/src/bsp/lk/platform/mt2735/include/platform/mt_reg_base.h b/src/bsp/lk/platform/mt2735/include/platform/mt_reg_base.h
old mode 100644
new mode 100755
index c049ee5..711dd0c
--- a/src/bsp/lk/platform/mt2735/include/platform/mt_reg_base.h
+++ b/src/bsp/lk/platform/mt2735/include/platform/mt_reg_base.h
@@ -72,7 +72,9 @@
 #define INT_POL_SECCTL0	    (MCUSYS_CFGREG_BASE + 0xA00) /* TODO: MT2735 */
 #define SEC_POL_CTL_EN0     INT_POL_SECCTL0              /* TODO: MT2735 */
 
-/*jb.qi change for reboot when sleep on 20230309 start*/
+#define PERI_TRACKER_BASE   (IO_PHYS + 0x00218000)
+#define INFRA_TRACKER_BASE  (IO_PHYS + 0x00314000)
+#define BUS_DBG_BASE        (IO_PHYS + 0x00208000)
 #define DRAMC_CH0_TOP5_BASE      (IO_PHYS + 0x00238000)
 #define DPM_PM_SRAM_BASE         (IO_PHYS + 0x00900000)
 #define DPM_DM_SRAM_BASE         (IO_PHYS + 0x00920000)
diff --git a/src/bsp/lk/platform/mt2735/include/platform/mtk_wdt.h b/src/bsp/lk/platform/mt2735/include/platform/mtk_wdt.h
old mode 100644
new mode 100755
index 8d8a589..219b6cd
--- a/src/bsp/lk/platform/mt2735/include/platform/mtk_wdt.h
+++ b/src/bsp/lk/platform/mt2735/include/platform/mtk_wdt.h
@@ -93,7 +93,10 @@
 #define RE_BOOT_BY_THERMAL_DIRECT       (0x20)
 #define RE_BOOT_BY_DEBUG                (0x40)
 #define RE_BOOT_BY_SECURITY             (0x80)
+#define RE_BOOT_BY_SYSRST               (0x200)
+#define RE_BOOT_BY_SSPM_RST             (0x400)
 #define RE_BOOT_BY_PMIC_FULL_RST        (0x800)    /* PMIC full (cold) reset */
+#define RE_BOOT_BY_MCUPM_RST            (0x1000)
 #define RE_BOOT_ABNORMAL                (0xF0)
 
 #define WDT_NORMAL_REBOOT               (0x100)
diff --git a/src/bsp/lk/platform/mt2735/include/platform/plat_debug.h b/src/bsp/lk/platform/mt2735/include/platform/plat_debug.h
new file mode 100755
index 0000000..f3e0c41
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/include/platform/plat_debug.h
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#define HAS_INFA_TRACKER
+#define HAS_PERI_TRACKER
+#define HAS_SLV
+
+#define SYS_TRACK_ENTRY             64
+#define LAST_DUMP_SIZE              0x8000
+
+#define INFRA_ENTRY_NUM             32
+#define PERI_ENTRY_NUM              16
+
+#define BUSTRACKER_TIMEOUT          0x300
+
+#define AR_TRACK_L_OFFSET           0x0100
+#define AR_TRACK_H_OFFSET           0x0104
+#define AW_TRACK_L_OFFSET           0x0300
+#define AW_TRACK_H_OFFSET           0x0304
+#define W_TRACK_DATA_VALID_OFFSET   0x0020
+
+/*FNEW OFFSET*/
+#define TRACKER_VALID_S             24
+#define TRACKER_VALID_E             24
+#define TRACKER_SECURE_S            23
+#define TRACKER_SECURE_E            23
+#define TRACKER_ID_S                10
+#define TRACKER_ID_E                22
+#define TRACKER_DATA_SIZE_S          6
+#define TRACKER_DATA_SIZE_E          8
+#define TRACKER_BURST_LEN_S          2
+#define TRACKER_BURST_LEN_E          5
diff --git a/src/bsp/lk/platform/mt2735/include/platform/plat_lastpc.h b/src/bsp/lk/platform/mt2735/include/platform/plat_lastpc.h
new file mode 100755
index 0000000..1252aab
--- /dev/null
+++ b/src/bsp/lk/platform/mt2735/include/platform/plat_lastpc.h
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ * Use of this source code is governed by a MIT-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/MIT
+ */
+
+#pragma once
+
+#include <platform/mt_reg_base.h>
+
+#define MCUCFG_BASE         MCUSYS_CFGREG_BASE
+#define SPM_PWR_STS_ADDR    (SPM_BASE + 0x830)
+#define SPM_PWR_STS_MASK    0x3FC00000
+#define SPM_PWR_STS_OFFSET  22
+
+const unsigned long cpu_dbg_sel[] = {
+    (MCUCFG_BASE + 0x0220),
+    (MCUCFG_BASE + 0x0A20),
+    (MCUCFG_BASE + 0x1220),
+    (MCUCFG_BASE + 0x1A20),
+    (MCUCFG_BASE + 0x2220),
+    (MCUCFG_BASE + 0x2A20),
+    (MCUCFG_BASE + 0x3220),
+    (MCUCFG_BASE + 0x3A20)
+};
+
+const unsigned long cpu_dbg_mon[] = {
+    (MCUCFG_BASE + 0x0224),
+    (MCUCFG_BASE + 0x0A24),
+    (MCUCFG_BASE + 0x1224),
+    (MCUCFG_BASE + 0x1A24),
+    (MCUCFG_BASE + 0x2224),
+    (MCUCFG_BASE + 0x2A24),
+    (MCUCFG_BASE + 0x3224),
+    (MCUCFG_BASE + 0x3A24)
+};
+
+const struct plt_cfg_pc_latch cfg_pc_latch = {
+    .nr_max_core = 8,
+    .nr_max_big_core = 4,
+    .core_dbg_sel = (unsigned long *) cpu_dbg_sel,
+    .core_dbg_mon = (unsigned long *) cpu_dbg_mon,
+    .version = LASTPC_V1,
+};
+
+enum {
+    LCORE_SCR_EL3     = 0x0,
+    LCORE_SCTLR_EL3   = 0x1,
+    LCORE_FAR_EL3_L   = 0x2,
+    LCORE_FAR_EL3_H   = 0x3,
+    LCORE_ESR_EL3     = 0x4,
+    LCORE_CPSR        = 0x5,
+    LCORE_ELR_L       = 0x6,
+    LCORE_ELR_H       = 0x7,
+    LCORE_LR_L        = 0x8,
+    LCORE_LR_H        = 0x9,
+    LCORE_SP_L        = 0xA,
+    LCORE_SP_H        = 0xB,
+    LCORE_PC_L        = 0xC,
+    LCORE_PC_H        = 0xD
+};
+
+enum {
+    BCORE_SCR_EL3_L   = 0x0,
+    BCORE_SCR_EL3_H   = 0x1,
+    BCORE_SCTLR_EL3_L = 0x2,
+    BCORE_SCTLR_EL3_H = 0x3,
+    BCORE_FAR_EL3_L   = 0x4,
+    BCORE_FAR_EL3_H   = 0x5,
+    BCORE_ESR_EL3_L   = 0x6,
+    BCORE_ESR_EL3_H   = 0x7,
+    BCORE_PC_L        = 0x8,
+    BCORE_PC_H        = 0x9,
+    BCORE_CPSR        = 0xA,
+    BCORE_ELR_L       = 0xB,
+    BCORE_ELR_H       = 0xC,
+    BCORE_PCSR_L      = 0xD,
+    BCORE_PCSR_H      = 0xE
+};