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>
This commit is contained in:
Furquan Shaikh
2017-04-07 13:26:01 -07:00
committed by Furquan Shaikh
parent bf6dfaefc2
commit 260b297a89
5 changed files with 85 additions and 80 deletions

View File

@ -39,6 +39,7 @@
#include <device/i2c.h> #include <device/i2c.h>
#include <endian.h> #include <endian.h>
#include <timer.h> #include <timer.h>
#include <tpm.h>
#include "tpm.h" #include "tpm.h"
#if IS_ENABLED(CONFIG_ARCH_X86) #if IS_ENABLED(CONFIG_ARCH_X86)

View File

@ -38,6 +38,7 @@
#include <device/i2c.h> #include <device/i2c.h>
#include <endian.h> #include <endian.h>
#include <timer.h> #include <timer.h>
#include <tpm.h>
#include "tpm.h" #include "tpm.h"
/* max. number of iterations after I2C NAK */ /* max. number of iterations after I2C NAK */

View File

@ -47,21 +47,6 @@ enum tpm_timeout {
#define TPM_RSP_SIZE_BYTE 2 #define TPM_RSP_SIZE_BYTE 2
#define TPM_RSP_RC_BYTE 6 #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_ACCESS(l) (0x0000 | ((l) << 4))
#define TPM_STS(l) (0x0001 | ((l) << 4)) #define TPM_STS(l) (0x0001 | ((l) << 4))
#define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4))

View File

@ -16,6 +16,7 @@
*/ */
#include <arch/early_variables.h> #include <arch/early_variables.h>
#include <assert.h>
#include <commonlib/endian.h> #include <commonlib/endian.h>
#include <console/console.h> #include <console/console.h>
#include <delay.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; 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 * SPI frame header for TPM transactions is 4 bytes in size, it is described
* in section "6.4.6 Spi Bit Protocol". * in section "6.4.6 Spi Bit Protocol".
@ -113,7 +85,7 @@ static int tpm_sync(void)
{ {
struct stopwatch sw; struct stopwatch sw;
stopwatch_init_usecs_expire(&sw, 10 * 1000); stopwatch_init_msecs_expire(&sw, 10);
while (!tis_plat_irq_status()) { while (!tis_plat_irq_status()) {
if (stopwatch_expired(&sw)) { if (stopwatch_expired(&sw)) {
printk(BIOS_ERR, "Timeout wait for tpm irq!\n"); printk(BIOS_ERR, "Timeout wait for tpm irq!\n");
@ -347,7 +319,53 @@ static uint32_t get_burst_count(void)
uint32_t status; uint32_t status;
read_tpm_sts(&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) 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))) if (!tpm2_read_reg(TPM_DID_VID_REG, &did_vid, sizeof(did_vid)))
return -1; return -1;
/* Try claiming locality zero. */ /* Claim locality 0. */
tpm2_read_reg(TPM_ACCESS_REG, &cmd, sizeof(cmd)); if (!tpm2_claim_locality())
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);
return -1; 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); read_tpm_sts(&status);
if (((status >> tpm_family_shift) & tpm_family_mask) != if ((status & TPM_STS_FAMILY_MASK) != TPM_STS_FAMILY_TPM_2_0) {
tpm_family_tpm2) {
printk(BIOS_ERR, "unexpected TPM family value, status: %#x\n", printk(BIOS_ERR, "unexpected TPM family value, status: %#x\n",
status); status);
return -1; 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. */ /* 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 * 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); fifo_transfer(command_size, fifo_buffer, fifo_transmit);
/* Now tell the TPM it can start processing the command. */ /* 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. */ /* 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 (!wait_for_status(expected_status_bits, expected_status_bits)) {
/* /*
* If timed out, which should never happen, let's at least * 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. */ /* Verify that 'data available' is not asseretd any more. */
read_tpm_sts(&status); 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); printk(BIOS_ERR, "unexpected final status %#x\n", status);
return 0; return 0;
} }
/* Move the TPM back to idle state. */ /* Move the TPM back to idle state. */
write_tpm_sts(command_ready); write_tpm_sts(TPM_STS_COMMAND_READY);
return payload_size; return payload_size;
} }

View File

@ -19,6 +19,32 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.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() * tis_init()
* *