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
+};