summaryrefslogtreecommitdiff
path: root/src/soc/amd/common/block/psp/rpmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/amd/common/block/psp/rpmc.c')
-rw-r--r--src/soc/amd/common/block/psp/rpmc.c99
1 files changed, 99 insertions, 0 deletions
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);