summaryrefslogtreecommitdiff
path: root/chip/g
diff options
context:
space:
mode:
authorScott <scollyer@chromium.org>2016-08-29 08:48:22 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-09-05 23:22:18 -0700
commitd5639272e2ed6b4478a39310c5aad6a4545509ad (patch)
tree60641b58b01a16be2afce1abc41ef42692d9cdeb /chip/g
parent7edd3827cf9d2174bc9d173c878379e0ad81c990 (diff)
downloadchrome-ec-d5639272e2ed6b4478a39310c5aad6a4545509ad.tar.gz
Cr50: I2CS TPM: Added routine to write to HW fifo a word at a time
Reads of the TPM fifo by the Host are done in chunks of up to 63 bytes at a time. The existing routine used to copy data read from the TPM layer to the I2CS fifo operates one byte at a time. This method is fine for single and four byte register reads. However, for larger buffers the performace can be improved by aligning the the fifo write pointer to be at a word boundary. BRANCH=none BUG=chrome-os-partner:40397 TEST=manual Utilized test code on the host to initiate TPM fifo reads of various lengths and added timing markers on the Cr50 to compare performance between the existing byte at a time and the new full buffer write funciton. Verifed that the fifo reads will still correct and compared the time consumed copy TPM fifo data to the I2CS HW fifo. This test processed 1910 bytes over 34 fifo reads. Byte at a time method: 1910 bytes: 6375 uS: Avg Time = 3.233 uS per byte Full buffer write: 1910 bytes: 3009 uS: Avg Time = 1.57 uS per byte Change-Id: I3a47a350ab7af740a452fd115c33117b453b9611 Signed-off-by: Scott <scollyer@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/377663 Commit-Ready: Scott Collyer <scollyer@chromium.org> Tested-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Diffstat (limited to 'chip/g')
-rw-r--r--chip/g/i2cs.c61
-rw-r--r--chip/g/i2cs.h10
2 files changed, 71 insertions, 0 deletions
diff --git a/chip/g/i2cs.c b/chip/g/i2cs.c
index b0fb579455..e53702f89d 100644
--- a/chip/g/i2cs.c
+++ b/chip/g/i2cs.c
@@ -192,6 +192,67 @@ void i2cs_post_read_data(uint8_t byte_to_read)
last_read_pointer = (last_read_pointer + 1) & REGISTER_FILE_MASK;
}
+void i2cs_post_read_fill_fifo(uint8_t *buffer, size_t len)
+{
+ volatile uint32_t *value_addr;
+ uint32_t word_out_value;
+ uint32_t addr_offset;
+ uint32_t remainder_bytes;
+ uint32_t start_offset;
+ uint32_t num_words;
+ int i, j;
+
+ /* Get offset into 1st fifo word*/
+ start_offset = last_read_pointer & 0x3;
+ /* Number of bytes to fill out 1st word */
+ remainder_bytes = (4 - start_offset) & 0x3;
+ /* Get pointer to base of fifo and offset */
+ addr_offset = last_read_pointer >> 2;
+ value_addr = GREG32_ADDR(I2CS, READ_BUFFER0);
+ /* Update read_pointer to reflect final value */
+ last_read_pointer = (last_read_pointer + len) &
+ REGISTER_FILE_MASK;
+
+ /* Insert bytes until fifo is word aligned */
+ if (remainder_bytes) {
+ /* mask the bytes to be kept */
+ word_out_value = *value_addr;
+ word_out_value &= (1 << (8 * start_offset)) - 1;
+ /* Write in remainder bytes */
+ for (i = 0; i < remainder_bytes; i++)
+ word_out_value |= *buffer++ << (8 * (start_offset + i));
+ /* Write to fifo regsiter */
+ value_addr[addr_offset] = word_out_value;
+ addr_offset = (addr_offset + 1) & (REGISTER_FILE_MASK >> 2);
+ /* Account for bytes consumed */
+ len -= remainder_bytes;
+ }
+
+ /* HW fifo is now word aligned */
+ num_words = len >> 2;
+ for (i = 0; i < num_words; i++) {
+ word_out_value = 0;
+ for (j = 0; j < 4; j++)
+ word_out_value |= *buffer++ << (j * 8);
+ /* Write word to fifo and update fifo offset */
+ value_addr[addr_offset] = word_out_value;
+ addr_offset = (addr_offset + 1) & (REGISTER_FILE_MASK >> 2);
+ }
+ len -= (num_words << 2);
+
+ /* Now proccess remaining bytes (if any), will be <= 3 at this point */
+ remainder_bytes = len;
+ if (remainder_bytes) {
+ /* read from HW fifo */
+ word_out_value = *value_addr;
+ /* Mask bytes that need to be kept */
+ word_out_value &= (0xffffffff << (8 * remainder_bytes));
+ for (i = 0; i < remainder_bytes; i++)
+ word_out_value |= *buffer++ << (8 * i);
+ value_addr[addr_offset] = word_out_value;
+ }
+}
+
int i2cs_register_write_complete_handler(wr_complete_handler_f wc_handler)
{
if (write_complete_handler_)
diff --git a/chip/g/i2cs.h b/chip/g/i2cs.h
index bd818f1ac1..76e8117be0 100644
--- a/chip/g/i2cs.h
+++ b/chip/g/i2cs.h
@@ -37,4 +37,14 @@ void i2cs_set_pinmux(void);
*/
size_t i2cs_get_read_fifo_buffer_depth(void);
+/*
+ * Write buffer of data into the I2CS HW read fifo. The function will operate a
+ * byte at a time until the fifo write pointer is word aligned. Then it will
+ * consume all remaining words of input data. There is another stage to handle
+ * any excess bytes. The efficiency benefits relative the byte at a time
+ * function diminish as the buffer size gets smaller and therefore not intended
+ * to be used for <= 4 byte buffers.
+ */
+void i2cs_post_read_fill_fifo(uint8_t *buffer, size_t len);
+
#endif /* ! __CHIP_G_I2CS_H */