diff options
-rw-r--r-- | chip/g/i2cs.c | 17 | ||||
-rw-r--r-- | chip/g/i2cs.h | 7 | ||||
-rw-r--r-- | common/i2cs_tpm.c | 20 | ||||
-rw-r--r-- | common/tpm_registers.c | 13 |
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 |