diff options
-rw-r--r-- | src/soc/amd/common/block/include/amdblocks/psp.h | 2 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/Kconfig | 13 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/Makefile.inc | 11 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/psp.c | 85 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/psp_def.h | 36 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/psp_gen1.c | 93 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/psp_gen2.c | 104 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/Kconfig | 2 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/psp.c | 4 |
9 files changed, 253 insertions, 97 deletions
diff --git a/src/soc/amd/common/block/include/amdblocks/psp.h b/src/soc/amd/common/block/include/amdblocks/psp.h index 36e110867a..53946fb8d2 100644 --- a/src/soc/amd/common/block/include/amdblocks/psp.h +++ b/src/soc/amd/common/block/include/amdblocks/psp.h @@ -5,7 +5,7 @@ #define __AMD_PSP_H__ /* Get the mailbox base address - specific to family of device. */ -struct psp_mbox *soc_get_mbox_address(void); +void *soc_get_mbox_address(void); /* BIOS-to-PSP functions return 0 if successful, else negative value */ #define PSPSTS_SUCCESS 0 diff --git a/src/soc/amd/common/block/psp/Kconfig b/src/soc/amd/common/block/psp/Kconfig index 0517a2f33f..9466cc6abd 100644 --- a/src/soc/amd/common/block/psp/Kconfig +++ b/src/soc/amd/common/block/psp/Kconfig @@ -3,7 +3,18 @@ config SOC_AMD_COMMON_BLOCK_PSP default n help This option builds in the Platform Security Processor initialization - functions. + functions. Do not select this directly in SoC code, select + SOC_AMD_COMMON_BLOCK_PSP_GENx instead. + +config SOC_AMD_COMMON_BLOCK_PSP_GEN1 + bool + default n + select SOC_AMD_COMMON_BLOCK_PSP + +config SOC_AMD_COMMON_BLOCK_PSP_GEN2 + bool + default n + select SOC_AMD_COMMON_BLOCK_PSP config SOC_AMD_PSP_SELECTABLE_SMU_FW bool diff --git a/src/soc/amd/common/block/psp/Makefile.inc b/src/soc/amd/common/block/psp/Makefile.inc index 2f5de1df9c..dc9a385e39 100644 --- a/src/soc/amd/common/block/psp/Makefile.inc +++ b/src/soc/amd/common/block/psp/Makefile.inc @@ -1,4 +1,15 @@ bootblock-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP) += psp.c +bootblock-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN1) += psp_gen1.c +bootblock-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN2) += psp_gen2.c + romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP) += psp.c +romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN1) += psp_gen1.c +romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN2) += psp_gen2.c + ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP) += psp.c +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN1) += psp_gen1.c +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN2) += psp_gen2.c + smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP) += psp.c +smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN1) += psp_gen1.c +smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN2) += psp_gen2.c diff --git a/src/soc/amd/common/block/psp/psp.c b/src/soc/amd/common/block/psp/psp.c index c35f41b20c..22404be6d6 100644 --- a/src/soc/amd/common/block/psp/psp.c +++ b/src/soc/amd/common/block/psp/psp.c @@ -6,10 +6,8 @@ #include <cbfs.h> #include <region_file.h> #include <timer.h> -#include <device/pci_def.h> #include <bootstate.h> #include <console/console.h> -#include <device/pci_ops.h> #include <amdblocks/psp.h> #include <soc/iomap.h> #include <soc/northbridge.h> @@ -43,94 +41,11 @@ static const char *status_to_string(int err) } } -static u32 rd_mbox_sts(struct psp_mbox *mbox) -{ - return read32(&mbox->mbox_status); -} - -static void wr_mbox_cmd(struct psp_mbox *mbox, u32 cmd) -{ - write32(&mbox->mbox_command, cmd); -} - -static u32 rd_mbox_cmd(struct psp_mbox *mbox) -{ - return read32(&mbox->mbox_command); -} - -static void wr_mbox_cmd_resp(struct psp_mbox *mbox, void *buffer) -{ - write64(&mbox->cmd_response, (uintptr_t)buffer); -} - static u32 rd_resp_sts(struct mbox_default_buffer *buffer) { return read32(&buffer->header.status); } -static int wait_initialized(struct psp_mbox *mbox) -{ - struct stopwatch sw; - - stopwatch_init_msecs_expire(&sw, PSP_INIT_TIMEOUT); - - do { - if (rd_mbox_sts(mbox) & STATUS_INITIALIZED) - return 0; - } while (!stopwatch_expired(&sw)); - - return -PSPSTS_INIT_TIMEOUT; -} - -static int wait_command(struct psp_mbox *mbox) -{ - struct stopwatch sw; - - stopwatch_init_msecs_expire(&sw, PSP_CMD_TIMEOUT); - - do { - if (!rd_mbox_cmd(mbox)) - return 0; - } while (!stopwatch_expired(&sw)); - - return -PSPSTS_CMD_TIMEOUT; -} - -static int send_psp_command(u32 command, void *buffer) -{ - struct psp_mbox *mbox = soc_get_mbox_address(); - if (!mbox) - return -PSPSTS_NOBASE; - - /* check for PSP error conditions */ - if (rd_mbox_sts(mbox) & STATUS_HALT) - return -PSPSTS_HALTED; - - if (rd_mbox_sts(mbox) & STATUS_RECOVERY) - return -PSPSTS_RECOVERY; - - /* PSP must be finished with init and ready to accept a command */ - if (wait_initialized(mbox)) - return -PSPSTS_INIT_TIMEOUT; - - if (wait_command(mbox)) - return -PSPSTS_CMD_TIMEOUT; - - /* set address of command-response buffer and write command register */ - wr_mbox_cmd_resp(mbox, buffer); - wr_mbox_cmd(mbox, command); - - /* PSP clears command register when complete */ - if (wait_command(mbox)) - return -PSPSTS_CMD_TIMEOUT; - - /* check delivery status */ - if (rd_mbox_sts(mbox) & (STATUS_ERROR | STATUS_TERMINATED)) - return -PSPSTS_SEND_ERROR; - - return 0; -} - /* * Print meaningful status to the console. Caller only passes a pointer to a * buffer if it's expected to contain its own status. diff --git a/src/soc/amd/common/block/psp/psp_def.h b/src/soc/amd/common/block/psp/psp_def.h index 4b3ca6a352..37755166f0 100644 --- a/src/soc/amd/common/block/psp/psp_def.h +++ b/src/soc/amd/common/block/psp/psp_def.h @@ -5,6 +5,7 @@ #define __AMD_PSP_DEF_H__ #include <types.h> +#include <commonlib/helpers.h> /* x86 to PSP commands */ #define MBOX_BIOS_CMD_DRAM_INFO 0x01 @@ -20,24 +21,42 @@ #define MBOX_BIOS_CMD_SMU_FW2 0x1a #define MBOX_BIOS_CMD_ABORT 0xfe -/* generic PSP interface status */ -#define STATUS_INITIALIZED 0x1 -#define STATUS_ERROR 0x2 -#define STATUS_TERMINATED 0x4 -#define STATUS_HALT 0x8 -#define STATUS_RECOVERY 0x10 +/* generic PSP interface status, v1 */ +#define PSPV1_STATUS_INITIALIZED BIT(0) +#define PSPV1_STATUS_ERROR BIT(1) +#define PSPV1_STATUS_TERMINATED BIT(2) +#define PSPV1_STATUS_HALT BIT(3) +#define PSPV1_STATUS_RECOVERY BIT(4) + +/* generic PSP interface status, v2 */ +#define PSPV2_STATUS_ERROR BIT(30) +#define PSPV2_STATUS_RECOVERY BIT(31) /* psp_mbox consists of hardware registers beginning at PSPx000070 * mbox_command: BIOS->PSP command, cleared by PSP when complete * mbox_status: BIOS->PSP interface status * cmd_response: pointer to command/response buffer */ -struct psp_mbox { +struct pspv1_mbox { u32 mbox_command; u32 mbox_status; u64 cmd_response; /* definition conflicts w/BKDG but matches agesa */ } __packed; +struct pspv2_mbox { + union { + u32 val; + struct pspv2_mbox_cmd_fields { + u16 mbox_status; + u8 mbox_command; + u32 reserved:6; + u32 recovery:1; + u32 ready:1; + } __packed fields; + }; + u64 cmd_response; +} __packed; + /* command/response format, BIOS builds this in memory * mbox_buffer_header: generic header * mbox_buffer: command-specific buffer format @@ -70,4 +89,7 @@ struct mbox_cmd_sx_info_buffer { #define PSP_INIT_TIMEOUT 10000 /* 10 seconds */ #define PSP_CMD_TIMEOUT 1000 /* 1 second */ +/* This command needs to be implemented by the generation specific code. */ +int send_psp_command(u32 command, void *buffer); + #endif /* __AMD_PSP_DEF_H__ */ diff --git a/src/soc/amd/common/block/psp/psp_gen1.c b/src/soc/amd/common/block/psp/psp_gen1.c new file mode 100644 index 0000000000..0e5aa30154 --- /dev/null +++ b/src/soc/amd/common/block/psp/psp_gen1.c @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* This file is part of the coreboot project. */ + +#include <device/mmio.h> +#include <timer.h> +#include <bootstate.h> +#include <amdblocks/psp.h> +#include <soc/iomap.h> +#include <soc/northbridge.h> +#include "psp_def.h" + +static u32 rd_mbox_sts(struct pspv1_mbox *mbox) +{ + return read32(&mbox->mbox_status); +} + +static void wr_mbox_cmd(struct pspv1_mbox *mbox, u32 cmd) +{ + write32(&mbox->mbox_command, cmd); +} + +static u32 rd_mbox_cmd(struct pspv1_mbox *mbox) +{ + return read32(&mbox->mbox_command); +} + +static void wr_mbox_cmd_resp(struct pspv1_mbox *mbox, void *buffer) +{ + write64(&mbox->cmd_response, (uintptr_t)buffer); +} + +static int wait_initialized(struct pspv1_mbox *mbox) +{ + struct stopwatch sw; + + stopwatch_init_msecs_expire(&sw, PSP_INIT_TIMEOUT); + + do { + if (rd_mbox_sts(mbox) & PSPV1_STATUS_INITIALIZED) + return 0; + } while (!stopwatch_expired(&sw)); + + return -PSPSTS_INIT_TIMEOUT; +} + +static int wait_command(struct pspv1_mbox *mbox) +{ + struct stopwatch sw; + + stopwatch_init_msecs_expire(&sw, PSP_CMD_TIMEOUT); + + do { + if (!rd_mbox_cmd(mbox)) + return 0; + } while (!stopwatch_expired(&sw)); + + return -PSPSTS_CMD_TIMEOUT; +} + +int send_psp_command(u32 command, void *buffer) +{ + struct pspv1_mbox *mbox = soc_get_mbox_address(); + if (!mbox) + return -PSPSTS_NOBASE; + + /* check for PSP error conditions */ + if (rd_mbox_sts(mbox) & PSPV1_STATUS_HALT) + return -PSPSTS_HALTED; + + if (rd_mbox_sts(mbox) & PSPV1_STATUS_RECOVERY) + return -PSPSTS_RECOVERY; + + /* PSP must be finished with init and ready to accept a command */ + if (wait_initialized(mbox)) + return -PSPSTS_INIT_TIMEOUT; + + if (wait_command(mbox)) + return -PSPSTS_CMD_TIMEOUT; + + /* set address of command-response buffer and write command register */ + wr_mbox_cmd_resp(mbox, buffer); + wr_mbox_cmd(mbox, command); + + /* PSP clears command register when complete */ + if (wait_command(mbox)) + return -PSPSTS_CMD_TIMEOUT; + + /* check delivery status */ + if (rd_mbox_sts(mbox) & (PSPV1_STATUS_ERROR | PSPV1_STATUS_TERMINATED)) + return -PSPSTS_SEND_ERROR; + + return 0; +} diff --git a/src/soc/amd/common/block/psp/psp_gen2.c b/src/soc/amd/common/block/psp/psp_gen2.c new file mode 100644 index 0000000000..b70babc14a --- /dev/null +++ b/src/soc/amd/common/block/psp/psp_gen2.c @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* This file is part of the coreboot project. */ + +#include <device/mmio.h> +#include <timer.h> +#include <bootstate.h> +#include <amdblocks/psp.h> +#include <soc/iomap.h> +#include <soc/northbridge.h> +#include "psp_def.h" + +static u16 rd_mbox_sts(struct pspv2_mbox *mbox) +{ + union { + u32 val; + struct pspv2_mbox_cmd_fields fields; + } tmp = { 0 }; + + tmp.val = read32(&mbox->val); + return tmp.fields.mbox_status; +} + +static void wr_mbox_cmd(struct pspv2_mbox *mbox, u8 cmd) +{ + union { + u32 val; + struct pspv2_mbox_cmd_fields fields; + } tmp = { 0 }; + + /* Write entire 32-bit area to begin command execution */ + tmp.fields.mbox_command = cmd; + write32(&mbox->val, tmp.val); +} + +static u8 rd_mbox_recovery(struct pspv2_mbox *mbox) +{ + union { + u32 val; + struct pspv2_mbox_cmd_fields fields; + } tmp = { 0 }; + + tmp.val = read32(&mbox->val); + return !!tmp.fields.recovery; +} + +static void wr_mbox_cmd_resp(struct pspv2_mbox *mbox, void *buffer) +{ + write64(&mbox->cmd_response, (uintptr_t)buffer); +} + +static int wait_command(struct pspv2_mbox *mbox, bool wait_for_ready) +{ + struct pspv2_mbox and_mask = { .val = ~0 }; + struct pspv2_mbox expected = { .val = 0 }; + struct stopwatch sw; + u32 tmp; + + /* Zero fields from and_mask that should be kept */ + and_mask.fields.mbox_command = 0; + and_mask.fields.ready = wait_for_ready ? 0 : 1; + + /* Expect mbox_cmd == 0 but ready depends */ + if (wait_for_ready) + expected.fields.ready = 1; + + stopwatch_init_msecs_expire(&sw, PSP_CMD_TIMEOUT); + + do { + tmp = read32(&mbox->val); + tmp &= ~and_mask.val; + if (tmp == expected.val) + return 0; + } while (!stopwatch_expired(&sw)); + + return -PSPSTS_CMD_TIMEOUT; +} + +int send_psp_command(u32 command, void *buffer) +{ + struct pspv2_mbox *mbox = soc_get_mbox_address(); + if (!mbox) + return -PSPSTS_NOBASE; + + if (rd_mbox_recovery(mbox)) + return -PSPSTS_RECOVERY; + + if (wait_command(mbox, true)) + return -PSPSTS_CMD_TIMEOUT; + + /* set address of command-response buffer and write command register */ + wr_mbox_cmd_resp(mbox, buffer); + wr_mbox_cmd(mbox, command); + + /* PSP clears command register when complete. All commands except + * SxInfo set the Ready bit. */ + if (wait_command(mbox, command != MBOX_BIOS_CMD_SX_INFO)) + return -PSPSTS_CMD_TIMEOUT; + + /* check delivery status */ + if (rd_mbox_sts(mbox)) + return -PSPSTS_SEND_ERROR; + + return 0; +} diff --git a/src/soc/amd/stoneyridge/Kconfig b/src/soc/amd/stoneyridge/Kconfig index 14615888e3..d73f3153e8 100644 --- a/src/soc/amd/stoneyridge/Kconfig +++ b/src/soc/amd/stoneyridge/Kconfig @@ -47,7 +47,7 @@ config CPU_SPECIFIC_OPTIONS select SOC_AMD_COMMON_BLOCK_HDA select SOC_AMD_COMMON_BLOCK_SATA select SOC_AMD_COMMON_BLOCK_PI - select SOC_AMD_COMMON_BLOCK_PSP + select SOC_AMD_COMMON_BLOCK_PSP_GEN1 select SOC_AMD_COMMON_BLOCK_CAR select SOC_AMD_COMMON_BLOCK_S3 select SOC_AMD_COMMON_BLOCK_SMBUS diff --git a/src/soc/amd/stoneyridge/psp.c b/src/soc/amd/stoneyridge/psp.c index bc2d725145..88bd61d4dd 100644 --- a/src/soc/amd/stoneyridge/psp.c +++ b/src/soc/amd/stoneyridge/psp.c @@ -30,7 +30,7 @@ void soc_enable_psp_early(void) pci_write_config32(SOC_PSP_DEV, PCI_COMMAND, cmd); }; -struct psp_mbox *soc_get_mbox_address(void) +void *soc_get_mbox_address(void) { uintptr_t psp_mmio; @@ -54,5 +54,5 @@ struct psp_mbox *soc_get_mbox_address(void) ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; } - return (struct psp_mbox *)(psp_mmio + PSP_MAILBOX_OFFSET); + return (void *)(psp_mmio + PSP_MAILBOX_OFFSET); } |