summaryrefslogtreecommitdiff
path: root/src/soc/amd/common/block
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/amd/common/block')
-rw-r--r--src/soc/amd/common/block/psp/Kconfig7
-rw-r--r--src/soc/amd/common/block/psp/Makefile.mk1
-rw-r--r--src/soc/amd/common/block/psp/rpmc.c153
3 files changed, 161 insertions, 0 deletions
diff --git a/src/soc/amd/common/block/psp/Kconfig b/src/soc/amd/common/block/psp/Kconfig
index 4f5c6bbe9c..9262e47d7d 100644
--- a/src/soc/amd/common/block/psp/Kconfig
+++ b/src/soc/amd/common/block/psp/Kconfig
@@ -31,6 +31,13 @@ config SOC_AMD_PSP_SELECTABLE_SMU_FW
fanned set of blobs. Ask your AMD representative whether your APU
is considered fanless.
+config SOC_AMD_COMMON_BLOCK_PSP_RPMC
+ bool
+ depends on SOC_AMD_COMMON_BLOCK_PSP_GEN2
+ help
+ Select this option in the SoC's Kconfig to include the support for
+ the replay-protected monotonic counter (RPMC) feature.
+
config SOC_AMD_COMMON_BLOCK_PSP_SPL
bool
help
diff --git a/src/soc/amd/common/block/psp/Makefile.mk b/src/soc/amd/common/block/psp/Makefile.mk
index 937cb8e649..dc811f9098 100644
--- a/src/soc/amd/common/block/psp/Makefile.mk
+++ b/src/soc/amd/common/block/psp/Makefile.mk
@@ -34,6 +34,7 @@ smm-y += psp_gen2.c
smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_SMI) += psp_smi_flash_gen2.c
smm-y += psp_smm_gen2.c
+ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_RPMC) += rpmc.c
ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_SPL) += spl_fuse.c
endif # CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN2
diff --git a/src/soc/amd/common/block/psp/rpmc.c b/src/soc/amd/common/block/psp/rpmc.c
new file mode 100644
index 0000000000..3e5d5e0e7b
--- /dev/null
+++ b/src/soc/amd/common/block/psp/rpmc.c
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <bootstate.h>
+#include <console/console.h>
+#include <types.h>
+#include "psp_def.h"
+
+union psp_rpmc_caps {
+ struct {
+ uint32_t psp_nvram_healthy : 1; /* [ 0.. 0] */
+ uint32_t psp_nvram_rpmc_protected : 1; /* [ 1.. 1] */
+ uint32_t : 8; /* [ 2.. 9] */
+ uint32_t spi_rpmc_slots_available : 4; /* [10..13] */
+ uint32_t : 2; /* [14..15] */
+ uint32_t spi_rpmc_slot_used : 4; /* [16..19] */
+ uint32_t psp_rpmc_slot_available : 4; /* [20..23] */
+ uint32_t : 6; /* [24..29] */
+ uint32_t psp_rpmc_revision : 2; /* [30..31] */
+ } r0; /* RPMC revision 0: 4 RPMC fuse slots in SoC */
+ struct {
+ uint32_t psp_nvram_healthy : 1; /* [ 0.. 0] */
+ uint32_t psp_nvram_rpmc_protected : 1; /* [ 1.. 1] */
+ uint32_t : 8; /* [ 2.. 9] */
+ uint32_t spi_rpmc_slots_available : 4; /* [10..13] */
+ uint32_t : 2; /* [14..15] */
+ uint32_t spi_rpmc_slot_used : 4; /* [16..19] */
+ uint32_t psp_rpmc_first_slot_available : 7; /* [20..26] */
+ uint32_t psp_rpmc_all_slots_used : 1; /* [27..27] */
+ uint32_t : 2; /* [28..29] */
+ uint32_t psp_rpmc_revision : 2; /* [30..31] */
+ } r1; /* RPMC revison 1: 16 RPMC fuse slots in SoC */
+ uint32_t raw;
+};
+
+enum psp_rpmc_revision {
+ PSP_RPMC_REVISION_0 = 0,
+ PSP_RPMC_REVISION_1 = 1,
+};
+
+#define HSTI_STATE_RPMC_PRODUCTION_ENABLED BIT(8)
+#define HSTI_STATE_RPMC_SPI_PRESENT BIT(9)
+
+static bool is_hsti_rpmc_provisioned(uint32_t hsti_state)
+{
+ return hsti_state & HSTI_STATE_RPMC_PRODUCTION_ENABLED;
+}
+
+static bool is_hsti_rpmc_spi_present(uint32_t hsti_state)
+{
+ return hsti_state & HSTI_STATE_RPMC_SPI_PRESENT;
+}
+
+static void print_hsti_rpmc_state(uint32_t hsti_state)
+{
+ printk(BIOS_SPEW, "RPMC %s provisioned\n",
+ is_hsti_rpmc_provisioned(hsti_state) ? "is" : "isn't");
+ printk(BIOS_SPEW, "SPI flash %s RPMC\n",
+ is_hsti_rpmc_spi_present(hsti_state) ? "supports" : "doesn't support");
+}
+
+static enum psp_rpmc_revision get_rpmc_rev(union psp_rpmc_caps psp_caps)
+{
+ /* Since the PSP RPMC revision field is in the same location for both revision 0 and 1,
+ we can usethe r0 struct in both cases for this */
+ return (enum psp_rpmc_revision)psp_caps.r0.psp_rpmc_revision;
+}
+
+static void print_rpmc_general_status(uint8_t healthy, uint8_t rpmc_protected)
+{
+ printk(BIOS_SPEW, "PSP NVRAM %s healthy\n", healthy ? "is" : "isn't");
+ printk(BIOS_SPEW, "PSP NVRAM %s using RPMC protection\n",
+ rpmc_protected ? "is" : " isn't");
+}
+
+#define SPI_RPMC_COUNTER_COUNT 4
+
+static void print_spi_rpmc_usage(uint8_t available, uint8_t used)
+{
+ for (size_t i = 0; i < SPI_RPMC_COUNTER_COUNT; i++) {
+ printk(BIOS_SPEW, "SPI flash RPMC counter %ld %s provisioned\n", i,
+ available & BIT(i) ? "can still be" : "has already been");
+ }
+
+ for (size_t i = 0; i < SPI_RPMC_COUNTER_COUNT; i++) {
+ printk(BIOS_SPEW, "SPI flash RPMC counter %ld is%s in use\n", i,
+ used & BIT(i) ? "" : " not");
+ }
+}
+
+#define PSP_RPMC_R0_SLOT_COUNT 4
+
+static void print_rpmc_rev0_status(union psp_rpmc_caps psp_caps)
+{
+ print_rpmc_general_status(psp_caps.r0.psp_nvram_healthy,
+ psp_caps.r0.psp_nvram_rpmc_protected);
+ print_spi_rpmc_usage(psp_caps.r0.spi_rpmc_slots_available,
+ psp_caps.r0.spi_rpmc_slot_used);
+ for (size_t i = 0; i < PSP_RPMC_R0_SLOT_COUNT; i++) {
+ printk(BIOS_SPEW, "SoC RPMC slot %ld %s provisioned\n", i,
+ psp_caps.r0.psp_rpmc_slot_available & BIT(i) ? "can still be" :
+ "has already been");
+ }
+}
+
+static void print_rpmc_rev1_status(union psp_rpmc_caps psp_caps)
+{
+ print_rpmc_general_status(psp_caps.r1.psp_nvram_healthy,
+ psp_caps.r1.psp_nvram_rpmc_protected);
+ print_spi_rpmc_usage(psp_caps.r1.spi_rpmc_slots_available,
+ psp_caps.r1.spi_rpmc_slot_used);
+ if (psp_caps.r1.psp_rpmc_all_slots_used) {
+ printk(BIOS_SPEW, "All SoC RPMC slots already used\n");
+ } else {
+ printk(BIOS_SPEW, "First available SoC RPMC slot is %d\n",
+ psp_caps.r1.psp_rpmc_first_slot_available);
+ }
+}
+
+static void psp_rpmc_report_status(union psp_rpmc_caps psp_caps, uint32_t hsti_state)
+{
+ const enum psp_rpmc_revision rev = get_rpmc_rev(psp_caps);
+
+ print_hsti_rpmc_state(hsti_state);
+
+ printk(BIOS_SPEW, "RPMC revision %d\n", rev);
+
+ switch (rev) {
+ case PSP_RPMC_REVISION_0:
+ print_rpmc_rev0_status(psp_caps);
+ break;
+ case PSP_RPMC_REVISION_1:
+ print_rpmc_rev1_status(psp_caps);
+ break;
+ default:
+ printk(BIOS_WARNING, "Unexpected RPMC revision\n");
+ }
+}
+
+static void psp_rpmc_configuration(void *unused)
+{
+ union psp_rpmc_caps psp_caps;
+ uint32_t hsti_state;
+
+ if (psp_get_psp_capabilities(&psp_caps.raw) != CB_SUCCESS ||
+ psp_get_hsti_state(&hsti_state) != CB_SUCCESS) {
+ printk(BIOS_ERR, "Getting RPMC state from PSP failed.\n");
+ return;
+ }
+
+ psp_rpmc_report_status(psp_caps, hsti_state);
+}
+
+BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_ENTRY, psp_rpmc_configuration, NULL);