summaryrefslogtreecommitdiff
path: root/src/drivers/i2c/tpm/tpm.c
diff options
context:
space:
mode:
authorDuncan Laurie <dlaurie@chromium.org>2016-09-07 10:52:12 -0700
committerDuncan Laurie <dlaurie@chromium.org>2016-09-08 16:24:08 +0200
commit1ca196841ac4db46d8d9c3c55004c3e9ee3c8844 (patch)
tree75c49bdb3430a4fb60a82201399b7d7ed53b54d0 /src/drivers/i2c/tpm/tpm.c
parent7fbdad80fd439a8afb04e20bd67c8c5fe766dc1a (diff)
drivers/i2c/tpm: Fix early TPM probe
The early TPM probe was done directly in tis.c ignoring the lower layer that provides appropriate access to the chip. Move this into a tpm_vendor_probe() function so it can use iic_tpm_read() with all of the built-in delays and semantics instead of calling i2c_readb() directly from the wrong layer. This fixes early init failures that were seen with the cr50 i2c tpm on the reef mainboard. Change-Id: I9bb3b820d10f6e2ea24c57b90cf0edc813cdc7e0 Signed-off-by: Duncan Laurie <dlaurie@chromium.org> Reviewed-on: https://review.coreboot.org/16527 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin@chromium.org> Reviewed-by: Furquan Shaikh <furquan@google.com> Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Diffstat (limited to 'src/drivers/i2c/tpm/tpm.c')
-rw-r--r--src/drivers/i2c/tpm/tpm.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/src/drivers/i2c/tpm/tpm.c b/src/drivers/i2c/tpm/tpm.c
index 5e3c0c1bc8..f0f5ca8d6c 100644
--- a/src/drivers/i2c/tpm/tpm.c
+++ b/src/drivers/i2c/tpm/tpm.c
@@ -46,6 +46,7 @@
#define SLEEP_DURATION 60 /* in usec */
#define SLEEP_DURATION_LONG 210 /* in usec */
#define SLEEP_DURATION_SAFE 750 /* in usec */
+#define SLEEP_DURATION_PROBE_MS 1000 /* in msec */
/* max. number of iterations after I2C NAK for 'long' commands
* we need this especially for sending TPM_READY, since the cleanup after the
@@ -695,6 +696,47 @@ out:
/* Initialization of I2C TPM */
+int tpm_vendor_probe(unsigned bus, uint32_t addr)
+{
+ struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev);
+ struct stopwatch sw;
+ uint8_t buf = 0;
+ int ret;
+ long sw_run_duration = SLEEP_DURATION_PROBE_MS;
+
+ tpm_dev->chip_type = UNKNOWN;
+ tpm_dev->bus = bus;
+ tpm_dev->addr = addr;
+ tpm_dev->sleep_short = SLEEP_DURATION_SAFE;
+ tpm_dev->sleep_long = SLEEP_DURATION_SAFE * 2;
+
+ /*
+ * Probe TPM. Check if the TPM_ACCESS register's ValidSts bit is set(1)
+ * If the bit remains clear(0) then claim that init has failed.
+ */
+ stopwatch_init_msecs_expire(&sw, sw_run_duration);
+ do {
+ ret = iic_tpm_read(TPM_ACCESS(0), &buf, 1);
+ if (!ret && (buf & TPM_STS_VALID)) {
+ sw_run_duration = stopwatch_duration_msecs(&sw);
+ break;
+ }
+ } while (!stopwatch_expired(&sw));
+
+ printk(BIOS_INFO,
+ "%s: ValidSts bit %s(%d) in TPM_ACCESS register after %ld ms\n",
+ __func__, (buf & TPM_STS_VALID) ? "set" : "clear",
+ (buf & TPM_STS_VALID) >> 7, sw_run_duration);
+
+ /*
+ * Claim failure if the ValidSts (bit 7) is clear.
+ */
+ if (!(buf & TPM_STS_VALID))
+ return -1;
+
+ return 0;
+}
+
int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr)
{
struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev);