summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Held <felix-coreboot@felixheld.de>2024-07-11 15:15:00 +0200
committerFelix Held <felix-coreboot@felixheld.de>2024-07-25 22:55:38 +0000
commitc7f022ae9567aece54bb2d5a206c0ee27ec34f39 (patch)
treebab80191be09fb009f95432ee8c55992c00e2781
parentebf90e3a8823781cab7b24dbaf41a783c31f4b38 (diff)
soc/amd/common/block/psp_gen2: add get_psp_mmio_base
Add get_psp_mmio_base which reads the PSP MMIO base address from the hardware registers. Since this function will not only be called in ramstage, but also in SMM, we can't just look for the specific domain resource consumer like it is done for the IOAPICs in the northbridge, but have to get this base address from the registers. In order to limit the performance impact of this, the base address gets cached in a static variable if an enabled PSP MMIO base register is found. We expect that this register is locked when it was configured and enabled; if we run into the unexpected case that the PSP MMIO register is enabled, but not locked, set the lock bit of the corresponding base address register to be sure that it won't change until the next reset and that the hardware value can't be different than the cached value. This is a preparation to move back to using MMIO access to the PSP registers and will also enable cases that require the use of the MMIO mapping of the PSP registers. Signed-off-by: Felix Held <felix-coreboot@felixheld.de> Change-Id: I1d51e30f186508b0fe1ab5eb79c73e6d4b9d1a4a Reviewed-on: https://review.coreboot.org/c/coreboot/+/83446 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Matt DeVillier <matt.devillier@amd.corp-partner.google.com> Reviewed-by: Martin Roth <martin.roth@amd.corp-partner.google.com>
-rw-r--r--src/soc/amd/common/block/psp/psp_def.h2
-rw-r--r--src/soc/amd/common/block/psp/psp_gen2.c71
2 files changed, 73 insertions, 0 deletions
diff --git a/src/soc/amd/common/block/psp/psp_def.h b/src/soc/amd/common/block/psp/psp_def.h
index 9def98bff1..f6efa21802 100644
--- a/src/soc/amd/common/block/psp/psp_def.h
+++ b/src/soc/amd/common/block/psp/psp_def.h
@@ -108,6 +108,8 @@ struct mbox_cmd_dtpm_config_buffer {
#define PSP_INIT_TIMEOUT 10000 /* 10 seconds */
#define PSP_CMD_TIMEOUT 1000 /* 1 second */
+uintptr_t get_psp_mmio_base(void);
+
void psp_print_cmd_status(int cmd_status, struct mbox_buffer_header *header);
/* This command needs to be implemented by the generation specific code. */
diff --git a/src/soc/amd/common/block/psp/psp_gen2.c b/src/soc/amd/common/block/psp/psp_gen2.c
index f647dcd215..7b92cc2025 100644
--- a/src/soc/amd/common/block/psp/psp_gen2.c
+++ b/src/soc/amd/common/block/psp/psp_gen2.c
@@ -3,6 +3,7 @@
#include <timer.h>
#include <types.h>
#include <amdblocks/psp.h>
+#include <amdblocks/root_complex.h>
#include <amdblocks/smn.h>
#include "psp_def.h"
@@ -10,6 +11,76 @@
#define PSP_MAILBOX_BUFFER_L_OFFSET 0x10574 /* 4 bytes */
#define PSP_MAILBOX_BUFFER_H_OFFSET 0x10578 /* 4 bytes */
+#define IOHC_MISC_PSP_MMIO_REG 0x2e0
+
+static uint64_t get_psp_mmio_mask(void)
+{
+ const struct non_pci_mmio_reg *mmio_regs;
+ size_t reg_count;
+ mmio_regs = get_iohc_non_pci_mmio_regs(&reg_count);
+
+ for (size_t i = 0; i < reg_count; i++) {
+ if (mmio_regs[i].iohc_misc_offset == IOHC_MISC_PSP_MMIO_REG)
+ return mmio_regs[i].mask;
+ }
+
+ printk(BIOS_ERR, "No PSP MMIO register description found.\n");
+ return 0;
+}
+
+#define PSP_MMIO_LOCK BIT(8)
+
+/* Getting the PSP MMIO base from the domain resources only works in ramstage, but not in SMM,
+ so we have to read this from the hardware registers */
+uintptr_t get_psp_mmio_base(void)
+{
+ static uintptr_t psp_mmio_base;
+ const struct domain_iohc_info *iohc;
+ size_t iohc_count;
+
+ if (psp_mmio_base)
+ return psp_mmio_base;
+
+ iohc = get_iohc_info(&iohc_count);
+ const uint64_t psp_mmio_mask = get_psp_mmio_mask();
+
+ if (!psp_mmio_mask)
+ return 0;
+
+ for (size_t i = 0; i < iohc_count; i++) {
+ uint64_t reg64 = smn_read64(iohc[i].misc_smn_base | IOHC_MISC_PSP_MMIO_REG);
+
+ if (!(reg64 & IOHC_MMIO_EN))
+ continue;
+
+ const uint64_t base = reg64 & psp_mmio_mask;
+
+ if (ENV_X86_32 && base >= 4ull * GiB) {
+ printk(BIOS_WARNING, "PSP MMIO base above 4GB.\n");
+ continue;
+ }
+
+ /* If the PSP MMIO base is enabled but the register isn't locked, set the lock
+ bit. This shouldn't happen, but better be a bit too careful here */
+ if (!(reg64 & PSP_MMIO_LOCK)) {
+ printk(BIOS_WARNING, "Enabled PSP MMIO in domain %zu isn't locked. "
+ "Locking it.\n", i);
+ reg64 |= PSP_MMIO_LOCK;
+ /* Since the lock bit lives in the lower one of the two 32 bit SMN
+ registers, we only need to write that one to lock it */
+ smn_write32(iohc[i].misc_smn_base | IOHC_MISC_PSP_MMIO_REG,
+ reg64 & 0xffffffff);
+ }
+
+ psp_mmio_base = base;
+ }
+
+ if (!psp_mmio_base)
+ printk(BIOS_ERR, "No usable PSP MMIO found.\n");
+
+ return psp_mmio_base;
+}
+
union pspv2_mbox_command {
u32 val;
struct pspv2_mbox_cmd_fields {