summaryrefslogtreecommitdiff
path: root/src/soc
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc')
-rw-r--r--src/soc/intel/common/basecode/include/intelbasecode/tom.h14
-rw-r--r--src/soc/intel/common/basecode/tom/Kconfig15
-rw-r--r--src/soc/intel/common/basecode/tom/Makefile.inc2
-rw-r--r--src/soc/intel/common/basecode/tom/tom.c127
4 files changed, 158 insertions, 0 deletions
diff --git a/src/soc/intel/common/basecode/include/intelbasecode/tom.h b/src/soc/intel/common/basecode/include/intelbasecode/tom.h
new file mode 100644
index 0000000000..d78ecd1a60
--- /dev/null
+++ b/src/soc/intel/common/basecode/include/intelbasecode/tom.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef SOC_INTEL_COMMON_BASECODE_TOM_H
+#define SOC_INTEL_COMMON_BASECODE_TOM_H
+
+#include <types.h>
+
+/* Early caching of TOM region */
+void early_tom_enable_cache_range(void);
+
+/* Update the TOM if required based on the input TOM address */
+void update_tom(uint32_t addr);
+
+#endif
diff --git a/src/soc/intel/common/basecode/tom/Kconfig b/src/soc/intel/common/basecode/tom/Kconfig
new file mode 100644
index 0000000000..ff91725a52
--- /dev/null
+++ b/src/soc/intel/common/basecode/tom/Kconfig
@@ -0,0 +1,15 @@
+config SOC_INTEL_COMMON_BASECODE_TOM
+ bool
+ default n
+ help
+ Driver code to store the top_of_ram (TOM) address into
+ non-volatile space (CMOS) during the first boot and use
+ it across all consecutive boot.
+
+ Purpose of this driver code is to cache the TOM (with a
+ fixed size) for all consecutive boots even before calling
+ into the FSP. Otherwise, this range remains un-cached until postcar
+ boot stage updates the MTRR programming. FSP-M and late romstage
+ uses this uncached TOM range for various purposes and having the
+ ability to cache this range beforehand would help to optimize the boot
+ time (more than 50ms).
diff --git a/src/soc/intel/common/basecode/tom/Makefile.inc b/src/soc/intel/common/basecode/tom/Makefile.inc
new file mode 100644
index 0000000000..2ebf4bb25f
--- /dev/null
+++ b/src/soc/intel/common/basecode/tom/Makefile.inc
@@ -0,0 +1,2 @@
+## SPDX-License-Identifier: GPL-2.0-only
+romstage-$(CONFIG_SOC_INTEL_COMMON_BASECODE_TOM) += tom.c
diff --git a/src/soc/intel/common/basecode/tom/tom.c b/src/soc/intel/common/basecode/tom/tom.c
new file mode 100644
index 0000000000..de696d555d
--- /dev/null
+++ b/src/soc/intel/common/basecode/tom/tom.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <console/console.h>
+#include <cpu/x86/mtrr.h>
+#include <ip_checksum.h>
+#include <intelbasecode/tom.h>
+#include <pc80/mc146818rtc.h>
+#include <stdint.h>
+
+/* We need a region in CMOS to store the TOM address */
+
+#define TOM_SIGNATURE 0x5F544F4D /* '_TOM' */
+
+#define TOM_CMOS_OFFSET 0x64
+
+/*
+ * Address of the tom_cmos_offset byte in CMOS. Should be reserved
+ * in mainboards' cmos.layout and not covered by checksum.
+ */
+
+#if CONFIG(USE_OPTION_TABLE)
+#include "option_table.h"
+#if CMOS_VSTART_tom_cmos_offset != TOM_CMOS_OFFSET * 8
+#error "CMOS start for TOM_CMOS is not correct, check your cmos.layout"
+#endif
+#if CMOS_VLEN_tom_cmos_offset != 12
+#error "CMOS length for TOM_CMOS bytes are not correct, check your cmos.layout"
+#endif
+#endif
+
+struct tom_table {
+ uint32_t signature;
+ uint32_t addr;
+ uint16_t checksum;
+} __packed;
+
+/* Read and validate tom_table structure from CMOS */
+static int tom_cmos_read(struct tom_table *tom)
+{
+ u8 i, *p;
+ u16 csum;
+
+ for (p = (u8 *)tom, i = 0; i < sizeof(*tom); i++, p++)
+ *p = cmos_read(TOM_CMOS_OFFSET + i);
+
+ /* Verify signature */
+ if (tom->signature != TOM_SIGNATURE) {
+ printk(BIOS_DEBUG, "tom_table invalid signature\n");
+ return -1;
+ }
+
+ /* Verify checksum over signature and counter only */
+ csum = compute_ip_checksum(tom, offsetof(struct tom_table, checksum));
+
+ if (csum != tom->checksum) {
+ printk(BIOS_DEBUG, "tom_table checksum mismatch\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Write tom_table structure to CMOS */
+static void tom_cmos_write(struct tom_table *tom)
+{
+ u8 i, *p;
+
+ /* Checksum over signature and counter only */
+ tom->checksum = compute_ip_checksum(
+ tom, offsetof(struct tom_table, checksum));
+
+ for (p = (u8 *)tom, i = 0; i < sizeof(*tom); i++, p++)
+ cmos_write(*p, TOM_CMOS_OFFSET + i);
+}
+
+/* Update the TOM if required based on the input TOM address */
+void update_tom(uint32_t addr)
+{
+ struct tom_table tom;
+
+ /* Read and increment boot count */
+ if (tom_cmos_read(&tom) < 0) {
+ /* Structure invalid, re-initialize */
+ tom.signature = TOM_SIGNATURE;
+ tom.addr = 0;
+ }
+
+ /* Update TOM if required */
+ if (tom.addr == addr)
+ return;
+
+ tom.addr = addr;
+
+ /* Write the new count to CMOS */
+ tom_cmos_write(&tom);
+
+ printk(BIOS_DEBUG, "Updated the TOM address into CMOS 0x%x\n", tom.addr);
+}
+
+static uint32_t get_tom_addr(void)
+{
+ struct tom_table tom;
+
+ if (tom_cmos_read(&tom) < 0)
+ return 0;
+
+ return tom.addr;
+}
+
+/* Early caching of TOM region */
+void early_tom_enable_cache_range(void)
+{
+ uint32_t tom = get_tom_addr();
+ if (!tom)
+ return;
+
+ int mtrr = get_free_var_mtrr();
+ if (mtrr == -1) {
+ printk(BIOS_WARNING, "tom_table update failure due to no free MTRR available!\n");
+ return;
+ }
+ /*
+ * We need to make sure late romstage (including FSP-M post mem) will be run
+ * cached. Caching 16MB below TOM is a safe to cover late romstage.
+ */
+ set_var_mtrr(mtrr, tom - 16 * MiB, 16 * MiB, MTRR_TYPE_WRBACK);
+}