summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFurquan Shaikh <furquan@chromium.org>2017-04-07 13:26:01 -0700
committerFurquan Shaikh <furquan@google.com>2017-04-13 05:04:13 +0200
commit260b297a8969d7119d514272af7abacd12c8c42d (patch)
tree4e17674a8ad483059c66a74959c7f436c82ad61c /src
parentbf6dfaefc2fd2f22e55e3227d8b023bcd992cae5 (diff)
downloadcoreboot-260b297a8969d7119d514272af7abacd12c8c42d.tar.xz
drivers/spi/tpm: Clean up SPI TPM driver
1. Move common TIS macros to include/tpm.h. 2. Use common TIS macros while referring to status and access registers. 3. Add a new function claim_locality to properly check for required access bits and claim locality 0. BUG=b:36873582 Change-Id: I11bf3e8b6e1f50b7868c9fe4394a858488367287 Signed-off-by: Furquan Shaikh <furquan@chromium.org> Reviewed-on: https://review.coreboot.org/19213 Tested-by: build bot (Jenkins) Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
Diffstat (limited to 'src')
-rw-r--r--src/drivers/i2c/tpm/cr50.c1
-rw-r--r--src/drivers/i2c/tpm/tpm.c1
-rw-r--r--src/drivers/i2c/tpm/tpm.h15
-rw-r--r--src/drivers/spi/tpm/tpm.c122
-rw-r--r--src/include/tpm.h26
5 files changed, 85 insertions, 80 deletions
diff --git a/src/drivers/i2c/tpm/cr50.c b/src/drivers/i2c/tpm/cr50.c
index 42c82d6fec..ce30bf1b7c 100644
--- a/src/drivers/i2c/tpm/cr50.c
+++ b/src/drivers/i2c/tpm/cr50.c
@@ -39,6 +39,7 @@
#include <device/i2c.h>
#include <endian.h>
#include <timer.h>
+#include <tpm.h>
#include "tpm.h"
#if IS_ENABLED(CONFIG_ARCH_X86)
diff --git a/src/drivers/i2c/tpm/tpm.c b/src/drivers/i2c/tpm/tpm.c
index e804d6fc60..5350695922 100644
--- a/src/drivers/i2c/tpm/tpm.c
+++ b/src/drivers/i2c/tpm/tpm.c
@@ -38,6 +38,7 @@
#include <device/i2c.h>
#include <endian.h>
#include <timer.h>
+#include <tpm.h>
#include "tpm.h"
/* max. number of iterations after I2C NAK */
diff --git a/src/drivers/i2c/tpm/tpm.h b/src/drivers/i2c/tpm/tpm.h
index 3a9a2ab949..e511e0df22 100644
--- a/src/drivers/i2c/tpm/tpm.h
+++ b/src/drivers/i2c/tpm/tpm.h
@@ -47,21 +47,6 @@ enum tpm_timeout {
#define TPM_RSP_SIZE_BYTE 2
#define TPM_RSP_RC_BYTE 6
-enum tis_access {
- TPM_ACCESS_VALID = 0x80,
- TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
- TPM_ACCESS_REQUEST_PENDING = 0x04,
- TPM_ACCESS_REQUEST_USE = 0x02,
-};
-
-enum tis_status {
- TPM_STS_VALID = 0x80,
- TPM_STS_COMMAND_READY = 0x40,
- TPM_STS_GO = 0x20,
- TPM_STS_DATA_AVAIL = 0x10,
- TPM_STS_DATA_EXPECT = 0x08,
-};
-
#define TPM_ACCESS(l) (0x0000 | ((l) << 4))
#define TPM_STS(l) (0x0001 | ((l) << 4))
#define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4))
diff --git a/src/drivers/spi/tpm/tpm.c b/src/drivers/spi/tpm/tpm.c
index 1c5e5353ad..0b5a835837 100644
--- a/src/drivers/spi/tpm/tpm.c
+++ b/src/drivers/spi/tpm/tpm.c
@@ -16,6 +16,7 @@
*/
#include <arch/early_variables.h>
+#include <assert.h>
#include <commonlib/endian.h>
#include <console/console.h>
#include <delay.h>
@@ -48,35 +49,6 @@ static struct tpm2_info g_tpm_info CAR_GLOBAL;
*/
static const int debug_level_ = CONFIG_DEBUG_TPM;
-/* Locality management bits (in TPM_ACCESS_REG) */
-enum tpm_access_bits {
- tpm_reg_valid_sts = (1 << 7),
- active_locality = (1 << 5),
- request_use = (1 << 1),
- tpm_establishment = (1 << 0),
-};
-
-/*
- * Variuous fields of the TPM status register, arguably the most important
- * register when interfacing to a TPM.
- */
-enum tpm_sts_bits {
- tpm_family_shift = 26,
- tpm_family_mask = ((1 << 2) - 1), /* 2 bits wide. */
- tpm_family_tpm2 = 1,
- reset_establishment_bit = (1 << 25),
- command_cancel = (1 << 24),
- burst_count_shift = 8,
- burst_count_mask = ((1 << 16) - 1), /* 16 bits wide. */
- sts_valid = (1 << 7),
- command_ready = (1 << 6),
- tpm_go = (1 << 5),
- data_avail = (1 << 4),
- expect = (1 << 3),
- self_test_done = (1 << 2),
- response_retry = (1 << 1),
-};
-
/*
* SPI frame header for TPM transactions is 4 bytes in size, it is described
* in section "6.4.6 Spi Bit Protocol".
@@ -113,7 +85,7 @@ static int tpm_sync(void)
{
struct stopwatch sw;
- stopwatch_init_usecs_expire(&sw, 10 * 1000);
+ stopwatch_init_msecs_expire(&sw, 10);
while (!tis_plat_irq_status()) {
if (stopwatch_expired(&sw)) {
printk(BIOS_ERR, "Timeout wait for tpm irq!\n");
@@ -347,7 +319,53 @@ static uint32_t get_burst_count(void)
uint32_t status;
read_tpm_sts(&status);
- return (status >> burst_count_shift) & burst_count_mask;
+ return (status & TPM_STS_BURST_COUNT_MASK) >> TPM_STS_BURST_COUNT_SHIFT;
+}
+
+static uint8_t tpm2_read_access_reg(void)
+{
+ uint8_t access;
+ tpm2_read_reg(TPM_ACCESS_REG, &access, sizeof(access));
+ /* We do not care about access establishment bit state. Ignore it. */
+ return access & ~TPM_ACCESS_ESTABLISHMENT;
+}
+
+static void tpm2_write_access_reg(uint8_t cmd)
+{
+ /* Writes to access register can set only 1 bit at a time. */
+ assert (!(cmd & (cmd - 1)));
+
+ tpm2_write_reg(TPM_ACCESS_REG, &cmd, sizeof(cmd));
+}
+
+static int tpm2_claim_locality(void)
+{
+ uint8_t access;
+
+ access = tpm2_read_access_reg();
+ /*
+ * If active locality is set (maybe reset line is not connected?),
+ * release the locality and try again.
+ */
+ if (access & TPM_ACCESS_ACTIVE_LOCALITY) {
+ tpm2_write_access_reg(TPM_ACCESS_ACTIVE_LOCALITY);
+ access = tpm2_read_access_reg();
+ }
+
+ if (access != TPM_ACCESS_VALID) {
+ printk(BIOS_ERR, "Invalid reset status: %#x\n", access);
+ return 0;
+ }
+
+ tpm2_write_access_reg(TPM_ACCESS_REQUEST_USE);
+ access = tpm2_read_access_reg();
+ if (access != (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
+ printk(BIOS_ERR, "Failed to claim locality 0, status: %#x\n",
+ access);
+ return 0;
+ }
+
+ return 1;
}
int tpm2_init(struct spi_slave *spi_if)
@@ -366,38 +384,12 @@ int tpm2_init(struct spi_slave *spi_if)
if (!tpm2_read_reg(TPM_DID_VID_REG, &did_vid, sizeof(did_vid)))
return -1;
- /* Try claiming locality zero. */
- tpm2_read_reg(TPM_ACCESS_REG, &cmd, sizeof(cmd));
- if ((cmd & (active_locality & tpm_reg_valid_sts)) ==
- (active_locality & tpm_reg_valid_sts)) {
- /*
- * Locality active - maybe reset line is not connected?
- * Release the locality and try again
- */
- cmd = active_locality;
- tpm2_write_reg(TPM_ACCESS_REG, &cmd, sizeof(cmd));
- tpm2_read_reg(TPM_ACCESS_REG, &cmd, sizeof(cmd));
- }
-
- /* The tpm_establishment bit can be either set or not, ignore it. */
- if ((cmd & ~tpm_establishment) != tpm_reg_valid_sts) {
- printk(BIOS_ERR, "invalid reset status: %#x\n", cmd);
+ /* Claim locality 0. */
+ if (!tpm2_claim_locality())
return -1;
- }
-
- cmd = request_use;
- tpm2_write_reg(TPM_ACCESS_REG, &cmd, sizeof(cmd));
- tpm2_read_reg(TPM_ACCESS_REG, &cmd, sizeof(cmd));
- if ((cmd & ~tpm_establishment) !=
- (tpm_reg_valid_sts | active_locality)) {
- printk(BIOS_ERR, "failed to claim locality 0, status: %#x\n",
- cmd);
- return -1;
- }
read_tpm_sts(&status);
- if (((status >> tpm_family_shift) & tpm_family_mask) !=
- tpm_family_tpm2) {
+ if ((status & TPM_STS_FAMILY_MASK) != TPM_STS_FAMILY_TPM_2_0) {
printk(BIOS_ERR, "unexpected TPM family value, status: %#x\n",
status);
return -1;
@@ -563,7 +555,7 @@ size_t tpm2_process_command(const void *tpm2_command, size_t command_size,
}
/* Let the TPM know that the command is coming. */
- write_tpm_sts(command_ready);
+ write_tpm_sts(TPM_STS_COMMAND_READY);
/*
* Tpm commands and responses written to and read from the FIFO
@@ -580,10 +572,10 @@ size_t tpm2_process_command(const void *tpm2_command, size_t command_size,
fifo_transfer(command_size, fifo_buffer, fifo_transmit);
/* Now tell the TPM it can start processing the command. */
- write_tpm_sts(tpm_go);
+ write_tpm_sts(TPM_STS_GO);
/* Now wait for it to report that the response is ready. */
- expected_status_bits = sts_valid | data_avail;
+ expected_status_bits = TPM_STS_VALID | TPM_STS_DATA_AVAIL;
if (!wait_for_status(expected_status_bits, expected_status_bits)) {
/*
* If timed out, which should never happen, let's at least
@@ -642,13 +634,13 @@ size_t tpm2_process_command(const void *tpm2_command, size_t command_size,
/* Verify that 'data available' is not asseretd any more. */
read_tpm_sts(&status);
- if ((status & expected_status_bits) != sts_valid) {
+ if ((status & expected_status_bits) != TPM_STS_VALID) {
printk(BIOS_ERR, "unexpected final status %#x\n", status);
return 0;
}
/* Move the TPM back to idle state. */
- write_tpm_sts(command_ready);
+ write_tpm_sts(TPM_STS_COMMAND_READY);
return payload_size;
}
diff --git a/src/include/tpm.h b/src/include/tpm.h
index bd85b43844..32a44c17eb 100644
--- a/src/include/tpm.h
+++ b/src/include/tpm.h
@@ -19,6 +19,32 @@
#include <stddef.h>
#include <stdint.h>
+enum tis_access {
+ TPM_ACCESS_VALID = (1 << 7),
+ TPM_ACCESS_ACTIVE_LOCALITY = (1 << 5),
+ TPM_ACCESS_REQUEST_PENDING = (1 << 2),
+ TPM_ACCESS_REQUEST_USE = (1 << 1),
+ TPM_ACCESS_ESTABLISHMENT = (1 << 0),
+};
+
+enum tis_status {
+ TPM_STS_FAMILY_SHIFT = 26,
+ TPM_STS_FAMILY_MASK = (0x3 << TPM_STS_FAMILY_SHIFT),
+ TPM_STS_FAMILY_TPM_2_0 = (1 << TPM_STS_FAMILY_SHIFT),
+ TPM_STS_FAMILY_TPM_1_2 = (0 << TPM_STS_FAMILY_SHIFT),
+ TPM_STS_RESET_ESTABLISHMENT = (1 << 25),
+ TPM_STS_COMMAND_CANCEL = (1 << 24),
+ TPM_STS_BURST_COUNT_SHIFT = 8,
+ TPM_STS_BURST_COUNT_MASK = (0xFFFF << TPM_STS_BURST_COUNT_SHIFT),
+ TPM_STS_VALID = (1 << 7),
+ TPM_STS_COMMAND_READY = (1 << 6),
+ TPM_STS_GO = (1 << 5),
+ TPM_STS_DATA_AVAIL = (1 << 4),
+ TPM_STS_DATA_EXPECT = (1 << 3),
+ TPM_STS_SELF_TEST_DONE = (1 << 2),
+ TPM_STS_RESPONSE_RETRY = (1 << 1),
+};
+
/*
* tis_init()
*