soc/intel/fast_spi: Check SPI Cycle In-Progress prior start HW Seq

This fixes no practical problem, especially for coreboot where only
one process should access the SPI controller. It makes the code look
more spec compliant.

As per EDS, SPI controller sets the HSFSTS.bit5 (SCIP) when software
sets the Flash Cycle Go (FGO) bit in the Hardware Sequencing Flash
Control register.

Software must initiate the next SPI transaction when this bit is 0.

Add non-blocking mechanism with `5sec` timeout to report back error
if current SPI transaction is failing due to on-going SPI access.

BUG=b:215255210
TEST=Able to boot brya and verified SPI read/write is successful.

Signed-off-by: Subrata Banik <subratabanik@google.com>
Change-Id: I4d35058244a73e77f6204c4d04d09bae9e5ac62c
Reviewed-on: https://review.coreboot.org/c/coreboot/+/61849
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nick Vaccaro <nvaccaro@google.com>
Reviewed-by: Edward O'Callaghan <quasisec@chromium.org>
Reviewed-by: Maulik V Vaghela <maulik.v.vaghela@intel.com>
This commit is contained in:
Subrata Banik 2022-02-11 13:58:31 +05:30 committed by Felix Held
parent 737ad67d12
commit 4de2c342fb
1 changed files with 23 additions and 0 deletions

View File

@ -129,11 +129,34 @@ static int wait_for_hwseq_xfer(struct fast_spi_flash_ctx *ctx,
return E_TIMEOUT; return E_TIMEOUT;
} }
static int wait_for_hwseq_spi_cycle_complete(struct fast_spi_flash_ctx *ctx)
{
struct stopwatch sw;
uint32_t hsfsts;
stopwatch_init_msecs_expire(&sw, SPIBAR_HWSEQ_XFER_TIMEOUT_MS);
do {
hsfsts = fast_spi_flash_ctrlr_reg_read(ctx, SPIBAR_HSFSTS_CTL);
if (!(hsfsts & SPIBAR_HSFSTS_SCIP))
return SUCCESS;
} while (!(stopwatch_expired(&sw)));
return E_TIMEOUT;
}
/* Execute FAST_SPI flash transfer. This is a blocking call. */ /* Execute FAST_SPI flash transfer. This is a blocking call. */
static int exec_sync_hwseq_xfer(struct fast_spi_flash_ctx *ctx, static int exec_sync_hwseq_xfer(struct fast_spi_flash_ctx *ctx,
uint32_t hsfsts_cycle, uint32_t flash_addr, uint32_t hsfsts_cycle, uint32_t flash_addr,
size_t len) size_t len)
{ {
if (wait_for_hwseq_spi_cycle_complete(ctx) != SUCCESS) {
printk(BIOS_ERR, "SPI Transaction Timeout (Exceeded %d ms) due to prior"
" operation at Flash Offset %x\n",
SPIBAR_HWSEQ_XFER_TIMEOUT_MS, flash_addr);
return E_TIMEOUT;
}
start_hwseq_xfer(ctx, hsfsts_cycle, flash_addr, len); start_hwseq_xfer(ctx, hsfsts_cycle, flash_addr, len);
return wait_for_hwseq_xfer(ctx, flash_addr); return wait_for_hwseq_xfer(ctx, flash_addr);
} }