soc/amd/common: Add code to print AMD STB to boot log

This allows platforms that support AMD's STB (Smart Trace Buffer) to
print the buffer at various points in the boot process.

The STB is roughly a hardware assisted postcode that captures the
time stamp of when the postcode was added to the buffer.  Reading
from the STB clears the data.

Signed-off-by: Martin Roth <gaumless@gmail.com>
Change-Id: I8d78c0e86b244f3bd16248edf3850447fb0a9e2c
Reviewed-on: https://review.coreboot.org/c/coreboot/+/68543
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Fred Reitberger <reitbergerfred@gmail.com>
diff --git a/src/soc/amd/common/block/include/amdblocks/stb.h b/src/soc/amd/common/block/include/amdblocks/stb.h
new file mode 100644
index 0000000..51b0194
--- /dev/null
+++ b/src/soc/amd/common/block/include/amdblocks/stb.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef AMD_BLOCK_STB_H
+#define AMD_BLOCK_STB_H
+
+#include <types.h>
+
+#define AMD_STB_PMI_0			0x30600
+
+#define AMD_STB_COREBOOT_MARKER		0xBAADF00D
+
+struct stb_entry_struct {
+	uint32_t ts;
+	uint32_t val;
+};
+
+void write_stb_to_console(void);
+void init_spill_buffer(void);
+void add_stb_to_timestamp_buffer(void);
+
+#endif /* AMD_BLOCK_STB_H */
diff --git a/src/soc/amd/common/block/stb/Kconfig b/src/soc/amd/common/block/stb/Kconfig
new file mode 100644
index 0000000..8935e92
--- /dev/null
+++ b/src/soc/amd/common/block/stb/Kconfig
@@ -0,0 +1,17 @@
+config SOC_AMD_COMMON_BLOCK_STB
+	bool
+	select SOC_AMD_COMMON_BLOCK_SMN
+	help
+	  Select in the SOC if it supports the Smart Trace Buffer
+
+if SOC_AMD_COMMON_BLOCK_STB
+
+config WRITE_STB_BUFFER_TO_CONSOLE
+	bool "Write STB entries to the console log"
+	default n
+	help
+	  This option will tell coreboot to print the STB buffer at various
+	  points through the boot process. Note that this will prevent the
+	  entries from being stored if the Spill-to-DRAM feature is enabled.
+
+endif
diff --git a/src/soc/amd/common/block/stb/Makefile.inc b/src/soc/amd/common/block/stb/Makefile.inc
new file mode 100644
index 0000000..5ce9c4b
--- /dev/null
+++ b/src/soc/amd/common/block/stb/Makefile.inc
@@ -0,0 +1,7 @@
+ifeq ($(CONFIG_SOC_AMD_COMMON_BLOCK_STB),y)
+
+bootblock-y += stb.c
+romstage-y += stb.c
+ramstage-y += stb.c
+
+endif # CONFIG_SOC_AMD_COMMON_BLOCK_STB
diff --git a/src/soc/amd/common/block/stb/stb.c b/src/soc/amd/common/block/stb/stb.c
new file mode 100644
index 0000000..074a4ed
--- /dev/null
+++ b/src/soc/amd/common/block/stb/stb.c
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <amdblocks/smn.h>
+#include <amdblocks/stb.h>
+#include <bootstate.h>
+#include <console/console.h>
+#include <soc/stb.h>
+
+#define STB_ENTRIES_PER_ROW 4
+
+static void stb_write32(uint32_t reg, uint32_t val)
+{
+	smn_write32(STB_CFG_SMN_ADDR + reg, val);
+}
+
+static uint32_t stb_read32(uint32_t reg)
+{
+	return smn_read32(STB_CFG_SMN_ADDR + reg);
+}
+
+void write_stb_to_console(void)
+{
+	int i;
+	int printed_data = 0;
+	struct stb_entry_struct stb_val;
+
+	/* Add a marker into the STB so it's easy to see where the end is. */
+	stb_write32(AMD_STB_PMI_0, AMD_STB_COREBOOT_MARKER);
+
+	for (i = 0; i < AMD_STB_SDRAM_FIFO_SIZE; i++) {
+		/*
+		 * It's possible to do a single read and leave the timestamp as the first
+		 * value of a pair, but by default the value will be first and time stamp
+		 * second.  We're just assuming that nothing has messed up the ordering.
+		 */
+		stb_val.val = stb_read32(AMD_STB_PMI_0);
+		stb_val.ts = stb_read32(AMD_STB_PMI_0);
+
+		if (stb_val.val == AMD_STB_COREBOOT_MARKER) {
+			if (!printed_data)
+				printk(BIOS_DEBUG, "No Smart Trace Buffer Data available.\n");
+			else
+				// Don't print the coreboot marker
+				printk(BIOS_DEBUG, "\n");
+			return;
+		}
+
+		if (i == 0)
+			printk(BIOS_DEBUG, "Available Smart Trace Buffer data:\n");
+		if ((i % STB_ENTRIES_PER_ROW) == 0)
+			printk(BIOS_DEBUG, "%04d,", i);
+		printk(BIOS_DEBUG, " 0x%08x,0x%08x, ", stb_val.ts, stb_val.val);
+		if ((i % STB_ENTRIES_PER_ROW) == STB_ENTRIES_PER_ROW - 1)
+			printk(BIOS_DEBUG, "\n");
+		printed_data = 1;
+
+	}
+
+}
+
+static void final_stb_console(void *unused)
+{
+	if (CONFIG(WRITE_STB_BUFFER_TO_CONSOLE))
+		write_stb_to_console();
+}
+
+BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, final_stb_console, NULL);