summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 {