diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/drivers/spi/tpm/tpm.c | 100 |
1 files changed, 49 insertions, 51 deletions
diff --git a/src/drivers/spi/tpm/tpm.c b/src/drivers/spi/tpm/tpm.c index cd1fbdf73b..1c5e5353ad 100644 --- a/src/drivers/spi/tpm/tpm.c +++ b/src/drivers/spi/tpm/tpm.c @@ -15,6 +15,7 @@ * Specification Revision 00.43". */ +#include <arch/early_variables.h> #include <commonlib/endian.h> #include <console/console.h> #include <delay.h> @@ -35,25 +36,11 @@ #define TPM_RID_REG (TPM_LOCALITY_0_SPI_BASE + 0xf04) #define TPM_FW_VER (TPM_LOCALITY_0_SPI_BASE + 0xf90) -/* SPI Interface descriptor used by the driver. */ -struct tpm_spi_if { - struct spi_slave slave; - int (*cs_assert)(const struct spi_slave *slave); - void (*cs_deassert)(const struct spi_slave *slave); - int (*xfer)(const struct spi_slave *slave, const void *dout, - size_t bytesout, void *din, - size_t bytesin); -}; - -/* Use the common SPI driver wrapper as the interface callbacks. */ -static struct tpm_spi_if tpm_if = { - .cs_assert = spi_claim_bus, - .cs_deassert = spi_release_bus, - .xfer = spi_xfer -}; +/* SPI slave structure for TPM device. */ +static struct spi_slave g_spi_slave CAR_GLOBAL; /* Cached TPM device identification. */ -static struct tpm2_info tpm_info; +static struct tpm2_info g_tpm_info CAR_GLOBAL; /* * TODO(vbendeb): make CONFIG_DEBUG_TPM an int to allow different level of @@ -100,16 +87,16 @@ typedef struct { void tpm2_get_info(struct tpm2_info *info) { - *info = tpm_info; + *info = car_get_var(g_tpm_info); } __attribute__((weak)) int tis_plat_irq_status(void) { - static int warning_displayed; + static int warning_displayed CAR_GLOBAL; - if (!warning_displayed) { + if (!car_get_var(warning_displayed)) { printk(BIOS_WARNING, "WARNING: tis_plat_irq_status() not implemented, wasting 10ms to wait on Cr50!\n"); - warning_displayed = 1; + car_set_var(warning_displayed, 1); } mdelay(10); @@ -148,18 +135,19 @@ static int start_transaction(int read_write, size_t bytes, unsigned addr) uint8_t byte; int i; struct stopwatch sw; - static int tpm_sync_needed; + static int tpm_sync_needed CAR_GLOBAL; + struct spi_slave *spi_slave = car_get_var_ptr(&g_spi_slave); /* Wait for tpm to finish previous transaction if needed */ - if (tpm_sync_needed) + if (car_get_var(tpm_sync_needed)) tpm_sync(); else - tpm_sync_needed = 1; + car_set_var(tpm_sync_needed, 1); /* Try to wake cr50 if it is asleep. */ - tpm_if.cs_assert(&tpm_if.slave); + spi_claim_bus(spi_slave); udelay(1); - tpm_if.cs_deassert(&tpm_if.slave); + spi_release_bus(spi_slave); udelay(100); /* @@ -174,7 +162,7 @@ static int start_transaction(int read_write, size_t bytes, unsigned addr) header.body[i + 1] = (addr >> (8 * (2 - i))) & 0xff; /* CS assert wakes up the slave. */ - tpm_if.cs_assert(&tpm_if.slave); + spi_claim_bus(spi_slave); /* * The TCG TPM over SPI specification introduces the notion of SPI @@ -201,7 +189,7 @@ static int start_transaction(int read_write, size_t bytes, unsigned addr) * to require to stall the master, this would present an issue. * crosbug.com/p/52132 has been opened to track this. */ - tpm_if.xfer(&tpm_if.slave, header.body, sizeof(header.body), NULL, 0); + spi_xfer(spi_slave, header.body, sizeof(header.body), NULL, 0); /* * Now poll the bus until TPM removes the stall bit. Give it up to 100 @@ -212,10 +200,10 @@ static int start_transaction(int read_write, size_t bytes, unsigned addr) do { if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "TPM flow control failure\n"); - tpm_if.cs_deassert(&tpm_if.slave); + spi_release_bus(spi_slave); return 0; } - tpm_if.xfer(&tpm_if.slave, NULL, 0, &byte, 1); + spi_xfer(spi_slave, NULL, 0, &byte, 1); } while (!(byte & 1)); return 1; } @@ -228,10 +216,11 @@ static void trace_dump(const char *prefix, uint32_t reg, size_t bytes, const uint8_t *buffer, int force) { - static char prev_prefix; - static unsigned prev_reg; - static int current_char; + static char prev_prefix CAR_GLOBAL; + static unsigned prev_reg CAR_GLOBAL; + static int current_char CAR_GLOBAL; const int BYTES_PER_LINE = 32; + int *current_char_ptr = car_get_var_ptr(¤t_char); if (!force) { if (!debug_level_) @@ -245,11 +234,12 @@ static void trace_dump(const char *prefix, uint32_t reg, * Do not print register address again if the last dump print was for * that register. */ - if ((prev_prefix != *prefix) || (prev_reg != reg)) { - prev_prefix = *prefix; - prev_reg = reg; + if ((car_get_var(prev_prefix) != *prefix) || + (car_get_var(prev_reg) != reg)) { + car_set_var(prev_prefix, *prefix); + car_set_var(prev_reg, reg); printk(BIOS_DEBUG, "\n%s %2.2x:", prefix, reg); - current_char = 0; + *current_char_ptr = 0; } if ((reg != TPM_DATA_FIFO_REG) && (bytes == 4)) { @@ -266,11 +256,12 @@ static void trace_dump(const char *prefix, uint32_t reg, * quantiites is printed byte at a time. */ for (i = 0; i < bytes; i++) { - if (current_char && !(current_char % BYTES_PER_LINE)) { + if (*current_char_ptr && + !(*current_char_ptr % BYTES_PER_LINE)) { printk(BIOS_DEBUG, "\n "); - current_char = 0; + *current_char_ptr = 0; } - current_char++; + (*current_char_ptr)++; printk(BIOS_DEBUG, " %2.2x", buffer[i]); } } @@ -282,7 +273,8 @@ static void trace_dump(const char *prefix, uint32_t reg, */ static void write_bytes(const void *buffer, size_t bytes) { - tpm_if.xfer(&tpm_if.slave, buffer, bytes, NULL, 0); + struct spi_slave *spi_slave = car_get_var_ptr(&g_spi_slave); + spi_xfer(spi_slave, buffer, bytes, NULL, 0); } /* @@ -291,7 +283,8 @@ static void write_bytes(const void *buffer, size_t bytes) */ static void read_bytes(void *buffer, size_t bytes) { - tpm_if.xfer(&tpm_if.slave, NULL, 0, buffer, bytes); + struct spi_slave *spi_slave = car_get_var_ptr(&g_spi_slave); + spi_xfer(spi_slave, NULL, 0, buffer, bytes); } /* @@ -302,11 +295,12 @@ static void read_bytes(void *buffer, size_t bytes) */ static int tpm2_write_reg(unsigned reg_number, const void *buffer, size_t bytes) { + struct spi_slave *spi_slave = car_get_var_ptr(&g_spi_slave); trace_dump("W", reg_number, bytes, buffer, 0); if (!start_transaction(false, bytes, reg_number)) return 0; write_bytes(buffer, bytes); - tpm_if.cs_deassert(&tpm_if.slave); + spi_release_bus(spi_slave); return 1; } @@ -318,12 +312,13 @@ static int tpm2_write_reg(unsigned reg_number, const void *buffer, size_t bytes) */ static int tpm2_read_reg(unsigned reg_number, void *buffer, size_t bytes) { + struct spi_slave *spi_slave = car_get_var_ptr(&g_spi_slave); if (!start_transaction(true, bytes, reg_number)) { memset(buffer, 0, bytes); return 0; } read_bytes(buffer, bytes); - tpm_if.cs_deassert(&tpm_if.slave); + spi_release_bus(spi_slave); trace_dump("R", reg_number, bytes, buffer, 0); return 1; } @@ -359,8 +354,10 @@ int tpm2_init(struct spi_slave *spi_if) { uint32_t did_vid, status; uint8_t cmd; + struct tpm2_info *tpm_info = car_get_var_ptr(&g_tpm_info); + struct spi_slave *spi_slave = car_get_var_ptr(&g_spi_slave); - memcpy(&tpm_if.slave, spi_if, sizeof(*spi_if)); + memcpy(spi_slave, spi_if, sizeof(*spi_if)); /* * It is enough to check the first register read error status to bail @@ -411,15 +408,15 @@ int tpm2_init(struct spi_slave *spi_if) * structure. */ tpm2_read_reg(TPM_RID_REG, &cmd, sizeof(cmd)); - tpm_info.vendor_id = did_vid & 0xffff; - tpm_info.device_id = did_vid >> 16; - tpm_info.revision = cmd; + tpm_info->vendor_id = did_vid & 0xffff; + tpm_info->device_id = did_vid >> 16; + tpm_info->revision = cmd; printk(BIOS_INFO, "Connected to device vid:did:rid of %4.4x:%4.4x:%2.2x\n", - tpm_info.vendor_id, tpm_info.device_id, tpm_info.revision); + tpm_info->vendor_id, tpm_info->device_id, tpm_info->revision); /* Let's report device FW version if available. */ - if (tpm_info.vendor_id == 0x1ae0) { + if (tpm_info->vendor_id == 0x1ae0) { int chunk_count = 0; size_t chunk_size; /* @@ -546,9 +543,10 @@ size_t tpm2_process_command(const void *tpm2_command, size_t command_size, uint8_t *rsp_body = tpm2_response; union fifo_transfer_buffer fifo_buffer; const int HEADER_SIZE = 6; + struct tpm2_info *tpm_info = car_get_var_ptr(&g_tpm_info); /* Do not try using an uninitialized TPM. */ - if (!tpm_info.vendor_id) + if (!tpm_info->vendor_id) return 0; /* Skip the two byte tag, read the size field. */ |