summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/g/i2cs.c17
-rw-r--r--chip/g/i2cs.h7
-rw-r--r--common/i2cs_tpm.c20
-rw-r--r--common/tpm_registers.c13
4 files changed, 52 insertions, 5 deletions
diff --git a/chip/g/i2cs.c b/chip/g/i2cs.c
index 2a0354005d..b0fb579455 100644
--- a/chip/g/i2cs.c
+++ b/chip/g/i2cs.c
@@ -202,3 +202,20 @@ int i2cs_register_write_complete_handler(wr_complete_handler_f wc_handler)
return 0;
}
+
+size_t i2cs_get_read_fifo_buffer_depth(void)
+{
+ uint32_t hw_read_pointer;
+ size_t depth;
+
+ /*
+ * Get the current value of the HW I2CS read pointer. Note that the read
+ * pointer is b8:b3 of the I2CS_READ_PTR register. The lower 3 bits of
+ * this register are used to support bit accesses by a host.
+ */
+ hw_read_pointer = GREAD(I2CS, READ_PTR) >> 3;
+ /* Determine the number of bytes buffered in the HW fifo */
+ depth = (last_read_pointer - hw_read_pointer) & REGISTER_FILE_MASK;
+
+ return depth;
+}
diff --git a/chip/g/i2cs.h b/chip/g/i2cs.h
index 6fe3fb2f75..bd818f1ac1 100644
--- a/chip/g/i2cs.h
+++ b/chip/g/i2cs.h
@@ -30,4 +30,11 @@ void i2cs_post_read_data(uint8_t byte_to_read);
*/
void i2cs_set_pinmux(void);
+/*
+ * Determine the number of bytes currently buffered in the I2CS READ fifo. This
+ * value is calculated by finding the difference between read pointer that's
+ * used by FW to add bytes to the HW fifo and the HW's read pointer.
+ */
+size_t i2cs_get_read_fifo_buffer_depth(void);
+
#endif /* ! __CHIP_G_I2CS_H */
diff --git a/common/i2cs_tpm.c b/common/i2cs_tpm.c
index dfc89ea822..87a075a9a9 100644
--- a/common/i2cs_tpm.c
+++ b/common/i2cs_tpm.c
@@ -74,7 +74,7 @@ static const struct i2c_tpm_reg_map i2c_to_tpm[] = {
{6, 4, 0xf00}, /* TPM DID VID */
{0xa, 4, 0x14}, /* TPM TPM_INTF_CAPABILITY */
{0xe, 1, 0xf04}, /* TPM RID */
- {0xf, 4, 0xf90}, /* TPM_FW_VER */
+ {0xf, 0, 0xf90}, /* TPM_FW_VER */
};
static void wr_complete_handler(void *i2cs_data, size_t i2cs_data_size)
@@ -150,6 +150,24 @@ static void wr_complete_handler(void *i2cs_data, size_t i2cs_data_size)
* burst size field of the tpm status register.
*/
reg_size = tpm_get_burst_size();
+
+ /* For TPM fifo reads, if there is already data pending in the
+ * I2CS hw fifo, then don't read any more TPM fifo data until
+ * the I2CS hw fifo has been fully drained.
+ *
+ * The Host will only read only enough data to extract the full
+ * TPM message length. However, Cr50 will fill the I2CS hw fifo
+ * with 'burstsize' amount of bytes. The 2nd fifo access for a
+ * given TPM repsonse by the Host will extract the queued up
+ * data. Following this, the Host will then read 'burstcount'
+ * amount of data for subsequent fifo accesses until the
+ * response has been fully read.
+ *
+ */
+ if (i2cs_get_read_fifo_buffer_depth())
+ /* Data is already in the queue, just return */
+ return;
+
/*
* Now, this is a hack, but we are short on SRAM, so let's
* reuse the receive buffer for the FIFO data sotrage. We know
diff --git a/common/tpm_registers.c b/common/tpm_registers.c
index 95071c10c9..615f7013bd 100644
--- a/common/tpm_registers.c
+++ b/common/tpm_registers.c
@@ -387,8 +387,6 @@ void tpm_register_put(uint32_t regaddr, const uint8_t *data, uint32_t data_size)
fifo_reg_write(data, data_size);
break;
case TPM_FW_VER:
- /* Reload versions, in case something has been updated */
- set_version_string();
/* Reset read byte count */
tpm_fw_ver_index = 0;
break;
@@ -419,7 +417,7 @@ void fifo_reg_read(uint8_t *dest, uint32_t data_size)
tpm_sts &= ~(burst_count_mask << burst_count_shift);
if (tpm_.fifo_write_index == tpm_.fifo_read_index) {
tpm_sts &= ~(data_avail | command_ready);
- /* Birst size for the following write requests. */
+ /* Burst size for the following write requests. */
tpm_sts |= 63 << burst_count_shift;
} else {
/*
@@ -494,12 +492,19 @@ static void tpm_init(void)
{
set_tpm_state(tpm_state_idle);
tpm_.regs.access = tpm_reg_valid_sts;
+ /*
+ * I2CS writes must limit the burstsize to 63 for fifo writes to work
+ * properly. For I2CS fifo writes the first byte is the I2C TPM address
+ * and the next up to 62 bytes are the data to write to that register.
+ */
tpm_.regs.sts = (tpm_family_tpm2 << tpm_family_shift) |
- (64 << burst_count_shift) | sts_valid;
+ (63 << burst_count_shift) | sts_valid;
/* TPM2 library functions. */
_plat__Signal_PowerOn();
+ /* Create version string to be read by host */
+ set_version_string();
/*
* Make sure NV RAM metadata is initialized, needed to check