summaryrefslogtreecommitdiff
path: root/src/soc/amd
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/amd')
-rw-r--r--src/soc/amd/common/block/psp/Kconfig9
-rw-r--r--src/soc/amd/common/block/psp/psp_def.h7
-rw-r--r--src/soc/amd/common/block/psp/rpmc.c99
3 files changed, 115 insertions, 0 deletions
diff --git a/src/soc/amd/common/block/psp/Kconfig b/src/soc/amd/common/block/psp/Kconfig
index 9262e47d7d..3ae5e439f6 100644
--- a/src/soc/amd/common/block/psp/Kconfig
+++ b/src/soc/amd/common/block/psp/Kconfig
@@ -38,6 +38,15 @@ config SOC_AMD_COMMON_BLOCK_PSP_RPMC
Select this option in the SoC's Kconfig to include the support for
the replay-protected monotonic counter (RPMC) feature.
+config PERFORM_RPMC_PROVISIONING
+ bool "Send RPMC fusing command to PSP"
+ default n
+ depends on SOC_AMD_COMMON_BLOCK_PSP_RPMC
+ help
+ Send the RPMC root key provisioning command to the PSP in case it's
+ not already fused. Sending this command will fuse the silicon which
+ is a permanent change.
+
config SOC_AMD_COMMON_BLOCK_PSP_SPL
bool
help
diff --git a/src/soc/amd/common/block/psp/psp_def.h b/src/soc/amd/common/block/psp/psp_def.h
index d1f57ac19c..d11199db39 100644
--- a/src/soc/amd/common/block/psp/psp_def.h
+++ b/src/soc/amd/common/block/psp/psp_def.h
@@ -27,6 +27,7 @@
#define MBOX_BIOS_CMD_PSB_AUTO_FUSING 0x21
#define MBOX_BIOS_CMD_PSP_CAPS_QUERY 0x27
#define MBOX_BIOS_CMD_SET_SPL_FUSE 0x2d
+#define MBOX_BIOS_CMD_SET_RPMC_ADDRESS 0x39
#define MBOX_BIOS_CMD_QUERY_SPL_FUSE 0x47
#define MBOX_BIOS_CMD_I2C_TPM_ARBITRATION 0x64
#define MBOX_BIOS_CMD_ABORT 0xfe
@@ -98,6 +99,12 @@ struct mbox_cmd_hsti_query_buffer {
uint32_t state;
} __packed __aligned(32);
+/* MBOX_BIOS_CMD_SET_RPMC_ADDRESS */
+struct mbox_cmd_set_rpmc_address_buffer {
+ struct mbox_buffer_header header;
+ uint32_t address;
+} __packed __aligned(32);
+
/* MBOX_BIOS_CMD_SET_SPL_FUSE */
struct mbox_cmd_late_spl_buffer {
struct mbox_buffer_header header;
diff --git a/src/soc/amd/common/block/psp/rpmc.c b/src/soc/amd/common/block/psp/rpmc.c
index 3e5d5e0e7b..a557459854 100644
--- a/src/soc/amd/common/block/psp/rpmc.c
+++ b/src/soc/amd/common/block/psp/rpmc.c
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
+#include <amdblocks/reset.h>
#include <bootstate.h>
#include <console/console.h>
#include <types.h>
@@ -136,6 +137,101 @@ static void psp_rpmc_report_status(union psp_rpmc_caps psp_caps, uint32_t hsti_s
}
}
+static bool is_psp_rpmc_slot_available(union psp_rpmc_caps psp_caps)
+{
+ const enum psp_rpmc_revision rev = get_rpmc_rev(psp_caps);
+
+ switch (rev) {
+ case PSP_RPMC_REVISION_0:
+ /*
+ * psp_rpmc_slot_available doesn't contain the number of available slots, but
+ * one bit for each slot. When none of those bits is set, there are no usable
+ * slots any more
+ */
+ return psp_caps.r0.psp_rpmc_slot_available != 0;
+ case PSP_RPMC_REVISION_1:
+ return !psp_caps.r1.psp_rpmc_all_slots_used;
+ default:
+ return false;
+ }
+}
+
+static enum cb_err get_first_available_spi_rpmc_counter(union psp_rpmc_caps psp_caps,
+ uint32_t *rpmc_counter_address)
+{
+ const enum psp_rpmc_revision rev = get_rpmc_rev(psp_caps);
+ uint8_t spi_rpmc_available;
+ unsigned int i;
+
+ switch (rev) {
+ case PSP_RPMC_REVISION_0:
+ spi_rpmc_available = psp_caps.r0.spi_rpmc_slots_available;
+ break;
+ case PSP_RPMC_REVISION_1:
+ spi_rpmc_available = psp_caps.r1.spi_rpmc_slots_available;
+ break;
+ default:
+ return CB_ERR;
+ }
+
+ for (i = 0; i < SPI_RPMC_COUNTER_COUNT; i++) {
+ if (spi_rpmc_available & BIT(i)) {
+ *rpmc_counter_address = i;
+ return CB_SUCCESS;
+ }
+ }
+
+ /* No RPMC counter available any more in the SPI flash */
+ return CB_ERR;
+}
+
+static void psp_rpmc_provision(union psp_rpmc_caps psp_caps, uint32_t hsti_state)
+{
+ uint32_t rpmc_counter_addr = 0;
+
+ if (is_hsti_rpmc_provisioned(hsti_state))
+ return;
+
+ if (!is_hsti_rpmc_spi_present(hsti_state)) {
+ printk(BIOS_ERR, "SPI flash doesn't support RPMC\n");
+ return;
+ }
+
+ if (!is_psp_rpmc_slot_available(psp_caps)) {
+ printk(BIOS_ERR, "No more RPMC provisioning slots available on this SoC\n");
+ return;
+ }
+
+ if (get_first_available_spi_rpmc_counter(psp_caps, &rpmc_counter_addr) != CB_SUCCESS) {
+ printk(BIOS_ERR,
+ "No more RPMC conters available for provisioning in the SPI flash\n");
+ return;
+ }
+
+ struct mbox_cmd_set_rpmc_address_buffer buffer = {
+ .header = {
+ .size = sizeof(buffer)
+ },
+ .address = rpmc_counter_addr,
+ };
+
+ printk(BIOS_DEBUG, "RPMC: perform fusing using RPMC counter address %d\n",
+ rpmc_counter_addr);
+
+ const int cmd_status = send_psp_command(MBOX_BIOS_CMD_SET_RPMC_ADDRESS, &buffer);
+
+ psp_print_cmd_status(cmd_status, &buffer.header);
+
+ if (cmd_status) {
+ printk(BIOS_ERR, "RPMC: Fusing request failed\n");
+ return;
+ }
+
+ printk(BIOS_NOTICE, "RPMC: Rebooting\n");
+ /* Reboot so that the PSP will do the actual provisioning and fusing */
+ warm_reset();
+}
+
static void psp_rpmc_configuration(void *unused)
{
union psp_rpmc_caps psp_caps;
@@ -148,6 +244,9 @@ static void psp_rpmc_configuration(void *unused)
}
psp_rpmc_report_status(psp_caps, hsti_state);
+
+ if (CONFIG(PERFORM_RPMC_PROVISIONING))
+ psp_rpmc_provision(psp_caps, hsti_state);
}
BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_ENTRY, psp_rpmc_configuration, NULL);