Attention is currently required from: Christian Walter. Tim Wawrzynczak has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/61720 )
Change subject: drivers/i2c/tpm/cr50: Add support to get cr50 firmware version ......................................................................
drivers/i2c/tpm/cr50: Add support to get cr50 firmware version
cr50-based devices that use the I2C protocol may still need to know the firmware version of the cr50, therefore port this functionality from the SPI driver to I2C.
Signed-off-by: Tim Wawrzynczak twawrzynczak@chromium.org Change-Id: I9dbdbc6ec717f1aa89111ae09249cbe2312054d9 --- M src/drivers/i2c/tpm/cr50.c M src/drivers/i2c/tpm/tpm.h 2 files changed, 79 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/20/61720/1
diff --git a/src/drivers/i2c/tpm/cr50.c b/src/drivers/i2c/tpm/cr50.c index 6c12ee4..ac07f4d 100644 --- a/src/drivers/i2c/tpm/cr50.c +++ b/src/drivers/i2c/tpm/cr50.c @@ -43,6 +43,7 @@ };
static struct tpm_inf_dev tpm_dev; +static struct cr50_firmware_version cr50_firmware_version;
__weak int tis_plat_irq_status(void) { @@ -470,6 +471,64 @@ return -1; }
+static int cr50_parse_fw_version(const char *version_str, struct cr50_firmware_version *ver) +{ + int epoch, major, minor; + + char *number = strstr(version_str, " RW_A:"); + if (!number) + number = strstr(version_str, " RW_B:"); + if (!number) + return -1; + number += 6; /* Skip past the colon. */ + + epoch = skip_atoi(&number); + if (*number++ != '.') + return -2; + major = skip_atoi(&number); + if (*number++ != '.') + return -2; + minor = skip_atoi(&number); + + ver->epoch = epoch; + ver->major = major; + ver->minor = minor; + return 0; +} + +static int get_fw_version(void) +{ + int chunk_count = 0; + size_t chunk_size = 50; + char version_str[301]; + + /* Read FW version if available */ + if (cr50_i2c_write(TPM_FW_VER(0), (void *)&chunk_size, 1) == 0) { + do { + if (cr50_i2c_read(TPM_FW_VER(0), + (uint8_t *)(version_str + chunk_count * chunk_size), + chunk_size)) + break; + + /* Zero-padding detected, break early */ + if (!version_str[++chunk_count * chunk_size - 1]) + break; + } while (chunk_count * chunk_size < sizeof(version_str) - chunk_size); + + if (cr50_parse_fw_version(version_str, &cr50_firmware_version)) { + printk(BIOS_ERR, "Unrecognized cr50 firmware version string\n"); + return -1; + } + } + + return 0; +} + +static int first_access_this_boot(void) +{ + return ENV_SEPARATE_VERSTAGE || ENV_BOOTBLOCK || !CONFIG(VBOOT); +} + int tpm_vendor_init(struct tpm_chip *chip, unsigned int bus, uint32_t dev_addr) { uint32_t did_vid = 0; @@ -497,6 +556,11 @@ printk(BIOS_DEBUG, "cr50 TPM 2.0 (i2c %u:0x%02x id 0x%x)\n", bus, dev_addr, did_vid >> 16);
+ get_fw_version(); + printk(BIOS_INFO, "cr50 TPM FW version %d.%d.%d\n", + cr50_firmware_version.epoch, cr50_firmware_version.major, + cr50_firmware_version.minor); + chip->is_open = 1; return 0; } @@ -504,3 +568,7 @@ void tpm_vendor_cleanup(struct tpm_chip *chip) { } +void cr50_get_firmware_version(struct cr50_firmware_version *version) +{ + *version = cr50_firmware_version; +} diff --git a/src/drivers/i2c/tpm/tpm.h b/src/drivers/i2c/tpm/tpm.h index eb4fef1..b5b084a 100644 --- a/src/drivers/i2c/tpm/tpm.h +++ b/src/drivers/i2c/tpm/tpm.h @@ -36,6 +36,7 @@ #define TPM_STS(l) (0x0001 | ((l) << 4)) #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) #define TPM_DID_VID(l) (0x0006 | ((l) << 4)) +#define TPM_FW_VER(l) (0x000f | ((l) << 4))
struct tpm_chip;
@@ -55,6 +56,16 @@ struct tpm_vendor_specific vendor; };
+/* Structure describing the elements of Cr50 firmware version. */ +struct cr50_firmware_version { + int epoch; + int major; + int minor; +}; + +/* Get the cr50 firmware version information. */ +void cr50_get_firmware_version(struct cr50_firmware_version *version); + /* ---------- Interface for TPM vendor ------------ */
int tpm_vendor_probe(unsigned int bus, uint32_t addr);