Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iocb microchipharmony i2c #340

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions hal/tpm_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
3 changes: 3 additions & 0 deletions hal/tpm_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
226 changes: 223 additions & 3 deletions hal/tpm_io_microchip.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <i2cbb/i2c_bb.h>
/* 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(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,
* even if not used.
* */
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
Expand Down Expand Up @@ -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 */
Expand Down