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:
committed by
Furquan Shaikh
parent
bf6dfaefc2
commit
260b297a89
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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()
|
||||
*
|
||||
|
Reference in New Issue
Block a user