From c4852e71579cd4b1a702dccae63d5c39f59cade6 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 21 Apr 2017 14:11:51 +0800 Subject: drivers/i2c/tpm/cr50: Use tis_plat_irq_status for Cr50 IRQ status The Cr50 TPM uses an IRQ to provide a "status" signal used for hand-shaking the reception of commands. Real IRQs are not supported in firmware, however firmware can still poll interrupt status registers for the same effect. Commit 94cc485338a3 ("drivers/i2c/tpm/cr50: Support interrupts for status") added support for the Cr50 driver on X86 platforms to use a KConfig file to supply an IRQ which it would poll using acpi_get_gpe. If the IRQ is not supplied, the Cr50 driver inserts a 20 ms wait. Unfortunately this doesn't work so well when using the i2c connected Cr50 on ARM platforms. Luckily, a more generic implementation to allow a mainboard to supply a Cr50 IRQ status polling function was solved for SPI connected Cr50s by commit 19e3d335bddb ("drivers/spi/tpm: using tpm irq to sync tpm transaction"). Let's refactor the i2c c50 driver to use this same approach, and change eve and reef boards to make use of DRIVER_TPM_TIS_ACPI_INTERRUPT for specifying the TPM flow control interrupt. This essentially reverts these two commits: 48f708d199 drivers/i2c/tpm/cr50: Initialize IRQ status handler before probe 94cc485338 drivers/i2c/tpm/cr50: Support interrupts for status And ports this commit to i2c/tpm/cr50: 19e3d335bd drivers/spi/tpm: using tpm irq to sync tpm transaction As a side effect the tpm_vendor_specific IRQ field goes back to its original usage as the "TPM 1.2 command complete" interrupt, instead of being repurposed to hold the flow control IRQ. BRANCH=none BUG=b:36786804 TEST=Boot reef w/ serial enabled firmware, verify verstage sees "cr50 TPM" and does not complain about lack of tis_plat_irq_status(). TEST=Boot eve w/ serial enabled firmware, verify verstage sees "cr50 TPM" and does not complain about lack of tis_plat_irq_status(). Change-Id: I004329eae1d8aabda51c46b8504bf210484782b4 Signed-off-by: Daniel Kurtz Reviewed-on: https://review.coreboot.org/19363 Reviewed-by: Julius Werner Reviewed-by: Aaron Durbin Tested-by: build bot (Jenkins) --- src/drivers/i2c/tpm/Kconfig | 5 ---- src/drivers/i2c/tpm/cr50.c | 59 ++++++++++++++------------------------------- src/drivers/i2c/tpm/tpm.h | 1 - 3 files changed, 18 insertions(+), 47 deletions(-) diff --git a/src/drivers/i2c/tpm/Kconfig b/src/drivers/i2c/tpm/Kconfig index 9e3a0aa82e..db6777e65d 100644 --- a/src/drivers/i2c/tpm/Kconfig +++ b/src/drivers/i2c/tpm/Kconfig @@ -44,11 +44,6 @@ config DRIVER_TPM_I2C_ADDR default 0x2 # 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 depends on I2C_TPM bool "Generate I2C TPM ACPI device" diff --git a/src/drivers/i2c/tpm/cr50.c b/src/drivers/i2c/tpm/cr50.c index ce30bf1b7c..aa59f1e917 100644 --- a/src/drivers/i2c/tpm/cr50.c +++ b/src/drivers/i2c/tpm/cr50.c @@ -42,10 +42,6 @@ #include #include "tpm.h" -#if IS_ENABLED(CONFIG_ARCH_X86) -#include -#endif - #define CR50_MAX_BUFSIZE 63 #define CR50_TIMEOUT_LONG_MS 2000 /* Long timeout while waiting for TPM */ #define CR50_TIMEOUT_SHORT_MS 2 /* Short timeout during transactions */ @@ -61,33 +57,33 @@ struct tpm_inf_dev { static struct tpm_inf_dev g_tpm_dev CAR_GLOBAL; +__attribute__ ((weak)) int tis_plat_irq_status(void) +{ + static int warning_displayed CAR_GLOBAL; + + if (!car_get_var(warning_displayed)) { + printk(BIOS_WARNING, "WARNING: tis_plat_irq_status() not implemented, wasting 20ms to wait on Cr50!\n"); + car_set_var(warning_displayed, 1); + } + mdelay(CR50_TIMEOUT_NOIRQ_MS); + + return 1; +} + /* 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_NOIRQ_MS); - return 0; - } - stopwatch_init_msecs_expire(&sw, CR50_TIMEOUT_IRQ_MS); - while (!chip->vendor.irq_status(chip->vendor.irq)) + while (!tis_plat_irq_status()) if (stopwatch_expired(&sw)) return -1; return 0; } -/* Clear pending interrupts */ -static void cr50_i2c_clear_tpm_irq(struct tpm_chip *chip) -{ - if (chip->vendor.irq_status) - chip->vendor.irq_status(chip->vendor.irq); -} - /* * cr50_i2c_read() - read from TPM register * @@ -111,7 +107,7 @@ static int cr50_i2c_read(struct tpm_chip *chip, uint8_t addr, return -1; /* Clear interrupt before starting transaction */ - cr50_i2c_clear_tpm_irq(chip); + tis_plat_irq_status(); /* Send the register address byte to the TPM */ if (i2c_write_raw(tpm_dev->bus, tpm_dev->addr, &addr, 1)) { @@ -161,7 +157,7 @@ static int cr50_i2c_write(struct tpm_chip *chip, memcpy(tpm_dev->buf + 1, buffer, len); /* Clear interrupt before starting transaction */ - cr50_i2c_clear_tpm_irq(chip); + tis_plat_irq_status(); /* Send write request buffer with address */ if (i2c_write_raw(tpm_dev->bus, tpm_dev->addr, tpm_dev->buf, len + 1)) { @@ -418,25 +414,6 @@ static void cr50_vendor_init(struct tpm_chip *chip) chip->vendor.recv = &cr50_i2c_tis_recv; chip->vendor.send = &cr50_i2c_tis_send; chip->vendor.cancel = &cr50_i2c_tis_ready; - chip->vendor.irq = CONFIG_DRIVER_TPM_I2C_IRQ; - - /* - * 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; -#endif - } - - if (chip->vendor.irq <= 0) - printk(BIOS_WARNING, - "%s: No IRQ, will use %ums delay for TPM ready\n", - __func__, CR50_TIMEOUT_NOIRQ_MS); } int tpm_vendor_probe(unsigned int bus, uint32_t addr) @@ -503,8 +480,8 @@ int tpm_vendor_init(struct tpm_chip *chip, unsigned int bus, uint32_t dev_addr) goto out_err; } - 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); + printk(BIOS_DEBUG, "cr50 TPM 2.0 (i2c %u:0x%02x id 0x%x)\n", + bus, dev_addr, 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 e511e0df22..35cf3972cf 100644 --- a/src/drivers/i2c/tpm/tpm.h +++ b/src/drivers/i2c/tpm/tpm.h @@ -59,7 +59,6 @@ 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 *); -- cgit v1.2.3