[coreboot-gerrit] Patch set updated for coreboot: drivers/i2c/tpm/cr50: Support interrupts for status

Duncan Laurie (dlaurie@chromium.org) gerrit at coreboot.org
Tue Sep 20 03:57:58 CEST 2016


Duncan Laurie (dlaurie at chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/16660

-gerrit

commit 78b02892d79a204cdcbb45530ffa7fbf2ca011ae
Author: Duncan Laurie <dlaurie at chromium.org>
Date:   Mon Sep 19 17:22:10 2016 -0700

    drivers/i2c/tpm/cr50: Support interrupts for status
    
    Support reading the ACPI GPE status (on x86) to determine when
    the cr50 is ready to return response data or is done processing
    written data.  If the interrupt is not defined by Kconfig then
    it will continue to use the safe delay.
    
    This was tested with reef hardware and a modified cr50 image
    that generates interrupts at the intended points.
    
    BUG=chrome-os-partner:53336
    
    Change-Id: I9f78f520fd089cb4471d8826a8cfecff67398bf8
    Signed-off-by: Duncan Laurie <dlaurie at chromium.org>
---
 src/drivers/i2c/tpm/Kconfig | 12 +++++++++-
 src/drivers/i2c/tpm/cr50.c  | 56 ++++++++++++++++++++++++++++++++++++++-------
 src/drivers/i2c/tpm/tpm.h   |  1 +
 3 files changed, 60 insertions(+), 9 deletions(-)

diff --git a/src/drivers/i2c/tpm/Kconfig b/src/drivers/i2c/tpm/Kconfig
index db77b95..a5ab077 100644
--- a/src/drivers/i2c/tpm/Kconfig
+++ b/src/drivers/i2c/tpm/Kconfig
@@ -2,9 +2,14 @@ config I2C_TPM
 	bool "I2C TPM"
 	depends on TPM || TPM2
 
+config MAINBOARD_HAS_I2C_TPM_CR50
+	bool
+	default n
+
 choice
 	prompt "I2C TPM Driver"
-	default I2C_TPM_GENERIC
+	default I2C_TPM_CR50 if MAINBOARD_HAS_I2C_TPM_CR50
+	default I2C_TPM_GENERIC if !MAINBOARD_HAS_I2C_TPM_CR50
 	depends on I2C_TPM
 
 config I2C_TPM_GENERIC
@@ -25,6 +30,11 @@ config DRIVER_TPM_I2C_ADDR
 	default 2 # FIXME, workaround for Kconfig BS
 	depends on I2C_TPM
 
+config DRIVER_TPM_I2C_IRQ
+	int "IRQ or GPE to use for TPM interrupt"
+	default -1
+	depends on I2C_TPM
+
 config DRIVER_I2C_TPM_ACPI
 	bool "Generate I2C TPM ACPI device"
 	default y if ARCH_X86 && I2C_TPM
diff --git a/src/drivers/i2c/tpm/cr50.c b/src/drivers/i2c/tpm/cr50.c
index af75644..d3c0efa 100644
--- a/src/drivers/i2c/tpm/cr50.c
+++ b/src/drivers/i2c/tpm/cr50.c
@@ -41,6 +41,9 @@
 #include <timer.h>
 #include "tpm.h"
 
+#if IS_ENABLED(CONFIG_ARCH_X86)
+#include <arch/acpi.h>
+#endif
 
 #define CR50_MAX_BUFSIZE	63
 #define CR50_TIMEOUT_LONG_MS	2000	/* Long timeout while waiting for TPM */
@@ -55,6 +58,26 @@ struct tpm_inf_dev {
 
 static struct tpm_inf_dev g_tpm_dev CAR_GLOBAL;
 
+/* Wait for interrupt to indicate the TPM is ready */
+static int cr50_i2c_wait_tpm_ready(struct tpm_chip *chip)
+{
+	struct stopwatch sw;
+
+	if (!chip->vendor.irq_status) {
+		/* Fixed delay if interrupt not supported */
+		mdelay(CR50_TIMEOUT_SHORT_MS);
+		return 0;
+	}
+
+	stopwatch_init_msecs_expire(&sw, 10 * CR50_TIMEOUT_SHORT_MS);
+
+	while (!chip->vendor.irq_status(chip->vendor.irq))
+		if (stopwatch_expired(&sw))
+			return -1;
+
+	return 0;
+}
+
 /*
  * cr50_i2c_read() - read from TPM register
  *
@@ -77,6 +100,10 @@ static int cr50_i2c_read(struct tpm_chip *chip, uint8_t addr,
 	if (tpm_dev->addr == 0)
 		return -1;
 
+	/* Clear interrupt before starting transaction */
+	if (chip->vendor.irq_status)
+		chip->vendor.irq_status(chip->vendor.irq);
+
 	/* Send the register address byte to the TPM */
 	if (i2c_write_raw(tpm_dev->bus, tpm_dev->addr, &addr, 1)) {
 		printk(BIOS_ERR, "%s: Address write failed\n", __func__);
@@ -84,7 +111,8 @@ static int cr50_i2c_read(struct tpm_chip *chip, uint8_t addr,
 	}
 
 	/* Wait for TPM to be ready with response data */
-	mdelay(CR50_TIMEOUT_SHORT_MS);
+	if (cr50_i2c_wait_tpm_ready(chip) < 0)
+		return -1;
 
 	/* Read response data from the TPM */
 	if (i2c_read_raw(tpm_dev->bus, tpm_dev->addr, buffer, len)) {
@@ -123,6 +151,10 @@ static int cr50_i2c_write(struct tpm_chip *chip,
 	tpm_dev->buf[0] = addr;
 	memcpy(tpm_dev->buf + 1, buffer, len);
 
+	/* Clear interrupt before starting transaction */
+	if (chip->vendor.irq_status)
+		chip->vendor.irq_status(chip->vendor.irq);
+
 	/* Send write request buffer with address */
 	if (i2c_write_raw(tpm_dev->bus, tpm_dev->addr, tpm_dev->buf, len + 1)) {
 		printk(BIOS_ERR, "%s: Error writing to TPM\n", __func__);
@@ -130,9 +162,7 @@ static int cr50_i2c_write(struct tpm_chip *chip,
 	}
 
 	/* Wait for TPM to be ready */
-	mdelay(CR50_TIMEOUT_SHORT_MS);
-
-	return 0;
+	return cr50_i2c_wait_tpm_ready(chip);
 }
 
 static int check_locality(struct tpm_chip *chip, int loc)
@@ -435,8 +465,18 @@ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr)
 
 	cr50_vendor_init(chip);
 
-	/* Disable interrupts (not supported) */
-	chip->vendor.irq = 0;
+	/*
+	 * Interrupts are not supported this early in firmware,
+	 * use use an arch-specific method to query for interrupt status.
+	 */
+	if (chip->vendor.irq > 0) {
+		if (IS_ENABLED(CONFIG_ARCH_X86)) {
+			/* Query GPE status for interrupt */
+			chip->vendor.irq_status = &acpi_get_gpe;
+		} else {
+			chip->vendor.irq = -1;
+		}
+	}
 
 	if (request_locality(chip, 0) != 0)
 		return -1;
@@ -450,8 +490,8 @@ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr)
 		goto out_err;
 	}
 
-	printk(BIOS_DEBUG, "cr50 TPM %u:%02x (device-id 0x%X)\n",
-	       tpm_dev->bus, tpm_dev->addr, vendor >> 16);
+	printk(BIOS_DEBUG, "cr50 TPM 2.0 (i2c %u:0x%02x irq %d id 0x%x)\n",
+	       bus, dev_addr, chip->vendor.irq, vendor >> 16);
 
 	chip->is_open = 1;
 	return 0;
diff --git a/src/drivers/i2c/tpm/tpm.h b/src/drivers/i2c/tpm/tpm.h
index 048c848..b6dda1a 100644
--- a/src/drivers/i2c/tpm/tpm.h
+++ b/src/drivers/i2c/tpm/tpm.h
@@ -74,6 +74,7 @@ struct tpm_vendor_specific {
 	uint8_t req_complete_val;
 	uint8_t req_canceled;
 	int irq;
+	int (*irq_status)(int irq);
 	int (*recv)(struct tpm_chip *, uint8_t *, size_t);
 	int (*send)(struct tpm_chip *, uint8_t *, size_t);
 	void (*cancel)(struct tpm_chip *);



More information about the coreboot-gerrit mailing list