summaryrefslogtreecommitdiff
path: root/src/drivers/i2c/tpm/cr50.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/i2c/tpm/cr50.c')
-rw-r--r--src/drivers/i2c/tpm/cr50.c93
1 files changed, 45 insertions, 48 deletions
diff --git a/src/drivers/i2c/tpm/cr50.c b/src/drivers/i2c/tpm/cr50.c
index a3ff7814de..37f0881980 100644
--- a/src/drivers/i2c/tpm/cr50.c
+++ b/src/drivers/i2c/tpm/cr50.c
@@ -189,7 +189,7 @@ static int request_locality(struct tpm_chip *chip, int loc)
}
/* cr50 requires all 4 bytes of status register to be read */
-static uint8_t cr50_tis_i2c_status(struct tpm_chip *chip)
+static uint8_t cr50_i2c_tis_status(struct tpm_chip *chip)
{
uint8_t buf[4];
if (cr50_i2c_read(chip, TPM_STS(chip->vendor.locality),
@@ -201,7 +201,7 @@ static uint8_t cr50_tis_i2c_status(struct tpm_chip *chip)
}
/* cr50 requires all 4 bytes of status register to be written */
-static void cr50_tis_i2c_ready(struct tpm_chip *chip)
+static void cr50_i2c_tis_ready(struct tpm_chip *chip)
{
uint8_t buf[4] = { TPM_STS_COMMAND_READY };
cr50_i2c_write(chip, TPM_STS(chip->vendor.locality), buf, sizeof(buf));
@@ -210,7 +210,7 @@ static void cr50_tis_i2c_ready(struct tpm_chip *chip)
/* cr50 uses bytes 3:2 of status register for burst count and
* all 4 bytes must be read */
-static int cr50_wait_burst_status(struct tpm_chip *chip, uint8_t mask,
+static int cr50_i2c_wait_burststs(struct tpm_chip *chip, uint8_t mask,
size_t *burst, int *status)
{
uint8_t buf[4];
@@ -240,28 +240,26 @@ static int cr50_wait_burst_status(struct tpm_chip *chip, uint8_t mask,
return -1;
}
-static int cr50_tis_i2c_recv(struct tpm_chip *chip, uint8_t *buf,
+static int cr50_i2c_tis_recv(struct tpm_chip *chip, uint8_t *buf,
size_t buf_len)
{
size_t burstcnt, current, len, expected;
uint8_t addr = TPM_DATA_FIFO(chip->vendor.locality);
+ uint8_t mask = TPM_STS_VALID | TPM_STS_DATA_AVAIL;
int status;
- int ret = -1;
if (buf_len < TPM_HEADER_SIZE)
- goto out;
+ goto out_err;
- if (cr50_wait_burst_status(chip, TPM_STS_VALID, &burstcnt, &status) < 0)
- goto out;
- if (!(status & TPM_STS_DATA_AVAIL)) {
+ if (cr50_i2c_wait_burststs(chip, mask, &burstcnt, &status) < 0) {
printk(BIOS_ERR, "%s: First chunk not available\n", __func__);
- goto out;
+ goto out_err;
}
/* Read first chunk of burstcnt bytes */
if (cr50_i2c_read(chip, addr, buf, burstcnt) != 0) {
printk(BIOS_ERR, "%s: Read failed\n", __func__);
- goto out;
+ goto out_err;
}
/* Determine expected data in the return buffer */
@@ -269,45 +267,43 @@ static int cr50_tis_i2c_recv(struct tpm_chip *chip, uint8_t *buf,
if (expected > buf_len) {
printk(BIOS_ERR, "%s: Too much data: %zu > %zu\n",
__func__, expected, buf_len);
- goto out;
+ goto out_err;
}
/* Now read the rest of the data */
current = burstcnt;
while (current < expected) {
/* Read updated burst count and check status */
- if (cr50_wait_burst_status(chip, TPM_STS_VALID,
- &burstcnt, &status) < 0)
- goto out;
- if (!(status & TPM_STS_DATA_AVAIL)) {
- printk(BIOS_ERR, "%s: Data not available\n", __func__);
- goto out;
- }
+ if (cr50_i2c_wait_burststs(chip, mask, &burstcnt, &status) < 0)
+ goto out_err;
len = min(burstcnt, expected - current);
if (cr50_i2c_read(chip, addr, buf + current, len) != 0) {
printk(BIOS_ERR, "%s: Read failed\n", __func__);
- goto out;
+ goto out_err;
}
current += len;
}
/* Ensure TPM is done reading data */
- if (cr50_wait_burst_status(chip, TPM_STS_VALID, &burstcnt, &status) < 0)
- goto out;
+ if (cr50_i2c_wait_burststs(chip, TPM_STS_VALID, &burstcnt, &status) < 0)
+ goto out_err;
if (status & TPM_STS_DATA_AVAIL) {
printk(BIOS_ERR, "%s: Data still available\n", __func__);
- goto out;
+ goto out_err;
}
- ret = current;
+ return current;
-out:
- return ret;
+out_err:
+ /* Abort current transaction if still pending */
+ if (cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY)
+ cr50_i2c_tis_ready(chip);
+ return -1;
}
-static int cr50_tis_i2c_send(struct tpm_chip *chip, uint8_t *buf, size_t len)
+static int cr50_i2c_tis_send(struct tpm_chip *chip, uint8_t *buf, size_t len)
{
int status;
size_t burstcnt, limit, sent = 0;
@@ -317,25 +313,26 @@ static int cr50_tis_i2c_send(struct tpm_chip *chip, uint8_t *buf, size_t len)
stopwatch_init_msecs_expire(&sw, CR50_TIMEOUT_LONG_MS);
/* Wait until TPM is ready for a command */
- while (!(cr50_tis_i2c_status(chip) & TPM_STS_COMMAND_READY)) {
+ while (!(cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY)) {
if (stopwatch_expired(&sw)) {
printk(BIOS_ERR, "%s: Command ready timeout\n",
__func__);
return -1;
}
- cr50_tis_i2c_ready(chip);
+ cr50_i2c_tis_ready(chip);
}
while (len > 0) {
+ uint8_t mask = TPM_STS_VALID;
+
+ /* Wait for data if this is not the first chunk */
+ if (sent > 0)
+ mask |= TPM_STS_DATA_EXPECT;
+
/* Read burst count and check status */
- if (cr50_wait_burst_status(chip, TPM_STS_VALID,
- &burstcnt, &status) < 0)
- goto out;
- if (sent > 0 && !(status & TPM_STS_DATA_EXPECT)) {
- printk(BIOS_ERR, "%s: Data not expected\n", __func__);
- goto out;
- }
+ if (cr50_i2c_wait_burststs(chip, mask, &burstcnt, &status) < 0)
+ goto out_err;
/* Use burstcnt - 1 to account for the address byte
* that is inserted by cr50_i2c_write() */
@@ -343,7 +340,7 @@ static int cr50_tis_i2c_send(struct tpm_chip *chip, uint8_t *buf, size_t len)
if (cr50_i2c_write(chip, TPM_DATA_FIFO(chip->vendor.locality),
&buf[sent], limit) != 0) {
printk(BIOS_ERR, "%s: Write failed\n", __func__);
- goto out;
+ goto out_err;
}
sent += limit;
@@ -351,25 +348,25 @@ static int cr50_tis_i2c_send(struct tpm_chip *chip, uint8_t *buf, size_t len)
}
/* Ensure TPM is not expecting more data */
- if (cr50_wait_burst_status(chip, TPM_STS_VALID, &burstcnt, &status) < 0)
- goto out;
+ if (cr50_i2c_wait_burststs(chip, TPM_STS_VALID, &burstcnt, &status) < 0)
+ goto out_err;
if (status & TPM_STS_DATA_EXPECT) {
printk(BIOS_ERR, "%s: Data still expected\n", __func__);
- goto out;
+ goto out_err;
}
/* Start the TPM command */
if (cr50_i2c_write(chip, TPM_STS(chip->vendor.locality), tpm_go,
sizeof(tpm_go)) < 0) {
printk(BIOS_ERR, "%s: Start command failed\n", __func__);
- goto out;
+ goto out_err;
}
return sent;
-out:
+out_err:
/* Abort current transaction if still pending */
- if (cr50_tis_i2c_status(chip) & TPM_STS_COMMAND_READY)
- cr50_tis_i2c_ready(chip);
+ if (cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY)
+ cr50_i2c_tis_ready(chip);
return -1;
}
@@ -379,10 +376,10 @@ static void cr50_vendor_init(struct tpm_chip *chip)
chip->vendor.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID;
chip->vendor.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID;
chip->vendor.req_canceled = TPM_STS_COMMAND_READY;
- chip->vendor.status = &cr50_tis_i2c_status;
- chip->vendor.recv = &cr50_tis_i2c_recv;
- chip->vendor.send = &cr50_tis_i2c_send;
- chip->vendor.cancel = &cr50_tis_i2c_ready;
+ chip->vendor.status = &cr50_i2c_tis_status;
+ chip->vendor.recv = &cr50_i2c_tis_recv;
+ chip->vendor.send = &cr50_i2c_tis_send;
+ chip->vendor.cancel = &cr50_i2c_tis_ready;
}
int tpm_vendor_probe(unsigned bus, uint32_t addr)