soc/amd/common/block/psp/psp_smi_flash: Fix flash busy check

Currently the PSP SMI handler works only if you are lucky. Since
ring 0 can start SPI flash transactions any time and the PSP SMI might
happen shortly after that, the SPI controller or SPI flash might be
busy. When the SPI flash is busy it cannot process certain commands,
for example reading the contents, causing the SPI flash memory map
to return all 0xffs.

By introducing the AMD fTPM code the PSP SMI happens more often at
boot and uncovered this issue. This issue was found when deleting
the MRC cache, which takes quite long, while the PSP SMI tried to
access the SPI flash. Adding small delays, as introduced by
CONSOLE_SERIAL, resolved the issue.

Add code to check if the SPI controller and the SPI flash are busy.
If so tell the PSP SMI to retry at a later point in time.

TEST: AMD glinda boots with CONSOLE_SERIAL disabled.
      Logging to CBMEM shows that the PSP SMI is fired 10 times
      before the SPI flash no longer reports that it's busy.

Signed-off-by: Patrick Rudolph <patrick.rudolph@amd.com>
Change-Id: I9122165e7c60b7c288d5b61b80d4cb582901841c
Reviewed-on: https://review.coreboot.org/c/coreboot/+/88437
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@mailbox.org>
Reviewed-by: Benjamin Doron <benjamin.doron00@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Patrick Rudolph 2025-07-15 09:54:39 +02:00 committed by Matt DeVillier
commit 038262155e
3 changed files with 40 additions and 11 deletions

View file

@ -70,6 +70,14 @@ enum spi100_speed {
#define SPI100_HOST_PREF_CONFIG 0x2c
#define SPI_RD4DW_EN_HOST BIT(15)
#define SPI_STATUS 0x4c
#define SPI_DONE_BYTE_COUNT_SHIFT 0
#define SPI_DONE_BYTE_COUNT_MASK 0xff
#define SPI_FIFO_WR_PTR_SHIFT 8
#define SPI_FIFO_WR_PTR_MASK 0x7f
#define SPI_FIFO_RD_PTR_SHIFT 16
#define SPI_FIFO_RD_PTR_MASK 0x7f
#define SPI_ROM_PAGE 0x5c
#define SPI_ROM_PAGE_SEL (BIT(0) | BIT(1))

View file

@ -96,14 +96,42 @@ static bool spi_controller_busy(void)
{
bool busy = false;
if (CONFIG(SOC_AMD_PICASSO)) {
/*
* When ring0 is operating on the SPI flash and the controller is
* busy, don't interrupt ongoing transfer.
*/
if (spi_read32(SPI_STATUS) & SPI_BUSY)
busy = true;
/*
* Even when the SPI controller is not busy, the SPI flash
* might be busy. When that's the case reading from the
* memory mapped SPI flash doesn't work and returns all 0xffs.
* Thus check if the SPI flash is busy.
*/
if (CONFIG(SPI_FLASH) && !busy) {
const struct spi_flash *spi_flash_dev;
uint8_t sr1 = 0;
spi_flash_dev = boot_device_spi_flash();
assert(spi_flash_dev);
if (spi_flash_dev) {
/* Read Status Register 1 */
if (spi_flash_status(spi_flash_dev, &sr1) < 0)
busy = true;
else if (sr1 & BIT(0))
busy = true;
}
}
if (CONFIG(SOC_AMD_PICASSO) && !busy) {
// Only implemented on Picasso and Raven Ridge
busy = (spi_read8(SPI_MISC_CNTRL) & SPI_SEMAPHORE_DRIVER_LOCKED);
if (busy)
printk(BIOS_NOTICE, "PSP: SPI controller busy\n");
}
if (busy)
printk(BIOS_NOTICE, "PSP: SPI controller or SPI flash busy\n");
return busy;
}

View file

@ -22,13 +22,6 @@
#define SPI_CMD_TRIGGER_EXECUTE BIT(7)
#define SPI_TX_BYTE_COUNT 0x48
#define SPI_RX_BYTE_COUNT 0x4b
#define SPI_STATUS 0x4c
#define SPI_DONE_BYTE_COUNT_SHIFT 0
#define SPI_DONE_BYTE_COUNT_MASK 0xff
#define SPI_FIFO_WR_PTR_SHIFT 8
#define SPI_FIFO_WR_PTR_MASK 0x7f
#define SPI_FIFO_RD_PTR_SHIFT 16
#define SPI_FIFO_RD_PTR_MASK 0x7f
enum spi_dump_state_phase {
SPI_DUMP_STATE_BEFORE_CMD,