From 6bd9d959ddc3fabd84c57de41c6a1db7c400f562 Mon Sep 17 00:00:00 2001 From: "ot_zhenguo.li" Date: Fri, 24 Feb 2023 13:55:27 +0800 Subject: soc/mediatek/mt8188: Enable lastbus debug hardware Lastbus is a bus debug tool. When the bus hangs, the bus transmission information before resetting will be recorded. The watchdog cannot clear it and it will be printed out for bus hanging analysis. There are two versions for lastbus: Version 1 for MT8186, and version 2 for MT8188. BUG=b:263753374 TEST=build pass. Change-Id: Ibaf510481d1941376bd8da0168ef17c99a0fb9a2 Signed-off-by: ot_zhenguo.li Signed-off-by: jason-ch chen Reviewed-on: https://review.coreboot.org/c/coreboot/+/73624 Reviewed-by: Rex-BC Chen Reviewed-by: Yidi Lin Tested-by: build bot (Jenkins) Reviewed-by: Yu-Ping Wu --- src/soc/mediatek/common/include/soc/lastbus.h | 21 ----- src/soc/mediatek/common/include/soc/lastbus_v1.h | 21 +++++ src/soc/mediatek/common/include/soc/lastbus_v2.h | 40 ++++++++ src/soc/mediatek/common/lastbus.c | 65 ------------- src/soc/mediatek/common/lastbus_v1.c | 65 +++++++++++++ src/soc/mediatek/common/lastbus_v2.c | 112 +++++++++++++++++++++++ src/soc/mediatek/mt8186/Makefile.inc | 2 +- src/soc/mediatek/mt8186/bootblock.c | 2 +- src/soc/mediatek/mt8188/Makefile.inc | 1 + src/soc/mediatek/mt8188/bootblock.c | 2 + src/soc/mediatek/mt8188/include/soc/addressmap.h | 6 ++ src/soc/mediatek/mt8188/lastbus.c | 79 ++++++++++++++++ 12 files changed, 328 insertions(+), 88 deletions(-) delete mode 100644 src/soc/mediatek/common/include/soc/lastbus.h create mode 100644 src/soc/mediatek/common/include/soc/lastbus_v1.h create mode 100644 src/soc/mediatek/common/include/soc/lastbus_v2.h delete mode 100644 src/soc/mediatek/common/lastbus.c create mode 100644 src/soc/mediatek/common/lastbus_v1.c create mode 100644 src/soc/mediatek/common/lastbus_v2.c create mode 100644 src/soc/mediatek/mt8188/lastbus.c (limited to 'src/soc/mediatek') diff --git a/src/soc/mediatek/common/include/soc/lastbus.h b/src/soc/mediatek/common/include/soc/lastbus.h deleted file mode 100644 index 3c93efbf60..0000000000 --- a/src/soc/mediatek/common/include/soc/lastbus.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -#ifndef SOC_MEDIATEK_COMMON_LASTBUS_H -#define SOC_MEDIATEK_COMMON_LASTBUS_H - -/* INFRA LASTBUS INFO */ -#define BUS_INFRA_SNAPSHOT 0xd00 -#define BUS_INFRA_CTRL 0xd04 -#define INFRASYS_CONFIG 0xffff000c -#define INFRA_NUM 17 - -/* PERI LASTBUS INFO */ -#define BUS_PERI_R0 0x500 -#define BUS_PERI_R1 0x504 -#define PERISYS_ENABLE 0xc -#define PERISYS_TIMEOUT 0xffff -#define PERI_NUM 18 - -void lastbus_init(void); - -#endif diff --git a/src/soc/mediatek/common/include/soc/lastbus_v1.h b/src/soc/mediatek/common/include/soc/lastbus_v1.h new file mode 100644 index 0000000000..bd6cd86776 --- /dev/null +++ b/src/soc/mediatek/common/include/soc/lastbus_v1.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SOC_MEDIATEK_COMMON_LASTBUS_V1_H +#define SOC_MEDIATEK_COMMON_LASTBUS_V1_H + +/* INFRA LASTBUS INFO */ +#define BUS_INFRA_SNAPSHOT 0xd00 +#define BUS_INFRA_CTRL 0xd04 +#define INFRASYS_CONFIG 0xffff000c +#define INFRA_NUM 17 + +/* PERI LASTBUS INFO */ +#define BUS_PERI_R0 0x500 +#define BUS_PERI_R1 0x504 +#define PERISYS_ENABLE 0xc +#define PERISYS_TIMEOUT 0xffff +#define PERI_NUM 18 + +void lastbus_init(void); + +#endif diff --git a/src/soc/mediatek/common/include/soc/lastbus_v2.h b/src/soc/mediatek/common/include/soc/lastbus_v2.h new file mode 100644 index 0000000000..d58da76b57 --- /dev/null +++ b/src/soc/mediatek/common/include/soc/lastbus_v2.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SOC_MEDIATEK_COMMON_LASTBUS_V2_H +#define SOC_MEDIATEK_COMMON_LASTBUS_V2_H + +#define NR_MAX_LASTBUS_IDLE_MASK 8 +#define NR_MAX_LASTBUS_MONITOR 16 +#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 + +struct lastbus_idle_mask { + u32 reg_offset; + u32 reg_value; +}; + +struct lastbus_monitor { + const char *name; + uintptr_t base; + size_t num_ports; + u16 bus_freq_mhz; + size_t num_idle_mask; + struct lastbus_idle_mask idle_masks[NR_MAX_LASTBUS_IDLE_MASK]; +}; + +struct lastbus_config { + const char *latch_platform; + 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); +extern const struct lastbus_config lastbus_cfg; + +#endif diff --git a/src/soc/mediatek/common/lastbus.c b/src/soc/mediatek/common/lastbus.c deleted file mode 100644 index cf4f8d1a42..0000000000 --- a/src/soc/mediatek/common/lastbus.c +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -#include -#include -#include -#include - -static unsigned long preisys_dump_offset[] = { - 0x500, /* PERIBUS_DBG0 */ - 0x504, /* PERIBUS_DBG1 */ - 0x508, /* PERIBUS_DBG2 */ - 0x50C, /* PERIBUS_DBG3 */ - 0x510, /* PERIBUS_DBG4 */ - 0x514, /* PERIBUS_DBG5 */ - 0x518, /* PERIBUS_DBG6 */ - 0x51C, /* PERIBUS_DBG7 */ - 0x520, /* PERIBUS_DBG8 */ - 0x524, /* PERIBUS_DBG9 */ - 0x528, /* PERIBUS_DBG10 */ - 0x52C, /* PERIBUS_DBG11 */ - 0x530, /* PERIBUS_DBG12 */ - 0x534, /* PERIBUS_DBG13 */ - 0x538, /* PERIBUS_DBG14 */ - 0x53C, /* PERIBUS_DBG15 */ - 0x580, /* PERIBUS_DBG16 */ - 0x584, /* PERIBUS_DBG17 */ -}; - -static void lastbus_setup(void) -{ - /* peri lastbus init */ - write32p(PERICFG_BASE + BUS_PERI_R0, PERISYS_TIMEOUT); - write32p(PERICFG_BASE + BUS_PERI_R1, PERISYS_ENABLE); - - /* infra lastbus init */ - write32p(INFRACFG_AO_BASE + BUS_INFRA_CTRL, INFRASYS_CONFIG); -} - -static void lastbus_dump(void) -{ - unsigned int i; - uintptr_t reg; - - if (read32p(INFRACFG_AO_BASE + BUS_INFRA_CTRL) & 0x1) { - printk(BIOS_DEBUG, "** Dump lastbus infra debug registers start **\n"); - for (i = 0; i < INFRA_NUM; i++) { - reg = INFRACFG_AO_BASE + BUS_INFRA_SNAPSHOT + 4 * i; - printk(BIOS_DEBUG, "%08x\n", read32p(reg)); - } - } - - if (read32p(PERICFG_BASE + BUS_PERI_R1) & 0x1) { - printk(BIOS_DEBUG, "** Dump lastbus peri debug registers start **\n"); - for (i = 0; i < PERI_NUM; i++) { - reg = PERICFG_BASE + preisys_dump_offset[i]; - printk(BIOS_DEBUG, "%08x\n", read32p(reg)); - } - } -} - -void lastbus_init(void) -{ - lastbus_dump(); - lastbus_setup(); -} diff --git a/src/soc/mediatek/common/lastbus_v1.c b/src/soc/mediatek/common/lastbus_v1.c new file mode 100644 index 0000000000..cf3fb1db39 --- /dev/null +++ b/src/soc/mediatek/common/lastbus_v1.c @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include + +static unsigned long preisys_dump_offset[] = { + 0x500, /* PERIBUS_DBG0 */ + 0x504, /* PERIBUS_DBG1 */ + 0x508, /* PERIBUS_DBG2 */ + 0x50C, /* PERIBUS_DBG3 */ + 0x510, /* PERIBUS_DBG4 */ + 0x514, /* PERIBUS_DBG5 */ + 0x518, /* PERIBUS_DBG6 */ + 0x51C, /* PERIBUS_DBG7 */ + 0x520, /* PERIBUS_DBG8 */ + 0x524, /* PERIBUS_DBG9 */ + 0x528, /* PERIBUS_DBG10 */ + 0x52C, /* PERIBUS_DBG11 */ + 0x530, /* PERIBUS_DBG12 */ + 0x534, /* PERIBUS_DBG13 */ + 0x538, /* PERIBUS_DBG14 */ + 0x53C, /* PERIBUS_DBG15 */ + 0x580, /* PERIBUS_DBG16 */ + 0x584, /* PERIBUS_DBG17 */ +}; + +static void lastbus_setup(void) +{ + /* peri lastbus init */ + write32p(PERICFG_BASE + BUS_PERI_R0, PERISYS_TIMEOUT); + write32p(PERICFG_BASE + BUS_PERI_R1, PERISYS_ENABLE); + + /* infra lastbus init */ + write32p(INFRACFG_AO_BASE + BUS_INFRA_CTRL, INFRASYS_CONFIG); +} + +static void lastbus_dump(void) +{ + unsigned int i; + uintptr_t reg; + + if (read32p(INFRACFG_AO_BASE + BUS_INFRA_CTRL) & 0x1) { + printk(BIOS_DEBUG, "** Dump lastbus infra debug registers start **\n"); + for (i = 0; i < INFRA_NUM; i++) { + reg = INFRACFG_AO_BASE + BUS_INFRA_SNAPSHOT + 4 * i; + printk(BIOS_DEBUG, "%08x\n", read32p(reg)); + } + } + + if (read32p(PERICFG_BASE + BUS_PERI_R1) & 0x1) { + printk(BIOS_DEBUG, "** Dump lastbus peri debug registers start **\n"); + for (i = 0; i < PERI_NUM; i++) { + reg = PERICFG_BASE + preisys_dump_offset[i]; + printk(BIOS_DEBUG, "%08x\n", read32p(reg)); + } + } +} + +void lastbus_init(void) +{ + lastbus_dump(); + lastbus_setup(); +} diff --git a/src/soc/mediatek/common/lastbus_v2.c b/src/soc/mediatek/common/lastbus_v2.c new file mode 100644 index 0000000000..2893c5a72a --- /dev/null +++ b/src/soc/mediatek/common/lastbus_v2.c @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include + +#define SYS_TIMER_0_OFFSET 0x400 +#define SYS_TIMER_1_OFFSET 0x404 +#define DEBUG_RESULT_OFFSET 0x408 + +static bool lastbus_is_timeout(const struct lastbus_monitor *m) +{ + return read32p(m->base) & LASTBUS_TIMEOUT; +} + +static uint64_t gray_code_to_binary(uint64_t gray_code) +{ + uint64_t value = 0; + while (gray_code) { + value ^= gray_code; + gray_code >>= 1; + } + return value; +} + +static void lastbus_dump_monitor(const struct lastbus_monitor *m) +{ + int i; + uint64_t gray_code, bin_code; + + printk(BIOS_INFO, "--- %s %#lx %ld ---\n", m->name, m->base, m->num_ports); + + for (i = 0; i < m->num_ports; i++) + printk(BIOS_INFO, "%08x\n", + read32p(m->base + DEBUG_RESULT_OFFSET + (i * 4))); + + gray_code = (uint64_t)read32p(m->base + SYS_TIMER_1_OFFSET) << 32 | + read32p(m->base + SYS_TIMER_0_OFFSET); + bin_code = gray_code_to_binary(gray_code); + printk(BIOS_INFO, "\ntimestamp: %#llx\n", bin_code); +} + +static void lastbus_dump(void) +{ + const struct lastbus_monitor *m; + bool found = false; + int i; + + for (i = 0; i < lastbus_cfg.num_used_monitors; i++) { + m = &lastbus_cfg.monitors[i]; + if (!lastbus_is_timeout(m)) + continue; + + if (!found) + printk(BIOS_INFO, + "\n******************* %s lastbus ******************\n", + lastbus_cfg.latch_platform); + found = true; + lastbus_dump_monitor(m); + } +} + +static u16 calculate_timeout_thres(u16 bus_freq_mhz, u32 timeout_ms) +{ + u64 value; + value = ((u64)timeout_ms * USECS_PER_MSEC * bus_freq_mhz) >> 10; + if (value >= UINT16_MAX) + return UINT16_MAX - 1; + return value >= 1 ? value - 1 : 0; +} + +static void lastbus_init_monitor(const struct lastbus_monitor *m, + u32 timeout_ms, u32 timeout_type) +{ + u16 timeout_thres; + int i; + + for (i = 0; i < m->num_idle_mask; i++) + write32p(m->base + m->idle_masks[i].reg_offset, + m->idle_masks[i].reg_value); + + /* clear timeout status with DBG_CKEN */ + write32p(m->base, LASTBUS_TIMEOUT_CLR | LASTBUS_DEBUG_CKEN); + /* de-assert clear bit */ + clrbits32p(m->base, LASTBUS_TIMEOUT_CLR); + + if (timeout_ms == UINT32_MAX) + timeout_thres = 0xFFFF; + else + timeout_thres = calculate_timeout_thres(m->bus_freq_mhz, timeout_ms); + + setbits32p(m->base, (timeout_thres << TIMEOUT_THRES_SHIFT) | + (timeout_type << TIMEOUT_TYPE_SHIFT)); + setbits32p(m->base, LASTBUS_DEBUG_EN); +} + +static void lastbus_setup(void) +{ + int i; + + for (i = 0; i < lastbus_cfg.num_used_monitors; i++) + lastbus_init_monitor(&lastbus_cfg.monitors[i], lastbus_cfg.timeout_ms, + lastbus_cfg.timeout_type); +} + +void lastbus_init(void) +{ + lastbus_dump(); + lastbus_setup(); +} diff --git a/src/soc/mediatek/mt8186/Makefile.inc b/src/soc/mediatek/mt8186/Makefile.inc index d03ea0e791..04d047acf1 100644 --- a/src/soc/mediatek/mt8186/Makefile.inc +++ b/src/soc/mediatek/mt8186/Makefile.inc @@ -14,7 +14,7 @@ all-y += ../common/uart.c bootblock-y += bootblock.c bootblock-y += ../common/eint_event.c bootblock-y += gic.c -bootblock-y += ../common/lastbus.c +bootblock-y += ../common/lastbus_v1.c bootblock-y += ../common/mmu_operations.c bootblock-y += ../common/tracker.c ../common/tracker_v1.c bootblock-y += ../common/wdt.c ../common/wdt_req.c wdt.c diff --git a/src/soc/mediatek/mt8186/bootblock.c b/src/soc/mediatek/mt8186/bootblock.c index 9b12e562a1..d06b11113b 100644 --- a/src/soc/mediatek/mt8186/bootblock.c +++ b/src/soc/mediatek/mt8186/bootblock.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/soc/mediatek/mt8188/Makefile.inc b/src/soc/mediatek/mt8188/Makefile.inc index 95df6dc1d9..651cff0d5a 100644 --- a/src/soc/mediatek/mt8188/Makefile.inc +++ b/src/soc/mediatek/mt8188/Makefile.inc @@ -11,6 +11,7 @@ all-y += ../common/uart.c bootblock-y += bootblock.c bootblock-y += ../common/eint_event.c +bootblock-y += ../common/lastbus_v2.c lastbus.c bootblock-y += ../common/mmu_operations.c bootblock-y += ../common/tracker.c ../common/tracker_v2.c bootblock-y += ../common/wdt.c ../common/wdt_req.c wdt.c diff --git a/src/soc/mediatek/mt8188/bootblock.c b/src/soc/mediatek/mt8188/bootblock.c index 32ef4af2e3..f7b7849b36 100644 --- a/src/soc/mediatek/mt8188/bootblock.c +++ b/src/soc/mediatek/mt8188/bootblock.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -11,6 +12,7 @@ void bootblock_soc_init(void) { mtk_mmu_init(); bustracker_init(); + lastbus_init(); mtk_wdt_init(); mt_pll_init(); unmask_eint_event_mask(); diff --git a/src/soc/mediatek/mt8188/include/soc/addressmap.h b/src/soc/mediatek/mt8188/include/soc/addressmap.h index 63f059616f..74489764f9 100644 --- a/src/soc/mediatek/mt8188/include/soc/addressmap.h +++ b/src/soc/mediatek/mt8188/include/soc/addressmap.h @@ -27,14 +27,20 @@ enum { APMIXED_BASE = IO_PHYS + 0x0000C000, SYSTIMER_BASE = IO_PHYS + 0x00017000, INFRACFG_AO_BCRM_BASE = IO_PHYS + 0x00022000, + INFRA_AO_DBUG_BASE = IO_PHYS + 0x00023000, PMIF_SPI_BASE = IO_PHYS + 0x00024000, PMICSPI_MST_BASE = IO_PHYS + 0x00025000, PMIF_SPMI_BASE = IO_PHYS + 0x00027000, + INFRA2_AO_DBUG_BASE = IO_PHYS + 0x00028000, SPMI_MST_BASE = IO_PHYS + 0x00029000, + PERI_AO_BASE = IO_PHYS + 0x0002B000, + PERI_AO2_BASE = IO_PHYS + 0x0002E000, DEVAPC_INFRA_AO_BASE = IO_PHYS + 0x00030000, DEVAPC_PERI_AO_BASE = IO_PHYS + 0x00034000, DEVAPC_PERI2_AO_BASE = IO_PHYS + 0x00038000, DEVAPC_PERI_PAR_AO_BASE = IO_PHYS + 0x0003C000, + PERI_PAR_AO_BASE = IO_PHYS + 0x00040000, + FMEM_AO_BASE = IO_PHYS + 0x00042000, DBG_TRACKER_BASE = IO_PHYS + 0x00208000, PERI_TRACKER_BASE = IO_PHYS + 0x00218000, EMI0_BASE = IO_PHYS + 0x00219000, diff --git a/src/soc/mediatek/mt8188/lastbus.c b/src/soc/mediatek/mt8188/lastbus.c new file mode 100644 index 0000000000..f2c0b0d57f --- /dev/null +++ b/src/soc/mediatek/mt8188/lastbus.c @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include + +const struct lastbus_config lastbus_cfg = { + .latch_platform = "MT8188", + .timeout_ms = 200, + .timeout_type = 0, + .num_used_monitors = 6, + .monitors = { + { + .name = "debug_ctrl_ao_INFRA_AO", + .base = INFRA_AO_DBUG_BASE, + .num_ports = 34, + .num_idle_mask = 2, + .idle_masks = { + { + .reg_offset = 0x04, + .reg_value = 0x2, + }, + { + .reg_offset = 0x08, + .reg_value = 0x10000, + }, + }, + .bus_freq_mhz = 78, + }, + { + .name = "debug_ctrl_ao_INFRA2_AO", + .base = INFRA2_AO_DBUG_BASE, + .num_ports = 9, + .num_idle_mask = 0, + .bus_freq_mhz = 78, + }, + { + .name = "debug_ctrl_ao_PERI_AO", + .base = PERI_AO_BASE, + .num_ports = 25, + .num_idle_mask = 1, + .idle_masks = { + { + .reg_offset = 0x04, + .reg_value = 0x20000, + }, + }, + .bus_freq_mhz = 78, + }, + { + .name = "debug_ctrl_ao_PERI_AO2", + .base = PERI_AO2_BASE, + .num_ports = 20, + .num_idle_mask = 0, + .bus_freq_mhz = 78, + }, + { + .name = "debug_ctrl_ao_PERI_PAR_AO", + .base = PERI_PAR_AO_BASE, + .num_ports = 18, + .num_idle_mask = 0, + .bus_freq_mhz = 78, + }, + { + .name = "debug_ctrl_ao_FMEM_AO", + .base = FMEM_AO_BASE, + .num_ports = 28, + .num_idle_mask = 1, + .idle_masks = { + { + .reg_offset = 0x14, + .reg_value = 0x204, + }, + }, + .bus_freq_mhz = 78, + }, + }, +}; -- cgit v1.2.3