diff options
Diffstat (limited to 'src/soc/amd/common/block/psp/rpmc.c')
-rw-r--r-- | src/soc/amd/common/block/psp/rpmc.c | 99 |
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); |