From 038262155e3105cb66027978aaab4c480321a0cb Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Tue, 15 Jul 2025 09:54:39 +0200 Subject: [PATCH] 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 Change-Id: I9122165e7c60b7c288d5b61b80d4cb582901841c Reviewed-on: https://review.coreboot.org/c/coreboot/+/88437 Reviewed-by: Angel Pons Reviewed-by: Paul Menzel Reviewed-by: Benjamin Doron Tested-by: build bot (Jenkins) --- .../amd/common/block/include/amdblocks/spi.h | 8 +++++ src/soc/amd/common/block/psp/psp_smi_flash.c | 36 ++++++++++++++++--- src/soc/amd/common/block/spi/fch_spi_ctrl.c | 7 ---- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/soc/amd/common/block/include/amdblocks/spi.h b/src/soc/amd/common/block/include/amdblocks/spi.h index 83d09e90d7..70de548bf7 100644 --- a/src/soc/amd/common/block/include/amdblocks/spi.h +++ b/src/soc/amd/common/block/include/amdblocks/spi.h @@ -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)) diff --git a/src/soc/amd/common/block/psp/psp_smi_flash.c b/src/soc/amd/common/block/psp/psp_smi_flash.c index 9f9f31d94c..7e0328330c 100644 --- a/src/soc/amd/common/block/psp/psp_smi_flash.c +++ b/src/soc/amd/common/block/psp/psp_smi_flash.c @@ -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; } diff --git a/src/soc/amd/common/block/spi/fch_spi_ctrl.c b/src/soc/amd/common/block/spi/fch_spi_ctrl.c index aa07542a54..95b68ff050 100644 --- a/src/soc/amd/common/block/spi/fch_spi_ctrl.c +++ b/src/soc/amd/common/block/spi/fch_spi_ctrl.c @@ -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,