summaryrefslogtreecommitdiff
path: root/src/soc/amd/common/block/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/amd/common/block/cpu')
-rw-r--r--src/soc/amd/common/block/cpu/Kconfig11
-rw-r--r--src/soc/amd/common/block/cpu/tsc/Makefile.inc20
-rw-r--r--src/soc/amd/common/block/cpu/tsc/monotonic_timer.c16
-rw-r--r--src/soc/amd/common/block/cpu/tsc/tsc_freq.c44
4 files changed, 91 insertions, 0 deletions
diff --git a/src/soc/amd/common/block/cpu/Kconfig b/src/soc/amd/common/block/cpu/Kconfig
index 826f80bdb5..c155975590 100644
--- a/src/soc/amd/common/block/cpu/Kconfig
+++ b/src/soc/amd/common/block/cpu/Kconfig
@@ -27,3 +27,14 @@ config MEMLAYOUT_LD_FILE
default "src/soc/amd/common/block/cpu/noncar/memlayout.ld"
endif # SOC_AMD_COMMON_BLOCK_NONCAR
+
+config SOC_AMD_COMMON_BLOCK_TSC_FAM17H_19H
+ bool
+ select COLLECT_TIMESTAMPS_NO_TSC # selected use SoC-specific timestamp function
+ select TSC_SYNC_LFENCE
+ select UDELAY_TSC
+ default n
+ help
+ Select this option to add the common functions for getting the TSC
+ frequency of AMD family 17h and 19h CPUs/APUs and to provide TSC-
+ based monotonic timer functionality to the build.
diff --git a/src/soc/amd/common/block/cpu/tsc/Makefile.inc b/src/soc/amd/common/block/cpu/tsc/Makefile.inc
new file mode 100644
index 0000000000..4f2729bcb6
--- /dev/null
+++ b/src/soc/amd/common/block/cpu/tsc/Makefile.inc
@@ -0,0 +1,20 @@
+ifeq ($(CONFIG_SOC_AMD_COMMON_BLOCK_TSC_FAM17H_19H),y)
+
+subdirs-y += ../../../../../../cpu/x86/tsc
+
+bootblock-y += tsc_freq.c
+bootblock-y += monotonic_timer.c
+
+verstage_x86-y += tsc_freq.c
+verstage_x86-y += monotonic_timer.c
+
+romstage-y += tsc_freq.c
+romstage-y += monotonic_timer.c
+
+ramstage-y += tsc_freq.c
+ramstage-y += monotonic_timer.c
+
+smm-y += tsc_freq.c
+smm-y += monotonic_timer.c
+
+endif # CONFIG_SOC_AMD_COMMON_BLOCK_TSC_FAM17H_19H
diff --git a/src/soc/amd/common/block/cpu/tsc/monotonic_timer.c b/src/soc/amd/common/block/cpu/tsc/monotonic_timer.c
new file mode 100644
index 0000000000..941532cca6
--- /dev/null
+++ b/src/soc/amd/common/block/cpu/tsc/monotonic_timer.c
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <cpu/x86/msr.h>
+#include <cpu/x86/tsc.h>
+#include <timer.h>
+#include <timestamp.h>
+
+void timer_monotonic_get(struct mono_time *mt)
+{
+ mono_time_set_usecs(mt, timestamp_get());
+}
+
+uint64_t timestamp_get(void)
+{
+ return rdtscll() / tsc_freq_mhz();
+}
diff --git a/src/soc/amd/common/block/cpu/tsc/tsc_freq.c b/src/soc/amd/common/block/cpu/tsc/tsc_freq.c
new file mode 100644
index 0000000000..55c86653ce
--- /dev/null
+++ b/src/soc/amd/common/block/cpu/tsc/tsc_freq.c
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <cpu/x86/msr.h>
+#include <cpu/amd/msr.h>
+#include <cpu/x86/tsc.h>
+#include <console/console.h>
+
+static unsigned long mhz;
+
+/* Use this default TSC frequency when it can not be correctly calculated.
+ Higher numbers are safer as it will result in longer delays using TSC */
+#define TSC_DEFAULT_FREQ_MHZ 4000
+
+unsigned long tsc_freq_mhz(void)
+{
+ msr_t msr;
+ uint8_t cpufid;
+ uint8_t cpudid;
+ uint8_t high_state;
+
+ if (mhz)
+ return mhz;
+
+ high_state = rdmsr(PS_LIM_REG).lo & 0x7;
+ msr = rdmsr(PSTATE_0_MSR + high_state);
+ if (!(msr.hi & 0x80000000))
+ die("Unknown error: cannot determine P-state 0\n");
+
+ cpufid = (msr.lo & 0xff);
+ cpudid = (msr.lo & 0x3f00) >> 8;
+
+ /* normally core frequency is calculated as (fid * 25) / (did / 8) */
+ if (!cpudid) {
+ mhz = TSC_DEFAULT_FREQ_MHZ;
+ printk(BIOS_ERR, "Invalid divisor, set TSC frequency to %ldMHz\n", mhz);
+ } else if ((cpudid >= 8) && (cpudid <= 0x30)) {
+ mhz = (200 * cpufid) / cpudid;
+ } else {
+ mhz = 25 * cpufid;
+ printk(BIOS_ERR, "Invalid frequency divisor 0x%x, assume 1\n", cpudid);
+ }
+
+ return mhz;
+}