diff options
author | ot_zhenguo.li <ot_zhenguo.li@mediatek.corp-partner.google.com> | 2023-02-24 13:55:27 +0800 |
---|---|---|
committer | Rex-BC Chen <rex-bc.chen@mediatek.com> | 2023-03-10 12:38:31 +0000 |
commit | 6bd9d959ddc3fabd84c57de41c6a1db7c400f562 (patch) | |
tree | 711884a36cf424ad1d35cc4874211596a8866e26 /src/soc/mediatek/common/lastbus_v2.c | |
parent | c9bf43f4d6caa4b59a6eaff8fff2929c609c6122 (diff) |
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 <ot_zhenguo.li@mediatek.corp-partner.google.com>
Signed-off-by: jason-ch chen <Jason-ch.Chen@mediatek.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/73624
Reviewed-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Reviewed-by: Yidi Lin <yidilin@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
Diffstat (limited to 'src/soc/mediatek/common/lastbus_v2.c')
-rw-r--r-- | src/soc/mediatek/common/lastbus_v2.c | 112 |
1 files changed, 112 insertions, 0 deletions
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 <console/console.h> +#include <device/mmio.h> +#include <soc/addressmap.h> +#include <soc/lastbus_v2.h> +#include <timer.h> + +#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(); +} |