diff options
-rw-r--r-- | src/soc/amd/common/block/psp/psp_def.h | 2 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/psp_gen2.c | 71 |
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(®_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 { |