diff --git a/hal/tpm_io_uboot.c b/hal/tpm_io_uboot.c index 22cc66e9..2ce68be5 100644 --- a/hal/tpm_io_uboot.c +++ b/hal/tpm_io_uboot.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -/* This example shows IO interfaces for U-boot */ +/* This example shows IO interfaces for U-boot using raw SPI */ #include #include @@ -43,36 +43,162 @@ #if defined(__UBOOT__) #include + #include + #include + #include + + /* SPI bus and chip select configuration for TPM + * These can be overridden in user_settings.h or board config */ + #ifndef TPM_SPI_BUS + #define TPM_SPI_BUS 0 + #endif + #ifndef TPM_SPI_CS + #define TPM_SPI_CS 0 + #endif + #ifndef TPM_SPI_MAX_HZ + #define TPM_SPI_MAX_HZ 1000000 /* 1 MHz - safe default */ + #endif + #define TPM_SPI_MODE SPI_MODE_0 /* Mode 0 (CPOL=0, CPHA=0) */ + + /* Maximum SPI frame size */ + #define MAX_SPI_FRAMESIZE 64 + + /* Static SPI device handles */ + static struct udevice *g_spi_bus = NULL; + static struct spi_slave *g_spi_slave = NULL; + static int g_spi_initialized = 0; + + /* Initialize SPI for TPM communication */ + static int uboot_spi_init(void) + { + int ret; + + if (g_spi_initialized) { + return 0; /* Already initialized */ + } + + /* Get SPI bus and slave device */ + ret = spi_get_bus_and_cs(TPM_SPI_BUS, TPM_SPI_CS, + &g_spi_bus, &g_spi_slave); + if (ret != 0) { + #ifdef DEBUG_WOLFTPM + printf("Failed to get SPI bus %d cs %d: %d\n", + TPM_SPI_BUS, TPM_SPI_CS, ret); + #endif + return ret; + } + + g_spi_initialized = 1; + + #ifdef DEBUG_WOLFTPM + printf("TPM SPI initialized: bus %d, cs %d\n", TPM_SPI_BUS, TPM_SPI_CS); + #endif + + return 0; + } + + /* Raw SPI transfer for wolfTPM TIS layer + * This is called by wolfTPM's TIS implementation for register read/write. + * The txBuf/rxBuf contain TIS-formatted SPI data including the 4-byte header. + */ int TPM2_IoCb_Uboot_SPI(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf, word16 xferSz, void* userCtx) { - int ret = 0; - struct udevice *dev; + int ret; + #ifdef WOLFTPM_CHECK_WAIT_STATE + int timeout = TPM_SPI_WAIT_RETRY; + byte tmp_rx; + #endif - /* Get the TPM device */ - if (ret == 0) { - ret = tcg2_platform_get_tpm2(&dev); - if ( ret != 0 || dev == NULL) { - #ifdef DEBUG_WOLFTPM - printf("Failed to get TPM device with error: %d\n", ret); - #endif - return TPM_RC_FAILURE; - } + (void)ctx; + (void)userCtx; + + /* Initialize SPI if needed */ + ret = uboot_spi_init(); + if (ret != 0) { + return TPM_RC_FAILURE; + } + + /* Claim the SPI bus */ + ret = spi_claim_bus(g_spi_slave); + if (ret != 0) { + #ifdef DEBUG_WOLFTPM + printf("Failed to claim SPI bus: %d\n", ret); + #endif + return TPM_RC_FAILURE; + } + + #ifdef WOLFTPM_CHECK_WAIT_STATE + /* Send TIS header first (4 bytes) with CS held */ + ret = spi_xfer(g_spi_slave, TPM_TIS_HEADER_SZ * 8, + txBuf, rxBuf, SPI_XFER_BEGIN); + if (ret != 0) { + #ifdef DEBUG_WOLFTPM + printf("SPI header xfer failed: %d\n", ret); + #endif + goto cleanup; } - /* Transfer the device data using tpm_xfer */ - if (ret == 0) { - ret = tpm_xfer(dev, txBuf, xferSz, rxBuf, &xferSz); - if (ret != 0) { + /* Check for wait state - TPM holds ready bit low if busy */ + if ((rxBuf[TPM_TIS_HEADER_SZ - 1] & TPM_TIS_READY_MASK) == 0) { + /* Poll for ready */ + do { + ret = spi_xfer(g_spi_slave, 8, NULL, &tmp_rx, 0); + if (ret != 0) { + break; + } + if (tmp_rx & TPM_TIS_READY_MASK) { + break; + } + } while (--timeout > 0); + + if (timeout <= 0 || ret != 0) { #ifdef DEBUG_WOLFTPM - printf("tpm_xfer failed with error: %d\n", ret); + printf("SPI wait state timeout\n"); #endif - return TPM_RC_FAILURE; + /* Deassert CS */ + spi_xfer(g_spi_slave, 0, NULL, NULL, SPI_XFER_END); + ret = TPM_RC_FAILURE; + goto cleanup; } } - return TPM_RC_SUCCESS; + /* Transfer remainder of data with CS deasserted at end */ + if (xferSz > TPM_TIS_HEADER_SZ) { + ret = spi_xfer(g_spi_slave, (xferSz - TPM_TIS_HEADER_SZ) * 8, + &txBuf[TPM_TIS_HEADER_SZ], + &rxBuf[TPM_TIS_HEADER_SZ], + SPI_XFER_END); + } else { + /* Just deassert CS if no more data */ + ret = spi_xfer(g_spi_slave, 0, NULL, NULL, SPI_XFER_END); + } + + #else + /* No wait state handling - send entire message at once + * This works for Infineon TPMs (SLB9670/SLB9672) which guarantee + * no wait states */ + ret = spi_xfer(g_spi_slave, xferSz * 8, txBuf, rxBuf, + SPI_XFER_BEGIN | SPI_XFER_END); + #endif /* WOLFTPM_CHECK_WAIT_STATE */ + + if (ret != 0) { + #ifdef DEBUG_WOLFTPM + printf("SPI xfer failed: %d\n", ret); + #endif + ret = TPM_RC_FAILURE; + } else { + ret = TPM_RC_SUCCESS; + } + + #ifdef WOLFTPM_CHECK_WAIT_STATE + cleanup: + #endif + spi_release_bus(g_spi_slave); + + return ret; } + #endif /* __UBOOT__ */ #endif /* WOLFTPM_LINUX_DEV || WOLFTPM_SWTPM || WOLFTPM_WINAPI */ #endif /* WOLFTPM_INCLUDE_IO_FILE */ diff --git a/src/tpm2.c b/src/tpm2.c index 1e998278..b86aa904 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -729,7 +729,7 @@ TPM_RC TPM2_Cleanup(TPM2_CTX* ctx) } #endif /* !WOLFTPM2_NO_WOLFCRYPT */ -#ifdef WOLFTPM_LINUX_DEV +#if defined(WOLFTPM_LINUX_DEV) && !defined(__UBOOT__) if (ctx->fd >= 0) close(ctx->fd); #endif