xref: /aosp_15_r20/external/coreboot/src/soc/mediatek/common/lastbus_v2.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <device/mmio.h>
5 #include <soc/addressmap.h>
6 #include <soc/lastbus_v2.h>
7 #include <timer.h>
8 
9 #define SYS_TIMER_0_OFFSET 0x400
10 #define SYS_TIMER_1_OFFSET 0x404
11 #define DEBUG_RESULT_OFFSET 0x408
12 
lastbus_is_timeout(const struct lastbus_monitor * m)13 static bool lastbus_is_timeout(const struct lastbus_monitor *m)
14 {
15 	return read32p(m->base) & LASTBUS_TIMEOUT;
16 }
17 
gray_code_to_binary(uint64_t gray_code)18 static uint64_t gray_code_to_binary(uint64_t gray_code)
19 {
20 	uint64_t value = 0;
21 	while (gray_code) {
22 		value ^= gray_code;
23 		gray_code >>= 1;
24 	}
25 	return value;
26 }
27 
lastbus_dump_monitor(const struct lastbus_monitor * m)28 static void lastbus_dump_monitor(const struct lastbus_monitor *m)
29 {
30 	int i;
31 	uint64_t gray_code, bin_code;
32 
33 	printk(BIOS_INFO, "--- %s %#lx %ld ---\n", m->name, m->base, m->num_ports);
34 
35 	for (i = 0; i < m->num_ports; i++)
36 		printk(BIOS_INFO, "%08x\n",
37 		       read32p(m->base + DEBUG_RESULT_OFFSET + (i * 4)));
38 
39 	gray_code = (uint64_t)read32p(m->base + SYS_TIMER_1_OFFSET) << 32 |
40 		    read32p(m->base + SYS_TIMER_0_OFFSET);
41 	bin_code = gray_code_to_binary(gray_code);
42 	printk(BIOS_INFO, "\ntimestamp: %#llx\n", bin_code);
43 }
44 
lastbus_dump(void)45 static void lastbus_dump(void)
46 {
47 	const struct lastbus_monitor *m;
48 	bool found  = false;
49 	int i;
50 
51 	for (i = 0; i < lastbus_cfg.num_used_monitors; i++) {
52 		m = &lastbus_cfg.monitors[i];
53 		if (!lastbus_is_timeout(m))
54 			continue;
55 
56 		if (!found)
57 			printk(BIOS_INFO,
58 			       "\n******************* %s lastbus ******************\n",
59 			       lastbus_cfg.latch_platform);
60 		found = true;
61 		lastbus_dump_monitor(m);
62 	}
63 }
64 
calculate_timeout_thres(u16 bus_freq_mhz,u32 timeout_ms)65 static u16 calculate_timeout_thres(u16 bus_freq_mhz, u32 timeout_ms)
66 {
67 	u64 value;
68 	value = ((u64)timeout_ms * USECS_PER_MSEC * bus_freq_mhz) >> 10;
69 	if (value >= UINT16_MAX)
70 		return UINT16_MAX - 1;
71 	return value >= 1 ? value - 1 : 0;
72 }
73 
lastbus_init_monitor(const struct lastbus_monitor * m,u32 timeout_ms,u32 timeout_type)74 static void lastbus_init_monitor(const struct lastbus_monitor *m,
75 				 u32 timeout_ms, u32 timeout_type)
76 {
77 	u16 timeout_thres;
78 	int i;
79 
80 	for (i = 0; i < m->num_idle_mask; i++)
81 		write32p(m->base + m->idle_masks[i].reg_offset,
82 			 m->idle_masks[i].reg_value);
83 
84 	/* clear timeout status with DBG_CKEN */
85 	write32p(m->base, LASTBUS_TIMEOUT_CLR | LASTBUS_DEBUG_CKEN);
86 	/* de-assert clear bit */
87 	clrbits32p(m->base, LASTBUS_TIMEOUT_CLR);
88 
89 	if (timeout_ms == UINT32_MAX)
90 		timeout_thres = 0xFFFF;
91 	else
92 		timeout_thres = calculate_timeout_thres(m->bus_freq_mhz, timeout_ms);
93 
94 	setbits32p(m->base, (timeout_thres << TIMEOUT_THRES_SHIFT) |
95 			    (timeout_type << TIMEOUT_TYPE_SHIFT));
96 	setbits32p(m->base, LASTBUS_DEBUG_EN);
97 }
98 
lastbus_setup(void)99 static void lastbus_setup(void)
100 {
101 	int i;
102 
103 	for (i = 0; i < lastbus_cfg.num_used_monitors; i++)
104 		lastbus_init_monitor(&lastbus_cfg.monitors[i], lastbus_cfg.timeout_ms,
105 				     lastbus_cfg.timeout_type);
106 }
107 
lastbus_init(void)108 void lastbus_init(void)
109 {
110 	lastbus_dump();
111 	lastbus_setup();
112 }
113