From d086604c0b4631b89ae37afacf44c92bbd651afb Mon Sep 17 00:00:00 2001 From: philljj Date: Tue, 2 Apr 2024 11:42:42 -0500 Subject: [PATCH 1/2] Implementation for TPM2_IoCb_MicrochipHarmony_I2C. --- hal/tpm_io.c | 3 + hal/tpm_io.h | 3 + hal/tpm_io_microchip.c | 226 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 229 insertions(+), 3 deletions(-) diff --git a/hal/tpm_io.c b/hal/tpm_io.c index d6faba18..3bf502c3 100644 --- a/hal/tpm_io.c +++ b/hal/tpm_io.c @@ -140,6 +140,9 @@ int TPM2_IoCb(TPM2_CTX* ctx, INT32 isRead, UINT32 addr, #elif defined(WOLFSSL_STM32_CUBEMX) /* Use STM32 CubeMX HAL for I2C */ ret = TPM2_IoCb_STCubeMX_I2C(ctx, isRead, addr, buf, size, userCtx); + #elif defined(WOLFTPM_MICROCHIP_HARMONY) + /* Use MicrochipHarmony I2C */ + ret = TPM2_IoCb_MicrochipHarmony_I2C(ctx, isRead, addr, buf, size, userCtx); #else /* TODO: Add your platform here for HW I2C interface */ printf("Add your platform here for HW I2C interface\n"); diff --git a/hal/tpm_io.h b/hal/tpm_io.h index 402412bc..7ca11de5 100644 --- a/hal/tpm_io.h +++ b/hal/tpm_io.h @@ -82,6 +82,9 @@ WOLFTPM_LOCAL int TPM2_IoCb_Linux_I2C(TPM2_CTX* ctx, int isRead, word32 addr, by #elif defined(WOLFSSL_STM32_CUBEMX) WOLFTPM_LOCAL int TPM2_IoCb_STCubeMX_I2C(TPM2_CTX* ctx, int isRead, word32 addr, byte* buf, word16 size, void* userCtx); +#elif defined(WOLFTPM_MICROCHIP_HARMONY) +WOLFTPM_LOCAL int TPM2_IoCb_MicrochipHarmony_I2C(TPM2_CTX* ctx, int isRead, word32 addr, + byte* buf, word16 size, void* userCtx); #endif /* __linux__ */ #else /* SPI */ diff --git a/hal/tpm_io_microchip.c b/hal/tpm_io_microchip.c index 178963ff..76d4f6bf 100644 --- a/hal/tpm_io_microchip.c +++ b/hal/tpm_io_microchip.c @@ -49,13 +49,232 @@ #if defined(WOLFTPM_MICROCHIP_HARMONY) +#include "configuration.h" +#include "definitions.h" + +#ifdef WOLFTPM_I2C /* Microchip Harmony Hal I2C */ + /* We are using the I2C bitbang library. */ + #include + /* Use sys_time to implement delay. */ + #include "system/time/sys_time.h" + + #ifndef TPM_I2C_TRIES + #define TPM_I2C_TRIES 10 + #endif + #ifndef TPM2_I2C_ADDR + #define TPM2_I2C_ADDR 0x2e + #endif + + static uintptr_t dummy_context; + + static void dummy_callback(uintptr_t context) + { + (void) context; + return; + } + + /* Wait for time_ms using Micochip Harmony SYS_TIME API. */ + static void microchip_wait(uint32_t time_ms) + { + /* Microchip Harmony example from documentation. + * SYS_TIME_DelayMS will internally create the timer, + * and SYS_TIME_DelayIsComplete will delete it when + * the delay has completed. */ + SYS_TIME_HANDLE timer = SYS_TIME_HANDLE_INVALID; + + if (SYS_TIME_DelayMS(time_ms, &timer) != SYS_TIME_SUCCESS) { + printf("error: microchip_wait: SYS_TIME_DelayMS failed\n"); + } + else if(SYS_TIME_DelayIsComplete(timer) != true) { + /* Loop until delay is complete. */ + while (SYS_TIME_DelayIsComplete(timer) == false); + } + + return; + } + + /* Microchip Harmony I2C */ + static int i2c_read(void* userCtx, word32 reg, byte* data, int len) + { + int ret = TPM_RC_FAILURE; + I2CBB_ERROR status = I2CBB_ERROR_NONE; + bool queued = false; + int timeout = TPM_I2C_TRIES; + int busy_retry = TPM_I2C_TRIES; + byte buf[1]; + + if (I2C_BB_IsBusy()) { + printf("error: i2c_read: already busy\n"); + return -1; + } + + /* TIS layer should never provide a buffer larger than this, + but double check for good coding practice */ + if (len > MAX_SPI_FRAMESIZE) { + printf("error: i2c_read: len too large: %d\n", len); + return BAD_FUNC_ARG; + } + + buf[0] = (reg & 0xFF); /* convert to simple 8-bit address for I2C */ + + do { + /* Queue the write with I2C_BB. */ + queued = I2C_BB_Write(TPM2_I2C_ADDR, buf, sizeof(buf)); + + if (!queued) { + printf("error: i2c_read: I2C_BB_Write failed\n"); + return -1; + } + + busy_retry = TPM_I2C_TRIES; + + while (I2C_BB_IsBusy() && --busy_retry > 0) { + microchip_wait(250); + } + + if (I2C_BB_IsBusy()) { + printf("error: i2c_read: busy wait timed out\n"); + return -1; + } + + status = I2C_BB_ErrorGet(); + if (status == I2CBB_ERROR_NAK) { + microchip_wait(250); + } + } while (status == I2CBB_ERROR_NAK && --timeout > 0); + + if (status != I2CBB_ERROR_NONE) { + if (status == I2CBB_ERROR_NAK) { + printf("error: i2c_read: I2C_BB_Write failed with NAK: %d\n", + status); + } + else { + printf("error: i2c_read: I2C_BB_Write failed: %d\n", status); + } + + return -1; + } + + timeout = TPM_I2C_TRIES; + + do { + /* Queue the read with I2C_BB. */ + queued = I2C_BB_Read(TPM2_I2C_ADDR, data, len); + + if (!queued) { + printf("error: i2c_read: I2C_BB_Read failed\n"); + return -1; + } + + busy_retry = TPM_I2C_TRIES; + + while (I2C_BB_IsBusy() && --busy_retry > 0) { + microchip_wait(250); + } + + status = I2C_BB_ErrorGet(); + if (status == I2CBB_ERROR_NAK) { + microchip_wait(250); + } + } while (status == I2CBB_ERROR_NAK && --timeout > 0); + + if (status == I2CBB_ERROR_NONE) { + ret = TPM_RC_SUCCESS; + } + else { + printf("error: I2C Read failure %d (tries %d)\n", + status, TPM_I2C_TRIES - timeout); + } + + return ret; + } + + static int i2c_write(void* userCtx, word32 reg, byte* data, int len) + { + int ret = TPM_RC_FAILURE; + I2CBB_ERROR status = I2CBB_ERROR_NONE; + bool queued = false; + int timeout = TPM_I2C_TRIES; + int busy_retry = TPM_I2C_TRIES; + byte buf[MAX_SPI_FRAMESIZE+1]; + + /* TIS layer should never provide a buffer larger than this, + but double check for good coding practice */ + if (len > MAX_SPI_FRAMESIZE) { + printf("error: i2c_write: len too large: %d\n", len); + return BAD_FUNC_ARG; + } + + if (I2C_BB_IsBusy()) { + printf("error: i2c_write: already busy\n"); + return -1; + } + + /* Build packet with TPM register and data */ + buf[0] = (reg & 0xFF); /* convert to simple 8-bit address for I2C */ + XMEMCPY(buf + 1, data, len); + + do { + /* Queue the write with I2C_BB. */ + //queued = I2C_BB_Write(i2cAddr, buf, len + 1); + queued = I2C_BB_Write(TPM2_I2C_ADDR, buf, len + 1); + + if (!queued) { + printf("error: i2c_write: I2C_BB_Write failed: %d\n", status); + return -1; + } + + while (I2C_BB_IsBusy() && --busy_retry > 0) { + microchip_wait(250); + } + + status = I2C_BB_ErrorGet(); + + if (status == I2CBB_ERROR_NAK) { + microchip_wait(250); + } + } while (status == I2CBB_ERROR_NAK && --timeout > 0); + + if (status == I2CBB_ERROR_NONE) { + ret = TPM_RC_SUCCESS; + } + else { + printf("I2C Write failure %d\n", status); + } + return ret; + } + + int TPM2_IoCb_MicrochipHarmony_I2C(TPM2_CTX* ctx, int isRead, word32 addr, + byte* buf, word16 size, void* userCtx) + { + int ret = TPM_RC_FAILURE; + + /* Set callback to null to do time based polling of + * I2C_BB_IsBusy instead. + * + * Note: Apparently a callback is actually required. + * */ + I2C_BB_Initialize(); + I2C_BB_CallbackRegister(dummy_callback, dummy_context); + + if (isRead) { + ret = i2c_read(userCtx, addr, buf, size); + } + else { + ret = i2c_write(userCtx, addr, buf, size); + } + + (void)userCtx; + (void)ctx; + + return ret; + } +#else /* Microchip Harmony Hal SPI */ + #ifdef WOLFTPM_CHECK_WAIT_STATE #error This driver does not support check wait state yet #endif -#include "configuration.h" -#include "definitions.h" - /* TPM Chip Select Pin (default PC5) */ #ifndef TPM_SPI_PIN #define SYS_PORT_PIN_PC5 @@ -98,6 +317,7 @@ int TPM2_IoCb_Microchip_SPI(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf, return ret; } +#endif /* WOLFTPM_I2C */ #endif /* WOLFTPM_MICROCHIP_HARMONY */ #endif /* !(WOLFTPM_LINUX_DEV || WOLFTPM_SWTPM || WOLFTPM_WINAPI) */ #endif /* WOLFTPM_INCLUDE_IO_FILE */ From b72e77a64be8d1294fa16bf5c58e1b08f0feee5e Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 2 Apr 2024 12:18:11 -0500 Subject: [PATCH 2/2] Small cleanup. --- hal/tpm_io_microchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/tpm_io_microchip.c b/hal/tpm_io_microchip.c index 76d4f6bf..a6682637 100644 --- a/hal/tpm_io_microchip.c +++ b/hal/tpm_io_microchip.c @@ -216,7 +216,6 @@ do { /* Queue the write with I2C_BB. */ - //queued = I2C_BB_Write(i2cAddr, buf, len + 1); queued = I2C_BB_Write(TPM2_I2C_ADDR, buf, len + 1); if (!queued) { @@ -252,7 +251,8 @@ /* Set callback to null to do time based polling of * I2C_BB_IsBusy instead. * - * Note: Apparently a callback is actually required. + * Note: Apparently a callback is actually required, + * even if not used. * */ I2C_BB_Initialize(); I2C_BB_CallbackRegister(dummy_callback, dummy_context);