aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/amd/common/block/include/amdblocks/psp.h2
-rw-r--r--src/soc/amd/common/block/psp/Kconfig13
-rw-r--r--src/soc/amd/common/block/psp/Makefile.inc11
-rw-r--r--src/soc/amd/common/block/psp/psp.c85
-rw-r--r--src/soc/amd/common/block/psp/psp_def.h36
-rw-r--r--src/soc/amd/common/block/psp/psp_gen1.c93
-rw-r--r--src/soc/amd/common/block/psp/psp_gen2.c104
-rw-r--r--src/soc/amd/stoneyridge/Kconfig2
-rw-r--r--src/soc/amd/stoneyridge/psp.c4
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);
}