[][MAC80211][wifi7][Misc][Sync Internal patches to External Release Folder]

[Description]
Add 20231011 MT7996 firmware and sync patches to External Release Folder

[Release-log]
N/A

Change-Id: I8971c21f494c3947f2ac7f19b8c398488356ca59
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8101977
diff --git a/autobuild_mac80211_release/mt7988_mt7996_mac80211/package/kernel/mt76/patches/0016-wifi-mt76-mt7996-add-firmware-WA-s-coredump.patch b/autobuild_mac80211_release/mt7988_mt7996_mac80211/package/kernel/mt76/patches/0016-wifi-mt76-mt7996-add-firmware-WA-s-coredump.patch
new file mode 100644
index 0000000..a850a6c
--- /dev/null
+++ b/autobuild_mac80211_release/mt7988_mt7996_mac80211/package/kernel/mt76/patches/0016-wifi-mt76-mt7996-add-firmware-WA-s-coredump.patch
@@ -0,0 +1,598 @@
+From 4d055393b680ce616cb96f75cca154016cfb9a68 Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Fri, 19 May 2023 14:16:50 +0800
+Subject: [PATCH 16/98] wifi: mt76: mt7996: add firmware WA's coredump.
+
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Change-Id: I51f115b4ae15bc0f871f93652570d72511dbf880
+---
+ mt7996/coredump.c | 180 ++++++++++++++++++++++++++++++----------------
+ mt7996/coredump.h |  35 ++++++---
+ mt7996/mac.c      |  31 +++++---
+ mt7996/mcu.c      |   5 ++
+ mt7996/mt7996.h   |   7 +-
+ mt7996/regs.h     |   7 +-
+ 6 files changed, 182 insertions(+), 83 deletions(-)
+
+diff --git a/mt7996/coredump.c b/mt7996/coredump.c
+index ccab0d7..60b8808 100644
+--- a/mt7996/coredump.c
++++ b/mt7996/coredump.c
+@@ -7,11 +7,11 @@
+ #include <linux/utsname.h>
+ #include "coredump.h"
+ 
+-static bool coredump_memdump;
++static bool coredump_memdump = true;
+ module_param(coredump_memdump, bool, 0644);
+ MODULE_PARM_DESC(coredump_memdump, "Optional ability to dump firmware memory");
+ 
+-static const struct mt7996_mem_region mt7996_mem_regions[] = {
++static const struct mt7996_mem_region mt7996_wm_mem_regions[] = {
+ 	{
+ 		.start = 0x00800000,
+ 		.len = 0x0004ffff,
+@@ -44,27 +44,55 @@ static const struct mt7996_mem_region mt7996_mem_regions[] = {
+ 	},
+ };
+ 
++static const struct mt7996_mem_region mt7996_wa_mem_regions[] = {
++	{
++		.start = 0xE0000000,
++		.len = 0x0000ffff,
++		.name = "CRAM",
++	},
++	{
++		.start = 0xE0010000,
++		.len = 0x000117ff,
++		.name = "CRAM2",
++	},
++	{
++		.start = 0x10000000,
++		.len = 0x0001bfff,
++		.name = "ILM",
++	},
++	{
++		.start = 0x10200000,
++		.len = 0x00063fff,
++		.name = "DLM",
++	},
++};
++
+ const struct mt7996_mem_region*
+-mt7996_coredump_get_mem_layout(struct mt7996_dev *dev, u32 *num)
++mt7996_coredump_get_mem_layout(struct mt7996_dev *dev, u8 type, u32 *num)
+ {
+ 	switch (mt76_chip(&dev->mt76)) {
+ 	case 0x7990:
+ 	case 0x7991:
+-		*num = ARRAY_SIZE(mt7996_mem_regions);
+-		return &mt7996_mem_regions[0];
++		if (type == MT7996_RAM_TYPE_WA) {
++			*num = ARRAY_SIZE(mt7996_wa_mem_regions);
++			return &mt7996_wa_mem_regions[0];
++		}
++
++		*num = ARRAY_SIZE(mt7996_wm_mem_regions);
++		return &mt7996_wm_mem_regions[0];
+ 	default:
+ 		return NULL;
+ 	}
+ }
+ 
+-static int mt7996_coredump_get_mem_size(struct mt7996_dev *dev)
++static int mt7996_coredump_get_mem_size(struct mt7996_dev *dev, u8 type)
+ {
+ 	const struct mt7996_mem_region *mem_region;
+ 	size_t size = 0;
+ 	u32 num;
+ 	int i;
+ 
+-	mem_region = mt7996_coredump_get_mem_layout(dev, &num);
++	mem_region = mt7996_coredump_get_mem_layout(dev, type, &num);
+ 	if (!mem_region)
+ 		return 0;
+ 
+@@ -81,14 +109,13 @@ static int mt7996_coredump_get_mem_size(struct mt7996_dev *dev)
+ 	return size;
+ }
+ 
+-struct mt7996_crash_data *mt7996_coredump_new(struct mt7996_dev *dev)
++struct mt7996_crash_data *mt7996_coredump_new(struct mt7996_dev *dev, u8 type)
+ {
+-	struct mt7996_crash_data *crash_data = dev->coredump.crash_data;
++	struct mt7996_crash_data *crash_data = dev->coredump.crash_data[type];
+ 
+ 	lockdep_assert_held(&dev->dump_mutex);
+ 
+-	if (coredump_memdump &&
+-	    !mt76_poll_msec(dev, MT_FW_DUMP_STATE, 0x3, 0x2, 500))
++	if (!coredump_memdump)
+ 		return NULL;
+ 
+ 	guid_gen(&crash_data->guid);
+@@ -98,12 +125,15 @@ struct mt7996_crash_data *mt7996_coredump_new(struct mt7996_dev *dev)
+ }
+ 
+ static void
+-mt7996_coredump_fw_state(struct mt7996_dev *dev, struct mt7996_coredump *dump,
++mt7996_coredump_fw_state(struct mt7996_dev *dev, u8 type, struct mt7996_coredump *dump,
+ 			 bool *exception)
+ {
+-	u32 count;
++	u32 count, reg = MT_FW_WM_DUMP_STATE;
++
++	if (type == MT7996_RAM_TYPE_WA)
++		reg = MT_FW_WA_DUMP_STATE;
+ 
+-	count = mt76_rr(dev, MT_FW_ASSERT_CNT);
++	count = mt76_rr(dev, reg);
+ 
+ 	/* normal mode: driver can manually trigger assert for detail info */
+ 	if (!count)
+@@ -115,53 +145,59 @@ mt7996_coredump_fw_state(struct mt7996_dev *dev, struct mt7996_coredump *dump,
+ }
+ 
+ static void
+-mt7996_coredump_fw_stack(struct mt7996_dev *dev, struct mt7996_coredump *dump,
++mt7996_coredump_fw_stack(struct mt7996_dev *dev, u8 type, struct mt7996_coredump *dump,
+ 			 bool exception)
+ {
+-	u32 oldest, i, idx;
++	u32 reg, i, offset = 0, val = MT7996_RAM_TYPE_WM;
+ 
+-	strscpy(dump->pc_current, "program counter", sizeof(dump->pc_current));
++	if (type == MT7996_RAM_TYPE_WA) {
++		offset = MT_MCU_WA_EXCP_BASE - MT_MCU_WM_EXCP_BASE;
++		val = MT7996_RAM_TYPE_WA;
++	}
+ 
+-	/* 0: WM PC log output */
+-	mt76_wr(dev, MT_CONN_DBG_CTL_OUT_SEL, 0);
++	/* 0: WM PC log output, 1: WA PC log output  */
++	mt76_wr(dev, MT_CONN_DBG_CTL_OUT_SEL, val);
+ 	/* choose 33th PC log buffer to read current PC index */
+ 	mt76_wr(dev, MT_CONN_DBG_CTL_PC_LOG_SEL, 0x3f);
+ 
+ 	/* read current PC */
+-	dump->pc_stack[0] = mt76_rr(dev, MT_CONN_DBG_CTL_PC_LOG);
++	for (i = 0; i < 10; i++)
++		dump->pc_cur[i] = mt76_rr(dev, MT_CONN_DBG_CTL_PC_LOG);
+ 
+ 	/* stop call stack record */
+ 	if (!exception) {
+-		mt76_clear(dev, MT_MCU_WM_EXCP_PC_CTRL, BIT(0));
+-		mt76_clear(dev, MT_MCU_WM_EXCP_LR_CTRL, BIT(0));
++		mt76_clear(dev, MT_MCU_WM_EXCP_PC_CTRL + offset, BIT(0));
++		mt76_clear(dev, MT_MCU_WM_EXCP_LR_CTRL + offset, BIT(0));
+ 	}
+ 
+-	oldest = (u32)mt76_get_field(dev, MT_MCU_WM_EXCP_PC_CTRL,
+-				     GENMASK(20, 16)) + 2;
+-	for (i = 0; i < 16; i++) {
+-		idx = ((oldest + 2 * i + 1) % 32);
+-		dump->pc_stack[i + 1] =
+-			mt76_rr(dev, MT_MCU_WM_EXCP_PC_LOG + idx * 4);
++	/* read PC log */
++	dump->pc_dbg_ctrl = mt76_rr(dev, MT_MCU_WM_EXCP_PC_CTRL + offset);
++	dump->pc_cur_idx = FIELD_GET(MT_MCU_WM_EXCP_PC_CTRL_IDX_STATUS,
++				     dump->pc_dbg_ctrl);
++	for (i = 0; i < 32; i++) {
++		reg = MT_MCU_WM_EXCP_PC_LOG + i * 4 + offset;
++		dump->pc_stack[i] = mt76_rr(dev, reg);
+ 	}
+ 
+-	oldest = (u32)mt76_get_field(dev, MT_MCU_WM_EXCP_LR_CTRL,
+-				     GENMASK(20, 16)) + 2;
+-	for (i = 0; i < 16; i++) {
+-		idx = ((oldest + 2 * i + 1) % 32);
+-		dump->lr_stack[i] =
+-			mt76_rr(dev, MT_MCU_WM_EXCP_LR_LOG + idx * 4);
++	/* read LR log */
++	dump->lr_dbg_ctrl = mt76_rr(dev, MT_MCU_WM_EXCP_LR_CTRL + offset);
++	dump->lr_cur_idx = FIELD_GET(MT_MCU_WM_EXCP_LR_CTRL_IDX_STATUS,
++				     dump->lr_dbg_ctrl);
++	for (i = 0; i < 32; i++) {
++		reg = MT_MCU_WM_EXCP_LR_LOG + i * 4 + offset;
++		dump->lr_stack[i] = mt76_rr(dev, reg);
+ 	}
+ 
+ 	/* start call stack record */
+ 	if (!exception) {
+-		mt76_set(dev, MT_MCU_WM_EXCP_PC_CTRL, BIT(0));
+-		mt76_set(dev, MT_MCU_WM_EXCP_LR_CTRL, BIT(0));
++		mt76_set(dev, MT_MCU_WM_EXCP_PC_CTRL + offset, BIT(0));
++		mt76_set(dev, MT_MCU_WM_EXCP_LR_CTRL + offset, BIT(0));
+ 	}
+ }
+ 
+-static struct mt7996_coredump *mt7996_coredump_build(struct mt7996_dev *dev)
++static struct mt7996_coredump *mt7996_coredump_build(struct mt7996_dev *dev, u8 type)
+ {
+-	struct mt7996_crash_data *crash_data = dev->coredump.crash_data;
++	struct mt7996_crash_data *crash_data = dev->coredump.crash_data[type];
+ 	struct mt7996_coredump *dump;
+ 	struct mt7996_coredump_mem *dump_mem;
+ 	size_t len, sofar = 0, hdr_len = sizeof(*dump);
+@@ -186,20 +222,31 @@ static struct mt7996_coredump *mt7996_coredump_build(struct mt7996_dev *dev)
+ 
+ 	dump = (struct mt7996_coredump *)(buf);
+ 	dump->len = len;
++	dump->hdr_len = hdr_len;
+ 
+ 	/* plain text */
+ 	strscpy(dump->magic, "mt76-crash-dump", sizeof(dump->magic));
+ 	strscpy(dump->kernel, init_utsname()->release, sizeof(dump->kernel));
++	strscpy(dump->fw_type, ((type == MT7996_RAM_TYPE_WA) ? "WA" : "WM"),
++		sizeof(dump->fw_type));
+ 	strscpy(dump->fw_ver, dev->mt76.hw->wiphy->fw_version,
+ 		sizeof(dump->fw_ver));
++	strscpy(dump->fw_patch_date, dev->patch_build_date,
++		sizeof(dump->fw_patch_date));
++	strscpy(dump->fw_ram_date[MT7996_RAM_TYPE_WM],
++		dev->ram_build_date[MT7996_RAM_TYPE_WM],
++		MT7996_BUILD_TIME_LEN);
++	strscpy(dump->fw_ram_date[MT7996_RAM_TYPE_WA],
++		dev->ram_build_date[MT7996_RAM_TYPE_WA],
++		MT7996_BUILD_TIME_LEN);
+ 
+ 	guid_copy(&dump->guid, &crash_data->guid);
+ 	dump->tv_sec = crash_data->timestamp.tv_sec;
+ 	dump->tv_nsec = crash_data->timestamp.tv_nsec;
+ 	dump->device_id = mt76_chip(&dev->mt76);
+ 
+-	mt7996_coredump_fw_state(dev, dump, &exception);
+-	mt7996_coredump_fw_stack(dev, dump, exception);
++	mt7996_coredump_fw_state(dev, type, dump, &exception);
++	mt7996_coredump_fw_stack(dev, type, dump, exception);
+ 
+ 	/* gather memory content */
+ 	dump_mem = (struct mt7996_coredump_mem *)(buf + sofar);
+@@ -213,17 +260,19 @@ static struct mt7996_coredump *mt7996_coredump_build(struct mt7996_dev *dev)
+ 	return dump;
+ }
+ 
+-int mt7996_coredump_submit(struct mt7996_dev *dev)
++int mt7996_coredump_submit(struct mt7996_dev *dev, u8 type)
+ {
+ 	struct mt7996_coredump *dump;
+ 
+-	dump = mt7996_coredump_build(dev);
++	dump = mt7996_coredump_build(dev, type);
+ 	if (!dump) {
+ 		dev_warn(dev->mt76.dev, "no crash dump data found\n");
+ 		return -ENODATA;
+ 	}
+ 
+ 	dev_coredumpv(dev->mt76.dev, dump, dump->len, GFP_KERNEL);
++	dev_info(dev->mt76.dev, "%s coredump completed\n",
++		 wiphy_name(dev->mt76.hw->wiphy));
+ 
+ 	return 0;
+ }
+@@ -231,23 +280,26 @@ int mt7996_coredump_submit(struct mt7996_dev *dev)
+ int mt7996_coredump_register(struct mt7996_dev *dev)
+ {
+ 	struct mt7996_crash_data *crash_data;
++	int i;
+ 
+-	crash_data = vzalloc(sizeof(*dev->coredump.crash_data));
+-	if (!crash_data)
+-		return -ENOMEM;
++	for (i = 0; i < MT7996_COREDUMP_MAX; i++) {
++		crash_data = vzalloc(sizeof(*dev->coredump.crash_data[i]));
++		if (!crash_data)
++			return -ENOMEM;
+ 
+-	dev->coredump.crash_data = crash_data;
++		dev->coredump.crash_data[i] = crash_data;
+ 
+-	if (coredump_memdump) {
+-		crash_data->memdump_buf_len = mt7996_coredump_get_mem_size(dev);
+-		if (!crash_data->memdump_buf_len)
+-			/* no memory content */
+-			return 0;
++		if (coredump_memdump) {
++			crash_data->memdump_buf_len = mt7996_coredump_get_mem_size(dev, i);
++			if (!crash_data->memdump_buf_len)
++				/* no memory content */
++				return 0;
+ 
+-		crash_data->memdump_buf = vzalloc(crash_data->memdump_buf_len);
+-		if (!crash_data->memdump_buf) {
+-			vfree(crash_data);
+-			return -ENOMEM;
++			crash_data->memdump_buf = vzalloc(crash_data->memdump_buf_len);
++			if (!crash_data->memdump_buf) {
++				vfree(crash_data);
++				return -ENOMEM;
++			}
+ 		}
+ 	}
+ 
+@@ -256,13 +308,17 @@ int mt7996_coredump_register(struct mt7996_dev *dev)
+ 
+ void mt7996_coredump_unregister(struct mt7996_dev *dev)
+ {
+-	if (dev->coredump.crash_data->memdump_buf) {
+-		vfree(dev->coredump.crash_data->memdump_buf);
+-		dev->coredump.crash_data->memdump_buf = NULL;
+-		dev->coredump.crash_data->memdump_buf_len = 0;
+-	}
++	int i;
+ 
+-	vfree(dev->coredump.crash_data);
+-	dev->coredump.crash_data = NULL;
++	for (i = 0; i < MT7996_COREDUMP_MAX; i++) {
++		if (dev->coredump.crash_data[i]->memdump_buf) {
++			vfree(dev->coredump.crash_data[i]->memdump_buf);
++			dev->coredump.crash_data[i]->memdump_buf = NULL;
++			dev->coredump.crash_data[i]->memdump_buf_len = 0;
++		}
++
++		vfree(dev->coredump.crash_data[i]);
++		dev->coredump.crash_data[i] = NULL;
++	}
+ }
+ 
+diff --git a/mt7996/coredump.h b/mt7996/coredump.h
+index af2ba21..01ed373 100644
+--- a/mt7996/coredump.h
++++ b/mt7996/coredump.h
+@@ -6,10 +6,13 @@
+ 
+ #include "mt7996.h"
+ 
++#define MT7996_COREDUMP_MAX	(MT7996_RAM_TYPE_WA + 1)
++
+ struct mt7996_coredump {
+ 	char magic[16];
+ 
+ 	u32 len;
++	u32 hdr_len;
+ 
+ 	guid_t guid;
+ 
+@@ -21,17 +24,28 @@ struct mt7996_coredump {
+ 	char kernel[64];
+ 	/* firmware version */
+ 	char fw_ver[ETHTOOL_FWVERS_LEN];
++	char fw_patch_date[MT7996_BUILD_TIME_LEN];
++	char fw_ram_date[MT7996_COREDUMP_MAX][MT7996_BUILD_TIME_LEN];
+ 
+ 	u32 device_id;
+ 
++	/* fw type */
++	char fw_type[8];
++
+ 	/* exception state */
+ 	char fw_state[12];
+ 
+ 	/* program counters */
+-	char pc_current[16];
+-	u32 pc_stack[17];
+-	/* link registers */
+-	u32 lr_stack[16];
++	u32 pc_dbg_ctrl;
++	u32 pc_cur_idx;
++	u32 pc_cur[10];
++	/* PC registers */
++	u32 pc_stack[32];
++
++	u32 lr_dbg_ctrl;
++	u32 lr_cur_idx;
++	/* LR registers */
++	u32 lr_stack[32];
+ 
+ 	/* memory content */
+ 	u8 data[];
+@@ -43,6 +57,7 @@ struct mt7996_coredump_mem {
+ } __packed;
+ 
+ struct mt7996_mem_hdr {
++	char name[64];
+ 	u32 start;
+ 	u32 len;
+ 	u8 data[];
+@@ -58,27 +73,27 @@ struct mt7996_mem_region {
+ #ifdef CONFIG_DEV_COREDUMP
+ 
+ const struct mt7996_mem_region *
+-mt7996_coredump_get_mem_layout(struct mt7996_dev *dev, u32 *num);
+-struct mt7996_crash_data *mt7996_coredump_new(struct mt7996_dev *dev);
+-int mt7996_coredump_submit(struct mt7996_dev *dev);
++mt7996_coredump_get_mem_layout(struct mt7996_dev *dev, u8 type, u32 *num);
++struct mt7996_crash_data *mt7996_coredump_new(struct mt7996_dev *dev, u8 type);
++int mt7996_coredump_submit(struct mt7996_dev *dev, u8 type);
+ int mt7996_coredump_register(struct mt7996_dev *dev);
+ void mt7996_coredump_unregister(struct mt7996_dev *dev);
+ 
+ #else /* CONFIG_DEV_COREDUMP */
+ 
+ static inline const struct mt7996_mem_region *
+-mt7996_coredump_get_mem_layout(struct mt7996_dev *dev, u32 *num)
++mt7996_coredump_get_mem_layout(struct mt7996_dev *dev, u8 type, u32 *num)
+ {
+ 	return NULL;
+ }
+ 
+-static inline int mt7996_coredump_submit(struct mt7996_dev *dev)
++static inline int mt7996_coredump_submit(struct mt7996_dev *dev, u8 type)
+ {
+ 	return 0;
+ }
+ 
+ static inline struct
+-mt7996_crash_data *mt7996_coredump_new(struct mt7996_dev *dev)
++mt7996_crash_data *mt7996_coredump_new(struct mt7996_dev *dev, u8 type)
+ {
+ 	return NULL;
+ }
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index ccb7b22..066955e 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -1962,28 +1962,25 @@ void mt7996_mac_reset_work(struct work_struct *work)
+ }
+ 
+ /* firmware coredump */
+-void mt7996_mac_dump_work(struct work_struct *work)
++void mt7996_mac_fw_coredump(struct mt7996_dev *dev, u8 type)
+ {
+ 	const struct mt7996_mem_region *mem_region;
+ 	struct mt7996_crash_data *crash_data;
+-	struct mt7996_dev *dev;
+ 	struct mt7996_mem_hdr *hdr;
+ 	size_t buf_len;
+ 	int i;
+ 	u32 num;
+ 	u8 *buf;
+ 
+-	dev = container_of(work, struct mt7996_dev, dump_work);
+-
+ 	mutex_lock(&dev->dump_mutex);
+ 
+-	crash_data = mt7996_coredump_new(dev);
++	crash_data = mt7996_coredump_new(dev, type);
+ 	if (!crash_data) {
+ 		mutex_unlock(&dev->dump_mutex);
+-		goto skip_coredump;
++		return;
+ 	}
+ 
+-	mem_region = mt7996_coredump_get_mem_layout(dev, &num);
++	mem_region = mt7996_coredump_get_mem_layout(dev, type, &num);
+ 	if (!mem_region || !crash_data->memdump_buf_len) {
+ 		mutex_unlock(&dev->dump_mutex);
+ 		goto skip_memdump;
+@@ -1993,6 +1990,9 @@ void mt7996_mac_dump_work(struct work_struct *work)
+ 	buf_len = crash_data->memdump_buf_len;
+ 
+ 	/* dumping memory content... */
++	dev_info(dev->mt76.dev, "%s start coredump for %s\n",
++		 wiphy_name(dev->mt76.hw->wiphy),
++		 ((type == MT7996_RAM_TYPE_WA) ? "WA" : "WM"));
+ 	memset(buf, 0, buf_len);
+ 	for (i = 0; i < num; i++) {
+ 		if (mem_region->len > buf_len) {
+@@ -2009,6 +2009,7 @@ void mt7996_mac_dump_work(struct work_struct *work)
+ 		mt7996_memcpy_fromio(dev, buf, mem_region->start,
+ 				     mem_region->len);
+ 
++		strscpy(hdr->name, mem_region->name, sizeof(mem_region->name));
+ 		hdr->start = mem_region->start;
+ 		hdr->len = mem_region->len;
+ 
+@@ -2025,8 +2026,20 @@ void mt7996_mac_dump_work(struct work_struct *work)
+ 	mutex_unlock(&dev->dump_mutex);
+ 
+ skip_memdump:
+-	mt7996_coredump_submit(dev);
+-skip_coredump:
++	mt7996_coredump_submit(dev, type);
++}
++
++void mt7996_mac_dump_work(struct work_struct *work)
++{
++	struct mt7996_dev *dev;
++
++	dev = container_of(work, struct mt7996_dev, dump_work);
++	if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT)
++		mt7996_mac_fw_coredump(dev, MT7996_RAM_TYPE_WA);
++
++	if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WM_WDT)
++		mt7996_mac_fw_coredump(dev, MT7996_RAM_TYPE_WM);
++
+ 	queue_work(dev->mt76.wq, &dev->reset_work);
+ }
+ 
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index ee1915c..2c611e7 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -2458,6 +2458,8 @@ static int mt7996_load_patch(struct mt7996_dev *dev)
+ 
+ 	dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
+ 		 be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
++	memcpy(dev->patch_build_date, hdr->build_date,
++	       sizeof(dev->patch_build_date));
+ 
+ 	for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {
+ 		struct mt7996_patch_sec *sec;
+@@ -2584,6 +2586,9 @@ static int __mt7996_load_ram(struct mt7996_dev *dev, const char *fw_type,
+ 	}
+ 
+ 	hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
++	memcpy(dev->ram_build_date[ram_type],
++	       hdr->build_date,
++	       sizeof(dev->ram_build_date[ram_type]));
+ 	dev_info(dev->mt76.dev, "%s Firmware Version: %.10s, Build Time: %.15s\n",
+ 		 fw_type, hdr->fw_ver, hdr->build_date);
+ 
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index c0ceef0..0bb20a9 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -57,6 +57,8 @@
+ #define MT7996_CRIT_TEMP		110
+ #define MT7996_MAX_TEMP			120
+ 
++#define MT7996_BUILD_TIME_LEN		24
++
+ #define MT7996_RRO_MAX_SESSION		1024
+ #define MT7996_RRO_WINDOW_MAX_LEN	1024
+ #define MT7996_RRO_ADDR_ELEM_LEN	128
+@@ -82,6 +84,7 @@ enum mt7996_ram_type {
+ 	MT7996_RAM_TYPE_WM,
+ 	MT7996_RAM_TYPE_WA,
+ 	MT7996_RAM_TYPE_DSP,
++	__MT7996_RAM_TYPE_MAX,
+ };
+ 
+ enum mt7996_txq_id {
+@@ -265,9 +268,11 @@ struct mt7996_dev {
+ 	struct mutex dump_mutex;
+ #ifdef CONFIG_DEV_COREDUMP
+ 	struct {
+-		struct mt7996_crash_data *crash_data;
++		struct mt7996_crash_data *crash_data[__MT7996_RAM_TYPE_MAX];
+ 	} coredump;
+ #endif
++	char patch_build_date[MT7996_BUILD_TIME_LEN];
++	char ram_build_date[__MT7996_RAM_TYPE_MAX][MT7996_BUILD_TIME_LEN];
+ 
+ 	struct list_head sta_rc_list;
+ 	struct list_head twt_list;
+diff --git a/mt7996/regs.h b/mt7996/regs.h
+index f7c99cd..bd0eb51 100644
+--- a/mt7996/regs.h
++++ b/mt7996/regs.h
+@@ -548,7 +548,8 @@ enum base_rev {
+ 
+ /* FW MODE SYNC */
+ #define MT_FW_ASSERT_CNT			0x02208274
+-#define MT_FW_DUMP_STATE			0x02209e90
++#define MT_FW_WM_DUMP_STATE			0x02209e90
++#define MT_FW_WA_DUMP_STATE			0x7C05B080
+ 
+ #define MT_SWDEF_BASE				0x00401400
+ 
+@@ -656,11 +657,15 @@ enum base_rev {
+ #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR		BIT(29)
+ 
+ /* CONN MCU EXCP CON */
++#define MT_MCU_WA_EXCP_BASE			0x890d0000
+ #define MT_MCU_WM_EXCP_BASE			0x89050000
++
+ #define MT_MCU_WM_EXCP(ofs)			(MT_MCU_WM_EXCP_BASE + (ofs))
+ #define MT_MCU_WM_EXCP_PC_CTRL			MT_MCU_WM_EXCP(0x100)
++#define MT_MCU_WM_EXCP_PC_CTRL_IDX_STATUS	GENMASK(20, 16)
+ #define MT_MCU_WM_EXCP_PC_LOG			MT_MCU_WM_EXCP(0x104)
+ #define MT_MCU_WM_EXCP_LR_CTRL			MT_MCU_WM_EXCP(0x200)
++#define MT_MCU_WM_EXCP_LR_CTRL_IDX_STATUS	GENMASK(20, 16)
+ #define MT_MCU_WM_EXCP_LR_LOG			MT_MCU_WM_EXCP(0x204)
+ 
+ #endif
+-- 
+2.18.0
+